Author: rambetter
[divverent/netradiant.git] / tools / quake3 / q3map2 / surface_foliage.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 Foliage code for Wolfenstein: Enemy Territory by ydnar@splashdamage.com
25
26 ------------------------------------------------------------------------------- */
27
28
29
30 /* marker */
31 #define SURFACE_FOLIAGE_C
32
33
34
35 /* dependencies */
36 #include "q3map2.h"
37
38
39
40 #define MAX_FOLIAGE_INSTANCES   8192
41
42 static int                                              numFoliageInstances;
43 static foliageInstance_t                foliageInstances[ MAX_FOLIAGE_INSTANCES ];
44
45
46
47 /*
48 SubdivideFoliageTriangle_r()
49 recursively subdivides a triangle until the triangle is smaller than
50 the desired density, then pseudo-randomly sets a point
51 */
52
53 static void SubdivideFoliageTriangle_r( mapDrawSurface_t *ds, foliage_t *foliage, bspDrawVert_t **tri )
54 {
55         bspDrawVert_t   mid, *tri2[ 3 ];
56         int                             max;
57         
58         
59         /* limit test */
60         if( numFoliageInstances >= MAX_FOLIAGE_INSTANCES )
61                 return;
62         
63         /* plane test */
64         {
65                 vec4_t          plane;
66                 
67                 
68                 /* make a plane */
69                 if( !PlaneFromPoints( plane, tri[ 0 ]->xyz, tri[ 1 ]->xyz, tri[ 2 ]->xyz ) )
70                         return;
71                 
72                 /* if normal is too far off vertical, then don't place an instance */
73                 if( plane[ 2 ] < 0.5f )
74                         return;
75         }
76         
77         /* subdivide calc */
78         {
79                 int                                     i;
80                 float                           *a, *b, dx, dy, dz, dist, maxDist;
81                 foliageInstance_t       *fi;
82                 
83                 
84                 /* get instance */
85                 fi = &foliageInstances[ numFoliageInstances ];
86                 
87                 /* find the longest edge and split it */
88                 max = -1;
89                 maxDist = 0.0f;
90                 VectorClear( fi->xyz );
91                 VectorClear( fi->normal );
92                 for( i = 0; i < 3; i++ )
93                 {
94                         /* get verts */
95                         a = tri[ i ]->xyz;
96                         b = tri[ (i + 1) % 3 ]->xyz;
97                         
98                         /* get dists */
99                         dx = a[ 0 ] - b[ 0 ];
100                         dy = a[ 1 ] - b[ 1 ];
101                         dz = a[ 2 ] - b[ 2 ];
102                         dist = (dx * dx) + (dy * dy) + (dz * dz);
103                         
104                         /* longer? */
105                         if( dist > maxDist )
106                         {
107                                 maxDist = dist;
108                                 max = i;
109                         }
110                         
111                         /* add to centroid */
112                         VectorAdd( fi->xyz, tri[ i ]->xyz, fi->xyz );
113                         VectorAdd( fi->normal, tri[ i ]->normal, fi->normal );
114                 }
115                 
116                 /* is the triangle small enough? */
117                 if( maxDist <= (foliage->density * foliage->density) )
118                 {
119                         float   alpha, odds, r;
120                         
121                         
122                         /* get average alpha */
123                         if( foliage->inverseAlpha == 2 )
124                                 alpha = 1.0f;
125                         else
126                         {
127                                 alpha = ((float) tri[ 0 ]->color[ 0 ][ 3 ] + (float) tri[ 1 ]->color[ 0 ][ 3 ] + (float) tri[ 2 ]->color[ 0 ][ 3 ]) / 765.0f;
128                                 if( foliage->inverseAlpha == 1 )
129                                         alpha = 1.0f - alpha;
130                                 if( alpha < 0.75f )
131                                         return;
132                         }
133                         
134                         /* roll the dice */
135                         odds = foliage->odds * alpha;
136                         r = Random();
137                         if( r > odds )
138                                 return;
139                         
140                         /* scale centroid */
141                         VectorScale( fi->xyz, 0.33333333f, fi->xyz );
142                         if( VectorNormalize( fi->normal, fi->normal ) == 0.0f )
143                                 return;
144                         
145                         /* add to count and return */
146                         numFoliageInstances++;
147                         return;
148                 }
149         }
150         
151         /* split the longest edge and map it */
152         LerpDrawVert( tri[ max ], tri[ (max + 1) % 3 ], &mid );
153         
154         /* recurse to first triangle */
155         VectorCopy( tri, tri2 );
156         tri2[ max ] = &mid;
157         SubdivideFoliageTriangle_r( ds, foliage, tri2 );
158         
159         /* recurse to second triangle */
160         VectorCopy( tri, tri2 );
161         tri2[ (max + 1) % 3 ] = &mid;
162         SubdivideFoliageTriangle_r( ds, foliage, tri2 );
163 }
164
165
166
167 /*
168 GenFoliage()
169 generates a foliage file for a bsp
170 */
171
172 void Foliage( mapDrawSurface_t *src )
173 {
174         int                                     i, j, k, x, y, pw[ 5 ], r, oldNumMapDrawSurfs;
175         mapDrawSurface_t        *ds;
176         shaderInfo_t            *si;
177         foliage_t                       *foliage;
178         mesh_t                          srcMesh, *subdivided, *mesh;
179         bspDrawVert_t           *verts, *dv[ 3 ], *fi;
180         vec3_t                          scale;
181         m4x4_t                          transform;
182         
183         
184         /* get shader */
185         si = src->shaderInfo;
186         if( si == NULL || si->foliage == NULL )
187                 return;
188         
189         /* do every foliage */
190         for( foliage = si->foliage; foliage != NULL; foliage = foliage->next )
191         {
192                 /* zero out */
193                 numFoliageInstances = 0;
194                 
195                 /* map the surface onto the lightmap origin/cluster/normal buffers */
196                 switch( src->type )
197                 {
198                         case SURFACE_META:
199                         case SURFACE_FORCED_META:
200                         case SURFACE_TRIANGLES:
201                                 /* get verts */
202                                 verts = src->verts;
203                                 
204                                 /* map the triangles */
205                                 for( i = 0; i < src->numIndexes; i += 3 )
206                                 {
207                                         dv[ 0 ] = &verts[ src->indexes[ i ] ];
208                                         dv[ 1 ] = &verts[ src->indexes[ i + 1 ] ];
209                                         dv[ 2 ] = &verts[ src->indexes[ i + 2 ] ];
210                                         SubdivideFoliageTriangle_r( src, foliage, dv );
211                                 }
212                                 break;
213                         
214                         case SURFACE_PATCH:
215                                 /* make a mesh from the drawsurf */ 
216                                 srcMesh.width = src->patchWidth;
217                                 srcMesh.height = src->patchHeight;
218                                 srcMesh.verts = src->verts;
219                                 subdivided = SubdivideMesh( srcMesh, 8, 512 );
220                                 
221                                 /* fit it to the curve and remove colinear verts on rows/columns */
222                                 PutMeshOnCurve( *subdivided );
223                                 mesh = RemoveLinearMeshColumnsRows( subdivided );
224                                 FreeMesh( subdivided );
225                                 
226                                 /* get verts */
227                                 verts = mesh->verts;
228                                 
229                                 /* map the mesh quads */
230                                 for( y = 0; y < (mesh->height - 1); y++ )
231                                 {
232                                         for( x = 0; x < (mesh->width - 1); x++ )
233                                         {
234                                                 /* set indexes */
235                                                 pw[ 0 ] = x + (y * mesh->width);
236                                                 pw[ 1 ] = x + ((y + 1) * mesh->width);
237                                                 pw[ 2 ] = x + 1 + ((y + 1) * mesh->width);
238                                                 pw[ 3 ] = x + 1 + (y * mesh->width);
239                                                 pw[ 4 ] = x + (y * mesh->width);        /* same as pw[ 0 ] */
240                                                 
241                                                 /* set radix */
242                                                 r = (x + y) & 1;
243                                                 
244                                                 /* get drawverts and map first triangle */
245                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
246                                                 dv[ 1 ] = &verts[ pw[ r + 1 ] ];
247                                                 dv[ 2 ] = &verts[ pw[ r + 2 ] ];
248                                                 SubdivideFoliageTriangle_r( src, foliage, dv );
249                                                 
250                                                 /* get drawverts and map second triangle */
251                                                 dv[ 0 ] = &verts[ pw[ r + 0 ] ];
252                                                 dv[ 1 ] = &verts[ pw[ r + 2 ] ];
253                                                 dv[ 2 ] = &verts[ pw[ r + 3 ] ];
254                                                 SubdivideFoliageTriangle_r( src, foliage, dv );
255                                         }
256                                 }
257                                 
258                                 /* free the mesh */
259                                 FreeMesh( mesh );
260                                 break;
261                         
262                         default:
263                                 break;
264                 }
265                 
266                 /* any origins? */
267                 if( numFoliageInstances < 1 )
268                         continue;
269                 
270                 /* remember surface count */
271                 oldNumMapDrawSurfs = numMapDrawSurfs;
272                 
273                 /* set transform matrix */
274                 VectorSet( scale, foliage->scale, foliage->scale, foliage->scale );
275                 m4x4_scale_for_vec3( transform, scale );
276                 
277                 /* add the model to the bsp */
278                 InsertModel( foliage->model, 0, 0, transform, NULL, NULL, src->entityNum, src->castShadows, src->recvShadows, 0, src->lightmapScale, 0, 0 );
279                 
280                 /* walk each new surface */
281                 for( i = oldNumMapDrawSurfs; i < numMapDrawSurfs; i++ )
282                 {
283                         /* get surface */
284                         ds = &mapDrawSurfs[ i ];
285                         
286                         /* set up */
287                         ds->type = SURFACE_FOLIAGE;
288                         ds->numFoliageInstances = numFoliageInstances;
289                         
290                         /* a wee hack */
291                         ds->patchWidth = ds->numFoliageInstances;
292                         ds->patchHeight = ds->numVerts;
293                         
294                         /* set fog to be same as source surface */
295                         ds->fogNum = src->fogNum;
296                         
297                         /* add a drawvert for every instance */
298                         verts = safe_malloc( (ds->numVerts + ds->numFoliageInstances) * sizeof( *verts ) );
299                         memset( verts, 0, (ds->numVerts + ds->numFoliageInstances) * sizeof( *verts ) );
300                         memcpy( verts, ds->verts, ds->numVerts * sizeof( *verts ) );
301                         free( ds->verts );
302                         ds->verts = verts;
303                         
304                         /* copy the verts */
305                         for( j = 0; j < ds->numFoliageInstances; j++ )
306                         {
307                                 /* get vert (foliage instance) */
308                                 fi = &ds->verts[ ds->numVerts + j ];
309
310                                 /* copy xyz and normal */
311                                 VectorCopy( foliageInstances[ j ].xyz, fi->xyz );
312                                 VectorCopy( foliageInstances[ j ].normal, fi->normal );
313
314                                 /* ydnar: set color */
315                                 for( k = 0; k < MAX_LIGHTMAPS; k++ )
316                                 {
317                                         fi->color[ k ][ 0 ] = 255;
318                                         fi->color[ k ][ 1 ] = 255;
319                                         fi->color[ k ][ 2 ] = 255;
320                                         fi->color[ k ][ 3 ] = 255;
321                                 }
322                         }
323                         
324                         /* increment */
325                         ds->numVerts += ds->numFoliageInstances;
326                 }
327         }
328 }