From fca98b08cfe4246ccdd11211476d8ab5dac7a56f Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 15 Feb 2022 20:05:51 +0200 Subject: [PATCH 1/1] start by copying windtk and dropping dirty rects and indexed colors --- .gitignore | 4 + Makefile | 20 +++++ src/agimpl.h | 54 +++++++++++++ src/anigui.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ src/anigui.h | 161 ++++++++++++++++++++++++++++++++++++++ src/widget.c | 243 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/widget.h | 30 ++++++++ src/window.c | 89 +++++++++++++++++++++ test.c | 113 +++++++++++++++++++++++++++ 9 files changed, 915 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 src/agimpl.h create mode 100644 src/anigui.c create mode 100644 src/anigui.h create mode 100644 src/widget.c create mode 100644 src/widget.h create mode 100644 src/window.c create mode 100644 test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0932ecf --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.o +*.d +*.swp +test diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..2423d12 --- /dev/null +++ b/Makefile @@ -0,0 +1,20 @@ +src = test.c $(wildcard src/*.c) +obj = $(src:.c=.o) +dep = $(src:.c=.d) +bin = test + +CFLAGS = -pedantic -Wall -Isrc -MMD +LDFLAGS = -lGL -lGLU -lglut + +$(bin): $(obj) + $(CC) -o $@ $(obj) $(LDFLAGS) + +-include $(dep) + +.PHONY: clean +clean: + rm -f $(obj) $(bin) + +.PHONY: cleandep +cleandep: + rm -f $(dep) diff --git a/src/agimpl.h b/src/agimpl.h new file mode 100644 index 0000000..2e5ab0f --- /dev/null +++ b/src/agimpl.h @@ -0,0 +1,54 @@ +#ifndef AGIMPL_H_ +#define AGIMPL_H_ + +#include +#include "anigui.h" +#include "widget.h" + +enum { + COL_FG, + COL_BG, + COL_BGHI, + COL_BGLO, + COL_FRM, + COL_FRMHI, + COL_FRMLO, + COL_FFRM, + COL_FFRMHI, + COL_FFRMLO, + + NUM_COLORS +}; + +enum { FRM_OUT, FRM_IN, FRM_NOFILL = 0x8000 }; +#define FRMSTYLE(x) ((x) & 0xff) + +#define MAX_UPD_RECTS 16 + +struct ag_context { + struct ag_graphics gfx; + struct ag_rect vp; + ag_widget *root; + struct ag_theme *theme; + + unsigned int colors[NUM_COLORS]; + + ag_widget *focuswin; +}; + +extern struct ag_context *ag_curctx_; +#define ag ag_curctx_ + +extern void *(*ag_alloc)(size_t sz); +extern void (*ag_free)(void *p); + +void *ag_zalloc(size_t sz); + +void ag_gfx_color(int cidx); +void ag_gfx_fillrect(struct ag_rect *r); +void ag_gfx_frame(struct ag_rect *r, int style, int basecol); +void ag_gfx_line(int x0, int y0, int x1, int y1); + +void ag_calc_window_rect(struct ag_rect *r, ag_widget *w); + +#endif /* AGIMPL_H_ */ diff --git a/src/anigui.c b/src/anigui.c new file mode 100644 index 0000000..1c4ab26 --- /dev/null +++ b/src/anigui.c @@ -0,0 +1,201 @@ +#include +#include +#include "agimpl.h" + +void *(*ag_alloc)(size_t sz) = malloc; +void (*ag_free)(void *p) = free; + +/* one day I may want to allow multiple contexts */ +static struct ag_context defctx; +struct ag_context *ag_curctx_ = &defctx; + +static unsigned int def_colors[] = { + 0xf0f0f0, /* font/foreground */ + 0x444444, /* background */ + 0x555555, /* highlight */ + 0x333333, /* shadow */ + 0x403065, /* inactive frame */ + 0x54349c, /* inactive frame highlight */ + 0x221e2c, /* inactive frame shadow */ + 0x8032aa, /* active frame */ + 0xb14de8, /* active frame highlight */ + 0x3b2846, /* active frame shadow */ + 0 +}; + +void *ag_zalloc(size_t sz) +{ + void *p = ag_alloc(sz); + if(p) { + memset(p, 0, sz); + } + return p; +} + +void ag_allocator(void *(*allocfunc)(size_t), void (*freefunc)(void *p)) +{ + ag_alloc = allocfunc ? allocfunc : malloc; + ag_free = freefunc ? freefunc : free; +} + + +int ag_init(int w, int h, struct ag_graphics *gfx) +{ + ag->root = 0; + if(!(ag->root = ag_alloc_widget(0))) { + return -1; + } + + ag_viewport(0, 0, w, h); + ag_graphics(gfx); + return 0; +} + +void ag_destroy(void) +{ + ag_free_tree(ag->root); + ag->root = 0; +} + +struct ag_theme *ag_load_theme(const char *path) +{ + return 0; /* TODO */ +} + +void ag_unload_theme(struct ag_theme *theme) +{ +} + +static void use_theme(ag_widget *w, struct ag_theme *theme) +{ + int i; + + if(w->use_theme) { + w->use_theme(w, theme); + } + + for(i=0; inum_child; i++) { + use_theme(w->child[i], theme); + } +} + +void ag_use_theme(struct ag_theme *theme) +{ + ag->theme = theme; + use_theme(ag->root, theme); +} + +void ag_viewport(int x, int y, int w, int h) +{ + ag_rect(&ag->vp, x, y, w, h); + ag_move(ag->root, x, y); + ag_resize(ag->root, w, h); +} + +void ag_graphics(struct ag_graphics *gfx) +{ + ag->gfx = *gfx; + memcpy(ag->colors, def_colors, sizeof ag->colors); +} + +void ag_inp_key(int key, int press) +{ +} + +void ag_inp_mouse(int bn, int st, int x, int y) +{ +} + +void ag_inp_motion(int x, int y) +{ +} + +void ag_draw_tree(ag_widget *tree) +{ + int i; + + if(tree->draw) { + tree->draw(tree, &ag->gfx); + } + + for(i=0; inum_child; i++) { + ag_draw_tree(tree->child[i]); + } +} + +void ag_draw(void) +{ + ag_draw_tree(ag->root); +} + +void ag_gfx_color(int cidx) +{ + int r = (ag->colors[cidx] >> 16) & 0xff; + int g = (ag->colors[cidx] >> 8) & 0xff; + int b = ag->colors[cidx] & 0xff; + ag->gfx.color(r, g, b); +} + +void ag_gfx_fillrect(struct ag_rect *r) +{ + ag->gfx.fillrect(r); +} + +void ag_gfx_fillrect4i(int x, int y, int w, int h) +{ + struct ag_rect r; + ag_rect(&r, x, y, w, h); + ag->gfx.fillrect(&r); +} + +void ag_gfx_frame(struct ag_rect *r, int style, int basecol) +{ + if((style & FRM_NOFILL) == 0) { + ag_gfx_color(basecol); + ag_gfx_fillrect(r); + } + ag_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 2 : basecol + 1); + ag_gfx_fillrect4i(r->x + 1, r->y + r->h - 1, r->w - 2, 1); + ag_gfx_fillrect4i(r->x + r->w - 1, r->y, 1, r->h); + ag_gfx_color(FRMSTYLE(style) == FRM_OUT ? basecol + 1 : basecol + 2); + ag_gfx_fillrect4i(r->x + 1, r->y, r->w - 2, 1); + ag_gfx_fillrect4i(r->x, r->y, 1, r->h); +} + +void ag_gfx_line(int x0, int y0, int x1, int y1) +{ + ag->gfx.line(x0, y0, x1, y1); +} + +void ag_rect(struct ag_rect *r, int x, int y, int w, int h) +{ + r->x = x; + r->y = y; + r->w = w; + r->h = h; +} + +void ag_rect_union(struct ag_rect *a, struct ag_rect *b) +{ + int x1, y1; + + x1 = a->x + a->w; + y1 = a->y + a->h; + + if(b->x < a->x) a->x = b->x; + if(b->y < a->y) a->y = b->y; + if(b->x + b->w > x1) x1 = b->x + b->w; + if(b->y + b->h > y1) y1 = b->y + b->h; + + a->w = x1 - a->x; + a->h = y1 - a->y; +} + +int ag_rect_overlap(struct ag_rect *a, struct ag_rect *b) +{ + if(a->x > b->x + b->w) return 0; + if(b->x > a->x + a->w) return 0; + if(a->y > b->y + b->h) return 0; + if(b->y > a->x + a->h) return 0; + return 1; +} diff --git a/src/anigui.h b/src/anigui.h new file mode 100644 index 0000000..e9537dc --- /dev/null +++ b/src/anigui.h @@ -0,0 +1,161 @@ +#ifndef ANIGUI_H_ +#define ANIGUI_H_ + +enum { + AG_TYPE_WIDGET, + AG_TYPE_WINDOW, + AG_TYPE_LABEL, + AG_TYPE_BUTTON, + AG_TYPE_CHECKBOX, + AG_TYPE_TEXTFIELD +}; + +enum { + AG_KEY_UP = 0x100, + AG_KEY_DOWN, + AG_KEY_LEFT, + AG_KEY_RIGHT, + AG_KEY_HOME, + AG_KEY_END, + AG_KEY_PGUP, + AG_KEY_PGDN +}; + +enum { + AG_WS_DEFAULT, + AG_WS_NOFRM +}; + +enum { + AG_CB_FOCUS, + AG_CB_UNFOCUS, + AG_CB_MODIFY, + AG_CB_CLICK, + AG_CB_MBUTTON, + AG_CB_MMOTION, + + AG_NUM_CALLBACKS +}; + +typedef struct ag_widget ag_widget; +typedef void (*ag_callback_func)(ag_widget*, void*); + +struct ag_image { + int width, height; + int bpp; + int pitch; + void *pixels; + void *udata; +}; + +struct ag_rect { + int x, y, w, h; +}; + +struct ag_graphics { + unsigned int flags; + + void (*color)(int r, int g, int b); + + void (*fillrect)(struct ag_rect *rect); + void (*line)(int x0, int y0, int x1, int y1); + + int (*newimage)(struct ag_image *img); + void (*blit)(int img, int x, int y, int w, int h); + + void (*text)(int font, const char *s, int x, int y); + void (*textbox)(int font, const char *s, int x, int y, struct ag_rect *boxret); + int (*lineheight)(int font); + int (*baseline)(int font); +}; + +typedef void (*ag_draw_func)(ag_widget*, struct ag_graphics*); + +struct ag_theme { + char *name; + void *so; + ag_draw_func draw_window; + ag_draw_func draw_label; + ag_draw_func draw_button; + ag_draw_func draw_checkbox; + ag_draw_func draw_textfield; + + struct ag_theme *next; +}; + +void ag_allocator(void *(*allocfunc)(size_t), void (*freefunc)(void*)); + +int ag_init(int w, int h, struct ag_graphics *gfx); +void ag_destroy(void); + +struct ag_theme *ag_load_theme(const char *path); /* load dynamically, where applicable */ +void ag_unload_theme(struct ag_theme *theme); +void ag_use_theme(struct ag_theme *theme); + +void ag_viewport(int x, int y, int w, int h); +void ag_graphics(struct ag_graphics *gfx); + +void ag_inp_key(int key, int press); +void ag_inp_mouse(int bn, int st, int x, int y); +void ag_inp_motion(int x, int y); + +void ag_draw(void); + +ag_widget *ag_alloc_widget(ag_widget *par); +void ag_free_widget(ag_widget *w); +void ag_free_tree(ag_widget *tree); + +ag_widget *ag_window(ag_widget *par, const char *title, int style, int x, int y, int width, int height); +ag_widget *ag_label(ag_widget *par, const char *text, int x, int y); +ag_widget *ag_button(ag_widget *par, const char *text, int x, int y, int width, int height); +ag_widget *ag_button_cb(ag_widget *par, const char *text, int x, int y, int width, + int height, ag_callback_func cbclick, void *cls); +ag_widget *ag_checkbox(ag_widget *par, const char *text, int chk, int x, int y, int width, int height); +ag_widget *ag_checkbox_cb(ag_widget *par, const char *text, int chk, int x, int y, + int width, int height, ag_callback_func cbtoggle, void *cls); +ag_widget *ag_textfield(ag_widget *par, const char *text, int x, int y, int width, int height); + +int ag_type(ag_widget *w); + +int ag_set_text(ag_widget *w, const char *text); +const char *ag_text(ag_widget *w); + +int ag_add_child(ag_widget *w, ag_widget *c); +int ag_remove_child(ag_widget *w, ag_widget *c); +ag_widget *ag_parent(ag_widget *w); /* parent widget */ +ag_widget *ag_widget_window(ag_widget *w); /* first ancestor of type window */ +int ag_child_count(ag_widget *w); /* number of children */ +ag_widget *ag_child(ag_widget *w, int idx); /* get child idx */ + +void ag_move(ag_widget *w, int x, int y); +void ag_resize(ag_widget *w, int x, int y); +int *ag_position(ag_widget *w, int *xret, int *yret); +int *ag_size(ag_widget *w, int *xret, int *yret); + +int ag_hittest(ag_widget *w, int x, int y); +ag_widget *ag_widget_at(int x, int y); + +void ag_layout(ag_widget *w, int layout); +void ag_padding(ag_widget *w, int pad); +/* calculates layout of child widgets and updates dimensions */ +void ag_relayout(ag_widget *w); + +void ag_focus(ag_widget *w); +void ag_unfocus(ag_widget *w); +int ag_isfocused(ag_widget *w); + +void ag_hover(ag_widget *w); +void ag_unhover(ag_widget *w); +int ag_ishover(ag_widget *w); + +void ag_enable(ag_widget *w); +void ag_disable(ag_widget *w); +int ag_isenabled(ag_widget *w); + +void ag_callback(ag_widget *w, int type, ag_callback_func func, void *cls); + +void ag_rect(struct ag_rect *r, int x, int y, int w, int h); +void ag_rect_union(struct ag_rect *a, struct ag_rect *b); +int ag_rect_overlap(struct ag_rect *a, struct ag_rect *b); + +#endif /* ANIGUI_H_ */ diff --git a/src/widget.c b/src/widget.c new file mode 100644 index 0000000..363f048 --- /dev/null +++ b/src/widget.c @@ -0,0 +1,243 @@ +#include +#include +#include "agimpl.h" + +ag_widget *ag_alloc_widget(ag_widget *par) +{ + ag_widget *w; + if(!(w = ag_zalloc(sizeof *w))) { + return 0; + } + w->type = AG_TYPE_WIDGET; + w->dirty = 1; + + if(!par) par = ag->root; + ag_add_child(par, w); + return w; +} + +void ag_free_widget(ag_widget *w) +{ + if(w) { + ag_free(w->text); + ag_free(w->child); + ag_free(w); + } +} + +void ag_free_tree(ag_widget *tree) +{ + int i; + + if(!tree) return; + + for(i=0; inum_child; i++) { + ag_free_tree(tree->child[i]); + } + ag_free_widget(tree); +} + +void ag_dirty_widget(ag_widget *w) +{ + int i; + + w->dirty = 1; + + for(i=0; inum_child; i++) { + ag_dirty_widget(w->child[i]); + } +} + +int ag_type(ag_widget *w) +{ + return w->type; +} + +int ag_set_text(ag_widget *w, const char *text) +{ + char *s; + + if(!(s = ag_alloc(strlen(text) + 1))) { + return -1; + } + strcpy(s, text); + ag_free(w->text); + w->text = s; + return 0; +} + +const char *ag_text(ag_widget *w) +{ + return w->text; +} + +static int find_child(ag_widget *w, ag_widget *c) +{ + int i; + for(i=0; inum_child; i++) { + if(w->child[i] == c) { + return i; + } + } + return -1; +} + +int ag_add_child(ag_widget *w, ag_widget *c) +{ + if(!w || !c) return -1; + + if(find_child(w, c) != -1) { + return 0; + } + if(c->parent) { + ag_remove_child(c->parent, c); + } + + if(w->num_child >= w->max_child) { + void *newarr; + int newsz = w->max_child ? w->max_child << 1 : 8; + if(!(newarr = ag_alloc(newsz * sizeof *w->child))) { + return -1; + } + memcpy(newarr, w->child, w->num_child * sizeof *w->child); + ag_free(w->child); + w->child = newarr; + w->max_child = newsz; + } + + w->child[w->num_child++] = c; + return 0; +} + +int ag_remove_child(ag_widget *w, ag_widget *c) +{ + int idx; + + if(!w->num_child || (idx = find_child(w, c)) == -1) { + return -1; + } + w->child[idx] = w->child[--w->num_child]; + + if(w->max_child > 8 && w->num_child < w->max_child / 3) { + void *newarr; + int newsz = w->max_child >> 1; + if(!(newarr = ag_alloc(newsz * sizeof *w->child))) { + return -1; + } + memcpy(newarr, w->child, w->num_child * sizeof *w->child); + ag_free(w->child); + w->child = newarr; + w->max_child = newsz; + } + return 0; +} + +ag_widget *ag_parent(ag_widget *w) +{ + return w->parent; +} + +ag_widget *ag_widget_window(ag_widget *w) +{ + ag_widget *par = w; + while(par && par->type != AG_TYPE_WINDOW) { + par = par->parent; + } + return par; +} + +int ag_child_count(ag_widget *w) +{ + return w->num_child; +} + +ag_widget *ag_child(ag_widget *w, int idx) +{ + if(idx < 0 || idx >= w->num_child) { + return 0; + } + return w->child[idx]; +} + +void ag_move(ag_widget *w, int x, int y) +{ + w->rect.x = x; + w->rect.y = y; + /* TODO: invalidate something */ +} + +void ag_resize(ag_widget *w, int x, int y) +{ + w->rect.w = x; + w->rect.h = y; + /* TODO: invalidate something */ +} + +int *ag_position(ag_widget *w, int *xret, int *yret) +{ + if(xret) *xret = w->rect.x; + if(yret) *yret = w->rect.y; + return &w->rect.x; +} + +int *ag_size(ag_widget *w, int *xret, int *yret) +{ + if(xret) *xret = w->rect.w; + if(yret) *yret = w->rect.h; + return &w->rect.w; +} + +int ag_hittest(ag_widget *w, int x, int y) +{ + return x >= w->rect.x && y >= w->rect.y && x < w->rect.x + w->rect.w && + y < w->rect.y + w->rect.h; +} + +ag_widget *ag_widget_at(int x, int y) +{ + int i; + ag_widget *w, *c; + + if(!ag_hittest(ag->root, x, y)) { + return 0; + } + + w = 0; + c = ag->root; + do { + w = c; + c = 0; + for(i=0; inum_child; i++) { + if(ag_hittest(w->child[i], x, y)) { + c = w->child[i]; + break; + } + } + } while(c); + + return w; +} + +/* +void ag_layout(ag_widget *w, int layout); +void ag_padding(ag_widget *w, int pad); +void ag_relayout(ag_widget *w); + +void ag_focus(ag_widget *w); +void ag_unfocus(ag_widget *w); +int ag_isfocused(ag_widget *w); + +void ag_hover(ag_widget *w); +void ag_unhover(ag_widget *w); +int ag_ishover(ag_widget *w); + +void ag_enable(ag_widget *w); +void ag_disable(ag_widget *w); +int ag_isenabled(ag_widget *w); +*/ + +void ag_callback(ag_widget *w, int type, ag_callback_func func, void *cls) +{ + w->cb[type] = func; + w->cbcls[type] = cls; +} diff --git a/src/widget.h b/src/widget.h new file mode 100644 index 0000000..60b384d --- /dev/null +++ b/src/widget.h @@ -0,0 +1,30 @@ +#ifndef WIDGET_H_ +#define WIDGET_H_ + +#include "anigui.h" + +struct ag_widget { + int type; + char *text; + struct ag_rect rect; + + struct ag_widget *parent; + struct ag_widget **child; /* dynamic array */ + int num_child, max_child; + int layout; + + ag_callback_func cb[AG_NUM_CALLBACKS]; + void *cbcls[AG_NUM_CALLBACKS]; + + int dirty; /* redraw pending */ + + ag_draw_func draw; + void (*click)(struct ag_widget *w); + void (*keypress)(struct ag_widget *w, int key); + void (*mbutton)(struct ag_widget *w, int bn, int st, int x, int y); + void (*mmotion)(struct ag_widget *w, int x, int y); + + void (*use_theme)(struct ag_widget *w, struct ag_theme *theme); +}; + +#endif /* WIDGET_H_ */ diff --git a/src/window.c b/src/window.c new file mode 100644 index 0000000..b715f99 --- /dev/null +++ b/src/window.c @@ -0,0 +1,89 @@ +#include "agimpl.h" + +static void draw_win(ag_widget *w, struct ag_graphics *gfx); +static void use_theme(ag_widget *w, struct ag_theme *theme); + +ag_widget *ag_window(ag_widget *par, const char *title, int style, int x, int y, int xsz, int ysz) +{ + ag_widget *w; + + if(!(w = ag_alloc_widget(par))) { + return 0; + } + w->type = AG_TYPE_WINDOW; + ag_set_text(w, title); + ag_move(w, x, y); + ag_resize(w, xsz, ysz); + /* TODO: style */ + + use_theme(w, ag->theme); + return w; +} + +#define FRMTHICK 1 +#define FRMBEVEL 1 +#define FRMOFFS (FRMTHICK + FRMBEVEL * 2) +#define TBARTHICK 12 /* TODO: base it on font metrics */ +#define TBAROFFS (TBARTHICK + FRMBEVEL * 2) + +void ag_calc_window_rect(struct ag_rect *r, ag_widget *w) +{ + r->x = w->rect.x - FRMOFFS; + r->y = w->rect.y - TBAROFFS - FRMOFFS; + r->w = w->rect.w + FRMOFFS * 2; + r->h = w->rect.h + TBAROFFS + FRMOFFS * 2; +} + +static void draw_win(ag_widget *w, struct ag_graphics *gfx) +{ + struct ag_rect fr, tmprect; + int frmcol = COL_FFRM;//ag->focuswin == w ? COL_FFRM : COL_FRM; + + ag_gfx_color(COL_BG); + ag_gfx_fillrect(&w->rect); + + ag_calc_window_rect(&fr, w); + + ag_gfx_frame(&fr, FRM_OUT | FRM_NOFILL, frmcol); /* outer bevel */ + + /* draw main frame */ + ag_gfx_color(frmcol); + + fr.x += FRMBEVEL; + fr.y += FRMBEVEL; + fr.w -= FRMBEVEL * 2; + fr.h -= FRMBEVEL * 2; + + tmprect = fr; + tmprect.w = FRMTHICK; + ag_gfx_fillrect(&tmprect); /* left bar */ + tmprect.x += fr.w - FRMTHICK; + ag_gfx_fillrect(&tmprect); /* right bar */ + + tmprect = fr; + tmprect.h = FRMTHICK; + tmprect.x += FRMTHICK; + tmprect.w -= FRMTHICK * 2; + ag_gfx_fillrect(&tmprect); /* top bar */ + tmprect.y += fr.h - FRMTHICK; + ag_gfx_fillrect(&tmprect); /* bottom bar */ + + /* inner bevel */ + fr.x += FRMTHICK; + fr.y += FRMTHICK; + fr.w -= FRMTHICK * 2; + fr.h -= FRMTHICK * 2; + ag_gfx_frame(&fr, FRM_IN | FRM_NOFILL, frmcol); + + /* titlebar */ + fr.x = w->rect.x; + fr.w = w->rect.w; + fr.y += FRMBEVEL; + fr.h = TBARTHICK + FRMBEVEL * 2; + ag_gfx_frame(&fr, FRM_OUT, frmcol); +} + +static void use_theme(ag_widget *w, struct ag_theme *theme) +{ + w->draw = theme && theme->draw_window ? theme->draw_window : draw_win; +} diff --git a/test.c b/test.c new file mode 100644 index 0000000..a575a53 --- /dev/null +++ b/test.c @@ -0,0 +1,113 @@ +#include +#include +#include +#include "anigui.h" + +static void display(void); +static void reshape(int x, int y); +static void keypress(unsigned char key, int x, int y); +static void keyrelease(unsigned char key, int x, int y); +static void mouse(int bn, int st, int x, int y); +static void motion(int x, int y); + +static void gfx_color(int r, int g, int b); +static void gfx_fillrect(struct ag_rect *r); +static void gfx_line(int x0, int y0, int x1, int y1); + +static struct ag_graphics gfx = { + 0, + gfx_color, + gfx_fillrect, + gfx_line +}; + +int main(int argc, char **argv) +{ + glutInit(&argc, argv); + glutInitWindowSize(800, 600); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE); + glutCreateWindow("windtk example"); + + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keypress); + glutKeyboardUpFunc(keyrelease); + glutMouseFunc(mouse); + glutMotionFunc(motion); + glutPassiveMotionFunc(motion); + + glClearColor(0.6, 0.6, 0.6, 1); + + if(ag_init(800, 600, &gfx) == -1) { + return 1; + } + ag_window(0, "foo", AG_WS_DEFAULT, 100, 100, 200, 200); + + glutMainLoop(); + return 0; +} + +static void display(void) +{ + glClear(GL_COLOR_BUFFER_BIT); + + ag_draw(); + + glutSwapBuffers(); +} + +static void reshape(int x, int y) +{ + glViewport(0, 0, x, y); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + glOrtho(0, x, y, 0, -1, 1); + + ag_viewport(0, 0, x, y); +} + +static void keypress(unsigned char key, int x, int y) +{ + if(key == 27) exit(0); + + ag_inp_key(key, 1); +} + +static void keyrelease(unsigned char key, int x, int y) +{ + ag_inp_key(key, 0); +} + +static void mouse(int bn, int st, int x, int y) +{ + ag_inp_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y); +} + +static void motion(int x, int y) +{ + ag_inp_motion(x, y); +} + +/* ------ graphics callbacks -------- */ +static void gfx_color(int r, int g, int b) +{ + glColor3ub(r, g, b); +} + +static void gfx_fillrect(struct ag_rect *r) +{ + glBegin(GL_QUADS); + glVertex2f(r->x, r->y); + glVertex2f(r->x + r->w, r->y); + glVertex2f(r->x + r->w, r->y + r->h); + glVertex2f(r->x, r->y + r->h); + glEnd(); +} + +static void gfx_line(int x0, int y0, int x1, int y1) +{ + glBegin(GL_LINES); + glVertex2f(x0, y0); + glVertex2f(x1, y1); + glEnd(); +} -- 1.7.10.4