• Advertisement

Archived

This topic is now archived and is closed to further replies.

g_Load3ds.Import3DS(&g_3DModel, FILE_NAME);

This topic is 5753 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

i think that it is this line of code that is giving me an assertion failed message any ideas of how it could be fixed? here is ALL of the code
  
#include <Main.h>
#include <3ds.h>

HDC			hDC=NULL;		// Private GDI Device Context

HGLRC		hRC=NULL;		// Permanent Rendering Context

HWND		hWnd=NULL;		// Holds Our Window Handle

HINSTANCE	hInstance;		// Holds The Instance Of The Application


bool	keys[256];			// Array Used For The Keyboard Routine

bool	active=TRUE;		// Window Active Flag Set To TRUE By Default

bool	fullscreen=TRUE;	// Fullscreen Flag Set To Fullscreen Mode By Default


#define FILE_NAME  "face.3ds"							// This is the 3D file we will load.


UINT g_Texture[MAX_TEXTURES] = {0};						// This holds the texture info, referenced by an ID


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


int   g_ViewMode	  = GL_TRIANGLES;	

LRESULT	CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int LoadScene(GLvoid)
{
	g_Load3ds.Import3DS(&g_3DModel, FILE_NAME);			// 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].textureId = 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 colo

	
	return TRUE;
}

int DrawGLScene(GLvoid)									// Here''s Where We Do All The Drawing

{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer

	glLoadIdentity();

	LoadScene();

	gluLookAt(		0, 1.5f, 8,		0, 0.5f, 0,			0, 1, 0);

	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(g_ViewMode);					// 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

	}


	return TRUE;										// Everything Went OK

}

int WINAPI WinMain(	HINSTANCE	hInstance,			// Instance

					HINSTANCE	hPrevInstance,		// Previous Instance

					LPSTR		lpCmdLine,			// Command Line Parameters

					int			nCmdShow)			// Window Show State

{
	MSG		msg;									// Windows Message Structure

	BOOL	done=FALSE;								// Bool Variable To Exit Loop


	// 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)
	{
		fullscreen=FALSE;							// Windowed Mode

	}

	// Create Our OpenGL Window

	if (!CreateGLWindow("Raja''s 3ds game! i did it!",640,480,16,fullscreen))
	{
		return 0;									// Quit If Window Was Not Created

	}

	while(!done)									// Loop That Runs While done=FALSE

	{
		if (PeekMessage(&msg,NULL,0,0,PM_REMOVE))	// Is There A Message Waiting?

		{
			if (msg.message==WM_QUIT)				// Have We Received A Quit Message?

			{
				done=TRUE;
			}
			else									// If Not, Deal With Window Messages

			{
				TranslateMessage(&msg);				// Translate The Message

				DispatchMessage(&msg);				// Dispatch The Message

			}
		}
		else										// If There Are No Messages

		{
			// Draw The Scene.  Watch For ESC Key And Quit Messages From DrawGLScene()

			if (active)								// Program Active?

			{
				if (keys[VK_ESCAPE])				// Was ESC Pressed?

				{
					done=TRUE;
					
					for(int i = 0; i < g_3DModel.numOfObjects; i++)
					{
						delete [] g_3DModel.pObject[i].pFaces;
						delete [] g_3DModel.pObject[i].pNormals;
						delete [] g_3DModel.pObject[i].pVerts;
						delete [] g_3DModel.pObject[i].pTexVerts;
					}
				}
				else								// Not Time To Quit, Update Screen

				{
					DrawGLScene();					// Draw The Scene

					SwapBuffers(hDC);				// Swap Buffers (Double Buffering)

				}
			}

			if (keys[VK_F1])						// Is F1 Being Pressed?

			{
				keys[VK_F1]=FALSE;					// If So Make Key FALSE

				KillGLWindow();						// Kill Our Current Window

				fullscreen=!fullscreen;				// Toggle Fullscreen / Windowed Mode

				// Recreate Our OpenGL Window

				if (!CreateGLWindow("Raja''s 3ds game! i did it!",640,480,16,fullscreen))
				{
					return 0;						// Quit If Window Was Not Created

				}
			}
		}
	}

	// Shutdown

	KillGLWindow();									// Kill The Window

	return (msg.wParam);							// Exit The Program

}
[source/]

