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