1 /*
2 Copyright (C) 1999-2006 Id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 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 GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21 //
22 // l3dslib.c: library for loading triangles from an Alias triangle file
23 //
24
25 #include <stdio.h>
26 #include "cmdlib.h"
27 #include "inout.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
StoreAliasTriangles(void)57 void StoreAliasTriangles( void ){
58 int i, j, k;
59
60 if ( ( totaltris + numtris ) > MAXTRIANGLES ) {
61 Error( "Error: Too many triangles" );
62 }
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
ParseVertexL(FILE * input)82 int ParseVertexL( FILE *input ){
83 int i, j, startbytesread, numverts;
84 unsigned short tshort;
85
86 if ( vertsfound ) {
87 Error( "Error: Multiple vertex chunks" );
88 }
89
90 vertsfound = 1;
91 startbytesread = bytesread;
92
93 if ( feof( input ) ) {
94 Error( "Error: unexpected end of file" );
95 }
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
105 for ( i = 0 ; i < numverts ; i++ )
106 {
107 for ( j = 0 ; j < 3 ; j++ )
108 {
109 if ( feof( input ) ) {
110 Error( "Error: unexpected end of file" );
111 }
112
113 fread( &fverts[i][j], sizeof( float ), 1, input );
114 bytesread += sizeof( float );
115 }
116 }
117
118 if ( vertsfound && trisfound ) {
119 StoreAliasTriangles();
120 }
121
122 return bytesread - startbytesread;
123 }
124
125
ParseFaceL1(FILE * input)126 int ParseFaceL1( FILE *input ){
127
128 int i, j, startbytesread;
129 unsigned short tshort;
130
131 if ( trisfound ) {
132 Error( "Error: Multiple face chunks" );
133 }
134
135 trisfound = 1;
136 startbytesread = bytesread;
137
138 if ( feof( input ) ) {
139 Error( "Error: unexpected end of file" );
140 }
141
142 fread( &tshort, sizeof( tshort ), 1, input );
143 bytesread += sizeof( tshort );
144 numtris = (int)tshort;
145
146 if ( numtris > MAXTRIANGLES ) {
147 Error( "Error: Too many triangles" );
148 }
149
150 for ( i = 0 ; i < numtris ; i++ )
151 {
152 for ( j = 0 ; j < 4 ; j++ )
153 {
154 if ( feof( input ) ) {
155 Error( "Error: unexpected end of file" );
156 }
157
158 fread( &tshort, sizeof( tshort ), 1, input );
159 bytesread += sizeof( tshort );
160 tris[i].v[j] = (int)tshort;
161 }
162 }
163
164 if ( vertsfound && trisfound ) {
165 StoreAliasTriangles();
166 }
167
168 return bytesread - startbytesread;
169 }
170
171
ParseChunk(FILE * input)172 int ParseChunk( FILE *input ){
173 #define BLOCK_SIZE 4096
174 char temp[BLOCK_SIZE];
175 unsigned short type;
176 int i, length, w, t, retval;
177
178 level++;
179 retval = 0;
180
181 // chunk type
182 if ( feof( input ) ) {
183 Error( "Error: unexpected end of file" );
184 }
185
186 fread( &type, sizeof( type ), 1, input );
187 bytesread += sizeof( type );
188
189 // chunk length
190 if ( feof( input ) ) {
191 Error( "Error: unexpected end of file" );
192 }
193
194 fread( &length, sizeof( length ), 1, input );
195 bytesread += sizeof( length );
196 w = length - 6;
197
198 // process chunk if we care about it, otherwise skip it
199 switch ( type )
200 {
201 case TRI_VERTEXL:
202 w -= ParseVertexL( input );
203 goto ParseSubchunk;
204
205 case TRI_FACEL1:
206 w -= ParseFaceL1( input );
207 goto ParseSubchunk;
208
209 case EDIT_OBJECT:
210 // read the name
211 i = 0;
212
213 do
214 {
215 if ( feof( input ) ) {
216 Error( "Error: unexpected end of file" );
217 }
218
219 fread( &temp[i], 1, 1, input );
220 i++;
221 w--;
222 bytesread++;
223 } while ( temp[i - 1] );
224
225 case MAIN3DS:
226 case OBJ_TRIMESH:
227 case EDIT3DS:
228 // parse through subchunks
229 ParseSubchunk:
230 while ( w > 0 )
231 {
232 w -= ParseChunk( input );
233 }
234
235 retval = length;
236 goto Done;
237
238 default:
239 // skip other chunks
240 while ( w > 0 )
241 {
242 t = w;
243
244 if ( t > BLOCK_SIZE ) {
245 t = BLOCK_SIZE;
246 }
247
248 if ( feof( input ) ) {
249 Error( "Error: unexpected end of file" );
250 }
251
252 fread( &temp, t, 1, input );
253 bytesread += t;
254
255 w -= t;
256 }
257
258 retval = length;
259 goto Done;
260 }
261
262 Done:
263 level--;
264 return retval;
265 }
266
267
Load3DSTriangleList(char * filename,triangle_t ** pptri,int * numtriangles)268 void Load3DSTriangleList( char *filename, triangle_t **pptri, int *numtriangles ){
269 FILE *input;
270 short int tshort;
271
272 bytesread = 0;
273 level = 0;
274 numtris = 0;
275 totaltris = 0;
276 vertsfound = 0;
277 trisfound = 0;
278
279 if ( ( input = fopen( filename, "rb" ) ) == 0 ) {
280 fprintf( stderr,"reader: could not open file '%s'\n", filename );
281 exit( 0 );
282 }
283
284 fread( &tshort, sizeof( tshort ), 1, input );
285
286 // should only be MAIN3DS, but some files seem to start with EDIT3DS, with
287 // no MAIN3DS
288 if ( ( tshort != MAIN3DS ) && ( tshort != EDIT3DS ) ) {
289 fprintf( stderr,"File is not a 3DS file.\n" );
290 exit( 0 );
291 }
292
293 // back to top of file so we can parse the first chunk descriptor
294 fseek( input, 0, SEEK_SET );
295
296 ptri = malloc( MAXTRIANGLES * sizeof( triangle_t ) );
297
298 *pptri = ptri;
299
300 // parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT |
301 // OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks
302 ParseChunk( input );
303
304 if ( vertsfound || trisfound ) {
305 Error( "Incomplete triangle set" );
306 }
307
308 *numtriangles = totaltris;
309
310 fclose( input );
311 }
312