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