//-----------------------------------------------------------------------------
// Name: ogl_cg_skinning.cpp
// Author: Kevin Harris
// Last Modified: 04/28/05
// Description: This sample demonstrates how to skin a mesh on the hardware
// using a Cg shader. To keep things simple, the skeletal
// system used in this sample is very simple and only consists
// of two bones or bone matrices.
//
// Special thanks go out to Cyril Zeller, and Matthias Wloka
// of nVIDIA for their help in straightening out a few oddities
// that my sample was suffering from. In short, Cg works fine
// and I'm occasionally a big dummy! ;)
//
// Control Keys: Left Mouse Button - Spin the matrix for bone0.
// Right Mouse Button - Spin the matrix for bone1.
//
// F1 - Toggle test geometry between a cylinder and a simple
// grouping of 3 quads.
// F2 - Toggle wire-frame mode
//-----------------------------------------------------------------------------
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include <Cg/Cg.h>
#include <Cg/cgGL.h>
#include "matrix4x4f.h"
#include "vector3f.h"
#include "resource.h"
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
HWND g_hWnd = NULL;
HDC g_hDC = NULL;
HGLRC g_hRC = NULL;
GLuint g_boneDisplayList = -1;
CGprofile g_CGprofile;
CGcontext g_CGcontext;
CGprogram g_CGprogram;
CGparameter g_CGparam_modelViewProjection;
CGparameter g_CGparam_modelViewInverse;
CGparameter g_CGparam_boneMatrices;
CGparameter g_CGparam_eyePosition;
CGparameter g_CGparam_lightVector;
CGparameter g_CGparam_weights;
CGparameter g_CGparam_matrixIndices;
CGparameter g_CGparam_numBones;
bool g_bRenderInWireFrame = false;
bool g_bRenderQuads = false;
float g_fDistance = -12.0f;
float g_fSpinX_L = 0.0f;
float g_fSpinY_L = 0.0f;
float g_fSpinX_R = 0.0f;
float g_fSpinY_R = 0.0f;
const int MAX_BONES = 2;
matrix4x4f g_boneMatrix0;
matrix4x4f g_boneMatrix1;
matrix4x4f g_matrixToRenderBone0;
matrix4x4f g_matrixToRenderBone1;
struct Vertex
{
float r, g, b, a;
float nx, ny, nz;
float x, y, z;
float weights[MAX_BONES];
float matrixIndices[MAX_BONES];
float numBones;
};
// Cylinder geometry
const int CYLINDER_RESOLUTION = 12;
const int NUM_CYLINDER_SECTIONS = 6;
const int NUM_VERTICES_PER_SECTION = CYLINDER_RESOLUTION * 2;
const int NUM_VERTICES = NUM_VERTICES_PER_SECTION * NUM_CYLINDER_SECTIONS;
Vertex g_cylinderVertices[NUM_VERTICES];
// Quad geometry
Vertex g_quadVertices[] =
{
// r g b a nx ny nz x y z w0 w1 mi0 mi1 nb
{ 1.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, -1.0f,0.0f,0.0f, 1.0f,0.0f, 0.0f,0.0f, 1.0f }, // Quad 0
{ 1.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, 1.0f,0.0f,0.0f, 1.0f,0.0f, 0.0f,0.0f, 1.0f },
{ 1.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, 1.0f,2.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f },
{ 1.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, -1.0f,2.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f },
{ 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, -1.0f,2.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f }, // Quad 1
{ 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, 1.0f,2.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f },
{ 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, 1.0f,4.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f },
{ 0.0f,1.0f,0.0f,1.0f, 0.0f,0.0f,1.0, -1.0f,4.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f },
{ 0.0f,0.0f,1.0f,1.0f, 0.0f,0.0f,1.0, -1.0f,4.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f }, // Quad 2
{ 0.0f,0.0f,1.0f,1.0f, 0.0f,0.0f,1.0, 1.0f,4.0f,0.0f, 0.5f,0.5f, 0.0f,1.0f, 2.0f },
{ 0.0f,0.0f,1.0f,1.0f, 0.0f,0.0f,1.0, 1.0f,6.0f,0.0f, 1.0f,0.0f, 1.0f,0.0f, 1.0f },
{ 0.0f,0.0f,1.0f,1.0f, 0.0f,0.0f,1.0, -1.0f,6.0f,0.0f, 1.0f,0.0f, 1.0f,0.0f, 1.0f }
};
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void init(void);
void render(void);
void shutDown(void);
void initShader(void);
void setShaderConstants(void);
void createMeshCylinderWithWeightedVertices(void);
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;
memset(&uMsg,0,sizeof(uMsg));
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON);
winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDI_OPENGL_ICON);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if( !RegisterClassEx(&winClass) )
return E_FAIL;
g_hWnd = CreateWindowEx( NULL, "MY_WINDOWS_CLASS",
"OpenGL - Skinning on the Hardware Using a Cg Shader",
WS_OVERLAPPEDWINDOW | WS_VISIBLE,
0, 0, 640, 480, NULL, NULL, hInstance, NULL );
if( g_hWnd == NULL )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
UpdateWindow( g_hWnd );
init();
initShader();
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
render();
}
shutDown();
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return uMsg.wParam;
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd,
UINT msg,
WPARAM wParam,
LPARAM lParam )
{
static POINT ptLastMousePosit_L;
static POINT ptCurrentMousePosit_L;
static bool bMousing_L;
static POINT ptLastMousePosit_R;
static POINT ptCurrentMousePosit_R;
static bool bMousing_R;
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
case VK_F1:
g_bRenderQuads = !g_bRenderQuads;
break;
case VK_F2:
g_bRenderInWireFrame = !g_bRenderInWireFrame;
if( g_bRenderInWireFrame == true )
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
else
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
break;
case 38: // Up Arrow Key
g_fDistance += 1.0f;
break;
case 40: // Down Arrow Key
g_fDistance -= 1.0f;
break;
}
}
break;
case WM_LBUTTONDOWN:
{
ptLastMousePosit_L.x = ptCurrentMousePosit_L.x = LOWORD (lParam);
ptLastMousePosit_L.y = ptCurrentMousePos