www.pudn.com > oglu_per_vertex_reflective_environment_mapping.zip > oglu_per_vertex_reflective_environment_mapping.cpp
//------------------------------------------------------------------------------ // Name: oglu_per_vertex_reflective_environment_mapping.cpp // Author: Christoph Kabek // Last Modified: 07/17/07 // Description: This sample shows how to do reflective environment mapping on // a per-vertex basis using Cg. // // Control Keys: 1 - Draws skull // 2 - Draws teapot // 3 - Draws sphere // w - Toggles wire frame mode // r - Toggles rotation // i - Zooms in // o - Zooms out // s - Toggles skybox rendering // // Note: System requirements are any accelerated 3D card which supports // vertex and pixel shaders (shader model 1.1) and the following // OpenGL 1.3 extensions: // GL_ARB_vertex_program/GL_ARB_fragment_program. // Textures of the nVidia SDKs were used. // This sample was tested on Windows XP + SP2 on an ATi Radeon 9800 Pro, // X700 mobile and on an nVidia GeForce FX 5200, a 6200 and a 7600 GT // and also with nVidia Cg 1.3 to 1.5. // The X700 mobile, however, displayed no objects for some reason, but I // noticed the same problems with many other demos, e.g. of the nVidia // SDK, and it troubled me a lot with other projects in the past, so I // guess it's an ATi driver's bug, since other chipsets displayed // everything fine. // You can use the code for any non-commercial use, but give the author // full credit if you do so. // It was NOT tested on performance and it was not programmed that way. // If you want to comment on this one, or if you experience or see any // errors, I would be glad to know them: // chrisDOTgraphicsATgmxDOTnet //------------------------------------------------------------------------------ // Trim down the footprint #define STRICT #define WIN32_LEAN_AND_MEAN #define VC_LEANMEAN // Disable deprecation #define _CRT_SECURE_NO_DEPRECATE // Link to necessary libraries #pragma comment ( lib, "opengl32.lib" ) #pragma comment ( lib, "glu32.lib" ) #pragma comment ( lib, "glaux.lib" ) #pragma comment ( lib, "cg.lib" ) #pragma comment ( lib, "cggl.lib" ) // Standard #include#include // Cg #include #include // GL #include #include #include #include "resource.h" // Note: This sample ships its own extension header. // For using your local file, comment out the next line and uncomment // the following line. #include "glext.h" //#include // For loading 3DS models, copyright (c) 2001 by Lev Povalahev #include "l3ds.h" //----------------------------------------------------------------------------- // GLOBALS //----------------------------------------------------------------------------- // Set view and rotation parameters GLfloat g_fEye[3] = { 0.0f, 0.0f, 5.0f }; GLfloat g_fRot[3] = { 0.0f, 45.0f, 0.0f }; // 3DS objects L3DS skull, teapot, sphere; L3DS *obj; GLuint g_uiCurrentObj = 1; // Cg parameters CGprofile cgVertexProfile, cgFragmentProfile; CGcontext cgContext; CGprogram cgVertexProgram, cgFragmentProgram; // Used for 3DS model rendering via vertex arrays CGparameter cgNormal, cgPosition, cgTexcoords; // Matrices CGparameter cgModelViewProj, cgModelView, cgModelViewI, cgModelViewIT; // Textures CGparameter cgEnvironmentMap; // Further parameters CGparameter cgEyePosition; // Flags BOOL g_bRotate = TRUE; BOOL g_bDrawSkybox = TRUE; // Constants defining the cubemap faces GLuint g_uiCubeMapConstants[6] = { GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB, GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB, GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB }; // Location of cubemap textures char *g_cCubemaps[6] = { "terrain_posx.bmp", "terrain_negx.bmp", "terrain_posy.bmp", "terrain_negy.bmp", "terrain_posz.bmp", "terrain_negz.bmp" }; // Texture IDs GLuint g_uiCubemapTexture; // Window related globals GLfloat g_fWidth = 1024.0f; GLfloat g_fHeight = 768.0f; HDC g_hDC = NULL; HGLRC g_hRC = NULL; HWND g_hWnd = NULL; HINSTANCE g_hInstance = NULL; //----------------------------------------------------------------------------- // PROTOTYPES //----------------------------------------------------------------------------- int WINAPI WinMain( HINSTANCE g_hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow); LRESULT CALLBACK WindowProc( HWND g_hWnd, UINT msg, WPARAM wParam, LPARAM lParam ); void loadCubeMap( void ); void display( void ); void cgErrorCallback( void ); void init( void ); void drawSkyBox( void ); void cleanExit( int exitval ); void drawtext( void ); void draw3DSObject( 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 ) ); // Specify window properties 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; // Create window g_hWnd = CreateWindowEx( NULL,"MY_WINDOWS_CLASS", "OpenGL - Per-Vertex Reflective Environment Mapping Using Cg", WS_OVERLAPPEDWINDOW, 0, 0, ( GLint )g_fWidth, ( GLint )g_fHeight, NULL, NULL, g_hInstance, NULL ); if( g_hWnd == NULL ) return E_FAIL; // Obligatory calls ShowWindow( g_hWnd, nCmdShow ); UpdateWindow( g_hWnd ); // Initialize all stuff init(); // Process commands while( uMsg.message != WM_QUIT ) { if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) ) { TranslateMessage( &uMsg ); DispatchMessage( &uMsg ); } else // Main render function display(); } cleanExit( 0 ); UnregisterClass( "MY_WINDOWS_CLASS", g_hInstance ); return uMsg.wParam; } //----------------------------------------------------------------------------- // Name: WindowProc() // Desc: The window's message handler //----------------------------------------------------------------------------- LRESULT CALLBACK WindowProc( HWND g_hWnd, UINT msg, WPARAM wParam, LPARAM lParam ) { static POINT ptLastMousePosit; static POINT ptCurrentMousePosit; static bool bMousing; switch( msg ) { case WM_KEYDOWN: { switch( wParam ) { case VK_ESCAPE: PostQuitMessage( 0 ); cleanExit( 0 ); break; case 'R': g_bRotate = !g_bRotate; break; case 'W': GLint mode[2]; glGetIntegerv( GL_POLYGON_MODE, mode ); if( mode[1] == GL_FILL ) { glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); } else if( mode[1] == GL_LINE ) { glPointSize( 4 ); glPolygonMode( GL_FRONT_AND_BACK, GL_POINT ); } else { glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); } break; case 'I': g_fEye[2] -= 0.1f; break; case 'O': g_fEye[2] += 0.1f; break; case 'S': g_bDrawSkybox = !g_bDrawSkybox; break; case '1': case '2': case '3': g_uiCurrentObj = wParam - '0'; break; } } break; case WM_LBUTTONDOWN: ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD( lParam ); ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD( lParam ); bMousing = true; break; case WM_LBUTTONUP: bMousing = false; break; case WM_MOUSEMOVE: ptCurrentMousePosit.x = LOWORD( lParam ); ptCurrentMousePosit.y = HIWORD( lParam ); if( bMousing ) { g_fRot[1] += ( ptCurrentMousePosit.x - ptLastMousePosit.x ); g_fRot[0] += ( ptCurrentMousePosit.y - ptLastMousePosit.y ); } ptLastMousePosit.x = ptCurrentMousePosit.x; ptLastMousePosit.y = ptCurrentMousePosit.y; break; case WM_SIZE: { int nWidth = LOWORD( lParam ); int nHeight = HIWORD( lParam ); glViewport( 0, 0, nWidth, nHeight ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 45.0, ( GLfloat )nWidth / ( GLfloat )nHeight, 0.1, 100.0 ); } break; case WM_CLOSE: cleanExit( 0 ); PostQuitMessage( 0 ); break; case WM_DESTROY: cleanExit( 0 ); PostQuitMessage( 0 ); break; default: return DefWindowProc( g_hWnd, msg, wParam, lParam ); break; } return 0; } //----------------------------------------------------------------------------- // Name: loadCubeMap( void ) // Desc: Loads the skybox/environment/cubemap textures //----------------------------------------------------------------------------- void loadCubeMap( void ) { AUX_RGBImageRec *pTextureImage = NULL; glGenTextures( 1, &g_uiCubemapTexture ); glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, g_uiCubemapTexture ); int j; for ( j=0; j < 6; j++ ) { pTextureImage = auxDIBImageLoad( g_cCubemaps[j] ); if( pTextureImage != NULL ) { // Build textures and mipmaps glTexImage2D( g_uiCubeMapConstants[j], 0, GL_RGB8, pTextureImage->sizeX, pTextureImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, pTextureImage->data ); gluBuild2DMipmaps( g_uiCubeMapConstants[j], GL_RGB8, pTextureImage->sizeX, pTextureImage->sizeY, GL_RGB, GL_UNSIGNED_BYTE, pTextureImage->data ); } else { MessageBox( NULL, "Could not load cube texture", "Error", MB_OK|MB_ICONEXCLAMATION ); cleanExit( 0 ); } if( pTextureImage ) { // Release all data, since OpenGL holds its own copy of the textures if( pTextureImage->data ) free( pTextureImage->data ); free( pTextureImage ); } } // Set texture properties glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); glTexParameteri( GL_TEXTURE_CUBE_MAP_ARB, GL_GENERATE_MIPMAP_SGIS, GL_TRUE ); glTexParameterf( GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_MAX_ANISOTROPY_EXT, 8.0f ); } //----------------------------------------------------------------------------- // Name: display( void ) // Desc: Render function //----------------------------------------------------------------------------- void display( void ) { glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // Translate view glTranslatef ( -g_fEye[0], -g_fEye[1], -g_fEye[2] ); // Rotates the screen by the angles glRotatef( g_fRot[0], 1.0f, 0.0f, 0.0f ); glRotatef( g_fRot[1], 0.0f, 1.0f, 0.0f ); glRotatef( g_fRot[2], 0.0f, 0.0f, 1.0f ); // Draw the environment if( g_bDrawSkybox ) drawSkyBox(); // Bind and enable shaders cgGLBindProgram( cgVertexProgram ); cgGLBindProgram( cgFragmentProgram ); cgGLEnableProfile( cgVertexProfile ); cgGLEnableProfile( cgFragmentProfile ); // Enable textures cgGLEnableTextureParameter( cgEnvironmentMap ); // Set all matrices cgGLSetStateMatrixParameter( cgModelViewProj, CG_GL_MODELVIEW_PROJECTION_MATRIX, CG_GL_MATRIX_IDENTITY ); cgGLSetStateMatrixParameter( cgModelView, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_IDENTITY ); cgGLSetStateMatrixParameter( cgModelViewI, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE ); cgGLSetStateMatrixParameter( cgModelViewIT, CG_GL_MODELVIEW_MATRIX, CG_GL_MATRIX_INVERSE_TRANSPOSE ); // Sets 3DS object corresponding to key input switch( g_uiCurrentObj ) { case 1: obj = &skull; break; case 2: obj = &teapot; break; case 3: obj = &sphere; break; default: break; } // Draws 3DS object draw3DSObject(); // Disable textures cgGLDisableTextureParameter( cgEnvironmentMap ); // Disable profiles cgGLDisableProfile( cgVertexProfile ); cgGLDisableProfile( cgFragmentProfile ); // Draw FPS, etc. drawtext(); SwapBuffers( g_hDC ); // Rotate around the y-axis, higher values increase the speed if( g_bRotate ) g_fRot[1] += 0.01f; } //----------------------------------------------------------------------------- // Name: cgErrorCallback( void ) // Desc: Cg error callback function //----------------------------------------------------------------------------- void cgErrorCallback( void ) { CGerror LastError = cgGetError(); if( LastError ) { char outbuf[1024] = ""; int i; // Retrieve time stamp SYSTEMTIME time; GetSystemTime( &time ); // Get last Cg error char *Listing = ( char* )cgGetLastListing( cgContext ); // Copy into buffer i = sprintf( outbuf, "\n---------------------------------------------------\n"); i += sprintf( outbuf + i, "%d.%d.%d, %d:%d:%d\n", time.wDay, time.wMonth, time.wYear, time.wHour, time.wMinute, time.wSecond ); i += sprintf( outbuf + i, "%s\n\n", cgGetErrorString( LastError ) ); i += sprintf( outbuf + i, "%s\n", Listing ); i += sprintf( outbuf + i, "---------------------------------------------------\n"); // Write into CGError.txt FILE *fp; fp = fopen( "CGError.txt", "a" ); if( NULL != fp ) fprintf( fp, outbuf ); MessageBox( NULL, "Cg error, check CGError.txt", "Error", MB_OK|MB_ICONEXCLAMATION ); cleanExit( 0 ); } } //----------------------------------------------------------------------------- // Name: init( void ) // Desc: Initializes all stuff //----------------------------------------------------------------------------- void init( void ) { GLuint PixelFormat; // Specify WGL context PIXELFORMATDESCRIPTOR pfd; memset( &pfd, 0, sizeof( PIXELFORMATDESCRIPTOR ) ); pfd.nSize = sizeof( PIXELFORMATDESCRIPTOR ); pfd.nVersion = 1; pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; pfd.iPixelType = PFD_TYPE_RGBA; pfd.cColorBits = 16; pfd.cDepthBits = 16; g_hDC = GetDC( g_hWnd ); PixelFormat = ChoosePixelFormat( g_hDC, &pfd ); SetPixelFormat( g_hDC, PixelFormat, &pfd); g_hRC = wglCreateContext( g_hDC ); wglMakeCurrent( g_hDC, g_hRC ); // Set up OpenGL glEnable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glClearColor( 0.0f, 0.0f, 0.0f, 1.0f ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); gluPerspective( 45.0f, g_fWidth / g_fHeight, 0.1f, 100.0f ); // Set up Cg cgVertexProfile = cgGLGetLatestProfile( CG_GL_VERTEX ); cgFragmentProfile = cgGLGetLatestProfile( CG_GL_FRAGMENT ); cgGLSetOptimalOptions( cgVertexProfile ); cgGLSetOptimalOptions( cgFragmentProfile ); // Load 3DS models skull.LoadFile( "skull.3ds" ); teapot.LoadFile( "teapot.3ds" ); sphere.LoadFile( "sphere.3ds" ); // Register error callback cgSetErrorCallback( cgErrorCallback ); // Context creation cgContext = cgCreateContext(); // Catch all vertex shader parameters and load vertex shader cgVertexProgram = cgCreateProgramFromFile( cgContext, CG_SOURCE, "oglu_per_vertex_reflective_environment_mapping_vs.cg", cgVertexProfile, NULL, NULL ); cgGLLoadProgram( cgVertexProgram ); cgModelViewProj = cgGetNamedParameter( cgVertexProgram, "ModelViewProj" ); cgModelView = cgGetNamedParameter( cgVertexProgram, "ModelView" ); cgModelViewI = cgGetNamedParameter( cgVertexProgram, "ModelViewI" ); cgModelViewIT = cgGetNamedParameter( cgVertexProgram, "ModelViewIT" ); cgPosition = cgGetNamedParameter( cgVertexProgram, "position" ); cgNormal = cgGetNamedParameter( cgVertexProgram, "N" ); cgTexcoords = cgGetNamedParameter( cgVertexProgram, "texCoord" ); cgEyePosition = cgGetNamedParameter( cgVertexProgram, "eyePosition" ); if ( !cgModelViewProj || !cgModelView || !cgModelViewI || !cgModelViewIT || !cgPosition || !cgNormal || !cgTexcoords || !cgEyePosition ) { MessageBox( NULL, "Unable to retrieve vertex program parameters, exiting...", "Error", MB_OK|MB_ICONEXCLAMATION ); cleanExit( 0 ); } // Set eye to origin cgGLSetParameter3f( cgEyePosition, 0.0f, 0.0f, 0.0f ); // Catch all pixel shader parameters and load pixel shader cgFragmentProgram = cgCreateProgramFromFile( cgContext, CG_SOURCE, "oglu_per_vertex_reflective_environment_mapping_ps.cg", cgFragmentProfile, NULL, NULL ); cgGLLoadProgram( cgFragmentProgram ); cgEnvironmentMap = cgGetNamedParameter( cgFragmentProgram, "environmentMap" ); if ( !cgEnvironmentMap ) { MessageBox( NULL, "Unable to retrieve fragment program parameters, exiting...", "Error", MB_OK|MB_ICONEXCLAMATION ); cleanExit( 0 ); } // Load the cubemap textures loadCubeMap( ); // Set texture parameter cgGLSetTextureParameter( cgEnvironmentMap, g_uiCubemapTexture ); } //----------------------------------------------------------------------------- // Name: drawSkyBox( void ) // Desc: Draws the skybox/environment //----------------------------------------------------------------------------- void drawSkyBox( void ) { // Define planes for our cube GLfloat xPlane[] = { 1.0f, 0.0f, 0.0f, 0.0f }; GLfloat yPlane[] = { 0.0f, 1.0f, 0.0f, 0.0f }; GLfloat zPlane[] = { 0.0f, 0.0f, 1.0f, 0.0f }; // Enable texture coordinates generation glEnable( GL_TEXTURE_GEN_S ); glEnable( GL_TEXTURE_GEN_T ); glEnable( GL_TEXTURE_GEN_R ); // Set texture environment parameter glTexEnvi( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE ); // Enable the cubemap extension glEnable( GL_TEXTURE_CUBE_MAP_ARB ); glBindTexture( GL_TEXTURE_CUBE_MAP_ARB, g_uiCubemapTexture ); // Generate texture coordinates glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); glTexGeni( GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); glTexGenfv( GL_S, GL_OBJECT_PLANE, xPlane ); glTexGenfv( GL_T, GL_OBJECT_PLANE, yPlane ); glTexGenfv( GL_R, GL_OBJECT_PLANE, zPlane ); // Skybox rendering needs disabling of z buffer glDisable( GL_DEPTH_TEST ); glMatrixMode( GL_MODELVIEW ); // Draw the cube glBegin( GL_QUADS ); // Front glTexCoord2f( 0, 0 ); glVertex3f( -30, -30, -30 ); glTexCoord2f( 1, 0 ); glVertex3f( 30, -30, -30 ); glTexCoord2f( 1, 1 ); glVertex3f( 30, 30, -30 ); glTexCoord2f( 0, 1 ); glVertex3f( -30, 30, -30 ); // Right glTexCoord2f( 0, 0 ); glVertex3f( 30, -30, -30 ); glTexCoord2f( 1, 0 ); glVertex3f( 30, -30, 30 ); glTexCoord2f( 1, 1 ); glVertex3f( 30, 30, 30 ); glTexCoord2f( 0, 1 ); glVertex3f( 30, 30, -30 ); // Back glTexCoord2f( 0, 0 ); glVertex3f( 30, -30, 30 ); glTexCoord2f( 1, 0 ); glVertex3f( -30, -30, 30 ); glTexCoord2f( 1, 1 ); glVertex3f( -30, 30, 30 ); glTexCoord2f( 0, 1 ); glVertex3f( 30, 30, 30 ); // Left glTexCoord2f( 0, 0 ); glVertex3f( -30, -30, 30 ); glTexCoord2f( 1, 0 ); glVertex3f( -30, -30, -30 ); glTexCoord2f( 1, 1 ); glVertex3f( -30, 30, -30 ); glTexCoord2f( 0, 1 ); glVertex3f( -30, 30, 30 ); // Top glTexCoord2f( 0, 0 ); glVertex3f( -30, 30, -30 ); glTexCoord2f( 1, 0 ); glVertex3f( 30, 30, -30 ); glTexCoord2f( 1, 1 ); glVertex3f( 30, 30, 30 ); glTexCoord2f( 0, 1 ); glVertex3f( -30, 30, 30 ); // Bottom glTexCoord2f( 0, 0 ); glVertex3f( -30, -30, 30 ); glTexCoord2f( 1, 0 ); glVertex3f( 30, -30, 30 ); glTexCoord2f( 1, 1 ); glVertex3f( 30, -30, -30 ); glTexCoord2f( 0, 1 ); glVertex3f( -30, -30, -30 ); glEnd(); glEnable( GL_DEPTH_TEST ); glDisable( GL_TEXTURE_CUBE_MAP_ARB ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_TEXTURE_GEN_R ); } //----------------------------------------------------------------------------- // Name: cleanExit( int exitval ) // Desc: Releases all stuff properly //----------------------------------------------------------------------------- void cleanExit( int exitval ) { if( cgVertexProgram ) cgDestroyProgram( cgVertexProgram ); if( cgFragmentProgram ) cgDestroyProgram( cgFragmentProgram ); if( cgContext ) cgDestroyContext( cgContext ); if( g_hRC != NULL ) { wglMakeCurrent( NULL, NULL ); wglDeleteContext( g_hRC ); g_hRC = NULL; } if( g_hRC != NULL ) { ReleaseDC( g_hWnd, g_hDC ); g_hDC = NULL; } exit( exitval ); } //----------------------------------------------------------------------------- // Name: drawtext( void ) // Desc: Draws frames per second (FPS), model vertex and triangle count //----------------------------------------------------------------------------- void drawtext( void ) { GLint x=0, y=0; char string[80] = { 0 }; RECT rect; // For FPS measuring static GLfloat framesPerSecond = 0.0f; static long lastTime = 0; static char strFrameRate[50] = ""; DWORD currentTime = 0; // Fetch screen values GetClientRect( g_hWnd, &rect ); GLint ww = rect.right; GLint wh = rect.bottom; glDisable( GL_DEPTH_TEST ); // Set up OpenGL matrix stacks glMatrixMode( GL_PROJECTION ); glPushMatrix(); glLoadIdentity(); gluOrtho2D( 0, ww-1, 0, wh-1 ); glMatrixMode( GL_MODELVIEW ); glPushMatrix(); glLoadIdentity(); // Create bitmaps for the device context font's first 256 glyphs wglUseFontBitmaps( g_hDC, 0, 256, 1000 ); // Set up for a string-drawing display list call glListBase( 1000 ); // FPS currentTime = GetTickCount() / 1000; x = ww-200; y = wh-15; // Increase the frame counter ++framesPerSecond; if ( currentTime - lastTime >= 1 ) { lastTime = currentTime; // Copy the frames per second into a string to display in the window sprintf( strFrameRate, "FPS: %d ", GLint( framesPerSecond ) ); // Reset the frames per second framesPerSecond = 0; } // Draw FPS on screen glRasterPos2i( x, y ); glCallLists( 29, GL_UNSIGNED_BYTE, strFrameRate ); // Get mesh LMesh &mesh = obj->GetMesh( 0 ); // Draw vertex count x = ww-200; y = wh-30; glRasterPos2i( x, y ); ZeroMemory( string, 80 ); sprintf( string, "Vertex count: %d ", mesh.GetVertexCount() ); glCallLists( 26, GL_UNSIGNED_BYTE, string ); // Draw triangle count x = ww-200; y = wh-45; glRasterPos2i( x, y ); ZeroMemory( string, 80 ); sprintf( string, "Triangle count: %d ", mesh.GetTriangleCount() ); glCallLists( 25, GL_UNSIGNED_BYTE, string ); // Reconfigure OpenGL matrix stacks glMatrixMode( GL_PROJECTION ); glPopMatrix(); glMatrixMode( GL_MODELVIEW ); glPopMatrix(); glEnable( GL_DEPTH_TEST ); } //----------------------------------------------------------------------------- // Name: draw3DSObject( void ) // Desc: 3DS model rendering function //----------------------------------------------------------------------------- void draw3DSObject( void ) { for ( GLuint z=0; z < obj->GetMeshCount(); z++ ) { LMesh &mesh = obj->GetMesh( z ); // Set vertex arrays as vertex shader inputs cgGLEnableClientState( cgNormal ); cgGLEnableClientState( cgPosition ); cgGLEnableClientState( cgTexcoords ); // Point to corresponding vertex arrays cgGLSetParameterPointer( cgNormal, 3, GL_FLOAT, 0, &mesh.GetNormal( 0 ) ); cgGLSetParameterPointer( cgPosition, 4, GL_FLOAT, 0, &mesh.GetVertex( 0 ) ); cgGLSetParameterPointer( cgTexcoords, 2, GL_FLOAT, 0, &mesh.GetUV( 0 ) ); // Draw primitives glDrawElements( GL_TRIANGLES, mesh.GetTriangleCount()*3, GL_UNSIGNED_SHORT, &mesh.GetTriangle( 0 ) ); cgGLDisableClientState( cgNormal ); cgGLDisableClientState( cgPosition ); cgGLDisableClientState( cgTexcoords ); } }