/////////////////////////////////////////////////////////////////////////////// // // OGLView.cpp : implementation file // // Purpose: Implementation of OpenGL Window of Hierarchical Animation System // // Created: // JL 9/1/97 // /////////////////////////////////////////////////////////////////////////////// // // Copyright 1997 Jeff Lander, All Rights Reserved. // For educational purposes only. // Please do not republish in electronic or print form without permission // Thanks - jeffl@darwin3d.com // /////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include #include #include "Dagger.h" #include "matrixops.h" #include "OGLView.h" #include "gltx.h" #include "motionAnalysis.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif GLint Floor = 0, Marble = 0, /* display list for marble texture */ Wood = 0, /* display list for wood texture */ OGL_AXIS_DLIST = 0, // OPENGL DISPLAY LIST ID OGL_SELECTED_DLIST = 0; // SELECTED BONE OPENGL DISPLAY LIST char *Marble_File = "marble.rgb"; char *Wood_File = "woodgrain.rgb"; #define YT -1.0 /* y translation */ #define RND ((float)rand() / ((float)RAND_MAX * 1.7)) #define MAX(a,b) ((a) > (b) ? (a) : (b)) #define SQR(a) ((a)*(a)) #define InitialBaseline 20.0 // ENABLE THE USE OF DISPLAY LISTS... // FOR TESTING I CAN COMMENT THEM OUT #define USE_DRAWLISTS 1 /// Application Definitions /////////////////////////////////////////////////// #define BOUNDING_VOLUME 3 #define ROTATE_SPEED 0.1 // SPEED OF ROTATION #define PRIMARY 0 // INDICATES ROTATION FOR INTERP START KEY #define SECONDARY 1 // INDICATES ROTATION FOR INTERP END KEY #define EULER_FIGURE 0 // INDICATES EULER FIGURE SHOULD BE DRAWN #define QUATERNION_FIGURE 1 // INDICATES QUATENINON FIGURE SHOULD BE DRAWN /////////////////////////////////////////////////////////////////////////////// #ifndef M_PI #define M_PI 3.14159265358979323846 #endif #define HALF_PI 1.57079632679489661923 /// Global Variables ////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// GLfloat cube_ambient[] = { 0.0, 0.5, 0.5, 1.0 }; GLfloat cube_diffuse_select[] = { 1.0, 0.5, 1.0, 0.0 }; GLfloat shadow[] = { 0.0, 0.0, 0.0, 1.0 }; GLfloat body_diffuse[] = { 0.7, 0.0, 0.7, 1.0 }; /////////////////////////////////////////////////////////////////////////////// // COGLView COGLView::COGLView() { // INITIALIZE THE MODE KEYS m_Skeleton = NULL; m_StatusBar = NULL; // CLEAR THIS. IT IS SET BY MAINFRAME BUT UNTIL THEN MARK IT m_UseQuat = TRUE; interpStartFrame = interpEndFrame = 0; m_AnimBlend = 0.0; m_NumEffectors = 0; m_Effectors = NULL; m_EffectorIDs = NULL; Initialize(); } void COGLView::Initialize() { m_SplitAnimation = false; m_autoCamera = NULL; m_FrontDutch = m_SideDutch = m_TopDutch = m_ObliqueDutch = 0.0; m_ZoomIn = m_ZoomOut = m_DollyOut = m_DollyIn = false; m_TiltUp = m_TiltDown = m_PanLeft = m_PanRight = false; m_TrackFace = false; m_FollowClosely = true; m_viewType = OBLIQUE_VIEW; m_showBoundingVolume = false; m_FrontFollow = m_SideFollow = m_TopFollow = m_ObliqueFollow = false; m_FrontBaseline = m_SideBaseline = m_TopBaseline = m_ObliqueBaseline = InitialBaseline; m_FrontFOV = m_SideFOV = m_TopFOV = m_ObliqueFOV = -1; m_ObliquePan = m_ObliqueTilt = 45; } COGLView::~COGLView() { } BOOL COGLView::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, t_Bone *skeleton, CSlider *slider, CCreateContext* pContext) { m_Skeleton = skeleton; m_Slider = slider; return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext); } BEGIN_MESSAGE_MAP(COGLView, CWnd) //{{AFX_MSG_MAP(COGLView) ON_WM_CREATE() ON_WM_DESTROY() ON_WM_PAINT() ON_WM_LBUTTONDOWN() ON_WM_RBUTTONDOWN() ON_WM_MOUSEMOVE() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // COGLView message handlers BOOL COGLView::SetupPixelFormat(HDC hdc) { /// Local Variables /////////////////////////////////////////////////////////// PIXELFORMATDESCRIPTOR pfd, *ppfd; int pixelformat; /////////////////////////////////////////////////////////////////////////////// ppfd = &pfd; ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR); ppfd->nVersion = 1; ppfd->dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; ppfd->dwLayerMask = PFD_MAIN_PLANE; ppfd->iPixelType = PFD_TYPE_RGBA; ppfd->cColorBits = 16; ppfd->cDepthBits = 16; ppfd->cAccumBits = 0; ppfd->cStencilBits = 0; pixelformat = ChoosePixelFormat(hdc, ppfd); if ((pixelformat = ChoosePixelFormat(hdc, ppfd)) == 0) { MessageBox("ChoosePixelFormat failed", "Error", MB_OK); return FALSE; } if (pfd.dwFlags & PFD_NEED_PALETTE) { MessageBox("Needs palette", "Error", MB_OK); return FALSE; } if (SetPixelFormat(hdc, pixelformat, ppfd) == FALSE) { MessageBox("SetPixelFormat failed", "Error", MB_OK); return FALSE; } return TRUE; } // KEITH: ADDED BUT NOT USED void COGLView::getChildPoint(t_Bone *child, float &x, float &y, float &z) { float v[16]; glGetFloatv(GL_MODELVIEW_MATRIX, v); glPushMatrix(); glTranslatef(child->trans.x, child->trans.y, child->trans.z); glRotatef(child->rot.z, 0.0f, 0.0f, 1.0f); //KEITH: PUT Z ROTATION FIRST glRotatef(child->rot.x, 1.0f, 0.0f, 0.0f); glRotatef(child->rot.y, 0.0f, 1.0f, 0.0f); glGetFloatv(GL_PROJECTION_MATRIX, v); x = v[3]; y = v[7]; z = v[11]; glPopMatrix(); } // KEITH: ADDED THIS FUNCTION void COGLView::drawEllipseStem_Joints(t_Bone *curJoint) { /* GLfloat torus_diffuse[] = { 0.7, 0.7, 0.0, 1.0 }; GLfloat cube_diffuse[] = { 0.0, 0.7, 0.7, 1.0 }; GLfloat octa_diffuse[] = { 0.7, 0.4, 0.4, 1.0 }; glutSolidTorus (0.275, 0.85, 16, 16); glutSolidCube (1.5); glutSolidOctahedron (); */ // USE SPHERICAL COORDINATES TO POSITION BODY PARTS float x = curJoint->trans.x; float y = curJoint->trans.y; float z = curJoint->trans.z; float h = sqrt(x*x + z*z); // parent: x0 = y0 = z0 = 0 glPushMatrix(); // DISTANCE TO CHILD float d = sqrt(x*x + y*y + z*z); // CHECK IF CHILD MOVED OFF THE PARENT'S Y AXIS if (h > 0) { // ORIENT PARENT'S Y AXIS TO POINT AT CHILD float phi, theta; phi = acos(x/h)*180.0/M_PI; theta = acos(y/h)*180.0/M_PI; glRotatef(phi, 0.0f, 1.0f, 0.0f); // y glRotatef(theta, 0.0f, 0.0f, 1.0f); // z if (z == 0) d = -d; // hack adjustment } else // IT DIDN'T, SO DON'T DO ANY ROTATIONS if (y < 0) d = -d; glTranslatef (0.f, d/2, 0.f); glScalef (0.1, fabs(d)/2, 0.1); //glMaterialfv(GL_FRONT, GL_DIFFUSE, body_diffuse); glutSolidSphere (1.0, 12, 8); glPopMatrix(); glPushMatrix(); glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 1.0f); // Z AXIS STARTS - COLOR BLUE glVertex3f(0,0,0); glVertex3f(x,y,z); glEnd(); glPopMatrix(); } // KEITH: ADDED THIS FUNCTION void COGLView::drawEllipseStem_Bones(t_Bone *curJoint) { // get distance of child's translation float x = curJoint->trans.x; float y = curJoint->trans.y; float z = curJoint->trans.z; float d = sqrt(x*x + y*y + z*z); if (y < 0) d = -d; glPushMatrix(); glScalef (0.1, 0.1, 0.1); //glMaterialfv(GL_FRONT, GL_DIFFUSE, sphere_diffuse); glutSolidSphere (1.0, 16, 16); glPopMatrix(); } /////////////////////////////////////////////////////////////////////////////// // Function: DrawAxis // Purpose: Draws the Axis model using GL Lines // Arguments: None /////////////////////////////////////////////////////////////////////////////// void COGLView::DrawAxis(void) { glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); // X AXIS STARTS - COLOR RED glVertex3f(-0.2f, 0.0f, 0.0f); glVertex3f( 0.2f, 0.0f, 0.0f); glVertex3f( 0.2f, 0.0f, 0.0f); // TOP PIECE OF ARROWHEAD glVertex3f( 0.15f, 0.04f, 0.0f); glVertex3f( 0.2f, 0.0f, 0.0f); // BOTTOM PIECE OF ARROWHEAD glVertex3f( 0.15f, -0.04f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); // Y AXIS STARTS - COLOR GREEN glVertex3f( 0.0f, 0.2f, 0.0f); glVertex3f( 0.0f, -0.2f, 0.0f); glVertex3f( 0.0f, 0.2f, 0.0f); // TOP PIECE OF ARROWHEAD glVertex3f( 0.04f, 0.15f, 0.0f); glVertex3f( 0.0f, 0.2f, 0.0f); // BOTTOM PIECE OF ARROWHEAD glVertex3f( -0.04f, 0.15f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); // Z AXIS STARTS - COLOR BLUE glVertex3f( 0.0f, 0.0f, 0.2f); glVertex3f( 0.0f, 0.0f, -0.2f); glVertex3f( 0.0f, 0.0f, 0.2f); // TOP PIECE OF ARROWHEAD glVertex3f( 0.0f, 0.04f, 0.15f); glVertex3f( 0.0f, 0.0f, 0.2f); // BOTTOM PIECE OF ARROWHEAD glVertex3f( 0.0f, -0.04f, 0.15f); glEnd(); } //// DrawAxis ///////////////////////////////////////////////////////////////// void COGLView::drawBoundingVolume() { glBegin(GL_LINES); glColor3f(1.0f, 1.0f, 0.0f); // YELLOW // XMIN PLANE glVertex3f(m_xmin, m_ymin, m_zmin); glVertex3f(m_xmin, m_ymin, m_zmax); glVertex3f(m_xmin, m_ymin, m_zmin); glVertex3f(m_xmin, m_ymax, m_zmin); glVertex3f(m_xmin, m_ymax, m_zmin); glVertex3f(m_xmin, m_ymax, m_zmax); glVertex3f(m_xmin, m_ymax, m_zmax); glVertex3f(m_xmin, m_ymin, m_zmax); // XMAX PLANE glVertex3f(m_xmax, m_ymin, m_zmin); glVertex3f(m_xmax, m_ymin, m_zmax); glVertex3f(m_xmax, m_ymin, m_zmin); glVertex3f(m_xmax, m_ymax, m_zmin); glVertex3f(m_xmax, m_ymax, m_zmin); glVertex3f(m_xmax, m_ymax, m_zmax); glVertex3f(m_xmax, m_ymax, m_zmax); glVertex3f(m_xmax, m_ymin, m_zmax); // ZMAX PLANE glVertex3f(m_xmin, m_ymin, m_zmax); glVertex3f(m_xmax, m_ymin, m_zmax); glVertex3f(m_xmin, m_ymax, m_zmax); glVertex3f(m_xmax, m_ymax, m_zmax); // ZMIN PLANE glVertex3f(m_xmin, m_ymin, m_zmin); glVertex3f(m_xmax, m_ymin, m_zmin); glVertex3f(m_xmin, m_ymax, m_zmin); glVertex3f(m_xmax, m_ymax, m_zmin); glEnd(); } int COGLView::OnCreate(LPCREATESTRUCT lpCreateStruct) { /// Local Variables /////////////////////////////////////////////////////////// RECT rect; /////////////////////////////////////////////////////////////////////////////// if (CWnd::OnCreate(lpCreateStruct) == -1) return -1; m_hDC = ::GetDC(m_hWnd); if (!SetupPixelFormat(m_hDC)) PostQuitMessage (0); m_hRC = wglCreateContext(m_hDC); wglMakeCurrent(m_hDC, m_hRC); GetClientRect(&rect); initializeGL(rect.right, rect.bottom); #if USE_DRAWLISTS // CREATE THE DISPLAY LIST FOR AN AXIS WITH ARROWS POINTING IN // THE POSITIVE DIRECTION Red = X, Green = Y, Blue = Z OGL_AXIS_DLIST = glGenLists(1); glNewList(OGL_AXIS_DLIST,GL_COMPILE); glBegin(GL_LINES); glColor3f(1.0f, 0.0f, 0.0f); // X AXIS STARTS - COLOR RED glVertex3f(-0.2f, 0.0f, 0.0f); glVertex3f( 0.2f, 0.0f, 0.0f); glVertex3f( 0.2f, 0.0f, 0.0f); // TOP PIECE OF ARROWHEAD glVertex3f( 0.15f, 0.04f, 0.0f); glVertex3f( 0.2f, 0.0f, 0.0f); // BOTTOM PIECE OF ARROWHEAD glVertex3f( 0.15f, -0.04f, 0.0f); glColor3f(0.0f, 1.0f, 0.0f); // Y AXIS STARTS - COLOR GREEN glVertex3f( 0.0f, 0.2f, 0.0f); glVertex3f( 0.0f, -0.2f, 0.0f); glVertex3f( 0.0f, 0.2f, 0.0f); // TOP PIECE OF ARROWHEAD glVertex3f( 0.04f, 0.15f, 0.0f); glVertex3f( 0.0f, 0.2f, 0.0f); // BOTTOM PIECE OF ARROWHEAD glVertex3f( -0.04f, 0.15f, 0.0f); glColor3f(0.0f, 0.0f, 1.0f); // Z AXIS STARTS - COLOR BLUE glVertex3f( 0.0f, 0.0f, 0.2f); glVertex3f( 0.0f, 0.0f, -0.2f); glVertex3f( 0.0f, 0.0f, 0.2f); // TOP PIECE OF ARROWHEAD glVertex3f( 0.0f, 0.04f, 0.15f); glVertex3f( 0.0f, 0.0f, 0.2f); // BOTTOM PIECE OF ARROWHEAD glVertex3f( 0.0f, -0.04f, 0.15f); glEnd(); glEndList(); // CREATE THE DISPLAY LIST THE SELECTED BONE JUST A CUBE OGL_SELECTED_DLIST = glGenLists(1); glNewList(OGL_SELECTED_DLIST,GL_COMPILE); glBegin(GL_QUADS); glColor3f(1.0f, 1.0f, 0.0f); // YELLOW // BOTTOM glVertex3f(-0.05f, -0.05f, -0.05f); glVertex3f( 0.05f, -0.05f, -0.05f); glVertex3f( 0.05f, -0.05f, 0.05f); glVertex3f(-0.05f, -0.05f, 0.05f); // BACK glVertex3f(-0.05f, 0.05f, -0.05f); glVertex3f( 0.05f, 0.05f, -0.05f); glVertex3f( 0.05f, -0.05f, -0.05f); glVertex3f(-0.05f, -0.05f, -0.05f); // FRONT glVertex3f(-0.05f, -0.05f, 0.05f); glVertex3f( 0.05f, -0.05f, 0.05f); glVertex3f( 0.05f, 0.05f, 0.05f); glVertex3f(-0.05f, 0.05f, 0.05f); // RIGHT glVertex3f(-0.05f, -0.05f, -0.05f); glVertex3f(-0.05f, -0.05f, 0.05f); glVertex3f(-0.05f, 0.05f, 0.05f); glVertex3f(-0.05f, 0.05f, -0.05f); // LEFT glVertex3f( 0.05f, 0.05f, -0.05f); glVertex3f( 0.05f, 0.05f, 0.05f); glVertex3f( 0.05f, -0.05f, 0.05f); glVertex3f( 0.05f, -0.05f, -0.05f); // TOP glVertex3f(-0.05f, 0.05f, 0.05f); glVertex3f( 0.05f, 0.05f, 0.05f); glVertex3f( 0.05f, 0.05f, -0.05f); glVertex3f(-0.05f, 0.05f, -0.05f); glEnd(); glEndList(); #endif drawScene(); return 0; } /* OpenGL code */ /////////////////////////////////////////////////////////////////////////////// // Function: resize // Purpose: This code handles the windows resize for OpenGL // Arguments: Width and heights of the view window /////////////////////////////////////////////////////////////////////////////// GLvoid COGLView::resize( GLsizei width, GLsizei height ) { glViewport(0, 0, width, height); aspect = (GLfloat)width/(GLfloat)height; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(45.0, aspect, 3.0, 7.0); glMatrixMode(GL_MODELVIEW); } //// resize ///////////////////////////////////////////////////////////////// GLvoid COGLView::initializeGL(GLsizei width, GLsizei height) { //glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClearColor(0.1f, 0.1f, 0.2f, 0.0f); glClearDepth(1.0); glDepthFunc(GL_LESS); glShadeModel(GL_SMOOTH); //glShadeModel(GL_FLAT); glEnable(GL_DEPTH_TEST); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_NORMALIZE); glEnable(GL_BLEND); glDisable(GL_DITHER); glMatrixMode(GL_PROJECTION); aspect = (GLfloat)width/(GLfloat)height; // Establish viewing volume gluPerspective(10.0, aspect,1, 2000); glMatrixMode(GL_MODELVIEW); // SET SOME OGL INITIAL STATES SO THEY ARE NOT DONE IN THE DRAW LOOP glPolygonMode(GL_FRONT,GL_FILL); glDepthFunc(GL_LESS); //glEnable(GL_CULL_FACE); glHint(GL_LINE_SMOOTH_HINT,GL_FASTEST); // LOAD TEXTURE GLTXimage *image; image = gltxReadRGB(Marble_File); Marble = glGenLists(1); glNewList(Marble, GL_COMPILE_AND_EXECUTE); { /* modulate the texture for highlights */ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); /* bi-linear mipmapping */ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* build the mipmaps */ gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->width, image->height, GL_RGB, GL_UNSIGNED_BYTE, image->data); } glEndList(); gltxDelete(image); image = gltxReadRGB(Wood_File); Wood = glGenLists(1); glNewList(Wood, GL_COMPILE_AND_EXECUTE); { /* modulate the texture for highlights */ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); /* bi-linear mipmapping */ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); /* build the mipmaps */ gluBuild2DMipmaps(GL_TEXTURE_2D, 3, image->width, image->height, GL_RGB, GL_UNSIGNED_BYTE, image->data); } glEndList(); gltxDelete(image); // CREATE CALL LIST FOR FLOOR GLfloat green[] = { 10, 0.874, 0.143, 1.0 }; GLfloat blue[] = { 0.123, 0.32, 0.798, 1.0 }; GLfloat specular[] = { 0.1, 0.1, 0.1, 0.1 }; Floor = glGenLists(1); glNewList(Floor, GL_COMPILE); { /* set the material */ glMaterialfv(GL_FRONT, GL_DIFFUSE, green); glMaterialfv(GL_FRONT, GL_AMBIENT, green); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); glMaterialf(GL_FRONT, GL_SHININESS, 20.0); /* use i to count the tiles */ int i = 0, name = 0, x, z; for(x = -4.0; x < 4.0; x += 1.0) { for(z = -4.0; z < 4.0; z += 1.0) { i++; /* draw only every other tile - * use i to determine if we need * to draw this tile or not */ if(i % 2) { glLoadName(name++); glBegin(GL_QUADS); { glTexCoord2f(0.0 + RND, 1.0 + RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x, YT, z); glTexCoord2f(0.0 + RND, 0.0 + RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x, YT, z + 1.0); glTexCoord2f(1.0 - RND, 0.0 + RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x + 1.0, YT, z + 1.0); glTexCoord2f(1.0 - RND, 1.0 - RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x + 1.0, YT, z); } glEnd(); } } /* add 1 to i, so we start on the * opposite type of number (odd/even) * each row */ i++; } /* do it again so we get the * other tiles, but this time in * a different material - set i * to 1, so that we start on a * different tile than before */ i = 1; /* set the material */ glMaterialfv(GL_FRONT, GL_DIFFUSE, blue); glMaterialfv(GL_FRONT, GL_AMBIENT, blue); glMaterialfv(GL_FRONT, GL_SPECULAR, specular); glMaterialf(GL_FRONT, GL_SHININESS, 10.0); for(x = -4.0; x < 4.0; x += 1.0) { for(z = -4.0; z < 4.0; z += 1.0) { i++; /* draw only every other tile - * use i to determine if we need * to draw this tile or not */ if(i % 2) { glLoadName(name++); glBegin(GL_QUADS); { glTexCoord2f(0.0 + RND, 1.0 + RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x, YT, z); glTexCoord2f(0.0 + RND, 0.0 + RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x, YT, z + 1.0); glTexCoord2f(1.0 - RND, 0.0 + RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x + 1.0, YT, z + 1.0); glTexCoord2f(1.0 - RND, 1.0 - RND); glNormal3f(0.0, 1.0, 0.0); glVertex3f(x + 1.0, YT, z); } glEnd(); } } /* add 1 to i, so we start on the * opposite type of number (odd/even) * each row */ i++; } } glEndList(); } void COGLView::destroyEndEffectors() { for (int i = 0; i < m_NumEffectors; i++) free(m_Effectors[i]); free(m_Effectors); free(m_EffectorIDs); m_NumEffectors = 0; m_Effectors = NULL; } void COGLView::setupEndEffectors(t_Bone *root) { if (m_Format == BVA_FORMAT) return; if (!strcmp(root->name, "Site")) { m_NumEffectors++; return; } else for (int i = 0; i < root->childCnt; i++) setupEndEffectors(root->children + i); // LEAVE IF NOT AT THE ROOT if (root != m_Skeleton) return; // LEAVE IF NO END EFFECTORS (this fcn. is called before a // skeleton is loaded, so avoid allocating memory then) if (m_NumEffectors == 0) return; // draw the motion sequence bounding box if (m_Skeleton->MA) { m_Skeleton->MA->getGlobalBoundingBox(m_xmin, m_ymin, m_zmin, m_xmax, m_ymax, m_zmax); m_Skeleton->MA->plotCameraFollowPath(m_FollowSmoothing); } m_cameraTargetX = m_Skeleton->children->primChannel[0]; m_cameraTargetY = m_Skeleton->children->primChannel[1]; m_cameraTargetZ = m_Skeleton->children->primChannel[2]; // ALLOCATE MEMORY TO HOLD THE EFFECTOR POSITIONS int frameCount = root->children->primFrameCount; m_Effectors = (float**) malloc(sizeof(float*)*m_NumEffectors); for (int i = 0; i < m_NumEffectors; i++) m_Effectors[i] = (float*) malloc(sizeof(float)*frameCount*3); m_EffectorIDs = (t_Bone**) malloc(sizeof(t_Bone*)*m_NumEffectors); // GET THE EFFECTOR POSITIONS root = root->children; for (int frame = 0; frame < frameCount; frame++) { int effNum = 0; MRot Identity = { 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; BoneSetFrame(root->parent, frame); getEndEffectors(root, effNum, frame, 0, 0, 0, Identity); } BoneSetFrame(root->parent, 0); } // find the global positions of the end effectors for the current frame void COGLView::getEndEffectors(t_Bone *root, int &effNum, int curFrame, float x, float y, float z, MRot rot) { // set the joint's parameters for the current frame BoneSetFrame(root, curFrame); //float x1, y1, z1, tx, ty, tz; float tx, ty, tz, theta, cx, sx, cy, sy, cz, sz; // DO NEW OFFSET RELATIVE TO GLOBAL ORIGIN tx = root->trans.x; ty = root->trans.y; tz = root->trans.z; // ROTATE VECTOR COUNTERCLOCKWISE USING CUMULATIVE ROTATIONS double v[4] = { tx, ty, tz, 1 }; double v2[4]; multMatrixVector(rot.Matrix, v, v2); // TRANSLATE SYSTEM BACK TO ORIGINAL LOCATION x += v2[0]; y += v2[1]; z += v2[2]; // ACCUMULATE ROTATIONS FOR THE FUTURE // get local rotations first theta = root->rot.z*(M_PI/180.0); cz = cos(theta); sz = sin(theta); theta = root->rot.x*(M_PI/180.0); cx = cos(theta); sx = sin(theta); theta = root->rot.y*(M_PI/180.0); cy = cos(theta); sy = sin(theta); double local[4][4] = { cz*cy-sz*sx*sy, -sz*cx, cz*sy+sz*sx*cy, 0, sz*cy+cz*sx*sy, cz*cx, sz*sy-cz*sx*cy, 0, -cx*sy, sx, cx*cy, 0, 0, 0, 0, 1 }; double result[4][4]; // accumulate multMatrix(rot.Matrix, local, result); copyMatrix(result, rot.Matrix); if (!strcmp(root->name, "Site")) { float *pts = m_Effectors[effNum] + curFrame*3; pts[0] = x; pts[1] = y; pts[2] = z; m_EffectorIDs[effNum] = root; effNum++; } else { for (int i = 0; i < root->childCnt; i++) getEndEffectors(root->children + i, effNum, curFrame, x, y, z, rot); } // resets frame to zero BoneSetFrame(root, 0); } void COGLView::drawEndEffectors(void) { if (m_Format != BVA_FORMAT && m_Skeleton->childCnt) { for (int effNum = 0; effNum < m_NumEffectors; effNum++) { // set material for selected end effector if (m_Skeleton->id == (long)m_EffectorIDs[effNum]) glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse_select); //glBegin(GL_LINE_STRIP); int curFrame = m_Skeleton->children->primCurFrame; int startFrame = (curFrame < 15 ? 0 : curFrame - 15); for (int frame = startFrame; frame <= curFrame; frame++) { glPushMatrix(); float *pts = m_Effectors[effNum] + frame*3; glTranslatef(pts[0], pts[1], pts[2]); //glColor3f(1.0f, 1.0f, 1.0f); //glVertex3f(0, 0, 0); glutSolidCube (.075); glPopMatrix(); } //glEnd(); // reset material if (m_Skeleton->id == (long)m_EffectorIDs[effNum]) glMaterialfv(GL_FRONT, GL_AMBIENT, cube_ambient); } } } /////////////////////////////////////////////////////////////////////////////// // Function: drawScene // Purpose: Actually draw the OpenGL Scene // Arguments: None /////////////////////////////////////////////////////////////////////////////// GLvoid COGLView::drawScene(GLvoid) { // set default camera target at center of motion volume float camTargetX = m_xmin + (m_xmax-m_xmin)/2; float camTargetY = m_ymin + (m_ymax-m_ymin)/2; float camTargetZ = m_zmin + (m_zmax-m_zmin)/2; float baseline, FOV; ///////////////////////////////////////////////////////////////////////////// // TRACK FACE (CLOSEUP) if (m_Skeleton->MA && m_TrackFace) { // get target int frame = m_Skeleton->children->primCurFrame; m_Skeleton->MA->getFaceTarget(frame, camTargetX, camTargetY, camTargetZ); // get FOV FOV = m_Skeleton->MA->getFaceFOV(InitialBaseline); } ///////////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////// // TRACK BODY (FITTING FIGURE IN FRAME) if (m_Skeleton->MA && m_FollowClosely) { // get target int frame = m_Skeleton->children->primCurFrame; m_Skeleton->MA->getCameraTarget(frame, camTargetX, camTargetY, camTargetZ); // get FOV FOV = m_Skeleton->MA->getFOV(InitialBaseline); } ///////////////////////////////////////////////// // CHANGE CAMERA FIELD OF VIEW, BASELINE, PAN, TILT. // ALSO, SET THE FOV (BUT NOT BASELINE, PAN NOR TILT). if (m_Skeleton->MA && !m_TrackFace && !m_FollowClosely) { // CHANGE FIELD OF VIEW BASED ON USER INPUT float deltaFOV = 0.0, deltaBaseline = 0.0, deltaPan = 0.0, deltaTilt = 0.0; if (m_ZoomIn) deltaFOV = -0.5; else if (m_ZoomOut) deltaFOV = 0.5; else if (m_DollyOut) deltaBaseline = -0.5; else if (m_DollyIn) deltaBaseline = 0.5; if (m_PanLeft) deltaPan = -ROTATE_SPEED*15.0; else if (m_PanRight) deltaPan = ROTATE_SPEED*15.0; if (m_TiltUp) deltaTilt = -ROTATE_SPEED*10.0; else if (m_TiltDown) deltaTilt = ROTATE_SPEED*10.0; switch (m_viewType) { case FRONT_VIEW: if (m_FrontFOV + deltaFOV >= 0) m_FrontFOV += deltaFOV; else m_ZoomOut = m_ZoomIn = false; if (m_FrontBaseline + deltaBaseline >= 0) m_FrontBaseline += deltaBaseline; else m_DollyOut = m_DollyIn = false; FOV = m_FrontFOV; baseline = m_FrontBaseline; break; case SIDE_VIEW: if (m_SideFOV + deltaFOV >= 0) m_SideFOV += deltaFOV; else m_ZoomOut = m_ZoomIn = false; if (m_SideBaseline + deltaBaseline >= 0) m_SideBaseline += deltaBaseline; else m_DollyOut = m_DollyIn = false; FOV = m_SideFOV; baseline = m_SideBaseline; break; case TOP_VIEW: if (m_TopFOV + deltaFOV >= 0) m_TopFOV += deltaFOV; else m_ZoomOut = m_ZoomIn = false; if (m_TopBaseline + deltaBaseline >= 0) m_TopBaseline += deltaBaseline; else m_DollyOut = m_DollyIn = false; FOV = m_TopFOV; baseline = m_TopBaseline; break; case OBLIQUE_VIEW: if (m_ObliqueFOV + deltaFOV >= 0) m_ObliqueFOV += deltaFOV; else m_ZoomOut = m_ZoomIn = false; if (m_ObliqueBaseline + deltaBaseline >= 0) m_ObliqueBaseline += deltaBaseline; else m_DollyOut = m_DollyIn = false; if ((m_ObliqueTilt + deltaTilt > 0) && (m_ObliqueTilt + deltaTilt <= 90)) m_ObliqueTilt += deltaTilt; else m_TiltUp = m_TiltDown = false; if (m_ObliquePan > 360) m_ObliquePan -= 360.0; else if (m_ObliquePan < 0) m_ObliquePan += 360.0; m_ObliquePan += deltaPan; FOV = m_ObliqueFOV; baseline = m_ObliqueBaseline; } char message[20]; sprintf(message, "%0.1f", baseline); m_StatusBar->SetPaneText(6,message); sprintf(message, "%0.1f", FOV); m_StatusBar->SetPaneText(7,message); sprintf(message, "%0.1f", m_ObliquePan); m_StatusBar->SetPaneText(8,message); sprintf(message, "%0.1f", m_ObliqueTilt); m_StatusBar->SetPaneText(9,message); } glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(FOV, aspect, 0.01, 2000); //glFrustum(xmin, xmax, ymin, ymax, 1, 2000); glMatrixMode(GL_MODELVIEW); ///////////////////////////////////////////////// GLfloat light_ambient[] = { 1.0, 1.0, 1.0, 1.0 }; glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient); glPushMatrix(); glDisable(GL_DEPTH_TEST); // TURN OFF DEPTH TEST FOR CLEAR glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glEnable(GL_DEPTH_TEST); // ENABLE DEPTH TESTING ///////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // FOLLOW CLOSELY if (m_Skeleton->MA && m_FollowClosely) { // camera orientation float rotY = m_initHipsNormal*M_PI/180.0; // auto cut between two cameras if (m_autoCamera) { // find hips normal int index = s_Channel_Type_Size[m_Skeleton->children->primChanType]*(m_Skeleton->children->primCurFrame); float hipsNormal = m_Skeleton->children->primChannel[index+5]; int normalDiff = hipsNormal - m_initHipsNormal; if (normalDiff > 360) normalDiff -= 360; if (normalDiff < 0) normalDiff += 360; if ((normalDiff >= 300 && normalDiff <= 360) || (normalDiff >= 0 && normalDiff < 120)) { // camera 1 char message[20]; sprintf(message, "C1: %d", normalDiff); m_StatusBar->SetPaneText(2,message); } else { // camera 2 rotY = (m_initHipsNormal+240)*M_PI/180.0; char message[20]; sprintf(message, "C2: %d", normalDiff); m_StatusBar->SetPaneText(2,message); } } float x = 0, y = 0; float z = InitialBaseline; float Rot[4][4] = {cos(rotY), 0, sin(rotY), 0, //x 0, 1, 0, 0, //y -sin(rotY), 0, cos(rotY), 0, //z 0, 0, 0, 1 }; //1 float x1 = Rot[0][0]*x + Rot[0][1]*y + Rot[0][2]*z; float y1 = Rot[1][0]*x + Rot[1][1]*y + Rot[1][2]*z; float z1 = Rot[2][0]*x + Rot[2][1]*y + Rot[2][2]*z; x = x1 + camTargetX; y = y1 + camTargetY; z = z1 + camTargetZ; //float baseline = (m_FrontBaseline >= InitialBaseline ? m_FrontBaseline : InitialBaseline); gluLookAt(x, y, z, camTargetX, camTargetY, camTargetZ, 0.0, 1.0, 0.0); } //////////////////////////////////////////////////////////////////////////// // SPOTLIGHT FOLLOW bool follow; switch (m_viewType) { case FRONT_VIEW: follow = m_FrontFollow; break; case SIDE_VIEW: follow = m_SideFollow; break; case TOP_VIEW: follow = m_TopFollow; break; case OBLIQUE_VIEW: follow = m_ObliqueFollow; } if (m_Skeleton->MA && follow) { // maintain baseline (set when "follow" chosen by director) by zooming float baseline = 0.f; switch (m_viewType) { case FRONT_VIEW: baseline = m_FrontBaseline; break; case SIDE_VIEW: baseline = m_SideBaseline; break; case TOP_VIEW: baseline = m_TopBaseline; break; case OBLIQUE_VIEW: baseline = m_ObliqueBaseline; } if (baseline >= InitialBaseline) baseline = 1.0; else if (baseline > 0) baseline = log10(baseline)/log10(InitialBaseline); float camSuggestedX, camSuggestedY, camSuggestedZ; int frame = m_Skeleton->children->primCurFrame; m_Skeleton->MA->getCameraTarget(frame, camSuggestedX, camSuggestedY, camSuggestedZ); float xDiff = camTargetX - camSuggestedX; float yDiff = camTargetY - camSuggestedY; float zDiff = camTargetZ - camSuggestedZ; camTargetX = camSuggestedX + xDiff*baseline; camTargetY = camSuggestedY + yDiff*baseline; camTargetZ = camSuggestedZ + zDiff*baseline; } /////////////////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////// // CAMERA VIEWING POSITIONS if (m_Skeleton->MA && !m_FollowClosely) { float x = m_xmin + (m_xmax-m_xmin)/2; float y = m_ymin + (m_ymax-m_ymin)/2; float z = m_zmin + (m_zmax-m_zmin)/2; float unitX = 0.0, unitY = 0.0, unitZ = 0.0; switch (m_viewType) { case FRONT_VIEW: unitX = sin(m_FrontDutch*M_PI/180.f); unitY = cos(m_FrontDutch*M_PI/180.f); gluLookAt(x, y, m_zmax + m_FrontBaseline, camTargetX, camTargetY, camTargetZ, unitX, unitY, 0.0); break; case SIDE_VIEW: gluLookAt(m_xmax + m_SideBaseline, y, z, camTargetX, camTargetY, camTargetZ, 0.0, 1.0, 0.0); break; case TOP_VIEW: gluLookAt(x, m_ymax + m_TopBaseline, z, camTargetX, camTargetY, camTargetZ, 0.0, 0.0, -1.0); break; case OBLIQUE_VIEW: float yoff = m_ObliqueBaseline*cos(m_ObliqueTilt*(M_PI/180.0)); float d = (float) sqrt(SQR(m_ObliqueBaseline) - SQR(yoff)); float xoff = d*sin(m_ObliquePan*(M_PI/180.0)); float zoff = d*cos(m_ObliquePan*(M_PI/180.0)); gluLookAt(x + xoff, y + yoff, z + zoff, camTargetX, camTargetY, camTargetZ, 0.0, 1.0, 0.0); } } ///////////////////////////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////// // DRAW THE SCENE // draw the floor //GLfloat floor_diffuse[] = { 0.5, 0.5, 1.0, 0.0 }; //GLfloat floor_ambient[] = { 0.5, 0.5, 0.5, 0.5 }; //glMaterialfv(GL_FRONT, GL_DIFFUSE, floor_diffuse); //glMaterialfv(GL_FRONT, GL_AMBIENT, floor_ambient); glPushMatrix(); //glRotatef(180.0, 1.0f, 0.f, 0.f); //glScalef(50.0, 0.1, 50.0); //glutSolidCube (1.0); glEnable(GL_TEXTURE_2D); glScalef(5.0, 0.1, 5.0); glCallList(Marble); glCallList(Floor); glDisable(GL_TEXTURE_2D); glPopMatrix(); if (m_Skeleton->MA && m_showBoundingVolume) { //glCallList(BOUNDING_VOLUME); drawBoundingVolume(); } // material for skeleton //glMaterialfv(GL_FRONT, GL_DIFFUSE, cube_diffuse); glMaterialfv(GL_FRONT, GL_AMBIENT, cube_ambient); if (m_SplitAnimation) { glPushMatrix(); glScalef(0.8f, 0.8f, 0.8f); glTranslatef(2, 0, 0); // MOVE EVERYTHING TO THE OBSERVER'S RIGHT // SHOW END EFFECTOR TRAIL //drawEndEffectors(); // KEITH: MODIFIED THIS LOOP TO USE THE FOLLOWING FUNCTION drawSkeletonRecursive(m_Skeleton, true); // RIGHT FIGURE (Quaternions) // DRAW SHADOW glPushMatrix(); glMaterialfv(GL_FRONT, GL_DIFFUSE, shadow); glTranslatef(0.0, 0.1, 0.0); if (m_Skeleton->childCnt) //glScalef(1.0, 0.01f, 1.0); glScalef(1.5/log(m_Skeleton->children->trans.y), 0.01f, 1.5/log(m_Skeleton->children->trans.y)); drawSkeletonRecursive(m_Skeleton, m_UseQuat); glPopMatrix(); // KEITH: MODIFIED THIS LOOP TO USE THE FOLLOWING FUNCTION glTranslatef(-5, 0, 0); // SHOW END EFFECTOR TRAIL //drawEndEffectors(); glMaterialfv(GL_FRONT, GL_AMBIENT, cube_ambient); drawSkeletonRecursive(m_Skeleton, false); // LEFT FIGURE (Euler) // DRAW SHADOW glMaterialfv(GL_FRONT, GL_DIFFUSE, shadow); glTranslatef(0.0, 0.1, 0.0); if (m_Skeleton->childCnt) glScalef(1.5/log(m_Skeleton->children->trans.y), 0.01f, 1.5/log(m_Skeleton->children->trans.y)); drawSkeletonRecursive(m_Skeleton, m_UseQuat); glPopMatrix(); } else { // SHOW END EFFECTOR TRAIL drawSkeletonRecursive(m_Skeleton, m_UseQuat); //if (!m_Slider->isSliding()) drawEndEffectors(); /* // DRAW SHADOW glMaterialfv(GL_FRONT, GL_DIFFUSE, shadow); glTranslatef(0.0, 0.1, 0.0); if (m_Skeleton->childCnt) //glScalef(1.0, 0.01f, 1.0); glScalef(1.5/log(m_Skeleton->children->trans.y), 0.01f, 1.5/log(m_Skeleton->children->trans.y)); drawSkeletonRecursive(m_Skeleton, m_UseQuat); */ } glPopMatrix(); glFinish(); SwapBuffers(m_hDC); UpdateStatusBarFrameInfo(); } //// drawScene ////////////////////////////////////////////////////// // KEITH: ADDED THE FOLLOWING FUNCTION void COGLView::drawSkeletonRecursive(t_Bone *root, BOOL useQuat) { t_Bone *curJoint; tQuaternion primaryQuat,secondaryQuat,axisAngle; for (int loop = 0; loop < root->childCnt; loop++) { curJoint = root->children + loop; // DRAW THE BONE (FOR BVH) if (root != m_Skeleton) drawEllipseStem_Joints(curJoint); glPushMatrix(); // SEE IF SLIDER IS BEING USED TO SHOW INTERPOLATION if (m_Slider->isSliding() && interpEndFrame != interpStartFrame) { // GET THE INTERPOLATION SCALE m_AnimBlend = m_Slider->GetSetting(); // LINEARLY INTERPOLATE THE TRANSLATION curJoint->trans.x = curJoint->p_trans.x + (curJoint->s_trans.x - curJoint->p_trans.x)*m_AnimBlend; curJoint->trans.y = curJoint->p_trans.y + (curJoint->s_trans.y - curJoint->p_trans.y)*m_AnimBlend; curJoint->trans.z = curJoint->p_trans.z + (curJoint->s_trans.z - curJoint->p_trans.z)*m_AnimBlend; glTranslatef(curJoint->trans.x, curJoint->trans.y, curJoint->trans.z); // INTERPOLATE THE ROTATIONS if (useQuat) { // SLERPED QUATERNIONS // (WHEN ANGLE ~ 0, INTERPOLATION ILL-DEFINED ==> DON'T SLERP) if (curJoint->primChanType != CHANNEL_TYPE_NONE) { EulerToQuaternion(&root->p_rot,&primaryQuat, curJoint->primChanType); EulerToQuaternion(&root->s_rot,&secondaryQuat, curJoint->primChanType); SlerpQuat(&primaryQuat,&secondaryQuat,m_AnimBlend,&root->quat); } // QUATERNION HAS TO BE CONVERTED TO AN AXIS/ANGLE REPRESENTATION QuatToAxisAngle(&curJoint->quat,&axisAngle); // DO THE ROTATION glRotatef(axisAngle.w, axisAngle.x, axisAngle.y, axisAngle.z); } else { // LERPED EULER ANGLES curJoint->rot.x = curJoint->p_rot.x + (curJoint->s_rot.x - curJoint->p_rot.x)*m_AnimBlend; curJoint->rot.y = curJoint->p_rot.y + (curJoint->s_rot.y - curJoint->p_rot.y)*m_AnimBlend; curJoint->rot.z = curJoint->p_rot.z + (curJoint->s_rot.z - curJoint->p_rot.z)*m_AnimBlend; // DO THE ROTATION glRotatef(curJoint->rot.z, 0.0f, 0.0f, 1.0f); //KEITH: PUT Z ROTATION FIRST glRotatef(curJoint->rot.x, 1.0f, 0.0f, 0.0f); glRotatef(curJoint->rot.y, 0.0f, 1.0f, 0.0f); } // INTERPOLATE THE FRAME NUMBER curJoint->primCurFrame = interpStartFrame + (interpEndFrame - interpStartFrame)*m_AnimBlend; } // NO, DISLAY REGULAR ANIMATION SEQUENCE else { glTranslatef(curJoint->trans.x, curJoint->trans.y, curJoint->trans.z); if (useQuat) { // QUATERNION HAS TO BE CONVERTED TO AN AXIS/ANGLE REPRESENTATION QuatToAxisAngle(&curJoint->quat,&axisAngle); // DO THE ROTATION glRotatef(axisAngle.w, axisAngle.x, axisAngle.y, axisAngle.z); } else { // Set observer's orientation and position glRotatef(curJoint->rot.z, 0.0f, 0.0f, 1.0f); //KEITH: PUT Z ROTATION FIRST glRotatef(curJoint->rot.x, 1.0f, 0.0f, 0.0f); glRotatef(curJoint->rot.y, 0.0f, 1.0f, 0.0f); } } // DRAW THE BONE (FOR BVA) if (m_Format == BVA_FORMAT) drawEllipseStem_Bones(curJoint); // draw the object #ifdef keith #if USE_DRAWLISTS // DRAW THE AXIS OGL OBJECT glCallList(OGL_AXIS_DLIST); // IF SOMETHING IS SELECTED, DRAW TAG BOX if (m_Skeleton->id == (long)curJoint) glCallList(OGL_SELECTED_DLIST); drawEllipseStem_Bones(curJoint); #else // DRAW THE AXIS OGL OBJECT USING DRAW ROUTINE if (m_Format == BVA_FORMAT) drawEllipseStem_Bones(curJoint); else if (!strcmp(curJoint->name,"Site")) DrawAxis(); #endif #endif if (curJoint->childCnt > 0) drawSkeletonRecursive(curJoint, useQuat); glPopMatrix(); } } void COGLView::OnDestroy() { CWnd::OnDestroy(); if (m_hRC) wglDeleteContext(m_hRC); if (m_hDC) ::ReleaseDC(m_hWnd,m_hDC); m_hRC = 0; m_hDC = 0; } void COGLView::OnPaint() { CPaintDC dc(this); // device context for painting drawScene(); // Do not call CWnd::OnPaint() for painting messages } void COGLView::OnLButtonDown(UINT nFlags, CPoint point) { // STORE OFF THE KIT POINT AND SETTINGS FOR THE MOVEMENT LATER m_mousepos = point; m_Grab_Rot_X = m_Skeleton->rot.x; m_Grab_Rot_Y = m_Skeleton->rot.y; m_Grab_Rot_Z = m_Skeleton->rot.z; m_Grab_Trans_X = m_Skeleton->trans.x; m_Grab_Trans_Y = m_Skeleton->trans.y; m_Grab_Trans_Z = m_Skeleton->trans.z; CWnd::OnLButtonDown(nFlags, point); } void COGLView::OnRButtonDown(UINT nFlags, CPoint point) { // STORE OFF THE KIT POINT AND SETTINGS FOR THE MOVEMENT LATER m_mousepos = point; m_Grab_Rot_X = m_Skeleton->rot.x; m_Grab_Rot_Y = m_Skeleton->rot.y; m_Grab_Rot_Z = m_Skeleton->rot.z; m_Grab_Trans_X = m_Skeleton->trans.x; m_Grab_Trans_Y = m_Skeleton->trans.y; m_Grab_Trans_Z = m_Skeleton->trans.z; CWnd::OnRButtonDown(nFlags, point); } // 0 = READY // 1 = ROTATE // 2 = TRANSLATE void COGLView::UpdateStatusBar(int mode) { /// Local Variables /////////////////////////////////////////////////////////// char message[80]; /////////////////////////////////////////////////////////////////////////////// if (mode == 1) { strcpy(message,"Pan/Tilt"); } else if (mode == 2) { strcpy(message,"Translate"); } else if (mode == 3) { strcpy(message,"Dolly"); } else if (mode == 4) { strcpy(message,"Zoom"); } else { strcpy(message,"Ready"); } m_StatusBar->SetPaneText(0,message); } void COGLView::UpdateStatusBarFrameInfo() { /// Local Variables /////////////////////////////////////////////////////////// char message[80]; /////////////////////////////////////////////////////////////////////////////// if (m_StatusBar != NULL && m_Skeleton->children != NULL) { sprintf(message,"Frame %3d/%3d",(int)m_Skeleton->children->primCurFrame,(int)m_Skeleton->children->primFrameCount); //m_StatusBar->SetPaneStyle(1,SBPS_POPOUT); m_StatusBar->SetPaneText(1,message); } } void COGLView::HandleKeyDown(UINT nChar) { //float deltaFOV = 0.0; if (m_TrackFace) return; float deltaDutch = 0.0; switch (nChar) { case 187: // '=' note: will treat this as a plus //deltaFOV = -0.5; // decrease FOV = zoom in m_ZoomIn = !m_ZoomIn; m_ZoomOut = false; break; case 189: // '-' //deltaFOV = 0.5; // increase FOV = zoom out m_ZoomOut = !m_ZoomOut; m_ZoomIn = false; break; case 219: // '[' m_DollyOut = !m_DollyOut; m_DollyIn = false; break; case 221: // ']' m_DollyIn = !m_DollyIn; m_DollyOut = false; break; case 37: // left arrow m_PanLeft = !m_PanLeft; m_PanRight = false; break; case 38: // up arrow m_TiltUp = !m_TiltUp; m_TiltDown = false; break; case 39: // right arrow m_PanRight = !m_PanRight; m_PanLeft = false; break; case 40: // down arrow m_TiltDown = !m_TiltDown; m_TiltUp = false; break; case 112: // F1 deltaDutch = -15.0; break; case 113: // F2 deltaDutch = 15.0; break; } char message[20]; switch(m_viewType) { case FRONT_VIEW: if (fabs(m_FrontDutch + deltaDutch) <= 75) m_FrontDutch += deltaDutch; sprintf(message, "%0.1f", m_FrontDutch); break; case SIDE_VIEW: if (fabs(m_SideDutch + deltaDutch) <= 75) m_SideDutch += deltaDutch; sprintf(message, "%0.1f", m_SideDutch); break; case TOP_VIEW: if (fabs(m_TopDutch + deltaDutch) <= 75) m_TopDutch += deltaDutch; sprintf(message, "%0.1f", m_TopDutch); break; case OBLIQUE_VIEW: if (fabs(m_ObliqueDutch + deltaDutch) <= 75) m_ObliqueDutch += deltaDutch; sprintf(message, "%0.1f", m_ObliqueDutch); break; } m_StatusBar->SetPaneText(10,message); drawScene(); } void COGLView::HandleKeyUp(UINT nChar) { } /////////////////////////////////////////////////////////////////////////////// // Function: OnMouseMove // Purpose: Handler for the mouse. Handles movement when pressed // Arguments: Flags for key masks and point /////////////////////////////////////////////////////////////////////////////// void COGLView::OnMouseMove(UINT nFlags, CPoint point) { if (m_TrackFace) return; UpdateStatusBar(0); float deltaBaseline = 0.0; float deltaPan = 0.0; float deltaTilt = 0.0; float deltaFOV = 0.0; if (nFlags & MK_LBUTTON > 0) { // IF I AM HOLDING THE 'CTRL' BUTTON TRANSLATE if ((nFlags & MK_CONTROL) > 0) { // TRANSLATE UpdateStatusBar(2); if ((point.x - m_mousepos.x) != 0) { m_Skeleton->trans.x = m_Grab_Trans_X + (.05f * (point.x - m_mousepos.x)); drawScene(); } if ((point.y - m_mousepos.y) != 0) { m_Skeleton->trans.y = m_Grab_Trans_Y - (.05f * (point.y - m_mousepos.y)); drawScene(); } } // ELSE "SHIFT" ROTATE THE ROOT else if ((nFlags & MK_SHIFT) > 0) { // TILT AND PAN UpdateStatusBar(1); if ((point.x - m_mousepos.x) != 0) { //m_Skeleton->rot.y = m_Grab_Rot_Y + ((float)ROTATE_SPEED * (point.x - m_mousepos.x)); //drawScene(); deltaPan = -((float)ROTATE_SPEED * (point.x - m_mousepos.x)); m_mousepos.x = point.x; } if ((point.y - m_mousepos.y) != 0) { //m_Skeleton->rot.x = m_Grab_Rot_X + ((float)ROTATE_SPEED * (point.y - m_mousepos.y)); //drawScene(); deltaTilt = -((float)ROTATE_SPEED * (point.y - m_mousepos.y)); m_mousepos.y = point.y; } } } else if ((nFlags & MK_RBUTTON) == MK_RBUTTON) { if ((nFlags & MK_CONTROL) > 0) { // DOLLY UpdateStatusBar(3); if ((point.x - m_mousepos.x) != 0) { //m_Skeleton->trans.z = m_Grab_Trans_Z + (.1f * (point.x - m_mousepos.x)); deltaBaseline = (.05f * (point.x - m_mousepos.x)); m_mousepos.x = point.x; } } else if ((nFlags & MK_SHIFT) > 0) { // ZOOM UpdateStatusBar(4); if ((point.x - m_mousepos.x) != 0) { //m_Skeleton->rot.z = m_Grab_Rot_Z + ((float)ROTATE_SPEED * (point.x - m_mousepos.x)); //drawScene(); deltaFOV = (.05f * (point.x - m_mousepos.x)); m_mousepos.x = point.x; } } } char message[20]; switch(m_viewType) { case FRONT_VIEW: m_FrontBaseline += deltaBaseline; if (m_FrontBaseline < 0) m_FrontBaseline = 0.f; m_FrontFOV += deltaFOV; break; case SIDE_VIEW: m_SideBaseline += deltaBaseline; if (m_SideBaseline < 0) m_SideBaseline = 0.f; m_SideFOV += deltaFOV; break; case TOP_VIEW: m_TopBaseline += deltaBaseline; if (m_TopBaseline < 0) m_TopBaseline = 0.f; m_TopFOV += deltaFOV; break; case OBLIQUE_VIEW: m_ObliqueBaseline += deltaBaseline; if (m_ObliqueBaseline < 0) m_ObliqueBaseline = 0.f; m_ObliqueTilt += deltaTilt; m_ObliquePan += deltaPan; m_ObliqueFOV += deltaFOV; break; } CWnd::OnMouseMove(nFlags, point); } //// OnMouseMove ////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Function: OnViewResetskeleton // Purpose: Reset the view settings for the skeleton // Arguments: None /////////////////////////////////////////////////////////////////////////////// void COGLView::OnViewResetskeleton() { m_Skeleton->trans.x = m_Skeleton->b_trans.x; //KEITH: CHANGED THIS LINE m_Skeleton->trans.y = m_Skeleton->b_trans.y; //KEITH: CHANGED THIS LINE m_Skeleton->trans.z = m_Skeleton->b_trans.z; //KEITH: CHANGED THIS LINE m_Skeleton->rot.x = 0.0f; m_Skeleton->rot.y = 0.0f; m_Skeleton->rot.z = 0.0f; drawScene(); } //// OnViewResetskeleton ////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Function: GetGLInfo // Purpose: Get the OpenGL Vendor and Rederer info as strings // Arguments: Strings to put the info in /////////////////////////////////////////////////////////////////////////////// void COGLView::GetGLInfo(char *who,char *which, char *version) { strcpy(who,(char *)::glGetString( GL_VENDOR )); strcpy(which,(char *)::glGetString( GL_RENDERER )); strcpy(version, (char *)::glGetString( GL_VERSION )); } //// GetGLInfo ///////////////////////////////////////////////////////////////// // KEITH: ADDED FOLLOWING FUNCTIONS // toggle Quaternion/Euler Angle rotation representation void COGLView::toggleQuatEuler() { // TODO: Add your command handler code here m_UseQuat = !m_UseQuat; if (m_UseQuat) m_StatusBar->SetPaneText(2,"Quaternions"); else m_StatusBar->SetPaneText(2,"Euler Angles"); } // set interpolation start frame void COGLView::specifyInterpStartFrame() { if (m_Skeleton->children != NULL) { interpStartFrame = (int) m_Skeleton->children->primCurFrame; char message[5]; sprintf(message,"%3d",interpStartFrame); m_StatusBar->SetPaneText(3,message); setTransformations(m_Skeleton, PRIMARY); } } // set interpolation end frame void COGLView::specifyInterpEndFrame() { if (m_Skeleton->children != NULL) { interpEndFrame = (int) m_Skeleton->children->primCurFrame; char message[5]; sprintf(message,"%3d",interpEndFrame); m_StatusBar->SetPaneText(4,message); setTransformations(m_Skeleton, SECONDARY); } } // capture current rotations for interpolation void COGLView::setTransformations(t_Bone *root, int which) { for (int i = 0; i < root->childCnt; i++) { t_Bone *curJoint = root->children + i; if (which == PRIMARY) { curJoint->p_rot = curJoint->rot; curJoint->p_trans = curJoint->trans; } else { curJoint->s_rot = curJoint->rot; curJoint->s_trans = curJoint->trans; } if (curJoint->childCnt > 0) setTransformations(curJoint, which); } } void COGLView::indicateLocked(BOOL locked) { if (locked) m_StatusBar->SetPaneText(5,"Locked"); else m_StatusBar->SetPaneText(5,"Unlocked"); } void COGLView::splitScreen() { // TODO: Add your command handler code here m_SplitAnimation = !m_SplitAnimation; if (m_SplitAnimation) { m_StatusBar->SetPaneText(2,"EA / Q"); m_StatusBar->SetPaneText(6,"Split"); } else { if (m_UseQuat) m_StatusBar->SetPaneText(2,"Quaternions"); else m_StatusBar->SetPaneText(2,"Euler Angles"); m_StatusBar->SetPaneText(6,""); } Invalidate(); // REDRAW THE DISPLAY } void COGLView::setFileFormat(CString exten) { if (!exten.CompareNoCase("BVA")) m_Format = BVA_FORMAT; else if (!exten.CompareNoCase("BVH")) m_Format = BVH_FORMAT; } void COGLView::showBoundingVolume() { m_showBoundingVolume = !m_showBoundingVolume; } void COGLView::setView(int view) { m_viewType = view; m_FollowClosely = false; } void COGLView::setInitialView(int view) { // SET CAMERA FIELD OF VIEW float diff1, diff2; diff1 = m_ymax - m_ymin; diff2 = m_xmax - m_xmin; if (diff2 > diff1) diff1 = diff2/aspect; m_FrontFOV = 2.f*(180.f/M_PI)*atan( diff1/(2.f*InitialBaseline) ); diff1 = m_ymax - m_ymin; diff2 = m_zmax - m_zmin; if (diff2 > diff1) diff1 = diff2/aspect; m_SideFOV = 2.f*(180.f/M_PI)*atan( diff1/(2.f*InitialBaseline) ); diff1 = m_zmax - m_zmin; diff2 = m_xmax - m_xmin; if (diff2 > diff1) diff1 = diff2/aspect; m_TopFOV = 2.f*(180.f/M_PI)*atan( diff1/(2.f*InitialBaseline) ); diff1 = aspect*cos(M_PI/4.f)*sqrt((m_zmax-m_zmin)*(m_zmax-m_zmin) + (m_ymax-m_ymin)*(m_ymax-m_ymin) + (m_xmax-m_xmin)*(m_xmax-m_xmin)); m_ObliqueFOV = 2.f*(180.f/M_PI)*atan( diff1/(2.f*InitialBaseline) ); m_FrontDutch = m_SideDutch = m_TopDutch = m_ObliqueDutch = 0.0; //setView(view); // find front of figure (hips normal) m_initHipsNormal = m_Skeleton->children->primChannel[5]; } void COGLView::follow() { switch(m_viewType) { case FRONT_VIEW: m_FrontFollow = !m_FrontFollow; break; case SIDE_VIEW: m_SideFollow = !m_SideFollow; break; case TOP_VIEW: m_TopFollow = !m_TopFollow; break; case OBLIQUE_VIEW: m_ObliqueFollow = !m_ObliqueFollow; } m_TrackFace = m_FollowClosely = false; } void COGLView::trackFace(float faceHeight) { m_TrackFace = !m_TrackFace; m_faceHeight = faceHeight; m_FollowClosely = m_FrontFollow = m_SideFollow = m_TopFollow = m_ObliqueFollow = false; } void COGLView::followClosely() { m_FollowClosely = !m_FollowClosely; m_TrackFace = m_FrontFollow = m_SideFollow = m_TopFollow = m_ObliqueFollow = false; } void COGLView::setFollowTolerance(float toleranceXZ, float toleranceY, int smooth) { m_FollowTolerance_XZ = toleranceXZ; m_FollowTolerance_Y = toleranceY; m_FollowSmoothing = smooth; m_Skeleton->MA->plotCameraFollowPath(smooth); } void COGLView::autoCamera() { // TODO: Add your command handler code here m_autoCamera = !m_autoCamera; }