more patches: targetname/killtarget handling fixes
[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: radiant/map.cpp
115 ===================================================================
116 --- radiant/map.cpp     (revision 304)
117 +++ radiant/map.cpp     (working copy)
118 @@ -270,6 +270,100 @@
119    ents->RemoveAll();
120  }
121  
122 +void Map_DoTargetFix(entity_t *e, const char *target, int num_ents, CPtrArray *ents, GPtrArray *new_ents)
123 +{
124 +       int j;
125 +       int id;
126 +       char newtarget[128];
127 +       entity_t *e_target;
128 +
129 +       qboolean targetnameFound = FALSE;
130 +       qboolean targetFound = FALSE;
131 +       qboolean colliding = FALSE;
132 +
133 +       if(!target)
134 +               return;
135 +       if(!*target)
136 +               return;
137 +
138 +       target = g_strdup(target);
139 +
140 +       // check the current map entities for an actual collision
141 +       for (e_target = entities.next; e_target != &entities; e_target = e_target->next)
142 +       {
143 +               if(
144 +                       !strcmp(target, ValueForKey(e_target, "target"))
145 +                       ||
146 +                       !strcmp(target, ValueForKey(e_target, "killtarget"))
147 +               )
148 +               {
149 +                       // make sure the collision is not between two imported entities
150 +                       for(j=0; j<(int)new_ents->len; j++)
151 +                       {
152 +                               if(e_target == g_ptr_array_index(new_ents, j))
153 +                               {
154 +                                       targetFound = true;
155 +                                       goto no_collision_yet_1;
156 +                               }
157 +                       }
158 +                       colliding = TRUE;
159 +no_collision_yet_1:
160 +                       ;
161 +               }
162 +               if(
163 +                       !strcmp(target, ValueForKey(e_target, "targetname"))
164 +               )
165 +               {
166 +                       // make sure the collision is not between two imported entities
167 +                       for(j=0; j<(int)new_ents->len; j++)
168 +                       {
169 +                               if(e_target == g_ptr_array_index(new_ents, j))
170 +                               {
171 +                                       targetnameFound = true;
172 +                                       goto no_collision_yet_2;
173 +                               }
174 +                       }
175 +                       colliding = TRUE;
176 +no_collision_yet_2:
177 +                       ;
178 +               }
179 +       }
180 +
181 +       // find the matching targeted entity(s)
182 +       if(colliding && targetFound && targetnameFound)
183 +       {
184 +               // We got a collision
185 +               // first look for a non-conflicting target name
186 +               id = GetUniqueTargetId(1);
187 +               sprintf(newtarget, "t%i", id);
188 +
189 +               for(j=num_ents-1; j>0; j--)
190 +               {
191 +                       e_target = (entity_t*)ents->GetAt(j);
192 +                       if(e_target != NULL)
193 +                       {
194 +                               const char *targetname = ValueForKey(e_target, "targetname");
195 +                               if( (targetname != NULL) && (strcmp(target, targetname) == 0) ) 
196 +                               {
197 +                                       SetKeyValue(e_target, "targetname", newtarget);
198 +                               }
199 +                               targetname = ValueForKey(e_target, "target");
200 +                               if( (targetname != NULL) && (strcmp(target, targetname) == 0) )
201 +                               {
202 +                                       SetKeyValue(e_target, "target", newtarget);
203 +                               }
204 +                               targetname = ValueForKey(e_target, "killtarget");
205 +                               if( (targetname != NULL) && (strcmp(target, targetname) == 0) )
206 +                               {
207 +                                       SetKeyValue(e_target, "killtarget", newtarget);
208 +                               }
209 +                       }
210 +               }
211 +       }
212 +
213 +       g_free(target);
214 +}
215 +
216  /*!\todo Possibly make the import Undo-friendly by calling Undo_End for new brushes and ents */
217  void Map_ImportEntities(CPtrArray *ents, bool bAddSelected = false)
218  {
219 @@ -466,60 +560,27 @@
220      }
221      else
222      {
223 -      // fix target/targetname collisions
224 -      if ((g_PrefsDlg.m_bDoTargetFix) && (strcmp(ValueForKey(e, "target"), "") != 0))
225 -      {
226 -        GPtrArray *t_ents = g_ptr_array_new();
227 -        entity_t *e_target;
228 -        const char *target = ValueForKey(e, "target");
229 -        qboolean bCollision=FALSE;
230 +      // keep a list of ents added to avoid testing collisions against them
231 +      g_ptr_array_add(new_ents, (gpointer)e);
232  
233 -        // check the current map entities for an actual collision
234 -        for (e_target = entities.next; e_target != &entities; e_target = e_target->next)
235 -        {
236 -          if(!strcmp(target, ValueForKey(e_target, "target")))
237 -          {
238 -            bCollision = TRUE;
239 -            // make sure the collision is not between two imported entities
240 -            for(j=0; j<(int)new_ents->len; j++)
241 -            {
242 -              if(e_target == g_ptr_array_index(new_ents, j))
243 -                bCollision = FALSE;
244 -            }
245 -          }
246 -        }
247 -
248 -        // find the matching targeted entity(s)
249 -        if(bCollision)
250 -        {
251 -          for(j=num_ents-1; j>0; j--)
252 -          {
253 -            e_target = (entity_t*)ents->GetAt(j);
254 -            if(e_target != NULL && e_target != e)
255 -            {
256 -              const char *targetname = ValueForKey(e_target, "targetname");
257 -              if( (targetname != NULL) && (strcmp(target, targetname) == 0) )
258 -                g_ptr_array_add(t_ents, (gpointer)e_target);
259 -            }
260 -          }
261 -          if(t_ents->len > 0)
262 -          {
263 -            // link the first to get a unique target/targetname
264 -            Entity_Connect(e, (entity_t*)g_ptr_array_index(t_ents,0));
265 -            // set the targetname of the rest of them manually
266 -            for(j = 1; j < (int)t_ents->len; j++)
267 -              SetKeyValue( (entity_t*)g_ptr_array_index(t_ents, j), "targetname", ValueForKey(e, "target") );
268 -          }
269 -          g_ptr_array_free(t_ents, FALSE);
270 -        }
271 -      }
272 -
273        // add the entity to the end of the entity list
274        Entity_AddToList(e, &entities);
275        g_qeglobals.d_num_entities++;
276  
277 -      // keep a list of ents added to avoid testing collisions against them
278 -      g_ptr_array_add(new_ents, (gpointer)e);
279 +      // fix target/targetname collisions
280 +      if (g_PrefsDlg.m_bDoTargetFix)
281 +         {
282 +                 const char *target;
283 +
284 +                 target = ValueForKey(e, "target");
285 +                 Map_DoTargetFix(e, target, num_ents, ents, new_ents);
286 +
287 +                 target = ValueForKey(e, "killtarget");
288 +                 Map_DoTargetFix(e, target, num_ents, ents, new_ents);
289 +
290 +                 target = ValueForKey(e, "targetname");
291 +                 Map_DoTargetFix(e, target, num_ents, ents, new_ents);
292 +         }
293      }
294    }
295    g_ptr_array_free(new_ents, FALSE);
296 Index: radiant/drag.cpp
297 ===================================================================
298 --- radiant/drag.cpp    (revision 304)
299 +++ radiant/drag.cpp    (working copy)
300 @@ -255,54 +255,6 @@
301  
302  entity_t *peLink;
303  
304 -void UpdateTarget(vec3_t origin, vec3_t dir)
305 -{
306 -       trace_t t;
307 -       entity_t *pe;
308 -       int i;
309 -       char sz[128];
310 -
311 -       t = Test_Ray (origin, dir, 0);
312 -
313 -       if (!t.brush)
314 -               return;
315 -
316 -       pe = t.brush->owner;
317 -
318 -       if (pe == NULL)
319 -               return;
320 -
321 -       // is this the first?
322 -       if (peLink != NULL)
323 -       {
324 -
325 -               // Get the target id from out current target
326 -               // if there is no id, make one
327 -
328 -               i = IntForKey(pe, "target");
329 -               if (i <= 0)
330 -               {
331 -                       i = GetUniqueTargetId(1);
332 -                       sprintf(sz, "%d", i);
333 -
334 -                       SetKeyValue(pe, "target", sz);
335 -               }
336 -
337 -               // set the target # into our src
338 -
339 -               sprintf(sz, "%d", i);
340 -               SetKeyValue(peLink, "targetname", sz);
341 -
342 -               Sys_UpdateWindows(W_ENTITY);
343 -
344 -       }
345 -
346 -       // promote the target to the src
347 -
348 -       peLink = pe;
349 -
350 -}
351 -
352  /*
353  ===========
354  Drag_Begin
355 Index: radiant/xywindow.cpp
356 ===================================================================
357 --- radiant/xywindow.cpp        (revision 304)
358 +++ radiant/xywindow.cpp        (working copy)
359 @@ -270,16 +270,17 @@
360  void DrawPathLines (void)
361  {
362    int       i, j, k;
363 -  vec3_t    mid, mid1;
364 +  vec3_t    mid, mid1, v;
365    entity_t *se, *te;
366    brush_t   *sb, *tb;
367    const char    *psz;
368 -  vec3_t    dir, s1, s2;
369 +  vec3_t    dir, s1, s2, dirortho;
370    vec_t len, f;
371    int       arrows;
372    int           num_entities;
373    const char        *ent_target[MAX_MAP_ENTITIES];
374    entity_t  *ent_entity[MAX_MAP_ENTITIES];
375 +  int lines;
376  
377    if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS)
378    {
379 @@ -295,6 +296,12 @@
380        ent_entity[num_entities] = te;
381        num_entities++;
382      }
383 +    ent_target[num_entities] = ValueForKey (te, "killtarget");
384 +    if (ent_target[num_entities][0])
385 +    {
386 +      ent_entity[num_entities] = te;
387 +      num_entities++;
388 +    }
389    }
390  
391    for (se = entities.next ; se != &entities ; se = se->next)
392 @@ -308,6 +315,9 @@
393      if (sb == &se->brushes)
394        continue;
395  
396 +       for (i=0 ; i<3 ; i++)
397 +               mid[i] = (sb->mins[i] + sb->maxs[i])*0.5;
398 +
399      for (k=0 ; k<num_entities ; k++)
400      {
401        if (strcmp (ent_target[k], psz))
402 @@ -318,14 +328,20 @@
403        if (tb == &te->brushes)
404          continue;
405  
406 -      for (i=0 ; i<3 ; i++)
407 -        mid[i] = (sb->mins[i] + sb->maxs[i])*0.5;
408 +         lines = 0;
409 +         if(!strcmp(ValueForKey(te, "target"), psz))
410 +                 lines += 1;
411 +         if(!strcmp(ValueForKey(te, "killtarget"), psz))
412 +                 lines += 2;
413  
414        for (i=0 ; i<3 ; i++)
415          mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5;
416  
417        VectorSubtract (mid1, mid, dir);
418        len = VectorNormalize (dir, dir);
419 +         dirortho[0] = -dir[1];
420 +         dirortho[1] = dir[0];
421 +         dirortho[2] = 0;
422        s1[0] = -dir[1]*8 + dir[0]*8;
423        s2[0] = dir[1]*8 + dir[0]*8;
424        s1[1] = dir[0]*8 + dir[1]*8;
425 @@ -334,8 +350,13 @@
426        qglColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
427  
428        qglBegin(GL_LINES);
429 -      qglVertex3fv(mid);
430 -      qglVertex3fv(mid1);
431 +         for(i = -lines + 1; i < lines; i += 2)
432 +         {
433 +                 VectorMA(mid, i, dirortho, v);
434 +                 qglVertex3fv(v);
435 +                 VectorMA(mid1, i, dirortho, v);
436 +                 qglVertex3fv(v);
437 +         }
438  
439        arrows = (int)(len / 256) + 1;
440  
441 Index: radiant/targetname.cpp
442 ===================================================================
443 --- radiant/targetname.cpp      (revision 304)
444 +++ radiant/targetname.cpp      (working copy)
445 @@ -24,11 +24,11 @@
446  /*!
447  connects two entities creating a unique target/targetname value 
448  */
449 -void Entity_Connect(entity_t *e1, entity_t *e2)
450 +void Entity_Connect(entity_t *e1, entity_t *e2, bool kill)
451  {
452    const char *maptarget;
453    char newtarget[16];
454 -  int maxtarget=0;  // highest t# value in the map
455 +  int id=0;  // highest t# value in the map
456    entity_t *e;      // map entities
457  
458    if (e1 == e2)
459 @@ -39,47 +39,54 @@
460                 return;
461         }
462  
463 -  for (e=entities.next ; e != &entities ; e=e->next)
464 -  {
465 -    maptarget = ValueForKey (e, "target");
466 -    if (maptarget && maptarget[0])
467 -    {
468 -      int targetnum = atoi(maptarget+1);
469 -      if (targetnum > maxtarget)
470 -        maxtarget = targetnum;
471 -    }
472 -  }
473 -  sprintf (newtarget, "t%i", maxtarget+1);
474 +       id = GetUniqueTargetId(1);
475 +       sprintf (newtarget, "t%i", id);
476    
477  #ifdef _DEBUG
478    Sys_Printf("Connecting entities with new target/targetname: %s\n", newtarget);
479  #endif  
480    
481 -       SetKeyValue (e1, "target", newtarget);
482 +       if(kill)
483 +               SetKeyValue (e1, "killtarget", newtarget);
484 +       else
485 +               SetKeyValue (e1, "target", newtarget);
486         SetKeyValue (e2, "targetname", newtarget);
487  }
488  
489 +static int TargetIdForKey(entity_t *pe, const char *key)
490 +{
491 +       const char *p = ValueForKey(pe, key);
492 +       if(!p)
493 +               return 0;
494 +       if(!*p)
495 +               return 0;
496 +       return atoi(p + 1);
497 +}
498 +
499  int GetUniqueTargetId(int iHint)
500  {
501 -       int iMin, iMax, i;
502 +       int iMax, i;
503         bool fFound;
504         entity_t *pe;
505         
506         fFound = FALSE;
507         pe = entities.next;
508 -       iMin = 0; 
509         iMax = 0;
510         
511         for (; pe != NULL && pe != &entities ; pe = pe->next)
512         {
513 -               i = IntForKey(pe, "target");
514 -               if (i)
515 -               {
516 -                       iMin = MIN(i, iMin);
517 -                       iMax = MAX(i, iMax);
518 -                       if (i == iHint)
519 -                               fFound = TRUE;
520 -               }
521 +               i = TargetIdForKey(pe, "target");
522 +               iMax = MAX(i, iMax);
523 +               if (i == iHint)
524 +                       fFound = TRUE;
525 +               i = TargetIdForKey(pe, "targetname");
526 +               iMax = MAX(i, iMax);
527 +               if (i == iHint)
528 +                       fFound = TRUE;
529 +               i = TargetIdForKey(pe, "killtarget");
530 +               iMax = MAX(i, iMax);
531 +               if (i == iHint)
532 +                       fFound = TRUE;
533         }
534  
535         if (fFound)
536 Index: radiant/qe3.cpp
537 ===================================================================
538 --- radiant/qe3.cpp     (revision 304)
539 +++ radiant/qe3.cpp     (working copy)
540 @@ -704,7 +704,7 @@
541  from the first selected to the secon
542  ===============
543  */
544 -void ConnectEntities (void)
545 +void ConnectEntities (bool kill)
546  {
547         entity_t        *e1, *e2;
548         const char              *target;
549 @@ -734,7 +734,7 @@
550                 return;
551         }
552  
553 -  target = ValueForKey (e1, "target");
554 +  target = ValueForKey (e1, kill ? "killtarget" : "target");
555    if (target && target[0])
556      newtarg = g_strdup(target);
557    else
558 @@ -743,12 +743,12 @@
559      if(target && target[0])
560        newtarg = g_strdup(target);
561      else
562 -      Entity_Connect(e1, e2);
563 +      Entity_Connect(e1, e2, kill);
564    }
565  
566    if(newtarg != NULL)
567    {
568 -    SetKeyValue(e1, "target", newtarg);
569 +    SetKeyValue(e1, kill ? "killtarget" : "target", newtarg);
570      SetKeyValue(e2, "targetname", newtarg);
571      g_free(newtarg);
572    }
573 Index: radiant/qe3.h
574 ===================================================================
575 --- radiant/qe3.h       (revision 304)
576 +++ radiant/qe3.h       (working copy)
577 @@ -229,7 +229,7 @@
578  void SelectEdgeByRay (vec3_t org, vec3_t dir);
579  void SelectVertexByRay (vec3_t org, vec3_t dir);
580  
581 -void ConnectEntities (void);
582 +void ConnectEntities (bool kill = false);
583  
584  extern int     update_bits;
585  
586 @@ -878,7 +878,7 @@
587  
588  // SPoG
589  // targetname.cpp
590 -void Entity_Connect(entity_t *e1, entity_t *e2);
591 +void Entity_Connect(entity_t *e1, entity_t *e2, bool kill = false);
592  int GetUniqueTargetId(int iHint);
593  
594  // xywindow.cpp
595 Index: tools/quake3/q3map2/convert_map.c
596 ===================================================================
597 --- tools/quake3/q3map2/convert_map.c   (revision 191)
598 +++ tools/quake3/q3map2/convert_map.c   (working copy)
599 @@ -46,6 +46,105 @@
600  #define        SNAP_FLOAT_TO_INT       4
601  #define        SNAP_INT_TO_FLOAT       (1.0 / SNAP_FLOAT_TO_INT)
602  
603 +typedef vec_t vec2_t[2];
604 +
605 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
606 +                    vec_t a10, vec_t a11, vec_t a12,
607 +                    vec_t a20, vec_t a21, vec_t a22)
608 +{
609 +       return
610 +               a00 * (a11 * a22 - a12 * a21)
611 +       -       a01 * (a10 * a22 - a12 * a20)
612 +       +       a02 * (a10 * a21 - a11 * a20);
613 +}
614 +
615 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
616 +{
617 +       bspDrawSurface_t *s;
618 +       int i;
619 +       int t;
620 +       vec_t best = 0;
621 +       vec_t thisarea;
622 +       vec3_t normdiff;
623 +       vec3_t v1v0, v2v0, norm;
624 +       bspDrawVert_t *vert[3];
625 +       winding_t *polygon;
626 +       plane_t *buildPlane = &mapplanes[buildSide->planenum];
627 +       int matches = 0;
628 +
629 +       // first, start out with NULLs
630 +       bestVert[0] = bestVert[1] = bestVert[2] = NULL;
631 +
632 +       // brute force through all surfaces
633 +       for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
634 +       {
635 +               if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
636 +                       continue;
637 +               if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
638 +                       continue;
639 +               for(t = 0; t + 3 <= s->numIndexes; t += 3)
640 +               {
641 +                       vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
642 +                       vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
643 +                       vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
644 +                       if(s->surfaceType == MST_PLANAR)
645 +                       {
646 +                               VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
647 +                               VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
648 +                               VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
649 +                       }
650 +                       else
651 +                       {
652 +                               // this is more prone to roundoff errors, but with embedded
653 +                               // models, there is no better way
654 +                               VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
655 +                               VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
656 +                               CrossProduct(v2v0, v1v0, norm);
657 +                               VectorNormalize(norm, norm);
658 +                               VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
659 +                       }
660 +                       if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
661 +                       if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
662 +                       if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
663 +                       // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
664 +                       polygon = CopyWinding(buildSide->winding);
665 +                       for(i = 0; i < 3; ++i)
666 +                       {
667 +                               // 0: 1, 2
668 +                               // 1: 2, 0
669 +                               // 2; 0, 1
670 +                               vec3_t *v1 = &vert[(i+1)%3]->xyz;
671 +                               vec3_t *v2 = &vert[(i+2)%3]->xyz;
672 +                               vec3_t triNormal;
673 +                               vec_t triDist;
674 +                               vec3_t sideDirection;
675 +                               // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
676 +                               VectorSubtract(*v2, *v1, sideDirection);
677 +                               CrossProduct(sideDirection, buildPlane->normal, triNormal);
678 +                               triDist = DotProduct(*v1, triNormal);
679 +                               ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
680 +                               if(!polygon)
681 +                                       goto exwinding;
682 +                       }
683 +                       thisarea = WindingArea(polygon);
684 +                       if(thisarea > 0)
685 +                               ++matches;
686 +                       if(thisarea > best)
687 +                       {
688 +                               best = thisarea;
689 +                               bestVert[0] = vert[0];
690 +                               bestVert[1] = vert[1];
691 +                               bestVert[2] = vert[2];
692 +                       }
693 +                       FreeWinding(polygon);
694 +exwinding:
695 +                       ;
696 +               }
697 +       }
698 +       //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
699 +       //      fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
700 +}
701 +
702  static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
703  {
704         int                             i, j;
705 @@ -54,12 +153,17 @@
706         bspShader_t             *shader;
707         char                    *texture;
708         bspPlane_t              *plane;
709 +       plane_t         *buildPlane;
710         vec3_t                  pts[ 3 ];
711 +       bspDrawVert_t   *vert[3];
712 +       int valid;
713         
714         
715         /* start brush */
716         fprintf( f, "\t// brush %d\n", num );
717         fprintf( f, "\t{\n" );
718 +       fprintf( f, "\tbrushDef\n" );
719 +       fprintf( f, "\t{\n" );
720         
721         /* clear out build brush */
722         for( i = 0; i < buildBrush->numsides; i++ )
723 @@ -109,9 +213,88 @@
724                 /* get build side */
725                 buildSide = &buildBrush->sides[ i ];
726                 
727 +               /* get plane */
728 +               buildPlane = &mapplanes[ buildSide->planenum ];
729 +               
730                 /* dummy check */
731                 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
732                         continue;
733 +
734 +               // st-texcoords -> texMat block
735 +               // start out with dummy
736 +               VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
737 +               VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
738 +
739 +               // find surface for this side (by brute force)
740 +               // surface format:
741 +               //   - meshverts point in pairs of three into verts
742 +               //   - (triangles)
743 +               //   - find the triangle that has most in common with our side
744 +               GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
745 +               valid = 0;
746 +
747 +               if(vert[0] && vert[1] && vert[2])
748 +               {
749 +                       int i;
750 +                       vec3_t texX, texY;
751 +                       vec3_t xy1I, xy1J, xy1K;
752 +                       vec2_t stI, stJ, stK;
753 +                       vec_t D, D0, D1, D2;
754 +
755 +                       ComputeAxisBase(buildPlane->normal, texX, texY);
756 +
757 +                       VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
758 +                       VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
759 +                       VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
760 +                       stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
761 +                       stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
762 +                       stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
763 +
764 +                       //   - solve linear equations:
765 +                       //     - (x, y) := xyz . (texX, texY)
766 +                       //     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
767 +                       //       (for three vertices)
768 +                       D = Det3x3(
769 +                               xy1I[0], xy1I[1], 1,
770 +                               xy1J[0], xy1J[1], 1,
771 +                               xy1K[0], xy1K[1], 1
772 +                       );
773 +                       if(D != 0)
774 +                       {
775 +                               for(i = 0; i < 2; ++i)
776 +                               {
777 +                                       D0 = Det3x3(
778 +                                               stI[i], xy1I[1], 1,
779 +                                               stJ[i], xy1J[1], 1,
780 +                                               stK[i], xy1K[1], 1
781 +                                       );
782 +                                       D1 = Det3x3(
783 +                                               xy1I[0], stI[i], 1,
784 +                                               xy1J[0], stJ[i], 1,
785 +                                               xy1K[0], stK[i], 1
786 +                                       );
787 +                                       D2 = Det3x3(
788 +                                               xy1I[0], xy1I[1], stI[i],
789 +                                               xy1J[0], xy1J[1], stJ[i],
790 +                                               xy1K[0], xy1K[1], stK[i]
791 +                                       );
792 +                                       VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
793 +                                       valid = 1;
794 +                               }
795 +                       }
796 +                       else
797 +                               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",
798 +                                       buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
799 +                                       vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], 
800 +                                       texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
801 +                                       vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
802 +                                       vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
803 +                                       vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
804 +                                       );
805 +               }
806 +               else
807 +                       if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
808 +                               fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
809                 
810                 /* get texture name */
811                 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
812 @@ -130,14 +313,21 @@
813                 
814                 /* print brush side */
815                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
816 -               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",
817 +               fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
818                         pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
819                         pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
820                         pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
821 -                       texture );
822 +                       buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
823 +                       buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
824 +                       texture,
825 +                       // DEBUG: valid ? 0 : C_DETAIL
826 +                       0
827 +                       );
828 +               // TODO write brush primitives format here
829         }
830         
831         /* end brush */
832 +       fprintf( f, "\t}\n" );
833         fprintf( f, "\t}\n\n" );
834  }
835  
836 Index: tools/quake3/q3map2/main.c
837 ===================================================================
838 --- tools/quake3/q3map2/main.c  (revision 191)
839 +++ tools/quake3/q3map2/main.c  (working copy)
840 @@ -541,6 +541,18 @@
841                                         Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
842                         }
843                 }
844 +               else if( !strcmp( argv[ i ],  "-ne" ) )
845 +               {
846 +                       normalEpsilon = atof( argv[ i + 1 ] );
847 +                       i++;
848 +                       Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
849 +               }
850 +               else if( !strcmp( argv[ i ],  "-de" ) )
851 +               {
852 +                       distanceEpsilon = atof( argv[ i + 1 ] );
853 +                       i++;
854 +                       Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
855 +               }
856         }
857         
858         /* clean up map name */
859 Index: tools/quake3/q3map2/model.c
860 ===================================================================
861 --- tools/quake3/q3map2/model.c (revision 193)
862 +++ tools/quake3/q3map2/model.c (working copy)
863 @@ -222,6 +222,8 @@
864         byte                            *color;
865         picoIndex_t                     *indexes;
866         remap_t                         *rm, *glob;
867 +       double                          normalEpsilon_save;
868 +       double                          distanceEpsilon_save;
869         
870         
871         /* get model */
872 @@ -398,9 +400,8 @@
873                 /* ydnar: giant hack land: generate clipping brushes for model triangles */
874                 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
875                 {
876 -                       vec3_t          points[ 3 ], backs[ 3 ];
877 +                       vec3_t          points[ 4 ], backs[ 3 ];
878                         vec4_t          plane, reverse, pa, pb, pc;
879 -                       vec3_t          nadir;
880                         
881                         
882                         /* temp hack */
883 @@ -437,90 +438,141 @@
884                                         /* note: this doesn't work as well as simply using the plane of the triangle, below */
885                                         for( k = 0; k < 3; k++ )
886                                         {
887 -                                               if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
888 -                                                       fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
889 +                                               if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
890 +                                                       fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
891                                                 {
892                                                         backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
893                                                         break;
894                                                 }
895                                         }
896                                 }
897 +
898 +                               VectorCopy( points[0], points[3] ); // for cyclic usage
899                                 
900                                 /* make plane for triangle */
901 +                               // div0: add some extra spawnflags:
902 +                               //   0: snap normals to axial planes for extrusion
903 +                               //   8: extrude with the original normals
904 +                               //  16: extrude only with up/down normals (ideal for terrain)
905 +                               //  24: extrude by distance zero (may need engine changes)
906                                 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
907                                 {
908 +                                       vec3_t bestNormal;
909 +                                       float backPlaneDistance = 2;
910 +
911 +                                       if(spawnFlags & 8) // use a DOWN normal
912 +                                       {
913 +                                               if(spawnFlags & 16)
914 +                                               {
915 +                                                       // 24: normal as is, and zero width (broken)
916 +                                                       VectorCopy(plane, bestNormal);
917 +                                               }
918 +                                               else
919 +                                               {
920 +                                                       // 8: normal as is
921 +                                                       VectorCopy(plane, bestNormal);
922 +                                               }
923 +                                       }
924 +                                       else
925 +                                       {
926 +                                               if(spawnFlags & 16)
927 +                                               {
928 +                                                       // 16: UP/DOWN normal
929 +                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
930 +                                               }
931 +                                               else
932 +                                               {
933 +                                                       // 0: axial normal
934 +                                                       if(fabs(plane[0]) > fabs(plane[1])) // x>y
935 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
936 +                                                                       VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
937 +                                                               else // x>y, z>=y
938 +                                                                       if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
939 +                                                                               VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
940 +                                                                       else // z>=x, x>y
941 +                                                                               VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
942 +                                                       else // y>=x
943 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
944 +                                                                       VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
945 +                                                               else // z>=y, y>=x
946 +                                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
947 +                                               }
948 +                                       }
949 +
950 +                                       /* build a brush */
951 +                                       buildBrush = AllocBrush( 48 );
952 +                                       buildBrush->entityNum = mapEntityNum;
953 +                                       buildBrush->original = buildBrush;
954 +                                       buildBrush->contentShader = si;
955 +                                       buildBrush->compileFlags = si->compileFlags;
956 +                                       buildBrush->contentFlags = si->contentFlags;
957 +                                       normalEpsilon_save = normalEpsilon;
958 +                                       distanceEpsilon_save = distanceEpsilon;
959 +                                       if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
960 +                                       {
961 +                                               buildBrush->detail = qfalse;
962 +
963 +                                               // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
964 +                                               if(normalEpsilon > 0)
965 +                                                       normalEpsilon = 0;
966 +                                               if(distanceEpsilon > 0)
967 +                                                       distanceEpsilon = 0;
968 +                                       }
969 +                                       else
970 +                                               buildBrush->detail = qtrue;
971 +
972                                         /* regenerate back points */
973                                         for( j = 0; j < 3; j++ )
974                                         {
975                                                 /* get vertex */
976                                                 dv = &ds->verts[ ds->indexes[ i + j ] ];
977 -                                               
978 -                                               /* copy xyz */
979 -                                               VectorCopy( dv->xyz, backs[ j ] );
980 -                                               
981 -                                               /* find nearest axial to plane normal and push back points opposite */
982 -                                               for( k = 0; k < 3; k++ )
983 -                                               {
984 -                                                       if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
985 -                                                               fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
986 -                                                       {
987 -                                                               backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
988 -                                                               break;
989 -                                                       }
990 -                                               }
991 +
992 +                                               // shift by some units
993 +                                               VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
994                                         }
995 -                                       
996 +
997                                         /* make back plane */
998                                         VectorScale( plane, -1.0f, reverse );
999 -                                       reverse[ 3 ] = -(plane[ 3 ] - 1);
1000 -                                       
1001 -                                       /* make back pyramid point */
1002 -                                       VectorCopy( points[ 0 ], nadir );
1003 -                                       VectorAdd( nadir, points[ 1 ], nadir );
1004 -                                       VectorAdd( nadir, points[ 2 ], nadir );
1005 -                                       VectorScale( nadir, 0.3333333333333f, nadir );
1006 -                                       VectorMA( nadir, -2.0f, plane, nadir );
1007 -                                       
1008 -                                       /* make 3 more planes */
1009 -                                       //%     if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
1010 -                                       //%             PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
1011 -                                       //%             PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
1012 +                                       reverse[ 3 ] = -plane[ 3 ];
1013 +                                       if((spawnFlags & 24) != 24)
1014 +                                               reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
1015 +                                       // 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)
1016 +
1017                                         if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
1018 -                                               PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1019 -                                               PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1020 +                                                       PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1021 +                                                       PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1022                                         {
1023 -                                               /* build a brush */
1024 -                                               buildBrush = AllocBrush( 48 );
1025 -                                               
1026 -                                               buildBrush->entityNum = mapEntityNum;
1027 -                                               buildBrush->original = buildBrush;
1028 -                                               buildBrush->contentShader = si;
1029 -                                               buildBrush->compileFlags = si->compileFlags;
1030 -                                               buildBrush->contentFlags = si->contentFlags;
1031 -                                               buildBrush->detail = qtrue;
1032 -                                               
1033                                                 /* set up brush sides */
1034                                                 buildBrush->numsides = 5;
1035                                                 for( j = 0; j < buildBrush->numsides; j++ )
1036                                                         buildBrush->sides[ j ].shaderInfo = si;
1037 +
1038                                                 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1039 -                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
1040 -                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
1041 -                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
1042 -                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
1043 -                                               
1044 -                                               /* add to entity */
1045 -                                               if( CreateBrushWindings( buildBrush ) )
1046 -                                               {
1047 -                                                       AddBrushBevels();
1048 -                                                       //%     EmitBrushes( buildBrush, NULL, NULL );
1049 -                                                       buildBrush->next = entities[ mapEntityNum ].brushes;
1050 -                                                       entities[ mapEntityNum ].brushes = buildBrush;
1051 -                                                       entities[ mapEntityNum ].numBrushes++;
1052 -                                               }
1053 -                                               else
1054 -                                                       free( buildBrush );
1055 +                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
1056 +                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
1057 +                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
1058 +                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
1059                                         }
1060 +                                       else
1061 +                                       {
1062 +                                               free(buildBrush);
1063 +                                               continue;
1064 +                                       }
1065 +
1066 +                                       normalEpsilon = normalEpsilon_save;
1067 +                                       distanceEpsilon = distanceEpsilon_save;
1068 +
1069 +                                       /* add to entity */
1070 +                                       if( CreateBrushWindings( buildBrush ) )
1071 +                                       {
1072 +                                               AddBrushBevels();
1073 +                                               //%     EmitBrushes( buildBrush, NULL, NULL );
1074 +                                               buildBrush->next = entities[ mapEntityNum ].brushes;
1075 +                                               entities[ mapEntityNum ].brushes = buildBrush;
1076 +                                               entities[ mapEntityNum ].numBrushes++;
1077 +                                       }
1078 +                                       else
1079 +                                               free( buildBrush );
1080                                 }
1081                         }
1082                 }
1083 Index: tools/quake3/q3map2/map.c
1084 ===================================================================
1085 --- tools/quake3/q3map2/map.c   (revision 193)
1086 +++ tools/quake3/q3map2/map.c   (working copy)
1087 @@ -184,7 +184,7 @@
1088  snaps a plane to normal/distance epsilons
1089  */
1090  
1091 -void SnapPlane( vec3_t normal, vec_t *dist )
1092 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
1093  {
1094  // SnapPlane disabled by LordHavoc because it often messes up collision
1095  // brushes made from triangles of embedded models, and it has little effect
1096 @@ -193,7 +193,13 @@
1097    SnapPlane reenabled by namespace because of multiple reports of
1098    q3map2-crashes which were triggered by this patch.
1099  */
1100 +       // div0: ensure the point "center" stays on the plane (actually, this
1101 +       // rotates the plane around the point center).
1102 +       // if center lies on the plane, it is guaranteed to stay on the plane by
1103 +       // this fix.
1104 +       vec_t centerDist = DotProduct(normal, center);
1105         SnapNormal( normal );
1106 +       *dist += (DotProduct(normal, center) - centerDist);
1107  
1108         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1109                 *dist = Q_rint( *dist );
1110 @@ -207,7 +213,7 @@
1111  must be within an epsilon distance of the plane
1112  */
1113  
1114 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
1115 +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?
1116  
1117  #ifdef USE_HASHING
1118  
1119 @@ -215,10 +221,14 @@
1120         int             i, j, hash, h;
1121         plane_t *p;
1122         vec_t   d;
1123 +       vec3_t centerofweight;
1124 +
1125 +       VectorClear(centerofweight);
1126 +       for(i = 0; i < numPoints; ++i)
1127 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1128         
1129 -       
1130         /* hash the plane */
1131 -       SnapPlane( normal, &dist );
1132 +       SnapPlane( normal, &dist, centerofweight );
1133         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1134         
1135         /* search the border bins as well */
1136 @@ -259,7 +269,13 @@
1137         plane_t *p;
1138         
1139  
1140 -       SnapPlane( normal, &dist );
1141 +       vec3_t centerofweight;
1142 +
1143 +       VectorClear(centerofweight);
1144 +       for(i = 0; i < numPoints; ++i)
1145 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1146 +       
1147 +       SnapPlane( normal, &dist, centerofweight );
1148         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
1149         {
1150                 if( PlaneEqual( p, normal, dist ) )
1151 Index: tools/quake3/q3map2/shaders.c
1152 ===================================================================
1153 --- tools/quake3/q3map2/shaders.c       (revision 191)
1154 +++ tools/quake3/q3map2/shaders.c       (working copy)
1155 @@ -793,8 +793,14 @@
1156         }
1157         
1158         if( VectorLength( si->color ) <= 0.0f )
1159 +       {
1160                 ColorNormalize( color, si->color );
1161 -       VectorScale( color, (1.0f / count), si->averageColor );
1162 +               VectorScale( color, (1.0f / count), si->averageColor );
1163 +       }
1164 +       else
1165 +       {
1166 +               VectorCopy( si->color, si->averageColor );
1167 +       }
1168  }
1169  
1170  
1171 Index: tools/quake3/q3map2/light_ydnar.c
1172 ===================================================================
1173 --- tools/quake3/q3map2/light_ydnar.c   (revision 191)
1174 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1175 @@ -1767,6 +1864,8 @@
1176         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1177         trace_t                         trace;
1178         float                           stackLightLuxels[ STACK_LL_SIZE ];
1179 +       vec3_t                          flood;
1180 +       float                           *floodlight;
1181         
1182         
1183         /* bail if this number exceeds the number of raw lightmaps */
1184 @@ -2223,6 +2332,78 @@
1185         FreeTraceLights( &trace );
1186         
1187         /*      -----------------------------------------------------------------
1188 +               floodlight pass
1189 +               ----------------------------------------------------------------- */
1190 +
1191 +       if( floodlighty )
1192 +       {
1193 +               /* walk lightmaps */
1194 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1195 +               {
1196 +                       /* early out */
1197 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1198 +                               continue;
1199 +                       
1200 +                       /* apply floodlight to each luxel */
1201 +                       for( y = 0; y < lm->sh; y++ )
1202 +                       {
1203 +                               for( x = 0; x < lm->sw; x++ )
1204 +                               {
1205 +                                       /* get cluster */
1206 +                                       cluster = SUPER_CLUSTER( x, y );
1207 +                                       //%     if( *cluster < 0 )
1208 +                                       //%             continue;
1209 +                                       
1210 +                                       /* get particulars */
1211 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1212 +                                       floodlight = SUPER_FLOODLIGHT( x, y );
1213 +                                       
1214 +                                       flood[0]=floodlightRGB[0]*floodlightIntensity;
1215 +                                       flood[1]=floodlightRGB[1]*floodlightIntensity;
1216 +                                       flood[2]=floodlightRGB[2]*floodlightIntensity;
1217 +                                                    
1218 +                                       /* scale light value */
1219 +                                       VectorScale( flood, *floodlight, flood );
1220 +                                       luxel[0]+=flood[0];
1221 +                                       luxel[1]+=flood[1];
1222 +                                       luxel[2]+=flood[2];
1223 +                                       
1224 +                                       if (luxel[3]==0) luxel[3]=1;
1225 +                               }
1226 +                       }
1227 +               }
1228 +       }
1229 +
1230 +       if (debugnormals)
1231 +       {
1232 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1233 +               {
1234 +                       /* early out */
1235 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1236 +                               continue;
1237 +                       
1238 +                       for( y = 0; y < lm->sh; y++ )
1239 +                       {
1240 +                               for( x = 0; x < lm->sw; x++ )
1241 +                               {
1242 +                                       /* get cluster */
1243 +                                       cluster = SUPER_CLUSTER( x, y );
1244 +                                       //%     if( *cluster < 0 )
1245 +                                       //%             continue;
1246 +                                       
1247 +                                       /* get particulars */
1248 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1249 +                                       normal = SUPER_NORMAL (  x, y );
1250 +               
1251 +                                       luxel[0]=(normal[0]*127)+127;
1252 +                                       luxel[1]=(normal[1]*127)+127;
1253 +                                       luxel[2]=(normal[2]*127)+127;
1254 +                               }
1255 +                       }
1256 +               }
1257 +       }
1258 +       
1259 +       /*      -----------------------------------------------------------------
1260                 dirt pass
1261                 ----------------------------------------------------------------- */
1262         
1263 @@ -3587,7 +3768,320 @@
1264         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1265  }
1266  
1267 +/////////////////////////////////////////////////////////////
1268  
1269 +#define FLOODLIGHT_CONE_ANGLE                  88      /* degrees */
1270 +#define FLOODLIGHT_NUM_ANGLE_STEPS             16
1271 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
1272 +#define FLOODLIGHT_NUM_VECTORS                 (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
1273  
1274 +static vec3_t  floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1275 +static int             numFloodVectors = 0;
1276  
1277 +void SetupFloodLight( void )
1278 +{
1279 +       int             i, j;
1280 +       float   angle, elevation, angleStep, elevationStep;
1281 +       const char      *value;
1282 +       double v1,v2,v3,v4,v5;
1283 +       
1284 +       /* note it */
1285 +       Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1286 +       
1287 +       /* calculate angular steps */
1288 +       angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1289 +       elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1290 +       
1291 +       /* iterate angle */
1292 +       angle = 0.0f;
1293 +       for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1294 +       {
1295 +               /* iterate elevation */
1296 +               for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1297 +               {
1298 +                       floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1299 +                       floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1300 +                       floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1301 +                       numFloodVectors++;
1302 +               }
1303 +       }
1304 +       
1305 +       /* emit some statistics */
1306 +       Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1307  
1308 +      /* floodlight */
1309 +       value = ValueForKey( &entities[ 0 ], "_floodlight" );
1310 +       
1311 +       if( value[ 0 ] != '\0' )
1312 +       {
1313 +               v1=v2=v3=0;
1314 +               v4=floodlightDistance;
1315 +               v5=floodlightIntensity;
1316 +               
1317 +               sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1318 +               
1319 +               floodlightRGB[0]=v1;
1320 +               floodlightRGB[1]=v2;
1321 +               floodlightRGB[2]=v3;
1322 +               
1323 +               if (VectorLength(floodlightRGB)==0)
1324 +               {
1325 +                       VectorSet(floodlightRGB,240,240,255);
1326 +               }
1327 +               
1328 +               if (v4<1) v4=1024;
1329 +               if (v5<1) v5=128;
1330 +               
1331 +               floodlightDistance=v4;
1332 +               floodlightIntensity=v5;
1333 +    
1334 +               floodlighty = qtrue;
1335 +               Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1336 +       }
1337 +       else
1338 +       {
1339 +               VectorSet(floodlightRGB,240,240,255);
1340 +               //floodlighty = qtrue;
1341 +               //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1342 +       }
1343 +       VectorNormalize(floodlightRGB,floodlightRGB);
1344 +}
1345 +
1346 +//27 - lighttracer style ambient occlusion light hack.
1347 +//Kudos to the dirtmapping author for most of this source.
1348 +void FloodLightRawLightmap( int rawLightmapNum )
1349 +{
1350 +       int                                     i, x, y, sx, sy, *cluster;
1351 +       float                           *origin, *normal, *floodlight, *floodlight2, average, samples;
1352 +       rawLightmap_t           *lm;
1353 +       surfaceInfo_t           *info;
1354 +       trace_t                         trace;
1355 +       
1356 +       /* bail if this number exceeds the number of raw lightmaps */
1357 +       if( rawLightmapNum >= numRawLightmaps )
1358 +               return;
1359 +       
1360 +       /* get lightmap */
1361 +       lm = &rawLightmaps[ rawLightmapNum ];
1362 +       
1363 +       memset(&trace,0,sizeof(trace_t));
1364 +       /* setup trace */
1365 +       trace.testOcclusion = qtrue;
1366 +       trace.forceSunlight = qfalse;
1367 +       trace.twoSided = qtrue;
1368 +       trace.recvShadows = lm->recvShadows;
1369 +       trace.numSurfaces = lm->numLightSurfaces;
1370 +       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1371 +       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1372 +       trace.testAll = qfalse;
1373 +       trace.distance = 1024;
1374 +       
1375 +       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1376 +       //trace.twoSided = qfalse;
1377 +       for( i = 0; i < trace.numSurfaces; i++ )
1378 +       {
1379 +               /* get surface */
1380 +               info = &surfaceInfos[ trace.surfaces[ i ] ];
1381 +               
1382 +               /* check twosidedness */
1383 +               if( info->si->twoSided )
1384 +               {
1385 +                       trace.twoSided = qtrue;
1386 +                       break;
1387 +               }
1388 +       }
1389 +       
1390 +       /* gather dirt */
1391 +       for( y = 0; y < lm->sh; y++ )
1392 +       {
1393 +               for( x = 0; x < lm->sw; x++ )
1394 +               {
1395 +                       /* get luxel */
1396 +                       cluster = SUPER_CLUSTER( x, y );
1397 +                       origin = SUPER_ORIGIN( x, y );
1398 +                       normal = SUPER_NORMAL( x, y );
1399 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1400 +                       
1401 +                       /* set default dirt */
1402 +                       *floodlight = 0.0f;
1403 +                       
1404 +                       /* only look at mapped luxels */
1405 +                       if( *cluster < 0 )
1406 +                               continue;
1407 +                       
1408 +                       /* copy to trace */
1409 +                       trace.cluster = *cluster;
1410 +                       VectorCopy( origin, trace.origin );
1411 +                       VectorCopy( normal, trace.normal );
1412 +         
1413 +
1414 +               
1415 +                       /* get dirt */
1416 +                       *floodlight = FloodLightForSample( &trace );
1417 +               }
1418 +       }
1419 +       
1420 +       /* testing no filtering */
1421 +       return;
1422 +       
1423 +       /* filter "dirt" */
1424 +       for( y = 0; y < lm->sh; y++ )
1425 +       {
1426 +               for( x = 0; x < lm->sw; x++ )
1427 +               {
1428 +                       /* get luxel */
1429 +                       cluster = SUPER_CLUSTER( x, y );
1430 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1431 +                       
1432 +                       /* filter dirt by adjacency to unmapped luxels */
1433 +                       average = *floodlight;
1434 +                       samples = 1.0f;
1435 +                       for( sy = (y - 1); sy <= (y + 1); sy++ )
1436 +                       {
1437 +                               if( sy < 0 || sy >= lm->sh )
1438 +                                       continue;
1439 +                               
1440 +                               for( sx = (x - 1); sx <= (x + 1); sx++ )
1441 +                               {
1442 +                                       if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1443 +                                               continue;
1444 +                                       
1445 +                                       /* get neighboring luxel */
1446 +                                       cluster = SUPER_CLUSTER( sx, sy );
1447 +                                       floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1448 +                                       if( *cluster < 0 || *floodlight2 <= 0.0f )
1449 +                                               continue;
1450 +                                       
1451 +                                       /* add it */
1452 +                                       average += *floodlight2;
1453 +                                       samples += 1.0f;
1454 +                               }
1455 +                               
1456 +                               /* bail */
1457 +                               if( samples <= 0.0f )
1458 +                                       break;
1459 +                       }
1460 +                       
1461 +                       /* bail */
1462 +                       if( samples <= 0.0f )
1463 +                               continue;
1464 +                       
1465 +                       /* scale dirt */
1466 +                       *floodlight = average / samples;
1467 +               }
1468 +       }
1469 +}
1470 +
1471 +/*
1472 +FloodLightForSample()
1473 +calculates floodlight value for a given sample
1474 +once again, kudos to the dirtmapping coder
1475 +*/
1476 +float FloodLightForSample( trace_t *trace )
1477 +{
1478 +       int             i;
1479 +       float   d;
1480 +       float   contribution;
1481 +       int     sub = 0;
1482 +       float   gatherLight, outLight;
1483 +       vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
1484 +       float   dd;
1485 +       int     vecs = 0;
1486
1487 +       gatherLight=0;
1488 +       /* dummy check */
1489 +       //if( !dirty )
1490 +       //      return 1.0f;
1491 +       if( trace == NULL || trace->cluster < 0 )
1492 +               return 0.0f;
1493 +       
1494 +
1495 +       /* setup */
1496 +       dd = floodlightDistance;
1497 +       VectorCopy( trace->normal, normal );
1498 +       
1499 +       /* check if the normal is aligned to the world-up */
1500 +       if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1501 +       {
1502 +               if( normal[ 2 ] == 1.0f )               
1503 +               {
1504 +                       VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1505 +                       VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1506 +               }
1507 +               else if( normal[ 2 ] == -1.0f )
1508 +               {
1509 +                       VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1510 +                       VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1511 +               }
1512 +       }
1513 +       else
1514 +       {
1515 +               VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1516 +               CrossProduct( normal, worldUp, myRt );
1517 +               VectorNormalize( myRt, myRt );
1518 +               CrossProduct( myRt, normal, myUp );
1519 +               VectorNormalize( myUp, myUp );
1520 +       }
1521 +
1522 +       /* iterate through ordered vectors */
1523 +       for( i = 0; i < numFloodVectors; i++ )
1524 +       {
1525 +               if (floodlight_lowquality==qtrue)
1526 +        {
1527 +                       if (rand()%10 != 0 ) continue;
1528 +               }
1529 +
1530 +               vecs++;
1531 +         
1532 +               /* transform vector into tangent space */
1533 +               direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1534 +               direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1535 +               direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1536 +
1537 +               /* set endpoint */
1538 +               VectorMA( trace->origin, dd, direction, trace->end );
1539 +
1540 +               //VectorMA( trace->origin, 1, direction, trace->origin );
1541 +                       
1542 +               SetupTrace( trace );
1543 +               /* trace */
1544 +               TraceLine( trace );
1545 +               contribution=1;
1546 +
1547 +               if (trace->compileFlags & C_SKY )
1548 +               {
1549 +                       contribution=1.0f;
1550 +               }
1551 +               else if ( trace->opaque )
1552 +               {
1553 +                       VectorSubtract( trace->hit, trace->origin, displacement );
1554 +                       d=VectorLength( displacement );
1555 +
1556 +                       // d=trace->distance;            
1557 +                       //if (d>256) gatherDirt+=1;
1558 +                       contribution=d/dd;
1559 +                       if (contribution>1) contribution=1.0f; 
1560 +             
1561 +                       //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1562 +               }
1563 +         
1564 +               gatherLight+=contribution;
1565 +       }
1566 +   
1567 +       /* early out */
1568 +       if( gatherLight <= 0.0f )
1569 +               return 0.0f;
1570 +       
1571 +       sub=vecs;
1572 +
1573 +       if (sub<1) sub=1;
1574 +       gatherLight/=(sub);
1575 +
1576 +       outLight=gatherLight;
1577 +       if( outLight > 1.0f )
1578 +               outLight = 1.0f;
1579 +       
1580 +       /* return to sender */
1581 +       return outLight;
1582 +}
1583 +
1584 Index: tools/quake3/q3map2/light.c
1585 ===================================================================
1586 --- tools/quake3/q3map2/light.c (revision 191)
1587 +++ tools/quake3/q3map2/light.c (working copy)
1588 @@ -1378,6 +1378,56 @@
1589                         break;
1590         }
1591         
1592 +       /////// Floodlighting for point //////////////////
1593 +       //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1594 +       if (floodlighty)
1595 +       {
1596 +               int q;
1597 +               float addSize,f;
1598 +               vec3_t col,dir;
1599 +               col[0]=col[1]=col[2]=floodlightIntensity;
1600 +               dir[0]=dir[1]=0;
1601 +               dir[2]=1;
1602 +      
1603 +               trace.testOcclusion = qtrue;
1604 +               trace.forceSunlight = qfalse;
1605 +               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1606 +               trace.testAll = qtrue;     
1607 +      
1608 +               for (q=0;q<2;q++)
1609 +               {
1610 +                       if (q==0) //upper hemisphere
1611 +                       {
1612 +                               trace.normal[0]=0;
1613 +                               trace.normal[1]=0;
1614 +                               trace.normal[2]=1;
1615 +                       }
1616 +                       else //lower hemisphere
1617 +                       {
1618 +                               trace.normal[0]=0;
1619 +                               trace.normal[1]=0;
1620 +                               trace.normal[2]=-1;
1621 +                       }
1622 +
1623 +                       f = FloodLightForSample(&trace);
1624 +
1625 +                       contributions[ numCon ].color[0]=col[0]*f;
1626 +                       contributions[ numCon ].color[1]=col[1]*f;
1627 +                       contributions[ numCon ].color[2]=col[2]*f;
1628 +
1629 +                       contributions[ numCon ].dir[0]=dir[0];
1630 +                       contributions[ numCon ].dir[1]=dir[1];
1631 +                       contributions[ numCon ].dir[2]=dir[2];
1632 +
1633 +                       contributions[ numCon ].style = 0;
1634 +                       numCon++;               
1635 +                       /* push average direction around */
1636 +                       addSize = VectorLength( col );
1637 +                       VectorMA( gp->dir, addSize, dir, gp->dir );
1638 +               }
1639 +       }
1640 +       /////////////////////
1641 +
1642         /* normalize to get primary light direction */
1643         VectorNormalize( gp->dir, gp->dir );
1644         
1645 @@ -1661,6 +1711,12 @@
1646                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1647         }
1648         
1649 +       /* floodlight them up */
1650 +       if( floodlighty )
1651 +       {
1652 +               Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1653 +               RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1654 +       }
1655  
1656         /* ydnar: set up light envelopes */
1657         SetupEnvelopes( qfalse, fast );
1658 @@ -1703,6 +1759,7 @@
1659                 /* flag bouncing */
1660                 bouncing = qtrue;
1661                 VectorClear( ambientColor );
1662 +               floodlighty = false;
1663                 
1664                 /* generate diffuse lights */
1665                 RadFreeLights();
1666 @@ -2191,6 +2256,21 @@
1667                         cpmaHack = qtrue;
1668                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
1669                 }
1670 +               else if( !strcmp( argv[ i ], "-floodlight" ) )
1671 +               {
1672 +                       floodlighty = qtrue;
1673 +                       Sys_Printf( "FloodLighting enabled\n" );
1674 +               }
1675 +               else if( !strcmp( argv[ i ], "-debugnormals" ) )
1676 +               {
1677 +                       debugnormals = qtrue;
1678 +                       Sys_Printf( "DebugNormals enabled\n" );
1679 +               }
1680 +               else if( !strcmp( argv[ i ], "-lowquality" ) )
1681 +               {
1682 +                       floodlight_lowquality = qtrue;
1683 +                       Sys_Printf( "Low Quality FloodLighting enabled\n" );
1684 +               }
1685                 
1686                 /* r7: dirtmapping */
1687                 else if( !strcmp( argv[ i ], "-dirty" ) )
1688 @@ -2279,6 +2359,7 @@
1689         /* ydnar: set up optimization */
1690         SetupBrushes();
1691         SetupDirt();
1692 +       SetupFloodLight();
1693         SetupSurfaceLightmaps();
1694         
1695         /* initialize the surface facet tracing */
1696 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1697 ===================================================================
1698 --- tools/quake3/q3map2/lightmaps_ydnar.c       (revision 191)
1699 +++ tools/quake3/q3map2/lightmaps_ydnar.c       (working copy)
1700 @@ -414,6 +414,12 @@
1701                 lm->superNormals = safe_malloc( size );
1702         memset( lm->superNormals, 0, size );
1703         
1704 +       /* allocate floodlight map storage */
1705 +       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1706 +       if( lm->superFloodLight == NULL )
1707 +               lm->superFloodLight = safe_malloc( size );
1708 +       memset( lm->superFloodLight, 0, size );
1709 +       
1710         /* allocate cluster map storage */
1711         size = lm->sw * lm->sh * sizeof( int );
1712         if( lm->superClusters == NULL )
1713 Index: tools/quake3/q3map2/q3map2.h
1714 ===================================================================
1715 --- tools/quake3/q3map2/q3map2.h        (revision 191)
1716 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1717 @@ -267,6 +267,7 @@
1718  #define SUPER_NORMAL_SIZE              4
1719  #define SUPER_DELUXEL_SIZE             3
1720  #define BSP_DELUXEL_SIZE               3
1721 +#define SUPER_FLOODLIGHT_SIZE  1
1722  
1723  #define VERTEX_LUXEL( s, v )   (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1724  #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1725 @@ -279,6 +280,7 @@
1726  #define SUPER_ORIGIN( x, y )   (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1727  #define SUPER_NORMAL( x, y )   (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1728  #define SUPER_DIRT( x, y )             (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3)   /* stash dirtyness in normal[ 3 ] */
1729 +#define SUPER_FLOODLIGHT( x, y )       (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )       
1730  
1731  
1732  
1733 @@ -1392,6 +1395,7 @@
1734         
1735         float                                   *superDeluxels; /* average light direction */
1736         float                                   *bspDeluxels;
1737 +       float                                   *superFloodLight; 
1738  }
1739  rawLightmap_t;
1740  
1741 @@ -1704,6 +1708,10 @@
1742  float                                          DirtForSample( trace_t *trace );
1743  void                                           DirtyRawLightmap( int num );
1744  
1745 +void                                           SetupFloodLight();
1746 +float                                          FloodLightForSample( trace_t *trace );
1747 +void                                           FloodLightRawLightmap( int num );
1748 +
1749  void                                           IlluminateRawLightmap( int num );
1750  void                                           IlluminateVertexes( int num );
1751  
1752 @@ -2098,6 +2106,13 @@
1753  Q_EXTERN float                         dirtScale Q_ASSIGN( 1.0f );
1754  Q_EXTERN float                         dirtGain Q_ASSIGN( 1.0f );
1755  
1756 +Q_EXTERN qboolean                      debugnormals Q_ASSIGN( qfalse );
1757 +Q_EXTERN qboolean                      floodlighty Q_ASSIGN( qfalse );
1758 +Q_EXTERN qboolean                      floodlight_lowquality Q_ASSIGN( qfalse );
1759 +Q_EXTERN vec3_t                                floodlightRGB;
1760 +Q_EXTERN float                         floodlightIntensity Q_ASSIGN( 512 );
1761 +Q_EXTERN float                         floodlightDistance Q_ASSIGN( 1024 );
1762 +
1763  Q_EXTERN qboolean                      dump Q_ASSIGN( qfalse );
1764  Q_EXTERN qboolean                      debug Q_ASSIGN( qfalse );
1765  Q_EXTERN qboolean                      debugUnused Q_ASSIGN( qfalse );
1766 Index: tools/quake3/q3map2/game_ja.h
1767 ===================================================================
1768 --- tools/quake3/q3map2/game_ja.h       (revision 191)
1769 +++ tools/quake3/q3map2/game_ja.h       (working copy)
1770 @@ -67,6 +67,7 @@
1771         qfalse,                         /* wolf lighting model? */
1772         128,                            /* lightmap width/height */
1773         1.0f,                           /* lightmap gamma */
1774 +       1.0f,                           /* lightmap exposure */
1775         1.0f,                           /* lightmap compensate */
1776         "RBSP",                         /* bsp file prefix */
1777         1,                                      /* bsp file version */
1778 Index: tools/quake3/q3map2/game_tremulous.h
1779 ===================================================================
1780 --- tools/quake3/q3map2/game_tremulous.h        (revision 191)
1781 +++ tools/quake3/q3map2/game_tremulous.h        (working copy)
1782 @@ -70,6 +70,7 @@
1783         qfalse,                         /* wolf lighting model? */
1784         128,                            /* lightmap width/height */
1785         1.0f,                           /* lightmap gamma */
1786 +       1.0f,                           /* lightmap exposure */
1787         1.0f,                           /* lightmap compensate */
1788         "IBSP",                         /* bsp file prefix */
1789         46,                                     /* bsp file version */
1790 Index: tools/quake3/q3map2/game_wolfet.h
1791 ===================================================================
1792 --- tools/quake3/q3map2/game_wolfet.h   (revision 191)
1793 +++ tools/quake3/q3map2/game_wolfet.h   (working copy)
1794 @@ -66,6 +66,7 @@
1795         qtrue,                          /* wolf lighting model? */
1796         128,                            /* lightmap width/height */
1797         1.0f,                           /* lightmap gamma */
1798 +       1.0f,                           /* lightmap exposure */
1799         1.0f,                           /* lightmap compensate */
1800         "IBSP",                         /* bsp file prefix */
1801         47,                                     /* bsp file version */
1802 Index: tools/quake3/q3map2/game_wolf.h
1803 ===================================================================
1804 --- tools/quake3/q3map2/game_wolf.h     (revision 191)
1805 +++ tools/quake3/q3map2/game_wolf.h     (working copy)
1806 @@ -129,6 +129,7 @@
1807         qtrue,                          /* wolf lighting model? */
1808         128,                            /* lightmap width/height */
1809         1.0f,                           /* lightmap gamma */
1810 +       1.0f,                           /* lightmap exposure */
1811         1.0f,                           /* lightmap compensate */
1812         "IBSP",                         /* bsp file prefix */
1813         47,                                     /* bsp file version */
1814 Index: tools/quake3/q3map2/game_sof2.h
1815 ===================================================================
1816 --- tools/quake3/q3map2/game_sof2.h     (revision 191)
1817 +++ tools/quake3/q3map2/game_sof2.h     (working copy)
1818 @@ -139,6 +139,7 @@
1819         qfalse,                                 /* wolf lighting model? */
1820         128,                                    /* lightmap width/height */
1821         1.0f,                                   /* lightmap gamma */
1822 +       1.0f,                                   /* lightmap exposure */
1823         1.0f,                                   /* lightmap compensate */
1824         "RBSP",                                 /* bsp file prefix */
1825         1,                                              /* bsp file version */
1826 Index: tools/quake3/q3map2/game_etut.h
1827 ===================================================================
1828 --- tools/quake3/q3map2/game_etut.h     (revision 191)
1829 +++ tools/quake3/q3map2/game_etut.h     (working copy)
1830 @@ -148,6 +148,7 @@
1831         qfalse,                         /* wolf lighting model? */
1832         128,                            /* lightmap width/height */
1833         2.2f,                           /* lightmap gamma */
1834 +       1.0f,                           /* lightmap exposure */
1835         1.0f,                           /* lightmap compensate */
1836         "IBSP",                         /* bsp file prefix */
1837         47,                                     /* bsp file version */
1838 Index: tools/quake3/q3map2/game_jk2.h
1839 ===================================================================
1840 --- tools/quake3/q3map2/game_jk2.h      (revision 191)
1841 +++ tools/quake3/q3map2/game_jk2.h      (working copy)
1842 @@ -64,6 +64,7 @@
1843         qfalse,                         /* wolf lighting model? */
1844         128,                            /* lightmap width/height */
1845         1.0f,                           /* lightmap gamma */
1846 +       1.0f,                           /* lightmap exposure */
1847         1.0f,                           /* lightmap compensate */
1848         "RBSP",                         /* bsp file prefix */
1849         1,                                      /* bsp file version */
1850 Index: tools/quake3/q3map2/game_qfusion.h
1851 ===================================================================
1852 --- tools/quake3/q3map2/game_qfusion.h  (revision 191)
1853 +++ tools/quake3/q3map2/game_qfusion.h  (working copy)
1854 @@ -115,6 +115,7 @@
1855         qfalse,                         /* wolf lighting model? */
1856         512,                            /* lightmap width/height */
1857         1.0f,                           /* lightmap gamma */
1858 +       1.0f,                           /* lightmap exposure */
1859         1.0f,                           /* lightmap compensate */
1860         "FBSP",                         /* bsp file prefix */
1861         1,                                      /* bsp file version */
1862 Index: tools/quake3/q3map2/game_tenebrae.h
1863 ===================================================================
1864 --- tools/quake3/q3map2/game_tenebrae.h (revision 191)
1865 +++ tools/quake3/q3map2/game_tenebrae.h (working copy)
1866 @@ -112,6 +112,7 @@
1867         qfalse,                         /* wolf lighting model? */
1868         512,                            /* lightmap width/height */
1869         2.0f,                           /* lightmap gamma */
1870 +       1.0f,                           /* lightmap exposure */
1871         1.0f,                           /* lightmap compensate */
1872         "IBSP",                         /* bsp file prefix */
1873         46,                                     /* bsp file version */
1874 Index: tools/quake3/q3map2/game_quake3.h
1875 ===================================================================
1876 --- tools/quake3/q3map2/game_quake3.h   (revision 191)
1877 +++ tools/quake3/q3map2/game_quake3.h   (working copy)
1878 @@ -112,6 +112,7 @@
1879         qfalse,                         /* wolf lighting model? */
1880         128,                            /* lightmap width/height */
1881         1.0f,                           /* lightmap gamma */
1882 +       1.0f,                           /* lightmap exposure */
1883         1.0f,                           /* lightmap compensate */
1884         "IBSP",                         /* bsp file prefix */
1885         46,                                     /* bsp file version */
1886 Index: tools/quake3/q3map2/game_ef.h
1887 ===================================================================
1888 --- tools/quake3/q3map2/game_ef.h       (revision 191)
1889 +++ tools/quake3/q3map2/game_ef.h       (working copy)
1890 @@ -113,6 +113,7 @@
1891         qfalse,                         /* wolf lighting model? */
1892         128,                            /* lightmap width/height */
1893         1.0f,                           /* lightmap gamma */
1894 +       1.0f,                           /* lightmap exposure */
1895         1.0f,                           /* lightmap compensate */
1896         "IBSP",                         /* bsp file prefix */
1897         46,                                     /* bsp file version */
1898 Index: tools/quake3/q3map2/light_ydnar.c
1899 ===================================================================
1900 --- tools/quake3/q3map2/light_ydnar.c   (revision 191)
1901 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1902 @@ -49,6 +49,7 @@
1903         int             i;
1904         float   max, gamma;
1905         vec3_t  sample;
1906 +       float   inv, dif;
1907         
1908         
1909         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
1910 @@ -72,16 +73,51 @@
1911                 /* gamma */
1912                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
1913         }
1914 +
1915 +       if (lightmapExposure == 1)
1916 +       {
1917 +               /* clamp with color normalization */
1918 +               max = sample[ 0 ];
1919 +               if( sample[ 1 ] > max )
1920 +                       max = sample[ 1 ];
1921 +               if( sample[ 2 ] > max )
1922 +                       max = sample[ 2 ];
1923 +               if( max > 255.0f )
1924 +                       VectorScale( sample, (255.0f / max), sample );
1925 +       }
1926 +       else
1927 +       {
1928 +               if (lightmapExposure==0)
1929 +               {
1930 +                       lightmapExposure=1.0f;
1931 +               }
1932 +               inv=1.f/lightmapExposure;
1933 +               //Exposure
1934 +       
1935 +               max = sample[ 0 ];
1936 +               if( sample[ 1 ] > max )
1937 +                       max = sample[ 1 ];
1938 +               if( sample[ 2 ] > max )
1939 +                       max = sample[ 2 ];  
1940 +      
1941 +               dif = (1-  exp(-max * inv) )  *  255;
1942 +
1943 +               if (max >0) 
1944 +               {
1945 +                       dif = dif / max;
1946 +               }
1947 +               else
1948 +               {
1949 +                       dif = 0;
1950 +               }
1951 +
1952 +               for (i=0;i<3;i++)
1953 +               {
1954 +                       sample[i]*=dif;
1955 +               }
1956 +       }
1957 +
1958         
1959 -       /* clamp with color normalization */
1960 -       max = sample[ 0 ];
1961 -       if( sample[ 1 ] > max )
1962 -               max = sample[ 1 ];
1963 -       if( sample[ 2 ] > max )
1964 -               max = sample[ 2 ];
1965 -       if( max > 255.0f )
1966 -               VectorScale( sample, (255.0f / max), sample );
1967 -       
1968         /* compensate for ingame overbrighting/bitshifting */
1969         VectorScale( sample, (1.0f / lightmapCompensate), sample );
1970         
1971 Index: tools/quake3/q3map2/light.c
1972 ===================================================================
1973 --- tools/quake3/q3map2/light.c (revision 191)
1974 +++ tools/quake3/q3map2/light.c (working copy)
1975 @@ -1836,6 +1893,14 @@
1976                         i++;
1977                 }
1978                 
1979 +               else if( !strcmp( argv[ i ], "-exposure" ) )
1980 +               {
1981 +                       f = atof( argv[ i + 1 ] );
1982 +                       lightmapExposure = f;
1983 +                       Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
1984 +                       i++;
1985 +               }
1986 +               
1987                 else if( !strcmp( argv[ i ], "-compensate" ) )
1988                 {
1989                         f = atof( argv[ i + 1 ] );
1990 Index: tools/quake3/q3map2/q3map2.h
1991 ===================================================================
1992 --- tools/quake3/q3map2/q3map2.h        (revision 191)
1993 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1994 @@ -543,6 +545,7 @@
1995         qboolean                        wolfLight;                                              /* when true, lights work like wolf q3map  */
1996         int                                     lightmapSize;                                   /* bsp lightmap width/height */
1997         float                           lightmapGamma;                                  /* default lightmap gamma */
1998 +       float                           lightmapExposure;                               /* default lightmap exposure */
1999         float                           lightmapCompensate;                             /* default lightmap compensate value */
2000         char                            *bspIdent;                                              /* 4-letter bsp file prefix */
2001         int                                     bspVersion;                                             /* bsp version to use */
2002 @@ -2117,6 +2132,7 @@
2003  
2004  /* ydnar: lightmap gamma/compensation */
2005  Q_EXTERN float                         lightmapGamma Q_ASSIGN( 1.0f );
2006 +Q_EXTERN float                         lightmapExposure Q_ASSIGN( 1.0f );
2007  Q_EXTERN float                         lightmapCompensate Q_ASSIGN( 1.0f );
2008  
2009  /* ydnar: for runtime tweaking of falloff tolerance */
2010 Index: tools/quake3/q3map2/light_ydnar.c
2011 ===================================================================
2012 --- tools/quake3/q3map2/light_ydnar.c   (revision 191)
2013 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
2014 @@ -384,7 +420,7 @@
2015  #define NUDGE                  0.5f
2016  #define BOGUS_NUDGE            -99999.0f
2017  
2018 -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 ] )
2019 +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 ] )
2020  {
2021         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
2022         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
2023 @@ -392,6 +428,12 @@
2024         vec3_t                  pNormal;
2025         vec3_t                  vecs[ 3 ];
2026         vec3_t                  nudged;
2027 +       vec3_t                  cverts[ 3 ];
2028 +       vec3_t                  temp;
2029 +       vec4_t                  sideplane, hostplane;
2030 +       vec3_t                  origintwo;
2031 +       int                             j, next;
2032 +       float                   e;
2033         float                   *nudge;
2034         static float    nudges[][ 2 ] =
2035                                         {
2036 @@ -485,6 +527,51 @@
2037         /* non axial lightmap projection (explicit xyz) */
2038         else
2039                 VectorCopy( dv->xyz, origin );
2040 +
2041 +       //////////////////////
2042 +       //27's test to make sure samples stay within the triangle boundaries
2043 +       //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
2044 +       //2) if it does, nudge it onto the correct side.
2045 +
2046 +       if (worldverts!=NULL)
2047 +       {
2048 +               for (j=0;j<3;j++)
2049 +               {
2050 +                       VectorCopy(worldverts[j],cverts[j]);    
2051 +               }
2052 +               PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2053 +
2054 +               for (j=0;j<3;j++)
2055 +               {
2056 +                       for (i=0;i<3;i++)
2057 +                       {
2058 +                               //build plane using 2 edges and a normal
2059 +                               next=(i+1)%3;
2060 +
2061 +                               VectorCopy(cverts[next],temp);
2062 +                               VectorAdd(temp,hostplane,temp);
2063 +                               PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2064 +
2065 +                               //planetest sample point  
2066 +                               e=DotProduct(origin,sideplane);
2067 +                               e=e-sideplane[3];
2068 +                               if (e>0)
2069 +                               {
2070 +                                       //we're bad.
2071 +                                       //VectorClear(origin);
2072 +                                       //Move the sample point back inside triangle bounds
2073 +                                       origin[0]-=sideplane[0]*(e+1);
2074 +                                       origin[1]-=sideplane[1]*(e+1);
2075 +                                       origin[2]-=sideplane[2]*(e+1);
2076 +#ifdef DEBUG_27_1
2077 +                                       VectorClear(origin);
2078 +#endif 
2079 +                               }
2080 +                       }
2081 +               }
2082 +       }
2083 +
2084 +       ////////////////////////
2085         
2086         /* planar surfaces have precalculated lightmap vectors for nudging */
2087         if( lm->plane != NULL )
2088 @@ -516,8 +603,13 @@
2089         else
2090                 origin[ lm->axisNum ] += lightmapSampleOffset;
2091         
2092 +       VectorCopy(origin,origintwo);
2093 +       origintwo[0]+=vecs[2][0];
2094 +       origintwo[1]+=vecs[2][1];
2095 +       origintwo[2]+=vecs[2][2];
2096 +       
2097         /* get cluster */
2098 -       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2099 +       pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2100         
2101         /* another retarded hack, storing nudge count in luxel[ 1 ] */
2102         luxel[ 1 ] = 0.0f;      
2103 @@ -533,14 +625,14 @@
2104                         for( i = 0; i < 3; i++ )
2105                         {
2106                                 /* set nudged point*/
2107 -                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2108 +                               nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2109                         }
2110                         nudge += 2;
2111                         
2112                         /* get pvs cluster */
2113                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
2114 -                       if( pointCluster >= 0 ) 
2115 -                               VectorCopy( nudged, origin );
2116 +                       //if( pointCluster >= 0 )       
2117 +                       //      VectorCopy( nudged, origin );
2118                         luxel[ 1 ] += 1.0f;
2119                 }
2120         }
2121 @@ -550,8 +642,8 @@
2122         {
2123                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
2124                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
2125 -               if( pointCluster >= 0 )
2126 -                       VectorCopy( nudged, origin );
2127 +               //if( pointCluster >= 0 )
2128 +               //      VectorCopy( nudged, origin );
2129                 luxel[ 1 ] += 1.0f;
2130         }
2131         
2132 @@ -597,7 +689,7 @@
2133  than the distance between two luxels (thanks jc :)
2134  */
2135  
2136 -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 ] )
2137 +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 ] )
2138  {
2139         bspDrawVert_t   mid, *dv2[ 3 ];
2140         int                             max;
2141 @@ -645,7 +737,7 @@
2142         
2143         /* split the longest edge and map it */
2144         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
2145 -       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
2146 +       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
2147         
2148         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
2149         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
2150 @@ -653,12 +745,12 @@
2151         /* recurse to first triangle */
2152         VectorCopy( dv, dv2 );
2153         dv2[ max ] = &mid;
2154 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2155 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2156         
2157         /* recurse to second triangle */
2158         VectorCopy( dv, dv2 );
2159         dv2[ (max + 1) % 3 ] = &mid;
2160 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2161 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2162  }
2163  
2164  
2165 @@ -674,6 +766,7 @@
2166         int                             i;
2167         vec4_t                  plane;
2168         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2169 +       vec3_t                  worldverts[ 3 ];
2170         
2171         
2172         /* get plane if possible */
2173 @@ -699,16 +792,20 @@
2174                 ttv = NULL;
2175         }
2176         
2177 +       VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2178 +       VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2179 +       VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
2180 +       
2181         /* map the vertexes */
2182 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2183 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2184 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2185 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
2186 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
2187 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
2188         
2189         /* 2002-11-20: prefer axial triangle edges */
2190         if( mapNonAxial )
2191         {
2192                 /* subdivide the triangle */
2193 -               MapTriangle_r( lm, info, dv, plane, stv, ttv );
2194 +               MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2195                 return qtrue;
2196         }
2197         
2198 @@ -730,7 +827,7 @@
2199                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
2200                         
2201                         /* map the degenerate triangle */
2202 -                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2203 +                       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2204                 }
2205         }
2206         
2207 @@ -792,8 +889,8 @@
2208         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
2209         
2210         /* map the vertexes */
2211 -       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
2212 -       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
2213 +       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
2214 +       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
2215         
2216         /* 0 and 2 */
2217         if( max == 0 )
2218 @@ -878,10 +975,10 @@
2219         }
2220         
2221         /* map the vertexes */
2222 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2223 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2224 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2225 -       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
2226 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
2227 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
2228 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
2229 +       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
2230         
2231         /* subdivide the quad */
2232         MapQuad_r( lm, info, dv, plane, stv, ttv );
2233 @@ -1173,7 +1270,7 @@
2234                                         continue;
2235                                 
2236                                 /* map the fake vert */
2237 -                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
2238 +                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
2239                         }
2240                 }
2241         }
2242 @@ -1963,22 +2062,32 @@
2243                                         deluxel = SUPER_DELUXEL( x, y );
2244                                         origin = SUPER_ORIGIN( x, y );
2245                                         normal = SUPER_NORMAL( x, y );
2246 -                                       
2247 -                                       /* set contribution count */
2248 -                                       lightLuxel[ 3 ] = 1.0f;
2249 -                                       
2250 -                                       /* setup trace */
2251 -                                       trace.cluster = *cluster;
2252 -                                       VectorCopy( origin, trace.origin );
2253 -                                       VectorCopy( normal, trace.normal );
2254 -                                       
2255 -                                       /* get light for this sample */
2256 -                                       LightContributionToSample( &trace );
2257 -                                       VectorCopy( trace.color, lightLuxel );
2258 -                                       
2259 -                                       /* add to count */
2260 -                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2261 +
2262 +                                       ////////// 27's temp hack for testing edge clipping ////
2263 +                                       if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2264 +                                       {
2265 +                                               lightLuxel[ 1 ] = 255;
2266 +                                               lightLuxel[ 3 ] = 1.0f;
2267                                                 totalLighted++;
2268 +                                       }
2269 +                                       else
2270 +                                       {
2271 +                                               /* set contribution count */
2272 +                                               lightLuxel[ 3 ] = 1.0f;
2273 +                                               
2274 +                                               /* setup trace */
2275 +                                               trace.cluster = *cluster;
2276 +                                               VectorCopy( origin, trace.origin );
2277 +                                               VectorCopy( normal, trace.normal );
2278 +                                               
2279 +                                               /* get light for this sample */
2280 +                                               LightContributionToSample( &trace );
2281 +                                               VectorCopy( trace.color, lightLuxel );
2282 +                                               
2283 +                                               /* add to count */
2284 +                                               if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2285 +                                                       totalLighted++;
2286 +                                       }
2287                                         
2288                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2289                                         if( deluxemap )
2290 Index: tools/quake3/q3map2/q3map2.h
2291 ===================================================================
2292 --- tools/quake3/q3map2/q3map2.h        (revision 303)
2293 +++ tools/quake3/q3map2/q3map2.h        (working copy)
2294 @@ -35,8 +35,8 @@
2295  
2296  
2297  /* version */
2298 -#define Q3MAP_VERSION  "2.5.17"
2299 -#define Q3MAP_MOTD             "Last one turns the lights off"
2300 +#define Q3MAP_VERSION  "2.5.17-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck"
2301 +#define Q3MAP_MOTD             "Light some candles, put them on a wooden table, take a photo, and paste it on the lightmaps!"
2302  
2303  
2304  
2305 Index: include/version.default
2306 ===================================================================
2307 --- include/version.default     (revision 290)
2308 +++ include/version.default     (working copy)
2309 @@ -1 +1 @@
2310 -1.4.0\r
2311 +1.4.0-div0-obj-targetname\r