]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake3/q3map2/convert_map.c
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / tools / quake3 / q3map2 / convert_map.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 CONVERT_MAP_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 ConvertBrush()\r
42 exports a map brush\r
43 */\r
44 \r
45 #define SNAP_FLOAT_TO_INT       4\r
46 #define SNAP_INT_TO_FLOAT       (1.0 / SNAP_FLOAT_TO_INT)\r
47 \r
48 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )\r
49 {\r
50         int                             i, j;\r
51         bspBrushSide_t  *side;\r
52         side_t                  *buildSide;\r
53         bspShader_t             *shader;\r
54         char                    *texture;\r
55         bspPlane_t              *plane;\r
56         vec3_t                  pts[ 3 ];\r
57         \r
58         \r
59         /* start brush */\r
60         fprintf( f, "\t// brush %d\n", num );\r
61         fprintf( f, "\t{\n" );\r
62         \r
63         /* clear out build brush */\r
64         for( i = 0; i < buildBrush->numsides; i++ )\r
65         {\r
66                 buildSide = &buildBrush->sides[ i ];\r
67                 if( buildSide->winding != NULL )\r
68                 {\r
69                         FreeWinding( buildSide->winding );\r
70                         buildSide->winding = NULL;\r
71                 }\r
72         }\r
73         buildBrush->numsides = 0;\r
74         \r
75         /* iterate through bsp brush sides */\r
76         for( i = 0; i < brush->numSides; i++ )\r
77         {\r
78                 /* get side */\r
79                 side = &bspBrushSides[ brush->firstSide + i ];\r
80                 \r
81                 /* get shader */\r
82                 if( side->shaderNum < 0 || side->shaderNum >= numBSPShaders )\r
83                         continue;\r
84                 shader = &bspShaders[ side->shaderNum ];\r
85                 if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) )\r
86                         continue;\r
87                 \r
88                 /* get plane */\r
89                 plane = &bspPlanes[ side->planeNum ];\r
90                 \r
91                 /* add build side */\r
92                 buildSide = &buildBrush->sides[ buildBrush->numsides ];\r
93                 buildBrush->numsides++;\r
94                 \r
95                 /* tag it */\r
96                 buildSide->shaderInfo = ShaderInfoForShader( shader->shader );\r
97                 buildSide->planenum = side->planeNum;\r
98                 buildSide->winding = NULL;\r
99         }\r
100         \r
101         /* make brush windings */\r
102         if( !CreateBrushWindings( buildBrush ) )\r
103                 return;\r
104         \r
105         /* iterate through build brush sides */\r
106         for( i = 0; i < buildBrush->numsides; i++ )\r
107         {\r
108                 /* get build side */\r
109                 buildSide = &buildBrush->sides[ i ];\r
110                 \r
111                 /* dummy check */\r
112                 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )\r
113                         continue;\r
114                 \r
115                 /* get texture name */\r
116                 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )\r
117                         texture = buildSide->shaderInfo->shader + 9;\r
118                 else\r
119                         texture = buildSide->shaderInfo->shader;\r
120                 \r
121                 /* get plane points and offset by origin */\r
122                 for( j = 0; j < 3; j++ )\r
123                 {\r
124                         VectorAdd( buildSide->winding->p[ j ], origin, pts[ j ] );\r
125                         //%     pts[ j ][ 0 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 0 ] * SNAP_FLOAT_TO_INT + 0.5f );\r
126                         //%     pts[ j ][ 1 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 1 ] * SNAP_FLOAT_TO_INT + 0.5f );\r
127                         //%     pts[ j ][ 2 ] = SNAP_INT_TO_FLOAT * floor( pts[ j ][ 2 ] * SNAP_FLOAT_TO_INT + 0.5f );\r
128                 }\r
129                 \r
130                 /* print brush side */\r
131                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */\r
132                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",\r
133                         pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],\r
134                         pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],\r
135                         pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],\r
136                         texture );\r
137         }\r
138         \r
139         /* end brush */\r
140         fprintf( f, "\t}\n\n" );\r
141 }\r
142 \r
143 #if 0\r
144         /* iterate through the brush sides (ignore the first 6 bevel planes) */\r
145         for( i = 0; i < brush->numSides; i++ )\r
146         {\r
147                 /* get side */\r
148                 side = &bspBrushSides[ brush->firstSide + i ];\r
149                 \r
150                 /* get shader */\r
151                 if( side->shaderNum < 0 || side->shaderNum >= numBSPShaders )\r
152                         continue;\r
153                 shader = &bspShaders[ side->shaderNum ];\r
154                 if( !Q_stricmp( shader->shader, "default" ) || !Q_stricmp( shader->shader, "noshader" ) )\r
155                         continue;\r
156                 \r
157                 /* get texture name */\r
158                 if( !Q_strncasecmp( shader->shader, "textures/", 9 ) )\r
159                         texture = shader->shader + 9;\r
160                 else\r
161                         texture = shader->shader;\r
162                 \r
163                 /* get plane */\r
164                 plane = &bspPlanes[ side->planeNum ];\r
165 \r
166                 /* make plane points */\r
167                 {\r
168                         vec3_t  vecs[ 2 ];\r
169 \r
170                         \r
171                         MakeNormalVectors( plane->normal, vecs[ 0 ], vecs[ 1 ] );\r
172                         VectorMA( vec3_origin, plane->dist, plane->normal, pts[ 0 ] );\r
173                         VectorMA( pts[ 0 ], 256.0f, vecs[ 0 ], pts[ 1 ] );\r
174                         VectorMA( pts[ 0 ], 256.0f, vecs[ 1 ], pts[ 2 ] );\r
175                 }\r
176 \r
177                 /* offset by origin */\r
178                 for( j = 0; j < 3; j++ )\r
179                         VectorAdd( pts[ j ], origin, pts[ j ] );\r
180                 \r
181                 /* print brush side */\r
182                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */\r
183                 fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",\r
184                         pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],\r
185                         pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],\r
186                         pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],\r
187                         texture );\r
188         }\r
189 #endif\r
190 \r
191 \r
192 \r
193 /*\r
194 ConvertPatch()\r
195 converts a bsp patch to a map patch\r
196 \r
197         {\r
198                 patchDef2\r
199                 {\r
200                         base_wall/concrete\r
201                         ( 9 3 0 0 0 )\r
202                         (\r
203                                 ( ( 168 168 -192 0 2 ) ( 168 168 -64 0 1 ) ( 168 168 64 0 0 ) ... )\r
204                                 ...\r
205                         )\r
206                 }\r
207         }\r
208 \r
209 */\r
210 \r
211 static void ConvertPatch( FILE *f, int num, bspDrawSurface_t *ds, vec3_t origin )\r
212 {\r
213         int                             x, y;\r
214         bspShader_t             *shader;\r
215         char                    *texture;\r
216         bspDrawVert_t   *dv;\r
217         vec3_t                  xyz;\r
218         \r
219         \r
220         /* only patches */\r
221         if( ds->surfaceType != MST_PATCH )\r
222                 return;\r
223         \r
224         /* get shader */\r
225         if( ds->shaderNum < 0 || ds->shaderNum >= numBSPShaders )\r
226                 return;\r
227         shader = &bspShaders[ ds->shaderNum ];\r
228         \r
229         /* get texture name */\r
230         if( !Q_strncasecmp( shader->shader, "textures/", 9 ) )\r
231                 texture = shader->shader + 9;\r
232         else\r
233                 texture = shader->shader;\r
234         \r
235         /* start patch */\r
236         fprintf( f, "\t// patch %d\n", num );\r
237         fprintf( f, "\t{\n" );\r
238         fprintf( f, "\t\tpatchDef2\n" );\r
239         fprintf( f, "\t\t{\n" );\r
240         fprintf( f, "\t\t\t%s\n", texture );\r
241         fprintf( f, "\t\t\t( %d %d 0 0 0 )\n", ds->patchWidth, ds->patchHeight );\r
242         fprintf( f, "\t\t\t(\n" );\r
243         \r
244         /* iterate through the verts */\r
245         for( x = 0; x < ds->patchWidth; x++ )\r
246         {\r
247                 /* start row */\r
248                 fprintf( f, "\t\t\t\t(" );\r
249                 \r
250                 /* iterate through the row */\r
251                 for( y = 0; y < ds->patchHeight; y++ )\r
252                 {\r
253                         /* get vert */\r
254                         dv = &bspDrawVerts[ ds->firstVert + (y * ds->patchWidth) + x ];\r
255                         \r
256                         /* offset it */\r
257                         VectorAdd( origin, dv->xyz, xyz );\r
258                         \r
259                         /* print vertex */\r
260                         fprintf( f, " ( %f %f %f %f %f )", xyz[ 0 ], xyz[ 1 ], xyz[ 2 ], dv->st[ 0 ], dv->st[ 1 ] );\r
261                 }\r
262                 \r
263                 /* end row */\r
264                 fprintf( f, " )\n" );\r
265         }\r
266         \r
267         /* end patch */\r
268         fprintf( f, "\t\t\t)\n" );\r
269         fprintf( f, "\t\t}\n" );\r
270         fprintf( f, "\t}\n\n" );\r
271 }\r
272 \r
273 \r
274 \r
275 /*\r
276 ConvertModel()\r
277 exports a bsp model to a map file\r
278 */\r
279 \r
280 static void ConvertModel( FILE *f, bspModel_t *model, int modelNum, vec3_t origin )\r
281 {\r
282         int                                     i, num;\r
283         bspBrush_t                      *brush;\r
284         bspDrawSurface_t        *ds;\r
285         \r
286         \r
287         /* convert bsp planes to map planes */\r
288         nummapplanes = numBSPPlanes;\r
289         for( i = 0; i < numBSPPlanes; i++ )\r
290         {\r
291                 VectorCopy( bspPlanes[ i ].normal, mapplanes[ i ].normal );\r
292                 mapplanes[ i ].dist = bspPlanes[ i ].dist;\r
293                 mapplanes[ i ].type = PlaneTypeForNormal( mapplanes[ i ].normal );\r
294                 mapplanes[ i ].hash_chain = NULL;\r
295         }\r
296         \r
297         /* allocate a build brush */\r
298         buildBrush = AllocBrush( 512 );\r
299         buildBrush->entityNum = 0;\r
300         buildBrush->original = buildBrush;\r
301         \r
302         /* go through each brush in the model */\r
303         for( i = 0; i < model->numBSPBrushes; i++ )\r
304         {\r
305                 num = i + model->firstBSPBrush;\r
306                 brush = &bspBrushes[ num ];\r
307                 ConvertBrush( f, num, brush, origin );\r
308         }\r
309         \r
310         /* free the build brush */\r
311         free( buildBrush );\r
312         \r
313         /* go through each drawsurf in the model */\r
314         for( i = 0; i < model->numBSPSurfaces; i++ )\r
315         {\r
316                 num = i + model->firstBSPSurface;\r
317                 ds = &bspDrawSurfaces[ num ];\r
318                 \r
319                 /* we only love patches */\r
320                 if( ds->surfaceType == MST_PATCH )\r
321                         ConvertPatch( f, num, ds, origin );\r
322         }\r
323 }\r
324 \r
325 \r
326 \r
327 /*\r
328 ConvertEPairs()\r
329 exports entity key/value pairs to a map file\r
330 */\r
331 \r
332 static void ConvertEPairs( FILE *f, entity_t *e )\r
333 {\r
334         epair_t *ep;\r
335         \r
336         \r
337         /* walk epairs */\r
338         for( ep = e->epairs; ep != NULL; ep = ep->next )\r
339         {\r
340                 /* ignore empty keys/values */\r
341                 if( ep->key[ 0 ] == '\0' || ep->value[ 0 ] == '\0' )\r
342                         continue;\r
343 \r
344                 /* ignore model keys with * prefixed values */\r
345                 if( !Q_stricmp( ep->key, "model" ) && ep->value[ 0 ] == '*' )\r
346                         continue;\r
347                 \r
348                 /* emit the epair */\r
349                 fprintf( f, "\t\"%s\" \"%s\"\n", ep->key, ep->value );\r
350         }\r
351 }\r
352 \r
353 \r
354 \r
355 /*\r
356 ConvertBSPToMap()\r
357 exports an quake map file from the bsp\r
358 */\r
359 \r
360 int ConvertBSPToMap( char *bspName )\r
361 {\r
362         int                             i, modelNum;\r
363         FILE                    *f;\r
364         bspModel_t              *model;\r
365         entity_t                *e;\r
366         vec3_t                  origin;\r
367         const char              *value;\r
368         char                    name[ 1024 ], base[ 1024 ];\r
369         \r
370         \r
371         /* note it */\r
372         Sys_Printf( "--- Convert BSP to MAP ---\n" );\r
373         \r
374         /* create the bsp filename from the bsp name */\r
375         strcpy( name, bspName );\r
376         StripExtension( name );\r
377         strcat( name, "_converted.map" );\r
378         Sys_Printf( "writing %s\n", name );\r
379         \r
380         ExtractFileBase( bspName, base );\r
381         strcat( base, ".bsp" );\r
382         \r
383         /* open it */\r
384         f = fopen( name, "wb" );\r
385         if( f == NULL )\r
386                 Error( "Open failed on %s\n", name );\r
387         \r
388         /* print header */\r
389         fprintf( f, "// Generated by Q3Map2 (ydnar) -convert -format map\n" );\r
390         \r
391         /* walk entity list */\r
392         for( i = 0; i < numEntities; i++ )\r
393         {\r
394                 /* get entity */\r
395                 e = &entities[ i ];\r
396                 \r
397                 /* start entity */\r
398                 fprintf( f, "// entity %d\n", i );\r
399                 fprintf( f, "{\n" );\r
400                 \r
401                 /* export keys */\r
402                 ConvertEPairs( f, e );\r
403                 fprintf( f, "\n" );\r
404                 \r
405                 /* get model num */\r
406                 if( i == 0 )\r
407                         modelNum = 0;\r
408                 else\r
409                 {\r
410                         value = ValueForKey( e, "model" );\r
411                         if( value[ 0 ] == '*' )\r
412                                 modelNum = atoi( value + 1 );\r
413                         else\r
414                                 modelNum = -1;\r
415                 }\r
416                 \r
417                 /* only handle bsp models */\r
418                 if( modelNum >= 0 )\r
419                 {\r
420                         /* get model */\r
421                         model = &bspModels[ modelNum ];\r
422                         \r
423                         /* get entity origin */\r
424                         value = ValueForKey( e, "origin" );\r
425                         if( value[ 0 ] == '\0' )\r
426                                 VectorClear( origin );\r
427                         else\r
428                                 GetVectorForKey( e, "origin", origin );\r
429                         \r
430                         /* convert model */\r
431                         ConvertModel( f, model, modelNum, origin );\r
432                 }\r
433                 \r
434                 /* end entity */\r
435                 fprintf( f, "}\n\n" );\r
436         }\r
437         \r
438         /* close the file and return */\r
439         fclose( f );\r
440         \r
441         /* return to sender */\r
442         return 0;\r
443 }\r