mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-03-01 19:46:08 +08:00
1022 lines
29 KiB
C++
1022 lines
29 KiB
C++
/* $NoKeywords: $ */
|
|
/*
|
|
//
|
|
// Copyright (c) 1993-2011 Robert McNeel & Associates. All rights reserved.
|
|
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
|
|
// McNeel & Associates.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
|
|
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
|
|
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
|
|
//
|
|
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
|
|
//
|
|
////////////////////////////////////////////////////////////////
|
|
*/
|
|
|
|
#include "../opennurbs_public_examples.h"
|
|
|
|
#include "../opennurbs_gl.h"
|
|
|
|
#if defined(ON_COMPILER_MSC)
|
|
|
|
#if ( _MSC_VER != 1400 )
|
|
// Tested compilers:
|
|
// Microsoft Visual Studio 2005
|
|
// Support for other compilers is not available.
|
|
#error The OpenGL example is not supported on this compiler.
|
|
// NOTE:
|
|
// Visual Studio 2005 / 8.0 was the last version of Visual
|
|
// studio to install the libraries and header files for
|
|
// Open GL auxillary functions.
|
|
#endif
|
|
|
|
#include <GL/GLaux.h> // Open GL auxillary functions
|
|
|
|
#define ON_EXAMPLE_GL_USE_GLAUX
|
|
|
|
#elif defined(ON_COMPILER_XCODE)
|
|
|
|
// Tested compilers:
|
|
// Apple Xcode 2.4.1
|
|
// Support for other Apple compilers is not available.
|
|
#include <GLUT/glut.h> // Open GL auxillary functions
|
|
#define ON_EXAMPLE_GL_USE_GLUT
|
|
|
|
#else
|
|
|
|
// Unsupported compiler:
|
|
// Support for other compilers is not available
|
|
#error Choose between OpenGL AUX or OpenGL GLUT.
|
|
|
|
//#include <GLaux.h> // Open GL auxillary functions
|
|
//#define ON_EXAMPLE_GL_USE_GLAUX
|
|
|
|
//#include <glut.h> // Open GL auxillary functions
|
|
//#define ON_EXAMPLE_GL_USE_GLUT
|
|
|
|
#endif
|
|
|
|
|
|
#if defined(_WINDOWS) || defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
|
#define MY_GL_CALLBACK CALLBACK
|
|
#define MY_USE_WINDOWS_STUFF
|
|
#else
|
|
#define MY_GL_CALLBACK
|
|
#endif
|
|
|
|
// Before working on this file, be sure to study the OpenNURBS toolkit
|
|
// file example_read.cpp and to read chapters 1 through 11 of the
|
|
// _Open_GL_Programming_Guide_.
|
|
//
|
|
// This file contains simple example in modeled after those found in
|
|
// the _Open_GL_Programming_Guide_. The nuts and bolts functions that
|
|
// demonstrate how to use Open GL to display OpenNURBS geometry are in
|
|
// opennurbs_gl.cpp.
|
|
|
|
////////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
class CModel : public ONX_Model
|
|
{
|
|
public:
|
|
void GetObjectMaterial( int object_index, ON_Material& material ) const;
|
|
ON_3dmView m_view;
|
|
ON_BoundingBox m_bbox;
|
|
};
|
|
|
|
void CModel::GetObjectMaterial(
|
|
int object_index,
|
|
ON_Material& material
|
|
) const
|
|
{
|
|
material.Default();
|
|
//const ON_Geometry* geo = 0;
|
|
|
|
if ( object_index >= 0 && object_index <= m_object_table.Count() )
|
|
{
|
|
const ONX_Model_Object& mo = m_object_table[object_index];
|
|
if ( 0 != mo.m_object )
|
|
{
|
|
switch( mo.m_object->ObjectType() )
|
|
{
|
|
case ON::surface_object:
|
|
case ON::brep_object:
|
|
case ON::mesh_object:
|
|
case ON::instance_reference:
|
|
GetRenderMaterial( mo.m_attributes, material );
|
|
break;
|
|
default:
|
|
{
|
|
// use emmissive object color for curve objects
|
|
ON_Color c = WireframeColor( mo.m_attributes );
|
|
ON_Color black(0,0,0);
|
|
material.Default();
|
|
material.SetAmbient(black);
|
|
material.SetDiffuse(black);
|
|
material.SetSpecular(black);
|
|
material.SetEmission(c);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
void GetDefaultView( const ON_BoundingBox& bbox, ON_3dmView& view )
|
|
{
|
|
// simple parallel projection of bounding box;
|
|
double window_height = 1.0;
|
|
double window_width = 1.0;
|
|
double dx, dy, dz;
|
|
double frus_near, frus_far;
|
|
ON_3dPoint camLoc;
|
|
ON_3dVector camDir, camUp;
|
|
view.m_target = 0.5*(bbox.m_min + bbox.m_max);
|
|
dx = 1.1*(bbox.m_max[0] - bbox.m_min[0]);
|
|
dy = 1.1*(bbox.m_max[1] - bbox.m_min[1]);
|
|
dz = 1.1*(bbox.m_max[2] - bbox.m_min[2]);
|
|
if ( dx <= 1.0e-6 && dy <= 1.0e-6 )
|
|
dx = dy = 2.0;
|
|
if ( window_height*dx < window_width*dy ) {
|
|
dx = dy*window_width/window_height;
|
|
}
|
|
else {
|
|
dy = dx*window_height/window_width;
|
|
}
|
|
if ( dz <= 0.1*(dx+dy) )
|
|
dz = 0.1*(dx+dy);
|
|
dx *= 0.5;
|
|
dy *= 0.5;
|
|
dz *= 0.5;
|
|
|
|
|
|
frus_near = 1.0;
|
|
frus_far = frus_near + 2.0*dz;
|
|
camLoc = view.m_target + (dz + frus_near)*ON_zaxis;
|
|
camDir = -ON_zaxis;
|
|
camUp = ON_yaxis;
|
|
|
|
view.m_vp.SetProjection( ON::parallel_view );
|
|
view.m_vp.SetCameraLocation( camLoc );
|
|
view.m_vp.SetCameraDirection( camDir );
|
|
view.m_vp.SetCameraUp( camUp );
|
|
view.m_vp.SetFrustum( -dx, dx, -dy, dy, frus_near, frus_far );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Globals for myDisplay() function passed to auxMainLoop()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
// GL display list "name"
|
|
static GLuint glb_display_list_number = 1;
|
|
|
|
// global pointer to active model
|
|
CModel* glb_model = 0;
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Functions used in main()
|
|
//
|
|
//////////////////////////////////////////////////////////////////////
|
|
|
|
ON_BOOL32 myInitGL( const ON_Viewport&, GLUnurbsObj*& );
|
|
|
|
void myBuildDisplayList(
|
|
GLuint, // display_list_number,
|
|
GLUnurbsObj*, // pointer to GL nurbs render
|
|
const CModel& // geometry to render
|
|
);
|
|
|
|
extern "C" {
|
|
void MY_GL_CALLBACK myNurbsErrorCallback( GLenum ); // for gluNurbsCallback()
|
|
|
|
void MY_GL_CALLBACK myDisplay( void ); // for auxMainLoop()
|
|
|
|
|
|
void MY_GL_CALLBACK myKeyLeftArrowEvent( void ); // for auxKeyFunc();
|
|
void MY_GL_CALLBACK myKeyRightArrowEvent( void ); // for auxKeyFunc();
|
|
void MY_GL_CALLBACK myKeyUpArrowEvent( void ); // for auxKeyFunc();
|
|
void MY_GL_CALLBACK myKeyDownArrowEvent( void ); // for auxKeyFunc();
|
|
void MY_GL_CALLBACK myKeyViewExtents( void ); // for auxKeyFunc();
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLAUX)
|
|
void MY_GL_CALLBACK myGLAUX_Reshape( GLsizei, GLsizei ); // for auxReshapeFunc()
|
|
|
|
void MY_GL_CALLBACK myGLAUX_MouseLeftEvent( AUX_EVENTREC* ); // for auxMouseFunc();
|
|
void MY_GL_CALLBACK myGLAUX_MouseMiddleEvent( AUX_EVENTREC* ); // for auxMouseFunc();
|
|
void MY_GL_CALLBACK myGLAUX_MouseRightEvent( AUX_EVENTREC* ); // for auxMouseFunc();
|
|
|
|
typedef void (CALLBACK* RHINO_GL_NURBS_ERROR)();
|
|
#endif
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLUT)
|
|
void MY_GL_CALLBACK myGLUT_Reshape( int, int ); // for glutReshapeFunc()
|
|
|
|
void MY_GL_CALLBACK myGLUT_MouseEvent( int button, int state, int x, int y );
|
|
void MY_GL_CALLBACK myGLUT_KeyboardEvent( unsigned char ch, int x, int y );
|
|
void MY_GL_CALLBACK myGLUT_SpecialKeyEvent( int ch, int x, int y ); // for auxKeyFunc();
|
|
|
|
// If you are using Apple's Xcode and you get a compile error
|
|
// on the typedef below, then try using the commented out typedef.
|
|
//
|
|
// Apple's Xcode 2.4 likes this typedef witht the (...)
|
|
typedef void (CALLBACK* RHINO_GL_NURBS_ERROR)(...);
|
|
//
|
|
// Apple's Xcode 3.2 likes this typedef witht the (...)
|
|
//typedef void (CALLBACK* RHINO_GL_NURBS_ERROR)();
|
|
#endif
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// used to set projections
|
|
//
|
|
void SetGLModelViewMatrix( const ON_Viewport& );
|
|
void SetGLProjectionMatrix( ON_Viewport& );
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
int main( int argc, const char *argv[] )
|
|
{
|
|
// reads model into global glb_model;
|
|
ON::Begin();
|
|
|
|
ON_TextLog error_log;
|
|
|
|
ON_BOOL32 bOK;
|
|
int window_width = 500;
|
|
int window_height = 500;
|
|
//double port_aspect = ((double)window_width)/((double)window_height);
|
|
|
|
// read the file into model
|
|
if ( argc != 2 ) {
|
|
printf("Syntax: %s filename.3dm\n",argv[0] );
|
|
return 0;
|
|
}
|
|
const char* sFileName = argv[1];
|
|
printf("\nFile: %s\n", sFileName );
|
|
|
|
// read the file
|
|
CModel model;
|
|
if ( !model.Read( sFileName, &error_log ) )
|
|
{
|
|
// read failed
|
|
error_log.Print("Unable to read file %s\n",sFileName);
|
|
return 1;
|
|
}
|
|
|
|
glb_model = &model;
|
|
|
|
// set bbox = world bounding box of all the objects
|
|
model.m_bbox = model.BoundingBox();
|
|
if ( !model.m_bbox.IsValid() )
|
|
{
|
|
// nothing to look at in this model
|
|
return 2;
|
|
}
|
|
|
|
// set model.m_view
|
|
if ( model.m_settings.m_views.Count() > 0 )
|
|
{
|
|
// use first viewport projection in file
|
|
double angle;
|
|
model.m_view.m_vp = model.m_settings.m_views[0].m_vp;
|
|
model.m_view.m_target = model.m_settings.m_views[0].m_target;
|
|
model.m_view.m_vp.GetCameraAngle( &angle );
|
|
model.m_view.m_vp.Extents( angle, model.m_bbox );
|
|
}
|
|
else
|
|
{
|
|
GetDefaultView( model.m_bbox, model.m_view );
|
|
}
|
|
|
|
// If needed, enlarge frustum so its aspect matches the window's aspect.
|
|
// Since the Rhino file does not store the far frustum distance in the
|
|
// file, viewports read from a Rhil file need to have the frustum's far
|
|
// value set by inspecting the bounding box of the geometry to be
|
|
// displayed.
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
//
|
|
// GL stuff starts here
|
|
//
|
|
for(;;) {
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLAUX)
|
|
wchar_t sWindowTitleString[256];
|
|
#endif
|
|
#if defined(ON_EXAMPLE_GL_USE_GLUT)
|
|
char sWindowTitleString[256];
|
|
#endif
|
|
sWindowTitleString[255] = 0;
|
|
if ( argv[0] && argv[0][0] )
|
|
{
|
|
int i;
|
|
for ( i = 0; i < 254 && argv[0][i]; i++ )
|
|
sWindowTitleString[i] = argv[0][i];
|
|
sWindowTitleString[i] = 0;
|
|
}
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLAUX)
|
|
auxInitPosition( 0, 0, window_width, window_height );
|
|
auxInitDisplayMode( AUX_SINGLE | AUX_RGB | AUX_DEPTH );
|
|
auxInitWindow( sWindowTitleString );
|
|
|
|
// register event handler functions
|
|
auxIdleFunc( 0 );
|
|
auxReshapeFunc( myGLAUX_Reshape );
|
|
auxMouseFunc( AUX_LEFTBUTTON, AUX_MOUSEDOWN, myGLAUX_MouseLeftEvent );
|
|
auxMouseFunc( AUX_LEFTBUTTON, AUX_MOUSEUP, myGLAUX_MouseLeftEvent );
|
|
auxMouseFunc( AUX_MIDDLEBUTTON, AUX_MOUSEDOWN, myGLAUX_MouseMiddleEvent );
|
|
auxMouseFunc( AUX_MIDDLEBUTTON, AUX_MOUSEUP, myGLAUX_MouseMiddleEvent );
|
|
auxMouseFunc( AUX_RIGHTBUTTON, AUX_MOUSEDOWN, myGLAUX_MouseRightEvent );
|
|
auxMouseFunc( AUX_RIGHTBUTTON, AUX_MOUSEUP, myGLAUX_MouseRightEvent );
|
|
auxKeyFunc( AUX_LEFT, myKeyLeftArrowEvent );
|
|
auxKeyFunc( AUX_RIGHT, myKeyRightArrowEvent );
|
|
auxKeyFunc( AUX_UP, myKeyUpArrowEvent );
|
|
auxKeyFunc( AUX_DOWN, myKeyDownArrowEvent );
|
|
auxKeyFunc( AUX_E, myKeyViewExtents );
|
|
auxKeyFunc( AUX_e, myKeyViewExtents );
|
|
auxKeyFunc( AUX_Z, myKeyViewExtents );
|
|
auxKeyFunc( AUX_z, myKeyViewExtents );
|
|
#endif
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLUT)
|
|
glutInit(&argc,(char**)argv);
|
|
glutInitWindowPosition( 0, 0);
|
|
glutInitWindowSize( window_width, window_height );
|
|
glutInitDisplayMode( GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH );
|
|
glutCreateWindow( sWindowTitleString );
|
|
|
|
// register event handler functions
|
|
glutIdleFunc( 0 );
|
|
glutReshapeFunc( myGLUT_Reshape );
|
|
glutMouseFunc( myGLUT_MouseEvent );
|
|
glutKeyboardFunc( myGLUT_KeyboardEvent );
|
|
glutSpecialFunc( myGLUT_SpecialKeyEvent );
|
|
glutDisplayFunc( myDisplay );
|
|
#endif
|
|
|
|
// setup model view matrix, GL defaults, and the GL NURBS renderer
|
|
GLUnurbsObj* pTheGLNURBSRender = NULL; // OpenGL NURBS rendering context
|
|
bOK = myInitGL( model.m_view.m_vp, pTheGLNURBSRender );
|
|
|
|
if ( bOK ) {
|
|
// build display list
|
|
myBuildDisplayList( glb_display_list_number,
|
|
pTheGLNURBSRender,
|
|
model );
|
|
|
|
// look at it
|
|
#if defined(ON_EXAMPLE_GL_USE_GLAUX)
|
|
auxMainLoop( myDisplay );
|
|
#endif
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLUT)
|
|
glutMainLoop( );
|
|
#endif
|
|
|
|
}
|
|
|
|
gluDeleteNurbsRenderer( pTheGLNURBSRender );
|
|
|
|
break;
|
|
}
|
|
|
|
//
|
|
// GL stuff ends here
|
|
//
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
ON::End();
|
|
|
|
return 0;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
void SetGLModelViewMatrix( const ON_Viewport& viewport )
|
|
{
|
|
ON_GL( viewport ); // updates GL model view matrix
|
|
}
|
|
|
|
void SetGLProjectionMatrix( ON_Viewport& viewport )
|
|
{
|
|
int pl, pr, pb, pt;
|
|
viewport.GetScreenPort( &pl, &pr, &pb, &pt, NULL, NULL );
|
|
ON_GL( viewport, pl, pr, pb, pt ); // updates GL projection matrix
|
|
}
|
|
|
|
ON_BOOL32 myInitGL( const ON_Viewport& viewport, GLUnurbsObj*& nobj )
|
|
{
|
|
// set the model view transform
|
|
SetGLModelViewMatrix( viewport );
|
|
|
|
// this stuff works with MSVC 4.2's Open GL. Changes may be needed for other
|
|
// GLs.
|
|
//ON_Color background_color(0,128,128);
|
|
ON_Color background_color(0,63,127);
|
|
//background_color = glb_model->m_settings.m_RenderSettings.m_background_color;
|
|
glClearColor( (float)background_color.FractionRed(),
|
|
(float)background_color.FractionGreen(),
|
|
(float)background_color.FractionBlue(),
|
|
1.0f
|
|
);
|
|
|
|
glLightModeli( GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE );
|
|
glDisable( GL_CULL_FACE );
|
|
|
|
// Rhino viewports have camera "Z" pointing at the camera in a right
|
|
// handed coordinate system.
|
|
glClearDepth( 0.0f );
|
|
glEnable( GL_DEPTH_TEST );
|
|
glDepthFunc( GL_GEQUAL );
|
|
|
|
glEnable( GL_LIGHTING );
|
|
glEnable( GL_DITHER );
|
|
//glEnable( GL_AUTO_NORMAL );
|
|
//glEnable( GL_NORMALIZE );
|
|
|
|
// default material
|
|
ON_GL( (ON_Material*)NULL );
|
|
|
|
|
|
// GL rendering of NURBS objects requires a GLUnurbsObj.
|
|
nobj = gluNewNurbsRenderer();
|
|
if ( !nobj )
|
|
return false;
|
|
|
|
gluNurbsProperty( nobj, GLU_SAMPLING_TOLERANCE, 20.0f );
|
|
gluNurbsProperty( nobj, GLU_PARAMETRIC_TOLERANCE, 0.5f );
|
|
gluNurbsProperty( nobj, GLU_DISPLAY_MODE, (GLfloat)GLU_FILL );
|
|
//gluNurbsProperty( nobj, GLU_DISPLAY_MODE, GLU_OUTLINE_POLYGON );
|
|
//gluNurbsProperty( nobj, GLU_DISPLAY_MODE, GLU_OUTLINE_PATCH );
|
|
gluNurbsProperty( nobj, GLU_SAMPLING_METHOD, (GLfloat)GLU_PATH_LENGTH );
|
|
//gluNurbsProperty( nobj, GLU_SAMPLING_METHOD, GLU_PARAMETRIC_ERROR );
|
|
//gluNurbsProperty( nobj, GLU_SAMPLING_METHOD, GLU_DOMAIN_DISTANCE );
|
|
gluNurbsProperty( nobj, GLU_CULLING, (GLfloat)GL_FALSE );
|
|
|
|
// register GL NURBS error callback
|
|
{
|
|
// hack to get around C vs C++ type checking trauma
|
|
RHINO_GL_NURBS_ERROR fn;
|
|
fn = (RHINO_GL_NURBS_ERROR)myNurbsErrorCallback;
|
|
gluNurbsCallback( nobj, GLU_ERROR, fn );
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLAUX)
|
|
void MY_GL_CALLBACK myGLAUX_Reshape( GLsizei w, GLsizei h )
|
|
{
|
|
static GLsizei w0 = 0;
|
|
static GLsizei h0 = 0;
|
|
if ( w != w0 || h != h0 ) {
|
|
h0 = h;
|
|
w0 = w;
|
|
ON_GL( glb_model->m_view.m_vp, 0, w-1, h-1, 0 ); // set projection transform
|
|
}
|
|
glViewport( 0, 0, w, h );
|
|
}
|
|
#endif
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLUT)
|
|
void MY_GL_CALLBACK myGLUT_Reshape( int w, int h )
|
|
{
|
|
static int w0 = 0;
|
|
static int h0 = 0;
|
|
if ( w != w0 || h != h0 ) {
|
|
h0 = h;
|
|
w0 = w;
|
|
ON_GL( glb_model->m_view.m_vp, 0, w-1, h-1, 0 ); // set projection transform
|
|
}
|
|
glViewport( 0, 0, w, h );
|
|
}
|
|
#endif
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
static void myRotateView( ON_Viewport& viewport,
|
|
const ON_3dVector& axis,
|
|
const ON_3dPoint& center,
|
|
double angle )
|
|
{
|
|
ON_Xform rot;
|
|
ON_3dPoint camLoc;
|
|
ON_3dVector camY, camZ;
|
|
|
|
rot.Rotation( angle, axis, center );
|
|
|
|
if ( !viewport.GetCameraFrame( camLoc, NULL, camY, camZ ) )
|
|
return;
|
|
|
|
camLoc = rot*camLoc;
|
|
camY = rot*camY;
|
|
camZ = -(rot*camZ);
|
|
|
|
viewport.SetCameraLocation( camLoc );
|
|
viewport.SetCameraDirection( camZ );
|
|
viewport.SetCameraUp( camY );
|
|
|
|
ON_GL( viewport ); // update model view
|
|
}
|
|
|
|
static void myRotateLeftRight( ON_Viewport& viewport, double angle )
|
|
{
|
|
// ON_3dVector axis = ON_zaxis; // rotate camera about world z axis (z up feel)
|
|
ON_3dVector axis = ON_zaxis; // rotate camera about world y axis (u up feel)
|
|
|
|
ON_3dPoint center;
|
|
if ( glb_model )
|
|
center = glb_model->m_view.m_target;
|
|
else
|
|
viewport.GetFrustumCenter( center );
|
|
myRotateView( viewport, axis, center, angle );
|
|
}
|
|
|
|
static void myRotateUpDown( ON_Viewport& viewport, double angle )
|
|
{
|
|
// rotates camera around the screen x axis
|
|
ON_3dVector camX;
|
|
ON_3dPoint center;
|
|
if ( glb_model )
|
|
center = glb_model->m_view.m_target;
|
|
else
|
|
viewport.GetFrustumCenter( center );
|
|
viewport.GetCameraFrame( NULL, camX, NULL, NULL );
|
|
myRotateView( viewport, camX, center, angle );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
void MY_GL_CALLBACK myKeyLeftArrowEvent( void )
|
|
{
|
|
myRotateLeftRight( glb_model->m_view.m_vp, ON_PI/12.0 );
|
|
}
|
|
|
|
void MY_GL_CALLBACK myKeyRightArrowEvent( void )
|
|
{
|
|
myRotateLeftRight( glb_model->m_view.m_vp, -ON_PI/12.0 );
|
|
}
|
|
|
|
void MY_GL_CALLBACK myKeyUpArrowEvent( void )
|
|
{
|
|
myRotateUpDown( glb_model->m_view.m_vp, ON_PI/12.0 );
|
|
}
|
|
|
|
void MY_GL_CALLBACK myKeyDownArrowEvent( void )
|
|
{
|
|
myRotateUpDown( glb_model->m_view.m_vp, -ON_PI/12.0 );
|
|
}
|
|
|
|
void MY_GL_CALLBACK myKeyViewExtents( void )
|
|
{
|
|
double half_angle = 7.5*ON_PI/180.0;
|
|
glb_model->m_view.m_vp.Extents( half_angle, glb_model->m_bbox );
|
|
SetGLModelViewMatrix( glb_model->m_view.m_vp );
|
|
SetGLProjectionMatrix( glb_model->m_view.m_vp );
|
|
}
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLAUX)
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Mouse event handling
|
|
//
|
|
|
|
static void myGLAUX_MouseEvent( GLint button, const AUX_EVENTREC* event )
|
|
{
|
|
static ON_BOOL32 bMouseActive = false;
|
|
static int mx0, my0;
|
|
int mx, my;
|
|
|
|
if ( !event ) {
|
|
bMouseActive = false;
|
|
return;
|
|
}
|
|
|
|
if ( event->event == AUX_MOUSEDOWN ) {
|
|
if ( bMouseActive ) {
|
|
bMouseActive = false;
|
|
return;
|
|
}
|
|
bMouseActive = true;
|
|
mx0 = event->data[AUX_MOUSEX];
|
|
my0 = event->data[AUX_MOUSEY];
|
|
return;
|
|
}
|
|
|
|
if ( !bMouseActive || event->event != AUX_MOUSEUP )
|
|
return;
|
|
|
|
mx = event->data[AUX_MOUSEX];
|
|
my = event->data[AUX_MOUSEY];
|
|
|
|
switch (button) {
|
|
case AUX_LEFTBUTTON:
|
|
// zoom
|
|
glb_model->m_view.m_vp.ZoomToScreenRect( mx0, my0, mx, my );
|
|
break;
|
|
case AUX_MIDDLEBUTTON:
|
|
break;
|
|
case AUX_RIGHTBUTTON:
|
|
// dolly
|
|
{
|
|
ON_3dVector dolly_vector;
|
|
double d;
|
|
ON_3dPoint camLoc;
|
|
ON_3dVector camZ;
|
|
glb_model->m_view.m_vp.GetCameraFrame( camLoc, NULL, NULL, camZ );
|
|
d = (camLoc-glb_model->m_view.m_target)*camZ;
|
|
if ( glb_model->m_view.m_vp.GetDollyCameraVector(mx0,my0,mx,my,d,dolly_vector) ) {
|
|
glb_model->m_view.m_vp.DollyCamera( dolly_vector );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// update GL model view and projection matrices to match viewport changes
|
|
SetGLModelViewMatrix( glb_model->m_view.m_vp );
|
|
SetGLProjectionMatrix( glb_model->m_view.m_vp );
|
|
|
|
bMouseActive = false;
|
|
}
|
|
|
|
void MY_GL_CALLBACK myGLAUX_MouseLeftEvent( AUX_EVENTREC* event )
|
|
{
|
|
myGLAUX_MouseEvent( AUX_LEFTBUTTON, event );
|
|
}
|
|
|
|
void MY_GL_CALLBACK myGLAUX_MouseMiddleEvent( AUX_EVENTREC* event )
|
|
{
|
|
myGLAUX_MouseEvent( AUX_MIDDLEBUTTON, event );
|
|
}
|
|
|
|
void MY_GL_CALLBACK myGLAUX_MouseRightEvent( AUX_EVENTREC* event )
|
|
{
|
|
myGLAUX_MouseEvent( AUX_RIGHTBUTTON, event );
|
|
}
|
|
#endif
|
|
|
|
#if defined(ON_EXAMPLE_GL_USE_GLUT)
|
|
|
|
void MY_GL_CALLBACK myGLUT_KeyboardEvent( unsigned char ch, int x, int y )
|
|
{
|
|
int m = glutGetModifiers();
|
|
if (m != GLUT_ACTIVE_ALT)
|
|
return;
|
|
if (ch == 'e' || ch == 'z') {
|
|
myKeyViewExtents();
|
|
glutPostRedisplay();
|
|
}
|
|
}
|
|
|
|
|
|
void MY_GL_CALLBACK myGLUT_SpecialKeyEvent( int ch, int x, int y )
|
|
{
|
|
if (ch == GLUT_KEY_LEFT)
|
|
myKeyLeftArrowEvent();
|
|
if (ch == GLUT_KEY_UP)
|
|
myKeyUpArrowEvent();
|
|
if (ch == GLUT_KEY_RIGHT)
|
|
myKeyRightArrowEvent();
|
|
if (ch == GLUT_KEY_DOWN)
|
|
myKeyDownArrowEvent();
|
|
glutPostRedisplay();
|
|
}
|
|
|
|
void myGLUT_MouseEvent( int button, int state, int x, int y )
|
|
{
|
|
static int mx0, my0;
|
|
static int mButton;
|
|
|
|
if ( state == GLUT_DOWN ) {
|
|
switch (button) {
|
|
case GLUT_LEFT_BUTTON:
|
|
case GLUT_MIDDLE_BUTTON:
|
|
case GLUT_RIGHT_BUTTON:
|
|
mButton = button;
|
|
mx0 = x;
|
|
my0 = y;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if ( state == GLUT_UP && button == mButton ) {
|
|
switch (mButton) {
|
|
case GLUT_LEFT_BUTTON:
|
|
// zoom
|
|
glb_model->m_view.m_vp.ZoomToScreenRect( mx0, my0, x, y );
|
|
break;
|
|
case GLUT_MIDDLE_BUTTON:
|
|
break;
|
|
case GLUT_RIGHT_BUTTON:
|
|
// dolly
|
|
{
|
|
ON_3dVector dolly_vector;
|
|
double d;
|
|
ON_3dPoint camLoc;
|
|
ON_3dVector camZ;
|
|
glb_model->m_view.m_vp.GetCameraFrame( camLoc, NULL, NULL, camZ );
|
|
d = (camLoc-glb_model->m_view.m_target)*camZ;
|
|
if ( glb_model->m_view.m_vp.GetDollyCameraVector(mx0,my0,x,y,d,dolly_vector) ) {
|
|
glb_model->m_view.m_vp.DollyCamera( dolly_vector );
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
// update GL model view and projection matrices to match viewport changes
|
|
SetGLModelViewMatrix( glb_model->m_view.m_vp );
|
|
SetGLProjectionMatrix( glb_model->m_view.m_vp );
|
|
glutPostRedisplay();
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void myDisplayObject( const ON_Object& geometry, const ON_Material& material, GLUnurbsObj* nobj )
|
|
{
|
|
// Called from myDisplay() to show geometry.
|
|
// Uses ON_GL() functions found in rhinoio_gl.cpp.
|
|
const ON_Point* point=0;
|
|
const ON_PointCloud* cloud=0;
|
|
const ON_Brep* brep=0;
|
|
const ON_Mesh* mesh=0;
|
|
const ON_Curve* curve=0;
|
|
const ON_Surface* surface=0;
|
|
|
|
// specify rendering material
|
|
ON_GL( material );
|
|
|
|
brep = ON_Brep::Cast(&geometry);
|
|
if ( brep )
|
|
{
|
|
ON_GL(*brep, nobj);
|
|
return;
|
|
}
|
|
|
|
mesh = ON_Mesh::Cast(&geometry);
|
|
if ( mesh )
|
|
{
|
|
ON_GL(*mesh);
|
|
return;
|
|
}
|
|
|
|
curve = ON_Curve::Cast(&geometry);
|
|
if ( curve )
|
|
{
|
|
ON_GL( *curve, nobj );
|
|
return;
|
|
}
|
|
|
|
surface = ON_Surface::Cast(&geometry);
|
|
if ( surface )
|
|
{
|
|
gluBeginSurface( nobj );
|
|
ON_GL( *surface, nobj );
|
|
gluEndSurface( nobj );
|
|
return;
|
|
}
|
|
|
|
point = ON_Point::Cast(&geometry);
|
|
if ( point )
|
|
{
|
|
ON_GL(*point);
|
|
return;
|
|
}
|
|
|
|
cloud = ON_PointCloud::Cast(&geometry);
|
|
if ( cloud )
|
|
{
|
|
ON_GL(*cloud);
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void MY_GL_CALLBACK myDisplayLighting( const ON_Viewport&, // viewport, // unreferenced
|
|
const CModel& model
|
|
)
|
|
{
|
|
int light_count = model.m_light_table.Count();
|
|
if ( light_count > 0 ) {
|
|
int maxlighti = light_count;
|
|
if ( maxlighti > GL_MAX_LIGHTS )
|
|
maxlighti = GL_MAX_LIGHTS;
|
|
int lighti;
|
|
for ( lighti = 0; lighti < maxlighti; lighti++ ) {
|
|
ON_GL( model.m_light_table[lighti].m_light, lighti+GL_LIGHT0 );
|
|
}
|
|
}
|
|
else {
|
|
// use default headlight
|
|
// use basic bright white head light with a bit of ambient
|
|
ON_Light head_light;
|
|
head_light.Default();
|
|
ON_GL( head_light, GL_LIGHT0 );
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
#if defined(MY_USE_WINDOWS_STUFF)
|
|
static void myDrawAxesSprite( const ON_Viewport& viewport, HDC hdc )
|
|
{
|
|
// Use simple Windows calls to draw world axes sprite in lower left corner.
|
|
// Note that Windows has screen (0,0) in the upper left corner; i.e,
|
|
// screen "y" increases downwards.
|
|
if ( !hdc )
|
|
return;
|
|
const int axes_size = 30;
|
|
|
|
int port_left, port_right, port_top, port_bottom;
|
|
if ( !viewport.GetScreenPort( &port_left, &port_right, &port_bottom, &port_top, NULL, NULL ) )
|
|
return;
|
|
const int scr_width = port_right - port_left; // no "+1" here
|
|
const int scr_height = port_bottom - port_top; // no "+1" here
|
|
|
|
if (4*axes_size >= scr_width )
|
|
return;
|
|
if (4*axes_size >= scr_height )
|
|
return;
|
|
|
|
int x0 = 3*axes_size/2;
|
|
int y0 = port_bottom - 3*axes_size/2;
|
|
int indx[3] = {0,1,2};
|
|
double scr_coord[3][2];
|
|
viewport.GetCoordinateSprite( axes_size, x0, y0, indx, scr_coord );
|
|
|
|
#define LXSIZE 3
|
|
#define LYSIZE 3
|
|
#define LOFF 3
|
|
|
|
// draw 3 axes from back to front
|
|
HPEN axis_pen[3];
|
|
axis_pen[0] = CreatePen( PS_SOLID, 2, RGB(255,0,0) );
|
|
axis_pen[1] = CreatePen( PS_SOLID, 2, RGB(0,255,0) );
|
|
axis_pen[2] = CreatePen( PS_SOLID, 2, RGB(0,0,255) );
|
|
HGDIOBJ saved_pen = SelectObject( hdc, axis_pen[0] );
|
|
|
|
int i, k, x, y, lx, ly;
|
|
for (i=0;i<3;i++) {
|
|
k = indx[i];
|
|
x = (int)scr_coord[k][0];
|
|
y = (int)scr_coord[k][1];
|
|
// use direction of screen vector to determine letter placement
|
|
lx = x-x0; ly = y-y0;
|
|
if (std::abs(lx) > std::abs(ly)) {
|
|
// center letter to right/left of axis end
|
|
lx = (x >= x0) ? x + LXSIZE+LOFF : x - LXSIZE-LOFF;
|
|
ly = y;
|
|
}
|
|
else if (std::abs(ly) > std::abs(lx)) {
|
|
// center letter above/below axis end
|
|
lx = x;
|
|
ly = (y >= y0) ? y + LYSIZE+LOFF : y - LYSIZE-LOFF;
|
|
}
|
|
else if (lx) {
|
|
// diagonal axis - center letter on axis
|
|
lx = (x >= x0) ? x + LXSIZE+LOFF : x - LXSIZE-LOFF;
|
|
ly = (y >= y0) ? y + LYSIZE+LOFF : y - LYSIZE-LOFF;
|
|
}
|
|
else {
|
|
// axis is perp to screen - center letter at axis end
|
|
lx = x;
|
|
ly = y;
|
|
}
|
|
SelectObject( hdc, axis_pen[k] );
|
|
|
|
// draw axis
|
|
MoveToEx( hdc, x0, y0, NULL );
|
|
LineTo( hdc, x, y );
|
|
|
|
// draw axis label
|
|
switch (k) {
|
|
case 0: // X
|
|
MoveToEx( hdc, lx-LXSIZE, ly-LYSIZE, NULL );
|
|
LineTo( hdc, lx+LXSIZE, ly+LYSIZE );
|
|
MoveToEx( hdc, lx-LXSIZE, ly+LYSIZE, NULL );
|
|
LineTo( hdc, lx+LXSIZE, ly-LYSIZE );
|
|
break;
|
|
case 1: // Y
|
|
MoveToEx( hdc, lx-LXSIZE, ly-LYSIZE, NULL );
|
|
LineTo( hdc, lx, ly );
|
|
LineTo( hdc, lx+LXSIZE, ly-LYSIZE );
|
|
MoveToEx( hdc, lx, ly, NULL );
|
|
LineTo( hdc, lx, ly+LYSIZE );
|
|
break;
|
|
case 2: // Z
|
|
MoveToEx( hdc, lx-LXSIZE, ly-LYSIZE, NULL );
|
|
LineTo( hdc, lx+LXSIZE, ly-LYSIZE );
|
|
LineTo( hdc, lx-LXSIZE, ly+LYSIZE );
|
|
LineTo( hdc, lx+LXSIZE, ly+LYSIZE );
|
|
break;
|
|
}
|
|
|
|
}
|
|
SelectObject( hdc, saved_pen );
|
|
DeleteObject( axis_pen[0] );
|
|
DeleteObject( axis_pen[1] );
|
|
DeleteObject( axis_pen[2] );
|
|
|
|
#undef LXSIZE
|
|
#undef LYSIZE
|
|
#undef LOFF
|
|
|
|
}
|
|
#endif
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void myBuildDisplayList( GLuint display_list_number,
|
|
GLUnurbsObj* pTheGLNurbsRender,
|
|
const CModel& model
|
|
)
|
|
{
|
|
ON_Material material;
|
|
glNewList( display_list_number, GL_COMPILE );
|
|
|
|
// display Rhino geometry using ON_GL() functions found in rhinoio_gl.cpp
|
|
int i;
|
|
const int object_count = model.m_object_table.Count();
|
|
for ( i = 0; i < object_count; i++ )
|
|
{
|
|
const ONX_Model_Object& mo = model.m_object_table[i];
|
|
if ( 0 != mo.m_object )
|
|
{
|
|
model.GetObjectMaterial( i, material );
|
|
myDisplayObject( *mo.m_object, material, pTheGLNurbsRender );
|
|
}
|
|
}
|
|
|
|
glEndList();
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void MY_GL_CALLBACK myDisplay( void )
|
|
{
|
|
// Uses globals glb_* because the GL aux tools don't provide an
|
|
// easy way to pass information into this callback.
|
|
int bUseRhinoSpotlights = false; // I like to use a simple headlight
|
|
// for a basic preview.
|
|
|
|
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
|
|
|
|
// lights
|
|
if ( bUseRhinoSpotlights && glb_model ) {
|
|
// Rhino spotlights (currently rotate along with geometry)
|
|
myDisplayLighting( glb_model->m_view.m_vp, *glb_model );
|
|
}
|
|
else {
|
|
// simple bright white headlight
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glPushMatrix();
|
|
glLoadIdentity();
|
|
GLfloat pos[4] = { (GLfloat)0.0, (GLfloat)0.0, (GLfloat)1.0, (GLfloat)0.0 };
|
|
glLightfv( GL_LIGHT0, GL_POSITION, pos );
|
|
GLfloat black[4] = { (GLfloat)0.0, (GLfloat)0.0, (GLfloat)0.0, (GLfloat)1.0 };
|
|
GLfloat white[4] = { (GLfloat)1.0, (GLfloat)1.0, (GLfloat)1.0, (GLfloat)1.0 };
|
|
glLightfv( GL_LIGHT0, GL_AMBIENT, black );
|
|
glLightfv( GL_LIGHT0, GL_DIFFUSE, white );
|
|
glLightfv( GL_LIGHT0, GL_SPECULAR, white );
|
|
glEnable( GL_LIGHT0 );
|
|
glPopMatrix();
|
|
}
|
|
|
|
// display list built with myBuildDisplayList()
|
|
glCallList( glb_display_list_number );
|
|
|
|
glFlush();
|
|
|
|
#if defined(MY_USE_WINDOWS_STUFF)
|
|
// Windows decorations
|
|
myDrawAxesSprite( glb_model->m_view.m_vp, wglGetCurrentDC() );
|
|
#endif
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|
|
|
|
void MY_GL_CALLBACK myNurbsErrorCallback( GLenum errCode )
|
|
{
|
|
const GLubyte* s = gluErrorString( errCode );
|
|
printf("GL NURBS ERROR: (%d) %s\n",errCode, s );
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////
|