Skip to main content
gamedev.net
🔒 Locked

Debugging! Help! Please!

Started by Mat1515 3 replies 1.1k views
Original Post
Mat1515
Mat1515
Hey ive been programming for about 1 year in C/C++ recently ive been trying to implement the 3DS loader from www.gametutials.com into my devloping game. I keep getting these errors tho and cannot fix them Help Please Errors = --------------------Configuration: Drag Race - Win32 Debug-------------------- Compiling... Camera.cpp c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2143: syntax error : missing '';'' before ''*'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2501: ''CVector2'' : missing storage-class or type specifiers c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2501: ''pTexVerts'' : missing storage-class or type specifiers Main.cpp c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2143: syntax error : missing '';'' before ''*'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2501: ''CVector2'' : missing storage-class or type specifiers c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2501: ''pTexVerts'' : missing storage-class or type specifiers c:\program files\microsoft visual studio\myprojects\drag race\main.cpp(373) : error C2039: ''pTexVerts'' : is not a member of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(85) : see declaration of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\main.cpp(374) : error C2039: ''pTexVerts'' : is not a member of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(85) : see declaration of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\main.cpp(374) : error C2228: left of ''.x'' must have class/struct/union type c:\program files\microsoft visual studio\myprojects\drag race\main.cpp(374) : error C2039: ''pTexVerts'' : is not a member of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(85) : see declaration of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\main.cpp(374) : error C2228: left of ''.y'' must have class/struct/union type c:\program files\microsoft visual studio\myprojects\drag race\main.cpp(495) : error C2039: ''pTexVerts'' : is not a member of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(85) : see declaration of ''t3DObject'' 3ds.cpp c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2143: syntax error : missing '';'' before ''*'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2501: ''CVector2'' : missing storage-class or type specifiers c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(94) : error C2501: ''pTexVerts'' : missing storage-class or type specifiers c:\program files\microsoft visual studio\myprojects\drag race\3ds.cpp(475) : error C2039: ''pTexVerts'' : is not a member of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(85) : see declaration of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\3ds.cpp(478) : error C2039: ''pTexVerts'' : is not a member of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\globals.hpp(85) : see declaration of ''t3DObject'' c:\program files\microsoft visual studio\myprojects\drag race\3ds.cpp(714) : error C2552: ''vSum'' : non-aggregates cannot be initialized with initializer list Error executing cl.exe. Drag Race.exe - 18 error(s), 0 warning(s) Code Below COMPILER SAYS PROBLEM IS IN HERE!
//GLOBAL DECLARATIONS GO HERE!!!

#ifndef _GLOBALS_H
#define _GLOBALS_H


//Includes

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <fstream>
#include <vector>
#include <gl\gl.h>										// Header File For The OpenGL32 Library

#include <gl\glu.h>										// Header File For The GLu32 Library

#include <gl\glaux.h>
#include <crtdbg.h>
using namespace std;

#define SCREEN_WIDTH 800								// We want our screen width 800 pixels

#define SCREEN_HEIGHT 600								// We want our screen height 600 pixels

#define SCREEN_DEPTH 16		
#define MAX_TEXTURES 100									// This says how many texture we will be using

//VECTOR CLASS

class CVector3 {
	public:				//Public Access

		// A default constructor

	CVector3() {}

	// This is our constructor that allows us to initialize our data upon creating an instance

	CVector3(float X, float Y, float Z) 
	{ 
		x = X; y = Y; z = Z;
	}

	// Here we overload the + operator so we can add vectors together 

	CVector3 operator+(CVector3 vVector)
	{
		// Return the added vectors result.

		return CVector3(vVector.x + x, vVector.y + y, vVector.z + z);
	}

	// Here we overload the - operator so we can subtract vectors 

	CVector3 operator-(CVector3 vVector)
	{
		// Return the subtracted vectors result

		return CVector3(x - vVector.x, y - vVector.y, z - vVector.z);
	}
	
	// Here we overload the * operator so we can multiply by scalars

	CVector3 operator*(float num)
	{
		// Return the scaled vector

		return CVector3(x * num, y * num, z * num);
	}

	// Here we overload the / operator so we can divide by a scalar

	CVector3 operator/(float num)
	{
		// Return the scale vector

		return CVector3(x / num, y / num, z / num);
	}

	float x, y, z;						
};

struct tFace
{
	int vertIndex[3];			// indicies for the verts that make up this triangle

	int coordIndex[3];			// indicies for the tex coords to texture this face

};

struct tMaterialInfo
{
	char  strName[255];			// The texture name

	char  strFile[255];			// The texture file name (If this is set it''s a texture map)

	BYTE  color[3];				// The color of the object (R, G, B)

	int   texureId;				// the texture ID

	float uTile;				// u tiling of texture  (Currently not used)

	float vTile;				// v tiling of texture	(Currently not used)

	float uOffset;			    // u offset of texture	(Currently not used)

	float vOffset;				// v offset of texture	(Currently not used)

};

struct t3DObject 
{
	int  numOfVerts;			// The number of verts in the model

	int  numOfFaces;			// The number of faces in the model

	int  numTexVertex;			// The number of texture coordinates

	int  materialID;			// The texture ID to use, which is the index into our texture array

	bool bHasTexture;			// This is TRUE if there is a texture map for this object

	char strName[255];			// The name of the object

	CVector3  *pVerts;			// The object''s vertices

	CVector3  *pNormals;		// The object''s normals

	CVector2  *pTexVerts;		// The texture''s UV coordinates

	tFace *pFaces;				// The faces information of the object

};

struct t3DModel 
{
	int numOfObjects;					// The number of objects in the model

	int numOfMaterials;					// The number of materials for the model

	vector<tMaterialInfo> pMaterials;	// The list of material information (Textures and colors)

	vector<t3DObject> pObject;			// The object list for our model

};

class CVector2 //Used to store UV coordinates

{
public:
	float x, y;
};

//CAMERA CLASS prototype

class CCamera{	
	public:
		CVector3 m_vPosition;		//Camera Position	

		CVector3 m_vView;			//Camera View

		CVector3 m_vUpVector;		//Up Direction

//m = member Variables 

//Camera Constructor

	CCamera();

	void RotateView(float angle, float x, float y, float z);

	void PositionCamera(float positionX,float positionY,float positionZ,
						float viewX,float viewY,float viewZ,
						float upVectorX, float upVectorY, float upVectorZ);

	void MoveCamera(float speed);

	void SetViewByMouse();

	void Look();
};
						
extern CCamera g_Camera;	//Allows all source files to use this



#endif 
Main.cpp
/*Drag Racing Objectives
	1)Draw 3D world of track
	2)Have single car race for ET and reaction time plus Speed(MPH)
	3)Allow modifictions to car and setup							*/
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glu32.lib")
#pragma comment(lib, "glaux.lib")

#include "Globals.hpp"
#include "3ds.h"

#define CameraSpeed 0.2f

HWND			hwnd = NULL;//handle to window

HINSTANCE		hInstance;//handle  to instance of application

HDC				hDC = NULL;//handle to Device Context

HGLRC			hRC = NULL;//handle to Rendering Context;


CCamera g_Camera; //our camera!

unsigned int g_Texture[MAX_TEXTURES];
CLoad3DS g_Load3ds;										// This is 3DS class.  This should go in a good model class.

t3DModel g_3DModel;										// This holds the 3D Model info that we load in


void KillOpenGL();


void CreateTexture(UINT textureArray[], LPSTR strFileName, int textureID)
{
	AUX_RGBImageRec *pBitmap = NULL;
	
	if(!strFileName)									// Return from the function if no file name was passed in

		return;
	
	pBitmap = auxDIBImageLoad(strFileName);				// Load the bitmap and store the data

	
	if(pBitmap == NULL)									// If we can''t load the file, quit!

		exit(0);

	// Generate a texture with the associative texture ID stored in the array

	glGenTextures(1, &textureArray[textureID]);

	// Bind the texture to the texture arrays index and init the texture

	glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);

	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pBitmap->sizeX, pBitmap->sizeY, GL_RGB, GL_UNSIGNED_BYTE, pBitmap->data);
		
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR_MIPMAP_LINEAR);

	// Now we need to free the bitmap data that we loaded since openGL stored it as a texture


	if (pBitmap)										// If we loaded the bitmap

	{
		if (pBitmap->data)								// If there is texture data

		{
			free(pBitmap->data);						// Free the texture data, we don''t need it anymore

		}

		free(pBitmap);									// Free the bitmap structure

	}
}


