Problems with MD3 loader

Discuss programming topics for the various GPL'd game engine sources.
Post Reply
drm_wayne
Posts: 232
Joined: Sat Feb 11, 2012 5:47 pm

Problems with MD3 loader

Post by drm_wayne »

I have some trouble with my MD3 loader (based on Qracks MD3 loader)..
I added a code to dump the normals to a external file (because they take kinda long to load), but it looks like theres something wrong.
Its just crashing when it comes to dump the md3 normalfile.
Can anybody see whats wrong?

Code: Select all

/*
=================
Mod_LoadQ3Model
=================
*/
void Mod_LoadQ3AliasModel (model_t *mod, void *buffer)
{
	int				i, j, size, base, texture_flag, version, gl_texnum;
	char			basename[MAX_QPATH];
	float			radiusmax;
	md3header_t		*header;
	md3frame_t		*frame;
	md3tag_t		*tag;
	md3surface_t	*surf;
	md3shader_t		*shader;
	md3triangle_t	*tris;
	md3tc_t			*tc;
	md3vert_t		*vert;
	char			md3name[128];

	COM_StripExtension(mod->name, &md3name[0]);

	if (!strcmp (md3name, "progs/g_shot") ||
		!strcmp (md3name, "progs/g_nail") ||
		!strcmp (md3name, "progs/g_nail2") ||
		!strcmp (md3name, "progs/g_rock") ||
		!strcmp (md3name, "progs/g_rock2") ||
		!strcmp (md3name, "progs/g_light") ||
		!strcmp (md3name, "progs/armor") ||
		!strcmp (md3name, "progs/backpack") ||
		!strcmp (md3name, "progs/w_g_key") ||
		!strcmp (md3name, "progs/w_s_key") ||
		!strcmp (md3name, "progs/m_g_key") ||
		!strcmp (md3name, "progs/m_s_key") ||
		!strcmp (md3name, "progs/b_g_key") ||
		!strcmp (md3name, "progs/b_s_key") ||
		!strcmp (md3name, "progs/quaddama") ||
		!strcmp (md3name, "progs/invisibl") ||
		!strcmp (md3name, "progs/invulner") ||
		!strcmp (md3name, "progs/jetpack") ||
		!strcmp (md3name, "progs/cube") ||
		!strcmp (md3name, "progs/suit") ||
		!strcmp (md3name, "progs/boots") ||
		!strcmp (md3name, "progs/end1") ||
		!strcmp (md3name, "progs/end2") ||
		!strcmp (md3name, "progs/end3") ||
		!strcmp (md3name, "progs/end4")) {
		mod->flags |= EF_ROTATE;
	}
	else if (!strcmp (md3name, "progs/missile"))
	{
		mod->flags |= EF_ROCKET;
	}
	else if (!strcmp (md3name, "progs/gib1") || //EF_GIB
		!strcmp (md3name, "progs/gib2") ||
		!strcmp (md3name, "progs/gib3") ||
		!strcmp (md3name, "progs/h_player") ||
		!strcmp (md3name, "progs/h_dog") ||
		!strcmp (md3name, "progs/h_mega") ||
		!strcmp (md3name, "progs/h_guard") ||
		!strcmp (md3name, "progs/h_wizard") ||
		!strcmp (md3name, "progs/h_knight") ||
		!strcmp (md3name, "progs/h_hellkn") ||
		!strcmp (md3name, "progs/h_zombie") ||
		!strcmp (md3name, "progs/h_shams") ||
		!strcmp (md3name, "progs/h_shal") ||
		!strcmp (md3name, "progs/h_ogre") ||
		!strcmp (md3name, "progs/armor") ||
		!strcmp (md3name, "progs/h_demon")) {
		mod->flags |= EF_GIB;
	}
	else if (!strcmp (md3name, "progs/grenade"))
	{
		mod->flags |= EF_GRENADE;
	}
	else if (!strcmp (md3name, "progs/w_spike"))
	{
		mod->flags |= EF_TRACER;
	}
	else if (!strcmp (md3name, "progs/k_spike"))
	{
		mod->flags |= EF_TRACER2;
	}
	else if (!strcmp (md3name, "progs/v_spike"))
	{
		mod->flags |= EF_TRACER3;
	}
	else if (!strcmp (md3name, "progs/zom_gib"))
	{
		mod->flags |= EF_ZOMGIB;
	}
	else if (!strcmp(md3name, "progs/v_shot")	||
		!strcmp(md3name, "progs/v_shot2")	||
		!strcmp(md3name, "progs/v_nail")	||
		!strcmp(md3name, "progs/v_nail2")	||
		!strcmp(md3name, "progs/v_rock")	||
		!strcmp(md3name, "progs/v_rock2"))
		{
			mod->modhint = MOD_WEAPON;
		}

	else if (!strcmp (md3name, "progs/lavaball"))
	{
		mod->modhint = MOD_LAVABALL;
	}

	header = (md3header_t *)buffer;

	version = LittleLong (header->version);
	if (version != MD3_VERSION)
		Sys_Error ("Mod_LoadQ3Model: %s has wrong version number (%i should be %i)", md3name, version, MD3_VERSION);
		
	Con_Printf ("Loading md3 model...%s \n", md3name);		

// endian-adjust all data
	header->numframes = LittleLong (header->numframes);

	if (header->numframes < 1)
		Sys_Error ("Mod_LoadQ3Model: model %s has no frames", md3name);
	else if (header->numframes > MAXMD3FRAMES)
		Sys_Error ("Mod_LoadQ3Model: model %s has too many frames", md3name);

	header->numtags = LittleLong (header->numtags);
	if (header->numtags > MAXMD3TAGS)
		Sys_Error ("Mod_LoadQ3Model: model %s has too many tags", md3name);

	header->numsurfs = LittleLong (header->numsurfs);
	if (header->numsurfs < 1)
		Sys_Error ("Mod_LoadQ3Model: model %s has no surfaces", md3name);
	else if (header->numsurfs > MAXMD3SURFS)
		Sys_Error ("Mod_LoadQ3Model: model %s has too many surfaces", md3name);

	header->numskins = LittleLong (header->numskins);
	header->ofsframes = LittleLong (header->ofsframes);
	header->ofstags = LittleLong (header->ofstags);
	header->ofssurfs = LittleLong (header->ofssurfs);
	header->ofsend = LittleLong (header->ofsend);

	// swap all the frames
	frame = (md3frame_t *)((byte *)header + header->ofsframes);
	for (i=0 ; i<header->numframes ; i++)
	{
		frame[i].radius = LittleFloat (frame->radius);
		for (j=0 ; j<3 ; j++)
		{
			frame[i].mins[j] = LittleFloat (frame[i].mins[j]);
			frame[i].maxs[j] = LittleFloat (frame[i].maxs[j]);
			frame[i].pos[j] = LittleFloat (frame[i].pos[j]);
		}
	}

	// swap all the tags
	tag = (md3tag_t *)((byte *)header + header->ofstags);
	for (i=0 ; i<header->numtags ; i++)
	{
		for (j=0 ; j<3 ; j++)
		{
			tag[i].pos[j] = LittleFloat (tag[i].pos[j]);
			tag[i].rot[0][j] = LittleFloat (tag[i].rot[0][j]);
			tag[i].rot[1][j] = LittleFloat (tag[i].rot[1][j]);
			tag[i].rot[2][j] = LittleFloat (tag[i].rot[2][j]);
		}
	}

	// swap all the surfaces
	surf = (md3surface_t *)((byte *)header + header->ofssurfs);
	for (i=0 ; i<header->numsurfs ; i++)
	{
		surf->ident = LittleLong (surf->ident);
		surf->flags = LittleLong (surf->flags);
		surf->numframes = LittleLong (surf->numframes);
		if (surf->numframes != header->numframes)
			Sys_Error ("Mod_LoadQ3Model: number of frames don't match in %s", md3name);

		surf->numshaders = LittleLong (surf->numshaders);
		if (surf->numshaders <= 0)
			Sys_Error ("Mod_LoadQ3Model: model %s has no shaders", md3name);
		else if (surf->numshaders > MAXMD3SHADERS)
			Sys_Error ("Mod_LoadQ3Model: model %s has too many shaders", md3name);

		surf->numverts = LittleLong (surf->numverts);
		if (surf->numverts <= 0)
			Sys_Error ("Mod_LoadQ3Model: model %s has no vertices", md3name);
		else if (surf->numverts > MAXMD3VERTS)
			Sys_Error ("Mod_LoadQ3Model: model %s has too many vertices", md3name);

		surf->numtris = LittleLong (surf->numtris);
		if (surf->numtris <= 0)
			Sys_Error ("Mod_LoadQ3Model: model %s has no triangles", md3name);
		else if (surf->numtris > MAXMD3TRIS)
			Sys_Error ("Mod_LoadQ3Model: model %s has too many triangles", md3name);

		surf->ofstris = LittleLong (surf->ofstris);
		surf->ofsshaders = LittleLong (surf->ofsshaders);
		surf->ofstc = LittleLong (surf->ofstc);
		surf->ofsverts = LittleLong (surf->ofsverts);
		surf->ofsend = LittleLong (surf->ofsend);

		// swap all the shaders
		shader = (md3shader_t *)((byte *)surf + surf->ofsshaders);
		for (j=0 ; j<surf->numshaders ; j++)
			shader[j].index = LittleLong (shader[j].index);

		// swap all the triangles
		tris = (md3triangle_t *)((byte *)surf + surf->ofstris);
		for (j=0 ; j<surf->numtris ; j++)
		{
			tris[j].indexes[0] = LittleLong (tris[j].indexes[0]);
			tris[j].indexes[1] = LittleLong (tris[j].indexes[1]);
			tris[j].indexes[2] = LittleLong (tris[j].indexes[2]);
		}

		// swap all the texture coords
		tc = (md3tc_t *)((byte *)surf + surf->ofstc);
		for (j=0 ; j<surf->numverts ; j++)
		{
			tc[j].s = LittleFloat (tc[j].s);
			tc[j].t = LittleFloat (tc[j].t);
		}
		// swap all the vertices
		vert = (md3vert_t *)((byte *)surf + surf->ofsverts);
		for (j=0 ; j < surf->numverts * surf->numframes ; j++)
		{
			vert[j].vec[0] = LittleShort (vert[j].vec[0]);
			vert[j].vec[1] = LittleShort (vert[j].vec[1]);
			vert[j].vec[2] = LittleShort (vert[j].vec[2]);
			vert[j].normal = LittleShort (vert[j].normal);
		}
		// find the next surface
		surf = (md3surface_t *)((byte *)surf + surf->ofsend);
	}

// allocate extra size for structures different in memory
	surf = (md3surface_t *)((byte *)header + header->ofssurfs);
	for (size = 0, i = 0 ; i < header->numsurfs ; i++)
	{
		size += surf->numshaders * sizeof(md3shader_mem_t);		  // shader containing texnum
		size += surf->numverts * surf->numframes * sizeof(md3vert_mem_t); // floating point vertices
		surf = (md3surface_t *)((byte *)surf + surf->ofsend);
	}
	header = static_cast<md3header_t*>(Cache_Alloc (&mod->cache, com_filesize + size, loadname));
	if (!mod->cache.data)
		return;

	memcpy (header, buffer, com_filesize);
	base = com_filesize;

	mod->type = mod_md3;
	mod->numframes = header->numframes;

	md3bboxmins[0] = md3bboxmins[1] = md3bboxmins[2] = 99999;
	md3bboxmaxs[0] = md3bboxmaxs[1] = md3bboxmaxs[2] = -99999;
	radiusmax = 0;

	frame = (md3frame_t *)((byte *)header + header->ofsframes);
	for (i=0 ; i<header->numframes ; i++)
	{
		for (j=0 ; j<3 ; j++)
		{
			md3bboxmins[j] = min(md3bboxmins[j], frame[i].mins[j]);
			md3bboxmaxs[j] = max(md3bboxmaxs[j], frame[i].maxs[j]);
		}
		radiusmax = max(radiusmax, frame[i].radius);
	}
	VectorCopy (md3bboxmins, mod->mins);
	VectorCopy (md3bboxmaxs, mod->maxs);
	mod->radius = radiusmax;

// load the skins
	Mod_LoadAllQ3Skins (mod->name, header);

// load the animation frames if loading the player model
	if (!strcmp(mod->name, "progs/player/lower.md3"))
		Mod_LoadQ3Animation ();

	surf = (md3surface_t *)((byte *)header + header->ofssurfs);

	for (i=0 ; i<header->numsurfs; i++)
	{
		shader = (md3shader_t *)((byte *)surf + surf->ofsshaders);
		surf->ofsshaders = base;
		size = surf->numshaders;
		for (j=0 ; j<size ; j++)
		{
			md3shader_mem_t	*memshader = (md3shader_mem_t *)((byte *)header + surf->ofsshaders);

			Q_strncpyz (memshader[j].name, shader->name, sizeof(memshader[j].name));
			memshader[j].index = shader->index;

			COM_StripExtension (COM_SkipPath(shader->name), basename);

			gl_texnum = 0;
            texture_flag = 0;
			Mod_LoadQ3ModelTexture (basename, texture_flag, &gl_texnum);
			memshader[j].gl_texnum = gl_texnum;

			shader++;
		}
		base += size * sizeof(md3shader_mem_t);

		vert = (md3vert_t *)((byte *)surf + surf->ofsverts);
		surf->ofsverts = base;
		size = surf->numverts * surf->numframes;
		
		//It takes a fucking _YEAR_ to calculate normals.
		//We'll store them in a cache file for future use if it's not already available.
		FILE* md3normalfile;
		md3normalfile = fopen(va("%s_%d.nrm", md3name, i), "rb");
		Con_DPrintf ("Looking for MD3 normalfile\n");		
		if (!md3normalfile) 
		{
			//Output 'em.
			
			md3normalfile = fopen(va("%s_%d.nrm", md3name, i), "wb");
			
			short* normalBuffer, ptr;
			normalBuffer = (short*)malloc(sizeof(short)*size*5 + 1);
			ptr = *normalBuffer;
		
			for (j=0 ; j<size ; j++)
			{
				float		lat, lng;
				vec3_t		ang;
				md3vert_mem_t	*vertexes = (md3vert_mem_t *)((byte *)header + surf->ofsverts);

				vertexes[j].oldnormal = vert->normal;

				vertexes[j].vec[0] = (float)vert->vec[0] * MD3_XYZ_SCALE;
				vertexes[j].vec[1] = (float)vert->vec[1] * MD3_XYZ_SCALE;
				vertexes[j].vec[2] = (float)vert->vec[2] * MD3_XYZ_SCALE;

				lat = ((vert->normal >> 8) & 0xff) * M_PI / 128.0f;
				lng = (vert->normal & 0xff) * M_PI / 128.0f;
				vertexes[j].normal[0] = cos(lat) * sin(lng);
				vertexes[j].normal[1] = sin(lat) * sin(lng);
				vertexes[j].normal[2] = cos(lng);

				vectoangles (vertexes[j].normal, ang);
				vertexes[j].anorm_pitch = ang[0] * 256 / 360;
				vertexes[j].anorm_yaw = ang[1] * 256 / 360;
				
				ptr = (short) vertexes[j].normal[0];
				ptr++;
				ptr = (short) vertexes[j].normal[1];
				ptr++;
				ptr = (short) vertexes[j].normal[2];
				ptr++;
				ptr = (short) vertexes[j].anorm_pitch;
				ptr++;
				ptr = (short) vertexes[j].anorm_yaw;
				ptr++;

				vert++;
			}
			fwrite(normalBuffer, 2, size*5, md3normalfile);
			Con_DPrintf ("Writing MD3 Normal File.\n");			
			fclose(md3normalfile);
			
			free(normalBuffer);
			ptr = NULL;
		}
		
		base += size * sizeof(md3vert_mem_t);
		
		surf = (md3surface_t *)((byte *)surf + surf->ofsend);
		
	}	
}

