Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

l3dslib.c (6068B)


      1 /*
      2 ===========================================================================
      3 Copyright (C) 1999-2005 Id Software, Inc.
      4 
      5 This file is part of Quake III Arena source code.
      6 
      7 Quake III Arena source code is free software; you can redistribute it
      8 and/or modify it under the terms of the GNU General Public License as
      9 published by the Free Software Foundation; either version 2 of the License,
     10 or (at your option) any later version.
     11 
     12 Quake III Arena source code is distributed in the hope that it will be
     13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
     14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     15 GNU General Public License for more details.
     16 
     17 You should have received a copy of the GNU General Public License
     18 along with Foobar; if not, write to the Free Software
     19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
     20 ===========================================================================
     21 */
     22 //
     23 // l3dslib.c: library for loading triangles from an Alias triangle file
     24 //
     25 
     26 #include <stdio.h>
     27 #include "cmdlib.h"
     28 #include "mathlib.h"
     29 #include "trilib.h"
     30 #include "l3dslib.h"
     31 
     32 #define MAIN3DS       0x4D4D
     33 #define EDIT3DS       0x3D3D  // this is the start of the editor config
     34 #define EDIT_OBJECT   0x4000
     35 #define OBJ_TRIMESH   0x4100
     36 #define TRI_VERTEXL   0x4110
     37 #define TRI_FACEL1    0x4120
     38 
     39 #define MAXVERTS	2000
     40 
     41 typedef struct {
     42 	int	v[4];
     43 } tri;
     44 
     45 float	fverts[MAXVERTS][3];
     46 tri		tris[MAXTRIANGLES];
     47 
     48 int	bytesread, level, numtris, totaltris;
     49 int	vertsfound, trisfound;
     50 
     51 triangle_t	*ptri;
     52 
     53 
     54 // Alias stores triangles as 3 explicit vertices in .tri files, so even though we
     55 // start out with a vertex pool and vertex indices for triangles, we have to convert
     56 // to raw, explicit triangles
     57 void StoreAliasTriangles (void)
     58 {
     59 	int		i, j, k;
     60 
     61 	if ((totaltris + numtris) > MAXTRIANGLES)
     62 		Error ("Error: Too many triangles");
     63 
     64 	for (i=0; i<numtris ; i++)
     65 	{
     66 		for (j=0 ; j<3 ; j++)
     67 		{
     68 			for (k=0 ; k<3 ; k++)
     69 			{
     70 				ptri[i+totaltris].verts[j][k] = fverts[tris[i].v[j]][k];
     71 			}
     72 		}
     73 	}
     74 	
     75 	totaltris += numtris;
     76 	numtris = 0;
     77 	vertsfound = 0;
     78 	trisfound = 0;
     79 }
     80 
     81 
     82 int ParseVertexL (FILE *input)
     83 {
     84 	int				i, j, startbytesread, numverts;
     85 	unsigned short	tshort;
     86 
     87 	if (vertsfound)
     88 		Error ("Error: Multiple vertex chunks");
     89 
     90 	vertsfound = 1;
     91 	startbytesread = bytesread;
     92 
     93 	if (feof(input))
     94 		Error ("Error: unexpected end of file");
     95 
     96 	fread(&tshort, sizeof(tshort), 1, input);
     97 	bytesread += sizeof(tshort);
     98 	numverts = (int)tshort;
     99 
    100 	if (numverts > MAXVERTS)
    101 		Error ("Error: Too many vertices");
    102 
    103 	for (i=0 ; i<numverts ; i++)
    104 	{
    105 		for (j=0 ; j<3 ; j++)
    106 		{
    107 			if (feof(input))
    108 				Error ("Error: unexpected end of file");
    109 
    110 			fread(&fverts[i][j], sizeof(float), 1, input);
    111 			bytesread += sizeof(float);
    112 		}
    113 	}
    114 
    115 	if (vertsfound && trisfound)
    116 		StoreAliasTriangles ();
    117 
    118 	return bytesread - startbytesread;
    119 }
    120 
    121 
    122 int ParseFaceL1 (FILE *input)
    123 {
    124 
    125 	int				i, j, startbytesread;
    126 	unsigned short	tshort;
    127 
    128 	if (trisfound)
    129 		Error ("Error: Multiple face chunks");
    130 
    131 	trisfound = 1;
    132 	startbytesread = bytesread;
    133 
    134 	if (feof(input))
    135 		Error ("Error: unexpected end of file");
    136 
    137 	fread(&tshort, sizeof(tshort), 1, input);
    138 	bytesread += sizeof(tshort);
    139 	numtris = (int)tshort;
    140 
    141 	if (numtris > MAXTRIANGLES)
    142 		Error ("Error: Too many triangles");
    143 
    144 	for (i=0 ; i<numtris ; i++)
    145 	{
    146 		for (j=0 ; j<4 ; j++)
    147 		{
    148 			if (feof(input))
    149 				Error ("Error: unexpected end of file");
    150 
    151 			fread(&tshort, sizeof(tshort), 1, input);
    152 			bytesread += sizeof(tshort);
    153 			tris[i].v[j] = (int)tshort;
    154 		}
    155 	}
    156 
    157 	if (vertsfound && trisfound)
    158 		StoreAliasTriangles ();
    159 
    160 	return bytesread - startbytesread;
    161 }
    162 
    163 
    164 int ParseChunk (FILE *input)
    165 {
    166 #define BLOCK_SIZE	4096
    167 	char			temp[BLOCK_SIZE];
    168 	unsigned short	type;
    169 	int				i, length, w, t, retval;
    170 
    171 	level++;
    172 	retval = 0;
    173 
    174 // chunk type
    175 	if (feof(input))
    176 		Error ("Error: unexpected end of file");
    177 
    178 	fread(&type, sizeof(type), 1, input);
    179 	bytesread += sizeof(type);
    180 
    181 // chunk length
    182 	if (feof(input))
    183 		Error ("Error: unexpected end of file");
    184 
    185 	fread (&length, sizeof(length), 1, input);
    186 	bytesread += sizeof(length);
    187 	w = length - 6;
    188 
    189 // process chunk if we care about it, otherwise skip it
    190 	switch (type)
    191 	{
    192 	case TRI_VERTEXL:
    193 		w -= ParseVertexL (input);
    194 		goto ParseSubchunk;
    195 
    196 	case TRI_FACEL1:
    197 		w -= ParseFaceL1 (input);
    198 		goto ParseSubchunk;
    199 
    200 	case EDIT_OBJECT:
    201 	// read the name
    202 		i = 0;
    203 
    204 		do
    205 		{
    206 			if (feof(input))
    207 				Error ("Error: unexpected end of file");
    208 
    209 			fread (&temp[i], 1, 1, input);
    210 			i++;
    211 			w--;
    212 			bytesread++;
    213 		} while (temp[i-1]);
    214 
    215 	case MAIN3DS:
    216 	case OBJ_TRIMESH:
    217 	case EDIT3DS:
    218 	// parse through subchunks
    219 ParseSubchunk:
    220 		while (w > 0)
    221 		{
    222 			w -= ParseChunk (input);
    223 		}
    224 
    225 		retval = length;
    226 		goto Done;
    227 
    228 	default:
    229 	// skip other chunks
    230 		while (w > 0)
    231 		{
    232 			t = w;
    233 
    234 			if (t > BLOCK_SIZE)
    235 				t = BLOCK_SIZE;
    236 
    237 			if (feof(input))
    238 				Error ("Error: unexpected end of file");
    239 
    240 			fread (&temp, t, 1, input);
    241 			bytesread += t;
    242 
    243 			w -= t;
    244 		}
    245 
    246 		retval = length;
    247 		goto Done;
    248 	}
    249 
    250 Done:
    251 	level--;
    252 	return retval;
    253 }
    254 
    255 
    256 void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles)
    257 {
    258 	FILE        *input;
    259 	short int	tshort;
    260 
    261 	bytesread = 0;
    262 	level = 0;
    263 	numtris = 0;
    264 	totaltris = 0;
    265 	vertsfound = 0;
    266 	trisfound = 0;
    267 
    268 	if ((input = fopen(filename, "rb")) == 0) {
    269 		fprintf(stderr,"reader: could not open file '%s'\n", filename);
    270 		exit(0);
    271 	}
    272 
    273 	fread(&tshort, sizeof(tshort), 1, input);
    274 
    275 // should only be MAIN3DS, but some files seem to start with EDIT3DS, with
    276 // no MAIN3DS
    277 	if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) {
    278 		fprintf(stderr,"File is not a 3DS file.\n");
    279 		exit(0);
    280 	}
    281 
    282 // back to top of file so we can parse the first chunk descriptor
    283 	fseek(input, 0, SEEK_SET);
    284 
    285 	ptri = malloc (MAXTRIANGLES * sizeof(triangle_t));
    286 
    287 	*pptri = ptri;
    288 
    289 // parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT |
    290 // OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks
    291 	ParseChunk (input);
    292 
    293 	if (vertsfound || trisfound)
    294 		Error ("Incomplete triangle set");
    295 
    296 	*numtriangles = totaltris;
    297 
    298 	fclose (input);
    299 }
    300