void CheckForMovement()
{
	if(GetKeyState(VK_UP) & 0x80)
	{
		g_Camera.MoveCamera(CameraSpeed);
	}
	if(GetKeyState(VK_DOWN) & 0x80)
	{
		g_Camera.MoveCamera(-CameraSpeed);
	}
	
}


void KillOpenGL()
{
	glDeleteTextures(1,&g_Texture[0]);
	glDeleteTextures(1,&g_Texture[1]);
	//deselect rending context and delete it

	wglMakeCurrent(hDC,NULL);
	wglDeleteContext(hRC);
	ShowCursor(true); //Hide Mouse Cursor

	//post quit message

	PostQuitMessage(0);
}

void SetUpGL()
{
	glShadeModel(GL_SMOOTH);//smooth colors blending

	glEnable(GL_TEXTURE_2D);
	glEnable(GL_DEPTH_TEST);
				
	g_Camera.PositionCamera(0, 0.5f, 6,   0, 0.5f, 0,   0, 1, 0); //Camera Start Position!

	ShowCursor(false); //Hide Mouse Cursor

	CreateTexture(g_Texture, "Walls.bmp", 0);
	CreateTexture(g_Texture, "Track.bmp",1);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);	
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);

	g_Load3ds.Import3DS(&g_3DModel, "CAMARO.3ds");			// Load our .3DS file into our model structure


	// Depending on how many textures we found, load each one (Assuming .BMP)

	// If you want to load other files than bitmaps, you will need to adjust CreateTexture().

	// Below, we go through all of the materials and check if they have a texture map to load.

	// Otherwise, the material just holds the color information and we don''t need to load a texture.


	// Go through all the materials

	for(int i = 0; i < g_3DModel.numOfMaterials; i++)
	{
		// Check to see if there is a file name to load in this material

		if(strlen(g_3DModel.pMaterials[i].strFile) > 0)
		{
			// Use the name of the texture file to load the bitmap, with a texture ID (i).

			// We pass in our global texture array, the name of the texture, and an ID to reference it.	

			CreateTexture(g_Texture, g_3DModel.pMaterials[i].strFile, i);			
		}

		// Set the texture ID for this material

		g_3DModel.pMaterials[i].texureId = i;
	}

	// Here, we turn on a lighting and enable lighting.  We don''t need to

	// set anything else for lighting because we will just take the defaults.

	// We also want color, so we turn that on


	glEnable(GL_LIGHT0);								// Turn on a light with defaults set

	glEnable(GL_LIGHTING);								// Turn on lighting

	glEnable(GL_COLOR_MATERIAL);						// Allow color


//////////// *** NEW *** ////////// *** NEW *** ///////////// *** NEW *** ////////////////////



}
bool SetupPixelFormat(HDC hDC)
{
	int nPixelFormat;

	static PIXELFORMATDESCRIPTOR pfd = {
		sizeof(PIXELFORMATDESCRIPTOR),//always set to this

		1,//version always set to 1

		PFD_DRAW_TO_WINDOW|	//support window

		PFD_SUPPORT_OPENGL|	//support opengl

		PFD_DOUBLEBUFFER,	//support double buffering

		PFD_TYPE_RGBA,	//color mode

		32,	//go for 32 bit color mode

		0,0,0,0,0,0,//ignore color bits, not used

		0,//no alpha buffer

		0,//ignore shift bits

		0,//no accumulation buffer

		0,0,0,0,//ignore accumulation bits

		16,//16-bit Z buffer size

		0,//no stencil buffer

		0,//no auxiliary buffer

		PFD_MAIN_PLANE,//main drawing plane

		0,//reserved

		0,0,0};//layer masks ignored


		//choose best matching pixel format, return index as int

		nPixelFormat = ChoosePixelFormat(hDC,&pfd);

		SetPixelFormat(hDC,nPixelFormat,&pfd);//set it!


		return true;
}


//window message handler

LRESULT CALLBACK WndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
	int height, width;//hold window width and height


	switch(message)//switch for sent windows message

	{
	case WM_CREATE://when a window is created

		hDC = GetDC(hwnd);//get the device context for the window pointed to by hwnd

		SetupPixelFormat(hDC);//setup pixel format according to hDC

		//create rendering context and set it as current

		hRC = wglCreateContext(hDC);
		wglMakeCurrent(hDC,hRC);

		return 0;
		break;
	case WM_CLOSE://window closes

		PostQuitMessage(0);//close window

		return 0;
		break;
	case WM_KEYDOWN:

		switch(wParam) 
		{// Check if we hit a key

			case VK_ESCAPE:								// If we hit the escape key

				PostQuitMessage(0);						// Send a QUIT message to the window

				return 0;
				break;
		}
		
		break;

	case WM_SIZE://case window is resized

		height = HIWORD(lParam);//get height from message

		width  = LOWORD(lParam);//get width from message

			
		if(height == 0)//avoid devide by 0

			height = 1;

		//reset the viewport to new dimentions

		glViewport(0,0,width,height);
		glMatrixMode(GL_PROJECTION);//set projection matrix

		glLoadIdentity();//reset projection matrix


		//calculate aspect ratio of window

		gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,1.0f,1000.0f);

		glMatrixMode(GL_MODELVIEW);//set modelvie matrix

		glLoadIdentity();//load identity Matrix[1,0,0]

											// [0,1,0]

											// [0,0,1]

		return 0;
		break;//break out to switch statement


	default:
		break;
	}

	return (DefWindowProc(hwnd,message,wParam,lParam));//send all unhandled message to windows

}


