Hi: I am intrested in bringing in more than one texture to the cross. I would like to display 2 or more textures but am not sure how to do this. Could anyone help me? I am using Visual Studio.net 2003. I have created a .bmp file the same as the original wood.bmp (same size, different texture), but I am not sure how to add it in. I am trying to make one part of the cross one texture and the other another texture. Below is my source. ~Convergence6.cpp~
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glut32.lib")
#pragma comment(lib, "glaux.lib")
#include "windows.h"
#include "stdio.h"
#include "GL/gl.h"
#include "GL/glu.h"
#include "GL/glaux.h"
#include "stdafx.h"
#include "SCI.h"
#include "MilkshapeModel.h"
#include "math.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
HDC hDC = NULL;
HGLRC hRC = NULL;
HWND hWnd = NULL;
HINSTANCE hInstance;
Model *pModel = NULL;
bool keys[256];
bool active = TRUE;
bool fullscreen = TRUE;
bool light;
bool lp;
bool fp;
bool sp;
int part1;
int part2;
int p1=0;
int p2=0;
//X Rotation
GLfloat xrot = 0;
//Y Rotation
GLfloat yrot = 0;
//Z Rotation
GLfloat zrot = 0;
//X Rotation Speed
GLfloat xspeed;
//Y Rotation Speed
GLfloat yspeed;
// Depth into the screen
GLfloat z = -10.0f;
GLUquadricObj *quadratic;
GLfloat LightAmbient[]= {0.5f, 0.5f, 0.5f, 1.0f};
GLfloat LightDiffuse[]= {1.0f, 1.0f, 1.0f, 1.0f};
GLfloat LightPosition[] = {0.0f, 0.0f, 2.0f, 1.0f};
//Which filter to use
GLuint filter;
//Storage for 6 textures
GLuint texture[6];
GLuint object = 1;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
AUX_RGBImageRec *LoadBMP(const char *Filename)
{
//File handle
FILE *File = NULL;
//Check filename was given
if(!Filename)
{
return NULL;
}
// Check to see if the file exists
File = fopen(Filename, "r");
//Does the file exist?
if(File)
{
// close the handle
fclose(File);
//Load the bitmap and return the pointer
return auxDIBImageLoad(Filename);
}
//if load failed to return null
return NULL;
}
GLuint LoadGLTexture(const char *filename)
{
// Create storage space for the texture
AUX_RGBImageRec *pImage;
GLuint texture = 0;
//pImage = LoadBMP("Data/Wood2.bmp");
pImage = LoadBMP("Data/Wood.bmp");
//Load the bitmap, check for errors, If bitmap's not found quit
if(pImage!=NULL && pImage -> data != NULL)
{
//Create 3 textures
glGenTextures(1, &texture);
//glGenTextures(2, &texture);
//Create nearest filtered texture
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, 3, pImage->sizeX, pImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, pImage->data);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
free(pImage->data);
free(pImage);
}
return texture;
}
GLvoid ReSizeGLScene(GLsizei width, GLsizei height)
{
// Prevents a divide by 0
if(height == 0)
{
height = 1;
}
// Reset the current viewport
glViewport(0,0,width,height);
//Select the Modelview matrix
glMatrixMode(GL_PROJECTION);
//Reset the Projection Matrix
glLoadIdentity();
//calculate the aspect ratio of the window
gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,1000.0f);
//Select the Modelview Matrix
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
int InitGL(GLvoid)
{
pModel ->reloadTextures();
glEnable(GL_TEXTURE_2D);
// Enable smooth shading
glShadeModel(GL_SMOOTH);
// Black Background (red, green, blue, alpha)
// Range 0.0f(darkest)-1.0f(brightest)
glClearColor(0.0f, 0.0f, 0.0f, 0.5f);
// Depth buffer setup
glClearDepth(1.0f);
// Enables depth testing
glEnable(GL_DEPTH_TEST);
// The Type of Depth Test To Do
glDepthFunc(GL_LEQUAL);
// Perspective calculations for the view to look better
glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
return TRUE;
}
int DrawGLScene(GLvoid)
{
// Clear screen and depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Reset the current modelview matrix
glLoadIdentity();
gluLookAt(250, 250, 250, 0, 0, 0, 0, 1, 0);
glRotatef(xrot, 1.0f, 0.0f, 0.0f);
glRotatef(yrot, 0.0f, 1.0f, 0.0f);
glRotatef(zrot, 0.0f, 0.0f, 1.0f);
pModel->draw();
return TRUE; // Keep Going
}
// Function to properly kill the window
GLvoid KillGLWindow(GLvoid)
{
// In full screen mode?
if(fullscreen)
{
// If so switch back to the desktop
ChangeDisplaySettings(NULL, 0);
// Show mouse pointer
ShowCursor(TRUE);
}
// Check for rendering context
if(hRC)
{
// Check to see if able to release RC and DC context
if(!wglMakeCurrent(NULL,NULL))
{
MessageBox(NULL, "Release of DC and RC Failed", "SHUTDOWN ERROR", MB_OK|MB_ICONINFORMATION);
}
// Check to see if able to delete RC
if(!wglDeleteContext(hRC))
{
// Error message if not able to.
MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
}
// Set the RC to Null
hRC = NULL;
}
//Check to see if able to release the DC
if(hDC && !ReleaseDC(hWnd, hDC))
{
// Error message if unable to release the DC
MessageBox(NULL, "Release device context failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Set DC to null.
hDC = NULL;
}
//Check to see if able to destroy the window
if(hWnd && !DestroyWindow(hWnd))
{
MessageBox(NULL, "Could not release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
// Set hWnd to null.
hWnd = NULL;
}
// Check to see if unable to register class
if(!UnregisterClass("OpenGL", hInstance))
{
MessageBox(NULL, "Could not unregister class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
hInstance = NULL;
}
}
BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
// Contains the result after searching for a match
GLuint PixelFormat;
// Windows class structure
WNDCLASS wc;
// Window Extended Style
DWORD dwExStyle;
// Window Style
DWORD dwStyle;
// Grabs Rectangle Upper Left/ Lower Right
RECT WindowRect;
/*****Values*****/
// Set left value to 0
WindowRect.left = (long)0;
// Set right value to requested width
WindowRect.right = (long) width;
// Set top value to 0.
WindowRect.top = (long)0;
// Set bottom value to requested height
WindowRect.bottom = (long) height;
//Set the global fullscreen flag
fullscreen = fullscreenflag;
// Grab an instance for the window
hInstance = GetModuleHandle(NULL);
//Redraw On Size, And Own DC for Window
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
// WndProc Handling messages
wc.lpfnWndProc = (WNDPROC) WndProc;
// No extra window data
wc.cbClsExtra = 0;
// No extra window data
wc.cbWndExtra = 0;
// Set the instance
wc.hInstance = hInstance;
// Load the default icon
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
// Load the Arrow Pointer
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
// No background required.
wc.hbrBackground = NULL;
// No Menu
wc.lpszMenuName = NULL;
// Set the class name
wc.lpszClassName = "OpenGL";
// Check to see if class is registered
if(!RegisterClass(&wc))
{
MessageBox(NULL, "Failed to register the window class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION);
return FALSE;
}
//Try fullscreen mode
if(fullscreen)
{
// Device Mode
DEVMODE dmScreenSettings;
// Clear Memory
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
// Size of DEVMODE structure
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
// Selected screen width
dmScreenSettings.dmPelsWidth = width;
// Selected screen height
dmScreenSettings.dmPanningHeight = height;
//Seleted bits per pixel
dmScreenSettings.dmBitsPerPel = bits;
dmScreenSettings.dmFields = DM_BITSPERPEL| DM_PELSWIDTH | DM_PELSHEIGHT;
//Select Mode
if(ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
if(MessageBox(NULL, "The Requested Fullscreen Mode is Not Supported By \n Your Video Card. Use Windowed Mode Instead?", "FSL GL", MB_YESNO|MB_ICONEXCLAMATION) ==
IDYES)
{
// Windowed mode selected
fullscreen = FALSE;
}
else
{
//Program closing message
MessageBox(NULL, "Program Closing", "ERROR", MB_OK|MB_ICONSTOP);
return FALSE;
}
}
}
// Check to see if in Full Screen Mode
if(fullscreen)
{
//Window extended Style
dwExStyle = WS_EX_APPWINDOW;
//Windows style
dwStyle = WS_POPUP;
// Hide Mouse pointer
ShowCursor(FALSE);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
//Adjust window to requested size
AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);
//Create Window
if(!(hWnd = CreateWindowEx( dwExStyle, // Extended Style For The Window
"OpenGL", // Class Name
title,
dwStyle| // Selected Window Style // Window Title
WS_CLIPSIBLINGS | // Required Window Style
WS_CLIPCHILDREN, // Required Window Style
0, 0, // Window Position
WindowRect.right-WindowRect.left, // Calculate Adjusted Window Width
WindowRect.bottom-WindowRect.top, // Calculate Adjusted Window Height
NULL, // No Parent Window
NULL, // No Menu
hInstance, // Instance
NULL))) // Don't Pass Anything To WM_CREATE
{
KillGLWindow();
MessageBox(NULL, "Window Creation Error", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
static PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
1, // Version Number
PFD_DRAW_TO_WINDOW | // Format Must Support Window
PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
PFD_DOUBLEBUFFER, // Must Support Double Buffering
PFD_TYPE_RGBA, // Request An RGBA Format
bits, // Select Our Color Depth
0, 0, 0, 0, 0, 0, // Color Bits Ignored
0, // No Alpha Buffer
0, // Shift Bit Ignored
0, // No Accumulation Buffer
0, 0, 0, 0, // Accumulation Bits Ignored
16, // 16Bit Z-Buffer (Depth Buffer)
0, // No Stencil Buffer
0, // No Auxiliary Buffer
PFD_MAIN_PLANE, // Main Drawing Layer
0, // Reserved
0, 0, 0 // Layer Masks Ignored
};
//Check to see if we recieved device context
if(!(hDC=GetDC(hWnd)))
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Can't create a GL device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
//Check for matching pixel format
if(!(PixelFormat=ChoosePixelFormat(hDC, &pfd)))
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Can't Find a suitable pixel format.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
//Check to see if able to set pixel format
if(!SetPixelFormat(hDC, PixelFormat, &pfd))
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Can't set the pixel format.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// Check for Rendering Context
if(!(hRC = wglCreateContext(hDC)))
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Can't create a GL device Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// Check to see if able to get Rendering Context
if(!(hRC = wglCreateContext(hDC)))
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Can't create a GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
// Try to activate the rendering context
if(!wglMakeCurrent(hDC, hRC))
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Can't create a GL Rendering Context.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
//Show the window.
ShowWindow(hWnd, SW_SHOW);
//Giving it higher priority (foreground window)
SetForegroundWindow(hWnd);
//Set the keyboard focus to this window
SetFocus(hWnd);
//Set up our perspective GL screen
ReSizeGLScene(width, height);
//Initialize our newly created GL
if(!InitGL())
{
// Reset the display
KillGLWindow();
MessageBox(NULL, "Initialization Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return FALSE;
}
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
// Check for windows message
switch (uMsg)
{
// Watch for windows activate message
case WM_ACTIVATE:
{
//Check minimazation state
if(!HIWORD(wParam))
{
// Program is active
active=TRUE;
}
else
{
//Program is no longer active
active=FALSE;
}
return 0;
}
// Intercept system command
case WM_SYSCOMMAND:
{
// check system calls
switch(wParam)
{
// Check to see if screen saver trying to start
case SC_SCREENSAVE:
// Check to see if the monitor is trying to enter power save
case SC_MONITORPOWER:
// Prevent from happening
return 0;
}
break;
}
// Did we recieve a close message
case WM_CLOSE:
{
// Send a quit message
PostQuitMessage(0);
// Jump Back
return 0;
}
// Check to see if a key is being held down
case WM_KEYDOWN:
{
keys[wParam]=TRUE;
return 0;
}
// Check to see if a key has been released
case WM_KEYUP:
{
keys[wParam]=FALSE;
return 0;
}
// Resize the OpenGL window
case WM_SIZE:
{
// LoWord = Width, HiWord = Height
ReSizeGLScene(LOWORD(lParam), HIWORD(lParam));
return 0;
}
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
BOOL done=FALSE;
int count=0;
int counta=0;
int rightLeft=0;
int rotback=0;
double xchange = 0;
double ychange = 0;
double zchange = 0;
int count1 = 0;
int count2 = 0;
int count_x_right = 0;
int count_x_left = 0;
int count_y_up = 0;
int count_y_down = 0;
int count_x_right_little = 0;
int count_x_left_little = 0;
int count_y_up_little = 0;
int count_y_down_little = 0;
int angle_x = 0;
double x_val;
double x_old;
double y_val;
double y_old;
double z_val;
double z_old;
#define SENSITIVITY = .8
// varibale to store address of character
unsigned char ua;
// Variables to acquire calibration values
unsigned char Xoff, Yoff, Zoff, Xmax, Ymax, Zmax;
// Variables to get x, y, and z values
unsigned char TiltX, TiltY, TiltZ;
int BadHandShakeTilt;
pModel = new MilkshapeModel();
if(pModel ->loadModelData("Data/Model2.ms3d") == false)
{
MessageBox(NULL, "Couldn't load the model data\\model.ms3d", "Error", MB_OK|MB_ICONERROR);
return 0;
}
// Ask the User which screen mode they prefer?
if(MessageBox(NULL, "Would you like to run in Fullscreen Mode?", "Start Fullscreen", MB_YESNO|MB_ICONQUESTION) == IDNO)
{
//Windowed mode
fullscreen = FALSE;
}
//Open up communication port.
bool bOK=SCIopen();
if (!bOK)
{
// If COM 4 does not open then Kill window and display error message.
KillGLWindow();
MessageBox(NULL, "COM 4 Failed.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
return 0;
}
//Handshake with hardware
SCIwrite("R", 1);
ua = ' ';
SCIread(ua,1);
if(ua != 'N')
{
KillGLWindow();
MessageBox(NULL, "Handshake failed!", "ERROR", MB_OK | MB_ICONEXCLAMATION);
}
//Get Calibration Values
//bool bSCI = SCIgetCal(Xoff, Xmax, Yoff, Ymax, Zoff, Zmax);
Xoff = 123;
Yoff = 131;
Zoff = 137;
Xmax = 189;
Ymax = 189;
Zmax = 152;
BadHandShakeTilt = 0;
//Create our OpenGLWindow
if(!CreateGLWindow("FSL OpenGL Framework", 640, 480, 16, fullscreen))
{
// Quit if the window has not been created
return 0;
}
// Loop that runs while done=False
while(!done)
{
bool bSCI2 = SCIgetXYZ(TiltX, TiltY, TiltZ);
if(!bSCI2)
{
TiltX=TiltY=TiltZ=0;
BadHandShakeTilt++;
}
if(BadHandShakeTilt > 10)
{
BadHandShakeTilt = 0;
SCIHandShake();
MessageBox(NULL, "Bad Tilt Values.", "ERROR", MB_OK | MB_ICONEXCLAMATION);
}
// Check to see if message is waiting
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
//Check to see if quit message has been received
if(msg.message==WM_QUIT)
{
done=TRUE;
}
// Deal with window message
else
{
// Translate the message
TranslateMessage(&msg);
// Dispatch the message
DispatchMessage(&msg);
}
}
else
{
//Draw the Scene. Watch for ESC key and Quit Messages from DrawGLScene
if(active)
{
// Was ESC Pressed
if(keys[VK_ESCAPE])
{
// ESC signaled a quit
done = TRUE;
}
// Not time to quit update the screen
else
{
//Draw the scene
DrawGLScene();
// Swap buffers (double buffering)
SwapBuffers(hDC);
if (keys['Z']) // Is Page Up Being Pressed?
{
z-=0.02f; // If So, Move Into The Screen
}
//Rotation for X axis Loop
// X Rotation Right
x_old = xchange;
xchange=(TiltX-Xoff*1.0)/(Xmax-Xoff*1.0);
if (xchange<-1.0)
xchange=-1.0;
else if (xchange>1.0)
xchange=1.0;
xchange=asin(xchange)*180.0/3.1416;
x_val = abs(x_old - xchange);
if(x_val > 7)
zrot = xchange;
y_old = ychange;
ychange=(TiltY-Yoff*1.0)/(Ymax-Yoff*1.0);
if (ychange<-1.0)
ychange=-1.0;
else if (ychange>1.0)
ychange=1.0;
ychange=asin(ychange)*180.0/3.1416;
y_val = abs(y_old - ychange);
if(y_val > 7)
xrot = ychange;
/*z_old = zchange;
zchange=(TiltZ-Zoff*1.0)/(Zmax-Zoff*1.0);
if (zchange<-1.0)
zchange=-1.0;
else if (zchange>1.0)
zchange=1.0;
zchange=asin(zchange)*180.0/3.1416;
z_val = abs(z_old - zchange);
if(z_val > 5)
yrot = zchange; */
//if( xchange > 40)
//{
//rotates it to center point
//rotates it to center point
/*if(count_x_left != 0)
{
count_x_left--;
yrot -= 0.9f;
}
if(count_x_left_little != 0)
{
count_x_left_little--;
yrot -= 0.5f;
}*/
/*if(count_x_left == 0 && count_x_left_little == 0 && count_x_right < 2)
{
xrot -= xchange;
//count_x_right++;
}
//}
if(xchange > 20 && xchange < 40)// If So, Decrease xspeed?
{
if(count_x_right !=0)
{
count_x_right--;
yrot +=4.5f;
count_x_right_little++;
}
//rotates it to center point
/*if(count_x_left != 0)
{
count_x_left--;
yrot -= 0.9f;
}
if(count_x_left_little != 0)
{
count_x_left_little--;
yrot -= 0.5f;
}*/
/*if(count_x_left_little == 0 && count_x_left == 0 && count_x_right_little < 2)
{
yrot -= 0.9f;
count_x_right_little++;
}
}
//X Rotation Left
if(xchange < -20 && xchange > -40)// If So, Decrease xspeed?
{
//rotate to center point
if(count_x_right != 0)
{
count_x_right--;
yrot += 0.05f;
//rightLeft = 2; //Left causes this to be 2
}
if(count_x_right == 0 && count_x_left < 500)
{
count_x_left++;
yrot += 0.05f;
}
}
if(xchange < 20 && xchange > -20)
{
if(count_x_right != 0)
{
count_x_right--;
yrot += 0.05f;
}
if(count_x_left != 0)
{
count_x_left--;
yrot -= 0.05f;
}
}
// X Rotation Right
ychange = TiltY - Yoff;
if(ychange > 20)// If So, Decrease xspeed?
{
//rotates it to center point
if(count_y_down != 0)
{
count_y_down--;
xrot -= 0.05f;
}
if(count_y_down == 0 && count_y_up < 500)
{
xrot -= 0.05f;
count_y_up++;
}
}
//X Rotation Left
if(ychange < -20)// If So, Decrease xspeed?
{
//rotate to center point
if(count_y_up != 0)
{
count_y_up--;
xrot += 0.05f;
}
if(count_y_up == 0 && count_y_down < 500)
{
count_y_down++;
xrot += 0.05f;
}
}
if(ychange < 20 && ychange > -20)
{
if(count_y_up != 0)
{
count_y_up--;
xrot += 0.05f;
}
if(count_y_down != 0)
{
count_y_down--;
xrot -= 0.05f;
}
} */
}
}
// Is F1 being pressed?
if (keys[VK_F1])
{
//if so make key FALSE
keys[VK_F1]=FALSE;
// Kill our current window
KillGLWindow();
// Toggle Full Screen/ Windowed Mode
fullscreen = !fullscreen;
//Recreate OpenGL Window
if(!CreateGLWindow("FSL OpenGL Framework", 640,480,16,fullscreen))
{
return 0;
}
}
}
}
// Shutdown
// Kill The window
KillGLWindow();
//Exit the program
return(1);//msg.wParam);
return 0;
}
/*
MilkshapeModel.cpp
Loads and renders a Milkshape3D model.
Author: Brett Porter
Email: brettporter@yahoo.com
Website: http://www.geocities.com/brettporter/
Copyright (C)2000, Brett Porter. All Rights Reserved.
This file may be used only as long as this copyright notice remains intact.
*/
#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include <ios>
#include "MilkshapeModel.h"
#include <fstream>
using namespace std;
MilkshapeModel::MilkshapeModel()
{
}
MilkshapeModel::~MilkshapeModel()
{
}
/*
MS3D STRUCTURES
*/
// byte-align structures
#ifdef _MSC_VER
# pragma pack( push, packing )
# pragma pack( 1 )
# define PACK_STRUCT
#elif defined( __GNUC__ )
# define PACK_STRUCT __attribute__((packed))
#else
# error you must byte-align these structures with the appropriate compiler directives
#endif
typedef unsigned char byte;
typedef unsigned short word;
// File header
struct MS3DHeader
{
char m_ID[10];
int m_version;
} PACK_STRUCT;
// Vertex information
struct MS3DVertex
{
byte m_flags;
float m_vertex[3];
char m_boneID;
byte m_refCount;
} PACK_STRUCT;
// Triangle information
struct MS3DTriangle
{
word m_flags;
word m_vertexIndices[3];
float m_vertexNormals[3][3];
float m_s[3], m_t[3];
byte m_smoothingGroup;
byte m_groupIndex;
} PACK_STRUCT;
// Material information
struct MS3DMaterial
{
char m_name[32];
float m_ambient[4];
float m_diffuse[4];
float m_specular[4];
float m_emissive[4];
float m_shininess; // 0.0f - 128.0f
float m_transparency; // 0.0f - 1.0f
byte m_mode; // 0, 1, 2 is unused now
char m_texture[128];
char m_alphamap[128];
} PACK_STRUCT;
// Joint information
struct MS3DJoint
{
byte m_flags;
char m_name[32];
char m_parentName[32];
float m_rotation[3];
float m_translation[3];
word m_numRotationKeyframes;
word m_numTranslationKeyframes;
} PACK_STRUCT;
// Keyframe data
struct MS3DKeyframe
{
float m_time;
float m_parameter[3];
} PACK_STRUCT;
// Default alignment
#ifdef _MSC_VER
# pragma pack( pop, packing )
#endif
#undef PACK_STRUCT
bool MilkshapeModel::loadModelData( const char *filename )
{
ifstream inputFile( filename, ios::in | ios::binary);
if ( inputFile.fail())
return false; // "Couldn't open the model file."
inputFile.seekg( 0, ios::end );
long fileSize = inputFile.tellg();
inputFile.seekg( 0, ios::beg );
const byte *pBuffer = new byte[fileSize];
inputFile.read( (char *)pBuffer, fileSize );
inputFile.close();
const byte *pPtr = pBuffer;
MS3DHeader *pHeader = ( MS3DHeader* )pPtr;
pPtr += sizeof( MS3DHeader );
if ( strncmp( pHeader->m_ID, "MS3D000000", 10 ) != 0 )
return false; // "Not a valid Milkshape3D model file."
if ( pHeader->m_version < 3 || pHeader->m_version > 8 )
return false; // "Unhandled file version. Only Milkshape3D Version 1.3 and 1.4 is supported." );
int nVertices = *( word* )pPtr;
m_numVertices = nVertices;
m_pVertices = new Vertex[nVertices];
pPtr += sizeof( word );
int i;
for ( i = 0; i < nVertices; i++ )
{
MS3DVertex *pVertex = ( MS3DVertex* )pPtr;
m_pVertices.m_boneID = pVertex->m_boneID;
memcpy( m_pVertices.m_location, pVertex->m_vertex, sizeof( float )*3 );
pPtr += sizeof( MS3DVertex );
}
int nTriangles = *( word* )pPtr;
m_numTriangles = nTriangles;
m_pTriangles = new Triangle[nTriangles];
pPtr += sizeof( word );
for ( i = 0; i < nTriangles; i++ )
{
MS3DTriangle *pTriangle = ( MS3DTriangle* )pPtr;
int vertexIndices[3] = { pTriangle->m_vertexIndices[0], pTriangle->m_vertexIndices[1], pTriangle->m_vertexIndices[2] };
float t[3] = { 1.0f-pTriangle->m_t[0], 1.0f-pTriangle->m_t[1], 1.0f-pTriangle->m_t[2] };
memcpy( m_pTriangles.m_vertexNormals, pTriangle->m_vertexNormals, sizeof( float )*3*3 );
memcpy( m_pTriangles.m_s, pTriangle->m_s, sizeof( float )*3 );
memcpy( m_pTriangles.m_t, t, sizeof( float )*3 );
memcpy( m_pTriangles.m_vertexIndices, vertexIndices, sizeof( int )*3 );
pPtr += sizeof( MS3DTriangle );
}
int nGroups = *( word* )pPtr;
m_numMeshes = nGroups;
m_pMeshes = new Mesh[nGroups];
pPtr += sizeof( word );
for ( i = 0; i < nGroups; i++ )
{
pPtr += sizeof( byte ); // flags
pPtr += 32; // name
word nTriangles = *( word* )pPtr;
pPtr += sizeof( word );
int *pTriangleIndices = new int[nTriangles];
for ( int j = 0; j < nTriangles; j++ )
{
pTriangleIndices[j] = *( word* )pPtr;
pPtr += sizeof( word );
}
char materialIndex = *( char* )pPtr;
pPtr += sizeof( char );
m_pMeshes.m_materialIndex = materialIndex;
m_pMeshes.m_numTriangles = nTriangles;
m_pMeshes.m_pTriangleIndices = pTriangleIndices;
}
int nMaterials = *( word* )pPtr;
m_numMaterials = nMaterials;
m_pMaterials = new Material[nMaterials];
pPtr += sizeof( word );
for ( int k = 0; k < nMaterials; k++ )
{
MS3DMaterial *pMaterial = ( MS3DMaterial* )pPtr;
memcpy( m_pMaterials[k].m_ambient, pMaterial->m_ambient, sizeof( float )*4 );
memcpy( m_pMaterials[k].m_diffuse, pMaterial->m_diffuse, sizeof( float )*4 );
memcpy( m_pMaterials[k].m_specular, pMaterial->m_specular, sizeof( float )*4 );
memcpy( m_pMaterials[k].m_emissive, pMaterial->m_emissive, sizeof( float )*4 );
m_pMaterials[k].m_shininess = pMaterial->m_shininess;
m_pMaterials[k].m_pTextureFilename = new char[strlen( pMaterial->m_texture )+1];
strcpy( m_pMaterials[k].m_pTextureFilename, pMaterial->m_texture );
pPtr += sizeof( MS3DMaterial );
}
reloadTextures();
delete[] pBuffer;
return true;
}
[/source/
~Model.cpp~
[souce]
/*
Model.cpp
Abstract base class for a model. The specific extended class will render the given model.
Author: Brett Porter
Email: brettporter@yahoo.com
Website: http://www.geocities.com/brettporter/
Copyright (C)2000, Brett Porter. All Rights Reserved.
This file may be used only as long as this copyright notice remains intact.
*/
#include <windows.h> // Header File For Windows
#include <gl\gl.h> // Header File For The OpenGL32 Library
#include "Model.h"
#include "Lesson31.h"
Model::Model()
{
m_numMeshes = 0;
m_pMeshes = NULL;
m_numMaterials = 0;
m_pMaterials = NULL;
m_numTriangles = 0;
m_pTriangles = NULL;
m_numVertices = 0;
m_pVertices = NULL;
}
Model::~Model()
{
int i;
for ( i = 0; i < m_numMeshes; i++ )
delete[] m_pMeshes.m_pTriangleIndices;
for ( i = 0; i < m_numMaterials; i++ )
delete[] m_pMaterials.m_pTextureFilename;
m_numMeshes = 0;
if ( m_pMeshes != NULL )
{
delete[] m_pMeshes;
m_pMeshes = NULL;
}
m_numMaterials = 0;
if ( m_pMaterials != NULL )
{
delete[] m_pMaterials;
m_pMaterials = NULL;
}
m_numTriangles = 0;
if ( m_pTriangles != NULL )
{
delete[] m_pTriangles;
m_pTriangles = NULL;
}
m_numVertices = 0;
if ( m_pVertices != NULL )
{
delete[] m_pVertices;
m_pVertices = NULL;
}
}
void Model::draw()
{
GLboolean texEnabled = glIsEnabled( GL_TEXTURE_2D );
// Draw by group
for ( int i = 0; i < m_numMeshes; i++ )
{
int materialIndex = m_pMeshes.m_materialIndex;
if ( materialIndex >= 0 )
{
glMaterialfv( GL_FRONT, GL_AMBIENT, m_pMaterials[materialIndex].m_ambient );
glMaterialfv( GL_FRONT, GL_DIFFUSE, m_pMaterials[materialIndex].m_diffuse );
glMaterialfv( GL_FRONT, GL_SPECULAR, m_pMaterials[materialIndex].m_specular );
glMaterialfv( GL_FRONT, GL_EMISSION, m_pMaterials[materialIndex].m_emissive );
glMaterialf( GL_FRONT, GL_SHININESS, m_pMaterials[materialIndex].m_shininess );
if ( m_pMaterials[materialIndex].m_texture > 0 )
{
glBindTexture( GL_TEXTURE_2D, m_pMaterials[materialIndex].m_texture );
glEnable( GL_TEXTURE_2D );
}
else
glDisable( GL_TEXTURE_2D );
}
else
{
// Material properties?
glDisable( GL_TEXTURE_2D );
}
glBegin( GL_TRIANGLES );
{
for ( int j = 0; j < m_pMeshes.m_numTriangles; j++ )
{
int triangleIndex = m_pMeshes.m_pTriangleIndices[j];
const Triangle* pTri = &m_pTriangles[triangleIndex];
for ( int k = 0; k < 3; k++ )
{
int index = pTri->m_vertexIndices[k];
glNormal3fv( pTri->m_vertexNormals[k] );
glTexCoord2f( pTri->m_s[k], pTri->m_t[k] );
glVertex3fv( m_pVertices[index].m_location );
}
}
}
glEnd();
}
if ( texEnabled )
glEnable( GL_TEXTURE_2D );
else
glDisable( GL_TEXTURE_2D );
}
void Model::reloadTextures()
{
for ( int i = 0; i < m_numMaterials; i++ )
if ( strlen( m_pMaterials.m_pTextureFilename ) > 0 )
m_pMaterials.m_texture = LoadGLTexture( m_pMaterials.m_pTextureFilename );
else
m_pMaterials.m_texture = 0;
}