Setup for 2D

This commit is contained in:
Clément Pons 2025-03-25 16:38:13 +01:00
parent 79f8d6d4dc
commit 6692bcf7ad
8 changed files with 148 additions and 3123 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
app.*

55
.vscode/c_cpp_properties.json vendored Normal file
View File

@ -0,0 +1,55 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}/**"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.22621.0",
"compilerPath": "C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.38.33130/bin/Hostx64/x64/cl.exe",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "${default}"
},
{
"name": "Emscripten",
"includePath": [
"${workspaceFolder}/../sokol",
"${workspaceFolder}/../sokol_gp"
],
"defines": [
"_DEBUG",
"UNICODE",
"_UNICODE"
],
"windowsSdkVersion": "10.0.22621.0",
"compilerPath": "C:\\Users\\c.pons\\Documents\\Perso\\Git\\emsdk\\upstream\\emscripten\\emcc.bat",
"cStandard": "c17",
"cppStandard": "c++17",
"intelliSenseMode": "windows-clang-x64",
"compilerPathInCppPropertiesJson": "C:\\Users\\c.pons\\Documents\\Perso\\Git\\emsdk\\upstream\\bin\\clang.exe",
"mergeConfigurations": false,
"browse": {
"path": [
"c:/Users/c.pons/Documents/Perso/Git/flecs_tests/**",
"c:/Users/c.pons/Documents/Perso/Git/flecs_tests"
],
"limitSymbolsToIncludedHeaders": true
},
"compilerArgs": [
"-O2",
"-sUSE_WEBGL2",
"-sASSERTIONS",
"-sWASM_BIGINT",
"-pthread",
"-sFILESYSTEM=0"
]
}
],
"version": 4
}

14
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,14 @@
{
"files.associations": {
"sokol_app.h": "c",
"emsc.h": "c",
"gl3.h": "c",
"sokol_gp.h": "c",
"sokol_glue.h": "c",
"sokol_gfx.h": "c",
"webgpu.h": "c",
"html5.h": "c",
"emscripten.h": "c",
"stddef.h": "c"
}
}

View File

@ -1 +1 @@
emcc -O2 src/main.c -o app.html -sUSE_WEBGL2 -sASSERTIONS -sWASM_BIGINT -pthread -I../sokol --shell-file=shell.html --closure 1 emcc -O3 src/main.c -o app.html -sUSE_WEBGL2 -sWASM_BIGINT -pthread -I../sokol -I../sokol_gp --shell-file=shell.html -sFILESYSTEM=0

1
debug.bat Normal file
View File

@ -0,0 +1 @@
emcc src/main.c -o app.html -sUSE_WEBGL2 -sASSERTIONS -sWASM_BIGINT -pthread -I../sokol -I../sokol_gp --shell-file=shell.html -sFILESYSTEM=0 -g

File diff suppressed because it is too large Load Diff

View File

@ -1,80 +0,0 @@
#pragma once
/* common emscripten platform helper functions */
#include <emscripten/emscripten.h>
#include <emscripten/html5.h>
#include <GLES3/gl3.h>
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wmissing-field-initializers"
#pragma clang diagnostic ignored "-Wmissing-braces"
#endif
static const char* _emsc_canvas_name = 0;
static int _emsc_sample_count = 0;
static double _emsc_width = 0;
static double _emsc_height = 0;
static GLint _emsc_framebuffer = 0;
enum {
EMSC_NONE = 0,
EMSC_ANTIALIAS = (1<<1)
};
/* track CSS element size changes and update the WebGL canvas size */
static EM_BOOL _emsc_size_changed(int event_type, const EmscriptenUiEvent* ui_event, void* user_data) {
(void)event_type;
(void)ui_event;
(void)user_data;
emscripten_get_element_css_size(_emsc_canvas_name, &_emsc_width, &_emsc_height);
emscripten_set_canvas_element_size(_emsc_canvas_name, _emsc_width, _emsc_height);
return true;
}
/* initialize WebGL context and canvas */
void emsc_init(const char* canvas_name, int flags) {
_emsc_canvas_name = canvas_name;
emscripten_get_element_css_size(canvas_name, &_emsc_width, &_emsc_height);
emscripten_set_canvas_element_size(canvas_name, _emsc_width, _emsc_height);
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, 0, false, _emsc_size_changed);
EMSCRIPTEN_WEBGL_CONTEXT_HANDLE ctx;
EmscriptenWebGLContextAttributes attrs;
emscripten_webgl_init_context_attributes(&attrs);
attrs.antialias = flags & EMSC_ANTIALIAS;
attrs.majorVersion = 2;
_emsc_sample_count = (flags & EMSC_ANTIALIAS) ? 4 : 1;
ctx = emscripten_webgl_create_context(canvas_name, &attrs);
emscripten_webgl_make_context_current(ctx);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, (GLint*)&_emsc_framebuffer);
}
int emsc_width(void) {
return (int) _emsc_width;
}
int emsc_height(void) {
return (int) _emsc_height;
}
sg_environment emsc_environment(void) {
return (sg_environment){
.defaults = {
.color_format = SG_PIXELFORMAT_RGBA8,
.depth_format = SG_PIXELFORMAT_DEPTH_STENCIL,
.sample_count = _emsc_sample_count,
}
};
}
sg_swapchain emsc_swapchain(void) {
return (sg_swapchain) {
.width = (int)_emsc_width,
.height = (int)_emsc_height,
.sample_count = _emsc_sample_count,
.color_format = SG_PIXELFORMAT_RGBA8,
.depth_format = SG_PIXELFORMAT_DEPTH_STENCIL,
.gl = {
.framebuffer = (uint32_t)_emsc_framebuffer,
}
};
}

