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