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