Thread: milkshape 3d, need someone who knows it well

  1. #1
    Software Developer jverkoey's Avatar
    Join Date
    Feb 2003
    Location
    New York
    Posts
    1,905

    milkshape 3d, need someone who knows it well

    ooook, I used the code from nehe's game tutorials for loading MS3D files, this is my MS3D header:

    Code:
    typedef struct MS3D_HEADER_TYP
    {
       	char id[10];
    	int  version;
    } MS3D_HEADER, *MS3D_HEADER_PTR;
    
    typedef struct MS3D_VERTEX_TYP
    {
    	unsigned char flags;
    	unsigned char refCount;
    	char boneID;
    	float vertex[3];
    } MS3D_VERTEX, *MS3D_VERTEX_PTR;
    
    typedef struct MS3D_TRIANGLE_TYP
    {
    	unsigned short flags;
    	unsigned short vertexIndices[3];
    	float vertexNormals[3][3];
    	float u[3];
    	float v[3];
    	unsigned char smoothingGroup;
    	unsigned char groupIndex;
    } MS3D_TRIANGLE, *MS3D_TRIANGLE_PTR;
    
    typedef struct MS3D_GROUP_TYP
    {
       	unsigned char	flags;
       	char name[32];
       	unsigned short	numTriangles;
    	unsigned short*	triangleIndices;
    	char materialIndex;
    } MS3D_GROUP, *MS3D_GROUP_PTR;
    
    class MS3D
    {
    public:
    	unsigned short	numVertices;
    	MS3D_VERTEX*	vertices;
    	unsigned short	numTriangles;
    	MS3D_TRIANGLE*	triangles;
    	unsigned short	numGroups;
    	MS3D_GROUP*	groups;
    	
    	bool Load(char* filename);
    	void Render();
    	
    	MS3D()
    	{}
    	
    	~MS3D()
    	{	
    		if(vertices)
    			delete vertices;		
    		if(triangles)
    			delete triangles;
    		if(groups)
    			delete groups;
    	}
    };
    
    bool MS3D::Load(char* filename)
    {
    	FILE* file;
    	MS3D_HEADER header;
    	int loop;
    	
    	if((file= fopen(filename, "rb"))==NULL)
    	{
    		// error message goes here
    		return false;
    	}
    	
    	fread(&header.id, sizeof(char), 10, file);
    	fread(&header.version, 1, sizeof(int), file);
    	if(strncmp(header.id, "MS3D000000", 10)!=0)
    	{
    		// error message goes here
    		return false;
    	}
    	
    	if(header.version!=3 && header.version!=4)
    	{
    		// error message goes here
    		return false;
    	}
    	
    	fread(&numVertices, sizeof(unsigned short), 1, file);
    	vertices= new MS3D_VERTEX [numVertices];
    	for(loop=0; loop<numVertices; loop++)
    	{
    		fread(&vertices[loop].flags,	sizeof(BYTE),  1, file);
    		fread( vertices[loop].vertex,	sizeof(float), 3, file);
    		fread(&vertices[loop].boneID,	sizeof(char),  1, file);
    		fread(&vertices[loop].refCount, sizeof(BYTE),  1, file);
    	}
    	
    	fread(&numTriangles, sizeof(unsigned short), 1, file);
    	triangles= new MS3D_TRIANGLE [numTriangles];
    	for(loop=0; loop<numTriangles; loop++)
    	{
    		fread(&triangles[loop].flags,		sizeof(unsigned short), 1, file);
    		fread( triangles[loop].vertexIndices,	sizeof(unsigned short), 3, file);
    		fread( triangles[loop].vertexNormals[0],sizeof(float),		3, file);
    		fread( triangles[loop].vertexNormals[1],sizeof(float),	 	3, file);
    		fread( triangles[loop].vertexNormals[2],sizeof(float),		3, file);
    		fread( triangles[loop].u,		sizeof(float),		3, file);
    		fread( triangles[loop].v,		sizeof(float),		3, file);
    		fread(&triangles[loop].smoothingGroup,	sizeof(unsigned char),	1, file);
    		fread(&triangles[loop].groupIndex,	sizeof(unsigned char),	1, file);
    	}
    	
    	fread(&numGroups, sizeof(unsigned short), 1, file);
    	groups= new MS3D_GROUP [numGroups];
    	for(loop=0; loop<numGroups; loop++)
    	{
    		fread(&groups[loop].flags,	 sizeof(unsigned char),	1,  file);
    		fread( groups[loop].name,	 sizeof(char),		32, file);
    		fread(&groups[loop].numTriangles,sizeof(unsigned short),1,  file);
    		
    		groups[loop].triangleIndices=new unsigned short [groups[loop].numTriangles];
    		
    		fread( groups[loop].triangleIndices, sizeof(unsigned short), groups[loop].numTriangles,file);
    		fread(&groups[loop].materialIndex,   sizeof(char), 1, file);
    	}
    
    	// error message goes here
    	return true;
    }
    
    void MS3D::Render()
    {
    	// Draw By Group
    	for(int loop1=0; loop1<numGroups; loop1++ )
    	{
    		// Draw As Regular Triangles, Since .MS3D's Aren't Optimized Like .MD2's
    		glBegin(GL_TRIANGLES);
    		for(int loop2=0; loop2<groups[loop1].numTriangles; loop2++)
    		{
    			int triangleIndex       =  groups[loop1].triangleIndices[loop2];
    			const MS3D_TRIANGLE* tri= &triangles[triangleIndex];
    			
    			// Loop Through The Triangle's Vertices, And Output Them!
    			for(int loop3=0; loop3<3; loop3++)
    			{
    				int index= tri->vertexIndices[loop3];
    				glNormal3fv( tri->vertexNormals[loop3]);
    				glTexCoord2f(tri->u[loop3], tri->v[loop3]);
    				glVertex3fv(vertices[index].vertex);
    			}
    		}
    		glEnd();
    	}
    }
    and that code successfully loads up an ms3d file, and displays it, by creating each object, ex: MS3D ship; and etc....

    now, what I need to be able to do, is load the ms3d file, but then allow the program to automatically load the bmps....but I don't know how to look at the bmps that are saved to it, so I can't exactly do that.....

    I don't want to have to preload everything, because that wont' give any functionality to my 3d artists, because I want them to be able to develop a file in ms3d, save it, and load it right in to the exe and not have to recompile anything........

    what I need is some easy code and a decent walkthrough of where to put everything that I'd need. the rest of my code for the program uses nehe.gamedev.net's bmp loader and that's pretty much it, so what I have is a function that loads the textures, but I could create another bmp texture loader for the ms3d header file, if it won't work any other way.......

    soo, in essense, i need to be able to load an ms3d, and its textures and be able to display it without having to recompile....
    really all i need is what the header files look like that have the file names..because I evidently have the wrong type of header file.....

  2. #2
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    Everything is in the milkshape 3d file itself, you only need to find the texture name of the bitmap, and pass it into any bitmap loading routine, nehe's should work fine. the bitmap must have dimensions of a power of two. I guess I don't completely understand what your problem is. I did everything exactly the same as brett porter from nehe (wrote it all myself but turned out more or less the same)

    aim me on CarlosTheJackass for help

    EDIT:

    I just got done taking testing in school. I really want to help you with this because I've done it all before and I know what's going on (ms3d is a pretty simple format)

    you've pretty much got everything correctly, but I don't see a 'gluint' or the equivalent in any of your structures. opengl refers to textures using a gluint, therefore you need to have a GLuint (or a datatype that is exactly the same size) to represent your texture. I'll show you my model class, and how it loads the texture

    Code:
    class Model {
    public:
    	Model();	
    	~Model();
    	//LOADING METHODS
    	//DATA STRUCTURES
    
    	struct vertex {
    		char mID[10];	//THIS TO BE USED FOR ANIMATIONS, DOESN'T GET USED QUITE YET
    		float mCoord[3];	//COORDINATE OF THIS VERTEX, YOU CAN CALL WITH GLVERTEX3FV
    	};
    	int mNumVerts;
    	vertex *mpVertices;	//THIS IS THE 'HEAP' OF VERTICES, THE VERTEX INDICES IN TRIANGLE REFERENCE WHICH TO BE USED
    	
    	struct triangle {
    		int mVertexIndices[3];	//INDEX INTO HEAP OF VERTICES TO BE USED FOR EACH TRIANGLE
    		float m_s[3], m_t[3];	//TEXTURE COORDINATES FOR EACH TRIANGLE
    		float mVertexNormals[3][3];	//NORMAL VECTOR FOR EACH VERTEX
    	};
    	int mNumTris;
    	triangle *mpTriangles;	//THIS IS THE HEAP OF TRIANGLES THAT WILL BE CREATED AND REFERENCED TO IN THE MESHES
    
    	struct mesh {
    		int materialindex;	//WHICH MATERIAL TO USE ON THE HEAP OF MATERIALS
    		int mNumTriangles;	//USED WHEN DRAWING, LOOP THROUGH THIS NUMBER AND DRAW
    		int *TriangleIndices;  
    	};
    	int mNumMeshes;
    	mesh *mpMeshes;	//HEAP OF MESHES
    
    	struct material {
    		float mAmbient[4], mDiffuse[4], mSpecular[4], mEmissive[4];	//MATERIAL PROPERTIES OF OBJECT
    		GLuint mTexture;	//ID FOR THE TEXTURE OF THE MATERIAL
    		char   *mTexFilename;	//FILENAME OF THE TEXTURE BEING WRAPPED AROUND OBJECT
    		float mShininess;	//AGAIN NOT SURE WHAT THIS IS FOR
    	};
    
    	int mNumMaterials;
    	material *mpMaterials;	//OUR HEAP OF MATERIALS
    
    
    	bool LoadModel(char *);
    	void Draw();
    	private:
    	bool LoadTextures();	//LOAD THE TEXTURES, THE MATERIAL IS WHAT ACTUALLY GETS THE FILE NAME
    	AUX_RGBImageRec	*LoadBMP(char*);
    	GLuint	LoadGLTextures(char*);
    };
    as you see there is a GLuint datatype and then there is a function which returns a GLuint.

    the actual implementation is as follows:

    Code:
    AUX_RGBImageRec * LoadBMP(char *FileName) {
    	FILE	*pFile = NULL;
    	if(!FileName)
    		return NULL;
    	pFile = fopen(FileName, "r");
    
    	if(pFile) {
    		fclose(pFile);
    		return auxDIBImageLoad(FileName);
    	}
    return NULL;
    
    }
    
    GLuint	LoadGLTextures(char *FileName) {
    	AUX_RGBImageRec	*pImage;
    	GLuint texture = 0;	//OUR TEMPORARY TEXTURE ID THINGAMABOB
    	pImage = LoadBMP(FileName);
    	if(pImage != NULL && pImage->data != NULL) {
    		glGenTextures(1, &texture);	//GENERATE ONE TEXTURE STORING IT AT THE TEXTURE ID OBJECT THINGAMABOB
    		glBindTexture(GL_TEXTURE_2D, texture);	//BINDS THE TEXTURE TO GL_TEXTURE_2D
    		glTexImage2D(GL_TEXTURE_2D, 0, 4, pImage->sizeX, pImage->sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, pImage->data);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    		glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    		free(pImage->data);
    		free(pImage);
    		return texture;
    	}
     
    		return NULL;
    }
    Ok that might have helped, but again i wasn't 100% sure what your problem was exactly. I always have the textures saved in the same directory as the model itself.

    EDIT: it has been a few months since I did this, but I think it's almost exactly the same as neHe's, so if I don't explain this articulately enough you can try going to Nehe and looking for an explanation there.

    EDIT:
    and then the last thing in the loading function:

    Code:
    if(!LoadTextures())
    MessageBox(NULL, "COULD NOT LOAD ALL TEXTURES", "ERROR", MB_OK);
    LoadTextures calls LoadGLTextures which calls LoadBMP. the 'actual' routine that loads the BMP is in the auxDIBImageFile() function
    Last edited by Silvercord; 03-06-2003 at 10:39 AM.

  3. #3
    Software Developer jverkoey's Avatar
    Join Date
    Feb 2003
    Location
    New York
    Posts
    1,905
    oookay, now how would i actually load up the structure for the textures? i don't want to know how to load the actual textures yet, i can figure that out once i learn how to actually know what's in the file, lol

    my code looks like this so far, for the loading part....

    Code:
    bool MS3D::Load(char* filename)
    {
    	FILE* file;
    	MS3D_HEADER header;
    	int loop;
    	
    	if((file= fopen(filename, "rb"))==NULL)
    	{
    		// error message goes here
    		return false;
    	}
    	
    	fread(&header.id, sizeof(char), 10, file);
    	fread(&header.version, 1, sizeof(int), file);
    	if(strncmp(header.id, "MS3D000000", 10)!=0)
    	{
    		// error message goes here
    		return false;
    	}
    	
    	if(header.version!=3 && header.version!=4)
    	{
    		// error message goes here
    		return false;
    	}
    	
    	fread(&numVertices, sizeof(unsigned short), 1, file);
    	vertices= new MS3D_VERTEX [numVertices];
    	for(loop=0; loop<numVertices; loop++)
    	{
    		fread(&vertices[loop].flags,	sizeof(BYTE),  1, file);
    		fread( vertices[loop].vertex,	sizeof(float), 3, file);
    		fread(&vertices[loop].boneID,	sizeof(char),  1, file);
    		fread(&vertices[loop].refCount, sizeof(BYTE),  1, file);
    	}
    	
    	fread(&numTriangles, sizeof(unsigned short), 1, file);
    	triangles= new MS3D_TRIANGLE [numTriangles];
    	for(loop=0; loop<numTriangles; loop++)
    	{
    		fread(&triangles[loop].flags,		sizeof(unsigned short), 1, file);
    		fread( triangles[loop].vertexIndices,	sizeof(unsigned short), 3, file);
    		fread( triangles[loop].vertexNormals[0],sizeof(float),		3, file);
    		fread( triangles[loop].vertexNormals[1],sizeof(float),	 	3, file);
    		fread( triangles[loop].vertexNormals[2],sizeof(float),		3, file);
    		fread( triangles[loop].u,		sizeof(float),		3, file);
    		fread( triangles[loop].v,		sizeof(float),		3, file);
    		fread(&triangles[loop].smoothingGroup,	sizeof(unsigned char),	1, file);
    		fread(&triangles[loop].groupIndex,	sizeof(unsigned char),	1, file);
    	}
    	
    	fread(&numGroups, sizeof(unsigned short), 1, file);
    	groups= new MS3D_GROUP [numGroups];
    	for(loop=0; loop<numGroups; loop++)
    	{
    		fread(&groups[loop].flags,	 sizeof(unsigned char),	1,  file);
    		fread( groups[loop].name,	 sizeof(char),		32, file);
    		fread(&groups[loop].numTriangles,sizeof(unsigned short),1,  file);
    		
    		groups[loop].triangleIndices=new unsigned short [groups[loop].numTriangles];
    		
    		fread( groups[loop].triangleIndices, sizeof(unsigned short), groups[loop].numTriangles,file);
    		fread(&groups[loop].materialIndex,   sizeof(char), 1, file);
    	}
    
    	fread(&mNumMaterials, sizeof(unsigned short), 1, file);
    	mpMaterials= new MS3D_MATERIAL [mNumMaterials];
    	for(loop=0; loop<mNumMaterials; loop++)
    	{
    		fread( mpMaterials[loop].mAmbient, sizeof(float), 4, file);
    		fread( mpMaterials[loop].mDiffuse, sizeof(float), 4, file);
    		fread( mpMaterials[loop].mSpecular, sizeof(float), 4, file);
    		fread( mpMaterials[loop].mEmissive, sizeof(float), 4, file);
    
    		fread(&mpMaterials[loop].mTexture, sizeof(GLuint), 1, file);
    
    		fread( mpMaterials[loop].mTexFilename, sizeof(char), 30, file);
    
    		fread(&mpMaterials[loop].mShininess, sizeof(float), 1, file);
    	}
    
    	// error message goes here
    	return true;
    }
    if loads without crashing, and I can tell how many textures there are, but i can't tell the file name or anything else that's actually in the structures.........i just pretty much copy/pasted the structure you used for the textures:

    Code:
    struct MS3D_MATERIAL
    {
    	float mAmbient[4], mDiffuse[4], mSpecular[4], mEmissive[4];	//MATERIAL PROPERTIES OF OBJECT
    	GLuint mTexture;	//ID FOR THE TEXTURE OF THE MATERIAL
    	char   mTexFilename[30];	//FILENAME OF THE TEXTURE BEING WRAPPED AROUND OBJECT
    	float mShininess;	//AGAIN NOT SURE WHAT THIS IS FOR
    };
    and i added the [30] on the filename, because there's no way to just "know" how to dynamically size the char variable as you're loading it, as far as I know..............

    what I want to be able to do is load up the ms3d file, and be able to look in the texture header thing, see what each filename is, and then load 'em...........but i don't know how

  4. #4
    Software Developer jverkoey's Avatar
    Join Date
    Feb 2003
    Location
    New York
    Posts
    1,905
    da$*it, i just figured out that all i had to do was reorder the way i loaded it all, lmao, still checkin' for bugs though........

    -edit, ok, that didn't work at all, it only loads the first texture's name, not its filename.....and the whole purpose of this was for me to be able to find the filename, and then be able to LOAD the texture from looking at that filename.........
    Last edited by jverkoey; 03-06-2003 at 06:10 PM.

  5. #5
    Banned
    Join Date
    Jan 2003
    Posts
    1,708
    I'm not sure what the problem is. You read the texture filename and pass it to a function. Something I noticed, but may not be the only thing wrong:

    What you have:

    char mTexFilename[30];

    What is in the MS3D file:

    char m_texture[128];

    This means there is 128bytes just for the filename, but you are only reading 30. This throws off the offsets into the file, because fread always iterates to the next position in the file.
    just try changing to this:
    char mTexFilename[128];
    fread( mpMaterials[loop].mTexFilename, sizeof(char), 128, file);

    again I really want to help you with this because I took the time to get to know this format pretty well. I feel bad though because the way I wrote it ends up looking exactly like brett porters. I should've wrote it the way you did so people might actually believe I wrote it myself...either that or I'll put it into a dll to try to hide it or something
    Last edited by Silvercord; 03-06-2003 at 08:01 PM.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. 3d graphics without API
    By h3ro in forum Game Programming
    Replies: 6
    Last Post: 05-31-2008, 11:51 AM
  2. 3D Network Analysis Tool
    By durban in forum Projects and Job Recruitment
    Replies: 1
    Last Post: 11-08-2005, 06:33 PM
  3. 3D starfield
    By VirtualAce in forum Game Programming
    Replies: 6
    Last Post: 06-26-2003, 12:40 PM
  4. 3D SDK for C++ programmers
    By chand in forum Game Programming
    Replies: 2
    Last Post: 05-20-2003, 07:38 AM
  5. 3d engines
    By Unregistered in forum Game Programming
    Replies: 7
    Last Post: 12-17-2001, 11:19 AM