// clang-format off // glad must be included before any other OpenGL libraries #include // clang-format on #include #include #include #include #include #include // clang-format off #ifndef IMGUI_DEFINE_MATH_OPERATORS #define IMGUI_DEFINE_MATH_OPERATORS #endif #include "backends/imgui_impl_glfw.h" #include "backends/imgui_impl_opengl3.h" #include "ImGuizmo.h" #include "imgui_internal.h" #include "imgui.h" // clang-format on #include "render_utils.h" #include "simulator.h" #include "srender.h" #include "utils.h" #define SCONVCOL_IMPLEMENTATION #include "sconvcol.h" GLFWwindow* gWindow = nullptr; GuiInputState* gGuiInputState = nullptr; CameraState* gCameraState = nullptr; // Rendering srndr* gRndr = nullptr; srview* gView = nullptr; srcmdbuf* gRndrCmds = nullptr; simd4x4f gProjMatrix{ simd4f_create(1.f, 0.f, 0.0, 0.f), simd4f_create(0.f, 1.f, 0.f, 0.f), simd4f_create(0.f, 0.f, 1.f, 0.f), simd4f_create(0.f, 0.f, 0.f, 1.f)}; simd4x4f gTransformMatrix{ simd4f_create(1.0f, 0.f, 0.0, 0.f), simd4f_create(0.f, 1.0f, 0.f, 0.f), simd4f_create(0.f, 0.f, 1.0f, 0.f), simd4f_create(0.f, 0.f, 0.f, 1.f)}; vectorial_inline simd4x4f simd4x4f_scale(simd4f s) { return simd4x4f_create( simd4f_create(simd4f_get_x(s), 0.f, 0.f, 0.f), simd4f_create(0.f, simd4f_get_y(s), 0.f, 0.f), simd4f_create(0.f, 0.f, simd4f_get_z(s), 0.f), simd4f_create(0.f, 0.f, 0.f, simd4f_get_w(s))); } double mouse_scroll_x = 0.; double mouse_scroll_y = 0.; enum ViewMode { ViewModeSimulation = 0, ViewModeGuizmoTest = 1 }; ViewMode gViewMode = ViewModeSimulation; bool gGizmoEnabled = true; enum ControlMode { ControlModeNone = 0, ControlModeFirstPersonView = 1 }; ControlMode gControlMode = ControlModeNone; struct Dialogs { bool mCameraDialog = false; bool mImGuiDemo = false; bool mSimulator = false; bool mImGuizmoTransform = false; }; Dialogs* gDialogs = nullptr; using namespace std; static void error_callback(int error, const char* description) { fprintf(stderr, "Error (%d): %s\n", error, description); } static void opengl_error_callback( GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam) { const char* source_str; switch (source) { case GL_DEBUG_SOURCE_API: source_str = "API"; break; case GL_DEBUG_SOURCE_WINDOW_SYSTEM: source_str = "Window System"; break; case GL_DEBUG_SOURCE_SHADER_COMPILER: source_str = "Shader Compiler"; break; case GL_DEBUG_SOURCE_THIRD_PARTY: source_str = "3rd Party"; break; case GL_DEBUG_SOURCE_APPLICATION: source_str = "Application"; break; default: source_str = "Other"; break; } const char* type_str; switch (type) { case GL_DEBUG_TYPE_ERROR: type_str = "Error"; break; case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR: type_str = "Deprecated Behaviour"; break; case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR: type_str = "Undefined Behaviour"; break; case GL_DEBUG_TYPE_PORTABILITY: type_str = "Portability"; break; case GL_DEBUG_TYPE_PERFORMANCE: type_str = "Performance"; break; case GL_DEBUG_TYPE_MARKER: type_str = "Marker"; break; case GL_DEBUG_TYPE_PUSH_GROUP: type_str = "Push Group"; break; case GL_DEBUG_TYPE_POP_GROUP: type_str = "Pop Group"; break; default: type_str = "Other"; break; } const char* severity_str; switch (severity) { case GL_DEBUG_SEVERITY_HIGH: severity_str = "high"; break; case GL_DEBUG_SEVERITY_MEDIUM: severity_str = "medium"; break; case GL_DEBUG_SEVERITY_LOW: severity_str = "low"; break; case GL_DEBUG_SEVERITY_NOTIFICATION: severity_str = "notification"; break; default: severity_str = "unknown"; } gLog( "OpenGL Error (%s, type %s, severity = %s): %s", source_str, type_str, severity_str, message); } static void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) glfwSetWindowShouldClose(window, GLFW_TRUE); } void signal_handler(int signo) { gLog("Received signal %d", signo); } void mouse_scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { mouse_scroll_x += xoffset; mouse_scroll_y += yoffset; } void handle_mouse() { if (!glfwGetWindowAttrib(gWindow, GLFW_FOCUSED)) { return; } double mouse_x, mouse_y; glfwGetCursorPos(gWindow, &mouse_x, &mouse_y); if (gGuiInputState->mouseButton) { gGuiInputState->mousedX = int32_t(mouse_x) - gGuiInputState->mouseX; gGuiInputState->mousedY = int32_t(mouse_y) - gGuiInputState->mouseY; } else { gGuiInputState->mousedX = 0; gGuiInputState->mousedY = 0; } gGuiInputState->mouseX = int32_t(mouse_x); gGuiInputState->mouseY = int32_t(mouse_y); gGuiInputState->mouseScroll = int32_t(mouse_scroll_y); gGuiInputState->mouseButton = glfwGetMouseButton(gWindow, 0) + (glfwGetMouseButton(gWindow, 1) << 1) + (glfwGetMouseButton(gWindow, 2) << 2); } void ShowDockspace(bool open) { static bool opt_fullscreen = true; static bool opt_padding = false; static ImGuiDockNodeFlags dockspace_flags = ImGuiDockNodeFlags_None; ImGuiIO& io = ImGui::GetIO(); (void)io; // We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into, // because it would be confusing to have two docking targets within each others. ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking; if (opt_fullscreen) { ImGuiViewport* viewport = ImGui::GetMainViewport(); ImGui::SetNextWindowPos(viewport->GetWorkPos()); ImGui::SetNextWindowSize(viewport->GetWorkSize()); ImGui::SetNextWindowViewport(viewport->ID); ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f); ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.0f); window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove; window_flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus; } else { dockspace_flags &= ~ImGuiDockNodeFlags_PassthruCentralNode; } // When using ImGuiDockNodeFlags_PassthruCentralNode, DockSpace() will render our background // and handle the pass-thru hole, so we ask Begin() to not render a background. if (dockspace_flags & ImGuiDockNodeFlags_PassthruCentralNode) window_flags |= ImGuiWindowFlags_NoBackground; // Important: note that we proceed even if Begin() returns false (aka window is collapsed). // This is because we want to keep our DockSpace() active. If a DockSpace() is inactive, // all active windows docked into it will lose their parent and become undocked. // We cannot preserve the docking relationship between an active window and an inactive docking, otherwise // any change of dockspace/settings would lead to windows being stuck in limbo and never being visible. if (!opt_padding) ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f)); ImGui::Begin("DockSpace Demo", &open, window_flags); if (!opt_padding) ImGui::PopStyleVar(); if (opt_fullscreen) ImGui::PopStyleVar(2); // DockSpace if (io.ConfigFlags & ImGuiConfigFlags_DockingEnable) { ImGuiID dockspace_id = ImGui::GetID("MyDockSpace"); ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags); } else { gLog("Error: no docking not enabled"); } ImGui::End(); } static ImGuizmo::OPERATION mCurrentGizmoOperation(ImGuizmo::TRANSLATE); void RenderGuizmoTest(srcmdbuf* cmdbuf) { srcmd rcmd; srcmd_clear(&rcmd); rcmd.type = SRndrCmdTypeGrid; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { simd4x4f_translation(&rcmd.mat, 0.0f, 0.0f, 0.0f); srcmdbuf_add(cmdbuf, &rcmd); } } rcmd.type = SRndrCmdTypeCube; rcmd.mat = gTransformMatrix; srcmdbuf_add(cmdbuf, &rcmd); } void ShowViewManip() { const ImGuiStyle& imgui_style = ImGui::GetStyle(); ImGuizmo::SetDrawlist(); float windowWidth = (float)ImGui::GetWindowWidth(); float windowHeight = (float)ImGui::GetWindowHeight(); ImGuizmo::SetRect( ImGui::GetWindowPos().x, ImGui::GetWindowPos().y, windowWidth, windowHeight); float viewManipulateRight = ImGui::GetWindowPos().x + windowWidth; float title_height = ImGui::GetFontSize() + imgui_style.FramePadding.y * 2.f; ImVec2 window_pos = ImGui::GetWindowPos(); ImVec2 view_manip_widget_size(128, 128); ImVec2 view_manip_widget_pos( viewManipulateRight - 128 - imgui_style.WindowPadding.x, window_pos.y + title_height + imgui_style.WindowPadding.y); ImGui::SetCursorPos(view_manip_widget_pos - ImGui::GetWindowPos()); ImGui::InvisibleButton("ViewManipulator", view_manip_widget_size); ImGuizmo::ViewManipulate( (float*)&(gCameraState->mtxView.x), 10.0f, view_manip_widget_pos, view_manip_widget_size, 0x40404040); } void ShowTransformManip( float* cameraView, float* cameraProjection, float* matrix) { static ImGuizmo::MODE mCurrentGizmoMode(ImGuizmo::LOCAL); static bool useSnap = false; static float snap[3] = {1.f, 1.f, 1.f}; static float bounds[] = {-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f}; static float boundsSnap[] = {0.1f, 0.1f, 0.1f}; static bool boundSizing = false; static bool boundSizingSnap = false; bool useWindow = false; bool editTransformDecomposition = true; ImVec2 window_size = ImGui::GetWindowSize(); ImVec2 window_pos = ImGui::GetWindowPos(); ImGuiStyle imgui_style = ImGui::GetStyle(); float title_height = ImGui::GetFontSize() + imgui_style.FramePadding.y * 2.f; window_pos.x += imgui_style.WindowPadding.x; window_pos.y += imgui_style.WindowPadding.y + title_height; window_size.x -= imgui_style.WindowPadding.x * 2; window_size.y -= imgui_style.WindowPadding.y * 2 + title_height; if (gDialogs->mImGuizmoTransform) { ImGui::Begin("Guizmo", &gDialogs->mImGuizmoTransform); if (editTransformDecomposition) { if (ImGui::IsKeyPressed(90)) mCurrentGizmoOperation = ImGuizmo::TRANSLATE; if (ImGui::IsKeyPressed(69)) mCurrentGizmoOperation = ImGuizmo::ROTATE; if (ImGui::IsKeyPressed(82)) // r Key mCurrentGizmoOperation = ImGuizmo::SCALE; if (ImGui::RadioButton( "Translate", mCurrentGizmoOperation == ImGuizmo::TRANSLATE)) mCurrentGizmoOperation = ImGuizmo::TRANSLATE; ImGui::SameLine(); if (ImGui::RadioButton( "Rotate", mCurrentGizmoOperation == ImGuizmo::ROTATE)) mCurrentGizmoOperation = ImGuizmo::ROTATE; ImGui::SameLine(); if (ImGui::RadioButton( "Scale", mCurrentGizmoOperation == ImGuizmo::SCALE)) mCurrentGizmoOperation = ImGuizmo::SCALE; if (ImGui::RadioButton( "Universal", mCurrentGizmoOperation == ImGuizmo::UNIVERSAL)) mCurrentGizmoOperation = ImGuizmo::UNIVERSAL; float matrixTranslation[3], matrixRotation[3], matrixScale[3]; ImGuizmo::DecomposeMatrixToComponents( matrix, matrixTranslation, matrixRotation, matrixScale); ImGui::InputFloat3("Tr", matrixTranslation); ImGui::InputFloat3("Rt", matrixRotation); ImGui::InputFloat3("Sc", matrixScale); ImGuizmo::RecomposeMatrixFromComponents( matrixTranslation, matrixRotation, matrixScale, matrix); if (mCurrentGizmoOperation != ImGuizmo::SCALE) { if (ImGui::RadioButton("Local", mCurrentGizmoMode == ImGuizmo::LOCAL)) mCurrentGizmoMode = ImGuizmo::LOCAL; ImGui::SameLine(); if (ImGui::RadioButton("World", mCurrentGizmoMode == ImGuizmo::WORLD)) mCurrentGizmoMode = ImGuizmo::WORLD; } if (ImGui::IsKeyPressed(83)) useSnap = !useSnap; ImGui::Checkbox("", &useSnap); ImGui::SameLine(); switch (mCurrentGizmoOperation) { case ImGuizmo::TRANSLATE: ImGui::InputFloat3("Snap", &snap[0]); break; case ImGuizmo::ROTATE: ImGui::InputFloat("Angle Snap", &snap[0]); break; case ImGuizmo::SCALE: ImGui::InputFloat("Scale Snap", &snap[0]); break; default: break; } ImGui::Checkbox("Bound Sizing", &boundSizing); if (boundSizing) { ImGui::PushID(3); ImGui::Checkbox("", &boundSizingSnap); ImGui::SameLine(); ImGui::InputFloat3("Snap", boundsSnap); ImGui::PopID(); } } ImGui::End(); } ImGuiIO& io = ImGui::GetIO(); float viewManipulateRight = io.DisplaySize.x; float viewManipulateTop = 0; if (useWindow) { ImGui::SetNextWindowSize(ImVec2(800, 400)); ImGui::SetNextWindowPos(ImVec2(400, 20)); ImGui::PushStyleColor( ImGuiCol_WindowBg, (ImVec4)ImColor(0.35f, 0.3f, 0.3f)); ImGui::Begin("Gizmo", 0); ImGuizmo::SetDrawlist(); float windowWidth = (float)ImGui::GetWindowWidth(); ImGuizmo::SetRect(window_pos.x, window_pos.y, window_size.x, window_size.y); } else { ImGuizmo::SetDrawlist(); ImGuizmo::SetRect(window_pos.x, window_pos.y, window_size.x, window_size.y); } simd4x4f identity_mat; simd4x4f_identity(&identity_mat); bool modified = ImGuizmo::Manipulate( cameraView, cameraProjection, mCurrentGizmoOperation, mCurrentGizmoMode, matrix, NULL, useSnap ? &snap[0] : NULL, boundSizing ? bounds : NULL, boundSizingSnap ? boundsSnap : NULL); if (useWindow) { ImGui::End(); ImGui::PopStyleColor(1); } } void SimulatorSceneRender(srcmdbuf* render_commands) { // Populate render commands srcmdbuf_clear(render_commands); srcmd rcmd; srcmd_clear(&rcmd); rcmd.type = SRndrCmdTypeFrame; srcmdbuf_add(render_commands, &rcmd); simulator_draw(render_commands); if (gDialogs->mSimulator) { ImGui::Begin("Simulator", &gDialogs->mSimulator); simulator_gui(); ImGui::End(); } } struct SceneHull { sch_hull hull; srmeshdata* mesh = nullptr; simd4x4f transform = { simd4f_create(1.f, 0.f, 0.0, 0.f), simd4f_create(0.f, 1.f, 0.f, 0.f), simd4f_create(0.f, 0.f, 1.f, 0.f), simd4f_create(0.f, 0.f, 0.f, 1.f)}; ~SceneHull() { if (mesh != nullptr) { destroy(); } }; void destroy() { srmesh_destroy(mesh); mesh = nullptr; } void createMesh() { assert(mesh == nullptr); // create mesh for hull static srvrtxdata mesh_buffer_data[1024]; static GLuint index_buffer_data[1024]; int vertex_index = -1; int index_count = -1; int triangle_count = 0; int face_vert0_idx = 0; for (int fi = 0; fi < hull.num_faces; fi++) { sch_face* face = &hull.faces[fi]; sch_edge* edge0 = face->edge; sch_vert* face_vert0 = edge0->vert; sch_edge* cur_edge = edge0->next; sch_vert* cur_vert = nullptr; sch_edge* next_edge = nullptr; sch_vert* next_vert = nullptr; int tri_vert_0_idx = 0; int tri_vert_1_idx = 0; int tri_vert_2_idx = 0; sch_plane plane; sch_hull_calc_plane(&hull, fi, &plane); // add face_vert0 (later used as tri_vert_0) vertex_index++; face_vert0_idx = vertex_index; tri_vert_0_idx = face_vert0_idx; srvrtxdata* mesh_vert = &mesh_buffer_data[tri_vert_0_idx]; mesh_vert->x = simd4f_get_x(face_vert0->p); mesh_vert->y = simd4f_get_y(face_vert0->p); mesh_vert->z = simd4f_get_z(face_vert0->p); mesh_vert->w = 1.f; mesh_vert->nx = simd4f_get_x(plane.n); mesh_vert->ny = simd4f_get_y(plane.n); mesh_vert->nz = simd4f_get_z(plane.n); mesh_vert->color[0] = fabs(mesh_vert->nx) * 255; mesh_vert->color[1] = fabs(mesh_vert->ny) * 255; mesh_vert->color[2] = fabs(mesh_vert->nz) * 255; mesh_vert->color[3] = 255; // add tri_vert_1 cur_vert = cur_edge->vert; tri_vert_1_idx = ++vertex_index; mesh_vert = &mesh_buffer_data[tri_vert_1_idx]; mesh_vert->x = simd4f_get_x(cur_vert->p); mesh_vert->y = simd4f_get_y(cur_vert->p); mesh_vert->z = simd4f_get_z(cur_vert->p); mesh_vert->w = 1.f; mesh_vert->nx = simd4f_get_x(plane.n); mesh_vert->ny = simd4f_get_y(plane.n); mesh_vert->nz = simd4f_get_z(plane.n); mesh_vert->color[0] = fabs(mesh_vert->nx) * 255; mesh_vert->color[1] = fabs(mesh_vert->ny) * 255; mesh_vert->color[2] = fabs(mesh_vert->nz) * 255; mesh_vert->color[3] = 255; do { // add face_vert0 index_buffer_data[++index_count] = tri_vert_0_idx; // add face_vert1 index_buffer_data[++index_count] = tri_vert_1_idx; next_edge = cur_edge->next; next_vert = next_edge->vert; tri_vert_2_idx = ++vertex_index; mesh_vert = &mesh_buffer_data[tri_vert_2_idx]; mesh_vert->x = simd4f_get_x(next_vert->p); mesh_vert->y = simd4f_get_y(next_vert->p); mesh_vert->z = simd4f_get_z(next_vert->p); mesh_vert->w = 1.f; mesh_vert->nx = simd4f_get_x(plane.n); mesh_vert->ny = simd4f_get_y(plane.n); mesh_vert->nz = simd4f_get_z(plane.n); mesh_vert->color[0] = fabs(mesh_vert->nx) * 255; mesh_vert->color[1] = fabs(mesh_vert->ny) * 255; mesh_vert->color[2] = fabs(mesh_vert->nz) * 255; mesh_vert->color[3] = 255; index_buffer_data[++index_count] = tri_vert_2_idx; triangle_count++; cur_edge = next_edge; tri_vert_1_idx = tri_vert_2_idx; } while (next_edge->next != edge0); } mesh = srmesh_create( mesh_buffer_data, vertex_index + 1, index_buffer_data, index_count + 1, GL_TRIANGLES, index_count + 1); } }; struct SconvHullScene { SceneHull mHullA; SceneHull mHullB; SceneHull* mCurrentHull; void setupSceneRotTrans() { simd4x4f rot; simd4x4f_axis_rotation(&rot, 0.4f, simd4f_create (0.f, 1.f, 0.f, 1.f)); simd4x4f translation; simd4x4f_translation(&translation, -0.5f - 0.51f * sqrtf(2.), 0.0f, 0.f); simd4x4f_matrix_mul(&translation, &rot, &mHullB.transform); } void setupSceneEdgeCollision() { simd4x4f rot_y; simd4x4f_axis_rotation(&rot_y, 0.25f * M_PI, simd4f_create (0.f, 1.f, 0.f, 1.f)); simd4x4f rot_z; simd4x4f_axis_rotation(&rot_z, 0.25f * M_PI, simd4f_create (0.f, 0.f, 1.f, 1.f)); simd4x4f rot; simd4x4f_matrix_mul(&rot_y, &rot_z, &rot); simd4x4f translation; simd4x4f_translation(&translation, 0.98f, 0.f, -0.98f); simd4x4f_matrix_mul(&translation, &rot, &mHullB.transform); } void setupRotatedBoxes () { simd4x4f trans_A; simd4x4f trans_B; simd4x4f_axis_rotation (&trans_A, M_PI / 180.0f * 45.f, simd4f_create(0.f, 0.f, 1.f, 1.f)); simd4x4f rot_B; simd4x4f_axis_rotation (&rot_B, M_PI / 180.0f * 45.f, simd4f_create(0.f, 1.f, 0.f, 1.f)); simd4x4f translation_B; simd4x4f_translation (&translation_B, sqrt(2.f) + 0.001, 0.f, 0.f); simd4x4f_matrix_mul (&translation_B, &rot_B, &trans_B); mHullA.transform = trans_A; mHullB.transform = trans_B; } void init() { sch_create_unitbox(&mHullA.hull); mHullA.createMesh(); sch_create_unitbox(&mHullB.hull); mHullB.createMesh(); // setupSceneEdgeCollision(); setupRotatedBoxes(); mCurrentHull = &mHullA; }; void destroy() { mHullA.destroy(); mHullB.destroy(); } void draw(srcmdbuf* render_commands) { // Populate render commands srcmdbuf_clear(render_commands); srcmd rcmd; srcmd_clear(&rcmd); rcmd.type = SRndrCmdTypeFrame; srcmdbuf_add(render_commands, &rcmd); rcmd.type = SRndrCmdTypeGrid; float origin[3] = {0.f, 0.f, 0.f}; for (int i = -1; i <= 1; i++) { for (int j = -1; j <= 1; j++) { simd4x4f_translation( &rcmd.mat, origin[0] + i * 10.0f, origin[1], origin[2] + j * 10.f); srcmdbuf_add(render_commands, &rcmd); } } ImGuizmo::Manipulate( (float*)&(gCameraState->mtxView), (float*)&(gProjMatrix), ImGuizmo::TRANSLATE, ImGuizmo::WORLD, (float*)(&mCurrentHull->transform), NULL); // Render hulls srcmd cmd; cmd.type = SrndrCmdTypeMesh; cmd.color = simd4f_create(1.f, 1.f, 1.f, 1.f); cmd.mat = mHullA.transform; cmd.meshdata = mHullA.mesh; srcmdbuf_add(render_commands, &cmd); cmd.type = SrndrCmdTypeMesh; cmd.color = simd4f_create(1.f, 1.f, 1.f, 1.f); cmd.mat = mHullB.transform; cmd.meshdata = mHullB.mesh; srcmdbuf_add(render_commands, &cmd); } }; SconvHullScene gHullScene; void ImSRenderWidget(srndr* renderer, srview* view) { ZoneScoped; const ImGuiStyle& imgui_style = ImGui::GetStyle(); // Render Output ImGui::Begin("Render Output", nullptr, ImGuiWindowFlags_NoScrollbar); // Update the gCameraState->mtxView const ImVec2 content_avail = ImGui::GetContentRegionAvail(); srview_set_size(view, int(content_avail.x), int(content_avail.y)); float view_width = content_avail.x / 50.f; float view_height = content_avail.y / 50.f; simd4x4f_ortho( &gProjMatrix, -0.5f * view_width, 0.5f * view_width, -0.5f * view_height, 0.5f * view_height, -50.0f, 50.0f); simd4x4f_perspective( &gProjMatrix, 70.f * (M_PI / 180.f), view_width / view_height, 0.1f, 50.f); srview_set_view(view, gCameraState->mtxView); srview_set_proj(view, gProjMatrix); // Perform the actual render GLuint view_texture; srview_get_output_texture(view, &view_texture); ImGui::Image( (void*)view_texture, content_avail, ImVec2(0.0f, 1.0f), ImVec2(1.0f, 0.0f)); ImGuiIO& io = ImGui::GetIO(); ShowViewManip(); ShowTransformManip( (float*)&(gCameraState->mtxView), (float*)&(gProjMatrix), (float*)(&gTransformMatrix)); ImGui::End(); }; int main() { gTimerInit(); LoggingInit(); if (signal(SIGUSR1, signal_handler) == SIG_ERR) { gLog("Error registering signal handler!"); } // Initialize GLFW glfwSetErrorCallback(error_callback); glfwInit(); const char* glsl_version = "#version 130"; glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_API); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2); glfwWindowHint(GLFW_SAMPLES, 16); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); #if __APPLE__ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); #endif gWindow = glfwCreateWindow(800, 600, "ViSimir", NULL, NULL); assert(gWindow != NULL); glfwMakeContextCurrent(gWindow); glfwSwapInterval(1); // Initialize OpenGL loader gladLoadGL(glfwGetProcAddress); glfwSetKeyCallback(gWindow, key_callback); glfwSetScrollCallback(gWindow, mouse_scroll_callback); std::cout << "OpenGL Version: " << glGetString(GL_VERSION) << endl; std::cout << "GLSL Version : " << glGetString(GL_SHADING_LANGUAGE_VERSION) << endl; glEnable(GL_DEBUG_OUTPUT); // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); glDebugMessageCallback(opengl_error_callback, nullptr); // During init, enable debug output // glEnable ( GL_DEBUG_OUTPUT ); // glDebugMessageCallback( (GLDEBUGPROC) opengl_error_callback, 0 ); // imgui initialization. IMGUI_CHECKVERSION(); ImGui::CreateContext(); ImGuiIO& io = ImGui::GetIO(); (void)io; io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; GuiInputState gui_input_state; gGuiInputState = &gui_input_state; ImGui_ImplGlfw_InitForOpenGL(gWindow, true); ImGui_ImplOpenGL3_Init(glsl_version); // Setup Style ImGui::StyleColorsDark(); //ImGui::StyleColorsClassic(); ImGuiStyle& style = ImGui::GetStyle(); style.WindowRounding = 0.0f; // When viewports are enabled it is preferable to disable WinodwRounding style.Colors[ImGuiCol_WindowBg].w = 1.0f; // When viewports are enabled it is preferable to disable WindowBg alpha double frame_time_last = glfwGetTime(); double frame_time_current = frame_time_last; double frame_delta_time = 0.0; uint64_t frame_counter = 0; bool show_demo_window = true; ImVec4 clear_color = ImVec4(0.45f, 0.55f, 0.60f, 1.00f); CameraState camera_state; CameraState_Init(&camera_state); gCameraState = &camera_state; Dialogs dialogs; gDialogs = &dialogs; gRndr = srndr_create(); gView = srview_create(); gRndrCmds = srcmdbuf_create(1024); // // Scene init // simulator_init(); gHullScene.init(); simd4x4f_translation(&gCameraState->mtxView, 0.1f, 0.1f, -0.5f); simd4f eye = simd4f_create(5.f, 4.f, 5.f, 1.f); simd4x4f_lookat( &gCameraState->mtxView, eye, simd4f_create(0.f, 0.f, 0.f, 1.f), simd4f_create(0.f, 1.f, 0.f, 1.f)); simd4x4f scale_mat = simd4x4f_scale(simd4f_create(1.f, 1.f, 1.f, 1.f)); simd4x4f_mul(&gTransformMatrix, &scale_mat, &gTransformMatrix); CameraState_CalcFromMatrix(gCameraState, &gCameraState->mtxView); while (!glfwWindowShouldClose(gWindow)) { FrameMark; frame_counter++; { ZoneNamedN(input_loop, "InputEvents", true); // Start the imgui frame such that widgets can be submitted handle_mouse(); glfwPollEvents(); } { ZoneNamedN(imgui_render, "ImGuiFrameStart", true); ImGui_ImplOpenGL3_NewFrame(); ImGui_ImplGlfw_NewFrame(); ImGui::NewFrame(); ShowDockspace(true); ImGuizmo::BeginFrame(); ImGuizmo::Enable(gGizmoEnabled); } frame_time_last = frame_time_current; frame_time_current = glfwGetTime(); frame_delta_time = frame_time_current - frame_time_last; gTimer->mFrameTime = (float)(frame_delta_time); if (!gTimer->mPaused) { gTimer->mDeltaTime = gTimer->mFrameTime; gTimer->mCurrentTime = gTimer->mCurrentTime + gTimer->mDeltaTime; } else { gTimer->mDeltaTime = 0.0f; } { ZoneNamedN(main_ui, "UpdateMainUI", true); assert(gTimer->mDeltaTime >= 0.0f); int width, height; ImGui::BeginMainMenuBar(); if (ImGui::BeginMenu("Dialogs")) { ImGui::Checkbox("Camera", &gDialogs->mCameraDialog); ImGui::Checkbox("Simulator", &gDialogs->mSimulator); ImGui::Checkbox("ImGuizmo Transform", &gDialogs->mImGuizmoTransform); ImGui::Checkbox("ImGui Demo", &gDialogs->mImGuiDemo); ImGui::EndMenu(); } float menu_bar_height = ImGui::GetWindowHeight(); ImGui::EndMainMenuBar(); if (glfwGetMouseButton(gWindow, GLFW_MOUSE_BUTTON_RIGHT)) { if (gControlMode == ControlModeNone) { gControlMode = ControlModeFirstPersonView; CameraState_CalcFromMatrix(gCameraState, &gCameraState->mtxView); glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_DISABLED); } } else { gControlMode = ControlModeNone; glfwSetInputMode(gWindow, GLFW_CURSOR, GLFW_CURSOR_NORMAL); } if (gControlMode == ControlModeFirstPersonView) { float camera_accel[3] = {0.f, 0.f, 0.f}; float accel_scale = 100.0; if (glfwGetKey(gWindow, GLFW_KEY_LEFT_SHIFT)) { accel_scale *= 3.; } else if (glfwGetKey(gWindow, GLFW_KEY_LEFT_CONTROL)) { accel_scale /= 3.; } if (glfwGetKey(gWindow, GLFW_KEY_W)) { camera_accel[0] -= accel_scale; } if (glfwGetKey(gWindow, GLFW_KEY_S)) { camera_accel[0] += accel_scale; } if (glfwGetKey(gWindow, GLFW_KEY_C)) { camera_accel[1] -= accel_scale; } if (glfwGetKey(gWindow, GLFW_KEY_SPACE)) { camera_accel[1] += accel_scale; } if (glfwGetKey(gWindow, GLFW_KEY_A)) { camera_accel[2] -= accel_scale; } if (glfwGetKey(gWindow, GLFW_KEY_D)) { camera_accel[2] += accel_scale; } CameraState_Update( gCameraState, frame_delta_time, gGuiInputState->mousedX, gGuiInputState->mousedY, camera_accel); } if (gDialogs->mCameraDialog) { ImGui::Begin("Camera Controls", &gDialogs->mCameraDialog); bool changed = false; changed = ImGui::SliderFloat( "Heading", &gCameraState->heading, -M_PI * 0.98, M_PI * 0.98); changed = ImGui::SliderFloat( "Pitch", &gCameraState->pitch, -M_PI * 0.49, M_PI * 0.49) || changed; changed = ImGui::SliderFloat3("Forward", gCameraState->forward, -1.f, 1.f) || changed; changed = ImGui::SliderFloat3("Right", gCameraState->right, -1.f, 1.f) || changed; changed = ImGui::SliderFloat3("Up", gCameraState->up, -1.f, 1.f) || changed; changed = ImGui::SliderFloat3("Pos", gCameraState->pos, -100.f, 100.f) || changed; if (changed) { CameraState_CalcToMatrix(gCameraState, &gCameraState->mtxView); } if (gDialogs->mImGuiDemo) { ImGui::ShowDemoWindow(&gDialogs->mImGuiDemo); } ImGui::End(); } //gHullScene.draw(gRndrCmds); SimulatorSceneRender(gRndrCmds); srndr_render(gRndr, gView, gRndrCmds); ImSRenderWidget(gRndr, gView); } simulator_update(gTimer->mDeltaTime); { ZoneNamedN(render_submit, "RenderSubmit", true); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); { ZoneNamedN(imgui_render, "ImGuiRender", true); // Rendering ImGui::Render(); int display_w, display_h; glfwMakeContextCurrent(gWindow); glfwGetFramebufferSize(gWindow, &display_w, &display_h); glViewport(0, 0, display_w, display_h); glClearColor( clear_color.x, clear_color.y, clear_color.z, clear_color.w); glClear(GL_COLOR_BUFFER_BIT); ImDrawData* draw_data = ImGui::GetDrawData(); assert(draw_data != NULL); ImGui_ImplOpenGL3_RenderDrawData(draw_data); } // Update and Render additional Platform Windows if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable) { ImGui::UpdatePlatformWindows(); ImGui::RenderPlatformWindowsDefault(); } { ZoneNamedN(gl_swap, "Swap", true); glfwMakeContextCurrent(gWindow); glfwSwapBuffers(gWindow); } { ZoneNamedN(fps_limit, "FPS limit", true); // Send the application to sleep if we have some time left for this frame double frame_target_time = 1.0 / 60.0; if (frame_delta_time < frame_target_time) { usleep((frame_target_time - frame_delta_time) * 1000000 * 0.98); } } } } gLog("Exiting application"); gHullScene.destroy(); srview_destroy(gView); srndr_destroy(gRndr); ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); glfwTerminate(); }