0030429: Samples - add simple glfw 3D Viewer sample
authormahaidong <13501108114@163.com>
Fri, 18 Jan 2019 08:00:30 +0000 (11:00 +0300)
committerbugmaster <bugmaster@opencascade.com>
Tue, 22 Jan 2019 12:58:32 +0000 (15:58 +0300)
Aspect_DisplayConnection now provides constructor wrapping existing X Display connection.

samples/glfw/CMakeLists.txt [new file with mode: 0644]
samples/glfw/GlfwOcctView.cpp [new file with mode: 0644]
samples/glfw/GlfwOcctView.h [new file with mode: 0644]
samples/glfw/GlfwOcctWindow.cpp [new file with mode: 0644]
samples/glfw/GlfwOcctWindow.h [new file with mode: 0644]
samples/glfw/main.cpp [new file with mode: 0644]
samples/glfw/readme.md [new file with mode: 0644]
src/Aspect/Aspect_DisplayConnection.cxx
src/Aspect/Aspect_DisplayConnection.hxx

diff --git a/samples/glfw/CMakeLists.txt b/samples/glfw/CMakeLists.txt
new file mode 100644 (file)
index 0000000..cc6cc3c
--- /dev/null
@@ -0,0 +1,68 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(glfw-occt-demo)
+
+set(CMAKE_CXX_STANDARD 11)
+set(APP_VERSION_MAJOR 1)
+set(APP_VERSION_MINOR 0)
+set(APP_TARGET glfwocct)
+
+INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR})
+file(GLOB SOURCES
+  *.h
+  *.cpp
+)
+source_group ("Headers" FILES
+  GlfwOcctView.h
+  GlfwOcctWindow.h)
+source_group ("Sources" FILES
+  GlfwOcctView.cpp
+  GlfwOcctWindow.cpp
+  main.cpp)
+
+# OpenGL
+find_package(OpenGL REQUIRED)
+
+# Open CASCADE Technology
+find_package(OpenCASCADE REQUIRED NO_DEFAULT_PATH)
+if (OpenCASCADE_FOUND)
+  message (STATUS "Using OpenCASCADE from \"${OpenCASCADE_DIR}\"" )
+  INCLUDE_DIRECTORIES(${OpenCASCADE_INCLUDE_DIR})
+  LINK_DIRECTORIES(${OpenCASCADE_LIBRARY_DIR})
+else()
+  message (WARNING "Could not find OpenCASCADE, please set OpenCASCADE_DIR variable." )
+  set (OCCT_LIBRARY_DIR)
+  set (OCCT_BIN_DIR)
+endif()
+
+SET(OpenCASCADE_LIBS 
+  TKernel
+  TKService
+  TKV3d
+  TKOpenGl
+  TKBRep
+  TKGeomBase
+  TKGeomAlgo
+  TKG3d
+  TKG2d
+  TKTopAlgo
+  TKPrim
+)
+
+# glfw
+find_package(glfw3 REQUIRED)
+if (glfw3_FOUND)
+  message (STATUS "Using glfw3 ${glfw3_VERSION}" )
+  INCLUDE_DIRECTORIES(${GLFW_INCLUDE_DIRS})
+  LINK_DIRECTORIES(${GLFW_LIBRARY_DIRS})
+else()
+  message (STATUS "glfw3 is not found." )
+endif()
+
+add_executable(${APP_TARGET} ${SOURCES})
+target_link_libraries(
+  ${APP_TARGET}
+  ${OpenCASCADE_LIBS}
+  glfw
+  ${OPENGL_LIBRARIES}
+)
diff --git a/samples/glfw/GlfwOcctView.cpp b/samples/glfw/GlfwOcctView.cpp
new file mode 100644 (file)
index 0000000..5e7c353
--- /dev/null
@@ -0,0 +1,324 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#include "GlfwOcctView.h"
+
+#include <AIS_Shape.hxx>
+#include <Aspect_Handle.hxx>
+#include <Aspect_DisplayConnection.hxx>
+#include <BRepPrimAPI_MakeBox.hxx>
+#include <BRepPrimAPI_MakeCone.hxx>
+#include <Message.hxx>
+#include <Message_Messenger.hxx>
+#include <OpenGl_GraphicDriver.hxx>
+#include <TopAbs_ShapeEnum.hxx>
+
+#include <iostream>
+
+#include <GLFW/glfw3.h>
+
+// ================================================================
+// Function : GlfwOcctView
+// Purpose  :
+// ================================================================
+GlfwOcctView::GlfwOcctView()
+: myCurAction3d (CurAction3d_Nothing),
+  myToRedraw (true)
+{
+}
+
+// ================================================================
+// Function : ~GlfwOcctView
+// Purpose  :
+// ================================================================
+GlfwOcctView::~GlfwOcctView()
+{
+}
+
+// ================================================================
+// Function : toView
+// Purpose  :
+// ================================================================
+GlfwOcctView* GlfwOcctView::toView (GLFWwindow* theWin)
+{
+  return static_cast<GlfwOcctView*>(glfwGetWindowUserPointer (theWin));
+}
+
+// ================================================================
+// Function : errorCallback
+// Purpose  :
+// ================================================================
+void GlfwOcctView::errorCallback (int theError, const char* theDescription)
+{
+  Message::DefaultMessenger()->Send (TCollection_AsciiString ("Error") + theError + ": " + theDescription, Message_Fail);
+}
+
+// ================================================================
+// Function : run
+// Purpose  :
+// ================================================================
+void GlfwOcctView::run()
+{
+  initWindow (800, 600, "glfw occt");
+  initViewer();
+  initDemoScene();
+  if (myView.IsNull())
+  {
+    return;
+  }
+
+  myView->MustBeResized();
+  myOcctWindow->Map();
+  mainloop();
+  cleanup();
+}
+
+// ================================================================
+// Function : initWindow
+// Purpose  :
+// ================================================================
+void GlfwOcctView::initWindow (int theWidth, int theHeight, const char* theTitle)
+{
+  glfwSetErrorCallback (GlfwOcctView::errorCallback);
+  glfwInit();
+  const bool toAskCoreProfile = true;
+  if (toAskCoreProfile)
+  {
+    glfwWindowHint (GLFW_CONTEXT_VERSION_MAJOR, 3);
+    glfwWindowHint (GLFW_CONTEXT_VERSION_MINOR, 3);
+#if defined (__APPLE__)
+    glfwWindowHint (GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+#endif
+    glfwWindowHint (GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+  }
+  myOcctWindow = new GlfwOcctWindow (theWidth, theHeight, theTitle);
+  glfwSetWindowUserPointer       (myOcctWindow->getGlfwWindow(), this);
+  // window callback
+  glfwSetWindowSizeCallback      (myOcctWindow->getGlfwWindow(), GlfwOcctView::onResizeCallback);
+  glfwSetFramebufferSizeCallback (myOcctWindow->getGlfwWindow(), GlfwOcctView::onFBResizeCallback);
+  // mouse callback
+  glfwSetScrollCallback          (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseScrollCallback);
+  glfwSetMouseButtonCallback     (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseButtonCallback);
+  glfwSetCursorPosCallback       (myOcctWindow->getGlfwWindow(), GlfwOcctView::onMouseMoveCallback);
+}
+
+// ================================================================
+// Function : initViewer
+// Purpose  :
+// ================================================================
+void GlfwOcctView::initViewer()
+{
+  if (myOcctWindow.IsNull()
+   || myOcctWindow->getGlfwWindow() == nullptr)
+  {
+    return;
+  }
+
+  Handle(OpenGl_GraphicDriver) aGraphicDriver = new OpenGl_GraphicDriver (myOcctWindow->GetDisplay(), false);
+  Handle(V3d_Viewer) aViewer = new V3d_Viewer (aGraphicDriver);
+  aViewer->SetDefaultLights();
+  aViewer->SetLightOn();
+  aViewer->SetDefaultTypeOfView (V3d_PERSPECTIVE);
+  aViewer->ActivateGrid (Aspect_GT_Rectangular, Aspect_GDM_Lines);
+  myView = aViewer->CreateView();
+  myView->SetImmediateUpdate (false);
+  myView->SetWindow (myOcctWindow, myOcctWindow->NativeGlContext());
+  myView->ChangeRenderingParams().ToShowStats = true;
+  myContext = new AIS_InteractiveContext (aViewer);
+}
+
+// ================================================================
+// Function : initDemoScene
+// Purpose  :
+// ================================================================
+void GlfwOcctView::initDemoScene()
+{
+  if (myContext.IsNull())
+  {
+    return;
+  }
+
+  myView->TriedronDisplay (Aspect_TOTP_LEFT_LOWER, Quantity_NOC_GOLD, 0.08, V3d_WIREFRAME);
+
+  gp_Ax2 anAxis;
+  anAxis.SetLocation (gp_Pnt (0.0, 0.0, 0.0));
+  Handle(AIS_Shape) aBox = new AIS_Shape (BRepPrimAPI_MakeBox (anAxis, 50, 50, 50).Shape());
+  myContext->Display (aBox, AIS_Shaded, 0, false);
+  anAxis.SetLocation (gp_Pnt (25.0, 125.0, 0.0));
+  Handle(AIS_Shape) aCone = new AIS_Shape (BRepPrimAPI_MakeCone (anAxis, 25, 0, 50).Shape());
+  myContext->Display (aCone, AIS_Shaded, 0, false);
+
+  TCollection_AsciiString aGlInfo;
+  {
+    TColStd_IndexedDataMapOfStringString aRendInfo;
+    myView->DiagnosticInformation (aRendInfo, Graphic3d_DiagnosticInfo_Basic);
+    for (TColStd_IndexedDataMapOfStringString::Iterator aValueIter (aRendInfo); aValueIter.More(); aValueIter.Next())
+    {
+      if (!aGlInfo.IsEmpty()) { aGlInfo += "\n"; }
+      aGlInfo += TCollection_AsciiString("  ") + aValueIter.Key() + ": " + aValueIter.Value();
+    }
+  }
+  Message::DefaultMessenger()->Send (TCollection_AsciiString("OpenGL info:\n") + aGlInfo, Message_Info);
+}
+
+// ================================================================
+// Function : mainloop
+// Purpose  :
+// ================================================================
+void GlfwOcctView::mainloop()
+{
+  while (!glfwWindowShouldClose (myOcctWindow->getGlfwWindow()))
+  {
+    // glfwPollEvents() for continuous rendering (immediate return if there are no new events)
+    // and glfwWaitEvents() for rendering on demand (something actually happened in the viewer)
+    //glfwPollEvents();
+    glfwWaitEvents();
+    if (!myView.IsNull())
+    {
+      if (myView->IsInvalidated())
+      {
+        myView->Redraw();
+      }
+      else if (myToRedraw)
+      {
+        myView->RedrawImmediate();
+      }
+      myToRedraw = false;
+    }
+  }
+}
+
+// ================================================================
+// Function : cleanup
+// Purpose  :
+// ================================================================
+void GlfwOcctView::cleanup()
+{
+  if (!myView.IsNull())
+  {
+    myView->Remove();
+  }
+  if (!myOcctWindow.IsNull())
+  {
+    myOcctWindow->Close();
+  }
+  glfwTerminate();
+}
+
+// ================================================================
+// Function : onResize
+// Purpose  :
+// ================================================================
+void GlfwOcctView::onResize (int theWidth, int theHeight)
+{
+  if (theWidth  != 0
+   && theHeight != 0
+   && !myView.IsNull())
+  {
+    myView->Window()->DoResize();
+    myView->MustBeResized();
+    myView->Invalidate();
+    myView->Redraw();
+    //myToRedraw = true;
+  }
+}
+
+// ================================================================
+// Function : onMouseScroll
+// Purpose  :
+// ================================================================
+void GlfwOcctView::onMouseScroll (double theOffsetX, double theOffsetY)
+{
+  if (myView.IsNull()) { return; }
+
+  const Graphic3d_Vec2i aPos = myOcctWindow->CursorPosition();
+  myView->StartZoomAtPoint (aPos.x(), aPos.y());
+  myView->ZoomAtPoint (0, 0, int(theOffsetY * 4.0), int(theOffsetY * 4.0));
+  myView->Invalidate();
+  myToRedraw = true;
+}
+
+// ================================================================
+// Function : onMouseButton
+// Purpose  :
+// ================================================================
+void GlfwOcctView::onMouseButton (int theButton, int theAction, int theMods)
+{
+  if (myView.IsNull()) { return; }
+
+  const Graphic3d_Vec2i aPos = myOcctWindow->CursorPosition();
+  if (theAction != GLFW_PRESS)
+  {
+    myCurAction3d = CurAction3d_Nothing;
+    return;
+  }
+
+  myMouseMin = aPos;
+  myMouseMax = aPos;
+  switch (theButton)
+  {
+    case GLFW_MOUSE_BUTTON_RIGHT:
+    {
+      myCurAction3d = CurAction3d_DynamicRoation;
+      myView->StartRotation (aPos.x(), aPos.y());
+      break;
+    }
+    case GLFW_MOUSE_BUTTON_MIDDLE:
+    {
+      myCurAction3d = CurAction3d_DynamicPanning;
+      break;
+    }
+  }
+}
+
+// ================================================================
+// Function : onMouseMove
+// Purpose  :
+// ================================================================
+void GlfwOcctView::onMouseMove (int thePosX, int thePosY)
+{
+  if (myView.IsNull()) { return; }
+
+  switch (myCurAction3d)
+  {
+    case CurAction3d_DynamicRoation:
+    {
+      myView->Rotation (thePosX, thePosY);
+      myView->Invalidate();
+      myToRedraw = true;
+      break;
+    }
+    case CurAction3d_DynamicPanning:
+    {
+      myView->Pan (thePosX - myMouseMax.x(), -(thePosY - myMouseMax.y()));
+      myView->Invalidate();
+      myToRedraw = true;
+      myMouseMax.SetValues (thePosX, thePosY);
+      break;
+    }
+    default:
+    {
+      myContext->MoveTo (thePosX, thePosY, myView, false);
+      myToRedraw = true;
+      break;
+    }
+  }
+}
diff --git a/samples/glfw/GlfwOcctView.h b/samples/glfw/GlfwOcctView.h
new file mode 100644 (file)
index 0000000..3abe268
--- /dev/null
@@ -0,0 +1,125 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#ifndef _GlfwOcctView_Header
+#define _GlfwOcctView_Header
+
+#include "GlfwOcctWindow.h"
+
+#include <AIS_InteractiveContext.hxx>
+#include <V3d_View.hxx>
+
+//! Sample class creating 3D Viewer within GLFW window.
+class GlfwOcctView
+{
+public:
+  enum CurAction3d
+  {
+    CurAction3d_Nothing,
+    CurAction3d_DynamicZooming,
+    CurAction3d_DynamicPanning,
+    CurAction3d_DynamicRoation
+  };
+
+public:
+  //! Default constructor.
+       GlfwOcctView();
+
+  //! Destructor.
+       ~GlfwOcctView();
+
+  //! Main application entry point.
+  void run();
+
+private:
+
+  //! Create GLFW window.
+  void initWindow (int theWidth, int theHeight, const char* theTitle);
+
+  //! Create 3D Viewer.
+  void initViewer();
+
+  //! Fill 3D Viewer with a DEMO items.
+  void initDemoScene();
+
+  //! Application event loop.
+  void mainloop();
+
+  //! Clean up before .
+  void cleanup();
+
+//! @name GLWF callbacks
+private:
+  //! Window resize event.
+  void onResize (int theWidth, int theHeight);
+
+  //! Mouse scroll event.
+  void onMouseScroll (double theOffsetX, double theOffsetY);
+
+  //! Mouse click event.
+  void onMouseButton (int theButton, int theAction, int theMods);
+
+  //! Mouse move event.
+  void onMouseMove (int thePosX, int thePosY);
+
+//! @name GLWF callbacks (static functions)
+private:
+
+  //! GLFW callback redirecting messages into Message::DefaultMessenger().
+  static void errorCallback (int theError, const char* theDescription);
+
+  //! Wrapper for glfwGetWindowUserPointer() returning this class instance.
+  static GlfwOcctView* toView (GLFWwindow* theWin);
+
+  //! Window resize callback.
+  static void onResizeCallback (GLFWwindow* theWin, int theWidth, int theHeight)
+  { toView(theWin)->onResize (theWidth, theHeight); }
+
+  //! Frame-buffer resize callback.
+  static void onFBResizeCallback (GLFWwindow* theWin, int theWidth, int theHeight)
+  { toView(theWin)->onResize (theWidth, theHeight); }
+
+  //! Mouse scroll callback.
+  static void onMouseScrollCallback (GLFWwindow* theWin, double theOffsetX, double theOffsetY)
+  { toView(theWin)->onMouseScroll (theOffsetX, theOffsetY); }
+
+  //! Mouse click callback.
+  static void onMouseButtonCallback (GLFWwindow* theWin, int theButton, int theAction, int theMods)
+  { toView(theWin)->onMouseButton (theButton, theAction, theMods); }
+
+  //! Mouse move callback.
+  static void onMouseMoveCallback (GLFWwindow* theWin, double thePosX, double thePosY)
+  { toView(theWin)->onMouseMove ((int )thePosX, (int )thePosY); }
+
+private:
+
+  Handle(GlfwOcctWindow) myOcctWindow;
+  Handle(V3d_View) myView;
+  Handle(AIS_InteractiveContext) myContext;
+
+  CurAction3d myCurAction3d;
+  Graphic3d_Vec2i myMouseMin;
+  Graphic3d_Vec2i myMouseMax;
+  bool myToRedraw;
+
+};
+
+#endif // _GlfwOcctView_Header
diff --git a/samples/glfw/GlfwOcctWindow.cpp b/samples/glfw/GlfwOcctWindow.cpp
new file mode 100644 (file)
index 0000000..20a3d48
--- /dev/null
@@ -0,0 +1,161 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#include "GlfwOcctWindow.h"
+
+#if defined (__APPLE__)
+  #undef Handle // avoid name collisions in macOS headers
+  #define GLFW_EXPOSE_NATIVE_COCOA
+  #define GLFW_EXPOSE_NATIVE_NSGL
+#elif defined (_WIN32)
+  #define GLFW_EXPOSE_NATIVE_WIN32
+  #define GLFW_EXPOSE_NATIVE_WGL
+#else
+  #define GLFW_EXPOSE_NATIVE_X11
+  #define GLFW_EXPOSE_NATIVE_GLX
+#endif
+#include <GLFW/glfw3.h>
+#include <GLFW/glfw3native.h>
+
+// ================================================================
+// Function : GlfwOcctWindow
+// Purpose  :
+// ================================================================
+GlfwOcctWindow::GlfwOcctWindow (int theWidth, int theHeight, const TCollection_AsciiString& theTitle)
+: myGlfwWindow (glfwCreateWindow (theWidth, theHeight, theTitle.ToCString(), NULL, NULL)),
+  myXLeft  (0),
+  myYTop   (0),
+  myXRight (0),
+  myYBottom(0)
+{
+  if (myGlfwWindow != nullptr)
+  {
+    int aWidth = 0, aHeight = 0;
+    glfwGetWindowPos (myGlfwWindow, &myXLeft, &myYTop);
+    glfwGetWindowSize(myGlfwWindow, &aWidth, &aHeight);
+    myXRight  = myXLeft + aWidth;
+    myYBottom = myYTop + aHeight;
+
+  #if !defined(_WIN32) && !defined(__APPLE__)
+    myDisplay = new Aspect_DisplayConnection (glfwGetX11Display());
+  #endif
+  }
+}
+
+// ================================================================
+// Function : Close
+// Purpose  :
+// ================================================================
+void GlfwOcctWindow::Close()
+{
+  if (myGlfwWindow != nullptr)
+  {
+    glfwDestroyWindow (myGlfwWindow);
+    myGlfwWindow = nullptr;
+  }
+}
+
+// ================================================================
+// Function : NativeHandle
+// Purpose  :
+// ================================================================
+Aspect_Drawable GlfwOcctWindow::NativeHandle() const
+{
+#if defined (__APPLE__)
+  return (Aspect_Drawable)glfwGetCocoaWindow (myGlfwWindow);
+#elif defined (_WIN32)
+  return (Aspect_Drawable)glfwGetWin32Window (myGlfwWindow);
+#else
+  return (Aspect_Drawable)glfwGetX11Window (myGlfwWindow);
+#endif
+}
+
+// ================================================================
+// Function : NativeGlContext
+// Purpose  :
+// ================================================================
+Aspect_RenderingContext GlfwOcctWindow::NativeGlContext() const
+{
+#if defined (__APPLE__)
+  return (NSOpenGLContext*)glfwGetNSGLContext (myGlfwWindow);
+#elif defined (_WIN32)
+  return glfwGetWGLContext (myGlfwWindow);
+#else
+  return glfwGetGLXContext (myGlfwWindow);
+#endif
+}
+
+// ================================================================
+// Function : IsMapped
+// Purpose  :
+// ================================================================
+Standard_Boolean GlfwOcctWindow::IsMapped() const
+{
+  return glfwGetWindowAttrib (myGlfwWindow, GLFW_VISIBLE) != 0;
+}
+
+// ================================================================
+// Function : Map
+// Purpose  :
+// ================================================================
+void GlfwOcctWindow::Map() const
+{
+  glfwShowWindow (myGlfwWindow);
+}
+
+// ================================================================
+// Function : Unmap
+// Purpose  :
+// ================================================================
+void GlfwOcctWindow::Unmap() const
+{
+  glfwHideWindow (myGlfwWindow);
+}
+
+// ================================================================
+// Function : DoResize
+// Purpose  :
+// ================================================================
+Aspect_TypeOfResize GlfwOcctWindow::DoResize() const
+{
+  if (glfwGetWindowAttrib (myGlfwWindow, GLFW_VISIBLE) == 1)
+  {
+    int anXPos = 0, anYPos = 0, aWidth = 0, aHeight = 0;
+    glfwGetWindowPos (myGlfwWindow, &anXPos, &anYPos);
+    glfwGetWindowSize(myGlfwWindow, &aWidth, &aHeight);
+    *const_cast<Standard_Integer*>(&myXLeft  ) = anXPos;
+    *const_cast<Standard_Integer*>(&myXRight ) = anXPos + aWidth;
+    *const_cast<Standard_Integer*>(&myYTop   ) = anYPos;
+    *const_cast<Standard_Integer*>(&myYBottom) = anYPos + aHeight;
+  }
+  return Aspect_TOR_UNKNOWN;
+}
+
+// ================================================================
+// Function : CursorPosition
+// Purpose  :
+// ================================================================
+Graphic3d_Vec2i GlfwOcctWindow::CursorPosition() const
+{
+  Graphic3d_Vec2d aPos;
+  glfwGetCursorPos (myGlfwWindow, &aPos.x(), &aPos.y());
+  return Graphic3d_Vec2i ((int )aPos.x(), (int )aPos.y());
+}
diff --git a/samples/glfw/GlfwOcctWindow.h b/samples/glfw/GlfwOcctWindow.h
new file mode 100644 (file)
index 0000000..9d61dac
--- /dev/null
@@ -0,0 +1,115 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#ifndef _GlfwOcctWindow_Header
+#define _GlfwOcctWindow_Header
+
+#include <Aspect_DisplayConnection.hxx>
+#include <Aspect_RenderingContext.hxx>
+#include <Aspect_Window.hxx>
+#include <Graphic3d_Vec.hxx>
+#include <TCollection_AsciiString.hxx>
+
+struct GLFWwindow;
+
+//! GLFWwindow wrapper implementing Aspect_Window interface.
+class GlfwOcctWindow : public Aspect_Window
+{
+  DEFINE_STANDARD_RTTI_INLINE(GlfwOcctWindow, Aspect_Window)
+public:
+  //! Main constructor.
+  GlfwOcctWindow (int theWidth, int theHeight, const TCollection_AsciiString& theTitle);
+
+  //! Close the window.
+  virtual ~GlfwOcctWindow() { Close(); }
+
+  //! Close the window.
+  void Close();
+
+  //! Return X Display connection.
+  const Handle(Aspect_DisplayConnection)& GetDisplay() const { return myDisplay; }
+
+  //! Return GLFW window.
+  GLFWwindow* getGlfwWindow() { return myGlfwWindow; }
+
+  //! Return native OpenGL context.
+  Aspect_RenderingContext NativeGlContext() const;
+
+  //! Return cursor position.
+  Graphic3d_Vec2i CursorPosition() const;
+
+public:
+
+  //! Returns native Window handle
+  virtual Aspect_Drawable NativeHandle() const Standard_OVERRIDE;
+
+  //! Returns parent of native Window handle.
+  virtual Aspect_Drawable NativeParentHandle() const Standard_OVERRIDE { return 0; }
+
+  //! Applies the resizing to the window <me>
+  virtual Aspect_TypeOfResize DoResize() const Standard_OVERRIDE;
+
+  //! Returns True if the window <me> is opened and False if the window is closed.
+  virtual Standard_Boolean IsMapped() const Standard_OVERRIDE;
+
+  //! Apply the mapping change to the window <me> and returns TRUE if the window is mapped at screen.
+  virtual Standard_Boolean DoMapping() const Standard_OVERRIDE { return Standard_True; }
+
+  //! Opens the window <me>.
+  virtual void Map() const Standard_OVERRIDE;
+
+  //! Closes the window <me>.
+  virtual void Unmap() const Standard_OVERRIDE;
+
+  virtual void Position (Standard_Integer& theX1, Standard_Integer& theY1,
+                         Standard_Integer& theX2, Standard_Integer& theY2) const Standard_OVERRIDE
+  {
+    theX1 = myXLeft;
+    theX2 = myXRight;
+    theY1 = myYTop;
+    theY2 = myYBottom;
+  }
+
+  //! Returns The Window RATIO equal to the physical WIDTH/HEIGHT dimensions.
+  virtual Standard_Real Ratio() const Standard_OVERRIDE
+  {
+    return Standard_Real (myXRight - myXLeft) / Standard_Real (myYBottom - myYTop);
+  }
+
+  //! Return window size.
+  virtual void Size (Standard_Integer& theWidth, Standard_Integer& theHeight) const Standard_OVERRIDE
+  {
+    theWidth  = myXRight - myXLeft;
+    theHeight = myYBottom - myYTop;
+  }
+
+  virtual Aspect_FBConfig NativeFBConfig() const Standard_OVERRIDE { return NULL; }
+
+protected:
+  Handle(Aspect_DisplayConnection) myDisplay;
+  GLFWwindow*      myGlfwWindow;
+  Standard_Integer myXLeft;
+  Standard_Integer myYTop;
+  Standard_Integer myXRight;
+  Standard_Integer myYBottom;
+};
+
+#endif // _GlfwOcctWindow_Header
diff --git a/samples/glfw/main.cpp b/samples/glfw/main.cpp
new file mode 100644 (file)
index 0000000..9632eab
--- /dev/null
@@ -0,0 +1,37 @@
+// Copyright (c) 2019 OPEN CASCADE SAS
+//
+// This file is part of the examples of the Open CASCADE Technology software library.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy
+// of this software and associated documentation files (the "Software"), to deal
+// in the Software without restriction, including without limitation the rights
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the Software is
+// furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all
+// copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE
+
+#include "GlfwOcctView.h"
+
+int main (int, char**)
+{
+  GlfwOcctView anApp;
+  try
+  {
+    anApp.run();
+  }
+  catch (const std::runtime_error& theError)
+  {
+    std::cerr << theError.what() << std::endl;
+    return EXIT_FAILURE;
+  }
+  return 0;
+}
diff --git a/samples/glfw/readme.md b/samples/glfw/readme.md
new file mode 100644 (file)
index 0000000..39c1cef
--- /dev/null
@@ -0,0 +1,4 @@
+A sample demonstrating usage of OCCT 3D Viewer within a window created using GLFW.
+
+Platforms: Windows, macOS, Linux
+Required: glfw
index e119a7a..1d5a53b 100755 (executable)
@@ -26,9 +26,11 @@ IMPLEMENT_STANDARD_RTTIEXT(Aspect_DisplayConnection,Standard_Transient)
 Aspect_DisplayConnection::Aspect_DisplayConnection()
 {
 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
+  myDisplay = NULL;
+  myIsOwnDisplay = false;
   OSD_Environment anEnv ("DISPLAY");
   myDisplayName = anEnv.Value();
-  Init();
+  Init (NULL);
 #endif
 }
 
@@ -39,7 +41,8 @@ Aspect_DisplayConnection::Aspect_DisplayConnection()
 Aspect_DisplayConnection::~Aspect_DisplayConnection()
 {
 #if !defined(_WIN32) && (!defined(__APPLE__) || defined(MACOSX_USE_GLX)) && !defined(__ANDROID__) && !defined(__QNX__)
-  if (myDisplay != NULL)
+  if (myDisplay != NULL
+   && myIsOwnDisplay)
   {
     XCloseDisplay (myDisplay);
   }
@@ -52,38 +55,39 @@ Aspect_DisplayConnection::~Aspect_DisplayConnection()
 // purpose  :
 // =======================================================================
 Aspect_DisplayConnection::Aspect_DisplayConnection (const TCollection_AsciiString& theDisplayName)
+: myDisplay (NULL),
+  myIsOwnDisplay (false)
 {
   myDisplayName = theDisplayName;
-  Init();
+  Init (NULL);
 }
 
 // =======================================================================
-// function : GetDisplay
-// purpose  :
-// =======================================================================
-Display* Aspect_DisplayConnection::GetDisplay()
-{
-  return myDisplay;
-}
-
-// =======================================================================
-// function : GetDisplayName
+// function : Aspect_DisplayConnection
 // purpose  :
 // =======================================================================
-TCollection_AsciiString Aspect_DisplayConnection::GetDisplayName()
+Aspect_DisplayConnection::Aspect_DisplayConnection (Display* theDisplay)
+: myDisplay (NULL),
+  myIsOwnDisplay (false)
 {
-  return myDisplayName;
+  Init (theDisplay);
 }
 
 // =======================================================================
 // function : Init
 // purpose  :
 // =======================================================================
-void Aspect_DisplayConnection::Init()
+void Aspect_DisplayConnection::Init (Display* theDisplay)
 {
-  myDisplay = XOpenDisplay (myDisplayName.ToCString());
-  myAtoms.Bind (Aspect_XA_DELETE_WINDOW, XInternAtom(myDisplay, "WM_DELETE_WINDOW", False));
-  
+  if (myDisplay != NULL
+   && myIsOwnDisplay)
+  {
+    XCloseDisplay (myDisplay);
+  }
+  myIsOwnDisplay = false;
+  myAtoms.Clear();
+
+  myDisplay = theDisplay != NULL ? theDisplay : XOpenDisplay (myDisplayName.ToCString());
   if (myDisplay == NULL)
   {
     TCollection_AsciiString aMessage;
@@ -91,6 +95,11 @@ void Aspect_DisplayConnection::Init()
     aMessage += myDisplayName + "\"";
     throw Aspect_DisplayConnectionDefinitionError(aMessage.ToCString());
   }
+  else
+  {
+    myIsOwnDisplay = theDisplay == NULL;
+    myAtoms.Bind (Aspect_XA_DELETE_WINDOW, XInternAtom(myDisplay, "WM_DELETE_WINDOW", False));
+  }
 }
 
 // =======================================================================
index d2080a7..1377495 100755 (executable)
@@ -47,25 +47,37 @@ public:
   //! screen_number - Specifies the screen to be used on that server. Optional variable.
   Aspect_DisplayConnection (const TCollection_AsciiString& theDisplayName);
 
+  //! Constructor wrapping existing Display instance.
+  //! WARNING! it is a responsibility of application to keep this pointer
+  //! valid while Aspect_DisplayConnection is alive and to close Display when it is no more needed.
+  Aspect_DisplayConnection (Display* theDisplay);
+
   //! @return pointer to Display structure that serves as the connection to the X server.
-  Display* GetDisplay();
-  
+  Display* GetDisplay() { return myDisplay; }
+
+  //! @return TRUE if X Display has been allocated by this class
+  Standard_Boolean IsOwnDisplay() const { return myIsOwnDisplay; }
+
   //! @return identifier(atom) for custom named property associated with windows that use current connection to X server.
   Atom GetAtom (const Aspect_XAtom theAtom) const;
 
   //! @return display name for this connection.
-  TCollection_AsciiString GetDisplayName();
-
-private:
+  const TCollection_AsciiString& GetDisplayName() { return myDisplayName; }
 
-  //! Open connection with display specified in myDisplayName class field.
-  void Init();
+  //! Open connection with display specified in myDisplayName class field
+  //! or takes theDisplay parameter when it is not NULL.
+  //! WARNING! When external Display is specified, it is a responsibility of application
+  //! to keep this pointer valid while Aspect_DisplayConnection is alive
+  //! and to close Display when it is no more needed.
+  //! @param theDisplay external pointer to allocated Display, or NULL if new connection should be created
+  void Init (Display* theDisplay);
 
 private:
 
   Display*                 myDisplay;
   NCollection_DataMap<Aspect_XAtom, Atom> myAtoms;
   TCollection_AsciiString  myDisplayName;
+  Standard_Boolean         myIsOwnDisplay;
 #endif
 
 private: