]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
more changes needed for Zero
[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 290)
117 +++ tools/quake3/q3map2/convert_map.c   (working copy)
118 @@ -45,6 +45,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 @@ -53,12 +152,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 @@ -108,9 +212,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 @@ -129,14 +312,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 290)
358 +++ tools/quake3/q3map2/main.c  (working copy)
359 @@ -276,6 +276,18 @@
360                         else
361                                 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
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 290)
381 +++ tools/quake3/q3map2/model.c (working copy)
382 @@ -221,6 +221,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 @@ -399,9 +401,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 290)
605 +++ tools/quake3/q3map2/map.c   (working copy)
606 @@ -183,9 +183,15 @@
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 -       SnapNormal( normal );
614 +       // div0: ensure the point "center" stays on the plane (actually, this
615 +       // rotates the plane around the point center).
616 +       // if center lies on the plane, it is guaranteed to stay on the plane by
617 +       // this fix.
618 +       vec_t centerDist = DotProduct(normal, center);
619 +       SnapNormal( normal );
620 +       *dist += (DotProduct(normal, center) - centerDist);
621  
622         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
623                 *dist = Q_rint( *dist );
624 @@ -199,7 +205,7 @@
625  must be within an epsilon distance of the plane
626  */
627  
628 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
629 +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?
630  
631  #ifdef USE_HASHING
632  
633 @@ -207,10 +213,14 @@
634         int             i, j, hash, h;
635         plane_t *p;
636         vec_t   d;
637 +       vec3_t centerofweight;
638 +
639 +       VectorClear(centerofweight);
640 +       for(i = 0; i < numPoints; ++i)
641 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
642         
643 -       
644         /* hash the plane */
645 -       SnapPlane( normal, &dist );
646 +       SnapPlane( normal, &dist, centerofweight );
647         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
648         
649         /* search the border bins as well */
650 @@ -251,7 +261,13 @@
651         plane_t *p;
652         
653  
654 -       SnapPlane( normal, &dist );
655 +       vec3_t centerofweight;
656 +
657 +       VectorClear(centerofweight);
658 +       for(i = 0; i < numPoints; ++i)
659 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
660 +       
661 +       SnapPlane( normal, &dist, centerofweight );
662         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
663         {
664                 if( PlaneEqual( p, normal, dist ) )
665 Index: tools/quake3/q3map2/shaders.c
666 ===================================================================
667 --- tools/quake3/q3map2/shaders.c       (revision 290)
668 +++ tools/quake3/q3map2/shaders.c       (working copy)
669 @@ -747,8 +747,14 @@
670         }
671         
672         if( VectorLength( si->color ) <= 0.0f )
673 +       {
674                 ColorNormalize( color, si->color );
675 -       VectorScale( color, (1.0f / count), si->averageColor );
676 +               VectorScale( color, (1.0f / count), si->averageColor );
677 +       }
678 +       else
679 +       {
680 +               VectorCopy( si->color, si->averageColor );
681 +       }
682  }
683  
684  
685 Index: tools/quake3/q3map2/light_ydnar.c
686 ===================================================================
687 --- tools/quake3/q3map2/light_ydnar.c   (revision 290)
688 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
689 @@ -1449,6 +1449,8 @@
690         vec3_t                          color, averageColor, averageDir, total, temp, temp2;
691         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
692         trace_t                         trace;
693 +       vec3_t                          flood;
694 +       float                           *floodlight;
695         
696         
697         /* bail if this number exceeds the number of raw lightmaps */
698 @@ -1871,6 +1873,78 @@
699         /* free light list */
700         FreeTraceLights( &trace );
701         
702 +       /*      -----------------------------------------------------------------
703 +               floodlight pass
704 +               ----------------------------------------------------------------- */
705 +
706 +       if( floodlighty )
707 +       {
708 +               /* walk lightmaps */
709 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
710 +               {
711 +                       /* early out */
712 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
713 +                               continue;
714 +                       
715 +                       /* apply floodlight to each luxel */
716 +                       for( y = 0; y < lm->sh; y++ )
717 +                       {
718 +                               for( x = 0; x < lm->sw; x++ )
719 +                               {
720 +                                       /* get cluster */
721 +                                       cluster = SUPER_CLUSTER( x, y );
722 +                                       //%     if( *cluster < 0 )
723 +                                       //%             continue;
724 +                                       
725 +                                       /* get particulars */
726 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
727 +                                       floodlight = SUPER_FLOODLIGHT( x, y );
728 +                                       
729 +                                       flood[0]=floodlightRGB[0]*floodlightIntensity;
730 +                                       flood[1]=floodlightRGB[1]*floodlightIntensity;
731 +                                       flood[2]=floodlightRGB[2]*floodlightIntensity;
732 +                                                    
733 +                                       /* scale light value */
734 +                                       VectorScale( flood, *floodlight, flood );
735 +                                       luxel[0]+=flood[0];
736 +                                       luxel[1]+=flood[1];
737 +                                       luxel[2]+=flood[2];
738 +                                       
739 +                                       if (luxel[3]==0) luxel[3]=1;
740 +                               }
741 +                       }
742 +               }
743 +       }
744 +
745 +       if (debugnormals)
746 +       {
747 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
748 +               {
749 +                       /* early out */
750 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
751 +                               continue;
752 +                       
753 +                       for( y = 0; y < lm->sh; y++ )
754 +                       {
755 +                               for( x = 0; x < lm->sw; x++ )
756 +                               {
757 +                                       /* get cluster */
758 +                                       cluster = SUPER_CLUSTER( x, y );
759 +                                       //%     if( *cluster < 0 )
760 +                                       //%             continue;
761 +                                       
762 +                                       /* get particulars */
763 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
764 +                                       normal = SUPER_NORMAL (  x, y );
765 +               
766 +                                       luxel[0]=(normal[0]*127)+127;
767 +                                       luxel[1]=(normal[1]*127)+127;
768 +                                       luxel[2]=(normal[2]*127)+127;
769 +                               }
770 +                       }
771 +               }
772 +       }
773 +       
774         /* -----------------------------------------------------------------
775            filter pass
776            ----------------------------------------------------------------- */
777 @@ -3123,7 +3197,320 @@
778         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
779  }
780  
781 +/////////////////////////////////////////////////////////////
782  
783 +#define FLOODLIGHT_CONE_ANGLE                  88      /* degrees */
784 +#define FLOODLIGHT_NUM_ANGLE_STEPS             16
785 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
786 +#define FLOODLIGHT_NUM_VECTORS                 (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
787  
788 +static vec3_t  floodVectors[ FLOODLIGHT_NUM_VECTORS ];
789 +static int             numFloodVectors = 0;
790  
791 +void SetupFloodLight( void )
792 +{
793 +       int             i, j;
794 +       float   angle, elevation, angleStep, elevationStep;
795 +       const char      *value;
796 +       double v1,v2,v3,v4,v5;
797 +       
798 +       /* note it */
799 +       Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
800 +       
801 +       /* calculate angular steps */
802 +       angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
803 +       elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
804 +       
805 +       /* iterate angle */
806 +       angle = 0.0f;
807 +       for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
808 +       {
809 +               /* iterate elevation */
810 +               for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
811 +               {
812 +                       floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
813 +                       floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
814 +                       floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
815 +                       numFloodVectors++;
816 +               }
817 +       }
818 +       
819 +       /* emit some statistics */
820 +       Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
821  
822 +      /* floodlight */
823 +       value = ValueForKey( &entities[ 0 ], "_floodlight" );
824 +       
825 +       if( value[ 0 ] != '\0' )
826 +       {
827 +               v1=v2=v3=0;
828 +               v4=floodlightDistance;
829 +               v5=floodlightIntensity;
830 +               
831 +               sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
832 +               
833 +               floodlightRGB[0]=v1;
834 +               floodlightRGB[1]=v2;
835 +               floodlightRGB[2]=v3;
836 +               
837 +               if (VectorLength(floodlightRGB)==0)
838 +               {
839 +                       VectorSet(floodlightRGB,240,240,255);
840 +               }
841 +               
842 +               if (v4<1) v4=1024;
843 +               if (v5<1) v5=128;
844 +               
845 +               floodlightDistance=v4;
846 +               floodlightIntensity=v5;
847 +    
848 +               floodlighty = qtrue;
849 +               Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
850 +       }
851 +       else
852 +       {
853 +               VectorSet(floodlightRGB,240,240,255);
854 +               //floodlighty = qtrue;
855 +               //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
856 +       }
857 +       VectorNormalize(floodlightRGB,floodlightRGB);
858 +}
859 +
860 +//27 - lighttracer style ambient occlusion light hack.
861 +//Kudos to the dirtmapping author for most of this source.
862 +void FloodLightRawLightmap( int rawLightmapNum )
863 +{
864 +       int                                     i, x, y, sx, sy, *cluster;
865 +       float                           *origin, *normal, *floodlight, *floodlight2, average, samples;
866 +       rawLightmap_t           *lm;
867 +       surfaceInfo_t           *info;
868 +       trace_t                         trace;
869 +       
870 +       /* bail if this number exceeds the number of raw lightmaps */
871 +       if( rawLightmapNum >= numRawLightmaps )
872 +               return;
873 +       
874 +       /* get lightmap */
875 +       lm = &rawLightmaps[ rawLightmapNum ];
876 +       
877 +       memset(&trace,0,sizeof(trace_t));
878 +       /* setup trace */
879 +       trace.testOcclusion = qtrue;
880 +       trace.forceSunlight = qfalse;
881 +       trace.twoSided = qtrue;
882 +       trace.recvShadows = lm->recvShadows;
883 +       trace.numSurfaces = lm->numLightSurfaces;
884 +       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
885 +       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
886 +       trace.testAll = qfalse;
887 +       trace.distance = 1024;
888 +       
889 +       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
890 +       //trace.twoSided = qfalse;
891 +       for( i = 0; i < trace.numSurfaces; i++ )
892 +       {
893 +               /* get surface */
894 +               info = &surfaceInfos[ trace.surfaces[ i ] ];
895 +               
896 +               /* check twosidedness */
897 +               if( info->si->twoSided )
898 +               {
899 +                       trace.twoSided = qtrue;
900 +                       break;
901 +               }
902 +       }
903 +       
904 +       /* gather dirt */
905 +       for( y = 0; y < lm->sh; y++ )
906 +       {
907 +               for( x = 0; x < lm->sw; x++ )
908 +               {
909 +                       /* get luxel */
910 +                       cluster = SUPER_CLUSTER( x, y );
911 +                       origin = SUPER_ORIGIN( x, y );
912 +                       normal = SUPER_NORMAL( x, y );
913 +                       floodlight = SUPER_FLOODLIGHT( x, y );
914 +                       
915 +                       /* set default dirt */
916 +                       *floodlight = 0.0f;
917 +                       
918 +                       /* only look at mapped luxels */
919 +                       if( *cluster < 0 )
920 +                               continue;
921 +                       
922 +                       /* copy to trace */
923 +                       trace.cluster = *cluster;
924 +                       VectorCopy( origin, trace.origin );
925 +                       VectorCopy( normal, trace.normal );
926 +         
927 +
928 +               
929 +                       /* get dirt */
930 +                       *floodlight = FloodLightForSample( &trace );
931 +               }
932 +       }
933 +       
934 +       /* testing no filtering */
935 +       return;
936 +       
937 +       /* filter "dirt" */
938 +       for( y = 0; y < lm->sh; y++ )
939 +       {
940 +               for( x = 0; x < lm->sw; x++ )
941 +               {
942 +                       /* get luxel */
943 +                       cluster = SUPER_CLUSTER( x, y );
944 +                       floodlight = SUPER_FLOODLIGHT( x, y );
945 +                       
946 +                       /* filter dirt by adjacency to unmapped luxels */
947 +                       average = *floodlight;
948 +                       samples = 1.0f;
949 +                       for( sy = (y - 1); sy <= (y + 1); sy++ )
950 +                       {
951 +                               if( sy < 0 || sy >= lm->sh )
952 +                                       continue;
953 +                               
954 +                               for( sx = (x - 1); sx <= (x + 1); sx++ )
955 +                               {
956 +                                       if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
957 +                                               continue;
958 +                                       
959 +                                       /* get neighboring luxel */
960 +                                       cluster = SUPER_CLUSTER( sx, sy );
961 +                                       floodlight2 = SUPER_FLOODLIGHT( sx, sy );
962 +                                       if( *cluster < 0 || *floodlight2 <= 0.0f )
963 +                                               continue;
964 +                                       
965 +                                       /* add it */
966 +                                       average += *floodlight2;
967 +                                       samples += 1.0f;
968 +                               }
969 +                               
970 +                               /* bail */
971 +                               if( samples <= 0.0f )
972 +                                       break;
973 +                       }
974 +                       
975 +                       /* bail */
976 +                       if( samples <= 0.0f )
977 +                               continue;
978 +                       
979 +                       /* scale dirt */
980 +                       *floodlight = average / samples;
981 +               }
982 +       }
983 +}
984 +
985 +/*
986 +FloodLightForSample()
987 +calculates floodlight value for a given sample
988 +once again, kudos to the dirtmapping coder
989 +*/
990 +float FloodLightForSample( trace_t *trace )
991 +{
992 +       int             i;
993 +       float   d;
994 +       float   contribution;
995 +       int     sub = 0;
996 +       float   gatherLight, outLight;
997 +       vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
998 +       float   dd;
999 +       int     vecs = 0;
1000
1001 +       gatherLight=0;
1002 +       /* dummy check */
1003 +       //if( !dirty )
1004 +       //      return 1.0f;
1005 +       if( trace == NULL || trace->cluster < 0 )
1006 +               return 0.0f;
1007 +       
1008 +
1009 +       /* setup */
1010 +       dd = floodlightDistance;
1011 +       VectorCopy( trace->normal, normal );
1012 +       
1013 +       /* check if the normal is aligned to the world-up */
1014 +       if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1015 +       {
1016 +               if( normal[ 2 ] == 1.0f )               
1017 +               {
1018 +                       VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1019 +                       VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1020 +               }
1021 +               else 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 +       }
1027 +       else
1028 +       {
1029 +               VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1030 +               CrossProduct( normal, worldUp, myRt );
1031 +               VectorNormalize( myRt, myRt );
1032 +               CrossProduct( myRt, normal, myUp );
1033 +               VectorNormalize( myUp, myUp );
1034 +       }
1035 +
1036 +       /* iterate through ordered vectors */
1037 +       for( i = 0; i < numFloodVectors; i++ )
1038 +       {
1039 +               if (floodlight_lowquality==qtrue)
1040 +        {
1041 +                       if (rand()%10 != 0 ) continue;
1042 +               }
1043 +
1044 +               vecs++;
1045 +         
1046 +               /* transform vector into tangent space */
1047 +               direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1048 +               direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1049 +               direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1050 +
1051 +               /* set endpoint */
1052 +               VectorMA( trace->origin, dd, direction, trace->end );
1053 +
1054 +               //VectorMA( trace->origin, 1, direction, trace->origin );
1055 +                       
1056 +               SetupTrace( trace );
1057 +               /* trace */
1058 +               TraceLine( trace );
1059 +               contribution=1;
1060 +
1061 +               if (trace->compileFlags & C_SKY )
1062 +               {
1063 +                       contribution=1.0f;
1064 +               }
1065 +               else if ( trace->opaque )
1066 +               {
1067 +                       VectorSubtract( trace->hit, trace->origin, displacement );
1068 +                       d=VectorLength( displacement );
1069 +
1070 +                       // d=trace->distance;            
1071 +                       //if (d>256) gatherDirt+=1;
1072 +                       contribution=d/dd;
1073 +                       if (contribution>1) contribution=1.0f; 
1074 +             
1075 +                       //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1076 +               }
1077 +         
1078 +               gatherLight+=contribution;
1079 +       }
1080 +   
1081 +       /* early out */
1082 +       if( gatherLight <= 0.0f )
1083 +               return 0.0f;
1084 +       
1085 +       sub=vecs;
1086 +
1087 +       if (sub<1) sub=1;
1088 +       gatherLight/=(sub);
1089 +
1090 +       outLight=gatherLight;
1091 +       if( outLight > 1.0f )
1092 +               outLight = 1.0f;
1093 +       
1094 +       /* return to sender */
1095 +       return outLight;
1096 +}
1097 +
1098 Index: tools/quake3/q3map2/light.c
1099 ===================================================================
1100 --- tools/quake3/q3map2/light.c (revision 290)
1101 +++ tools/quake3/q3map2/light.c (working copy)
1102 @@ -1363,6 +1363,56 @@
1103                         break;
1104         }
1105         
1106 +       /////// Floodlighting for point //////////////////
1107 +       //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1108 +       if (floodlighty)
1109 +       {
1110 +               int q;
1111 +               float addSize,f;
1112 +               vec3_t col,dir;
1113 +               col[0]=col[1]=col[2]=floodlightIntensity;
1114 +               dir[0]=dir[1]=0;
1115 +               dir[2]=1;
1116 +      
1117 +               trace.testOcclusion = qtrue;
1118 +               trace.forceSunlight = qfalse;
1119 +               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1120 +               trace.testAll = qtrue;     
1121 +      
1122 +               for (q=0;q<2;q++)
1123 +               {
1124 +                       if (q==0) //upper hemisphere
1125 +                       {
1126 +                               trace.normal[0]=0;
1127 +                               trace.normal[1]=0;
1128 +                               trace.normal[2]=1;
1129 +                       }
1130 +                       else //lower hemisphere
1131 +                       {
1132 +                               trace.normal[0]=0;
1133 +                               trace.normal[1]=0;
1134 +                               trace.normal[2]=-1;
1135 +                       }
1136 +
1137 +                       f = FloodLightForSample(&trace);
1138 +
1139 +                       contributions[ numCon ].color[0]=col[0]*f;
1140 +                       contributions[ numCon ].color[1]=col[1]*f;
1141 +                       contributions[ numCon ].color[2]=col[2]*f;
1142 +
1143 +                       contributions[ numCon ].dir[0]=dir[0];
1144 +                       contributions[ numCon ].dir[1]=dir[1];
1145 +                       contributions[ numCon ].dir[2]=dir[2];
1146 +
1147 +                       contributions[ numCon ].style = 0;
1148 +                       numCon++;               
1149 +                       /* push average direction around */
1150 +                       addSize = VectorLength( col );
1151 +                       VectorMA( gp->dir, addSize, dir, gp->dir );
1152 +               }
1153 +       }
1154 +       /////////////////////
1155 +
1156         /* normalize to get primary light direction */
1157         VectorNormalize( gp->dir, gp->dir );
1158         
1159 @@ -1544,6 +1594,12 @@
1160         qboolean        minVertex, minGrid;
1161         const char      *value;
1162         
1163 +       /* floodlight them up */
1164 +       if( floodlighty )
1165 +       {
1166 +               Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1167 +               RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1168 +       }
1169  
1170         /* ydnar: smooth normals */
1171         if( shade )
1172 @@ -1675,6 +1731,7 @@
1173                 /* flag bouncing */
1174                 bouncing = qtrue;
1175                 VectorClear( ambientColor );
1176 +               floodlighty = qfalse;
1177                 
1178                 /* generate diffuse lights */
1179                 RadFreeLights();
1180 @@ -2114,6 +2171,21 @@
1181                         loMem = qtrue;
1182                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
1183                 }
1184 +               else if( !strcmp( argv[ i ], "-floodlight" ) )
1185 +               {
1186 +                       floodlighty = qtrue;
1187 +                       Sys_Printf( "FloodLighting enabled\n" );
1188 +               }
1189 +               else if( !strcmp( argv[ i ], "-debugnormals" ) )
1190 +               {
1191 +                       debugnormals = qtrue;
1192 +                       Sys_Printf( "DebugNormals enabled\n" );
1193 +               }
1194 +               else if( !strcmp( argv[ i ], "-lowquality" ) )
1195 +               {
1196 +                       floodlight_lowquality = qtrue;
1197 +                       Sys_Printf( "Low Quality FloodLighting enabled\n" );
1198 +               }
1199                 
1200                 else
1201                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
1202 @@ -2156,6 +2228,7 @@
1203         
1204         /* ydnar: set up optimization */
1205         SetupBrushes();
1206 +       SetupFloodLight();
1207         SetupSurfaceLightmaps();
1208         
1209         /* initialize the surface facet tracing */
1210 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1211 ===================================================================
1212 --- tools/quake3/q3map2/lightmaps_ydnar.c       (revision 290)
1213 +++ tools/quake3/q3map2/lightmaps_ydnar.c       (working copy)
1214 @@ -413,6 +413,12 @@
1215                 lm->superNormals = safe_malloc( size );
1216         memset( lm->superNormals, 0, size );
1217         
1218 +       /* allocate floodlight map storage */
1219 +       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1220 +       if( lm->superFloodLight == NULL )
1221 +               lm->superFloodLight = safe_malloc( size );
1222 +       memset( lm->superFloodLight, 0, size );
1223 +       
1224         /* allocate cluster map storage */
1225         size = lm->sw * lm->sh * sizeof( int );
1226         if( lm->superClusters == NULL )
1227 Index: tools/quake3/q3map2/q3map2.h
1228 ===================================================================
1229 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1230 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1231 @@ -265,6 +265,7 @@
1232  #define SUPER_NORMAL_SIZE              3
1233  #define SUPER_DELUXEL_SIZE             3
1234  #define BSP_DELUXEL_SIZE               3
1235 +#define SUPER_FLOODLIGHT_SIZE  1
1236  
1237  #define VERTEX_LUXEL( s, v )   (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1238  #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1239 @@ -273,6 +274,7 @@
1240  #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1241  #define SUPER_ORIGIN( x, y )   (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1242  #define SUPER_NORMAL( x, y )   (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1243 +#define SUPER_FLOODLIGHT( x, y )       (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )       
1244  #define SUPER_CLUSTER( x, y )  (lm->superClusters + (((y) * lm->sw) + (x)))
1245  #define SUPER_DELUXEL( x, y )  (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1246  #define BSP_DELUXEL( x, y )            (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE))
1247 @@ -1364,6 +1366,7 @@
1248         
1249         float                                   *superDeluxels; /* average light direction */
1250         float                                   *bspDeluxels;
1251 +       float                                   *superFloodLight; 
1252  }
1253  rawLightmap_t;
1254  
1255 @@ -1670,6 +1673,9 @@
1256  void                                           SmoothNormals( void );
1257  
1258  void                                           MapRawLightmap( int num );
1259 +void                                           SetupFloodLight();
1260 +float                                          FloodLightForSample( trace_t *trace );
1261 +void                                           FloodLightRawLightmap( int num );
1262  void                                           IlluminateRawLightmap( int num );
1263  void                                           IlluminateVertexes( int num );
1264  
1265 @@ -2037,6 +2043,12 @@
1266  Q_EXTERN qboolean                      sunOnly;
1267  Q_EXTERN int                           approximateTolerance Q_ASSIGN( 0 );
1268  Q_EXTERN qboolean                      noCollapse;
1269 +Q_EXTERN qboolean                      debugnormals Q_ASSIGN( qfalse );
1270 +Q_EXTERN qboolean                      floodlighty Q_ASSIGN( qfalse );
1271 +Q_EXTERN qboolean                      floodlight_lowquality Q_ASSIGN( qfalse );
1272 +Q_EXTERN vec3_t                                floodlightRGB;
1273 +Q_EXTERN float                         floodlightIntensity Q_ASSIGN( 512 );
1274 +Q_EXTERN float                         floodlightDistance Q_ASSIGN( 1024 );
1275  Q_EXTERN qboolean                      debug;
1276  Q_EXTERN qboolean                      debugSurfaces;
1277  Q_EXTERN qboolean                      debugUnused;
1278 Index: tools/quake3/q3map2/q3map2.h
1279 ===================================================================
1280 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1281 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1282 @@ -1274,6 +1274,7 @@
1283         vec3_t                          color;                  /* starts out at full color, may be reduced if transparent surfaces are crossed */
1284         
1285         /* output */
1286 +       vec3_t                          hit;
1287         int                                     compileFlags;   /* for determining surface compile flags traced through */
1288         qboolean                        passSolid;
1289         qboolean                        opaque;
1290 Index: tools/quake3/q3map2/light_trace.c
1291 ===================================================================
1292 --- tools/quake3/q3map2/light_trace.c   (revision 290)
1293 +++ tools/quake3/q3map2/light_trace.c   (working copy)
1294 @@ -1596,6 +1596,7 @@
1295         /* bogus node number means solid, end tracing unless testing all */
1296         if( nodeNum < 0 )
1297         {
1298 +               VectorCopy( origin, trace->hit );
1299                 trace->passSolid = qtrue;
1300                 return qtrue;
1301         }
1302 @@ -1606,6 +1607,7 @@
1303         /* solid? */
1304         if( node->type == TRACE_LEAF_SOLID )
1305         {
1306 +               VectorCopy( origin, trace->hit );
1307                 trace->passSolid = qtrue;
1308                 return qtrue;
1309         }
1310 Index: tools/quake3/q3map2/light_ydnar.c
1311 ===================================================================
1312 --- tools/quake3/q3map2/light_ydnar.c   (revision 290)
1313 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1314 @@ -372,7 +372,7 @@
1315  #define NUDGE                  0.5f
1316  #define BOGUS_NUDGE            -99999.0f
1317  
1318 -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 ] )
1319 +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 ] )
1320  {
1321         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
1322         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
1323 @@ -380,6 +380,12 @@
1324         vec3_t                  pNormal;
1325         vec3_t                  vecs[ 3 ];
1326         vec3_t                  nudged;
1327 +       vec3_t                  cverts[ 3 ];
1328 +       vec3_t                  temp;
1329 +       vec4_t                  sideplane, hostplane;
1330 +       vec3_t                  origintwo;
1331 +       int                             j, next;
1332 +       float                   e;
1333         float                   *nudge;
1334         static float    nudges[][ 2 ] =
1335                                         {
1336 @@ -473,6 +479,51 @@
1337         /* non axial lightmap projection (explicit xyz) */
1338         else
1339                 VectorCopy( dv->xyz, origin );
1340 +
1341 +       //////////////////////
1342 +       //27's test to make sure samples stay within the triangle boundaries
1343 +       //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
1344 +       //2) if it does, nudge it onto the correct side.
1345 +
1346 +       if (worldverts!=NULL)
1347 +       {
1348 +               for (j=0;j<3;j++)
1349 +               {
1350 +                       VectorCopy(worldverts[j],cverts[j]);    
1351 +               }
1352 +               PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
1353 +
1354 +               for (j=0;j<3;j++)
1355 +               {
1356 +                       for (i=0;i<3;i++)
1357 +                       {
1358 +                               //build plane using 2 edges and a normal
1359 +                               next=(i+1)%3;
1360 +
1361 +                               VectorCopy(cverts[next],temp);
1362 +                               VectorAdd(temp,hostplane,temp);
1363 +                               PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
1364 +
1365 +                               //planetest sample point  
1366 +                               e=DotProduct(origin,sideplane);
1367 +                               e=e-sideplane[3];
1368 +                               if (e>0)
1369 +                               {
1370 +                                       //we're bad.
1371 +                                       //VectorClear(origin);
1372 +                                       //Move the sample point back inside triangle bounds
1373 +                                       origin[0]-=sideplane[0]*(e+1);
1374 +                                       origin[1]-=sideplane[1]*(e+1);
1375 +                                       origin[2]-=sideplane[2]*(e+1);
1376 +#ifdef DEBUG_27_1
1377 +                                       VectorClear(origin);
1378 +#endif 
1379 +                               }
1380 +                       }
1381 +               }
1382 +       }
1383 +
1384 +       ////////////////////////
1385         
1386         /* planar surfaces have precalculated lightmap vectors for nudging */
1387         if( lm->plane != NULL )
1388 @@ -504,8 +555,13 @@
1389         else
1390                 origin[ lm->axisNum ] += lightmapSampleOffset;
1391         
1392 +       VectorCopy(origin,origintwo);
1393 +       origintwo[0]+=vecs[2][0];
1394 +       origintwo[1]+=vecs[2][1];
1395 +       origintwo[2]+=vecs[2][2];
1396 +       
1397         /* get cluster */
1398 -       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
1399 +       pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
1400         
1401         /* another retarded hack, storing nudge count in luxel[ 1 ] */
1402         luxel[ 1 ] = 0.0f;      
1403 @@ -521,14 +577,14 @@
1404                         for( i = 0; i < 3; i++ )
1405                         {
1406                                 /* set nudged point*/
1407 -                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
1408 +                               nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
1409                         }
1410                         nudge += 2;
1411                         
1412                         /* get pvs cluster */
1413                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
1414 -                       if( pointCluster >= 0 ) 
1415 -                               VectorCopy( nudged, origin );
1416 +                       //if( pointCluster >= 0 )       
1417 +                       //      VectorCopy( nudged, origin );
1418                         luxel[ 1 ] += 1.0f;
1419                 }
1420         }
1421 @@ -538,8 +594,8 @@
1422         {
1423                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
1424                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
1425 -               if( pointCluster >= 0 )
1426 -                       VectorCopy( nudged, origin );
1427 +               //if( pointCluster >= 0 )
1428 +               //      VectorCopy( nudged, origin );
1429                 luxel[ 1 ] += 1.0f;
1430         }
1431         
1432 @@ -585,7 +641,7 @@
1433  than the distance between two luxels (thanks jc :)
1434  */
1435  
1436 -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 ] )
1437 +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 ] )
1438  {
1439         bspDrawVert_t   mid, *dv2[ 3 ];
1440         int                             max;
1441 @@ -633,7 +689,7 @@
1442         
1443         /* split the longest edge and map it */
1444         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
1445 -       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
1446 +       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
1447         
1448         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
1449         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
1450 @@ -641,12 +697,12 @@
1451         /* recurse to first triangle */
1452         VectorCopy( dv, dv2 );
1453         dv2[ max ] = &mid;
1454 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1455 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1456         
1457         /* recurse to second triangle */
1458         VectorCopy( dv, dv2 );
1459         dv2[ (max + 1) % 3 ] = &mid;
1460 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1461 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1462  }
1463  
1464  
1465 @@ -662,6 +718,7 @@
1466         int                             i;
1467         vec4_t                  plane;
1468         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
1469 +       vec3_t                  worldverts[ 3 ];
1470         
1471         
1472         /* get plane if possible */
1473 @@ -687,16 +744,20 @@
1474                 ttv = NULL;
1475         }
1476         
1477 +       VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
1478 +       VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
1479 +       VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
1480 +       
1481         /* map the vertexes */
1482 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
1483 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
1484 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
1485 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
1486 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
1487 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
1488         
1489         /* 2002-11-20: prefer axial triangle edges */
1490         if( mapNonAxial )
1491         {
1492                 /* subdivide the triangle */
1493 -               MapTriangle_r( lm, info, dv, plane, stv, ttv );
1494 +               MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
1495                 return qtrue;
1496         }
1497         
1498 @@ -718,7 +779,7 @@
1499                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
1500                         
1501                         /* map the degenerate triangle */
1502 -                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
1503 +                       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
1504                 }
1505         }
1506         
1507 @@ -780,8 +841,8 @@
1508         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
1509         
1510         /* map the vertexes */
1511 -       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
1512 -       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
1513 +       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
1514 +       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
1515         
1516         /* 0 and 2 */
1517         if( max == 0 )
1518 @@ -866,10 +927,10 @@
1519         }
1520         
1521         /* map the vertexes */
1522 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
1523 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
1524 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
1525 -       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
1526 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
1527 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
1528 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
1529 +       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
1530         
1531         /* subdivide the quad */
1532         MapQuad_r( lm, info, dv, plane, stv, ttv );
1533 @@ -1161,7 +1222,7 @@
1534                                         continue;
1535                                 
1536                                 /* map the fake vert */
1537 -                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
1538 +                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
1539                         }
1540                 }
1541         }
1542 @@ -1636,22 +1697,32 @@
1543                                         deluxel = SUPER_DELUXEL( x, y );
1544                                         origin = SUPER_ORIGIN( x, y );
1545                                         normal = SUPER_NORMAL( x, y );
1546 -                                       
1547 -                                       /* set contribution count */
1548 -                                       lightLuxel[ 3 ] = 1.0f;
1549 -                                       
1550 -                                       /* setup trace */
1551 -                                       trace.cluster = *cluster;
1552 -                                       VectorCopy( origin, trace.origin );
1553 -                                       VectorCopy( normal, trace.normal );
1554 -                                       
1555 -                                       /* get light for this sample */
1556 -                                       LightContributionToSample( &trace );
1557 -                                       VectorCopy( trace.color, lightLuxel );
1558 -                                       
1559 -                                       /* add to count */
1560 -                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
1561 +
1562 +                                       ////////// 27's temp hack for testing edge clipping ////
1563 +                                       if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
1564 +                                       {
1565 +                                               lightLuxel[ 1 ] = 255;
1566 +                                               lightLuxel[ 3 ] = 1.0f;
1567                                                 totalLighted++;
1568 +                                       }
1569 +                                       else
1570 +                                       {
1571 +                                               /* set contribution count */
1572 +                                               lightLuxel[ 3 ] = 1.0f;
1573 +                                               
1574 +                                               /* setup trace */
1575 +                                               trace.cluster = *cluster;
1576 +                                               VectorCopy( origin, trace.origin );
1577 +                                               VectorCopy( normal, trace.normal );
1578 +                                               
1579 +                                               /* get light for this sample */
1580 +                                               LightContributionToSample( &trace );
1581 +                                               VectorCopy( trace.color, lightLuxel );
1582 +                                               
1583 +                                               /* add to count */
1584 +                                               if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
1585 +                                                       totalLighted++;
1586 +                                       }
1587                                         
1588                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
1589                                         if( deluxemap )
1590 Index: tools/quake3/q3map2/q3map2.h
1591 ===================================================================
1592 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1593 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1594 @@ -34,8 +34,8 @@
1595  
1596  
1597  /* version */
1598 -#define Q3MAP_VERSION  "2.5.11"
1599 -#define Q3MAP_MOTD             "A well-oiled toaster oven"
1600 +#define Q3MAP_VERSION  "2.5.11-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTtrianglecheck"
1601 +#define Q3MAP_MOTD             "Blackhole Box gives the light back"
1602  
1603  
1604  
1605 Index: include/version.default
1606 ===================================================================
1607 --- include/version.default     (revision 290)
1608 +++ include/version.default     (working copy)
1609 @@ -1 +1 @@
1610 -1.4.0\r
1611 +1.4.0-div0-obj\r