929855d084587306bf237ad21f8fd4bcd3651a9a
[xonotic/netradiant.git] / tools / quake3 / q3map2 / convert_bsp.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 /* dependencies */
32 #include "q3map2.h"
33
34
35
36 /*
37    AnalyzeBSP() - ydnar
38    analyzes a Quake engine BSP file
39  */
40
41 typedef struct abspHeader_s
42 {
43         char ident[ 4 ];
44         int version;
45
46         bspLump_t lumps[ 1 ];       /* unknown size */
47 }
48 abspHeader_t;
49
50 typedef struct abspLumpTest_s
51 {
52         int radix, minCount;
53         char            *name;
54 }
55 abspLumpTest_t;
56
57 int AnalyzeBSP( int argc, char **argv ){
58         abspHeader_t            *header;
59         int size, i, version, offset, length, lumpInt, count;
60         char ident[ 5 ];
61         void                    *lump;
62         float lumpFloat;
63         char lumpString[ 1024 ], source[ 1024 ];
64         qboolean lumpSwap = qfalse;
65         abspLumpTest_t          *lumpTest;
66         static abspLumpTest_t lumpTests[] =
67         {
68                 { sizeof( bspPlane_t ),         6,      "IBSP LUMP_PLANES" },
69                 { sizeof( bspBrush_t ),         1,      "IBSP LUMP_BRUSHES" },
70                 { 8,                            6,      "IBSP LUMP_BRUSHSIDES" },
71                 { sizeof( bspBrushSide_t ),     6,      "RBSP LUMP_BRUSHSIDES" },
72                 { sizeof( bspModel_t ),         1,      "IBSP LUMP_MODELS" },
73                 { sizeof( bspNode_t ),          2,      "IBSP LUMP_NODES" },
74                 { sizeof( bspLeaf_t ),          1,      "IBSP LUMP_LEAFS" },
75                 { 104,                          3,      "IBSP LUMP_DRAWSURFS" },
76                 { 44,                           3,      "IBSP LUMP_DRAWVERTS" },
77                 { 4,                            6,      "IBSP LUMP_DRAWINDEXES" },
78                 { 128 * 128 * 3,                1,      "IBSP LUMP_LIGHTMAPS" },
79                 { 256 * 256 * 3,                1,      "IBSP LUMP_LIGHTMAPS (256 x 256)" },
80                 { 512 * 512 * 3,                1,      "IBSP LUMP_LIGHTMAPS (512 x 512)" },
81                 { 0, 0, NULL }
82         };
83
84
85         /* arg checking */
86         if ( argc < 1 ) {
87                 Sys_Printf( "Usage: q3map -analyze [-lumpswap] [-v] <mapname>\n" );
88                 return 0;
89         }
90
91         /* process arguments */
92         for ( i = 1; i < ( argc - 1 ); i++ )
93         {
94                 /* -format map|ase|... */
95                 if ( !strcmp( argv[ i ],  "-lumpswap" ) ) {
96                         Sys_Printf( "Swapped lump structs enabled\n" );
97                         lumpSwap = qtrue;
98                 }
99         }
100
101         /* clean up map name */
102         strcpy( source, ExpandArg( argv[ i ] ) );
103         Sys_Printf( "Loading %s\n", source );
104
105         /* load the file */
106         size = LoadFile( source, (void**) &header );
107         if ( size == 0 || header == NULL ) {
108                 Sys_Printf( "Unable to load %s.\n", source );
109                 return -1;
110         }
111
112         /* analyze ident/version */
113         memcpy( ident, header->ident, 4 );
114         ident[ 4 ] = '\0';
115         version = LittleLong( header->version );
116
117         Sys_Printf( "Identity:      %s\n", ident );
118         Sys_Printf( "Version:       %d\n", version );
119         Sys_Printf( "---------------------------------------\n" );
120
121         /* analyze each lump */
122         for ( i = 0; i < 100; i++ )
123         {
124                 /* call of duty swapped lump pairs */
125                 if ( lumpSwap ) {
126                         offset = LittleLong( header->lumps[ i ].length );
127                         length = LittleLong( header->lumps[ i ].offset );
128                 }
129
130                 /* standard lump pairs */
131                 else
132                 {
133                         offset = LittleLong( header->lumps[ i ].offset );
134                         length = LittleLong( header->lumps[ i ].length );
135                 }
136
137                 /* extract data */
138                 lump = (byte*) header + offset;
139                 lumpInt = LittleLong( (int) *( (int*) lump ) );
140                 lumpFloat = LittleFloat( (float) *( (float*) lump ) );
141                 memcpy( lumpString, (char*) lump, ( (size_t)length < sizeof( lumpString ) ? (size_t)length : sizeof( lumpString ) - 1 ) );
142                 lumpString[ sizeof( lumpString ) - 1 ] = '\0';
143
144                 /* print basic lump info */
145                 Sys_Printf( "Lump:          %d\n", i );
146                 Sys_Printf( "Offset:        %d bytes\n", offset );
147                 Sys_Printf( "Length:        %d bytes\n", length );
148
149                 /* only operate on valid lumps */
150                 if ( length > 0 ) {
151                         /* print data in 4 formats */
152                         Sys_Printf( "As hex:        %08X\n", lumpInt );
153                         Sys_Printf( "As int:        %d\n", lumpInt );
154                         Sys_Printf( "As float:      %f\n", lumpFloat );
155                         Sys_Printf( "As string:     %s\n", lumpString );
156
157                         /* guess lump type */
158                         if ( lumpString[ 0 ] == '{' && lumpString[ 2 ] == '"' ) {
159                                 Sys_Printf( "Type guess:    IBSP LUMP_ENTITIES\n" );
160                         }
161                         else if ( strstr( lumpString, "textures/" ) ) {
162                                 Sys_Printf( "Type guess:    IBSP LUMP_SHADERS\n" );
163                         }
164                         else
165                         {
166                                 /* guess based on size/count */
167                                 for ( lumpTest = lumpTests; lumpTest->radix > 0; lumpTest++ )
168                                 {
169                                         if ( ( length % lumpTest->radix ) != 0 ) {
170                                                 continue;
171                                         }
172                                         count = length / lumpTest->radix;
173                                         if ( count < lumpTest->minCount ) {
174                                                 continue;
175                                         }
176                                         Sys_Printf( "Type guess:    %s (%d x %d)\n", lumpTest->name, count, lumpTest->radix );
177                                 }
178                         }
179                 }
180
181                 Sys_Printf( "---------------------------------------\n" );
182
183                 /* end of file */
184                 if ( offset + length >= size ) {
185                         break;
186                 }
187         }
188
189         /* last stats */
190         Sys_Printf( "Lump count:    %d\n", i + 1 );
191         Sys_Printf( "File size:     %d bytes\n", size );
192
193         /* return to caller */
194         return 0;
195 }
196
197
198
199 /*
200    BSPInfo()
201    emits statistics about the bsp file
202  */
203
204 int BSPInfo( int count, char **fileNames ){
205         int i;
206         char source[ 1024 ], ext[ 64 ];
207         int size;
208         FILE        *f;
209
210
211         /* dummy check */
212         if ( count < 1 ) {
213                 Sys_Printf( "No files to dump info for.\n" );
214                 return -1;
215         }
216
217         /* enable info mode */
218         infoMode = qtrue;
219
220         /* walk file list */
221         for ( i = 0; i < count; i++ )
222         {
223                 Sys_Printf( "---------------------------------\n" );
224
225                 /* mangle filename and get size */
226                 strcpy( source, fileNames[ i ] );
227                 ExtractFileExtension( source, ext );
228                 if ( !Q_stricmp( ext, "map" ) ) {
229                         StripExtension( source );
230                 }
231                 DefaultExtension( source, ".bsp" );
232                 f = fopen( source, "rb" );
233                 if ( f ) {
234                         size = Q_filelength( f );
235                         fclose( f );
236                 }
237                 else{
238                         size = 0;
239                 }
240
241                 /* load the bsp file and print lump sizes */
242                 Sys_Printf( "%s\n", source );
243                 LoadBSPFile( source );
244                 PrintBSPFileSizes();
245
246                 /* print sizes */
247                 Sys_Printf( "\n" );
248                 Sys_Printf( "          total         %9d\n", size );
249                 Sys_Printf( "                        %9d KB\n", size / 1024 );
250                 Sys_Printf( "                        %9d MB\n", size / ( 1024 * 1024 ) );
251
252                 Sys_Printf( "---------------------------------\n" );
253         }
254
255         /* return count */
256         return i;
257 }
258
259
260 static void ExtrapolateTexcoords( const float *axyz, const float *ast, const float *bxyz, const float *bst, const float *cxyz, const float *cst, const float *axyz_new, float *ast_out, const float *bxyz_new, float *bst_out, const float *cxyz_new, float *cst_out ){
261         vec4_t scoeffs, tcoeffs;
262         float md;
263         m4x4_t solvematrix;
264
265         vec3_t norm;
266         vec3_t dab, dac;
267         VectorSubtract( bxyz, axyz, dab );
268         VectorSubtract( cxyz, axyz, dac );
269         CrossProduct( dab, dac, norm );
270
271         // assume:
272         //   s = f(x, y, z)
273         //   s(v + norm) = s(v) when n ortho xyz
274
275         // s(v) = DotProduct(v, scoeffs) + scoeffs[3]
276
277         // solve:
278         //   scoeffs * (axyz, 1) == ast[0]
279         //   scoeffs * (bxyz, 1) == bst[0]
280         //   scoeffs * (cxyz, 1) == cst[0]
281         //   scoeffs * (norm, 0) == 0
282         // scoeffs * [axyz, 1 | bxyz, 1 | cxyz, 1 | norm, 0] = [ast[0], bst[0], cst[0], 0]
283         solvematrix[0] = axyz[0];
284         solvematrix[4] = axyz[1];
285         solvematrix[8] = axyz[2];
286         solvematrix[12] = 1;
287         solvematrix[1] = bxyz[0];
288         solvematrix[5] = bxyz[1];
289         solvematrix[9] = bxyz[2];
290         solvematrix[13] = 1;
291         solvematrix[2] = cxyz[0];
292         solvematrix[6] = cxyz[1];
293         solvematrix[10] = cxyz[2];
294         solvematrix[14] = 1;
295         solvematrix[3] = norm[0];
296         solvematrix[7] = norm[1];
297         solvematrix[11] = norm[2];
298         solvematrix[15] = 0;
299
300         md = m4_det( solvematrix );
301         if ( md * md < 1e-10 ) {
302                 Sys_Printf( "Cannot invert some matrix, some texcoords aren't extrapolated!" );
303                 return;
304         }
305
306         m4x4_invert( solvematrix );
307
308         scoeffs[0] = ast[0];
309         scoeffs[1] = bst[0];
310         scoeffs[2] = cst[0];
311         scoeffs[3] = 0;
312         m4x4_transform_vec4( solvematrix, scoeffs );
313         tcoeffs[0] = ast[1];
314         tcoeffs[1] = bst[1];
315         tcoeffs[2] = cst[1];
316         tcoeffs[3] = 0;
317         m4x4_transform_vec4( solvematrix, tcoeffs );
318
319         ast_out[0] = scoeffs[0] * axyz_new[0] + scoeffs[1] * axyz_new[1] + scoeffs[2] * axyz_new[2] + scoeffs[3];
320         ast_out[1] = tcoeffs[0] * axyz_new[0] + tcoeffs[1] * axyz_new[1] + tcoeffs[2] * axyz_new[2] + tcoeffs[3];
321         bst_out[0] = scoeffs[0] * bxyz_new[0] + scoeffs[1] * bxyz_new[1] + scoeffs[2] * bxyz_new[2] + scoeffs[3];
322         bst_out[1] = tcoeffs[0] * bxyz_new[0] + tcoeffs[1] * bxyz_new[1] + tcoeffs[2] * bxyz_new[2] + tcoeffs[3];
323         cst_out[0] = scoeffs[0] * cxyz_new[0] + scoeffs[1] * cxyz_new[1] + scoeffs[2] * cxyz_new[2] + scoeffs[3];
324         cst_out[1] = tcoeffs[0] * cxyz_new[0] + tcoeffs[1] * cxyz_new[1] + tcoeffs[2] * cxyz_new[2] + tcoeffs[3];
325 }
326
327 /*
328    ScaleBSPMain()
329    amaze and confuse your enemies with wierd scaled maps!
330  */
331
332 int ScaleBSPMain( int argc, char **argv ){
333         int i, j;
334         float f, a;
335         vec3_t scale;
336         vec3_t vec;
337         char str[ 1024 ];
338         int uniform, axis;
339         qboolean texscale;
340         float *old_xyzst = NULL;
341         float spawn_ref = 0;
342
343
344         /* arg checking */
345         if ( argc < 3 ) {
346                 Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
347                 return 0;
348         }
349
350         texscale = qfalse;
351         for ( i = 1; i < argc - 2; ++i )
352         {
353                 if ( !strcmp( argv[i], "-tex" ) ) {
354                         texscale = qtrue;
355                 }
356                 else if ( !strcmp( argv[i], "-spawn_ref" ) ) {
357                         spawn_ref = atof( argv[i + 1] );
358                         ++i;
359                 }
360                 else{
361                         break;
362                 }
363         }
364
365         /* get scale */
366         // if(argc-2 >= i) // always true
367         scale[2] = scale[1] = scale[0] = atof( argv[ argc - 2 ] );
368         if ( argc - 3 >= i ) {
369                 scale[1] = scale[0] = atof( argv[ argc - 3 ] );
370         }
371         if ( argc - 4 >= i ) {
372                 scale[0] = atof( argv[ argc - 4 ] );
373         }
374
375         uniform = ( ( scale[0] == scale[1] ) && ( scale[1] == scale[2] ) );
376
377         if ( scale[0] == 0.0f || scale[1] == 0.0f || scale[2] == 0.0f ) {
378                 Sys_Printf( "Usage: q3map [-v] -scale [-tex] [-spawn_ref <value>] <value> <mapname>\n" );
379                 Sys_Printf( "Non-zero scale value required.\n" );
380                 return 0;
381         }
382
383         /* do some path mangling */
384         strcpy( source, ExpandArg( argv[ argc - 1 ] ) );
385         StripExtension( source );
386         DefaultExtension( source, ".bsp" );
387
388         /* load the bsp */
389         Sys_Printf( "Loading %s\n", source );
390         LoadBSPFile( source );
391         ParseEntities();
392
393         /* note it */
394         Sys_Printf( "--- ScaleBSP ---\n" );
395         Sys_FPrintf( SYS_VRB, "%9d entities\n", numEntities );
396
397         /* scale entity keys */
398         for ( i = 0; i < numBSPEntities && i < numEntities; i++ )
399         {
400                 /* scale origin */
401                 GetVectorForKey( &entities[ i ], "origin", vec );
402                 if ( ( vec[ 0 ] || vec[ 1 ] || vec[ 2 ] ) ) {
403                         if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
404                                 vec[2] += spawn_ref;
405                         }
406                         vec[0] *= scale[0];
407                         vec[1] *= scale[1];
408                         vec[2] *= scale[2];
409                         if ( !strncmp( ValueForKey( &entities[i], "classname" ), "info_player_", 12 ) ) {
410                                 vec[2] -= spawn_ref;
411                         }
412                         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
413                         SetKeyValue( &entities[ i ], "origin", str );
414                 }
415
416                 a = FloatForKey( &entities[ i ], "angle" );
417                 if ( a == -1 || a == -2 ) { // z scale
418                         axis = 2;
419                 }
420                 else if ( fabs( sin( DEG2RAD( a ) ) ) < 0.707 ) {
421                         axis = 0;
422                 }
423                 else{
424                         axis = 1;
425                 }
426
427                 /* scale door lip */
428                 f = FloatForKey( &entities[ i ], "lip" );
429                 if ( f ) {
430                         f *= scale[axis];
431                         sprintf( str, "%f", f );
432                         SetKeyValue( &entities[ i ], "lip", str );
433                 }
434
435                 /* scale plat height */
436                 f = FloatForKey( &entities[ i ], "height" );
437                 if ( f ) {
438                         f *= scale[2];
439                         sprintf( str, "%f", f );
440                         SetKeyValue( &entities[ i ], "height", str );
441                 }
442
443                 // TODO maybe allow a definition file for entities to specify which values are scaled how?
444         }
445
446         /* scale models */
447         for ( i = 0; i < numBSPModels; i++ )
448         {
449                 bspModels[ i ].mins[0] *= scale[0];
450                 bspModels[ i ].mins[1] *= scale[1];
451                 bspModels[ i ].mins[2] *= scale[2];
452                 bspModels[ i ].maxs[0] *= scale[0];
453                 bspModels[ i ].maxs[1] *= scale[1];
454                 bspModels[ i ].maxs[2] *= scale[2];
455         }
456
457         /* scale nodes */
458         for ( i = 0; i < numBSPNodes; i++ )
459         {
460                 bspNodes[ i ].mins[0] *= scale[0];
461                 bspNodes[ i ].mins[1] *= scale[1];
462                 bspNodes[ i ].mins[2] *= scale[2];
463                 bspNodes[ i ].maxs[0] *= scale[0];
464                 bspNodes[ i ].maxs[1] *= scale[1];
465                 bspNodes[ i ].maxs[2] *= scale[2];
466         }
467
468         /* scale leafs */
469         for ( i = 0; i < numBSPLeafs; i++ )
470         {
471                 bspLeafs[ i ].mins[0] *= scale[0];
472                 bspLeafs[ i ].mins[1] *= scale[1];
473                 bspLeafs[ i ].mins[2] *= scale[2];
474                 bspLeafs[ i ].maxs[0] *= scale[0];
475                 bspLeafs[ i ].maxs[1] *= scale[1];
476                 bspLeafs[ i ].maxs[2] *= scale[2];
477         }
478
479         if ( texscale ) {
480                 Sys_Printf( "Using texture unlocking (and probably breaking texture alignment a lot)\n" );
481                 old_xyzst = safe_malloc( sizeof( *old_xyzst ) * numBSPDrawVerts * 5 );
482                 for ( i = 0; i < numBSPDrawVerts; i++ )
483                 {
484                         old_xyzst[5 * i + 0] = bspDrawVerts[i].xyz[0];
485                         old_xyzst[5 * i + 1] = bspDrawVerts[i].xyz[1];
486                         old_xyzst[5 * i + 2] = bspDrawVerts[i].xyz[2];
487                         old_xyzst[5 * i + 3] = bspDrawVerts[i].st[0];
488                         old_xyzst[5 * i + 4] = bspDrawVerts[i].st[1];
489                 }
490         }
491
492         /* scale drawverts */
493         for ( i = 0; i < numBSPDrawVerts; i++ )
494         {
495                 bspDrawVerts[i].xyz[0] *= scale[0];
496                 bspDrawVerts[i].xyz[1] *= scale[1];
497                 bspDrawVerts[i].xyz[2] *= scale[2];
498                 bspDrawVerts[i].normal[0] /= scale[0];
499                 bspDrawVerts[i].normal[1] /= scale[1];
500                 bspDrawVerts[i].normal[2] /= scale[2];
501                 VectorNormalize( bspDrawVerts[i].normal, bspDrawVerts[i].normal );
502         }
503
504         if ( texscale ) {
505                 for ( i = 0; i < numBSPDrawSurfaces; i++ )
506                 {
507                         switch ( bspDrawSurfaces[i].surfaceType )
508                         {
509                         case SURFACE_FACE:
510                         case SURFACE_META:
511                                 if ( bspDrawSurfaces[i].numIndexes % 3 ) {
512                                         Error( "Not a triangulation!" );
513                                 }
514                                 for ( j = bspDrawSurfaces[i].firstIndex; j < bspDrawSurfaces[i].firstIndex + bspDrawSurfaces[i].numIndexes; j += 3 )
515                                 {
516                                         int ia = bspDrawIndexes[j] + bspDrawSurfaces[i].firstVert, ib = bspDrawIndexes[j + 1] + bspDrawSurfaces[i].firstVert, ic = bspDrawIndexes[j + 2] + bspDrawSurfaces[i].firstVert;
517                                         bspDrawVert_t *a = &bspDrawVerts[ia], *b = &bspDrawVerts[ib], *c = &bspDrawVerts[ic];
518                                         float *oa = &old_xyzst[ia * 5], *ob = &old_xyzst[ib * 5], *oc = &old_xyzst[ic * 5];
519                                         // extrapolate:
520                                         //   a->xyz -> oa
521                                         //   b->xyz -> ob
522                                         //   c->xyz -> oc
523                                         ExtrapolateTexcoords(
524                                                 &oa[0], &oa[3],
525                                                 &ob[0], &ob[3],
526                                                 &oc[0], &oc[3],
527                                                 a->xyz, a->st,
528                                                 b->xyz, b->st,
529                                                 c->xyz, c->st );
530                                 }
531                                 break;
532                         }
533                 }
534         }
535
536         /* scale planes */
537         if ( uniform ) {
538                 for ( i = 0; i < numBSPPlanes; i++ )
539                 {
540                         bspPlanes[ i ].dist *= scale[0];
541                 }
542         }
543         else
544         {
545                 for ( i = 0; i < numBSPPlanes; i++ )
546                 {
547                         bspPlanes[ i ].normal[0] /= scale[0];
548                         bspPlanes[ i ].normal[1] /= scale[1];
549                         bspPlanes[ i ].normal[2] /= scale[2];
550                         f = 1 / VectorLength( bspPlanes[i].normal );
551                         VectorScale( bspPlanes[i].normal, f, bspPlanes[i].normal );
552                         bspPlanes[ i ].dist *= f;
553                 }
554         }
555
556         /* scale gridsize */
557         GetVectorForKey( &entities[ 0 ], "gridsize", vec );
558         if ( ( vec[ 0 ] + vec[ 1 ] + vec[ 2 ] ) == 0.0f ) {
559                 VectorCopy( gridSize, vec );
560         }
561         vec[0] *= scale[0];
562         vec[1] *= scale[1];
563         vec[2] *= scale[2];
564         sprintf( str, "%f %f %f", vec[ 0 ], vec[ 1 ], vec[ 2 ] );
565         SetKeyValue( &entities[ 0 ], "gridsize", str );
566
567         /* inject command line parameters */
568         InjectCommandLine( argv, 0, argc - 1 );
569
570         /* write the bsp */
571         UnparseEntities();
572         StripExtension( source );
573         DefaultExtension( source, "_s.bsp" );
574         Sys_Printf( "Writing %s\n", source );
575         WriteBSPFile( source );
576
577         /* return to sender */
578         return 0;
579 }
580
581
582 /*
583    PseudoCompileBSP()
584    a stripped down ProcessModels
585  */
586 void PseudoCompileBSP( qboolean need_tree ){
587         int models;
588         char modelValue[10];
589         entity_t *entity;
590         face_t *faces;
591         tree_t *tree;
592         node_t *node;
593         brush_t *brush;
594         side_t *side;
595         int i;
596
597         SetDrawSurfacesBuffer();
598         mapDrawSurfs = safe_malloc( sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
599         memset( mapDrawSurfs, 0, sizeof( mapDrawSurface_t ) * MAX_MAP_DRAW_SURFS );
600         numMapDrawSurfs = 0;
601
602         BeginBSPFile();
603         models = 1;
604         for ( mapEntityNum = 0; mapEntityNum < numEntities; mapEntityNum++ )
605         {
606                 /* get entity */
607                 entity = &entities[ mapEntityNum ];
608                 if ( entity->brushes == NULL && entity->patches == NULL ) {
609                         continue;
610                 }
611
612                 if ( mapEntityNum != 0 ) {
613                         sprintf( modelValue, "*%d", models++ );
614                         SetKeyValue( entity, "model", modelValue );
615                 }
616
617                 /* process the model */
618                 Sys_FPrintf( SYS_VRB, "############### model %i ###############\n", numBSPModels );
619                 BeginModel();
620
621                 entity->firstDrawSurf = numMapDrawSurfs;
622
623                 ClearMetaTriangles();
624                 PatchMapDrawSurfs( entity );
625
626                 if ( mapEntityNum == 0 && need_tree ) {
627                         faces = MakeStructuralBSPFaceList( entities[0].brushes );
628                         tree = FaceBSP( faces );
629                         node = tree->headnode;
630                 }
631                 else
632                 {
633                         node = AllocNode();
634                         node->planenum = PLANENUM_LEAF;
635                         tree = AllocTree();
636                         tree->headnode = node;
637                 }
638
639                 /* a minimized ClipSidesIntoTree */
640                 for ( brush = entity->brushes; brush; brush = brush->next )
641                 {
642                         /* walk the brush sides */
643                         for ( i = 0; i < brush->numsides; i++ )
644                         {
645                                 /* get side */
646                                 side = &brush->sides[ i ];
647                                 if ( side->winding == NULL ) {
648                                         continue;
649                                 }
650                                 /* shader? */
651                                 if ( side->shaderInfo == NULL ) {
652                                         continue;
653                                 }
654                                 /* save this winding as a visible surface */
655                                 DrawSurfaceForSide( entity, brush, side, side->winding );
656                         }
657                 }
658
659                 if ( meta ) {
660                         ClassifyEntitySurfaces( entity );
661                         MakeEntityDecals( entity );
662                         MakeEntityMetaTriangles( entity );
663                         SmoothMetaTriangles();
664                         MergeMetaTriangles();
665                 }
666                 FilterDrawsurfsIntoTree( entity, tree );
667
668                 FilterStructuralBrushesIntoTree( entity, tree );
669                 FilterDetailBrushesIntoTree( entity, tree );
670
671                 EmitBrushes( entity->brushes, &entity->firstBrush, &entity->numBrushes );
672                 EndModel( entity, node );
673         }
674         EndBSPFile( qfalse );
675 }
676
677 /*
678    ConvertBSPMain()
679    main argument processing function for bsp conversion
680  */
681
682 int ConvertBSPMain( int argc, char **argv ){
683         int i;
684         int ( *convertFunc )( char * );
685         game_t  *convertGame;
686         char ext[1024];
687         qboolean map_allowed, force_bsp, force_map;
688
689
690         /* set default */
691         convertFunc = ConvertBSPToASE;
692         convertGame = NULL;
693         map_allowed = qfalse;
694         force_bsp = qfalse;
695         force_map = qfalse;
696
697         /* arg checking */
698         if ( argc < 1 ) {
699                 Sys_Printf( "Usage: q3map -convert [-format <ase|obj|map_bp|map>] [-shadersasbitmap|-lightmapsastexcoord|-deluxemapsastexcoord] [-readbsp|-readmap [-meta|-patchmeta]] [-v] <mapname>\n" );
700                 return 0;
701         }
702
703         /* process arguments */
704         for ( i = 1; i < ( argc - 1 ); i++ )
705         {
706                 /* -format map|ase|... */
707                 if ( !strcmp( argv[ i ],  "-format" ) ) {
708                         i++;
709                         if ( !Q_stricmp( argv[ i ], "ase" ) ) {
710                                 convertFunc = ConvertBSPToASE;
711                                 map_allowed = qfalse;
712                         }
713                         else if ( !Q_stricmp( argv[ i ], "obj" ) ) {
714                                 convertFunc = ConvertBSPToOBJ;
715                                 map_allowed = qfalse;
716                         }
717                         else if ( !Q_stricmp( argv[ i ], "map_bp" ) ) {
718                                 convertFunc = ConvertBSPToMap_BP;
719                                 map_allowed = qtrue;
720                         }
721                         else if ( !Q_stricmp( argv[ i ], "map" ) ) {
722                                 convertFunc = ConvertBSPToMap;
723                                 map_allowed = qtrue;
724                         }
725                         else
726                         {
727                                 convertGame = GetGame( argv[ i ] );
728                                 map_allowed = qfalse;
729                                 if ( convertGame == NULL ) {
730                                         Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
731                                 }
732                         }
733                 }
734                 else if ( !strcmp( argv[ i ],  "-ne" ) ) {
735                         normalEpsilon = atof( argv[ i + 1 ] );
736                         i++;
737                         Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
738                 }
739                 else if ( !strcmp( argv[ i ],  "-de" ) ) {
740                         distanceEpsilon = atof( argv[ i + 1 ] );
741                         i++;
742                         Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
743                 }
744                 else if ( !strcmp( argv[ i ],  "-shaderasbitmap" ) || !strcmp( argv[ i ],  "-shadersasbitmap" ) ) {
745                         shadersAsBitmap = qtrue;
746                 }
747                 else if ( !strcmp( argv[ i ],  "-lightmapastexcoord" ) || !strcmp( argv[ i ],  "-lightmapsastexcoord" ) ) {
748                         lightmapsAsTexcoord = qtrue;
749                 }
750                 else if ( !strcmp( argv[ i ],  "-deluxemapastexcoord" ) || !strcmp( argv[ i ],  "-deluxemapsastexcoord" ) ) {
751                         lightmapsAsTexcoord = qtrue;
752                         deluxemap = qtrue;
753                 }
754                 else if ( !strcmp( argv[ i ],  "-readbsp" ) ) {
755                         force_bsp = qtrue;
756                 }
757                 else if ( !strcmp( argv[ i ],  "-readmap" ) ) {
758                         force_map = qtrue;
759                 }
760                 else if ( !strcmp( argv[ i ],  "-meta" ) ) {
761                         meta = qtrue;
762                 }
763                 else if ( !strcmp( argv[ i ],  "-patchmeta" ) ) {
764                         meta = qtrue;
765                         patchMeta = qtrue;
766                 }
767         }
768
769         LoadShaderInfo();
770
771         /* clean up map name */
772         strcpy( source, ExpandArg( argv[i] ) );
773         ExtractFileExtension( source, ext );
774
775         if ( !map_allowed && !force_map ) {
776                 force_bsp = qtrue;
777         }
778
779         if ( force_map || ( !force_bsp && !Q_stricmp( ext, "map" ) && map_allowed ) ) {
780                 if ( !map_allowed ) {
781                         Sys_Printf( "WARNING: the requested conversion should not be done from .map files. Compile a .bsp first.\n" );
782                 }
783                 StripExtension( source );
784                 DefaultExtension( source, ".map" );
785                 Sys_Printf( "Loading %s\n", source );
786                 LoadMapFile( source, qfalse, convertGame == NULL );
787                 PseudoCompileBSP( convertGame != NULL );
788         }
789         else
790         {
791                 StripExtension( source );
792                 DefaultExtension( source, ".bsp" );
793                 Sys_Printf( "Loading %s\n", source );
794                 LoadBSPFile( source );
795                 ParseEntities();
796         }
797
798         /* bsp format convert? */
799         if ( convertGame != NULL ) {
800                 /* set global game */
801                 game = convertGame;
802
803                 /* write bsp */
804                 StripExtension( source );
805                 DefaultExtension( source, "_c.bsp" );
806                 Sys_Printf( "Writing %s\n", source );
807                 WriteBSPFile( source );
808
809                 /* return to sender */
810                 return 0;
811         }
812
813         /* normal convert */
814         return convertFunc( source );
815 }