View File

@ -1,172 +1,90 @@
//------------------------------------------------------------------------------ // This is an example on how to set up and use Sokol GP to draw a filled rectangle.
// cube-emsc.c
// Shader uniforms updates. // Includes Sokol GFX, Sokol GP and Sokol APP, doing all implementations.
//------------------------------------------------------------------------------
#define HANDMADE_MATH_IMPLEMENTATION
#define HANDMADE_MATH_NO_SSE
#include "HandmadeMath.h"
#define SOKOL_IMPL #define SOKOL_IMPL
#define SOKOL_GLES3 #define SOKOL_GLES3
#include "sokol_gfx.h" #include "sokol_gfx.h"
#include "sokol_log.h" #include "sokol_gp.h"
#include "emsc.h" #include "sokol_app.h"
#include "sokol_glue.h"
static struct { #include <stdio.h> // for fprintf()
float rx, ry; #include <stdlib.h> // for exit()
sg_pipeline pip; #include <math.h> // for sinf() and cosf()
sg_bindings bind;
sg_pass_action pass_action;
} state = {
.pass_action.colors[0] = { .load_action = SG_LOADACTION_CLEAR, .clear_value = { 0.0f, 0.0f, 0.0f, 1.0f } }
};
typedef struct { // Called on every frame of the application.
hmm_mat4 mvp; static void frame(void) {
} params_t; // Get current window size.
int width = sapp_width(), height = sapp_height();
float ratio = width/(float)height;
static EM_BOOL draw(double time, void* userdata); // Begin recording draw commands for a frame buffer of size (width, height).
sgp_begin(width, height);
// Set frame buffer drawing region to (0,0,width,height).
sgp_viewport(0, 0, width, height);
// Set drawing coordinate space to (left=-ratio, right=ratio, top=1, bottom=-1).
sgp_project(-ratio, ratio, 1.0f, -1.0f);
int main() { // Clear the frame buffer.
// setup WebGL context sgp_set_color(0.1f, 0.1f, 0.1f, 1.0f);
emsc_init("#canvas", EMSC_ANTIALIAS); sgp_clear();
// setup sokol_gfx // Draw an animated rectangle that rotates and changes its colors.
sg_setup(&(sg_desc){ float time = sapp_frame_count() * sapp_frame_duration();
.environment = emsc_environment(), float r = sinf(time)*0.5+0.5, g = cosf(time)*0.5+0.5;
.logger.func = slog_func sgp_set_color(r, g, 0.3f, 1.0f);
}); sgp_rotate_at(time, 0.0f, 0.0f);
assert(sg_isvalid()); sgp_draw_filled_rect(-0.5f, -0.5f, 1.0f, 1.0f);
// cube vertex buffer // Begin a render pass.
float vertices[] = { sg_pass pass = {.swapchain = sglue_swapchain()};
-1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, sg_begin_pass(&pass);
1.0, -1.0, -1.0, 1.0, 0.0, 0.0, 1.0, // Dispatch all draw commands to Sokol GFX.
1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, sgp_flush();
-1.0, 1.0, -1.0, 1.0, 0.0, 0.0, 1.0, // Finish a draw command queue, clearing it.
sgp_end();
-1.0, -1.0, 1.0, 0.0, 1.0, 0.0, 1.0, // End render pass.
1.0, -1.0, 1.0, 0.0, 1.0, 0.0, 1.0, sg_end_pass();
1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, // Commit Sokol render.
-1.0, 1.0, 1.0, 0.0, 1.0, 0.0, 1.0, sg_commit();
-1.0, -1.0, -1.0, 0.0, 0.0, 1.0, 1.0,
-1.0, 1.0, -1.0, 0.0, 0.0, 1.0, 1.0,
-1.0, 1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 0.0, 1.0, 1.0,
1.0, -1.0, -1.0, 1.0, 0.5, 0.0, 1.0,
1.0, 1.0, -1.0, 1.0, 0.5, 0.0, 1.0,
1.0, 1.0, 1.0, 1.0, 0.5, 0.0, 1.0,
1.0, -1.0, 1.0, 1.0, 0.5, 0.0, 1.0,
-1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0,
-1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0,
1.0, -1.0, 1.0, 0.0, 0.5, 1.0, 1.0,
1.0, -1.0, -1.0, 0.0, 0.5, 1.0, 1.0,
-1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0,
-1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0,
1.0, 1.0, 1.0, 1.0, 0.0, 0.5, 1.0,
1.0, 1.0, -1.0, 1.0, 0.0, 0.5, 1.0
};
state.bind.vertex_buffers[0] = sg_make_buffer(&(sg_buffer_desc){
.data = SG_RANGE(vertices)
});
// create an index buffer for the cube
uint16_t indices[] = {
0, 1, 2, 0, 2, 3,
6, 5, 4, 7, 6, 4,
8, 9, 10, 8, 10, 11,
14, 13, 12, 15, 14, 12,
16, 17, 18, 16, 18, 19,
22, 21, 20, 23, 22, 20
};
state.bind.index_buffer = sg_make_buffer(&(sg_buffer_desc){
.type = SG_BUFFERTYPE_INDEXBUFFER,
.data = SG_RANGE(indices)
});
// create shader
sg_shader shd = sg_make_shader(&(sg_shader_desc){
.vertex_func.source =
"#version 300 es\n"
"uniform mat4 mvp;\n"
"in vec4 position;\n"
"in vec4 color0;\n"
"out vec4 color;\n"
"void main() {\n"
" gl_Position = mvp * position;\n"
" color = color0;\n"
"}\n",
.fragment_func.source =
"#version 300 es\n"
"precision mediump float;\n"
"in vec4 color;\n"
"out vec4 frag_color;\n"
"void main() {\n"
" frag_color = color;\n"
"}\n",
.attrs = {
[0].glsl_name = "position",
[1].glsl_name = "color0"
},
.uniform_blocks[0] = {
.stage = SG_SHADERSTAGE_VERTEX,
.size = sizeof(params_t),
.glsl_uniforms = {
[0] = { .glsl_name = "mvp", .type = SG_UNIFORMTYPE_MAT4 }
}
},
});
// create pipeline object
state.pip = sg_make_pipeline(&(sg_pipeline_desc){
.layout = {
// test to provide buffer stride, but no attr offsets
.buffers[0].stride = 28,
.attrs = {
[0].format=SG_VERTEXFORMAT_FLOAT3,
[1].format=SG_VERTEXFORMAT_FLOAT4
}
},
.shader = shd,
.index_type = SG_INDEXTYPE_UINT16,
.depth = {
.compare = SG_COMPAREFUNC_LESS_EQUAL,
.write_enabled = true
},
.cull_mode = SG_CULLMODE_BACK
});
// hand off control to browser loop
emscripten_request_animation_frame_loop(draw, 0);
return 0;
} }
// draw one frame // Called when the application is initializing.
static EM_BOOL draw(double time, void* userdata) { static void init(void) {
(void)time; (void)userdata; // Initialize Sokol GFX.
// compute model-view-projection matrix for vertex shader sg_desc sgdesc = {
hmm_mat4 proj = HMM_Perspective(60.0f, (float)emsc_width()/(float)emsc_height(), 0.01f, 10.0f); .environment = sglue_environment(),
hmm_mat4 view = HMM_LookAt(HMM_Vec3(0.0f, 1.5f, 6.0f), HMM_Vec3(0.0f, 0.0f, 0.0f), HMM_Vec3(0.0f, 1.0f, 0.0f));
hmm_mat4 view_proj = HMM_MultiplyMat4(proj, view);
state.rx += 1.0f; state.ry += 2.0f;
hmm_mat4 rxm = HMM_Rotate(state.rx, HMM_Vec3(1.0f, 0.0f, 0.0f));
hmm_mat4 rym = HMM_Rotate(state.ry, HMM_Vec3(0.0f, 1.0f, 0.0f));
hmm_mat4 model = HMM_MultiplyMat4(rxm, rym);
const params_t vs_params = {
.mvp = HMM_MultiplyMat4(view_proj, model)
}; };
sg_setup(&sgdesc);
if (!sg_isvalid()) {
fprintf(stderr, "Failed to create Sokol GFX context!\n");
exit(-1);
}
// ...and draw // Initialize Sokol GP, adjust the size of command buffers for your own use.
sg_begin_pass(&(sg_pass){ .action = state.pass_action, .swapchain = emsc_swapchain() }); sgp_desc sgpdesc = {0};
sg_apply_pipeline(state.pip); sgp_setup(&sgpdesc);
sg_apply_bindings(&state.bind); if (!sgp_is_valid()) {
sg_apply_uniforms(0, &SG_RANGE(vs_params)); fprintf(stderr, "Failed to create Sokol GP context: %s\n", sgp_get_error_message(sgp_get_last_error()));
sg_draw(0, 36, 1); exit(-1);
sg_end_pass(); }
sg_commit(); }
return EM_TRUE;
// Called when the application is shutting down.
static void cleanup(void) {
// Cleanup Sokol GP and Sokol GFX resources.
sgp_shutdown();
sg_shutdown();
}
// Implement application main through Sokol APP.
sapp_desc sokol_main(int argc, char* argv[]) {
(void)argc;
(void)argv;
return (sapp_desc){
.init_cb = init,
.frame_cb = frame,
.cleanup_cb = cleanup,
.window_title = "Rectangle (Sokol GP)",
};
} }