Jump to content
  • Advertisement
Sign in to follow this  
Dragon_Strike

OpenGL 3ds loader problem (crashes)

This topic is 4143 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

im having some trouble loading 3ds models... when i try to load a model I get an error and the program crashes... the loader when i try to load very simple models ive created quickly.. something like a textured box... any ideas what might be causing it? there error is something like "Debug assertion" and "Expression: _CrtCheckMemory" im using the following loader code..


#ifndef MODEL_3DS_H
#define MODEL_3DS_H

// I decided to use my CIMAGE class b/c adding all of its functions
// Would have greatly bloated the model class's code
// Just replace this with your favorite texture class
#include "BaseCode/Image.h"
#include "BaseCode/Math/math.h"
#include <stdio.h>

class Model_3DS  
{
public:
	// A VERY simple vector struct
	// I could have included a complex class but I wanted the model class to stand alone
	struct Vector {
		float x;
		float y;
		float z;
	};

	// Vertex struct to make code easier to read in places
	struct Vertex {
		float x;
		float y;
		float z;
	};

	// Color struct holds the diffuse color of the material
	struct Color4i {
		unsigned char r;
		unsigned char g;
		unsigned char b;
		unsigned char a;
	};

	// Holds the material info
	// TODO: add color support for non textured polys
	struct Material {
		char name[80];	// The material's name
		CIMAGE tex;	// The texture (this is the only outside reference in this class)
		bool textured;	// whether or not it is textured
		Color4i color;
	};

	// Every chunk in the 3ds file starts with this struct
	struct ChunkHeader {
		unsigned short id;	// The chunk's id
		unsigned long  len;	// The lenght of the chunk
	};

	// I sort the mesh by material so that I won't have to switch textures a great deal
	struct MaterialFaces {
		unsigned short *subFaces;	// Index to our vertex array of all the faces that use this material
		int numSubFaces;			// The number of faces
		int MatIndex;				// An index to our materials
	};

	// The 3ds file can be made up of several objects
	struct Object {
		char name[80];				// The object name
		float *Vertexes;			// The array of vertices
		float *Normals;				// The array of the normals for the vertices
		float *Tangents;				// The array of the normals for the vertices
		float *TexCoords;			// The array of texture coordinates for the vertices
		unsigned short *Faces;		// The array of face indices
		int numFaces;				// The number of faces
		int numMatFaces;			// The number of differnet material faces
		int numVerts;				// The number of vertices
		int numTexCoords;			// The number of vertices
		bool textured;				// True: the object has textures
		MaterialFaces *MatFaces;	// The faces are divided by materials
		Vector pos;					// The position to move the object to
		Vector rot;					// The angles to rotate the object
	};

	char *modelname;		// The name of the model
	char *path;				// The path of the model
	int numObjects;			// Total number of objects in the model
	int numMaterials;		// Total number of materials in the model
	int totalVerts;			// Total number of vertices in the model
	int totalFaces;			// Total number of faces in the model
	bool shownormals;		// True: show the normals
	Material *Materials;	// The array of materials
	Object *Objects;		// The array of objects in the model
	Vector pos;				// The position to move the model to
	Vector rot;				// The angles to rotate the model
	float scale;			// The size you want the model scaled to
	bool lit;				// True: the model is lit
	bool visible;			// True: the model gets rendered
	void Load(char *name);	// Loads a model
	void Draw();			// Draws the model
	FILE *bin3ds;			// The binary 3ds file
	Model_3DS();			// Constructor
	virtual ~Model_3DS();	// Destructor

private:
	void IntColorChunkProcessor(long length, long findex, int matindex);
	void FloatColorChunkProcessor(long length, long findex, int matindex);
	// Processes the Main Chunk that all the other chunks exist is
	void MainChunkProcessor(long length, long findex);
		// Processes the model's info
		void EditChunkProcessor(long length, long findex);
			
			// Processes the model's materials
			void MaterialChunkProcessor(long length, long findex, int matindex);
				// Processes the names of the materials
				void MaterialNameChunkProcessor(long length, long findex, int matindex);
				// Processes the material's diffuse color
				void DiffuseColorChunkProcessor(long length, long findex, int matindex);
				// Processes the material's texture maps
				void TextureMapChunkProcessor(long length, long findex, int matindex);
					// Processes the names of the textures and load the textures
					void MapNameChunkProcessor(long length, long findex, int matindex);
			
			// Processes the model's geometry
			void ObjectChunkProcessor(long length, long findex, int objindex);
				// Processes the triangles of the model
				void TriangularMeshChunkProcessor(long length, long findex, int objindex);
					// Processes the vertices of the model and loads them
					void VertexListChunkProcessor(long length, long findex, int objindex);
					// Processes the texture cordiantes of the vertices and loads them
					void TexCoordsChunkProcessor(long length, long findex, int objindex);
					// Processes the faces of the model and loads the faces
					void FacesDescriptionChunkProcessor(long length, long findex, int objindex);
						// Processes the materials of the faces and splits them up by material
						void FacesMaterialsListChunkProcessor(long length, long findex, int objindex, int subfacesindex);

	// Calculates the normals of the vertices by averaging
	// the normals of the faces that use that vertex
	void CalculateNormals();
};

#endif MODEL_3DS_H



