fix a crash in RBSP reading
[divverent/netradiant.git] / tools / quake3 / q3map2 / bspfile_rbsp.c
1 /* -------------------------------------------------------------------------------
2
3 Copyright (C) 1999-2007 id Software, Inc. and contributors.
4 For a list of contributors, see the accompanying CONTRIBUTORS file.
5
6 This file is part of GtkRadiant.
7
8 GtkRadiant is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 GtkRadiant is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with GtkRadiant; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
21
22 ----------------------------------------------------------------------------------
23
24 This code has been altered significantly from its original form, to support
25 several games based on the Quake III Arena engine, in the form of "Q3Map2."
26
27 ------------------------------------------------------------------------------- */
28
29
30
31 /* marker */
32 #define BSPFILE_RBSP_C
33
34
35
36 /* dependencies */
37 #include "q3map2.h"
38
39
40
41
42 /* -------------------------------------------------------------------------------
43
44 this file handles translating the bsp file format used by quake 3, rtcw, and ef
45 into the abstracted bsp file used by q3map2.
46
47 ------------------------------------------------------------------------------- */
48
49 /* constants */
50 #define LUMP_ENTITIES           0
51 #define LUMP_SHADERS            1
52 #define LUMP_PLANES                     2
53 #define LUMP_NODES                      3
54 #define LUMP_LEAFS                      4
55 #define LUMP_LEAFSURFACES       5
56 #define LUMP_LEAFBRUSHES        6
57 #define LUMP_MODELS                     7
58 #define LUMP_BRUSHES            8
59 #define LUMP_BRUSHSIDES         9
60 #define LUMP_DRAWVERTS          10
61 #define LUMP_DRAWINDEXES        11
62 #define LUMP_FOGS                       12
63 #define LUMP_SURFACES           13
64 #define LUMP_LIGHTMAPS          14
65 #define LUMP_LIGHTGRID          15
66 #define LUMP_VISIBILITY         16
67 #define LUMP_LIGHTARRAY         17
68 #define HEADER_LUMPS            18
69
70
71 /* types */
72 typedef struct
73 {
74         char            ident[ 4 ];
75         int                     version;
76         
77         bspLump_t       lumps[ HEADER_LUMPS ];
78 }
79 rbspHeader_t;
80
81
82
83 /* light grid */
84 #define MAX_MAP_GRID            0xffff
85 #define MAX_MAP_GRIDARRAY       0x100000
86 #define LG_EPSILON                      4
87
88
89 static void CopyLightGridLumps( rbspHeader_t *header )
90 {
91         int                             i;
92         unsigned short  *inArray;
93         bspGridPoint_t  *in, *out;
94         
95         
96         /* get count */
97         numBSPGridPoints = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTARRAY, sizeof( *inArray ) );
98         
99         /* allocate buffer */
100         bspGridPoints = safe_malloc( numBSPGridPoints * sizeof( *bspGridPoints ) );
101         memset( bspGridPoints, 0, numBSPGridPoints * sizeof( *bspGridPoints ) );
102         
103         /* copy */
104         inArray = GetLump( (bspHeader_t*) header, LUMP_LIGHTARRAY );
105         in = GetLump( (bspHeader_t*) header, LUMP_LIGHTGRID );
106         out = bspGridPoints;
107         for( i = 0; i < numBSPGridPoints; i++ )
108         {
109                 memcpy( out, &in[ *inArray ], sizeof( *in ) );
110                 inArray++;
111                 out++;
112         }
113 }
114
115
116 static void AddLightGridLumps( FILE *file, rbspHeader_t *header )
117 {
118         int                             i, j, k, c, d;
119         int                             numGridPoints, maxGridPoints;
120         bspGridPoint_t  *gridPoints, *in, *out;
121         int                             numGridArray;
122         unsigned short  *gridArray;
123         qboolean                bad;
124         
125         
126         /* allocate temporary buffers */
127         maxGridPoints = (numBSPGridPoints < MAX_MAP_GRID) ? numBSPGridPoints : MAX_MAP_GRID;
128         gridPoints = safe_malloc( maxGridPoints * sizeof( *gridPoints ) );
129         gridArray = safe_malloc( numBSPGridPoints * sizeof( *gridArray ) );
130         
131         /* zero out */
132         numGridPoints = 0;
133         numGridArray = numBSPGridPoints;
134         
135         /* for each bsp grid point, find an approximate twin */
136         Sys_Printf( "Storing lightgrid: %d points\n", numBSPGridPoints );
137         for( i = 0; i < numGridArray; i++ )
138         {
139                 /* get points */
140                 in = &bspGridPoints[ i ];
141                 
142                 /* walk existing list */
143                 for( j = 0; j < numGridPoints; j++ )
144                 {
145                         /* get point */
146                         out = &gridPoints[ j ];
147                         
148                         /* compare styles */
149                         if( *((unsigned int*) in->styles) != *((unsigned int*) out->styles) )
150                                 continue;
151                         
152                         /* compare direction */
153                         d = abs( in->latLong[ 0 ] - out->latLong[ 0 ] );
154                         if( d < (255 - LG_EPSILON) && d > LG_EPSILON )
155                                 continue;
156                         d = abs( in->latLong[ 1 ] - out->latLong[ 1 ] );
157                         if( d < 255 - LG_EPSILON && d > LG_EPSILON )
158                                 continue;
159                         
160                         /* compare light */
161                         bad = qfalse;
162                         for( k = 0; (k < MAX_LIGHTMAPS && bad == qfalse); k++ )
163                         {
164                                 for( c = 0; c < 3; c++ )
165                                 {
166                                         if( abs( (int) in->ambient[ k ][ c ] - (int) out->ambient[ k ][ c ]) > LG_EPSILON ||
167                                                 abs( (int) in->directed[ k ][ c ] - (int) out->directed[ k ][ c ]) > LG_EPSILON )
168                                         {
169                                                 bad = qtrue;
170                                                 break;
171                                         }
172                                 }
173                         }
174                         
175                         /* failure */
176                         if( bad )
177                                 continue;
178                         
179                         /* this sample is ok */
180                         break;
181                 }
182                 
183                 /* set sample index */
184                 gridArray[ i ] = (unsigned short) j;
185                 
186                 /* if no sample found, add a new one */
187                 if( j >= numGridPoints && numGridPoints < maxGridPoints )
188                 {
189                         out = &gridPoints[ numGridPoints++ ];
190                         memcpy( out, in, sizeof( *in ) );
191                 }
192         }
193         
194         /* swap array */
195         for( i = 0; i < numGridArray; i++ )
196                 gridArray[ i ] = LittleShort( gridArray[ i ] );
197         
198         /* write lumps */
199         AddLump( file, (bspHeader_t*) header, LUMP_LIGHTGRID, gridPoints, (numGridPoints * sizeof( *gridPoints )) );
200         AddLump( file, (bspHeader_t*) header, LUMP_LIGHTARRAY, gridArray, (numGridArray * sizeof( *gridArray )) );
201         
202         /* free buffers */
203         free( gridPoints );
204         free( gridArray );
205 }
206
207
208
209 /*
210 LoadRBSPFile()
211 loads a raven bsp file into memory
212 */
213
214 void LoadRBSPFile( const char *filename )
215 {
216         rbspHeader_t    *header;
217         
218         
219         /* load the file header */
220         LoadFile( filename, (void**) &header );
221
222         /* swap the header (except the first 4 bytes) */
223         SwapBlock( (int*) ((byte*) header + sizeof( int )), sizeof( *header ) - sizeof( int ) );
224         
225         /* make sure it matches the format we're trying to load */
226         if( force == qfalse && *((int*) header->ident) != *((int*) game->bspIdent) )
227                 Error( "%s is not a %s file", filename, game->bspIdent );
228         if( force == qfalse && header->version != game->bspVersion )
229                 Error( "%s is version %d, not %d", filename, header->version, game->bspVersion );
230         
231         /* load/convert lumps */
232         numBSPShaders = CopyLump_Allocate( (bspHeader_t*) header, LUMP_SHADERS, (void **) &bspShaders, sizeof( bspShader_t ), &allocatedBSPShaders );
233         
234         numBSPModels = CopyLump_Allocate( (bspHeader_t*) header, LUMP_MODELS, (void **) &bspModels, sizeof( bspModel_t ), &allocatedBSPModels );
235         
236         numBSPPlanes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_PLANES, (void **) &bspPlanes, sizeof( bspPlane_t ), &allocatedBSPPlanes );
237         
238         numBSPLeafs = CopyLump( (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, sizeof( bspLeaf_t ) );
239         
240         numBSPNodes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_NODES, (void **) &bspNodes, sizeof( bspNode_t ), &allocatedBSPNodes );
241         
242         numBSPLeafSurfaces = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFSURFACES, (void **) &bspLeafSurfaces, sizeof( bspLeafSurfaces[ 0 ] ), &allocatedBSPLeafSurfaces );
243         
244         numBSPLeafBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_LEAFBRUSHES, (void **) &bspLeafBrushes, sizeof( bspLeafBrushes[ 0 ] ), &allocatedBSPLeafBrushes );
245         
246         numBSPBrushes = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHES, (void **) &bspBrushes, sizeof( bspBrush_t ), &allocatedBSPLeafBrushes );
247         
248         numBSPBrushSides = CopyLump_Allocate( (bspHeader_t*) header, LUMP_BRUSHSIDES, (void **) &bspBrushSides, sizeof( bspBrushSide_t ), &allocatedBSPBrushSides );
249         
250         numBSPDrawVerts = GetLumpElements( (bspHeader_t*) header, LUMP_DRAWVERTS, sizeof( bspDrawVerts[ 0 ] ) );
251                 SetDrawVerts( numBSPDrawVerts );
252                 CopyLump( (bspHeader_t*) header, LUMP_DRAWVERTS, bspDrawVerts, sizeof( bspDrawVerts[ 0 ] ) );
253         
254         numBSPDrawSurfaces = GetLumpElements( (bspHeader_t*) header, LUMP_SURFACES, sizeof( bspDrawSurfaces[ 0 ] ) );
255                 SetDrawSurfaces( numBSPDrawSurfaces );
256                 CopyLump( (bspHeader_t*) header, LUMP_SURFACES, bspDrawSurfaces, sizeof( bspDrawSurfaces[ 0 ] ) );
257         
258         numBSPFogs = CopyLump( (bspHeader_t*) header, LUMP_FOGS, bspFogs, sizeof( bspFogs[ 0 ] ) );
259         
260         numBSPDrawIndexes = CopyLump( (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, sizeof( bspDrawIndexes[ 0 ] ) );
261         
262         numBSPVisBytes = CopyLump( (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, 1 );
263         
264         numBSPLightBytes = GetLumpElements( (bspHeader_t*) header, LUMP_LIGHTMAPS, 1 );
265                 bspLightBytes = safe_malloc( numBSPLightBytes );
266                 CopyLump( (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, 1 );
267         
268         bspEntDataSize = CopyLump( (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, 1);
269         
270         CopyLightGridLumps( header );
271         
272         /* free the file buffer */
273         free( header );
274 }
275
276
277
278 /*
279 WriteRBSPFile()
280 writes a raven bsp file
281 */
282
283 void WriteRBSPFile( const char *filename )
284 {               
285         rbspHeader_t    outheader, *header;
286         FILE                    *file;
287         time_t                  t;
288         char                    marker[ 1024 ];
289         int                             size;
290         
291         
292         /* set header */
293         header = &outheader;
294         memset( header, 0, sizeof( *header ) );
295         
296         //%     Swapfile();
297         
298         /* set up header */
299         *((int*) (bspHeader_t*) header->ident) = *((int*) game->bspIdent);
300         header->version = LittleLong( game->bspVersion );
301         
302         /* write initial header */
303         file = SafeOpenWrite( filename );
304         SafeWrite( file, (bspHeader_t*) header, sizeof( *header ) );    /* overwritten later */
305         
306         /* add marker lump */
307         time( &t );
308         sprintf( marker, "I LOVE MY Q3MAP2 %s on %s)", Q3MAP_VERSION, asctime( localtime( &t ) ) );
309         AddLump( file, (bspHeader_t*) header, 0, marker, strlen( marker ) + 1 );
310         
311         /* add lumps */
312         AddLump( file, (bspHeader_t*) header, LUMP_SHADERS, bspShaders, numBSPShaders * sizeof( bspShader_t ) );
313         AddLump( file, (bspHeader_t*) header, LUMP_PLANES, bspPlanes, numBSPPlanes * sizeof( bspPlane_t ) );
314         AddLump( file, (bspHeader_t*) header, LUMP_LEAFS, bspLeafs, numBSPLeafs * sizeof( bspLeaf_t ) );
315         AddLump( file, (bspHeader_t*) header, LUMP_NODES, bspNodes, numBSPNodes * sizeof( bspNode_t ) );
316         AddLump( file, (bspHeader_t*) header, LUMP_BRUSHES, bspBrushes, numBSPBrushes*sizeof( bspBrush_t ) );
317         AddLump( file, (bspHeader_t*) header, LUMP_BRUSHSIDES, bspBrushSides, numBSPBrushSides * sizeof( bspBrushSides[ 0 ] ) );
318         AddLump( file, (bspHeader_t*) header, LUMP_LEAFSURFACES, bspLeafSurfaces, numBSPLeafSurfaces * sizeof( bspLeafSurfaces[ 0 ] ) );
319         AddLump( file, (bspHeader_t*) header, LUMP_LEAFBRUSHES, bspLeafBrushes, numBSPLeafBrushes * sizeof( bspLeafBrushes[ 0 ] ) );
320         AddLump( file, (bspHeader_t*) header, LUMP_MODELS, bspModels, numBSPModels * sizeof( bspModel_t ) );
321         AddLump( file, (bspHeader_t*) header, LUMP_DRAWVERTS, bspDrawVerts, numBSPDrawVerts * sizeof( bspDrawVerts[ 0 ] ) );
322         AddLump( file, (bspHeader_t*) header, LUMP_SURFACES, bspDrawSurfaces, numBSPDrawSurfaces * sizeof( bspDrawSurfaces[ 0 ] ) );
323         AddLump( file, (bspHeader_t*) header, LUMP_VISIBILITY, bspVisBytes, numBSPVisBytes );
324         AddLump( file, (bspHeader_t*) header, LUMP_LIGHTMAPS, bspLightBytes, numBSPLightBytes );
325         AddLightGridLumps( file, header );
326         AddLump( file, (bspHeader_t*) header, LUMP_ENTITIES, bspEntData, bspEntDataSize );
327         AddLump( file, (bspHeader_t*) header, LUMP_FOGS, bspFogs, numBSPFogs * sizeof( bspFog_t ) );
328         AddLump( file, (bspHeader_t*) header, LUMP_DRAWINDEXES, bspDrawIndexes, numBSPDrawIndexes * sizeof( bspDrawIndexes[ 0 ] ) );
329         
330         /* emit bsp size */
331         size = ftell( file );
332         Sys_Printf( "Wrote %.1f MB (%d bytes)\n", (float) size / (1024 * 1024), size );
333         
334         /* write the completed header */
335         fseek( file, 0, SEEK_SET );
336         SafeWrite( file, header, sizeof( *header ) );
337         
338         /* close the file */
339         fclose( file ); 
340 }