[source]
#include <Main.h>

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]);

	// This sets the alignment requirements for the start of each pixel row in memory.

	glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

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

	glBindTexture(GL_TEXTURE_2D, textureArray[textureID]);

	// Build Mipmaps (builds different versions of the picture for distances - looks better)

	gluBuild2DMipmaps(GL_TEXTURE_2D, 3, pBitmap->sizeX, pBitmap->sizeY, GL_RGB, GL_UNSIGNED_BYTE, pBitmap->data);

	// Lastly, we need to tell OpenGL the quality of our texture map.  GL_LINEAR is the smoothest.

	// GL_NEAREST is faster than GL_LINEAR, but looks blochy and pixelated.  Good for slower computers though.

	// Read more about the MIN and MAG filters at the bottom of main.cpp

		
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_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

	}
}

GLvoid ReSizeGLScene(GLsizei width, GLsizei height)		// Resize And Initialize The GL Window

{
	if (height==0)										// Prevent A Divide By Zero By

	{
		height=1;										// Making Height Equal One

	}

	glViewport(0,0,width,height);						// Reset The Current Viewport


	glMatrixMode(GL_PROJECTION);						// Select The Projection Matrix

	glLoadIdentity();									// Reset The Projection Matrix


	// Calculate The Aspect Ratio Of The Window

	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f);

	glMatrixMode(GL_MODELVIEW);							// Select The Modelview Matrix

	glLoadIdentity();									// Reset The Modelview Matrix

}

int InitGL(GLvoid)										// All Setup For OpenGL Goes Here

{
	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading

	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background

	glClearDepth(1.0f);									// Depth Buffer Setup

	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing

	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do

	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	return TRUE;										// Initialization Went OK

}

GLvoid KillGLWindow(GLvoid)								// Properly Kill The Window