// This is used to generate a warning from the compiler
#define _QUOTE(x) # x
#define QUOTE(x) _QUOTE(x)
#define __FILE__LINE__ __FILE__ "(" QUOTE(__LINE__) ") : "
#define warn( x )  message( __FILE__LINE__ #x "\n" ) 

// You need to uncomment this if you are using MFC
#pragma warn( You need to uncomment this if you are using MFC )
//#include "stdafx.h"

#include "Model_3DS.h"

#include <math.h>			// Header file for the math library
#include <gl\gl.h>			// Header file for the OpenGL32 library

// The chunk's id numbers
#define MAIN3DS				0x4D4D
 #define MAIN_VERS			0x0002
 #define EDIT3DS			0x3D3D
  #define MESH_VERS			0x3D3E
  #define OBJECT			0x4000
   #define TRIG_MESH		0x4100
    #define VERT_LIST		0x4110
    #define FACE_DESC		0x4120
     #define FACE_MAT		0x4130
    #define TEX_VERTS		0x4140
     #define SMOOTH_GROUP	0x4150
    #define LOCAL_COORDS	0x4160
  #define MATERIAL			0xAFFF
   #define MAT_NAME			0xA000
   #define MAT_AMBIENT		0xA010
   #define MAT_DIFFUSE		0xA020
   #define MAT_SPECULAR		0xA030
   #define SHINY_PERC		0xA040
   #define SHINY_STR_PERC	0xA041
   #define TRANS_PERC		0xA050
   #define TRANS_FOFF_PERC	0xA052
   #define REF_BLUR_PERC	0xA053
   #define RENDER_TYPE		0xA100
   #define SELF_ILLUM		0xA084
   #define MAT_SELF_ILPCT	0xA08A
   #define WIRE_THICKNESS	0xA087
   #define MAT_TEXMAP		0xA200
    #define MAT_MAPNAME		0xA300
  #define ONE_UNIT			0x0100
 #define KEYF3DS			0xB000
  #define FRAMES			0xB008
  #define MESH_INFO			0xB002
   #define HIER_POS			0xB030
   #define HIER_FATHER		0xB010
   #define PIVOT_PT			0xB013
   #define TRACK00			0xB020
   #define TRACK01			0xB021
   #define TRACK02			0xB022
#define	COLOR_RGB			0x0010
#define COLOR_TRU			0x0011
#define COLOR_TRUG			0x0012
#define COLOR_RGBG			0x0013
#define PERC_INT			0x0030
#define PERC_FLOAT			0x0031

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

Model_3DS::Model_3DS()
{
	// Initialization

	// Don't show the normals by default
	shownormals = false;

	// The model is lit by default
	lit = true;

	// The model is visible by default
	visible = true;

	// Set up the default position
	pos.x = 0.0f;
	pos.y = 0.0f;
	pos.z = 0.0f;
	// Set up the default rotation
	rot.x = 0.0f;
	rot.y = 0.0f;
	rot.z = 0.0f;

	// Set up the path
	path = new char[80];
	sprintf(path, "");

	// Zero out our counters for MFC
	numObjects = 0;
	numMaterials = 0;

	// Set the scale to one
	scale = 1.0f;
}

Model_3DS::~Model_3DS()
{

}

