PeriDyno 1.2.1
Loading...
Searching...
No Matches
WSimulationCanvas.cpp
Go to the documentation of this file.
1#include "WSimulationCanvas.h"
2
3#include "ImageEncoder.h"
4#include "imgui_impl_wt.h"
5
6#include <GLFW/glfw3.h>
7#include <GLRenderEngine.h>
8#include <ImGuizmo.h>
9
10#include "SceneGraph.h"
11
12#include <Wt/WApplication.h>
13#include <Wt/WImage.h>
14#include <Wt/WMemoryResource.h>
15
16
17using namespace dyno;
18
19std::map<Wt::Key, PKeyboardType> WKeyMap =
20{
21 {Wt::Key::Unknown, PKEY_UNKNOWN},
22 {Wt::Key::Space, PKEY_SPACE},
23 {Wt::Key::Key_0, PKEY_0},
24 {Wt::Key::Key_1, PKEY_1},
25 {Wt::Key::Key_2, PKEY_2},
26 {Wt::Key::Key_3, PKEY_3},
27 {Wt::Key::Key_4, PKEY_4},
28 {Wt::Key::Key_5, PKEY_5},
29 {Wt::Key::Key_6, PKEY_6},
30 {Wt::Key::Key_7, PKEY_7},
31 {Wt::Key::Key_8, PKEY_8},
32 {Wt::Key::Key_9, PKEY_9},
33 {Wt::Key::A, PKEY_A},
34 {Wt::Key::B, PKEY_B},
35 {Wt::Key::C, PKEY_C},
36 {Wt::Key::D, PKEY_D},
37 {Wt::Key::E, PKEY_E},
38 {Wt::Key::F, PKEY_F},
39 {Wt::Key::G, PKEY_G},
40 {Wt::Key::H, PKEY_H},
41 {Wt::Key::I, PKEY_I},
42 {Wt::Key::J, PKEY_J},
43 {Wt::Key::K, PKEY_K},
44 {Wt::Key::L, PKEY_L},
45 {Wt::Key::M, PKEY_M},
46 {Wt::Key::N, PKEY_N},
47 {Wt::Key::O, PKEY_O},
48 {Wt::Key::P, PKEY_P},
49 {Wt::Key::Q, PKEY_Q},
50 {Wt::Key::R, PKEY_R},
51 {Wt::Key::S, PKEY_S},
52 {Wt::Key::T, PKEY_T},
53 {Wt::Key::U, PKEY_U},
54 {Wt::Key::V, PKEY_V},
55 {Wt::Key::W, PKEY_W},
56 {Wt::Key::X, PKEY_X},
57 {Wt::Key::Y, PKEY_Y},
58 {Wt::Key::Z, PKEY_Z},
59 {Wt::Key::Escape, PKEY_ESCAPE},
60 {Wt::Key::Enter, PKEY_ENTER},
61 {Wt::Key::Tab, PKEY_TAB},
62 {Wt::Key::Backspace, PKEY_BACKSPACE},
63 {Wt::Key::Insert, PKEY_INSERT},
64 {Wt::Key::Delete, PKEY_DELETE},
65 {Wt::Key::Right, PKEY_RIGHT},
66 {Wt::Key::Left, PKEY_LEFT},
67 {Wt::Key::Down, PKEY_DOWN},
68 {Wt::Key::Up, PKEY_UP},
69 {Wt::Key::PageUp, PKEY_PAGE_UP},
70 {Wt::Key::PageDown, PKEY_PAGE_DOWN},
71 {Wt::Key::Home, PKEY_HOME},
72 {Wt::Key::End, PKEY_END},
73 {Wt::Key::F1, PKEY_F1},
74 {Wt::Key::F2, PKEY_F2},
75 {Wt::Key::F3, PKEY_F3},
76 {Wt::Key::F4, PKEY_F4},
77 {Wt::Key::F5, PKEY_F5},
78 {Wt::Key::F6, PKEY_F6},
79 {Wt::Key::F7, PKEY_F7},
80 {Wt::Key::F8, PKEY_F8},
81 {Wt::Key::F9, PKEY_F9},
82 {Wt::Key::F10, PKEY_F10},
83 {Wt::Key::F11, PKEY_F11},
84 {Wt::Key::F12, PKEY_F12}
85};
86
87PModifierBits mappingWtModifierBits(Wt::KeyboardModifier mods)
88{
89 if (mods == Wt::KeyboardModifier::Control)
90 {
92 }
93 else if (mods == Wt::KeyboardModifier::Shift)
94 {
96 }
97 else if (mods == Wt::KeyboardModifier::Alt)
98 {
100 }
101 else
103}
104
106{
107 this->setLayoutSizeAware(true);
108 this->setStyleClass("remote-framebuffer");
109 this->resize("100%", "90%");
110
111 this->mouseWentUp().preventDefaultAction(true);
112 this->mouseWentDown().preventDefaultAction(true);
113 this->mouseDragged().preventDefaultAction(true);
114 this->touchStarted().preventDefaultAction(true);
115 this->touchMoved().preventDefaultAction(true);
116 this->touchEnded().preventDefaultAction(true);
117
118 this->mouseWentDown().connect(this, &WSimulationCanvas::onMousePressed);
119 this->mouseWheel().connect(this, &WSimulationCanvas::onMouseWheeled);
120 this->mouseDragged().connect(this, &WSimulationCanvas::onMouseDrag);
121 this->mouseWentUp().connect(this, &WSimulationCanvas::onMouseReleased);
122
123 //this->keyWentDown().connect(this, &WSimulationCanvas::onKeyWentDown);
124 //this->keyWentUp().connect(this, &WSimulationCanvas::onKeyWentUp);
125
126 this->setAttributeValue("oncontextmenu", "return false;");
127
128 mApp = Wt::WApplication::instance();
129
130 mImage = this->addNew<Wt::WImage>();
131 mImage->resize("100%", "100%");
132
133 mImage->setJavaScriptMember("currURL", "null");
134 mImage->setJavaScriptMember("nextURL", "null");
135 mImage->setJavaScriptMember("onload",
136 "function() {"
137 "this.currURL = this.nextURL;"
138 "this.nextURL = null;"
139 "if (this.currURL != null) {"
140 "this.src = this.currURL;"
141 "}"
142 "}.bind(" + mImage->jsRef() + ")");
143 mImage->setJavaScriptMember("onerror",
144 "function() {"
145 "this.currURL = this.nextURL;"
146 "this.nextURL = null;"
147 "if (this.currURL != null) {"
148 "this.src = this.currURL;"
149 "}"
150 "}.bind(" + mImage->jsRef() + ")");
151 mImage->setJavaScriptMember("update",
152 "function(url) { "
153 "if (this.currURL == null) {"
154 "this.currURL = url;"
155 "this.src = this.currURL;"
156 "} else {" // still loading
157 "this.nextURL = url;"
158 "}"
159 "}.bind(" + mImage->jsRef() + ")");
160
161 mImageData.resize(width * height * 3); // initialize image buffer
162 mJpegEncoder = std::make_unique<ImageEncoderNV>();
163 mJpegEncoder->SetQuality(100);
164 mJpegResource = std::make_unique<Wt::WMemoryResource>("image/jpeg");
165
166 mRenderEngine = std::make_shared<dyno::GLRenderEngine>();
167
168 this->setWindowSize(width, height);
169
170 // initialize OpenGL context and RenderEngine
171 this->initializeGL();
172
173 //this->toggleImGUI();
174}
175
177{
178 makeCurrent();
179
180 delete mImGuiCtx;
181
182 mRenderEngine->terminate();
183
184 mFramebuffer.release();
185 mFrameColor.release();
186
187 mImageData.resize(0);
188 mJpegBuffer.resize(0);
189
190 glfwDestroyWindow(mContext);
191 //glfwTerminate();
192 Wt::log("warning") << "WSimulationCanvas destory";
193}
194
196{
197 // initialize render engine and target
198 glfwInit();
199 // Set all the required options for GLFW
200 glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
201 glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
202 glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
203 glfwWindowHint(GLFW_VISIBLE, GLFW_FALSE);
204
205 mContext = glfwCreateWindow(width, height, "", NULL, NULL);
206 if (!mContext)
207 {
208 Wt::log("error") << "Failed to create OpenGL context!";
209 exit(-1);
210 }
211
212 makeCurrent();
213
214 mRenderEngine->initialize();
215
216 if (showImGUI())
217 {
218 mImGuiCtx = new ImGuiBackendWt(this);
219 // Setup Dear ImGui context
220 ImGui::StyleColorsDark();
221
222 // Get Context scale
223 float xscale, yscale;
224 glfwGetMonitorContentScale(glfwGetPrimaryMonitor(), &xscale, &yscale);
225
226 // Initialize ImWindow
227 mImWindow.initialize(xscale);
228 mImWindow.setEnableViewManipulate(false);
229 }
230
231 // create framebuffer here...
232 mFrameColor.format = GL_RGB;
233 mFrameColor.internalFormat = GL_RGB;
234 mFrameColor.type = GL_BYTE;
235 mFrameColor.create();
236 mFrameColor.resize(width, height);
237
238 mFramebuffer.create();
239 mFramebuffer.bind();
240 const unsigned int GL_COLOR_ATTACHMENT0 = 0x8CE0;
241 mFramebuffer.setTexture(GL_COLOR_ATTACHMENT0, &mFrameColor); //
242 unsigned int buffers[]{ GL_COLOR_ATTACHMENT0 };
243 mFramebuffer.drawBuffers(1, buffers);
244 mFramebuffer.unbind();
245
246 doneCurrent();
247}
248
250{
251 if (glfwGetCurrentContext() != mContext)
252 glfwMakeContextCurrent(mContext);
253}
254
256{
257 glfwMakeContextCurrent(NULL);
258}
259
261{
262 mCamera->setWidth(width);
263 mCamera->setHeight(height);
264 mImageData.resize(width * height * 3);
265
266 this->makeCurrent();
267 // resize framebuffer
268 mFrameColor.resize(width, height);
269 this->doneCurrent();
270
271 WContainerWidget::layoutSizeChanged(width, height);
272 scheduleRender();
273}
274
275void WSimulationCanvas::onMousePressed(const Wt::WMouseEvent& evt)
276{
277 if (!mImGuiCtx->handleMousePressed(evt))
278 {
279 mMouseButtonDown = true;
280
281 if (evt.button() == Wt::MouseButton::Right)
282 {
283 mtempCursorX = evt.widget().x;
284 }
285
286 Wt::Coordinates coord = evt.widget();
287 mCamera->registerPoint(coord.x, coord.y);
288 }
289
290 mCursorX = evt.widget().x;
291 mCursorY = evt.widget().y;
292
293 auto camera = this->getCamera();
294 camera->registerPoint(evt.widget().x, evt.widget().y);
295
296 scheduleRender();
297}
298
299void WSimulationCanvas::onMouseDrag(const Wt::WMouseEvent& evt)
300{
301 if (!mImGuiCtx->handleMouseDrag(evt))
302 {
303 auto mods = evt.modifiers();
304
305 if (mods.test(Wt::KeyboardModifier::Alt) && mMouseButtonDown == true)
306 {
307 Wt::Coordinates coord = evt.widget();
308 if (evt.button() == Wt::MouseButton::Left) {
309 mCamera->rotateToPoint(coord.x, coord.y);
310 }
311 else if (evt.button() == Wt::MouseButton::Middle) {
312 mCamera->translateToPoint(coord.x, coord.y);
313 }
314 else if (evt.button() == Wt::MouseButton::Right) {
315 auto cam = this->getCamera();
316 cam->zoom(-0.005 * float(evt.widget().x - mtempCursorX));
317 mtempCursorX = evt.widget().x;
318 }
319 }
320 }
321 scheduleRender();
322}
323
324void WSimulationCanvas::onMouseReleased(const Wt::WMouseEvent& evt)
325{
326 if (!mImGuiCtx->handleMouseReleased(evt))
327 {
328 mMouseButtonDown = false;
329 }
330
332 {
333 if (evt.button() == Wt::MouseButton::Left)
334 //&& !ImGuizmo::IsUsing()
335 //&& !ImGui::GetIO().WantCaptureMouse)
336 {
337 int width = mCamera->viewportWidth();
338 int height = mCamera->viewportHeight();
339 int x = evt.widget().x;
340 int y = std::abs(height - evt.widget().y);
341
342 int w = std::abs(mCursorX - x);
343 int h = std::abs(mCursorY - y);
344
345 makeCurrent();
346 const auto& selection = this->select(x, y, w, h);
347 doneCurrent();
348
350 ;
351 }
352 }
353
354 scheduleRender();
355}
356
357void WSimulationCanvas::onMouseWheeled(const Wt::WMouseEvent& evt)
358{
359 mCamera->zoom(-1.0 * evt.wheelDelta());
360 scheduleRender();
361}
362
363void WSimulationCanvas::onKeyWentDown(const Wt::WKeyEvent& evt)
364{
365 PKeyboardEvent keyEvent;
366 keyEvent.key = WKeyMap.find(evt.key()) == WKeyMap.end() ? PKEY_UNKNOWN : WKeyMap[evt.key()];
367 keyEvent.action = AT_PRESS;
368 keyEvent.mods = mappingWtModifierBits(evt.modifiers());
369
370 mScene->onKeyboardEvent(keyEvent);
371
372 switch (evt.key())
373 {
374 case Wt::Key::H:
375 this->toggleImGUI();
376 break;
377 default:
378 break;
379 }
380
381 scheduleRender();
382}
383
384void WSimulationCanvas::onKeyWentUp(const Wt::WKeyEvent& evt)
385{
386}
387
388void WSimulationCanvas::selectNode(std::shared_ptr<dyno::Node> node)
389{
390 makeCurrent();
391 this->select(node);
392 doneCurrent();
393}
394
395void WSimulationCanvas::render(Wt::WFlags<Wt::RenderFlag> flags)
396{
397 update();
398}
399
401{
402 // do render
403 {
404 this->makeCurrent();
405
406 if (mScene)
407 {
408 mScene->updateGraphicsContext();
409 }
410
411 // update rendering params
412 mRenderParams.width = mCamera->viewportWidth();
413 mRenderParams.height = mCamera->viewportHeight();
414 mRenderParams.transforms.model = glm::mat4(1); // TODO: world transform?
415 mRenderParams.transforms.view = mCamera->getViewMat();
416 mRenderParams.transforms.proj = mCamera->getProjMat();
417 mRenderParams.unitScale = mCamera->unitScale();
418
419 mFramebuffer.bind();
420 // heck: ImGUI widgets need to render twice...
421 if (showImGUI())
422 {
423 // Start the Dear ImGui frame
424 mImGuiCtx->NewFrame(mCamera->viewportWidth(), mCamera->viewportHeight());
425 mImWindow.draw(this);
426 mImGuiCtx->Render();
427 }
428
429 mRenderEngine->draw(mScene.get(), mRenderParams);
430
431 if (showImGUI())
432 {
433 // Start the Dear ImGui frame
434 mImGuiCtx->NewFrame(mCamera->viewportWidth(), mCamera->viewportHeight());
435 mImWindow.draw(this);
436 mImGuiCtx->Render();
437 }
438
439 // dump framebuffer
440 mFrameColor.dump(mImageData.data());
441 mFramebuffer.unbind();
442
443 this->doneCurrent();
444 }
445
446 // encode image
447 {
448 mJpegBuffer.clear();
449
450 mJpegEncoder->Encode(mImageData.data(),
451 mCamera->viewportWidth(), mCamera->viewportHeight(), 0,
453
454 Wt::log("info") << mCamera->viewportWidth() << " x " << mCamera->viewportHeight()
455 << ", JPG size: " << mJpegBuffer.size() / 1024 << " kb";
456 }
457
458 // update UI
459 {
460 mJpegResource->setData(std::move(mJpegBuffer));
461 const std::string url = mJpegResource->generateUrl();
462 mImage->callJavaScriptMember("update", WWebWidget::jsStringLiteral(url));
463 }
464}
465
466void WSimulationCanvas::setScene(std::shared_ptr<dyno::SceneGraph> scene)
467{
468 this->mScene = scene;
469
470 // TODO: move to somewhere else!
471 if (this->mScene)
472 {
473 makeCurrent();
474 this->mScene->reset();
475 doneCurrent();
476
477 scheduleRender();
478 }
479}
PModifierBits mappingWtModifierBits(Wt::KeyboardModifier mods)
std::map< Wt::Key, PKeyboardType > WKeyMap
void selectNode(std::shared_ptr< dyno::Node > node)
std::unique_ptr< Wt::WMemoryResource > mJpegResource
void render(Wt::WFlags< Wt::RenderFlag > flags) override
dyno::ImWindow mImWindow
Wt::Signal< std::shared_ptr< dyno::Node > > _selectNodeSignal
std::vector< unsigned char > mImageData
ImGuiBackendWt * mImGuiCtx
void onMouseDrag(const Wt::WMouseEvent &evt)
void onMouseWheeled(const Wt::WMouseEvent &evt)
std::shared_ptr< dyno::SceneGraph > mScene
Wt::WApplication * mApp
void layoutSizeChanged(int width, int height) override
std::vector< unsigned char > mJpegBuffer
void onKeyWentUp(const Wt::WKeyEvent &evt)
dyno::Texture2D mFrameColor
void onMouseReleased(const Wt::WMouseEvent &evt)
std::unique_ptr< ImageEncoder > mJpegEncoder
void setScene(std::shared_ptr< dyno::SceneGraph > scene)
void onKeyWentDown(const Wt::WKeyEvent &evt)
dyno::Framebuffer mFramebuffer
void onMousePressed(const Wt::WMouseEvent &evt)
virtual std::shared_ptr< Camera > getCamera()
SelectionMode getSelectionMode()
std::shared_ptr< Camera > mCamera
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)
This is an implementation of AdditiveCCD based on peridyno.
Definition Array.h:25
PModifierBits
@ MB_CONTROL
@ MB_NO_MODIFIER
@ MB_SHIFT
int scene
Definition GltfFunc.h:20
@ AT_PRESS
Definition InputModule.h:36
@ PKEY_P
Definition InputModule.h:76
@ PKEY_S
Definition InputModule.h:79
@ PKEY_LEFT
@ PKEY_F4
@ PKEY_F6
@ PKEY_A
Definition InputModule.h:61
@ PKEY_T
Definition InputModule.h:80
@ PKEY_F2
@ PKEY_4
Definition InputModule.h:53
@ PKEY_H
Definition InputModule.h:68
@ PKEY_F5
@ PKEY_F8
@ PKEY_O
Definition InputModule.h:75
@ PKEY_1
Definition InputModule.h:50
@ PKEY_Q
Definition InputModule.h:77
@ PKEY_7
Definition InputModule.h:56
@ PKEY_F11
@ PKEY_F7
@ PKEY_SPACE
Definition InputModule.h:43
@ PKEY_BACKSPACE
Definition InputModule.h:96
@ PKEY_Y
Definition InputModule.h:85
@ PKEY_D
Definition InputModule.h:64
@ PKEY_J
Definition InputModule.h:70
@ PKEY_R
Definition InputModule.h:78
@ PKEY_C
Definition InputModule.h:63
@ PKEY_5
Definition InputModule.h:54
@ PKEY_3
Definition InputModule.h:52
@ PKEY_N
Definition InputModule.h:74
@ PKEY_RIGHT
Definition InputModule.h:99
@ PKEY_F1
@ PKEY_I
Definition InputModule.h:69
@ PKEY_F10
@ PKEY_V
Definition InputModule.h:82
@ PKEY_F
Definition InputModule.h:66
@ PKEY_K
Definition InputModule.h:71
@ PKEY_DOWN
@ PKEY_F9
@ PKEY_B
Definition InputModule.h:62
@ PKEY_PAGE_UP
@ PKEY_END
@ PKEY_W
Definition InputModule.h:83
@ PKEY_G
Definition InputModule.h:67
@ PKEY_INSERT
Definition InputModule.h:97
@ PKEY_UNKNOWN
Definition InputModule.h:42
@ PKEY_8
Definition InputModule.h:57
@ PKEY_2
Definition InputModule.h:51
@ PKEY_6
Definition InputModule.h:55
@ PKEY_E
Definition InputModule.h:65
@ PKEY_F3
@ PKEY_ESCAPE
Definition InputModule.h:93
@ PKEY_UP
@ PKEY_F12
@ PKEY_HOME
@ PKEY_0
Definition InputModule.h:49
@ PKEY_Z
Definition InputModule.h:86
@ PKEY_U
Definition InputModule.h:81
@ PKEY_ENTER
Definition InputModule.h:94
@ PKEY_9
Definition InputModule.h:58
@ PKEY_X
Definition InputModule.h:84
@ PKEY_M
Definition InputModule.h:73
@ PKEY_TAB
Definition InputModule.h:95
@ PKEY_DELETE
Definition InputModule.h:98
@ PKEY_L
Definition InputModule.h:72
@ PKEY_PAGE_DOWN
PKeyboardType key
PModifierBits mods