]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
fix func_sparks
[divverent/nexuiz.git] / misc / gtkradiant / gtkradiant-nexuiz-patchset.diff
1 NOTE: this patch set is autogenerated from the "singlepatches" subdirectory of nexuiz/trunk/misc.
2
3 Do not commit changes to THIS!
4
5 Always run
6         sh mergepatches.sh > gtkradiant-nexuiz-patchset.diff
7 before committing new singlepatches!
8
9
10
11 Index: libs/picomodel/pm_obj.c
12 ===================================================================
13 --- libs/picomodel/pm_obj.c     (revision 290)
14 +++ libs/picomodel/pm_obj.c     (working copy)
15 @@ -215,10 +215,9 @@
16         }
17  }
18  
19 -#if 0
20  static int _obj_mtl_load( picoModel_t *model )
21  {
22 -       //picoShader_t *curShader = NULL;
23 +       picoShader_t *curShader = NULL;
24         picoParser_t *p;
25         picoByte_t   *mtlBuffer;
26         int                       mtlBufSize;
27 @@ -266,7 +265,7 @@
28                 /* get next token in material file */
29                 if (_pico_parse( p,1 ) == NULL)
30                         break;
31 -#if 0
32 +#if 1
33  
34                 /* skip empty lines */
35                 if (p->token == NULL || !strlen( p->token ))
36 @@ -308,6 +307,7 @@
37                 else if (!_pico_stricmp(p->token,"map_kd"))
38                 {
39                         char *mapName;
40 +                       picoShader_t *shader;
41  
42                         /* pointer to current shader must be valid */
43                         if (curShader == NULL)
44 @@ -322,6 +322,10 @@
45                                 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
46                                 _obj_mtl_error_return;
47                         }
48 +                       /* create a new pico shader */
49 +                       shader = PicoNewShader( model );
50 +                       if (shader == NULL)
51 +                               _obj_mtl_error_return;
52                         /* set shader map name */
53                         PicoSetShaderMapName( shader,mapName );
54                 }
55 @@ -478,7 +482,6 @@
56         /* return with success */
57         return 1;
58  }
59 -#endif
60  
61  /* _obj_load:
62   *  loads a wavefront obj model file.
63 @@ -523,7 +526,7 @@
64         PicoSetModelFileName( model,fileName );
65  
66         /* try loading the materials; we don't handle the result */
67 -#if 0
68 +#if 1
69         _obj_mtl_load( model );
70  #endif
71  
72 @@ -832,6 +835,41 @@
73                                 curVertex += max;
74                         }
75                 }
76 +               else if (!_pico_stricmp(p->token,"usemtl"))
77 +               {
78 +                       picoShader_t *shader;
79 +                       char *name;
80 +
81 +                       /* get material name */
82 +                       name = _pico_parse( p,0 );
83 +
84 +                       /* validate material name */
85 +                       if (name == NULL || !strlen(name))
86 +                       {
87 +                               _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
88 +                       }
89 +                       else
90 +                       {
91 +                               shader = PicoFindShader( model, name, 1 );
92 +                               if (shader == NULL)
93 +                               {
94 +                                       _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
95 +
96 +                                       /* create a new pico shader */
97 +                                       shader = PicoNewShader( model );
98 +                                       if (shader != NULL)
99 +                                       {
100 +                                               PicoSetShaderName( shader,name );
101 +                                               PicoSetShaderMapName( shader,name );
102 +                                               PicoSetSurfaceShader( curSurface, shader );
103 +                                       }
104 +                               }
105 +                               else
106 +                               {
107 +                                       PicoSetSurfaceShader( curSurface, shader );
108 +                               }
109 +                       }
110 +               }
111                 /* skip unparsed rest of line and continue */
112                 _pico_parse_skip_rest( p );
113         }
114 Index: tools/quake3/q3map2/convert_map.c
115 ===================================================================
116 --- tools/quake3/q3map2/convert_map.c   (revision 191)
117 +++ tools/quake3/q3map2/convert_map.c   (working copy)
118 @@ -46,6 +46,105 @@
119  #define        SNAP_FLOAT_TO_INT       4
120  #define        SNAP_INT_TO_FLOAT       (1.0 / SNAP_FLOAT_TO_INT)
121  
122 +typedef vec_t vec2_t[2];
123 +
124 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
125 +                    vec_t a10, vec_t a11, vec_t a12,
126 +                    vec_t a20, vec_t a21, vec_t a22)
127 +{
128 +       return
129 +               a00 * (a11 * a22 - a12 * a21)
130 +       -       a01 * (a10 * a22 - a12 * a20)
131 +       +       a02 * (a10 * a21 - a11 * a20);
132 +}
133 +
134 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
135 +{
136 +       bspDrawSurface_t *s;
137 +       int i;
138 +       int t;
139 +       vec_t best = 0;
140 +       vec_t thisarea;
141 +       vec3_t normdiff;
142 +       vec3_t v1v0, v2v0, norm;
143 +       bspDrawVert_t *vert[3];
144 +       winding_t *polygon;
145 +       plane_t *buildPlane = &mapplanes[buildSide->planenum];
146 +       int matches = 0;
147 +
148 +       // first, start out with NULLs
149 +       bestVert[0] = bestVert[1] = bestVert[2] = NULL;
150 +
151 +       // brute force through all surfaces
152 +       for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
153 +       {
154 +               if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
155 +                       continue;
156 +               if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
157 +                       continue;
158 +               for(t = 0; t + 3 <= s->numIndexes; t += 3)
159 +               {
160 +                       vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
161 +                       vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
162 +                       vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
163 +                       if(s->surfaceType == MST_PLANAR)
164 +                       {
165 +                               VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
166 +                               VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
167 +                               VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
168 +                       }
169 +                       else
170 +                       {
171 +                               // this is more prone to roundoff errors, but with embedded
172 +                               // models, there is no better way
173 +                               VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
174 +                               VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
175 +                               CrossProduct(v2v0, v1v0, norm);
176 +                               VectorNormalize(norm, norm);
177 +                               VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
178 +                       }
179 +                       if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
180 +                       if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
181 +                       if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
182 +                       // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
183 +                       polygon = CopyWinding(buildSide->winding);
184 +                       for(i = 0; i < 3; ++i)
185 +                       {
186 +                               // 0: 1, 2
187 +                               // 1: 2, 0
188 +                               // 2; 0, 1
189 +                               vec3_t *v1 = &vert[(i+1)%3]->xyz;
190 +                               vec3_t *v2 = &vert[(i+2)%3]->xyz;
191 +                               vec3_t triNormal;
192 +                               vec_t triDist;
193 +                               vec3_t sideDirection;
194 +                               // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
195 +                               VectorSubtract(*v2, *v1, sideDirection);
196 +                               CrossProduct(sideDirection, buildPlane->normal, triNormal);
197 +                               triDist = DotProduct(*v1, triNormal);
198 +                               ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
199 +                               if(!polygon)
200 +                                       goto exwinding;
201 +                       }
202 +                       thisarea = WindingArea(polygon);
203 +                       if(thisarea > 0)
204 +                               ++matches;
205 +                       if(thisarea > best)
206 +                       {
207 +                               best = thisarea;
208 +                               bestVert[0] = vert[0];
209 +                               bestVert[1] = vert[1];
210 +                               bestVert[2] = vert[2];
211 +                       }
212 +                       FreeWinding(polygon);
213 +exwinding:
214 +                       ;
215 +               }
216 +       }
217 +       //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
218 +       //      fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
219 +}
220 +
221  static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
222  {
223         int                             i, j;
224 @@ -54,12 +153,17 @@
225         bspShader_t             *shader;
226         char                    *texture;
227         bspPlane_t              *plane;
228 +       plane_t         *buildPlane;
229         vec3_t                  pts[ 3 ];
230 +       bspDrawVert_t   *vert[3];
231 +       int valid;
232         
233         
234         /* start brush */
235         fprintf( f, "\t// brush %d\n", num );
236         fprintf( f, "\t{\n" );
237 +       fprintf( f, "\tbrushDef\n" );
238 +       fprintf( f, "\t{\n" );
239         
240         /* clear out build brush */
241         for( i = 0; i < buildBrush->numsides; i++ )
242 @@ -109,9 +213,88 @@
243                 /* get build side */
244                 buildSide = &buildBrush->sides[ i ];
245                 
246 +               /* get plane */
247 +               buildPlane = &mapplanes[ buildSide->planenum ];
248 +               
249                 /* dummy check */
250                 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
251                         continue;
252 +
253 +               // st-texcoords -> texMat block
254 +               // start out with dummy
255 +               VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
256 +               VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
257 +
258 +               // find surface for this side (by brute force)
259 +               // surface format:
260 +               //   - meshverts point in pairs of three into verts
261 +               //   - (triangles)
262 +               //   - find the triangle that has most in common with our side
263 +               GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
264 +               valid = 0;
265 +
266 +               if(vert[0] && vert[1] && vert[2])
267 +               {
268 +                       int i;
269 +                       vec3_t texX, texY;
270 +                       vec3_t xy1I, xy1J, xy1K;
271 +                       vec2_t stI, stJ, stK;
272 +                       vec_t D, D0, D1, D2;
273 +
274 +                       ComputeAxisBase(buildPlane->normal, texX, texY);
275 +
276 +                       VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
277 +                       VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
278 +                       VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
279 +                       stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
280 +                       stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
281 +                       stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
282 +
283 +                       //   - solve linear equations:
284 +                       //     - (x, y) := xyz . (texX, texY)
285 +                       //     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
286 +                       //       (for three vertices)
287 +                       D = Det3x3(
288 +                               xy1I[0], xy1I[1], 1,
289 +                               xy1J[0], xy1J[1], 1,
290 +                               xy1K[0], xy1K[1], 1
291 +                       );
292 +                       if(D != 0)
293 +                       {
294 +                               for(i = 0; i < 2; ++i)
295 +                               {
296 +                                       D0 = Det3x3(
297 +                                               stI[i], xy1I[1], 1,
298 +                                               stJ[i], xy1J[1], 1,
299 +                                               stK[i], xy1K[1], 1
300 +                                       );
301 +                                       D1 = Det3x3(
302 +                                               xy1I[0], stI[i], 1,
303 +                                               xy1J[0], stJ[i], 1,
304 +                                               xy1K[0], stK[i], 1
305 +                                       );
306 +                                       D2 = Det3x3(
307 +                                               xy1I[0], xy1I[1], stI[i],
308 +                                               xy1J[0], xy1J[1], stJ[i],
309 +                                               xy1K[0], xy1K[1], stK[i]
310 +                                       );
311 +                                       VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
312 +                                       valid = 1;
313 +                               }
314 +                       }
315 +                       else
316 +                               fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
317 +                                       buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
318 +                                       vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], 
319 +                                       texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
320 +                                       vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
321 +                                       vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
322 +                                       vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
323 +                                       );
324 +               }
325 +               else
326 +                       if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
327 +                               fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
328                 
329                 /* get texture name */
330                 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
331 @@ -130,14 +313,21 @@
332                 
333                 /* print brush side */
334                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
335 -               fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
336 +               fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
337                         pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
338                         pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
339                         pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
340 -                       texture );
341 +                       buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
342 +                       buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
343 +                       texture,
344 +                       // DEBUG: valid ? 0 : C_DETAIL
345 +                       0
346 +                       );
347 +               // TODO write brush primitives format here
348         }
349         
350         /* end brush */
351 +       fprintf( f, "\t}\n" );
352         fprintf( f, "\t}\n\n" );
353  }
354  
355 Index: tools/quake3/q3map2/main.c
356 ===================================================================
357 --- tools/quake3/q3map2/main.c  (revision 191)
358 +++ tools/quake3/q3map2/main.c  (working copy)
359 @@ -541,6 +541,18 @@
360                                         Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
361                         }
362                 }
363 +               else if( !strcmp( argv[ i ],  "-ne" ) )
364 +               {
365 +                       normalEpsilon = atof( argv[ i + 1 ] );
366 +                       i++;
367 +                       Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
368 +               }
369 +               else if( !strcmp( argv[ i ],  "-de" ) )
370 +               {
371 +                       distanceEpsilon = atof( argv[ i + 1 ] );
372 +                       i++;
373 +                       Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
374 +               }
375         }
376         
377         /* clean up map name */
378 Index: tools/quake3/q3map2/model.c
379 ===================================================================
380 --- tools/quake3/q3map2/model.c (revision 193)
381 +++ tools/quake3/q3map2/model.c (working copy)
382 @@ -222,6 +222,8 @@
383         byte                            *color;
384         picoIndex_t                     *indexes;
385         remap_t                         *rm, *glob;
386 +       double                          normalEpsilon_save;
387 +       double                          distanceEpsilon_save;
388         
389         
390         /* get model */
391 @@ -398,9 +400,8 @@
392                 /* ydnar: giant hack land: generate clipping brushes for model triangles */
393                 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
394                 {
395 -                       vec3_t          points[ 3 ], backs[ 3 ];
396 +                       vec3_t          points[ 4 ], backs[ 3 ];
397                         vec4_t          plane, reverse, pa, pb, pc;
398 -                       vec3_t          nadir;
399                         
400                         
401                         /* temp hack */
402 @@ -437,90 +438,141 @@
403                                         /* note: this doesn't work as well as simply using the plane of the triangle, below */
404                                         for( k = 0; k < 3; k++ )
405                                         {
406 -                                               if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
407 -                                                       fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
408 +                                               if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
409 +                                                       fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
410                                                 {
411                                                         backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
412                                                         break;
413                                                 }
414                                         }
415                                 }
416 +
417 +                               VectorCopy( points[0], points[3] ); // for cyclic usage
418                                 
419                                 /* make plane for triangle */
420 +                               // div0: add some extra spawnflags:
421 +                               //   0: snap normals to axial planes for extrusion
422 +                               //   8: extrude with the original normals
423 +                               //  16: extrude only with up/down normals (ideal for terrain)
424 +                               //  24: extrude by distance zero (may need engine changes)
425                                 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
426                                 {
427 +                                       vec3_t bestNormal;
428 +                                       float backPlaneDistance = 2;
429 +
430 +                                       if(spawnFlags & 8) // use a DOWN normal
431 +                                       {
432 +                                               if(spawnFlags & 16)
433 +                                               {
434 +                                                       // 24: normal as is, and zero width (broken)
435 +                                                       VectorCopy(plane, bestNormal);
436 +                                               }
437 +                                               else
438 +                                               {
439 +                                                       // 8: normal as is
440 +                                                       VectorCopy(plane, bestNormal);
441 +                                               }
442 +                                       }
443 +                                       else
444 +                                       {
445 +                                               if(spawnFlags & 16)
446 +                                               {
447 +                                                       // 16: UP/DOWN normal
448 +                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
449 +                                               }
450 +                                               else
451 +                                               {
452 +                                                       // 0: axial normal
453 +                                                       if(fabs(plane[0]) > fabs(plane[1])) // x>y
454 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
455 +                                                                       VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
456 +                                                               else // x>y, z>=y
457 +                                                                       if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
458 +                                                                               VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
459 +                                                                       else // z>=x, x>y
460 +                                                                               VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
461 +                                                       else // y>=x
462 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
463 +                                                                       VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
464 +                                                               else // z>=y, y>=x
465 +                                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
466 +                                               }
467 +                                       }
468 +
469 +                                       /* build a brush */
470 +                                       buildBrush = AllocBrush( 48 );
471 +                                       buildBrush->entityNum = mapEntityNum;
472 +                                       buildBrush->original = buildBrush;
473 +                                       buildBrush->contentShader = si;
474 +                                       buildBrush->compileFlags = si->compileFlags;
475 +                                       buildBrush->contentFlags = si->contentFlags;
476 +                                       normalEpsilon_save = normalEpsilon;
477 +                                       distanceEpsilon_save = distanceEpsilon;
478 +                                       if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
479 +                                       {
480 +                                               buildBrush->detail = qfalse;
481 +
482 +                                               // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
483 +                                               if(normalEpsilon > 0)
484 +                                                       normalEpsilon = 0;
485 +                                               if(distanceEpsilon > 0)
486 +                                                       distanceEpsilon = 0;
487 +                                       }
488 +                                       else
489 +                                               buildBrush->detail = qtrue;
490 +
491                                         /* regenerate back points */
492                                         for( j = 0; j < 3; j++ )
493                                         {
494                                                 /* get vertex */
495                                                 dv = &ds->verts[ ds->indexes[ i + j ] ];
496 -                                               
497 -                                               /* copy xyz */
498 -                                               VectorCopy( dv->xyz, backs[ j ] );
499 -                                               
500 -                                               /* find nearest axial to plane normal and push back points opposite */
501 -                                               for( k = 0; k < 3; k++ )
502 -                                               {
503 -                                                       if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
504 -                                                               fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
505 -                                                       {
506 -                                                               backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
507 -                                                               break;
508 -                                                       }
509 -                                               }
510 +
511 +                                               // shift by some units
512 +                                               VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
513                                         }
514 -                                       
515 +
516                                         /* make back plane */
517                                         VectorScale( plane, -1.0f, reverse );
518 -                                       reverse[ 3 ] = -(plane[ 3 ] - 1);
519 -                                       
520 -                                       /* make back pyramid point */
521 -                                       VectorCopy( points[ 0 ], nadir );
522 -                                       VectorAdd( nadir, points[ 1 ], nadir );
523 -                                       VectorAdd( nadir, points[ 2 ], nadir );
524 -                                       VectorScale( nadir, 0.3333333333333f, nadir );
525 -                                       VectorMA( nadir, -2.0f, plane, nadir );
526 -                                       
527 -                                       /* make 3 more planes */
528 -                                       //%     if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
529 -                                       //%             PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
530 -                                       //%             PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
531 +                                       reverse[ 3 ] = -plane[ 3 ];
532 +                                       if((spawnFlags & 24) != 24)
533 +                                               reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
534 +                                       // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
535 +
536                                         if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
537 -                                               PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
538 -                                               PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
539 +                                                       PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
540 +                                                       PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
541                                         {
542 -                                               /* build a brush */
543 -                                               buildBrush = AllocBrush( 48 );
544 -                                               
545 -                                               buildBrush->entityNum = mapEntityNum;
546 -                                               buildBrush->original = buildBrush;
547 -                                               buildBrush->contentShader = si;
548 -                                               buildBrush->compileFlags = si->compileFlags;
549 -                                               buildBrush->contentFlags = si->contentFlags;
550 -                                               buildBrush->detail = qtrue;
551 -                                               
552                                                 /* set up brush sides */
553                                                 buildBrush->numsides = 5;
554                                                 for( j = 0; j < buildBrush->numsides; j++ )
555                                                         buildBrush->sides[ j ].shaderInfo = si;
556 +
557                                                 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
558 -                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
559 -                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
560 -                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
561 -                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
562 -                                               
563 -                                               /* add to entity */
564 -                                               if( CreateBrushWindings( buildBrush ) )
565 -                                               {
566 -                                                       AddBrushBevels();
567 -                                                       //%     EmitBrushes( buildBrush, NULL, NULL );
568 -                                                       buildBrush->next = entities[ mapEntityNum ].brushes;
569 -                                                       entities[ mapEntityNum ].brushes = buildBrush;
570 -                                                       entities[ mapEntityNum ].numBrushes++;
571 -                                               }
572 -                                               else
573 -                                                       free( buildBrush );
574 +                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
575 +                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
576 +                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
577 +                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
578                                         }
579 +                                       else
580 +                                       {
581 +                                               free(buildBrush);
582 +                                               continue;
583 +                                       }
584 +
585 +                                       normalEpsilon = normalEpsilon_save;
586 +                                       distanceEpsilon = distanceEpsilon_save;
587 +
588 +                                       /* add to entity */
589 +                                       if( CreateBrushWindings( buildBrush ) )
590 +                                       {
591 +                                               AddBrushBevels();
592 +                                               //%     EmitBrushes( buildBrush, NULL, NULL );
593 +                                               buildBrush->next = entities[ mapEntityNum ].brushes;
594 +                                               entities[ mapEntityNum ].brushes = buildBrush;
595 +                                               entities[ mapEntityNum ].numBrushes++;
596 +                                       }
597 +                                       else
598 +                                               free( buildBrush );
599                                 }
600                         }
601                 }
602 Index: tools/quake3/q3map2/map.c
603 ===================================================================
604 --- tools/quake3/q3map2/map.c   (revision 193)
605 +++ tools/quake3/q3map2/map.c   (working copy)
606 @@ -184,7 +184,7 @@
607  snaps a plane to normal/distance epsilons
608  */
609  
610 -void SnapPlane( vec3_t normal, vec_t *dist )
611 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
612  {
613  // SnapPlane disabled by LordHavoc because it often messes up collision
614  // brushes made from triangles of embedded models, and it has little effect
615 @@ -193,7 +193,13 @@
616    SnapPlane reenabled by namespace because of multiple reports of
617    q3map2-crashes which were triggered by this patch.
618  */
619 +       // div0: ensure the point "center" stays on the plane (actually, this
620 +       // rotates the plane around the point center).
621 +       // if center lies on the plane, it is guaranteed to stay on the plane by
622 +       // this fix.
623 +       vec_t centerDist = DotProduct(normal, center);
624         SnapNormal( normal );
625 +       *dist += (DotProduct(normal, center) - centerDist);
626  
627         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
628                 *dist = Q_rint( *dist );
629 @@ -207,7 +213,7 @@
630  must be within an epsilon distance of the plane
631  */
632  
633 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
634 +int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
635  
636  #ifdef USE_HASHING
637  
638 @@ -215,10 +221,14 @@
639         int             i, j, hash, h;
640         plane_t *p;
641         vec_t   d;
642 +       vec3_t centerofweight;
643 +
644 +       VectorClear(centerofweight);
645 +       for(i = 0; i < numPoints; ++i)
646 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
647         
648 -       
649         /* hash the plane */
650 -       SnapPlane( normal, &dist );
651 +       SnapPlane( normal, &dist, centerofweight );
652         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
653         
654         /* search the border bins as well */
655 @@ -259,7 +269,13 @@
656         plane_t *p;
657         
658  
659 -       SnapPlane( normal, &dist );
660 +       vec3_t centerofweight;
661 +
662 +       VectorClear(centerofweight);
663 +       for(i = 0; i < numPoints; ++i)
664 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
665 +       
666 +       SnapPlane( normal, &dist, centerofweight );
667         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
668         {
669                 if( PlaneEqual( p, normal, dist ) )
670 Index: tools/quake3/q3map2/shaders.c
671 ===================================================================
672 --- tools/quake3/q3map2/shaders.c       (revision 191)
673 +++ tools/quake3/q3map2/shaders.c       (working copy)
674 @@ -793,8 +793,14 @@
675         }
676         
677         if( VectorLength( si->color ) <= 0.0f )
678 +       {
679                 ColorNormalize( color, si->color );
680 -       VectorScale( color, (1.0f / count), si->averageColor );
681 +               VectorScale( color, (1.0f / count), si->averageColor );
682 +       }
683 +       else
684 +       {
685 +               VectorCopy( si->color, si->averageColor );
686 +       }
687  }
688  
689  
690 Index: tools/quake3/q3map2/light_ydnar.c
691 ===================================================================
692 --- tools/quake3/q3map2/light_ydnar.c   (revision 191)
693 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
694 @@ -1767,6 +1864,8 @@
695         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
696         trace_t                         trace;
697         float                           stackLightLuxels[ STACK_LL_SIZE ];
698 +       vec3_t                          flood;
699 +       float                           *floodlight;
700         
701         
702         /* bail if this number exceeds the number of raw lightmaps */
703 @@ -2223,6 +2332,78 @@
704         FreeTraceLights( &trace );
705         
706         /*      -----------------------------------------------------------------
707 +               floodlight pass
708 +               ----------------------------------------------------------------- */
709 +
710 +       if( floodlighty )
711 +       {
712 +               /* walk lightmaps */
713 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
714 +               {
715 +                       /* early out */
716 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
717 +                               continue;
718 +                       
719 +                       /* apply floodlight to each luxel */
720 +                       for( y = 0; y < lm->sh; y++ )
721 +                       {
722 +                               for( x = 0; x < lm->sw; x++ )
723 +                               {
724 +                                       /* get cluster */
725 +                                       cluster = SUPER_CLUSTER( x, y );
726 +                                       //%     if( *cluster < 0 )
727 +                                       //%             continue;
728 +                                       
729 +                                       /* get particulars */
730 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
731 +                                       floodlight = SUPER_FLOODLIGHT( x, y );
732 +                                       
733 +                                       flood[0]=floodlightRGB[0]*floodlightIntensity;
734 +                                       flood[1]=floodlightRGB[1]*floodlightIntensity;
735 +                                       flood[2]=floodlightRGB[2]*floodlightIntensity;
736 +                                                    
737 +                                       /* scale light value */
738 +                                       VectorScale( flood, *floodlight, flood );
739 +                                       luxel[0]+=flood[0];
740 +                                       luxel[1]+=flood[1];
741 +                                       luxel[2]+=flood[2];
742 +                                       
743 +                                       if (luxel[3]==0) luxel[3]=1;
744 +                               }
745 +                       }
746 +               }
747 +       }
748 +
749 +       if (debugnormals)
750 +       {
751 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
752 +               {
753 +                       /* early out */
754 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
755 +                               continue;
756 +                       
757 +                       for( y = 0; y < lm->sh; y++ )
758 +                       {
759 +                               for( x = 0; x < lm->sw; x++ )
760 +                               {
761 +                                       /* get cluster */
762 +                                       cluster = SUPER_CLUSTER( x, y );
763 +                                       //%     if( *cluster < 0 )
764 +                                       //%             continue;
765 +                                       
766 +                                       /* get particulars */
767 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
768 +                                       normal = SUPER_NORMAL (  x, y );
769 +               
770 +                                       luxel[0]=(normal[0]*127)+127;
771 +                                       luxel[1]=(normal[1]*127)+127;
772 +                                       luxel[2]=(normal[2]*127)+127;
773 +                               }
774 +                       }
775 +               }
776 +       }
777 +       
778 +       /*      -----------------------------------------------------------------
779                 dirt pass
780                 ----------------------------------------------------------------- */
781         
782 @@ -3587,7 +3768,320 @@
783         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
784  }
785  
786 +/////////////////////////////////////////////////////////////
787  
788 +#define FLOODLIGHT_CONE_ANGLE                  88      /* degrees */
789 +#define FLOODLIGHT_NUM_ANGLE_STEPS             16
790 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
791 +#define FLOODLIGHT_NUM_VECTORS                 (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
792  
793 +static vec3_t  floodVectors[ FLOODLIGHT_NUM_VECTORS ];
794 +static int             numFloodVectors = 0;
795  
796 +void SetupFloodLight( void )
797 +{
798 +       int             i, j;
799 +       float   angle, elevation, angleStep, elevationStep;
800 +       const char      *value;
801 +       double v1,v2,v3,v4,v5;
802 +       
803 +       /* note it */
804 +       Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
805 +       
806 +       /* calculate angular steps */
807 +       angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
808 +       elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
809 +       
810 +       /* iterate angle */
811 +       angle = 0.0f;
812 +       for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
813 +       {
814 +               /* iterate elevation */
815 +               for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
816 +               {
817 +                       floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
818 +                       floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
819 +                       floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
820 +                       numFloodVectors++;
821 +               }
822 +       }
823 +       
824 +       /* emit some statistics */
825 +       Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
826  
827 +      /* floodlight */
828 +       value = ValueForKey( &entities[ 0 ], "_floodlight" );
829 +       
830 +       if( value[ 0 ] != '\0' )
831 +       {
832 +               v1=v2=v3=0;
833 +               v4=floodlightDistance;
834 +               v5=floodlightIntensity;
835 +               
836 +               sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
837 +               
838 +               floodlightRGB[0]=v1;
839 +               floodlightRGB[1]=v2;
840 +               floodlightRGB[2]=v3;
841 +               
842 +               if (VectorLength(floodlightRGB)==0)
843 +               {
844 +                       VectorSet(floodlightRGB,240,240,255);
845 +               }
846 +               
847 +               if (v4<1) v4=1024;
848 +               if (v5<1) v5=128;
849 +               
850 +               floodlightDistance=v4;
851 +               floodlightIntensity=v5;
852 +    
853 +               floodlighty = qtrue;
854 +               Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
855 +       }
856 +       else
857 +       {
858 +               VectorSet(floodlightRGB,240,240,255);
859 +               //floodlighty = qtrue;
860 +               //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
861 +       }
862 +       VectorNormalize(floodlightRGB,floodlightRGB);
863 +}
864 +
865 +//27 - lighttracer style ambient occlusion light hack.
866 +//Kudos to the dirtmapping author for most of this source.
867 +void FloodLightRawLightmap( int rawLightmapNum )
868 +{
869 +       int                                     i, x, y, sx, sy, *cluster;
870 +       float                           *origin, *normal, *floodlight, *floodlight2, average, samples;
871 +       rawLightmap_t           *lm;
872 +       surfaceInfo_t           *info;
873 +       trace_t                         trace;
874 +       
875 +       /* bail if this number exceeds the number of raw lightmaps */
876 +       if( rawLightmapNum >= numRawLightmaps )
877 +               return;
878 +       
879 +       /* get lightmap */
880 +       lm = &rawLightmaps[ rawLightmapNum ];
881 +       
882 +       memset(&trace,0,sizeof(trace_t));
883 +       /* setup trace */
884 +       trace.testOcclusion = qtrue;
885 +       trace.forceSunlight = qfalse;
886 +       trace.twoSided = qtrue;
887 +       trace.recvShadows = lm->recvShadows;
888 +       trace.numSurfaces = lm->numLightSurfaces;
889 +       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
890 +       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
891 +       trace.testAll = qfalse;
892 +       trace.distance = 1024;
893 +       
894 +       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
895 +       //trace.twoSided = qfalse;
896 +       for( i = 0; i < trace.numSurfaces; i++ )
897 +       {
898 +               /* get surface */
899 +               info = &surfaceInfos[ trace.surfaces[ i ] ];
900 +               
901 +               /* check twosidedness */
902 +               if( info->si->twoSided )
903 +               {
904 +                       trace.twoSided = qtrue;
905 +                       break;
906 +               }
907 +       }
908 +       
909 +       /* gather dirt */
910 +       for( y = 0; y < lm->sh; y++ )
911 +       {
912 +               for( x = 0; x < lm->sw; x++ )
913 +               {
914 +                       /* get luxel */
915 +                       cluster = SUPER_CLUSTER( x, y );
916 +                       origin = SUPER_ORIGIN( x, y );
917 +                       normal = SUPER_NORMAL( x, y );
918 +                       floodlight = SUPER_FLOODLIGHT( x, y );
919 +                       
920 +                       /* set default dirt */
921 +                       *floodlight = 0.0f;
922 +                       
923 +                       /* only look at mapped luxels */
924 +                       if( *cluster < 0 )
925 +                               continue;
926 +                       
927 +                       /* copy to trace */
928 +                       trace.cluster = *cluster;
929 +                       VectorCopy( origin, trace.origin );
930 +                       VectorCopy( normal, trace.normal );
931 +         
932 +
933 +               
934 +                       /* get dirt */
935 +                       *floodlight = FloodLightForSample( &trace );
936 +               }
937 +       }
938 +       
939 +       /* testing no filtering */
940 +       return;
941 +       
942 +       /* filter "dirt" */
943 +       for( y = 0; y < lm->sh; y++ )
944 +       {
945 +               for( x = 0; x < lm->sw; x++ )
946 +               {
947 +                       /* get luxel */
948 +                       cluster = SUPER_CLUSTER( x, y );
949 +                       floodlight = SUPER_FLOODLIGHT( x, y );
950 +                       
951 +                       /* filter dirt by adjacency to unmapped luxels */
952 +                       average = *floodlight;
953 +                       samples = 1.0f;
954 +                       for( sy = (y - 1); sy <= (y + 1); sy++ )
955 +                       {
956 +                               if( sy < 0 || sy >= lm->sh )
957 +                                       continue;
958 +                               
959 +                               for( sx = (x - 1); sx <= (x + 1); sx++ )
960 +                               {
961 +                                       if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
962 +                                               continue;
963 +                                       
964 +                                       /* get neighboring luxel */
965 +                                       cluster = SUPER_CLUSTER( sx, sy );
966 +                                       floodlight2 = SUPER_FLOODLIGHT( sx, sy );
967 +                                       if( *cluster < 0 || *floodlight2 <= 0.0f )
968 +                                               continue;
969 +                                       
970 +                                       /* add it */
971 +                                       average += *floodlight2;
972 +                                       samples += 1.0f;
973 +                               }
974 +                               
975 +                               /* bail */
976 +                               if( samples <= 0.0f )
977 +                                       break;
978 +                       }
979 +                       
980 +                       /* bail */
981 +                       if( samples <= 0.0f )
982 +                               continue;
983 +                       
984 +                       /* scale dirt */
985 +                       *floodlight = average / samples;
986 +               }
987 +       }
988 +}
989 +
990 +/*
991 +FloodLightForSample()
992 +calculates floodlight value for a given sample
993 +once again, kudos to the dirtmapping coder
994 +*/
995 +float FloodLightForSample( trace_t *trace )
996 +{
997 +       int             i;
998 +       float   d;
999 +       float   contribution;
1000 +       int     sub = 0;
1001 +       float   gatherLight, outLight;
1002 +       vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
1003 +       float   dd;
1004 +       int     vecs = 0;
1005
1006 +       gatherLight=0;
1007 +       /* dummy check */
1008 +       //if( !dirty )
1009 +       //      return 1.0f;
1010 +       if( trace == NULL || trace->cluster < 0 )
1011 +               return 0.0f;
1012 +       
1013 +
1014 +       /* setup */
1015 +       dd = floodlightDistance;
1016 +       VectorCopy( trace->normal, normal );
1017 +       
1018 +       /* check if the normal is aligned to the world-up */
1019 +       if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1020 +       {
1021 +               if( normal[ 2 ] == 1.0f )               
1022 +               {
1023 +                       VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1024 +                       VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1025 +               }
1026 +               else if( normal[ 2 ] == -1.0f )
1027 +               {
1028 +                       VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1029 +                       VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1030 +               }
1031 +       }
1032 +       else
1033 +       {
1034 +               VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1035 +               CrossProduct( normal, worldUp, myRt );
1036 +               VectorNormalize( myRt, myRt );
1037 +               CrossProduct( myRt, normal, myUp );
1038 +               VectorNormalize( myUp, myUp );
1039 +       }
1040 +
1041 +       /* iterate through ordered vectors */
1042 +       for( i = 0; i < numFloodVectors; i++ )
1043 +       {
1044 +               if (floodlight_lowquality==qtrue)
1045 +        {
1046 +                       if (rand()%10 != 0 ) continue;
1047 +               }
1048 +
1049 +               vecs++;
1050 +         
1051 +               /* transform vector into tangent space */
1052 +               direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1053 +               direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1054 +               direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1055 +
1056 +               /* set endpoint */
1057 +               VectorMA( trace->origin, dd, direction, trace->end );
1058 +
1059 +               //VectorMA( trace->origin, 1, direction, trace->origin );
1060 +                       
1061 +               SetupTrace( trace );
1062 +               /* trace */
1063 +               TraceLine( trace );
1064 +               contribution=1;
1065 +
1066 +               if (trace->compileFlags & C_SKY )
1067 +               {
1068 +                       contribution=1.0f;
1069 +               }
1070 +               else if ( trace->opaque )
1071 +               {
1072 +                       VectorSubtract( trace->hit, trace->origin, displacement );
1073 +                       d=VectorLength( displacement );
1074 +
1075 +                       // d=trace->distance;            
1076 +                       //if (d>256) gatherDirt+=1;
1077 +                       contribution=d/dd;
1078 +                       if (contribution>1) contribution=1.0f; 
1079 +             
1080 +                       //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1081 +               }
1082 +         
1083 +               gatherLight+=contribution;
1084 +       }
1085 +   
1086 +       /* early out */
1087 +       if( gatherLight <= 0.0f )
1088 +               return 0.0f;
1089 +       
1090 +       sub=vecs;
1091 +
1092 +       if (sub<1) sub=1;
1093 +       gatherLight/=(sub);
1094 +
1095 +       outLight=gatherLight;
1096 +       if( outLight > 1.0f )
1097 +               outLight = 1.0f;
1098 +       
1099 +       /* return to sender */
1100 +       return outLight;
1101 +}
1102 +
1103 Index: tools/quake3/q3map2/light.c
1104 ===================================================================
1105 --- tools/quake3/q3map2/light.c (revision 191)
1106 +++ tools/quake3/q3map2/light.c (working copy)
1107 @@ -1378,6 +1378,56 @@
1108                         break;
1109         }
1110         
1111 +       /////// Floodlighting for point //////////////////
1112 +       //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1113 +       if (floodlighty)
1114 +       {
1115 +               int q;
1116 +               float addSize,f;
1117 +               vec3_t col,dir;
1118 +               col[0]=col[1]=col[2]=floodlightIntensity;
1119 +               dir[0]=dir[1]=0;
1120 +               dir[2]=1;
1121 +      
1122 +               trace.testOcclusion = qtrue;
1123 +               trace.forceSunlight = qfalse;
1124 +               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1125 +               trace.testAll = qtrue;     
1126 +      
1127 +               for (q=0;q<2;q++)
1128 +               {
1129 +                       if (q==0) //upper hemisphere
1130 +                       {
1131 +                               trace.normal[0]=0;
1132 +                               trace.normal[1]=0;
1133 +                               trace.normal[2]=1;
1134 +                       }
1135 +                       else //lower hemisphere
1136 +                       {
1137 +                               trace.normal[0]=0;
1138 +                               trace.normal[1]=0;
1139 +                               trace.normal[2]=-1;
1140 +                       }
1141 +
1142 +                       f = FloodLightForSample(&trace);
1143 +
1144 +                       contributions[ numCon ].color[0]=col[0]*f;
1145 +                       contributions[ numCon ].color[1]=col[1]*f;
1146 +                       contributions[ numCon ].color[2]=col[2]*f;
1147 +
1148 +                       contributions[ numCon ].dir[0]=dir[0];
1149 +                       contributions[ numCon ].dir[1]=dir[1];
1150 +                       contributions[ numCon ].dir[2]=dir[2];
1151 +
1152 +                       contributions[ numCon ].style = 0;
1153 +                       numCon++;               
1154 +                       /* push average direction around */
1155 +                       addSize = VectorLength( col );
1156 +                       VectorMA( gp->dir, addSize, dir, gp->dir );
1157 +               }
1158 +       }
1159 +       /////////////////////
1160 +
1161         /* normalize to get primary light direction */
1162         VectorNormalize( gp->dir, gp->dir );
1163         
1164 @@ -1661,6 +1711,12 @@
1165                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1166         }
1167         
1168 +       /* floodlight them up */
1169 +       if( floodlighty )
1170 +       {
1171 +               Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1172 +               RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1173 +       }
1174  
1175         /* ydnar: set up light envelopes */
1176         SetupEnvelopes( qfalse, fast );
1177 @@ -1703,6 +1759,7 @@
1178                 /* flag bouncing */
1179                 bouncing = qtrue;
1180                 VectorClear( ambientColor );
1181 +               floodlighty = false;
1182                 
1183                 /* generate diffuse lights */
1184                 RadFreeLights();
1185 @@ -2191,6 +2256,21 @@
1186                         cpmaHack = qtrue;
1187                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
1188                 }
1189 +               else if( !strcmp( argv[ i ], "-floodlight" ) )
1190 +               {
1191 +                       floodlighty = qtrue;
1192 +                       Sys_Printf( "FloodLighting enabled\n" );
1193 +               }
1194 +               else if( !strcmp( argv[ i ], "-debugnormals" ) )
1195 +               {
1196 +                       debugnormals = qtrue;
1197 +                       Sys_Printf( "DebugNormals enabled\n" );
1198 +               }
1199 +               else if( !strcmp( argv[ i ], "-lowquality" ) )
1200 +               {
1201 +                       floodlight_lowquality = qtrue;
1202 +                       Sys_Printf( "Low Quality FloodLighting enabled\n" );
1203 +               }
1204                 
1205                 /* r7: dirtmapping */
1206                 else if( !strcmp( argv[ i ], "-dirty" ) )
1207 @@ -2279,6 +2359,7 @@
1208         /* ydnar: set up optimization */
1209         SetupBrushes();
1210         SetupDirt();
1211 +       SetupFloodLight();
1212         SetupSurfaceLightmaps();
1213         
1214         /* initialize the surface facet tracing */
1215 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1216 ===================================================================
1217 --- tools/quake3/q3map2/lightmaps_ydnar.c       (revision 191)
1218 +++ tools/quake3/q3map2/lightmaps_ydnar.c       (working copy)
1219 @@ -414,6 +414,12 @@
1220                 lm->superNormals = safe_malloc( size );
1221         memset( lm->superNormals, 0, size );
1222         
1223 +       /* allocate floodlight map storage */
1224 +       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1225 +       if( lm->superFloodLight == NULL )
1226 +               lm->superFloodLight = safe_malloc( size );
1227 +       memset( lm->superFloodLight, 0, size );
1228 +       
1229         /* allocate cluster map storage */
1230         size = lm->sw * lm->sh * sizeof( int );
1231         if( lm->superClusters == NULL )
1232 Index: tools/quake3/q3map2/q3map2.h
1233 ===================================================================
1234 --- tools/quake3/q3map2/q3map2.h        (revision 191)
1235 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1236 @@ -267,6 +267,7 @@
1237  #define SUPER_NORMAL_SIZE              4
1238  #define SUPER_DELUXEL_SIZE             3
1239  #define BSP_DELUXEL_SIZE               3
1240 +#define SUPER_FLOODLIGHT_SIZE  1
1241  
1242  #define VERTEX_LUXEL( s, v )   (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1243  #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1244 @@ -279,6 +280,7 @@
1245  #define SUPER_ORIGIN( x, y )   (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1246  #define SUPER_NORMAL( x, y )   (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1247  #define SUPER_DIRT( x, y )             (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3)   /* stash dirtyness in normal[ 3 ] */
1248 +#define SUPER_FLOODLIGHT( x, y )       (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )       
1249  
1250  
1251  
1252 @@ -1392,6 +1395,7 @@
1253         
1254         float                                   *superDeluxels; /* average light direction */
1255         float                                   *bspDeluxels;
1256 +       float                                   *superFloodLight; 
1257  }
1258  rawLightmap_t;
1259  
1260 @@ -1704,6 +1708,10 @@
1261  float                                          DirtForSample( trace_t *trace );
1262  void                                           DirtyRawLightmap( int num );
1263  
1264 +void                                           SetupFloodLight();
1265 +float                                          FloodLightForSample( trace_t *trace );
1266 +void                                           FloodLightRawLightmap( int num );
1267 +
1268  void                                           IlluminateRawLightmap( int num );
1269  void                                           IlluminateVertexes( int num );
1270  
1271 @@ -2098,6 +2106,13 @@
1272  Q_EXTERN float                         dirtScale Q_ASSIGN( 1.0f );
1273  Q_EXTERN float                         dirtGain Q_ASSIGN( 1.0f );
1274  
1275 +Q_EXTERN qboolean                      debugnormals Q_ASSIGN( qfalse );
1276 +Q_EXTERN qboolean                      floodlighty Q_ASSIGN( qfalse );
1277 +Q_EXTERN qboolean                      floodlight_lowquality Q_ASSIGN( qfalse );
1278 +Q_EXTERN vec3_t                                floodlightRGB;
1279 +Q_EXTERN float                         floodlightIntensity Q_ASSIGN( 512 );
1280 +Q_EXTERN float                         floodlightDistance Q_ASSIGN( 1024 );
1281 +
1282  Q_EXTERN qboolean                      dump Q_ASSIGN( qfalse );
1283  Q_EXTERN qboolean                      debug Q_ASSIGN( qfalse );
1284  Q_EXTERN qboolean                      debugUnused Q_ASSIGN( qfalse );
1285 Index: tools/quake3/q3map2/game_ja.h
1286 ===================================================================
1287 --- tools/quake3/q3map2/game_ja.h       (revision 191)
1288 +++ tools/quake3/q3map2/game_ja.h       (working copy)
1289 @@ -67,6 +67,7 @@
1290         qfalse,                         /* wolf lighting model? */
1291         128,                            /* lightmap width/height */
1292         1.0f,                           /* lightmap gamma */
1293 +       1.0f,                           /* lightmap exposure */
1294         1.0f,                           /* lightmap compensate */
1295         "RBSP",                         /* bsp file prefix */
1296         1,                                      /* bsp file version */
1297 Index: tools/quake3/q3map2/game_tremulous.h
1298 ===================================================================
1299 --- tools/quake3/q3map2/game_tremulous.h        (revision 191)
1300 +++ tools/quake3/q3map2/game_tremulous.h        (working copy)
1301 @@ -70,6 +70,7 @@
1302         qfalse,                         /* wolf lighting model? */
1303         128,                            /* lightmap width/height */
1304         1.0f,                           /* lightmap gamma */
1305 +       1.0f,                           /* lightmap exposure */
1306         1.0f,                           /* lightmap compensate */
1307         "IBSP",                         /* bsp file prefix */
1308         46,                                     /* bsp file version */
1309 Index: tools/quake3/q3map2/game_wolfet.h
1310 ===================================================================
1311 --- tools/quake3/q3map2/game_wolfet.h   (revision 191)
1312 +++ tools/quake3/q3map2/game_wolfet.h   (working copy)
1313 @@ -66,6 +66,7 @@
1314         qtrue,                          /* wolf lighting model? */
1315         128,                            /* lightmap width/height */
1316         1.0f,                           /* lightmap gamma */
1317 +       1.0f,                           /* lightmap exposure */
1318         1.0f,                           /* lightmap compensate */
1319         "IBSP",                         /* bsp file prefix */
1320         47,                                     /* bsp file version */
1321 Index: tools/quake3/q3map2/game_wolf.h
1322 ===================================================================
1323 --- tools/quake3/q3map2/game_wolf.h     (revision 191)
1324 +++ tools/quake3/q3map2/game_wolf.h     (working copy)
1325 @@ -129,6 +129,7 @@
1326         qtrue,                          /* wolf lighting model? */
1327         128,                            /* lightmap width/height */
1328         1.0f,                           /* lightmap gamma */
1329 +       1.0f,                           /* lightmap exposure */
1330         1.0f,                           /* lightmap compensate */
1331         "IBSP",                         /* bsp file prefix */
1332         47,                                     /* bsp file version */
1333 Index: tools/quake3/q3map2/game_sof2.h
1334 ===================================================================
1335 --- tools/quake3/q3map2/game_sof2.h     (revision 191)
1336 +++ tools/quake3/q3map2/game_sof2.h     (working copy)
1337 @@ -139,6 +139,7 @@
1338         qfalse,                                 /* wolf lighting model? */
1339         128,                                    /* lightmap width/height */
1340         1.0f,                                   /* lightmap gamma */
1341 +       1.0f,                                   /* lightmap exposure */
1342         1.0f,                                   /* lightmap compensate */
1343         "RBSP",                                 /* bsp file prefix */
1344         1,                                              /* bsp file version */
1345 Index: tools/quake3/q3map2/game_etut.h
1346 ===================================================================
1347 --- tools/quake3/q3map2/game_etut.h     (revision 191)
1348 +++ tools/quake3/q3map2/game_etut.h     (working copy)
1349 @@ -148,6 +148,7 @@
1350         qfalse,                         /* wolf lighting model? */
1351         128,                            /* lightmap width/height */
1352         2.2f,                           /* lightmap gamma */
1353 +       1.0f,                           /* lightmap exposure */
1354         1.0f,                           /* lightmap compensate */
1355         "IBSP",                         /* bsp file prefix */
1356         47,                                     /* bsp file version */
1357 Index: tools/quake3/q3map2/game_jk2.h
1358 ===================================================================
1359 --- tools/quake3/q3map2/game_jk2.h      (revision 191)
1360 +++ tools/quake3/q3map2/game_jk2.h      (working copy)
1361 @@ -64,6 +64,7 @@
1362         qfalse,                         /* wolf lighting model? */
1363         128,                            /* lightmap width/height */
1364         1.0f,                           /* lightmap gamma */
1365 +       1.0f,                           /* lightmap exposure */
1366         1.0f,                           /* lightmap compensate */
1367         "RBSP",                         /* bsp file prefix */
1368         1,                                      /* bsp file version */
1369 Index: tools/quake3/q3map2/game_qfusion.h
1370 ===================================================================
1371 --- tools/quake3/q3map2/game_qfusion.h  (revision 191)
1372 +++ tools/quake3/q3map2/game_qfusion.h  (working copy)
1373 @@ -115,6 +115,7 @@
1374         qfalse,                         /* wolf lighting model? */
1375         512,                            /* lightmap width/height */
1376         1.0f,                           /* lightmap gamma */
1377 +       1.0f,                           /* lightmap exposure */
1378         1.0f,                           /* lightmap compensate */
1379         "FBSP",                         /* bsp file prefix */
1380         1,                                      /* bsp file version */
1381 Index: tools/quake3/q3map2/game_tenebrae.h
1382 ===================================================================
1383 --- tools/quake3/q3map2/game_tenebrae.h (revision 191)
1384 +++ tools/quake3/q3map2/game_tenebrae.h (working copy)
1385 @@ -112,6 +112,7 @@
1386         qfalse,                         /* wolf lighting model? */
1387         512,                            /* lightmap width/height */
1388         2.0f,                           /* lightmap gamma */
1389 +       1.0f,                           /* lightmap exposure */
1390         1.0f,                           /* lightmap compensate */
1391         "IBSP",                         /* bsp file prefix */
1392         46,                                     /* bsp file version */
1393 Index: tools/quake3/q3map2/game_quake3.h
1394 ===================================================================
1395 --- tools/quake3/q3map2/game_quake3.h   (revision 191)
1396 +++ tools/quake3/q3map2/game_quake3.h   (working copy)
1397 @@ -112,6 +112,7 @@
1398         qfalse,                         /* wolf lighting model? */
1399         128,                            /* lightmap width/height */
1400         1.0f,                           /* lightmap gamma */
1401 +       1.0f,                           /* lightmap exposure */
1402         1.0f,                           /* lightmap compensate */
1403         "IBSP",                         /* bsp file prefix */
1404         46,                                     /* bsp file version */
1405 Index: tools/quake3/q3map2/game_ef.h
1406 ===================================================================
1407 --- tools/quake3/q3map2/game_ef.h       (revision 191)
1408 +++ tools/quake3/q3map2/game_ef.h       (working copy)
1409 @@ -113,6 +113,7 @@
1410         qfalse,                         /* wolf lighting model? */
1411         128,                            /* lightmap width/height */
1412         1.0f,                           /* lightmap gamma */
1413 +       1.0f,                           /* lightmap exposure */
1414         1.0f,                           /* lightmap compensate */
1415         "IBSP",                         /* bsp file prefix */
1416         46,                                     /* bsp file version */
1417 Index: tools/quake3/q3map2/light_ydnar.c
1418 ===================================================================
1419 --- tools/quake3/q3map2/light_ydnar.c   (revision 191)
1420 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1421 @@ -49,6 +49,7 @@
1422         int             i;
1423         float   max, gamma;
1424         vec3_t  sample;
1425 +       float   inv, dif;
1426         
1427         
1428         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
1429 @@ -72,16 +73,51 @@
1430                 /* gamma */
1431                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
1432         }
1433 +
1434 +       if (lightmapExposure == 1)
1435 +       {
1436 +               /* clamp with color normalization */
1437 +               max = sample[ 0 ];
1438 +               if( sample[ 1 ] > max )
1439 +                       max = sample[ 1 ];
1440 +               if( sample[ 2 ] > max )
1441 +                       max = sample[ 2 ];
1442 +               if( max > 255.0f )
1443 +                       VectorScale( sample, (255.0f / max), sample );
1444 +       }
1445 +       else
1446 +       {
1447 +               if (lightmapExposure==0)
1448 +               {
1449 +                       lightmapExposure=1.0f;
1450 +               }
1451 +               inv=1.f/lightmapExposure;
1452 +               //Exposure
1453 +       
1454 +               max = sample[ 0 ];
1455 +               if( sample[ 1 ] > max )
1456 +                       max = sample[ 1 ];
1457 +               if( sample[ 2 ] > max )
1458 +                       max = sample[ 2 ];  
1459 +      
1460 +               dif = (1-  exp(-max * inv) )  *  255;
1461 +
1462 +               if (max >0) 
1463 +               {
1464 +                       dif = dif / max;
1465 +               }
1466 +               else
1467 +               {
1468 +                       dif = 0;
1469 +               }
1470 +
1471 +               for (i=0;i<3;i++)
1472 +               {
1473 +                       sample[i]*=dif;
1474 +               }
1475 +       }
1476 +
1477         
1478 -       /* clamp with color normalization */
1479 -       max = sample[ 0 ];
1480 -       if( sample[ 1 ] > max )
1481 -               max = sample[ 1 ];
1482 -       if( sample[ 2 ] > max )
1483 -               max = sample[ 2 ];
1484 -       if( max > 255.0f )
1485 -               VectorScale( sample, (255.0f / max), sample );
1486 -       
1487         /* compensate for ingame overbrighting/bitshifting */
1488         VectorScale( sample, (1.0f / lightmapCompensate), sample );
1489         
1490 Index: tools/quake3/q3map2/light.c
1491 ===================================================================
1492 --- tools/quake3/q3map2/light.c (revision 191)
1493 +++ tools/quake3/q3map2/light.c (working copy)
1494 @@ -1836,6 +1893,14 @@
1495                         i++;
1496                 }
1497                 
1498 +               else if( !strcmp( argv[ i ], "-exposure" ) )
1499 +               {
1500 +                       f = atof( argv[ i + 1 ] );
1501 +                       lightmapExposure = f;
1502 +                       Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
1503 +                       i++;
1504 +               }
1505 +               
1506                 else if( !strcmp( argv[ i ], "-compensate" ) )
1507                 {
1508                         f = atof( argv[ i + 1 ] );
1509 Index: tools/quake3/q3map2/q3map2.h
1510 ===================================================================
1511 --- tools/quake3/q3map2/q3map2.h        (revision 191)
1512 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1513 @@ -543,6 +545,7 @@
1514         qboolean                        wolfLight;                                              /* when true, lights work like wolf q3map  */
1515         int                                     lightmapSize;                                   /* bsp lightmap width/height */
1516         float                           lightmapGamma;                                  /* default lightmap gamma */
1517 +       float                           lightmapExposure;                               /* default lightmap exposure */
1518         float                           lightmapCompensate;                             /* default lightmap compensate value */
1519         char                            *bspIdent;                                              /* 4-letter bsp file prefix */
1520         int                                     bspVersion;                                             /* bsp version to use */
1521 @@ -2117,6 +2132,7 @@
1522  
1523  /* ydnar: lightmap gamma/compensation */
1524  Q_EXTERN float                         lightmapGamma Q_ASSIGN( 1.0f );
1525 +Q_EXTERN float                         lightmapExposure Q_ASSIGN( 1.0f );
1526  Q_EXTERN float                         lightmapCompensate Q_ASSIGN( 1.0f );
1527  
1528  /* ydnar: for runtime tweaking of falloff tolerance */
1529 Index: tools/quake3/q3map2/light_ydnar.c
1530 ===================================================================
1531 --- tools/quake3/q3map2/light_ydnar.c   (revision 191)
1532 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1533 @@ -384,7 +420,7 @@
1534  #define NUDGE                  0.5f
1535  #define BOGUS_NUDGE            -99999.0f
1536  
1537 -static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
1538 +static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
1539  {
1540         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
1541         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
1542 @@ -392,6 +428,12 @@
1543         vec3_t                  pNormal;
1544         vec3_t                  vecs[ 3 ];
1545         vec3_t                  nudged;
1546 +       vec3_t                  cverts[ 3 ];
1547 +       vec3_t                  temp;
1548 +       vec4_t                  sideplane, hostplane;
1549 +       vec3_t                  origintwo;
1550 +       int                             j, next;
1551 +       float                   e;
1552         float                   *nudge;
1553         static float    nudges[][ 2 ] =
1554                                         {
1555 @@ -485,6 +527,51 @@
1556         /* non axial lightmap projection (explicit xyz) */
1557         else
1558                 VectorCopy( dv->xyz, origin );
1559 +
1560 +       //////////////////////
1561 +       //27's test to make sure samples stay within the triangle boundaries
1562 +       //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
1563 +       //2) if it does, nudge it onto the correct side.
1564 +
1565 +       if (worldverts!=NULL)
1566 +       {
1567 +               for (j=0;j<3;j++)
1568 +               {
1569 +                       VectorCopy(worldverts[j],cverts[j]);    
1570 +               }
1571 +               PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
1572 +
1573 +               for (j=0;j<3;j++)
1574 +               {
1575 +                       for (i=0;i<3;i++)
1576 +                       {
1577 +                               //build plane using 2 edges and a normal
1578 +                               next=(i+1)%3;
1579 +
1580 +                               VectorCopy(cverts[next],temp);
1581 +                               VectorAdd(temp,hostplane,temp);
1582 +                               PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
1583 +
1584 +                               //planetest sample point  
1585 +                               e=DotProduct(origin,sideplane);
1586 +                               e=e-sideplane[3];
1587 +                               if (e>0)
1588 +                               {
1589 +                                       //we're bad.
1590 +                                       //VectorClear(origin);
1591 +                                       //Move the sample point back inside triangle bounds
1592 +                                       origin[0]-=sideplane[0]*(e+1);
1593 +                                       origin[1]-=sideplane[1]*(e+1);
1594 +                                       origin[2]-=sideplane[2]*(e+1);
1595 +#ifdef DEBUG_27_1
1596 +                                       VectorClear(origin);
1597 +#endif 
1598 +                               }
1599 +                       }
1600 +               }
1601 +       }
1602 +
1603 +       ////////////////////////
1604         
1605         /* planar surfaces have precalculated lightmap vectors for nudging */
1606         if( lm->plane != NULL )
1607 @@ -516,8 +603,13 @@
1608         else
1609                 origin[ lm->axisNum ] += lightmapSampleOffset;
1610         
1611 +       VectorCopy(origin,origintwo);
1612 +       origintwo[0]+=vecs[2][0];
1613 +       origintwo[1]+=vecs[2][1];
1614 +       origintwo[2]+=vecs[2][2];
1615 +       
1616         /* get cluster */
1617 -       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
1618 +       pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
1619         
1620         /* another retarded hack, storing nudge count in luxel[ 1 ] */
1621         luxel[ 1 ] = 0.0f;      
1622 @@ -533,14 +625,14 @@
1623                         for( i = 0; i < 3; i++ )
1624                         {
1625                                 /* set nudged point*/
1626 -                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
1627 +                               nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
1628                         }
1629                         nudge += 2;
1630                         
1631                         /* get pvs cluster */
1632                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
1633 -                       if( pointCluster >= 0 ) 
1634 -                               VectorCopy( nudged, origin );
1635 +                       //if( pointCluster >= 0 )       
1636 +                       //      VectorCopy( nudged, origin );
1637                         luxel[ 1 ] += 1.0f;
1638                 }
1639         }
1640 @@ -550,8 +642,8 @@
1641         {
1642                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
1643                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
1644 -               if( pointCluster >= 0 )
1645 -                       VectorCopy( nudged, origin );
1646 +               //if( pointCluster >= 0 )
1647 +               //      VectorCopy( nudged, origin );
1648                 luxel[ 1 ] += 1.0f;
1649         }
1650         
1651 @@ -597,7 +689,7 @@
1652  than the distance between two luxels (thanks jc :)
1653  */
1654  
1655 -static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
1656 +static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
1657  {
1658         bspDrawVert_t   mid, *dv2[ 3 ];
1659         int                             max;
1660 @@ -645,7 +737,7 @@
1661         
1662         /* split the longest edge and map it */
1663         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
1664 -       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
1665 +       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
1666         
1667         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
1668         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
1669 @@ -653,12 +745,12 @@
1670         /* recurse to first triangle */
1671         VectorCopy( dv, dv2 );
1672         dv2[ max ] = &mid;
1673 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1674 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1675         
1676         /* recurse to second triangle */
1677         VectorCopy( dv, dv2 );
1678         dv2[ (max + 1) % 3 ] = &mid;
1679 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1680 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1681  }
1682  
1683  
1684 @@ -674,6 +766,7 @@
1685         int                             i;
1686         vec4_t                  plane;
1687         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
1688 +       vec3_t                  worldverts[ 3 ];
1689         
1690         
1691         /* get plane if possible */
1692 @@ -699,16 +792,20 @@
1693                 ttv = NULL;
1694         }
1695         
1696 +       VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
1697 +       VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
1698 +       VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
1699 +       
1700         /* map the vertexes */
1701 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
1702 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
1703 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
1704 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
1705 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
1706 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
1707         
1708         /* 2002-11-20: prefer axial triangle edges */
1709         if( mapNonAxial )
1710         {
1711                 /* subdivide the triangle */
1712 -               MapTriangle_r( lm, info, dv, plane, stv, ttv );
1713 +               MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
1714                 return qtrue;
1715         }
1716         
1717 @@ -730,7 +827,7 @@
1718                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
1719                         
1720                         /* map the degenerate triangle */
1721 -                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1722 +                       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1723                 }
1724         }
1725         
1726 @@ -792,8 +889,8 @@
1727         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
1728         
1729         /* map the vertexes */
1730 -       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
1731 -       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
1732 +       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
1733 +       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
1734         
1735         /* 0 and 2 */
1736         if( max == 0 )
1737 @@ -878,10 +975,10 @@
1738         }
1739         
1740         /* map the vertexes */
1741 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
1742 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
1743 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
1744 -       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
1745 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
1746 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
1747 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
1748 +       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
1749         
1750         /* subdivide the quad */
1751         MapQuad_r( lm, info, dv, plane, stv, ttv );
1752 @@ -1173,7 +1270,7 @@
1753                                         continue;
1754                                 
1755                                 /* map the fake vert */
1756 -                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
1757 +                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1758                         }
1759                 }
1760         }
1761 @@ -1963,22 +2062,32 @@
1762                                         deluxel = SUPER_DELUXEL( x, y );
1763                                         origin = SUPER_ORIGIN( x, y );
1764                                         normal = SUPER_NORMAL( x, y );
1765 -                                       
1766 -                                       /* set contribution count */
1767 -                                       lightLuxel[ 3 ] = 1.0f;
1768 -                                       
1769 -                                       /* setup trace */
1770 -                                       trace.cluster = *cluster;
1771 -                                       VectorCopy( origin, trace.origin );
1772 -                                       VectorCopy( normal, trace.normal );
1773 -                                       
1774 -                                       /* get light for this sample */
1775 -                                       LightContributionToSample( &trace );
1776 -                                       VectorCopy( trace.color, lightLuxel );
1777 -                                       
1778 -                                       /* add to count */
1779 -                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
1780 +
1781 +                                       ////////// 27's temp hack for testing edge clipping ////
1782 +                                       if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
1783 +                                       {
1784 +                                               lightLuxel[ 1 ] = 255;
1785 +                                               lightLuxel[ 3 ] = 1.0f;
1786                                                 totalLighted++;
1787 +                                       }
1788 +                                       else
1789 +                                       {
1790 +                                               /* set contribution count */
1791 +                                               lightLuxel[ 3 ] = 1.0f;
1792 +                                               
1793 +                                               /* setup trace */
1794 +                                               trace.cluster = *cluster;
1795 +                                               VectorCopy( origin, trace.origin );
1796 +                                               VectorCopy( normal, trace.normal );
1797 +                                               
1798 +                                               /* get light for this sample */
1799 +                                               LightContributionToSample( &trace );
1800 +                                               VectorCopy( trace.color, lightLuxel );
1801 +                                               
1802 +                                               /* add to count */
1803 +                                               if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
1804 +                                                       totalLighted++;
1805 +                                       }
1806                                         
1807                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
1808                                         if( deluxemap )
1809 Index: tools/quake3/q3map2/q3map2.h
1810 ===================================================================
1811 --- tools/quake3/q3map2/q3map2.h        (revision 303)
1812 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1813 @@ -35,8 +35,8 @@
1814  
1815  
1816  /* version */
1817 -#define Q3MAP_VERSION  "2.5.17"
1818 -#define Q3MAP_MOTD             "Last one turns the lights off"
1819 +#define Q3MAP_VERSION  "2.5.17-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck"
1820 +#define Q3MAP_MOTD             "Light some candles, put them on a wooden table, take a photo, and paste it on the lightmaps!"
1821  
1822  
1823  
1824 Index: include/version.default
1825 ===================================================================
1826 --- include/version.default     (revision 290)
1827 +++ include/version.default     (working copy)
1828 @@ -1 +1 @@
1829 -1.4.0\r
1830 +1.4.0-div0-obj\r