void Model_3DS::Load(char *name)
{
	// holds the main chunk header
	ChunkHeader main;

	// strip "'s
	if (strstr(name, "\""))
		name = strtok(name, "\"");

	// Find the path
	if (strstr(name, "/") || strstr(name, "\\"))
	{
		// Holds the name of the model minus the path
		char *temp;

		// Find the name without the path
		if (strstr(name, "/"))
			temp = strrchr(name, '/');
		else
			temp = strrchr(name, '\\');

		// Allocate space for the path
		path = new char[strlen(name)-strlen(temp)+1];

		// Get a pointer to the end of the path and name
		char *src = name + strlen(name) - 1;

		// Back up until a \ or the start
		while (src != path && !((*(src-1)) == '\\' || (*(src-1)) == '/'))
			src--;

		// Copy the path into path
		memcpy (path, name, src-name);
		path[src-name] = 0;
	}

	// Load the file
	bin3ds = fopen(name,"rb");

	// Make sure we are at the beginning
	fseek(bin3ds, 0, SEEK_SET);

	// Load the Main Chunk's header
	fread(&main.id,sizeof(main.id),1,bin3ds);
    fread(&main.len,sizeof(main.len),1,bin3ds);

	// Start Processing
	MainChunkProcessor(main.len, ftell(bin3ds));

	// Don't need the file anymore so close it
	fclose(bin3ds);

	// Calculate the vertex normals
	CalculateNormals();

	// For future reference
	modelname = name;

	// Find the total number of faces and vertices
	totalFaces = 0;
	totalVerts = 0;

	for (int i = 0; i < numObjects; i ++)
	{
		totalFaces += Objects.numFaces/3;
		totalVerts += Objects.numVerts;
	}

	// If the object doesn't have any texcoords generate some
	for (int k = 0; k < numObjects; k++)
	{
		if (Objects[k].numTexCoords == 0)
		{
			// Set the number of texture coords
			Objects[k].numTexCoords = Objects[k].numVerts;

			// Allocate an array to hold the texture coordinates
			Objects[k].TexCoords = new GLfloat[Objects[k].numTexCoords * 2];

			// Make some texture coords
			for (int m = 0; m < Objects[k].numTexCoords; m++)
			{
				Objects[k].TexCoords[2*m] = Objects[k].Vertexes[3*m];
				Objects[k].TexCoords[2*m+1] = Objects[k].Vertexes[3*m+1];
			}
		}
	}

	// Let's build simple colored textures for the materials w/o a texture
	for (int j = 0; j < numMaterials; j++)
	{
		if (Materials[j].textured == false)
		{
			unsigned char r = Materials[j].color.r;
			unsigned char g = Materials[j].color.g;
			unsigned char b = Materials[j].color.b;
			//Materials[j].tex.BuildColorTexture(r, g, b);
			Materials[j].textured = true;
		}
	}
}
void Model_3DS::Draw()
{
	if (visible)
	{
	glPushMatrix();

		// Move the model
		glTranslatef(pos.x, pos.y, pos.z);

		// Rotate the model
		glRotatef(rot.x, 1.0f, 0.0f, 0.0f);
		glRotatef(rot.y, 0.0f, 1.0f, 0.0f);
		glRotatef(rot.z, 0.0f, 0.0f, 1.0f);

		glScalef(scale, scale, scale);

		// Loop through the objects
		for (int i = 0; i < numObjects; i++)
		{
			// Enable texture coordiantes, normals, and vertices arrays
			if (Objects.textured)
				glEnableClientState(GL_TEXTURE_COORD_ARRAY);
			if (lit)
			{
				glEnableClientState(GL_NORMAL_ARRAY);
				glEnableClientState(GL_COLOR_ARRAY);
			}

			glEnableClientState(GL_VERTEX_ARRAY);

			// Point them to the objects arrays
			if (Objects.textured)
				glTexCoordPointer(2, GL_FLOAT, 0, Objects.TexCoords);
			if (lit)
			{
				glNormalPointer(GL_FLOAT, 0, Objects.Normals);
				glColorPointer(3, GL_FLOAT, 0, Objects.Tangents);
			}

			glVertexPointer(3, GL_FLOAT, 0, Objects.Vertexes);

			// Loop through the faces as sorted by material and draw them
			for (int j = 0; j < Objects.numMatFaces; j ++)
			{
				// Use the material's texture
				Materials[Objects.MatFaces[j].MatIndex].tex.Bind();

				glPushMatrix();

					// Move the model
					glTranslatef(Objects.pos.x, Objects.pos.y, Objects.pos.z);

					// Rotate the model
					//glRotatef(Objects.rot.x, 1.0f, 0.0f, 0.0f);
					//glRotatef(Objects.rot.y, 0.0f, 1.0f, 0.0f);
					//glRotatef(Objects.rot.z, 0.0f, 0.0f, 1.0f);

					glRotatef(Objects.rot.z, 0.0f, 0.0f, 1.0f);
					glRotatef(Objects.rot.y, 0.0f, 1.0f, 0.0f);
					glRotatef(Objects.rot.x, 1.0f, 0.0f, 0.0f);

					// Draw the faces using an index to the vertex array
					glDrawElements(GL_TRIANGLES, Objects.MatFaces[j].numSubFaces, GL_UNSIGNED_SHORT, Objects.MatFaces[j].subFaces);

				glPopMatrix();
			}


			// Show the normals?
			if (shownormals)
			{
				// Loop through the vertices and normals and draw the normal
				for (int k = 0; k < Objects.numVerts * 2; k += 3)
				{
					// Disable texturing
					glDisable(GL_TEXTURE_2D);
					// Disbale lighting if the model is lit
					if (lit)
						glDisable(GL_LIGHTING);
					// Draw the normals blue
					glColor3f(0.0f, 0.0f, 1.0f);

					// Draw a line between the vertex and the end of the normal
					glBegin(GL_LINES);
						glVertex3f(Objects.Vertexes[k], Objects.Vertexes[k+1], Objects.Vertexes[k+2]);
						glVertex3f(Objects.Vertexes[k]+Objects.Normals[k]*3.0, Objects.Vertexes[k+1]+Objects.Normals[k+1]*3.0, Objects.Vertexes[k+2]+Objects.Normals[k+2]*3.0);
					glEnd();

					// Reset the color to white
					glColor3f(1.0f, 1.0f, 1.0f);
					// If the model is lit then renable lighting
					if (lit)
						glEnable(GL_LIGHTING);
				}

				for (int k = 0; k < Objects.numVerts * 2; k += 3)
				{
					// Disable texturing
					glDisable(GL_TEXTURE_2D);
					// Disbale lighting if the model is lit
					if (lit)
						glDisable(GL_LIGHTING);
					// Draw the normals blue
					glColor3f(0.0f, 0.0f, 1.0f);

					// Draw a line between the vertex and the end of the normal
					glBegin(GL_LINES);
						glVertex3f(Objects.Vertexes[k],Objects.Vertexes[k+1], Objects.Vertexes[k+2]);
						glVertex3f(Objects.Vertexes[k]+Objects.Tangents[k]*2.0, Objects.Vertexes[k+1]+Objects.Tangents[k+1]*2.0, Objects.Vertexes[k+2]+Objects.Tangents[k+2]*2.0);
					glEnd();

					// Reset the color to white
					glColor3f(1.0f, 1.0f, 1.0f);
					// If the model is lit then renable lighting
					if (lit)
						glEnable(GL_LIGHTING);
				}

				for (int k = 0; k < Objects.numVerts * 2; k += 3)
				{
					// Disable texturing
					glDisable(GL_TEXTURE_2D);
					// Disbale lighting if the model is lit
					if (lit)
						glDisable(GL_LIGHTING);
					// Draw the normals blue
					glColor3f(0.0f, 0.0f, 1.0f);

					vec3 Normal = vec3(Objects.Normals[k], Objects.Normals[k+1], Objects.Normals[k+2]);
					vec3 Tangent = vec3(Objects.Tangents[k], Objects.Tangents[k+1], Objects.Tangents[k+2]);

					vec3 BiNormal = cross(Normal,Tangent);
					// Draw a line between the vertex and the end of the normal
					glBegin(GL_LINES);
						glVertex3f(Objects.Vertexes[k],Objects.Vertexes[k+1], Objects.Vertexes[k+2]);
						glVertex3f(Objects.Vertexes[k]+BiNormal.x, Objects.Vertexes[k+1]+BiNormal.y, Objects.Vertexes[k+2]+BiNormal.z);
					glEnd();

					// Reset the color to white
					glColor3f(1.0f, 1.0f, 1.0f);
					// If the model is lit then renable lighting
					if (lit)
						glEnable(GL_LIGHTING);
				}
			}
		}

	glPopMatrix();
	}
}

