diff --git a/.gitignore b/.gitignore index b1a61a4..2d1da73 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ +data/*.wasm # Workspace files are user-specific *.sublime-workspace diff --git a/CWasm.sublime-project b/CWasm.sublime-project index 6ec223c..e425227 100644 --- a/CWasm.sublime-project +++ b/CWasm.sublime-project @@ -92,11 +92,32 @@ "ArenaMark GetArenaMark(Arena* arena)", "ArenaMark GetScratch()", "ArenaMark GetScratch1(Arena* conflictArena)", + "GlId jsGlCreateBuffer()", + "GlId jsGlCreateProgram()", + "GlId jsGlCreateShader(GlEnum shaderType)", + "GlId jsGlCreateVertexArray()", + "bool jsGlGetProgramParameterBool(GlId programId, GlEnum parameter)", + "bool jsGlGetShaderParameterBool(GlId shaderId, GlEnum parameter)", "inline void* ReallocMem(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize)", "inline void* ReallocMemUnaligned(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize)", + "int jsGlGetProgramParameterInt(GlId programId, GlEnum parameter)", + "int jsGlGetShaderParameterInt(GlId shaderId, GlEnum parameter)", "void InitGlobalArenas(u32 scratchArenasSize)", "void ResetToArenaMark(ArenaMark arenaMark)", "void ResetToMark(Arena* arena, u32 mark)", + "void jsGlAttachShader(GlId programId, GlId shaderId)", + "void jsGlBindBuffer(GlEnum bufferType, GlId bufferId)", + "void jsGlBindVertexArray(GlId vaoId)", + "void jsGlBufferData(GlEnum bufferType, u32 dataLength, const void* dataPntr, GlEnum usageHint)", + "void jsGlClear(int bufferBits)", + "void jsGlClearColor(r32 rValue, r32 gValue, r32 bValue, r32 aValue)", + "void jsGlCompileShader(GlId shaderId)", + "void jsGlDrawArrays(GlEnum geometryType, int startIndex, int count)", + "void jsGlEnableVertexAttribArray(GlEnum location)", + "void jsGlLinkProgram(GlId programId)", + "void jsGlShaderSource(GlId shaderId, int sourceLength, const char* sourcePntr)", + "void jsGlUseProgram(GlId programId)", + "void jsGlVertexAttribPointer(GlEnum attribLocation, int componentCount, GlEnum componentType, bool normalized, int stride, int offset)", "void* AllocMemUnaligned(Arena* arena, u32 numBytes)", "void* ReallocMemAligned(Arena* arena, void* oldPntr, u32 oldSize, u32 newSize, u32 newAlignment)", ], diff --git a/build.bat b/build.bat index 6ad502c..539836f 100644 --- a/build.bat +++ b/build.bat @@ -28,6 +28,7 @@ if %ERRORLEVEL% NEQ 0 ( echo [Done!] ) +XCOPY ".\%app_module_name%" "..\data\" /Y > NUL rem Convert .wasm to .wat (the text format for WebAssembly) for debug inspection set "app_module_wat_name=%app_module_name:.wasm=.wat%" diff --git a/cwasm.c b/cwasm.c index 4837420..c8637c6 100644 --- a/cwasm.c +++ b/cwasm.c @@ -9,6 +9,10 @@ Description: #include "cwasm.h" #include "std/src/std_main.c" + +#include "cwasm_webgl_js_imports.h" +#include "cwasm_webgl_constants.h" + #include "cwasm_arena.c" #include "cwasm_debug.c" @@ -16,9 +20,9 @@ void InitializeCWasm(u32 scratchArenasSize) { // CwasmDebugOutput(__FILE__, __LINE__, __func__, DbgLevel_Warning, true, "Hello\nWorld!"); Write_D("Hello\nWorld!"); - PrintLine_D(" Fuzzy %u Bunnies!\n%s", 31415926, "What"); + PrintLine_I(" Fuzzy %u Bunnies!\n%s", 31415926, "What"); WriteLine_D(""); - WriteLine_I("When"); + WriteLine_W("When"); Write_D("\n"); WriteLine_E("Where"); InitGlobalArenas(scratchArenasSize); diff --git a/cwasm_webgl_constants.h b/cwasm_webgl_constants.h new file mode 100644 index 0000000..43a1367 --- /dev/null +++ b/cwasm_webgl_constants.h @@ -0,0 +1,730 @@ +/* +File: cwasm_webgl_constants.h +Author: Taylor Robbins +Date: 09\01\2025 +*/ + +#ifndef _CWASM_WEBGL_CONSTANTS_H +#define _CWASM_WEBGL_CONSTANTS_H + +// https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Constants + +// +--------------------------------------------------------------+ +// | Standard WebGL 1 Constants | +// +--------------------------------------------------------------+ +// +==============================+ +// | Clearing Buffers | +// +==============================+ +#define GL_DEPTH_BUFFER_BIT 0x00000100 +#define GL_STENCIL_BUFFER_BIT 0x00000400 +#define GL_COLOR_BUFFER_BIT 0x00004000 + +// +==============================+ +// | Rendering Primitives | +// +==============================+ +#define GL_POINTS 0x0000 +#define GL_LINES 0x0001 +#define GL_LINE_LOOP 0x0002 +#define GL_LINE_STRIP 0x0003 +#define GL_TRIANGLES 0x0004 +#define GL_TRIANGLE_STRIP 0x0005 +#define GL_TRIANGLE_FAN 0x0006 + +// +==============================+ +// | Blending Modes | +// +==============================+ +#define GL_ZERO 0 +#define GL_ONE 1 +#define GL_SRC_COLOR 0x0300 +#define GL_ONE_MINUS_SRC_COLOR 0x0301 +#define GL_SRC_ALPHA 0x0302 +#define GL_ONE_MINUS_SRC_ALPHA 0x0303 +#define GL_DST_ALPHA 0x0304 +#define GL_ONE_MINUS_DST_ALPHA 0x0305 +#define GL_DST_COLOR 0x0306 +#define GL_ONE_MINUS_DST_COLOR 0x0307 +#define GL_SRC_ALPHA_SATURATE 0x0308 +#define GL_CONSTANT_COLOR 0x8001 +#define GL_ONE_MINUS_CONSTANT_COLOR 0x8002 +#define GL_CONSTANT_ALPHA 0x8003 +#define GL_ONE_MINUS_CONSTANT_ALPHA 0x8004 + +// +==============================+ +// | Blending Equations | +// +==============================+ +#define GL_FUNC_ADD 0x8006 +#define GL_FUNC_SUBTRACT 0x800A +#define GL_FUNC_REVERSE_SUBTRACT 0x800B + +// +==============================+ +// | GL Parameters | +// +==============================+ +#define GL_BLEND_EQUATION 0x8009 +#define GL_BLEND_EQUATION_RGB 0x8009 +#define GL_BLEND_EQUATION_ALPHA 0x883D +#define GL_BLEND_DST_RGB 0x80C8 +#define GL_BLEND_SRC_RGB 0x80C9 +#define GL_BLEND_DST_ALPHA 0x80CA +#define GL_BLEND_SRC_ALPHA 0x80CB +#define GL_BLEND_COLOR 0x8005 +#define GL_ARRAY_BUFFER_BINDING 0x8894 +#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895 +#define GL_LINE_WIDTH 0x0B21 +#define GL_ALIASED_POINT_SIZE_RANGE 0x846D +#define GL_ALIASED_LINE_WIDTH_RANGE 0x846E +#define GL_CULL_FACE_MODE 0x0B45 +#define GL_FRONT_FACE 0x0B46 +#define GL_DEPTH_RANGE 0x0B70 +#define GL_DEPTH_WRITEMASK 0x0B72 +#define GL_DEPTH_CLEAR_VALUE 0x0B73 +#define GL_DEPTH_FUNC 0x0B74 +#define GL_STENCIL_CLEAR_VALUE 0x0B91 +#define GL_STENCIL_FUNC 0x0B92 +#define GL_STENCIL_FAIL 0x0B94 +#define GL_STENCIL_PASS_DEPTH_FAIL 0x0B95 +#define GL_STENCIL_PASS_DEPTH_PASS 0x0B96 +#define GL_STENCIL_REF 0x0B97 +#define GL_STENCIL_VALUE_MASK 0x0B93 +#define GL_STENCIL_WRITEMASK 0x0B98 +#define GL_STENCIL_BACK_FUNC 0x8800 +#define GL_STENCIL_BACK_FAIL 0x8801 +#define GL_STENCIL_BACK_PASS_DEPTH_FAIL 0x8802 +#define GL_STENCIL_BACK_PASS_DEPTH_PASS 0x8803 +#define GL_STENCIL_BACK_REF 0x8CA3 +#define GL_STENCIL_BACK_VALUE_MASK 0x8CA4 +#define GL_STENCIL_BACK_WRITEMASK 0x8CA5 +#define GL_VIEWPORT 0x0BA2 +#define GL_SCISSOR_BOX 0x0C10 +#define GL_COLOR_CLEAR_VALUE 0x0C22 +#define GL_COLOR_WRITEMASK 0x0C23 +#define GL_UNPACK_ALIGNMENT 0x0CF5 +#define GL_PACK_ALIGNMENT 0x0D05 +#define GL_MAX_TEXTURE_SIZE 0x0D33 +#define GL_MAX_VIEWPORT_DIMS 0x0D3A +#define GL_SUBPIXEL_BITS 0x0D50 +#define GL_RED_BITS 0x0D52 +#define GL_GREEN_BITS 0x0D53 +#define GL_BLUE_BITS 0x0D54 +#define GL_ALPHA_BITS 0x0D55 +#define GL_DEPTH_BITS 0x0D56 +#define GL_STENCIL_BITS 0x0D57 +#define GL_POLYGON_OFFSET_UNITS 0x2A00 +#define GL_POLYGON_OFFSET_FACTOR 0x8038 +#define GL_TEXTURE_BINDING_2D 0x8069 +#define GL_SAMPLE_BUFFERS 0x80A8 +#define GL_SAMPLES 0x80A9 +#define GL_SAMPLE_COVERAGE_VALUE 0x80AA +#define GL_SAMPLE_COVERAGE_INVERT 0x80AB +#define GL_COMPRESSED_TEXTURE_FORMATS 0x86A3 +#define GL_VENDOR 0x1F00 +#define GL_RENDERER 0x1F01 +#define GL_VERSION 0x1F02 +#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A +#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B +#define GL_BROWSER_DEFAULT_WEBGL 0x9244 + +// +==============================+ +// | Buffers | +// +==============================+ +#define GL_STATIC_DRAW 0x88E4 +#define GL_STREAM_DRAW 0x88E0 +#define GL_DYNAMIC_DRAW 0x88E8 +#define GL_ARRAY_BUFFER 0x8892 +#define GL_ELEMENT_ARRAY_BUFFER 0x8893 +#define GL_BUFFER_SIZE 0x8764 +#define GL_BUFFER_USAGE 0x8765 + +// +==============================+ +// | Vertex Attributes | +// +==============================+ +#define GL_CURRENT_VERTEX_ATTRIB 0x8626 +#define GL_VERTEX_ATTRIB_ARRAY_ENABLED 0x8622 +#define GL_VERTEX_ATTRIB_ARRAY_SIZE 0x8623 +#define GL_VERTEX_ATTRIB_ARRAY_STRIDE 0x8624 +#define GL_VERTEX_ATTRIB_ARRAY_TYPE 0x8625 +#define GL_VERTEX_ATTRIB_ARRAY_NORMALIZED 0x886A +#define GL_VERTEX_ATTRIB_ARRAY_POINTER 0x8645 +#define GL_VERTEX_ATTRIB_ARRAY_BUFFER_BINDING 0x889F + +// +==============================+ +// | Culling | +// +==============================+ +#define GL_CULL_FACE 0x0B44 +#define GL_FRONT 0x0404 +#define GL_BACK 0x0405 +#define GL_FRONT_AND_BACK 0x0408 + +// +==============================+ +// | Enabling and Disabling | +// +==============================+ +#define GL_BLEND 0x0BE2 +#define GL_DEPTH_TEST 0x0B71 +#define GL_DITHER 0x0BD0 +#define GL_POLYGON_OFFSET_FILL 0x8037 +#define GL_SAMPLE_ALPHA_TO_COVERAGE 0x809E +#define GL_SAMPLE_COVERAGE 0x80A0 +#define GL_SCISSOR_TEST 0x0C11 +#define GL_STENCIL_TEST 0x0B90 + +// +==============================+ +// | Errors | +// +==============================+ +#define GL_NO_ERROR 0 +#define GL_INVALID_ENUM 0x0500 +#define GL_INVALID_VALUE 0x0501 +#define GL_INVALID_OPERATION 0x0502 +#define GL_OUT_OF_MEMORY 0x0505 +#define GL_CONTEXT_LOST_WEBGL 0x9242 + +// +==============================+ +// | Front Face Directions | +// +==============================+ +#define GL_CW 0x0900 +#define GL_CCW 0x0901 + +// +==============================+ +// | Hints | +// +==============================+ +#define GL_DONT_CARE 0x1100 +#define GL_FASTEST 0x1101 +#define GL_NICEST 0x1102 +#define GL_GENERATE_MIPMAP_HINT 0x8192 + +// +==============================+ +// | Data Types | +// +==============================+ +#define GL_BYTE 0x1400 +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_SHORT 0x1402 +#define GL_UNSIGNED_SHORT 0x1403 +#define GL_INT 0x1404 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 + +// +==============================+ +// | Pixel Formats | +// +==============================+ +#define GL_DEPTH_COMPONENT 0x1902 +#define GL_ALPHA 0x1906 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_LUMINANCE 0x1909 +#define GL_LUMINANCE_ALPHA 0x190A + +// +==============================+ +// | Pixel Types | +// +==============================+ +#define GL_UNSIGNED_BYTE 0x1401 +#define GL_UNSIGNED_SHORT_4_4_4_4 0x8033 +#define GL_UNSIGNED_SHORT_5_5_5_1 0x8034 +#define GL_UNSIGNED_SHORT_5_6_5 0x8363 + +// +==============================+ +// | Shaders | +// +==============================+ +#define GL_FRAGMENT_SHADER 0x8B30 +#define GL_VERTEX_SHADER 0x8B31 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_DELETE_STATUS 0x8B80 +#define GL_LINK_STATUS 0x8B82 +#define GL_VALIDATE_STATUS 0x8B83 +#define GL_ATTACHED_SHADERS 0x8B85 +#define GL_ACTIVE_ATTRIBUTES 0x8B89 +#define GL_ACTIVE_UNIFORMS 0x8B86 +#define GL_MAX_VERTEX_ATTRIBS 0x8869 +#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB +#define GL_MAX_VARYING_VECTORS 0x8DFC +#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D +#define GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS 0x8B4C +#define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD +#define GL_SHADER_TYPE 0x8B4F +#define GL_SHADING_LANGUAGE_VERSION 0x8B8C +#define GL_CURRENT_PROGRAM 0x8B8D + +// +==============================+ +// | Depth or Stencil Tests | +// +==============================+ +#define GL_NEVER 0x0200 +#define GL_LESS 0x0201 +#define GL_EQUAL 0x0202 +#define GL_LEQUAL 0x0203 +#define GL_GREATER 0x0204 +#define GL_NOTEQUAL 0x0205 +#define GL_GEQUAL 0x0206 +#define GL_ALWAYS 0x0207 + +// +==============================+ +// | Stencil Actions | +// +==============================+ +#define GL_KEEP 0x1E00 +#define GL_REPLACE 0x1E01 +#define GL_INCR 0x1E02 +#define GL_DECR 0x1E03 +#define GL_INVERT 0x150A +#define GL_INCR_WRAP 0x8507 +#define GL_DECR_WRAP 0x8508 + +// +==============================+ +// | Textures | +// +==============================+ +#define GL_NEAREST 0x2600 +#define GL_LINEAR 0x2601 +#define GL_NEAREST_MIPMAP_NEAREST 0x2700 +#define GL_LINEAR_MIPMAP_NEAREST 0x2701 +#define GL_NEAREST_MIPMAP_LINEAR 0x2702 +#define GL_LINEAR_MIPMAP_LINEAR 0x2703 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_TEXTURE_2D 0x0DE1 +#define GL_TEXTURE 0x1702 +#define GL_TEXTURE_CUBE_MAP 0x8513 +#define GL_TEXTURE_BINDING_CUBE_MAP 0x8514 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x8515 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x8516 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x8517 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x8518 +#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x8519 +#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x851A +#define GL_MAX_CUBE_MAP_TEXTURE_SIZE 0x851C +#define GL_TEXTURE0 0x84C0 +#define GL_TEXTURE1 0x84C1 +#define GL_TEXTURE2 0x84C2 +#define GL_TEXTURE3 0x84C3 +#define GL_TEXTURE4 0x84C4 +#define GL_TEXTURE5 0x84C5 +#define GL_TEXTURE6 0x84C6 +#define GL_TEXTURE7 0x84C7 +#define GL_TEXTURE8 0x84C8 +#define GL_TEXTURE9 0x84C9 +#define GL_TEXTURE10 0x84CA +#define GL_TEXTURE11 0x84CB +#define GL_TEXTURE12 0x84CC +#define GL_TEXTURE13 0x84CD +#define GL_TEXTURE14 0x84CE +#define GL_TEXTURE15 0x84CF +#define GL_TEXTURE16 0x84D0 +#define GL_TEXTURE17 0x84D1 +#define GL_TEXTURE18 0x84D2 +#define GL_TEXTURE19 0x84D3 +#define GL_TEXTURE20 0x84D4 +#define GL_TEXTURE21 0x84D5 +#define GL_TEXTURE22 0x84D6 +#define GL_TEXTURE23 0x84D7 +#define GL_TEXTURE24 0x84D8 +#define GL_TEXTURE25 0x84D9 +#define GL_TEXTURE26 0x84DA +#define GL_TEXTURE27 0x84DB +#define GL_TEXTURE28 0x84DC +#define GL_TEXTURE29 0x84DD +#define GL_TEXTURE30 0x84DE +#define GL_TEXTURE31 0x84DF +#define GL_ACTIVE_TEXTURE 0x84E0 +#define GL_REPEAT 0x2901 +#define GL_CLAMP_TO_EDGE 0x812F +#define GL_MIRRORED_REPEAT 0x8370 + +// +==============================+ +// | Uniform Types | +// +==============================+ +#define GL_FLOAT_VEC2 0x8B50 +#define GL_FLOAT_VEC3 0x8B51 +#define GL_FLOAT_VEC4 0x8B52 +#define GL_INT_VEC2 0x8B53 +#define GL_INT_VEC3 0x8B54 +#define GL_INT_VEC4 0x8B55 +#define GL_BOOL 0x8B56 +#define GL_BOOL_VEC2 0x8B57 +#define GL_BOOL_VEC3 0x8B58 +#define GL_BOOL_VEC4 0x8B59 +#define GL_FLOAT_MAT2 0x8B5A +#define GL_FLOAT_MAT3 0x8B5B +#define GL_FLOAT_MAT4 0x8B5C +#define GL_SAMPLER_2D 0x8B5E +#define GL_SAMPLER_CUBE 0x8B60 + +// +==================================+ +// | Shader Precision-Specified Types | +// +==================================+ +#define GL_LOW_FLOAT 0x8DF0 +#define GL_MEDIUM_FLOAT 0x8DF1 +#define GL_HIGH_FLOAT 0x8DF2 +#define GL_LOW_INT 0x8DF3 +#define GL_MEDIUM_INT 0x8DF4 +#define GL_HIGH_INT 0x8DF5 + +// +================================+ +// | Framebuffers and Renderbuffers | +// +================================+ +#define GL_FRAMEBUFFER 0x8D40 +#define GL_RENDERBUFFER 0x8D41 +#define GL_RGBA4 0x8056 +#define GL_RGB5_A1 0x8057 +#define GL_RGB565 0x8D62 +#define GL_DEPTH_COMPONENT16 0x81A5 +#define GL_STENCIL_INDEX8 0x8D48 +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_RENDERBUFFER_WIDTH 0x8D42 +#define GL_RENDERBUFFER_HEIGHT 0x8D43 +#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44 +#define GL_RENDERBUFFER_RED_SIZE 0x8D50 +#define GL_RENDERBUFFER_GREEN_SIZE 0x8D51 +#define GL_RENDERBUFFER_BLUE_SIZE 0x8D52 +#define GL_RENDERBUFFER_ALPHA_SIZE 0x8D53 +#define GL_RENDERBUFFER_DEPTH_SIZE 0x8D54 +#define GL_RENDERBUFFER_STENCIL_SIZE 0x8D55 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE 0x8CD0 +#define GL_FRAMEBUFFER_ATTACHMENT_OBJECT_NAME 0x8CD1 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL 0x8CD2 +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE 0x8CD3 +#define GL_COLOR_ATTACHMENT0 0x8CE0 +#define GL_DEPTH_ATTACHMENT 0x8D00 +#define GL_STENCIL_ATTACHMENT 0x8D20 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_NONE 0 +#define GL_FRAMEBUFFER_COMPLETE 0x8CD5 +#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6 +#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7 +#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9 +#define GL_FRAMEBUFFER_UNSUPPORTED 0x8CDD +#define GL_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_RENDERBUFFER_BINDING 0x8CA7 +#define GL_MAX_RENDERBUFFER_SIZE 0x84E8 +#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506 + +// +==============================+ +// | Pixel Storage Modes | +// +==============================+ +#define GL_UNPACK_FLIP_Y_WEBGL 0x9240 +#define GL_UNPACK_PREMULTIPLY_ALPHA_WEBGL 0x9241 +#define GL_UNPACK_COLORSPACE_CONVERSION_WEBGL 0x9243 + +// +--------------------------------------------------------------+ +// | Additional WebGL 2 Constants | +// +--------------------------------------------------------------+ +// +==============================+ +// | GL Parameters | +// +==============================+ +#define GL_READ_BUFFER 0x0C02 +#define GL_UNPACK_ROW_LENGTH 0x0CF2 +#define GL_UNPACK_SKIP_ROWS 0x0CF3 +#define GL_UNPACK_SKIP_PIXELS 0x0CF4 +#define GL_PACK_ROW_LENGTH 0x0D02 +#define GL_PACK_SKIP_ROWS 0x0D03 +#define GL_PACK_SKIP_PIXELS 0x0D04 +#define GL_TEXTURE_BINDING_3D 0x806A +#define GL_UNPACK_SKIP_IMAGES 0x806D +#define GL_UNPACK_IMAGE_HEIGHT 0x806E +#define GL_MAX_3D_TEXTURE_SIZE 0x8073 +#define GL_MAX_ELEMENTS_VERTICES 0x80E8 +#define GL_MAX_ELEMENTS_INDICES 0x80E9 +#define GL_MAX_TEXTURE_LOD_BIAS 0x84FD +#define GL_MAX_FRAGMENT_UNIFORM_COMPONENTS 0x8B49 +#define GL_MAX_VERTEX_UNIFORM_COMPONENTS 0x8B4A +#define GL_MAX_ARRAY_TEXTURE_LAYERS 0x88FF +#define GL_MIN_PROGRAM_TEXEL_OFFSET 0x8904 +#define GL_MAX_PROGRAM_TEXEL_OFFSET 0x8905 +#define GL_MAX_VARYING_COMPONENTS 0x8B4B +#define GL_FRAGMENT_SHADER_DERIVATIVE_HINT 0x8B8B +#define GL_RASTERIZER_DISCARD 0x8C89 +#define GL_VERTEX_ARRAY_BINDING 0x85B5 +#define GL_MAX_VERTEX_OUTPUT_COMPONENTS 0x9122 +#define GL_MAX_FRAGMENT_INPUT_COMPONENTS 0x9125 +#define GL_MAX_SERVER_WAIT_TIMEOUT 0x9111 +#define GL_MAX_ELEMENT_INDEX 0x8D6B + +// +==============================+ +// | Textures | +// +==============================+ +#define GL_RED 0x1903 +#define GL_RGB8 0x8051 +#define GL_RGBA8 0x8058 +#define GL_RGB10_A2 0x8059 +#define GL_TEXTURE_3D 0x806F +#define GL_TEXTURE_WRAP_R 0x8072 +#define GL_TEXTURE_MIN_LOD 0x813A +#define GL_TEXTURE_MAX_LOD 0x813B +#define GL_TEXTURE_BASE_LEVEL 0x813C +#define GL_TEXTURE_MAX_LEVEL 0x813D +#define GL_TEXTURE_COMPARE_MODE 0x884C +#define GL_TEXTURE_COMPARE_FUNC 0x884D +#define GL_SRGB 0x8C40 +#define GL_SRGB8 0x8C41 +#define GL_SRGB8_ALPHA8 0x8C43 +#define GL_COMPARE_REF_TO_TEXTURE 0x884E +#define GL_RGBA32F 0x8814 +#define GL_RGB32F 0x8815 +#define GL_RGBA16F 0x881A +#define GL_RGB16F 0x881B +#define GL_TEXTURE_2D_ARRAY 0x8C1A +#define GL_TEXTURE_BINDING_2D_ARRAY 0x8C1D +#define GL_R11F_G11F_B10F 0x8C3A +#define GL_RGB9_E5 0x8C3D +#define GL_RGBA32UI 0x8D70 +#define GL_RGB32UI 0x8D71 +#define GL_RGBA16UI 0x8D76 +#define GL_RGB16UI 0x8D77 +#define GL_RGBA8UI 0x8D7C +#define GL_RGB8UI 0x8D7D +#define GL_RGBA32I 0x8D82 +#define GL_RGB32I 0x8D83 +#define GL_RGBA16I 0x8D88 +#define GL_RGB16I 0x8D89 +#define GL_RGBA8I 0x8D8E +#define GL_RGB8I 0x8D8F +#define GL_RED_INTEGER 0x8D94 +#define GL_RGB_INTEGER 0x8D98 +#define GL_RGBA_INTEGER 0x8D99 +#define GL_R8 0x8229 +#define GL_RG8 0x822B +#define GL_R16F 0x822D +#define GL_R32F 0x822E +#define GL_RG16F 0x822F +#define GL_RG32F 0x8230 +#define GL_R8I 0x8231 +#define GL_R8UI 0x8232 +#define GL_R16I 0x8233 +#define GL_R16UI 0x8234 +#define GL_R32I 0x8235 +#define GL_R32UI 0x8236 +#define GL_RG8I 0x8237 +#define GL_RG8UI 0x8238 +#define GL_RG16I 0x8239 +#define GL_RG16UI 0x823A +#define GL_RG32I 0x823B +#define GL_RG32UI 0x823C +#define GL_R8_SNORM 0x8F94 +#define GL_RG8_SNORM 0x8F95 +#define GL_RGB8_SNORM 0x8F96 +#define GL_RGBA8_SNORM 0x8F97 +#define GL_RGB10_A2UI 0x906F +#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F +#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF + +// +==============================+ +// | Pixel Types | +// +==============================+ +#define GL_UNSIGNED_INT_2_10_10_10_REV 0x8368 +#define GL_UNSIGNED_INT_10F_11F_11F_REV 0x8C3B +#define GL_UNSIGNED_INT_5_9_9_9_REV 0x8C3E +#define GL_FLOAT_32_UNSIGNED_INT_24_8_REV 0x8DAD +#define GL_UNSIGNED_INT_24_8 0x84FA +#define GL_HALF_FLOAT 0x140B +#define GL_RG 0x8227 +#define GL_RG_INTEGER 0x8228 +#define GL_INT_2_10_10_10_REV 0x8D9F + +// +==============================+ +// | Queries | +// +==============================+ +#define GL_CURRENT_QUERY 0x8865 +#define GL_QUERY_RESULT 0x8866 +#define GL_QUERY_RESULT_AVAILABLE 0x8867 +#define GL_ANY_SAMPLES_PASSED 0x8C2F +#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A + +// +==============================+ +// | Draw Buffers | +// +==============================+ +#define GL_MAX_DRAW_BUFFERS 0x8824 +#define GL_DRAW_BUFFER0 0x8825 +#define GL_DRAW_BUFFER1 0x8826 +#define GL_DRAW_BUFFER2 0x8827 +#define GL_DRAW_BUFFER3 0x8828 +#define GL_DRAW_BUFFER4 0x8829 +#define GL_DRAW_BUFFER5 0x882A +#define GL_DRAW_BUFFER6 0x882B +#define GL_DRAW_BUFFER7 0x882C +#define GL_DRAW_BUFFER8 0x882D +#define GL_DRAW_BUFFER9 0x882E +#define GL_DRAW_BUFFER10 0x882F +#define GL_DRAW_BUFFER11 0x8830 +#define GL_DRAW_BUFFER12 0x8831 +#define GL_DRAW_BUFFER13 0x8832 +#define GL_DRAW_BUFFER14 0x8833 +#define GL_DRAW_BUFFER15 0x8834 +#define GL_MAX_COLOR_ATTACHMENTS 0x8CDF +#define GL_COLOR_ATTACHMENT1 0x8CE1 +#define GL_COLOR_ATTACHMENT2 0x8CE2 +#define GL_COLOR_ATTACHMENT3 0x8CE3 +#define GL_COLOR_ATTACHMENT4 0x8CE4 +#define GL_COLOR_ATTACHMENT5 0x8CE5 +#define GL_COLOR_ATTACHMENT6 0x8CE6 +#define GL_COLOR_ATTACHMENT7 0x8CE7 +#define GL_COLOR_ATTACHMENT8 0x8CE8 +#define GL_COLOR_ATTACHMENT9 0x8CE9 +#define GL_COLOR_ATTACHMENT10 0x8CEA +#define GL_COLOR_ATTACHMENT11 0x8CEB +#define GL_COLOR_ATTACHMENT12 0x8CEC +#define GL_COLOR_ATTACHMENT13 0x8CED +#define GL_COLOR_ATTACHMENT14 0x8CEE +#define GL_COLOR_ATTACHMENT15 0x8CEF + +// +==============================+ +// | Samlpers | +// +==============================+ +#define GL_SAMPLER_3D 0x8B5F +#define GL_SAMPLER_2D_SHADOW 0x8B62 +#define GL_SAMPLER_2D_ARRAY 0x8DC1 +#define GL_SAMPLER_2D_ARRAY_SHADOW 0x8DC4 +#define GL_SAMPLER_CUBE_SHADOW 0x8DC5 +#define GL_INT_SAMPLER_2D 0x8DCA +#define GL_INT_SAMPLER_3D 0x8DCB +#define GL_INT_SAMPLER_CUBE 0x8DCC +#define GL_INT_SAMPLER_2D_ARRAY 0x8DCF +#define GL_UNSIGNED_INT_SAMPLER_2D 0x8DD2 +#define GL_UNSIGNED_INT_SAMPLER_3D 0x8DD3 +#define GL_UNSIGNED_INT_SAMPLER_CUBE 0x8DD4 +#define GL_UNSIGNED_INT_SAMPLER_2D_ARRAY 0x8DD7 +#define GL_MAX_SAMPLES 0x8D57 +#define GL_SAMPLER_BINDING 0x8919 + +// +==============================+ +// | Buffers | +// +==============================+ +#define GL_PIXEL_PACK_BUFFER 0x88EB +#define GL_PIXEL_UNPACK_BUFFER 0x88EC +#define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#define GL_COPY_READ_BUFFER 0x8F36 +#define GL_COPY_WRITE_BUFFER 0x8F37 +#define GL_COPY_READ_BUFFER_BINDING 0x8F36 +#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37 + +// +==============================+ +// | Data Types | +// +==============================+ +#define GL_FLOAT_MAT2x3 0x8B65 +#define GL_FLOAT_MAT2x4 0x8B66 +#define GL_FLOAT_MAT3x2 0x8B67 +#define GL_FLOAT_MAT3x4 0x8B68 +#define GL_FLOAT_MAT4x2 0x8B69 +#define GL_FLOAT_MAT4x3 0x8B6A +#define GL_UNSIGNED_INT_VEC2 0x8DC6 +#define GL_UNSIGNED_INT_VEC3 0x8DC7 +#define GL_UNSIGNED_INT_VEC4 0x8DC8 +#define GL_UNSIGNED_NORMALIZED 0x8C17 +#define GL_SIGNED_NORMALIZED 0x8F9C + +// +==============================+ +// | Vertex Attributes | +// +==============================+ +#define GL_VERTEX_ATTRIB_ARRAY_INTEGER 0x88FD +#define GL_VERTEX_ATTRIB_ARRAY_DIVISOR 0x88FE + +// +==============================+ +// | Transform Feedback | +// +==============================+ +#define GL_TRANSFORM_FEEDBACK_BUFFER_MODE 0x8C7F +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_COMPONENTS 0x8C80 +#define GL_TRANSFORM_FEEDBACK_VARYINGS 0x8C83 +#define GL_TRANSFORM_FEEDBACK_BUFFER_START 0x8C84 +#define GL_TRANSFORM_FEEDBACK_BUFFER_SIZE 0x8C85 +#define GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN 0x8C88 +#define GL_MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS 0x8C8A +#define GL_MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS 0x8C8B +#define GL_INTERLEAVED_ATTRIBS 0x8C8C +#define GL_SEPARATE_ATTRIBS 0x8C8D +#define GL_TRANSFORM_FEEDBACK_BUFFER 0x8C8E +#define GL_TRANSFORM_FEEDBACK_BUFFER_BINDING 0x8C8F +#define GL_TRANSFORM_FEEDBACK 0x8E22 +#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23 +#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25 + +// +================================+ +// | Framebuffers and Renderbuffers | +// +================================+ +#define GL_FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING 0x8210 +#define GL_FRAMEBUFFER_ATTACHMENT_COMPONENT_TYPE 0x8211 +#define GL_FRAMEBUFFER_ATTACHMENT_RED_SIZE 0x8212 +#define GL_FRAMEBUFFER_ATTACHMENT_GREEN_SIZE 0x8213 +#define GL_FRAMEBUFFER_ATTACHMENT_BLUE_SIZE 0x8214 +#define GL_FRAMEBUFFER_ATTACHMENT_ALPHA_SIZE 0x8215 +#define GL_FRAMEBUFFER_ATTACHMENT_DEPTH_SIZE 0x8216 +#define GL_FRAMEBUFFER_ATTACHMENT_STENCIL_SIZE 0x8217 +#define GL_FRAMEBUFFER_DEFAULT 0x8218 +#define GL_DEPTH_STENCIL_ATTACHMENT 0x821A +#define GL_DEPTH_STENCIL 0x84F9 +#define GL_DEPTH24_STENCIL8 0x88F0 +#define GL_DRAW_FRAMEBUFFER_BINDING 0x8CA6 +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#define GL_READ_FRAMEBUFFER_BINDING 0x8CAA +#define GL_RENDERBUFFER_SAMPLES 0x8CAB +#define GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LAYER 0x8CD4 +#define GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE 0x8D56 + +// +==============================+ +// | Uniforms | +// +==============================+ +#define GL_UNIFORM_BUFFER 0x8A11 +#define GL_UNIFORM_BUFFER_BINDING 0x8A28 +#define GL_UNIFORM_BUFFER_START 0x8A29 +#define GL_UNIFORM_BUFFER_SIZE 0x8A2A +#define GL_MAX_VERTEX_UNIFORM_BLOCKS 0x8A2B +#define GL_MAX_FRAGMENT_UNIFORM_BLOCKS 0x8A2D +#define GL_MAX_COMBINED_UNIFORM_BLOCKS 0x8A2E +#define GL_MAX_UNIFORM_BUFFER_BINDINGS 0x8A2F +#define GL_MAX_UNIFORM_BLOCK_SIZE 0x8A30 +#define GL_MAX_COMBINED_VERTEX_UNIFORM_COMPONENTS 0x8A31 +#define GL_MAX_COMBINED_FRAGMENT_UNIFORM_COMPONENTS 0x8A33 +#define GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT 0x8A34 +#define GL_ACTIVE_UNIFORM_BLOCKS 0x8A36 +#define GL_UNIFORM_TYPE 0x8A37 +#define GL_UNIFORM_SIZE 0x8A38 +#define GL_UNIFORM_BLOCK_INDEX 0x8A3A +#define GL_UNIFORM_OFFSET 0x8A3B +#define GL_UNIFORM_ARRAY_STRIDE 0x8A3C +#define GL_UNIFORM_MATRIX_STRIDE 0x8A3D +#define GL_UNIFORM_IS_ROW_MAJOR 0x8A3E +#define GL_UNIFORM_BLOCK_BINDING 0x8A3F +#define GL_UNIFORM_BLOCK_DATA_SIZE 0x8A40 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS 0x8A42 +#define GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES 0x8A43 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_VERTEX_SHADER 0x8A44 +#define GL_UNIFORM_BLOCK_REFERENCED_BY_FRAGMENT_SHADER 0x8A46 + +// +==============================+ +// | Sync Objects | +// +==============================+ +#define GL_OBJECT_TYPE 0x9112 +#define GL_SYNC_CONDITION 0x9113 +#define GL_SYNC_STATUS 0x9114 +#define GL_SYNC_FLAGS 0x9115 +#define GL_SYNC_FENCE 0x9116 +#define GL_SYNC_GPU_COMMANDS_COMPLETE 0x9117 +#define GL_UNSIGNALED 0x9118 +#define GL_SIGNALED 0x9119 +#define GL_ALREADY_SIGNALED 0x911A +#define GL_TIMEOUT_EXPIRED 0x911B +#define GL_CONDITION_SATISFIED 0x911C +#define GL_WAIT_FAILED 0x911D +#define GL_SYNC_FLUSH_COMMANDS_BIT 0x00000001 + +// +==============================+ +// | Miscellaneous | +// +==============================+ +#define GL_COLOR 0x1800 +#define GL_DEPTH 0x1801 +#define GL_STENCIL 0x1802 +#define GL_MIN 0x8007 +#define GL_MAX 0x8008 +#define GL_DEPTH_COMPONENT24 0x81A6 +#define GL_STREAM_READ 0x88E1 +#define GL_STREAM_COPY 0x88E2 +#define GL_STATIC_READ 0x88E5 +#define GL_STATIC_COPY 0x88E6 +#define GL_DYNAMIC_READ 0x88E9 +#define GL_DYNAMIC_COPY 0x88EA +#define GL_DEPTH_COMPONENT32F 0x8CAC +#define GL_DEPTH32F_STENCIL8 0x8CAD +#define GL_INVALID_INDEX 0xFFFFFFFF +#define GL_TIMEOUT_IGNORED 1 +#define GL_MAX_CLIENT_WAIT_TIMEOUT_WEBGL 0x9247 + +//TODO: Any extension constants we want to add here? + +#endif // _CWASM_WEBGL_CONSTANTS_H diff --git a/cwasm_webgl_js_imports.h b/cwasm_webgl_js_imports.h new file mode 100644 index 0000000..da0da59 --- /dev/null +++ b/cwasm_webgl_js_imports.h @@ -0,0 +1,35 @@ +/* +File: cwasm_webgl_js_imports.h +Author: Taylor Robbins +Date: 09\01\2025 +*/ + +#ifndef _CWASM_WEBGL_JS_IMPORTS_H +#define _CWASM_WEBGL_JS_IMPORTS_H + +typedef int GlId; // Really this is just an index into a javascript array that holds the real reference to the WebGL object +typedef int GlEnum; + +MAYBE_EXTERN_C GlId jsGlCreateBuffer(); +MAYBE_EXTERN_C void jsGlBindBuffer(GlEnum bufferType, GlId bufferId); +MAYBE_EXTERN_C void jsGlBufferData(GlEnum bufferType, u32 dataLength, const void* dataPntr, GlEnum usageHint); +MAYBE_EXTERN_C GlId jsGlCreateVertexArray(); +MAYBE_EXTERN_C void jsGlBindVertexArray(GlId vaoId); +MAYBE_EXTERN_C void jsGlEnableVertexAttribArray(GlEnum location); +MAYBE_EXTERN_C void jsGlVertexAttribPointer(GlEnum attribLocation, int componentCount, GlEnum componentType, bool normalized, int stride, int offset); +MAYBE_EXTERN_C GlId jsGlCreateShader(GlEnum shaderType); +MAYBE_EXTERN_C void jsGlShaderSource(GlId shaderId, int sourceLength, const char* sourcePntr); +MAYBE_EXTERN_C void jsGlCompileShader(GlId shaderId); +MAYBE_EXTERN_C bool jsGlGetShaderParameterBool(GlId shaderId, GlEnum parameter); +MAYBE_EXTERN_C int jsGlGetShaderParameterInt(GlId shaderId, GlEnum parameter); +MAYBE_EXTERN_C GlId jsGlCreateProgram(); +MAYBE_EXTERN_C void jsGlAttachShader(GlId programId, GlId shaderId); +MAYBE_EXTERN_C void jsGlLinkProgram(GlId programId); +MAYBE_EXTERN_C void jsGlUseProgram(GlId programId); +MAYBE_EXTERN_C bool jsGlGetProgramParameterBool(GlId programId, GlEnum parameter); +MAYBE_EXTERN_C int jsGlGetProgramParameterInt(GlId programId, GlEnum parameter); +MAYBE_EXTERN_C void jsGlClearColor(r32 rValue, r32 gValue, r32 bValue, r32 aValue); +MAYBE_EXTERN_C void jsGlClear(int bufferBits); +MAYBE_EXTERN_C void jsGlDrawArrays(GlEnum geometryType, int startIndex, int count); + +#endif // _CWASM_WEBGL_JS_IMPORTS_H diff --git a/data/gl_functions.js b/data/gl_functions.js new file mode 100644 index 0000000..34e6323 --- /dev/null +++ b/data/gl_functions.js @@ -0,0 +1,236 @@ + +import { appGlobals } from './globals.js' +import { wasmPntrToJsString, wasmPntrAndLengthToJsString } from './wasm_functions.js' + +export var glObjects = { + buffers: [ null ], + vaos: [ null ], + shaders: [ null ], + programs: [ null ], +}; + +// +--------------------------------------------------------------+ +// | Helpers | +// +--------------------------------------------------------------+ +export function verifyGlBufferId(bufferId, allowZero) +{ + if (typeof(bufferId) != "number") { return "BufferId is not a number!"; } + if (bufferId == 0) { return allowZero ? null : "BufferId is 0!"; } + if (glObjects == null || glObjects.buffers == null) { return "Buffers array has not been initialized yet!"; } + if (bufferId >= glObjects.buffers.length) { return "BufferId is too high!"; } + if (glObjects.buffers[bufferId] == null) { return "BufferId is for a destroyed vertBuffer!"; } + return null; +} +export function verifyGlVaoId(vaoId, allowZero) +{ + if (typeof(vaoId) != "number") { return "VaoId is not a number!"; } + if (vaoId == 0) { return allowZero ? null : "VaoId is 0!"; } + if (glObjects == null || glObjects.vaos == null) { return "Vaos array has not been initialized yet!"; } + if (vaoId >= glObjects.vaos.length) { return "VaoId is too high!"; } + if (glObjects.vaos[vaoId] == null) { return "VaoId is for a destroyed array!"; } + return null; +} +export function verifyGlShaderId(shaderId, allowZero) +{ + if (typeof(shaderId) != "number") { return "ShaderId is not a number!"; } + if (shaderId == 0) { return allowZero ? null : "ShaderId is 0!"; } + if (glObjects == null || glObjects.shaders == null) { return "Shaders array has not been initialized yet!"; } + if (shaderId >= glObjects.shaders.length) { return "ShaderId is too high!"; } + if (glObjects.shaders[shaderId] == null) { return "ShaderId is for a destroyed shader!"; } + return null; +} +export function verifyGlProgramId(programId, allowZero) +{ + if (typeof(programId) != "number") { return "ProgramId is not a number!"; } + if (programId == 0) { return allowZero ? null : "ProgramId is 0!"; } + if (glObjects == null || glObjects.programs == null) { return "Programs array has not been initialized yet!"; } + if (programId >= glObjects.programs.length) { return "ProgramId is too high!"; } + if (glObjects.programs[programId] == null) { return "ProgramId is for a destroyed program!"; } + return null; +} +export function verifyParameter(verifyResult, functionName, parameterName, parameterValue) +{ + if (verifyResult == null) { return true; } + console.error("Invalid argument \"" + parameterName + "\" passed to " + functionName + ": " + verifyResult); + console.error("Argument value: " + parameterValue); + return false; +} + +// +--------------------------------------------------------------+ +// | WebGL API | +// +--------------------------------------------------------------+ +export function jsGlCreateBuffer() +{ + let newBuffer = appGlobals.glContext.createBuffer(); + let newBufferId = glObjects.buffers.length; + glObjects.buffers.push(newBuffer); + return newBufferId; +} + +export function jsGlBindBuffer(bufferType, bufferId) +{ + if (!verifyParameter(verifyGlBufferId(bufferId, true), "gl.bindBuffer", "bufferId", bufferId)) { return; } + let buffer = glObjects.buffers[bufferId]; + appGlobals.glContext.bindBuffer(bufferType, buffer); +} + +export function jsGlBufferData(bufferType, dataLength, dataPntr, usageHint) +{ + let dataArray = appGlobals.memDataView.buffer.slice(dataPntr, dataPntr + dataLength) + appGlobals.glContext.bufferData(bufferType, dataArray, usageHint); +} + +export function jsGlCreateVertexArray() +{ + let newVao = appGlobals.glContext.createVertexArray(); + let newVaoId = glObjects.vaos.length; + glObjects.vaos.push(newVao); + return newVaoId; +} + +export function jsGlBindVertexArray(vaoId) +{ + if (!verifyParameter(verifyGlVaoId(vaoId, true), "gl.bindVertexArray", "vaoId", vaoId)) { return; } + let vao = glObjects.vaos[vaoId]; + appGlobals.glContext.bindVertexArray(vao); +} + +export function jsGlEnableVertexAttribArray(location) +{ + appGlobals.glContext.enableVertexAttribArray(location); +} + +export function jsGlVertexAttribPointer(attribLocation, componentCount, componentType, normalized, stride, offset) +{ + appGlobals.glContext.vertexAttribPointer(attribLocation, componentCount, componentType, normalized, stride, offset); +} + +export function jsGlCreateShader(shaderType) +{ + let newShader = appGlobals.glContext.createShader(shaderType); + let newShaderId = glObjects.shaders.length; + glObjects.shaders.push(newShader); + return newShaderId; +} + +export function jsGlShaderSource(shaderId, sourceLength, sourcePntr) +{ + if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.shaderSource", "shaderId", shaderId)) { return; } + let shader = glObjects.shaders[shaderId]; + let sourceStr = wasmPntrAndLengthToJsString(sourcePntr, sourceLength); + appGlobals.glContext.shaderSource(shader, sourceStr); +} + +export function jsGlCompileShader(shaderId) +{ + if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.compileShader", "shaderId", shaderId)) { return; } + let shader = glObjects.shaders[shaderId]; + appGlobals.glContext.compileShader(shader); +} + +export function jsGlGetShaderParameterBool(shaderId, parameter) +{ + if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.getShaderParameter", "shaderId", shaderId)) { return false; } + let shader = glObjects.shaders[shaderId]; + let paramValue = appGlobals.glContext.getShaderParameter(shader, parameter); + if (typeof(paramValue) != "boolean") { console.error("Tried to get GL parameter " + parameter + " as bool when it's actually: " + typeof(paramValue)); return false; } + return paramValue; +} +export function jsGlGetShaderParameterInt(shaderId, parameter) +{ + if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.getShaderParameter", "shaderId", shaderId)) { return false; } + let shader = glObjects.shaders[shaderId]; + let paramValue = appGlobals.glContext.getShaderParameter(shader, parameter); + if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as number when it's actually: " + typeof(paramValue)); return false; } + return paramValue; +} + +export function jsGlCreateProgram() +{ + let newProgram = appGlobals.glContext.createProgram(); + let newProgramId = glObjects.programs.length; + glObjects.programs.push(newProgram); + return newProgramId; +} + +export function jsGlAttachShader(programId, shaderId) +{ + if (!verifyParameter(verifyGlProgramId(programId, false), "gl.attachShader", "programId", programId)) { return; } + if (!verifyParameter(verifyGlShaderId(shaderId, false), "gl.attachShader", "shaderId", shaderId)) { return; } + let program = glObjects.programs[programId]; + let shader = glObjects.shaders[shaderId]; + appGlobals.glContext.attachShader(program, shader); +} + +export function jsGlLinkProgram(programId) +{ + if (!verifyParameter(verifyGlProgramId(programId, false), "gl.linkProgram", "programId", programId)) { return; } + let program = glObjects.programs[programId]; + appGlobals.glContext.linkProgram(program); +} + +export function jsGlUseProgram(programId) +{ + if (!verifyParameter(verifyGlProgramId(programId, true), "gl.useProgram", "programId", programId)) { return; } + let program = glObjects.programs[programId]; + appGlobals.glContext.useProgram(program); +} + +export function jsGlGetProgramParameterBool(programId, parameter) +{ + if (!verifyParameter(verifyGlProgramId(programId, false), "gl.getProgramParameter", "programId", programId)) { return false; } + let program = glObjects.programs[programId]; + let paramValue = appGlobals.glContext.getProgramParameter(program, parameter); + if (typeof(paramValue) != "boolean") { console.error("Tried to get GL parameter " + parameter + " as bool when it's actually: " + typeof(paramValue)); return false; } + return paramValue; +} +export function jsGlGetProgramParameterInt(programId, parameter) +{ + if (!verifyParameter(verifyGlProgramId(programId, false), "gl.getProgramParameter", "programId", programId)) { return false; } + let program = glObjects.programs[programId]; + let paramValue = appGlobals.glContext.getProgramParameter(program, parameter); + if (typeof(paramValue) != "number") { console.error("Tried to get GL parameter " + parameter + " as number when it's actually: " + typeof(paramValue)); return false; } + return paramValue; +} + +export function jsGlClearColor(rValue, gValue, bValue, aValue) +{ + appGlobals.glContext.clearColor(rValue, gValue, bValue, aValue); +} + +export function jsGlClear(bufferBits) +{ + appGlobals.glContext.clear(bufferBits); +} + +export function jsGlDrawArrays(geometryType, startIndex, count) +{ + appGlobals.glContext.drawArrays(geometryType, startIndex, count); +} + +export let jsGlFunctions = { + jsGlCreateBuffer: jsGlCreateBuffer, + jsGlBindBuffer: jsGlBindBuffer, + jsGlBufferData: jsGlBufferData, + jsGlCreateVertexArray: jsGlCreateVertexArray, + jsGlBindVertexArray: jsGlBindVertexArray, + jsGlEnableVertexAttribArray: jsGlEnableVertexAttribArray, + jsGlVertexAttribPointer: jsGlVertexAttribPointer, + jsGlCreateShader: jsGlCreateShader, + jsGlShaderSource: jsGlShaderSource, + jsGlCompileShader: jsGlCompileShader, + jsGlGetShaderParameterBool: jsGlGetShaderParameterBool, + jsGlGetShaderParameterInt: jsGlGetShaderParameterInt, + jsGlCreateProgram: jsGlCreateProgram, + jsGlAttachShader: jsGlAttachShader, + jsGlLinkProgram: jsGlLinkProgram, + jsGlUseProgram: jsGlUseProgram, + jsGlGetProgramParameterBool: jsGlGetProgramParameterBool, + jsGlGetProgramParameterInt: jsGlGetProgramParameterInt, + jsGlClearColor: jsGlClearColor, + jsGlClear: jsGlClear, + jsGlDrawArrays: jsGlDrawArrays, +}; + +//TODO: string getShaderInfoLog(shaderId) +//TODO: string getProgramInfoLog(programId) diff --git a/data/globals.js b/data/globals.js new file mode 100644 index 0000000..0c9a20d --- /dev/null +++ b/data/globals.js @@ -0,0 +1,14 @@ + +export const WASM_MEMORY_PAGE_SIZE = (64 * 1024); //64kB or 65,536b +export const WASM_MEMORY_MAX_NUM_PAGES = (64 * 1024) //65,536 pages * 64 kB/page = 4GB +export const WASM_MEMORY_MAX_SIZE = (WASM_MEMORY_MAX_NUM_PAGES * WASM_MEMORY_PAGE_SIZE) + +export var appGlobals = +{ + heapBase: 0, + canvas: null, + glContext: null, + memDataView: null, + wasmModule: null, + textDecoder: null, +}; diff --git a/data/index.html b/data/index.html new file mode 100644 index 0000000..5c66f56 --- /dev/null +++ b/data/index.html @@ -0,0 +1,20 @@ + + + + + + + + +
+

