r689 - trunk
lordhavoc at icculus.org
lordhavoc at icculus.org
Fri Apr 7 20:45:03 EDT 2006
Author: lordhavoc
Date: 2006-04-07 20:45:02 -0400 (Fri, 07 Apr 2006)
New Revision: 689
Modified:
trunk/util.c
trunk/util.h
Log:
added a util_convertobj command
rewrote/replaced Util_WriteModel with Util_BuildModel system, which
allows easier construction of md5mesh files by featuring vertex lookups
and adaptive allocations (so you can simply add a triangle to the mesh
for instance)
Modified: trunk/util.c
===================================================================
--- trunk/util.c 2006-04-08 00:42:44 UTC (rev 688)
+++ trunk/util.c 2006-04-08 00:45:02 UTC (rev 689)
@@ -240,48 +240,377 @@
#undef ReadNext
}
-// FIXME: this is very unlikely to overflow but it should be made buffer size safe at some point
-void Util_WriteModel(const char *filename, NUint32 nummeshes, Util_Mesh *meshes)
+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(int[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;i < nummeshes;i++)
- textmaxsize += meshes[i].numvertices * 60 + meshes[i].numtriangles * 40;
+ 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", nummeshes);
- for (i = 0;i < nummeshes;i++)
+ 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 + meshes[i].numvertices * 100 + meshes[i].numtriangles * 100 + meshes[i].numvertices * 100 + 1000)
+ if (textmaxsize < textsize + surface->num_vertices * 100 + surface->num_triangles * 100 + surface->num_vertices * 100 + 1000)
{
- textmaxsize = textsize + meshes[i].numvertices * 200 + meshes[i].numtriangles * 200 + meshes[i].numvertices * 200 + 2000;
+ 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", meshes[i].materialname, meshes[i].numvertices);
- for (num = 0;num < meshes[i].numvertices;num++)
- textsize += snprintf(text + textsize, textmaxsize - textsize, "\tvert %u ( %.6f %.6f ) %u 1\n", num, meshes[i].texcoord2f[num*2+0], meshes[i].texcoord2f[num*2+1], num);
- textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumtris %u\n", meshes[i].numtriangles);
- for (num = 0;num < meshes[i].numtriangles;num++)
- textsize += snprintf(text + textsize, textmaxsize - textsize, "\ttri %u %u %u %u\n", num, meshes[i].element3i[num*3+0], meshes[i].element3i[num*3+1], meshes[i].element3i[num*3+2]);
- textsize += snprintf(text + textsize, textmaxsize - textsize, "\n\tnumweights %u\n", meshes[i].numvertices);
- for (num = 0;num < meshes[i].numvertices;num++)
- textsize += snprintf(text + textsize, textmaxsize - textsize, "\tweight %u 0 1.000000 ( %.6f %.6f %.6f )\n", num, meshes[i].vertex3f[num*3+0], meshes[i].vertex3f[num*3+1], meshes[i].vertex3f[num*3+2]);
+ 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);
}
+#if 1
+void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend)
+#else
+static NUint32 default_remapcoords[3] = {0, 1, 2};
+static float default_scalecoords[3] = {1, 1, 1};
+
+void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend, Nbool flip, NUint32 remapcoords[3], float scalecoords[3])
+#endif
+{
+ 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;
+#if 0
+ if (remapcoords == NULL)
+ remapcoords = default_remapcoords;
+ if (scalecoords == NULL)
+ scalecoords = default_scalecoords;
+#endif
+ 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]));
+ }
+#if 1
+ 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]);
+#else
+ data_vertex3f[num_vertices*3+remapcoords[0]] = atof(argv[1]) * scalecoords[0];
+ data_vertex3f[num_vertices*3+remapcoords[1]] = atof(argv[2]) * scalecoords[1];
+ data_vertex3f[num_vertices*3+remapcoords[2]] = atof(argv[3]) * scalecoords[2];
+#endif
+ 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]));
+ }
+#if 1
+ 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]);
+#else
+ data_normal3f[num_normals*3+remapcoords[0]] = atof(argv[1]) * scalecoords[0];
+ data_normal3f[num_normals*3+remapcoords[1]] = atof(argv[2]) * scalecoords[1];
+ data_normal3f[num_normals*3+remapcoords[2]] = atof(argv[3]) * scalecoords[2];
+#endif
+ 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)
+ {
+#if 0
+ if (flip)
+ Util_BuildModel_AddTriangle(b, surfaceindex, indices[0], indices[i], indices[i-1]);
+ else
+#endif
+ 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 i, tilesize, width, height, bx, by, tx, ty, tilewidth, tileheight, num, nummeshes, tileswidth, tilesheight;
+ NUint32 tilesize, width, height, bx, by, tx, ty, tilewidth, tileheight, num, tileswidth, tilesheight;
NUint8 *pixels;
const char *basename, *imagename, *materialname;
char *tilename;
Nvec terrainsize[3], texturesize[2], terrainscale[3], terrainorigin[3], texturescale[2];
- Util_Mesh *meshes, *mesh;
+ Util_BuildModel b;
basename = Shell_Callback_GetArg(1);
imagename = Shell_Callback_GetArg(2);
tilesize = (int) Shell_Callback_GetArgValue(3);
@@ -313,10 +642,295 @@
terrainorigin[2] = terrainsize[2] * -0.5;
tileswidth = width / tilesize;
tilesheight = height / tilesize;
- nummeshes = 0;
+ Util_BuildModel_Begin(&b);
for (by = 0;by < height;by += tilesize)
+ {
for (bx = 0;bx < width;bx += tilesize)
- nummeshes++;
+ {
+ NUint32 surfaceindex = Util_BuildModel_AddSurface(&b, materialname);
+ tilewidth = Bound(0, width - bx, tilesize+2);
+ tileheight = Bound(0, height - by, tilesize+2);
+ for (ty = 0, num = 0;ty < tileheight;ty++)
+ {
+ for (tx = 0;tx < tilewidth;tx++, num++)
+ {
+ NUint32 w = width*4;
+ NUint8 *p = pixels + ((by + ty) * width + (bx + tx)) * 4;
+ NUint32 pxi, pyi;
+ double px, py, pz, pxf, pyf;
+ px = bx + Bound(0.5, tx, tilewidth - 1.5);
+ py = by + Bound(0.5, ty, tileheight - 1.5);
+ pxi = (int)px;
+ pyi = (int)py;
+ pxf = px - pxi;
+ 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]);
+ }
+ }
+ for (ty = 0, num = 0;ty < tileheight-1;ty++)
+ {
+ 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);
+ }
+ }
+ }
+ }
+ Mem_Free(&pixels);
+ tilename = String_APrintf(Global_Zone, "%s.md5mesh", basename);
+ Util_BuildModel_Write(&b, tilename);
+ String_Free(&tilename);
+ Util_BuildModel_End(&b);
+}
+
+static Shell_SymbolDecl Util_Shell_MakeTerrain_Decl = {
+ "util_maketerrain",
+ "Turn a heightmap image into a set of md5mesh files.",
+ "Usage: util_maketerrain <maps/mymap/terrain> <image.tga> <tilesize> <terrainsizex> <terrainsizey> <terrainsizez> <material> <texturerepeatsizex> <texturerepeatsizey>\n"
+ "Example: util_maketerrain maps/mymap/terrain maps/mymap/terrain.tga 32 1000 1000 1000 maps/mymap/grass 32 32\n"
+ "would produce md5mesh tiles named maps/mymap/terrain_00_00.md5mesh and up (each containing up to 33x33 vertices and 32x32x2 triangles) comprising a 1000m wide x 1000m long x 1000m high terrain with a material named maps/mymap/grass repeating every 32m x 32m",
+ "ssvvvvsvv",
+ (Shell_Symbol_Callback) Util_Shell_MakeTerrain
+};
+
+static void Util_Shell_ConvertOBJ(void)
+{
+ Nsize objtextsize;
+ Util_BuildModel b;
+ const char *inputname = Shell_Callback_GetArg(1);
+ const char *outputname = Shell_Callback_GetArg(2);
+#if 0
+ float scale = atof(Shell_Callback_GetArg(3));
+ Nbool flip = atoi(Shell_Callback_GetArg(4)) != 0;
+ NUint32 conversionmode = atoi(Shell_Callback_GetArg(5));
+ NUint32 remapcoords[3];
+ float scalecoords[3];
+#endif
+ char *objtext = File_LoadFile(inputname, &objtextsize);
+ if (!objtext)
+ {
+ Shell_Callback_ThrowError("Could not open OBJ file\n");
+ // SHELLTODO
+ return;
+ }
+ Util_BuildModel_Begin(&b);
+#if 1
+ Util_BuildModel_ImportOBJ(&b, inputname, objtext, objtext + objtextsize);
+#else
+ scalecoords[0] = conversionmode & 1 ? -scale : scale;
+ scalecoords[1] = conversionmode & 2 ? -scale : scale;
+ scalecoords[2] = conversionmode & 4 ? -scale : scale;
+ switch((conversionmode / 8) % 6)
+ {
+ default:
+ case 0: remapcoords[0] = 0;remapcoords[1] = 1;remapcoords[2] = 2;break;
+ case 1: remapcoords[0] = 0;remapcoords[1] = 2;remapcoords[2] = 1;break;
+ case 2: remapcoords[0] = 1;remapcoords[1] = 0;remapcoords[2] = 2;break;
+ case 3: remapcoords[0] = 1;remapcoords[1] = 2;remapcoords[2] = 0;break;
+ case 4: remapcoords[0] = 2;remapcoords[1] = 0;remapcoords[2] = 1;break;
+ case 5: remapcoords[0] = 2;remapcoords[1] = 1;remapcoords[2] = 0;break;
+ }
+ Util_BuildModel_ImportOBJ(&b, inputname, objtext, objtext + objtextsize, flip, remapcoords, scalecoords);
+#endif
+ Util_BuildModel_Write(&b, outputname);
+ Util_BuildModel_End(&b);
+ Mem_Free(&objtext);
+}
+
+static Shell_SymbolDecl Util_Shell_ConvertOBJ_Decl = {
+ "util_convertobj",
+ "Turn a .obj model into a .md5mesh model file.",
+#if 1
+ "Usage: util_convertobj <inputname> <outputname>\n"
+ "Example: util_convertobj maps/mymap/mymodel.obj maps/mymap/mymodel.md5mesh",
+ "ss",
+#else
+ "Usage: util_convertobj <inputname> <outputname> <scale> <fliptriangles> <coordinateconversionmode>\n"
+ "Example: util_convertobj maps/mymap/mymodel.obj maps/mymap/mymodel.md5mesh 1 0 8\n"
+ "coordinate conversion mode is a special number that rotates and/or mirrors the geometry, it is in the range 0-47, example value for most 3D programs is 8",
+ "ssvvv",
+#endif
+ (Shell_Symbol_Callback) Util_Shell_ConvertOBJ
+};
+
+
+
+/*
+UNFINISHED
+#define UTIL_SHELL_CONVERTLWO_FACE_MAXVERTS 4
+typedef struct Util_Shell_ConvertLWO_Face
+{
+ NUint32 surfaceindex;
+ NUint32 numpoints;
+ float point[UTIL_SHELL_CONVERTLWO_FACE_MAXVERTS][3];
+}
+Util_Shell_ConvertLWO_Face;
+
+static void Util_Shell_ConvertLWO(void)
+{
+ NUint8 *lwodata;
+ Nsize lwosize;
+
+ NUint32 i, tilesize, width, height, bx, by, tx, ty, tilewidth, tileheight, num, nummeshes, tileswidth, tilesheight;
+ NUint8 *pixels;
+ const char *basename, *imagename, *materialname;
+ char *tilename;
+ Nvec terrainsize[3], texturesize[2], terrainscale[3], terrainorigin[3], texturescale[2];
+ Util_Mesh *meshes, *mesh;
+
+ inputname = Shell_Callback_GetArg(1);
+ outputname = Shell_Callback_GetArg(2);
+ lwodata = File_LoadFile(inputname, &lwosize);
+ if (!lwodata)
+ {
+ Shell_Callback_ThrowError("Could not open LWO file\n");
+ // SHELLTODO
+ return;
+ }
+ if (lwosize < 8 || memcmp(lwodata, "FORM", 4))
+ {
+ Mem_Free(&lwodata);
+ Shell_Callback_ThrowError("Not an Interchange File Format (and therefore not an LWO file)\n");
+ // SHELLTODO
+ return;
+ }
+ if ((lwodata[4] * 16777216 + lwodata[5] * 65536 + lwodata[6] * 256 + lwodata[7]) + 8 > lwosize)
+ {
+ Mem_Free(&lwodata);
+ Shell_Callback_ThrowError("Corrupt Interchange File Format file (truncated FORM chunk)\n");
+ // SHELLTODO
+ return;
+ }
+ if (memcmp(lwodata + 8, "LWO2", 4))
+ {
+ Mem_Free(&lwodata);
+ Shell_Callback_ThrowError("File is Interchange File Format but not an LWO2 (Lightwave 6 or later) file\n");
+ // SHELLTODO
+ return;
+ }
+ lwodatastart = lwodata + 12;
+ lwodataend = lwodata + 8 + (lwodata[4] * 16777216 + lwodata[5] * 65536 + lwodata[6] * 256 + lwodata[7]);
+ chunk_pnts = NULL;
+ chunk_vmap_txuv = NULL;
+ chunk_pols_face = NULL;
+ chunk_ptag_surf = NULL;
+ chunk_vmap_txuv_numtexcoordcomponents = 0;
+ chunk_vmap_txuv_numtexcoords = 0;
+ chunk_vmap_txuv_texcoords = NULL;
+ for (chunk = lwodatastart;chunk <= lwodataend - 8;chunk = contentend)
+ {
+ chunksize = (chunk[4] * 16777216 + chunk[5] * 65536 + chunk[6] * 256 + chunk[7]);
+ content = chunk;
+ contentend = chunk + 8 + chunksize;
+ if (!memcmp(chunk, "PNTS"))
+ {
+ chunk_pnts = chunk;
+ continue;
+ }
+ if (!memcmp(chunk, "VMAP"))
+ {
+ // read type of vertex map
+ if (!memcmp(content, "TXUV", 4))
+ {
+ //
+ chunk_vmap_txuv = chunk;
+ content += 4;
+ // read number of components
+ chunk_vmap_txuv_numtexcoordcomponents = content[0] * 256 + content[1]);
+ content += 2;
+ // skip name of this TXUV chunk, typically Texture
+ while (*content)
+ content++;
+ // skip to 4 byte boundary in file
+ while ((content - lwodatastart) & 3)
+ content++;
+ chunk_vmap_txuv_numtexcoords = (contentend - content) / (numtexcoordcomponents * 4);
+ chunk_vmap_txuv_texcoords = content;
+ }
+ continue;
+ }
+ if (!memcmp(chunk, "POLS", 4))
+ {
+ // polygons
+ if (!memcmp(content, "FACE", 4))
+ {
+ // polygons stored as short numpoints, short index[]
+ chunk_pols_face = chunk;
+ // count the number of triangles we'll be loading
+ content += 4;
+ polygons = content;
+ numtriangles = 0;
+ numpolygons = 0;
+ polygonmaterials = Mem_Alloc(Global_Zone, numpolygons * sizeof(short));
+ while (content < contentend)
+ {
+ int p;
+ p = content[2] * 256 + content[3];
+ content += 2;
+ numpolygons++;
+ if (p >= 3)
+ numtriangles += p - 2;
+ for (;p;p--)
+ content += 2;
+ }
+ }
+ continue;
+ }
+ if (!memcmp(chunk, "PTAG", 4))
+ {
+ // polygon attributes
+ if (!memcmp(chunk, "SURF", 4))
+ {
+ // list of polygons and their corresponding surfaces
+ chunk_ptag_surf = chunk;
+ }
+ continue;
+ }
+ if (!memcmp(chunk, "CLIP", 4))
+ {
+ //unknown
+ content += 4;
+ imageindex++;
+ for (;content < contentend;content = nextcontent)
+ {
+ nextcontent = content + content[4] * 256 + content[5];
+ if (!memcmp(content, "STIL", 4))
+ {
+ // image name
+ strncpy(imagename[imageindex], content, sizeof(imagename[imageindex]) - 1);
+ }
+ }
+ }
+ if (!memcmp(chunk, "SURF", 4))
+ {
+ materialindex++;
+ // surface name, often Default
+ while (*content)
+ content++;
+ // skip to 4 byte boundary in file
+ while ((content - lwodatastart) & 3)
+ content++;
+ for (;content < contentend;content = nextcontent)
+ {
+ nextcontent = content + content[4] * 256 + content[5];
+ if (!memcmp(content, "IMAG", 4))
+ {
+ // image index
+ materialimage[materialindex] = content[6] * 256 + content[7];
+ }
+ }
+ }
+ }
+
+ polygonmaterials = Mem_Alloc(Global_Zone,
+ for (
+
+
//nummeshes = tileswidth * tilesheight;
meshes = Mem_Alloc(Global_Zone, nummeshes * sizeof(Util_Mesh));
mesh = meshes;
@@ -394,29 +1008,18 @@
"ssvvvvsvv",
(Shell_Symbol_Callback) Util_Shell_MakeTerrain
};
+*/
-float skyboxvertex3f[6*4*3] =
+float skyboxvertex[6][4][8] =
{
- 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, -1, 1, // px
- -1, -1, 1, -1, -1, -1, -1, 1, -1, -1, 1, 1, // nx
- 1, -1, 1, 1, -1, -1, -1, -1, -1, -1, -1, 1, // py
- -1, 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, // ny
- -1, 1, 1, 1, 1, 1, 1, -1, 1, -1, -1, 1, // pz
- 1, 1, -1, -1, 1, -1, -1, -1, -1, 1, -1, -1 // nz
+ {{ 1, 1, 1, -1, 0, 0, 0, 1}, { 1, 1, -1, -1, 0, 0, 1, 1}, { 1, -1, -1, -1, 0, 0, 1, 0}, { 1, -1, 1, -1, 0, 0, 0, 0}}, // px
+ {{-1, -1, 1, 1, 0, 0, 1, 0}, {-1, -1, -1, 1, 0, 0, 0, 0}, {-1, 1, -1, 1, 0, 0, 0, 1}, {-1, 1, 1, 1, 0, 0, 1, 1}}, // nx
+ {{ 1, -1, 1, 0, -1, 0, 1, 1}, { 1, -1, -1, 0, -1, 0, 1, 0}, {-1, -1, -1, 0, -1, 0, 0, 0}, {-1, -1, 1, 0, -1, 0, 0, 1}}, // py
+ {{-1, 1, 1, 0, 1, 0, 0, 0}, {-1, 1, -1, 0, 1, 0, 0, 1}, { 1, 1, -1, 0, 1, 0, 1, 1}, { 1, 1, 1, 0, 1, 0, 1, 0}}, // ny
+ {{-1, 1, 1, 0, 0, -1, 0, 1}, { 1, 1, 1, 0, 0, -1, 1, 1}, { 1, -1, 1, 0, 0, -1, 1, 0}, {-1, -1, 1, 0, 0, -1, 0, 0}}, // pz
+ {{ 1, 1, -1, 0, 0, 1, 0, 1}, {-1, 1, -1, 0, 0, 1, 1, 1}, {-1, -1, -1, 0, 0, 1, 1, 0}, { 1, -1, -1, 0, 0, 1, 0, 0}} // nz
};
-float skyboxtexcoord2f[6*4*2] =
-{
- 0, 1, 1, 1, 1, 0, 0, 0, // px
- 1, 0, 0, 0, 0, 1, 1, 1, // nx
- 1, 1, 1, 0, 0, 0, 0, 1, // py
- 0, 0, 0, 1, 1, 1, 1, 0, // ny
- 0, 1, 1, 1, 1, 0, 0, 0, // pz
- 0, 1, 1, 1, 1, 0, 0, 0 // nz
-};
-
-NUint32 skyboxelements[6] = {0, 2, 1, 0, 3, 2};
-
const char *skyboxsuffix[6] = {"px", "nx", "py", "ny", "pz", "nz"};
static void Util_Shell_MakeSkyBox(void)
@@ -424,29 +1027,28 @@
NUint32 i;
double boxsize;
const char *basefilename, *baseimagename;
- char *filename, *materialname[6];
- float verts[6*4*3];
- Util_Mesh meshes[6];
+ char *filename;
+ Util_BuildModel b;
basefilename = Shell_Callback_GetArg(1);
baseimagename = Shell_Callback_GetArg(2);
boxsize = atof(Shell_Callback_GetArg(3));
+ Util_BuildModel_Begin(&b);
for (i = 0;i < 6;i++)
{
- materialname[i] = String_APrintf(Global_Zone, "%s_%s", baseimagename, skyboxsuffix[i]);
- meshes[i].materialname = materialname[i];
- meshes[i].numvertices = 4;
- meshes[i].vertex3f = verts + i*4*3;
- meshes[i].texcoord2f = skyboxtexcoord2f + i*4*2;
- meshes[i].numtriangles = 2;
- meshes[i].element3i = skyboxelements;
+ NUint32 j;
+ NUint32 indices[4];
+ char *materialname = String_APrintf(Global_Zone, "%s_%s", baseimagename, skyboxsuffix[i]);
+ NUint32 surfaceindex = Util_BuildModel_AddSurface(&b, materialname);
+ 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]);
}
- for (i = 0;i < 72;i++)
- verts[i] = skyboxvertex3f[i] * boxsize;
filename = String_APrintf(Global_Zone, "%s.md5mesh", basefilename);
- Util_WriteModel(filename, 6, meshes);
+ Util_BuildModel_Write(&b, filename);
String_Free(&filename);
- for (i = 0;i < 6;i++)
- String_Free(&materialname[i]);
+ Util_BuildModel_End(&b);
}
static Shell_SymbolDecl Util_Shell_MakeSkyBox_Decl = {
@@ -463,6 +1065,7 @@
{
Shell_RegisterFunction(&Util_Shell_MakeTerrain_Decl);
Shell_RegisterFunction(&Util_Shell_MakeSkyBox_Decl);
+ Shell_RegisterFunction(&Util_Shell_ConvertOBJ_Decl);
}
void Util_Quit(void)
Modified: trunk/util.h
===================================================================
--- trunk/util.h 2006-04-08 00:42:44 UTC (rev 688)
+++ trunk/util.h 2006-04-08 00:45:02 UTC (rev 689)
@@ -40,21 +40,39 @@
// lex the next token
void Util_ParseC_Lex(Util_ParseC_Thread *thread);
-typedef struct Util_Mesh
+typedef struct Util_BuildModel_Surface
{
// no support for skeletal weighting since this is only used by utilities building simple models
- const char *materialname;
- NUint32 numvertices;
- float *vertex3f;
- float *texcoord2f;
- NUint32 numtriangles;
- NUint32 *element3i;
+ char materialname[64];
+ NUint32 num_triangles, max_triangles;
+ NUint32 *data_element3i;
+ NUint32 num_vertices, max_vertices;
+ float *data_vertex8f;
}
-Util_Mesh;
+Util_BuildModel_Surface;
-// writes a .md5mesh file given an array of meshes
-void Util_WriteModel(const char *filename, NUint32 nummeshes, Util_Mesh *meshes);
+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);
+#if 1
+void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend);
+#else
+void Util_BuildModel_ImportOBJ(Util_BuildModel *b, const char *inputname, const char *text, const char *textend, Nbool flip, NUint32 remapcoords[3], float scalecoords[3]);
+#endif
+
void Util_Init(void);
void Util_Quit(void);
More information about the neither-commits
mailing list