void RenderScene()
{
	//every.1 = 1 foot

	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);//clear buffer

	glLoadIdentity();//reset model view matrix


		g_Camera.Look();
		glBindTexture(GL_TEXTURE_2D,g_Texture[0]);	

	glPushMatrix();
	glTranslatef(-20.0f,0.0f,0.0f);
		glBegin(GL_QUADS);
		//***TRACK WALLS***//

				//LEFT WALL

		glTexCoord2d(0.0,0.0);glVertex3f(-0.25f,-1.0f,0.0f);//bottom left

		glTexCoord2d(2.5,0.0);glVertex3f(-0.25f,1.0f,0.0f);
		glTexCoord2d(2.5,1.0);glVertex3f(0.25f,1.0f,0.0f);	
		glTexCoord2d(0.0,1.0);glVertex3f(0.25f,-1.0f,0.0f);

			glTexCoord2d(0.0,0.0);glVertex3f(0.25f,-1.0f,0.0f);//bottomleft

			glTexCoord2d(0.0,1.5);glVertex3f(0.25f,1.0f,0.0f);
			glTexCoord2d(200.0,1.5);glVertex3f(0.25f,1.0f,-500.0f);
		    glTexCoord2d(200,0.0);glVertex3f(0.25f,-1.0f,-500.0f);

			glVertex3f(0.25f,-1.0f,-500.0f);
			glVertex3f(0.25f,1.0f,-500.0f);
			glVertex3f(-0.25f,1.0f,-500.0f);	
			glVertex3f(-0.25f,-1.0f,-500.0f);

			glTexCoord2d(0.0,0.0);glVertex3f(-0.25f,-1.0f,-500.0f);
			glTexCoord2d(0.0,1.5);glVertex3f(-0.25f,1.0f,-500.0f);
			glTexCoord2d(200.0,1.5);glVertex3f(-0.25f,1.0f,0.0f);
			glTexCoord2d(200,0.0);glVertex3f(-0.25f,-1.0f,0.0f);
		//***TRACK WALLS END***/

		glEnd();

	glTranslatef(40.0f,0.0f,0.0f);

		glBegin(GL_QUADS);
		//***TRACK WALLS***//

				//LEFT WALL

			glTexCoord2d(0.0,0.0);glVertex3f(-0.25f,-1.0f,0.0f);//bottom left

			glTexCoord2d(2.5,0.0);glVertex3f(-0.25f,1.0f,0.0f);
			glTexCoord2d(2.5,1.0);glVertex3f(0.25f,1.0f,0.0f);	
			glTexCoord2d(0.0,1.0);glVertex3f(0.25f,-1.0f,0.0f);

			glTexCoord2d(0.0,0.0);glVertex3f(0.25f,-1.0f,0.0f);//bottomleft

			glTexCoord2d(0.0,1.5);glVertex3f(0.25f,1.0f,0.0f);
			glTexCoord2d(200.0,1.5);glVertex3f(0.25f,1.0f,-500.0f);
		    glTexCoord2d(200,0.0);glVertex3f(0.25f,-1.0f,-500.0f);

			glVertex3f(0.25f,-1.0f,-500.0f);
			glVertex3f(0.25f,1.0f,-500.0f);
			glVertex3f(-0.25f,1.0f,-500.0f);	
			glVertex3f(-0.25f,-1.0f,-500.0f);

			glTexCoord2d(0.0,0.0);glVertex3f(-0.25f,-1.0f,-500.0f);
			glTexCoord2d(0.0,1.5);glVertex3f(-0.25f,1.0f,-500.0f);
			glTexCoord2d(200.0,1.5);glVertex3f(-0.25f,1.0f,0.0f);
			glTexCoord2d(200,0.0);glVertex3f(-0.25f,-1.0f,0.0f);
		//***TRACK WALLS END***/

		glEnd();


	glBindTexture(GL_TEXTURE_2D,g_Texture[1]);
		//**TRACK**//

		glBegin(GL_QUADS);
			glTexCoord2d(0.0,0.0);glVertex3f(-0.25f,-1.0f,0.0f);
			glTexCoord2d(0.0,200.0);glVertex3f(-0.25f,-1.0f,-500.0f);
			glTexCoord2d(30.0,200.0);glVertex3f(-39.75f,-1.0f,-500.0f);
			glTexCoord2d(30.0,0.0);glVertex3f(-39.75f,-1.0f,0.0f);
		glEnd();
	glPopMatrix();

	// I am going to attempt to explain what is going on below up here as not to clutter the 

	// code below.  We have a model that has a certain amount of objects and textures.  We want 

	// to go through each object in the model, bind it''s texture map to it, then render it.

	// To render the current object, we go through all of it''s faces (Polygons).  

	// What is a face you ask?  A face is just (in this case) a triangle of the object.

	// For instance, a cube has 12 faces because each side has 2 triangles.

	// You might be thinking.  Well, if there are 12 faces in a cube, that makes

	// 36 vertices that we needed to read in for that object.  Not really true.  Because

	// a lot of the vertices are the same, since they share sides, they only need to save

	// 8 vertices, and ignore the duplicates.  Then, you have an array of all the

	// unique vertices in that object.  No 2 vertices will be the same.  This cuts down

	// on memory.  Then, another array is saved, which is the index numbers for each face,

	// which index in to that array of vertices.  That might sound silly, but it is better

	// than saving tons of duplicate vertices.  The same thing happens for UV coordinates.

	// You don''t save duplicate UV coordinates, you just save the unique ones, then an array

	// that index''s into them.  This might be confusing, but most 3D files use this format.

	// This loop below will stay the same for most file formats that you load, so all you need

	// to change is the loading code.  You don''t need to change this loop (Except for animation).


	// Since we know how many objects our model has, go through each of them.

	for(int i = 0; i < g_3DModel.numOfObjects; i++)
	{
		// Make sure we have valid objects just in case. (size() is in the vector class)

		if(g_3DModel.pObject.size() <= 0) break;

		// Get the current object that we are displaying

		t3DObject *pObject = &g_3DModel.pObject[i];
			
		// Check to see if this object has a texture map, if so bind the texture to it.

		if(pObject->bHasTexture) {

			// Turn on texture mapping and turn off color

			glEnable(GL_TEXTURE_2D);

			// Reset the color to normal again

			glColor3ub(255, 255, 255);

			// Bind the texture map to the object by it''s materialID

			glBindTexture(GL_TEXTURE_2D, g_Texture[pObject->materialID]);
		} else {

			// Turn off texture mapping and turn on color

			glDisable(GL_TEXTURE_2D);

			// Reset the color to normal again

			glColor3ub(255, 255, 255);
		}

		// This determines if we are in wireframe or normal mode

		glBegin(GL_TRIANGLES);					// Begin drawing with our selected mode (triangles or lines)


			// Go through all of the faces (polygons) of the object and draw them

			for(int j = 0; j < pObject->numOfFaces; j++)
			{
				// Go through each corner of the triangle and draw it.

				for(int whichVertex = 0; whichVertex < 3; whichVertex++)
				{
					// Get the index for each point of the face

					int index = pObject->pFaces[j].vertIndex[whichVertex];
			
					// Give OpenGL the normal for this vertex.

					glNormal3f(pObject->pNormals[ index ].x, pObject->pNormals[ index ].y, pObject->pNormals[ index ].z);
				
					// If the object has a texture associated with it, give it a texture coordinate.

					if(pObject->bHasTexture) {

						// Make sure there was a UVW map applied to the object or else it won''t have tex coords.

						if(pObject->pTexVerts) {
							glTexCoord2f(pObject->pTexVerts[ index ].x, pObject->pTexVerts[ index ].y);
						}
					} else {

						// Make sure there is a valid material/color assigned to this object.

						// You should always at least assign a material color to an object, 

						// but just in case we want to check the size of the material list.

						// if the size is at least one, and the material ID != -1,

						// then we have a valid material.

						if(g_3DModel.pMaterials.size() && pObject->materialID >= 0) 
						{
							// Get and set the color that the object is, since it must not have a texture

							BYTE *pColor = g_3DModel.pMaterials[pObject->materialID].color;

							// Assign the current color to this model

							glColor3ub(pColor[0], pColor[1], pColor[2]);
						}
					}

					// Pass in the current vertex of the object (Corner of current face)

					glVertex3f(pObject->pVerts[ index ].x, pObject->pVerts[ index ].y, pObject->pVerts[ index ].z);
				}
			}

		glEnd();								// End the drawing

	}

}

