From 6775ea26d3db64575143ac2cc0dde08740df7b52 Mon Sep 17 00:00:00 2001 From: PS Date: Tue, 29 Mar 2022 18:09:50 +0200 Subject: [PATCH] textures, window fixes --- build/build.sh | 3 +- build/build_.sh | 2 + run_tree/wasm/debug/lumenarium.wasm | Bin 49390 -> 57484 bytes .../wasm/debug/lumenarium_wasm_imports.js | 209 ++++++++++++++-- run_tree/win32/intel/debug/debug.rdbg | Bin 1349 -> 1206 bytes run_tree/win32/intel/debug/err.txt | 1 + .../intel/debug/lumenarium_first_win32.obj | Bin 134583 -> 160688 bytes src/app/editor/foldhaus_editor.cpp | 236 +++++++++--------- src_v2/editor/lumenarium_editor.cpp | 102 +++++++- src_v2/editor/lumenarium_editor.h | 12 + src_v2/editor/lumenarium_editor_renderer.cpp | 87 +------ src_v2/editor/lumenarium_editor_renderer.h | 4 +- src_v2/editor/lumenarium_ui.h | 36 +++ src_v2/lumenarium_first.cpp | 97 +------ src_v2/lumenarium_first.h | 5 +- src_v2/lumenarium_string.cpp | 3 +- src_v2/platform/lumenarium_assert.h | 28 ++- src_v2/platform/lumenarium_platform.h | 20 +- .../lumenarium_platform_common_includes.h | 10 +- .../platform/wasm/lumenarium_first_wasm.cpp | 17 +- .../platform/wasm/lumenarium_wasm_imports.js | 209 ++++++++++++++-- .../platform/wasm/lumenarium_wasm_webgl.cpp | 94 ++++++- .../platform/win32/lumenarium_first_win32.cpp | 14 ++ .../win32/lumenarium_win32_graphics.cpp | 85 ++++++- .../win32/lumenarium_win32_window.cpp | 9 +- 25 files changed, 899 insertions(+), 384 deletions(-) create mode 100644 run_tree/win32/intel/debug/err.txt create mode 100644 src_v2/editor/lumenarium_editor.h create mode 100644 src_v2/editor/lumenarium_ui.h 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 898b757ab1bdd748ff42ca3a34a8134640ba3f36..2960abaa7bee9e5c533b9753267595ea916b789b 100644 GIT binary patch delta 28617 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 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 0f16f81b1dfd750060cf056d8d209882ec828e87..f78c41edc47c99c5665b943ccc884228d58a7102 100644 GIT binary patch delta 220 zcmX@gwT*K^6rFwoYcf3=lq=fB9Qvr t;>Hwv5D-)FQpal9Hn0=*-y32U$!f3$Su9@=RuAwFj~UCOfdQ0sz9$Il2G< delta 265 zcmdnSd6a8H6r=ceZ77gd6E`+>!Dm=v&yiI->QrR0}`)G;wY03(nJfa=lV z^}!~psRk6~0Ah9^PAW}HOD!rE0y5Kc^wM*ji&7IyQk@{8lczEV3V=+O^Y~o}!XWl! X6&6!&5Ceo68962wve>hNtYriMX6-~> 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 895b93cf864f72c26e1bd471d5b60ca8972521e3..f70d1299c12b73a147d011c4127b17a69051d413 100644 GIT binary patch literal 160688 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
b&lK5?mal&n2!v@_2>U!m#RwsfqO`~ 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 IBH#h_02(HRT>t<8 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