🠟 The canvas is below 🠟

+
+ + Your browser does not support the HTML5 canvas tag. + +
+

🠝 The canvas is above 🠝

+
+ + + \ No newline at end of file diff --git a/data/main.css b/data/main.css new file mode 100644 index 0000000..f0763b0 --- /dev/null +++ b/data/main.css @@ -0,0 +1,22 @@ +body +{ + /* TODO: Where does this collection of font names come from? Is it standard or something? */ + font-family: -apple-system,BlinkMacSystemFont,segoe ui,Helvetica,Arial,sans-serif,apple color emoji,segoe ui emoji,segoe ui symbol; +} + +.main_section +{ + text-align: center; +} + +#canvas_container +{ + display: inline-block; +} + +canvas +{ + border: 1px solid black; + width: 640px; + height: 480px; +} \ No newline at end of file diff --git a/data/main.js b/data/main.js new file mode 100644 index 0000000..3401367 --- /dev/null +++ b/data/main.js @@ -0,0 +1,80 @@ + +import { WASM_MEMORY_PAGE_SIZE, appGlobals } from './globals.js' +import { loadWasmModule, wasmPntrToJsString, wasmPntrAndLengthToJsString } from './wasm_functions.js' +import { jsStdFunctions } from './std_functions.js' +import { jsGlFunctions } from './gl_functions.js' + +function AcquireCanvas(canvasWidth, canvasHeight) +{ + var canvas = document.getElementsByTagName("canvas")[0]; + // console.log(canvas); + + // set the display size of the canvas. + canvas.style.width = canvasWidth + "px"; + canvas.style.height = canvasHeight + "px"; + + // set the size of the drawingBuffer + var devicePixelRatio = window.devicePixelRatio || 1; + canvas.width = canvasWidth * devicePixelRatio; + canvas.height = canvasHeight * devicePixelRatio; + + // canvasContainer = document.getElementById("canvas_container"); + // console.assert(canvasContainer != null, "Couldn't find canvas container DOM element!"); + appGlobals.canvas = canvas; + return canvas; +} + +function CreateGlContext(canvas) +{ + var canvasContextGl = canvas.getContext("webgl2"); + if (canvasContextGl === null) { console.error("Unable to initialize WebGL render context. Your browser or machine may not support it :("); return null; } + // console.dir(canvasContextGl); + appGlobals.glContext = canvasContextGl; + return canvasContextGl; +} + +async function LoadWasmModule(wasmFilePath, initialWasmPageCount) +{ + appGlobals.textDecoder = new TextDecoder("utf-8"); + + let wasmEnvironment = + { + ...jsStdFunctions, + ...jsGlFunctions, + }; + appGlobals.wasmModule = await loadWasmModule(wasmFilePath, wasmEnvironment); + + appGlobals.memDataView = new DataView(new Uint8Array(appGlobals.wasmModule.exports.memory.buffer).buffer); + // let heapBaseAddress = appGlobals.wasmModule.exports.__heap_base.value; + // console.log("__heap_base = " + heapBaseAddress); + + let memorySize = appGlobals.wasmModule.exports.memory.buffer.byteLength; + let numMemoryPagesAfterLoad = memorySize / WASM_MEMORY_PAGE_SIZE; + if ((memorySize % WASM_MEMORY_PAGE_SIZE) != 0) + { + console.warn("memorySize (" + memorySize + ") is not a multiple of WASM_MEMORY_PAGE_SIZE (" + WASM_MEMORY_PAGE_SIZE + ")"); + numMemoryPagesAfterLoad++; + } + appGlobals.wasmModule.exports.init_mem(numMemoryPagesAfterLoad); +} + +async function MainLoop() +{ + console.log("Initializing WebGL Canvas..."); + var canvas = AcquireCanvas(600, 400); + var glContext = CreateGlContext(canvas); + + console.log("Loading WASM Module..."); + await LoadWasmModule("app.wasm", 4); + appGlobals.wasmModule.exports.App_Initialize(); + + console.log("Running!"); + function renderFrame() + { + appGlobals.wasmModule.exports.App_UpdateAndRender(); + window.requestAnimationFrame(renderFrame); + } + window.requestAnimationFrame(renderFrame); +} + +MainLoop(); \ No newline at end of file diff --git a/data/std_functions.js b/data/std_functions.js new file mode 100644 index 0000000..560c8c7 --- /dev/null +++ b/data/std_functions.js @@ -0,0 +1,73 @@ +/* +File: std_functions.c +Author: Taylor Robbins +Date: 09\01\2025 +Description: + ** Contains all the functions that are required as imports by the C standard library implementation in the std folder +*/ + +import { WASM_MEMORY_PAGE_SIZE, appGlobals } from './globals.js' +import { wasmPntrToJsString, wasmPntrAndLengthToJsString } from './wasm_functions.js' + +export function jsStdPrint(level, messageStrPntr, messageLength) +{ + let messageStr = wasmPntrAndLengthToJsString(messageStrPntr, messageLength); + if (level == 0) { console.debug(messageStr); } + else if (level == 1) { console.info(messageStr); } + else if (level == 2) { console.warn(messageStr); } + else if (level == 3) { console.error(messageStr); } + else { console.log(messageStr); } +} + +export function jsStdAbort(messageStrPntr, exitCode) +{ + let messageStr = wasmPntrToJsString(messageStrPntr); + let exitStr = "Abort [" + exitCode + "]: " + messageStr; + console.error(exitStr); + throw new Error(exitStr); +} + +export function jsStdAssertFailure(filePathPntr, fileLineNum, funcNamePntr, conditionStrPntr, messageStrPntr) +{ + let filePath = wasmPntrToJsString(filePathPntr); + let funcName = wasmPntrToJsString(funcNamePntr); + let conditionStr = wasmPntrToJsString(conditionStrPntr); + let outputMessage = ""; + if (messageStrPntr != 0) + { + let messageStr = wasmPntrToJsString(messageStrPntr); + outputMessage = "Assertion failed, " + messageStr + " (" + conditionStr + ") is not true! In " + filePath + ":" + fileLineNum + " " + funcName + "(...)"; + } + else + { + outputMessage = "Assertion failed! (" + conditionStr + ") is not true! In " + filePath + ":" + fileLineNum + " " + funcName + "(...)"; + } + console.error(outputMessage); + throw new Error(outputMessage); +} + +export function jsStdDebugBreak() +{ + //TODO: This is not a proper solution, really. Can we somehow notify the debugger in Firefox/Chrome/Safari/etc.? + alert("A debug breakpoint has been hit!"); +} + +//TODO: Can we use these inside the Wasm module rather than calling out to javascript?? +// __builtin_wasm_memory_size(0); // the number of 64Kb pages we have +// __builtin_wasm_memory_grow(0, blocks); // increases amount of pages +// __builtin_huge_valf(); // similar to Infinity in JS +export function jsStdGrowMemory(numPages) +{ + let currentPageCount = appGlobals.wasmModule.exports.memory.buffer.byteLength / WASM_MEMORY_PAGE_SIZE; + // console.log("Memory growing by " + numPages + " pages (" + currentPageCount + " -> " + (currentPageCount + numPages) + ")"); + appGlobals.wasmModule.exports.memory.grow(numPages); + appGlobals.memDataView = new DataView(new Uint8Array(appGlobals.wasmModule.exports.memory.buffer).buffer); +} + +export let jsStdFunctions = { + jsStdPrint: jsStdPrint, + jsStdAbort: jsStdAbort, + jsStdAssertFailure: jsStdAssertFailure, + jsStdDebugBreak: jsStdDebugBreak, + jsStdGrowMemory: jsStdGrowMemory, +}; diff --git a/data/wasm_functions.js b/data/wasm_functions.js new file mode 100644 index 0000000..7177602 --- /dev/null +++ b/data/wasm_functions.js @@ -0,0 +1,42 @@ + +import { appGlobals } from './globals.js' + +export async function loadWasmModule(filePath, environment) +{ + let result = null; + try + { + const fetchPromise = fetch(filePath); + const wasmModule = await WebAssembly.instantiateStreaming( + fetchPromise, + { env: environment } + ); + result = wasmModule.instance; + } + catch (exception) + { + console.error("Failed to load WASM module from \"" + filePath + "\":", exception); + } + return result; +} + +//TODO: We should do some performance measurements of wasmPntrToJsString vs wasmPntrAndLengthToJsString! +export function wasmPntrToJsString(ptr) +{ + let cIndex = ptr; + while (cIndex < appGlobals.memDataView.byteLength) + { + let byteValue = appGlobals.memDataView.getUint8(cIndex, true); + if (byteValue == 0) { break; } + cIndex++; + } + return appGlobals.textDecoder.decode( + appGlobals.memDataView.buffer.slice(ptr, cIndex) + ); +} +export function wasmPntrAndLengthToJsString(ptr, length) +{ + return appGlobals.textDecoder.decode( + appGlobals.memDataView.buffer.slice(ptr, ptr + length) + ); +} diff --git a/test_app.c b/test_app.c index 64ee8e9..8dc2916 100644 --- a/test_app.c +++ b/test_app.c @@ -8,20 +8,143 @@ Description: #include "cwasm.c" -#define SCRATCH_ARENAS_SIZE Kilobytes(128) - -WASM_EXPORT(InitializeApp) void InitializeApp() +struct { - InitializeCWasm(SCRATCH_ARENAS_SIZE); + GlId positionBuffer; + GlId colorBuffer; + GlId vao; + GlId vertexShader; + GlId fragmentShader; + GlId testShader; + + u32 frameIndex; +} app; + +static const char* VertexShaderCodeStr; +static const char* FragmentShaderCodeStr; + +WASM_EXPORT(App_Initialize) void App_Initialize() +{ + InitializeCWasm(Kilobytes(128)); + + memset(&app, 0x00, sizeof(app)); + + r32 positions[] = { + -0.9, -0.79, // left bottom corner + 1.0, -1.0, // right bottom corner + 0.0, 1.0 // center top corner + }; + app.positionBuffer = jsGlCreateBuffer(); + jsGlBindBuffer(GL_ARRAY_BUFFER, app.positionBuffer); + jsGlBufferData(GL_ARRAY_BUFFER, sizeof(positions), &positions[0], GL_STATIC_DRAW); + + u8 colors[] = { + // R , G , B + 255, 0, 0, // red + 0, 255, 0, // green + 0, 0, 255 // blue + }; + app.colorBuffer = jsGlCreateBuffer(); + jsGlBindBuffer(GL_ARRAY_BUFFER, app.colorBuffer); + jsGlBufferData(GL_ARRAY_BUFFER, sizeof(colors), &colors[0], GL_STATIC_DRAW); + + app.vao = jsGlCreateVertexArray(); + jsGlBindVertexArray(app.vao); // start "recording" + // position attribute data + jsGlBindBuffer(GL_ARRAY_BUFFER, app.positionBuffer); + jsGlEnableVertexAttribArray(0); + jsGlVertexAttribPointer( + 0, // attrib location + 2, // components per element: vec2 for our postition data + GL_FLOAT, // buffer data type: we have Float32Array + false, // whether the data is normalized to 0.0 1.0 range in shaders + 0, // stride, not important atm + 0 // offset, not important atm + ); + // color attribute data + jsGlBindBuffer(GL_ARRAY_BUFFER, app.colorBuffer); + jsGlEnableVertexAttribArray(1); + jsGlVertexAttribPointer( + 1, // attrib location + 3, // components per element: + GL_UNSIGNED_BYTE, // we have Uint8Array + true, // the 0..255 is normalized into 0.0...1.0 in shaders + 0, + 0 + ); + jsGlBindVertexArray(0); // end "recording" + + app.vertexShader = jsGlCreateShader(GL_VERTEX_SHADER); + jsGlShaderSource(app.vertexShader, (int)strlen(VertexShaderCodeStr), VertexShaderCodeStr); + jsGlCompileShader(app.vertexShader); + if (!jsGlGetShaderParameterBool(app.vertexShader, GL_COMPILE_STATUS)) { WriteLine_E("Failed to compile vertex shader!"); } //TODO: jsGlGetShaderInfoLog + app.fragmentShader = jsGlCreateShader(GL_FRAGMENT_SHADER); + jsGlShaderSource(app.fragmentShader, (int)strlen(FragmentShaderCodeStr), FragmentShaderCodeStr); + jsGlCompileShader(app.fragmentShader); + if (!jsGlGetShaderParameterBool(app.fragmentShader, GL_COMPILE_STATUS)) { WriteLine_E("Failed to compile fragment shader!"); } //TODO: jsGlGetShaderInfoLog + app.testShader = jsGlCreateProgram(); + jsGlAttachShader(app.testShader, app.vertexShader); + jsGlAttachShader(app.testShader, app.fragmentShader); + jsGlLinkProgram(app.testShader); + // also debug the program status + if (!jsGlGetProgramParameterBool(app.testShader, GL_LINK_STATUS)) { WriteLine_E("Failed to link shader program!"); } //TODO: jsGlGetProgramInfoLog } -WASM_EXPORT(HelloFromWasm) float HelloFromWasm(float value, float value2) +WASM_EXPORT(App_UpdateAndRender) void App_UpdateAndRender() { - printf("Called HelloFromWasm(%g)!\n", fmodf(value, value2)); - for (int iIndex = 0; iIndex < 1024; iIndex++) - { - void* newMem = grow_mem(1024); - printf("mem[%d] = %p\n", iIndex, newMem); - } - return value*(value+1)*2; + r32 time = app.frameIndex * (1000.0f/60.0f); + jsGlClearColor(sinf(time * 0.0005f + 1.5f)/2 + 0.5f, sinf(time * 0.0013f + 2.3f)/2 + 0.5f, sinf(time * 0.0007f + 3.7f)/2 + 0.5f, 1.0f); + jsGlClear(GL_COLOR_BUFFER_BIT); + jsGlBindVertexArray(app.vao); // our vertex array object + jsGlUseProgram(app.testShader); // our shader program + jsGlDrawArrays( + GL_TRIANGLES, // drawing mode + 0, // index of the first vertex to draw + 3 // number of vertices to draw + ); + + app.frameIndex++; } + +static const char* VertexShaderCodeStr = "#version 300 es\n" +"// ^^^\n" +"// the version definition has to be the first line in\n" +"// the string.\n" +"\n" +"// sets the precision level for all float and vec\n" +"// data types\n" +"precision highp float;\n" +"\n" +"// this is the vertex attribute at index 0\n" +"// which we defined in the vertex array object.\n" +"// we can use any name for this in the glsl code\n" +"// the important bit is the location=0\n" +"layout(location=0) in vec2 aPos;\n" +"\n" +"// this is the color attrib at index: 1\n" +"layout(location=1) in vec3 aCol;\n" +"\n" +"// this is the interpolate color which is\n" +"// passed to the fragment shader\n" +"out vec3 vCol;\n" +"\n" +"void main(){\n" +" vCol = aCol; // just pass through the value \n" +" \n" +" // vertex position for the shader program\n" +" // always a vec4 value\n" +" gl_Position = vec4(aPos, 0.0, 1.0);\n" +"}\n"; + +static const char* FragmentShaderCodeStr = "#version 300 es\n" +"precision highp float;\n" +"\n" +"in vec3 vCol; // the data from vertex shader\n" +"\n" +"// fragment output value\n" +"// essentially the color of the output pixel\n" +"out vec4 outCol;\n" +"\n" +"void main(){\n" +" outCol = vec4(vCol, 1.0);\n" +"}\n";