//the main entry point

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nShowCmd)
{
	WNDCLASSEX ws;//window class

	MSG msg; //message

	bool done;  //flag saying when we are done


	//class structure

	ws.cbClsExtra = 0;//nothing extra

	ws.cbSize = sizeof(WNDCLASSEX);//always set to this

	ws.cbWndExtra = 0;//nothing extra

	ws.hbrBackground = NULL;//no need for a backgound

	ws.hCursor = LoadCursor(NULL, IDC_ARROW);//default cursor

	ws.hIcon = NULL;//no icon

	ws.hIconSm = NULL;//no tray icon

	ws.hInstance = hInstance;//instance of APP

	ws.lpfnWndProc = WndProc;//message handler for window

	ws.lpszClassName = "My Class";//class name

	ws.lpszMenuName = NULL;//no menu

	ws.style = CS_HREDRAW|CS_VREDRAW;//when resized redraw screen


	//register the class

	if(!RegisterClassEx(&ws))
	{
		MessageBox(NULL,"ERROR","Unable To Register Class!",MB_OK);
		return 0;//fails registering exit

	}

	//create window

	hwnd = CreateWindowEx(NULL,//extended style

		"My Class",//class name

		"Matt Janas",//app name

		WS_OVERLAPPEDWINDOW|WS_VISIBLE|WS_SYSMENU|
		WS_CLIPCHILDREN|
		WS_CLIPSIBLINGS,//style don''t draw unseen parts of windows

		100,100,//x,y

		800,600,//width height

		NULL,//handle to parent

		NULL,//handle to menu

		hInstance,//app instance

		NULL);//no extra params


	//check to see if window was created

	if(!hwnd)
	{
		MessageBox(NULL,"ERROR","Unable To Create Window!",MB_OK);
		return 0; //quit

	}

	ShowWindow(hwnd,SW_SHOW);//display window

	UpdateWindow(hwnd);//update window


	SetUpGL();//go to set up GL

	
			
	done = false;//flag to start main loop


	//main message loop

	while(!done)
	{
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))//check for messages

		{
			if(msg.message == WM_QUIT)//if there is a QUIT message

			done = true;//end APP


			TranslateMessage(&msg);
			DispatchMessage(&msg); 
		}								//translate and dispatch to event queue	

		else 
		{
			//rendering in here!

			g_Camera.SetViewByMouse();
			CheckForMovement(); //Check Keys

			RenderScene();//draw stuff


			
			SwapBuffers(hDC);//swap buffer Back to Front


		}
		
	}

	// When we are done, we need to free all the model data

	// We do this by walking through all the objects and freeing their information


	// Go through all the objects in the scene

	for(int i = 0; i < g_3DModel.numOfObjects; i++)
	{
		// Free the faces, normals, vertices, and texture coordinates.

		delete [] g_3DModel.pObject[i].pFaces;
		delete [] g_3DModel.pObject[i].pNormals;
		delete [] g_3DModel.pObject[i].pVerts;
		delete [] g_3DModel.pObject[i].pTexVerts;
	}
	
	KillOpenGL();

	return msg.wParam;
}

Camera.cpp
#include "Globals.hpp"

#define SCREEN_HEIGHT 600
#define SCREEN_WIDTH 800

CVector3 Cross(CVector3 vVector1, CVector3 vVector2)
{
	CVector3 vNormal;									// The vector to hold the cross product

	
	// The X value for the vector is:  (V1.y * V2.z) - (V1.z * V2.y)													// Get the X value

	vNormal.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
														
	// The Y value for the vector is:  (V1.z * V2.x) - (V1.x * V2.z)

	vNormal.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
														
	// The Z value for the vector is:  (V1.x * V2.y) - (V1.y * V2.x)

	vNormal.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));

	// Return the cross product

	return vNormal;										 
}


float Magnitude(CVector3 vNormal)
{
	return (float)sqrt( (vNormal.x * vNormal.x) + 
						(vNormal.y * vNormal.y) + 
						(vNormal.z * vNormal.z) );
}

CVector3 Normalize(CVector3 vVector)
{
	// Get the magnitude of our normal

	float magnitude = Magnitude(vVector);				

	vVector = vVector / magnitude;		
	
	// Finally, return our normalized vector

	return vVector;										
}

//Camera Class Definitions


//Constructor


CCamera::CCamera()
{
	CVector3 vZero = CVector3(0.0, 0.0, 0.0);		// Init a vVector to 0 0 0 for our position

	CVector3 vView = CVector3(0.0, 1.0, 0.5);		// Init a starting view vVector (looking up and out the screen) 

	CVector3 vUp   = CVector3(0.0, 0.0, 1.0);		// Init a standard up vVector (Rarely ever changes)


	m_vPosition	= vZero;					// Init the position to zero

	m_vView		= vView;					// Init the view to a std starting view

	m_vUpVector	= vUp;						// Init the UpVector

}
GLvoid CCamera::PositionCamera(float positionX,float positionY,float positionZ,
							   float viewX,float viewY,float viewZ,
							   float upVectorX,float upVectorY,float upVectorZ)
{
	CVector3 vPosition	= CVector3(positionX, positionY, positionZ);
	CVector3 vView		= CVector3(viewX, viewY, viewZ);
	CVector3 vUpVector	= CVector3(upVectorX, upVectorY, upVectorZ);

	m_vPosition = vPosition;					// Assign the position

	m_vView = vView;							// Assign the view

	m_vUpVector = vUpVector;					// Assign the up vector


}

void CCamera::MoveCamera(float speed)
{
	CVector3 vVector = CVector3(0.0f,0.0f,0.0f);

	//V = v - p (Get direction were facing!)

	vVector.x = m_vView.x - m_vPosition.x; //Get x direction

	vVector.y = m_vView.y - m_vPosition.y; //get y direction

	vVector.z = m_vView.z - m_vPosition.z;	//get z direction


	m_vPosition.x += vVector.x * speed;		// Add our acceleration to our position''s X

	m_vPosition.z += vVector.z * speed;		// Add our acceleration to our position''s Z

	m_vView.x += vVector.x * speed;			// Add our acceleration to our view''s X

	m_vView.z += vVector.z * speed;			// Add our acceleration to our view''s Z

}

void CCamera::RotateView(float angle,float x,float y,float z)
{
	CVector3 vNewView;
	CVector3 vView;

	//Get Direction we''re facing

	vView.x = m_vView.x - m_vPosition.x;		// This gets the direction of the X	

	vView.y = m_vView.y - m_vPosition.y;		// This gets the direction of the Y

	vView.z = m_vView.z - m_vPosition.z;		// This gets the direction of the Z

	
	float cosTheta = (float)cos(angle);
	float sinTheta = (float)sin(angle);
	
	// Find the new x position for the new rotated point

	vNewView.x  = (cosTheta + (1 - cosTheta) * x * x)		* vView.x;
	vNewView.x += ((1 - cosTheta) * x * y - z * sinTheta)	* vView.y;
	vNewView.x += ((1 - cosTheta) * x * z + y * sinTheta)	* vView.z;
	
	// Find the new y position for the new rotated point

	vNewView.y  = ((1 - cosTheta) * x * y + z * sinTheta)	* vView.x;
	vNewView.y += (cosTheta + (1 - cosTheta) * y * y)		* vView.y;
	vNewView.y += ((1 - cosTheta) * y * z - x * sinTheta)	* vView.z;

	// Find the new z position for the new rotated point

	vNewView.z  = ((1 - cosTheta) * x * z - y * sinTheta)	* vView.x;
	vNewView.z += ((1 - cosTheta) * y * z + x * sinTheta)	* vView.y;
	vNewView.z += (cosTheta + (1 - cosTheta) * z * z)		* vView.z;

	// Now we just add the newly rotated vector to our position to set

	// our new rotated view of our camera.

	m_vView.x = m_vPosition.x + vNewView.x;
	m_vView.y = m_vPosition.y + vNewView.y;
	m_vView.z = m_vPosition.z + vNewView.z;
}

void CCamera::SetViewByMouse()
{
	POINT mousePos;									// This is a window structure that holds an X and Y

	int middleX = SCREEN_WIDTH  >> 1;				// This is a binary shift to get half the width

	int middleY = SCREEN_HEIGHT >> 1;				// This is a binary shift to get half the height

	float angleY = 0.0f;							// This is the direction for looking up or down

	float angleZ = 0.0f;							// This will be the value we need to rotate around the Y axis (Left and Right)

	static float currentRotX = 0.0f;
	
	// Get the mouse''s current X,Y position

	GetCursorPos(&mousePos);						
	
	// If our cursor is still in the middle, we never moved... so don''t update the screen

	if( (mousePos.x == middleX) && (mousePos.y == middleY) ) return;

	// Set the mouse position to the middle of our window

	SetCursorPos(middleX, middleY);							

	// Get the direction the mouse moved in, but bring the number down to a reasonable amount

	angleY = (float)( (middleX - mousePos.x) ) / 1000.0f;		
	angleZ = (float)( (middleY - mousePos.y) ) / 1000.0f;
	
	static float lastRotX = 0.0f; 
 	lastRotX = currentRotX; // We store off the currentRotX and will use it in when the angle is capped

	currentRotX += angleZ;
 
	// If the current rotation (in radians) is greater than 1.0, we want to cap it.

	if(currentRotX > 1.0f)     
	{
		currentRotX = 1.0f;
		
		// Rotate by remaining angle if there is any

		if(lastRotX != 1.0f) 
		{
	
			CVector3 vAxis = Cross(m_vView - m_vPosition, m_vUpVector);
			vAxis = Normalize(vAxis);
				
			// rotate the camera by the remaining angle (1.0f - lastRotX)

			RotateView( 1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z);
		}
	}
	// Check if the rotation is below -1.0, if so we want to make sure it doesn''t continue

	else if(currentRotX < -1.0f)
	{
		currentRotX = -1.0f;
		
		// Rotate by the remaining angle if there is any

		if(lastRotX != -1.0f)
		{
			CVector3 vAxis = Cross(m_vView - m_vPosition, m_vUpVector);
			vAxis = Normalize(vAxis);
			
			RotateView( -1.0f - lastRotX, vAxis.x, vAxis.y, vAxis.z);
		}
	}
	// Otherwise, we can rotate the view around our position

	else 
	{	
	
		CVector3 vAxis = Cross(m_vView - m_vPosition, m_vUpVector);
		vAxis = Normalize(vAxis);
	
		// Rotate around our perpendicular axis

		RotateView(angleZ, vAxis.x, vAxis.y, vAxis.z);
	}

	// Always rotate the camera around the y-axis

	RotateView(angleY, 0, 1, 0);
}

