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