/* Copyright (C) 1999-2006 Id Software, Inc. and contributors. For a list of contributors, see the accompanying CONTRIBUTORS file. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ // // l3dslib.c: library for loading triangles from an Alias triangle file // #include #include "cmdlib.h" #include "inout.h" #include "mathlib.h" #include "trilib.h" #include "l3dslib.h" #include "token.h" #include "fmodel.h" #include "bspfile.h" #define MAIN3DS 0x4D4D #define EDIT3DS 0x3D3D // this is the start of the editor config #define EDIT_OBJECT 0x4000 #define OBJ_TRIMESH 0x4100 #define TRI_VERTEXL 0x4110 #define TRI_FACEL1 0x4120 #define MAXVERTS 2000 typedef struct { int v[4]; } tri; float fverts[MAXVERTS][3]; tri tris[MAXTRIANGLES]; int bytesread, level, numtris, totaltris; int vertsfound, trisfound; triangle_t *ptri; void DefaultNodesList( mesh_node_t **nodesList, int *num_mesh_nodes, int *numtriangles ){ int pos, bit, i; if ( nodesList ) { *num_mesh_nodes = 1; memset( &( *nodesList )[0], 0, sizeof( mesh_node_t ) ); strcpy( ( *nodesList )[0].name, "default" ); // set all of the tris to be used for the top node for ( i = 0; i < ( *numtriangles ); i++ ) { pos = ( i ) >> 3; bit = 1 << ( ( i ) & 7 ); ( *nodesList )[0].tris[pos] |= bit; } } } // Alias stores triangles as 3 explicit vertices in .tri files, so even though we // start out with a vertex pool and vertex indices for triangles, we have to convert // to raw, explicit triangles void StoreAliasTriangles( void ){ int i, j, k; if ( ( totaltris + numtris ) > MAXTRIANGLES ) { Error( "Error: Too many triangles" ); } for ( i = 0; i < numtris ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) { for ( k = 0 ; k < 3 ; k++ ) { ptri[i + totaltris].verts[j][k] = fverts[tris[i].v[j]][k]; } } } totaltris += numtris; numtris = 0; vertsfound = 0; trisfound = 0; } int ParseVertexL( FILE *input ){ int i, j, startbytesread, numverts; unsigned short tshort; if ( vertsfound ) { Error( "Error: Multiple vertex chunks" ); } vertsfound = 1; startbytesread = bytesread; if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &tshort, sizeof( tshort ), 1, input ); bytesread += sizeof( tshort ); numverts = (int)tshort; if ( numverts > MAXVERTS ) { Error( "Error: Too many vertices" ); } for ( i = 0 ; i < numverts ; i++ ) { for ( j = 0 ; j < 3 ; j++ ) { if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &fverts[i][j], sizeof( float ), 1, input ); bytesread += sizeof( float ); } } if ( vertsfound && trisfound ) { StoreAliasTriangles(); } return bytesread - startbytesread; } int ParseFaceL1( FILE *input ){ int i, j, startbytesread; unsigned short tshort; if ( trisfound ) { Error( "Error: Multiple face chunks" ); } trisfound = 1; startbytesread = bytesread; if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &tshort, sizeof( tshort ), 1, input ); bytesread += sizeof( tshort ); numtris = (int)tshort; if ( numtris > MAXTRIANGLES ) { Error( "Error: Too many triangles" ); } for ( i = 0 ; i < numtris ; i++ ) { for ( j = 0 ; j < 4 ; j++ ) { if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &tshort, sizeof( tshort ), 1, input ); bytesread += sizeof( tshort ); tris[i].v[j] = (int)tshort; } } if ( vertsfound && trisfound ) { StoreAliasTriangles(); } return bytesread - startbytesread; } int ParseChunk( FILE *input ){ #define BLOCK_SIZE 4096 char temp[BLOCK_SIZE]; unsigned short type; int i, length, w, t, retval; level++; retval = 0; // chunk type if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &type, sizeof( type ), 1, input ); bytesread += sizeof( type ); // chunk length if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &length, sizeof( length ), 1, input ); bytesread += sizeof( length ); w = length - 6; // process chunk if we care about it, otherwise skip it switch ( type ) { case TRI_VERTEXL: w -= ParseVertexL( input ); goto ParseSubchunk; case TRI_FACEL1: w -= ParseFaceL1( input ); goto ParseSubchunk; case EDIT_OBJECT: // read the name i = 0; do { if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &temp[i], 1, 1, input ); i++; w--; bytesread++; } while ( temp[i - 1] ); case MAIN3DS: case OBJ_TRIMESH: case EDIT3DS: // parse through subchunks ParseSubchunk: while ( w > 0 ) { w -= ParseChunk( input ); } retval = length; goto Done; default: // skip other chunks while ( w > 0 ) { t = w; if ( t > BLOCK_SIZE ) { t = BLOCK_SIZE; } if ( feof( input ) ) { Error( "Error: unexpected end of file" ); } fread( &temp, t, 1, input ); bytesread += t; w -= t; } retval = length; goto Done; } Done: level--; return retval; } void Load3DSTriangleList( char *filename, triangle_t **pptri, int *numtriangles, mesh_node_t **nodesList, int *num_mesh_nodes ){ FILE *input; short int tshort; if ( nodesList ) { *num_mesh_nodes = 0; *nodesList = (mesh_node_t *) SafeMalloc( MAX_FM_MESH_NODES * sizeof( mesh_node_t ), "Mesh Node List" ); } bytesread = 0; level = 0; numtris = 0; totaltris = 0; vertsfound = 0; trisfound = 0; if ( ( input = fopen( filename, "rb" ) ) == 0 ) { fprintf( stderr,"reader: could not open file '%s'\n", filename ); exit( 0 ); } fread( &tshort, sizeof( tshort ), 1, input ); // should only be MAIN3DS, but some files seem to start with EDIT3DS, with // no MAIN3DS if ( ( tshort != MAIN3DS ) && ( tshort != EDIT3DS ) ) { fprintf( stderr,"File is not a 3DS file.\n" ); exit( 0 ); } // back to top of file so we can parse the first chunk descriptor fseek( input, 0, SEEK_SET ); ptri = malloc( MAXTRIANGLES * sizeof( triangle_t ) ); *pptri = ptri; // parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT | // OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks ParseChunk( input ); if ( vertsfound || trisfound ) { Error( "Incomplete triangle set" ); } *numtriangles = totaltris; fclose( input ); DefaultNodesList( nodesList,num_mesh_nodes,numtriangles ); } //========================================================================== // // LoadASC // //========================================================================== void LoadASC( char *fileName, triangle_t **triList, int *triangleCount, mesh_node_t **nodesList, int *num_mesh_nodes ){ int i, j; int vertexCount; struct { float v[3]; } *vList; int triCount; triangle_t *tList; float x, y, z; // float x2, y2, z2; // float rx, ry, rz; qboolean goodObject; if ( nodesList ) { *num_mesh_nodes = 0; *nodesList = (mesh_node_t *) SafeMalloc( MAX_FM_MESH_NODES * sizeof( mesh_node_t ), "Mesh Node List" ); } TK_OpenSource( fileName ); goodObject = false; while ( goodObject == false ) { TK_Beyond( TK_C_NAMED ); TK_Beyond( TK_OBJECT ); TK_Beyond( TK_C_TRI ); TK_Beyond( TK_MESH ); TK_BeyondRequire( TK_C_VERTICES, TK_COLON ); TK_FetchRequire( TK_INTNUMBER ); vertexCount = tk_IntNumber; if ( vertexCount > 0 ) { goodObject = true; } } TK_BeyondRequire( TK_C_FACES, TK_COLON ); TK_FetchRequire( TK_INTNUMBER ); triCount = tk_IntNumber; if ( triCount >= MAXTRIANGLES ) { Error( "Too many triangles in file %s\n", fileName ); } *triangleCount = triCount; tList = (triangle_t *) SafeMalloc( MAXTRIANGLES * sizeof( triangle_t ), "Triangle list" ); *triList = tList; memset( *triList,0,MAXTRIANGLES * sizeof( triangle_t ) ); TK_BeyondRequire( TK_C_VERTEX, TK_LIST ); /* rx = ((rotation[0]+90.0)/360.0)*2.0*M_PI; //rx = (rotation[0]/360.0)*2.0*M_PI; ry = (rotation[1]/360.0)*2.0*M_PI; rz = (rotation[2]/360.0)*2.0*M_PI; */ vList = (void *) SafeMalloc( vertexCount * sizeof vList[0], "Vertex list" ); for ( i = 0; i < vertexCount; i++ ) { TK_BeyondRequire( TK_C_VERTEX, TK_INTNUMBER ); if ( tk_IntNumber != i ) { Error( "File '%s', line %d:\nVertex index mismatch.\n", tk_SourceName, tk_Line ); } TK_FetchRequireFetch( TK_COLON ); TK_BeyondRequire( TK_COLON, TK_FLOATNUMBER ); x = tk_FloatNumber; TK_BeyondRequire( TK_COLON, TK_FLOATNUMBER ); y = tk_FloatNumber; TK_BeyondRequire( TK_COLON, TK_FLOATNUMBER ); z = tk_FloatNumber; /* x2 = x*cos(rz)+y*sin(rz); y2 = -x*sin(rz)+y*cos(rz); x = x2; y = y2; y2 = y*cos(rx)+z*sin(rx); z2 = -y*sin(rx)+z*cos(rx); y = y2; z = z2; x2 = x*cos(ry)-z*sin(ry); z2 = x*sin(ry)+z*cos(ry); x = x2; z = z2; */ vList[i].v[0] = x; vList[i].v[1] = y; vList[i].v[2] = z; } TK_BeyondRequire( TK_C_FACE, TK_LIST ); for ( i = 0; i < triCount; i++ ) { TK_BeyondRequire( TK_C_FACE, TK_INTNUMBER ); if ( tk_IntNumber != i ) { Error( "File '%s', line %d:\nTriangle index mismatch.\n", tk_SourceName, tk_Line ); } for ( j = 0; j < 3; j++ ) { TK_BeyondRequire( TK_IDENTIFIER, TK_COLON ); TK_FetchRequire( TK_INTNUMBER ); if ( tk_IntNumber >= vertexCount ) { Error( "File '%s', line %d:\nVertex number" " > vertexCount: %d\n", tk_SourceName, tk_Line, tk_IntNumber ); } tList[i].verts[2 - j][0] = vList[tk_IntNumber].v[0]; tList[i].verts[2 - j][1] = vList[tk_IntNumber].v[1]; tList[i].verts[2 - j][2] = vList[tk_IntNumber].v[2]; #ifdef _QDATA tList[i].indicies[2 - j] = tk_IntNumber; #endif } /* printf("Face %i:\n v0: %f, %f, %f\n v1: %f, %f, %f\n" " v2: %f, %f, %f\n", i, tList[i].verts[0][0], tList[i].verts[0][1], tList[i].verts[0][2], tList[i].verts[1][0], tList[i].verts[1][1], tList[i].verts[1][2], tList[i].verts[2][0], tList[i].verts[2][1], tList[i].verts[2][2]); */ } DefaultNodesList( nodesList,num_mesh_nodes,triangleCount ); }