diff options
Diffstat (limited to 'Fuse/demos')
| -rw-r--r-- | Fuse/demos/fuse.slang | 31 | ||||
| -rw-r--r-- | Fuse/demos/fuse_demo.c | 280 |
2 files changed, 311 insertions, 0 deletions
diff --git a/Fuse/demos/fuse.slang b/Fuse/demos/fuse.slang new file mode 100644 index 0000000..837a3dc --- /dev/null +++ b/Fuse/demos/fuse.slang @@ -0,0 +1,31 @@ +struct VertexInput { + [[vk::location(0)]] float2 pos : POSITION; + [[vk::location(1)]] float4 col : COLOR; +}; + +struct VertexOutput { + float4 col : COLOR; + float4 pos : SV_Position; +}; + +struct UBO { + float2 viewport; +}; + +[[vk::binding(0, 0)]] +ConstantBuffer<UBO> ubo; + +[shader("vertex")] +VertexOutput vertMain(VertexInput input) +{ + VertexOutput output; + output.col = input.col; + output.pos = float4(input.pos*2.0/ubo.viewport - 1.0, 0.0, 1.0); + return output; +} + +[shader("fragment")] +float4 fragMain(VertexOutput input) : SV_Target +{ + return input.col; +} diff --git a/Fuse/demos/fuse_demo.c b/Fuse/demos/fuse_demo.c new file mode 100644 index 0000000..60128bd --- /dev/null +++ b/Fuse/demos/fuse_demo.c @@ -0,0 +1,280 @@ +#include "rend.h" +#include "rend.c" +#include "fuse.h" +#include "fuse.c" +#include <stddef.h> +#include <stdio.h> + +/* has to be included last because rend will ask for certain modules */ +#define PODIUM_IMPLEMENTATION +#include "podium.h" + +typedef struct { float x, y; } FuseVec2; +typedef struct { float x, y, z, w; } FuseVec4; + +#pragma pack(push, 1) +typedef struct { + FuseVec2 pos; + FuseVec4 color; +} FuseVertex; +#pragma pack(pop) + +static FuseVertex fuse_renderer_data[1024]; +static size_t fuse_renderer_idx = 0; + +struct data_t { float offset_x; float padding = 0 }; +struct data_t button_data = { .offset_x = 0, .padding = 0}; + +void stretch_button_op(void *data) { + struct data_t* ptr = (struct data_t*) data; + data->offset_x += 10; + data->padding += 10; +} + + +static inline FuseVec4 +fuse__unpack_color(uint32_t c) +{ + FuseVec4 v; + v.x = (float) ((c >> 24) & 0xFF) / 255.0f; // Red + v.y = (float) ((c >> 16) & 0xFF) / 255.0f; // Green + v.z = (float) ((c >> 8) & 0xFF) / 255.0f; // Blue + v.w = (float) ( c & 0xFF) / 255.0f; // Alpha + return v; +} + +void fuse_handler(FuseCanvas canvas, FuseCmd *cmd, void *data) { + switch (cmd->type) { + case FUSE_CMD_RECT: + FuseRect rect = cmd->rect; + FuseVec4 color = fuse__unpack_color(rect.color); + FuseVertex c0 = { + .pos = { rect.x, rect.y }, + .color = color + }; + + FuseVertex c1 = { + .pos = { rect.x + rect.w, rect.y }, + .color = color + }; + + FuseVertex c2 = { + .pos = { rect.x + rect.w, rect.y + rect.h }, + .color = color + }; + + FuseVertex c3 = { + .pos = { rect.x, rect.y + rect.h }, + .color = color + }; + + fuse_renderer_data[fuse_renderer_idx++] = c0; + fuse_renderer_data[fuse_renderer_idx++] = c1; + fuse_renderer_data[fuse_renderer_idx++] = c2; + + fuse_renderer_data[fuse_renderer_idx++] = c2; + fuse_renderer_data[fuse_renderer_idx++] = c3; + fuse_renderer_data[fuse_renderer_idx++] = c0; + break; + } +} + +#define SCREEN_WIDTH 800 +#define SCREEN_HEIGHT 600 + +int main() { + + P_Window window; + if (!p_window_open(&window, 800, 600, "fuse_demo")) { + PFATAL("Failed to open window!"); + return 1; + } + + if (!rend_init(REND_BACKEND_AUTO)) { + PFATAL("Failed to initialize backend!"); + return 1; + } + + RendRenderer renderer = rend_renderer_create(&window, true); + RendShader vert = rend_shader_from_spv_path(REND_SHADER_VERTEX, "fuse.vert.spv"); + RendShader frag = rend_shader_from_spv_path(REND_SHADER_FRAG, "fuse.frag.spv"); + + RendPipelineConfig ui_cfg = rend_pipeline_config_create( + REND_TOPOLOGY_TRIANGLE_LIST, + REND_POLYGON_MODE_FILL, + REND_CULL_MODE_BACK); + rend_pipeline_config_depth_test(ui_cfg, false); + + /* configure vertex input */ + int b0 = rend_pipeline_config_vertex_binding_add(ui_cfg, sizeof (FuseVertex), REND_INPUT_RATE_VERTEX); + rend_pipeline_config_vertex_attribute_add(ui_cfg, b0, 0, REND_FORMAT_R32G32_SFLOAT, offsetof(FuseVertex, pos)); + rend_pipeline_config_vertex_attribute_add(ui_cfg, b0, 1, REND_FORMAT_R32G32B32A32_SFLOAT, offsetof(FuseVertex, color)); + rend_pipeline_config_resource_binding_add(ui_cfg, 0, 0, REND_BUFFER_UNIFORM, REND_SHADER_VERTEX, 1); + + /* add the shaders */ + rend_pipeline_config_shader_add(ui_cfg, vert); + rend_pipeline_config_shader_add(ui_cfg, frag); + + RendPipeline ui_pipeline = rend_pipeline_create(renderer, ui_cfg); + + RendResourceSet ui_resources = rend_resource_set_create(renderer, ui_pipeline, 0); + + FuseCanvas canvas = fuse_canvas_create(1024, NULL); + + u64 frame_t = NANOS_PER_SEC / 60; + + bool running = true; + P_Event ev; + float pev = 0, px = 0, py = 0; + + float nob = 0.3; + + float target_screen[2] = { SCREEN_WIDTH, SCREEN_HEIGHT }; + rend_resource_set_write_buffer(ui_resources, 0, REND_BUFFER_UNIFORM, target_screen, 2 * sizeof *target_screen, 0); + + float real_screen_width = 0; + float real_screen_heigth = 0; + + enum UI_State { + UI_START_MENU, + UI_OPTIONS, + }; + + int ui_state = UI_START_MENU; + + while (running) { + + u64 start = p_get_time(); + + pev = 0; + /* event loop */ + while (p_window_poll_event(&window, &ev)) { + if (ev.type == P_EVENT_WINDOW_CLOSE) { + running = false; + break; + } + + switch (ev.type) { + case P_EVENT_WINDOW_RESIZE: + real_screen_width = ev.resize.width; + real_screen_heigth = ev.resize.height; + break; + case P_EVENT_POINTER: + px = ev.pointer.x; + py = ev.pointer.y; + switch (ev.pointer.state) { + case P_POINTER_PRESSED: + if (ev.pointer.button == 1 || ev.pointer.button == 0) + pev = FUSE_POINTER_PRESSED; + break; + case P_POINTER_RELEASED: + if (ev.pointer.button == 1 || ev.pointer.button == 0) + pev = FUSE_POINTER_RELEASED; + break; + default: + case P_POINTER_MOVED: + break; + } + + fuse_canvas_pointer(pev, px * SCREEN_WIDTH / real_screen_width, py * SCREEN_HEIGHT / real_screen_heigth); + break; + } + } + + /* Clears the Screen */ + fuse_canvas_clear(canvas, 0x000000); + + /* Inside a div, children no longer have fixed positions, + * instead x, y represent an offset so that they can still be animated! + * Width and height represent min width and min height instead! */ + if (ui_state == UI_START_MENU) { + // NOTE: brackets for legibility only + FUSE_LAYOUT_DIRECTION(FUSE_DIRECTION_COLUMN); + fuse_div_begin(0, 0, SCREEN_WIDTH / 4, SCREEN_HEIGHT, 0xFFFFFFaa); + { + + fuse_hovered(stretch_button_op, data); + + if (fuse_button_text("Start New Game", button_data.offset_x, 0, 100, 0, 0xFF0000FF, 0x000000FF)) { + printf("start new game"); + } + + + if (fuse_button_text("Options", 0, 0, 100, 0, 0xFF0000FF, 0x000000FF)) { + ui_state = UI_OPTIONS; + } + + + if (fuse_button_text("Credits", 0, 0, 100, 0, 0xFF0000FF, 0x000000FF)) { + printf("awesome credits"); + } + + if (fuse_button_text("Quit Game")) { + running = false; + break; + } + + fuse_hovered_clear(); + + } + fuse_div_end(); + + /* back to global layouting */ + fuse_3d_object(); + fuse_3d_point_at(); + + + } else if (ui_state == UI_OPTIONS) { + + /* Inside a flex the same x,y as offsets and width and height as minimums rules apply + * The difference is that a flex is flexible, by default it does not have a fixed size + * but you may specify minimums and maximus for it to work around. + */ + + FUSE( + .max_width = 300, + .max_height = 600, + .direction = FUSE_DIRECTION_COLUMN, + .gap = 32 + ); + + fuse_flex_begin(0, 0, SCREEN_WIDTH / 4, SCREEN_HEIGHT, 0xFFFFFFaa); + { + if (fuse_checkbox_text("VSYNC", &vsync)) { + vsync = ~vsync; + } + } + } + + fuse_slider(100, 200, 300, 600, 0xFFFF00FF, 0xFF0000FF, &nob); + + fuse_canvas_draw(canvas, fuse_handler, NULL); + + /* call renderer */ + if (rend_renderer_frame_begin(renderer)) { + rend_pipeline_bind(ui_pipeline); + rend_resource_set_bind(ui_pipeline, 0, ui_resources); + + rend_pipeline_push_data(ui_pipeline, fuse_renderer_data, fuse_renderer_idx, sizeof *fuse_renderer_data); + rend_pipeline_draw(ui_pipeline); + + rend_renderer_frame_end(renderer, NULL); + } + + fuse_renderer_idx = 0; + + u64 elapsed = p_get_time() - start; + + /* the renderer should already be forcing vsync */ + if (elapsed < frame_t) + p_sleep_ns(frame_t - elapsed); + } + + + fuse_canvas_destroy(canvas); + + rend_quit(); + + p_window_close(&window); + return 0; +} |
