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