r714 - in trunk: . base/shaders

lordhavoc at icculus.org lordhavoc at icculus.org
Fri May 12 04:36:48 EDT 2006


Author: lordhavoc
Date: 2006-05-12 04:36:47 -0400 (Fri, 12 May 2006)
New Revision: 714

Modified:
   trunk/base/shaders/light.vert
   trunk/model.c
   trunk/model.h
   trunk/util.c
   trunk/util.h
Log:
migrated Util_BuildModel code into Model_Build namespace and it now uses
the Model struct


Modified: trunk/base/shaders/light.vert
===================================================================
--- trunk/base/shaders/light.vert	2006-05-09 20:05:18 UTC (rev 713)
+++ trunk/base/shaders/light.vert	2006-05-12 08:36:47 UTC (rev 714)
@@ -30,14 +30,14 @@
 	vec3 lightminusvertex = LightPosition - gl_Vertex.xyz;
 	LightVector.x = dot(lightminusvertex, gl_MultiTexCoord1.xyz);
 	LightVector.y = dot(lightminusvertex, gl_MultiTexCoord2.xyz);
-	LightVector.z = -dot(lightminusvertex, gl_MultiTexCoord3.xyz);
+	LightVector.z = dot(lightminusvertex, gl_MultiTexCoord3.xyz);
 
 #if defined(USESPECULAR) || defined(USEFOG) || defined(USEOFFSETMAPPING)
 	// transform unnormalized eye direction into tangent space
 	vec3 eyeminusvertex = EyePosition - gl_Vertex.xyz;
 	EyeVector.x = dot(eyeminusvertex, gl_MultiTexCoord1.xyz);
 	EyeVector.y = dot(eyeminusvertex, gl_MultiTexCoord2.xyz);
-	EyeVector.z = -dot(eyeminusvertex, gl_MultiTexCoord3.xyz);
+	EyeVector.z = dot(eyeminusvertex, gl_MultiTexCoord3.xyz);
 #endif
 
 	// transform vertex to camera space, using ftransform to match non-VS

Modified: trunk/model.c
===================================================================
--- trunk/model.c	2006-05-09 20:05:18 UTC (rev 713)
+++ trunk/model.c	2006-05-12 08:36:47 UTC (rev 714)
@@ -22,21 +22,37 @@
 	}
 }
 
-// build vectors (along S, T, and Normal) for a triangle
-static void Model_TriangleVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f, float *normal3f)
+// build smoothed normals for all vertices of a mesh
+static void Model_MeshNormals(NUint32 numtriangles, const NUint32 *element3i, NUint32 numvertices, const float *vertex3f, const float *texcoord2f, float *normal3f)
 {
-	float f, tangentcross[3], v10[3], v20[3], tc10[2], tc20[2];
-	// 103 add/sub/negate/multiply (1 cycle), 3 divide (20 cycle), 3 sqrt (22 cycle), 4 compare (3 cycle?), total cycles not counting load/store/exchange roughly 241 cycles
-	// 12 add, 28 subtract, 57 multiply, 3 divide, 3 sqrt, 4 compare, 50% chance of 6 negates
+	NUint32 i, j;
+	float normal[3];
+	// clear the output array
+	memset(normal3f, 0, numvertices * sizeof(float[3]));
+	// iterate the triangles
+	for (i = 0;i < numtriangles;i++)
+	{
+		TriangleNormal(vertex3f + element3i[i*3+0]*3, vertex3f + element3i[i*3+1]*3, vertex3f + element3i[i*3+2]*3, normal);
+		// accumulate normals
+		for (j = 0;j < 3;j++)
+			VectorAdd(normal3f + element3i[i*3+j]*3, normal, normal3f + element3i[i*3+j]*3);
+	}
+	// normalize the results
+	for (i = 0;i < numvertices;i++)
+		VectorNormalize(normal3f + i * 3);
+}
 
+// build tangent vectors (vectors along S, T texcoords) for a triangle
+static void Model_TangentVectors(const float *v0, const float *v1, const float *v2, const float *tc0, const float *tc1, const float *tc2, float *svector3f, float *tvector3f)
+{
+	float tangentcross[3], v10[3], v20[3], tc10[2], tc20[2], normal3f[3];
+
 	// 6 multiply, 9 subtract
 	VectorSubtract(v1, v0, v10);
 	VectorSubtract(v2, v0, v20);
 	normal3f[0] = v20[1] * v10[2] - v10[1] * v20[2];
 	normal3f[1] = v20[2] * v10[0] - v10[2] * v20[0];
 	normal3f[2] = v20[0] * v10[1] - v10[0] * v20[1];
-	// 1 sqrt, 1 divide, 6 multiply, 2 add, 1 compare
-	VectorNormalize(normal3f);
 	// 12 multiply, 10 subtract
 	tc10[1] = tc1[1] - tc0[1];
 	tc20[1] = tc2[1] - tc0[1];
@@ -48,18 +64,6 @@
 	tvector3f[0] = v20[0] * tc10[0] - v10[0] * tc20[0];
 	tvector3f[1] = v20[1] * tc10[0] - v10[1] * tc20[0];
 	tvector3f[2] = v20[2] * tc10[0] - v10[2] * tc20[0];
-	// 12 multiply, 4 add, 6 subtract
-	f = DotProduct(svector3f, normal3f);
-	svector3f[0] -= f * normal3f[0];
-	svector3f[1] -= f * normal3f[1];
-	svector3f[2] -= f * normal3f[2];
-	f = DotProduct(tvector3f, normal3f);
-	tvector3f[0] -= f * normal3f[0];
-	tvector3f[1] -= f * normal3f[1];
-	tvector3f[2] -= f * normal3f[2];
-	// 2 sqrt, 2 divide, 12 multiply, 4 add, 2 compare
-	VectorNormalize(svector3f);
-	VectorNormalize(tvector3f);
 	// if texture is mapped the wrong way (counterclockwise), the tangents
 	// have to be flipped, this is detected by calculating a normal from the
 	// two tangents, and seeing if it is opposite the surface normal
@@ -73,39 +77,48 @@
 }
 
 // build smoothed vectors (along S, T, and Normal) for all vertices of a mesh
