2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\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
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
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
21 ----------------------------------------------------------------------------------
\r
23 Foliage code for Wolfenstein: Enemy Territory by ydnar@splashdamage.com
\r
25 ------------------------------------------------------------------------------- */
\r
30 #define SURFACE_FOLIAGE_C
\r
39 #define MAX_FOLIAGE_INSTANCES 8192
\r
41 static int numFoliageInstances;
\r
42 static foliageInstance_t foliageInstances[ MAX_FOLIAGE_INSTANCES ];
\r
47 SubdivideFoliageTriangle_r()
\r
48 recursively subdivides a triangle until the triangle is smaller than
\r
49 the desired density, then pseudo-randomly sets a point
\r
52 static void SubdivideFoliageTriangle_r( mapDrawSurface_t *ds, foliage_t *foliage, bspDrawVert_t **tri )
\r
54 bspDrawVert_t mid, *tri2[ 3 ];
\r
59 if( numFoliageInstances >= MAX_FOLIAGE_INSTANCES )
\r
68 if( !PlaneFromPoints( plane, tri[ 0 ]->xyz, tri[ 1 ]->xyz, tri[ 2 ]->xyz ) )
\r
71 /* if normal is too far off vertical, then don't place an instance */
\r
72 if( plane[ 2 ] < 0.5f )
\r
76 /* subdivide calc */
\r
79 float *a, *b, dx, dy, dz, dist, maxDist;
\r
80 foliageInstance_t *fi;
\r
84 fi = &foliageInstances[ numFoliageInstances ];
\r
86 /* find the longest edge and split it */
\r
89 VectorClear( fi->xyz );
\r
90 VectorClear( fi->normal );
\r
91 for( i = 0; i < 3; i++ )
\r
95 b = tri[ (i + 1) % 3 ]->xyz;
\r
98 dx = a[ 0 ] - b[ 0 ];
\r
99 dy = a[ 1 ] - b[ 1 ];
\r
100 dz = a[ 2 ] - b[ 2 ];
\r
101 dist = (dx * dx) + (dy * dy) + (dz * dz);
\r
104 if( dist > maxDist )
\r
110 /* add to centroid */
\r
111 VectorAdd( fi->xyz, tri[ i ]->xyz, fi->xyz );
\r
112 VectorAdd( fi->normal, tri[ i ]->normal, fi->normal );
\r
115 /* is the triangle small enough? */
\r
116 if( maxDist <= (foliage->density * foliage->density) )
\r
118 float alpha, odds, r;
\r
121 /* get average alpha */
\r
122 if( foliage->inverseAlpha == 2 )
\r
126 alpha = ((float) tri[ 0 ]->color[ 0 ][ 3 ] + (float) tri[ 1 ]->color[ 0 ][ 3 ] + (float) tri[ 2 ]->color[ 0 ][ 3 ]) / 765.0f;
\r
127 if( foliage->inverseAlpha == 1 )
\r
128 alpha = 1.0f - alpha;
\r
129 if( alpha < 0.75f )
\r
133 /* roll the dice */
\r
134 odds = foliage->odds * alpha;
\r
139 /* scale centroid */
\r
140 VectorScale( fi->xyz, 0.33333333f, fi->xyz );
\r
141 if( VectorNormalize( fi->normal, fi->normal ) == 0.0f )
\r
144 /* add to count and return */
\r
145 numFoliageInstances++;
\r
150 /* split the longest edge and map it */
\r
151 LerpDrawVert( tri[ max ], tri[ (max + 1) % 3 ], &mid );
\r
153 /* recurse to first triangle */
\r
154 VectorCopy( tri, tri2 );
\r
155 tri2[ max ] = ∣
\r
156 SubdivideFoliageTriangle_r( ds, foliage, tri2 );
\r
158 /* recurse to second triangle */
\r
159 VectorCopy( tri, tri2 );
\r
160 tri2[ (max + 1) % 3 ] = ∣
\r
161 SubdivideFoliageTriangle_r( ds, foliage, tri2 );
\r
168 generates a foliage file for a bsp
\r
171 void Foliage( mapDrawSurface_t *src )
\r
173 int i, j, k, x, y, pw[ 5 ], r, oldNumMapDrawSurfs;
\r
174 mapDrawSurface_t *ds;
\r
176 foliage_t *foliage;
\r
177 mesh_t srcMesh, *subdivided, *mesh;
\r
178 bspDrawVert_t *verts, *dv[ 3 ], *fi;
\r
184 si = src->shaderInfo;
\r
185 if( si == NULL || si->foliage == NULL )
\r
188 /* do every foliage */
\r
189 for( foliage = si->foliage; foliage != NULL; foliage = foliage->next )
\r
192 numFoliageInstances = 0;
\r
194 /* map the surface onto the lightmap origin/cluster/normal buffers */
\r
195 switch( src->type )
\r
198 case SURFACE_FORCED_META:
\r
199 case SURFACE_TRIANGLES:
\r
201 verts = src->verts;
\r
203 /* map the triangles */
\r
204 for( i = 0; i < src->numIndexes; i += 3 )
\r
206 dv[ 0 ] = &verts[ src->indexes[ i ] ];
\r
207 dv[ 1 ] = &verts[ src->indexes[ i + 1 ] ];
\r
208 dv[ 2 ] = &verts[ src->indexes[ i + 2 ] ];
\r
209 SubdivideFoliageTriangle_r( src, foliage, dv );
\r
213 case SURFACE_PATCH:
\r
214 /* make a mesh from the drawsurf */
\r
215 srcMesh.width = src->patchWidth;
\r
216 srcMesh.height = src->patchHeight;
\r
217 srcMesh.verts = src->verts;
\r
218 subdivided = SubdivideMesh( srcMesh, 8, 512 );
\r
220 /* fit it to the curve and remove colinear verts on rows/columns */
\r
221 PutMeshOnCurve( *subdivided );
\r
222 mesh = RemoveLinearMeshColumnsRows( subdivided );
\r
223 FreeMesh( subdivided );
\r
226 verts = mesh->verts;
\r
228 /* map the mesh quads */
\r
229 for( y = 0; y < (mesh->height - 1); y++ )
\r
231 for( x = 0; x < (mesh->width - 1); x++ )
\r
234 pw[ 0 ] = x + (y * mesh->width);
\r
235 pw[ 1 ] = x + ((y + 1) * mesh->width);
\r
236 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
\r
237 pw[ 3 ] = x + 1 + (y * mesh->width);
\r
238 pw[ 4 ] = x + (y * mesh->width); /* same as pw[ 0 ] */
\r
243 /* get drawverts and map first triangle */
\r
244 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
\r
245 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
\r
246 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
\r
247 SubdivideFoliageTriangle_r( src, foliage, dv );
\r
249 /* get drawverts and map second triangle */
\r
250 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
\r
251 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
\r
252 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
\r
253 SubdivideFoliageTriangle_r( src, foliage, dv );
\r
257 /* free the mesh */
\r
266 if( numFoliageInstances < 1 )
\r
269 /* remember surface count */
\r
270 oldNumMapDrawSurfs = numMapDrawSurfs;
\r
272 /* set transform matrix */
\r
273 VectorSet( scale, foliage->scale, foliage->scale, foliage->scale );
\r
274 m4x4_scale_for_vec3( transform, scale );
\r
276 /* add the model to the bsp */
\r
277 InsertModel( foliage->model, 0, transform, NULL, NULL, src->entityNum, src->castShadows, src->recvShadows, 0, src->lightmapScale );
\r
279 /* walk each new surface */
\r
280 for( i = oldNumMapDrawSurfs; i < numMapDrawSurfs; i++ )
\r
283 ds = &mapDrawSurfs[ i ];
\r
286 ds->type = SURFACE_FOLIAGE;
\r
287 ds->numFoliageInstances = numFoliageInstances;
\r
290 ds->patchWidth = ds->numFoliageInstances;
\r
291 ds->patchHeight = ds->numVerts;
\r
293 /* set fog to be same as source surface */
\r
294 ds->fogNum = src->fogNum;
\r
296 /* add a drawvert for every instance */
\r
297 verts = safe_malloc( (ds->numVerts + ds->numFoliageInstances) * sizeof( *verts ) );
\r
298 memset( verts, 0, (ds->numVerts + ds->numFoliageInstances) * sizeof( *verts ) );
\r
299 memcpy( verts, ds->verts, ds->numVerts * sizeof( *verts ) );
\r
303 /* copy the verts */
\r
304 for( j = 0; j < ds->numFoliageInstances; j++ )
\r
306 /* get vert (foliage instance) */
\r
307 fi = &ds->verts[ ds->numVerts + j ];
\r
309 /* copy xyz and normal */
\r
310 VectorCopy( foliageInstances[ j ].xyz, fi->xyz );
\r
311 VectorCopy( foliageInstances[ j ].normal, fi->normal );
\r
313 /* ydnar: set color */
\r
314 for( k = 0; k < MAX_LIGHTMAPS; k++ )
\r
316 fi->color[ k ][ 0 ] = 255;
\r
317 fi->color[ k ][ 1 ] = 255;
\r
318 fi->color[ k ][ 2 ] = 255;
\r
319 fi->color[ k ][ 3 ] = 255;
\r
324 ds->numVerts += ds->numFoliageInstances;
\r