bunch of stuff for pre-alpha build
[fishladder.git] / vg / vg_ui.h
1 // Copyright (C) 2021 Harry Godden (hgn) - All Rights Reserved
2
3 SHADER_DEFINE( shader_ui,
4
5 // VERTEX
6 "layout (location=0) in vec2 a_co;" // i16, i16, .. ?
7 "layout (location=1) in vec2 a_uv;" // i8, i8
8 "layout (location=2) in vec4 a_colour;" // u32
9 "uniform mat3 uPv;"
10 ""
11 "out vec2 aTexCoords;"
12 "out vec4 aColour;"
13 ""
14 "void main()"
15 "{"
16 "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );"
17 "aTexCoords = a_uv * 0.01388888888;"
18 "aColour = a_colour;"
19 "}",
20
21 // FRAGMENT
22 "uniform sampler2D uTexGlyphs;"
23 "out vec4 FragColor;"
24 ""
25 "in vec2 aTexCoords;"
26 "in vec4 aColour;"
27 ""
28 "void main()"
29 "{"
30 "vec4 glyph = texture( uTexGlyphs, aTexCoords );"
31 "FragColor = aColour * vec4( 1.0, 1.0, 1.0, glyph.r );"
32 "}"
33 ,
34 UNIFORMS({ "uPv", "uTexGlyphs" })
35 )
36
37 #define UI_AUTO_FILL 0
38 //#define UI_DEBUG
39
40 // Types
41 // ===========================================================================================================
42
43 typedef i16 ui_px;
44 typedef u32 ui_colour;
45 typedef ui_px ui_rect[4];
46 typedef struct ui_ctx ui_ctx;
47
48 struct ui_ctx
49 {
50 ui_px padding;
51
52 struct ui_qnode
53 {
54 ui_rect rect;
55 ui_colour colour;
56 int mouse_over;
57 int capture_id;
58 }
59 stack[ 32 ];
60
61 #pragma pack(push,1)
62 struct ui_vert
63 {
64 ui_px co[2];
65 u8 uv[2];
66 u32 colour;
67 }
68 *verts;
69 #pragma pack(pop)
70
71 u32 num_verts;
72 u16 *indices;
73 u32 num_indices;
74
75 ui_rect cursor;
76 u32 stack_count;
77 u32 capture_mouse_id;
78 int capture_lock;
79 u32 id_base;
80
81 // User input
82 ui_px mouse[2];
83 int click_state; // 0: released, 1: on down, 2: pressed, 3: on release
84 };
85
86 // Globals
87 // ===========================================================================================================
88
89 // Opengl
90 GLuint ui_glyph_texture;
91 GLuint ui_vao;
92 GLuint ui_vbo;
93 GLuint ui_ebo;
94
95 #define UI_BUFFER_SIZE 30000
96 #define UI_INDEX_SIZE 20000
97
98 ui_ctx ui_global_ctx = { .padding = 8 };
99
100
101 // Initialization
102 // ===========================================================================================================
103
104 static void ui_default_init(void)
105 {
106 // Load font
107 {
108 u32 compressed[] = {
109 #include "fonts/weiholmir.h"
110 };
111
112 u32 pixels = 0, total = 72*72, data = 0;
113 u8 *image = malloc( total );
114
115 while( pixels < total )
116 {
117 for( int b = 31; b >= 0; b-- )
118 {
119 image[ pixels ++ ] = (compressed[data] & (0x1 << b))? 0xff: 0x00;
120
121 if( pixels >= total )
122 {
123 total = 0;
124 break;
125 }
126 }
127 data++;
128 }
129
130 glGenTextures( 1, &ui_glyph_texture );
131 glBindTexture( GL_TEXTURE_2D, ui_glyph_texture );
132
133 glTexImage2D( GL_TEXTURE_2D, 0, GL_R8, 72, 72, 0, GL_RED, GL_UNSIGNED_BYTE, image );
134
135 vg_tex2d_clamp();
136 vg_tex2d_nearest();
137
138 free( image );
139 }
140
141 // Setup OpenGL memory
142 {
143 SHADER_INIT( shader_ui );
144
145 // Generate the buffer we are gonna be drawing to
146 glGenVertexArrays(1, &ui_vao);
147 glGenBuffers( 1, &ui_vbo );
148 glGenBuffers( 1, &ui_ebo );
149 glBindVertexArray( ui_vao );
150
151 glBindBuffer( GL_ARRAY_BUFFER, ui_vbo );
152
153 glBufferData( GL_ARRAY_BUFFER, UI_BUFFER_SIZE * sizeof( struct ui_vert ), NULL, GL_DYNAMIC_DRAW );
154 glBindVertexArray( ui_vao );
155
156 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ui_ebo );
157 glBufferData( GL_ELEMENT_ARRAY_BUFFER, UI_INDEX_SIZE * sizeof( u16 ), NULL, GL_DYNAMIC_DRAW );
158
159 u32 const stride = sizeof( struct ui_vert );
160
161 // XY
162 glVertexAttribPointer( 0, 2, GL_UNSIGNED_SHORT, GL_FALSE, stride, (void *)offsetof( struct ui_vert, co ) );
163 glEnableVertexAttribArray( 0 );
164
165 // UV
166 glVertexAttribPointer( 1, 2, GL_UNSIGNED_BYTE, GL_FALSE, stride, (void *)offsetof( struct ui_vert, uv ) );
167 glEnableVertexAttribArray( 1 );
168
169 // COLOUR
170 glVertexAttribPointer( 2, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, (void *)offsetof( struct ui_vert, colour ) );
171 glEnableVertexAttribArray( 2 );
172 }
173
174 // Initialize default context
175 {
176 ui_global_ctx.verts = (struct ui_vert *)malloc( UI_BUFFER_SIZE * sizeof(struct ui_vert) );
177 ui_global_ctx.indices = (u16*)malloc( UI_INDEX_SIZE * sizeof(u16) );
178 }
179 }
180
181 static void ui_default_free(void)
182 {
183 glDeleteTextures( 1, &ui_glyph_texture );
184
185 glDeleteVertexArrays( 1, &ui_vao );
186 glDeleteBuffers( 1, &ui_vbo );
187 glDeleteBuffers( 1, &ui_ebo );
188
189 free( ui_global_ctx.verts );
190 free( ui_global_ctx.indices );
191 }
192
193 static void ui_draw( ui_ctx *ctx )
194 {
195 glBindVertexArray( ui_vao );
196
197 glBindBuffer( GL_ARRAY_BUFFER, ui_vbo );
198 glBufferSubData( GL_ARRAY_BUFFER, 0, ctx->num_verts * sizeof( struct ui_vert ), ctx->verts );
199
200 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, ui_ebo );
201 glBufferSubData( GL_ELEMENT_ARRAY_BUFFER, 0, ctx->num_indices * sizeof( u16 ), ctx->indices );
202
203 glEnable(GL_BLEND);
204 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
205 glBlendEquation(GL_FUNC_ADD);
206
207 SHADER_USE( shader_ui );
208
209 m3x3f view = M3X3_IDENTITY;
210 m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } );
211 m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), -1.0f/((float)vg_window_y*0.5f), 1.0f } );
212 glUniformMatrix3fv( SHADER_UNIFORM( shader_ui, "uPv" ), 1, GL_FALSE, (float *)view );
213
214 glActiveTexture( GL_TEXTURE0 );
215 glBindTexture( GL_TEXTURE_2D, ui_glyph_texture );
216 glUniform1i( SHADER_UNIFORM( shader_ui, "uTexGlyphs" ), 0 );
217
218 glDrawElements( GL_TRIANGLES, ctx->num_indices, GL_UNSIGNED_SHORT, (void*)(0) );
219
220 //vg_info( "Verts: %u, Indices: %u\n", ctx->num_verts, ctx->num_indices );
221
222 glDisable(GL_BLEND);
223 }
224
225 // Rect controls
226 // ===========================================================================================================
227
228 static void ui_rect_copy( ui_rect src, ui_rect dst )
229 {
230 dst[0] = src[0];
231 dst[1] = src[1];
232 dst[2] = src[2];
233 dst[3] = src[3];
234 }
235
236 static void ui_rect_pad( ui_rect rect, ui_px pad )
237 {
238 rect[0] += pad;
239 rect[1] += pad;
240 rect[2] -= pad*2;
241 rect[3] -= pad*2;
242 }
243
244 static void ui_vis_rect( ui_rect rect, u32 colour )
245 {
246 #ifdef UI_DEBUG
247 v2f p0;
248 v2f p1;
249
250 p0[0] = rect[0];
251 p0[1] = rect[1];
252 p1[0] = rect[0]+rect[2];
253 p1[1] = rect[1]+rect[3];
254
255 vg_line( p0, (v2f){p1[0],p0[1]}, colour );
256 vg_line( (v2f){p1[0],p0[1]}, p1, colour );
257 vg_line( p1, (v2f){p0[0],p1[1]}, colour );
258 vg_line( (v2f){p0[0],p1[1]}, p0, colour );
259 #endif
260 }
261
262 // Stack control
263 // ===========================================================================================================
264
265 static struct ui_qnode *ui_current( ui_ctx *ctx )
266 {
267 return &ctx->stack[ ctx->stack_count-1 ];
268 }
269
270 static void ui_new_node( ui_ctx *ctx )
271 {
272 if( ctx->stack_count == vg_list_size( ctx->stack ) )
273 vg_exiterr( "[UI] Stack overflow while creating box!" );
274
275 struct ui_qnode *parent = &ctx->stack[ ctx->stack_count-1 ];
276 struct ui_qnode *node = &ctx->stack[ ctx->stack_count++ ];
277 ui_rect_copy( ctx->cursor, node->rect );
278
279 if( parent->mouse_over )
280 {
281 if( ctx->mouse[0] >= node->rect[0] && ctx->mouse[0] <= node->rect[0]+node->rect[2] &&
282 ctx->mouse[1] >= node->rect[1] && ctx->mouse[1] <= node->rect[1]+node->rect[3] )
283 node->mouse_over = 1;
284 else
285 node->mouse_over = 0;
286 }
287 else
288 {
289 node->mouse_over = 0;
290 }
291 }
292
293 static int ui_hasmouse( ui_ctx *ctx )
294 {
295 struct ui_qnode *node = ui_current( ctx );
296 return (node->mouse_over && (node->capture_id == ctx->capture_mouse_id));
297 }
298
299 static void ui_end( ui_ctx *ctx )
300 {
301 struct ui_qnode *node = &ctx->stack[ --ctx->stack_count ];
302
303 ui_rect_copy( node->rect, ctx->cursor );
304 ui_vis_rect( ctx->cursor,
305 (node->mouse_over && (node->capture_id == ctx->capture_mouse_id))? 0xffff0000: 0xff0000ff );
306 }
307
308 static void ui_end_down( ui_ctx *ctx )
309 {
310 ui_px height = ui_current( ctx )->rect[3];
311 ui_end( ctx );
312 ctx->cursor[1] += height;
313 }
314
315 static void ui_end_right( ui_ctx *ctx )
316 {
317 ui_px width = ui_current( ctx )->rect[2];
318 ui_end( ctx );
319 ctx->cursor[0] += width;
320 }
321
322 static void ui_fill_y( ui_ctx *ctx )
323 {
324 struct ui_qnode *node = ui_current( ctx );
325 ctx->cursor[3] = node->rect[3] - (ctx->cursor[1]-node->rect[1]);
326 }
327
328 static void ui_fill_x( ui_ctx *ctx )
329 {
330 struct ui_qnode *node = ui_current( ctx );
331 ctx->cursor[2] = node->rect[2] - (ctx->cursor[0]-node->rect[0]);
332 }
333
334 // Alignment: | [] | -> | []|
335 static void ui_align_bottom( ui_ctx *ctx )
336 {
337 struct ui_qnode *node = ui_current( ctx );
338 ctx->cursor[1] = node->rect[1] + node->rect[3] - ctx->cursor[3];
339 }
340
341 static void ui_align_right( ui_ctx *ctx )
342 {
343 struct ui_qnode *node = ui_current( ctx );
344 ctx->cursor[0] = node->rect[0] + node->rect[2] - ctx->cursor[2];
345 }
346
347 static void ui_align_top( ui_ctx *ctx )
348 {
349 ctx->cursor[1] = ui_current( ctx )->rect[1];
350 }
351
352 static void ui_align_left( ui_ctx *ctx )
353 {
354 ctx->cursor[0] = ui_current( ctx )->rect[0];
355 }
356
357 static void ui_clamp_rect( ui_rect parent, ui_rect dest )
358 {
359 dest[0] = vg_min( parent[0] + parent[2] - dest[2], dest[0] );
360 dest[1] = vg_min( parent[1] + parent[3] - dest[3], dest[1] );
361 dest[0] = vg_max( parent[0], dest[0] );
362 dest[1] = vg_max( parent[1], dest[1] );
363 }
364
365 static u32 ui_group_id( ui_ctx *ctx, u32 lesser_unique )
366 {
367 return ctx->id_base | lesser_unique;
368 }
369
370 static void ui_capture_mouse( ui_ctx *ctx, u32 id )
371 {
372 u32 group_uid = ui_group_id(ctx,id);
373
374 struct ui_qnode *node = &ctx->stack[ ctx->stack_count-1 ];
375 node->capture_id = group_uid;
376
377 if( !ctx->capture_lock && node->mouse_over )
378 {
379 ctx->capture_mouse_id = group_uid;
380 }
381 }
382
383 // Drawing
384 // ===========================================================================================================
385
386 static struct ui_vert *ui_fill_rect_uv( ui_ctx *ctx, ui_rect rect, u32 colour, ui_px uv[4] )
387 {
388 struct ui_vert *vertices = &ctx->verts[ ctx->num_verts ];
389 vertices[0].co[0] = rect[0];
390 vertices[0].co[1] = rect[1];
391 vertices[0].uv[0] = uv[0];
392 vertices[0].uv[1] = uv[1];
393 vertices[0].colour = colour;
394 vertices[1].co[0] = rect[0]+rect[2];
395 vertices[1].co[1] = rect[1];
396 vertices[1].uv[0] = uv[2];
397 vertices[1].uv[1] = uv[1];
398 vertices[1].colour = colour;
399 vertices[2].co[0] = rect[0]+rect[2];
400 vertices[2].co[1] = rect[1]+rect[3];
401 vertices[2].uv[0] = uv[2];
402 vertices[2].uv[1] = uv[3];
403 vertices[2].colour = colour;
404 vertices[3].co[0] = rect[0];
405 vertices[3].co[1] = rect[1]+rect[3];
406 vertices[3].uv[0] = uv[0];
407 vertices[3].uv[1] = uv[3];
408 vertices[3].colour = colour;
409 u16 ind_start = ctx->num_verts;
410 u16 *indices = &ctx->indices[ ctx->num_indices ];
411
412 indices[0] = ind_start+0;
413 indices[1] = ind_start+2;
414 indices[2] = ind_start+1;
415
416 indices[3] = ind_start+0;
417 indices[4] = ind_start+3;
418 indices[5] = ind_start+2;
419
420 ctx->num_indices += 6;
421 ctx->num_verts += 4;
422
423 return vertices;
424 }
425
426 static struct ui_vert *ui_fill_rect( ui_ctx *ctx, ui_rect rect, u32 colour )
427 {
428 return ui_fill_rect_uv( ctx, rect, colour, (ui_px[4]){ 66, 66, 66, 66 } );
429 }
430
431 static void ui_text( ui_ctx *ctx, const char *str, ui_px scale, int alignment )
432 {
433 ui_rect text_cursor;
434
435 text_cursor[0] = ctx->cursor[0];
436 text_cursor[1] = ctx->cursor[1];
437 text_cursor[2] = 7*scale;
438 text_cursor[3] = 7*scale;
439
440 u32 current_colour = 0xffffffff;
441
442 const char *_c = str;
443 char c;
444 while( (c = *(_c ++)) )
445 {
446 if( c == '\n' )
447 {
448 text_cursor[1] += 10*scale;
449 text_cursor[0] = ctx->cursor[0];
450 continue;
451 }
452 else if( c >= 33 && c <= 126 )
453 {
454 u8 glyph_base[2];
455 u8 glyph_index = c - 32;
456 glyph_base[0] = glyph_index%10;
457 glyph_base[1] = (glyph_index-glyph_base[0])/10;
458
459 glyph_base[0] *= 7;
460 glyph_base[1] *= 7;
461
462 ui_fill_rect_uv( ctx, text_cursor, current_colour, (ui_px[4]){glyph_base[0],glyph_base[1],glyph_base[0]+7,glyph_base[1]+7} );
463 }
464 else if( c == '\x1B' )
465 {
466 _c ++;
467 u16 colour_id = 0;
468 for( int i = 0; i < 3; i ++ )
469 {
470 if( _c[i] )
471 {
472 if( _c[i] == 'm' )
473 {
474 _c = _c + i + 1;
475
476 switch( colour_id )
477 {
478 case '0': current_colour = 0xffffffff; break;
479 case '3'|'1'<<8: current_colour = 0xff201fee; break;
480 case '3'|'2'<<8: current_colour = 0xff37e420; break;
481 case '3'|'3'<<8: current_colour = 0xff0ed8e2; break;
482 case '3'|'4'<<8: current_colour = 0xfff15010; break;
483 case '3'|'5'<<8: current_colour = 0xffee20ee; break;
484 case '3'|'6'<<8: current_colour = 0xffeeee20; break;
485 case '3'|'7'<<8: current_colour = 0xffffffff; break;
486 }
487
488 break;
489 }
490
491 colour_id |= _c[i] << (i*8);
492 }
493 else
494 {
495 _c = _c +i;
496 break;
497 }
498 }
499 }
500
501 text_cursor[0] += 6*scale;
502 }
503 }
504
505 // API control
506 // ====================================================================
507
508 static void ui_begin( ui_ctx *ctx, ui_px res_x, ui_px res_y )
509 {
510 ctx->cursor[0] = 0;
511 ctx->cursor[1] = 0;
512 ctx->cursor[2] = res_x;
513 ctx->cursor[3] = res_y;
514
515 ui_rect_copy( ctx->cursor, ctx->stack[0].rect );
516 ctx->stack[0].mouse_over = 1;
517
518 ctx->stack_count = 1;
519
520 ctx->num_verts = 0;
521 ctx->num_indices = 0;
522 }
523
524 static void ui_resolve( ui_ctx *ctx )
525 {
526 if( ctx->stack_count-1 )
527 vg_exiterr( "[UI] Mismatched node create/drestroy!" );
528
529 if( ctx->click_state == 3 || ctx->click_state == 0 )
530 {
531 ctx->capture_lock = 0;
532 }
533 }
534
535 // User Input piping
536 // ====================================================================
537
538 static void ui_set_mouse( ui_ctx *ctx, int x, int y, int click_state )
539 {
540 ctx->mouse[0] = x;
541 ctx->mouse[1] = y;
542
543 ctx->click_state = click_state;
544 }
545
546 // High level controls
547 // ====================================================================
548
549 struct ui_window
550 {
551 const char *title;
552 ui_rect transform;
553
554 int drag;
555 ui_px drag_offset[2];
556 };
557
558 static int ui_button( ui_ctx *ctx, u32 id )
559 {
560 ui_new_node( ctx );
561 {
562 ui_capture_mouse( ctx, id );
563
564 if( ui_hasmouse(ctx) )
565 {
566 ui_fill_rect( ctx, ctx->cursor, 0xffcccccc );
567
568 if( ctx->click_state == 1 )
569 ctx->capture_lock = 1;
570 else if( ctx->capture_lock && ctx->click_state == 3 )
571 {
572 return 1;
573 }
574 }
575 else
576 ui_fill_rect( ctx, ctx->cursor, 0xff999999 );
577 }
578
579 return 0;
580 }
581
582 static int ui_window( ui_ctx *ctx, struct ui_window *window, u32 control_group )
583 {
584 ctx->id_base = control_group << 16;
585
586 if( window->drag )
587 {
588 window->transform[0] = ctx->mouse[0]+window->drag_offset[0];
589 window->transform[1] = ctx->mouse[1]+window->drag_offset[1];
590
591 ui_clamp_rect( ctx->stack[0].rect, window->transform );
592
593 if( ctx->click_state == 0 || ctx->click_state == 3 )
594 {
595 window->drag = 0;
596 }
597 }
598
599 ui_rect_copy( window->transform, ctx->cursor );
600
601 ui_new_node( ctx );
602 {
603 ui_capture_mouse( ctx, __COUNTER__ );
604
605 //ui_fill_rect( ctx, ctx->cursor, 0xff333333 );
606
607 // Drag bar
608 ctx->cursor[3] = 25;
609 ui_new_node( ctx );
610 {
611 ui_capture_mouse( ctx, __COUNTER__ );
612
613 struct ui_vert *drag_bar = ui_fill_rect( ctx, ctx->cursor, 0xff555555 );
614
615 // title..
616 ctx->cursor[0] += 2;
617 ctx->cursor[1] += 2;
618 ui_text( ctx, window->title, 2, 0 );
619
620 // Close button
621 ctx->cursor[3] = 25;
622 ctx->cursor[2] = 25;
623 ui_align_right( ctx );
624 ui_align_top( ctx );
625 ui_rect_pad( ctx->cursor, 4 );
626
627 if( ui_button( ctx, __COUNTER__ ) )
628 {
629 vg_info( "Click clacked\n" );
630 }
631 ctx->cursor[0] += 2;
632 ui_text( ctx, "x", 2, 0 );
633 ui_end( ctx );
634
635 if( ui_hasmouse( ctx ) )
636 {
637 drag_bar[0].colour = 0xff777777;
638 drag_bar[1].colour = 0xff777777;
639 drag_bar[2].colour = 0xff777777;
640 drag_bar[3].colour = 0xff777777;
641
642 // start drag
643 if( ctx->click_state == 1 )
644 {
645 window->drag = 1;
646 window->drag_offset[0] = window->transform[0]-ctx->mouse[0];
647 window->drag_offset[1] = window->transform[1]-ctx->mouse[1];
648 }
649 }
650 }
651 ui_end_down( ctx );
652 }
653
654 return 1;
655 }
656
657 static void ui_test(void)
658 {
659 /*
660 +------------------------------------------------------+
661 | Central Market [x]|
662 +------+--------------+-+------------------------------+
663 | Buy | Balance |#| [filters] [favorites] |
664 | <>_ | () 2,356 |#|----------------------------+-+
665 |------|--------------|#| [] potion of madness 4 |#|
666 | Sell | \ Main sword |#|----------------------------|#|
667 | _*^ |--------------|#| [] Balance of time 23 | |
668 |------| * Side arm |#|----------------------------| |
669 | 235 |--------------| | [] Strength 5,300 | |
670 | | () Sheild | |----------------------------| |
671 | |--------------| | [] Bewilder 2,126 | |
672 | [ & Spells ] |----------------------------| |
673 | |--------------| | [] Eternal flames 6 | |
674 +------+--------------+-+----------------------------+-+
675 */
676
677 ui_begin( &ui_global_ctx, vg_window_x, vg_window_y );
678
679 // TODO: Find a more elegent form for this
680 int mouse_state = 0;
681 if( vg_get_button( "primary" ) ) mouse_state = 2;
682 if( vg_get_button_down( "primary" ) ) mouse_state = 1;
683 if( vg_get_button_up( "primary" ) ) mouse_state = 3;
684
685 ui_set_mouse( &ui_global_ctx, vg_mouse[0], vg_mouse[1], mouse_state );
686
687 /*
688 static struct ui_window window =
689 {
690 .transform = { 20, 20, 500, 350 },
691 .title = "Central Market"
692 };
693
694 if( ui_window( &ui_global_ctx, &window, __COUNTER__ ) )
695 {
696 // Contents
697 //ui_text( &ui_global_ctx, "A slice of heaven. O for awesome, this chocka \nfull cuzzie is as rip-off as a cracker.\nMeanwhile, in behind the bicycle shed, Hercules Morse,\nas big as a horse and Mrs Falani were up to no \ngood with a bunch of crook pikelets. Meanwhile, \nat the black singlet woolshed party, not even au,\nsort your drinking out.", 1, 0 );
698 ui_global_ctx.cursor[2] = 75;
699 ui_fill_y( &ui_global_ctx );
700
701 ui_new_node( &ui_global_ctx );
702 {
703 ui_global_ctx.cursor[3] = 75;
704
705 if( ui_button( &ui_global_ctx, __COUNTER__ ) )
706 vg_info( "Buy\n" );
707 {
708 ui_rect_pad( ui_global_ctx.cursor, 4 );
709 ui_text( &ui_global_ctx, "Buy", 2, 0 );
710 }
711 ui_end_down( &ui_global_ctx );
712
713 if( ui_button( &ui_global_ctx, __COUNTER__ ) )
714 vg_info( "Sell\n" );
715 {
716 ui_rect_pad( ui_global_ctx.cursor, 4 );
717 ui_text( &ui_global_ctx, "Sell", 2, 0 );
718 }
719 ui_end_down( &ui_global_ctx );
720 }
721 ui_end_right( &ui_global_ctx );
722
723 ui_global_ctx.cursor[2] = 200;
724 ui_new_node( &ui_global_ctx );
725 {
726
727 }
728 ui_end_right( &ui_global_ctx );
729 }
730 ui_end( &ui_global_ctx );
731 */
732
733 ui_rect rbf;
734 ui_rect_copy( ui_global_ctx.cursor, rbf );
735
736 ui_global_ctx.cursor[0] = 6;
737 ui_global_ctx.cursor[3] = 21;
738 ui_fill_x( &ui_global_ctx );
739 ui_align_bottom( &ui_global_ctx );
740 ui_text( &ui_global_ctx, "Marble computer build 2 -- development version -- (C) Harry Godden 2021\nAknowledgements: 'credits' in console (`)", 1, 0 );
741
742 ui_resolve( &ui_global_ctx );
743
744 m3x3f view = M3X3_IDENTITY;
745 m3x3_translate( view, (v3f){ -1.0f, 1.0f, 0.0f } );
746 m3x3_scale( view, (v3f){ 1.0f/((float)vg_window_x*0.5f), -1.0f/((float)vg_window_y*0.5f), 1.0f } );
747 //vg_lines_drawall( (float*)view );
748
749 ui_draw( &ui_global_ctx );
750
751 ui_rect_copy( rbf, ui_global_ctx.cursor );
752 }