703 lines
21 KiB
C++
703 lines
21 KiB
C++
// clang-format off
|
|
// glad must be included before any other OpenGL libraries
|
|
#include <glad/gl.h>
|
|
// clang-format on
|
|
|
|
#include <GLFW/glfw3.h>
|
|
#include <csignal>
|
|
#include <unistd.h>
|
|
|
|
#include <Tracy.hpp>
|
|
#include <cstdio>
|
|
#include <iostream>
|
|
|
|
#include "backends/imgui_impl_glfw.h"
|
|
#include "backends/imgui_impl_opengl3.h"
|
|
#include "imgui.h"
|
|
#include "ImGuizmo.h"
|
|
|
|
#ifndef IMGUI_DEFINE_MATH_OPERATORS
|
|
#define IMGUI_DEFINE_MATH_OPERATORS
|
|
#endif
|
|
#include "imgui_internal.h"
|
|
#include "simulator.h"
|
|
#include "srender.h"
|
|
#include "utils.h"
|
|
#include "render_utils.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;
|
|
|
|
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) {
|
|
gLog(
|
|
"OpenGL Error: %s type %0x%x, severity = 0x%x, message = %s",
|
|
(type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""),
|
|
type,
|
|
severity,
|
|
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 = mouse_x - gGuiInputState->mouseX;
|
|
gGuiInputState->mousedY = mouse_y - gGuiInputState->mouseY;
|
|
} else {
|
|
gGuiInputState->mousedX = 0;
|
|
gGuiInputState->mousedY = 0;
|
|
}
|
|
gGuiInputState->mouseX = mouse_x;
|
|
gGuiInputState->mouseY = mouse_y;
|
|
gGuiInputState->mouseScroll = 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);
|
|
int gizmoCount = 1;
|
|
float camDistance = 8.f;
|
|
|
|
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;
|
|
|
|
int title_height = ImGui::GetFontSize() + imgui_style.FramePadding.y * 2;
|
|
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();
|
|
int title_height = ImGui::GetFontSize() + imgui_style.FramePadding.y * 2;
|
|
|
|
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;
|
|
|
|
ImGui::Begin("Guizmo");
|
|
|
|
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;
|
|
}
|
|
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 DoRender() {
|
|
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(gView, content_avail.x, 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(gView, gCameraState->mtxView);
|
|
srview_set_proj(gView, gProjMatrix);
|
|
|
|
// Populate render commands
|
|
srcmdbuf_clear(gRndrCmds);
|
|
|
|
srcmd rcmd;
|
|
srcmd_clear(&rcmd);
|
|
|
|
rcmd.type = SRndrCmdTypeFrame;
|
|
srcmdbuf_add(gRndrCmds, &rcmd);
|
|
|
|
if (gViewMode == ViewModeSimulation) {
|
|
simulator_draw(gRndrCmds);
|
|
simulator_gui();
|
|
} else {
|
|
RenderGuizmoTest(gRndrCmds);
|
|
}
|
|
|
|
// Perform the actual render
|
|
srndr_render(gRndr, gView, gRndrCmds);
|
|
GLuint view_texture;
|
|
srview_get_output_texture(gView, &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(void) {
|
|
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;
|
|
|
|
gRndr = srndr_create();
|
|
gView = srview_create();
|
|
gRndrCmds = srcmdbuf_create(1024);
|
|
simulator_init();
|
|
|
|
simd4x4f_translation(&gCameraState->mtxView, 0.1f, 0.1f, -0.5f);
|
|
simd4f eye = simd4f_create(0.f, 0.f, 10.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();
|
|
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("ImGui Demo", &show_demo_window);
|
|
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};
|
|
|
|
if (glfwGetKey(gWindow, GLFW_KEY_W)) {
|
|
camera_accel[0] -= 100.f;
|
|
}
|
|
if (glfwGetKey(gWindow, GLFW_KEY_S)) {
|
|
camera_accel[0] += 100.f;
|
|
}
|
|
if (glfwGetKey(gWindow, GLFW_KEY_C)) {
|
|
camera_accel[1] -= 100.f;
|
|
}
|
|
if (glfwGetKey(gWindow, GLFW_KEY_SPACE)) {
|
|
camera_accel[1] += 100.f;
|
|
}
|
|
if (glfwGetKey(gWindow, GLFW_KEY_A)) {
|
|
camera_accel[2] -= 100.f;
|
|
}
|
|
if (glfwGetKey(gWindow, GLFW_KEY_D)) {
|
|
camera_accel[2] += 100.f;
|
|
}
|
|
|
|
CameraState_Update(gCameraState, frame_delta_time, gGuiInputState->mousedX, gGuiInputState->mousedY, camera_accel);
|
|
}
|
|
|
|
ImGui::Begin("Camera Controls");
|
|
|
|
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);
|
|
}
|
|
ImGui::End();
|
|
|
|
if (show_demo_window) ImGui::ShowDemoWindow();
|
|
|
|
ShowDockspace(true);
|
|
|
|
DoRender();
|
|
}
|
|
|
|
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");
|
|
|
|
srview_destroy(gView);
|
|
srndr_destroy(gRndr);
|
|
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
ImGui_ImplGlfw_Shutdown();
|
|
ImGui::DestroyContext();
|
|
glfwTerminate();
|
|
}
|