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.
mouseButtonFromGlfw(int theButton)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.
keyFlagsFromGlfw(int theFlags)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 // ================================================================
GlfwOcctView()80 GlfwOcctView::GlfwOcctView()
81 {
82 }
83
84 // ================================================================
85 // Function : ~GlfwOcctView
86 // Purpose :
87 // ================================================================
~GlfwOcctView()88 GlfwOcctView::~GlfwOcctView()
89 {
90 }
91
92 // ================================================================
93 // Function : toView
94 // Purpose :
95 // ================================================================
toView(GLFWwindow * theWin)96 GlfwOcctView* GlfwOcctView::toView (GLFWwindow* theWin)
97 {
98 return static_cast<GlfwOcctView*>(glfwGetWindowUserPointer (theWin));
99 }
100
101 // ================================================================
102 // Function : errorCallback
103 // Purpose :
104 // ================================================================
errorCallback(int theError,const char * theDescription)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 // ================================================================
run()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 // ================================================================
initWindow(int theWidth,int theHeight,const char * theTitle)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 // ================================================================
initViewer()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 // ================================================================
initDemoScene()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 // ================================================================
mainloop()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 // ================================================================
cleanup()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 // ================================================================
onResize(int theWidth,int theHeight)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 // ================================================================
onMouseScroll(double theOffsetX,double theOffsetY)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 // ================================================================
onMouseButton(int theButton,int theAction,int theMods)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 // ================================================================
onMouseMove(int thePosX,int thePosY)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 }
314