目录
1、编写代码
Viewer.h
Viewer.cpp
ViewerInteractor.h
ViewerInteractor.cpp
helloworld.cpp
2、配置
3、编译运行
1、编写代码
Viewer.h
#pragma once
#ifdef _WIN32
#include <Windows.h>
#endif
// Local includes
#include "ViewerInteractor.h"
// OpenCascade includes
#include <TopoDS_Shape.hxx>
#include <WNT_Window.hxx>
// Standard includes
#include <vector>
class V3d_Viewer;
class V3d_View;
class AIS_InteractiveContext;
class AIS_ViewController;
//-----------------------------------------------------------------------------
//! Simple 3D viewer.
class Viewer
{
public:
Viewer(const int left,
const int top,
const int width,
const int height);
public:
Viewer& operator<<(const TopoDS_Shape& shape)
{
this->AddShape(shape);
return *this;
}
void AddShape(const TopoDS_Shape& shape);
void StartMessageLoop();
private:
static LRESULT WINAPI
wndProcProxy(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam);
LRESULT CALLBACK
wndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam);
void init(const HANDLE& windowHandle);
/* API-related things */
private:
std::vector<TopoDS_Shape> m_shapes; //!< Shapes to visualize.
/* OpenCascade's things */
private:
Handle(V3d_Viewer) m_viewer;
Handle(V3d_View) m_view;
Handle(AIS_InteractiveContext) m_context;
Handle(WNT_Window) m_wntWindow;
Handle(ViewerInteractor) m_evtMgr;
/* Lower-level things */
private:
HINSTANCE m_hInstance; //!< Handle to the instance of the module.
HWND m_hWnd; //!< Handle to the instance of the window.
bool m_bQuit; //!< Indicates whether user want to quit from window.
};
Viewer.cpp
// Own include
#include "Viewer.h"
// OpenCascade includes
#include <AIS_InteractiveContext.hxx>
#include <AIS_Shape.hxx>
#include <Aspect_DisplayConnection.hxx>
#include <Aspect_Handle.hxx>
#include <OpenGl_GraphicDriver.hxx>
#include <V3d_AmbientLight.hxx>
#include <V3d_DirectionalLight.hxx>
#include <V3d_View.hxx>
#include <V3d_Viewer.hxx>
namespace {
//! Adjust the style of local selection.
//! \param[in] context the AIS context.
void AdjustSelectionStyle(const Handle(AIS_InteractiveContext)& context)
{
// Initialize style for sub-shape selection.
Handle(Prs3d_Drawer) selDrawer = new Prs3d_Drawer;
//
selDrawer->SetLink(context->DefaultDrawer());
selDrawer->SetFaceBoundaryDraw(true);
selDrawer->SetDisplayMode(1); // Shaded
selDrawer->SetTransparency(0.5f);
selDrawer->SetZLayer(Graphic3d_ZLayerId_Topmost);
selDrawer->SetColor(Quantity_NOC_GOLD);
selDrawer->SetBasicFillAreaAspect(new Graphic3d_AspectFillArea3d());
// Adjust fill area aspect.
const Handle(Graphic3d_AspectFillArea3d)&
fillArea = selDrawer->BasicFillAreaAspect();
//
fillArea->SetInteriorColor(Quantity_NOC_GOLD);
fillArea->SetBackInteriorColor(Quantity_NOC_GOLD);
//
fillArea->ChangeFrontMaterial().SetMaterialName(Graphic3d_NOM_NEON_GNC);
fillArea->ChangeFrontMaterial().SetTransparency(0.4f);
fillArea->ChangeBackMaterial().SetMaterialName(Graphic3d_NOM_NEON_GNC);
fillArea->ChangeBackMaterial().SetTransparency(0.4f);
selDrawer->UnFreeBoundaryAspect()->SetWidth(1.0);
// Update AIS context.
context->SetHighlightStyle(Prs3d_TypeOfHighlight_LocalSelected, selDrawer);
}
}
//-----------------------------------------------------------------------------
Viewer::Viewer(const int left,
const int top,
const int width,
const int height)
: m_hWnd(NULL),
m_bQuit(false)
{
// Register the window class once
static HINSTANCE APP_INSTANCE = NULL;
if (APP_INSTANCE == NULL)
{
APP_INSTANCE = GetModuleHandleW(NULL);
m_hInstance = APP_INSTANCE;
WNDCLASSW WC;
WC.cbClsExtra = 0;
WC.cbWndExtra = 0;
WC.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
WC.hCursor = LoadCursor(NULL, IDC_ARROW);
WC.hIcon = LoadIcon(NULL, IDI_APPLICATION);
WC.hInstance = APP_INSTANCE;
WC.lpfnWndProc = (WNDPROC)wndProcProxy;
WC.lpszClassName = L"OpenGLClass";
WC.lpszMenuName = 0;
WC.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
if (!RegisterClassW(&WC))
{
return;
}
}
// Set coordinates for window's area rectangle.
RECT Rect;
SetRect(&Rect,
left, top,
left + width, top + height);
// Adjust window rectangle.
AdjustWindowRect(&Rect, WS_OVERLAPPEDWINDOW, false);
// Create window.
m_hWnd = CreateWindow(L"OpenGLClass",
L"Quaoar >>> 3D",
WS_OVERLAPPEDWINDOW,
Rect.left, Rect.top, // Adjusted x, y positions
Rect.right - Rect.left, Rect.bottom - Rect.top, // Adjusted width and height
NULL, NULL,
m_hInstance,
this);
// Check if window has been created successfully.
if (m_hWnd == NULL)
{
return;
}
// Show window finally.
ShowWindow(m_hWnd, TRUE);
HANDLE windowHandle = (HANDLE)m_hWnd;
this->init(windowHandle);
}
//-----------------------------------------------------------------------------
void Viewer::AddShape(const TopoDS_Shape& shape)
{
m_shapes.push_back(shape);
}
//-----------------------------------------------------------------------------
//! Starts message loop.
void Viewer::StartMessageLoop()
{
for (auto sh : m_shapes)
{
Handle(AIS_Shape) shape = new AIS_Shape(sh);
m_context->Display(shape, true);
m_context->SetDisplayMode(shape, AIS_Shaded, true);
// Adjust selection style.
::AdjustSelectionStyle(m_context);
// Activate selection modes.
m_context->Activate(4, true); // faces
m_context->Activate(2, true); // edges
}
MSG Msg;
while (!m_bQuit)
{
switch (::MsgWaitForMultipleObjectsEx(0, NULL, 12, QS_ALLINPUT, 0))
{
case WAIT_OBJECT_0:
{
while (::PeekMessage(&Msg, NULL, 0, 0, PM_REMOVE))
{
if (Msg.message == WM_QUIT)
m_bQuit = true;// return;
::TranslateMessage(&Msg);
::DispatchMessage(&Msg);
}
}
}
}
}
//-----------------------------------------------------------------------------
void Viewer::init(const HANDLE& windowHandle)
{
static Handle(Aspect_DisplayConnection) displayConnection;
//
if (displayConnection.IsNull())
displayConnection = new Aspect_DisplayConnection();
HWND winHandle = (HWND)windowHandle;
//
if (winHandle == NULL)
return;
// Create OCCT viewer.
Handle(OpenGl_GraphicDriver)
graphicDriver = new OpenGl_GraphicDriver(displayConnection, false);
m_viewer = new V3d_Viewer(graphicDriver);
// Lightning.
Handle(V3d_DirectionalLight) LightDir = new V3d_DirectionalLight(V3d_Zneg, Quantity_Color(Quantity_NOC_GRAY97), 1);
Handle(V3d_AmbientLight) LightAmb = new V3d_AmbientLight();
//
LightDir->SetDirection(1.0, -2.0, -10.0);
//
m_viewer->AddLight(LightDir);
m_viewer->AddLight(LightAmb);
m_viewer->SetLightOn(LightDir);
m_viewer->SetLightOn(LightAmb);
// AIS context.
m_context = new AIS_InteractiveContext(m_viewer);
// Configure some global props.
const Handle(Prs3d_Drawer)& contextDrawer = m_context->DefaultDrawer();
//
if (!contextDrawer.IsNull())
{
const Handle(Prs3d_ShadingAspect)& SA = contextDrawer->ShadingAspect();
const Handle(Graphic3d_AspectFillArea3d)& FA = SA->Aspect();
contextDrawer->SetFaceBoundaryDraw(true); // Draw edges.
FA->SetEdgeOff();
// Fix for inifinite lines has been reduced to 1000 from its default value 500000.
contextDrawer->SetMaximalParameterValue(1000);
}
// Main view creation.
m_view = m_viewer->CreateView();
m_view->SetImmediateUpdate(false);
// Event manager is constructed when both contex and view become available.
m_evtMgr = new ViewerInteractor(m_view, m_context);
// Aspect window creation
m_wntWindow = new WNT_Window(winHandle);
m_view->SetWindow(m_wntWindow, nullptr);
//
if (!m_wntWindow->IsMapped())
{
m_wntWindow->Map();
}
m_view->MustBeResized();
// View settings.
m_view->SetShadingModel(V3d_PHONG);
// Configure rendering parameters
Graphic3d_RenderingParams& RenderParams = m_view->ChangeRenderingParams();
RenderParams.IsAntialiasingEnabled = true;
RenderParams.NbMsaaSamples = 8; // Anti-aliasing by multi-sampling
RenderParams.IsShadowEnabled = false;
RenderParams.CollectedStats = Graphic3d_RenderingParams::PerfCounters_NONE;
}
//-----------------------------------------------------------------------------
LRESULT WINAPI Viewer::wndProcProxy(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
if (message == WM_CREATE)
{
// Save pointer to our class instance (sent on window create) to window storage.
CREATESTRUCTW* pCreateStruct = (CREATESTRUCTW*)lparam;
SetWindowLongPtr(hwnd, int(GWLP_USERDATA), (LONG_PTR)pCreateStruct->lpCreateParams);
}
// Get pointer to our class instance.
Viewer* pThis = (Viewer*)GetWindowLongPtr(hwnd, int(GWLP_USERDATA));
return (pThis != NULL) ? pThis->wndProc(hwnd, message, wparam, lparam)
: DefWindowProcW(hwnd, message, wparam, lparam);
}
//-----------------------------------------------------------------------------
//! Window procedure.
LRESULT Viewer::wndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam)
{
if (m_view.IsNull())
return DefWindowProc(hwnd, message, wparam, lparam);
switch (message)
{
case WM_PAINT:
{
PAINTSTRUCT aPaint;
BeginPaint(m_hWnd, &aPaint);
EndPaint(m_hWnd, &aPaint);
m_evtMgr->ProcessExpose();
break;
}
case WM_SIZE:
{
m_evtMgr->ProcessConfigure();
break;
}
case WM_MOVE:
case WM_MOVING:
case WM_SIZING:
{
switch (m_view->RenderingParams().StereoMode)
{
case Graphic3d_StereoMode_RowInterlaced:
case Graphic3d_StereoMode_ColumnInterlaced:
case Graphic3d_StereoMode_ChessBoard:
{
// track window moves to reverse stereo pair
m_view->MustBeResized();
m_view->Update();
break;
}
default:
break;
}
break;
}
case WM_KEYUP:
case WM_KEYDOWN:
{
const Aspect_VKey vkey = WNT_Window::VirtualKeyFromNative((int)wparam);
//
if (vkey != Aspect_VKey_UNKNOWN)
{
const double timeStamp = m_evtMgr->EventTime();
if (message == WM_KEYDOWN)
{
m_evtMgr->KeyDown(vkey, timeStamp);
}
else
{
m_evtMgr->KeyUp(vkey, timeStamp);
}
}
break;
}
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
{
const Graphic3d_Vec2i pos(LOWORD(lparam), HIWORD(lparam));
const Aspect_VKeyFlags flags = WNT_Window::MouseKeyFlagsFromEvent(wparam);
Aspect_VKeyMouse button = Aspect_VKeyMouse_NONE;
//
switch (message)
{
case WM_LBUTTONUP:
case WM_LBUTTONDOWN:
button = Aspect_VKeyMouse_LeftButton;
break;
case WM_MBUTTONUP:
case WM_MBUTTONDOWN:
button = Aspect_VKeyMouse_MiddleButton;
break;
case WM_RBUTTONUP:
case WM_RBUTTONDOWN:
button = Aspect_VKeyMouse_RightButton;
break;
}
if (message == WM_LBUTTONDOWN
|| message == WM_MBUTTONDOWN
|| message == WM_RBUTTONDOWN)
{
SetFocus(hwnd);
SetCapture(hwnd);
if (!m_evtMgr.IsNull())
m_evtMgr->PressMouseButton(pos, button, flags, false);
}
else
{
ReleaseCapture();
if (!m_evtMgr.IsNull())
m_evtMgr->ReleaseMouseButton(pos, button, flags, false);
}
m_evtMgr->FlushViewEvents(m_context, m_view, true);
break;
}
case WM_MOUSEWHEEL:
{
const int delta = GET_WHEEL_DELTA_WPARAM(wparam);
const double deltaF = double(delta) / double(WHEEL_DELTA);
//
const Aspect_VKeyFlags flags = WNT_Window::MouseKeyFlagsFromEvent(wparam);
//
Graphic3d_Vec2i pos(int(short(LOWORD(lparam))), int(short(HIWORD(lparam))));
POINT cursorPnt = { pos.x(), pos.y() };
if (ScreenToClient(hwnd, &cursorPnt))
{
pos.SetValues(cursorPnt.x, cursorPnt.y);
}
if (!m_evtMgr.IsNull())
{
m_evtMgr->UpdateMouseScroll(Aspect_ScrollDelta(pos, deltaF, flags));
m_evtMgr->FlushViewEvents(m_context, m_view, true);
}
break;
}
case WM_MOUSEMOVE:
{
Graphic3d_Vec2i pos(LOWORD(lparam), HIWORD(lparam));
Aspect_VKeyMouse buttons = WNT_Window::MouseButtonsFromEvent(wparam);
Aspect_VKeyFlags flags = WNT_Window::MouseKeyFlagsFromEvent(wparam);
// don't make a slide-show from input events - fetch the actual mouse cursor position
CURSORINFO cursor;
cursor.cbSize = sizeof(cursor);
if (::GetCursorInfo(&cursor) != FALSE)
{
POINT cursorPnt = { cursor.ptScreenPos.x, cursor.ptScreenPos.y };
if (ScreenToClient(hwnd, &cursorPnt))
{
// as we override mouse position, we need overriding also mouse state
pos.SetValues(cursorPnt.x, cursorPnt.y);
buttons = WNT_Window::MouseButtonsAsync();
flags = WNT_Window::MouseKeyFlagsAsync();
}
}
if (m_wntWindow.IsNull() || (HWND)m_wntWindow->HWindow() != hwnd)
{
// mouse move events come also for inactive windows
break;
}
if (!m_evtMgr.IsNull())
{
m_evtMgr->UpdateMousePosition(pos, buttons, flags, false);
m_evtMgr->FlushViewEvents(m_context, m_view, true);
}
break;
}
default:
{
break;
}
case WM_DESTROY:
m_bQuit = true;
}
return DefWindowProc(hwnd, message, wparam, lparam);
}
ViewerInteractor.h
#pragma once
// OpenCascade includes
#include <AIS_ViewController.hxx>
#include <TColgp_Array1OfPnt2d.hxx>
#include <TCollection_AsciiString.hxx>
class AIS_InteractiveContext;
class V3d_View;
//! Manages input events.
class ViewerInteractor : public Standard_Transient, public AIS_ViewController
{
public:
// OCCT RTTI
DEFINE_STANDARD_RTTI_INLINE(ViewerInteractor, Standard_Transient)
public:
//! Ctor.
//! \param[in] view the V3d view instance.
//! \param[in] ctx the interactive context.
ViewerInteractor(const Handle(V3d_View)& view,
const Handle(AIS_InteractiveContext)& ctx);
//! Dtor.
virtual ~ViewerInteractor();
public:
//! Return interactive context.
const Handle(AIS_InteractiveContext)&
GetContext() const { return m_ctx; }
//! Handle mouse button press/release event.
virtual bool UpdateMouseButtons(const Graphic3d_Vec2i& thePoint,
Aspect_VKeyMouse theButtons,
Aspect_VKeyFlags theModifiers,
bool theIsEmulated) Standard_OVERRIDE;
//! Release key.
virtual void KeyDown(Aspect_VKey theKey,
double theTime,
double thePressure = 1.0) Standard_OVERRIDE;
//! Release key.
virtual void KeyUp(Aspect_VKey theKey,
double theTime) Standard_OVERRIDE;
//! Redraw the View on an Expose Event
virtual void ProcessExpose();
//! Handle redraw.
virtual void handleViewRedraw(const Handle(AIS_InteractiveContext)& theCtx,
const Handle(V3d_View)& theView) Standard_OVERRIDE;
//! Resize View.
virtual void ProcessConfigure();
//! Handle KeyPress event.
void ProcessKeyPress(Aspect_VKey theKey);
private:
Handle(V3d_View) m_view; //!< 3D view.
Handle(AIS_InteractiveContext) m_ctx; //!< Interactive context.
};
ViewerInteractor.cpp
// Own include
#include "ViewerInteractor.h"
// OpenCascade includes
#include <Aspect_Grid.hxx>
#include <AIS_AnimationCamera.hxx>
#include <AIS_InteractiveContext.hxx>
#include <AIS_Shape.hxx>
#include <V3d_View.hxx>
//-----------------------------------------------------------------------------
ViewerInteractor::ViewerInteractor(const Handle(V3d_View)& view,
const Handle(AIS_InteractiveContext)& ctx)
: m_view(view),
m_ctx(ctx)
{}
//-----------------------------------------------------------------------------
ViewerInteractor::~ViewerInteractor()
{}
//-----------------------------------------------------------------------------
bool ViewerInteractor::UpdateMouseButtons(const Graphic3d_Vec2i& point,
Aspect_VKeyMouse buttons,
Aspect_VKeyFlags modifiers,
bool isEmulated)
{
return AIS_ViewController::UpdateMouseButtons(point, buttons, modifiers, isEmulated);
}
//-----------------------------------------------------------------------------
void ViewerInteractor::ProcessExpose()
{
if (!m_view.IsNull())
{
m_view->Invalidate();
FlushViewEvents(m_ctx, m_view, true);
}
}
//-----------------------------------------------------------------------------
void ViewerInteractor::handleViewRedraw(const Handle(AIS_InteractiveContext)& ctx,
const Handle(V3d_View)& view)
{
AIS_ViewController::handleViewRedraw(ctx, view);
}
//-----------------------------------------------------------------------------
void ViewerInteractor::ProcessConfigure()
{
if (!m_view.IsNull())
{
m_view->MustBeResized();
FlushViewEvents(m_ctx, m_view, true);
}
}
//-----------------------------------------------------------------------------
void ViewerInteractor::KeyDown(Aspect_VKey key,
double time,
double pressure)
{
AIS_ViewController::KeyDown(key, time, pressure);
}
//-----------------------------------------------------------------------------
void ViewerInteractor::KeyUp(Aspect_VKey key,
double time)
{
const unsigned int modifOld = myKeys.Modifiers();
//
AIS_ViewController::KeyUp(key, time);
//
const unsigned int modifNew = myKeys.Modifiers();
ProcessKeyPress(key | modifNew);
}
//-----------------------------------------------------------------------------
void ViewerInteractor::ProcessKeyPress(Aspect_VKey key)
{
if (m_ctx.IsNull() || m_view.IsNull())
{
return;
}
switch (key)
{
case Aspect_VKey_F:
{
if (m_ctx->NbSelected() > 0)
{
m_ctx->FitSelected(m_view);
}
else
{
m_view->FitAll();
}
break;
}
case Aspect_VKey_S:
case Aspect_VKey_W:
{
const int dm = (key == Aspect_VKey_S) ? AIS_Shaded : AIS_WireFrame;
if (m_ctx->NbSelected() == 0)
{
m_ctx->SetDisplayMode(dm, false);
m_ctx->UpdateCurrentViewer();
}
else
{
for (m_ctx->InitSelected(); m_ctx->MoreSelected(); m_ctx->NextSelected())
{
m_ctx->SetDisplayMode(m_ctx->SelectedInteractive(), dm, false);
}
m_ctx->UpdateCurrentViewer();
}
break;
}
case Aspect_VKey_Backspace: // Axonometry.
{
m_view->SetProj(V3d_XposYnegZpos);
m_view->Redraw();
break;
}
case Aspect_VKey_T:
{
m_view->SetProj(V3d_TypeOfOrientation_Zup_Top);
m_view->Redraw();
break;
}
case Aspect_VKey_B:
{
m_view->SetProj(V3d_TypeOfOrientation_Zup_Bottom);
m_view->Redraw();
break;
}
case Aspect_VKey_L:
{
m_view->SetProj(V3d_TypeOfOrientation_Zup_Left);
m_view->Redraw();
break;
}
case Aspect_VKey_R:
{
m_view->SetProj(V3d_TypeOfOrientation_Zup_Right);
m_view->Redraw();
break;
}
default: break;
}
}
helloworld.cpp
#include "Viewer.h"
#include <BRepTools.hxx>
#include <BRepPrimAPI_MakeBox.hxx>
int main(int argc, char** argv)
{
Viewer vout(50, 50, 500, 500);
vout << BRepPrimAPI_MakeBox(10, 10, 20)
<< BRepPrimAPI_MakeBox(20, 30, 10);
if (argc > 1)
{
BRep_Builder bb;
TopoDS_Shape fromFile;
//
if (!BRepTools::Read(fromFile, argv[1], bb))
{
std::cout << "Failed to read BREP shape from file " << argv[1] << std::endl;
return 1;
}
vout << fromFile;
}
vout.StartMessageLoop();
return 0;
}
2、配置
库文件和头文件同以前
附加依赖项添加以下:
TKernel.lib
TKMath.lib
TKTopAlgo.lib
TKBRep.lib
TKPrim.lib
TKOpenGl.lib
TKService.lib
TKV3d.lib
kernel32.lib
user32.lib
gdi32.lib
winspool.lib
把freetype.lib和freetype.dll拷贝到源码编译后的库文件目录
D:\vs pj\opencascade\3rdparty\freetype-2.5.5-vc14-64
D:\vs pj\opencascade\install\win64\vc14