-static void Model_MeshVectors(NUint32 numtriangles, const NUint32 *element3i, NUint32 numvertices, const float *vertex3f, const float *texcoord2f, float *svector3f, float *tvector3f, float *normal3f)
+static void Model_MeshTangents(NUint32 numtriangles, const NUint32 *element3i, NUint32 numvertices, const float *vertex3f, const float *texcoord2f, float *normal3f, float *svector3f, float *tvector3f)
 {
 	NUint32 i, j;
-	float svector[3], tvector[3], normal[3];
 	// this calculates a set of vectors per triangle and blends them onto the
 	// triangle's vertices, if triangle share vertices (continuous mesh) this
 	// smooths them, if they are not shared then this looks facetted.
 	//
-	// a possibly more intelligent scheme would be to smooth vectors on all
-	// vertices at the same position that share similar vectors, but that
-	// takes longer and may still yield artifacts on texcoord seams
+	// a possibly more intelligent scheme would be to smooth normals on all
+	// vertices at the same position that share similar normals, but that
+	// takes longer and is difficult if they belong to different meshes
 	// clear the output arrays
 	memset(svector3f, 0, numvertices * sizeof(float[3]));
 	memset(tvector3f, 0, numvertices * sizeof(float[3]));
-	memset(normal3f, 0, numvertices * sizeof(float[3]));
 	// iterate the triangles
 	for (i = 0;i < numtriangles;i++)
 	{
-		Model_TriangleVectors(vertex3f + element3i[i*3+0] * 3, vertex3f + element3i[i*3+1] * 3, vertex3f + element3i[i*3+2] * 3, texcoord2f + element3i[i*3+0] * 2, texcoord2f + element3i[i*3+1] * 2, texcoord2f + element3i[i*3+2] * 2, svector, tvector, normal);
+		float svector[3], tvector[3];
+		Model_TangentVectors(vertex3f + element3i[i*3+0] * 3, vertex3f + element3i[i*3+1] * 3, vertex3f + element3i[i*3+2] * 3, texcoord2f + element3i[i*3+0] * 2, texcoord2f + element3i[i*3+1] * 2, texcoord2f + element3i[i*3+2] * 2, svector, tvector);
 		// accumulate vectors onto vertices
 		for (j = 0;j < 3;j++)
 		{
 			VectorAdd(svector3f + element3i[i*3+j]*3, svector, svector3f + element3i[i*3+j]*3);
 			VectorAdd(tvector3f + element3i[i*3+j]*3, tvector, tvector3f + element3i[i*3+j]*3);
-			VectorAdd(normal3f + element3i[i*3+j]*3, normal, normal3f + element3i[i*3+j]*3);
 		}
 	}
-	// normalize the results
-	for (i = 0;i < numvertices;i++)
+	// project tangents onto planes and normalize the results
+	for (i = 0;i < numvertices;i++, svector3f += 3, tvector3f += 3, normal3f += 3)
 	{
-		VectorNormalize(svector3f + i * 3);
-		VectorNormalize(tvector3f + i * 3);
-		VectorNormalize(normal3f + i * 3);
+		// project tangents onto plane defined by normal
+		// (makes sure they are perpendicular to the normal)
+		float f;
+		f = DotProduct(svector3f, normal3f);
+		svector3f[0] -= f * normal3f[0];
+		svector3f[1] -= f * normal3f[1];
+		svector3f[2] -= f * normal3f[2];
+		f = DotProduct(tvector3f, normal3f);
+		tvector3f[0] -= f * normal3f[0];
+		tvector3f[1] -= f * normal3f[1];
+		tvector3f[2] -= f * normal3f[2];
+		// normalize the tangents
+		VectorNormalize(svector3f);
+		VectorNormalize(tvector3f);
 	}
 }
 
@@ -175,6 +188,563 @@
 	Mem_Free(&hashtable);
 }
 
