1 // Copyright (c) 2019 OPEN CASCADE SAS
3 // This file is part of the examples of the Open CASCADE Technology software library.
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:
12 // The above copyright notice and this permission notice shall be included in all
13 // copies or substantial portions of the Software.
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
22 #include "GlfwOcctView.h"
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>
36 #include <GLFW/glfw3.h>
40 //! Convert GLFW mouse button into Aspect_VKeyMouse.
41 static Aspect_VKeyMouse mouseButtonFromGlfw (int theButton)
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;
49 return Aspect_VKeyMouse_NONE;
52 //! Convert GLFW key modifiers into Aspect_VKeyFlags.
53 static Aspect_VKeyFlags keyFlagsFromGlfw (int theFlags)
55 Aspect_VKeyFlags aFlags = Aspect_VKeyFlags_NONE;
56 if ((theFlags & GLFW_MOD_SHIFT) != 0)
58 aFlags |= Aspect_VKeyFlags_SHIFT;
60 if ((theFlags & GLFW_MOD_CONTROL) != 0)
62 aFlags |= Aspect_VKeyFlags_CTRL;
64 if ((theFlags & GLFW_MOD_ALT) != 0)
66 aFlags |= Aspect_VKeyFlags_ALT;
68 if ((theFlags & GLFW_MOD_SUPER) != 0)
70 aFlags |= Aspect_VKeyFlags_META;
76 // ================================================================
77 // Function : GlfwOcctView
79 // ================================================================
80 GlfwOcctView::GlfwOcctView()
84 // ================================================================
85 // Function : ~GlfwOcctView
87 // ================================================================
88 GlfwOcctView::~GlfwOcctView()
92 // ================================================================
95 // ================================================================
96 GlfwOcctView* GlfwOcctView::toView (GLFWwindow* theWin)
98 return static_cast<GlfwOcctView*>(glfwGetWindowUserPointer (theWin));
101 // ================================================================
102 // Function : errorCallback
104 // ================================================================
105 void GlfwOcctView::errorCallback (int theError, const char* theDescription)
107 Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error") + theError + ": " + theDescription, Message_Fail);
110 // ================================================================
113 // ================================================================
114 void GlfwOcctView::run()
116 initWindow (800, 600, "glfw occt");
124 myView->MustBeResized();
130 // ================================================================
131 // Function : initWindow
133 // ================================================================
134 void GlfwOcctView::initWindow (int theWidth, int theHeight, const char* theTitle)
136 glfwSetErrorCallback (GlfwOcctView::errorCallback);
138 const bool toAskCoreProfile = true;
139 if (toAskCoreProfile)
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);
146 glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
148 myOcctWindow = new GlfwOcctWindow (theWidth, theHeight, theTitle);
149 glfwSetWindowUserPointer (myOcctWindow->getGlfwWindow(), this);
151 glfwSetWindowSizeCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onResizeCallback);
152 glfwSetFramebufferSizeCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onFBResizeCallback);
154 glfwSetScrollCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseScrollCallback);
155 glfwSetMouseButtonCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseButtonCallback);
156 glfwSetCursorPosCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseMoveCallback);
159 // ================================================================
160 // Function : initViewer
162 // ================================================================
163 void GlfwOcctView::initViewer()
165 if (myOcctWindow.IsNull()
166 || myOcctWindow->getGlfwWindow() == nullptr)
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);
184 // ================================================================
185 // Function : initDemoScene
187 // ================================================================
188 void GlfwOcctView::initDemoScene()
190 if (myContext.IsNull())
195 myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_WIREFRAME);
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);
205 TCollection_AsciiString aGlInfo;
207 TColStd_IndexedDataMapOfStringString aRendInfo;
208 myView->DiagnosticInformation (aRendInfo, Graphic3d_DiagnosticInfo_Basic);
209 for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aRendInfo); aValueIter.More(); aValueIter.Next())
211 if (!aGlInfo.IsEmpty()) { aGlInfo += "\n"; }
212 aGlInfo += TCollection_AsciiString(" ") + aValueIter.Key() + ": " + aValueIter.Value();
215 Message::DefaultMessenger()->Send (TCollection_AsciiString("OpenGL info:\n") + aGlInfo, Message_Info);
218 // ================================================================
219 // Function : mainloop
221 // ================================================================
222 void GlfwOcctView::mainloop()
224 while (!glfwWindowShouldClose (myOcctWindow->getGlfwWindow()))
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)
230 if (!myView.IsNull())
232 FlushViewEvents (myContext, myView, true);
237 // ================================================================
238 // Function : cleanup
240 // ================================================================
241 void GlfwOcctView::cleanup()
243 if (!myView.IsNull())
247 if (!myOcctWindow.IsNull())
249 myOcctWindow->Close();
254 // ================================================================
255 // Function : onResize
257 // ================================================================
258 void GlfwOcctView::onResize (int theWidth, int theHeight)
264 myView->Window()->DoResize();
265 myView->MustBeResized();
266 myView->Invalidate();
271 // ================================================================
272 // Function : onMouseScroll
274 // ================================================================
275 void GlfwOcctView::onMouseScroll (double theOffsetX, double theOffsetY)
277 if (!myView.IsNull())
279 UpdateZoom (Aspect_ScrollDelta (myOcctWindow->CursorPosition(), int(theOffsetY * 8.0)));
283 // ================================================================
284 // Function : onMouseButton
286 // ================================================================
287 void GlfwOcctView::onMouseButton (int theButton, int theAction, int theMods)
289 if (myView.IsNull()) { return; }
291 const Graphic3d_Vec2i aPos = myOcctWindow->CursorPosition();
292 if (theAction == GLFW_PRESS)
294 PressMouseButton (aPos, mouseButtonFromGlfw (theButton), keyFlagsFromGlfw (theMods), false);
298 ReleaseMouseButton (aPos, mouseButtonFromGlfw (theButton), keyFlagsFromGlfw (theMods), false);
302 // ================================================================
303 // Function : onMouseMove
305 // ================================================================
306 void GlfwOcctView::onMouseMove (int thePosX, int thePosY)
308 const Graphic3d_Vec2i aNewPos (thePosX, thePosY);
309 if (!myView.IsNull())
311 UpdateMousePosition (aNewPos, PressedMouseButtons(), LastMouseFlags(), false);