0031056: Samples - update glfw sample to use AIS_ViewController
[occt.git] / samples / glfw / GlfwOcctView.cpp
CommitLineData
9c0787df 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
3818aaca 38namespace
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
9c0787df 76// ================================================================
77// Function : GlfwOcctView
78// Purpose :
79// ================================================================
80GlfwOcctView::GlfwOcctView()
9c0787df 81{
82}
83
84// ================================================================
85// Function : ~GlfwOcctView
86// Purpose :
87// ================================================================
88GlfwOcctView::~GlfwOcctView()
89{
90}
91
92// ================================================================
93// Function : toView
94// Purpose :
95// ================================================================
96GlfwOcctView* GlfwOcctView::toView (GLFWwindow* theWin)
97{
98 return static_cast<GlfwOcctView*>(glfwGetWindowUserPointer (theWin));
99}
100
101// ================================================================
102// Function : errorCallback
103// Purpose :
104// ================================================================
105void 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// ================================================================
114void 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// ================================================================
134void 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// ================================================================
163void 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// ================================================================
188void 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// ================================================================
222void 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 {
3818aaca 232 FlushViewEvents (myContext, myView, true);
9c0787df 233 }
234 }
235}
236
237// ================================================================
238// Function : cleanup
239// Purpose :
240// ================================================================
241void 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// ================================================================
258void 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();
9c0787df 268 }
269}
270
271// ================================================================
272// Function : onMouseScroll
273// Purpose :
274// ================================================================
275void GlfwOcctView::onMouseScroll (double theOffsetX, double theOffsetY)
276{
3818aaca 277 if (!myView.IsNull())
278 {
279 UpdateZoom (Aspect_ScrollDelta (myOcctWindow->CursorPosition(), int(theOffsetY * 8.0)));
280 }
9c0787df 281}
282
283// ================================================================
284// Function : onMouseButton
285// Purpose :
286// ================================================================
287void GlfwOcctView::onMouseButton (int theButton, int theAction, int theMods)
288{
289 if (myView.IsNull()) { return; }
290
291 const Graphic3d_Vec2i aPos = myOcctWindow->CursorPosition();
3818aaca 292 if (theAction == GLFW_PRESS)
9c0787df 293 {
3818aaca 294 PressMouseButton (aPos, mouseButtonFromGlfw (theButton), keyFlagsFromGlfw (theMods), false);
9c0787df 295 }
3818aaca 296 else
9c0787df 297 {
3818aaca 298 ReleaseMouseButton (aPos, mouseButtonFromGlfw (theButton), keyFlagsFromGlfw (theMods), false);
9c0787df 299 }
300}
301
302// ================================================================
303// Function : onMouseMove
304// Purpose :
305// ================================================================
306void GlfwOcctView::onMouseMove (int thePosX, int thePosY)
307{
3818aaca 308 const Graphic3d_Vec2i aNewPos (thePosX, thePosY);
309 if (!myView.IsNull())
9c0787df 310 {
3818aaca 311 UpdateMousePosition (aNewPos, PressedMouseButtons(), LastMouseFlags(), false);
9c0787df 312 }
313}