chore: sync from fn-registry agent
This commit is contained in:
@@ -0,0 +1,98 @@
|
|||||||
|
# engine_smoke — gamedev stack smoke test. Issue 0072a.
|
||||||
|
# Standalone — does NOT use add_imgui_app() / fn_framework.
|
||||||
|
#
|
||||||
|
# Two build modes:
|
||||||
|
# 1. As subdir of cpp/ (cmake -S cpp -B build): cpp/CMakeLists.txt already
|
||||||
|
# adds vendor/sdl3 and exposes SDL3::SDL3-static. We just link.
|
||||||
|
# 2. As top-level (cmake -S cpp/apps/engine_smoke -B build) — used by the
|
||||||
|
# WASM pipeline and any standalone build. We do project() + manually
|
||||||
|
# add_subdirectory the vendored SDL3.
|
||||||
|
|
||||||
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
|
# Detect mode: top-level vs subdir.
|
||||||
|
if(CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
|
||||||
|
project(engine_smoke CXX)
|
||||||
|
set(_TOP_LEVEL TRUE)
|
||||||
|
else()
|
||||||
|
set(_TOP_LEVEL FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD 17)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
|
||||||
|
|
||||||
|
# Resolve the repo's cpp/vendor regardless of build mode.
|
||||||
|
get_filename_component(_REPO_CPP_ROOT ${CMAKE_CURRENT_LIST_DIR}/../.. ABSOLUTE)
|
||||||
|
set(_VENDOR ${_REPO_CPP_ROOT}/vendor)
|
||||||
|
|
||||||
|
if(_TOP_LEVEL)
|
||||||
|
# Bring in SDL3 ourselves.
|
||||||
|
if(NOT EXISTS ${_VENDOR}/sdl3/CMakeLists.txt)
|
||||||
|
message(FATAL_ERROR "SDL3 vendoring missing: ${_VENDOR}/sdl3 — see cpp/vendor/sdl3.VENDORING.md")
|
||||||
|
endif()
|
||||||
|
set(SDL_SHARED OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_STATIC ON CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_TEST_LIBRARY OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_TESTS OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_EXAMPLES OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_INSTALL OFF CACHE BOOL "" FORCE)
|
||||||
|
set(SDL_X11_XSCRNSAVER OFF CACHE BOOL "" FORCE)
|
||||||
|
add_subdirectory(${_VENDOR}/sdl3 ${CMAKE_BINARY_DIR}/_sdl3 EXCLUDE_FROM_ALL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# --- ImGui (sources we need) ---
|
||||||
|
set(_IMGUI_SRCS
|
||||||
|
${_VENDOR}/imgui/imgui.cpp
|
||||||
|
${_VENDOR}/imgui/imgui_demo.cpp
|
||||||
|
${_VENDOR}/imgui/imgui_draw.cpp
|
||||||
|
${_VENDOR}/imgui/imgui_tables.cpp
|
||||||
|
${_VENDOR}/imgui/imgui_widgets.cpp
|
||||||
|
${_VENDOR}/imgui/backends/imgui_impl_sdl3.cpp
|
||||||
|
${_VENDOR}/imgui/backends/imgui_impl_opengl3.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(engine_smoke
|
||||||
|
main.cpp
|
||||||
|
${_IMGUI_SRCS}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(engine_smoke PRIVATE
|
||||||
|
${_VENDOR}/imgui
|
||||||
|
${_VENDOR}/sokol
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(engine_smoke PRIVATE SDL3::SDL3-static)
|
||||||
|
|
||||||
|
if(NOT EMSCRIPTEN)
|
||||||
|
find_package(OpenGL REQUIRED)
|
||||||
|
target_link_libraries(engine_smoke PRIVATE OpenGL::GL)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(EMSCRIPTEN)
|
||||||
|
set_target_properties(engine_smoke PROPERTIES SUFFIX ".html")
|
||||||
|
target_compile_options(engine_smoke PRIVATE
|
||||||
|
-Os
|
||||||
|
-fno-exceptions
|
||||||
|
-fno-rtti
|
||||||
|
-ffunction-sections
|
||||||
|
-fdata-sections
|
||||||
|
)
|
||||||
|
target_link_options(engine_smoke PRIVATE
|
||||||
|
-Os
|
||||||
|
-sUSE_WEBGL2=1
|
||||||
|
-sFULL_ES3=1
|
||||||
|
-sALLOW_MEMORY_GROWTH=1
|
||||||
|
-sINITIAL_MEMORY=33554432
|
||||||
|
-sASSERTIONS=0
|
||||||
|
-sENVIRONMENT=web
|
||||||
|
-Wl,--gc-sections
|
||||||
|
# NOTE: -sFILESYSTEM=0 + --closure=1 broke under SDL3 (closure
|
||||||
|
# references undeclared FS). Saves ~30KB JS + ~30KB wasm if
|
||||||
|
# we ever stub SDL3 filesystem refs out. Re-enable per app.
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
set_target_properties(engine_smoke PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||||
|
endif()
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
---
|
||||||
|
name: engine_smoke
|
||||||
|
lang: cpp
|
||||||
|
domain: gamedev
|
||||||
|
description: "Smoke test del stack gamedev: SDL3 + sokol_gfx + Dear ImGui. Valida que el stack compila y corre en PC (Linux/Windows desktop GL) y WASM (WebGL2 via emscripten) antes de invertir tiempo en runtime real (issue 0072a)."
|
||||||
|
tags: [imgui, sdl3, sokol, gamedev, smoke, wasm]
|
||||||
|
uses_functions: []
|
||||||
|
uses_types: []
|
||||||
|
framework: "imgui"
|
||||||
|
entry_point: "main.cpp"
|
||||||
|
dir_path: "cpp/apps/engine_smoke"
|
||||||
|
repo_url: ""
|
||||||
|
e2e_checks:
|
||||||
|
- id: build_pc
|
||||||
|
cmd: "cmake --build build --target engine_smoke -j"
|
||||||
|
timeout_s: 300
|
||||||
|
- id: smoke_self
|
||||||
|
cmd: "timeout 5 ./build/cpp/apps/engine_smoke/engine_smoke || test $? = 124"
|
||||||
|
timeout_s: 10
|
||||||
|
severity: warning # requires display in CI; warning, not critical
|
||||||
|
- id: build_wasm
|
||||||
|
cmd: "bash bash/functions/pipelines/build_wasm_cpp_app.sh engine_smoke"
|
||||||
|
timeout_s: 600
|
||||||
|
severity: warning # requires emsdk
|
||||||
|
- id: wasm_size_budget
|
||||||
|
cmd: "test -f build/wasm/engine_smoke/engine_smoke.wasm.gz && test $(stat -c%s build/wasm/engine_smoke/engine_smoke.wasm.gz) -lt 1572864"
|
||||||
|
severity: warning
|
||||||
|
---
|
||||||
|
|
||||||
|
# engine_smoke
|
||||||
|
|
||||||
|
Primer experimento del stack gamedev (issue [0072a](../../../dev/issues/0072a-gamedev-smoke-sdl3-sokol-imgui.md)).
|
||||||
|
|
||||||
|
## Que hace
|
||||||
|
|
||||||
|
1. Abre ventana SDL3 1280x720 con context OpenGL.
|
||||||
|
2. Inicializa `sokol_gfx` sobre ese context (GL 3.3 desktop, GLES3 en WASM).
|
||||||
|
3. Pinta un fullscreen triangle con un fragment shader animado (gradient time-based).
|
||||||
|
4. Pinta sobre eso un panel ImGui con FPS, tamaño de ventana y boton Quit.
|
||||||
|
|
||||||
|
Sin `fn_framework`, sin `add_imgui_app()`. CMakeLists standalone para evitar contaminar el shell desktop hasta validar el stack.
|
||||||
|
|
||||||
|
## Build PC (Linux)
|
||||||
|
|
||||||
|
Desde la raiz del fn_registry:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cmake -S cpp -B build -DCMAKE_BUILD_TYPE=Release
|
||||||
|
cmake --build build --target engine_smoke -j
|
||||||
|
./build/cpp/apps/engine_smoke/engine_smoke
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build WASM
|
||||||
|
|
||||||
|
Requiere `emsdk` instalado y activado en el shell. Ver `cpp/vendor/sokol.VENDORING.md` y `bash/functions/pipelines/build_wasm_cpp_app.sh`.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
bash bash/functions/pipelines/build_wasm_cpp_app.sh engine_smoke
|
||||||
|
# Sirve build/wasm/engine_smoke/engine_smoke.html en navegador
|
||||||
|
```
|
||||||
|
|
||||||
|
Budget objetivo: gzip ≤ 1.5 MB.
|
||||||
|
|
||||||
|
## Stack vendoreado
|
||||||
|
|
||||||
|
- `cpp/vendor/sdl3/` — SDL3 release-3.4.8
|
||||||
|
- `cpp/vendor/sokol/` — sokol_gfx single-header pinned commit
|
||||||
|
- `cpp/vendor/imgui/` — ImGui 1.92.7 con backends `imgui_impl_sdl3` + `imgui_impl_opengl3`
|
||||||
|
|
||||||
|
## Notas de implementacion
|
||||||
|
|
||||||
|
- Fullscreen tri via `gl_VertexID` (3 vertices, no VBO). Cubre todo el viewport sin atributos.
|
||||||
|
- Uniform `u_time` actualizado por frame.
|
||||||
|
- Backend ImGui = `imgui_impl_opengl3` (oficial, 0 LoC custom). Compatible WebGL2 emscripten.
|
||||||
|
- `SOKOL_GLCORE` desktop / `SOKOL_GLES3` web — selccion compile-time.
|
||||||
|
- `setup_gfx` se llama UNA VEZ tras crear el GL context. `sg_setup` toma `sglue_environment()` que lee el contexto activo.
|
||||||
|
|
||||||
|
## No-objetivos (smoke)
|
||||||
|
|
||||||
|
- No texturas reales (eso entra en 0072b).
|
||||||
|
- No audio.
|
||||||
|
- No input game-style.
|
||||||
|
- No fn_framework integration.
|
||||||
|
- No mobile (Android/iOS son issues 0072g/h).
|
||||||
@@ -0,0 +1,242 @@
|
|||||||
|
// engine_smoke — gamedev stack smoke test.
|
||||||
|
// Validates SDL3 + sokol_gfx + Dear ImGui (imgui_impl_sdl3 + imgui_impl_opengl3)
|
||||||
|
// builds and runs on PC (desktop GL 3.3) and WASM (WebGL2 via -sFULL_ES3=1).
|
||||||
|
//
|
||||||
|
// Issue 0072a. Standalone — does NOT use fn_framework / add_imgui_app.
|
||||||
|
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
#include <SDL3/SDL.h>
|
||||||
|
|
||||||
|
// sokol_gfx — single TU includes the implementation.
|
||||||
|
#define SOKOL_IMPL
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
#define SOKOL_GLES3
|
||||||
|
#else
|
||||||
|
#define SOKOL_GLCORE
|
||||||
|
#endif
|
||||||
|
#include "sokol_gfx.h"
|
||||||
|
#include "sokol_log.h"
|
||||||
|
// sokol_glue.h is NOT used: it pulls in sokol_app symbols. We use SDL3 for
|
||||||
|
// windowing, so we build sg_environment / sg_swapchain manually.
|
||||||
|
|
||||||
|
#include "imgui.h"
|
||||||
|
#include "backends/imgui_impl_sdl3.h"
|
||||||
|
#include "backends/imgui_impl_opengl3.h"
|
||||||
|
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
#include <emscripten/emscripten.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct App {
|
||||||
|
SDL_Window* win = nullptr;
|
||||||
|
SDL_GLContext gl = nullptr;
|
||||||
|
sg_pipeline pip{};
|
||||||
|
sg_bindings bind{};
|
||||||
|
sg_pass_action pass_action{};
|
||||||
|
bool running = true;
|
||||||
|
uint64_t frame = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
App g_app;
|
||||||
|
|
||||||
|
// Fullscreen-quad vertex shader (no inputs, gl_VertexID trick).
|
||||||
|
const char* VS_SRC =
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
"#version 300 es\n"
|
||||||
|
#else
|
||||||
|
"#version 330 core\n"
|
||||||
|
#endif
|
||||||
|
"out vec2 v_uv;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" vec2 p = vec2((gl_VertexID == 1) ? 3.0 : -1.0, (gl_VertexID == 2) ? 3.0 : -1.0);\n"
|
||||||
|
" v_uv = p * 0.5 + 0.5;\n"
|
||||||
|
" gl_Position = vec4(p, 0.0, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
const char* FS_SRC =
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
"#version 300 es\n"
|
||||||
|
"precision mediump float;\n"
|
||||||
|
#else
|
||||||
|
"#version 330 core\n"
|
||||||
|
#endif
|
||||||
|
"in vec2 v_uv;\n"
|
||||||
|
"out vec4 frag;\n"
|
||||||
|
"uniform float u_time;\n"
|
||||||
|
"void main() {\n"
|
||||||
|
" float r = 0.5 + 0.5 * sin(u_time + v_uv.x * 6.2831);\n"
|
||||||
|
" float g = 0.5 + 0.5 * sin(u_time * 1.3 + v_uv.y * 6.2831);\n"
|
||||||
|
" float b = 0.5 + 0.5 * sin(u_time * 0.7 + (v_uv.x + v_uv.y) * 6.2831);\n"
|
||||||
|
" frag = vec4(r, g, b, 1.0);\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
sg_environment make_environment() {
|
||||||
|
sg_environment env{};
|
||||||
|
env.defaults.color_format = SG_PIXELFORMAT_RGBA8;
|
||||||
|
env.defaults.depth_format = SG_PIXELFORMAT_DEPTH_STENCIL;
|
||||||
|
env.defaults.sample_count = 1;
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
|
||||||
|
sg_swapchain make_swapchain(int w, int h) {
|
||||||
|
sg_swapchain sw{};
|
||||||
|
sw.width = w;
|
||||||
|
sw.height = h;
|
||||||
|
sw.sample_count = 1;
|
||||||
|
sw.color_format = SG_PIXELFORMAT_RGBA8;
|
||||||
|
sw.depth_format = SG_PIXELFORMAT_DEPTH_STENCIL;
|
||||||
|
sw.gl.framebuffer = 0; // default framebuffer
|
||||||
|
return sw;
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup_gfx() {
|
||||||
|
sg_desc d{};
|
||||||
|
d.environment = make_environment();
|
||||||
|
d.logger.func = slog_func;
|
||||||
|
sg_setup(&d);
|
||||||
|
|
||||||
|
sg_shader_desc sd{};
|
||||||
|
sd.vertex_func.source = VS_SRC;
|
||||||
|
sd.fragment_func.source = FS_SRC;
|
||||||
|
sd.uniform_blocks[0].stage = SG_SHADERSTAGE_FRAGMENT;
|
||||||
|
sd.uniform_blocks[0].size = sizeof(float);
|
||||||
|
sd.uniform_blocks[0].layout = SG_UNIFORMLAYOUT_NATIVE;
|
||||||
|
sd.uniform_blocks[0].glsl_uniforms[0].type = SG_UNIFORMTYPE_FLOAT;
|
||||||
|
sd.uniform_blocks[0].glsl_uniforms[0].glsl_name = "u_time";
|
||||||
|
sg_shader shd = sg_make_shader(&sd);
|
||||||
|
|
||||||
|
sg_pipeline_desc pd{};
|
||||||
|
pd.shader = shd;
|
||||||
|
pd.primitive_type = SG_PRIMITIVETYPE_TRIANGLES;
|
||||||
|
g_app.pip = sg_make_pipeline(&pd);
|
||||||
|
|
||||||
|
g_app.pass_action.colors[0].load_action = SG_LOADACTION_CLEAR;
|
||||||
|
g_app.pass_action.colors[0].clear_value = {0.05f, 0.05f, 0.08f, 1.0f};
|
||||||
|
}
|
||||||
|
|
||||||
|
void frame() {
|
||||||
|
SDL_Event ev;
|
||||||
|
while (SDL_PollEvent(&ev)) {
|
||||||
|
ImGui_ImplSDL3_ProcessEvent(&ev);
|
||||||
|
if (ev.type == SDL_EVENT_QUIT) g_app.running = false;
|
||||||
|
if (ev.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED) g_app.running = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
SDL_GetWindowSizeInPixels(g_app.win, &w, &h);
|
||||||
|
|
||||||
|
sg_pass p{};
|
||||||
|
p.action = g_app.pass_action;
|
||||||
|
p.swapchain = make_swapchain(w, h);
|
||||||
|
sg_begin_pass(&p);
|
||||||
|
sg_apply_pipeline(g_app.pip);
|
||||||
|
|
||||||
|
float t = (float)g_app.frame * (1.0f / 60.0f);
|
||||||
|
sg_range time_range{ &t, sizeof(t) };
|
||||||
|
sg_apply_uniforms(0, &time_range);
|
||||||
|
|
||||||
|
sg_draw(0, 3, 1); // 3 vertices, fullscreen tri via gl_VertexID
|
||||||
|
|
||||||
|
// ImGui on top
|
||||||
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
|
ImGui_ImplSDL3_NewFrame();
|
||||||
|
ImGui::NewFrame();
|
||||||
|
|
||||||
|
ImGui::SetNextWindowPos(ImVec2(10, 10));
|
||||||
|
ImGui::Begin("engine_smoke", nullptr,
|
||||||
|
ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize |
|
||||||
|
ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove);
|
||||||
|
ImGui::Text("SDL3 + sokol_gfx + ImGui");
|
||||||
|
ImGui::Text("FPS: %.1f", ImGui::GetIO().Framerate);
|
||||||
|
ImGui::Text("Frame: %llu Size: %dx%d", (unsigned long long)g_app.frame, w, h);
|
||||||
|
if (ImGui::Button("Quit")) g_app.running = false;
|
||||||
|
ImGui::End();
|
||||||
|
|
||||||
|
ImGui::Render();
|
||||||
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
|
sg_end_pass();
|
||||||
|
sg_commit();
|
||||||
|
SDL_GL_SwapWindow(g_app.win);
|
||||||
|
g_app.frame++;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
void emscripten_loop() {
|
||||||
|
if (!g_app.running) {
|
||||||
|
emscripten_cancel_main_loop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
frame();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int /*argc*/, char** /*argv*/) {
|
||||||
|
if (!SDL_Init(SDL_INIT_VIDEO)) {
|
||||||
|
std::fprintf(stderr, "SDL_Init failed: %s\n", SDL_GetError());
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
|
#else
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
|
||||||
|
#endif
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
|
||||||
|
|
||||||
|
g_app.win = SDL_CreateWindow("engine_smoke", 1280, 720,
|
||||||
|
SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIGH_PIXEL_DENSITY);
|
||||||
|
if (!g_app.win) {
|
||||||
|
std::fprintf(stderr, "SDL_CreateWindow failed: %s\n", SDL_GetError());
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
g_app.gl = SDL_GL_CreateContext(g_app.win);
|
||||||
|
if (!g_app.gl) {
|
||||||
|
std::fprintf(stderr, "SDL_GL_CreateContext failed: %s\n", SDL_GetError());
|
||||||
|
SDL_DestroyWindow(g_app.win);
|
||||||
|
SDL_Quit();
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
SDL_GL_MakeCurrent(g_app.win, g_app.gl);
|
||||||
|
SDL_GL_SetSwapInterval(1);
|
||||||
|
|
||||||
|
setup_gfx();
|
||||||
|
|
||||||
|
IMGUI_CHECKVERSION();
|
||||||
|
ImGui::CreateContext();
|
||||||
|
ImGui::StyleColorsDark();
|
||||||
|
ImGui_ImplSDL3_InitForOpenGL(g_app.win, g_app.gl);
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 300 es");
|
||||||
|
#else
|
||||||
|
ImGui_ImplOpenGL3_Init("#version 330 core");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__EMSCRIPTEN__)
|
||||||
|
emscripten_set_main_loop(emscripten_loop, 0, 1);
|
||||||
|
#else
|
||||||
|
while (g_app.running) frame();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
|
ImGui_ImplSDL3_Shutdown();
|
||||||
|
ImGui::DestroyContext();
|
||||||
|
sg_shutdown();
|
||||||
|
SDL_GL_DestroyContext(g_app.gl);
|
||||||
|
SDL_DestroyWindow(g_app.win);
|
||||||
|
SDL_Quit();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user