diff --git a/src/AnimGraph/AnimGraphData.h b/src/AnimGraph/AnimGraphData.h index 805863a..08fe330 100644 --- a/src/AnimGraph/AnimGraphData.h +++ b/src/AnimGraph/AnimGraphData.h @@ -103,6 +103,8 @@ enum class AnimGraphType { GraphTypeLast }; +/*** Defines data on which an animation graph is executed (i.e. skeleton, animations). + */ struct AnimGraphContext { AnimGraph* m_graph = nullptr; ozz::animation::Skeleton* m_skeleton = nullptr; diff --git a/src/AnimGraphEditor/AnimGraphEditor.cc b/src/AnimGraphEditor/AnimGraphEditor.cc index 35674d3..d6e9669 100644 --- a/src/AnimGraphEditor/AnimGraphEditor.cc +++ b/src/AnimGraphEditor/AnimGraphEditor.cc @@ -797,9 +797,9 @@ void BlendTreeEditorDebugWidget() { ImGui::TableSetColumnIndex(0); ImGui::Text("Pin"); ImGui::TableNextColumn(); - ImGui::Text("%x", sNodeConnectionDebugState.sourceSocket.pin.AsPointer()); + ImGui::Text("%p", sNodeConnectionDebugState.sourceSocket.pin.AsPointer()); ImGui::TableNextColumn(); - ImGui::Text("%x", sNodeConnectionDebugState.targetSocket.pin.AsPointer()); + ImGui::Text("%p", sNodeConnectionDebugState.targetSocket.pin.AsPointer()); ImGui::TableNextRow(); ImGui::TableSetColumnIndex(0); diff --git a/src/main.cc b/src/main.cc index 6349f72..0fba704 100644 --- a/src/main.cc +++ b/src/main.cc @@ -39,14 +39,207 @@ const int MaxIndices = MaxVertices * 3; uint64_t last_time = 0; const int cMSAASampleCount = 8; -sg_pass_action pass_action; -sg_pipeline pip; -sg_bindings bind; - typedef struct { ImVec2 disp_size; } vs_params_t; +struct SokolImGuiState { + sg_pass_action pass_action; + sg_pipeline pip; + sg_bindings bind; + + void Init(GLFWwindow* window); + void Render(ImDrawData* draw_data, int width, int height); + void Shutdown(); +}; + +void SokolImGuiState::Init(GLFWwindow* window) { + // setup Dear Imgui + ImGui::CreateContext(); + ImGui::StyleColorsDark(); + ImGuiIO& io = ImGui::GetIO(); + io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; + io.IniFilename = "ATPImgui.ini"; + + //io.Fonts->AddFontDefault(); + ImFontConfig font_config; + font_config.OversampleH = 4; + font_config.OversampleV = 4; + font_config.GlyphExtraSpacing.x = 1.0f; + io.Fonts->AddFontFromMemoryCompressedTTF( + // roboto_medium_ttf_compressed_data, + // roboto_medium_ttf_compressed_size, + droid_sans_ttf_compressed_data, + droid_sans_ttf_compressed_size, + 14, + &font_config); + + ImGui_ImplGlfw_InitForOpenGL(window, true); + ImGui_ImplOpenGL3_Init("#version 130"); + + // ImNodes + ImNodes::CreateContext(); + + // dynamic vertex- and index-buffers for imgui-generated geometry + sg_buffer_desc vbuf_desc = {}; + vbuf_desc.usage = SG_USAGE_STREAM; + vbuf_desc.size = MaxVertices * sizeof(ImDrawVert); + bind.vertex_buffers[0] = sg_make_buffer(&vbuf_desc); + + sg_buffer_desc ibuf_desc = {}; + ibuf_desc.type = SG_BUFFERTYPE_INDEXBUFFER; + ibuf_desc.usage = SG_USAGE_STREAM; + ibuf_desc.size = MaxIndices * sizeof(ImDrawIdx); + bind.index_buffer = sg_make_buffer(&ibuf_desc); + + // font texture for imgui's default font + unsigned char* font_pixels; + int font_width, font_height; + io.Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height); + sg_image_desc img_desc = {}; + img_desc.width = font_width; + img_desc.height = font_height; + img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; + img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; + img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; + img_desc.data.subimage[0][0] = + sg_range{font_pixels, size_t(font_width * font_height * 4)}; + bind.fs_images[0] = sg_make_image(&img_desc); + + // shader object for imgui rendering + sg_shader_desc shd_desc = {}; + auto& ub = shd_desc.vs.uniform_blocks[0]; + ub.size = sizeof(vs_params_t); + ub.uniforms[0].name = "disp_size"; + ub.uniforms[0].type = SG_UNIFORMTYPE_FLOAT2; + shd_desc.vs.source = + "#version 330\n" + "uniform vec2 disp_size;\n" + "layout(location=0) in vec2 position;\n" + "layout(location=1) in vec2 texcoord0;\n" + "layout(location=2) in vec4 color0;\n" + "out vec2 uv;\n" + "out vec4 color;\n" + "void main() {\n" + " gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, " + "1.0);\n" + " uv = texcoord0;\n" + " color = color0;\n" + "}\n"; + shd_desc.fs.images[0].name = "tex"; + shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; + shd_desc.fs.source = + "#version 330\n" + "uniform sampler2D tex;\n" + "in vec2 uv;\n" + "in vec4 color;\n" + "out vec4 frag_color;\n" + "void main() {\n" + " frag_color = texture(tex, uv) * color;\n" + "}\n"; + sg_shader shd = sg_make_shader(&shd_desc); + + // pipeline object for imgui rendering + sg_pipeline_desc pip_desc = {}; + pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert); + auto& attrs = pip_desc.layout.attrs; + attrs[0].format = SG_VERTEXFORMAT_FLOAT2; + attrs[1].format = SG_VERTEXFORMAT_FLOAT2; + attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; + pip_desc.shader = shd; + pip_desc.index_type = SG_INDEXTYPE_UINT16; + pip_desc.colors[0].blend.enabled = true; + pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; + pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; + pip_desc.colors[0].write_mask = SG_COLORMASK_RGB; + pip_desc.sample_count = cMSAASampleCount; + pip_desc.label = "imgui-rendering"; + pip = sg_make_pipeline(&pip_desc); + + // initial clear color + pass_action.colors[0].action = SG_ACTION_CLEAR; + pass_action.colors[0].value = {0.1f, 0.1f, 0.1f, 1.0f}; +} + +void SokolImGuiState::Render(ImDrawData* draw_data, int width, int height) { + assert(draw_data); + + sg_begin_default_pass(&pass_action, width, height); + + if (draw_data->CmdListsCount == 0) { + sg_end_pass(); + return; + } + + sg_image default_image = bind.fs_images[0]; + + // render the command list + sg_apply_pipeline(pip); + vs_params_t vs_params; + vs_params.disp_size.x = ImGui::GetIO().DisplaySize.x; + vs_params.disp_size.y = ImGui::GetIO().DisplaySize.y; + sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE(vs_params)); + for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++) { + const ImDrawList* cl = draw_data->CmdLists[cl_index]; + + // append vertices and indices to buffers, record start offsets in resource binding struct + const uint32_t vtx_size = cl->VtxBuffer.size() * sizeof(ImDrawVert); + const uint32_t idx_size = cl->IdxBuffer.size() * sizeof(ImDrawIdx); + const uint32_t vb_offset = sg_append_buffer( + bind.vertex_buffers[0], + {&cl->VtxBuffer.front(), vtx_size}); + const uint32_t ib_offset = + sg_append_buffer(bind.index_buffer, {&cl->IdxBuffer.front(), idx_size}); + /* don't render anything if the buffer is in overflow state (this is also + checked internally in sokol_gfx, draw calls that attempt from + overflowed buffers will be silently dropped) + */ + if (sg_query_buffer_overflow(bind.vertex_buffers[0]) + || sg_query_buffer_overflow(bind.index_buffer)) { + continue; + } + + bind.vertex_buffer_offsets[0] = vb_offset; + bind.index_buffer_offset = ib_offset; + sg_apply_bindings(&bind); + + int base_element = 0; + for (const ImDrawCmd& pcmd : cl->CmdBuffer) { + if (pcmd.UserCallback) { + pcmd.UserCallback(cl, &pcmd); + } else { + uint32_t prev_fs_image_id = bind.fs_images[0].id; + if (pcmd.TextureId != 0) { + bind.fs_images[0].id = (uint32_t)(uintptr_t)pcmd.TextureId; + sg_apply_bindings(&bind); + } + + const int scissor_x = (int)(pcmd.ClipRect.x); + const int scissor_y = (int)(pcmd.ClipRect.y); + const int scissor_w = (int)(pcmd.ClipRect.z - pcmd.ClipRect.x); + const int scissor_h = (int)(pcmd.ClipRect.w - pcmd.ClipRect.y); + sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true); + sg_draw(base_element, pcmd.ElemCount, 1); + + if (pcmd.TextureId != 0) { + bind.fs_images[0].id = prev_fs_image_id; + sg_apply_bindings(&bind); + } + } + base_element += pcmd.ElemCount; + } + } + + sg_end_pass(); +} + +void SokolImGuiState::Shutdown() { + ImGui_ImplOpenGL3_Shutdown(); + ImGui_ImplGlfw_Shutdown(); +} + +SokolImGuiState gSokolImGuiState = {}; + static void draw_imgui(ImDrawData*); #define HANDMADE_MATH_NO_SSE @@ -72,7 +265,7 @@ static struct { ozz::vector local_matrices; } ozz; sg_pass_action pass_action = {}; - Camera camera; + Camera camera = {}; struct { bool skeleton; bool animation; @@ -163,6 +356,13 @@ struct Viewport { this->pass = sg_make_pass(&offscreen_pass_desc); } + + void Render() { + sg_begin_pass(pass, &pass_action); + sgl_load_pipeline(glpip); + sgl_draw(); + sg_end_pass(); + } }; struct ApplicationConfig { @@ -352,12 +552,7 @@ void from_json(const nlohmann::json& j, ApplicationConfig& config) { ApplicationConfig gApplicationConfig; -// io buffers for skeleton and animation data files, we know the max file size upfront -static uint8_t skel_data_buffer[4 * 1024]; -static uint8_t anim_data_buffer[32 * 1024]; - static void draw_grid(); -static void frame(); void handle_mouse(GLFWwindow* w, GuiInputState* io_input_state) { if (!glfwGetWindowAttrib(w, GLFW_FOCUSED)) { @@ -374,7 +569,7 @@ void handle_mouse(GLFWwindow* w, GuiInputState* io_input_state) { io_input_state->mousedX = 0; io_input_state->mousedY = 0; } - io_input_state->mouseX = int32_t(mouse_x); + io_input_state->mouseX = static_cast(mouse_x); io_input_state->mouseY = int32_t(mouse_y); io_input_state->mouseButton = glfwGetMouseButton(w, 0) @@ -433,7 +628,6 @@ void sokol_logger( int main() { // window and GL context via GLFW and flextGL glfwInit(); - const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GLFW_TRUE); @@ -500,111 +694,8 @@ int main() { Camera_Init(&state.camera); - // setup Dear Imgui - ImGui::CreateContext(); - ImGui::StyleColorsDark(); + gSokolImGuiState.Init(window); ImGuiIO& io = ImGui::GetIO(); - io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; - io.IniFilename = "ATPImgui.ini"; - - //io.Fonts->AddFontDefault(); - ImFontConfig font_config; - font_config.OversampleH = 4; - font_config.OversampleV = 4; - font_config.GlyphExtraSpacing.x = 1.0f; - io.Fonts->AddFontFromMemoryCompressedTTF( - // roboto_medium_ttf_compressed_data, - // roboto_medium_ttf_compressed_size, - droid_sans_ttf_compressed_data, - droid_sans_ttf_compressed_size, - 14, - &font_config); - - ImGui_ImplGlfw_InitForOpenGL(window, true); - ImGui_ImplOpenGL3_Init(glsl_version); - - // ImNodes - ImNodes::CreateContext(); - - // dynamic vertex- and index-buffers for imgui-generated geometry - sg_buffer_desc vbuf_desc = {}; - vbuf_desc.usage = SG_USAGE_STREAM; - vbuf_desc.size = MaxVertices * sizeof(ImDrawVert); - bind.vertex_buffers[0] = sg_make_buffer(&vbuf_desc); - - sg_buffer_desc ibuf_desc = {}; - ibuf_desc.type = SG_BUFFERTYPE_INDEXBUFFER; - ibuf_desc.usage = SG_USAGE_STREAM; - ibuf_desc.size = MaxIndices * sizeof(ImDrawIdx); - bind.index_buffer = sg_make_buffer(&ibuf_desc); - - // font texture for imgui's default font - unsigned char* font_pixels; - int font_width, font_height; - io.Fonts->GetTexDataAsRGBA32(&font_pixels, &font_width, &font_height); - sg_image_desc img_desc = {}; - img_desc.width = font_width; - img_desc.height = font_height; - img_desc.pixel_format = SG_PIXELFORMAT_RGBA8; - img_desc.wrap_u = SG_WRAP_CLAMP_TO_EDGE; - img_desc.wrap_v = SG_WRAP_CLAMP_TO_EDGE; - img_desc.data.subimage[0][0] = - sg_range{font_pixels, size_t(font_width * font_height * 4)}; - bind.fs_images[0] = sg_make_image(&img_desc); - - // shader object for imgui rendering - sg_shader_desc shd_desc = {}; - auto& ub = shd_desc.vs.uniform_blocks[0]; - ub.size = sizeof(vs_params_t); - ub.uniforms[0].name = "disp_size"; - ub.uniforms[0].type = SG_UNIFORMTYPE_FLOAT2; - shd_desc.vs.source = - "#version 330\n" - "uniform vec2 disp_size;\n" - "layout(location=0) in vec2 position;\n" - "layout(location=1) in vec2 texcoord0;\n" - "layout(location=2) in vec4 color0;\n" - "out vec2 uv;\n" - "out vec4 color;\n" - "void main() {\n" - " gl_Position = vec4(((position/disp_size)-0.5)*vec2(2.0,-2.0), 0.5, " - "1.0);\n" - " uv = texcoord0;\n" - " color = color0;\n" - "}\n"; - shd_desc.fs.images[0].name = "tex"; - shd_desc.fs.images[0].image_type = SG_IMAGETYPE_2D; - shd_desc.fs.source = - "#version 330\n" - "uniform sampler2D tex;\n" - "in vec2 uv;\n" - "in vec4 color;\n" - "out vec4 frag_color;\n" - "void main() {\n" - " frag_color = texture(tex, uv) * color;\n" - "}\n"; - sg_shader shd = sg_make_shader(&shd_desc); - - // pipeline object for imgui rendering - sg_pipeline_desc pip_desc = {}; - pip_desc.layout.buffers[0].stride = sizeof(ImDrawVert); - auto& attrs = pip_desc.layout.attrs; - attrs[0].format = SG_VERTEXFORMAT_FLOAT2; - attrs[1].format = SG_VERTEXFORMAT_FLOAT2; - attrs[2].format = SG_VERTEXFORMAT_UBYTE4N; - pip_desc.shader = shd; - pip_desc.index_type = SG_INDEXTYPE_UINT16; - pip_desc.colors[0].blend.enabled = true; - pip_desc.colors[0].blend.src_factor_rgb = SG_BLENDFACTOR_SRC_ALPHA; - pip_desc.colors[0].blend.dst_factor_rgb = SG_BLENDFACTOR_ONE_MINUS_SRC_ALPHA; - pip_desc.colors[0].write_mask = SG_COLORMASK_RGB; - pip_desc.sample_count = cMSAASampleCount; - pip_desc.label = "imgui-rendering"; - pip = sg_make_pipeline(&pip_desc); - - // initial clear color - pass_action.colors[0].action = SG_ACTION_CLEAR; - pass_action.colors[0].value = {0.1f, 0.1f, 0.1f, 1.0f}; Viewport offscreen_viewport; @@ -1038,16 +1129,12 @@ int main() { ImGui::ShowDemoWindow(); } - sg_begin_pass(offscreen_viewport.pass, &offscreen_viewport.pass_action); - sgl_load_pipeline(offscreen_viewport.glpip); - sgl_draw(); - sg_end_pass(); + offscreen_viewport.Render(); // Rendering of the main gui - sg_begin_default_pass(&pass_action, cur_width, cur_height); ImGui::Render(); - draw_imgui(ImGui::GetDrawData()); - sg_end_pass(); + + gSokolImGuiState.Render(ImGui::GetDrawData(), cur_width, cur_height); sg_commit(); glfwSwapBuffers(window); @@ -1060,8 +1147,7 @@ int main() { ax::NodeEditor::DestroyEditor(gApplicationConfig.graph_editor.context); ImNodes::DestroyContext(); - ImGui_ImplOpenGL3_Shutdown(); - ImGui_ImplGlfw_Shutdown(); + gSokolImGuiState.Shutdown(); ImGui::DestroyContext(); @@ -1074,54 +1160,6 @@ int main() { return 0; } -bool LoadSkeleton(const char* _filename, ozz::animation::Skeleton* _skeleton) { - assert(_filename && _skeleton); - ozz::log::Out() << "Loading skeleton archive " << _filename << "." - << std::endl; - ozz::io::File file(_filename, "rb"); - if (!file.opened()) { - ozz::log::Err() << "Failed to open skeleton file " << _filename << "." - << std::endl; - return false; - } - ozz::io::IArchive archive(&file); - if (!archive.TestTag()) { - ozz::log::Err() << "Failed to load skeleton instance from file " - << _filename << "." << std::endl; - return false; - } - - // Once the tag is validated, reading cannot fail. - archive >> *_skeleton; - - return true; -} - -bool LoadAnimation( - const char* _filename, - ozz::animation::Animation* _animation) { - assert(_filename && _animation); - ozz::log::Out() << "Loading animation archive: " << _filename << "." - << std::endl; - ozz::io::File file(_filename, "rb"); - if (!file.opened()) { - ozz::log::Err() << "Failed to open animation file " << _filename << "." - << std::endl; - return false; - } - ozz::io::IArchive archive(&file); - if (!archive.TestTag()) { - ozz::log::Err() << "Failed to load animation instance from file " - << _filename << "." << std::endl; - return false; - } - - // Once the tag is validated, reading cannot fail. - archive >> *_animation; - - return true; -} - static void draw_vec(const ozz::math::SimdFloat4& vec) { sgl_v3f(ozz::math::GetX(vec), ozz::math::GetY(vec), ozz::math::GetZ(vec)); } @@ -1172,70 +1210,3 @@ static void draw_grid(void) { sgl_end(); } - -// draw ImGui draw lists via sokol-gfx -void draw_imgui(ImDrawData* draw_data) { - assert(draw_data); - if (draw_data->CmdListsCount == 0) { - return; - } - - sg_image default_image = bind.fs_images[0]; - - // render the command list - sg_apply_pipeline(pip); - vs_params_t vs_params; - vs_params.disp_size.x = ImGui::GetIO().DisplaySize.x; - vs_params.disp_size.y = ImGui::GetIO().DisplaySize.y; - sg_apply_uniforms(SG_SHADERSTAGE_VS, 0, SG_RANGE(vs_params)); - for (int cl_index = 0; cl_index < draw_data->CmdListsCount; cl_index++) { - const ImDrawList* cl = draw_data->CmdLists[cl_index]; - - // append vertices and indices to buffers, record start offsets in resource binding struct - const uint32_t vtx_size = cl->VtxBuffer.size() * sizeof(ImDrawVert); - const uint32_t idx_size = cl->IdxBuffer.size() * sizeof(ImDrawIdx); - const uint32_t vb_offset = sg_append_buffer( - bind.vertex_buffers[0], - {&cl->VtxBuffer.front(), vtx_size}); - const uint32_t ib_offset = - sg_append_buffer(bind.index_buffer, {&cl->IdxBuffer.front(), idx_size}); - /* don't render anything if the buffer is in overflow state (this is also - checked internally in sokol_gfx, draw calls that attempt from - overflowed buffers will be silently dropped) - */ - if (sg_query_buffer_overflow(bind.vertex_buffers[0]) - || sg_query_buffer_overflow(bind.index_buffer)) { - continue; - } - - bind.vertex_buffer_offsets[0] = vb_offset; - bind.index_buffer_offset = ib_offset; - sg_apply_bindings(&bind); - - int base_element = 0; - for (const ImDrawCmd& pcmd : cl->CmdBuffer) { - if (pcmd.UserCallback) { - pcmd.UserCallback(cl, &pcmd); - } else { - uint32_t prev_fs_image_id = bind.fs_images[0].id; - if (pcmd.TextureId != 0) { - bind.fs_images[0].id = (uint32_t)(uintptr_t)pcmd.TextureId; - sg_apply_bindings(&bind); - } - - const int scissor_x = (int)(pcmd.ClipRect.x); - const int scissor_y = (int)(pcmd.ClipRect.y); - const int scissor_w = (int)(pcmd.ClipRect.z - pcmd.ClipRect.x); - const int scissor_h = (int)(pcmd.ClipRect.w - pcmd.ClipRect.y); - sg_apply_scissor_rect(scissor_x, scissor_y, scissor_w, scissor_h, true); - sg_draw(base_element, pcmd.ElemCount, 1); - - if (pcmd.TextureId != 0) { - bind.fs_images[0].id = prev_fs_image_id; - sg_apply_bindings(&bind); - } - } - base_element += pcmd.ElemCount; - } - } -} \ No newline at end of file