PeriDyno 1.0.0
Loading...
Searching...
No Matches
GlfwRenderWindow.cpp
Go to the documentation of this file.
1#include "GlfwRenderWindow.h"
2
3#include <cstdlib>
4#include <cstring>
5#include <iostream>
6#include <sstream>
7
8#include "SceneGraph.h"
10#include "Log.h"
11
12#include <RenderEngine.h>
13#include <OrbitCamera.h>
14#include <TrackballCamera.h>
15
16#include <GLRenderEngine.h>
17#include <SceneGraphFactory.h>
18
19#include <glad/glad.h>
20// Include glfw3.h after our OpenGL definitions
21#include <GLFW/glfw3.h>
22
23#include "imgui.h"
24#include "imgui_impl_glfw.h"
25#include "imgui_impl_opengl3.h"
26
27#include "ImGuizmo.h"
28
29#include <ImWidget.h>
30
31#define STB_IMAGE_WRITE_IMPLEMENTATION
32#include <stb/stb_image_write.h>
33
34namespace dyno
35{
36 static void RecieveLogMessage(const Log::Message& m)
37 {
38 switch (m.type)
39 {
40 case Log::Info:
41 std::cout << ">>>: " << m.text << std::endl; break;
42 case Log::Warning:
43 std::cout << "???: " << m.text << std::endl; break;
44 case Log::Error:
45 std::cout << "!!!: " << m.text << std::endl; break;
46 case Log::User:
47 std::cout << ">>>: " << m.text << std::endl; break;
48 default: break;
49 }
50 }
51
52 static void glfw_error_callback(int error, const char* description)
53 {
54 fprintf(stderr, "Glfw Error %d: %s\n", error, description);
55 }
56
57 GlfwRenderWindow::GlfwRenderWindow(int argc /*= 0*/, char **argv /*= NULL*/)
58 : RenderWindow()
59 {
61
62 // create render engine
63 mRenderEngine = std::make_shared<GLRenderEngine>();
64 }
65
67 {
68 // Cleanup
69 ImGui_ImplOpenGL3_Shutdown();
71 ImGui::DestroyContext();
72
73 glfwDestroyWindow(mWindow);
74 glfwTerminate();
75 }
76
77 void GlfwRenderWindow::initialize(int width, int height)
78 {
79 mWindowTitle = std::string("PeriDyno ") + std::to_string(PERIDYNO_VERSION_MAJOR) + std::string(".") + std::to_string(PERIDYNO_VERSION_MINOR) + std::string(".") + std::to_string(PERIDYNO_VERSION_PATCH);
80
81 // Setup window
82 glfwSetErrorCallback(glfw_error_callback);
83 if (!glfwInit())
84 return;
85
86 // Decide GL+GLSL versions
87#if defined(IMGUI_IMPL_OPENGL_ES2)
88 // GL ES 2.0 + GLSL 100
89 const char* glsl_version = "#version 100";
90 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 2);
91 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
92 glfwWindowHint(GLFW_CLIENT_API, GLFW_OPENGL_ES_API);
93#elif defined(__APPLE__)
94 // GL 3.2 + GLSL 150
95 const char* glsl_version = "#version 150";
96 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
97 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
98 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
99 glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // Required on Mac
100#else
101 // GL 3.0 + GLSL 130
102 const char* glsl_version = "#version 130";
103 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
104 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
105 //glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); // 3.2+ only
106 //glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); // 3.0+ only
107#endif
108 // enable multisamples for anti alias
109 glfwWindowHint(GLFW_SAMPLES, 4);
110
111 // Create window with graphics context
112 mWindow = glfwCreateWindow(width, height, mWindowTitle.c_str(), NULL, NULL);
113 if (mWindow == NULL)
114 return;
115
117
118 glfwMakeContextCurrent(mWindow);
119
120 if (!gladLoadGL()) {
121 Log::sendMessage(Log::Error, "Failed to load GLAD!");
122 //SPDLOG_CRITICAL("Failed to load GLAD!");
123 exit(-1);
124 }
125
126 glfwSwapInterval(1); // Enable vsync
127
128 glfwSetWindowUserPointer(mWindow, this);
129
130 // Initialize OpenGL loader
131#if defined(IMGUI_IMPL_OPENGL_LOADER_GL3W)
132 bool err = gl3wInit() != 0;
133#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLEW)
134 bool err = glewInit() != GLEW_OK;
135#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD)
136 bool err = gladLoadGL() == 0;
137#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLAD2)
138 bool err = gladLoadGL(glfwGetProcAddress) == 0; // glad2 recommend using the windowing library loader instead of the (optionally) bundled one.
139#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING2)
140 bool err = false;
141 glbinding::Binding::initialize();
142#elif defined(IMGUI_IMPL_OPENGL_LOADER_GLBINDING3)
143 bool err = false;
144 glbinding::initialize([](const char* name) { return (glbinding::ProcAddress)glfwGetProcAddress(name); });
145#else
146 bool err = false; // If you use IMGUI_IMPL_OPENGL_LOADER_CUSTOM, your loader is likely to requires some form of initialization.
147#endif
148 if (err)
149 {
150 fprintf(stderr, "Failed to initialize OpenGL loader!\n");
151 return;
152 }
153
154 // Setup Dear ImGui context
155 IMGUI_CHECKVERSION();
156 ImGui::CreateContext();
157 ImGuiIO& io = ImGui::GetIO(); (void)io;
158 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
159 //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
160
161 // Setup Dear ImGui style
162 ImGui::StyleColorsDark();
163 //ImGui::StyleColorsClassic();
164 // initializeStyle();
165
166 // Setup Platform/Renderer backends
168 ImGui_ImplOpenGL3_Init(glsl_version);
169
170 // Get Context scale
171 float xscale, yscale;
172 glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
173
174 // initialize rendering engine
175 mRenderEngine->initialize();
176
177 // Jian: initialize ImWindow
178 mImWindow.initialize(xscale);
179
180 this->setWindowSize(width, height);
181 }
182
184 {
185 ImGuiStyle& style = ImGui::GetStyle();
186 style.WindowRounding = 6.0f;
187 style.ChildRounding = 6.0f;
188 style.FrameRounding = 6.0f;
189 style.PopupRounding = 6.0f;
190 }
191
193 {
194 auto activeScene = SceneGraphFactory::instance()->active();
195
196 activeScene->reset();
197
198 // Main loop
199 while (!glfwWindowShouldClose(mWindow))
200 {
201 glfwPollEvents();
202
203 if (mAnimationToggle){
204
205 if (this->isScreenRecordingOn())
206 {
207 saveScreen(activeScene->getFrameNumber());
208 }
209
210 activeScene->takeOneFrame();
211 }
212
213 activeScene->updateGraphicsContext();
214
215 // update rendering params
216 mRenderParams.width = mCamera->viewportWidth();
217 mRenderParams.height = mCamera->viewportHeight();
218
219 // check if window is minimized
220 if (mRenderParams.width == 0 || mRenderParams.height == 0)
221 continue;
222
223 mRenderParams.transforms.model = glm::mat4(1); // TODO: world transform?
224 mRenderParams.transforms.view = mCamera->getViewMat();
225 mRenderParams.transforms.proj = mCamera->getProjMat();
226 mRenderParams.unitScale = mCamera->unitScale();
227
228 mRenderEngine->draw(activeScene.get(), mRenderParams);
229
230 // Start the Dear ImGui frame
231 ImGui_ImplOpenGL3_NewFrame();
233 ImGui::NewFrame();
234
235 if(showImGUI())
236 mImWindow.draw(this);
237
238// // Draw widgets
239// // TODO: maybe move into mImWindow...
240// for (auto widget : mWidgets)
241// {
242// widget->update();
243// widget->paint();
244// }
245
246
247
248// // draw a pick rect
249// if (mButtonType == GLFW_MOUSE_BUTTON_LEFT &&
250// mButtonAction == GLFW_PRESS &&
251// mButtonMode == 0 &&
252// !ImGuizmo::IsUsing() &&
253// !ImGui::GetIO().WantCaptureMouse) {
254// double xpos, ypos;
255// glfwGetCursorPos(mWindow, &xpos, &ypos);
256//
257// ImVec2 pMin = { fminf(xpos, mCursorPosX), fminf(ypos, mCursorPosY) };
258// ImVec2 pMax = { fmaxf(xpos, mCursorPosX), fmaxf(ypos, mCursorPosY) };
259//
260// // visible rectangle
261// if (pMin.x != pMax.x || pMin.y != pMax.y) {
262// // fill
263// ImGui::GetBackgroundDrawList()->AddRectFilled(pMin, pMax, ImColor{ 0.2f, 0.2f, 0.2f, 0.5f });
264// // border
265// ImGui::GetBackgroundDrawList()->AddRect(pMin, pMax, ImColor{ 0.8f, 0.8f, 0.8f, 0.8f }, 0, 0, 1.5f);
266// }
267// }
268
269 ImGui::Render();
270 ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
271
272 glfwSwapBuffers(mWindow);
273 }
274
275 mRenderEngine->terminate();
276 }
277
278 const std::string& GlfwRenderWindow::name() const
279 {
280 return mWindowTitle;
281 }
282
283 void GlfwRenderWindow::setWindowTitle(const std::string& title)
284 {
285 glfwSetWindowTitle(mWindow, title.c_str());
286 }
287
288 void GlfwRenderWindow::setCursorPos(double x, double y)
289 {
290 mCursorPosX = x;
291 mCursorPosY = y;
292 }
293
295 {
296 return mCursorPosX;
297 }
298
300 {
301 return mCursorPosY;
302 }
303
304 void GlfwRenderWindow::onSaveScreen(const std::string &filename)
305 {
306 int width;
307 int height;
308 glfwGetFramebufferSize(mWindow, &width, &height);
309
310 unsigned char *data = new unsigned char[width * height * 3]; //RGB
311 assert(data);
312 glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
313 glPixelStorei(GL_PACK_ALIGNMENT, 1);
314 glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, (void*)data);
315
316 stbi_flip_vertically_on_write(true);
317 int status = stbi_write_bmp(filename.c_str(), width, height, 3, data);
318
319 delete data;
320 }
321
323 {
324 glfwSwapInterval(1);
325 }
326
328 {
329 glfwSwapInterval(0);
330 }
331
336
338 {
339 return getCamera()->viewportWidth();
340 }
341
343 {
344 return getCamera()->viewportHeight();
345 }
346
364
366 {
367
368 }
369
370 void GlfwRenderWindow::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods)
371 {
372 double xpos, ypos;
373 glfwGetCursorPos(window, &xpos, &ypos);
374
375 GlfwRenderWindow* activeWindow = (GlfwRenderWindow*)glfwGetWindowUserPointer(window);
376
377 // Object selection
378 if (activeWindow->getSelectionMode() == RenderWindow::OBJECT_MODE)
379 {
380 // handle picking
381 if (activeWindow->getButtonType() == GLFW_MOUSE_BUTTON_LEFT &&
382 activeWindow->getButtonAction() == GLFW_PRESS &&
383 activeWindow->getButtonMode() == 0 &&
384 action == GLFW_RELEASE) {
385
386 // in picking
387 int x = fmin(xpos, activeWindow->getCursorPosX());
388 int y = fmax(ypos, activeWindow->getCursorPosY());
389 int w = fabs(xpos - activeWindow->getCursorPosX());
390 int h = fabs(ypos - activeWindow->getCursorPosY());
391 // flip y to texture space...
392 y = activeWindow->getHeight() - y - 1;
393
394 const auto& selection = activeWindow->select(x, y, w, h);
395 }
396 }
397
398 auto camera = activeWindow->getCamera();
399
400 activeWindow->setButtonType(button);
401 activeWindow->setButtonAction(action);
402 activeWindow->setButtonMode(mods);
403
404 // Primitive selection
405 if (activeWindow->getSelectionMode() == RenderWindow::PRIMITIVE_MODE)
406 {
407 PMouseEvent mouseEvent;
408 mouseEvent.ray = camera->castRayInWorldSpace((float)xpos, (float)ypos);
409 mouseEvent.buttonType = (PButtonType)button;
410 mouseEvent.actionType = (PActionType)action;
411 mouseEvent.mods = (PModifierBits)activeWindow->getButtonMode();
412 mouseEvent.camera = camera;
413 mouseEvent.x = (float)xpos;
414 mouseEvent.y = (float)ypos;
415
416 auto activeScene = SceneGraphFactory::instance()->active();
417
418 if (activeScene->getWorkMode() == SceneGraph::EDIT_MODE)
419 {
420 activeScene->onMouseEvent(mouseEvent, activeWindow->getCurrentSelectedNode());
421 }
422 else
423 activeScene->onMouseEvent(mouseEvent);
424
425
426 if (action == GLFW_PRESS)
427 {
428 activeWindow->imWindow()->mousePressEvent(mouseEvent);
429 }
430
431 if (action == GLFW_RELEASE)
432 {
433 activeWindow->imWindow()->mouseReleaseEvent(mouseEvent);
434 }
435 }
436
437 if (action == GLFW_PRESS)
438 {
439 // if(mOpenCameraRotate)
440 camera->registerPoint((float)xpos, (float)ypos);
441 activeWindow->setButtonState(GLFW_DOWN);
442 }
443 else
444 glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
445
446 if (action == GLFW_RELEASE)
447 {
448 activeWindow->setButtonState(GLFW_UP);
449 }
450
451 // update cursor position record
452
453 if (action == GLFW_PRESS)
454 {
455 activeWindow->setCursorPos(xpos, ypos);
456 activeWindow->mCursorTempX = xpos;
457 }
458 else
459 {
460 activeWindow->setCursorPos(-1, -1);
461 activeWindow->mCursorTempX = -1;
462 }
463
464 }
465
466 void GlfwRenderWindow::cursorPosCallback(GLFWwindow* window, double x, double y)
467 {
468 GlfwRenderWindow* activeWindow = (GlfwRenderWindow*)glfwGetWindowUserPointer(window); // User Pointer
469 auto camera = activeWindow->getCamera();
470
471 PMouseEvent mouseEvent;
472 mouseEvent.ray = camera->castRayInWorldSpace((float)x, (float)y);
473 mouseEvent.buttonType = (PButtonType)activeWindow->getButtonType();
475 mouseEvent.mods = (PModifierBits)activeWindow->getButtonMode();
476 mouseEvent.camera = camera;
477 mouseEvent.x = (float)x;
478 mouseEvent.y = (float)y;
479
480 auto activeScene = SceneGraphFactory::instance()->active();
481 activeScene->onMouseEvent(mouseEvent);
482
483 if (activeWindow->getButtonType() == GLFW_MOUSE_BUTTON_LEFT &&
484 activeWindow->getButtonState() == GLFW_DOWN &&
485 activeWindow->getButtonMode() == GLFW_MOD_ALT &&
486 !activeWindow->mImWindow.cameraLocked())
487 {
488 camera->rotateToPoint(x, y);
489 }
490 else if (
491 activeWindow->getButtonType() == GLFW_MOUSE_BUTTON_MIDDLE &&
492 activeWindow->getButtonState() == GLFW_DOWN &&
493 activeWindow->getButtonMode() == GLFW_MOD_ALT &&
494 !activeWindow->mImWindow.cameraLocked())
495 {
496 camera->translateToPoint(x, y);
497 }
498 else if (
499 activeWindow->getButtonType() == GLFW_MOUSE_BUTTON_RIGHT &&
500 activeWindow->getButtonState() == GLFW_DOWN &&
501 activeWindow->getButtonMode() == GLFW_MOD_ALT &&
502 !activeWindow->mImWindow.cameraLocked())
503 {
504 if (activeWindow->mCursorTempX != -1)
505 {
506 camera->zoom(-0.005 * (x - activeWindow->mCursorTempX));
507 activeWindow->mCursorTempX = x;
508 }
509 }
510 activeWindow->imWindow()->mouseMoveEvent(mouseEvent);
511 }
512
513 void GlfwRenderWindow::cursorEnterCallback(GLFWwindow* window, int entered)
514 {
515 if (entered)
516 {
517 // The cursor entered the content area of the window
518 }
519 else
520 {
521 // The cursor left the content area of the window
522 }
523 }
524
525 void GlfwRenderWindow::scrollCallback(GLFWwindow* window, double offsetX, double OffsetY)
526 {
527 GlfwRenderWindow* activeWindow = (GlfwRenderWindow*)glfwGetWindowUserPointer(window);
528 auto camera = activeWindow->getCamera();
529
530 if (!activeWindow->mImWindow.cameraLocked())
531 {
532 int state = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL);
533 int altState = glfwGetKey(window, GLFW_KEY_LEFT_ALT);
534 //If the left control key is pressed, slow the zoom speed.
535 if (state == GLFW_PRESS && altState == GLFW_PRESS)
536 camera->zoom(-0.1*OffsetY);
537 else if (altState == GLFW_PRESS)
538 camera->zoom(-OffsetY);
539 }
540 }
541
542 void GlfwRenderWindow::keyboardCallback(GLFWwindow* window, int key, int scancode, int action, int mods)
543 {
544 GlfwRenderWindow* activeWindow = (GlfwRenderWindow*)glfwGetWindowUserPointer(window);
545
546 PKeyboardEvent keyEvent;
547 keyEvent.key = (PKeyboardType)key;
548 keyEvent.action = (PActionType)action;
549 keyEvent.mods = (PModifierBits)mods;
550
551 auto activeScene = SceneGraphFactory::instance()->active();
552 activeScene->onKeyboardEvent(keyEvent);
553
554 if (action != GLFW_PRESS)
555 return;
556
557 switch (key)
558 {
559 case GLFW_KEY_ESCAPE:
560 glfwSetWindowShouldClose(window, GLFW_TRUE);
561 break;
562 case GLFW_KEY_SPACE:
563 activeWindow->toggleAnimation();
564 break;
565 case GLFW_KEY_LEFT:
566 break;
567 case GLFW_KEY_RIGHT:
568 break;
569 case GLFW_KEY_UP:
570 break;
571 case GLFW_KEY_DOWN:
572 break;
573 case GLFW_KEY_PAGE_UP:
574 break;
575 case GLFW_KEY_PAGE_DOWN:
576 break;
577 case GLFW_KEY_N:
578 activeScene->takeOneFrame();
579 activeScene->updateGraphicsContext();
580 break;
581 case GLFW_KEY_F1:
582 activeWindow->toggleImGUI();
583 break;
584 default:
585 break;
586 }
587 }
588
589 void GlfwRenderWindow::reshapeCallback(GLFWwindow* window, int w, int h)
590 {
591 GlfwRenderWindow* app = (GlfwRenderWindow*)glfwGetWindowUserPointer(window);
592 app->setWindowSize(w, h);
593 }
594
595}
assert(queueCount >=1)
void(* mCursorPosFunc)(GLFWwindow *window, double x, double y)
void setCursorPos(double x, double y)
void setWindowTitle(const std::string &title)
void(* mScrollFunc)(GLFWwindow *window, double offsetX, double OffsetY)
void setButtonState(ButtonState state)
void initialize(int width, int height) override
static void scrollCallback(GLFWwindow *window, double offsetX, double OffsetY)
void onSaveScreen(const std::string &filename) override
static void keyboardCallback(GLFWwindow *window, int key, int scancode, int action, int mods)
static void reshapeCallback(GLFWwindow *window, int w, int h)
GlfwRenderWindow(int argc=0, char **argv=NULL)
const std::string & name() const
void setButtonAction(uint action)
void(* mReshapeFunc)(GLFWwindow *window, int w, int h)
ButtonState getButtonState() const
void setButtonType(uint button)
void(* mKeyboardFunc)(GLFWwindow *window, int key, int scancode, int action, int mods)
static void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
static void cursorPosCallback(GLFWwindow *window, double x, double y)
static void cursorEnterCallback(GLFWwindow *window, int entered)
void(* mCursorEnterFunc)(GLFWwindow *window, int entered)
void(* mMouseButtonFunc)(GLFWwindow *window, int button, int action, int mods)
void setButtonMode(uint mode)
void mouseMoveEvent(const PMouseEvent &event)
Definition ImWindow.cpp:441
void mouseReleaseEvent(const PMouseEvent &event)
Definition ImWindow.cpp:452
bool cameraLocked()
Definition ImWindow.cpp:585
void mousePressEvent(const PMouseEvent &event)
Definition ImWindow.cpp:462
@ Warning
Warning information.
Definition Log.h:49
@ Info
Information to user.
Definition Log.h:48
@ User
User specific message.
Definition Log.h:51
@ Error
Error information while executing something.
Definition Log.h:50
static void setUserReceiver(void(*userFunc)(const Message &))
Set user function to receive newly sent messages to logger.
Definition Log.cpp:57
static void sendMessage(MessageType type, const std::string &text)
Add a new message to log.
Definition Log.cpp:41
virtual std::shared_ptr< Camera > getCamera()
void saveScreen(unsigned int frame)
SelectionMode getSelectionMode()
std::shared_ptr< Camera > mCamera
bool & isScreenRecordingOn()
RenderParams mRenderParams
std::shared_ptr< RenderEngine > mRenderEngine
virtual const Selection & select(int x, int y, int w, int h)
virtual std::shared_ptr< Node > getCurrentSelectedNode()
virtual void setWindowSize(int w, int h)
static SceneGraphFactory * instance()
std::shared_ptr< SceneGraph > active()
void ImGui_ImplGlfw_NewFrame()
bool ImGui_ImplGlfw_InitForOpenGL(GLFWwindow *window, bool install_callbacks)
void ImGui_ImplGlfw_Shutdown()
This is an implementation of AdditiveCCD based on peridyno.
Definition Array.h:25
PModifierBits
static void RecieveLogMessage(const Log::Message &m)
PActionType
Definition InputModule.h:33
@ AT_REPEAT
Definition InputModule.h:37
static void glfw_error_callback(int error, const char *description)
PKeyboardType
Definition InputModule.h:41
PButtonType
Definition InputModule.h:25
std::string text
Definition Log.h:56
MessageType type
Definition Log.h:55
PKeyboardType key
PModifierBits mods
TRay3D< float > ray
PButtonType buttonType
std::shared_ptr< Camera > camera
PModifierBits mods
PActionType actionType