0032137: Coding Rules - merge redundant .lxx files into header files within Package gp
[occt.git] / samples / glfw / GlfwOcctView.cpp
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 "GlfwOcctView.h"
23
24 #include <AIS_Shape.hxx>
25 #include <Aspect_Handle.hxx>
26 #include <Aspect_DisplayConnection.hxx>
27 #include <BRepPrimAPI_MakeBox.hxx>
28 #include <BRepPrimAPI_MakeCone.hxx>
29 #include <Message.hxx>
30 #include <Message_Messenger.hxx>
31 #include <OpenGl_GraphicDriver.hxx>
32 #include <TopAbs_ShapeEnum.hxx>
33
34 #include <iostream>
35
36 #include <GLFW/glfw3.h>
37
38 namespace
39 {
40   //! Convert GLFW mouse button into Aspect_VKeyMouse.
41   static Aspect_VKeyMouse mouseButtonFromGlfw (int theButton)
42   {
43     switch (theButton)
44     {
45       case GLFW_MOUSE_BUTTON_LEFT:   return Aspect_VKeyMouse_LeftButton;
46       case GLFW_MOUSE_BUTTON_RIGHT:  return Aspect_VKeyMouse_RightButton;
47       case GLFW_MOUSE_BUTTON_MIDDLE: return Aspect_VKeyMouse_MiddleButton;
48     }
49     return Aspect_VKeyMouse_NONE;
50   }
51
52   //! Convert GLFW key modifiers into Aspect_VKeyFlags.
53   static Aspect_VKeyFlags keyFlagsFromGlfw (int theFlags)
54   {
55     Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
56     if ((theFlags & GLFW_MOD_SHIFT) != 0)
57     {
58       aFlags |= Aspect_VKeyFlags_SHIFT;
59     }
60     if ((theFlags & GLFW_MOD_CONTROL) != 0)
61     {
62       aFlags |= Aspect_VKeyFlags_CTRL;
63     }
64     if ((theFlags & GLFW_MOD_ALT) != 0)
65     {
66       aFlags |= Aspect_VKeyFlags_ALT;
67     }
68     if ((theFlags & GLFW_MOD_SUPER) != 0)
69     {
70       aFlags |= Aspect_VKeyFlags_META;
71     }
72     return aFlags;
73   }
74 }
75
76 // ================================================================
77 // Function : GlfwOcctView
78 // Purpose  :
79 // ================================================================
80 GlfwOcctView::GlfwOcctView()
81 {
82 }
83
84 // ================================================================
85 // Function : ~GlfwOcctView
86 // Purpose  :
87 // ================================================================
88 GlfwOcctView::~GlfwOcctView()
89 {
90 }
91
92 // ================================================================
93 // Function : toView
94 // Purpose  :
95 // ================================================================
96 GlfwOcctView* GlfwOcctView::toView (GLFWwindow* theWin)
97 {
98   return static_cast<GlfwOcctView*>(glfwGetWindowUserPointer (theWin));
99 }
100
101 // ================================================================
102 // Function : errorCallback
103 // Purpose  :
104 // ================================================================
105 void GlfwOcctView::errorCallback (int theError, const char* theDescription)
106 {
107   Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error") + theError + ": " + theDescription, Message_Fail);
108 }
109
110 // ================================================================
111 // Function : run
112 // Purpose  :
113 // ================================================================
114 void GlfwOcctView::run()
115 {
116   initWindow (800, 600, "glfw occt");
117   initViewer();
118   initDemoScene();
119   if (myView.IsNull())
120   {
121     return;
122   }
123
124   myView->MustBeResized();
125   myOcctWindow->Map();
126   mainloop();
127   cleanup();
128 }
129
130 // ================================================================
131 // Function : initWindow
132 // Purpose  :
133 // ================================================================
134 void GlfwOcctView::initWindow (int theWidth, int theHeight, const char* theTitle)
135 {
136   glfwSetErrorCallback (GlfwOcctView::errorCallback);
137   glfwInit();
138   const bool toAskCoreProfile = true;
139   if (toAskCoreProfile)
140   {
141     glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
142     glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3);
143 #if defined (__APPLE__)
144     glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
145 #endif
146     glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
147   }
148   myOcctWindow = new GlfwOcctWindow (theWidth, theHeight, theTitle);
149   glfwSetWindowUserPointer       (myOcctWindow->getGlfwWindow(), this);
150   // window callback
151   glfwSetWindowSizeCallback      (myOcctWindow->getGlfwWindow(), GlfwOcctView::onResizeCallback);
152   glfwSetFramebufferSizeCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onFBResizeCallback);
153   // mouse callback
154   glfwSetScrollCallback          (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseScrollCallback);
155   glfwSetMouseButtonCallback     (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseButtonCallback);
156   glfwSetCursorPosCallback       (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseMoveCallback);
157 }
158
159 // ================================================================
160 // Function : initViewer
161 // Purpose  :
162 // ================================================================
163 void GlfwOcctView::initViewer()
164 {
165   if (myOcctWindow.IsNull()
166    || myOcctWindow->getGlfwWindow() == nullptr)
167   {
168     return;
169   }
170
171   Handle(OpenGl_GraphicDriver) aGraphicDriver = new OpenGl_GraphicDriver (myOcctWindow->GetDisplay(), false);
172   Handle(V3d_Viewer) aViewer = new V3d_Viewer (aGraphicDriver);
173   aViewer->SetDefaultLights();
174   aViewer->SetLightOn();
175   aViewer->SetDefaultTypeOfView (V3d_PERSPECTIVE);
176   aViewer->ActivateGrid (Aspect_GT_Rectangular, Aspect_GDM_Lines);
177   myView = aViewer->CreateView();
178   myView->SetImmediateUpdate (false);
179   myView->SetWindow (myOcctWindow, myOcctWindow->NativeGlContext());
180   myView->ChangeRenderingParams().ToShowStats = true;
181   myContext = new AIS_InteractiveContext (aViewer);
182 }
183
184 // ================================================================
185 // Function : initDemoScene
186 // Purpose  :
187 // ================================================================
188 void GlfwOcctView::initDemoScene()
189 {
190   if (myContext.IsNull())
191   {
192     return;
193   }
194
195   myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_WIREFRAME);
196
197   gp_Ax2 anAxis;
198   anAxis.SetLocation (gp_Pnt (0.0, 0.0, 0.0));
199   Handle(AIS_Shape) aBox = new AIS_Shape (BRepPrimAPI_MakeBox (anAxis, 50, 50, 50).Shape());
200   myContext->Display (aBox, AIS_Shaded, 0, false);
201   anAxis.SetLocation (gp_Pnt (25.0, 125.0, 0.0));
202   Handle(AIS_Shape) aCone = new AIS_Shape (BRepPrimAPI_MakeCone (anAxis, 25, 0, 50).Shape());
203   myContext->Display (aCone, AIS_Shaded, 0, false);
204
205   TCollection_AsciiString aGlInfo;
206   {
207     TColStd_IndexedDataMapOfStringString aRendInfo;
208     myView->DiagnosticInformation (aRendInfo, Graphic3d_DiagnosticInfo_Basic);
209     for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aRendInfo); aValueIter.More(); aValueIter.Next())
210     {
211       if (!aGlInfo.IsEmpty()) { aGlInfo += "\n"; }
212       aGlInfo += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
213     }
214   }
215   Message::DefaultMessenger()->Send (TCollection_AsciiString("OpenGL info:\n") + aGlInfo, Message_Info);
216 }
217
218 // ================================================================
219 // Function : mainloop
220 // Purpose  :
221 // ================================================================
222 void GlfwOcctView::mainloop()
223 {
224   while (!glfwWindowShouldClose (myOcctWindow->getGlfwWindow()))
225   {
226     // glfwPollEvents() for continuous rendering (immediate return if there are no new events)
227     // and glfwWaitEvents() for rendering on demand (something actually happened in the viewer)
228     //glfwPollEvents();
229     glfwWaitEvents();
230     if (!myView.IsNull())
231     {
232       FlushViewEvents (myContext, myView, true);
233     }
234   }
235 }
236
237 // ================================================================
238 // Function : cleanup
239 // Purpose  :
240 // ================================================================
241 void GlfwOcctView::cleanup()
242 {
243   if (!myView.IsNull())
244   {
245     myView->Remove();
246   }
247   if (!myOcctWindow.IsNull())
248   {
249     myOcctWindow->Close();
250   }
251   glfwTerminate();
252 }
253
254 // ================================================================
255 // Function : onResize
256 // Purpose  :
257 // ================================================================
258 void GlfwOcctView::onResize (int theWidth, int theHeight)
259 {
260   if (theWidth  != 0
261    && theHeight != 0
262    && !myView.IsNull())
263   {
264     myView->Window()->DoResize();
265     myView->MustBeResized();
266     myView->Invalidate();
267     myView->Redraw();
268   }
269 }
270
271 // ================================================================
272 // Function : onMouseScroll
273 // Purpose  :
274 // ================================================================
275 void GlfwOcctView::onMouseScroll (double theOffsetX, double theOffsetY)
276 {
277   if (!myView.IsNull())
278   {
279     UpdateZoom (Aspect_ScrollDelta (myOcctWindow->CursorPosition(), int(theOffsetY * 8.0)));
280   }
281 }
282
283 // ================================================================
284 // Function : onMouseButton
285 // Purpose  :
286 // ================================================================
287 void GlfwOcctView::onMouseButton (int theButton, int theAction, int theMods)
288 {
289   if (myView.IsNull()) { return; }
290
291   const Graphic3d_Vec2i aPos = myOcctWindow->CursorPosition();
292   if (theAction == GLFW_PRESS)
293   {
294     PressMouseButton (aPos, mouseButtonFromGlfw (theButton), keyFlagsFromGlfw (theMods), false);
295   }
296   else
297   {
298     ReleaseMouseButton (aPos, mouseButtonFromGlfw (theButton), keyFlagsFromGlfw (theMods), false);
299   }
300 }
301
302 // ================================================================
303 // Function : onMouseMove
304 // Purpose  :
305 // ================================================================
306 void GlfwOcctView::onMouseMove (int thePosX, int thePosY)
307 {
308   const Graphic3d_Vec2i aNewPos (thePosX, thePosY);
309   if (!myView.IsNull())
310   {
311     UpdateMousePosition (aNewPos, PressedMouseButtons(), LastMouseFlags(), false);
312   }
313 }