Merge commit '515673c08f8718a237e90c2130a1f5294f966d6a'
[xonotic/netradiant.git] / tools / quake2 / common / l3dslib.c
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
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