4 static void Load3DS( const char *filename, _3DS_t *p3DS, qboolean verbose );
\r
6 static qboolean s_verbose;
\r
8 #define MAX_MATERIALS 100
\r
9 #define MAX_NAMED_OBJECTS 100
\r
10 #define MAX_MESH_MATERIAL_GROUPS 100
\r
11 #define MAX_TRI_OBJECTS 512
\r
13 static char s_buffer[1000000];
\r
15 static int ReadString( FILE *fp, char *buffer )
\r
22 fread( &buffer[i], 1, sizeof( char ), fp );
\r
24 } while ( buffer[i++] != 0 );
\r
30 static int ReadChunkAndLength( FILE *fp, short *chunk, long *len )
\r
32 if ( fread( chunk, sizeof( short ), 1, fp ) != 1 )
\r
34 if ( fread( len, sizeof( long ), 1, fp ) != 1 )
\r
35 Error( "Unexpected EOF found" );
\r
39 static void LoadMapName( FILE *fp, char *buffer, int thisChunkLen )
\r
41 unsigned short chunkID;
\r
45 while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
49 case _3DS_CHUNK_MAT_MAPNAME:
\r
50 fread( buffer, chunkLen - 6, 1, fp );
\r
53 fread( s_buffer, chunkLen - 6, 1, fp );
\r
56 bytesRead += chunkLen;
\r
57 if ( bytesRead >= thisChunkLen )
\r
62 static void LoadMaterialList( FILE *fp, long thisChunkLen, _3DSMaterial_t *pMat )
\r
65 unsigned short chunkID;
\r
71 memset( &mat, 0, sizeof( mat ) );
\r
74 printf( " >>> MATERIAL LIST\n" );
\r
76 while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
80 case _3DS_CHUNK_MAT_NAME:
\r
81 fread( mat.name, chunkLen - 6, 1, fp );
\r
83 printf( " found mat name '%s'\n", mat.name );
\r
85 case _3DS_CHUNK_TEXMAP:
\r
86 LoadMapName( fp, mat.texture, chunkLen - 6 );
\r
88 printf( " found texture '%s'\n", mat.texture );
\r
90 case _3DS_CHUNK_SPECMAP:
\r
91 LoadMapName( fp, mat.specular, chunkLen - 6 );
\r
93 printf( " found specular map '%s'\n", mat.specular );
\r
95 case _3DS_CHUNK_OPACMAP:
\r
96 LoadMapName( fp, mat.opacity, chunkLen - 6 );
\r
98 printf( " found opacity map '%s'\n", mat.opacity );
\r
100 case _3DS_CHUNK_REFLMAP:
\r
101 LoadMapName( fp, mat.reflection, chunkLen - 6 );
\r
103 printf( " found reflection map '%s'\n", mat.reflection );
\r
105 case _3DS_CHUNK_BUMPMAP:
\r
106 LoadMapName( fp, mat.bump, chunkLen - 6 );
\r
108 printf( " found bump map '%s'\n", mat.bump );
\r
111 fread( s_buffer, chunkLen - 6, 1, fp );
\r
115 bytesRead += chunkLen;
\r
117 if ( bytesRead >= thisChunkLen )
\r
123 if ( mat.texture[0] )
\r
125 sprintf( buffer, "%s%s", curdir, mat.texture );
\r
126 if ( strstr( buffer, gamedir + 1 ) )
\r
127 strcpy( mat.texture, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
\r
129 strcpy( mat.texture, buffer );
\r
132 if ( mat.specular[0] )
\r
134 sprintf( buffer, "%s%s", curdir, mat.specular );
\r
135 if ( strstr( buffer, gamedir + 1 ) )
\r
136 strcpy( mat.specular, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
\r
138 strcpy( mat.specular, buffer );
\r
143 sprintf( buffer, "%s%s", curdir, mat.bump );
\r
144 if ( strstr( buffer, gamedir + 1 ) )
\r
145 strcpy( mat.bump, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
\r
147 strcpy( mat.bump, buffer );
\r
150 if ( mat.reflection[0] )
\r
152 sprintf( buffer, "%s%s", curdir, mat.reflection );
\r
153 if ( strstr( buffer, gamedir + 1 ) )
\r
154 strcpy( mat.reflection, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
\r
156 strcpy( mat.reflection, buffer );
\r
159 if ( mat.opacity[0] )
\r
161 sprintf( buffer, "%s%s", curdir, mat.opacity );
\r
162 if ( strstr( buffer, gamedir + 1 ) )
\r
163 strcpy( mat.opacity, strstr( buffer, gamedir + 1 ) + strlen( gamedir ) - 1 );
\r
165 strcpy( mat.opacity, buffer );
\r
171 static void LoadMeshMaterialGroup( FILE *fp, long thisChunkLen, _3DSMeshMaterialGroup_t *pMMG )
\r
173 _3DSMeshMaterialGroup_t mmg;
\r
175 memset( &mmg, 0, sizeof( mmg ) );
\r
177 ReadString( fp, mmg.name );
\r
179 fread( &mmg.numFaces, sizeof( mmg.numFaces ), 1, fp );
\r
180 mmg.pFaces = malloc( sizeof( mmg.pFaces[0] ) * mmg.numFaces );
\r
181 fread( mmg.pFaces, sizeof( mmg.pFaces[0] ), mmg.numFaces, fp );
\r
185 printf( " >>> MESH MATERIAL GROUP '%s' (%d faces)\n", mmg.name, mmg.numFaces );
\r
190 for ( i = 0; i < mmg.numFaces; i++ )
\r
192 printf( " %d\n", mmg.pFaces[i] );
\r
200 static void LoadNamedTriObject( FILE *fp, long thisChunkLen, _3DSTriObject_t *pTO )
\r
203 unsigned short chunkID;
\r
205 long bytesRead = 0;
\r
206 _3DSTriObject_t triObj;
\r
207 _3DSMeshMaterialGroup_t meshMaterialGroups[MAX_MESH_MATERIAL_GROUPS];
\r
208 int numMeshMaterialGroups = 0;
\r
210 memset( &triObj, 0, sizeof( triObj ) );
\r
213 printf( " >>> NAMED TRI OBJECT\n" );
\r
215 while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
219 case _3DS_CHUNK_MSH_MAT_GROUP:
\r
220 LoadMeshMaterialGroup( fp, chunkLen - 6, &meshMaterialGroups[numMeshMaterialGroups] );
\r
221 bytesRead += chunkLen;
\r
222 numMeshMaterialGroups++;
\r
224 case _3DS_CHUNK_FACE_ARRAY:
\r
225 fread( &triObj.numFaces, sizeof( triObj.numFaces ), 1, fp );
\r
226 assert( triObj.pFaces == 0 );
\r
228 triObj.pFaces = malloc( sizeof( triObj.pFaces[0] ) * triObj.numFaces );
\r
229 fread( triObj.pFaces, sizeof( triObj.pFaces[0] ), triObj.numFaces, fp );
\r
230 bytesRead += sizeof( triObj.numFaces ) + triObj.numFaces * sizeof( triObj.pFaces[0] ) + 6;
\r
234 printf( " found face array with %d faces\n", triObj.numFaces );
\r
235 for ( i = 0; i < triObj.numFaces; i++ )
\r
237 printf( " %d: %d,%d,%d\n", i, triObj.pFaces[i].a, triObj.pFaces[i].b, triObj.pFaces[i].c );
\r
242 case _3DS_CHUNK_POINT_ARRAY:
\r
243 fread( &triObj.numPoints, sizeof( triObj.numPoints ), 1, fp );
\r
244 triObj.pPoints = malloc( sizeof( triObj.pPoints[0] ) * triObj.numPoints );
\r
245 fread( triObj.pPoints, sizeof( triObj.pPoints[0] ), triObj.numPoints, fp );
\r
246 bytesRead += sizeof( triObj.numPoints ) + triObj.numPoints * sizeof( triObj.pPoints[0] ) + 6;
\r
248 // flip points around into our coordinate system
\r
249 for ( i = 0; i < triObj.numPoints; i++ )
\r
253 x = triObj.pPoints[i].x;
\r
254 y = triObj.pPoints[i].y;
\r
255 z = triObj.pPoints[i].z;
\r
257 triObj.pPoints[i].x = -y;
\r
258 triObj.pPoints[i].y = x;
\r
259 triObj.pPoints[i].z = z;
\r
264 printf( " found point array with %d points\n", triObj.numPoints );
\r
265 for ( i = 0; i < triObj.numPoints; i++ )
\r
267 printf( " %d: %f,%f,%f\n", i, triObj.pPoints[i].x, triObj.pPoints[i].y, triObj.pPoints[i].z );
\r
271 case _3DS_CHUNK_TEX_VERTS:
\r
272 fread( &triObj.numTexVerts, sizeof( triObj.numTexVerts ), 1, fp );
\r
273 triObj.pTexVerts = malloc( sizeof( triObj.pTexVerts[0] ) * triObj.numTexVerts );
\r
274 fread( triObj.pTexVerts, sizeof( triObj.pTexVerts[0] ), triObj.numTexVerts, fp );
\r
275 bytesRead += sizeof( triObj.numTexVerts ) + sizeof( triObj.pTexVerts[0] ) * triObj.numTexVerts + 6;
\r
279 printf( " found tex vert array with %d tex verts\n", triObj.numTexVerts );
\r
280 for ( i = 0; i < triObj.numTexVerts; i++ )
\r
282 printf( " %d: %f,%f\n", i, triObj.pTexVerts[i].s, triObj.pTexVerts[i].t );
\r
287 fread( s_buffer, chunkLen - 6, 1, fp );
\r
288 bytesRead += chunkLen;
\r
292 if ( bytesRead >= thisChunkLen )
\r
297 if ( numMeshMaterialGroups == 0 )
\r
299 numMeshMaterialGroups = 1;
\r
300 strcpy( meshMaterialGroups[0].name, "(null)" );
\r
301 if ( pTO->numTexVerts ) {
\r
302 printf( "Warning: assigning (null) skin to tri object\n" );
\r
307 assert( pTO->numFaces == meshMaterialGroups[0].numFaces );
\r
310 pTO->pMeshMaterialGroups = malloc( sizeof( _3DSMeshMaterialGroup_t ) * numMeshMaterialGroups );
\r
311 memcpy( pTO->pMeshMaterialGroups, meshMaterialGroups, numMeshMaterialGroups * sizeof( meshMaterialGroups[0] ) );
\r
312 pTO->numMeshMaterialGroups = numMeshMaterialGroups;
\r
317 assert( numMeshMaterialGroups <= 1 );
\r
320 static void LoadNamedObject( FILE *fp, long thisChunkLen, _3DSNamedObject_t *pNO )
\r
323 unsigned short chunkID;
\r
325 long bytesRead = 0;
\r
327 _3DSTriObject_t triObj[MAX_TRI_OBJECTS];
\r
328 int numTriObjects = 0;
\r
330 memset( triObj, 0, sizeof( triObj ) );
\r
332 bytesRead += ReadString( fp, name );
\r
335 printf( " >>> NAMED OBJECT '%s'\n", name );
\r
337 while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
341 case _3DS_CHUNK_NAMED_TRI_OBJECT:
\r
342 LoadNamedTriObject( fp, chunkLen - 6, &triObj[numTriObjects] );
\r
346 fread( s_buffer, chunkLen - 6, 1, fp );
\r
350 bytesRead += chunkLen;
\r
352 if ( bytesRead >= thisChunkLen )
\r
356 strcpy( pNO->name, name );
\r
357 pNO->pTriObjects = malloc( sizeof( _3DSTriObject_t ) * numTriObjects );
\r
358 memcpy( pNO->pTriObjects, triObj, sizeof( triObj[0] ) * numTriObjects );
\r
359 pNO->numTriObjects = numTriObjects;
\r
361 assert( numTriObjects <= 1 );
\r
364 static void LoadEditChunk( FILE *fp, long thisChunkLen, _3DSEditChunk_t *pEC )
\r
366 unsigned short chunkID;
\r
368 long bytesRead = 0;
\r
369 _3DSEditChunk_t editChunk;
\r
371 _3DSMaterial_t mat[MAX_MATERIALS];
\r
372 _3DSNamedObject_t namedObjects[MAX_NAMED_OBJECTS];
\r
374 int numMaterials = 0, numNamedObjects = 0;
\r
376 memset( &editChunk, 0, sizeof( editChunk ) );
\r
379 printf( ">>> EDIT CHUNK\n" );
\r
381 while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
385 case _3DS_CHUNK_MAT_LIST:
\r
386 LoadMaterialList( fp, chunkLen - 6, &mat[numMaterials] );
\r
389 case _3DS_CHUNK_NAMED_OBJECT:
\r
390 LoadNamedObject( fp, chunkLen - 6, &namedObjects[numNamedObjects] );
\r
391 if ( namedObjects[numNamedObjects].numTriObjects != 0 )
\r
394 case _3DS_CHUNK_MESH_VERSION:
\r
396 fread( s_buffer, chunkLen - 6, 1, fp );
\r
400 bytesRead += chunkLen;
\r
402 if ( bytesRead >= thisChunkLen )
\r
406 if ( numMaterials == 0 )
\r
409 strcpy( mat[0].name, "(null)" );
\r
410 printf( "Warning: no material definitions found\n" );
\r
413 pEC->numNamedObjects = numNamedObjects;
\r
415 pEC->pMaterials = malloc( sizeof( _3DSMaterial_t ) * numMaterials );
\r
416 pEC->pNamedObjects = malloc( sizeof( _3DSNamedObject_t ) * numNamedObjects );
\r
418 memcpy( pEC->pMaterials, mat, numMaterials * sizeof( mat[0] ) );
\r
419 memcpy( pEC->pNamedObjects, namedObjects, numNamedObjects * sizeof( namedObjects[0] ) );
\r
422 static void Load3DS( const char *filename, _3DS_t *p3DS, qboolean verbose )
\r
425 unsigned short chunkID;
\r
427 _3DSEditChunk_t editChunk;
\r
429 s_verbose = verbose;
\r
431 if ( ( fp = fopen( filename, "rb" ) ) == 0 )
\r
432 Error( "Unable to open '%s'", filename );
\r
434 // read magic number
\r
435 if ( ( fread( &chunkID, sizeof( short ), 1, fp ) != 1 ) ||
\r
436 ( LittleShort( chunkID ) != _3DS_CHUNK_MAGIC ) )
\r
438 Error( "Missing or incorrect magic number in '%s'", filename );
\r
440 if ( fread( &chunkLen, sizeof( chunkLen ), 1, fp ) != 1 )
\r
441 Error( "Unexpected EOF encountered in '%s'", filename );
\r
443 if ( !ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
444 Error( "Missing version number in '%s'", filename );
\r
445 if ( fread( s_buffer, chunkLen - 6, 1, fp ) != 1 )
\r
446 Error( "Unexpected EOF encountered in '%s'", filename );
\r
448 while ( ReadChunkAndLength( fp, &chunkID, &chunkLen ) )
\r
452 case _3DS_CHUNK_EDIT:
\r
453 LoadEditChunk( fp, chunkLen - 6, &editChunk );
\r
455 case _3DS_CHUNK_KEYFRAME_DATA:
\r
456 fread( s_buffer, chunkLen - 6, 1, fp );
\r
459 fread( s_buffer, chunkLen - 6, 1, fp );
\r
466 p3DS->editChunk = editChunk;
\r
469 static void ComputeNormals( _3DSTriObject_t *pTO, triangle_t *pTris )
\r
471 vec3_t faceNormals[POLYSET_MAXTRIANGLES];
\r
472 vec3_t vertexNormals[POLYSET_MAXTRIANGLES*3];
\r
473 vec3_t side0, side1, facenormal;
\r
476 memset( faceNormals, 0, sizeof( faceNormals ) );
\r
477 memset( vertexNormals, 0, sizeof( vertexNormals ) );
\r
480 // compute face normals
\r
482 for ( f = 0; f < pTO->numFaces; f++ )
\r
484 VectorSubtract( pTris[f].verts[0], pTris[f].verts[1], side0 );
\r
485 VectorSubtract( pTris[f].verts[2], pTris[f].verts[1], side1 );
\r
487 CrossProduct( side0, side1, facenormal );
\r
488 VectorNormalize( facenormal, faceNormals[f] );
\r
492 // sum vertex normals
\r
494 for ( v = 0; v < pTO->numPoints; v++ )
\r
496 for ( f = 0; f < pTO->numFaces; f++ )
\r
498 if ( ( pTO->pFaces[f].a == v ) ||
\r
499 ( pTO->pFaces[f].b == v ) ||
\r
500 ( pTO->pFaces[f].c == v ) )
\r
502 vertexNormals[v][0] += faceNormals[f][0];
\r
503 vertexNormals[v][1] += faceNormals[f][1];
\r
504 vertexNormals[v][2] += faceNormals[f][2];
\r
508 VectorNormalize( vertexNormals[v], vertexNormals[v] );
\r
512 // copy vertex normals into triangles
\r
514 for ( f = 0; f < pTO->numFaces; f++ )
\r
516 int i0 = pTO->pFaces[f].c;
\r
517 int i1 = pTO->pFaces[f].b;
\r
518 int i2 = pTO->pFaces[f].a;
\r
520 VectorCopy( vertexNormals[i0], pTris[f].normals[0] );
\r
521 VectorCopy( vertexNormals[i1], pTris[f].normals[1] );
\r
522 VectorCopy( vertexNormals[i2], pTris[f].normals[2] );
\r
527 ** void _3DS_LoadPolysets
\r
529 void _3DS_LoadPolysets( const char *filename, polyset_t **ppPSET, int *numpsets, qboolean verbose )
\r
534 triangle_t *ptri, *triangles;
\r
538 memset( &_3ds, 0, sizeof( _3ds ) );
\r
539 Load3DS( filename, &_3ds, verbose );
\r
541 // compute information
\r
542 numPolysets = _3ds.editChunk.numNamedObjects;
\r
545 pPSET = calloc( 1, numPolysets * sizeof( polyset_t ) );
\r
546 triangles = ptri = calloc( 1, POLYSET_MAXTRIANGLES * sizeof( triangle_t ) );
\r
548 // copy the data over
\r
549 for ( i = 0; i < numPolysets; i++ )
\r
551 char matnamebuf[1024];
\r
554 _3DSTriObject_t *pTO = &_3ds.editChunk.pNamedObjects[i].pTriObjects[0];
\r
556 pPSET[i].triangles = ptri;
\r
557 pPSET[i].numtriangles = pTO->numFaces;
\r
558 strcpy( pPSET[i].name, _3ds.editChunk.pNamedObjects[i].name );
\r
560 strcpy( matnamebuf, filename );
\r
561 if ( strrchr( matnamebuf, '/' ) )
\r
562 *( strrchr( matnamebuf, '/' ) + 1 )= 0;
\r
563 strcat( matnamebuf, pTO->pMeshMaterialGroups[0].name );
\r
565 if ( strstr( matnamebuf, gamedir ) )
\r
566 strcpy( pPSET[i].materialname, strstr( matnamebuf, gamedir ) + strlen( gamedir ) );
\r
568 strcpy( pPSET[i].materialname, pTO->pMeshMaterialGroups[0].name );
\r
570 assert( pPSET[i].numtriangles < POLYSET_MAXTRIANGLES );
\r
572 for ( tri = ptri, j = 0; j < pPSET[i].numtriangles; j++ )
\r
574 int i0 = pTO->pFaces[j].c;
\r
575 int i1 = pTO->pFaces[j].b;
\r
576 int i2 = pTO->pFaces[j].a;
\r
578 tri->verts[0][0] = pTO->pPoints[i0].x;
\r
579 tri->verts[0][1] = pTO->pPoints[i0].y;
\r
580 tri->verts[0][2] = pTO->pPoints[i0].z;
\r
582 tri->verts[1][0] = pTO->pPoints[i1].x;
\r
583 tri->verts[1][1] = pTO->pPoints[i1].y;
\r
584 tri->verts[1][2] = pTO->pPoints[i1].z;
\r
586 tri->verts[2][0] = pTO->pPoints[i2].x;
\r
587 tri->verts[2][1] = pTO->pPoints[i2].y;
\r
588 tri->verts[2][2] = pTO->pPoints[i2].z;
\r
590 for ( k = 0; k < 3; k++ )
\r
592 tri->colors[0][k] = 1;
\r
593 tri->colors[1][k] = 1;
\r
594 tri->colors[2][k] = 1;
\r
598 if ( pTO->pTexVerts )
\r
600 tri->texcoords[0][0] = pTO->pTexVerts[i0].s;
\r
601 tri->texcoords[0][1] = 1.0f - pTO->pTexVerts[i0].t;
\r
602 tri->texcoords[1][0] = pTO->pTexVerts[i1].s;
\r
603 tri->texcoords[1][1] = 1.0f - pTO->pTexVerts[i1].t;
\r
604 tri->texcoords[2][0] = pTO->pTexVerts[i2].s;
\r
605 tri->texcoords[2][1] = 1.0f - pTO->pTexVerts[i2].t;
\r
611 ptri += pPSET[i].numtriangles;
\r
612 assert( ptri - triangles < POLYSET_MAXTRIANGLES );
\r
615 // compute normal data
\r
617 for ( i = 0; i < numPolysets; i++ )
\r
619 // unique vertices based solely on vertex position
\r
620 ComputeNormals( &_3ds.editChunk.pNamedObjects[i].pTriObjects[0],
\r
621 pPSET[i].triangles );
\r
625 free( _3ds.editChunk.pMaterials );
\r
626 free( _3ds.editChunk.pNamedObjects );
\r
629 *numpsets = numPolysets;
\r