Mercurial
diff infinite_canvas/main.c @ 276:b55c22cff335
Add interactive infinite canvas prototype
| author | MrJuneJune <me@mrjunejune.com> |
|---|---|
| date | Mon, 17 Aug 2026 16:57:56 -0700 |
| parents | |
| children | 8d560f50ed4c |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/infinite_canvas/main.c Mon Aug 17 16:57:56 2026 -0700 @@ -0,0 +1,184 @@ +#include "infinite_canvas/canvas.h" +#include "infinite_canvas/web_surface.h" + +#if defined(INFINITE_CANVAS_DEV_UI) +#include "infinite_canvas/dev_ui.h" +#endif + +#if defined(PLATFORM_WEB) +#include <emscripten/emscripten.h> +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +typedef struct { + Dowa_Arena *p_arena; + Canvas_Camera camera; + Canvas_Scene scene; + Canvas_Web_Surface web_surface; + Font font; + Canvas_Theme theme; + boolean owns_font; + const char *p_screenshot_path; + uint32 frame_count; +#if defined(INFINITE_CANVAS_DEV_UI) + Canvas_Dev_UI dev_ui; +#endif +} Canvas_App; + +static Canvas_App *g_app = NULL; + +static void Canvas_App_Draw_Frame(void) +{ + int32 width = GetScreenWidth(); + int32 height = GetScreenHeight(); + Canvas_Camera_Set_Viewport(&g_app->camera, width, height); + + boolean block_pointer_input = FALSE; +#if defined(INFINITE_CANVAS_DEV_UI) + block_pointer_input = Canvas_Dev_UI_Contains_Pointer(&g_app->dev_ui); +#endif + boolean web_input = Canvas_Web_Surface_Update_Input( + &g_app->web_surface, + &g_app->camera, + &g_app->scene); + block_pointer_input = block_pointer_input || web_input; + boolean entity_input = Canvas_Scene_Update_Interaction( + &g_app->scene, + &g_app->camera, + block_pointer_input); + boolean keyboard_focus = + Canvas_Scene_Is_Text_Editing(&g_app->scene) || + Canvas_Web_Surface_Is_Focused(&g_app->web_surface); + if (!keyboard_focus && IsKeyPressed(KEY_P)) { + Canvas_Scene_Toggle_Selected_Pin(&g_app->scene, &g_app->camera); + } + Canvas_Update_Camera_Input( + &g_app->camera, + block_pointer_input || entity_input, + keyboard_focus); + Canvas_Scene_Sync_Pinned(&g_app->scene, &g_app->camera); + Canvas_Scene_Update_Notification_Stack(&g_app->scene, &g_app->camera); + + Canvas_Web_Surface_Sync(&g_app->web_surface, &g_app->camera, &g_app->scene); + + BeginDrawing(); + ClearBackground(g_app->theme.background); + Canvas_Draw_World( + &g_app->camera, + &g_app->scene, + g_app->font, + &g_app->theme); + Canvas_Web_Surface_Draw(&g_app->web_surface, &g_app->camera, &g_app->scene); +#if defined(INFINITE_CANVAS_DEV_UI) + Canvas_Dev_UI_Draw( + &g_app->dev_ui, + &g_app->camera, + &g_app->scene, + g_app->font, + &g_app->theme); +#endif + EndDrawing(); + g_app->frame_count++; +#if !defined(PLATFORM_WEB) + if (g_app->frame_count == 30) { + RestoreWindow(); + SetWindowFocused(); + } +#endif + if (g_app->p_screenshot_path && + g_app->frame_count == 180) { + TakeScreenshot(g_app->p_screenshot_path); + } +} + +int main(int argc, char **p_argv) +{ +#if !defined(PLATFORM_WEB) + int32 subprocess_result = Canvas_Web_Surface_Execute_Subprocess(argc, p_argv); + if (subprocess_result >= 0) return subprocess_result; +#else + (void)argc; + (void)p_argv; +#endif + + Dowa_Arena *p_arena = Dowa_Arena_Create(8 * ONE_MEGA_BYTE); + if (!p_arena) return 1; + + g_app = (Canvas_App *)Dowa_Arena_Allocate(p_arena, sizeof(*g_app)); + if (!g_app) { + Dowa_Arena_Free(p_arena); + return 1; + } + memset(g_app, 0, sizeof(*g_app)); + g_app->p_arena = p_arena; + g_app->p_screenshot_path = getenv("INFINITE_CANVAS_SCREENSHOT"); + Canvas_Theme_Resolve( + &g_app->theme, + Canvas_Theme_Mode_From_String(getenv("INFINITE_CANVAS_THEME"))); + + SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT); +#if defined(INFINITE_CANVAS_DEV_UI) + InitWindow(1920, 1200, "Infinite Canvas"); + SetWindowMinSize(1200, 800); +#else + InitWindow(1280, 720, "Infinite Canvas"); + SetWindowMinSize(640, 360); +#endif + SetTargetFPS(60); +#if !defined(PLATFORM_WEB) + SetWindowFocused(); +#endif + if (!Canvas_Web_Surface_Init(&g_app->web_surface, p_arena)) { + TraceLog(LOG_WARNING, "Web surface initialization failed"); + } + + g_app->font = LoadFontEx("infinite_canvas/assets/Inter-Variable.ttf", 48, NULL, 0); + g_app->owns_font = g_app->font.texture.id != 0; + if (!g_app->owns_font) g_app->font = GetFontDefault(); + else SetTextureFilter(g_app->font.texture, TEXTURE_FILTER_BILINEAR); + Canvas_Camera_Init(&g_app->camera, GetScreenWidth(), GetScreenHeight()); + Canvas_Scene_Init(&g_app->scene, p_arena); + if (getenv("INFINITE_CANVAS_BROWSER_STRESS")) { + Canvas_Scene_Add_Browser_Grid(&g_app->scene); + } else { + Canvas_Scene_Add_Demo(&g_app->scene); + } + const char *p_image_source = getenv("INFINITE_CANVAS_IMAGE_SOURCE"); + if (p_image_source) { + for (size_t index = 0; index < Dowa_Array_Length(g_app->scene.p_entities); index++) { + Canvas_Entity *p_entity = &g_app->scene.p_entities[index]; + if (p_entity->type == CANVAS_ENTITY_IMAGE) { + snprintf(p_entity->text, sizeof(p_entity->text), "%s", p_image_source); + break; + } + } + } +#if !defined(PLATFORM_WEB) + for (size_t index = 0; index < Dowa_Array_Length(g_app->scene.p_entities); index++) { + Canvas_Entity *p_entity = &g_app->scene.p_entities[index]; + if (p_entity->type == CANVAS_ENTITY_WEB_CONTENT) { + snprintf(p_entity->text, sizeof(p_entity->text), "https://www.google.com"); + break; + } + } +#endif +#if defined(INFINITE_CANVAS_DEV_UI) + Canvas_Dev_UI_Init(&g_app->dev_ui, g_app->font, &g_app->theme); +#endif + +#if defined(PLATFORM_WEB) + emscripten_set_main_loop(Canvas_App_Draw_Frame, 0, 1); +#else + while (!WindowShouldClose()) Canvas_App_Draw_Frame(); + Canvas_Web_Surface_Shutdown(&g_app->web_surface); + if (g_app->owns_font) UnloadFont(g_app->font); + Dowa_Arena_Free(p_arena); + g_app = NULL; + CloseWindow(); +#endif + + return 0; +}