Mercurial
comparison 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 |
comparison
equal
deleted
inserted
replaced
| 274:c9be578316a6 | 276:b55c22cff335 |
|---|---|
| 1 #include "infinite_canvas/canvas.h" | |
| 2 #include "infinite_canvas/web_surface.h" | |
| 3 | |
| 4 #if defined(INFINITE_CANVAS_DEV_UI) | |
| 5 #include "infinite_canvas/dev_ui.h" | |
| 6 #endif | |
| 7 | |
| 8 #if defined(PLATFORM_WEB) | |
| 9 #include <emscripten/emscripten.h> | |
| 10 #endif | |
| 11 | |
| 12 #include <stdio.h> | |
| 13 #include <stdlib.h> | |
| 14 #include <string.h> | |
| 15 | |
| 16 typedef struct { | |
| 17 Dowa_Arena *p_arena; | |
| 18 Canvas_Camera camera; | |
| 19 Canvas_Scene scene; | |
| 20 Canvas_Web_Surface web_surface; | |
| 21 Font font; | |
| 22 Canvas_Theme theme; | |
| 23 boolean owns_font; | |
| 24 const char *p_screenshot_path; | |
| 25 uint32 frame_count; | |
| 26 #if defined(INFINITE_CANVAS_DEV_UI) | |
| 27 Canvas_Dev_UI dev_ui; | |
| 28 #endif | |
| 29 } Canvas_App; | |
| 30 | |
| 31 static Canvas_App *g_app = NULL; | |
| 32 | |
| 33 static void Canvas_App_Draw_Frame(void) | |
| 34 { | |
| 35 int32 width = GetScreenWidth(); | |
| 36 int32 height = GetScreenHeight(); | |
| 37 Canvas_Camera_Set_Viewport(&g_app->camera, width, height); | |
| 38 | |
| 39 boolean block_pointer_input = FALSE; | |
| 40 #if defined(INFINITE_CANVAS_DEV_UI) | |
| 41 block_pointer_input = Canvas_Dev_UI_Contains_Pointer(&g_app->dev_ui); | |
| 42 #endif | |
| 43 boolean web_input = Canvas_Web_Surface_Update_Input( | |
| 44 &g_app->web_surface, | |
| 45 &g_app->camera, | |
| 46 &g_app->scene); | |
| 47 block_pointer_input = block_pointer_input || web_input; | |
| 48 boolean entity_input = Canvas_Scene_Update_Interaction( | |
| 49 &g_app->scene, | |
| 50 &g_app->camera, | |
| 51 block_pointer_input); | |
| 52 boolean keyboard_focus = | |
| 53 Canvas_Scene_Is_Text_Editing(&g_app->scene) || | |
| 54 Canvas_Web_Surface_Is_Focused(&g_app->web_surface); | |
| 55 if (!keyboard_focus && IsKeyPressed(KEY_P)) { | |
| 56 Canvas_Scene_Toggle_Selected_Pin(&g_app->scene, &g_app->camera); | |
| 57 } | |
| 58 Canvas_Update_Camera_Input( | |
| 59 &g_app->camera, | |
| 60 block_pointer_input || entity_input, | |
| 61 keyboard_focus); | |
| 62 Canvas_Scene_Sync_Pinned(&g_app->scene, &g_app->camera); | |
| 63 Canvas_Scene_Update_Notification_Stack(&g_app->scene, &g_app->camera); | |
| 64 | |
| 65 Canvas_Web_Surface_Sync(&g_app->web_surface, &g_app->camera, &g_app->scene); | |
| 66 | |
| 67 BeginDrawing(); | |
| 68 ClearBackground(g_app->theme.background); | |
| 69 Canvas_Draw_World( | |
| 70 &g_app->camera, | |
| 71 &g_app->scene, | |
| 72 g_app->font, | |
| 73 &g_app->theme); | |
| 74 Canvas_Web_Surface_Draw(&g_app->web_surface, &g_app->camera, &g_app->scene); | |
| 75 #if defined(INFINITE_CANVAS_DEV_UI) | |
| 76 Canvas_Dev_UI_Draw( | |
| 77 &g_app->dev_ui, | |
| 78 &g_app->camera, | |
| 79 &g_app->scene, | |
| 80 g_app->font, | |
| 81 &g_app->theme); | |
| 82 #endif | |
| 83 EndDrawing(); | |
| 84 g_app->frame_count++; | |
| 85 #if !defined(PLATFORM_WEB) | |
| 86 if (g_app->frame_count == 30) { | |
| 87 RestoreWindow(); | |
| 88 SetWindowFocused(); | |
| 89 } | |
| 90 #endif | |
| 91 if (g_app->p_screenshot_path && | |
| 92 g_app->frame_count == 180) { | |
| 93 TakeScreenshot(g_app->p_screenshot_path); | |
| 94 } | |
| 95 } | |
| 96 | |
| 97 int main(int argc, char **p_argv) | |
| 98 { | |
| 99 #if !defined(PLATFORM_WEB) | |
| 100 int32 subprocess_result = Canvas_Web_Surface_Execute_Subprocess(argc, p_argv); | |
| 101 if (subprocess_result >= 0) return subprocess_result; | |
| 102 #else | |
| 103 (void)argc; | |
| 104 (void)p_argv; | |
| 105 #endif | |
| 106 | |
| 107 Dowa_Arena *p_arena = Dowa_Arena_Create(8 * ONE_MEGA_BYTE); | |
| 108 if (!p_arena) return 1; | |
| 109 | |
| 110 g_app = (Canvas_App *)Dowa_Arena_Allocate(p_arena, sizeof(*g_app)); | |
| 111 if (!g_app) { | |
| 112 Dowa_Arena_Free(p_arena); | |
| 113 return 1; | |
| 114 } | |
| 115 memset(g_app, 0, sizeof(*g_app)); | |
| 116 g_app->p_arena = p_arena; | |
| 117 g_app->p_screenshot_path = getenv("INFINITE_CANVAS_SCREENSHOT"); | |
| 118 Canvas_Theme_Resolve( | |
| 119 &g_app->theme, | |
| 120 Canvas_Theme_Mode_From_String(getenv("INFINITE_CANVAS_THEME"))); | |
| 121 | |
| 122 SetConfigFlags(FLAG_WINDOW_RESIZABLE | FLAG_WINDOW_HIGHDPI | FLAG_MSAA_4X_HINT); | |
| 123 #if defined(INFINITE_CANVAS_DEV_UI) | |
| 124 InitWindow(1920, 1200, "Infinite Canvas"); | |
| 125 SetWindowMinSize(1200, 800); | |
| 126 #else | |
| 127 InitWindow(1280, 720, "Infinite Canvas"); | |
| 128 SetWindowMinSize(640, 360); | |
| 129 #endif | |
| 130 SetTargetFPS(60); | |
| 131 #if !defined(PLATFORM_WEB) | |
| 132 SetWindowFocused(); | |
| 133 #endif | |
| 134 if (!Canvas_Web_Surface_Init(&g_app->web_surface, p_arena)) { | |
| 135 TraceLog(LOG_WARNING, "Web surface initialization failed"); | |
| 136 } | |
| 137 | |
| 138 g_app->font = LoadFontEx("infinite_canvas/assets/Inter-Variable.ttf", 48, NULL, 0); | |
| 139 g_app->owns_font = g_app->font.texture.id != 0; | |
| 140 if (!g_app->owns_font) g_app->font = GetFontDefault(); | |
| 141 else SetTextureFilter(g_app->font.texture, TEXTURE_FILTER_BILINEAR); | |
| 142 Canvas_Camera_Init(&g_app->camera, GetScreenWidth(), GetScreenHeight()); | |
| 143 Canvas_Scene_Init(&g_app->scene, p_arena); | |
| 144 if (getenv("INFINITE_CANVAS_BROWSER_STRESS")) { | |
| 145 Canvas_Scene_Add_Browser_Grid(&g_app->scene); | |
| 146 } else { | |
| 147 Canvas_Scene_Add_Demo(&g_app->scene); | |
| 148 } | |
| 149 const char *p_image_source = getenv("INFINITE_CANVAS_IMAGE_SOURCE"); | |
| 150 if (p_image_source) { | |
| 151 for (size_t index = 0; index < Dowa_Array_Length(g_app->scene.p_entities); index++) { | |
| 152 Canvas_Entity *p_entity = &g_app->scene.p_entities[index]; | |
| 153 if (p_entity->type == CANVAS_ENTITY_IMAGE) { | |
| 154 snprintf(p_entity->text, sizeof(p_entity->text), "%s", p_image_source); | |
| 155 break; | |
| 156 } | |
| 157 } | |
| 158 } | |
| 159 #if !defined(PLATFORM_WEB) | |
| 160 for (size_t index = 0; index < Dowa_Array_Length(g_app->scene.p_entities); index++) { | |
| 161 Canvas_Entity *p_entity = &g_app->scene.p_entities[index]; | |
| 162 if (p_entity->type == CANVAS_ENTITY_WEB_CONTENT) { | |
| 163 snprintf(p_entity->text, sizeof(p_entity->text), "https://www.google.com"); | |
| 164 break; | |
| 165 } | |
| 166 } | |
| 167 #endif | |
| 168 #if defined(INFINITE_CANVAS_DEV_UI) | |
| 169 Canvas_Dev_UI_Init(&g_app->dev_ui, g_app->font, &g_app->theme); | |
| 170 #endif | |
| 171 | |
| 172 #if defined(PLATFORM_WEB) | |
| 173 emscripten_set_main_loop(Canvas_App_Draw_Frame, 0, 1); | |
| 174 #else | |
| 175 while (!WindowShouldClose()) Canvas_App_Draw_Frame(); | |
| 176 Canvas_Web_Surface_Shutdown(&g_app->web_surface); | |
| 177 if (g_app->owns_font) UnloadFont(g_app->font); | |
| 178 Dowa_Arena_Free(p_arena); | |
| 179 g_app = NULL; | |
| 180 CloseWindow(); | |
| 181 #endif | |
| 182 | |
| 183 return 0; | |
| 184 } |