void CCamera::Look()
{
	gluLookAt(g_Camera.m_vPosition.x, (g_Camera.m_vPosition.y+4.0f), g_Camera.m_vPosition.z,	
			  g_Camera.m_vView.x,	  g_Camera.m_vView.y+4.0f,	  g_Camera.m_vView.z,	
			  g_Camera.m_vUpVector.x, g_Camera.m_vUpVector.y, g_Camera.m_vUpVector.z);
}
3ds.cpp

#include "Globals.hpp"
#include "3ds.h"
#include <assert.h>

// Global

int gBuffer[50000] = {0};					// This is used to read past unwanted data


// This file handles all of the code needed to load a .3DS file.

// Basically, how it works is, you load a chunk, then you check

// the chunk ID.  Depending on the chunk ID, you load the information

// that is stored in that chunk.  If you do not want to read that information,

// you read past it.  You know how many bytes to read past the chunk because

// every chunk stores the length in bytes of that chunk.


///////////////////////////////// CLOAD3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This constructor initializes the tChunk data

/////

///////////////////////////////// CLOAD3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


CLoad3DS::CLoad3DS()
{
	m_FilePointer = NULL;
}

///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This is called by the client to open the .3ds file, read it, then clean up

/////

///////////////////////////////// IMPORT 3DS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


bool CLoad3DS::Import3DS(t3DModel *pModel, char *strFileName)
{
	char strMessage[255] = {0};
	tChunk currentChunk = {0};

	// Open the 3DS file

	m_FilePointer = fopen(strFileName, "rb");

	// Make sure we have a valid file pointer (we found the file)

	if(!m_FilePointer) 
	{
		sprintf(strMessage, "Unable to find the file: %s!", strFileName);
		MessageBox(NULL, strMessage, "Error", MB_OK);
		return false;
	}

	// Once we have the file open, we need to read the very first data chunk

	// to see if it''s a 3DS file.  That way we don''t read an invalid file.

	// If it is a 3DS file, then the first chunk ID will be equal to PRIMARY (some hex num)


	// Read the first chuck of the file to see if it''s a 3DS file

	ReadChunk(&currentChunk);

	// Make sure this is a 3DS file

	if (currentChunk.ID != PRIMARY)
	{
		sprintf(strMessage, "Unable to load PRIMARY chuck from file: %s!", strFileName);
		MessageBox(NULL, strMessage, "Error", MB_OK);
		return false;
	}

	// Now we actually start reading in the data.  ProcessNextChunk() is recursive


	// Begin loading objects, by calling this recursive function

	ProcessNextChunk(pModel, &currentChunk);

	// After we have read the whole 3DS file, we want to calculate our own vertex normals.

	ComputeNormals(pModel);

	// Clean up after everything

	CleanUp();

	return true;
}

///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function cleans up our allocated memory and closes the file

/////

///////////////////////////////// CLEAN UP \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::CleanUp()
{
	if (m_FilePointer) {
		fclose(m_FilePointer);					// Close the current file pointer

		m_FilePointer = NULL;
	}
}


///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads the main sections of the .3DS file, then dives deeper with recursion

/////

///////////////////////////////// PROCESS NEXT CHUNK\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ProcessNextChunk(t3DModel *pModel, tChunk *pPreviousChunk)
{
	t3DObject newObject = {0};					// This is used to add to our object list

	tMaterialInfo newTexture = {0};				// This is used to add to our material list


	tChunk currentChunk = {0};					// The current chunk to load

	tChunk tempChunk = {0};						// A temp chunk for holding data		


	// Below we check our chunk ID each time we read a new chunk.  Then, if

	// we want to extract the information from that chunk, we do so.

	// If we don''t want a chunk, we just read past it.  


	// Continue to read the sub chunks until we have reached the length.

	// After we read ANYTHING we add the bytes read to the chunk and then check

	// check against the length.

	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
	{
		// Read next Chunk

		ReadChunk(&currentChunk);

		// Check the chunk ID

		switch (currentChunk.ID)
		{
		case VERSION:							// This holds the version of the file

			
			// If the file was made in 3D Studio Max, this chunk has an int that 

			// holds the file version.  Since there might be new additions to the 3DS file

			// format in 4.0, we give a warning to that problem.

			// However, if the file wasn''t made by 3D Studio Max, we don''t 100% what the

			// version length will be so we''ll simply ignore the value


			// Read the file version and add the bytes read to our bytesRead variable

			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);

			// If the file version is over 3, give a warning that there could be a problem

			if ((currentChunk.length - currentChunk.bytesRead == 4) && (gBuffer[0] > 0x03)) {
				MessageBox(NULL, "This 3DS file is over version 3 so it may load incorrectly", "Warning", MB_OK);
			}
			break;

		case OBJECTINFO:						// This holds the version of the mesh

			{	
			// This chunk holds the version of the mesh.  It is also the head of the MATERIAL

			// and OBJECT chunks.  From here on we start reading in the material and object info.


			// Read the next chunk

			ReadChunk(&tempChunk);

			// Get the version of the mesh

			tempChunk.bytesRead += fread(gBuffer, 1, tempChunk.length - tempChunk.bytesRead, m_FilePointer);

			// Increase the bytesRead by the bytes read from the last chunk

			currentChunk.bytesRead += tempChunk.bytesRead;

			// Go to the next chunk, which is the object has a texture, it should be MATERIAL, then OBJECT.

			ProcessNextChunk(pModel, &currentChunk);
			break;
		}
		case MATERIAL:							// This holds the material information


			// This chunk is the header for the material info chunks


			// Increase the number of materials

			pModel->numOfMaterials++;

			// Add a empty texture structure to our texture list.

			// If you are unfamiliar with STL''s "vector" class, all push_back()

			// does is add a new node onto the list.  I used the vector class

			// so I didn''t need to write my own link list functions.  

			pModel->pMaterials.push_back(newTexture);

			// Proceed to the material loading function

			ProcessNextMaterialChunk(pModel, &currentChunk);
			break;

		case OBJECT:							// This holds the name of the object being read

				
			// This chunk is the header for the object info chunks.  It also

			// holds the name of the object.


			// Increase the object count

			pModel->numOfObjects++;
		
			// Add a new tObject node to our list of objects (like a link list)

			pModel->pObject.push_back(newObject);
			
			// Initialize the object and all it''s data members

			memset(&(pModel->pObject[pModel->numOfObjects - 1]), 0, sizeof(t3DObject));

			// Get the name of the object and store it, then add the read bytes to our byte counter.

			currentChunk.bytesRead += GetString(pModel->pObject[pModel->numOfObjects - 1].strName);
			
			// Now proceed to read in the rest of the object information

			ProcessNextObjectChunk(pModel, &(pModel->pObject[pModel->numOfObjects - 1]), &currentChunk);
			break;

		case EDITKEYFRAME:

			// Because I wanted to make this a SIMPLE tutorial as possible, I did not include

			// the key frame information.  This chunk is the header for all the animation info.

			// In a later tutorial this will be the subject and explained thoroughly.


			//ProcessNextKeyFrameChunk(pModel, currentChunk);


			// Read past this chunk and add the bytes read to the byte counter

			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
			break;

		default: 
			
			// If we didn''t care about a chunk, then we get here.  We still need

			// to read past the unknown or ignored chunk and add the bytes read to the byte counter.

			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
			break;
		}

		// Add the bytes read from the last chunk to the previous chunk passed in.

		pPreviousChunk->bytesRead += currentChunk.bytesRead;
	}
}