Baker
Posts: 3666
Joined: Tue Mar 14, 2006 5:15 am

Re: Problems with MD3 loader

Post by Baker »

drm_wayne wrote:Its just crashing when it comes to dump the md3 normalfile.
1) What line is it crashing on?
2) Offtopic: Is this C or C++ ? I would assume C++. Was that your intent? i.e. "static_cast<md3header_t*>" instead of C "(md3header_t *)"
3) A raw write of a buffer to disk? Not really good practice, although maybe not related to your problem. And a different topic.
4) Ok ...
short* normalBuffer, ptr;
normalBuffer = (short*)malloc(sizeof(short)*size*5 + 1);
ptr = *normalBuffer; <---------------------- WHAT?
normalBuffer is a pointer to short. ptr is a pointer to short. I take it normalBuffer is supposed to be an array of shorts.

Any time you see *normalBuffer think of it as normalBuffer[0] or the first element of your array. Normal buffer holds shorts, right? A value of -32768 to + 32767

So ptr = *normalBuffer is going to assign ptr to memory address of -32768 to + 32767. Certainly invalid.

You need ptr=normalBuffer; for starters. You aren't trying to assign ptr to the value of the first member of normalBuffer (*normalBuffer or normalBuffer[0]), but the address of the first member of normalBuffer (which is simply ptr = normalBuffer or as I think of it in my head ... &normalBuffer[0] ).
The night is young. How else can I annoy the world before sunsrise? 8) Inquisitive minds want to know ! And if they don't -- well like that ever has stopped me before ..
drm_wayne
Posts: 232
Joined: Sat Feb 11, 2012 5:47 pm

Re: Problems with MD3 loader

Post by drm_wayne »

hmm i see i tried to make something that is way above my poor coding skills..
The original code is from Qrack, and it takes too long to load MD3 models when its on to calculate the normals
(In time, you can get married, buy a house, get 2 children and choose a grave stone.) :lol:

I wodner if theres an faster way to load MD3 models?
r00k
Posts: 1111
Joined: Sat Nov 13, 2004 10:39 pm

Re: Problems with MD3 loader

Post by r00k »

The md3 loader is legacy from JoeQuake, I think it was just really for demos.
It does work for me but i really never use it.
dimman
Posts: 7
Joined: Wed Jan 29, 2014 1:58 pm

Re: Problems with MD3 loader

Post by dimman »

Even if its not pretty, ptr is _not_ a pointer to short but a regular short.

'short *a, b'. Only a is a pointer to short, b is just a short.
Post Reply