diff --git a/build/build.sh b/build/build.sh index 9be186f..d2ffa2d 100644 --- a/build/build.sh +++ b/build/build.sh @@ -1,2 +1,3 @@ SCRIPT_REL_DIR=$(dirname "${BASH_SOURCE[0]}") -$SCRIPT_REL_DIR/build_.sh debug win32 intel \ No newline at end of file +$SCRIPT_REL_DIR/build_.sh debug win32 intel +$SCRIPT_REL_DIR/build_.sh debug wasm intel \ No newline at end of file diff --git a/build/build_.sh b/build/build_.sh index b70899a..b7d0978 100644 --- a/build/build_.sh +++ b/build/build_.sh @@ -126,6 +126,7 @@ add_flag CompilerFlags_win32 "-wd4505" # add_flag CompilerFlags_win32 "-wd4100" # add_flag CompilerFlags_win32 "-wd4189" # add_flag CompilerFlags_win32 "-wd4702" # +add_flag CompilerFlags_win32 "-wd4996" # _CRT_SECURE_NO_WARNINGS CompilerFlags_osx="" @@ -143,6 +144,7 @@ CompilerFlags_DEBUG_win32="" add_flag CompilerFlags_DEBUG_win32 "-Od" # add_flag CompilerFlags_DEBUG_win32 "-Zi" # add_flag CompilerFlags_DEBUG_win32 "-DDEBUG" # +add_flag CompilerFlags_DEBUG_win32 "-DPRINT_ASSERTS" CompilerFlags_DEBUG="-O0" add_flag CompilerFlags_DEBUG "-g" # diff --git a/run_tree/wasm/debug/lumenarium.wasm b/run_tree/wasm/debug/lumenarium.wasm index 898b757..2960aba 100644 Binary files a/run_tree/wasm/debug/lumenarium.wasm and b/run_tree/wasm/debug/lumenarium.wasm differ diff --git a/run_tree/wasm/debug/lumenarium_wasm_imports.js b/run_tree/wasm/debug/lumenarium_wasm_imports.js index 299fa8a..29d372c 100644 --- a/run_tree/wasm/debug/lumenarium_wasm_imports.js +++ b/run_tree/wasm/debug/lumenarium_wasm_imports.js @@ -34,6 +34,35 @@ function wasm_get_proc(inst, proc_ptr) function fract (v) { return v % 1; } +function u32_to_byte_array_32 (v) +{ + let result = [0, 0, 0, 0]; + result[0] = (v & 0xff); + result[1] = (((v - result[0]) >> 8 ) & 0xff); + result[2] = (((v - result[1]) >> 16) & 0xff); + result[3] = (((v - result[2]) >> 24) & 0xff); + return result; +} + +function byte_array_32_to_u32 (arr) +{ + // NOTE(PS): the '>>>' operators in this function deal with the fact + // that bit shift operators convert numbers to s32's. The >>> just + // converts them back to u32s + let r0 = ((arr[0] & 0xff) << 0 ); + let r1 = ((arr[1] & 0xff) << 8 ); + let r2 = ((arr[2] & 0xff) << 16); + let r3 = (((arr[3] & 0xff) << 24) >>> 0); + let result = (r0 | r1 | r2 | r3) >>> 0; + return result; +} + +function put_u32 (ptr, value) +{ + let src = u32_to_byte_array_32(value); + wasm_write_bytes(lumenarium_wasm_instance, src, ptr, 4); +} + var lumenarium_wasm_imports = { memset: (dst, size, value) => { @@ -122,12 +151,46 @@ var lumenarium_wasm_imports = { let string = wasm_read_string(lumenarium_wasm_instance, str_base, len); console.log(string); }, + + wasm_get_canvas_dim: (w_ptr, h_ptr) => { + const canvas = document.querySelector("#gl_canvas"); + + let w_view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, w_ptr, 4); + let w = canvas.width; + let wb = u32_to_byte_array_32(w); + for (let i = 0; i < 4; i++) w_view[i] = wb[i]; + + let h_view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, h_ptr, 4); + let h = canvas.height; + let hb = u32_to_byte_array_32(h); + for (let i = 0; i < 4; i++) h_view[i] = hb[i]; + }, }; /////////////////////////////////////// // Web GL Imports let gl = null; +let gl_error = false; + +function glErrorReport(outer_args) { + const err = gl.getError(); + if (err == gl.NO_ERROR) return; + + gl_error = true; + let msg = ""; + switch (err) { + case gl.NO_ERROR: { msg = "NO_ERROR"; } break; + case gl.INVALID_ENUM: { msg = "INVALID_ENUM"; } break; + case gl.INVALID_VALUE: { msg = "INVALID_VALUE"; } break; + case gl.INVALID_OPERATION: { msg = "INVALID_OPERATION"; } break; + case gl.INVALID_FRAMEBUFFER_OPERATION: { msg = "INVALID_FRAMEBUFFER_OPERATION"; } break; + case gl.OUT_OF_MEMORY: { msg = "OUT_OF_MEMORY"; } break; + case gl.CONTEXT_LOST_WEBGL: { msg = "CONTEXT_LOST_WEBGL"; } break; + default: { msg = "Uknown error"; } break; + } + console.error(`WebGL Error: ${msg} ${err}`, outer_args); +} // NOTE(PS): it seems like its not enough to set // the values of imports to gl.function @@ -135,16 +198,37 @@ let gl = null; // instead we need to wrap them for some reason. // Not sure why function glClearColor (r, g, b, a) { return gl.clearColor(r,g,b,a); } -function glEnable(v) { return gl.enable(v); } -function glDisable(v) { return gl.disable(v); } -function glBlendFunc(a,b) { return gl.blendFunc(a,b); } +function glEnable(v) { + const r = gl.enable(v); + glErrorReport(arguments); + return r; +} +function glDisable(v) { + const r = gl.disable(v); + glErrorReport(arguments); + return r; +} +function glBlendFunc(a,b) { + const r = gl.blendFunc(a,b); + glErrorReport(arguments); + return r; +} function glViewport(xmin, ymin, xmax, ymax) { return gl.viewport(xmin,ymin,xmax,ymax); } -function glDepthFunc(v) { return gl.depthFunc(v); } -function glClear(mask) { return gl.clear(mask); } +function glDepthFunc(v) { + const r = gl.depthFunc(v); + glErrorReport(arguments); + return r; +} +function glClear(mask) { + const r = gl.clear(mask); + glErrorReport(arguments); + return r; +} let glBuffers = []; let glShaders = []; let glPrograms = []; +let glTextures = []; function gl_get_managed_resource(arr, id) { if (id == 0) return null; return arr[id - 1]; @@ -152,55 +236,76 @@ function gl_get_managed_resource(arr, id) { function gl_get_buffer(id) { return gl_get_managed_resource(glBuffers, id); } function gl_get_shader(id) { return gl_get_managed_resource(glShaders, id); } function gl_get_program(id) { return gl_get_managed_resource(glPrograms, id); } +function gl_get_texture(id) { return gl_get_managed_resource(glTextures, id); } function glCreateBuffer() { let buffer = gl.createBuffer(); + glErrorReport(arguments); let new_len = glBuffers.push(buffer); return new_len; } + function glBindBuffer(buffer_kind, buffer_id) { - return gl.bindBuffer(buffer_kind, gl_get_buffer(buffer_id)); + const r = gl.bindBuffer(buffer_kind, gl_get_buffer(buffer_id)); + glErrorReport(arguments); + return r; } + function glBufferData(target, size, ptr, usage) { let data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, size); - return gl.bufferData(target, data, usage); + const r = gl.bufferData(target, data, usage); + glErrorReport(arguments); + return r; } + function glCreateShader(kind) { let shader = gl.createShader(kind); + glErrorReport(arguments); let new_len = glShaders.push(shader); return new_len; } + function glShaderSource(shader_id, shader_code, shader_code_len) { let str = wasm_read_string(lumenarium_wasm_instance, shader_code, shader_code_len); - console.error("For some reason, str isn't getting the correct data out of here", str); - return gl.shaderSource(gl_get_shader(shader_id), str); + const r = gl.shaderSource(gl_get_shader(shader_id), str); + glErrorReport(arguments); + return r; } + function glCompileShader(shader_id) { let s = gl_get_shader(shader_id); let r = gl.compileShader(s); + glErrorReport(arguments); let m = gl.getShaderInfoLog(s); + glErrorReport(arguments); if (m.length > 0) { console.error("glCompileShader: \n\n" + m); } } + function glCreateProgram() { let prog = gl.createProgram(); + glErrorReport(arguments); let new_len = glPrograms.push(prog); return new_len; } + function glAttachShader(program, shader) { let s = gl_get_shader(shader); let p = gl_get_program(program); - return gl.attachShader(p, s); + const r = gl.attachShader(p, s); + glErrorReport(arguments); + return r; } + function glLinkProgram(program) { let p = gl_get_program(program); @@ -210,43 +315,94 @@ function glLinkProgram(program) console.error("Failed to compile WebGL program. \n\n"+info); } } + function glUseProgram(program) { let p = gl_get_program(program); - return gl.useProgram(p); + const r = gl.useProgram(p); + glErrorReport(arguments); + return r; } + function glGetAttribLocation(program, name, name_len) { let str = wasm_read_string(lumenarium_wasm_instance, name, name_len); - return gl.getAttribLocation(gl_get_program(program), str); + const r = gl.getAttribLocation(gl_get_program(program), str); + glErrorReport(arguments); + return r; } + function glVertexAttribPointer(attr, size, type, normalized, stride, pointer) { - return gl.vertexAttribPointer(attr, size, type, normalized, stride, pointer); + const r = gl.vertexAttribPointer(attr, size, type, normalized, stride, pointer); + glErrorReport(arguments); + return r; } + function glEnableVertexAttribArray(index) { - return gl.enableVertexAttribArray(index); + const r = gl.enableVertexAttribArray(index); + glErrorReport(arguments); + return r; } + function glDrawElements(type, index_count, ele_type, indices) { - return gl.drawElements(type, index_count, ele_type, indices); + const r = gl.drawElements(type, index_count, ele_type, indices); + glErrorReport(arguments); + return r; +} + +function glGenTextures(count, ids_ptr, ids_size) +{ + for (let i = 0; i < count; i++) + { + const tex = gl.createTexture(); + glErrorReport(arguments); + let new_len = glTextures.push(tex); + put_u32(ids_ptr + (i * 4), new_len); + } +} + +function glBindTexture(slot, id) +{ + let tex = gl_get_texture(id); + const r = gl.bindTexture(slot, tex); + glErrorReport(arguments); + return r; +} + +function glTexParameteri(slot, param, value) +{ + const r = gl.texParameteri(slot, param, value); + glErrorReport(arguments); + return r; +} + +function glTexImage2D(target, level, internalformat, width, height, border, format, type, data_ptr, data_size) +{ + const data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, data_ptr, data_size); + const r = gl.texImage2D(target, level, internalformat, width, height, border, format, type, data); + glErrorReport(arguments); + return r; +} + +function glTexSubImage2D(target, level, offsetx, offsety, width, height, format, type, data_ptr, data_size) +{ + const data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, data_ptr, data_size); + const r = gl.texSubImage2D(target, level, offsetx, offsety, width, height, format, type, data); + glErrorReport(arguments); + return r; } function webgl_add_imports (canvas_selector, imports) { const canvas = document.querySelector(canvas_selector); if (!canvas) return console.error("no canvas"); - gl = canvas.getContext("webgl"); + gl = canvas.getContext("webgl2"); if (gl === null) return console.error("no webgl ctx"); - console.log( - gl.FLOAT.toString(16), "\n", - gl.UNSIGNED_INT.toString(16), "\n" - ); - - - + imports.glHadError = () => { return gl_error; }; imports.glClearColor = glClearColor; imports.glEnable = glEnable; imports.glDisable = glDisable; @@ -269,6 +425,11 @@ function webgl_add_imports (canvas_selector, imports) { imports.glVertexAttribPointer = glVertexAttribPointer; imports.glEnableVertexAttribArray = glEnableVertexAttribArray; imports.glDrawElements = glDrawElements; - + imports.glGenTextures = glGenTextures; + imports.glBindTexture = glBindTexture; + imports.glTexParameteri = glTexParameteri; + imports.glTexImage2D = glTexImage2D; + imports.glTexSubImage2D = glTexSubImage2D; + imports.glBindTexture = glBindTexture; return imports; } \ No newline at end of file diff --git a/run_tree/win32/intel/debug/debug.rdbg b/run_tree/win32/intel/debug/debug.rdbg index 0f16f81..f78c41e 100644 Binary files a/run_tree/win32/intel/debug/debug.rdbg and b/run_tree/win32/intel/debug/debug.rdbg differ diff --git a/run_tree/win32/intel/debug/err.txt b/run_tree/win32/intel/debug/err.txt new file mode 100644 index 0000000..9002a22 --- /dev/null +++ b/run_tree/win32/intel/debug/err.txt @@ -0,0 +1 @@ +OpenGL Version: 3.3.0 - Build 27.20.100.9778 diff --git a/run_tree/win32/intel/debug/lumenarium_first_win32.obj b/run_tree/win32/intel/debug/lumenarium_first_win32.obj index 895b93c..f70d129 100644 Binary files a/run_tree/win32/intel/debug/lumenarium_first_win32.obj and b/run_tree/win32/intel/debug/lumenarium_first_win32.obj differ diff --git a/src/app/editor/foldhaus_editor.cpp b/src/app/editor/foldhaus_editor.cpp index 3764b25..8db76a9 100644 --- a/src/app/editor/foldhaus_editor.cpp +++ b/src/app/editor/foldhaus_editor.cpp @@ -8,147 +8,147 @@ internal void Editor_HandleInput (app_state* State, rect2 WindowBounds, input_queue InputQueue, mouse_state Mouse, context Context) { - DEBUG_TRACK_FUNCTION; + DEBUG_TRACK_FUNCTION; + + b32 MouseInputHandled = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); + + gs_string TextInputString = PushString(State->Transient, 32); + + panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); + if (ActivePanel) + { + panel_definition ActiveDef = State->PanelSystem.PanelDefs[ActivePanel->TypeIndex]; - b32 MouseInputHandled = HandleMousePanelInteraction(&State->PanelSystem, State->WindowBounds, Mouse, State); - - gs_string TextInputString = PushString(State->Transient, 32); - - panel* ActivePanel = PanelSystem_GetPanelContainingPoint(&State->PanelSystem, Mouse.Pos); - if (ActivePanel) + input_command_registry ActiveCommands = {}; + if (State->Modes.ActiveModesCount > 0) { - panel_definition ActiveDef = State->PanelSystem.PanelDefs[ActivePanel->TypeIndex]; - - input_command_registry ActiveCommands = {}; - if (State->Modes.ActiveModesCount > 0) - { - ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; - } - else if (ActiveDef.InputCommands) - { - ActiveCommands.Commands = ActiveDef.InputCommands; - ActiveCommands.Size = sizeof(*ActiveDef.InputCommands) / sizeof(ActiveDef.InputCommands[0]); - ActiveCommands.Used = ActiveCommands.Size; - } - - // Fill up the command queue - for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) - { - input_entry Event = InputQueue.Entries[EventIdx]; - - bool IsMouseEvent = (Event.Key == KeyCode_MouseLeftButton || - Event.Key == KeyCode_MouseMiddleButton || - Event.Key == KeyCode_MouseRightButton); - if (IsMouseEvent && MouseInputHandled) - { - continue; - } - - // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege - // Down and Up over Held. In other words, we don't want to call a Held command on the - // frame when the button was released, even if the command is registered to both events - if (KeyTransitionedDown(Event)) - { - if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue)) - { - char KeyASCII = KeyCodeToChar(Event.Key); - if (KeyASCII) - { - OutChar(&TextInputString, KeyASCII); - } - } - } - else if (KeyTransitionedUp(Event)) - { - FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); - } - else if (KeyHeldDown(Event)) - { - if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue)) - { - char KeyASCII = KeyCodeToChar(Event.Key); - if (KeyASCII) - { - OutChar(&TextInputString, KeyASCII); - } - } - } - } + ActiveCommands = State->Modes.ActiveModes[State->Modes.ActiveModesCount - 1].Commands; + } + else if (ActiveDef.InputCommands) + { + ActiveCommands.Commands = ActiveDef.InputCommands; + ActiveCommands.Size = sizeof(*ActiveDef.InputCommands) / sizeof(ActiveDef.InputCommands[0]); + ActiveCommands.Used = ActiveCommands.Size; } - // Execute all commands in CommandQueue - for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) + // Fill up the command queue + for (s32 EventIdx = 0; EventIdx < InputQueue.QueueUsed; EventIdx++) { - command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; - if (Entry->Command.Proc) + input_entry Event = InputQueue.Entries[EventIdx]; + + bool IsMouseEvent = (Event.Key == KeyCode_MouseLeftButton || + Event.Key == KeyCode_MouseMiddleButton || + Event.Key == KeyCode_MouseRightButton); + if (IsMouseEvent && MouseInputHandled) + { + continue; + } + + // NOTE(Peter): These are in the order Down, Up, Held because we want to privalege + // Down and Up over Held. In other words, we don't want to call a Held command on the + // frame when the button was released, even if the command is registered to both events + if (KeyTransitionedDown(Event)) + { + if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Began, &State->CommandQueue)) { - Entry->Command.Proc(State, Entry->Event, Mouse, Context, ActivePanel); + char KeyASCII = KeyCodeToChar(Event.Key); + if (KeyASCII) + { + OutChar(&TextInputString, KeyASCII); + } } - else + } + else if (KeyTransitionedUp(Event)) + { + FindAndPushExistingCommand(ActiveCommands, Event, Command_Ended, &State->CommandQueue); + } + else if (KeyHeldDown(Event)) + { + if (!FindAndPushExistingCommand(ActiveCommands, Event, Command_Held, &State->CommandQueue)) { - EndCurrentOperationMode(State); + char KeyASCII = KeyCodeToChar(Event.Key); + if (KeyASCII) + { + OutChar(&TextInputString, KeyASCII); + } } + } } - - State->Interface.TempInputString = TextInputString.ConstString; - - ClearCommandQueue(&State->CommandQueue); + } + + // Execute all commands in CommandQueue + for (s32 CommandIdx = State->CommandQueue.Used - 1; CommandIdx >= 0; CommandIdx--) + { + command_queue_entry* Entry = &State->CommandQueue.Commands[CommandIdx]; + if (Entry->Command.Proc) + { + Entry->Command.Proc(State, Entry->Event, Mouse, Context, ActivePanel); + } + else + { + EndCurrentOperationMode(State); + } + } + + State->Interface.TempInputString = TextInputString.ConstString; + + ClearCommandQueue(&State->CommandQueue); } internal void Editor_Update(app_state* State, context* Context, input_queue InputQueue) { - Context->Mouse.CursorType = CursorType_Arrow; - State->WindowBounds = Context->WindowBounds; - State->Interface.Mouse = Context->Mouse; - - State->Interface.HotWidgetFramesSinceUpdate += 1; - if (State->Interface.HotWidgetFramesSinceUpdate > 1) - { - State->Interface.HotWidget = {}; - } - - Assert(State->Interface.PerFrameMemory && - (u64)State->Interface.PerFrameMemory != 0x5); - - PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds); - Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); + Context->Mouse.CursorType = CursorType_Arrow; + State->WindowBounds = Context->WindowBounds; + State->Interface.Mouse = Context->Mouse; + + State->Interface.HotWidgetFramesSinceUpdate += 1; + if (State->Interface.HotWidgetFramesSinceUpdate > 1) + { + State->Interface.HotWidget = {}; + } + + Assert(State->Interface.PerFrameMemory && + (u64)State->Interface.PerFrameMemory != 0x5); + + PanelSystem_UpdateLayout(&State->PanelSystem, State->WindowBounds); + Editor_HandleInput(State, State->WindowBounds, InputQueue, Context->Mouse, *Context); } internal void Editor_Render(app_state* State, context* Context, render_command_buffer* RenderBuffer) { - State->Interface.WindowBounds = Context->WindowBounds; - PushRenderOrthographic(RenderBuffer, State->WindowBounds); - PushRenderClearScreen(RenderBuffer); + State->Interface.WindowBounds = Context->WindowBounds; + PushRenderOrthographic(RenderBuffer, State->WindowBounds); + PushRenderClearScreen(RenderBuffer); + + + ui_InterfaceReset(&State->Interface); + State->Interface.RenderBuffer = RenderBuffer; + ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout")); + { + DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); - - ui_InterfaceReset(&State->Interface); - State->Interface.RenderBuffer = RenderBuffer; - ui_PushLayout(&State->Interface, Context->WindowBounds, LayoutDirection_TopDown, MakeString("Editor Layout")); + for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) { - DrawAllPanels(State->PanelSystem, RenderBuffer, &Context->Mouse, State, *Context); - - for (s32 m = 0; m < State->Modes.ActiveModesCount; m++) - { - operation_mode OperationMode = State->Modes.ActiveModes[m]; - if (OperationMode.Render != 0) - { - OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); - } - } + operation_mode OperationMode = State->Modes.ActiveModes[m]; + if (OperationMode.Render != 0) + { + OperationMode.Render(State, RenderBuffer, OperationMode, Context->Mouse, *Context); + } } - ui_PopLayout(&State->Interface, MakeString("Editor Layout")); - - - // Draw the Interface - if (State->Interface.DrawOrderRoot != 0) - { - ui_widget* Widget = State->Interface.DrawOrderRoot; - Editor_DrawWidgetList(State, Context, RenderBuffer, Widget, Context->WindowBounds); - } - - Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); + } + ui_PopLayout(&State->Interface, MakeString("Editor Layout")); + + + // Draw the Interface + if (State->Interface.DrawOrderRoot != 0) + { + ui_widget* Widget = State->Interface.DrawOrderRoot; + Editor_DrawWidgetList(State, Context, RenderBuffer, Widget, Context->WindowBounds); + } + + Context->GeneralWorkQueue->CompleteQueueWork(Context->GeneralWorkQueue, Context->ThreadContext); } diff --git a/src_v2/editor/lumenarium_editor.cpp b/src_v2/editor/lumenarium_editor.cpp index 8fc0d0e..af166ce 100644 --- a/src_v2/editor/lumenarium_editor.cpp +++ b/src_v2/editor/lumenarium_editor.cpp @@ -1,8 +1,101 @@ +static r32 z_ = 0; +static r32 r_ = 0.3f; +static r32 quad_verts[] = { + -r_, -r_, z_, 1.0f, 0, 0, + r_, -r_, z_, 1.0f, 1, 0, + r_, r_, z_, 1.0f, 1, 1, + -r_, r_, z_, 1.0f, 0, 1, +}; + +static u32 quad_indices[] = { + 0, 1, 2, + 0, 2, 3, +}; + +static String shader_code_vert_win32 = lit_str( + "#version 330 core\n" + "layout (location = 0) in vec4 coordinates;\n" + "layout (location = 1) in vec2 uv;\n" + "out vec2 tex_coord;\n" + "void main(void) {\n" + " gl_Position = coordinates;\n" + " tex_coord = uv;\n" + "}" + ); + +static String shader_code_vert_wasm = lit_str( + "precision highp float;\n" + "attribute vec4 coordinates;\n" + "attribute vec2 uv;\n" + "varying vec2 tex_coord;\n" + "void main(void) {\n" + " gl_Position = coordinates;\n" + " tex_coord = uv;\n" + "}"); + +static String shader_code_frag_win32 = lit_str( + "#version 330 core\n" + "in vec2 tex_coord;\n" + "out vec4 FragColor;\n" + "uniform sampler2D texture;\n" + "void main(void) {\n" + "// FragColor = vec4(1,tex_coord.x,tex_coord.y,1);\n" + " FragColor = texture(texture, tex_coord);\n" + "}" + ); + +static String shader_code_frag_wasm = lit_str( + "precision highp float;\n" + "varying vec2 tex_coord;\n" + "uniform sampler2D texture;\n" + "void main(void) {\n" + " gl_FragColor = texture2D(texture, tex_coord);\n" + " // vec4(1, tex_coord.x, tex_coord.y, 1);\n" + "}"); + +static u32 pix[] = { + 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000, + 0xFF000000, 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, + 0xFFFFFFFF, 0xFF000000, 0xFFFFFFFF, 0xFF000000, +}; + +void make_quad(Platform_Geometry_Buffer* geo, Platform_Shader* shd, Platform_Texture* tex) +{ + // TODO(PS): TEMP +#if defined(PLATFORM_win32) + String shader_code_vert = shader_code_vert_win32; + String shader_code_frag = shader_code_frag_win32; +#elif defined(PLATFORM_wasm) + String shader_code_vert = shader_code_vert_wasm; + String shader_code_frag = shader_code_frag_wasm; +#endif + + *geo = platform_geometry_buffer_create( + quad_verts, 24, quad_indices, 6 + ); + + String attribs[] = { + lit_str("coordinates"), + lit_str("uv"), + }; + *shd = platform_shader_create( + shader_code_vert, shader_code_frag, attribs, 2 + ); + + platform_vertex_attrib_pointer(*geo, *shd, 4, shd->attrs[0], 6, 0); + platform_vertex_attrib_pointer(*geo, *shd, 2, shd->attrs[1], 6, 4); + + *tex = platform_texture_create((u8*)pix, 4, 4, 4); +} + internal void ed_init(App_State* state) { - + Editor* editor = allocator_alloc_struct(permanent, Editor); + state->editor = editor; + make_quad(&editor->renderer.geo, &editor->renderer.shd, &editor->renderer.tex); } internal void @@ -14,6 +107,13 @@ ed_frame_prepare(App_State* state) internal void ed_frame(App_State* state) { + for (u32 i = 0; i < 16; i++) + { + if (i % 2 == 1) continue; + pix[i] += 1; + } + platform_texture_update(state->editor->renderer.tex, (u8*)pix, 4, 4, 4); + edr_render(state); } diff --git a/src_v2/editor/lumenarium_editor.h b/src_v2/editor/lumenarium_editor.h new file mode 100644 index 0000000..08ab6df --- /dev/null +++ b/src_v2/editor/lumenarium_editor.h @@ -0,0 +1,12 @@ +/* date = March 27th 2022 0:50 pm */ + +#ifndef LUMENARIUM_EDITOR_H +#define LUMENARIUM_EDITOR_H + +struct Editor +{ + v2 window_dim; + Editor_Renderer renderer; +}; + +#endif //LUMENARIUM_EDITOR_H diff --git a/src_v2/editor/lumenarium_editor_renderer.cpp b/src_v2/editor/lumenarium_editor_renderer.cpp index 53b443f..deedaa7 100644 --- a/src_v2/editor/lumenarium_editor_renderer.cpp +++ b/src_v2/editor/lumenarium_editor_renderer.cpp @@ -1,82 +1,4 @@ -internal void -edr_init(App_State* state) -{ - v4 quad_verts[] = { - -0.5f, 0.5f, 0.0f, 1.0f, - -0.5f, -0.5f, 0.0f, 1.0f, - 00.5f, -0.5f, 0.0f, 1.0f, - 00.5f, 0.5f, 0.0f, 1.0f, - }; - - u32 quad_indices[] = { - 3, 2, 1, - 3, 1, 0, - }; - - char* shader_code_vert = - "#version 140\n" - "attribute vec4 coordinates;\n" - "void main(void) {\n" - " gl_Position = coordinates;\n" - "}"; - - char* shader_code_frag = - "#version 140\n" - "void main(void) {\n" - " gl_FragColor = vec4(1, 0, 1, 1);\n" - "}"; - -#if 0 - /* ======= Geometry =======*/ - - glCreateBuffers(1, &buffer_vertex); - glBindBuffer(GL_ARRAY_BUFFER, buffer_vertex); - glBufferData(GL_ARRAY_BUFFER, quad_verts, GL_STATIC_DRAW); - glBindBuffer(GL_ARRAY_BUFFER, NULL); - - glCreateBuffer(1, &buffer_index); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_index); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, quad_indices, GL_STATIC_DRAW); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, NULL); - - /* ======= Shaders =======*/ - - shader_vert = glCreateShader(GL_VERTEX_SHADER); - glShaderSource(shader_vertex, shader_code_vert); - glCompileShader(shader_vert); - - shader_frag = glCreateShader(GL_FRAGMENT_SHADER); - glShaderSource(shader_frag, shader_code_frag); - glCompileShader(shader_frag); - - shader_prog = glCreateProgram(); - glAttachShader(shader_prog, shader_vert); - glAttachShader(shader_prog, shader_frag); - glLinkProgram(shader_prog); - glUseProgram(shader_prog); - - /* ======= Associating shaders to buffer objects =======*/ - - glBindBuffer(GL_ARRAY_BUFFER, buffer_vertex); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_index); - coord = glGetAttribLocation(shader_prog, "coordinates"); - glVertexAttribPointer(coord, 4, GL_FLOAT, false, 0, 0); - glEnableVertexAttribArray(coord); -#endif -} - -internal void -edr_render_quad() -{ -#if 0 - glBindBuffer(GL_ARRAY_BUFFER, buffer_vertex); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, buffer_index); - glEnableVertexAttribArray(coord); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); -#endif -} - internal void edr_render(App_State* state) @@ -84,11 +6,12 @@ edr_render(App_State* state) Platform_Graphics_Frame_Desc desc = {}; desc.clear_color = { 0.1f, 0.1f, 0.1f, 1 }; desc.viewport_min = { 0, 0 }; - desc.viewport_max = { 1600, 900 }; + desc.viewport_max = state->editor->window_dim; platform_frame_begin(desc); platform_frame_clear(); -#if 0 - edr_render_quad(); -#endif + platform_geometry_bind(state->editor->renderer.geo); + platform_texture_bind(state->editor->renderer.tex); + platform_shader_bind(state->editor->renderer.shd); + platform_geometry_draw(state->editor->renderer.geo); } \ No newline at end of file diff --git a/src_v2/editor/lumenarium_editor_renderer.h b/src_v2/editor/lumenarium_editor_renderer.h index 2be94b0..bebff8e 100644 --- a/src_v2/editor/lumenarium_editor_renderer.h +++ b/src_v2/editor/lumenarium_editor_renderer.h @@ -5,7 +5,9 @@ struct Editor_Renderer { - + Platform_Shader shd; + Platform_Geometry_Buffer geo; + Platform_Texture tex; }; #endif //LUMENARIUM_EDITOR_RENDERER_H diff --git a/src_v2/editor/lumenarium_ui.h b/src_v2/editor/lumenarium_ui.h new file mode 100644 index 0000000..72c6af8 --- /dev/null +++ b/src_v2/editor/lumenarium_ui.h @@ -0,0 +1,36 @@ +/* date = March 28th 2022 10:52 pm */ + +#ifndef LUMENARIUM_UI_H +#define LUMENARIUM_UI_H + +struct Font_Glyph +{ + u32 code_point; + v2 uv_min; + v2 uv_max; +}; + +struct Font_Glyph_Table +{ + Font_Glyph* values; + u32 cap; + u32 len; +}; + +struct Font_Bitmap +{ + u8* pixels; + u32 width; + u32 height; + u32 stride; + + Platform_Texture texture; +}; + +struct Font +{ + Font_Glyph_Table glyphs; + Font_Bitmap bitmap; +}; + +#endif //LUMENARIUM_UI_H diff --git a/src_v2/lumenarium_first.cpp b/src_v2/lumenarium_first.cpp index 9e81109..003f8d5 100644 --- a/src_v2/lumenarium_first.cpp +++ b/src_v2/lumenarium_first.cpp @@ -1,73 +1,6 @@ #include "lumenarium_first.h" #include "user_space/user_space_incenter.cpp" -Platform_Geometry_Buffer quad0; -Platform_Shader shader0; - -static r32 z_ = 0; -static r32 r_ = 0.3f; -static r32 quad_verts[] = { - -r_, -r_, z_, 1.0f, - r_, -r_, z_, 1.0f, - r_, r_, z_, 1.0f, - -r_, r_, z_, 1.0f, -}; - -static u32 quad_indices[] = { - 0, 1, 2, - 0, 2, 3, -}; - -static String shader_code_vert_win32 = lit_str( - "#version 330 core\n" - "layout (location = 0) in vec4 coordinates;\n" - "void main(void) {\n" - " gl_Position = coordinates;\n" - "}" - ); - -static String shader_code_vert_wasm = lit_str( - "attribute vec4 coordinates;\n" - "void main(void) {\n" - " gl_Position = coordinates;\n" - "}"); - -static String shader_code_frag_win32 = lit_str( - "#version 330 core\n" - "out vec4 FragColor;\n" - "void main(void) {\n" - " FragColor = vec4(1,0,1,1);\n" - "}" - ); - -static String shader_code_frag_wasm = lit_str( - "void main(void) {\n" - " gl_FragColor = vec4(1, 0, 1, 1);\n" - "}"); - -void make_quad() -{ - // TODO(PS): TEMP -#if defined(PLATFORM_win32) - String shader_code_vert = shader_code_vert_win32; - String shader_code_frag = shader_code_frag_win32; -#elif defined(PLATFORM_wasm) - String shader_code_vert = shader_code_vert_wasm; - String shader_code_frag = shader_code_frag_wasm; -#endif - - quad0 = platform_geometry_buffer_create( - quad_verts, 16, quad_indices, 6 - ); - - String attribs[] = { lit_str("coordinates") }; - shader0 = platform_shader_create( - shader_code_vert, shader_code_frag, attribs, 1 - ); - - platform_vertex_attrib_pointer(quad0, shader0, 0); -} - internal App_State* lumenarium_init() { @@ -76,7 +9,6 @@ lumenarium_init() permanent = bump_allocator_create_reserve(MB(4)); scratch = bump_allocator_create_reserve(KB(64)); - run_tests(); App_Init_Desc desc = incenter_get_init_desc(); @@ -84,19 +16,16 @@ lumenarium_init() state = allocator_alloc_struct(permanent, App_State); add_flag(state->flags, AppState_IsRunning); + add_flag(state->flags, AppState_RunEditor); state->input_state = input_state_create(); en_init(state, desc); - if (!has_flag(state->flags, AppState_NoEditor)) + if (has_flag(state->flags, AppState_RunEditor)) { ed_init(state); } incenter_init(state); - - - make_quad(); - return state; } @@ -108,7 +37,7 @@ lumenarium_frame_prepare(App_State* state) input_state_swap_frames(&state->input_state); en_frame_prepare(state); - if (!has_flag(state->flags, AppState_NoEditor)) + if (has_flag(state->flags, AppState_RunEditor)) { ed_frame_prepare(state); } @@ -119,23 +48,9 @@ internal void lumenarium_frame(App_State* state) { en_frame(state); - if (!has_flag(state->flags, AppState_NoEditor)) + if (has_flag(state->flags, AppState_RunEditor)) { - //ed_frame(state); - - Platform_Graphics_Frame_Desc desc = {}; - desc.clear_color = { 0.1f, 0.1f, 0.1f, 1 }; - desc.viewport_min = { 0, 0 }; - desc.viewport_max = { 1600, 900 }; - platform_frame_begin(desc); - platform_frame_clear(); - - - platform_geometry_bind(quad0); - platform_shader_bind(shader0); - platform_geometry_draw(quad0); - - + ed_frame(state); } incenter_frame(state); } @@ -176,7 +91,7 @@ lumenarium_cleanup(App_State* state) { incenter_cleanup(state); en_cleanup(state); - if (!has_flag(state->flags, AppState_NoEditor)) + if (has_flag(state->flags, AppState_RunEditor)) { ed_cleanup(state); } diff --git a/src_v2/lumenarium_first.h b/src_v2/lumenarium_first.h index 392008c..441ef69 100644 --- a/src_v2/lumenarium_first.h +++ b/src_v2/lumenarium_first.h @@ -15,6 +15,7 @@ typedef struct App_State App_State; // Editor #include "editor/lumenarium_editor_renderer.h" +#include "editor/lumenarium_editor.h" ////////////////////////////////////////////// // Lumenarium Runtime Environment @@ -36,7 +37,7 @@ enum { AppState_None = 0, AppState_IsRunning = 1, - AppState_NoEditor = 2, + AppState_RunEditor = 2, }; struct App_Init_Desc @@ -50,6 +51,8 @@ struct App_State Input_State input_state; Assembly_Array assemblies; + + Editor* editor; }; #include "engine/lumenarium_engine_assembly.cpp" diff --git a/src_v2/lumenarium_string.cpp b/src_v2/lumenarium_string.cpp index 83f4ad1..157f2c6 100644 --- a/src_v2/lumenarium_string.cpp +++ b/src_v2/lumenarium_string.cpp @@ -7,7 +7,8 @@ c_str_len(char* s) return result; } -#define str_varg(str) (int)(str).len, (char*)(str).str +#define str_varg(s) (int)(s).len, (char*)(s).str +#define str_expand(s) (char*)(s).str, (u64)(s).len #define lit_str(s) String{ (u8*)(s), (u64)sizeof(s)-1, (u64)sizeof(s)-1 } internal String diff --git a/src_v2/platform/lumenarium_assert.h b/src_v2/platform/lumenarium_assert.h index 69e837b..213d041 100644 --- a/src_v2/platform/lumenarium_assert.h +++ b/src_v2/platform/lumenarium_assert.h @@ -3,27 +3,47 @@ #ifndef LUMENARIUM_ASSERT_H #define LUMENARIUM_ASSERT_H +#if defined(PRINT_ASSERTS) +# include +# define err_write(s,...) err_write_(s,__VA_ARGS__) +static FILE* file_err; +void err_write_(char* fmt, ...) { + if (!file_err) return; + va_list args; + va_start(args, fmt); + vfprintf(file_err, fmt, args); + va_end(args); +} +void open_err_file() { file_err = fopen("./err.txt", "wb"); } +void close_err_file() { fclose(file_err); } +#else +# define err_write(s,...) +void open_err_file() {} +void close_err_file() {} +#endif + #if !defined(PLATFORM_wasm) + // this assert works by simply trying to write to an invalid address // (in this case, 0x0), which will crash in most debuggers # define assert_always (*((volatile s32*)0) = 0xFFFF) #else -WASM_EXTERN void wasm_assert_always(char* file, u32 file_len, u32 line); +WASM_EXTERN void wasm_assert_always(char* file, unsigned int file_len, unsigned int line); # define assert_always wasm_assert_always(__FILE__, sizeof(__FILE__), __LINE__) #endif // defined(PLATFORM_WASM) #ifdef USE_ASSERTS -# define assert(c) if (!(c)) { assert_always; } +# define assert(c) if (!(c)) { err_write("Assert Hit: %s:%d\n", __FILE__, (u32)__LINE__); close_err_file(); assert_always; } // useful for catching cases that you aren't sure you'll hit, but // want to be alerted when they happen -# define invalid_code_path assert_always +# define invalid_code_path assert(0); // useful for switch statements on enums that might grow. You'll // break in the debugger the first time the default case is hit // with a new enum value -# define invalid_default_case default: { assert_always; } break; +# define invalid_default_case default: { assert(0); } break; #else # define assert(c) diff --git a/src_v2/platform/lumenarium_platform.h b/src_v2/platform/lumenarium_platform.h index 67cf492..a96a830 100644 --- a/src_v2/platform/lumenarium_platform.h +++ b/src_v2/platform/lumenarium_platform.h @@ -309,6 +309,13 @@ struct Platform_Geometry_Buffer u32 indices_len; }; +struct Platform_Texture +{ + u32 id; + + u32 w, h, s; +}; + struct Platform_Graphics_Frame_Desc { v4 clear_color; @@ -319,18 +326,23 @@ struct Platform_Graphics_Frame_Desc void platform_frame_begin(Platform_Graphics_Frame_Desc desc); void platform_frame_clear(); +// Geometry Platform_Geometry_Buffer platform_geometry_buffer_create(r32* vertices, u32 vertices_len, u32* indices, u32 indices_len); Platform_Shader platform_shader_create( String code_vert, String code_frag, String* attribs, u32 attribs_len ); -void platform_vertex_attrib_pointer( - Platform_Geometry_Buffer geo, Platform_Shader shader, u32 attrib_index - ); +// Shaders void platform_geometry_bind(Platform_Geometry_Buffer geo); void platform_shader_bind(Platform_Shader shader); void platform_geometry_draw(Platform_Geometry_Buffer geo); void platform_vertex_attrib_pointer( - Platform_Geometry_Buffer geo, Platform_Shader shader, u32 attr_index + Platform_Geometry_Buffer geo, Platform_Shader shader, u32 count, u32 attr_index, u32 stride, u32 offset ); + +// Textures +Platform_Texture platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride); +void platform_texture_bind(Platform_Texture tex); +void platform_texture_update(Platform_Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride); + #endif //LUMENARIUM_PLATFORM_H diff --git a/src_v2/platform/lumenarium_platform_common_includes.h b/src_v2/platform/lumenarium_platform_common_includes.h index 421b694..802889c 100644 --- a/src_v2/platform/lumenarium_platform_common_includes.h +++ b/src_v2/platform/lumenarium_platform_common_includes.h @@ -13,9 +13,13 @@ #include "lumenarium_assert.h" -#include "glcorearb.h" -#include "glext.h" -#include "wglext.h" +// NOTE(PS): only need the opengl extension headers +// when running on a platform that is using opengl 3.3+ +#if !defined(PLATFORM_wasm) +# include "glcorearb.h" +# include "glext.h" +# include "wglext.h" +#endif #if 0 #define HMM_SINF sin diff --git a/src_v2/platform/wasm/lumenarium_first_wasm.cpp b/src_v2/platform/wasm/lumenarium_first_wasm.cpp index e4285a0..8446aa6 100644 --- a/src_v2/platform/wasm/lumenarium_first_wasm.cpp +++ b/src_v2/platform/wasm/lumenarium_first_wasm.cpp @@ -25,6 +25,8 @@ WASM_EXTERN void print(const char* text, int len); typedef void wasm_animation_frame_cb(u32 time_elapsed); WASM_EXTERN void wasm_request_animation_frame(wasm_animation_frame_cb* cb); +WASM_EXTERN void wasm_get_canvas_dim(u32* w_ptr, u32* h_ptr); + EXTERN_C_BEGIN; int @@ -46,14 +48,25 @@ update(u32 time_elapsed) lumenarium_frame(wasm_app_state); // TODO(PS): check for app running flags - wasm_request_animation_frame(update); + if (!glHadError()) + { + wasm_request_animation_frame(update); + } } WASM_EXPORT int main(void) { wasm_app_state = lumenarium_init(); - //wasm_request_animation_frame(update); + if (has_flag(wasm_app_state->flags, AppState_RunEditor)) + { + u32 w, h; + wasm_get_canvas_dim(&w, &h); + wasm_app_state->editor->window_dim = v2{ + (r32)w, (r32)h + }; + } + wasm_request_animation_frame(update); return 0; #if 0 diff --git a/src_v2/platform/wasm/lumenarium_wasm_imports.js b/src_v2/platform/wasm/lumenarium_wasm_imports.js index 299fa8a..29d372c 100644 --- a/src_v2/platform/wasm/lumenarium_wasm_imports.js +++ b/src_v2/platform/wasm/lumenarium_wasm_imports.js @@ -34,6 +34,35 @@ function wasm_get_proc(inst, proc_ptr) function fract (v) { return v % 1; } +function u32_to_byte_array_32 (v) +{ + let result = [0, 0, 0, 0]; + result[0] = (v & 0xff); + result[1] = (((v - result[0]) >> 8 ) & 0xff); + result[2] = (((v - result[1]) >> 16) & 0xff); + result[3] = (((v - result[2]) >> 24) & 0xff); + return result; +} + +function byte_array_32_to_u32 (arr) +{ + // NOTE(PS): the '>>>' operators in this function deal with the fact + // that bit shift operators convert numbers to s32's. The >>> just + // converts them back to u32s + let r0 = ((arr[0] & 0xff) << 0 ); + let r1 = ((arr[1] & 0xff) << 8 ); + let r2 = ((arr[2] & 0xff) << 16); + let r3 = (((arr[3] & 0xff) << 24) >>> 0); + let result = (r0 | r1 | r2 | r3) >>> 0; + return result; +} + +function put_u32 (ptr, value) +{ + let src = u32_to_byte_array_32(value); + wasm_write_bytes(lumenarium_wasm_instance, src, ptr, 4); +} + var lumenarium_wasm_imports = { memset: (dst, size, value) => { @@ -122,12 +151,46 @@ var lumenarium_wasm_imports = { let string = wasm_read_string(lumenarium_wasm_instance, str_base, len); console.log(string); }, + + wasm_get_canvas_dim: (w_ptr, h_ptr) => { + const canvas = document.querySelector("#gl_canvas"); + + let w_view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, w_ptr, 4); + let w = canvas.width; + let wb = u32_to_byte_array_32(w); + for (let i = 0; i < 4; i++) w_view[i] = wb[i]; + + let h_view = wasm_mem_get_u8_arr(lumenarium_wasm_instance, h_ptr, 4); + let h = canvas.height; + let hb = u32_to_byte_array_32(h); + for (let i = 0; i < 4; i++) h_view[i] = hb[i]; + }, }; /////////////////////////////////////// // Web GL Imports let gl = null; +let gl_error = false; + +function glErrorReport(outer_args) { + const err = gl.getError(); + if (err == gl.NO_ERROR) return; + + gl_error = true; + let msg = ""; + switch (err) { + case gl.NO_ERROR: { msg = "NO_ERROR"; } break; + case gl.INVALID_ENUM: { msg = "INVALID_ENUM"; } break; + case gl.INVALID_VALUE: { msg = "INVALID_VALUE"; } break; + case gl.INVALID_OPERATION: { msg = "INVALID_OPERATION"; } break; + case gl.INVALID_FRAMEBUFFER_OPERATION: { msg = "INVALID_FRAMEBUFFER_OPERATION"; } break; + case gl.OUT_OF_MEMORY: { msg = "OUT_OF_MEMORY"; } break; + case gl.CONTEXT_LOST_WEBGL: { msg = "CONTEXT_LOST_WEBGL"; } break; + default: { msg = "Uknown error"; } break; + } + console.error(`WebGL Error: ${msg} ${err}`, outer_args); +} // NOTE(PS): it seems like its not enough to set // the values of imports to gl.function @@ -135,16 +198,37 @@ let gl = null; // instead we need to wrap them for some reason. // Not sure why function glClearColor (r, g, b, a) { return gl.clearColor(r,g,b,a); } -function glEnable(v) { return gl.enable(v); } -function glDisable(v) { return gl.disable(v); } -function glBlendFunc(a,b) { return gl.blendFunc(a,b); } +function glEnable(v) { + const r = gl.enable(v); + glErrorReport(arguments); + return r; +} +function glDisable(v) { + const r = gl.disable(v); + glErrorReport(arguments); + return r; +} +function glBlendFunc(a,b) { + const r = gl.blendFunc(a,b); + glErrorReport(arguments); + return r; +} function glViewport(xmin, ymin, xmax, ymax) { return gl.viewport(xmin,ymin,xmax,ymax); } -function glDepthFunc(v) { return gl.depthFunc(v); } -function glClear(mask) { return gl.clear(mask); } +function glDepthFunc(v) { + const r = gl.depthFunc(v); + glErrorReport(arguments); + return r; +} +function glClear(mask) { + const r = gl.clear(mask); + glErrorReport(arguments); + return r; +} let glBuffers = []; let glShaders = []; let glPrograms = []; +let glTextures = []; function gl_get_managed_resource(arr, id) { if (id == 0) return null; return arr[id - 1]; @@ -152,55 +236,76 @@ function gl_get_managed_resource(arr, id) { function gl_get_buffer(id) { return gl_get_managed_resource(glBuffers, id); } function gl_get_shader(id) { return gl_get_managed_resource(glShaders, id); } function gl_get_program(id) { return gl_get_managed_resource(glPrograms, id); } +function gl_get_texture(id) { return gl_get_managed_resource(glTextures, id); } function glCreateBuffer() { let buffer = gl.createBuffer(); + glErrorReport(arguments); let new_len = glBuffers.push(buffer); return new_len; } + function glBindBuffer(buffer_kind, buffer_id) { - return gl.bindBuffer(buffer_kind, gl_get_buffer(buffer_id)); + const r = gl.bindBuffer(buffer_kind, gl_get_buffer(buffer_id)); + glErrorReport(arguments); + return r; } + function glBufferData(target, size, ptr, usage) { let data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, ptr, size); - return gl.bufferData(target, data, usage); + const r = gl.bufferData(target, data, usage); + glErrorReport(arguments); + return r; } + function glCreateShader(kind) { let shader = gl.createShader(kind); + glErrorReport(arguments); let new_len = glShaders.push(shader); return new_len; } + function glShaderSource(shader_id, shader_code, shader_code_len) { let str = wasm_read_string(lumenarium_wasm_instance, shader_code, shader_code_len); - console.error("For some reason, str isn't getting the correct data out of here", str); - return gl.shaderSource(gl_get_shader(shader_id), str); + const r = gl.shaderSource(gl_get_shader(shader_id), str); + glErrorReport(arguments); + return r; } + function glCompileShader(shader_id) { let s = gl_get_shader(shader_id); let r = gl.compileShader(s); + glErrorReport(arguments); let m = gl.getShaderInfoLog(s); + glErrorReport(arguments); if (m.length > 0) { console.error("glCompileShader: \n\n" + m); } } + function glCreateProgram() { let prog = gl.createProgram(); + glErrorReport(arguments); let new_len = glPrograms.push(prog); return new_len; } + function glAttachShader(program, shader) { let s = gl_get_shader(shader); let p = gl_get_program(program); - return gl.attachShader(p, s); + const r = gl.attachShader(p, s); + glErrorReport(arguments); + return r; } + function glLinkProgram(program) { let p = gl_get_program(program); @@ -210,43 +315,94 @@ function glLinkProgram(program) console.error("Failed to compile WebGL program. \n\n"+info); } } + function glUseProgram(program) { let p = gl_get_program(program); - return gl.useProgram(p); + const r = gl.useProgram(p); + glErrorReport(arguments); + return r; } + function glGetAttribLocation(program, name, name_len) { let str = wasm_read_string(lumenarium_wasm_instance, name, name_len); - return gl.getAttribLocation(gl_get_program(program), str); + const r = gl.getAttribLocation(gl_get_program(program), str); + glErrorReport(arguments); + return r; } + function glVertexAttribPointer(attr, size, type, normalized, stride, pointer) { - return gl.vertexAttribPointer(attr, size, type, normalized, stride, pointer); + const r = gl.vertexAttribPointer(attr, size, type, normalized, stride, pointer); + glErrorReport(arguments); + return r; } + function glEnableVertexAttribArray(index) { - return gl.enableVertexAttribArray(index); + const r = gl.enableVertexAttribArray(index); + glErrorReport(arguments); + return r; } + function glDrawElements(type, index_count, ele_type, indices) { - return gl.drawElements(type, index_count, ele_type, indices); + const r = gl.drawElements(type, index_count, ele_type, indices); + glErrorReport(arguments); + return r; +} + +function glGenTextures(count, ids_ptr, ids_size) +{ + for (let i = 0; i < count; i++) + { + const tex = gl.createTexture(); + glErrorReport(arguments); + let new_len = glTextures.push(tex); + put_u32(ids_ptr + (i * 4), new_len); + } +} + +function glBindTexture(slot, id) +{ + let tex = gl_get_texture(id); + const r = gl.bindTexture(slot, tex); + glErrorReport(arguments); + return r; +} + +function glTexParameteri(slot, param, value) +{ + const r = gl.texParameteri(slot, param, value); + glErrorReport(arguments); + return r; +} + +function glTexImage2D(target, level, internalformat, width, height, border, format, type, data_ptr, data_size) +{ + const data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, data_ptr, data_size); + const r = gl.texImage2D(target, level, internalformat, width, height, border, format, type, data); + glErrorReport(arguments); + return r; +} + +function glTexSubImage2D(target, level, offsetx, offsety, width, height, format, type, data_ptr, data_size) +{ + const data = wasm_mem_get_u8_arr(lumenarium_wasm_instance, data_ptr, data_size); + const r = gl.texSubImage2D(target, level, offsetx, offsety, width, height, format, type, data); + glErrorReport(arguments); + return r; } function webgl_add_imports (canvas_selector, imports) { const canvas = document.querySelector(canvas_selector); if (!canvas) return console.error("no canvas"); - gl = canvas.getContext("webgl"); + gl = canvas.getContext("webgl2"); if (gl === null) return console.error("no webgl ctx"); - console.log( - gl.FLOAT.toString(16), "\n", - gl.UNSIGNED_INT.toString(16), "\n" - ); - - - + imports.glHadError = () => { return gl_error; }; imports.glClearColor = glClearColor; imports.glEnable = glEnable; imports.glDisable = glDisable; @@ -269,6 +425,11 @@ function webgl_add_imports (canvas_selector, imports) { imports.glVertexAttribPointer = glVertexAttribPointer; imports.glEnableVertexAttribArray = glEnableVertexAttribArray; imports.glDrawElements = glDrawElements; - + imports.glGenTextures = glGenTextures; + imports.glBindTexture = glBindTexture; + imports.glTexParameteri = glTexParameteri; + imports.glTexImage2D = glTexImage2D; + imports.glTexSubImage2D = glTexSubImage2D; + imports.glBindTexture = glBindTexture; return imports; } \ No newline at end of file diff --git a/src_v2/platform/wasm/lumenarium_wasm_webgl.cpp b/src_v2/platform/wasm/lumenarium_wasm_webgl.cpp index d164900..88be506 100644 --- a/src_v2/platform/wasm/lumenarium_wasm_webgl.cpp +++ b/src_v2/platform/wasm/lumenarium_wasm_webgl.cpp @@ -6,6 +6,7 @@ // TODO(PS): you guessed the data types and names of ALL of this // fix it! +typedef int GLint; typedef unsigned int GLuint; typedef float GLfloat; typedef unsigned int GLenum; @@ -35,9 +36,19 @@ typedef unsigned int GLsizei; #define GL_FRAGMENT_SHADER 0x8b30 #define GL_VERTEX_SHADER 0x8b31 #define GL_TRIANGLES 0x0004 -#define GL_UNSIGNED_INT 0x1406 -#define GL_FLOAT 0x1405 +#define GL_UNSIGNED_INT 0x1405 +#define GL_FLOAT 0x1406 +#define GL_TEXTURE_WRAP_S 0x2802 +#define GL_TEXTURE_WRAP_T 0x2803 +#define GL_REPEAT 0x2901 +#define GL_TEXTURE_MIN_FILTER 0x2801 +#define GL_TEXTURE_MAG_FILTER 0x2800 +#define GL_LINEAR 0x2601 +#define GL_RGB 0x1907 +#define GL_RGBA 0x1908 +#define GL_UNSIGNED_BYTE 0x1401 +WASM_EXTERN bool glHadError(); WASM_EXTERN void glClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a); WASM_EXTERN void glEnable(GLuint i); WASM_EXTERN void glDisable(GLuint i); @@ -60,6 +71,12 @@ WASM_EXTERN GLuint glGetAttribLocation(GLuint program, const char* name, GLuint WASM_EXTERN void glVertexAttribPointer(GLuint attr, GLuint size, GLenum type, GLboolean normalized, GLsizei stride, const void *pointer); WASM_EXTERN void glEnableVertexAttribArray(GLuint index); WASM_EXTERN void glDrawElements(GLenum type, GLuint count, GLenum ele_type, void* indices); +WASM_EXTERN void glGenTextures(GLuint count, GLuint* ids, u32 ids_size); +WASM_EXTERN void glBindTexture(GLenum slot, GLuint id); +WASM_EXTERN void glTexParameteri(GLenum slot, GLenum param, GLenum value); +WASM_EXTERN void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const void * data, u32 data_size); +WASM_EXTERN void glBindTexture(GLenum target, GLuint id); +WASM_EXTERN void glTexSubImage2D(GLenum target, GLint level, GLuint offsetx, GLuint offsety, GLuint w, GLuint h, GLenum format, GLenum type, void* ptr, u32 ptr_size); Platform_Geometry_Buffer platform_geometry_buffer_create( @@ -97,13 +114,11 @@ platform_shader_create( Platform_Shader result = {}; GLuint shader_vert = glCreateShader(GL_VERTEX_SHADER); - GLuint vert_len = (GLuint)code_vert.len; - glShaderSource(shader_vert, (char*)&code_vert.str, vert_len); + glShaderSource(shader_vert, str_expand(code_vert)); glCompileShader(shader_vert); GLuint shader_frag = glCreateShader(GL_FRAGMENT_SHADER); - GLuint frag_len = (GLuint)code_frag.len; - glShaderSource(shader_frag, (char*)&code_frag.str, frag_len); + glShaderSource(shader_frag, str_expand(code_frag)); glCompileShader(shader_frag); result.id = (GLuint)glCreateProgram(); @@ -138,7 +153,7 @@ void platform_shader_bind(Platform_Shader shader) { glUseProgram(shader.id); - for (GLuint i = 0; i < PLATFORM_SHADER_MAX_ATTRS && shader.attrs[i] != PLATFORM_SHADER_MAX_ATTRS; i++) + for (GLuint i = 0; i < PLATFORM_SHADER_MAX_ATTRS && shader.attrs[i] != PLATFORM_SHADER_ATTR_LAST; i++) { glEnableVertexAttribArray(shader.attrs[i]); } @@ -152,11 +167,70 @@ platform_geometry_draw( } void platform_vertex_attrib_pointer( - Platform_Geometry_Buffer geo, Platform_Shader shader, GLuint attr_index + Platform_Geometry_Buffer geo, Platform_Shader shader, u32 count, u32 attr_index, u32 stride, u32 offset ){ - platform_shader_bind(shader); + //platform_shader_bind(shader); platform_geometry_bind(geo); - glVertexAttribPointer(shader.attrs[attr_index], 4, GL_FLOAT, false, 0, 0); + glVertexAttribPointer(shader.attrs[attr_index], count, GL_FLOAT, false, stride * sizeof(float), (void*)(offset * sizeof(float))); +} + +Platform_Texture +platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride) +{ + Platform_Texture result = {}; + glGenTextures(1, &result.id, sizeof(u32)); + glBindTexture(GL_TEXTURE_2D, result.id); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width, + height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixels, + (width * height) * sizeof(u32) + ); + + result.w = width; + result.h = height; + result.s = stride; + + return result; +} + +void +platform_texture_update(Platform_Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride) +{ + // NOTE(PS): this function simply replaces the entire image + // we can write a more granular version if we need it + + assert(tex.w == width && tex.h == height && tex.s == stride); + platform_texture_bind(tex); + glTexSubImage2D( + GL_TEXTURE_2D, + 0, + 0, 0, // offset + width, height, + GL_RGBA, + GL_UNSIGNED_BYTE, + new_pixels, + width * height * sizeof(u32) + ); +} + + +void +platform_texture_bind(Platform_Texture tex) +{ + glBindTexture(GL_TEXTURE_2D, tex.id); } void diff --git a/src_v2/platform/win32/lumenarium_first_win32.cpp b/src_v2/platform/win32/lumenarium_first_win32.cpp index 252ce0e..d27f084 100644 --- a/src_v2/platform/win32/lumenarium_first_win32.cpp +++ b/src_v2/platform/win32/lumenarium_first_win32.cpp @@ -180,6 +180,8 @@ WinMain( PSTR lpCmdLine, INT nCmdShow) { + open_err_file(); + // Window Setup win32_window_create( &win32_main_window, @@ -189,6 +191,7 @@ WinMain( 900, win32_window_event_handler ); + win32_window_update_dim(&win32_main_window); win32_time_init(); win32_files_init(); @@ -230,6 +233,15 @@ WinMain( // using invalid resources if (!running || !has_flag(state->flags, AppState_IsRunning)) continue; + // Update window size + if (has_flag(state->flags, AppState_RunEditor)) + { + state->editor->window_dim = v2{ + (r32)win32_main_window.info.width, + (r32)win32_main_window.info.height + }; + } + lumenarium_frame(state); SwapBuffers(win32_main_window.dc); @@ -261,6 +273,8 @@ WinMain( // windows cleanup UnregisterClass(win32_main_window.window_class.lpszClassName, hInstance); + + close_err_file(); return 0; } diff --git a/src_v2/platform/win32/lumenarium_win32_graphics.cpp b/src_v2/platform/win32/lumenarium_win32_graphics.cpp index 59e04dc..848d91d 100644 --- a/src_v2/platform/win32/lumenarium_win32_graphics.cpp +++ b/src_v2/platform/win32/lumenarium_win32_graphics.cpp @@ -1,12 +1,16 @@ -#define win32_gl_no_error() win32_gl_no_error_() -void win32_gl_no_error_() { +#define win32_gl_no_error() win32_gl_no_error_(__FILE__, __LINE__) +void win32_gl_no_error_(char* file, u32 line) { u32 error = glGetError(); char* str = 0; if (error) { str = win32_gl_error_to_string(error); } - assert(error == 0); + if (error != 0) + { + err_write("OpenGL error: %s:%d\n\t%s :: %d\n", file, line, str, error); + invalid_code_path; + } } Platform_Geometry_Buffer @@ -64,7 +68,7 @@ platform_shader_create( { // errors GLint shader_vert_compiled; gl.glGetShaderiv(shader_vert, GL_COMPILE_STATUS, &shader_vert_compiled); - if (shader_vert_compiled != GL_TRUE) + if (!shader_vert_compiled) { GLsizei log_length = 0; GLchar message[1024]; @@ -79,7 +83,7 @@ platform_shader_create( { // errors GLint shader_frag_compiled; gl.glGetShaderiv(shader_frag, GL_COMPILE_STATUS, &shader_frag_compiled); - if (shader_frag_compiled != GL_TRUE) + if (!shader_frag_compiled) { GLsizei log_length = 0; GLchar message[1024]; @@ -122,7 +126,7 @@ platform_shader_create( void platform_geometry_bind(Platform_Geometry_Buffer geo) { - gl.glBindVertexArray(geo.buffer_id_vertices); + gl.glBindVertexArray(geo.buffer_id_vao); win32_gl_no_error(); gl.glBindBuffer(GL_ARRAY_BUFFER, geo.buffer_id_vertices); @@ -155,15 +159,76 @@ platform_geometry_draw( } void platform_vertex_attrib_pointer( - Platform_Geometry_Buffer geo, Platform_Shader shader, u32 attr_index + Platform_Geometry_Buffer geo, Platform_Shader shader, GLuint count, GLuint attr_index, GLuint stride, GLuint offset ){ platform_geometry_bind(geo); - gl.glVertexAttribPointer(shader.attrs[attr_index], 4, GL_FLOAT, false, 0, 0); + gl.glVertexAttribPointer(shader.attrs[attr_index], count, GL_FLOAT, false, stride * sizeof(float), (void*)(offset * sizeof(float))); win32_gl_no_error(); gl.glEnableVertexAttribArray(shader.attrs[attr_index]); win32_gl_no_error(); } +Platform_Texture +platform_texture_create(u8* pixels, u32 width, u32 height, u32 stride) +{ + Platform_Texture result = {}; + glGenTextures(1, &result.id); + win32_gl_no_error(); + + glBindTexture(GL_TEXTURE_2D, result.id); + win32_gl_no_error(); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + win32_gl_no_error(); + + glTexImage2D( + GL_TEXTURE_2D, + 0, + GL_RGBA, + width, + height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + pixels + ); + win32_gl_no_error(); + + result.w = width; + result.h = height; + result.s = stride; + + return result; +} + +void +platform_texture_update(Platform_Texture tex, u8* new_pixels, u32 width, u32 height, u32 stride) +{ + // NOTE(PS): this function simply replaces the entire image + // we can write a more granular version if we need it + + assert(tex.w == width && tex.h == height && tex.s == stride); + platform_texture_bind(tex); + glTexSubImage2D( + GL_TEXTURE_2D, + 0, + 0, 0, // offset + width, height, + GL_RGBA, + GL_UNSIGNED_BYTE, + new_pixels + ); +} + +void +platform_texture_bind(Platform_Texture tex) +{ + glBindTexture(GL_TEXTURE_2D, tex.id); + win32_gl_no_error(); +} void platform_frame_begin(Platform_Graphics_Frame_Desc desc) @@ -180,10 +245,10 @@ platform_frame_begin(Platform_Graphics_Frame_Desc desc) glDisable(GL_CULL_FACE); - //glDisable(GL_TEXTURE_2D); - glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LESS); + + win32_gl_no_error(); } void diff --git a/src_v2/platform/win32/lumenarium_win32_window.cpp b/src_v2/platform/win32/lumenarium_win32_window.cpp index cf37008..54ca09f 100644 --- a/src_v2/platform/win32/lumenarium_win32_window.cpp +++ b/src_v2/platform/win32/lumenarium_win32_window.cpp @@ -96,7 +96,6 @@ win32_window_create( hinstance, 0 ); - return true; } return false; @@ -333,12 +332,8 @@ win32_window_opengl_ctx_create_ext(HDC dc, Win32_Window_OpenGL_Info* info) invalid_code_path; } -#if 0 - //char* version_string = (char*)glGetString(GL_VERSION); - OutputDebugStringA("OpenGL Version: "); - OutputDebugStringA(version_string); - OutputDebugStringA("\n"); -#endif + char* version_string = (char*)glGetString(GL_VERSION); + err_write("OpenGL Version: %s\n", version_string); } internal void