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 SURFACE_EXTRA_C
33 
34 
35 
36 /* dependencies */
37 #include "q3map2.h"
38 
39 
40 
41 /* -------------------------------------------------------------------------------
42 
43    ydnar: srf file module
44 
45    ------------------------------------------------------------------------------- */
46 
47 typedef struct surfaceExtra_s
48 {
49 	mapDrawSurface_t        *mds;
50 	shaderInfo_t            *si;
51 	int parentSurfaceNum;
52 	int entityNum;
53 	int castShadows, recvShadows;
54 	int sampleSize;
55 	float longestCurve;
56 	vec3_t lightmapAxis;
57 }
58 surfaceExtra_t;
59 
60 #define GROW_SURFACE_EXTRAS 1024
61 
62 int numSurfaceExtras = 0;
63 int maxSurfaceExtras = 0;
64 surfaceExtra_t              *surfaceExtras;
65 surfaceExtra_t seDefault = { NULL, NULL, -1, 0, WORLDSPAWN_CAST_SHADOWS, WORLDSPAWN_RECV_SHADOWS, 0, 0, { 0, 0, 0 } };
66 
67 
68 
69 /*
70    AllocSurfaceExtra()
71    allocates a new extra storage
72  */
73 
AllocSurfaceExtra(void)74 static surfaceExtra_t *AllocSurfaceExtra( void ){
75 	surfaceExtra_t  *se;
76 
77 
78 	/* enough space? */
79 	if ( numSurfaceExtras >= maxSurfaceExtras ) {
80 		/* reallocate more room */
81 		maxSurfaceExtras += GROW_SURFACE_EXTRAS;
82 		se = safe_malloc( maxSurfaceExtras * sizeof( surfaceExtra_t ) );
83 		if ( surfaceExtras != NULL ) {
84 			memcpy( se, surfaceExtras, numSurfaceExtras * sizeof( surfaceExtra_t ) );
85 			free( surfaceExtras );
86 		}
87 		surfaceExtras = se;
88 	}
89 
90 	/* add another */
91 	se = &surfaceExtras[ numSurfaceExtras ];
92 	numSurfaceExtras++;
93 	memcpy( se, &seDefault, sizeof( surfaceExtra_t ) );
94 
95 	/* return it */
96 	return se;
97 }
98 
99 
100 
101 /*
102    SetDefaultSampleSize()
103    sets the default lightmap sample size
104  */
105 
SetDefaultSampleSize(int sampleSize)106 void SetDefaultSampleSize( int sampleSize ){
107 	seDefault.sampleSize = sampleSize;
108 }
109 
110 
111 
112 /*
113    SetSurfaceExtra()
114    stores extra (q3map2) data for the specific numbered drawsurface
115  */
116 
SetSurfaceExtra(mapDrawSurface_t * ds,int num)117 void SetSurfaceExtra( mapDrawSurface_t *ds, int num ){
118 	surfaceExtra_t  *se;
119 
120 
121 	/* dummy check */
122 	if ( ds == NULL || num < 0 ) {
123 		return;
124 	}
125 
126 	/* get a new extra */
127 	se = AllocSurfaceExtra();
128 
129 	/* copy out the relevant bits */
130 	se->mds = ds;
131 	se->si = ds->shaderInfo;
132 	se->parentSurfaceNum = ds->parent != NULL ? ds->parent->outputNum : -1;
133 	se->entityNum = ds->entityNum;
134 	se->castShadows = ds->castShadows;
135 	se->recvShadows = ds->recvShadows;
136 	se->sampleSize = ds->sampleSize;
137 	se->longestCurve = ds->longestCurve;
138 	VectorCopy( ds->lightmapAxis, se->lightmapAxis );
139 
140 	/* debug code */
141 	//%	Sys_FPrintf( SYS_VRB, "SetSurfaceExtra(): entityNum = %d\n", ds->entityNum );
142 }
143 
144 
145 
146 /*
147    GetSurfaceExtra*()
148    getter functions for extra surface data
149  */
150 
GetSurfaceExtra(int num)151 static surfaceExtra_t *GetSurfaceExtra( int num ){
152 	if ( num < 0 || num >= numSurfaceExtras ) {
153 		return &seDefault;
154 	}
155 	return &surfaceExtras[ num ];
156 }
157 
158 
GetSurfaceExtraShaderInfo(int num)159 shaderInfo_t *GetSurfaceExtraShaderInfo( int num ){
160 	surfaceExtra_t  *se = GetSurfaceExtra( num );
161 	return se->si;
162 }
163 
164 
GetSurfaceExtraParentSurfaceNum(int num)165 int GetSurfaceExtraParentSurfaceNum( int num ){
166 	surfaceExtra_t  *se = GetSurfaceExtra( num );
167 	return se->parentSurfaceNum;
168 }
169 
170 
GetSurfaceExtraEntityNum(int num)171 int GetSurfaceExtraEntityNum( int num ){
172 	surfaceExtra_t  *se = GetSurfaceExtra( num );
173 	return se->entityNum;
174 }
175 
176 
GetSurfaceExtraCastShadows(int num)177 int GetSurfaceExtraCastShadows( int num ){
178 	surfaceExtra_t  *se = GetSurfaceExtra( num );
179 	return se->castShadows;
180 }
181 
182 
GetSurfaceExtraRecvShadows(int num)183 int GetSurfaceExtraRecvShadows( int num ){
184 	surfaceExtra_t  *se = GetSurfaceExtra( num );
185 	return se->recvShadows;
186 }
187 
188 
GetSurfaceExtraSampleSize(int num)189 int GetSurfaceExtraSampleSize( int num ){
190 	surfaceExtra_t  *se = GetSurfaceExtra( num );
191 	return se->sampleSize;
192 }
193 
194 
GetSurfaceExtraLongestCurve(int num)195 float GetSurfaceExtraLongestCurve( int num ){
196 	surfaceExtra_t  *se = GetSurfaceExtra( num );
197 	return se->longestCurve;
198 }
199 
200 
GetSurfaceExtraLightmapAxis(int num,vec3_t lightmapAxis)201 void GetSurfaceExtraLightmapAxis( int num, vec3_t lightmapAxis ){
202 	surfaceExtra_t  *se = GetSurfaceExtra( num );
203 	VectorCopy( se->lightmapAxis, lightmapAxis );
204 }
205 
206 
207 
208 
209 /*
210    WriteSurfaceExtraFile()
211    writes out a surface info file (<map>.srf)
212  */
213 
WriteSurfaceExtraFile(const char * path)214 void WriteSurfaceExtraFile( const char *path ){
215 	char srfPath[ 1024 ];
216 	FILE            *sf;
217 	surfaceExtra_t  *se;
218 	int i;
219 
220 
221 	/* dummy check */
222 	if ( path == NULL || path[ 0 ] == '\0' ) {
223 		return;
224 	}
225 
226 	/* note it */
227 	Sys_Printf( "--- WriteSurfaceExtraFile ---\n" );
228 
229 	/* open the file */
230 	strcpy( srfPath, path );
231 	StripExtension( srfPath );
232 	strcat( srfPath, ".srf" );
233 	Sys_Printf( "Writing %s\n", srfPath );
234 	sf = fopen( srfPath, "w" );
235 	if ( sf == NULL ) {
236 		Error( "Error opening %s for writing", srfPath );
237 	}
238 
239 	/* lap through the extras list */
240 	for ( i = -1; i < numSurfaceExtras; i++ )
241 	{
242 		/* get extra */
243 		se = GetSurfaceExtra( i );
244 
245 		/* default or surface num? */
246 		if ( i < 0 ) {
247 			fprintf( sf, "default" );
248 		}
249 		else{
250 			fprintf( sf, "%d", i );
251 		}
252 
253 		/* valid map drawsurf? */
254 		if ( se->mds == NULL ) {
255 			fprintf( sf, "\n" );
256 		}
257 		else
258 		{
259 			fprintf( sf, " // %s V: %d I: %d %s\n",
260 					 surfaceTypes[ se->mds->type ],
261 					 se->mds->numVerts,
262 					 se->mds->numIndexes,
263 					 ( se->mds->planar ? "planar" : "" ) );
264 		}
265 
266 		/* open braces */
267 		fprintf( sf, "{\n" );
268 
269 		/* shader */
270 		if ( se->si != NULL ) {
271 			fprintf( sf, "\tshader %s\n", se->si->shader );
272 		}
273 
274 		/* parent surface number */
275 		if ( se->parentSurfaceNum != seDefault.parentSurfaceNum ) {
276 			fprintf( sf, "\tparent %d\n", se->parentSurfaceNum );
277 		}
278 
279 		/* entity number */
280 		if ( se->entityNum != seDefault.entityNum ) {
281 			fprintf( sf, "\tentity %d\n", se->entityNum );
282 		}
283 
284 		/* cast shadows */
285 		if ( se->castShadows != seDefault.castShadows || se == &seDefault ) {
286 			fprintf( sf, "\tcastShadows %d\n", se->castShadows );
287 		}
288 
289 		/* recv shadows */
290 		if ( se->recvShadows != seDefault.recvShadows || se == &seDefault ) {
291 			fprintf( sf, "\treceiveShadows %d\n", se->recvShadows );
292 		}
293 
294 		/* lightmap sample size */
295 		if ( se->sampleSize != seDefault.sampleSize || se == &seDefault ) {
296 			fprintf( sf, "\tsampleSize %d\n", se->sampleSize );
297 		}
298 
299 		/* longest curve */
300 		if ( se->longestCurve != seDefault.longestCurve || se == &seDefault ) {
301 			fprintf( sf, "\tlongestCurve %f\n", se->longestCurve );
302 		}
303 
304 		/* lightmap axis vector */
305 		if ( VectorCompare( se->lightmapAxis, seDefault.lightmapAxis ) == qfalse ) {
306 			fprintf( sf, "\tlightmapAxis ( %f %f %f )\n", se->lightmapAxis[ 0 ], se->lightmapAxis[ 1 ], se->lightmapAxis[ 2 ] );
307 		}
308 
309 		/* close braces */
310 		fprintf( sf, "}\n\n" );
311 	}
312 
313 	/* close the file */
314 	fclose( sf );
315 }
316 
317 
318 
319 /*
320    LoadSurfaceExtraFile()
321    reads a surface info file (<map>.srf)
322  */
323 
LoadSurfaceExtraFile(const char * path)324 void LoadSurfaceExtraFile( const char *path ){
325 	char srfPath[ 1024 ];
326 	surfaceExtra_t  *se;
327 	int surfaceNum, size;
328 	byte            *buffer;
329 
330 
331 	/* dummy check */
332 	if ( path == NULL || path[ 0 ] == '\0' ) {
333 		return;
334 	}
335 
336 	/* load the file */
337 	strcpy( srfPath, path );
338 	StripExtension( srfPath );
339 	strcat( srfPath, ".srf" );
340 	Sys_Printf( "Loading %s\n", srfPath );
341 	size = LoadFile( srfPath, (void**) &buffer );
342 	if ( size <= 0 ) {
343 		Sys_Printf( "WARNING: Unable to find surface file %s, using defaults.\n", srfPath );
344 		return;
345 	}
346 
347 	/* parse the file */
348 	ParseFromMemory( (char *) buffer, size );
349 
350 	/* tokenize it */
351 	while ( 1 )
352 	{
353 		/* test for end of file */
354 		if ( !GetToken( qtrue ) ) {
355 			break;
356 		}
357 
358 		/* default? */
359 		if ( !Q_stricmp( token, "default" ) ) {
360 			se = &seDefault;
361 		}
362 
363 		/* surface number */
364 		else
365 		{
366 			surfaceNum = atoi( token );
367 			if ( surfaceNum < 0 || surfaceNum > MAX_MAP_DRAW_SURFS ) {
368 				Error( "ReadSurfaceExtraFile(): %s, line %d: bogus surface num %d", srfPath, scriptline, surfaceNum );
369 			}
370 			while ( surfaceNum >= numSurfaceExtras )
371 				se = AllocSurfaceExtra();
372 			se = &surfaceExtras[ surfaceNum ];
373 		}
374 
375 		/* handle { } section */
376 		if ( !GetToken( qtrue ) || strcmp( token, "{" ) ) {
377 			Error( "ReadSurfaceExtraFile(): %s, line %d: { not found", srfPath, scriptline );
378 		}
379 		while ( 1 )
380 		{
381 			if ( !GetToken( qtrue ) ) {
382 				break;
383 			}
384 			if ( !strcmp( token, "}" ) ) {
385 				break;
386 			}
387 
388 			/* shader */
389 			if ( !Q_stricmp( token, "shader" ) ) {
390 				GetToken( qfalse );
391 				se->si = ShaderInfoForShader( token );
392 			}
393 
394 			/* parent surface number */
395 			else if ( !Q_stricmp( token, "parent" ) ) {
396 				GetToken( qfalse );
397 				se->parentSurfaceNum = atoi( token );
398 			}
399 
400 			/* entity number */
401 			else if ( !Q_stricmp( token, "entity" ) ) {
402 				GetToken( qfalse );
403 				se->entityNum = atoi( token );
404 			}
405 
406 			/* cast shadows */
407 			else if ( !Q_stricmp( token, "castShadows" ) ) {
408 				GetToken( qfalse );
409 				se->castShadows = atoi( token );
410 			}
411 
412 			/* recv shadows */
413 			else if ( !Q_stricmp( token, "receiveShadows" ) ) {
414 				GetToken( qfalse );
415 				se->recvShadows = atoi( token );
416 			}
417 
418 			/* lightmap sample size */
419 			else if ( !Q_stricmp( token, "sampleSize" ) ) {
420 				GetToken( qfalse );
421 				se->sampleSize = atoi( token );
422 			}
423 
424 			/* longest curve */
425 			else if ( !Q_stricmp( token, "longestCurve" ) ) {
426 				GetToken( qfalse );
427 				se->longestCurve = atof( token );
428 			}
429 
430 			/* lightmap axis vector */
431 			else if ( !Q_stricmp( token, "lightmapAxis" ) ) {
432 				Parse1DMatrix( 3, se->lightmapAxis );
433 			}
434 
435 			/* ignore all other tokens on the line */
436 			while ( TokenAvailable() )
437 				GetToken( qfalse );
438 		}
439 	}
440 
441 	/* free the buffer */
442 	free( buffer );
443 }
444