0031668: Visualization - WebGL sample doesn't work on Emscripten 1.39
[occt.git] / samples / webgl / WasmOcctView.cpp
CommitLineData
565baee6 1// Copyright (c) 2019 OPEN CASCADE SAS
2//
3// This file is part of the examples of the Open CASCADE Technology software library.
4//
5// Permission is hereby granted, free of charge, to any person obtaining a copy
6// of this software and associated documentation files (the "Software"), to deal
7// in the Software without restriction, including without limitation the rights
8// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9// copies of the Software, and to permit persons to whom the Software is
10// furnished to do so, subject to the following conditions:
11//
12// The above copyright notice and this permission notice shall be included in all
13// copies or substantial portions of the Software.
14//
15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
21
22#include "WasmOcctView.h"
23
24#include "WasmVKeys.h"
25
26#include <AIS_Shape.hxx>
27#include <AIS_ViewCube.hxx>
28#include <Aspect_Handle.hxx>
29#include <Aspect_DisplayConnection.hxx>
30#include <Aspect_NeutralWindow.hxx>
31#include <Message.hxx>
32#include <Message_Messenger.hxx>
33#include <OpenGl_GraphicDriver.hxx>
34#include <Prs3d_DatumAspect.hxx>
35
36#include <iostream>
37
38#define THE_CANVAS_ID "canvas"
39
40namespace
41{
42 EM_JS(int, jsCanvasGetWidth, (), {
43 return canvas.width;
44 });
45
46 EM_JS(int, jsCanvasGetHeight, (), {
47 return canvas.height;
48 });
49
50 EM_JS(float, jsDevicePixelRatio, (), {
51 var aDevicePixelRatio = window.devicePixelRatio || 1;
52 return aDevicePixelRatio;
53 });
54
55 //! Return cavas size in pixels.
56 static Graphic3d_Vec2i jsCanvasSize()
57 {
58 return Graphic3d_Vec2i (jsCanvasGetWidth(), jsCanvasGetHeight());
59 }
60}
61
62// ================================================================
63// Function : WasmOcctView
64// Purpose :
65// ================================================================
66WasmOcctView::WasmOcctView()
67: myDevicePixelRatio (1.0f),
68 myUpdateRequests (0)
69{
70}
71
72// ================================================================
73// Function : ~WasmOcctView
74// Purpose :
75// ================================================================
76WasmOcctView::~WasmOcctView()
77{
78}
79
80// ================================================================
81// Function : run
82// Purpose :
83// ================================================================
84void WasmOcctView::run()
85{
86 initWindow();
87 initViewer();
88 initDemoScene();
89 if (myView.IsNull())
90 {
91 return;
92 }
93
94 myView->MustBeResized();
95 myView->Redraw();
96
97 // There is no inifinite message loop, main() will return from here immediately.
98 // Tell that our Module should be left loaded and handle events through callbacks.
99 //emscripten_set_main_loop (redrawView, 60, 1);
100 //emscripten_set_main_loop (redrawView, -1, 1);
101 EM_ASM(Module['noExitRuntime'] = true);
102}
103
104// ================================================================
105// Function : initWindow
106// Purpose :
107// ================================================================
108void WasmOcctView::initWindow()
109{
110 myDevicePixelRatio = jsDevicePixelRatio();
111 myCanvasId = THE_CANVAS_ID;
7465bfa6 112 const char* aTargetId = !myCanvasId.IsEmpty() ? myCanvasId.ToCString() : EMSCRIPTEN_EVENT_TARGET_WINDOW;
565baee6 113 const EM_BOOL toUseCapture = EM_TRUE;
7465bfa6 114 emscripten_set_resize_callback (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onResizeCallback);
565baee6 115
7465bfa6 116 emscripten_set_mousedown_callback (aTargetId, this, toUseCapture, onMouseCallback);
117 emscripten_set_mouseup_callback (aTargetId, this, toUseCapture, onMouseCallback);
118 emscripten_set_mousemove_callback (aTargetId, this, toUseCapture, onMouseCallback);
565baee6 119 emscripten_set_dblclick_callback (aTargetId, this, toUseCapture, onMouseCallback);
120 emscripten_set_click_callback (aTargetId, this, toUseCapture, onMouseCallback);
121 emscripten_set_mouseenter_callback (aTargetId, this, toUseCapture, onMouseCallback);
122 emscripten_set_mouseleave_callback (aTargetId, this, toUseCapture, onMouseCallback);
123 emscripten_set_wheel_callback (aTargetId, this, toUseCapture, onWheelCallback);
124
125 emscripten_set_touchstart_callback (aTargetId, this, toUseCapture, onTouchCallback);
126 emscripten_set_touchend_callback (aTargetId, this, toUseCapture, onTouchCallback);
127 emscripten_set_touchmove_callback (aTargetId, this, toUseCapture, onTouchCallback);
128 emscripten_set_touchcancel_callback(aTargetId, this, toUseCapture, onTouchCallback);
129
7465bfa6 130 //emscripten_set_keypress_callback (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyCallback);
131 emscripten_set_keydown_callback (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyDownCallback);
132 emscripten_set_keyup_callback (EMSCRIPTEN_EVENT_TARGET_WINDOW, this, toUseCapture, onKeyUpCallback);
565baee6 133}
134
135// ================================================================
136// Function : dumpGlInfo
137// Purpose :
138// ================================================================
139void WasmOcctView::dumpGlInfo (bool theIsBasic)
140{
141 TColStd_IndexedDataMapOfStringString aGlCapsDict;
142 myView->DiagnosticInformation (aGlCapsDict, theIsBasic ? Graphic3d_DiagnosticInfo_Basic : Graphic3d_DiagnosticInfo_Complete);
143 if (theIsBasic)
144 {
145 TCollection_AsciiString aViewport;
146 aGlCapsDict.FindFromKey ("Viewport", aViewport);
147 aGlCapsDict.Clear();
148 aGlCapsDict.Add ("Viewport", aViewport);
149 }
150 aGlCapsDict.Add ("Display scale", TCollection_AsciiString(myDevicePixelRatio));
151
152 // beautify output
153 {
154 TCollection_AsciiString* aGlVer = aGlCapsDict.ChangeSeek ("GLversion");
155 TCollection_AsciiString* aGlslVer = aGlCapsDict.ChangeSeek ("GLSLversion");
156 if (aGlVer != NULL
157 && aGlslVer != NULL)
158 {
159 *aGlVer = *aGlVer + " [GLSL: " + *aGlslVer + "]";
160 aGlslVer->Clear();
161 }
162 }
163
164 TCollection_AsciiString anInfo;
165 for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aGlCapsDict); aValueIter.More(); aValueIter.Next())
166 {
167 if (!aValueIter.Value().IsEmpty())
168 {
169 if (!anInfo.IsEmpty())
170 {
171 anInfo += "\n";
172 }
173 anInfo += aValueIter.Key() + ": " + aValueIter.Value();
174 }
175 }
176
177 ::Message::DefaultMessenger()->Send (anInfo, Message_Warning);
178}
179
180// ================================================================
181// Function : initPixelScaleRatio
182// Purpose :
183// ================================================================
184void WasmOcctView::initPixelScaleRatio()
185{
186 SetTouchToleranceScale (myDevicePixelRatio);
187 if (!myView.IsNull())
188 {
189 myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
190 }
191 if (!myContext.IsNull())
192 {
193 myContext->SetPixelTolerance (int(myDevicePixelRatio * 6.0));
194 if (!myViewCube.IsNull())
195 {
196 static const double THE_CUBE_SIZE = 60.0;
197 myViewCube->SetSize (myDevicePixelRatio * THE_CUBE_SIZE, false);
198 myViewCube->SetBoxFacetExtension (myViewCube->Size() * 0.15);
199 myViewCube->SetAxesPadding (myViewCube->Size() * 0.10);
200 myViewCube->SetFontHeight (THE_CUBE_SIZE * 0.16);
201 if (myViewCube->HasInteractiveContext())
202 {
203 myContext->Redisplay (myViewCube, false);
204 }
205 }
206 }
207}
208
209// ================================================================
210// Function : initViewer
211// Purpose :
212// ================================================================
213bool WasmOcctView::initViewer()
214{
215 // Build with "--preload-file MyFontFile.ttf" option
216 // and register font in Font Manager to use custom font(s).
217 /*const char* aFontPath = "MyFontFile.ttf";
218 if (Handle(Font_SystemFont) aFont = Font_FontMgr::GetInstance()->CheckFont (aFontPath))
219 {
220 Font_FontMgr::GetInstance()->RegisterFont (aFont, true);
221 }
222 else
223 {
224 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: font '") + aFontPath + "' is not found", Message_Fail);
225 }*/
226
227 Handle(Aspect_DisplayConnection) aDisp;
228 Handle(OpenGl_GraphicDriver) aDriver = new OpenGl_GraphicDriver (aDisp, false);
229 aDriver->ChangeOptions().buffersNoSwap = true; // swap has no effect in WebGL
230 if (!aDriver->InitContext())
231 {
232 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error: EGL initialization failed"), Message_Fail);
233 return false;
234 }
235
236 Handle(V3d_Viewer) aViewer = new V3d_Viewer (aDriver);
237 aViewer->SetComputedMode (false);
238 aViewer->SetDefaultShadingModel (Graphic3d_TOSM_FRAGMENT);
239 aViewer->SetDefaultLights();
240 aViewer->SetLightOn();
241
242 Handle(Aspect_NeutralWindow) aWindow = new Aspect_NeutralWindow();
243 Graphic3d_Vec2i aWinSize = jsCanvasSize();
244 if (aWinSize.x() < 10 || aWinSize.y() < 10)
245 {
246 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Warning: invalid canvas size"), Message_Warning);
247 }
248 aWindow->SetSize (aWinSize.x(), aWinSize.y());
249
250 myTextStyle = new Prs3d_TextAspect();
251 myTextStyle->SetFont (Font_NOF_ASCII_MONO);
252 myTextStyle->SetHeight (12);
253 myTextStyle->Aspect()->SetColor (Quantity_NOC_GRAY95);
254 myTextStyle->Aspect()->SetColorSubTitle (Quantity_NOC_BLACK);
255 myTextStyle->Aspect()->SetDisplayType (Aspect_TODT_SHADOW);
256 myTextStyle->Aspect()->SetTextFontAspect (Font_FA_Bold);
257 myTextStyle->Aspect()->SetTextZoomable (false);
258 myTextStyle->SetHorizontalJustification (Graphic3d_HTA_LEFT);
259 myTextStyle->SetVerticalJustification (Graphic3d_VTA_BOTTOM);
260
261 myView = new V3d_View (aViewer);
262 myView->SetImmediateUpdate (false);
263 myView->ChangeRenderingParams().Resolution = (unsigned int )(96.0 * myDevicePixelRatio + 0.5);
264 myView->ChangeRenderingParams().ToShowStats = true;
265 myView->ChangeRenderingParams().StatsTextAspect = myTextStyle->Aspect();
266 myView->ChangeRenderingParams().StatsTextHeight = (int )myTextStyle->Height();
267 myView->SetWindow (aWindow);
268 dumpGlInfo (false);
269
270 myContext = new AIS_InteractiveContext (aViewer);
271 initPixelScaleRatio();
272 return true;
273}
274
275// ================================================================
276// Function : initDemoScene
277// Purpose :
278// ================================================================
279void WasmOcctView::initDemoScene()
280{
281 if (myContext.IsNull())
282 {
283 return;
284 }
285
286 //myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_WIREFRAME);
287
288 myViewCube = new AIS_ViewCube();
289 // presentation parameters
290 initPixelScaleRatio();
291 myViewCube->SetTransformPersistence (new Graphic3d_TransformPers (Graphic3d_TMF_TriedronPers, Aspect_TOTP_RIGHT_LOWER, Graphic3d_Vec2i (100, 100)));
292 myViewCube->Attributes()->SetDatumAspect (new Prs3d_DatumAspect());
293 myViewCube->Attributes()->DatumAspect()->SetTextAspect (myTextStyle);
294 // animation parameters
295 myViewCube->SetViewAnimation (myViewAnimation);
296 myViewCube->SetFixedAnimationLoop (false);
297 myViewCube->SetAutoStartAnimation (true);
298 myContext->Display (myViewCube, false);
299
300 // Build with "--preload-file MySampleFile.brep" option to load some shapes here.
301}
302
303
304// ================================================================
305// Function : updateView
306// Purpose :
307// ================================================================
308void WasmOcctView::updateView()
309{
310 if (!myView.IsNull())
311 {
312 if (++myUpdateRequests == 1)
313 {
314 emscripten_async_call (onRedrawView, this, 0);
315 }
316 }
317}
318
319// ================================================================
320// Function : redrawView
321// Purpose :
322// ================================================================
323void WasmOcctView::redrawView()
324{
325 if (!myView.IsNull())
326 {
327 FlushViewEvents (myContext, myView, true);
328 }
329}
330
331// ================================================================
332// Function : handleViewRedraw
333// Purpose :
334// ================================================================
335void WasmOcctView::handleViewRedraw (const Handle(AIS_InteractiveContext)& theCtx,
336 const Handle(V3d_View)& theView)
337{
338 myUpdateRequests = 0;
339 AIS_ViewController::handleViewRedraw (theCtx, theView);
340 if (myToAskNextFrame)
341 {
342 // ask more frames
343 ++myUpdateRequests;
344 emscripten_async_call (onRedrawView, this, 0);
345 }
346}
347
348// ================================================================
349// Function : onResizeEvent
350// Purpose :
351// ================================================================
352EM_BOOL WasmOcctView::onResizeEvent (int theEventType, const EmscriptenUiEvent* theEvent)
353{
354 (void )theEventType; // EMSCRIPTEN_EVENT_RESIZE or EMSCRIPTEN_EVENT_CANVASRESIZED
355 (void )theEvent;
356 if (myView.IsNull())
357 {
358 return EM_FALSE;
359 }
360
361 Handle(Aspect_NeutralWindow) aWindow = Handle(Aspect_NeutralWindow)::DownCast (myView->Window());
362 Graphic3d_Vec2i aWinSizeOld, aWinSizeNew (jsCanvasSize());
363 if (aWinSizeNew.x() < 10 || aWinSizeNew.y() < 10)
364 {
365 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Warning: invalid canvas size"), Message_Warning);
366 }
367 aWindow->Size (aWinSizeOld.x(), aWinSizeOld.y());
368 const float aPixelRatio = jsDevicePixelRatio();
369 if (aWinSizeNew != aWinSizeOld
370 || aPixelRatio != myDevicePixelRatio)
371 {
372 if (myDevicePixelRatio != aPixelRatio)
373 {
374 myDevicePixelRatio = aPixelRatio;
375 initPixelScaleRatio();
376 }
377 aWindow->SetSize (aWinSizeNew.x(), aWinSizeNew.y());
378 myView->MustBeResized();
379 myView->Invalidate();
380 myView->Redraw();
381 dumpGlInfo (true);
382 }
383 return EM_TRUE;
384}
385
386// ================================================================
387// Function : onMouseEvent
388// Purpose :
389// ================================================================
390EM_BOOL WasmOcctView::onMouseEvent (int theEventType, const EmscriptenMouseEvent* theEvent)
391{
392 if (myView.IsNull())
393 {
394 return EM_FALSE;
395 }
396
397 Graphic3d_Vec2i aWinSize;
398 myView->Window()->Size (aWinSize.x(), aWinSize.y());
7465bfa6 399 const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->targetX, theEvent->targetY));
565baee6 400 Aspect_VKeyFlags aFlags = 0;
401 if (theEvent->ctrlKey == EM_TRUE) { aFlags |= Aspect_VKeyFlags_CTRL; }
402 if (theEvent->shiftKey == EM_TRUE) { aFlags |= Aspect_VKeyFlags_SHIFT; }
403 if (theEvent->altKey == EM_TRUE) { aFlags |= Aspect_VKeyFlags_ALT; }
404 if (theEvent->metaKey == EM_TRUE) { aFlags |= Aspect_VKeyFlags_META; }
405
406 const bool isEmulated = false;
407 const Aspect_VKeyMouse aButtons = WasmVKeys_MouseButtonsFromNative (theEvent->buttons);
408 switch (theEventType)
409 {
410 case EMSCRIPTEN_EVENT_MOUSEMOVE:
411 {
412 if ((aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
413 || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
414 && PressedMouseButtons() == Aspect_VKeyMouse_NONE)
415 {
416 return EM_FALSE;
417 }
418 if (UpdateMousePosition (aNewPos, aButtons, aFlags, isEmulated))
419 {
420 updateView();
421 }
422 break;
423 }
424 case EMSCRIPTEN_EVENT_MOUSEDOWN:
425 case EMSCRIPTEN_EVENT_MOUSEUP:
426 {
427 if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
428 || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
429 {
430 return EM_FALSE;
431 }
432 if (UpdateMouseButtons (aNewPos, aButtons, aFlags, isEmulated))
433 {
434 updateView();
435 }
436 break;
437 }
438 case EMSCRIPTEN_EVENT_CLICK:
439 case EMSCRIPTEN_EVENT_DBLCLICK:
440 {
441 if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
442 || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
443 {
444 return EM_FALSE;
445 }
446 break;
447 }
448 case EMSCRIPTEN_EVENT_MOUSEENTER:
449 {
450 break;
451 }
452 case EMSCRIPTEN_EVENT_MOUSELEAVE:
453 {
454 // there is no SetCapture() support, so that mouse unclick events outside canvas will not arrive,
455 // so we have to forget current state...
456 if (UpdateMouseButtons (aNewPos, Aspect_VKeyMouse_NONE, aFlags, isEmulated))
457 {
458 updateView();
459 }
460 break;
461 }
462 }
463 return EM_TRUE;
464}
465
466// ================================================================
467// Function : onWheelEvent
468// Purpose :
469// ================================================================
470EM_BOOL WasmOcctView::onWheelEvent (int theEventType, const EmscriptenWheelEvent* theEvent)
471{
472 if (myView.IsNull()
473 || theEventType != EMSCRIPTEN_EVENT_WHEEL)
474 {
475 return EM_FALSE;
476 }
477
478 Graphic3d_Vec2i aWinSize;
479 myView->Window()->Size (aWinSize.x(), aWinSize.y());
7465bfa6 480 const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (theEvent->mouse.targetX, theEvent->mouse.targetY));
565baee6 481 if (aNewPos.x() < 0 || aNewPos.x() > aWinSize.x()
482 || aNewPos.y() < 0 || aNewPos.y() > aWinSize.y())
483 {
484 return EM_FALSE;
485 }
486
487 double aDelta = 0.0;
488 switch (theEvent->deltaMode)
489 {
490 case DOM_DELTA_PIXEL:
491 {
492 aDelta = theEvent->deltaY / (5.0 * myDevicePixelRatio);
493 break;
494 }
495 case DOM_DELTA_LINE:
496 {
497 aDelta = theEvent->deltaY * 8.0;
498 break;
499 }
500 case DOM_DELTA_PAGE:
501 {
502 aDelta = theEvent->deltaY >= 0.0 ? 24.0 : -24.0;
503 break;
504 }
505 }
506
507 if (UpdateZoom (Aspect_ScrollDelta (aNewPos, -aDelta)))
508 {
509 updateView();
510 }
511 return EM_TRUE;
512}
513
514// ================================================================
515// Function : onTouchEvent
516// Purpose :
517// ================================================================
518EM_BOOL WasmOcctView::onTouchEvent (int theEventType, const EmscriptenTouchEvent* theEvent)
519{
520 const double aClickTolerance = 5.0;
521 if (myView.IsNull())
522 {
523 return EM_FALSE;
524 }
525
526 Graphic3d_Vec2i aWinSize;
527 myView->Window()->Size (aWinSize.x(), aWinSize.y());
528 bool hasUpdates = false;
529 for (int aTouchIter = 0; aTouchIter < theEvent->numTouches; ++aTouchIter)
530 {
531 const EmscriptenTouchPoint& aTouch = theEvent->touches[aTouchIter];
532 if (!aTouch.isChanged)
533 {
534 continue;
535 }
536
537 const Standard_Size aTouchId = (Standard_Size )aTouch.identifier;
538 const Graphic3d_Vec2i aNewPos = convertPointToBacking (Graphic3d_Vec2i (aTouch.canvasX, aTouch.canvasY));
539 switch (theEventType)
540 {
541 case EMSCRIPTEN_EVENT_TOUCHSTART:
542 {
543 if (aNewPos.x() >= 0 && aNewPos.x() < aWinSize.x()
544 && aNewPos.y() >= 0 && aNewPos.y() < aWinSize.y())
545 {
546 hasUpdates = true;
547 AddTouchPoint (aTouchId, Graphic3d_Vec2d (aNewPos));
548 myClickTouch.From.SetValues (-1.0, -1.0);
549 if (myTouchPoints.Extent() == 1)
550 {
551 myClickTouch.From = Graphic3d_Vec2d (aNewPos);
552 }
553 }
554 break;
555 }
556 case EMSCRIPTEN_EVENT_TOUCHMOVE:
557 {
558 const int anOldIndex = myTouchPoints.FindIndex (aTouchId);
559 if (anOldIndex != 0)
560 {
561 hasUpdates = true;
562 UpdateTouchPoint (aTouchId, Graphic3d_Vec2d (aNewPos));
563 if (myTouchPoints.Extent() == 1
564 && (myClickTouch.From - Graphic3d_Vec2d (aNewPos)).cwiseAbs().maxComp() > aClickTolerance)
565 {
566 myClickTouch.From.SetValues (-1.0, -1.0);
567 }
568 }
569 break;
570 }
571 case EMSCRIPTEN_EVENT_TOUCHEND:
572 case EMSCRIPTEN_EVENT_TOUCHCANCEL:
573 {
574 if (RemoveTouchPoint (aTouchId))
575 {
576 if (myTouchPoints.IsEmpty()
577 && myClickTouch.From.minComp() >= 0.0)
578 {
579 if (myDoubleTapTimer.IsStarted()
580 && myDoubleTapTimer.ElapsedTime() <= myMouseDoubleClickInt)
581 {
582 myView->FitAll (0.01, false);
583 myView->Invalidate();
584 }
585 else
586 {
587 myDoubleTapTimer.Stop();
588 myDoubleTapTimer.Reset();
589 myDoubleTapTimer.Start();
590 SelectInViewer (Graphic3d_Vec2i (myClickTouch.From), false);
591 }
592 }
593 hasUpdates = true;
594 }
595 break;
596 }
597 }
598 }
599 if (hasUpdates)
600 {
601 updateView();
602 }
603 return hasUpdates || !myTouchPoints.IsEmpty() ? EM_TRUE : EM_FALSE;
604}
605
606// ================================================================
607// Function : onKeyDownEvent
608// Purpose :
609// ================================================================
610EM_BOOL WasmOcctView::onKeyDownEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent)
611{
612 if (myView.IsNull()
613 || theEventType != EMSCRIPTEN_EVENT_KEYDOWN) // EMSCRIPTEN_EVENT_KEYPRESS
614 {
615 return EM_FALSE;
616 }
617
618 const double aTimeStamp = EventTime();
619 const Aspect_VKey aVKey = WasmVKeys_VirtualKeyFromNative (theEvent->keyCode);
620 if (aVKey == Aspect_VKey_UNKNOWN)
621 {
622 return EM_FALSE;
623 }
624
625 if (theEvent->repeat == EM_FALSE)
626 {
627 myKeys.KeyDown (aVKey, aTimeStamp);
628 }
629
630 if (Aspect_VKey2Modifier (aVKey) == 0)
631 {
632 // normal key
633 }
634 return EM_FALSE;
635}
636
637// ================================================================
638// Function : onKeyUpEvent
639// Purpose :
640// ================================================================
641EM_BOOL WasmOcctView::onKeyUpEvent (int theEventType, const EmscriptenKeyboardEvent* theEvent)
642{
643 if (myView.IsNull()
644 || theEventType != EMSCRIPTEN_EVENT_KEYUP)
645 {
646 return EM_FALSE;
647 }
648
649 const double aTimeStamp = EventTime();
650 const Aspect_VKey aVKey = WasmVKeys_VirtualKeyFromNative (theEvent->keyCode);
651 if (aVKey == Aspect_VKey_UNKNOWN)
652 {
653 return EM_FALSE;
654 }
655
656 if (theEvent->repeat == EM_TRUE)
657 {
658 return EM_FALSE;
659 }
660
661 const unsigned int aModif = myKeys.Modifiers();
662 myKeys.KeyUp (aVKey, aTimeStamp);
663 if (Aspect_VKey2Modifier (aVKey) == 0)
664 {
665 // normal key released
666 switch (aVKey | aModif)
667 {
668 case Aspect_VKey_F:
669 {
670 myView->FitAll (0.01, false);
671 myView->Invalidate();
672 updateView();
673 return EM_TRUE;
674 }
675 }
676 }
677 return EM_FALSE;
678}