Files
2025-12-15 23:22:33 +08:00

1417 lines
43 KiB
C++

/***********************************************************************************************************************
*
* Copyright (c) 2010 - 2025 by Tech Soft 3D, Inc.
* The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., and considered a trade secret
* as defined under civil and criminal statutes. Tech Soft 3D shall pursue its civil and criminal remedies in the event
* of unauthorized use or misappropriation of its trade secrets. Use of this information by anyone other than authorized
* employees of Tech Soft 3D, Inc. is granted only under a written non-disclosure agreement, expressly prescribing the
* scope and manner of such use.
*
***********************************************************************************************************************/
/**
\file Viewer.cpp
This file demonstrates how to programmatically visualize a PRC file with a basic OpenGL program using HOOPS Exchange
and the connectors and visitors tools.
In the main function, we open the file.
Then we traverse once the model in order to retrieve the bounding box of the model.
Then we re-traverse the model to draw the different items.
***********************************************************************************************************************/
//#define DIRECT_RENDERING
#define INITIALIZE_A3D_API
#include <A3DSDKIncludes.h>
#include <hoops_license.h>
#include "../common.hpp"
#define TF_A3DLIBS
#include <math.h>
#include <stdarg.h>
#include <time.h>
#include <vector>
#include "callback_opengl.h"
#include "Matrix.h"
#include "trackball.h"
#include "TreeTraverse.h"
#include "VisitorContainer.h"
#include "VisitorTessellation.h"
#include "VisitorTransfo.h"
#include "VisitorTree.h"
#include "Viewer.h"
#include "VisitorCascadedAttribute.h"
//#####################################################################################################################
A3DUns32 mNumberOfViews;
A3DUns32 mCurrentViewIndex = ~0U;
bool stbDrawView = false;
//#####################################################################################################################
static A3DStatus DrawModel(const A3DAsmModelFile* pModelFile);
//######################################################################################################################
A3DStatus DrawGetBoundingBox(const A3DAsmModelFile* pModelFile, A3DBoundingBoxData* psBoundingBox,
const A3DBool bIncludeMarkups = false);
//######################################################################################################################
static A3DStatus Draw(const A3DAsmModelFile* pModelFile, const A3DBool bIncludeMarkups = false);
//######################################################################################################################
A3DAsmModelFile* ComputeSection(A3DAsmModelFile* pModelFile, A3DPlanarSectionData sSectionParametersData);
//######################################################################################################################
void ComputeHLR(
A3DAsmModelFile const * pModelFile,
A3DMkpView const *pActiveView,
A3DHLRViewPlaneData const &sHLRViewPlaneData,
GLuint &uiHLRDisplayList,
GLuint &uiHLRTanEdgeDisplayList,
GLuint &uiHLRHiddenDisplayList,
GLuint &uiHLRHiddenTanEdgeDisplayList,
GLuint &uiHLRSectionDisplayList);
//######################################################################################################################
static bool stbTrackBallAnimate = GL_FALSE;
//######################################################################################################################
static GLsizei stiXScreen = 0;
static GLsizei stiYScreen = 0;
static GLdouble stdXPan = 0.0;
static GLdouble stdYPan = 0.0;
static GLdouble stdZoom = 1.0;
static GLdouble stdXPan_Save = 0.0;
static GLdouble stdYPan_Save = 0.0;
static GLdouble stdZoom_Save = 1.0;
static GLint staiViewport[4];
//######################################################################################################################
static bool stbLButtonDown = false;
static bool stbRButtonDown = false;
//######################################################################################################################
static GLuint stuiModelFileDisplayList = 0;
static GLuint stuiMarkupsDisplayList = 0;
static GLuint stuiTriedronDisplayList = 0;
static GLuint stuiHLRDisplayList = 0;
static GLuint stuiHLRTanEdgeDisplayList = 0;
static GLuint stuiHLRHiddenDisplayList = 0;
static GLuint stuiHLRHiddenTanEdgeDisplayList = 0;
static GLuint stuiHLRSectionDisplayList = 0;
//######################################################################################################################
static GLfloat stafLightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat stafLightAmbient[] = { 0.1f, 0.1f, 0.1f, 1.0f };
static GLfloat stafLightPosition[] = { 0.0f, 0.0f, 1.0f, 0.0f };
//######################################################################################################################
static GLfloat stafMaterialDiffuse[] = { 0.6f, 0.6f, 0.6f, 1.0f };
static GLfloat stafMaterialSpecular[] = { 1.0f, 1.0f, 1.0f, 1.0f };
static GLfloat stafMaterialShininess[] = { 100.0f };
//######################################################################################################################
static GLfloat stafTextColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
static GLfloat stafErrorTextColor[] = { 1.0f, 0.0f, 0.0f, 1.0f };
//######################################################################################################################
static unsigned int stuiClearColor = 0xB2B2B2;
//######################################################################################################################
static GLint staiWinSize[2];
static GLint staiWinPosition[2];
static bool stbFullScreen = false;
//######################################################################################################################
static clock_t stiStart, stiEnd;
static float stfElapsed;
static unsigned int stiNbFrames = 0;
static float stfFps = 0.0f;
//######################################################################################################################
static A3DUTF8Char stpcWinTitle[_MAX_PATH];
//######################################################################################################################
static bool stbDisplayHelp = false;
static bool stbDisplayInfos = false;
//static bool stbDisplayMarkups = true;
static bool stbDisplaySection = false;
static bool stbDisplayHLR = false;
static bool stbDisplayHLRHidden = true;
static bool stbDisplayHLRTanEdge = true;
static bool stbDisplayHLRSection = true;
static bool stbDoubleSideRendering = true;
static A3DVector3dData origin3d;
static A3DVector3dData direction3d;
static A3DVector3dData stHLROrigin;
//######################################################################################################################
#define TRIEDRON_SIZE 40.0
//######################################################################################################################
#define A3DGL_MIN(a,b) (((a) < (b)) ? (a) : (b))
#define A3DGL_MAX(a,b) (((a) > (b)) ? (a) : (b))
static int stTraverseSet(A3DRiSet* pSet, A3DRiSet ** ppRISectionElements);
//######################################################################################################################
class A3DPRCViewerGLInfo
{
public:
A3DBoundingBoxData sBoundingBox;
double dBoundingBoxRadius;
A3DVector3dData sBoundingBoxCenter;
public:
//##################################################################################################################
A3DPRCViewerGLInfo() { Init(); }
//##################################################################################################################
void Init()
{
A3D_INITIALIZE_DATA(A3DBoundingBoxData, sBoundingBox);
A3D_INITIALIZE_DATA(A3DVector3dData, sBoundingBoxCenter);
dBoundingBoxRadius = 0.0;
}
//##################################################################################################################
void operator=(const A3DPRCViewerGLInfo& sOther)
{
sBoundingBox.m_sMin.m_dX = sOther.sBoundingBox.m_sMin.m_dX;
sBoundingBox.m_sMin.m_dY = sOther.sBoundingBox.m_sMin.m_dY;
sBoundingBox.m_sMin.m_dZ = sOther.sBoundingBox.m_sMin.m_dZ;
sBoundingBox.m_sMax.m_dX = sOther.sBoundingBox.m_sMax.m_dX;
sBoundingBox.m_sMax.m_dY = sOther.sBoundingBox.m_sMax.m_dY;
sBoundingBox.m_sMax.m_dZ = sOther.sBoundingBox.m_sMax.m_dZ;
dBoundingBoxRadius = sOther.dBoundingBoxRadius;
sBoundingBoxCenter.m_dX = sOther.sBoundingBoxCenter.m_dX;
sBoundingBoxCenter.m_dY = sOther.sBoundingBoxCenter.m_dY;
sBoundingBoxCenter.m_dZ = sOther.sBoundingBoxCenter.m_dZ;
}
//##################################################################################################################
void Calculate()
{
A3DVector3dData sMin;
A3DVector3dData sMax;
sMin.m_dX = sBoundingBox.m_sMin.m_dX;
sMin.m_dY = sBoundingBox.m_sMin.m_dY;
sMin.m_dZ = sBoundingBox.m_sMin.m_dZ;
sMax.m_dX = sBoundingBox.m_sMax.m_dX;
sMax.m_dY = sBoundingBox.m_sMax.m_dY;
sMax.m_dZ = sBoundingBox.m_sMax.m_dZ;
A3DDouble dBX = sMax.m_dX - sMin.m_dX;
A3DDouble dBY = sMax.m_dY - sMin.m_dY;
A3DDouble dBZ = sMax.m_dZ - sMin.m_dZ;
dBoundingBoxRadius = (float) sqrt(dBX*dBX + dBY*dBY + dBZ*dBZ) / 2.0f;
sBoundingBoxCenter.m_dX = (sMin.m_dX + sMax.m_dX) / 2.0;
sBoundingBoxCenter.m_dY = (sMin.m_dY + sMax.m_dY) / 2.0;
sBoundingBoxCenter.m_dZ = (sMin.m_dZ + sMax.m_dZ) / 2.0;
}
//##################################################################################################################
A3DPRCViewerGLInfo operator+(const A3DPRCViewerGLInfo& sOther)
{
A3DPRCViewerGLInfo sSum;
ExtentUnion(&sBoundingBox, &sOther.sBoundingBox, &sSum.sBoundingBox);
sSum.Calculate();
return sSum;
}
private:
//##################################################################################################################
void ExtentUnion(const A3DBoundingBoxData* e1, const A3DBoundingBoxData* e2, A3DBoundingBoxData* r)
{
r->m_sMin.m_dX = A3DGL_MIN(e1->m_sMin.m_dX, e2->m_sMin.m_dX);
r->m_sMax.m_dX = A3DGL_MAX(e1->m_sMax.m_dX, e2->m_sMax.m_dX);
r->m_sMin.m_dY = A3DGL_MIN(e1->m_sMin.m_dY, e2->m_sMin.m_dY);
r->m_sMax.m_dY = A3DGL_MAX(e1->m_sMax.m_dY, e2->m_sMax.m_dY);
r->m_sMin.m_dZ = A3DGL_MIN(e1->m_sMin.m_dZ, e2->m_sMin.m_dZ);
r->m_sMax.m_dZ = A3DGL_MAX(e1->m_sMax.m_dZ, e2->m_sMax.m_dZ);
}
};
//######################################################################################################################
static A3DSDKHOOPSExchangeLoader* stpHOOPSExchangeLoader = nullptr;
static A3DAsmModelFile* pSectionnedModelFile = nullptr;
//######################################################################################################################
static A3DPRCViewerGLInfo stsInfo;
static A3DPRCViewerGLInfo stsInfo3D;
static A3DPRCViewerGLInfo stsInfoMarkups;
//######################################################################################################################
#define HEX_TO_RED(hexcolor) ((GLclampf) ((hexcolor & 0xFF0000) >> 16) / 255.0f)
#define HEX_TO_GREEN(hexcolor) ((GLclampf) ((hexcolor & 0x00FF00) >> 8) / 255.0f)
#define HEX_TO_BLUE(hexcolor) ((GLclampf) (hexcolor & 0x0000FF) / 255.0f)
//######################################################################################################################
static enum
{
KE_NONE = 0,
KE_ZOOMING,
KE_PANNING
} eMotionType;
//######################################################################################################################
void Reshape(GLsizei w, GLsizei h)
{
tbReshape(w, h);
glViewport(0, 0, w, h);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
// gluPerspective(FOVY, (float)w / (h == 0.0 ? 1.0: (float)h), stsInfo.dBoundingBoxRadius * 0.1,
// stsInfo.dBoundingBoxRadius * 100.0);
// glOrtho(-w/2., w/2., -h/2., h/2., stsInfo.dBoundingBoxRadius * 0.1,stsInfo.dBoundingBoxRadius * 100.0);
glOrtho( -stsInfo.dBoundingBoxRadius * (float)w / (h == 0.0 ? 1.0: (float)h), stsInfo.dBoundingBoxRadius * (float)w / (h == 0.0 ? 1.0: (float)h),
-stsInfo.dBoundingBoxRadius, stsInfo.dBoundingBoxRadius,
-stsInfo.dBoundingBoxRadius-100,stsInfo.dBoundingBoxRadius * 100.0);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glGetIntegerv(GL_VIEWPORT, staiViewport);
if(!stbFullScreen)
{
staiWinSize[0] = w;
staiWinSize[1] = h;
}
}
//######################################################################################################################
void InitGL(void)
{
glClearColor(HEX_TO_RED(stuiClearColor), HEX_TO_GREEN(stuiClearColor), HEX_TO_BLUE(stuiClearColor), 1.0f);
glPointSize(5.0f);
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
glEnable(GL_NORMALIZE);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
glShadeModel(GL_SMOOTH);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glLightfv(GL_LIGHT0, GL_DIFFUSE, stafLightDiffuse);
glLightfv(GL_LIGHT0, GL_AMBIENT, stafLightAmbient);
//glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, stafMaterialDiffuse);
//glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, stafMaterialSpecular);
//glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, stafMaterialShininess);
stuiTriedronDisplayList = glGenLists(1);
glNewList(stuiTriedronDisplayList, GL_COMPILE);
{
glPushAttrib(GL_LIGHTING_BIT | GL_LINE_BIT);
glDisable(GL_LIGHTING);
glLineWidth(2.0);
glBegin(GL_LINES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(TRIEDRON_SIZE, 0.0f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, TRIEDRON_SIZE, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.0f, 0.0f);
glVertex3f(0.0f, 0.0f, TRIEDRON_SIZE);
glEnd();
glPopAttrib();
}
glEndList();
stdZoom = 1.0;
stdXPan = 0.0;
stdYPan = 0.0;
#ifdef _DEBUG
stiStart = clock();
#endif
}
//######################################################################################################################
void DrawTriedron(void)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
{
glLoadIdentity();
glOrtho(0.0, staiViewport[2], 0.0, staiViewport[3], -100.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
{
glLoadIdentity();
glTranslated(TRIEDRON_SIZE*1.5, TRIEDRON_SIZE*1.5, 0.0);
tbMatrix();
glCallList(stuiTriedronDisplayList);
}
glPopMatrix();
}
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
}
//######################################################################################################################
static float stfX = 1.0f, stfY = 97.0f, stfLineH = 2.0f;
//######################################################################################################################
static char stpcMsg[2048];
//######################################################################################################################
void PrintString(const char* format, ...)
{
va_list args;
va_start(args, format);
vsprintf(stpcMsg, format, args);
va_end(args);
glRasterPos2f(stfX, stfY);
char* pcPos = &stpcMsg[0];
while(*pcPos)
{
if(*pcPos == '\n')
{
stfY -= stfLineH;
glRasterPos2f(stfX, stfY);
}
else
glutBitmapCharacter(GLUT_BITMAP_8_BY_13, *pcPos);
pcPos++;
}
}
//######################################################################################################################
void DrawError(char const * acMessage, A3DStatus sStatus)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0.0, 100.0, 0.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glColor3fv(stafErrorTextColor);
stfX = 1.0f;
stfY = 85.0f;
if (acMessage)
PrintString("%s %d\n", acMessage, sStatus);
else
PrintString("ERROR %d\n", sStatus);
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
//#####################################################################################################################
void DrawStrings(void)
{
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0.0, 100.0, 0.0, 100.0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glColor3fv(stafTextColor);
if (stbDrawView)
{
stfX = 1.0f;
stfY = 80.0f;
PrintString("VIEWS\n");
PrintString("Total of views: %d \n",mNumberOfViews);
PrintString(" View number: %d\n", mCurrentViewIndex);
}
if(stbDisplayInfos)
{
stfX = 1.0f;
stfY = 97.0f;
stiNbFrames++;
stiEnd = clock();
stfElapsed = (float)(stiEnd - stiStart) / CLOCKS_PER_SEC;
if(stfElapsed >= 1.0)
{
stfFps = stiNbFrames/stfElapsed;
stiStart = stiEnd;
stiNbFrames = 0;
}
PrintString("%.2f fps\n", stfFps);
PrintString("Bounding box\n");
A3DVector3dData& sMin = stsInfo.sBoundingBox.m_sMin;
A3DVector3dData& sMax = stsInfo.sBoundingBox.m_sMax;
PrintString(" Extent: [%.3f, %.3f, %.3f] -> [%.3f, %.3f, %.3f]\n",
sMin.m_dX, sMin.m_dY, sMin.m_dZ, sMax.m_dX, sMax.m_dY, sMax.m_dZ);
PrintString(" Radius: %.3f\n", stsInfo.dBoundingBoxRadius);
}
if(stbDisplayHelp)
{
stfX = 1.0f;
stfY = 70.0f;
PrintString("HELP\n");
PrintString(" MOUSE:\n");
PrintString(" Left button: rotating\n");
PrintString(" Right button: zooming\n");
PrintString(" Right+Left button: panning\n");
PrintString("\n");
PrintString(" KEYBOARD:\n");
PrintString(" F1: print this help\n");
PrintString(" F2: open a file (in the console)\n");
PrintString(" F3: toggle markup display\n");
PrintString(" F4: toggle full screen\n");
PrintString(" F5: change background color\n");
PrintString(" F6: toggle render mode %s\n", DisplayTriangles() == 1 ? "[SHADING]" :
DisplayTriangles() == 2 ? "[WIREFRAME]" :
DisplayTriangles() == 3 ? "[SHADING&WIREFRAME]":"NONE");
PrintString(" F7: toggle normals display %s\n", DisplayTriangleNormals() == 0 ? "[NONE]" :
DisplayTriangleNormals() == 1 ? "[TRIANGLE PLANE NORMALS (blue)]" :
DisplayTriangleNormals() == 2 ? "[NORMALS (green)]" :
DisplayTriangleNormals() == 3 ? "[TRIANGLE PLANE NORMALS (blue) & NORMALS (green)]" : "?");
PrintString(" (Up and down keys to change normals display length) %lf\n", DisplayTriangleNormalLength());
PrintString(" F8: toggle rotation animation\n");
PrintString(" F9: toggle double-side rendering %s\n", stbDoubleSideRendering ? "[ON]" : "[OFF]");
PrintString(" F10: compute a planar section. Use the page up and page down keys to change the origin coordinates of the section\n");
PrintString(" F11: toggle information display\n");
PrintString(" h: toggle computed HLR\n");
PrintString(" s: in HLR mode, hide/show section\n");
PrintString(" t: in HLR mode, hide/show tangent edge\n");
PrintString(" v: in HLR mode, hide/show hidden element\n");
PrintString(" Use the RIGHT and LEFT keys to toggle the views\n");
}
glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING);
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
glPopMatrix();
}
//######################################################################################################################
void DrawHLR()
{
glPushMatrix();
{
glLoadIdentity();
glTranslated(-stsInfo.dBoundingBoxRadius*stdXPan, -stsInfo.dBoundingBoxRadius*stdYPan, 0.);
glScalef(stdZoom, stdZoom, stdZoom);
if (stbDisplayHLRHidden)
glCallList(stuiHLRHiddenDisplayList);
if (stbDisplayHLRHidden && stbDisplayHLRTanEdge)
glCallList(stuiHLRHiddenTanEdgeDisplayList);
glCallList(stuiHLRDisplayList);
if (stbDisplayHLRTanEdge)
glCallList(stuiHLRTanEdgeDisplayList);
if (stbDisplayHLRSection)
glCallList(stuiHLRSectionDisplayList);
}
glPopMatrix();
}
//######################################################################################################################
void Display(void)
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
if (stbDisplayHLR)
{
DrawHLR();
}
else
{
glPushMatrix();
{
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, stafLightPosition);
glTranslated(0.0f, 0.0f, -3.0*stsInfo.dBoundingBoxRadius);
glTranslated(-stsInfo.dBoundingBoxRadius*stdXPan, -stsInfo.dBoundingBoxRadius*stdYPan,
0);
tbMatrix();
glTranslated(-stsInfo.sBoundingBoxCenter.m_dX, -stsInfo.sBoundingBoxCenter.m_dY,
0);
glScalef(stdZoom, stdZoom, stdZoom); // scale the matrix
#ifdef DIRECT_RENDERING
Draw(stpHOOPSExchangeLoader->m_psModelFile);
if (GetstbDrawMarkups())
{
constexpr bool bIncludeMarkups = true;
Draw(stpHOOPSExchangeLoader->m_psModelFile, bIncludeMarkups);
}
#else
glCallList(stuiModelFileDisplayList);
if(GetstbDrawMarkups())
glCallList(stuiMarkupsDisplayList);
#endif
}
glPopMatrix();
DrawTriedron();
}
if(stbDisplayInfos || stbDisplayHelp || stbDrawView)
DrawStrings();
glFlush();
glFinish();
glutSwapBuffers();
}
void GetOpenGLMatrix(A3DDouble adModelView[16], A3DDouble adProjectMatrix[16])
{
glPushMatrix();
{
glLoadIdentity();
glLightfv(GL_LIGHT0, GL_POSITION, stafLightPosition);
glTranslated(0.0f, 0.0f, -3.0*stsInfo.dBoundingBoxRadius);
glTranslated(-stsInfo.dBoundingBoxRadius*stdXPan, -stsInfo.dBoundingBoxRadius*stdYPan,
0.);
tbMatrix();
glTranslated(-stsInfo.sBoundingBoxCenter.m_dX, -stsInfo.sBoundingBoxCenter.m_dY,
0.);
glScalef(stdZoom, stdZoom, stdZoom); // scale the matrix
glGetDoublev(GL_MODELVIEW_MATRIX, adModelView);
glGetDoublev(GL_PROJECTION_MATRIX , adProjectMatrix);
}
glPopMatrix();
}
//######################################################################################################################
static bool stbTBRunning = false;
//######################################################################################################################
void MouseButton(int button, int state, GLsizei x, GLsizei y)
{
//GLboolean bActiveShift = glutGetModifiers() & GLUT_ACTIVE_SHIFT;
//GLboolean bActiveCtrl = glutGetModifiers() & GLUT_ACTIVE_CTRL;
//GLboolean bDownState = (state == GLUT_DOWN);
if(button == GLUT_LEFT_BUTTON)
{
if(state == GLUT_DOWN)
stbLButtonDown = true;
else if(state == GLUT_UP)
stbLButtonDown = false;
}
else if(button == GLUT_RIGHT_BUTTON)
{
if(state == GLUT_DOWN)
stbRButtonDown = true;
else if(state == GLUT_UP)
stbRButtonDown = false;
}
if(!stbLButtonDown && !stbRButtonDown)
glutSetCursor(GLUT_CURSOR_LEFT_ARROW);
eMotionType = KE_NONE;
if(stbLButtonDown)
{
if(!stbRButtonDown)
{
tbMouse(button, state, x, y);
stbTBRunning = true;
}
else
{
if(stbTBRunning)
tbMouse(GLUT_LEFT_BUTTON, GLUT_UP, x, y);
eMotionType = KE_PANNING;
glutSetCursor(GLUT_CURSOR_SPRAY);
}
}
else
{
if(stbRButtonDown)
{
eMotionType = KE_ZOOMING;
glutSetCursor(GLUT_CURSOR_UP_DOWN);
}
else
{
tbMouse(button, state, x, y);
stbTBRunning = false;
}
}
stiXScreen = x;
stiYScreen = y;
glutPostRedisplay();
}
//######################################################################################################################
//void MouseWheel(int /* number */, int direction, int /* x */, int /* y */)
//{
// // TODO
// stdZoom += stsReadModelResult.dBoundingBoxRadius * 0.001 * direction;
// glutPostRedisplay();
//}
//######################################################################################################################
void Motion(GLsizei x, GLsizei y)
{
tbMotion(x, y);
switch(eMotionType)
{
case KE_PANNING:
{
stdXPan -= (GLdouble)(x - stiXScreen)/(GLdouble)staiViewport[2] * 2.0;
stdYPan += (GLdouble)(y - stiYScreen)/(GLdouble)staiViewport[3] * 2.0;
break;
}
case KE_ZOOMING:
{
stdZoom -= (GLdouble)(y - stiYScreen)/(GLdouble)staiViewport[3] * 10.0;
if (stdZoom<0)
stdZoom = 0;
break;
}
default:
break;
}
stiXScreen = x;
stiYScreen = y;
glutPostRedisplay();
}
//######################################################################################################################
A3DStatus OpenFile(const A3DUTF8Char* pcCADFile);
//######################################################################################################################
A3DStatus CloseFile();
//######################################################################################################################
static void stRebuildGenList()
{
glDeleteLists(stuiModelFileDisplayList, 1);
stuiModelFileDisplayList = glGenLists(1);
glNewList(stuiModelFileDisplayList, GL_COMPILE);
if(!stbDisplaySection)
Draw(stpHOOPSExchangeLoader->m_psModelFile);
else
Draw(pSectionnedModelFile);
glEndList();
Reshape(staiWinSize[0], staiWinSize[1]);
glutPostRedisplay();
}
static void stRebuildGenListHLR()
{
// Get active View
A3DAsmModelFileData sData;
A3D_INITIALIZE_DATA(A3DAsmModelFileData, sData);
A3DAsmModelFileGet(stpHOOPSExchangeLoader->m_psModelFile, &sData);
A3DAsmProductOccurrenceData sPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sPOData);
A3DAsmProductOccurrenceGet(sData.m_ppPOccurrences[0], &sPOData);
A3DMkpView const *pActiveView = nullptr;
if (sPOData.m_uiViewsSize > 0)
{
mNumberOfViews = sPOData.m_uiViewsSize;
if (mCurrentViewIndex != -1)
{
pActiveView = sPOData.m_ppViews[mCurrentViewIndex];
}
}
else if (sPOData.m_pPart != nullptr)
{
A3DAsmPartDefinitionData sPartData;
A3D_INITIALIZE_DATA(A3DAsmPartDefinitionData, sPartData);
if (A3DAsmPartDefinitionGet(sPOData.m_pPart, &sPartData) == A3D_SUCCESS)
{
mNumberOfViews = sPartData.m_uiViewsSize;
if (mCurrentViewIndex != -1)
{
pActiveView = sPartData.m_ppViews[mCurrentViewIndex];
}
A3DAsmPartDefinitionGet(nullptr, &sPartData);
}
}
A3DDouble adModelView[16], adProjectMatrix[16];
GetOpenGLMatrix( adModelView, adProjectMatrix);
A3DMatrix4x4 sModelViewMat(adModelView), sCameraMat;
sModelViewMat.Invert(sCameraMat);
A3DHLRViewPlaneData sHLRViewPlaneData;
A3D_INITIALIZE_DATA(A3DHLRViewPlaneData,sHLRViewPlaneData);
sHLRViewPlaneData.m_adOrigin[0] = stHLROrigin.m_dX = sCameraMat[12];
sHLRViewPlaneData.m_adOrigin[1] = stHLROrigin.m_dY = sCameraMat[13];
sHLRViewPlaneData.m_adOrigin[2] = stHLROrigin.m_dZ = sCameraMat[14];
double dLength = stsInfo.dBoundingBoxRadius / 2.;
sHLRViewPlaneData.m_adAxis1[0] = sCameraMat[0] * dLength;
sHLRViewPlaneData.m_adAxis1[1] = sCameraMat[1] * dLength;
sHLRViewPlaneData.m_adAxis1[2] = sCameraMat[2] * dLength;
sHLRViewPlaneData.m_adAxis2[0] = sCameraMat[4] * dLength;
sHLRViewPlaneData.m_adAxis2[1] = sCameraMat[5] * dLength;
sHLRViewPlaneData.m_adAxis2[2] = sCameraMat[6] * dLength;
sHLRViewPlaneData.m_bUseClipBox = false;
ComputeHLR(stpHOOPSExchangeLoader->m_psModelFile, pActiveView, sHLRViewPlaneData,
stuiHLRDisplayList, stuiHLRTanEdgeDisplayList, stuiHLRHiddenDisplayList, stuiHLRHiddenTanEdgeDisplayList, stuiHLRSectionDisplayList);
stbDisplayHLR = true;
Reshape(staiWinSize[0], staiWinSize[1]);
A3DAsmModelFileGet(nullptr, &sData);
A3DAsmProductOccurrenceGet(nullptr, &sPOData);
}
//######################################################################################################################
void SpecialKey(int key, int /* x */, int /* y */)
{
switch(key)
{
case 27:
exit(0);
case GLUT_KEY_F1:
stbDisplayHelp = !stbDisplayHelp;
glutPostRedisplay();
break;
case GLUT_KEY_F2:
{
A3DUTF8Char pcFilePath[_MAX_PATH];
fprintf(stdout, "\nFile path: ");
scanf("%s", pcFilePath);
CloseFile();
if(OpenFile(pcFilePath) == A3D_SUCCESS)
{
mCurrentViewIndex=~0U;
stbDrawView = false;
Reshape(staiWinSize[0], staiWinSize[1]);
stdZoom = 1.;
stdYPan = 0.0;
}
Display();
}
break;
case GLUT_KEY_F3:
SetstbDrawMarkups(!GetstbDrawMarkups());
if(GetstbDrawMarkups())
stsInfo = stsInfo3D + stsInfoMarkups;
else
stsInfo = stsInfo3D;
Reshape(staiWinSize[0], staiWinSize[1]);
glutPostRedisplay();
break;
case GLUT_KEY_F4:
stbFullScreen = !stbFullScreen;
if(stbFullScreen)
glutFullScreen();
else
{
glutPositionWindow(staiWinPosition[0], staiWinPosition[1]);
glutReshapeWindow(staiWinSize[0], staiWinSize[1]);
}
break;
case GLUT_KEY_F5:
{
char pcNewColor[_MAX_PATH];
fprintf(stdout, "\nNew color (0xHHHHHH): ");
scanf("%s", pcNewColor);
sscanf(pcNewColor, "%x", &stuiClearColor);
glClearColor(HEX_TO_RED(stuiClearColor), HEX_TO_GREEN(stuiClearColor), HEX_TO_BLUE(stuiClearColor), 1.0f);
glutPostRedisplay();
}
break;
case GLUT_KEY_F6:
DisplayTriangles()++;
if(DisplayTriangles() > 3)
DisplayTriangles() = 1;
stRebuildGenList();
break;
case GLUT_KEY_F7:
DisplayTriangleNormals()++;
if(DisplayTriangleNormals() > 3)
DisplayTriangleNormals() = 0;
DisplayTriangleNormalLength() = stsInfo3D.dBoundingBoxRadius*2 / 100;
stRebuildGenList();
break;
case GLUT_KEY_F8:
tbMouse(GLUT_LEFT_BUTTON, GLUT_UP, 0, 0);
stbTBRunning = false;
stbTrackBallAnimate = !stbTrackBallAnimate;
tbAnimate(stbTrackBallAnimate);
break;
case GLUT_KEY_F9:
stbDoubleSideRendering = !stbDoubleSideRendering;
if(stbDoubleSideRendering)
{
glDisable(GL_CULL_FACE);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
}
else
{
glEnable(GL_CULL_FACE);
glCullFace(GL_BACK);
glLightModelf(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
}
stRebuildGenList();
break;
case GLUT_KEY_F10:
{
stbDisplaySection = !stbDisplaySection;
fprintf(stdout, "DisplaySection = %s\n", (stbDisplaySection) ? "true" : "false");
if(stbDisplaySection)
{
A3D_INITIALIZE_DATA(A3DVector3dData, origin3d);
origin3d.m_dX = stsInfo.sBoundingBoxCenter.m_dX;
origin3d.m_dY = stsInfo.sBoundingBoxCenter.m_dY;
origin3d.m_dZ = stsInfo.sBoundingBoxCenter.m_dZ;
A3D_INITIALIZE_DATA(A3DVector3dData, direction3d);
char Direction[20] = "Direction";
int nb1 = 0;
int nb2 = 0;
int nb3 = 0;
fprintf(stdout, "\nEnter the x direction of your section: \n");
scanf("%s", Direction);
sscanf(Direction, "%d", &nb1);
fprintf(stdout, "\nEnter the y direction of your section: \n");
scanf("%s", Direction);
sscanf(Direction, "%d", &nb2);
fprintf(stdout, "\nEnter the z direction of your section: \n");
scanf("%s", Direction);
sscanf(Direction, "%d", &nb3);
direction3d.m_dX = (A3DDouble) nb1;
direction3d.m_dY = (A3DDouble) nb2;
direction3d.m_dZ = (A3DDouble) nb3;
A3DPlanarSectionData sSectionParametersData;
A3D_INITIALIZE_DATA(A3DPlanarSectionData, sSectionParametersData);
sSectionParametersData.m_sOrigin = origin3d;
sSectionParametersData.m_sDirection = direction3d;
sSectionParametersData.m_bColor = true;
sSectionParametersData.m_bCreateFaces = true;
pSectionnedModelFile = ComputeSection(stpHOOPSExchangeLoader->m_psModelFile, sSectionParametersData);
stRebuildGenList();
}
else
stRebuildGenList();
}
break;
case GLUT_KEY_F11:
stbDisplayInfos = !stbDisplayInfos;
glutPostRedisplay();
break;
case GLUT_KEY_UP:
DisplayTriangleNormalLength() *= 2;
stRebuildGenList();
break;
case GLUT_KEY_DOWN:
DisplayTriangleNormalLength() /= 2;
stRebuildGenList();
break;
case GLUT_KEY_RIGHT:
{
if (mCurrentViewIndex==mNumberOfViews-1)
mCurrentViewIndex = ~0U;
else
mCurrentViewIndex++;
stbDrawView = (mCurrentViewIndex != ~0U);
stRebuildGenList();
glutPostRedisplay();
}
break;
case GLUT_KEY_INSERT:
{
stRebuildGenList();
glutPostRedisplay();
}
break;
case GLUT_KEY_LEFT:
{
if (mCurrentViewIndex==~0U)
mCurrentViewIndex = mNumberOfViews-1;
else
mCurrentViewIndex--;
stbDrawView = (mCurrentViewIndex != ~0U);
stRebuildGenList();
glutPostRedisplay();
}
break;
case GLUT_KEY_PAGE_UP:
{
if(stbDisplaySection)
{
origin3d.m_dX = origin3d.m_dX+direction3d.m_dX*0.1;
origin3d.m_dY = origin3d.m_dY+direction3d.m_dY*0.1;
origin3d.m_dZ = origin3d.m_dZ+direction3d.m_dZ*0.1;
A3DPlanarSectionData sSectionParametersData;
A3D_INITIALIZE_DATA(A3DPlanarSectionData, sSectionParametersData);
sSectionParametersData.m_sOrigin = origin3d;
sSectionParametersData.m_sDirection = direction3d;
sSectionParametersData.m_bColor = true;
sSectionParametersData.m_bCreateFaces = true;
pSectionnedModelFile = ComputeSection(stpHOOPSExchangeLoader->m_psModelFile, sSectionParametersData);
stRebuildGenList();
}
}
break;
case GLUT_KEY_PAGE_DOWN:
{
if(stbDisplaySection)
{
origin3d.m_dX = origin3d.m_dX-direction3d.m_dX*0.1;
origin3d.m_dY = origin3d.m_dY-direction3d.m_dY*0.1;
origin3d.m_dZ = origin3d.m_dZ-direction3d.m_dZ*0.1;
A3DPlanarSectionData sSectionParametersData;
A3D_INITIALIZE_DATA(A3DPlanarSectionData, sSectionParametersData);
sSectionParametersData.m_sOrigin = origin3d;
sSectionParametersData.m_sDirection = direction3d;
sSectionParametersData.m_bColor = true;
sSectionParametersData.m_bCreateFaces = true;
pSectionnedModelFile = ComputeSection(stpHOOPSExchangeLoader->m_psModelFile, sSectionParametersData);
stRebuildGenList();
}
}
break;
}
}
//######################################################################################################################
A3DStatus DrawGetBoundingBox(const A3DAsmModelFile* pModelFile, A3DBoundingBoxData* psBoundingBox, const A3DBool bIncludeMarkups)
{
A3DStatus iRet = A3D_SUCCESS;
if (pModelFile == nullptr)
return A3D_INVALID_ENTITY_NULL;
if (psBoundingBox == nullptr)
return A3D_INVALID_DATA_STRUCT_NULL;
stLoadIdentity();
stExtentInit(psBoundingBox);
SetstbDrawMarkups(bIncludeMarkups);
SetstpsBoundingBox(psBoundingBox);
SetstbUseCallbacks(false);
CHECK_RET(DrawModel(pModelFile));
return iRet;
}
//######################################################################################################################
void Key( unsigned char key, int /*x*/, int /*y*/)
{
switch (key)
{
case 's':
stbDisplayHLRSection = !stbDisplayHLRSection;
glutPostRedisplay();
break;
case 't':
stbDisplayHLRTanEdge = !stbDisplayHLRTanEdge;
glutPostRedisplay();
break;
case 'v':
stbDisplayHLRHidden = !stbDisplayHLRHidden;
glutPostRedisplay();
break;
case 'h':
{
if( !stbDisplayHLR)
{
stRebuildGenListHLR();
stbDisplayHLR = true;
stdXPan_Save = stdXPan; stdXPan = 0.;
stdYPan_Save = stdYPan; stdYPan = 0.;
stdZoom_Save = stdZoom;
}
else
{
stbDisplayHLR = false;
stdXPan = stdXPan_Save;
stdYPan = stdYPan_Save;
stdZoom = stdZoom_Save;
}
}
glutPostRedisplay();
break;
case 27:
exit(0);
break;
default:
break;
}
}
//######################################################################################################################
static A3DStatus DrawModel(const A3DAsmModelFile* pModelFile)
{
A3DAsmModelFileData sData;
A3D_INITIALIZE_DATA(A3DAsmModelFileData, sData);
CHECK_RET(A3DAsmModelFileGet(pModelFile, &sData));
// Creation of the ModelFile Connector
A3DModelFileConnector sModelFileConnector(pModelFile);
A3DVisitorContainer sCadVisitorContainer(CONNECT_TRANSFO);
sCadVisitorContainer.SetTraverseInstance(true);
A3DAsmProductOccurrenceData sPOData;
A3D_INITIALIZE_DATA(A3DAsmProductOccurrenceData, sPOData);
CHECK_RET(A3DAsmProductOccurrenceGet(sData.m_ppPOccurrences[0], &sPOData));
if (sPOData.m_uiViewsSize > 0)
{
mNumberOfViews = sPOData.m_uiViewsSize;
if (mCurrentViewIndex != -1 && mCurrentViewIndex<mNumberOfViews)
{
sCadVisitorContainer.SetActivateView(sPOData.m_ppViews[mCurrentViewIndex]);
}
}
else if (sPOData.m_pPart != nullptr)
{
A3DAsmPartDefinitionData sPartData;
A3D_INITIALIZE_DATA(A3DAsmPartDefinitionData, sPartData);
CHECK_RET(A3DAsmPartDefinitionGet(sPOData.m_pPart, &sPartData));
mNumberOfViews = sPartData.m_uiViewsSize;
if (mCurrentViewIndex != -1 && mCurrentViewIndex<mNumberOfViews)
{
sCadVisitorContainer.SetActivateView(sPartData.m_ppViews[mCurrentViewIndex]);
}
A3DAsmPartDefinitionGet(nullptr, &sPartData);
}
CHECK_RET(A3DAsmProductOccurrenceGet(nullptr, &sPOData));
CHECK_RET(A3DAsmModelFileGet(nullptr, &sData));
// Create the Visitor for the styles
A3DVisitorColorMaterials *psVisitorColorMaterial = new A3DVisitorColorMaterials(&sCadVisitorContainer);
sCadVisitorContainer.push(psVisitorColorMaterial);
A3DTreeVisitor *pA3DTreeVisitor = new A3DTreeVisitor(&sCadVisitorContainer);
sCadVisitorContainer.push(pA3DTreeVisitor);
// Create the Visitor for the tessellation
A3DVisitorTessellation *psVisitorTessellation = new A3DVisitorTessellation(&sCadVisitorContainer);
sCadVisitorContainer.push(psVisitorTessellation);
// Traverse the ModelFile Connector
sModelFileConnector.Traverse(&sCadVisitorContainer);
stsInfo3D.Calculate();
// TODO: Add the cameras
return A3D_SUCCESS;
}
//######################################################################################################################
A3DStatus Draw(const A3DAsmModelFile* pModelFile, const A3DBool bIncludeMarkups)
{
if(pModelFile == nullptr)
return A3D_INVALID_ENTITY_NULL;
if(!GetstbCallbacksInitialized())
return A3D_ERROR;
stLoadIdentity();
SetstbDrawMarkups(bIncludeMarkups);
SetstbUseCallbacks(true);
CHECK_RET(DrawModel(pModelFile));
return A3D_SUCCESS;
}
//######################################################################################################################
A3DStatus OpenFile(const A3DUTF8Char* pcCADFileName)
{
if(stpHOOPSExchangeLoader == nullptr)
return A3D_ERROR;
A3DImport sImport(pcCADFileName);
sImport.m_sLoadData.m_sSpecifics.m_sProE.m_bReadExplodeStateAsView = true;
sImport.m_sLoadData.m_sGeneral.m_bReadPmis = true;
sImport.m_sLoadData.m_sGeneral.m_bReadConstructionAndReferences = false;
sImport.m_sLoadData.m_sGeneral.m_bReadWireframes = false;
sImport.m_sLoadData.m_sTessellation.m_bAccurateTessellation = false;
A3DStatus iRet = stpHOOPSExchangeLoader->Import(sImport);
if(iRet != A3D_SUCCESS && iRet != A3D_LOAD_MULTI_MODELS_CADFILE && iRet != A3D_LOAD_MISSING_COMPONENTS)
return iRet;
// Traverse the model once to retrieve the bounding box
CHECK_RET(DrawGetBoundingBox(stpHOOPSExchangeLoader->m_psModelFile, &stsInfo3D.sBoundingBox));
stsInfo3D.Calculate();
#ifndef DIRECT_RENDERING
stuiModelFileDisplayList = glGenLists(1);
glNewList(stuiModelFileDisplayList, GL_COMPILE);
{
if(!stbDisplaySection)
{
// Traverse the model a second time to draw the items
CHECK_RET(Draw(stpHOOPSExchangeLoader->m_psModelFile));
}
else
{
// Draw the section
CHECK_RET(Draw(pSectionnedModelFile));
}
}
glEndList();
#endif
Reshape(staiWinSize[0], staiWinSize[1]);
// Traverse the model once to retrieve the bounding box with the markups
constexpr bool bIncludeMarkups = true;
CHECK_RET(DrawGetBoundingBox(stpHOOPSExchangeLoader->m_psModelFile, &stsInfoMarkups.sBoundingBox, bIncludeMarkups));
stsInfoMarkups.Calculate();
#ifndef DIRECT_RENDERING
stuiMarkupsDisplayList = glGenLists(1);
glNewList(stuiMarkupsDisplayList, GL_COMPILE_AND_EXECUTE);
{
if(!stbDisplaySection)
{
// Traverse the model a second time to draw the items (including the markups)
CHECK_RET(Draw(stpHOOPSExchangeLoader->m_psModelFile, bIncludeMarkups));
}
}
glEndList();
#endif
Reshape(staiWinSize[0], staiWinSize[1]);
fprintf(stdout, "Done.\n");
if(GetstbDrawMarkups())
stsInfo = stsInfo3D + stsInfoMarkups;
else
stsInfo = stsInfo3D;
sprintf(stpcWinTitle, "HOOPS Exchange Viewer - %s", pcCADFileName);
glutSetWindowTitle(stpcWinTitle);
return A3D_SUCCESS;
}
//######################################################################################################################
A3DStatus CloseFile()
{
#ifndef DIRECT_RENDERING
glDeleteLists(stuiModelFileDisplayList, 1);
glDeleteLists(stuiMarkupsDisplayList, 1);
glDeleteLists(stuiHLRDisplayList, 1);
glDeleteLists(stuiHLRTanEdgeDisplayList, 1);
glDeleteLists(stuiHLRHiddenDisplayList,1);
glDeleteLists(stuiHLRHiddenTanEdgeDisplayList,1);
glDeleteLists(stuiHLRSectionDisplayList, 1);
//glDeleteLists(stuiTriedronDisplayList, 1);
stuiModelFileDisplayList = stuiMarkupsDisplayList = stuiHLRDisplayList = stuiHLRTanEdgeDisplayList = stuiHLRHiddenDisplayList = stuiHLRHiddenTanEdgeDisplayList = stuiHLRSectionDisplayList = 0;
#endif
return A3D_SUCCESS;
}
//######################################################################################################################
void terminate2()
{
CloseFile();
delete stpHOOPSExchangeLoader;
stpHOOPSExchangeLoader = nullptr;
ListLeaks();
}
static MY_CHAR acSrcFileName[_MAX_PATH * 2];
static MY_CHAR acLogFileName[_MAX_PATH * 2];
//######################################################################################################################
// Main function
#ifdef _MSC_VER
int wmain(A3DInt32 iArgc, A3DUniChar** ppcArgv)
#else
int main(A3DInt32 iArgc, A3DUTF8Char** ppcArgv)
#endif
{
//
// ### COMMAND LINE ARGUMENTS
//
if (iArgc > 4)
{
MY_PRINTF2("Usage:\n %s [input CAD file] [Clear color value] [output LOG file]\n", ppcArgv[0]);
MY_PRINTF(" Default output LOG file is [input CAD file]_Log.txt\n\n");
return A3D_ERROR;
}
if (iArgc > 1) MY_STRCPY(acSrcFileName, ppcArgv[1]);
else MY_STRCPY(acSrcFileName, DEFAULT_INPUT_CAD);
if (iArgc > 2) MY_SSCANF(ppcArgv[2], "%x", &stuiClearColor);
else stuiClearColor = 0xB2B2B2;
if (iArgc > 3) MY_STRCPY(acLogFileName, ppcArgv[3]);
else MY_SPRINTF(acLogFileName, "%s_Log.txt", acSrcFileName);
GetLogFile(acLogFileName); // Initialize log file
//
// ### INITIALIZE HOOPS EXCHANGE
//
stpHOOPSExchangeLoader = new A3DSDKHOOPSExchangeLoader(_T(HOOPS_BINARY_DIRECTORY), HOOPS_LICENSE);
if (stpHOOPSExchangeLoader->m_eSDKStatus != A3D_SUCCESS)
{
A3DStatus eSDKStatus = stpHOOPSExchangeLoader->m_eSDKStatus;
delete stpHOOPSExchangeLoader;
stpHOOPSExchangeLoader = nullptr;
return eSDKStatus;
}
CHECK_RET(A3DDllSetCallbacksMemory(CheckMalloc, CheckFree));
CHECK_RET(A3DDllSetCallbacksReport(PrintLogMessage, PrintLogWarning, PrintLogError));
//
// ### PROCESS SAMPLE CODE
//
glutInit((int*)(&iArgc), (char**)ppcArgv);
GLsizei iScreenW = glutGet(GLUT_SCREEN_WIDTH);
GLsizei iScreenH = glutGet(GLUT_SCREEN_HEIGHT);
staiWinSize[0] = (GLsizei)((double)iScreenW * 0.7);
staiWinSize[1] = (GLsizei)((double)iScreenH * 0.7);
staiWinPosition[0] = (iScreenW - staiWinSize[0]) / 2;
staiWinPosition[1] = (iScreenH - staiWinSize[1]) / 2;
glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowPosition(staiWinPosition[0], staiWinPosition[1]);
glutInitWindowSize(staiWinSize[0], staiWinSize[1]);
glutCreateWindow("A3DPRCViewerGL");
glViewport(0, 0, staiWinSize[0], staiWinSize[1]);
tbInit(GLUT_LEFT_BUTTON);
tbAnimate(stbTrackBallAnimate);
stsInfo.Init();
stsInfo3D.Init();
stsInfoMarkups.Init();
A3DUTF8Char sSrcFileNameUTF8[_MAX_PATH];
#ifdef _MSC_VER
A3DMiscUTF16ToUTF8(acSrcFileName, sSrcFileNameUTF8);
#else
MY_STRCPY(sSrcFileNameUTF8, acSrcFileName);
#endif
CHECK_RET_TERM(OpenFile(sSrcFileNameUTF8));
InitGL();
glutReshapeFunc(Reshape);
glutDisplayFunc(Display);
glutKeyboardFunc(Key);
glutSpecialFunc(SpecialKey);
glutMouseFunc(MouseButton);
//glutMouseWheelFunc(MouseWheel);
glutMotionFunc(Motion);
glutIdleFunc(nullptr);
fprintf(stdout, "\nF1 for help\n");
// glut call exit(0) when closing windows, so set atexit to properly close the DLL
atexit(terminate2);
glutMainLoop();
//
// ### TERMINATE HOOPS EXCHANGE
//
return 0;
}