OpenHaptics에서 HDAPI와 HLAPI를 함께 사용하는 예제
- xlos
- 개발관련팁
- 2007. 4. 18.
기타 설정 파일은 첨부파일 참조
/*****************************************************************************
Copyright (c) 2004 SensAble Technologies, Inc. All rights reserved.
OpenHaptics(TM) toolkit. The material embodied in this software and use of
this software is subject to the terms and conditions of the clickthrough
Development License Agreement.
For questions, comments or bug reports, go to forums at:
http://dsc.sensable.com
Module Name:
HelloSphere.cpp
Description:
This example demonstrates basic haptic rendering of a shape.
******************************************************************************/
#include <math.h>
#include <assert.h>
#ifdef WIN32
#include <windows.h>
#endif
#include <GL/gl.h>
#include <GL/glut.h>
#include <HL/hl.h>
#include <HDU/hduMatrix.h>
#include <HDU/hduError.h>
#include <HLU/hlu.h>
// haptic device and rendering context handles
static HHD hHD = HD_INVALID_HANDLE;
static HHLRC hHLRC = 0;
// shape id for shape we will render haptically
HLuint sphereShapeId;
#define CURSOR_SIZE_PIXELS 20
static double gCursorScale;
static GLuint gCursorDisplayList = 0;
/* Function prototypes. */
void glutDisplay(void);
void glutReshape(int width, int height);
void glutIdle(void);
void exitHandler(void);
void initGL();
void initHL();
void initScene();
void drawSceneHaptics();
void drawSceneGraphics();
void drawCursor();
void updateWorkspace();
/*************************************************************
ADDED
*************************************************************/
HDCallbackCode HDCALLBACK hdBeginCB(void *data)
{
// calling hdBeginFrame increments the HD frame counter.
hdBeginFrame(hdGetCurrentDevice());
HDErrorInfo error;
if (HD_DEVICE_ERROR(error = hdGetError()))
{
hduPrintError(stderr, &error, "Error in hdBeginCB\n");
return HD_CALLBACK_DONE;
}
return HD_CALLBACK_CONTINUE;
}
HDCallbackCode HDCALLBACK hdEndCB(void *data)
{
HDint bts;
hdGetIntegerv(HD_CURRENT_BUTTONS, &bts);
if(bts & HD_DEVICE_BUTTON_1)
{
hduVector3Dd force;
hdGetDoublev(HD_CURRENT_FORCE, force);
hdSetDoublev(HD_CURRENT_FORCE, force *= 0.1);
}
// calling hdEndFrame decrements the frame counter.
// when the beginFrame counter reaches 0, forces are rendered.
// Note that HL makes calls to hdBeginFrame & hdEndFrame internally
hdEndFrame(hdGetCurrentDevice());
HDErrorInfo error;
if (HD_DEVICE_ERROR(error = hdGetError()))
{
hduPrintError(stderr, &error, "Error in hdEndCB\n");
return HD_CALLBACK_DONE;
}
return HD_CALLBACK_CONTINUE;
}
/*************************************************************
END ADDED
*************************************************************/
/*******************************************************************************
Initializes GLUT for displaying a simple haptic scene
*******************************************************************************/
int main(int argc, char *argv[])
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH);
glutInitWindowSize(500, 500);
glutCreateWindow("HelloSphere Example");
/* Set glut callback functions. */
glutDisplayFunc(glutDisplay);
glutReshapeFunc(glutReshape);
glutIdleFunc(glutIdle);
/* Provide a cleanup routine for handling application exit. */
atexit(exitHandler);
initScene();
glutMainLoop();
return 0;
}
/*******************************************************************************
GLUT callback for redrawing the view
*******************************************************************************/
void glutDisplay()
{
drawSceneHaptics();
drawSceneGraphics();
glutSwapBuffers();
}
/*******************************************************************************
GLUT callback for reshaping the window. This is the main place where the
viewing and workspace transforms get initialized.
*******************************************************************************/
void glutReshape(int width, int height)
{
static const double kPI = 3.1415926535897932384626433832795;
static const double kFovY = 40;
double nearDist, farDist, aspect;
glViewport(0, 0, width, height);
/* Compute the viewing parameters based on a fixed fov and viewing
* a canonical box centered at the origin */
nearDist = 1.0 / tan((kFovY / 2.0) * kPI / 180.0);
farDist = nearDist + 2.0;
aspect = (double) width / height;
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(kFovY, aspect, nearDist, farDist);
/* Place the camera down the Z axis looking at the origin */
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(0, 0, nearDist + 1.0,
0, 0, 0,
0, 1, 0);
updateWorkspace();
}
/*******************************************************************************
GLUT callback for idle state. Use this as an opportunity to request a redraw.
Also check for HLAPI errors that have occurred since the last idle check
*******************************************************************************/
void glutIdle()
{
HLerror error;
while (HL_ERROR(error = hlGetError()))
{
fprintf(stderr, "HL Error: %s\n", error.errorCode);
if (error.errorCode == HL_DEVICE_ERROR)
{
hduPrintError(stderr, &error.errorInfo,
"Error during haptic rendering\n");
}
}
glutPostRedisplay();
}
/*******************************************************************************
Initialize the scene. Handle initializing both OpenGL and HL
*******************************************************************************/
void initScene()
{
initGL();
initHL();
}
/*******************************************************************************
Setup general OpenGL rendering properties, like lights, depth buffering, etc.
*******************************************************************************/
void initGL()
{
static const GLfloat light_model_ambient[] = {0.3f, 0.3f, 0.3f, 1.0f};
static const GLfloat light0_diffuse[] = {0.9f, 0.9f, 0.9f, 0.9f};
static const GLfloat light0_direction[] = {0.0f, -0.4f, 1.0f, 0.0f};
/* Enable depth buffering for hidden surface removal. */
glDepthFunc(GL_LEQUAL);
glEnable(GL_DEPTH_TEST);
/* Cull back faces. */
glCullFace(GL_BACK);
glEnable(GL_CULL_FACE);
/* Set lighting parameters */
glEnable(GL_LIGHTING);
glEnable(GL_NORMALIZE);
glShadeModel(GL_SMOOTH);
glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER, GL_FALSE);
glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, light_model_ambient);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_diffuse);
glLightfv(GL_LIGHT0, GL_POSITION, light0_direction);
glEnable(GL_LIGHT0);
}
/*******************************************************************************
Initialize the HDAPI. This involves initing a device configuration, enabling
forces, and scheduling a haptic thread callback for servicing the device.
*******************************************************************************/
void initHL()
{
HDErrorInfo error;
hHD = hdInitDevice(HD_DEFAULT_DEVICE);
if (HD_DEVICE_ERROR(error = hdGetError()))
{
hduPrintError(stderr, &error, "Failed to initialize haptic device");
fprintf(stderr, "Press any key to exit");
getchar();
exit(-1);
}
/*************************************************************
ADDED
*************************************************************/
hdScheduleAsynchronous(hdBeginCB, 0, HD_MAX_SCHEDULER_PRIORITY);
hdScheduleAsynchronous(hdEndCB, 0, HD_MIN_SCHEDULER_PRIORITY);
/*************************************************************
END ADDED
*************************************************************/
hHLRC = hlCreateContext(hHD);
hlMakeCurrent(hHLRC);
// Enable optimization of the viewing parameters when rendering
// geometry for OpenHaptics
hlEnable(HL_HAPTIC_CAMERA_VIEW);
// generate id's for the three shapes
sphereShapeId = hlGenShapes(1);
hlTouchableFace(HL_FRONT);
}
/*******************************************************************************
This handler will get called when the application is exiting.
Deallocates any state and cleans up.
*******************************************************************************/
void exitHandler()
{
// deallocate the sphere shape id we reserved in in initHL
hlDeleteShapes(sphereShapeId, 1);
// free up the haptic rendering context
hlMakeCurrent(NULL);
if (hHLRC != NULL)
{
hlDeleteContext(hHLRC);
}
// free up the haptic device
if (hHD != HD_INVALID_HANDLE)
{
hdDisableDevice(hHD);
}
}
/*******************************************************************************
Use the current OpenGL viewing transforms to initialize a transform for the
haptic device workspace so that it's properly mapped to world coordinates.
*******************************************************************************/
void updateWorkspace()
{
GLdouble modelview[16];
GLdouble projection[16];
GLint viewport[4];
glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
glGetDoublev(GL_PROJECTION_MATRIX, projection);
glGetIntegerv(GL_VIEWPORT, viewport);
hlMatrixMode(HL_TOUCHWORKSPACE);
hlLoadIdentity();
/* fit haptic workspace to view volume */
hluFitWorkspace(projection);
/* compute cursor scale */
gCursorScale = hluScreenToModelScale(modelview, projection, viewport);
gCursorScale *= CURSOR_SIZE_PIXELS;
}
/*******************************************************************************
The main routine for displaying the scene. Get the latest snapshot of state
from the haptic thread and use it for displaying a 3D cursor.
*******************************************************************************/
void drawSceneGraphics()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// draw 3D cursor at haptic device position
drawCursor();
// draw a sphere using OpenGL
glutSolidSphere(0.5, 32, 32);
}
/*******************************************************************************
The main routine for rendering scene haptics.
Renders the sphere haptically.
*******************************************************************************/
void drawSceneHaptics()
{
// start haptic frame - must do this before rendering any haptic shapes
hlBeginFrame();
// set material properties for the shapes to be drawn
hlMaterialf(HL_FRONT_AND_BACK, HL_STIFFNESS, 0.7f);
hlMaterialf(HL_FRONT_AND_BACK, HL_DAMPING, 0.1f);
hlMaterialf(HL_FRONT_AND_BACK, HL_STATIC_FRICTION, 0.2f);
hlMaterialf(HL_FRONT_AND_BACK, HL_DYNAMIC_FRICTION, 0.3f);
// start a new haptic shape, use the feedback buffer to
// capture OpenGL geometry for haptic rendering
hlBeginShape(HL_SHAPE_FEEDBACK_BUFFER, sphereShapeId);
// use OpenGL commands to create geometry
glutSolidSphere(0.5, 32, 32);
// end the shape
hlEndShape();
// end the haptic frame
hlEndFrame();
}
/*******************************************************************************
Draw a 3D cursor for the haptic device using the current local transform,
the workspace to world transform and the screen coordinate scale.
*******************************************************************************/
void drawCursor()
{
static const double kCursorRadius = 0.5;
static const double kCursorHeight = 1.5;
static const int kCursorTess = 15;
HLdouble proxyxform[16];
GLUquadricObj *qobj = 0;
glPushAttrib(GL_CURRENT_BIT | GL_ENABLE_BIT | GL_LIGHTING_BIT);
glPushMatrix();
if (!gCursorDisplayList)
{
gCursorDisplayList = glGenLists(1);
glNewList(gCursorDisplayList, GL_COMPILE);
qobj = gluNewQuadric();
gluCylinder(qobj, 0.0, kCursorRadius, kCursorHeight,
kCursorTess, kCursorTess);
glTranslated(0.0, 0.0, kCursorHeight);
gluCylinder(qobj, kCursorRadius, 0.0, kCursorHeight / 5.0,
kCursorTess, kCursorTess);
gluDeleteQuadric(qobj);
glEndList();
}
/* Get the proxy transform in world coordinates */
hlGetDoublev(HL_PROXY_TRANSFORM, proxyxform);
glMultMatrixd(proxyxform);
/* Apply the local cursor scale factor. */
glScaled(gCursorScale, gCursorScale, gCursorScale);
glEnable(GL_COLOR_MATERIAL);
glColor3f(0.0, 0.5, 1.0);
glCallList(gCursorDisplayList);
glPopMatrix();
glPopAttrib();
}