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