void Model_3DS::CalculateNormals()
{
	// Let's build some normals
	for (int i = 0; i < numObjects; i++)
	{
		for (int g = 0; g < Objects.numVerts; g++)
		{
			vec3 Pos1 = vec3(Objects.Vertexes[g*3],
							 Objects.Vertexes[g*3+1],
							 Objects.Vertexes[g*3+2]);

			for (int i2 = 0; i2 < numObjects; i2++)
			{
				for (int g2 = 0; g2 < Objects[i2].numVerts; g2++)
				{
					vec3 Pos2 = vec3(Objects[i2].Vertexes[g2*3],
									Objects[i2].Vertexes[g2*3+1],
									Objects[i2].Vertexes[g2*3+2]);

					if (Pos1 == Pos2)
					{
						Objects.Normals[g*3] += Objects[i2].Normals[g2*3];
						Objects.Normals[g*3+1] += Objects[i2].Normals[g2*3+1];
						Objects.Normals[g*3+2] += Objects[i2].Normals[g2*3+2];

						Objects[i2].Normals[g2*3] = Objects.Normals[g*3];
						Objects[i2].Normals[g2*3+1] = Objects.Normals[g*3+1];
						Objects[i2].Normals[g2*3+2] = Objects.Normals[g*3+2];

						Objects.Tangents[g*3] += Objects[i2].Tangents[g2*3];
						Objects.Tangents[g*3+1] += Objects[i2].Tangents[g2*3+1];
						Objects.Tangents[g*3+2] += Objects[i2].Tangents[g2*3+2];

						Objects[i2].Tangents[g2*3] = Objects.Tangents[g*3];
						Objects[i2].Tangents[g2*3+1] = Objects.Tangents[g*3+1];
						Objects[i2].Tangents[g2*3+2] = Objects.Tangents[g*3+2];
					}
				}
			}
				          
		}
	}

	for (int i = 0; i < numObjects; i++)
	{
		for (int g = 0; g < Objects.numVerts; g++)
		{
			// Reduce each vert's normal to unit
			float length;
			Vector unit;

			unit.x = Objects.Normals[g*3];
			unit.y = Objects.Normals[g*3+1];
			unit.z = Objects.Normals[g*3+2];

			length = (float)sqrt((unit.x*unit.x) + (unit.y*unit.y) + (unit.z*unit.z));

			if (length == 0.0f)
				length = 1.0f;

			unit.x /= length;
			unit.y /= length;
			unit.z /= length;

			Objects.Normals[g*3]   = unit.x;
			Objects.Normals[g*3+1] = unit.y;
			Objects.Normals[g*3+2] = unit.z;



			unit.x = Objects.Tangents[g*3];
			unit.y = Objects.Tangents[g*3+1];
			unit.z = Objects.Tangents[g*3+2];

			length = (float)sqrt((unit.x*unit.x) + (unit.y*unit.y) + (unit.z*unit.z));

			if (length == 0.0f)
				length = 1.0f;

			unit.x /= length;
			unit.y /= length;
			unit.z /= length;

			Objects.Tangents[g*3]   = unit.x;
			Objects.Tangents[g*3+1] = unit.y;
			Objects.Tangents[g*3+2] = unit.z;
		}
	}
}