+void Model_Build_Begin(Model *b, Mem_Zone *memzone, Nbool isskeletal)
+{
+	memset(b, 0, sizeof(*b));
+	b->memzone = memzone;
+	b->isskeletal = isskeletal;
+}
+
+static void Model_Build_GenerateNeighbors(Model_Mesh *mesh)
+{
+	Model_MeshNeighbors(mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, mesh->num_vertices);
+}
+
+static void Model_Build_GeneratePlanes(Model_Mesh *mesh)
+{
+	Model_BuildTrianglePlanes(mesh->data_vertex3f, mesh->num_triangles, mesh->data_element3i, mesh->data_plane4f);
+}
+
+static void Model_Build_GenerateNormals(Model_Mesh *mesh)
+{
+	Model_MeshNormals(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f);
+}
+
+static void Model_Build_GenerateTangents(Model_Mesh *mesh)
+{
+	Model_MeshTangents(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f, mesh->data_svector3f, mesh->data_tvector3f);
+}
+
+static void Model_Build_GenerateLightmapTexCoords(Model_Mesh *mesh)
+{
+	// TODO
+	// this function should build non-overlapping triangle groups in a
+	// lightmap texture with some kind of assumed resolution based on the
+	// model bounding box (the resolution only matters when ensuring that
+	// some texture exists around each group to accomodate linear filtering,
+	// or perhaps a bit more if we decide to use mipmapped lightmaps)
+	//
+	// TODO: how do do this?
+}
+
+void Model_Build_Compile(Model *b, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes)
+{
+	NUint32 i, j;
+	const float *v;
+	Model_Mesh *mesh;
+	Nbool initbox;
+	initbox = true;
+	VectorClear(b->basecullmins);
+	VectorClear(b->basecullmaxs);
+	for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++)
+	{
+		if (mesh->max_triangles > mesh->num_triangles)
+		{
+			mesh->max_triangles = mesh->num_triangles;
+			if (mesh->data_element3i) Mem_ReAlloc(b->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i));
+			if (mesh->data_neighbor3i) Mem_ReAlloc(b->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i));
+			if (mesh->data_plane4f) Mem_ReAlloc(b->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f));
+		}
+
+		if (mesh->max_vertices > mesh->num_vertices)
+		{
+			mesh->max_vertices = mesh->num_vertices;
+			if (mesh->data_vertex3f) Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f));
+			if (mesh->data_svector3f) Mem_ReAlloc(b->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f));
+			if (mesh->data_tvector3f) Mem_ReAlloc(b->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f));
+			if (mesh->data_normal3f) Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f));
+			if (mesh->data_texcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f));
+			if (mesh->data_lightmaptexcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f));
+			if (mesh->data_weightindex4b) Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b));
+			if (mesh->data_weightvalue4b) Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b));
+		}
+
+		if (generateneighbors)
+		{
+			if (!mesh->data_neighbor3i) Mem_ReAlloc(b->memzone, &mesh->data_neighbor3i, mesh->max_triangles * 3 * sizeof(*mesh->data_neighbor3i));
+			Model_Build_GenerateNeighbors(mesh);
+		}
+
+		if (generateplanes)
+		{
+			if (!mesh->data_plane4f) Mem_ReAlloc(b->memzone, &mesh->data_plane4f, mesh->max_triangles * 4 * sizeof(*mesh->data_plane4f));
+			Model_Build_GeneratePlanes(mesh);
+		}
+
+		if (generatenormals)
+		{
+			if (!mesh->data_normal3f) Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f));
+			Model_Build_GenerateNormals(mesh);
+		}
+
+		if (generatetangents)
+		{
+			if (!mesh->data_svector3f) Mem_ReAlloc(b->memzone, &mesh->data_svector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_svector3f));
+			if (!mesh->data_tvector3f) Mem_ReAlloc(b->memzone, &mesh->data_tvector3f, mesh->max_vertices * 3 * sizeof(*mesh->data_tvector3f));
+			Model_Build_GenerateTangents(mesh);
+		}
+
+		if (generatelightmaptexcoords)
+		{
+			if (!mesh->data_lightmaptexcoord2f) Mem_ReAlloc(b->memzone, &mesh->data_lightmaptexcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_lightmaptexcoord2f));
+			Model_Build_GenerateLightmapTexCoords(mesh);
+		}
+
+		if (mesh->data_collisionbrushes)
+		{
+			Collision_Brush_FreeBrushesForTriangleMesh(mesh->data_collisionbrushes, mesh->max_collisionbrushes);
+			mesh->num_collisionbrushes = 0;
+			mesh->max_collisionbrushes = 0;
+			mesh->data_collisionbrushes = NULL;
+		}
+		if (generatecollisionbrushes)
+		{
+			mesh->num_collisionbrushes = mesh->num_triangles;
+			mesh->max_collisionbrushes = mesh->num_collisionbrushes;
+			mesh->data_collisionbrushes = Collision_Brush_AllocBrushesForTriangleMesh(b->memzone, mesh->max_collisionbrushes);
+			Collision_Brush_UpdateTriangleMeshBrushes(mesh->data_collisionbrushes, mesh->max_collisionbrushes, mesh->data_element3i, mesh->data_vertex3f);
+		}
+
+		for (j = 0, v = mesh->data_vertex3f;j < mesh->num_vertices;j++, v += 3)
+		{
+			if (initbox)
+			{
+				initbox = false;
+				VectorCopy(v, b->basecullmins);
+				VectorCopy(v, b->basecullmaxs);
+			}
+			else
+			{
+				b->basecullmins[0] = Min(b->basecullmins[0], v[0]);
+				b->basecullmins[1] = Min(b->basecullmins[1], v[1]);
+				b->basecullmins[2] = Min(b->basecullmins[2], v[2]);
+				b->basecullmaxs[0] = Max(b->basecullmaxs[0], v[0]);
+				b->basecullmaxs[1] = Max(b->basecullmaxs[1], v[1]);
+				b->basecullmaxs[2] = Max(b->basecullmaxs[2], v[2]);
+			}
+		}
+	}
+}
+
+void Model_Build_Free(Model *b)
+{
+	NUint32 i;
+	Model_Mesh *mesh;
+	for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++)
+	{
+		if (mesh->materialname) String_Free(&mesh->materialname);
+		if (mesh->data_element3i) Mem_Free(&mesh->data_element3i);
+		if (mesh->data_neighbor3i) Mem_Free(&mesh->data_neighbor3i);
+		if (mesh->data_plane4f) Mem_Free(&mesh->data_plane4f);
+		if (mesh->data_vertex3f) Mem_Free(&mesh->data_vertex3f);
+		if (mesh->data_svector3f) Mem_Free(&mesh->data_svector3f);
+		if (mesh->data_tvector3f) Mem_Free(&mesh->data_tvector3f);
+		if (mesh->data_normal3f) Mem_Free(&mesh->data_normal3f);
+		if (mesh->data_texcoord2f) Mem_Free(&mesh->data_texcoord2f);
+		if (mesh->data_lightmaptexcoord2f) Mem_Free(&mesh->data_lightmaptexcoord2f);
+		if (mesh->data_weightindex4b) Mem_Free(&mesh->data_weightindex4b);
+		if (mesh->data_weightvalue4b) Mem_Free(&mesh->data_weightvalue4b);
+		if (mesh->data_collisionbrushes) Collision_Brush_FreeBrushesForTriangleMesh(mesh->data_collisionbrushes, mesh->max_collisionbrushes);
+	}
+	if (b->data_meshes)
+		Mem_Free(&b->data_meshes);
+	memset(b, 0, sizeof(*b));
+}
+
+NUint32 Model_Build_AddSurface(Model *b, Mem_Zone *zone, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices)
+{
+	Model_Mesh *mesh;
+	if (b->num_meshes >= b->max_meshes)
+	{
+		b->max_meshes = Max(b->max_meshes * 2, 16);
+		Mem_ReAlloc(Global_Zone, &b->data_meshes, b->max_meshes * sizeof(*b->data_meshes));
+	}
+	mesh = b->data_meshes + b->num_meshes;
+	String_Set(&mesh->materialname, zone, materialname);
+	mesh->max_triangles = initialtriangles;
+	mesh->max_vertices = initialvertices;
+	b->num_meshes++;
+	return b->num_meshes - 1;
+}
+
+NUint32 Model_Build_AddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t)
+{
+	float *v;
+	Model_Mesh *mesh = b->data_meshes + meshindex;
+	if (mesh->num_vertices >= mesh->max_vertices)
+	{
+		mesh->max_vertices = Max(mesh->max_vertices * 2, 1024);
+		Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f));
+		Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f));
+		Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f));
+		if (b->isskeletal)
+		{
+			Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b));
+			Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b));
+		}
+	}
+	v = mesh->data_vertex3f + mesh->num_vertices * 3;
+	v[0] = x;
+	v[1] = y;
+	v[2] = z;
+	v = mesh->data_normal3f + mesh->num_vertices * 3;
+	v[0] = nx;
+	v[1] = ny;
+	v[2] = nz;
+	v = mesh->data_texcoord2f + mesh->num_vertices * 2;
+	v[0] = s;
+	v[1] = t;
+	if (b->isskeletal)
+	{
+		NUint8 *wi = mesh->data_weightindex4b + mesh->num_vertices * 4;
+		NUint8 *wf = mesh->data_weightvalue4b + mesh->num_vertices * 4;
+		wi[0] = 0;
+		wi[1] = 0;
+		wi[2] = 0;
+		wi[3] = 0;
+		wf[0] = 255;
+		wf[1] = 0;
+		wf[2] = 0;
+		wf[3] = 0;
+	}
+	mesh->num_vertices++;
+	return mesh->num_vertices - 1;
+}
+
+NUint32 Model_Build_AddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb)
+{
+	float *v;
+	Model_Mesh *mesh = b->data_meshes + meshindex;
+	if (mesh->num_vertices >= mesh->max_vertices)
+	{
+		mesh->max_vertices = Max(mesh->max_vertices * 2, 1024);
+		Mem_ReAlloc(b->memzone, &mesh->data_vertex3f, mesh->max_vertices * 3 * sizeof(*mesh->data_vertex3f));
+		Mem_ReAlloc(b->memzone, &mesh->data_normal3f, mesh->max_vertices * 3 * sizeof(*mesh->data_normal3f));
+		Mem_ReAlloc(b->memzone, &mesh->data_texcoord2f, mesh->max_vertices * 2 * sizeof(*mesh->data_texcoord2f));
+		if (b->isskeletal)
+		{
+			Mem_ReAlloc(b->memzone, &mesh->data_weightindex4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightindex4b));
+			Mem_ReAlloc(b->memzone, &mesh->data_weightvalue4b, mesh->max_vertices * 4 * sizeof(*mesh->data_weightvalue4b));
+		}
+	}
+	v = mesh->data_vertex3f + mesh->num_vertices * 3;
+	v[0] = x;
+	v[1] = y;
+	v[2] = z;
+	v = mesh->data_normal3f + mesh->num_vertices * 3;
+	v[0] = nx;
+	v[1] = ny;
+	v[2] = nz;
+	v = mesh->data_texcoord2f + mesh->num_vertices * 2;
+	v[0] = s;
+	v[1] = t;
+	if (b->isskeletal)
+	{
+		NUint8 *wi = mesh->data_weightindex4b + mesh->num_vertices * 4;
+		NUint8 *wf = mesh->data_weightvalue4b + mesh->num_vertices * 4;
+		Vector4Copy(wib, wi);
+		Vector4Copy(wfb, wf);
+	}
+	mesh->num_vertices++;
+	return mesh->num_vertices - 1;
+}
+
+NUint32 Model_Build_FindOrAddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t)
+{
+	NUint32 i;
+	float *v, *n, *tc;
+	NUint8 *wi, *wf;
+	Model_Mesh *mesh = b->data_meshes + meshindex;
+	for (i = 0, v = mesh->data_vertex3f, n = mesh->data_normal3f, tc = mesh->data_texcoord2f, wi = mesh->data_weightindex4b, wf = mesh->data_weightvalue4b;i < mesh->num_vertices;i++, v += 3, n += 3, tc += 2, wi += 4, wf += 4)
+		if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001
+		 && fabs(n[0] - nx) < 0.0001 && fabs(n[1] - ny) < 0.0001 && fabs(n[2] - nz) < 0.0001
+		 && fabs(tc[0] - s) < 0.0001 && fabs(tc[1] - t) < 0.0001)
+			return i;
+	return Model_Build_AddVertex(b, meshindex, x, y, z, nx, ny, nz, s, t);
+}
+
+NUint32 Model_Build_FindOrAddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb)
+{
+	NUint32 i;
+	float *v, *n, *tc;
+	NUint8 *wi, *wf;
+	Model_Mesh *mesh = b->data_meshes + meshindex;
+	for (i = 0, v = mesh->data_vertex3f, n = mesh->data_normal3f, tc = mesh->data_texcoord2f, wi = mesh->data_weightindex4b, wf = mesh->data_weightvalue4b;i < mesh->num_vertices;i++, v += 3, n += 3, tc += 2, wi += 4, wf += 4)
+		if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001
+		 && fabs(n[0] - nx) < 0.0001 && fabs(n[1] - ny) < 0.0001 && fabs(n[2] - nz) < 0.0001
+		 && fabs(tc[0] - s) < 0.0001 && fabs(tc[1] - t) < 0.0001
+		 && wi[0] == wib[0] && wi[1] == wib[1] && wi[2] == wib[2] && wi[3] == wib[3]
+		 && wf[0] == wfb[0] && wf[1] == wfb[1] && wf[2] == wfb[2] && wf[3] == wfb[3])
+			return i;
+	return Model_Build_AddVertexSkeletal(b, meshindex, x, y, z, nx, ny, nz, s, t, wib, wfb);
+}
+
+NUint32 Model_Build_AddTriangle(Model *b, NUint32 meshindex, int e0, int e1, int e2)
+{
+	Model_Mesh *mesh = b->data_meshes + meshindex;
+	NUint32 *e;
+	if (mesh->num_triangles >= mesh->max_triangles)
+	{
+		mesh->max_triangles = Max(mesh->max_triangles * 2, 1024);
+		Mem_ReAlloc(b->memzone, &mesh->data_element3i, mesh->max_triangles * 3 * sizeof(*mesh->data_element3i));
+	}
+	e = mesh->data_element3i + mesh->num_triangles * 3;
+	e[0] = e0;
+	e[1] = e1;
+	e[2] = e2;
+	mesh->num_triangles++;
+	return mesh->num_triangles - 1;
+}
+
+void Model_Build_Write(Model *b, const char *filename)
+{
+	// FIXME: this is very unlikely to overflow but it should be made buffer size safe at some point
+	NUint32 i, num;
+	Nsize textsize, textmaxsize;
+	char *text;
+	Model_Mesh *mesh;
+	textmaxsize = 0x100000;
+	for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++)
+		textmaxsize += mesh->num_vertices * 60 + mesh->num_triangles * 40;
+	textsize = 0;
+	text = Mem_Alloc(Global_Zone, textmaxsize);
+	textsize += snprintf(text + textsize, textmaxsize - textsize, "MD5Version 10\ncommandline \"\"\n\nnumJoints 1\nnumMeshes %u\n\njoints {\n\t\"ROOT\"\t-1 ( 0.000000 0.000000 0.000000 ) ( 0.000000 0.000000 0.000000 ) // \n}\n", b->num_meshes);
+	for (i = 0, mesh = b->data_meshes;i < b->num_meshes;i++, mesh++)
+	{
+		if (textmaxsize < textsize + mesh->num_vertices * 100 + mesh->num_triangles * 100 + mesh->num_vertices * 100 + 1000)
+		{
+			textmaxsize = textsize + mesh->num_vertices * 200 + mesh->num_triangles * 200 + mesh->num_vertices * 200 + 2000;
+			Mem_ReAlloc(Global_Zone, &text, textmaxsize);
+		}
+		textsize += snprintf(text + textsize, textmaxsize - textsize, "\nmesh {\n\tshader \"%s\"\n\n\tnumverts %u\n", mesh->materialname, mesh->num_vertices);
+		for (num = 0;num < mesh->num_vertices;num++)
+			textsize += snprintf(text + textsize, textmaxsize - textsize, "\tvert %u ( %.6f %.6f ) %u 1\n", num, mesh->data_texcoord2f[num*2+0], mesh->data_texcoord2f[num*2+1], num);
+		textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumtris %u\n", mesh->num_triangles);
+		for (num = 0;num < mesh->num_triangles;num++)
+			textsize += snprintf(text + textsize, textmaxsize - textsize, "\ttri %u %u %u %u\n", num, mesh->data_element3i[num*3+0], mesh->data_element3i[num*3+1], mesh->data_element3i[num*3+2]);
+		textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumweights %u\n", mesh->num_vertices);
+		for (num = 0;num < mesh->num_vertices;num++)
+			textsize += snprintf(text + textsize, textmaxsize - textsize, "\tweight %u 0 1.000000 ( %.6f %.6f %.6f )\n", num, mesh->data_vertex3f[num*3+0], mesh->data_vertex3f[num*3+1], mesh->data_vertex3f[num*3+2]);
+		textsize += snprintf(text + textsize, textmaxsize - textsize, "}\n");
+	}
+	File_WriteFile(filename, text, textsize);
+	Mem_Free(&text);
+}
+
+void Model_Build_ImportOBJ(Model *b, const char *inputname, const char *text, const char *textend)
+{
+	NUint32 linenumber = 0;
+	NSint32 meshindex = -1;
+	NUint32 num_vertices = 0, max_vertices = 0;
+	NUint32 num_normals = 0, max_normals = 0;
+	NUint32 num_texcoords = 0, max_texcoords = 0;
+	float *data_vertex3f = NULL;
+	float *data_normal3f = NULL;
+	float *data_texcoord2f = NULL;
+	while (text < textend)
+	{
+		Nbool comment = false;
+		NUint32 argc = 0;
+		char argv[64][256];
+		// parse the line
+		linenumber++;
+		while (text < textend && *text != '\r' && *text != '\n')
+		{
+			if (comment || *text <= ' ')
+				text++;
+			else if (*text == '#')
+				comment = true;
+			else
+			{
+				NUint32 charnum;
+				for (charnum = 0;text < textend && *text > ' ';text++)
+					if (charnum < sizeof(argv[0]) - 1)
+						argv[argc][charnum++] = *text;
+				argv[argc++][charnum] = 0;
+			}
+		}
+		if (*text == '\r' && text[1] == '\n')
+			text++;
+		if (*text == '\n')
+			text++;
+		// now we have a command
+		if (argc < 1)
+			continue;
+		if (!String_Compare(argv[0], "v"))
+		{
+			// v -4.99960e-2 0.250000 -1.00000
+			if (argc == 4)
+			{
+				if (num_vertices >= max_vertices)
+				{
+					max_vertices = Max(max_vertices * 2, 1024);
+					Mem_ReAlloc(Global_Zone, &data_vertex3f, max_vertices * sizeof(float[3]));
+				}
+				data_vertex3f[num_vertices*3+0] = atof(argv[1]);
+				data_vertex3f[num_vertices*3+2] = atof(argv[2]);
+				data_vertex3f[num_vertices*3+1] = atof(argv[3]);
+				num_vertices++;
+			}
+			else
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3);
+		}
+		else if (!String_Compare(argv[0], "vn"))
+		{
+			// vn 1.99019e-6 2.65359e-5 -1.000000
+			if (argc == 4)
+			{
+				if (num_normals >= max_normals)
+				{
+					max_normals = Max(max_normals * 2, 1024);
+					Mem_ReAlloc(Global_Zone, &data_normal3f, max_normals * sizeof(float[3]));
+				}
+				data_normal3f[num_normals*3+0] = atof(argv[1]);
+				data_normal3f[num_normals*3+2] = atof(argv[2]);
+				data_normal3f[num_normals*3+1] = atof(argv[3]);
+				num_normals++;
+			}
+			else
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3);
+		}
+		else if (!String_Compare(argv[0], "vt"))
+		{
+			// vt 0.00000e+0 1.99019e-6
+			if (argc == 3)
+			{
+				if (num_texcoords >= max_texcoords)
+				{
+					max_texcoords = Max(max_texcoords * 2, 1024);
+					Mem_ReAlloc(Global_Zone, &data_texcoord2f, max_texcoords * sizeof(float[2]));
+				}
+				data_texcoord2f[num_texcoords*2+0] = atof(argv[1]);
+				data_texcoord2f[num_texcoords*2+1] = -atof(argv[2]);
+				num_texcoords++;
+			}
+			else
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 2);
+		}
+		else if (!String_Compare(argv[0], "usemtl"))
+		{
+			// usemtl mtrl/chrome
+			if (argc == 2)
+				meshindex = Model_Build_AddSurface(b, Global_Zone, argv[1], 0, 0);
+			else
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
+		}
+		else if (!String_Compare(argv[0], "f"))
+		{
+			// f 1/11/5 18/56/71 17/58/67
+			NUint32 i;
+			NUint32 indices[64];
+			if (argc >= 4)
+			{
+				if (meshindex == -1)
+					meshindex = Model_Build_AddSurface(b, Global_Zone, "default", 0, 0);
+				for (i = 0;i < argc - 1;i++)
+				{
+					NUint32 j;
+					const char *s = argv[i+1];
+					float v[3];
+					float vn[3];
+					float tc[2];
+					// if there are 3 indices, they are vertex, texcoord, normal
+					// if there are 2 indices, they are vertex, texcoord
+					// if there is only one index, it is vertex
+					// so we just initialize the values to defaults,
+					// and update them as indices are read
+					VectorClear(v);
+					VectorClear(vn);
+					Vector2Clear(tc);
+					for (j = 0;j < 3;j++)
+					{
+						if (*s)
+						{
+							NSint32 k = atoi(s);
+							switch (j)
+							{
+							case 0:
+								if (k < 0)
+									k += num_vertices;
+								else
+									k--;
+								if (k >= 0 && k < num_vertices)
+									VectorCopy(data_vertex3f + k * 3, v);
+								else
+									Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face vertex index (parameter #%i)\n", inputname, linenumber, i + 1);
+								break;
+							case 1:
+								if (k < 0)
+									k += num_texcoords;
+								else
+									k--;
+								if (k >= 0 && k < num_texcoords)
+									Vector2Copy(data_texcoord2f + k * 2, tc);
+								else
+									Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face texcoord index (parameter #%i)\n", inputname, linenumber, i + 1);
+								break;
+							case 2:
+								if (k < 0)
+									k += num_normals;
+								else
+									k--;
+								if (k >= 0 && k < num_normals)
+									VectorCopy(data_normal3f + k * 3, vn);
+								else
+									Console_Printf("Model_Build_ImportOBJ: %s:%i: invalid face vertexnormal index (parameter #%i)\n", inputname, linenumber, i + 1);
+								break;
+							}
+						}
+						// this weird code construct exits at NUL, or if the
+						// character is /, and then leaves s at the character
+						// after the NUL or /
+						while (*s)
+						{
+							if (*s == '/')
+							{
+								s++;
+								break;
+							}
+							s++;
+						}
+					}
+					indices[i] = Model_Build_FindOrAddVertex(b, meshindex, v[0], v[1], v[2], vn[0], vn[1], vn[2], tc[0], tc[1]);
+					// make a triangle fan if we have enough vertices
+					if (i >= 2)
+						Model_Build_AddTriangle(b, meshindex, indices[0], indices[i-1], indices[i]);
+				}
+			}
+			else
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i or more parameters\n", inputname, linenumber, argv[0], 3);
+		}
+		else if (!String_Compare(argv[0], "o"))
+		{
+			// o cylinder1
+			if (argc != 2)
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
+		}
+		else if (!String_Compare(argv[0], "mtllib"))
+		{
+			// mtllib zrail2.mtl
+			if (argc != 2)
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
+		}
+		else if (!String_Compare(argv[0], "g"))
+		{
+			// g cylinder1_mtrl/invisible
+			if (argc != 2)
+				Console_Printf("Model_Build_ImportOBJ: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
+		}
+		else
+			Console_Printf("Model_Build_ImportOBJ: %s:%i: unknown obj command %s\n", inputname, linenumber, argv[0]);
+	}
+	if (data_vertex3f)
+		Mem_Free(&data_vertex3f);
+	if (data_normal3f)
+		Mem_Free(&data_normal3f);
+	if (data_texcoord2f)
+		Mem_Free(&data_texcoord2f);
+}
+
 /* example clips of an MD5 model
 MD5Version 10
 commandline ""
@@ -578,7 +1148,8 @@
 					VectorCopy(md5weights[md5weightrange[i*2+0]].vertex, mesh->data_vertex3f + i*3);
 			}
 			// compile the base frame of the mesh for static uses
-			Model_MeshVectors(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_svector3f, mesh->data_tvector3f, mesh->data_normal3f);
+			Model_MeshNormals(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f);
+			Model_MeshTangents(mesh->num_triangles, mesh->data_element3i, mesh->num_vertices, mesh->data_vertex3f, mesh->data_texcoord2f, mesh->data_normal3f, mesh->data_svector3f, mesh->data_tvector3f);
 			Model_MeshNeighbors(mesh->num_triangles, mesh->data_element3i, mesh->data_neighbor3i, mesh->num_vertices);
 			Model_BuildTrianglePlanes(mesh->data_vertex3f, mesh->num_triangles, mesh->data_element3i, mesh->data_plane4f);
 			// collision brushes are for the static frame

Modified: trunk/model.h
===================================================================
--- trunk/model.h	2006-05-09 20:05:18 UTC (rev 713)
+++ trunk/model.h	2006-05-12 08:36:47 UTC (rev 714)
@@ -80,6 +80,11 @@
 
 typedef struct Model
 {
+	// set at the creation of the Model
+	Mem_Zone *memzone;
+
+	Nbool isskeletal;
+
 	NUint32 num_meshes;
 	NUint32 max_meshes;
 	Model_Mesh *data_meshes;
@@ -97,6 +102,18 @@
 void Model_Load(ResourceEntry *r);
 void Model_Unload(ResourceEntry *r);
 
+void Model_Build_Begin(Model *b, Mem_Zone *memzone, Nbool isskeletal);
+void Model_Build_Compile(Model *b, Nbool generateneighbors, Nbool generateplanes, Nbool generatenormals, Nbool generatetangents, Nbool generatelightmaptexcoords, Nbool generatecollisionbrushes);
+void Model_Build_Free(Model *b);
+NUint32 Model_Build_AddSurface(Model *b, Mem_Zone *zone, const char *materialname, NUint32 initialtriangles, NUint32 initialvertices);
+NUint32 Model_Build_AddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t);
+NUint32 Model_Build_AddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb);
+NUint32 Model_Build_FindOrAddVertex(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t);
+NUint32 Model_Build_FindOrAddVertexSkeletal(Model *b, NUint32 meshindex, float x, float y, float z, float nx, float ny, float nz, float s, float t, NUint8 *wib, NUint8 *wfb);
+NUint32 Model_Build_AddTriangle(Model *b, NUint32 meshindex, int e0, int e1, int e2);
+void Model_Build_Write(Model *b, const char *filename);
+void Model_Build_ImportOBJ(Model *b, const char *inputname, const char *text, const char *textend);
+
 // this function decodes skeletal vertex information to your supplied arrays
 // NOTE: outplane4f requires outvertex3f
 void Model_GetVertices(NUint32 resourceindex, NUint32 meshindex, const matrix4x4_t *transforms, float *outvertex3f, float *outsvector3f, float *outtvector3f, float *outnormal3f, float *outplane4f);

Modified: trunk/util.c
===================================================================
--- trunk/util.c	2006-05-09 20:05:18 UTC (rev 713)
+++ trunk/util.c	2006-05-12 08:36:47 UTC (rev 714)
@@ -2,6 +2,7 @@
 #include "ncommon.h"
 #include "util.h"
 #include "texture.h"
+#include "model.h"
 
 static Shell_SymbolDecl Util_Shell_MakeSkyBox_Decl;
 static Shell_SymbolDecl Util_Shell_MakeTerrain_Decl;
@@ -240,337 +241,6 @@
 #undef ReadNext
 }
 
-void Util_BuildModel_Begin(Util_BuildModel *b)
-{
-	memset(b, 0, sizeof(*b));
-}
-
-void Util_BuildModel_End(Util_BuildModel *b)
-{
-	NUint32 i;
-	Util_BuildModel_Surface *surface;
-	for (i = 0, surface = b->data_surfaces;i < b->num_surfaces;i++, surface++)
-	{
-		Mem_Free(&surface->data_element3i);
-		Mem_Free(&surface->data_vertex8f);
-	}
-	Mem_Free(&b->data_surfaces);
-	memset(b, 0, sizeof(*b));
-}
-
-NUint32 Util_BuildModel_AddSurface(Util_BuildModel *b, const char *materialname)
-{
-	Util_BuildModel_Surface *surface;
-	if (b->num_surfaces >= b->max_surfaces)
-	{
-		b->max_surfaces = Max(b->max_surfaces * 2, 16);
-		Mem_ReAlloc(Global_Zone, &b->data_surfaces, b->max_surfaces * sizeof(Util_BuildModel_Surface));
-	}
-	surface = b->data_surfaces + b->num_surfaces;
-	strncpy(surface->materialname, materialname, sizeof(surface->materialname) - 1);
-	b->num_surfaces++;
-	return b->num_surfaces - 1;
-}
-
-NUint32 Util_BuildModel_AddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t)
-{
-	float *v;
-	Util_BuildModel_Surface *surface = b->data_surfaces + surfaceindex;
-	if (surface->num_vertices >= surface->max_vertices)
-	{
-		surface->max_vertices = Max(surface->max_vertices * 2, 1024);
-		Mem_ReAlloc(Global_Zone, &surface->data_vertex8f, surface->max_vertices * sizeof(float[8]));
-	}
-	v = surface->data_vertex8f + surface->num_vertices * 8;
-	v[0] = x;
-	v[1] = y;
-	v[2] = z;
-	v[3] = nx;
-	v[4] = ny;
-	v[5] = nz;
-	v[6] = s;
-	v[7] = t;
-	surface->num_vertices++;
-	return surface->num_vertices - 1;
-}
-
-NUint32 Util_BuildModel_FindOrAddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t)
-{
-	NUint32 i;
-	float *v;
-	Util_BuildModel_Surface *surface = b->data_surfaces + surfaceindex;
-	for (i = 0, v = surface->data_vertex8f;i < surface->num_vertices;i++, v += 8)
-		if (fabs(v[0] - x) < 0.0001 && fabs(v[1] - y) < 0.0001 && fabs(v[2] - z) < 0.0001 && fabs(v[3] - nx) < 0.0001 && fabs(v[4] - ny) < 0.0001 && fabs(v[5] - nz) < 0.0001 && fabs(v[6] - s) < 0.0001 && fabs(v[7] - t) < 0.0001)
-			return i;
-	return Util_BuildModel_AddVertex(b, surfaceindex, x, y, z, nx, ny, nz, s, t);
-}
-
-NUint32 Util_BuildModel_AddTriangle(Util_BuildModel *b, NUint32 surfaceindex, int e0, int e1, int e2)
-{
-	Util_BuildModel_Surface *surface = b->data_surfaces + surfaceindex;
-	NUint32 *e;
-	if (surface->num_triangles >= surface->max_triangles)
-	{
-		surface->max_triangles = Max(surface->max_triangles * 2, 1024);
-		Mem_ReAlloc(Global_Zone, &surface->data_element3i, surface->max_triangles * sizeof(NUint32[3]));
-	}
-	e = surface->data_element3i + surface->num_triangles * 3;
-	e[0] = e0;
-	e[1] = e1;
-	e[2] = e2;
-	surface->num_triangles++;
-	return surface->num_triangles - 1;
-}
-
-void Util_BuildModel_Write(Util_BuildModel *b, const char *filename)
-{
-	// FIXME: this is very unlikely to overflow but it should be made buffer size safe at some point
-	NUint32 i, num;
-	Nsize textsize, textmaxsize;
-	char *text;
-	Util_BuildModel_Surface *surface;
-	textmaxsize = 0x100000;
-	for (i = 0, surface = b->data_surfaces;i < b->num_surfaces;i++, surface++)
-		textmaxsize += surface->num_vertices * 60 + surface->num_triangles * 40;
-	textsize = 0;
-	text = Mem_Alloc(Global_Zone, textmaxsize);
-	textsize += snprintf(text + textsize, textmaxsize - textsize, "MD5Version 10\ncommandline \"\"\n\nnumJoints 1\nnumMeshes %u\n\njoints {\n\t\"ROOT\"\t-1 ( 0.000000 0.000000 0.000000 ) ( 0.000000 0.000000 0.000000 ) // \n}\n", b->num_surfaces);
-	for (i = 0, surface = b->data_surfaces;i < b->num_surfaces;i++, surface++)
-	{
-		if (textmaxsize < textsize + surface->num_vertices * 100 + surface->num_triangles * 100 + surface->num_vertices * 100 + 1000)
-		{
-			textmaxsize = textsize + surface->num_vertices * 200 + surface->num_triangles * 200 + surface->num_vertices * 200 + 2000;
-			Mem_ReAlloc(Global_Zone, &text, textmaxsize);
-		}
-		textsize += snprintf(text + textsize, textmaxsize - textsize, "\nmesh {\n\tshader \"%s\"\n\n\tnumverts %u\n", surface->materialname, surface->num_vertices);
-		for (num = 0;num < surface->num_vertices;num++)
-			textsize += snprintf(text + textsize, textmaxsize - textsize, "\tvert %u ( %.6f %.6f ) %u 1\n", num, surface->data_vertex8f[num*8+6], surface->data_vertex8f[num*8+7], num);
-		textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumtris %u\n", surface->num_triangles);
-		for (num = 0;num < surface->num_triangles;num++)
-			textsize += snprintf(text + textsize, textmaxsize - textsize, "\ttri %u %u %u %u\n", num, surface->data_element3i[num*3+0], surface->data_element3i[num*3+1], surface->data_element3i[num*3+2]);
-		textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumweights %u\n", surface->num_vertices);
-		for (num = 0;num < surface->num_vertices;num++)
-			textsize += snprintf(text + textsize, textmaxsize - textsize, "\tweight %u 0 1.000000 ( %.6f %.6f %.6f )\n", num, surface->data_vertex8f[num*8+0], surface->data_vertex8f[num*8+1], surface->data_vertex8f[num*8+2]);
-		textsize += snprintf(text + textsize, textmaxsize - textsize, "}\n");
-	}
-	File_WriteFile(filename, text, textsize);
-	Mem_Free(&text);
-}
-
-void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend)
-{
-	NUint32 linenumber = 0;
-	NSint32 surfaceindex = -1;
-	NUint32 num_vertices = 0, max_vertices = 0;
-	NUint32 num_normals = 0, max_normals = 0;
-	NUint32 num_texcoords = 0, max_texcoords = 0;
-	float *data_vertex3f = NULL;
-	float *data_normal3f = NULL;
-	float *data_texcoord2f = NULL;
-	while (text < textend)
-	{
-		Nbool comment = false;
-		NUint32 argc = 0;
-		char argv[64][256];
-		// parse the line
-		linenumber++;
-		while (text < textend && *text != '\r' && *text != '\n')
-		{
-			if (comment || *text <= ' ')
-				text++;
-			else if (*text == '#')
-				comment = true;
-			else
-			{
-				NUint32 charnum;
-				for (charnum = 0;text < textend && *text > ' ';text++)
-					if (charnum < sizeof(argv[0]) - 1)
-						argv[argc][charnum++] = *text;
-				argv[argc++][charnum] = 0;
-			}
-		}
-		if (*text == '\r' && text[1] == '\n')
-			text++;
-		if (*text == '\n')
-			text++;
-		// now we have a command
-		if (argc < 1)
-			continue;
-		if (!String_Compare(argv[0], "v"))
-		{
-			// v -4.99960e-2 0.250000 -1.00000
-			if (argc == 4)
-			{
-				if (num_vertices >= max_vertices)
-				{
-					max_vertices = Max(max_vertices * 2, 1024);
-					Mem_ReAlloc(Global_Zone, &data_vertex3f, max_vertices * sizeof(float[3]));
-				}
-				data_vertex3f[num_vertices*3+0] = atof(argv[1]);
-				data_vertex3f[num_vertices*3+2] = atof(argv[2]);
-				data_vertex3f[num_vertices*3+1] = atof(argv[3]);
-				num_vertices++;
-			}
-			else
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3);
-		}
-		else if (!String_Compare(argv[0], "vn"))
-		{
-			// vn 1.99019e-6 2.65359e-5 -1.000000
-			if (argc == 4)
-			{
-				if (num_normals >= max_normals)
-				{
-					max_normals = Max(max_normals * 2, 1024);
-					Mem_ReAlloc(Global_Zone, &data_normal3f, max_normals * sizeof(float[3]));
-				}
-				data_normal3f[num_normals*3+0] = atof(argv[1]);
-				data_normal3f[num_normals*3+2] = atof(argv[2]);
-				data_normal3f[num_normals*3+1] = atof(argv[3]);
-				num_normals++;
-			}
-			else
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 3);
-		}
-		else if (!String_Compare(argv[0], "vt"))
-		{
-			// vt 0.00000e+0 1.99019e-6
-			if (argc == 3)
-			{
-				if (num_texcoords >= max_texcoords)
-				{
-					max_texcoords = Max(max_texcoords * 2, 1024);
-					Mem_ReAlloc(Global_Zone, &data_texcoord2f, max_texcoords * sizeof(float[2]));
-				}
-				data_texcoord2f[num_texcoords*2+0] = atof(argv[1]);
-				data_texcoord2f[num_texcoords*2+1] = -atof(argv[2]);
-				num_texcoords++;
-			}
-			else
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 2);
-		}
-		else if (!String_Compare(argv[0], "usemtl"))
-		{
-			// usemtl mtrl/chrome
-			if (argc == 2)
-				surfaceindex = Util_BuildModel_AddSurface(b, argv[1]);
-			else
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
-		}
-		else if (!String_Compare(argv[0], "f"))
-		{
-			// f 1/11/5 18/56/71 17/58/67
-			NUint32 i;
-			NUint32 indices[64];
-			if (argc >= 4)
-			{
-				if (surfaceindex == -1)
-					surfaceindex = Util_BuildModel_AddSurface(b, "default");
-				for (i = 0;i < argc - 1;i++)
-				{
-					NUint32 j;
-					const char *s = argv[i+1];
-					float v[3];
-					float vn[3];
-					float tc[2];
-					// if there are 3 indices, they are vertex, texcoord, normal
-					// if there are 2 indices, they are vertex, texcoord
-					// if there is only one index, it is vertex
-					// so we just initialize the values to defaults,
-					// and update them as indices are read
-					VectorClear(v);
-					VectorClear(vn);
-					Vector2Clear(tc);
-					for (j = 0;j < 3;j++)
-					{
-						if (*s)
-						{
-							NSint32 k = atoi(s);
-							switch (j)
-							{
-							case 0:
-								if (k < 0)
-									k += num_vertices;
-								else
-									k--;
-								if (k >= 0 && k < num_vertices)
-									VectorCopy(data_vertex3f + k * 3, v);
-								else
-									Console_Printf("util_convertobj: %s:%i: invalid face vertex index (parameter #%i)\n", inputname, linenumber, i + 1);
-								break;
-							case 1:
-								if (k < 0)
-									k += num_texcoords;
-								else
-									k--;
-								if (k >= 0 && k < num_texcoords)
-									Vector2Copy(data_texcoord2f + k * 2, tc);
-								else
-									Console_Printf("util_convertobj: %s:%i: invalid face texcoord index (parameter #%i)\n", inputname, linenumber, i + 1);
-								break;
-							case 2:
-								if (k < 0)
-									k += num_normals;
-								else
-									k--;
-								if (k >= 0 && k < num_normals)
-									VectorCopy(data_normal3f + k * 3, vn);
-								else
-									Console_Printf("util_convertobj: %s:%i: invalid face vertexnormal index (parameter #%i)\n", inputname, linenumber, i + 1);
-								break;
-							}
-						}
-						// this weird code construct exits at NUL, or if the
-						// character is /, and then leaves s at the character
-						// after the NUL or /
-						while (*s)
-						{
-							if (*s == '/')
-							{
-								s++;
-								break;
-							}
-							s++;
-						}
-					}
-					indices[i] = Util_BuildModel_FindOrAddVertex(b, surfaceindex, v[0], v[1], v[2], vn[0], vn[1], vn[2], tc[0], tc[1]);
-					// make a triangle fan if we have enough vertices
-					if (i >= 2)
-						Util_BuildModel_AddTriangle(b, surfaceindex, indices[0], indices[i-1], indices[i]);
-				}
-			}
-			else
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i or more parameters\n", inputname, linenumber, argv[0], 3);
-		}
-		else if (!String_Compare(argv[0], "o"))
-		{
-			// o cylinder1
-			if (argc != 2)
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
-		}
-		else if (!String_Compare(argv[0], "mtllib"))
-		{
-			// mtllib zrail2.mtl
-			if (argc != 2)
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
-		}
-		else if (!String_Compare(argv[0], "g"))
-		{
-			// g cylinder1_mtrl/invisible
-			if (argc != 2)
-				Console_Printf("util_convertobj: %s:%i: command %s takes %i parameters\n", inputname, linenumber, argv[0], 1);
-		}
-		else
-			Console_Printf("util_convertobj: %s:%i: unknown obj command %s\n", inputname, linenumber, argv[0]);
-	}
-	if (data_vertex3f)
-		Mem_Free(&data_vertex3f);
-	if (data_normal3f)
-		Mem_Free(&data_normal3f);
-	if (data_texcoord2f)
-		Mem_Free(&data_texcoord2f);
-}
-
 static void Util_Shell_MakeTerrain(void)
 {
 	NUint32 tilesize, width, height, bx, by, tx, ty, tilewidth, tileheight, num, tileswidth, tilesheight;
@@ -578,7 +248,7 @@
 	const char *basename, *imagename, *materialname;
 	char *tilename;
 	Nvec terrainsize[3], texturesize[2], terrainscale[3], terrainorigin[3], texturescale[2];
-	Util_BuildModel b;
+	Model b;
 	basename = Shell_Callback_GetArg(1);
 	imagename = Shell_Callback_GetArg(2);
 	tilesize = (int) Shell_Callback_GetArgValue(3);
@@ -610,12 +280,12 @@
 	terrainorigin[2] = terrainsize[2] * -0.5;
 	tileswidth = width / tilesize;
 	tilesheight = height / tilesize;
-	Util_BuildModel_Begin(&b);
+	Model_Build_Begin(&b, Global_Zone, false);
 	for (by = 0;by < height;by += tilesize)
 	{
 		for (bx = 0;bx < width;bx += tilesize)
 		{
-			NUint32 surfaceindex = Util_BuildModel_AddSurface(&b, materialname);
+			NUint32 meshindex = Model_Build_AddSurface(&b, Global_Zone, materialname, 0, 0);
 			tilewidth = Bound(0, width - bx, tilesize+2);
 			tileheight = Bound(0, height - by, tilesize+2);
 			for (ty = 0, num = 0;ty < tileheight;ty++)
@@ -634,8 +304,8 @@
 					pyf = py - pyi;
 					p = pixels + (pyi * width + pxi) * 4;
 					pz = ((p[0]+p[1]+p[2])*(1.0-pxf)+(p[4]+p[5]+p[6])*(pxf))*(1.0-pyf)+((p[w+0]+p[w+1]+p[w+2])*(1.0-pxf)+(p[w+4]+p[w+5]+p[w+6])*(pxf))*(pyf);
-					// FIXME: this SHOULD calculate a valid surface normal!!
-					Util_BuildModel_AddVertex(&b, surfaceindex, px * terrainscale[0] + terrainorigin[0], py * terrainscale[1] + terrainorigin[1], pz * terrainscale[2] + terrainorigin[2], 0, 0, 1, (px * terrainscale[0] + terrainorigin[0]) * texturescale[0], (py * terrainscale[1] + terrainorigin[1]) * texturescale[1]);
+					// FIXME: this SHOULD calculate a valid mesh normal!!
+					Model_Build_AddVertex(&b, meshindex, px * terrainscale[0] + terrainorigin[0], py * terrainscale[1] + terrainorigin[1], pz * terrainscale[2] + terrainorigin[2], 0, 0, 1, (px * terrainscale[0] + terrainorigin[0]) * texturescale[0], (py * terrainscale[1] + terrainorigin[1]) * texturescale[1]);
 				}
 			}
 			for (ty = 0, num = 0;ty < tileheight-1;ty++)
@@ -643,17 +313,17 @@
 				for (tx = 0;tx < tilewidth-1;tx++, num += 6)
 				{
 					NUint32 i = ty*tilewidth+tx;
-					Util_BuildModel_AddTriangle(&b, surfaceindex, i, i+1, i+1+tilewidth);
-					Util_BuildModel_AddTriangle(&b, surfaceindex, i, i+1+tilewidth, i+tilewidth);
+					Model_Build_AddTriangle(&b, meshindex, i, i+1, i+1+tilewidth);
+					Model_Build_AddTriangle(&b, meshindex, i, i+1+tilewidth, i+tilewidth);
 				}
 			}
 		}
 	}
 	Mem_Free(&pixels);
 	tilename = String_APrintf(Global_Zone, "%s.md5mesh", basename);
-	Util_BuildModel_Write(&b, tilename);
+	Model_Build_Write(&b, tilename);
 	String_Free(&tilename);
-	Util_BuildModel_End(&b);
+	Model_Build_Free(&b);
 }
 
 static Shell_SymbolDecl Util_Shell_MakeTerrain_Decl = {
@@ -669,7 +339,7 @@
 static void Util_Shell_ConvertOBJ(void)
 {
 	Nsize objtextsize;
-	Util_BuildModel b;
+	Model b;
 	const char *inputname = Shell_Callback_GetArg(1);
 	const char *outputname = Shell_Callback_GetArg(2);
 	char *objtext = File_LoadFile(inputname, &objtextsize);
@@ -679,10 +349,10 @@
 		// SHELLTODO
 		return;
 	}
-	Util_BuildModel_Begin(&b);
-	Util_BuildModel_ImportOBJ(&b, inputname, objtext, objtext + objtextsize);
-	Util_BuildModel_Write(&b, outputname);
-	Util_BuildModel_End(&b);
+	Model_Build_Begin(&b, Global_Zone, false);
+	Model_Build_ImportOBJ(&b, inputname, objtext, objtext + objtextsize);
+	Model_Build_Write(&b, outputname);
+	Model_Build_Free(&b);
 	Mem_Free(&objtext);
 }
 
@@ -702,7 +372,7 @@
 #define UTIL_SHELL_CONVERTLWO_FACE_MAXVERTS 4
 typedef struct Util_Shell_ConvertLWO_Face
 {
-	NUint32 surfaceindex;
+	NUint32 meshindex;
 	NUint32 numpoints;
 	float point[UTIL_SHELL_CONVERTLWO_FACE_MAXVERTS][3];
 }
@@ -823,7 +493,7 @@
 			// polygon attributes
 			if (!memcmp(chunk, "SURF", 4))
 			{
-				// list of polygons and their corresponding surfaces
+				// list of polygons and their corresponding meshes
 				chunk_ptag_surf = chunk;
 			}
 			continue;
@@ -846,7 +516,7 @@
 		if (!memcmp(chunk, "SURF", 4))
 		{
 			materialindex++;
-			// surface name, often Default
+			// mesh name, often Default
 			while (*content)
 				content++;
 			// skip to 4 byte boundary in file
@@ -965,27 +635,27 @@
 	double boxsize;
 	const char *basefilename, *baseimagename;
 	char *filename;
-	Util_BuildModel b;
+	Model b;
 	basefilename = Shell_Callback_GetArg(1);
 	baseimagename = Shell_Callback_GetArg(2);
 	boxsize = atof(Shell_Callback_GetArg(3));
-	Util_BuildModel_Begin(&b);
+	Model_Build_Begin(&b, 0, 0);
 	for (i = 0;i < 6;i++)
 	{
 		NUint32 j;
 		NUint32 indices[4];
 		char *materialname = String_APrintf(Global_Zone, "%s_%s", baseimagename, skyboxsuffix[i]);
-		NUint32 surfaceindex = Util_BuildModel_AddSurface(&b, materialname);
+		NUint32 meshindex = Model_Build_AddSurface(&b, Global_Zone, materialname, 2, 4);
 		String_Free(&materialname);
 		for (j = 0;j < 4;j++)
-			indices[j] = Util_BuildModel_FindOrAddVertex(&b, surfaceindex, skyboxvertex[i][j][0], skyboxvertex[i][j][1], skyboxvertex[i][j][2], skyboxvertex[i][j][3], skyboxvertex[i][j][4], skyboxvertex[i][j][5], skyboxvertex[i][j][6], skyboxvertex[i][j][7]);
-		Util_BuildModel_AddTriangle(&b, surfaceindex, indices[0], indices[2], indices[1]);
-		Util_BuildModel_AddTriangle(&b, surfaceindex, indices[0], indices[3], indices[2]);
+			indices[j] = Model_Build_FindOrAddVertex(&b, meshindex, skyboxvertex[i][j][0], skyboxvertex[i][j][1], skyboxvertex[i][j][2], skyboxvertex[i][j][3], skyboxvertex[i][j][4], skyboxvertex[i][j][5], skyboxvertex[i][j][6], skyboxvertex[i][j][7]);
+		Model_Build_AddTriangle(&b, meshindex, indices[0], indices[2], indices[1]);
+		Model_Build_AddTriangle(&b, meshindex, indices[0], indices[3], indices[2]);
 	}
 	filename = String_APrintf(Global_Zone, "%s.md5mesh", basefilename);
-	Util_BuildModel_Write(&b, filename);
+	Model_Build_Write(&b, filename);
 	String_Free(&filename);
-	Util_BuildModel_End(&b);
+	Model_Build_Free(&b);
 }
 
 static Shell_SymbolDecl Util_Shell_MakeSkyBox_Decl = {

Modified: trunk/util.h
===================================================================
--- trunk/util.h	2006-05-09 20:05:18 UTC (rev 713)
+++ trunk/util.h	2006-05-12 08:36:47 UTC (rev 714)
@@ -40,35 +40,6 @@
 // lex the next token
 void Util_ParseC_Lex(Util_ParseC_Thread *thread);
 
-typedef struct Util_BuildModel_Surface
-{
-	// no support for skeletal weighting since this is only used by utilities building simple models
-	char materialname[64];
-	NUint32 num_triangles, max_triangles;
-	NUint32 *data_element3i;
-	NUint32 num_vertices, max_vertices;
-	float *data_vertex8f;
-}
-Util_BuildModel_Surface;
-
-typedef struct Util_BuildModel
-{
-	NUint32 num_surfaces, max_surfaces;
-	Util_BuildModel_Surface *data_surfaces;
-	// no support for skeleton since this is only used by utilities building simple models
-}
-Util_BuildModel;
-
-// a small system for easily building md5mesh files
-void Util_BuildModel_Begin(Util_BuildModel *b);
-void Util_BuildModel_End(Util_BuildModel *b);
-NUint32 Util_BuildModel_AddSurface(Util_BuildModel *b, const char *materialname);
-NUint32 Util_BuildModel_AddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t);
-NUint32 Util_BuildModel_FindOrAddVertex(Util_BuildModel *b, NUint32 surfaceindex, float x, float y, float z, float nx, float ny, float nz, float s, float t);
-NUint32 Util_BuildModel_AddTriangle(Util_BuildModel *b, NUint32 surfaceindex, int e0, int e1, int e2);
-void Util_BuildModel_Write(Util_BuildModel *b, const char *filename);
-void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend);
-
 void Util_Init(void);
 void Util_Quit(void);
 




More information about the neither-commits mailing list