///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function handles all the information about the objects in the file

/////

///////////////////////////////// PROCESS NEXT OBJECT CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
	// The current chunk to work with

	tChunk currentChunk = {0};

	// Continue to read these chunks until we read the end of this sub chunk

	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
	{
		// Read the next chunk

		ReadChunk(&currentChunk);

		// Check which chunk we just read

		switch (currentChunk.ID)
		{
		case OBJECT_MESH:					// This lets us know that we are reading a new object

		
			// We found a new object, so let''s read in it''s info using recursion

			ProcessNextObjectChunk(pModel, pObject, &currentChunk);
			break;

		case OBJECT_VERTICES:				// This is the objects vertices

			ReadVertices(pObject, &currentChunk);
			break;

		case OBJECT_FACES:					// This is the objects face information

			ReadVertexIndices(pObject, &currentChunk);
			break;

		case OBJECT_MATERIAL:				// This holds the material name that the object has

			
			// This chunk holds the name of the material that the object has assigned to it.

			// This could either be just a color or a texture map.  This chunk also holds

			// the faces that the texture is assigned to (In the case that there is multiple

			// textures assigned to one object, or it just has a texture on a part of the object.

			// Since most of my game objects just have the texture around the whole object, and 

			// they aren''t multitextured, I just want the material name.


			// We now will read the name of the material assigned to this object

			ReadObjectMaterial(pModel, pObject, &currentChunk);			
			break;

		case OBJECT_UV:						// This holds the UV texture coordinates for the object


			// This chunk holds all of the UV coordinates for our object.  Let''s read them in.

			ReadUVCoordinates(pObject, &currentChunk);
			break;

		default:  

			// Read past the ignored or unknown chunks

			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
			break;
		}

		// Add the bytes read from the last chunk to the previous chunk passed in.

		pPreviousChunk->bytesRead += currentChunk.bytesRead;
	}
}


///////////////////////////////// PROCESS NEXT MATERIAL CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function handles all the information about the material (Texture)

/////