void Model_3DS::MainChunkProcessor(long length, long findex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			// This is the mesh information like vertices, faces, and materials
			case EDIT3DS	:
				EditChunkProcessor(h.len, ftell(bin3ds));
				break;
			// I left this in case anyone gets very ambitious
			case KEYF3DS	:
				//KeyFrameChunkProcessor(h.len, ftell(bin3ds));
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::EditChunkProcessor(long length, long findex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// First count the number of Objects and Materials
	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case OBJECT	:
				numObjects++;
				break;
			case MATERIAL	:
				numMaterials++;
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// Now load the materials
	if (numMaterials > 0)
	{
		Materials = new Material[numMaterials];

		// Material is set to untextured until we find otherwise
		for (int d = 0; d < numMaterials; d++)
			Materials[d].textured = false;

		fseek(bin3ds, findex, SEEK_SET);

		int i = 0;

		while (ftell(bin3ds) < (findex + length - 6))
		{
			fread(&h.id,sizeof(h.id),1,bin3ds);
			fread(&h.len,sizeof(h.len),1,bin3ds);

			switch (h.id)
			{
				case MATERIAL	:
					MaterialChunkProcessor(h.len, ftell(bin3ds), i);
					i++;
					break;
				default			:
					break;
			}

			fseek(bin3ds, (h.len - 6), SEEK_CUR);
		}
	}

	// Load the Objects (individual meshes in the whole model)
	if (numObjects > 0)
	{
		Objects = new Object[numObjects];

		// Set the textured variable to false until we find a texture
		for (int k = 0; k < numObjects; k++)
			Objects[k].textured = false;

		// Zero the objects position and rotation
		for (int m = 0; m < numObjects; m++)
		{
			Objects[m].pos.x = 0.0f;
			Objects[m].pos.y = 0.0f;
			Objects[m].pos.z = 0.0f;

			Objects[m].rot.x = 0.0f;
			Objects[m].rot.y = 0.0f;
			Objects[m].rot.z = 0.0f;
		}

		// Zero out the number of texture coords
		for (int n = 0; n < numObjects; n++)
			Objects[n].numTexCoords = 0;

		fseek(bin3ds, findex, SEEK_SET);

		int j = 0;

		while (ftell(bin3ds) < (findex + length - 6))
		{
			fread(&h.id,sizeof(h.id),1,bin3ds);
			fread(&h.len,sizeof(h.len),1,bin3ds);

			switch (h.id)
			{
				case OBJECT	:
					ObjectChunkProcessor(h.len, ftell(bin3ds), j);
					j++;
					break;
				default			:
					break;
			}

			fseek(bin3ds, (h.len - 6), SEEK_CUR);
		}
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::MaterialChunkProcessor(long length, long findex, int matindex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case MAT_NAME	:
				// Loads the material's names
				MaterialNameChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			case MAT_AMBIENT	:
				//ColorChunkProcessor(h.len, ftell(bin3ds));
				break;
			case MAT_DIFFUSE	:
				DiffuseColorChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			case MAT_SPECULAR	:
				//ColorChunkProcessor(h.len, ftell(bin3ds));
			case MAT_TEXMAP	:
				// Finds the names of the textures of the material and loads them
				TextureMapChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::MaterialNameChunkProcessor(long length, long findex, int matindex)
{
	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the material's name
	for (int i = 0; i < 80; i++)
	{
		Materials[matindex].name = fgetc(bin3ds);
		if (Materials[matindex].name == 0)
		{
			Materials[matindex].name = NULL;
			break;
		}
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::DiffuseColorChunkProcessor(long length, long findex, int matindex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		// Determine the format of the color and load it
		switch (h.id)
		{
			case COLOR_RGB	:
				// A rgb float color chunk
				FloatColorChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			case COLOR_TRU	:
				// A rgb int color chunk
				IntColorChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			case COLOR_RGBG	:
				// A rgb gamma corrected float color chunk
				FloatColorChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			case COLOR_TRUG	:
				// A rgb gamma corrected int color chunk
				IntColorChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::FloatColorChunkProcessor(long length, long findex, int matindex)
{
	float r;
	float g;
	float b;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	fread(&r,sizeof(r),1,bin3ds);
	fread(&g,sizeof(g),1,bin3ds);
	fread(&b,sizeof(b),1,bin3ds);

	Materials[matindex].color.r = (unsigned char)(r*255.0f);
	Materials[matindex].color.g = (unsigned char)(r*255.0f);
	Materials[matindex].color.b = (unsigned char)(r*255.0f);
	Materials[matindex].color.a = 255;

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::IntColorChunkProcessor(long length, long findex, int matindex)
{
	unsigned char r;
	unsigned char g;
	unsigned char b;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	fread(&r,sizeof(r),1,bin3ds);
	fread(&g,sizeof(g),1,bin3ds);
	fread(&b,sizeof(b),1,bin3ds);

	Materials[matindex].color.r = r;
	Materials[matindex].color.g = g;
	Materials[matindex].color.b = b;
	Materials[matindex].color.a = 255;

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::TextureMapChunkProcessor(long length, long findex, int matindex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case MAT_MAPNAME:
				// Read the name of texture in the Diffuse Color map
				MapNameChunkProcessor(h.len, ftell(bin3ds), matindex);
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::MapNameChunkProcessor(long length, long findex, int matindex)
{
	char name[80];

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the name of the texture
	for (int i = 0; i < 80; i++)
	{
		name = fgetc(bin3ds);
		if (name == 0)
		{
			name = NULL;
			break;
		}
	}

	// Load the name and indicate that the material has a texture
	char fullname[80];
	sprintf(fullname, "%s%s", path, name);
	Materials[matindex].tex.Load(fullname);
	Materials[matindex].textured = true;

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::ObjectChunkProcessor(long length, long findex, int objindex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Load the object's name
	for (int i = 0; i < 80; i++)
	{
		Objects[objindex].name = fgetc(bin3ds);
		if (Objects[objindex].name == 0)
		{
			Objects[objindex].name = NULL;
			break;
		}
	}

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case TRIG_MESH	:
				// Process the triangles of the object
				TriangularMeshChunkProcessor(h.len, ftell(bin3ds), objindex);
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::TriangularMeshChunkProcessor(long length, long findex, int objindex)
{
	ChunkHeader h;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case VERT_LIST	:
				// Load the vertices of the onject
				VertexListChunkProcessor(h.len, ftell(bin3ds), objindex);
				break;
			case LOCAL_COORDS	:
				//LocalCoordinatesChunkProcessor(h.len, ftell(bin3ds));
				break;
			case TEX_VERTS	:
				// Load the texture coordinates for the vertices
				TexCoordsChunkProcessor(h.len, ftell(bin3ds), objindex);
				Objects[objindex].textured = true;
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// After we have loaded the vertices we can load the faces
	fseek(bin3ds, findex, SEEK_SET);

	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case FACE_DESC	:
				// Load the faces of the object
				FacesDescriptionChunkProcessor(h.len, ftell(bin3ds), objindex);
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::VertexListChunkProcessor(long length, long findex, int objindex)
{
	unsigned short numVerts;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the number of vertices of the object
	fread(&numVerts,sizeof(numVerts),1,bin3ds);

	// Allocate arrays for the vertices and normals
	Objects[objindex].Vertexes = new GLfloat[numVerts * 3];
	Objects[objindex].Normals = new GLfloat[numVerts * 3];
	Objects[objindex].Tangents = new GLfloat[numVerts * 3];
	// Assign the number of vertices for future use
	Objects[objindex].numVerts = numVerts;

	// Zero out the normals array
	for (int j = 0; j < numVerts * 3; j++)
	{
		Objects[objindex].Normals[j] = 0.0f;
		Objects[objindex].Tangents[j] = 0.0f;
	}

	// Read the vertices, switching the y and z coordinates and changing the sign of the z coordinate
	for (int i = 0; i < numVerts * 3; i+=3)
	{
		fread(&Objects[objindex].Vertexes,sizeof(GLfloat),1,bin3ds);
		fread(&Objects[objindex].Vertexes[i+2],sizeof(GLfloat),1,bin3ds);
		fread(&Objects[objindex].Vertexes[i+1],sizeof(GLfloat),1,bin3ds);

		// Change the sign of the z coordinate
		Objects[objindex].Vertexes[i+2] = -Objects[objindex].Vertexes[i+2];
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::TexCoordsChunkProcessor(long length, long findex, int objindex)
{
	// The number of texture coordinates
	unsigned short numCoords;

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the number of coordinates
	fread(&numCoords,sizeof(numCoords),1,bin3ds);

	// Allocate an array to hold the texture coordinates
	Objects[objindex].TexCoords = new GLfloat[numCoords * 2];

	// Set the number of texture coords
	Objects[objindex].numTexCoords = numCoords;

	// Read teh texture coordiantes into the array
	for (int i = 0; i < numCoords * 2; i+=2)
	{
		fread(&Objects[objindex].TexCoords,sizeof(GLfloat),1,bin3ds);
		fread(&Objects[objindex].TexCoords[i+1],sizeof(GLfloat),1,bin3ds);
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::FacesDescriptionChunkProcessor(long length, long findex, int objindex)
{
	ChunkHeader h;
	unsigned short numFaces;	// The number of faces in the object
	unsigned short vertA;		// The first vertex of the face
	unsigned short vertB;		// The second vertex of the face
	unsigned short vertC;		// The third vertex of the face
	unsigned short flags;		// The winding order flags
	long subs;					// Holds our place in the file
	int numMatFaces = 0;		// The number of different materials

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the number of faces
	fread(&numFaces,sizeof(numFaces),1,bin3ds);

	// Allocate an array to hold the faces
	Objects[objindex].Faces = new GLushort[numFaces * 3];
	// Store the number of faces
	Objects[objindex].numFaces = numFaces * 3;

	// Read the faces into the array
	for (int i = 0; i < numFaces * 3; i+=3)
	{
		// Read the vertices of the face
		fread(&vertA,sizeof(vertA),1,bin3ds);
		fread(&vertB,sizeof(vertB),1,bin3ds);
		fread(&vertC,sizeof(vertC),1,bin3ds);
		fread(&flags,sizeof(flags),1,bin3ds);

		// Place them in the array
		Objects[objindex].Faces   = vertA;
		Objects[objindex].Faces[i+1] = vertB;
		Objects[objindex].Faces[i+2] = vertC;

		// Calculate the face's normal
		Vector n;
		Vertex v1;
		Vertex v2;
		Vertex v3;

		v1.x = Objects[objindex].Vertexes[vertA*3];
		v1.y = Objects[objindex].Vertexes[vertA*3+1];
		v1.z = Objects[objindex].Vertexes[vertA*3+2];
		v2.x = Objects[objindex].Vertexes[vertB*3];
		v2.y = Objects[objindex].Vertexes[vertB*3+1];
		v2.z = Objects[objindex].Vertexes[vertB*3+2];
		v3.x = Objects[objindex].Vertexes[vertC*3];
		v3.y = Objects[objindex].Vertexes[vertC*3+1];
		v3.z = Objects[objindex].Vertexes[vertC*3+2];

		// calculate the normal
		float u[3], v[3];

		// V2 - V3;
		u[0] = v2.x - v3.x;
		u[1] = v2.y - v3.y;
		u[2] = v2.z - v3.z;

		// V2 - V1;
		v[0] = v2.x - v1.x;
		v[1] = v2.y - v1.y;
		v[2] = v2.z - v1.z;

		n.x = (u[1]*v[2] - u[2]*v[1]);
		n.y = (u[2]*v[0] - u[0]*v[2]);
		n.z = (u[0]*v[1] - u[1]*v[0]);

		// Add this normal to its verts' normals
		Objects[objindex].Normals[vertA*3]   += n.x;
		Objects[objindex].Normals[vertA*3+1] += n.y;
		Objects[objindex].Normals[vertA*3+2] += n.z;
		Objects[objindex].Normals[vertB*3]   += n.x;
		Objects[objindex].Normals[vertB*3+1] += n.y;
		Objects[objindex].Normals[vertB*3+2] += n.z;
		Objects[objindex].Normals[vertC*3]   += n.x;
		Objects[objindex].Normals[vertC*3+1] += n.y;
		Objects[objindex].Normals[vertC*3+2] += n.z;


		vec3 P1,P2,P3;
		vec2 UV1,UV2,UV3;

		P1.x = Objects[objindex].Vertexes[vertA*3];
		P1.y = Objects[objindex].Vertexes[vertA*3+1];
		P1.z = Objects[objindex].Vertexes[vertA*3+2];
		P2.x = Objects[objindex].Vertexes[vertB*3];
		P2.y = Objects[objindex].Vertexes[vertB*3+1];
		P2.z = Objects[objindex].Vertexes[vertB*3+2];
		P3.x = Objects[objindex].Vertexes[vertC*3];
		P3.y = Objects[objindex].Vertexes[vertC*3+1];
		P3.z = Objects[objindex].Vertexes[vertC*3+2];



		UV1.x = Objects[objindex].TexCoords[vertA*2];
		UV1.y = Objects[objindex].TexCoords[vertA*2+1];
		UV2.x = Objects[objindex].TexCoords[vertB*2];
		UV2.y = Objects[objindex].TexCoords[vertB*2+1];
		UV3.x = Objects[objindex].TexCoords[vertC*2];
		UV3.y = Objects[objindex].TexCoords[vertC*2+1];
	

		vec3 Edge1 = P2 - P1;
		vec3 Edge2 = P3 - P1;
		vec2 Edge1uv = UV2 - UV1;
		vec2 Edge2uv = UV3 - UV1;
        vec3 tangent;
		float cp = Edge1uv.y * Edge2uv.x - Edge1uv.x * Edge2uv.y;

		if ( cp != 0.0f ) {
			float mul = 1.0f / cp;
			tangent   = (Edge1 * -Edge2uv.y + Edge2 * Edge1uv.y) * mul;				
		}



		// Add this normal to its verts' normals
		Objects[objindex].Tangents[vertA*3]   += tangent.x;
		Objects[objindex].Tangents[vertA*3+1] += tangent.y;
		Objects[objindex].Tangents[vertA*3+2] += tangent.z;
		Objects[objindex].Tangents[vertB*3]   += tangent.x;
		Objects[objindex].Tangents[vertB*3+1] += tangent.y;
		Objects[objindex].Tangents[vertB*3+2] += tangent.z;
		Objects[objindex].Tangents[vertC*3]   += tangent.x;
		Objects[objindex].Tangents[vertC*3+1] += tangent.y;
		Objects[objindex].Tangents[vertC*3+2] += tangent.z;

	}

	// Store our current file position
	subs = ftell(bin3ds);

	// Check to see how many materials the faces are split into
	while (ftell(bin3ds) < (findex + length - 6))
	{
		fread(&h.id,sizeof(h.id),1,bin3ds);
		fread(&h.len,sizeof(h.len),1,bin3ds);

		switch (h.id)
		{
			case FACE_MAT	:
				//FacesMaterialsListChunkProcessor(h.len, ftell(bin3ds), objindex);
				numMatFaces++;
				break;
			default			:
				break;
		}

		fseek(bin3ds, (h.len - 6), SEEK_CUR);
	}

	// Split the faces up according to their materials
	if (numMatFaces > 0)
	{
		// Allocate an array to hold the lists of faces divided by material
		Objects[objindex].MatFaces = new MaterialFaces[numMatFaces];
		// Store the number of material faces
		Objects[objindex].numMatFaces = numMatFaces;

		fseek(bin3ds, subs, SEEK_SET);

		int j = 0;

		// Split the faces up
		while (ftell(bin3ds) < (findex + length - 6))
		{
			fread(&h.id,sizeof(h.id),1,bin3ds);
			fread(&h.len,sizeof(h.len),1,bin3ds);

			switch (h.id)
			{
				case FACE_MAT	:
					// Process the faces and split them up
					FacesMaterialsListChunkProcessor(h.len, ftell(bin3ds), objindex, j);
					j++;
					break;
				default			:
					break;
			}

			fseek(bin3ds, (h.len - 6), SEEK_CUR);
		}
	}

	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}

void Model_3DS::FacesMaterialsListChunkProcessor(long length, long findex, int objindex, int subfacesindex)
{
	char name[80];				// The material's name
	unsigned short numEntries;	// The number of faces associated with this material
	unsigned short Face;		// Holds the faces as they are read
	int material;				// An index to the Materials array for this material

	// move the file pointer to the beginning of the main
	// chunk's data findex + the size of the header
	fseek(bin3ds, findex, SEEK_SET);

	// Read the material's name
	for (int i = 0; i < 80; i++)
	{
		name = fgetc(bin3ds);
		if (name == 0)
		{
			name = NULL;
			break;
		}
	}

	// Faind the material's index in the Materials array
	for (material = 0; material < numMaterials; material++)
	{
		if (strcmp(name, Materials[material].name) == 0)
			break;
	}

	// Store this value for later so that we can find the material
	Objects[objindex].MatFaces[subfacesindex].MatIndex = material;

	// Read the number of faces associated with this material
	fread(&numEntries,sizeof(numEntries),1,bin3ds);

	// Allocate an array to hold the list of faces associated with this material
	Objects[objindex].MatFaces[subfacesindex].subFaces = new GLushort[numEntries * 3];
	// Store this number for later use
	Objects[objindex].MatFaces[subfacesindex].numSubFaces = numEntries * 3;

	// Read the faces into the array
	for (i = 0; i < numEntries * 3; i+=3)
	{
		// read the face
		fread(&Face,sizeof(Face),1,bin3ds);
		// Add the face's vertices to the list
		Objects[objindex].MatFaces[subfacesindex].subFaces = Objects[objindex].Faces[Face * 3];
		Objects[objindex].MatFaces[subfacesindex].subFaces[i+1] = Objects[objindex].Faces[Face * 3 + 1];
		Objects[objindex].MatFaces[subfacesindex].subFaces[i+2] = Objects[objindex].Faces[Face * 3 + 2];
	}
	
	// move the file pointer back to where we got it so
	// that the ProcessChunk() which we interrupted will read
	// from the right place
	fseek(bin3ds, findex, SEEK_SET);
}





as a sidenote how would i modify the loader to load bumpmaps aswell.. if u dont know how to fix this maybe u could suggest a better loader... i dont really feel there is any reason to crate an own loader.. due to how much time it requires and that there should be some good free ones out there... ive tried lib3ds... but ive never got that to work... [Edited by - Dragon_Strike on May 17, 2007 12:16:18 PM]

Share this post


Link to post
Share on other sites
Advertisement
First of all, copy the exact error, but not after finding out on which line exactly it occurs. Second of all, do something about your spelling.

This is just friendly advice so you get more chance on a more useful answer.

Share this post


Link to post
Share on other sites
Quote:
Original post by Subotron
First of all, copy the exact error, but not after finding out on which line exactly it occurs. Second of all, do something about your spelling.

This is just friendly advice so you get more chance on a more useful answer.



it says... file: dbgheap.c
line: 346

and yea.. ill work on my spelling...

Share this post


Link to post
Share on other sites
The error sounds like you are trying to access a null pointer or write to invalid memory. Does it crash when you load or when you draw the file? Can you run the application in debug mode and find the exact line that causes the exception? That will make it much easier to work out the cause.

Share this post


Link to post
Share on other sites
Quote:
Original post by weasalmongler
The error sounds like you are trying to access a null pointer or write to invalid memory. Does it crash when you load or when you draw the file? Can you run the application in debug mode and find the exact line that causes the exception? That will make it much easier to work out the cause.


its when loading the file.. i cant get the line... i get a new window with the error and then the program shuts down.. i dont get any line where the error occurred even in debug mode...

im troubleshooting now and trying to find about where in the load sequence it crashes...

Share this post


Link to post
Share on other sites
this is what ive got...

Load->MainChunkProcessor->EditChunkProcessor->ObjectChunkProcessor->TriangularMeshChunkProcessor->

VertexListChunkProcessor (however i get the error after closing the program when i disable this one)

thats as far as i get right now...

Share this post


Link to post
Share on other sites
If it is crashing in VertexListChunkProcessor then make sure that objindex always remains in a valid range for the number of objects actually created. In the debugger set breakpoints in a few places and examine what the values of different variables are, make sure they are all correct. The code you've posted is quite long and is difficult to debug without running it.

Share this post


Link to post
Share on other sites
well as far as ive been able to debug the problems seems to occur here..

Objects[objindex].Vertexes = new GLfloat[numVerts * 3];
Objects[objindex].Normals = new GLfloat[numVerts * 3];
Objects[objindex].Tangents = new GLfloat[numVerts * 3];

but i dont understand how...

anyways.. im giving up on this... ive tried for a few hours now... but i dont think im good enough to be able to solve this problem..

ill have to search around for another loader...

thx alot for the help anyway...

Share this post


Link to post
Share on other sites
I'm sure that the problem is that your objindex does not lie in the [0, numObjects-1] range. That would lead to the program trying to write to invalid memory and cause the crash. You just need to work out why objindex isn't the right value.

Sorry to hear you're giving up. Best of luck with it in future.

Share this post


Link to post
Share on other sites
well on second thought.. if i give up with this i have to give up with 3d programming.. .since this is an important part...

so the hell with it.. ill write my own loader...

ive just begun with it but ive alrdy encountered a problem.. the model doesnt draw properly... im just trying to load a simple box and draw its polygons.. but it gets messed up... i just get to planes facing each other.. they are not connected for some reason

i hope its not to much code to read through.. i have no idea what could be wrong

EDIT:::

i seem to have solved it...

which brings me to the next question.. wher can i find some documentation on more advanced loading? models consisting of several objects... loading the texturenames (diffusemap, bumpmap etc...)..

[Edited by - Dragon_Strike on May 17, 2007 12:19:45 PM]

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!