{
	if (fullscreen)										// Are We In Fullscreen Mode?

	{
		ChangeDisplaySettings(NULL,0);					// If So Switch Back To The Desktop

		ShowCursor(TRUE);								// Show Mouse Pointer

	}

	if (hRC)											// Do We Have A Rendering Context?

	{
		if (!wglMakeCurrent(NULL,NULL))					// Are We Able To Release The DC And RC Contexts?

		{
			MessageBox(NULL,"Release Of DC And RC Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}

		if (!wglDeleteContext(hRC))						// Are We Able To Delete The RC?

		{
			MessageBox(NULL,"Release Rendering Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		}
		hRC=NULL;										// Set RC To NULL

	}

	if (hDC && !ReleaseDC(hWnd,hDC))					// Are We Able To Release The DC

	{
		MessageBox(NULL,"Release Device Context Failed.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hDC=NULL;										// Set DC To NULL

	}

	if (hWnd && !DestroyWindow(hWnd))					// Are We Able To Destroy The Window?

	{
		MessageBox(NULL,"Could Not Release hWnd.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hWnd=NULL;										// Set hWnd To NULL

	}

	if (!UnregisterClass("OpenGL",hInstance))			// Are We Able To Unregister Class

	{
		MessageBox(NULL,"Could Not Unregister Class.","SHUTDOWN ERROR",MB_OK | MB_ICONINFORMATION);
		hInstance=NULL;									// Set hInstance To NULL

	}
}

BOOL CreateGLWindow(char* title, int width, int height, int bits, bool fullscreenflag)
{
	GLuint		PixelFormat;			// Holds The Results After Searching For A Match

	WNDCLASS	wc;						// Windows Class Structure

	DWORD		dwExStyle;				// Window Extended Style

	DWORD		dwStyle;				// Window Style

	RECT		WindowRect;				// Grabs Rectangle Upper Left / Lower Right Values

	WindowRect.left=(long)0;			// Set Left Value To 0

	WindowRect.right=(long)width;		// Set Right Value To Requested Width

	WindowRect.top=(long)0;				// Set Top Value To 0

	WindowRect.bottom=(long)height;		// Set Bottom Value To Requested Height


	fullscreen=fullscreenflag;			// Set The Global Fullscreen Flag


	hInstance			= GetModuleHandle(NULL);				// Grab An Instance For Our Window

	wc.style			= CS_HREDRAW | CS_VREDRAW | CS_OWNDC;	// Redraw On Size, And Own DC For Window.

	wc.lpfnWndProc		= (WNDPROC) WndProc;					// WndProc Handles Messages

	wc.cbClsExtra		= 0;									// No Extra Window Data

	wc.cbWndExtra		= 0;									// No Extra Window Data

	wc.hInstance		= hInstance;							// Set The Instance

	wc.hIcon			= LoadIcon(NULL, IDI_WINLOGO);			// Load The Default Icon

	wc.hCursor			= LoadCursor(NULL, IDC_ARROW);			// Load The Arrow Pointer

	wc.hbrBackground	= NULL;									// No Background Required For GL

	wc.lpszMenuName		= NULL;									// We Don''t Want A Menu

	wc.lpszClassName	= "OpenGL";								// Set The Class Name


	if (!RegisterClass(&wc))									// Attempt To Register The Window Class

	{
		MessageBox(NULL,"Failed To Register The Window Class.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;											// Return FALSE

	}
	
	if (fullscreen)												// Attempt Fullscreen Mode?

	{
		DEVMODE dmScreenSettings;								// Device Mode

		memset(&dmScreenSettings,0,sizeof(dmScreenSettings));	// Makes Sure Memory''s Cleared

		dmScreenSettings.dmSize=sizeof(dmScreenSettings);		// Size Of The Devmode Structure

		dmScreenSettings.dmPelsWidth	= width;				// Selected Screen Width

		dmScreenSettings.dmPelsHeight	= height;				// Selected Screen Height

		dmScreenSettings.dmBitsPerPel	= bits;					// Selected Bits Per Pixel

		dmScreenSettings.dmFields=DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT;

		// Try To Set Selected Mode And Get Results.  NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar.

		if (ChangeDisplaySettings(&dmScreenSettings,CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL)
		{
			// If The Mode Fails, Offer Two Options.  Quit Or Use Windowed Mode.

			if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES)
			{
				fullscreen=FALSE;		// Windowed Mode Selected.  Fullscreen = FALSE

			}
			else
			{
				// Pop Up A Message Box Letting User Know The Program Is Closing.

				MessageBox(NULL,"Program Will Now Close.","ERROR",MB_OK|MB_ICONSTOP);
				return FALSE;									// Return FALSE

			}
		}
	}

	if (fullscreen)												// Are We Still In Fullscreen Mode?

	{
		dwExStyle=WS_EX_APPWINDOW;								// Window Extended Style

		dwStyle=WS_POPUP;										// Windows Style

		ShowCursor(FALSE);										// Hide Mouse Pointer

	}
	else
	{
		dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;			// Window Extended Style

		dwStyle=WS_OVERLAPPEDWINDOW;							// Windows Style

	}

	AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle);		// Adjust Window To True Requested Size


	// Create The Window

	if (!(hWnd=CreateWindowEx(	dwExStyle,							// Extended Style For The Window

								"OpenGL",							// Class Name

								title,								// Window Title

								dwStyle |							// Defined Window Style

								WS_CLIPSIBLINGS |					// Required Window Style

								WS_CLIPCHILDREN,					// Required Window Style

								0, 0,								// Window Position

								WindowRect.right-WindowRect.left,	// Calculate Window Width

								WindowRect.bottom-WindowRect.top,	// Calculate Window Height

								NULL,								// No Parent Window

								NULL,								// No Menu

								hInstance,							// Instance

								NULL)))								// Dont Pass Anything To WM_CREATE

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Window Creation Error.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	static	PIXELFORMATDESCRIPTOR pfd=				// pfd Tells Windows How We Want Things To Be

	{
		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

	};
	
	if (!(hDC=GetDC(hWnd)))							// Did We Get A Device Context?

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Can''t Create A GL Device Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	if (!(PixelFormat=ChoosePixelFormat(hDC,&pfd)))	// Did Windows Find A Matching Pixel Format?

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Can''t Find A Suitable PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	if(!SetPixelFormat(hDC,PixelFormat,&pfd))		// Are We Able To Set The Pixel Format?

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Can''t Set The PixelFormat.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	if (!(hRC=wglCreateContext(hDC)))				// Are We Able To Get A Rendering Context?

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Can''t Create A GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	if(!wglMakeCurrent(hDC,hRC))					// Try To Activate The Rendering Context

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Can''t Activate The GL Rendering Context.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	ShowWindow(hWnd,SW_SHOW);						// Show The Window

	SetForegroundWindow(hWnd);						// Slightly Higher Priority

	SetFocus(hWnd);									// Sets Keyboard Focus To The Window

	ReSizeGLScene(width, height);

	if (!InitGL())									// Initialize Our Newly Created GL Window

	{
		KillGLWindow();								// Reset The Display

		MessageBox(NULL,"Initialization Failed.","ERROR",MB_OK|MB_ICONEXCLAMATION);
		return FALSE;								// Return FALSE

	}

	return TRUE;									// Success

}

LRESULT CALLBACK WndProc(	HWND	hWnd,			// Handle For This Window

							UINT	uMsg,			// Message For This Window

							WPARAM	wParam,			// Additional Message Information

							LPARAM	lParam)			// Additional Message Information

{
	switch (uMsg)									// Check For Windows Messages

	{
		case WM_ACTIVATE:							// Watch For Window Activate Message

		{
			if (!HIWORD(wParam))					// Check Minimization State

			{
				active=TRUE;						// Program Is Active

			}
			else
			{
				active=FALSE;						// Program Is No Longer Active

			}

			return 0;								// Return To The Message Loop

		}

		case WM_SYSCOMMAND:							// Intercept System Commands

		{
			switch (wParam)							// Check System Calls

			{
				case SC_SCREENSAVE:					// Screensaver Trying To Start?

				case SC_MONITORPOWER:				// Monitor Trying To Enter Powersave?

				return 0;							// Prevent From Happening

			}
			break;									// Exit

		}

		case WM_CLOSE:								// Did We Receive A Close Message?

		{
			PostQuitMessage(0);						// Send A Quit Message

			return 0;								// Jump Back

		}

		case WM_KEYDOWN:							// Is A Key Being Held Down?

		{
			keys[wParam] = TRUE;					// If So, Mark It As TRUE

			return 0;								// Jump Back

		}

		case WM_KEYUP:								// Has A Key Been Released?

		{
			keys[wParam] = FALSE;					// If So, Mark It As FALSE

			return 0;								// Jump Back

		}

		case WM_SIZE:								// Resize The OpenGL Window

		{
			ReSizeGLScene(LOWORD(lParam),HIWORD(lParam));  // LoWord=Width, HiWord=Height

			return 0;								// Jump Back

		}
	}

	// Pass All Unhandled Messages To DefWindowProc

	return DefWindowProc(hWnd,uMsg,wParam,lParam);
}
[source/]

[source]
#include "Main.h"
#include "3ds.h"

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

/////

/////	This constructor initializes the tChunk data

/////

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


CLoad3DS::CLoad3DS()
{
	m_CurrentChunk = new tChunk;				// Initialize and allocate our current chunk

	m_TempChunk = new tChunk;					// Initialize and allocate a temporary chunk

}

///////////////////////////////// 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};

	// 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(m_CurrentChunk);

	// Make sure this is a 3DS file

	if (m_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, m_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()
{

	fclose(m_FilePointer);						// Close the current file pointer

	delete m_CurrentChunk;						// Free the current chunk

	delete m_TempChunk;							// Free our temporary chunk

}


///////////////////////////////// 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

	unsigned int version = 0;					// This will hold the file version

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


	m_CurrentChunk = new tChunk;				// Allocate a new chunk				


	// 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(m_CurrentChunk);

		// Check the chunk ID

		switch (m_CurrentChunk->ID)
		{
		case VERSION:							// This holds the version of the file

			
			// This chunk has an unsigned short 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.


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

			m_CurrentChunk->bytesRead += fread(&version, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);

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

			if (version > 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(m_TempChunk);

			// Get the version of the mesh

			m_TempChunk->bytesRead += fread(&version, 1, m_TempChunk->length - m_TempChunk->bytesRead, m_FilePointer);

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

			m_CurrentChunk->bytesRead += m_TempChunk->bytesRead;

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

			ProcessNextChunk(pModel, m_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, m_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.

			m_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]), m_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, m_CurrentChunk);


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

			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_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.

			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}

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

		pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
	}

	// Free the current chunk and set it back to the previous chunk (since it started that way)

	delete m_CurrentChunk;
	m_CurrentChunk = pPreviousChunk;
}


///////////////////////////////// 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)
{
	int buffer[50000] = {0};					// This is used to read past unwanted data


	// Allocate a new chunk to work with

	m_CurrentChunk = new tChunk;

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

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

		ReadChunk(m_CurrentChunk);

		// Check which chunk we just read

		switch (m_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, m_CurrentChunk);
			break;

		case OBJECT_VERTICES:				// This is the objects vertices

			ReadVertices(pObject, m_CurrentChunk);
			break;

		case OBJECT_FACES:					// This is the objects face information

			ReadVertexIndices(pObject, m_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, m_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, m_CurrentChunk);
			break;

		default:  

			// Read past the ignored or unknown chunks

			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}

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

		pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
	}

	// Free the current chunk and set it back to the previous chunk (since it started that way)

	delete m_CurrentChunk;
	m_CurrentChunk = pPreviousChunk;
}


///////////////////////////////// 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)
{
	int buffer[50000] = {0};					// This is used to read past unwanted data


	// Allocate a new chunk to work with

	m_CurrentChunk = new tChunk;

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

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

		ReadChunk(m_CurrentChunk);

		// Check which chunk we just read in

		switch (m_CurrentChunk->ID)
		{
		case MATNAME:							// This chunk holds the name of the material

			
			// Here we read in the material name

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

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

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

			
			// Proceed to read in the material information

			ProcessNextMaterialChunk(pModel, m_CurrentChunk);
			break;

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


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

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

			// Read past the ignored or unknown chunks

			m_CurrentChunk->bytesRead += fread(buffer, 1, m_CurrentChunk->length - m_CurrentChunk->bytesRead, m_FilePointer);
			break;
		}

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

		pPreviousChunk->bytesRead += m_CurrentChunk->bytesRead;
	}

	// Free the current chunk and set it back to the previous chunk (since it started that way)

	delete m_CurrentChunk;
	m_CurrentChunk = pPreviousChunk;
}

///////////////////////////////// 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)
{
	// Read the color chunk info

	ReadChunk(m_TempChunk);

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

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

	// Add the bytes read to our chunk

	pChunk->bytesRead += m_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

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


	// *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(buffer, 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;
	}
}
[source/]

thanks

please reply

  
Sir Darkan Fireblade

Share this post


Link to post
Share on other sites
Advertisement

  • Advertisement