Minor cleanup and refactoring.

This commit is contained in:
Martin Felis 2025-03-30 22:35:49 +02:00
parent 887131af37
commit c173707a18
3 changed files with 215 additions and 242 deletions

View File

@ -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;

View File

@ -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);

View File

@ -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<ozz::math::SoaTransform> 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<int32_t>(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::animation::Skeleton>()) {
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::animation::Animation>()) {
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;
}
}
}