PeriDyno 1.0.0
Loading...
Searching...
No Matches
WSimulationCanvas.cpp
Go to the documentation of this file.
1#include "WSimulationCanvas.h"
2#include "ImageEncoder.h"
3
4#include <Wt/WApplication.h>
5#include <Wt/WMemoryResource.h>
6#include <Wt/WImage.h>
7
8#include <GLFW/glfw3.h>
9
10#include <SceneGraph.h>
11#include <GLRenderEngine.h>
12#include <OrbitCamera.h>
13#include <TrackballCamera.h>
14
15#include "imgui_impl_wt.h"
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%", "100%");
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 scheduleRender();
290}
291
292void WSimulationCanvas::onMouseDrag(const Wt::WMouseEvent& evt)
293{
294 if (!mImGuiCtx->handleMouseDrag(evt))
295 {
296 auto mods = evt.modifiers();
297
298 if (mods.test(Wt::KeyboardModifier::Alt) && mMouseButtonDown == true)
299 {
300 Wt::Coordinates coord = evt.widget();
301 if (evt.button() == Wt::MouseButton::Left) {
302 mCamera->rotateToPoint(coord.x, coord.y);
303 }
304 else if (evt.button() == Wt::MouseButton::Middle) {
305 mCamera->translateToPoint(coord.x, coord.y);
306 }
307 else if (evt.button() == Wt::MouseButton::Right) {
308 auto cam = this->getCamera();
309 cam->zoom(-0.005 * float(evt.widget().x - mtempCursorX));
310 mtempCursorX = evt.widget().x;
311 }
312 }
313 }
314 scheduleRender();
315}
316
317void WSimulationCanvas::onMouseReleased(const Wt::WMouseEvent& evt)
318{
319 if (!mImGuiCtx->handleMouseReleased(evt))
320 {
321 mMouseButtonDown = false;
322 }
323
324 scheduleRender();
325}
326
327void WSimulationCanvas::onMouseWheeled(const Wt::WMouseEvent& evt)
328{
329 mCamera->zoom(-1.0 * evt.wheelDelta());
330 scheduleRender();
331}
332
333void WSimulationCanvas::onKeyWentDown(const Wt::WKeyEvent& evt)
334{
335 Wt::log("Error") << "´¥·¢ÁË";
336 PKeyboardEvent keyEvent;
337 keyEvent.key = WKeyMap.find(evt.key()) == WKeyMap.end() ? PKEY_UNKNOWN : WKeyMap[evt.key()];
338 keyEvent.action = AT_PRESS;
339 keyEvent.mods = mappingWtModifierBits(evt.modifiers());
340
341 mScene->onKeyboardEvent(keyEvent);
342
343 switch (evt.key())
344 {
345 case Wt::Key::H:
346 this->toggleImGUI();
347 break;
348 default:
349 break;
350 }
351
352 scheduleRender();
353}
354
355void WSimulationCanvas::onKeyWentUp(const Wt::WKeyEvent& evt)
356{
357}
358
359void WSimulationCanvas::render(Wt::WFlags<Wt::RenderFlag> flags)
360{
361 update();
362}
363
365{
366 // do render
367 {
368 this->makeCurrent();
369
370 if (mScene)
371 {
372 mScene->updateGraphicsContext();
373 }
374
375 // update rendering params
376 mRenderParams.width = mCamera->viewportWidth();
377 mRenderParams.height = mCamera->viewportHeight();
378 mRenderParams.transforms.model = glm::mat4(1); // TODO: world transform?
379 mRenderParams.transforms.view = mCamera->getViewMat();
380 mRenderParams.transforms.proj = mCamera->getProjMat();
381 mRenderParams.unitScale = mCamera->unitScale();
382
383 mFramebuffer.bind();
384 // heck: ImGUI widgets need to render twice...
385 if (showImGUI())
386 {
387 // Start the Dear ImGui frame
388 mImGuiCtx->NewFrame(mCamera->viewportWidth(), mCamera->viewportHeight());
389 mImWindow.draw(this);
390 mImGuiCtx->Render();
391 }
392
393 mRenderEngine->draw(mScene.get(), mRenderParams);
394
395 if (showImGUI())
396 {
397 // Start the Dear ImGui frame
398 mImGuiCtx->NewFrame(mCamera->viewportWidth(), mCamera->viewportHeight());
399 mImWindow.draw(this);
400 mImGuiCtx->Render();
401 }
402
403 // dump framebuffer
404 mFrameColor.dump(mImageData.data());
405 mFramebuffer.unbind();
406
407 this->doneCurrent();
408 }
409
410 // encode image
411 {
412 mJpegBuffer.clear();
413
414 mJpegEncoder->Encode(mImageData.data(),
415 mCamera->viewportWidth(), mCamera->viewportHeight(), 0,
417
418 Wt::log("info") << mCamera->viewportWidth() << " x " << mCamera->viewportHeight()
419 << ", JPG size: " << mJpegBuffer.size() / 1024 << " kb";
420 }
421
422 // update UI
423 {
424 mJpegResource->setData(std::move(mJpegBuffer));
425 const std::string url = mJpegResource->generateUrl();
426 mImage->callJavaScriptMember("update", WWebWidget::jsStringLiteral(url));
427 }
428}
429
430void WSimulationCanvas::setScene(std::shared_ptr<dyno::SceneGraph> scene)
431{
432 this->mScene = scene;
433
434 // TODO: move to somewhere else!
435 if (this->mScene)
436 {
437 makeCurrent();
438 this->mScene->reset();
439 doneCurrent();
440
441 scheduleRender();
442 }
443}
PModifierBits mappingWtModifierBits(Wt::KeyboardModifier mods)
std::map< Wt::Key, PKeyboardType > WKeyMap
std::unique_ptr< Wt::WMemoryResource > mJpegResource
void render(Wt::WFlags< Wt::RenderFlag > flags) override
dyno::ImWindow mImWindow
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()
std::shared_ptr< Camera > mCamera
RenderParams mRenderParams
std::shared_ptr< RenderEngine > mRenderEngine
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