1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
|
#ifndef _FUSE_C_
#define _FUSE_C_
/* __________________________________________________________________________
* | CmdType | CmdRect | CmdType | CmdRectBorder | ...
* --------------------------------------------------------------------------
*/
#include "fuse.h"
#include "fuse_internal.h"
#include "fuse_backend.h"
#include "fuse_tween.c"
#include "allocators.c"
#include <stdint.h>
#include <string.h>
#define FUSE_MIN(a, b) ((a < b) ? a : b)
#define FUSE_MAX(a, b) ((a > b) ? a : b)
#define FUSE_LIMIT(n, a, b) (FUSE_MAX(a, FUSE_MIN(b, n)))
#define FUSE_IS_HOVERED(x, y, w, h) (\
f__canvas->pointer_x >= x && f__canvas->pointer_x <= x + w &&\
f__canvas->pointer_y >= y && f__canvas->pointer_y <= y + h)
static inline size_t fuse__element(); // "base class" of all UI widgets
static inline void fuse__cmdbuffer_push(FuseCmd cmd);
static void fuse__cmdbuffer_print();
static const char* fuse__cmd_name(uint8_t type);
extern FuseCanvas
fuse_canvas_create(size_t memory_limit, FuseStyle base_style)
{
(void) base_style;
FuseCanvas new = malloc(sizeof *new);
memset(new, 0, sizeof *new);
new->memory = malloc(memory_limit);
al_arena_create(&new->arena, new->memory, memory_limit);
size_t cmdbuffer_mem = (memory_limit * 8) / 10;
cmdbuffer_mem -= (cmdbuffer_mem % sizeof *new->cmdbuffer_ptr); // remove remainder
FuseCmd *cmdbuffer_ptr = al_arena_alloc(&new->arena, cmdbuffer_mem);
new->cmdbuffer_ptr = cmdbuffer_ptr;
new->cmdbuffer_size = cmdbuffer_mem / sizeof (*cmdbuffer_ptr);
new->cmdbuffer_head = 0;
size_t element_data_mem = memory_limit - cmdbuffer_mem;
void *element_data_ptr = al_arena_alloc(&new->arena, element_data_mem);
al_arena_create(&new->element_data_arena, element_data_ptr, element_data_mem);
fuse_canvas_set(new);
return new;
}
extern void
fuse_canvas_set(FuseCanvas canvas)
{
f__canvas = canvas;
}
extern void
fuse_canvas_debug(FuseCanvas canvas, bool debug)
{
canvas->debug = debug;
}
extern void
fuse_canvas_clear(FuseCanvas canvas)
{
canvas->cmdbuffer_head = 0;
canvas->current_id = 0;
canvas->current_frame++;
}
extern void
fuse_canvas_draw(FuseCanvas canvas, FuseRendererCallback callback, void* data)
{
for (size_t u = 0; u < f__canvas->cmdbuffer_head; u++) {
FuseCmd cmd = f__canvas->cmdbuffer_ptr[u];
assert(cmd.type < FUSE_CMD_COUNT && "[FUSE] WARN: INVALID TYPE IN COMMAND BUFFER");
callback(canvas, &cmd, data);
}
}
extern void
fuse_canvas_resize(FuseCanvas canvas, float w, float h)
{
canvas->width = w;
canvas->height = h;
}
extern void
fuse_canvas_pointer(FuseCanvas canvas, int pointer_state, float x, float y)
{
canvas->pointer_state = pointer_state;
canvas->pointer_x = x;
canvas->pointer_y = y;
#ifdef FUSE_DEBUG
const char *pstate[] = {
[FUSE_POINTER_NONE] = "NONE",
[FUSE_POINTER_PRESSED] = "PRESSED",
[FUSE_POINTER_RELEASED] = "RELEASED",
[FUSE_POINTER_ALT] = "ALT"
};
printf("[DEBUG] [FUSE] px=%f py=%f ps=%s\n", canvas->pointer_x, canvas->pointer_y, pstate[pointer_state]);
#endif
}
extern void
fuse_canvas_destroy(FuseCanvas canvas)
{
free(canvas->memory);
free(canvas);
}
extern bool
fuse_button(float x, float y, float width, float height, uint32_t selected, uint32_t hovered)
{
size_t id = fuse__element();
bool clicked = false;
bool hot = FUSE_IS_HOVERED(x, y, width, height);
if (hot) f__canvas->hot = id;
/* are we the active component? */
if (f__canvas->active == id) {
if (f__canvas->pointer_state == FUSE_POINTER_RELEASED) {
if (hot) clicked = true;
f__canvas->active = 0;
}
} else if (hot && f__canvas->pointer_state == FUSE_POINTER_PRESSED) {
f__canvas->active = id;
}
FuseCmd cmd = {
.type = FUSE_CMD_RECT,
.rect = {
.color = (hot) ? hovered : selected,
.x = x,
.y = y,
.w = width,
.h = height,
}
};
fuse__cmdbuffer_push(cmd);
return clicked;
}
extern void
fuse_slider(float x, float y, float width, float height, uint32_t slider, uint32_t nob, float *nob_pos)
{
size_t id = fuse__element();
/* are we the hot component? */
bool hot = FUSE_IS_HOVERED(x, y, width, height);
if (hot) f__canvas->hot = id;
bool is_vert = (width < height);
float nob_width = is_vert ? width : height;
float nob_height = is_vert ? width : height;
float track_len = is_vert ? (height - nob_height) : (width - nob_width);
float p_off = is_vert ? (f__canvas->pointer_y - (y + nob_height * 0.5f)) : (f__canvas->pointer_x - (x + nob_width * 0.5f));
float val = (track_len > 0.0f) ? (p_off / track_len) : 0.0f;
/* calculate nob_pos from pointer */
if (f__canvas->active == id) {
if (f__canvas->pointer_state == FUSE_POINTER_RELEASED) {
if (hot) { /* clicked */ }
f__canvas->active = 0;
}
*nob_pos = FUSE_MAX(0.0f, FUSE_MIN(1.0f, val));
} else if (hot && f__canvas->pointer_state == FUSE_POINTER_PRESSED) {
f__canvas->active = id;
*nob_pos = FUSE_MAX(0.0f, FUSE_MIN(1.0f, val));
}
/* clamp nob_pos */
*nob_pos = FUSE_LIMIT(*nob_pos, 0.0f, 1.0f);
float nob_x = is_vert ? 0.0f : (*nob_pos * (width - nob_width));
float nob_y = is_vert ? (*nob_pos * (height - nob_height)) : 0.0f;
FuseCmd cmd = {
.type = FUSE_CMD_RECT,
.rect = {
.color = slider,
.x = x,
.y = y,
.w = width,
.h = height,
}
};
FuseCmd nob_rect = {
.type = FUSE_CMD_RECT,
.rect = {
.color = nob,
.x = x + nob_x,
.y = y + nob_y,
.w = nob_width,
.h = nob_height,
}
};
fuse__cmdbuffer_push(cmd);
fuse__cmdbuffer_push(nob_rect);
}
extern int
fuse_tooltip(const char *text)
{
FUSE_TODO;
/* NOTE(vasco): this is supposed to add a tooltip when the last element was hovered...
* will probably need to grab the last element's box?
* I mean i need to know it's bounds and add an element that
* shows up after being hovered over a few frames
* so we will need to retain some data via the hashmap
*
* that's the plan for now
*/
(void) text;
}
static inline size_t
fuse__element()
{
// we increment first because 0 is used for when no element is
// selected
size_t id = ++f__canvas->current_id;
return id;
}
static inline void
fuse__cmdbuffer_push(FuseCmd cmd)
{
if (f__canvas->cmdbuffer_head < f__canvas->cmdbuffer_size)
f__canvas->cmdbuffer_ptr[f__canvas->cmdbuffer_head++] = cmd;
}
static void
fuse__cmdbuffer_print()
{
for (size_t u = 0; u < f__canvas->cmdbuffer_head; u++) {
FuseCmd cmd = f__canvas->cmdbuffer_ptr[u];
assert(cmd.type < FUSE_CMD_COUNT && "[FUSE] WARN: INVALID TYPE IN COMMAND BUFFER");
printf("CMD: %s - ", fuse__cmd_name(cmd.type));
switch (cmd.type) {
case FUSE_CMD_RECT:
printf("x=%f y=%f w=%f h=%f col=%x", cmd.rect.x, cmd.rect.y, cmd.rect.w, cmd.rect.h, cmd.rect.color);
break;
}
printf("\n");
}
}
static const char*
fuse__cmd_name(uint8_t type)
{
assert(type < FUSE_CMD_COUNT);
return fuse_cmd_name[type];
}
extern bool
fuse_button_text(const char *text, float x, float y, float width, float height, uint32_t selected, uint32_t hovered)
{
(void) text; (void) x; (void) y; (void) width; (void) height; (void) selected; (void) hovered;
FUSE_TODO;
return false;
}
extern bool
fuse_checkbox_text(const char *text, bool *value)
{
(void) text; (void) value;
FUSE_TODO;
return false;
}
extern bool
fuse_element_is_hovered(const char *text)
{
(void) text;
FUSE_TODO;
return false;
}
extern void
fuse_hovered(void (*op)(void*), void *data)
{
(void) op; (void) data;
FUSE_TODO;
}
extern void
fuse_hovered_clear()
{
FUSE_TODO;
}
extern void
fuse_rotate_rad()
{
FUSE_TODO;
}
extern void
fuse_rotate_deg()
{
FUSE_TODO;
}
extern void
fuse_layout(FuseLayoutInfo info)
{
(void) info;
FUSE_TODO;
}
extern void
fuse_div_begin(float x, float y, float width, float height, uint32_t color)
{
(void) x; (void) y; (void) width; (void) height; (void) color;
FUSE_TODO;
}
extern void
fuse_div_end()
{
FUSE_TODO;
}
extern void
fuse_flex_begin(float x, float y, float width, float height, uint32_t color)
{
(void) x; (void) y; (void) width; (void) height; (void) color;
FUSE_TODO;
}
extern void
fuse_flex_end()
{
FUSE_TODO;
}
extern FuseStyle
fuse_style_save(const char *path)
{
(void) path;
FUSE_TODO;
return NULL;
}
extern void
fuse_style_set(FuseStyle style)
{
(void) style;
FUSE_TODO;
}
extern void
fuse_style_load(const char *path)
{
(void) path;
FUSE_TODO;
}
extern void
fuse_window_begin(char *name, float width, float height, uint32_t border_color, uint32_t border_width)
{
(void) name; (void) width; (void) height; (void) border_color; (void) border_width;
FUSE_TODO;
}
extern void
fuse_window_end()
{
FUSE_TODO;
}
extern void
fuse_grid_begin(uint32_t cols, uint32_t rows, const float *col_ratios, const float *row_ratios)
{
(void) cols; (void) rows; (void) col_ratios; (void) row_ratios;
FUSE_TODO;
}
extern void fuse_grid_next_row() { FUSE_TODO; }
extern void fuse_grid_next_col() { FUSE_TODO; }
extern void fuse_grid_prev_row() { FUSE_TODO; }
extern void fuse_grid_prev_col() { FUSE_TODO; }
extern void fuse_grid_next() { FUSE_TODO; }
extern void fuse_grid_prev() { FUSE_TODO; }
extern void
fuse_grid_goto(uint32_t col, uint32_t row)
{
(void) col; (void) row;
FUSE_TODO;
}
extern void fuse_grid_end() { FUSE_TODO; }
extern void fuse_3d_object() { FUSE_TODO; }
extern void fuse_3d_point_at() { FUSE_TODO; }
extern int
fuse_animate_i(FuseAnimation anim, int i1, int i2)
{
(void) anim; (void) i1; (void) i2;
FUSE_TODO;
return 0;
}
extern float
fuse_animate_f(FuseAnimation anim, float f1, float f2, float f, bool loop)
{
(void) anim; (void) f1; (void) f2; (void) f; (void) loop;
FUSE_TODO;
return 0.0f;
}
#endif // _FUSE_C_
|