added nanovg demo

This commit is contained in:
vurtun 2015-05-31 14:41:46 +02:00
parent ef9570ca81
commit 248c67acf9
3 changed files with 624 additions and 286 deletions

337
demo/nanovg.c Normal file
View File

@ -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
View File

@ -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
View File

@ -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,