///////////////////////////////// PROCESS NEXT MATERIAL CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ProcessNextMaterialChunk(t3DModel *pModel, tChunk *pPreviousChunk)
{
	// The current chunk to work with

	tChunk currentChunk = {0};

	// Continue to read these chunks until we read the end of this sub chunk

	while (pPreviousChunk->bytesRead < pPreviousChunk->length)
	{
		// Read the next chunk

		ReadChunk(&currentChunk);

		// Check which chunk we just read in

		switch (currentChunk.ID)
		{
		case MATNAME:							// This chunk holds the name of the material

			
			// Here we read in the material name

			currentChunk.bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strName, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
			break;

		case MATDIFFUSE:						// This holds the R G B color of our object

			ReadColorChunk(&(pModel->pMaterials[pModel->numOfMaterials - 1]), &currentChunk);
			break;
		
		case MATMAP:							// This is the header for the texture info

			
			// Proceed to read in the material information

			ProcessNextMaterialChunk(pModel, &currentChunk);
			break;

		case MATMAPFILE:						// This stores the file name of the material


			// Here we read in the material''s file name

			currentChunk.bytesRead += fread(pModel->pMaterials[pModel->numOfMaterials - 1].strFile, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
			break;
		
		default:  

			// Read past the ignored or unknown chunks

			currentChunk.bytesRead += fread(gBuffer, 1, currentChunk.length - currentChunk.bytesRead, m_FilePointer);
			break;
		}

		// Add the bytes read from the last chunk to the previous chunk passed in.

		pPreviousChunk->bytesRead += currentChunk.bytesRead;
	}
}

///////////////////////////////// READ CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in a chunk ID and it''s length in bytes

/////

///////////////////////////////// READ CHUNK \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ReadChunk(tChunk *pChunk)
{
	// This reads the chunk ID which is 2 bytes.

	// The chunk ID is like OBJECT or MATERIAL.  It tells what data is

	// able to be read in within the chunks section.  

	pChunk->bytesRead = fread(&pChunk->ID, 1, 2, m_FilePointer);

	// Then, we read the length of the chunk which is 4 bytes.

	// This is how we know how much to read in, or read past.

	pChunk->bytesRead += fread(&pChunk->length, 1, 4, m_FilePointer);
}

///////////////////////////////// GET STRING \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in a string of characters

/////

///////////////////////////////// GET STRING \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


int CLoad3DS::GetString(char *pBuffer)
{
	int index = 0;

	// Read 1 byte of data which is the first letter of the string

	fread(pBuffer, 1, 1, m_FilePointer);

	// Loop until we get NULL

	while (*(pBuffer + index++) != 0) {

		// Read in a character at a time until we hit NULL.

		fread(pBuffer + index, 1, 1, m_FilePointer);
	}

	// Return the string length, which is how many bytes we read in (including the NULL)

	return strlen(pBuffer) + 1;
}


///////////////////////////////// READ COLOR \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in the RGB color data

/////

///////////////////////////////// READ COLOR \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk)
{
	tChunk tempChunk = {0};

	// Read the color chunk info

	ReadChunk(&tempChunk);

	// Read in the R G B color (3 bytes - 0 through 255)

	tempChunk.bytesRead += fread(pMaterial->color, 1, tempChunk.length - tempChunk.bytesRead, m_FilePointer);

	// Add the bytes read to our chunk

	pChunk->bytesRead += tempChunk.bytesRead;
}


///////////////////////////////// READ VERTEX INDECES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in the indices for the vertex array

/////

///////////////////////////////// READ VERTEX INDECES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ReadVertexIndices(t3DObject *pObject, tChunk *pPreviousChunk)
{
	unsigned short index = 0;					// This is used to read in the current face index


	// In order to read in the vertex indices for the object, we need to first

	// read in the number of them, then read them in.  Remember,

	// we only want 3 of the 4 values read in for each face.  The fourth is

	// a visibility flag for 3D Studio Max that doesn''t mean anything to us.


	// Read in the number of faces that are in this object (int)

	pPreviousChunk->bytesRead += fread(&pObject->numOfFaces, 1, 2, m_FilePointer);

	// Alloc enough memory for the faces and initialize the structure

	pObject->pFaces = new tFace [pObject->numOfFaces];
	memset(pObject->pFaces, 0, sizeof(tFace) * pObject->numOfFaces);

	// Go through all of the faces in this object

	for(int i = 0; i < pObject->numOfFaces; i++)
	{
		// Next, we read in the A then B then C index for the face, but ignore the 4th value.

		// The fourth value is a visibility flag for 3D Studio Max, we don''t care about this.

		for(int j = 0; j < 4; j++)
		{
			// Read the first vertice index for the current face 

			pPreviousChunk->bytesRead += fread(&index, 1, sizeof(index), m_FilePointer);

			if(j < 3)
			{
				// Store the index in our face structure.

				pObject->pFaces[i].vertIndex[j] = index;
			}
		}
	}
}


///////////////////////////////// READ UV COORDINATES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in the UV coordinates for the object

/////

///////////////////////////////// READ UV COORDINATES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ReadUVCoordinates(t3DObject *pObject, tChunk *pPreviousChunk)
{
	// In order to read in the UV indices for the object, we need to first

	// read in the amount there are, then read them in.


	// Read in the number of UV coordinates there are (int)

	pPreviousChunk->bytesRead += fread(&pObject->numTexVertex, 1, 2, m_FilePointer);

	// Allocate memory to hold the UV coordinates

	pObject->pTexVerts = new CVector2 [pObject->numTexVertex];

	// Read in the texture coodinates (an array 2 float)

	pPreviousChunk->bytesRead += fread(pObject->pTexVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}


///////////////////////////////// READ VERTICES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in the vertices for the object

/////

///////////////////////////////// READ VERTICES \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ReadVertices(t3DObject *pObject, tChunk *pPreviousChunk)
{
	// Like most chunks, before we read in the actual vertices, we need

	// to find out how many there are to read in.  Once we have that number

	// we then fread() them into our vertice array.


	// Read in the number of vertices (int)

	pPreviousChunk->bytesRead += fread(&(pObject->numOfVerts), 1, 2, m_FilePointer);

	// Allocate the memory for the verts and initialize the structure

	pObject->pVerts = new CVector3 [pObject->numOfVerts];
	memset(pObject->pVerts, 0, sizeof(CVector3) * pObject->numOfVerts);

	// Read in the array of vertices (an array of 3 floats)

	pPreviousChunk->bytesRead += fread(pObject->pVerts, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);

	// Now we should have all of the vertices read in.  Because 3D Studio Max

	// Models with the Z-Axis pointing up (strange and ugly I know!), we need

	// to flip the y values with the z values in our vertices.  That way it

	// will be normal, with Y pointing up.  If you prefer to work with Z pointing

	// up, then just delete this next loop.  Also, because we swap the Y and Z

	// we need to negate the Z to make it come out correctly.


	// Go through all of the vertices that we just read and swap the Y and Z values

	for(int i = 0; i < pObject->numOfVerts; i++)
	{
		// Store off the Y value

		float fTempY = pObject->pVerts[i].y;

		// Set the Y value to the Z value

		pObject->pVerts[i].y = pObject->pVerts[i].z;

		// Set the Z value to the Y value, 

		// but negative Z because 3D Studio max does the opposite.

		pObject->pVerts[i].z = -fTempY;
	}
}


///////////////////////////////// READ OBJECT MATERIAL \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function reads in the material name assigned to the object and sets the materialID

/////

///////////////////////////////// READ OBJECT MATERIAL \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk)
{
	char strMaterial[255] = {0};			// This is used to hold the objects material name


	// *What is a material?*  - A material is either the color or the texture map of the object.

	// It can also hold other information like the brightness, shine, etc... Stuff we don''t

	// really care about.  We just want the color, or the texture map file name really.


	// Here we read the material name that is assigned to the current object.

	// strMaterial should now have a string of the material name, like "Material #2" etc..

	pPreviousChunk->bytesRead += GetString(strMaterial);

	// Now that we have a material name, we need to go through all of the materials

	// and check the name against each material.  When we find a material in our material

	// list that matches this name we just read in, then we assign the materialID

	// of the object to that material index.  You will notice that we passed in the

	// model to this function.  This is because we need the number of textures.

	// Yes though, we could have just passed in the model and not the object too.


	// Go through all of the textures

	for(int i = 0; i < pModel->numOfMaterials; i++)
	{
		// If the material we just read in matches the current texture name

		if(strcmp(strMaterial, pModel->pMaterials[i].strName) == 0)
		{
			// Set the material ID to the current index ''i'' and stop checking

			pObject->materialID = i;

			// Now that we found the material, check if it''s a texture map.

			// If the strFile has a string length of 1 and over it''s a texture

			if(strlen(pModel->pMaterials[i].strFile) > 0) {

				// Set the object''s flag to say it has a texture map to bind.

				pObject->bHasTexture = true;
			}	
			break;
		}
		else
		{
			// Set the ID to -1 to show there is no material for this object

			pObject->materialID = -1;
		}
	}

	// Read past the rest of the chunk since we don''t care about shared vertices

	// You will notice we subtract the bytes already read in this chunk from the total length.

	pPreviousChunk->bytesRead += fread(gBuffer, 1, pPreviousChunk->length - pPreviousChunk->bytesRead, m_FilePointer);
}			

// *Note* 

//

// Below are some math functions for calculating vertex normals.  We want vertex normals

// because it makes the lighting look really smooth and life like.  You probably already

// have these functions in the rest of your engine, so you can delete these and call

// your own.  I wanted to add them so I could show how to calculate vertex normals.


//////////////////////////////	Math Functions  ////////////////////////////////*


// This computes the magnitude of a normal.   (magnitude = sqrt(x^2 + y^2 + z^2)

#define Mag(Normal) (sqrt(Normal.x*Normal.x + Normal.y*Normal.y + Normal.z*Normal.z))

// This calculates a vector between 2 points and returns the result

CVector3 Vector(CVector3 vPoint1, CVector3 vPoint2)
{
	CVector3 vVector;							// The variable to hold the resultant vector


	vVector.x = vPoint1.x - vPoint2.x;			// Subtract point1 and point2 x''s

	vVector.y = vPoint1.y - vPoint2.y;			// Subtract point1 and point2 y''s

	vVector.z = vPoint1.z - vPoint2.z;			// Subtract point1 and point2 z''s


	return vVector;								// Return the resultant vector

}

// This adds 2 vectors together and returns the result

CVector3 AddVector(CVector3 vVector1, CVector3 vVector2)
{
	CVector3 vResult;							// The variable to hold the resultant vector

	
	vResult.x = vVector2.x + vVector1.x;		// Add Vector1 and Vector2 x''s

	vResult.y = vVector2.y + vVector1.y;		// Add Vector1 and Vector2 y''s

	vResult.z = vVector2.z + vVector1.z;		// Add Vector1 and Vector2 z''s


	return vResult;								// Return the resultant vector

}

// This divides a vector by a single number (scalar) and returns the result

CVector3 DivideVectorByScaler(CVector3 vVector1, float Scaler)
{
	CVector3 vResult;							// The variable to hold the resultant vector

	
	vResult.x = vVector1.x / Scaler;			// Divide Vector1''s x value by the scaler

	vResult.y = vVector1.y / Scaler;			// Divide Vector1''s y value by the scaler

	vResult.z = vVector1.z / Scaler;			// Divide Vector1''s z value by the scaler


	return vResult;								// Return the resultant vector

}

// This returns the cross product between 2 vectors

CVector3 Cross(CVector3 vVector1, CVector3 vVector2)
{
	CVector3 vCross;								// The vector to hold the cross product

												// Get the X value

	vCross.x = ((vVector1.y * vVector2.z) - (vVector1.z * vVector2.y));
												// Get the Y value

	vCross.y = ((vVector1.z * vVector2.x) - (vVector1.x * vVector2.z));
												// Get the Z value

	vCross.z = ((vVector1.x * vVector2.y) - (vVector1.y * vVector2.x));

	return vCross;								// Return the cross product

}

// This returns the normal of a vector

CVector3 Normalize(CVector3 vNormal)
{
	double Magnitude;							// This holds the magitude			


	Magnitude = Mag(vNormal);					// Get the magnitude


	vNormal.x /= (float)Magnitude;				// Divide the vector''s X by the magnitude

	vNormal.y /= (float)Magnitude;				// Divide the vector''s Y by the magnitude

	vNormal.z /= (float)Magnitude;				// Divide the vector''s Z by the magnitude


	return vNormal;								// Return the normal

}

///////////////////////////////// COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*

/////

/////	This function computes the normals and vertex normals of the objects

/////

///////////////////////////////// COMPUTER NORMALS \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*


void CLoad3DS::ComputeNormals(t3DModel *pModel)
{
	CVector3 vVector1, vVector2, vNormal, vPoly[3];

	// If there are no objects, we can skip this part

	if(pModel->numOfObjects <= 0)
		return;

	// What are vertex normals?  And how are they different from other normals?

	// Well, if you find the normal to a triangle, you are finding a "Face Normal".

	// If you give OpenGL a face normal for lighting, it will make your object look

	// really flat and not very round.  If we find the normal for each vertex, it makes

	// the smooth lighting look.  This also covers up blocky looking objects and they appear

	// to have more polygons than they do.    Basically, what you do is first

	// calculate the face normals, then you take the average of all the normals around each

	// vertex.  It''s just averaging.  That way you get a better approximation for that vertex.


	// Go through each of the objects to calculate their normals

	for(int index = 0; index < pModel->numOfObjects; index++)
	{
		// Get the current object

		t3DObject *pObject = &(pModel->pObject[index]);

		// Here we allocate all the memory we need to calculate the normals

		CVector3 *pNormals		= new CVector3 [pObject->numOfFaces];
		CVector3 *pTempNormals	= new CVector3 [pObject->numOfFaces];
		pObject->pNormals		= new CVector3 [pObject->numOfVerts];

		// Go though all of the faces of this object

		for(int i=0; i < pObject->numOfFaces; i++)
		{												
			// To cut down LARGE code, we extract the 3 points of this face

			vPoly[0] = pObject->pVerts[pObject->pFaces[i].vertIndex[0]];
			vPoly[1] = pObject->pVerts[pObject->pFaces[i].vertIndex[1]];
			vPoly[2] = pObject->pVerts[pObject->pFaces[i].vertIndex[2]];

			// Now let''s calculate the face normals (Get 2 vectors and find the cross product of those 2)


			vVector1 = Vector(vPoly[0], vPoly[2]);		// Get the vector of the polygon (we just need 2 sides for the normal)

			vVector2 = Vector(vPoly[2], vPoly[1]);		// Get a second vector of the polygon


			vNormal  = Cross(vVector1, vVector2);		// Return the cross product of the 2 vectors (normalize vector, but not a unit vector)

			pTempNormals[i] = vNormal;					// Save the un-normalized normal for the vertex normals

			vNormal  = Normalize(vNormal);				// Normalize the cross product to give us the polygons normal


			pNormals[i] = vNormal;						// Assign the normal to the list of normals

		}

		//////////////// Now Get The Vertex Normals /////////////////


		CVector3 vSum = {0.0, 0.0, 0.0};
		CVector3 vZero = vSum;
		int shared=0;

		for (i = 0; i < pObject->numOfVerts; i++)			// Go through all of the vertices

		{
			for (int j = 0; j < pObject->numOfFaces; j++)	// Go through all of the triangles

			{												// Check if the vertex is shared by another face

				if (pObject->pFaces[j].vertIndex[0] == i || 
					pObject->pFaces[j].vertIndex[1] == i || 
					pObject->pFaces[j].vertIndex[2] == i)
				{
					vSum = AddVector(vSum, pTempNormals[j]);// Add the un-normalized normal of the shared face

					shared++;								// Increase the number of shared triangles

				}
			}      
			
			// Get the normal by dividing the sum by the shared.  We negate the shared so it has the normals pointing out.

			pObject->pNormals[i] = DivideVectorByScaler(vSum, float(-shared));

			// Normalize the normal for the final vertex normal

			pObject->pNormals[i] = Normalize(pObject->pNormals[i]);	

			vSum = vZero;									// Reset the sum

			shared = 0;										// Reset the shared

		}
	
		// Free our memory and start over on the next object

		delete [] pTempNormals;
		delete [] pNormals;
	}
}


#ifndef _3DS_H
#define _3DS_H

//>------ Primary Chunk, at the beginning of each file

#define PRIMARY       0x4D4D

//>------ Main Chunks

#define OBJECTINFO    0x3D3D				// This gives the version of the mesh and is found right before the material and object information

#define VERSION       0x0002				// This gives the version of the .3ds file

#define EDITKEYFRAME  0xB000				// This is the header for all of the key frame info


//>------ sub defines of OBJECTINFO

#define MATERIAL	  0xAFFF				// This stored the texture info

#define OBJECT		  0x4000				// This stores the faces, vertices, etc...


//>------ sub defines of MATERIAL

#define MATNAME       0xA000				// This holds the material name

#define MATDIFFUSE    0xA020				// This holds the color of the object/material

#define MATMAP        0xA200				// This is a header for a new material

#define MATMAPFILE    0xA300				// This holds the file name of the texture


#define OBJECT_MESH   0x4100				// This lets us know that we are reading a new object


//>------ sub defines of OBJECT_MESH

#define OBJECT_VERTICES     0x4110			// The objects vertices

#define OBJECT_FACES		0x4120			// The objects faces

#define OBJECT_MATERIAL		0x4130			// This is found if the object has a material, either texture map or color

#define OBJECT_UV			0x4140			// The UV texture coordinates



// Here is our structure for our 3DS indicies (since .3DS stores 4 unsigned shorts)

struct tIndices {							

	unsigned short a, b, c, bVisible;		// This will hold point1, 2, and 3 index''s into the vertex array plus a visible flag

};

// This holds the chunk info

struct tChunk
{
	unsigned short int ID;					// The chunk''s ID		

	unsigned int length;					// The length of the chunk

	unsigned int bytesRead;					// The amount of bytes read within that chunk

};

// This class handles all of the loading code

class CLoad3DS
{
public:
	CLoad3DS();								// This inits the data members


	// This is the function that you call to load the 3DS

	bool Import3DS(t3DModel *pModel, char *strFileName);

private:
	// This reads in a string and saves it in the char array passed in

	int GetString(char *);

	// This reads the next chunk

	void ReadChunk(tChunk *);

	// This reads the next large chunk

	void ProcessNextChunk(t3DModel *pModel, tChunk *);

	// This reads the object chunks

	void ProcessNextObjectChunk(t3DModel *pModel, t3DObject *pObject, tChunk *);

	// This reads the material chunks

	void ProcessNextMaterialChunk(t3DModel *pModel, tChunk *);

	// This reads the RGB value for the object''s color

	void ReadColorChunk(tMaterialInfo *pMaterial, tChunk *pChunk);

	// This reads the objects vertices

	void ReadVertices(t3DObject *pObject, tChunk *);

	// This reads the objects face information

	void ReadVertexIndices(t3DObject *pObject, tChunk *);

	// This reads the texture coodinates of the object

	void ReadUVCoordinates(t3DObject *pObject, tChunk *);

	// This reads in the material name assigned to the object and sets the materialID

	void ReadObjectMaterial(t3DModel *pModel, t3DObject *pObject, tChunk *pPreviousChunk);
	
	// This computes the vertex normals for the object (used for lighting)

	void ComputeNormals(t3DModel *pModel);

	// This frees memory and closes the file

	void CleanUp();
	
	// The file pointer

	FILE *m_FilePointer;
};


#endif


Ut o not me again:) lol
Colin Jeanne
Colin Jeanne
You need to define your classes before you use them.


Thanks Salsa!Colin Jeanne | Invader''s Realm
"I forgot I had the Scroll Lock key until a few weeks ago when some asshole program used it. It even used it right" - Conner McCloud
Mat1515
Mat1515
i did the error os referencing to this


struct t3DObject {
int numOfVerts; // The number of verts in the model

int numOfFaces; // The number of faces in the model int numTexVertex; // The number of texture coordinates

int materialID; // The texture ID to use, which is the index into our texture array

bool bHasTexture; // This is TRUE if there is a texture map for this object

char strName[255]; // The name of the object

CVector3 *pVerts; // The object's vertices

CVector3 *pNormals; // The object's normals

CVector2 *pTexVerts; // The texture's UV coordinates

tFace *pFaces; // The faces information of the object

};


Could it be that im compiling with Visual C++ 6.0 when the code was written with Visual C++ 7.0. Maybe 6.0 is lacking something new in C++ standard?

[edited by - Mat1515 on March 2, 2004 5:49:13 PM]
Ut o not me again:) lol
Colin Jeanne
Colin Jeanne
No. You dont have the declarations of CVector2 and t3DObject until after that bit of code. C++ is a one-pass compilation system and so you must declare the objects you are using before you use them.


Thanks Salsa!Colin Jeanne | Invader''s Realm
"I forgot I had the Scroll Lock key until a few weeks ago when some asshole program used it. It even used it right" - Conner McCloud

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.