'------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ ' ' Interface for the Nuklear Gui - https://github.com/vurtun/nuklear ' ' MIT License - (c) Peter van Eerten, September/October 2018 - v0.8. ' ' ======================================================== ' Reserved constants and variables for internal processing ' ======================================================== ' NUKLEAR_MEMORY_SIZE ' NUKLEAR_FONT ' NUKLEAR_FONT_ZOOM ' NUKLEAR_FONT_LENGTH ' ' ======================== ' User API ' ======================== ' nk_canvas_new() ' nk_canvas_events(window) ' nk_canvas_changed(window) ' nk_canvas_render(window) ' nk_canvas_free(window) ' nk_canvas_tex(data, width, height) ' nk_canvas_tex_free(texture) ' ' ============================================================================= ' Create a new window using the 'nuklear_type' type. Flow *must* be as follows: ' ============================================================================= ' (1) Check events - use 'nk_canvas_events()' ' (2) Create GUI - use regular Nuklear API ' (3) Draw GUI - use 'nk_canvas_render()' ' -> optionally, first check if there is a change using 'nl_canvas_changed()' ' '------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ PRAGMA INCLUDE nuklear-master/nuklear.h PRAGMA OPTIONS -DNK_IMPLEMENTATION -DNK_INCLUDE_DEFAULT_ALLOCATOR -DNK_INCLUDE_STANDARD_IO -DNK_INCLUDE_FIXED_TYPES -DNK_ZERO_COMMAND_MEMORY OPTION PARSE FALSE CONST NUKLEAR_MEMORY_SIZE = 64*1024 CONST NUKLEAR_FONT_ZOOM = 0.6 ' With scaling = 0.6, the value 12 works best CONST NUKLEAR_FONT_LENGTH = 12.0 USEH typedef struct nk_context nuklear_window; typedef struct nk_user_font nuklear_font; typedef struct nk_style nuklear_style; typedef struct nk_list_view nuklear_list; typedef struct nk_color nuklear_color; typedef struct nk_colorf nuklear_colorf; typedef struct nk_image nuklear_image; typedef struct nk_rect nuklear_rect; typedef struct nk_command_buffer nuklear_buffer; ENDUSEH RECORD nuklear LOCAL ctx TYPE nuklear_window LOCAL mouse_state TYPE int LOCAL buffer, gui_state TYPE void* ENDRECORD ' Font is the canvas font and global for this context DECLARE NUKLEAR_FONT TYPE nuklear_font ' The value of 28 is the actual max height of the Canvas internal Hershey font NUKLEAR_FONT.height = 28.0*NUKLEAR_FONT_ZOOM NUKLEAR_FONT.userdata.ptr = 0 NUKLEAR_FONT.width = NUKLEAR_text_width_calculation '-------------------------------------------------------------------------------------------------------------------------- FUNCTION NUKLEAR_text_width_calculation(nk_handle handle, float height, const char *text, int len) TYPE float RETURN len*NUKLEAR_FONT_LENGTH ENDFUNCTION '-------------------------------------------------------------------------------------------------------------------------- FUNCTION nk_canvas_new() TYPE nuklear_type LOCAL this TYPE nuklear_type this.buffer = calloc(1, NUKLEAR_MEMORY_SIZE) this.gui_state = calloc(1, NUKLEAR_MEMORY_SIZE) nk_init_fixed(&this.ctx, this.buffer, NUKLEAR_MEMORY_SIZE, &NUKLEAR_FONT) RETURN this ENDFUNCTION '-------------------------------------------------------------------------------------------------------------------------- SUB nk_canvas_events(nuklear_type *this) LOCAL mouse_button LOCAL mstat = 0 TYPE static int ' Mouse events nk_input_begin(&this->ctx) IF this->mouse_state <> CANVAS.mstate THEN SELECT CANVAS.mbutton CASE 1 mouse_button = NK_BUTTON_LEFT CASE 2 mouse_button = NK_BUTTON_MIDDLE CASE 3 mouse_button = NK_BUTTON_RIGHT CASE 4, 5 mouse_button = NK_BUTTON_MAX ENDSELECT nk_input_button(&this->ctx, mouse_button, CANVAS.mx, CANVAS.my, CANVAS.mstate) this->mouse_state = CANVAS.mstate ELSE IF CANVAS.mbutton = 4 THEN nk_input_scroll(&this->ctx, nk_vec2(0, 3)) CANVAS.mstate = 0 CANVAS.mbutton = 0 ELIF CANVAS.mbutton = 5 THEN nk_input_scroll(&this->ctx, nk_vec2(0, -3)) CANVAS.mstate = 0 CANVAS.mbutton = 0 ENDIF nk_input_motion(&this->ctx, CANVAS.mx, CANVAS.my) ENDIF nk_input_end(&this->ctx) END SUB '-------------------------------------------------------------------------------------------------------------------------- FUNCTION nk_canvas_changed(nuklear_type *this) LOCAL cmds TYPE void* LOCAL changed = FALSE cmds = nk_buffer_memory(&this->ctx.memory) IF memcmp(cmds, this->gui_state, this->ctx.memory.allocated) THEN changed = TRUE memcpy(this->gui_state, cmds, this->ctx.memory.allocated) ELSE nk_clear(&this->ctx) ENDIF RETURN changed ENDFUNCTION '-------------------------------------------------------------------------------------------------------------------------- SUB NUKLEAR_interpolate(struct nk_color c1, struct nk_color c2, struct nk_color *result, float fraction) LOCAL r, g, b, a TYPE float r = c1.r + (c2.r - c1.r) * fraction g = c1.g + (c2.g - c1.g) * fraction b = c1.b + (c2.b - c1.b) * fraction a = c1.a + (c2.a - c1.a) * fraction result->r = (nk_byte)NK_CLAMP(0, r, 255) result->g = (nk_byte)NK_CLAMP(0, g, 255) result->b = (nk_byte)NK_CLAMP(0, b, 255) result->a = (nk_byte)NK_CLAMP(0, a, 255) ENDSUB SUB NUKLEAR_fill_rect_multi_color(short x, short y, unsigned short w, unsigned short h, nuklear_color left, nuklear_color top, nuklear_color right, nuklear_color bottom) LOCAL X1, X2, Y TYPE nuklear_color LOCAL fraction_x, fraction_y TYPE float LOCAL i, j TYPE int FOR j = 0 TO h-1 fraction_y = ((float)j) / h FOR i = 0 TO w-1 fraction_x = ((float)i) / w NUKLEAR_interpolate(left, top, &X1, fraction_x) NUKLEAR_interpolate(right, bottom, &X2, fraction_x) NUKLEAR_interpolate(X1, X2, &Y, fraction_y) INK(Y.r, Y.g, Y.b, Y.a) PIXEL(x + i, y + j) NEXT NEXT ENDSUB '-------------------------------------------------------------------------------------------------------------------------- FUNCTION nk_canvas_tex(void *d, w, h) TYPE int LOCAL tex TYPE int glGenTextures(1, &tex) glBindTexture(GL_TEXTURE_2D, tex) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, d) RETURN tex ENDFUNCTION '-------------------------------------------------------------------------------------------------------------------------- SUB nk_canvas_tex_free(int texture) glDeleteTextures(1, &texture) END SUB '-------------------------------------------------------------------------------------------------------------------------- SUB nk_canvas_render(nuklear_type *this) LOCAL cmd TYPE const struct nk_command* LOCAL s TYPE const struct nk_command_scissor* LOCAL l TYPE const struct nk_command_line* LOCAL r TYPE const struct nk_command_rect* LOCAL rf TYPE const struct nk_command_rect_filled* LOCAL c TYPE const struct nk_command_circle* LOCAL cf TYPE const struct nk_command_circle_filled* LOCAL t TYPE const struct nk_command_text* LOCAL tr TYPE const struct nk_command_triangle* LOCAL trf TYPE const struct nk_command_triangle_filled* LOCAL p TYPE const struct nk_command_polygon* LOCAL pf TYPE const struct nk_command_polygon_filled* LOCAL pl TYPE const struct nk_command_polyline* LOCAL q TYPE const struct nk_command_curve* LOCAL a TYPE const struct nk_command_arc* LOCAL af TYPE const struct nk_command_arc_filled* LOCAL rc TYPE const struct nk_command_rect_multi_color* LOCAL im TYPE const struct nk_command_image* LOCAL xpos, ypos, xr, yr, xtot, ytot TYPE unsigned short LOCAL texture, i TYPE int cmd = nk__begin(&this->ctx) WHILE TRUE IF cmd = 0 THEN BREAK SELECT cmd->type CASE NK_COMMAND_SCISSOR s = (const struct nk_command_scissor*)cmd ypos = CANVAS.ysize-(int)((s->y)+(s->h)) glEnable(GL_SCISSOR_TEST) glScissor( (int)s->x, (int)ypos, (int)s->w, (int)s->h ) CASE NK_COMMAND_LINE l = (const struct nk_command_line*)cmd INK(l->color.r, l->color.g, l->color.b, l->color.a) SCALE(1.0) PEN(l->line_thickness, FALSE) LINE(l->begin.x, l->begin.y, l->end.x, l->end.y) CASE NK_COMMAND_RECT r = (const struct nk_command_rect*)cmd INK(r->color.r, r->color.g, r->color.b, r->color.a) xr = (r->w)/2 yr = (r->h)/2 SCALE(1.0) PEN(r->line_thickness, FALSE) SQUARE(r->x+xr, r->y+yr, xr, yr, FALSE) CASE NK_COMMAND_RECT_FILLED rf = (const struct nk_command_rect_filled*)cmd INK(rf->color.r, rf->color.g, rf->color.b, rf->color.a) xr = (rf->w)/2 yr = (rf->h)/2 SCALE(1.0) SQUARE(rf->x+xr, rf->y+yr, xr, yr, TRUE) CASE NK_COMMAND_CIRCLE c = (const struct nk_command_circle*)cmd INK(c->color.r, c->color.g, c->color.b, c->color.a) xr = (c->w)/2.0 yr = (c->h)/2.0 SCALE(1.0) PEN(c->line_thickness, FALSE) CIRCLE(c->x+xr, c->y+yr, xr, yr, FALSE) CASE NK_COMMAND_CIRCLE_FILLED cf = (const struct nk_command_circle_filled*)cmd INK(cf->color.r, cf->color.g, cf->color.b, cf->color.a) xr = (cf->w)/2 yr = (cf->h)/2 SCALE(1.0) CIRCLE(cf->x+xr, cf->y+yr, xr, yr, TRUE) CASE NK_COMMAND_TEXT t = (const struct nk_command_text*)cmd INK(t->foreground.r, t->foreground.g, t->foreground.b, t->foreground.a) SCALE(NUKLEAR_FONT_ZOOM) PEN(1.0, TRUE) FONTALIGN(1) TEXT((STRING)t->string, t->x, t->y+(NUKLEAR_FONT.height/2)) CASE NK_COMMAND_TRIANGLE tr = (const struct nk_command_triangle*)cmd INK(tr->color.r, tr->color.g, tr->color.b, tr->color.a) SCALE(1.0) PEN(tr->line_thickness, FALSE) LINE(tr->a.x, tr->a.y, tr->b.x, tr->b.y) LINE(tr->b.x, tr->b.y, tr->c.x, tr->c.y) LINE(tr->c.x, tr->c.y, tr->a.x, tr->a.y) CASE NK_COMMAND_TRIANGLE_FILLED trf = (const struct nk_command_triangle_filled*)cmd INK(trf->color.r, trf->color.g, trf->color.b, trf->color.a) SCALE(1.0) LINE(trf->a.x, trf->a.y, trf->b.x, trf->b.y) LINE(trf->b.x, trf->b.y, trf->c.x, trf->c.y) LINE(trf->c.x, trf->c.y, trf->a.x, trf->a.y) PAINT((trf->a.x+trf->b.x+trf->c.x)/3, (trf->a.y+trf->b.y+trf->c.y)/3) CASE NK_COMMAND_POLYGON p = (const struct nk_command_polygon*)cmd INK(p->color.r, p->color.g, p->color.b, p->color.a) SCALE(1.0) PEN(p->line_thickness, FALSE) FOR i = 0 TO p->point_count-1 xpos = p->points[i].x ypos = p->points[i].y IF i < p->point_count-1 THEN LINE(xpos, ypos, p->points[i+1].x, p->points[i+1].y) ELSE LINE(xpos, ypos, p->points[0].x, p->points[0].y) ENDIF NEXT CASE NK_COMMAND_POLYGON_FILLED pf = (const struct nk_command_polygon_filled*)cmd INK(pf->color.r, pf->color.g, pf->color.b, pf->color.a) SCALE(1.0) xtot = ytot = 0 FOR i = 0 TO pf->point_count-1 xpos = pf->points[i].x ypos = pf->points[i].y INCR xtot, xpos INCR ytot, ypos IF i < pf->point_count-1 THEN LINE(xpos, ypos, pf->points[i+1].x, pf->points[i+1].y) ELSE LINE(xpos, ypos, pf->points[0].x, pf->points[0].y) ENDIF NEXT PAINT(xtot/pf->point_count, ytot/pf->point_count) CASE NK_COMMAND_POLYLINE pl = (const struct nk_command_polyline*)cmd INK(pl->color.r, pl->color.g, pl->color.b, pl->color.a) SCALE(1.0) PEN(pl->line_thickness, FALSE) FOR i = 0 TO pl->point_count-1 xpos = pl->points[i].x ypos = pl->points[i].y IF i < pl->point_count-1 THEN LINE(xpos, ypos, pl->points[i+1].x, pl->points[i+1].y) ELSE LINE(xpos, ypos, pl->points[0].x, pl->points[0].y) ENDIF NEXT CASE NK_COMMAND_CURVE q = (const struct nk_command_curve*)cmd INK(q->color.r, q->color.g, q->color.b, q->color.a) SCALE(1.0) PEN(q->line_thickness, FALSE) CBEZIER(q->begin.x, q->begin.y, q->ctrl[0].x, q->ctrl[0].y, q->ctrl[1].x, q->ctrl[1].y, q->end.x, q->end.y) CASE NK_COMMAND_ARC a = (const struct nk_command_arc*)cmd INK(a->color.r, a->color.g, a->color.b, a->color.a) SCALE(1.0) PEN(a->line_thickness, FALSE) ARC((float)a->cx, (float)a->cy, (float)a->r, (float)a->r, a->a[0], a->a[1], FALSE) CASE NK_COMMAND_ARC_FILLED af = (const struct nk_command_arc_filled*)cmd INK(af->color.r, af->color.g, af->color.b, af->color.a) SCALE(1.0) ARC((float)af->cx, (float)af->cy, (float)af->r, (float)af->r, af->a[0], af->a[1], TRUE) CASE NK_COMMAND_RECT_MULTI_COLOR rc = (const struct nk_command_rect_multi_color*)cmd SCALE(1.0) NUKLEAR_fill_rect_multi_color(rc->x, rc->y, rc->w, rc->h, rc->left, rc->top, rc->right, rc->bottom) CASE NK_COMMAND_IMAGE im = (const struct nk_command_image*)cmd SCALE(1.0) CALL Draw_Prepare glColor4ub(255,255,255,255) : ' Prevent color mixup with the texture glEnable(GL_TEXTURE_2D) glBegin(GL_QUADS) glTexCoord2f(0.0f, 0.0f) : glVertex2f(im->x, im->y) glTexCoord2f(0.0f, 1.0f) : glVertex2f(im->x, im->y + im->h) glTexCoord2f(1.0f, 1.0f) : glVertex2f(im->x + im->w, im->y + im->h) glTexCoord2f(1.0f, 0.0f) : glVertex2f(im->x + im->w, im->y) glEnd() glDisable(GL_TEXTURE_2D) CASE NK_COMMAND_NOP PRINT "Nothing" ENDSELECT ' Disable scissor after drawing command was performed IF cmd->type <> NK_COMMAND_SCISSOR THEN glDisable(GL_SCISSOR_TEST) cmd = nk__next(&this->ctx, cmd) WEND nk_clear(&this->ctx) END SUB '-------------------------------------------------------------------------------------------------------------------------- SUB nk_canvas_free(nuklear_type *this) free(this->buffer) free(this->gui_state) nk_free(&this->ctx) END SUB '--------------------------------------------------------------------------------------------------------------------------