diff --git a/gui.c b/gui.c index ba45b0e..4035898 100644 --- a/gui.c +++ b/gui.c @@ -193,6 +193,7 @@ gui_push_command(struct gui_draw_list *list, gui_size count, memory += sizeof(struct gui_draw_command); memory += sizeof(struct gui_vertex) * count; list->needed += memory; + list->vertex_count += count; current = (gui_byte*)list->end - (gui_byte*)list->begin; if (list->size <= (current + memory)) return NULL; @@ -352,7 +353,7 @@ gui_end(struct gui_draw_list *list) gui_int gui_button(struct gui_draw_list *list, const struct gui_input *in, - struct gui_color bg, struct gui_color fg, + const struct gui_font *font, struct gui_color bg, struct gui_color fg, gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, const char *str, gui_int len) { @@ -377,10 +378,9 @@ gui_slider(struct gui_draw_list *list, const struct gui_input *in, { gui_int mouse_x, mouse_y; gui_int clicked_x, clicked_y; - - gui_float cursor_w; gui_int cursor_x; gui_int cursor_y; + gui_float cursor_w; gui_int cursor_h; if (step == 0.0f) return value; @@ -428,12 +428,10 @@ gui_progress(struct gui_draw_list *list, const struct gui_input *in, gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, gui_size value, gui_size max, gui_bool modifyable) { - gui_int mouse_x, mouse_y; gui_float scale; - gui_int cursor_x; - gui_int cursor_y; - gui_int cursor_w; - gui_int cursor_h; + gui_int mouse_x, mouse_y; + gui_int cursor_x, cursor_y; + gui_int cursor_w, cursor_h; if (!list || !in) return 0; mouse_x = in->mouse_pos.x; @@ -466,33 +464,23 @@ gui_scroll(struct gui_draw_list *list, const struct gui_input *in, gui_int x, gui_int y, gui_int w, gui_int h, gui_int offset, gui_int dst) { - gui_int mouse_x; - gui_int mouse_y; - gui_int prev_x; - gui_int prev_y; + gui_int mouse_x, mouse_y; + gui_int prev_x, prev_y; gui_bool up, down; - gui_int button_size; - gui_int button_half; - gui_int button_y; - gui_int bar_h; - gui_int bar_y; + gui_int button_size, button_half, button_y; + gui_int bar_h, bar_y; gui_float ratio; gui_float off; - gui_int cursor_x; - gui_int cursor_y; - gui_int cursor_w; - gui_int cursor_h; - gui_int cursor_px; - gui_int cursor_py; - gui_bool inscroll; - gui_bool incursor; + gui_int cursor_x, cursor_y; + gui_int cursor_w, cursor_h; + gui_int cursor_px, cursor_py; + gui_bool inscroll, incursor; gui_int pad; gui_int xoff, yoff, boff; - gui_int xpad, ypad; - gui_int xmid; + gui_int xpad, ypad, xmid; if (!list || !in) return 0; gui_rectf(list, x, y, w, h, bg); @@ -527,8 +515,8 @@ gui_scroll(struct gui_draw_list *list, const struct gui_input *in, yoff = y + (button_size - pad); boff = button_y + (button_size - pad); - up = gui_button(list, in, fg, bg, x, y, button_size, button_size, 0, "", 0); - down = gui_button(list,in,fg,bg,x,button_y,button_size,button_size,0,"", 0); + up = gui_button(list, in, NULL, fg, bg, x, y, button_size, button_size, 0, "", 0); + down = gui_button(list,in,NULL, fg,bg,x,button_y,button_size,button_size,0,"", 0); gui_trianglef(list, xmid, y + pad, xoff, yoff, xpad, yoff, bg); gui_trianglef(list, xpad, ypad, xoff, ypad, xmid, boff, bg); diff --git a/gui.h b/gui.h index b6d57b5..d4dfcdc 100644 --- a/gui.h +++ b/gui.h @@ -7,11 +7,12 @@ #define TINY_GUI_H_ #define GUI_UTF_SIZE 4 -#define GUI_INPUT_MAX 16 -#define GUI_GLYPHES_MAX 512 +#define GUI_INPUT_MAX 8 typedef int gui_int; +typedef int gui_short; typedef int gui_bool; +typedef unsigned int gui_flags; typedef unsigned char gui_char; typedef float gui_float; typedef void* gui_texture; @@ -43,6 +44,7 @@ struct gui_draw_command { struct gui_draw_list { struct gui_draw_command *begin; struct gui_draw_command *end; + gui_size vertex_count; gui_byte *memory; gui_size size; gui_size needed; @@ -74,11 +76,34 @@ struct gui_input { }; struct gui_font_glyph { - gui_glyph glpyh; + gui_int code; + gui_short xadvance; + gui_short width, height; + gui_float xoff, yoff; + struct gui_texCoord uv[2]; }; struct gui_font { - struct gui_font_glyph glyphes[GUI_GLYPHES_MAX]; + gui_short height; + gui_float scale; + gui_texture texture; + struct gui_vec2 tex_size; + struct gui_font_glyph *glyphes; + gui_size glyph_count; + const struct gui_font_glyph *fallback; +}; + +enum gui_panel_flags { + GUI_PANEL_HEADER = 0x01, + GUI_PANEL_MINIMIZABLE = 0x02, + GUI_PANEL_CLOSEABLE = 0x04, + GUI_PANEL_SCALEABLE = 0x08, + GUI_PANEL_SCROLLBAR = 0x10 +}; + +struct gui_panel { + gui_flags flags; + gui_int at_x, at_y; }; void gui_input_begin(struct gui_input *in); @@ -99,6 +124,7 @@ gui_int gui_button(struct gui_draw_list *list, const struct gui_input *in, gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, const char *str, gui_int len); gui_int gui_toggle(struct gui_draw_list *list, const struct gui_input *in, + const struct gui_font *font, struct gui_color bg, struct gui_color fg, gui_int x, gui_int y, gui_int w, gui_int h, gui_int pad, const char *str, gui_int len, gui_int active); diff --git a/mono.font b/mono.font new file mode 100644 index 0000000..eca6aa8 Binary files /dev/null and b/mono.font differ diff --git a/x11.c b/x11.c index 0c76444..6151a2b 100644 --- a/x11.c +++ b/x11.c @@ -28,18 +28,11 @@ #include "gui.h" /* macros */ -#define internal static -#define global static -#define persistent static - #define WIN_WIDTH 800 #define WIN_HEIGHT 600 #define DTIME 33 #define MAX_VERTEX_BUFFER (16 * 1024) -#define CONSOLE_MAX_CMDLINE 1024 -#define CONSOLE_MAX_TEXT (16 * 1024) - #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)) @@ -59,30 +52,32 @@ struct XWindow { int running; }; -struct Console { +struct GUI { struct XWindow *win; - struct gui_draw_list gui; + struct gui_draw_list out; struct gui_input input; - struct gui_font font; - /* text */ - int output_len; - char output[CONSOLE_MAX_TEXT]; - char line[CONSOLE_MAX_CMDLINE]; - int line_len; + struct gui_font *font; }; /* functions */ -internal void die(const char*,...); -internal long timestamp(void); -internal void sleep_for(long ms); +static void die(const char*,...); +static void* xcalloc(size_t nmemb, size_t size); +static long timestamp(void); +static void sleep_for(long ms); +static char* ldfile(const char*, int, size_t*); -internal void kpress(struct Console*, XEvent*); -internal void bpress(struct Console*, XEvent*); -internal void brelease(struct Console*, XEvent*); -internal void bmotion(struct Console*, XEvent*); -internal void resize(struct Console*, XEvent*); +static void kpress(struct GUI*, XEvent*); +static void bpress(struct GUI*, XEvent*); +static void brelease(struct GUI*, XEvent*); +static void bmotion(struct GUI*, XEvent*); +static void resize(struct GUI*, XEvent*); -internal void +static struct gui_font *ldfont(const char*, unsigned char); +static void delfont(struct gui_font *font); +static void draw(struct GUI*, int, int , const struct gui_draw_list*); + +/* gobals */ +static void die(const char *fmt, ...) { va_list ap; @@ -92,7 +87,7 @@ die(const char *fmt, ...) exit(EXIT_FAILURE); } -internal void* +static void* xcalloc(size_t nmemb, size_t size) { void *p = calloc(nmemb, size); @@ -101,7 +96,7 @@ xcalloc(size_t nmemb, size_t size) return p; } -internal long +static long timestamp(void) { struct timeval tv; @@ -109,7 +104,7 @@ timestamp(void) return (long)((long)tv.tv_sec * 1000 + (long)tv.tv_usec/1000); } -internal void +static void sleep_for(long t) { const time_t sec = (int)(t/1000); @@ -121,7 +116,7 @@ sleep_for(long t) } static void -kpress(struct Console *con, XEvent* e) +kpress(struct GUI *con, XEvent* e) { int ret; struct XWindow *xw = con->win; @@ -140,7 +135,7 @@ kpress(struct Console *con, XEvent* e) } static void -krelease(struct Console *con, XEvent* e) +krelease(struct GUI *con, XEvent* e) { int ret; struct XWindow *xw = con->win; @@ -158,7 +153,7 @@ krelease(struct Console *con, XEvent* e) } static void -bpress(struct Console *con, XEvent *evt) +bpress(struct GUI *con, XEvent *evt) { const float x = evt->xbutton.x; const float y = evt->xbutton.y; @@ -167,7 +162,7 @@ bpress(struct Console *con, XEvent *evt) } static void -brelease(struct Console *con, XEvent *evt) +brelease(struct GUI *con, XEvent *evt) { const float x = evt->xbutton.x; const float y = evt->xbutton.y; @@ -177,7 +172,7 @@ brelease(struct Console *con, XEvent *evt) } static void -bmotion(struct Console *con, XEvent *evt) +bmotion(struct GUI *con, XEvent *evt) { const gui_int x = evt->xbutton.x; const gui_int y = evt->xbutton.y; @@ -186,21 +181,130 @@ bmotion(struct Console *con, XEvent *evt) } static void -resize(struct Console *con, XEvent* evt) +resize(struct GUI *con, XEvent* evt) { struct XWindow *xw = con->win; XGetWindowAttributes(xw->dpy, xw->win, &xw->gwa); glViewport(0, 0, xw->gwa.width, xw->gwa.height); } +static char* +ldfile(const char* path, int flags, size_t* siz) +{ + char *buf; + int fd = open(path, flags); + struct stat status; + if (fd == -1) + die("Failed to open file: %s (%s)\n", + path, strerror(errno)); + if (fstat(fd, &status) < 0) + die("Failed to call fstat: %s",strerror(errno)); + *siz = status.st_size; + buf = xcalloc(*siz, 1); + if (read(fd, buf, *siz) < 0) + die("Failed to call read: %s",strerror(errno)); + close(fd); + return buf; +} + +static struct gui_font* +ldfont(const char *name, unsigned char height) +{ + union conversion { + gui_texture handle; + uintptr_t ptr; + } convert; + GLuint texture; + size_t size; + struct gui_font *font; + short i = 0; + uint32_t bpp; + short max_height = 0; + + uint32_t iheight; + uint32_t iwidth; + + /* header */ + unsigned char *buffer = (unsigned char*)ldfile(name, O_RDONLY, &size); + uint16_t num = *(uint16_t*)buffer; + uint16_t indexes = *(uint16_t*)&buffer[0x02] + 1; + uint16_t tex_width = *(uint16_t*)&buffer[0x04]; + uint16_t tex_height = *(uint16_t*)&buffer[0x06]; + + /* glyphes */ + unsigned char *header; + unsigned char *data; + unsigned char *iter = &buffer[0x08]; + size_t mem = sizeof(struct gui_font_glyph) * indexes; + struct gui_font_glyph *glyphes = xcalloc(mem, 1); + for(i = 0; i < num; ++i) { + short id = *(uint16_t*)&iter[0]; + short x = *(uint16_t*)&iter[2]; + short y = *(uint16_t*)&iter[4]; + short w = *(uint16_t*)&iter[6]; + short h = *(uint16_t*)&iter[8]; + + glyphes[id].code = id; + glyphes[id].width = w; + glyphes[id].height = h; + glyphes[id].xoff = *(float*)&iter[10]; + glyphes[id].yoff = *(float*)&iter[14]; + glyphes[id].xadvance = *(float*)&iter[18]; + glyphes[id].uv[0].u = (gui_float)x/(gui_float)tex_width; + glyphes[id].uv[0].v = (gui_float)y/(gui_float)tex_height; + glyphes[id].uv[1].u = (gui_float)(x+w)/(gui_float)tex_width; + glyphes[id].uv[1].v = (gui_float)(y+h)/(gui_float)tex_height; + if (glyphes[id].height > max_height) max_height = glyphes[id].height; + iter += 22; + } + + /* texture */ + header = iter; + assert(header[0] == 'B'); + assert(header[1] == 'M'); + + data = header + 54; + glGenTextures(1, &texture); + convert.ptr = texture; + glBindTexture(GL_TEXTURE_2D, texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_width, tex_height, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + /* font */ + font = xcalloc(sizeof(struct gui_font), 1); + font->height = height; + font->scale = (float)height/(float)max_height; + font->texture = convert.handle; + font->tex_size.x = tex_width; + font->tex_size.y = tex_height; + font->fallback = &glyphes['?']; + font->glyphes = glyphes; + font->glyph_count = indexes; + free(buffer); + return font; +} + static void -draw(int width, int height, const struct gui_draw_list *list) +delfont(struct gui_font *font) +{ + if (!font) return; + if (font->glyphes) + free(font->glyphes); + free(font); +} + +static void +draw(struct GUI *con, int width, int height, const struct gui_draw_list *list) { const struct gui_draw_command *cmd; - persistent const size_t v = sizeof(struct gui_vertex); - persistent const size_t p = offsetof(struct gui_vertex, pos); - persistent const size_t t = offsetof(struct gui_vertex, uv); - persistent const size_t c = offsetof(struct gui_vertex, color); + static const size_t v = sizeof(struct gui_vertex); + static const size_t p = offsetof(struct gui_vertex, pos); + static const size_t t = offsetof(struct gui_vertex, uv); + static const size_t c = offsetof(struct gui_vertex, color); if (!list) return; glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_TRANSFORM_BIT); @@ -222,6 +326,20 @@ draw(int width, int height, const struct gui_draw_list *list) glPushMatrix(); glLoadIdentity(); + glBindTexture(GL_TEXTURE_2D, (unsigned long)con->font->texture); + glColor4ub(255,255,255,255); + glBegin(GL_QUADS); + glTexCoord3d(1, 1, 0); + glVertex2f(300, 300); + glTexCoord2d(0, 1); + glVertex2f(50, 300); + glTexCoord2d(0, 0); + glVertex2f(50, 50); + glTexCoord2d(1, 0); + glVertex2f(300, 50); + glEnd(); + +#if 0 cmd = list->begin; while (cmd) { const int x = (int)cmd->clip_rect.x; @@ -237,6 +355,7 @@ draw(int width, int height, const struct gui_draw_list *list) glDrawArrays(GL_TRIANGLES, 0, cmd->vertex_count); cmd = gui_next(list, cmd); } +#endif glDisableClientState(GL_COLOR_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); @@ -252,7 +371,7 @@ int main(int argc, char *argv[]) { struct XWindow xw; - struct Console con; + struct GUI gui; long dt, started; gui_byte *buffer; gui_size buffer_size = MAX_VERTEX_BUFFER; @@ -260,6 +379,7 @@ main(int argc, char *argv[]) const struct gui_color colorB = {45, 45, 45, 255}; const struct gui_color colorC = {0, 0, 0, 255}; static GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE,24, GLX_DOUBLEBUFFER, None}; + GLenum err; gui_float slider = 5.0f; gui_float prog = 60.0f; @@ -268,7 +388,7 @@ main(int argc, char *argv[]) /* x11 */ UNUSED(argc); UNUSED(argv); memset(&xw, 0, sizeof xw); - memset(&con, 0, sizeof con); + memset(&gui, 0, sizeof gui); xw.dpy = XOpenDisplay(NULL); if (!xw.dpy) die("XOpenDisplay failed\n"); @@ -291,7 +411,8 @@ main(int argc, char *argv[]) XMapWindow(xw.dpy, xw.win); XFlush(xw.dpy); XSync(xw.dpy, False); - con.win = &xw; + gui.win = &xw; + gui.font = ldfont("mono.font", 16); /* OpenGL */ xw.glc = glXCreateContext(xw.dpy, xw.vi, NULL, GL_TRUE); @@ -300,37 +421,36 @@ main(int argc, char *argv[]) xw.running = 1; while (xw.running) { - /*----------------------- Input -----------------------------*/ XEvent ev; started = timestamp(); - gui_input_begin(&con.input); + gui_input_begin(&gui.input); while (XCheckWindowEvent(xw.dpy, xw.win, xw.swa.event_mask, &ev)) { - if (ev.type == Expose||ev.type == ConfigureNotify) resize(&con, &ev); - else if (ev.type == MotionNotify) bmotion(&con, &ev); - else if (ev.type == ButtonPress) bpress(&con, &ev); - else if (ev.type == ButtonRelease) brelease(&con, &ev); - else if (ev.type == KeyPress) kpress(&con, &ev); - else if (ev.type == KeyRelease) kpress(&con, &ev); + if (ev.type == Expose||ev.type == ConfigureNotify) resize(&gui, &ev); + else if (ev.type == MotionNotify) bmotion(&gui, &ev); + else if (ev.type == ButtonPress) bpress(&gui, &ev); + else if (ev.type == ButtonRelease) brelease(&gui, &ev); + else if (ev.type == KeyPress) kpress(&gui, &ev); + else if (ev.type == KeyRelease) krelease(&gui, &ev); } - gui_input_end(&con.input); + gui_input_end(&gui.input); /* ------------------------- GUI --------------------------*/ - gui_begin(&con.gui, buffer, MAX_VERTEX_BUFFER); - if (gui_button(&con.gui, &con.input, colorA, colorC, 50,50,150,30,5,"",0)) + gui_begin(&gui.out, buffer, MAX_VERTEX_BUFFER); + if (gui_button(&gui.out, &gui.input, NULL, colorA, colorC, 50,50,150,30,5,"",0)) fprintf(stdout, "Button pressed!\n"); - slider = gui_slider(&con.gui, &con.input, colorA, colorB, - 50,100,150,30,2, 0.0f, slider, 10.0f, 1.0f); - prog = gui_progress(&con.gui, &con.input, colorA, colorB, - 50,150,150,30,2, prog, 100.0f, gui_true); - offset = gui_scroll(&con.gui, &con.input, colorA, colorB, - 250,50,16,300, offset, 600); - gui_end(&con.gui); + slider = gui_slider(&gui.out, &gui.input, colorA, colorB, + 50, 100, 150, 30, 2, 0.0f, slider, 10.0f, 1.0f); + prog = gui_progress(&gui.out, &gui.input, colorA, colorB, + 50, 150, 150, 30, 2, prog, 100.0f, gui_true); + offset = gui_scroll(&gui.out, &gui.input, colorA, colorB, + 250, 50, 16, 300, offset, 600); + gui_end(&gui.out); /* ---------------------------------------------------------*/ /* Draw */ glClearColor(45.0f/255.0f,45.0f/255.0f,45.0f/255.0f,1); glClear(GL_COLOR_BUFFER_BIT); - draw(xw.gwa.width, xw.gwa.height, &con.gui); + draw(&gui, xw.gwa.width, xw.gwa.height, &gui.out); glXSwapBuffers(xw.dpy, xw.win); /* Timing */ @@ -342,6 +462,7 @@ main(int argc, char *argv[]) } /* Cleanup */ + delfont(gui.font); glXMakeCurrent(xw.dpy, None, NULL); glXDestroyContext(xw.dpy, xw.glc); XDestroyWindow(xw.dpy, xw.win);