You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
324 lines
13 KiB
C++
324 lines
13 KiB
C++
//------------------------------------------------------------------------------
|
|
// Copyright (c) 2018-2025 Michele Morrone
|
|
// All rights reserved.
|
|
//
|
|
// https://michelemorrone.eu - https://brutpitt.com
|
|
//
|
|
// X: https://x.com/BrutPitt - GitHub: https://github.com/BrutPitt
|
|
//
|
|
// direct mail: brutpitt(at)gmail.com - me(at)michelemorrone.eu
|
|
//
|
|
// This software is distributed under the terms of the BSD 2-Clause license
|
|
//------------------------------------------------------------------------------
|
|
#include <cstdlib>
|
|
#include <iostream>
|
|
#include <glad/glad.h>
|
|
#include <imgui/imgui.h>
|
|
#include <imgui/imgui_internal.h>
|
|
#include <imgui/imgui_impl_glfw.h>
|
|
#include <imgui/imgui_impl_opengl3.h>
|
|
#include <GLFW/glfw3.h>
|
|
|
|
#include "oglDebug.h"
|
|
#include "../commons/shadersAndModel.h"
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// imGuIZMO: include imGuIZMOquat.h or imguizmo_quat.h
|
|
#include <imguizmo_quat.h> // now also imguizmo_quat.h from v3.1
|
|
|
|
int width = 1280, height = 800;
|
|
GLFWwindow *glfwWindow;
|
|
|
|
const int nElemVtx = 4;
|
|
const int nVertex = sizeof(coloredCubeData)/(sizeof(float)*2*nElemVtx);
|
|
|
|
// Shaders & Vertex attributes
|
|
GLuint program, vao, vaoBuffer;
|
|
enum loc { vtxIdx = 0, colIdx, mvpIdx, lightIdx}; // shader locations
|
|
|
|
mat4 mvpMatrix, viewMatrix, projMatrix;
|
|
mat4 lightMatrix, cubeObj;
|
|
|
|
/// imGuIZMO / vGizmo3D : declare global/static/member/..
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
vg::vGizmo3D track; // using vGizmo3D global/static/member instead of specifics variables...
|
|
// have rotations & Pan/Dolly position variables inside to use with imGuIZMO.quat
|
|
// And it's necessary if you want use also direct-screen manipulator
|
|
|
|
mat4 compensateView; // compensate rotation of viewMatrix lookAt Matrix
|
|
|
|
// light model
|
|
vec3 lightPos(2, 2.5, 3); // Light Position
|
|
|
|
void draw()
|
|
{
|
|
glUseProgram(program);
|
|
|
|
glProgramUniformMatrix4fv(program, loc::mvpIdx, 1, false, value_ptr(mvpMatrix) ); // vgMath permits cast to mat4*
|
|
glProgramUniformMatrix4fv(program, loc::lightIdx, 1, false, value_ptr(lightMatrix)); // using value_ptr maintains GLM compatibility
|
|
|
|
glBindVertexArray(vao);
|
|
//glDrawArrays(GL_TRIANGLES, 0, nVertex);
|
|
glDrawArraysInstanced(GL_TRIANGLES, 0, nVertex, 2); // now using instanced draw to "simulate" light
|
|
|
|
glUseProgram(0);
|
|
}
|
|
|
|
void setPerspective()
|
|
{
|
|
float aspectRatio = float(height) / float(width); // Set "camera" position and perspective
|
|
float fov = radians( 45.0f ) * aspectRatio;
|
|
projMatrix = perspective( fov, 1/aspectRatio, 0.1f, 100.0f );
|
|
}
|
|
|
|
void setScene()
|
|
{
|
|
viewMatrix = lookAt( vec3( 10.0f, 10.0f, 10.0f ), // From / EyePos
|
|
vec3( 0.0f, 0.0f, 0.0f ), // To /
|
|
vec3( 3.0f, 1.0f, .0f)); // Up
|
|
|
|
// Now scale cube to better view light position
|
|
cubeObj = mat4(1); // nothing to do ... scale( vec3(.5));
|
|
|
|
/// imGuIZMO / vGizmo3D
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
//track.setRotation(quat(1,0,0,0)); // vGizmo3D with NO initial rotation (default initialization)
|
|
//track.setRotation(eulerAngleXYZ(vec3(radians(45),
|
|
// radians( 0),
|
|
// radians( 0)))); // vGizmo3D with rotation of 45 degrees on X axis
|
|
track.setRotation(viewMatrix); // vGizmo3D with ViewMatrix (lookAt) rotation
|
|
|
|
// for Pan & Dolly always bounded on screen coords (x = left/right, y = up/douw, z = in/out) we remove viewMatrix rotation
|
|
// otherwise Pan & Dolly have as reference the Cartesian axes
|
|
compensateView = inverse(mat4_cast(quat(viewMatrix)));
|
|
|
|
|
|
// acquiring rotation for the light pos
|
|
const float len = length(lightPos);
|
|
//if(len<1.0 && len>= FLT_EPSILON) { normalize(lightPos); len = 1.0; } // controls are not necessary: lightPos is known
|
|
//else if(len > FLT_EPSILON)
|
|
quat q = angleAxis(acosf(-lightPos.x/len), normalize(vec3(FLT_EPSILON, lightPos.z, -lightPos.y)));
|
|
track.setSecondRot(q); // store secondary rotation for the Light
|
|
|
|
setPerspective();
|
|
}
|
|
|
|
void glfwWindowSizeCallback(GLFWwindow* window, int w, int h)
|
|
{
|
|
width = w; height = h;
|
|
setPerspective();
|
|
glViewport(0, 0, width, height);
|
|
|
|
track.viewportSize(w, h); // call it on resize window to re-adjust mouse sensitivity
|
|
|
|
draw();
|
|
}
|
|
|
|
void initGL()
|
|
{
|
|
enableDebugCallback();
|
|
|
|
GLuint vertex = glCreateShader(GL_VERTEX_SHADER);
|
|
glShaderSource(vertex, 1, &vertex_instanced, NULL);
|
|
glCompileShader(vertex);
|
|
glCompileShader(vertex);
|
|
|
|
GLuint fragment = glCreateShader(GL_FRAGMENT_SHADER);
|
|
glShaderSource(fragment, 1, &fragment_code, NULL);
|
|
glCompileShader(fragment);
|
|
checkShader(fragment);
|
|
|
|
program = glCreateProgram();
|
|
glAttachShader(program, vertex);
|
|
glAttachShader(program, fragment);
|
|
glLinkProgram(program);
|
|
checkProgram(program);
|
|
|
|
glDeleteShader(vertex);
|
|
glDeleteShader(fragment);
|
|
|
|
glCreateVertexArrays(1, &vao);
|
|
glCreateBuffers(1, &vaoBuffer);
|
|
glNamedBufferStorage(vaoBuffer, sizeof(coloredCubeData), coloredCubeData, 0);
|
|
|
|
glVertexArrayAttribBinding(vao,loc::vtxIdx, 0);
|
|
glVertexArrayAttribFormat(vao, loc::vtxIdx, nElemVtx, GL_FLOAT, GL_FALSE, 0);
|
|
glEnableVertexArrayAttrib(vao, loc::vtxIdx);
|
|
|
|
glVertexArrayAttribBinding(vao,loc::colIdx, 0);
|
|
glVertexArrayAttribFormat(vao, loc::colIdx, nElemVtx, GL_FLOAT, GL_FALSE, nElemVtx*sizeof(float));
|
|
glEnableVertexArrayAttrib(vao, loc::colIdx);
|
|
|
|
glVertexArrayVertexBuffer(vao, 0, vaoBuffer, 0, 2*nElemVtx*sizeof(float));
|
|
|
|
glViewport(0, 0, width, height);
|
|
|
|
glDisable(GL_BLEND);
|
|
glDepthMask(GL_TRUE);
|
|
glEnable(GL_CULL_FACE);
|
|
glEnable(GL_DEPTH_TEST);
|
|
glDepthFunc(GL_LESS);
|
|
glFrontFace(GL_CW);
|
|
|
|
glDepthRange(-1.0, 1.0);
|
|
setScene();
|
|
}
|
|
void initFramework()
|
|
{
|
|
glfwInit();
|
|
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
|
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
|
|
|
|
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
|
|
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
|
glfwWindowHint(GLFW_DOUBLEBUFFER, GL_TRUE);
|
|
|
|
glfwWindow = glfwCreateWindow(width, height, "glCube", NULL, NULL);
|
|
if (!glfwWindow)
|
|
{
|
|
glfwTerminate();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
glfwMakeContextCurrent(glfwWindow);
|
|
gladLoadGLLoader((GLADloadproc) glfwGetProcAddress); //get OpenGL extensions
|
|
|
|
glfwSetWindowSizeCallback(glfwWindow, glfwWindowSizeCallback);
|
|
|
|
glfwSwapInterval(1); // 0 vSync off - 1 vSync on
|
|
}
|
|
|
|
void initImGui()
|
|
{
|
|
// Setup Dear ImGui context
|
|
IMGUI_CHECKVERSION();
|
|
ImGui::CreateContext();
|
|
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
|
io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
|
|
|
// Setup Dear ImGui style
|
|
ImGui::StyleColorsDark();
|
|
|
|
// Setup Platform/Renderer backends
|
|
ImGui_ImplGlfw_InitForOpenGL(glfwWindow, true);
|
|
ImGui_ImplOpenGL3_Init("#version 450");
|
|
}
|
|
|
|
|
|
int main(int /* argc */, char ** /* argv */) // necessary for SDLmain in Windows
|
|
{
|
|
initFramework(); // initialize GLFW framework
|
|
initGL(); // init OpenGL building vaoBuffer and shader program (compile and link vtx/frag shaders)
|
|
|
|
// other OpenGL settings... used locally
|
|
vec4 bgColor = vec4(0.0f);
|
|
GLfloat f=1.0f;
|
|
|
|
// Setup/Initialize Dear ImGui context
|
|
initImGui();
|
|
ImGuiStyle& style = ImGui::GetStyle();
|
|
|
|
// imGuIZMO: set mouse feeling and key mods
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
imguiGizmo::setGizmoFeelingRot(1.5f); // default 1.0, >1 more mouse sensitivity, <1 less mouse sensitivity
|
|
imguiGizmo::setPanScale(.5f); // default 1.0, >1 more, <1 less
|
|
imguiGizmo::setDollyScale(.5f); // default 1.0, >1 more, <1 less
|
|
imguiGizmo::setDollyWheelScale(.5f); // default 1.0, > more, < less ... (from v3.1 separate values)
|
|
imguiGizmo::setPanModifier(vg::evSuperModifier); // change KEY modifier: CTRL (default) ==> SUPER
|
|
imguiGizmo::setDollyModifier(vg::evControlModifier); // change KEY modifier: SHIFT (default) ==> CTRL
|
|
|
|
// main render/draw loop
|
|
while (!glfwWindowShouldClose(glfwWindow)) {
|
|
glfwPollEvents();
|
|
glClearBufferfv(GL_DEPTH, 0, &f);
|
|
glClearBufferfv(GL_COLOR, 0, value_ptr(bgColor));
|
|
|
|
if (glfwGetWindowAttrib(glfwWindow, GLFW_ICONIFIED) != 0) {
|
|
ImGui_ImplGlfw_Sleep(10);
|
|
continue;
|
|
}
|
|
|
|
// ImGUI: prepare new frame
|
|
ImGui_ImplOpenGL3_NewFrame();
|
|
ImGui_ImplGlfw_NewFrame();
|
|
ImGui::NewFrame();
|
|
|
|
// ImGui: Your windows here
|
|
|
|
// Imgui window: build a transparent window (container) to insert widget
|
|
float widgetSize=240;
|
|
ImGui::SetNextWindowSize(ImVec2(widgetSize, height), ImGuiCond_Always); // top ...
|
|
ImGui::SetNextWindowPos(ImVec2(width-widgetSize, 0), ImGuiCond_Always); // ... right aligned
|
|
|
|
ImGui::PushStyleColor(ImGuiCol_WindowBg,ImVec4(0.f,0.f,0.f,0.f)); // transparent Wnd Background
|
|
ImGui::PushStyleColor(ImGuiCol_FrameBg,ImVec4(0.f,0.f,0.f,0.f)); // transparent frame Background
|
|
const float prevWindowBorderSize = style.WindowBorderSize; // Save current border size...
|
|
style.WindowBorderSize = .0f; // ... to draw the window with ZERO broder
|
|
|
|
bool isVisible = true; // visibility flag: always on
|
|
ImGui::Begin("##giz", &isVisible, ImGuiWindowFlags_NoTitleBar| // noTitle / noResize / Noscrollbar
|
|
ImGuiWindowFlags_NoResize|
|
|
ImGuiWindowFlags_NoScrollbar);
|
|
|
|
|
|
// colored text for display quat(w,x,y,z) components
|
|
ImGui::SetCursorPos(ImVec2(0,0));
|
|
ImGui::PushItemWidth(widgetSize*.25-2);
|
|
ImGui::TextColored(ImVec4(1,1,1,1), "w: % 1.2f", track.getRotation().w); ImGui::SameLine();
|
|
ImGui::TextColored(ImVec4(1,0,0,1), "x: % 1.2f", track.getRotation().x); ImGui::SameLine();
|
|
ImGui::TextColored(ImVec4(0,1,0,1), "y: % 1.2f", track.getRotation().y); ImGui::SameLine();
|
|
ImGui::TextColored(ImVec4(0,0,1,1), "z: % 1.2f", track.getRotation().z);
|
|
ImGui::PopItemWidth();
|
|
|
|
// ImGuIZMO.quat widget
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
ImGui::gizmo3D("##aaa", track.refRotation(), lightPos, widgetSize); // if(ImGui::gizmo3D(...) == true) ---> widget has been updated
|
|
|
|
// ImGuIZMO.quat with also pan and Dolly/zoom
|
|
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
ImGui::gizmo3D("##a01", track.refPosition(), track.refRotation(), widgetSize); // Ctrl+LButton = Pan ... Shift+LButton = Dolly/Zoom
|
|
|
|
// End Imgui window (container) block
|
|
ImGui::End();
|
|
style.WindowBorderSize = prevWindowBorderSize; // restore border size
|
|
ImGui::PopStyleColor(); // frame color (pushed)
|
|
ImGui::PopStyleColor(); // Background (pushed)
|
|
|
|
// transferring the rotation to cube model matrix...
|
|
mat4 modelMatrix = cubeObj * mat4_cast(track.getRotation());
|
|
|
|
// Build a "translation" matrix
|
|
mat4 translationMatrix = translate(mat4(1), track.getPosition()); // add translations (pan/dolly) to an identity matrix
|
|
|
|
// build MVPs matrices to pass to shader
|
|
mvpMatrix = projMatrix * viewMatrix * compensateView * translationMatrix * modelMatrix;
|
|
lightMatrix = projMatrix * viewMatrix * compensateView * translationMatrix * translate(mat4(1), lightPos) * scale(mat4(1), vec3(.1));
|
|
|
|
// draw the cube, passing matrices to the vtx shader
|
|
draw();
|
|
|
|
// ImGui Rendering
|
|
ImGui::Render();
|
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
|
|
|
glfwSwapBuffers(glfwWindow);
|
|
}
|
|
|
|
// Cleanup ImGui
|
|
ImGui_ImplOpenGL3_Shutdown();
|
|
ImGui_ImplGlfw_Shutdown();
|
|
ImGui::DestroyContext();
|
|
|
|
// Cleanup OpenGL
|
|
glDeleteVertexArrays(1, &vao);
|
|
glDeleteBuffers(1, &vaoBuffer);
|
|
glDeleteProgram(program);
|
|
|
|
// Cleanup Framework
|
|
glfwDestroyWindow(glfwWindow);
|
|
glfwTerminate();
|
|
|
|
return EXIT_SUCCESS;
|
|
} |