added nanovg demo
This commit is contained in:
parent
ef9570ca81
commit
248c67acf9
|
@ -0,0 +1,337 @@
|
|||
/*
|
||||
Copyright (c) 2015
|
||||
vurtun <polygone@gmx.net>
|
||||
MIT licence
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#define NANOVG_GLES2_IMPLEMENTATION
|
||||
#include "nanovg/nanovg.h"
|
||||
#include "nanovg/nanovg_gl.h"
|
||||
#include "nanovg/nanovg_gl_utils.h"
|
||||
#include "../gui.h"
|
||||
|
||||
/* macros */
|
||||
#define DTIME 16
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#define MAX(a,b) ((a) < (b) ? (b) : (a))
|
||||
#define CLAMP(i,v,x) (MAX(MIN(v,x), i))
|
||||
#define LEN(a) (sizeof(a)/sizeof(a)[0])
|
||||
#define UNUSED(a) ((void)(a))
|
||||
|
||||
#include "demo.c"
|
||||
|
||||
static void
|
||||
die(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
va_end(ap);
|
||||
fputs("\n", stderr);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
static gui_size
|
||||
font_get_width(gui_handle handle, const gui_char *text, gui_size len)
|
||||
{
|
||||
gui_size width;
|
||||
float bounds[4];
|
||||
NVGcontext *ctx = (NVGcontext*)handle.ptr;
|
||||
nvgTextBounds(ctx, 0, 0, text, &text[len], bounds);
|
||||
width = (gui_size)(bounds[2] - bounds[0]);
|
||||
return width;
|
||||
}
|
||||
|
||||
static void
|
||||
draw_text(NVGcontext *ctx, float x, float y, struct gui_color c,
|
||||
const gui_char *string, gui_size len)
|
||||
{
|
||||
gui_float height = 0;
|
||||
nvgBeginPath(ctx);
|
||||
nvgTextMetrics(ctx, NULL, NULL, &height);
|
||||
nvgFillColor(ctx, nvgRGBA(c.r, c.g, c.b, c.a));
|
||||
nvgText(ctx, x, y + height, string, &string[len]);
|
||||
nvgFill(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_line(NVGcontext *ctx, float x0, float y0, float x1, float y1, struct gui_color c)
|
||||
{
|
||||
nvgBeginPath(ctx);
|
||||
nvgMoveTo(ctx, x0, y0);
|
||||
nvgLineTo(ctx, x1, y1);
|
||||
nvgFillColor(ctx, nvgRGBA(c.r, c.g, c.b, c.a));
|
||||
nvgFill(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_rect(NVGcontext *ctx, float x, float y, float w, float h, struct gui_color c)
|
||||
{
|
||||
nvgBeginPath(ctx);
|
||||
nvgRect(ctx, x, y, w, h);
|
||||
nvgFillColor(ctx, nvgRGBA(c.r, c.g, c.b, c.a));
|
||||
nvgFill(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_circle(NVGcontext *ctx, float x, float y, float r, struct gui_color c)
|
||||
{
|
||||
NVGpaint bg;
|
||||
nvgBeginPath(ctx);
|
||||
nvgCircle(ctx, x + r, y + r, r);
|
||||
nvgFillColor(ctx, nvgRGBA(c.r, c.g, c.b, c.a));
|
||||
nvgFill(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_triangle(NVGcontext *ctx, float x0, float y0, float x1, float y1,
|
||||
float x2, float y2, struct gui_color c)
|
||||
{
|
||||
nvgBeginPath(ctx);
|
||||
nvgMoveTo(ctx, x0, y0);
|
||||
nvgLineTo(ctx, x1, y1);
|
||||
nvgLineTo(ctx, x2, y2);
|
||||
nvgLineTo(ctx, x0, y0);
|
||||
nvgFillColor(ctx, nvgRGBA(c.r, c.g, c.b, c.a));
|
||||
nvgFill(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_image(NVGcontext *ctx, gui_handle img, float x, float y, float w, float h, float r)
|
||||
{
|
||||
NVGpaint imgpaint;
|
||||
imgpaint = nvgImagePattern(ctx, x, y, w, h, 0, img.id, 1.0f);
|
||||
nvgBeginPath(ctx);
|
||||
nvgRoundedRect(ctx, x, y, w, h, r);
|
||||
nvgFillPaint(ctx, imgpaint);
|
||||
nvgFill(ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
execute(NVGcontext *nvg, gui_command_buffer *list, int width, int height)
|
||||
{
|
||||
static const struct gui_color col = {255, 0, 0, 255};
|
||||
const struct gui_command *cmd;
|
||||
|
||||
glPushAttrib(GL_ENABLE_BIT|GL_COLOR_BUFFER_BIT|GL_TRANSFORM_BIT);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
nvgBeginFrame(nvg, width, height, ((float)width/(float)height));
|
||||
gui_foreach_command(cmd, list) {
|
||||
switch (cmd->type) {
|
||||
case GUI_COMMAND_NOP: break;
|
||||
case GUI_COMMAND_SCISSOR: {
|
||||
const struct gui_command_scissor *s = gui_command(scissor, cmd);
|
||||
nvgScissor(nvg, s->x, s->y, s->w, s->h);
|
||||
} break;
|
||||
case GUI_COMMAND_LINE: {
|
||||
const struct gui_command_line *l = gui_command(line, cmd);
|
||||
draw_line(nvg, l->begin[0], l->begin[1], l->end[0], l->end[1], l->color);
|
||||
} break;
|
||||
case GUI_COMMAND_RECT: {
|
||||
const struct gui_command_rect *r = gui_command(rect, cmd);
|
||||
draw_rect(nvg, r->x, r->y, r->w, r->h, r->color);
|
||||
} break;
|
||||
case GUI_COMMAND_CIRCLE: {
|
||||
const struct gui_command_circle *c = gui_command(circle, cmd);
|
||||
draw_circle(nvg, c->x, c->y, (float)c->w / 2.0f, c->color);
|
||||
} break;
|
||||
case GUI_COMMAND_TRIANGLE: {
|
||||
const struct gui_command_triangle *t = gui_command(triangle, cmd);
|
||||
draw_triangle(nvg, t->a[0], t->a[1], t->b[0], t->b[1], t->c[0], t->c[1], t->color);
|
||||
} break;
|
||||
case GUI_COMMAND_TEXT: {
|
||||
const struct gui_command_text *t = gui_command(text, cmd);
|
||||
draw_text(nvg, t->x, t->y, t->fg, t->string, t->length);
|
||||
} break;
|
||||
case GUI_COMMAND_IMAGE: {
|
||||
const struct gui_command_image *i = gui_command(image, cmd);
|
||||
draw_image(nvg, i->img, i->x, i->y, i->w, i->h, 1);
|
||||
} break;
|
||||
case GUI_COMMAND_MAX:
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
nvgResetScissor(nvg);
|
||||
nvgEndFrame(nvg);
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
static void
|
||||
draw(NVGcontext *nvg,struct gui_stack *stack, int width, int height)
|
||||
{
|
||||
struct gui_panel*iter;
|
||||
gui_foreach_panel(iter, stack)
|
||||
execute(nvg, iter->buffer, width, height);
|
||||
}
|
||||
|
||||
static void
|
||||
key(struct gui_input *in, SDL_Event *evt, gui_bool down)
|
||||
{
|
||||
SDL_Keycode sym = evt->key.keysym.sym;
|
||||
if (sym == SDLK_LCTRL || sym == SDLK_RCTRL)
|
||||
gui_input_key(in, GUI_KEY_CTRL, down);
|
||||
else if (sym == SDLK_RSHIFT || sym == SDLK_LSHIFT)
|
||||
gui_input_key(in, GUI_KEY_SHIFT, down);
|
||||
else if (sym == SDLK_DELETE)
|
||||
gui_input_key(in, GUI_KEY_DEL, down);
|
||||
else if (sym == SDLK_RETURN)
|
||||
gui_input_key(in, GUI_KEY_ENTER, down);
|
||||
else if (sym == SDLK_SPACE)
|
||||
gui_input_key(in, GUI_KEY_SPACE, down);
|
||||
else if (sym == SDLK_BACKSPACE)
|
||||
gui_input_key(in, GUI_KEY_BACKSPACE, down);
|
||||
}
|
||||
|
||||
static void
|
||||
motion(struct gui_input *in, SDL_Event *evt)
|
||||
{
|
||||
const gui_int x = evt->motion.x;
|
||||
const gui_int y = evt->motion.y;
|
||||
gui_input_motion(in, x, y);
|
||||
}
|
||||
|
||||
static void
|
||||
btn(struct gui_input *in, SDL_Event *evt, gui_bool down)
|
||||
{
|
||||
const gui_int x = evt->button.x;
|
||||
const gui_int y = evt->button.y;
|
||||
if (evt->button.button == SDL_BUTTON_LEFT)
|
||||
gui_input_button(in, x, y, down);
|
||||
}
|
||||
|
||||
static void
|
||||
text(struct gui_input *in, SDL_Event *evt)
|
||||
{
|
||||
gui_glyph glyph;
|
||||
memcpy(glyph, evt->text.text, GUI_UTF_SIZE);
|
||||
gui_input_char(in, glyph);
|
||||
}
|
||||
|
||||
static void
|
||||
resize(SDL_Event *evt)
|
||||
{
|
||||
if (evt->window.event != SDL_WINDOWEVENT_RESIZED) return;
|
||||
glViewport(0, 0, evt->window.data1, evt->window.data2);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[])
|
||||
{
|
||||
/* Platform */
|
||||
int width, height;
|
||||
const char *font_path;
|
||||
gui_size font_height;
|
||||
SDL_Window *win;
|
||||
SDL_GLContext glContext;
|
||||
NVGcontext *vg = NULL;
|
||||
unsigned int started;
|
||||
unsigned int dt;
|
||||
|
||||
/* GUI */
|
||||
struct gui_input in;
|
||||
struct gui_font font;
|
||||
struct demo_gui gui;
|
||||
|
||||
if (argc < 3) {
|
||||
fprintf(stdout,"Missing TTF Font file/height argument: nanovg <path> <height>\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
font_path = argv[1];
|
||||
font_height = (gui_size)MAX(0, atoi(argv[2]));
|
||||
|
||||
/* SDL */
|
||||
SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_EVENTS);
|
||||
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||
win = SDL_CreateWindow("Demo",
|
||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||
WINDOW_WIDTH, WINDOW_HEIGHT, SDL_WINDOW_OPENGL|SDL_WINDOW_SHOWN);
|
||||
glContext = SDL_GL_CreateContext(win);
|
||||
SDL_GetWindowSize(win, &width, &height);
|
||||
|
||||
/* OpenGL */
|
||||
glewExperimental = 1;
|
||||
if (glewInit() != GLEW_OK)
|
||||
die("[GLEW] failed setup\n");
|
||||
glViewport(0, 0, WINDOW_WIDTH, WINDOW_HEIGHT);
|
||||
|
||||
/* nanovg */
|
||||
vg = nvgCreateGLES2(NVG_ANTIALIAS|NVG_DEBUG);
|
||||
if (!vg) die("[NVG]: failed to init\n");
|
||||
nvgCreateFont(vg, "fixed", font_path);
|
||||
nvgFontFace(vg, "fixed");
|
||||
nvgFontSize(vg, font_height);
|
||||
nvgTextAlign(vg, NVG_ALIGN_LEFT|NVG_ALIGN_MIDDLE);
|
||||
|
||||
/* GUI */
|
||||
memset(&in, 0, sizeof in);
|
||||
memset(&gui, 0, sizeof gui);
|
||||
gui.memory = malloc(MAX_MEMORY);
|
||||
font.userdata.ptr = vg;
|
||||
nvgTextMetrics(vg, NULL, NULL, &font.height);
|
||||
font.width = font_get_width;
|
||||
init_demo(&gui, &font);
|
||||
|
||||
while (gui.running) {
|
||||
/* Input */
|
||||
SDL_Event evt;
|
||||
started = SDL_GetTicks();
|
||||
gui_input_begin(&in);
|
||||
while (SDL_PollEvent(&evt)) {
|
||||
if (evt.type == SDL_WINDOWEVENT) resize(&evt);
|
||||
else if (evt.type == SDL_QUIT) goto cleanup;
|
||||
else if (evt.type == SDL_KEYUP) key(&in, &evt, gui_false);
|
||||
else if (evt.type == SDL_KEYDOWN) key(&in, &evt, gui_true);
|
||||
else if (evt.type == SDL_MOUSEBUTTONDOWN) btn(&in, &evt, gui_true);
|
||||
else if (evt.type == SDL_MOUSEBUTTONUP) btn(&in, &evt, gui_false);
|
||||
else if (evt.type == SDL_MOUSEMOTION) motion(&in, &evt);
|
||||
else if (evt.type == SDL_TEXTINPUT) text(&in, &evt);
|
||||
}
|
||||
gui_input_end(&in);
|
||||
|
||||
/* GUI */
|
||||
SDL_GetWindowSize(win, &width, &height);
|
||||
run_demo(&gui, &in);
|
||||
|
||||
/* Draw */
|
||||
glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
||||
draw(vg, &gui.stack, width, height);
|
||||
SDL_GL_SwapWindow(win);
|
||||
|
||||
/* Timing */
|
||||
dt = SDL_GetTicks() - started;
|
||||
if (dt < DTIME)
|
||||
SDL_Delay(DTIME - dt);
|
||||
}
|
||||
|
||||
cleanup:
|
||||
/* Cleanup */
|
||||
free(gui.memory);
|
||||
nvgDeleteGLES2(vg);
|
||||
SDL_DestroyWindow(win);
|
||||
SDL_Quit();
|
||||
return 0;
|
||||
}
|
||||
|
537
gui.c
537
gui.c
|
@ -45,8 +45,8 @@
|
|||
#define OFFSETOF(st, m) ((gui_size)(&((st *)0)->m))
|
||||
|
||||
static const struct gui_rect null_rect = {-9999.0f, 9999.0f, 9999.0f, 9999.0f};
|
||||
static const gui_char utfbyte[GUI_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||
static const gui_char utfmask[GUI_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static const gui_byte utfbyte[GUI_UTF_SIZE+1] = {0x80, 0, 0xC0, 0xE0, 0xF0};
|
||||
static const gui_byte utfmask[GUI_UTF_SIZE+1] = {0xC0, 0x80, 0xE0, 0xF0, 0xF8};
|
||||
static const long utfmin[GUI_UTF_SIZE+1] = {0, 0, 0x80, 0x800, 0x100000};
|
||||
static const long utfmax[GUI_UTF_SIZE+1] = {0x10FFFF, 0x7F, 0x7FF, 0xFFFF, 0x10FFFF};
|
||||
|
||||
|
@ -310,6 +310,271 @@ gui_input_end(struct gui_input *in)
|
|||
vec2_sub(in->mouse_delta, in->mouse_pos, in->mouse_prev);
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
*
|
||||
* Buffer
|
||||
*
|
||||
* ===============================================================
|
||||
*/
|
||||
void
|
||||
gui_buffer_init(struct gui_buffer *buffer, const struct gui_allocator *memory,
|
||||
gui_size initial_size, gui_float grow_factor)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(memory);
|
||||
ASSERT(initial_size);
|
||||
if (!buffer || !memory || !initial_size) return;
|
||||
|
||||
zero(buffer, sizeof(*buffer));
|
||||
buffer->type = GUI_BUFFER_DYNAMIC;
|
||||
buffer->memory.ptr = memory->alloc(memory->userdata, initial_size);
|
||||
buffer->memory.size = initial_size;
|
||||
buffer->grow_factor = grow_factor;
|
||||
buffer->pool = *memory;
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_init_fixed(struct gui_buffer *buffer, void *memory, gui_size size)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(memory);
|
||||
ASSERT(size);
|
||||
if (!buffer || !memory || !size) return;
|
||||
|
||||
zero(buffer, sizeof(*buffer));
|
||||
buffer->type = GUI_BUFFER_FIXED;
|
||||
buffer->memory.ptr = memory;
|
||||
buffer->memory.size = size;
|
||||
}
|
||||
|
||||
void*
|
||||
gui_buffer_alloc(struct gui_buffer *b, gui_size size, gui_size align)
|
||||
{
|
||||
gui_size cap;
|
||||
gui_size alignment;
|
||||
void *unaligned;
|
||||
void *memory;
|
||||
|
||||
ASSERT(b);
|
||||
if (!b || !size) return NULL;
|
||||
b->needed += size;
|
||||
|
||||
unaligned = PTR_ADD(void, b->memory.ptr, b->allocated);
|
||||
memory = ALIGN_PTR(unaligned, align);
|
||||
alignment = (gui_size)((gui_byte*)memory - (gui_byte*)unaligned);
|
||||
|
||||
if ((b->allocated + size + alignment) >= b->memory.size) {
|
||||
if (b->type != GUI_BUFFER_DYNAMIC || !b->pool.realloc)
|
||||
return NULL;
|
||||
|
||||
cap = (gui_size)((gui_float)b->memory.size * b->grow_factor);
|
||||
b->memory.ptr = b->pool.realloc(b->pool.userdata, b->memory.ptr, cap);
|
||||
if (!b->memory.ptr) return NULL;
|
||||
|
||||
b->memory.size = cap;
|
||||
unaligned = PTR_ADD(gui_byte, b->memory.ptr, b->allocated);
|
||||
memory = ALIGN_PTR(unaligned, align);
|
||||
alignment = (gui_size)((gui_byte*)memory - (gui_byte*)unaligned);
|
||||
}
|
||||
|
||||
b->allocated += size + alignment;
|
||||
b->needed += alignment;
|
||||
b->calls++;
|
||||
return memory;
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_reset(struct gui_buffer *buffer)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
buffer->allocated = 0;
|
||||
buffer->calls = 0;
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_clear(struct gui_buffer *buffer)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
if (!buffer || !buffer->memory.ptr) return;
|
||||
if (buffer->type == GUI_BUFFER_FIXED) return;
|
||||
if (!buffer->pool.free) return;
|
||||
buffer->pool.free(buffer->pool.userdata, buffer->memory.ptr);
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_info(struct gui_memory_status *status, struct gui_buffer *buffer)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(status);
|
||||
if (!status || !buffer) return;
|
||||
status->allocated = buffer->allocated;
|
||||
status->size = buffer->memory.size;
|
||||
status->needed = buffer->needed;
|
||||
status->memory = buffer->memory.ptr;
|
||||
status->calls = buffer->calls;
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
*
|
||||
* Command buffer
|
||||
*
|
||||
* ===============================================================
|
||||
*/
|
||||
void*
|
||||
gui_command_buffer_push(gui_command_buffer* buffer,
|
||||
enum gui_command_type type, gui_size size)
|
||||
{
|
||||
static const gui_size align = ALIGNOF(struct gui_command);
|
||||
struct gui_command *cmd;
|
||||
gui_size alignment;
|
||||
void *unaligned;
|
||||
void *memory;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return NULL;
|
||||
|
||||
cmd = gui_buffer_alloc(buffer, size, align);
|
||||
if (!cmd) return NULL;
|
||||
|
||||
unaligned = (gui_byte*)cmd + size;
|
||||
memory = ALIGN_PTR(unaligned, align);
|
||||
alignment = (gui_size)((gui_byte*)memory - (gui_byte*)unaligned);
|
||||
|
||||
cmd->type = type;
|
||||
cmd->offset = size + alignment;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_scissor(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h)
|
||||
{
|
||||
struct gui_command_scissor *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_SCISSOR, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(0, w);
|
||||
cmd->h = (gui_ushort)MAX(0, h);
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_line(gui_command_buffer *buffer, gui_float x0, gui_float y0,
|
||||
gui_float x1, gui_float y1, struct gui_color c)
|
||||
{
|
||||
struct gui_command_line *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_LINE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->begin[0] = (gui_short)x0;
|
||||
cmd->begin[1] = (gui_short)y0;
|
||||
cmd->end[0] = (gui_short)x1;
|
||||
cmd->end[1] = (gui_short)y1;
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_rect(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, struct gui_color c)
|
||||
{
|
||||
struct gui_command_rect *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_RECT, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(0, w);
|
||||
cmd->h = (gui_ushort)MAX(0, h);
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_circle(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, struct gui_color c)
|
||||
{
|
||||
struct gui_command_circle *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_CIRCLE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(w, 0);
|
||||
cmd->h = (gui_ushort)MAX(h, 0);
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_triangle(gui_command_buffer *buffer, gui_float x0, gui_float y0,
|
||||
gui_float x1, gui_float y1, gui_float x2, gui_float y2, struct gui_color c)
|
||||
{
|
||||
struct gui_command_triangle *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_TRIANGLE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->a[0] = (gui_short)x0;
|
||||
cmd->a[1] = (gui_short)y0;
|
||||
cmd->b[0] = (gui_short)x1;
|
||||
cmd->b[1] = (gui_short)y1;
|
||||
cmd->c[0] = (gui_short)x2;
|
||||
cmd->c[1] = (gui_short)y2;
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_image(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, gui_handle img)
|
||||
{
|
||||
struct gui_command_image *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_IMAGE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(0, w);
|
||||
cmd->h = (gui_ushort)MAX(0, h);
|
||||
cmd->img = img;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_text(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, const gui_char *string, gui_size length,
|
||||
const struct gui_font *font, struct gui_color bg, struct gui_color fg)
|
||||
{
|
||||
struct gui_command_text *cmd;
|
||||
ASSERT(buffer);
|
||||
ASSERT(font);
|
||||
if (!buffer || !string || !length) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_TEXT, sizeof(*cmd) + length + 1);
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)w;
|
||||
cmd->h = (gui_ushort)h;
|
||||
cmd->bg = bg;
|
||||
cmd->fg = fg;
|
||||
cmd->font = font->userdata;
|
||||
cmd->length = length;
|
||||
memcopy(cmd->string, string, length);
|
||||
cmd->string[length] = '\0';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
*
|
||||
|
@ -451,7 +716,7 @@ gui_button_triangle(gui_command_buffer *out, gui_float x, gui_float y,
|
|||
|
||||
gui_bool
|
||||
gui_button_image(gui_command_buffer *out, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, gui_image img, enum gui_button_behavior b,
|
||||
gui_float w, gui_float h, gui_handle img, enum gui_button_behavior b,
|
||||
const struct gui_button *button, const struct gui_input *in)
|
||||
{
|
||||
gui_bool pressed;
|
||||
|
@ -892,270 +1157,6 @@ gui_scroll(gui_command_buffer *out, gui_float x, gui_float y,
|
|||
return scroll_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
*
|
||||
* Buffer
|
||||
*
|
||||
* ===============================================================
|
||||
*/
|
||||
void
|
||||
gui_buffer_init(struct gui_buffer *buffer, const struct gui_allocator *memory,
|
||||
gui_size initial_size, gui_float grow_factor)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(memory);
|
||||
ASSERT(initial_size);
|
||||
if (!buffer || !memory || !initial_size) return;
|
||||
|
||||
zero(buffer, sizeof(*buffer));
|
||||
buffer->type = GUI_BUFFER_DYNAMIC;
|
||||
buffer->memory.ptr = memory->alloc(memory->userdata, initial_size);
|
||||
buffer->memory.size = initial_size;
|
||||
buffer->grow_factor = grow_factor;
|
||||
buffer->pool = *memory;
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_init_fixed(struct gui_buffer *buffer, void *memory, gui_size size)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(memory);
|
||||
ASSERT(size);
|
||||
if (!buffer || !memory || !size) return;
|
||||
|
||||
zero(buffer, sizeof(*buffer));
|
||||
buffer->type = GUI_BUFFER_FIXED;
|
||||
buffer->memory.ptr = memory;
|
||||
buffer->memory.size = size;
|
||||
}
|
||||
|
||||
void*
|
||||
gui_buffer_alloc(struct gui_buffer *b, gui_size size, gui_size align)
|
||||
{
|
||||
gui_size cap;
|
||||
gui_size alignment;
|
||||
void *unaligned;
|
||||
void *memory;
|
||||
|
||||
ASSERT(b);
|
||||
if (!b || !size) return NULL;
|
||||
b->needed += size;
|
||||
|
||||
unaligned = PTR_ADD(void, b->memory.ptr, b->allocated);
|
||||
memory = ALIGN_PTR(unaligned, align);
|
||||
alignment = (gui_size)((gui_byte*)memory - (gui_byte*)unaligned);
|
||||
|
||||
if ((b->allocated + size + alignment) >= b->memory.size) {
|
||||
if (b->type != GUI_BUFFER_DYNAMIC || !b->pool.realloc)
|
||||
return NULL;
|
||||
|
||||
cap = (gui_size)((gui_float)b->memory.size * b->grow_factor);
|
||||
b->memory.ptr = b->pool.realloc(b->pool.userdata, b->memory.ptr, cap);
|
||||
if (!b->memory.ptr) return NULL;
|
||||
|
||||
b->memory.size = cap;
|
||||
unaligned = PTR_ADD(gui_byte, b->memory.ptr, b->allocated);
|
||||
memory = ALIGN_PTR(unaligned, align);
|
||||
alignment = (gui_size)((gui_byte*)memory - (gui_byte*)unaligned);
|
||||
}
|
||||
|
||||
b->allocated += size + alignment;
|
||||
b->needed += alignment;
|
||||
b->calls++;
|
||||
return memory;
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_reset(struct gui_buffer *buffer)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
buffer->allocated = 0;
|
||||
buffer->calls = 0;
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_clear(struct gui_buffer *buffer)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
if (!buffer || !buffer->memory.ptr) return;
|
||||
if (buffer->type == GUI_BUFFER_FIXED) return;
|
||||
if (!buffer->pool.free) return;
|
||||
buffer->pool.free(buffer->pool.userdata, buffer->memory.ptr);
|
||||
}
|
||||
|
||||
void
|
||||
gui_buffer_info(struct gui_memory_status *status, struct gui_buffer *buffer)
|
||||
{
|
||||
ASSERT(buffer);
|
||||
ASSERT(status);
|
||||
if (!status || !buffer) return;
|
||||
status->allocated = buffer->allocated;
|
||||
status->size = buffer->memory.size;
|
||||
status->needed = buffer->needed;
|
||||
status->memory = buffer->memory.ptr;
|
||||
status->calls = buffer->calls;
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
*
|
||||
* Command buffer
|
||||
*
|
||||
* ===============================================================
|
||||
*/
|
||||
void*
|
||||
gui_command_buffer_push(gui_command_buffer* buffer,
|
||||
enum gui_command_type type, gui_size size)
|
||||
{
|
||||
static const gui_size align = ALIGNOF(struct gui_command);
|
||||
struct gui_command *cmd;
|
||||
gui_size alignment;
|
||||
void *unaligned;
|
||||
void *memory;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return NULL;
|
||||
|
||||
cmd = gui_buffer_alloc(buffer, size, align);
|
||||
if (!cmd) return NULL;
|
||||
|
||||
unaligned = (gui_byte*)cmd + size;
|
||||
memory = ALIGN_PTR(unaligned, align);
|
||||
alignment = (gui_size)((gui_byte*)memory - (gui_byte*)unaligned);
|
||||
|
||||
cmd->type = type;
|
||||
cmd->offset = size + alignment;
|
||||
return cmd;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_scissor(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h)
|
||||
{
|
||||
struct gui_command_scissor *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_SCISSOR, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(0, w);
|
||||
cmd->h = (gui_ushort)MAX(0, h);
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_line(gui_command_buffer *buffer, gui_float x0, gui_float y0,
|
||||
gui_float x1, gui_float y1, struct gui_color c)
|
||||
{
|
||||
struct gui_command_line *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_LINE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->begin[0] = (gui_short)x0;
|
||||
cmd->begin[1] = (gui_short)y0;
|
||||
cmd->end[0] = (gui_short)x1;
|
||||
cmd->end[1] = (gui_short)y1;
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_rect(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, struct gui_color c)
|
||||
{
|
||||
struct gui_command_rect *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_RECT, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(0, w);
|
||||
cmd->h = (gui_ushort)MAX(0, h);
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_circle(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, struct gui_color c)
|
||||
{
|
||||
struct gui_command_circle *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_CIRCLE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(w, 0);
|
||||
cmd->h = (gui_ushort)MAX(h, 0);
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_triangle(gui_command_buffer *buffer, gui_float x0, gui_float y0,
|
||||
gui_float x1, gui_float y1, gui_float x2, gui_float y2, struct gui_color c)
|
||||
{
|
||||
struct gui_command_triangle *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_TRIANGLE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->a[0] = (gui_short)x0;
|
||||
cmd->a[1] = (gui_short)y0;
|
||||
cmd->b[0] = (gui_short)x1;
|
||||
cmd->b[1] = (gui_short)y1;
|
||||
cmd->c[0] = (gui_short)x2;
|
||||
cmd->c[1] = (gui_short)y2;
|
||||
cmd->color = c;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_image(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, gui_image img)
|
||||
{
|
||||
struct gui_command_image *cmd;
|
||||
ASSERT(buffer);
|
||||
if (!buffer) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_IMAGE, sizeof(*cmd));
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)MAX(0, w);
|
||||
cmd->h = (gui_ushort)MAX(0, h);
|
||||
cmd->img = img;
|
||||
}
|
||||
|
||||
void
|
||||
gui_command_buffer_push_text(gui_command_buffer *buffer, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, const gui_char *string, gui_size length,
|
||||
const struct gui_font *font, struct gui_color bg, struct gui_color fg)
|
||||
{
|
||||
struct gui_command_text *cmd;
|
||||
ASSERT(buffer);
|
||||
ASSERT(font);
|
||||
if (!buffer || !string || !length) return;
|
||||
|
||||
cmd = gui_command_buffer_push(buffer, GUI_COMMAND_TEXT, sizeof(*cmd) + length + 1);
|
||||
if (!cmd) return;
|
||||
cmd->x = (gui_short)x;
|
||||
cmd->y = (gui_short)y;
|
||||
cmd->w = (gui_ushort)w;
|
||||
cmd->h = (gui_ushort)h;
|
||||
cmd->bg = bg;
|
||||
cmd->fg = fg;
|
||||
cmd->font = font->userdata;
|
||||
cmd->length = length;
|
||||
memcopy(cmd->string, string, length);
|
||||
cmd->string[length] = '\0';
|
||||
}
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
*
|
||||
|
@ -1901,7 +1902,7 @@ gui_panel_button_triangle(struct gui_panel_layout *layout, enum gui_heading head
|
|||
}
|
||||
|
||||
gui_bool
|
||||
gui_panel_button_image(struct gui_panel_layout *layout, gui_image image,
|
||||
gui_panel_button_image(struct gui_panel_layout *layout, gui_handle image,
|
||||
enum gui_button_behavior behavior)
|
||||
{
|
||||
struct gui_rect bounds;
|
||||
|
|
36
gui.h
36
gui.h
|
@ -22,6 +22,7 @@ extern "C" {
|
|||
/* Types */
|
||||
#ifdef GUI_USE_FIXED_TYPES
|
||||
#include <stdint.h>
|
||||
typedef int8_t gui_char;
|
||||
typedef int32_t gui_int;
|
||||
typedef int32_t gui_bool;
|
||||
typedef int16_t gui_short;
|
||||
|
@ -31,13 +32,13 @@ typedef uint16_t gui_ushort;
|
|||
typedef uint32_t gui_uint;
|
||||
typedef uint64_t gui_ulong;
|
||||
typedef uint32_t gui_flags;
|
||||
typedef uint8_t gui_char;
|
||||
typedef uint8_t gui_byte;
|
||||
typedef uint32_t gui_flag;
|
||||
typedef uint64_t gui_size;
|
||||
#else
|
||||
typedef int gui_int;
|
||||
typedef int gui_bool;
|
||||
typedef char gui_char;
|
||||
typedef short gui_short;
|
||||
typedef long gui_long;
|
||||
typedef float gui_float;
|
||||
|
@ -45,7 +46,6 @@ typedef unsigned short gui_ushort;
|
|||
typedef unsigned int gui_uint;
|
||||
typedef unsigned long gui_ulong;
|
||||
typedef unsigned int gui_flags;
|
||||
typedef unsigned char gui_char;
|
||||
typedef unsigned char gui_byte;
|
||||
typedef unsigned int gui_flag;
|
||||
typedef unsigned long gui_size;
|
||||
|
@ -61,10 +61,10 @@ struct gui_key {gui_bool down, clicked;};
|
|||
struct gui_font;
|
||||
|
||||
/* Callbacks */
|
||||
typedef void* gui_image;
|
||||
typedef union {void *ptr; gui_int id;} gui_handle;
|
||||
typedef gui_char gui_glyph[GUI_UTF_SIZE];
|
||||
typedef gui_bool(*gui_filter)(gui_long unicode);
|
||||
typedef gui_size(*gui_text_width_f)(void*, const gui_char*, gui_size);
|
||||
typedef gui_size(*gui_text_width_f)(gui_handle, const gui_char*, gui_size);
|
||||
|
||||
/*
|
||||
* ==============================================================
|
||||
|
@ -125,10 +125,10 @@ struct gui_memory_status {
|
|||
};
|
||||
|
||||
struct gui_allocator {
|
||||
void *userdata;
|
||||
void*(*alloc)(void *usr, gui_size);
|
||||
void*(*realloc)(void *usr, void*, gui_size);
|
||||
void(*free)(void *usr, void*);
|
||||
gui_handle userdata;
|
||||
void*(*alloc)(gui_handle, gui_size);
|
||||
void*(*realloc)(gui_handle, void*, gui_size);
|
||||
void(*free)(gui_handle, void*);
|
||||
};
|
||||
|
||||
struct gui_memory {
|
||||
|
@ -216,7 +216,7 @@ struct gui_command_image {
|
|||
struct gui_command header;
|
||||
gui_short x, y;
|
||||
gui_ushort w, h;
|
||||
gui_image img;
|
||||
gui_handle img;
|
||||
};
|
||||
|
||||
struct gui_command_triangle {
|
||||
|
@ -229,11 +229,11 @@ struct gui_command_triangle {
|
|||
|
||||
struct gui_command_text {
|
||||
struct gui_command header;
|
||||
void *font;
|
||||
gui_short x, y;
|
||||
gui_ushort w, h;
|
||||
gui_handle font;
|
||||
struct gui_color bg;
|
||||
struct gui_color fg;
|
||||
gui_short x, y;
|
||||
gui_ushort w, h;
|
||||
gui_size length;
|
||||
gui_char string[1];
|
||||
};
|
||||
|
@ -255,7 +255,7 @@ void gui_command_buffer_push_circle(gui_command_buffer*, gui_float, gui_float,
|
|||
void gui_command_buffer_push_triangle(gui_command_buffer*, gui_float, gui_float,
|
||||
gui_float, gui_float, gui_float, gui_float, struct gui_color);
|
||||
void gui_command_buffer_push_image(gui_command_buffer*, gui_float,
|
||||
gui_float, gui_float, gui_float, gui_image);
|
||||
gui_float, gui_float, gui_float, gui_handle);
|
||||
void gui_command_buffer_push_text(gui_command_buffer*, gui_float, gui_float,
|
||||
gui_float, gui_float, const gui_char*, gui_size,
|
||||
const struct gui_font*, struct gui_color, struct gui_color);
|
||||
|
@ -280,7 +280,7 @@ void gui_command_buffer_push_text(gui_command_buffer*, gui_float, gui_float,
|
|||
* ===============================================================
|
||||
*/
|
||||
struct gui_font {
|
||||
void *userdata;
|
||||
gui_handle userdata;
|
||||
gui_float height;
|
||||
gui_text_width_f width;
|
||||
};
|
||||
|
@ -388,7 +388,7 @@ gui_bool gui_button_text(gui_command_buffer*, gui_float x, gui_float y,
|
|||
gui_float w, gui_float h, const char*, enum gui_button_behavior,
|
||||
const struct gui_button*, const struct gui_input*, const struct gui_font*);
|
||||
gui_bool gui_button_image(gui_command_buffer*, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, gui_image, enum gui_button_behavior,
|
||||
gui_float w, gui_float h, gui_handle img, enum gui_button_behavior,
|
||||
const struct gui_button*, const struct gui_input*);
|
||||
gui_bool gui_button_triangle(gui_command_buffer*, gui_float x, gui_float y,
|
||||
gui_float w, gui_float h, enum gui_heading, enum gui_button_behavior,
|
||||
|
@ -546,8 +546,6 @@ enum gui_panel_flags {
|
|||
GUI_PANEL_TAB = 0x400
|
||||
};
|
||||
|
||||
struct gui_layout;
|
||||
struct gui_stack;
|
||||
struct gui_panel {
|
||||
gui_float x, y;
|
||||
gui_float w, h;
|
||||
|
@ -580,6 +578,8 @@ struct gui_panel_layout {
|
|||
};
|
||||
|
||||
/* Panel */
|
||||
struct gui_stack;
|
||||
struct gui_layout;
|
||||
void gui_panel_init(struct gui_panel*, gui_float x, gui_float y, gui_float w,
|
||||
gui_float h, gui_flags, gui_command_buffer*, const struct gui_config*);
|
||||
gui_bool gui_panel_begin(struct gui_panel_layout *layout, struct gui_panel*,
|
||||
|
@ -607,7 +607,7 @@ gui_bool gui_panel_button_color(struct gui_panel_layout*, const struct gui_color
|
|||
enum gui_button_behavior);
|
||||
gui_bool gui_panel_button_triangle(struct gui_panel_layout*, enum gui_heading,
|
||||
enum gui_button_behavior);
|
||||
gui_bool gui_panel_button_image(struct gui_panel_layout*, gui_image image,
|
||||
gui_bool gui_panel_button_image(struct gui_panel_layout*, gui_handle img,
|
||||
enum gui_button_behavior);
|
||||
gui_bool gui_panel_button_toggle(struct gui_panel_layout*, const char*, gui_bool value);
|
||||
gui_float gui_panel_slider(struct gui_panel_layout*, gui_float min, gui_float val,
|
||||
|
|
Loading…
Reference in New Issue