]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
add a trivial patch to write BSP version 46 again
[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.orig        2008-09-06 15:32:05.000000000 +0200
14 +++ libs/picomodel/pm_obj.c     2008-09-06 15:32:09.000000000 +0200
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.orig        2008-09-06 15:32:05.000000000 +0200
117 +++ radiant/map.cpp     2008-09-06 15:32:10.000000000 +0200
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 -
231 -        // check the current map entities for an actual collision
232 -        for (e_target = entities.next; e_target != &entities; e_target = e_target->next)
233 -        {
234 -          if(!strcmp(target, ValueForKey(e_target, "target")))
235 -          {
236 -            bCollision = TRUE;
237 -            // make sure the collision is not between two imported entities
238 -            for(j=0; j<(int)new_ents->len; j++)
239 -            {
240 -              if(e_target == g_ptr_array_index(new_ents, j))
241 -                bCollision = FALSE;
242 -            }
243 -          }
244 -        }
245 -
246 -        // find the matching targeted entity(s)
247 -        if(bCollision)
248 -        {
249 -          for(j=num_ents-1; j>0; j--)
250 -          {
251 -            e_target = (entity_t*)ents->GetAt(j);
252 -            if(e_target != NULL && e_target != e)
253 -            {
254 -              const char *targetname = ValueForKey(e_target, "targetname");
255 -              if( (targetname != NULL) && (strcmp(target, targetname) == 0) )
256 -                g_ptr_array_add(t_ents, (gpointer)e_target);
257 -            }
258 -          }
259 -          if(t_ents->len > 0)
260 -          {
261 -            // link the first to get a unique target/targetname
262 -            Entity_Connect(e, (entity_t*)g_ptr_array_index(t_ents,0));
263 -            // set the targetname of the rest of them manually
264 -            for(j = 1; j < (int)t_ents->len; j++)
265 -              SetKeyValue( (entity_t*)g_ptr_array_index(t_ents, j), "targetname", ValueForKey(e, "target") );
266 -          }
267 -          g_ptr_array_free(t_ents, FALSE);
268 -        }
269 -      }
270 +      // keep a list of ents added to avoid testing collisions against them
271 +      g_ptr_array_add(new_ents, (gpointer)e);
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.orig       2008-09-06 15:32:05.000000000 +0200
299 +++ radiant/drag.cpp    2008-09-06 15:32:10.000000000 +0200
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.orig   2008-09-06 15:32:05.000000000 +0200
358 +++ radiant/xywindow.cpp        2008-09-06 15:32:10.000000000 +0200
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.orig 2008-09-06 15:32:05.000000000 +0200
444 +++ radiant/targetname.cpp      2008-09-06 15:32:10.000000000 +0200
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.orig        2008-09-06 15:32:05.000000000 +0200
539 +++ radiant/qe3.cpp     2008-09-06 15:32:10.000000000 +0200
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.orig  2008-09-06 15:32:05.000000000 +0200
576 +++ radiant/qe3.h       2008-09-06 15:32:10.000000000 +0200
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.orig      2008-09-06 15:32:05.000000000 +0200
598 +++ tools/quake3/q3map2/convert_map.c   2008-09-06 15:32:11.000000000 +0200
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.orig     2008-09-06 15:32:05.000000000 +0200
839 +++ tools/quake3/q3map2/main.c  2008-09-06 15:32:11.000000000 +0200
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/game_quake3.h
860 ===================================================================
861 --- tools/quake3/q3map2/game_quake3.h.orig      2008-09-11 10:59:01.000000000 +0200
862 +++ tools/quake3/q3map2/game_quake3.h   2008-09-11 10:59:07.000000000 +0200
863 @@ -114,7 +114,7 @@
864         1.0f,                           /* lightmap gamma */
865         1.0f,                           /* lightmap compensate */
866         "IBSP",                         /* bsp file prefix */
867 -       47,                                     /* bsp file version */
868 +       46,                                     /* bsp file version */
869         qfalse,                         /* cod-style lump len/ofs order */
870         LoadIBSPFile,           /* bsp load function */
871         WriteIBSPFile,          /* bsp write function */
872 Index: tools/quake3/q3map2/model.c
873 ===================================================================
874 --- tools/quake3/q3map2/model.c.orig    2008-09-06 15:32:05.000000000 +0200
875 +++ tools/quake3/q3map2/model.c 2008-09-06 15:32:12.000000000 +0200
876 @@ -222,6 +222,8 @@
877         byte                            *color;
878         picoIndex_t                     *indexes;
879         remap_t                         *rm, *glob;
880 +       double                          normalEpsilon_save;
881 +       double                          distanceEpsilon_save;
882         
883         
884         /* get model */
885 @@ -398,9 +400,8 @@
886                 /* ydnar: giant hack land: generate clipping brushes for model triangles */
887                 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
888                 {
889 -                       vec3_t          points[ 3 ], backs[ 3 ];
890 +                       vec3_t          points[ 4 ], backs[ 3 ];
891                         vec4_t          plane, reverse, pa, pb, pc;
892 -                       vec3_t          nadir;
893                         
894                         
895                         /* temp hack */
896 @@ -437,90 +438,141 @@
897                                         /* note: this doesn't work as well as simply using the plane of the triangle, below */
898                                         for( k = 0; k < 3; k++ )
899                                         {
900 -                                               if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
901 -                                                       fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
902 +                                               if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
903 +                                                       fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
904                                                 {
905                                                         backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
906                                                         break;
907                                                 }
908                                         }
909                                 }
910 +
911 +                               VectorCopy( points[0], points[3] ); // for cyclic usage
912                                 
913                                 /* make plane for triangle */
914 +                               // div0: add some extra spawnflags:
915 +                               //   0: snap normals to axial planes for extrusion
916 +                               //   8: extrude with the original normals
917 +                               //  16: extrude only with up/down normals (ideal for terrain)
918 +                               //  24: extrude by distance zero (may need engine changes)
919                                 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
920                                 {
921 +                                       vec3_t bestNormal;
922 +                                       float backPlaneDistance = 2;
923 +
924 +                                       if(spawnFlags & 8) // use a DOWN normal
925 +                                       {
926 +                                               if(spawnFlags & 16)
927 +                                               {
928 +                                                       // 24: normal as is, and zero width (broken)
929 +                                                       VectorCopy(plane, bestNormal);
930 +                                               }
931 +                                               else
932 +                                               {
933 +                                                       // 8: normal as is
934 +                                                       VectorCopy(plane, bestNormal);
935 +                                               }
936 +                                       }
937 +                                       else
938 +                                       {
939 +                                               if(spawnFlags & 16)
940 +                                               {
941 +                                                       // 16: UP/DOWN normal
942 +                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
943 +                                               }
944 +                                               else
945 +                                               {
946 +                                                       // 0: axial normal
947 +                                                       if(fabs(plane[0]) > fabs(plane[1])) // x>y
948 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
949 +                                                                       VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
950 +                                                               else // x>y, z>=y
951 +                                                                       if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
952 +                                                                               VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
953 +                                                                       else // z>=x, x>y
954 +                                                                               VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
955 +                                                       else // y>=x
956 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
957 +                                                                       VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
958 +                                                               else // z>=y, y>=x
959 +                                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
960 +                                               }
961 +                                       }
962 +
963 +                                       /* build a brush */
964 +                                       buildBrush = AllocBrush( 48 );
965 +                                       buildBrush->entityNum = mapEntityNum;
966 +                                       buildBrush->original = buildBrush;
967 +                                       buildBrush->contentShader = si;
968 +                                       buildBrush->compileFlags = si->compileFlags;
969 +                                       buildBrush->contentFlags = si->contentFlags;
970 +                                       normalEpsilon_save = normalEpsilon;
971 +                                       distanceEpsilon_save = distanceEpsilon;
972 +                                       if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
973 +                                       {
974 +                                               buildBrush->detail = qfalse;
975 +
976 +                                               // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
977 +                                               if(normalEpsilon > 0)
978 +                                                       normalEpsilon = 0;
979 +                                               if(distanceEpsilon > 0)
980 +                                                       distanceEpsilon = 0;
981 +                                       }
982 +                                       else
983 +                                               buildBrush->detail = qtrue;
984 +
985                                         /* regenerate back points */
986                                         for( j = 0; j < 3; j++ )
987                                         {
988                                                 /* get vertex */
989                                                 dv = &ds->verts[ ds->indexes[ i + j ] ];
990 -                                               
991 -                                               /* copy xyz */
992 -                                               VectorCopy( dv->xyz, backs[ j ] );
993 -                                               
994 -                                               /* find nearest axial to plane normal and push back points opposite */
995 -                                               for( k = 0; k < 3; k++ )
996 -                                               {
997 -                                                       if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
998 -                                                               fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
999 -                                                       {
1000 -                                                               backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
1001 -                                                               break;
1002 -                                                       }
1003 -                                               }
1004 +
1005 +                                               // shift by some units
1006 +                                               VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
1007                                         }
1008 -                                       
1009 +
1010                                         /* make back plane */
1011                                         VectorScale( plane, -1.0f, reverse );
1012 -                                       reverse[ 3 ] = -(plane[ 3 ] - 1);
1013 -                                       
1014 -                                       /* make back pyramid point */
1015 -                                       VectorCopy( points[ 0 ], nadir );
1016 -                                       VectorAdd( nadir, points[ 1 ], nadir );
1017 -                                       VectorAdd( nadir, points[ 2 ], nadir );
1018 -                                       VectorScale( nadir, 0.3333333333333f, nadir );
1019 -                                       VectorMA( nadir, -2.0f, plane, nadir );
1020 -                                       
1021 -                                       /* make 3 more planes */
1022 -                                       //%     if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
1023 -                                       //%             PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
1024 -                                       //%             PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
1025 +                                       reverse[ 3 ] = -plane[ 3 ];
1026 +                                       if((spawnFlags & 24) != 24)
1027 +                                               reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
1028 +                                       // 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)
1029 +
1030                                         if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
1031 -                                               PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1032 -                                               PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1033 +                                                       PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1034 +                                                       PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1035                                         {
1036 -                                               /* build a brush */
1037 -                                               buildBrush = AllocBrush( 48 );
1038 -                                               
1039 -                                               buildBrush->entityNum = mapEntityNum;
1040 -                                               buildBrush->original = buildBrush;
1041 -                                               buildBrush->contentShader = si;
1042 -                                               buildBrush->compileFlags = si->compileFlags;
1043 -                                               buildBrush->contentFlags = si->contentFlags;
1044 -                                               buildBrush->detail = qtrue;
1045 -                                               
1046                                                 /* set up brush sides */
1047                                                 buildBrush->numsides = 5;
1048                                                 for( j = 0; j < buildBrush->numsides; j++ )
1049                                                         buildBrush->sides[ j ].shaderInfo = si;
1050 +
1051                                                 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1052 -                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
1053 -                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
1054 -                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
1055 -                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
1056 -                                               
1057 -                                               /* add to entity */
1058 -                                               if( CreateBrushWindings( buildBrush ) )
1059 -                                               {
1060 -                                                       AddBrushBevels();
1061 -                                                       //%     EmitBrushes( buildBrush, NULL, NULL );
1062 -                                                       buildBrush->next = entities[ mapEntityNum ].brushes;
1063 -                                                       entities[ mapEntityNum ].brushes = buildBrush;
1064 -                                                       entities[ mapEntityNum ].numBrushes++;
1065 -                                               }
1066 -                                               else
1067 -                                                       free( buildBrush );
1068 +                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
1069 +                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
1070 +                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
1071 +                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
1072 +                                       }
1073 +                                       else
1074 +                                       {
1075 +                                               free(buildBrush);
1076 +                                               continue;
1077 +                                       }
1078 +
1079 +                                       normalEpsilon = normalEpsilon_save;
1080 +                                       distanceEpsilon = distanceEpsilon_save;
1081 +
1082 +                                       /* add to entity */
1083 +                                       if( CreateBrushWindings( buildBrush ) )
1084 +                                       {
1085 +                                               AddBrushBevels();
1086 +                                               //%     EmitBrushes( buildBrush, NULL, NULL );
1087 +                                               buildBrush->next = entities[ mapEntityNum ].brushes;
1088 +                                               entities[ mapEntityNum ].brushes = buildBrush;
1089 +                                               entities[ mapEntityNum ].numBrushes++;
1090                                         }
1091 +                                       else
1092 +                                               free( buildBrush );
1093                                 }
1094                         }
1095                 }
1096 Index: tools/quake3/q3map2/map.c
1097 ===================================================================
1098 --- tools/quake3/q3map2/map.c.orig      2008-09-06 15:32:04.000000000 +0200
1099 +++ tools/quake3/q3map2/map.c   2008-09-06 15:32:12.000000000 +0200
1100 @@ -184,7 +184,7 @@
1101  snaps a plane to normal/distance epsilons
1102  */
1103  
1104 -void SnapPlane( vec3_t normal, vec_t *dist )
1105 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
1106  {
1107  // SnapPlane disabled by LordHavoc because it often messes up collision
1108  // brushes made from triangles of embedded models, and it has little effect
1109 @@ -193,7 +193,13 @@
1110    SnapPlane reenabled by namespace because of multiple reports of
1111    q3map2-crashes which were triggered by this patch.
1112  */
1113 +       // div0: ensure the point "center" stays on the plane (actually, this
1114 +       // rotates the plane around the point center).
1115 +       // if center lies on the plane, it is guaranteed to stay on the plane by
1116 +       // this fix.
1117 +       vec_t centerDist = DotProduct(normal, center);
1118         SnapNormal( normal );
1119 +       *dist += (DotProduct(normal, center) - centerDist);
1120  
1121         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1122                 *dist = Q_rint( *dist );
1123 @@ -207,7 +213,7 @@
1124  must be within an epsilon distance of the plane
1125  */
1126  
1127 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
1128 +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?
1129  
1130  #ifdef USE_HASHING
1131  
1132 @@ -215,10 +221,14 @@
1133         int             i, j, hash, h;
1134         plane_t *p;
1135         vec_t   d;
1136 -       
1137 +       vec3_t centerofweight;
1138 +
1139 +       VectorClear(centerofweight);
1140 +       for(i = 0; i < numPoints; ++i)
1141 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1142         
1143         /* hash the plane */
1144 -       SnapPlane( normal, &dist );
1145 +       SnapPlane( normal, &dist, centerofweight );
1146         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1147         
1148         /* search the border bins as well */
1149 @@ -259,7 +269,13 @@
1150         plane_t *p;
1151         
1152  
1153 -       SnapPlane( normal, &dist );
1154 +       vec3_t centerofweight;
1155 +
1156 +       VectorClear(centerofweight);
1157 +       for(i = 0; i < numPoints; ++i)
1158 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1159 +
1160 +       SnapPlane( normal, &dist, centerofweight );
1161         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
1162         {
1163                 if( PlaneEqual( p, normal, dist ) )
1164 Index: tools/quake3/q3map2/shaders.c
1165 ===================================================================
1166 --- tools/quake3/q3map2/shaders.c.orig  2008-09-06 15:32:04.000000000 +0200
1167 +++ tools/quake3/q3map2/shaders.c       2008-09-06 15:32:13.000000000 +0200
1168 @@ -794,8 +794,14 @@
1169         }
1170         
1171         if( VectorLength( si->color ) <= 0.0f )
1172 +       {
1173                 ColorNormalize( color, si->color );
1174 -       VectorScale( color, (1.0f / count), si->averageColor );
1175 +               VectorScale( color, (1.0f / count), si->averageColor );
1176 +       }
1177 +       else
1178 +       {
1179 +               VectorCopy( si->color, si->averageColor );
1180 +       }
1181  }
1182  
1183  
1184 Index: tools/quake3/q3map2/light_ydnar.c
1185 ===================================================================
1186 --- tools/quake3/q3map2/light_ydnar.c.orig      2008-09-06 15:32:04.000000000 +0200
1187 +++ tools/quake3/q3map2/light_ydnar.c   2008-09-06 15:32:14.000000000 +0200
1188 @@ -1767,6 +1767,8 @@
1189         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1190         trace_t                         trace;
1191         float                           stackLightLuxels[ STACK_LL_SIZE ];
1192 +       vec3_t                          flood;
1193 +       float                           *floodlight;
1194         
1195         
1196         /* bail if this number exceeds the number of raw lightmaps */
1197 @@ -2223,6 +2225,78 @@
1198         FreeTraceLights( &trace );
1199         
1200         /*      -----------------------------------------------------------------
1201 +               floodlight pass
1202 +               ----------------------------------------------------------------- */
1203 +
1204 +       if( floodlighty )
1205 +       {
1206 +               /* walk lightmaps */
1207 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1208 +               {
1209 +                       /* early out */
1210 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1211 +                               continue;
1212 +
1213 +                       /* apply floodlight to each luxel */
1214 +                       for( y = 0; y < lm->sh; y++ )
1215 +                       {
1216 +                               for( x = 0; x < lm->sw; x++ )
1217 +                               {
1218 +                                       /* get cluster */
1219 +                                       cluster = SUPER_CLUSTER( x, y );
1220 +                                       //%     if( *cluster < 0 )
1221 +                                       //%             continue;
1222 +
1223 +                                       /* get particulars */
1224 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1225 +                                       floodlight = SUPER_FLOODLIGHT( x, y );
1226 +
1227 +                                       flood[0]=floodlightRGB[0]*floodlightIntensity;
1228 +                                       flood[1]=floodlightRGB[1]*floodlightIntensity;
1229 +                                       flood[2]=floodlightRGB[2]*floodlightIntensity;
1230 +
1231 +                                       /* scale light value */
1232 +                                       VectorScale( flood, *floodlight, flood );
1233 +                                       luxel[0]+=flood[0];
1234 +                                       luxel[1]+=flood[1];
1235 +                                       luxel[2]+=flood[2];
1236 +
1237 +                                       if (luxel[3]==0) luxel[3]=1;
1238 +                               }
1239 +                       }
1240 +               }
1241 +       }
1242 +
1243 +       if (debugnormals)
1244 +       {
1245 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1246 +               {
1247 +                       /* early out */
1248 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1249 +                               continue;
1250 +
1251 +                       for( y = 0; y < lm->sh; y++ )
1252 +                       {
1253 +                               for( x = 0; x < lm->sw; x++ )
1254 +                               {
1255 +                                       /* get cluster */
1256 +                                       cluster = SUPER_CLUSTER( x, y );
1257 +                                       //%     if( *cluster < 0 )
1258 +                                       //%             continue;
1259 +
1260 +                                       /* get particulars */
1261 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1262 +                                       normal = SUPER_NORMAL (  x, y );
1263 +
1264 +                                       luxel[0]=(normal[0]*127)+127;
1265 +                                       luxel[1]=(normal[1]*127)+127;
1266 +                                       luxel[2]=(normal[2]*127)+127;
1267 +                               }
1268 +                       }
1269 +               }
1270 +       }
1271 +
1272 +       /*      -----------------------------------------------------------------
1273                 dirt pass
1274                 ----------------------------------------------------------------- */
1275         
1276 @@ -3587,7 +3661,320 @@
1277         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1278  }
1279  
1280 +/////////////////////////////////////////////////////////////
1281 +
1282 +#define FLOODLIGHT_CONE_ANGLE                  88      /* degrees */
1283 +#define FLOODLIGHT_NUM_ANGLE_STEPS             16
1284 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
1285 +#define FLOODLIGHT_NUM_VECTORS                 (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
1286 +
1287 +static vec3_t  floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1288 +static int             numFloodVectors = 0;
1289 +
1290 +void SetupFloodLight( void )
1291 +{
1292 +       int             i, j;
1293 +       float   angle, elevation, angleStep, elevationStep;
1294 +       const char      *value;
1295 +       double v1,v2,v3,v4,v5;
1296 +
1297 +       /* note it */
1298 +       Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1299 +
1300 +       /* calculate angular steps */
1301 +       angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1302 +       elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1303 +
1304 +       /* iterate angle */
1305 +       angle = 0.0f;
1306 +       for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1307 +       {
1308 +               /* iterate elevation */
1309 +               for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1310 +               {
1311 +                       floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1312 +                       floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1313 +                       floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1314 +                       numFloodVectors++;
1315 +               }
1316 +       }
1317 +
1318 +       /* emit some statistics */
1319 +       Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1320  
1321 +      /* floodlight */
1322 +       value = ValueForKey( &entities[ 0 ], "_floodlight" );
1323  
1324 +       if( value[ 0 ] != '\0' )
1325 +       {
1326 +               v1=v2=v3=0;
1327 +               v4=floodlightDistance;
1328 +               v5=floodlightIntensity;
1329 +
1330 +               sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1331 +
1332 +               floodlightRGB[0]=v1;
1333 +               floodlightRGB[1]=v2;
1334 +               floodlightRGB[2]=v3;
1335 +
1336 +               if (VectorLength(floodlightRGB)==0)
1337 +               {
1338 +                       VectorSet(floodlightRGB,240,240,255);
1339 +               }
1340  
1341 +               if (v4<1) v4=1024;
1342 +               if (v5<1) v5=128;
1343 +
1344 +               floodlightDistance=v4;
1345 +               floodlightIntensity=v5;
1346 +
1347 +               floodlighty = qtrue;
1348 +               Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1349 +       }
1350 +       else
1351 +       {
1352 +               VectorSet(floodlightRGB,240,240,255);
1353 +               //floodlighty = qtrue;
1354 +               //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1355 +       }
1356 +       VectorNormalize(floodlightRGB,floodlightRGB);
1357 +}
1358 +
1359 +//27 - lighttracer style ambient occlusion light hack.
1360 +//Kudos to the dirtmapping author for most of this source.
1361 +void FloodLightRawLightmap( int rawLightmapNum )
1362 +{
1363 +       int                                     i, x, y, sx, sy, *cluster;
1364 +       float                           *origin, *normal, *floodlight, *floodlight2, average, samples;
1365 +       rawLightmap_t           *lm;
1366 +       surfaceInfo_t           *info;
1367 +       trace_t                         trace;
1368 +
1369 +       /* bail if this number exceeds the number of raw lightmaps */
1370 +       if( rawLightmapNum >= numRawLightmaps )
1371 +               return;
1372 +
1373 +       /* get lightmap */
1374 +       lm = &rawLightmaps[ rawLightmapNum ];
1375 +
1376 +       memset(&trace,0,sizeof(trace_t));
1377 +       /* setup trace */
1378 +       trace.testOcclusion = qtrue;
1379 +       trace.forceSunlight = qfalse;
1380 +       trace.twoSided = qtrue;
1381 +       trace.recvShadows = lm->recvShadows;
1382 +       trace.numSurfaces = lm->numLightSurfaces;
1383 +       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1384 +       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1385 +       trace.testAll = qfalse;
1386 +       trace.distance = 1024;
1387 +
1388 +       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1389 +       //trace.twoSided = qfalse;
1390 +       for( i = 0; i < trace.numSurfaces; i++ )
1391 +       {
1392 +               /* get surface */
1393 +               info = &surfaceInfos[ trace.surfaces[ i ] ];
1394 +
1395 +               /* check twosidedness */
1396 +               if( info->si->twoSided )
1397 +               {
1398 +                       trace.twoSided = qtrue;
1399 +                       break;
1400 +               }
1401 +       }
1402 +
1403 +       /* gather dirt */
1404 +       for( y = 0; y < lm->sh; y++ )
1405 +       {
1406 +               for( x = 0; x < lm->sw; x++ )
1407 +               {
1408 +                       /* get luxel */
1409 +                       cluster = SUPER_CLUSTER( x, y );
1410 +                       origin = SUPER_ORIGIN( x, y );
1411 +                       normal = SUPER_NORMAL( x, y );
1412 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1413 +
1414 +                       /* set default dirt */
1415 +                       *floodlight = 0.0f;
1416 +
1417 +                       /* only look at mapped luxels */
1418 +                       if( *cluster < 0 )
1419 +                               continue;
1420 +
1421 +                       /* copy to trace */
1422 +                       trace.cluster = *cluster;
1423 +                       VectorCopy( origin, trace.origin );
1424 +                       VectorCopy( normal, trace.normal );
1425 +
1426 +
1427 +
1428 +                       /* get dirt */
1429 +                       *floodlight = FloodLightForSample( &trace );
1430 +               }
1431 +       }
1432 +
1433 +       /* testing no filtering */
1434 +       return;
1435 +
1436 +       /* filter "dirt" */
1437 +       for( y = 0; y < lm->sh; y++ )
1438 +       {
1439 +               for( x = 0; x < lm->sw; x++ )
1440 +               {
1441 +                       /* get luxel */
1442 +                       cluster = SUPER_CLUSTER( x, y );
1443 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1444 +
1445 +                       /* filter dirt by adjacency to unmapped luxels */
1446 +                       average = *floodlight;
1447 +                       samples = 1.0f;
1448 +                       for( sy = (y - 1); sy <= (y + 1); sy++ )
1449 +                       {
1450 +                               if( sy < 0 || sy >= lm->sh )
1451 +                                       continue;
1452 +
1453 +                               for( sx = (x - 1); sx <= (x + 1); sx++ )
1454 +                               {
1455 +                                       if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1456 +                                               continue;
1457 +
1458 +                                       /* get neighboring luxel */
1459 +                                       cluster = SUPER_CLUSTER( sx, sy );
1460 +                                       floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1461 +                                       if( *cluster < 0 || *floodlight2 <= 0.0f )
1462 +                                               continue;
1463 +
1464 +                                       /* add it */
1465 +                                       average += *floodlight2;
1466 +                                       samples += 1.0f;
1467 +                               }
1468 +
1469 +                               /* bail */
1470 +                               if( samples <= 0.0f )
1471 +                                       break;
1472 +                       }
1473 +
1474 +                       /* bail */
1475 +                       if( samples <= 0.0f )
1476 +                               continue;
1477 +
1478 +                       /* scale dirt */
1479 +                       *floodlight = average / samples;
1480 +               }
1481 +       }
1482 +}
1483 +
1484 +/*
1485 +FloodLightForSample()
1486 +calculates floodlight value for a given sample
1487 +once again, kudos to the dirtmapping coder
1488 +*/
1489 +float FloodLightForSample( trace_t *trace )
1490 +{
1491 +       int             i;
1492 +       float   d;
1493 +       float   contribution;
1494 +       int     sub = 0;
1495 +       float   gatherLight, outLight;
1496 +       vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
1497 +       float   dd;
1498 +       int     vecs = 0;
1499 +
1500 +       gatherLight=0;
1501 +       /* dummy check */
1502 +       //if( !dirty )
1503 +       //      return 1.0f;
1504 +       if( trace == NULL || trace->cluster < 0 )
1505 +               return 0.0f;
1506 +
1507 +
1508 +       /* setup */
1509 +       dd = floodlightDistance;
1510 +       VectorCopy( trace->normal, normal );
1511 +
1512 +       /* check if the normal is aligned to the world-up */
1513 +       if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1514 +       {
1515 +               if( normal[ 2 ] == 1.0f )
1516 +               {
1517 +                       VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1518 +                       VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1519 +               }
1520 +               else if( normal[ 2 ] == -1.0f )
1521 +               {
1522 +                       VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1523 +                       VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1524 +               }
1525 +       }
1526 +       else
1527 +       {
1528 +               VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1529 +               CrossProduct( normal, worldUp, myRt );
1530 +               VectorNormalize( myRt, myRt );
1531 +               CrossProduct( myRt, normal, myUp );
1532 +               VectorNormalize( myUp, myUp );
1533 +       }
1534 +
1535 +       /* iterate through ordered vectors */
1536 +       for( i = 0; i < numFloodVectors; i++ )
1537 +       {
1538 +               if (floodlight_lowquality==qtrue)
1539 +        {
1540 +                       if (rand()%10 != 0 ) continue;
1541 +               }
1542 +
1543 +               vecs++;
1544 +
1545 +               /* transform vector into tangent space */
1546 +               direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1547 +               direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1548 +               direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1549 +
1550 +               /* set endpoint */
1551 +               VectorMA( trace->origin, dd, direction, trace->end );
1552 +
1553 +               //VectorMA( trace->origin, 1, direction, trace->origin );
1554 +
1555 +               SetupTrace( trace );
1556 +               /* trace */
1557 +               TraceLine( trace );
1558 +               contribution=1;
1559 +
1560 +               if (trace->compileFlags & C_SKY )
1561 +               {
1562 +                       contribution=1.0f;
1563 +               }
1564 +               else if ( trace->opaque )
1565 +               {
1566 +                       VectorSubtract( trace->hit, trace->origin, displacement );
1567 +                       d=VectorLength( displacement );
1568 +
1569 +                       // d=trace->distance;
1570 +                       //if (d>256) gatherDirt+=1;
1571 +                       contribution=d/dd;
1572 +                       if (contribution>1) contribution=1.0f;
1573 +
1574 +                       //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1575 +               }
1576 +
1577 +               gatherLight+=contribution;
1578 +       }
1579 +
1580 +       /* early out */
1581 +       if( gatherLight <= 0.0f )
1582 +               return 0.0f;
1583 +
1584 +       sub=vecs;
1585 +
1586 +       if (sub<1) sub=1;
1587 +       gatherLight/=(sub);
1588 +
1589 +       outLight=gatherLight;
1590 +       if( outLight > 1.0f )
1591 +               outLight = 1.0f;
1592 +
1593 +       /* return to sender */
1594 +       return outLight;
1595 +}
1596  
1597 Index: tools/quake3/q3map2/light.c
1598 ===================================================================
1599 --- tools/quake3/q3map2/light.c.orig    2008-09-06 15:32:04.000000000 +0200
1600 +++ tools/quake3/q3map2/light.c 2008-09-06 15:32:14.000000000 +0200
1601 @@ -1378,6 +1378,56 @@
1602                         break;
1603         }
1604         
1605 +       /////// Floodlighting for point //////////////////
1606 +       //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1607 +       if (floodlighty)
1608 +       {
1609 +               int q;
1610 +               float addSize,f;
1611 +               vec3_t col,dir;
1612 +               col[0]=col[1]=col[2]=floodlightIntensity;
1613 +               dir[0]=dir[1]=0;
1614 +               dir[2]=1;
1615 +
1616 +               trace.testOcclusion = qtrue;
1617 +               trace.forceSunlight = qfalse;
1618 +               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1619 +               trace.testAll = qtrue;
1620 +
1621 +               for (q=0;q<2;q++)
1622 +               {
1623 +                       if (q==0) //upper hemisphere
1624 +                       {
1625 +                               trace.normal[0]=0;
1626 +                               trace.normal[1]=0;
1627 +                               trace.normal[2]=1;
1628 +                       }
1629 +                       else //lower hemisphere
1630 +                       {
1631 +                               trace.normal[0]=0;
1632 +                               trace.normal[1]=0;
1633 +                               trace.normal[2]=-1;
1634 +                       }
1635 +
1636 +                       f = FloodLightForSample(&trace);
1637 +
1638 +                       contributions[ numCon ].color[0]=col[0]*f;
1639 +                       contributions[ numCon ].color[1]=col[1]*f;
1640 +                       contributions[ numCon ].color[2]=col[2]*f;
1641 +
1642 +                       contributions[ numCon ].dir[0]=dir[0];
1643 +                       contributions[ numCon ].dir[1]=dir[1];
1644 +                       contributions[ numCon ].dir[2]=dir[2];
1645 +
1646 +                       contributions[ numCon ].style = 0;
1647 +                       numCon++;
1648 +                       /* push average direction around */
1649 +                       addSize = VectorLength( col );
1650 +                       VectorMA( gp->dir, addSize, dir, gp->dir );
1651 +               }
1652 +       }
1653 +       /////////////////////
1654 +
1655         /* normalize to get primary light direction */
1656         VectorNormalize( gp->dir, gp->dir );
1657         
1658 @@ -1661,6 +1711,12 @@
1659                 RunThreadsOnIndividual( numRawLightmaps, qtrue, DirtyRawLightmap );
1660         }
1661         
1662 +       /* floodlight them up */
1663 +       if( floodlighty )
1664 +       {
1665 +               Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1666 +               RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1667 +       }
1668  
1669         /* ydnar: set up light envelopes */
1670         SetupEnvelopes( qfalse, fast );
1671 @@ -1703,6 +1759,7 @@
1672                 /* flag bouncing */
1673                 bouncing = qtrue;
1674                 VectorClear( ambientColor );
1675 +               floodlighty = false;
1676                 
1677                 /* generate diffuse lights */
1678                 RadFreeLights();
1679 @@ -2191,6 +2248,21 @@
1680                         cpmaHack = qtrue;
1681                         Sys_Printf( "Enabling Challenge Pro Mode Asstacular Vertex Lighting Mode (tm)\n" );
1682                 }
1683 +               else if( !strcmp( argv[ i ], "-floodlight" ) )
1684 +               {
1685 +                       floodlighty = qtrue;
1686 +                       Sys_Printf( "FloodLighting enabled\n" );
1687 +               }
1688 +               else if( !strcmp( argv[ i ], "-debugnormals" ) )
1689 +               {
1690 +                       debugnormals = qtrue;
1691 +                       Sys_Printf( "DebugNormals enabled\n" );
1692 +               }
1693 +               else if( !strcmp( argv[ i ], "-lowquality" ) )
1694 +               {
1695 +                       floodlight_lowquality = qtrue;
1696 +                       Sys_Printf( "Low Quality FloodLighting enabled\n" );
1697 +               }
1698                 
1699                 /* r7: dirtmapping */
1700                 else if( !strcmp( argv[ i ], "-dirty" ) )
1701 @@ -2279,6 +2351,7 @@
1702         /* ydnar: set up optimization */
1703         SetupBrushes();
1704         SetupDirt();
1705 +       SetupFloodLight();
1706         SetupSurfaceLightmaps();
1707         
1708         /* initialize the surface facet tracing */
1709 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1710 ===================================================================
1711 --- tools/quake3/q3map2/lightmaps_ydnar.c.orig  2008-09-06 15:32:04.000000000 +0200
1712 +++ tools/quake3/q3map2/lightmaps_ydnar.c       2008-09-06 15:32:14.000000000 +0200
1713 @@ -414,6 +414,12 @@
1714                 lm->superNormals = safe_malloc( size );
1715         memset( lm->superNormals, 0, size );
1716         
1717 +       /* allocate floodlight map storage */
1718 +       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1719 +       if( lm->superFloodLight == NULL )
1720 +               lm->superFloodLight = safe_malloc( size );
1721 +       memset( lm->superFloodLight, 0, size );
1722 +
1723         /* allocate cluster map storage */
1724         size = lm->sw * lm->sh * sizeof( int );
1725         if( lm->superClusters == NULL )
1726 Index: tools/quake3/q3map2/q3map2.h
1727 ===================================================================
1728 --- tools/quake3/q3map2/q3map2.h.orig   2008-09-06 15:32:04.000000000 +0200
1729 +++ tools/quake3/q3map2/q3map2.h        2008-09-06 15:32:14.000000000 +0200
1730 @@ -266,6 +266,7 @@
1731  #define SUPER_NORMAL_SIZE              4
1732  #define SUPER_DELUXEL_SIZE             3
1733  #define BSP_DELUXEL_SIZE               3
1734 +#define SUPER_FLOODLIGHT_SIZE  1
1735  
1736  #define VERTEX_LUXEL( s, v )   (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1737  #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1738 @@ -278,6 +279,7 @@
1739  #define SUPER_ORIGIN( x, y )   (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1740  #define SUPER_NORMAL( x, y )   (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1741  #define SUPER_DIRT( x, y )             (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE) + 3)   /* stash dirtyness in normal[ 3 ] */
1742 +#define SUPER_FLOODLIGHT( x, y )       (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )
1743  
1744  
1745  
1746 @@ -1400,6 +1402,7 @@
1747         
1748         float                                   *superDeluxels; /* average light direction */
1749         float                                   *bspDeluxels;
1750 +       float                                   *superFloodLight;
1751  }
1752  rawLightmap_t;
1753  
1754 @@ -1712,6 +1715,10 @@
1755  float                                          DirtForSample( trace_t *trace );
1756  void                                           DirtyRawLightmap( int num );
1757  
1758 +void                                           SetupFloodLight();
1759 +float                                          FloodLightForSample( trace_t *trace );
1760 +void                                           FloodLightRawLightmap( int num );
1761 +
1762  void                                           IlluminateRawLightmap( int num );
1763  void                                           IlluminateVertexes( int num );
1764  
1765 @@ -2106,6 +2113,13 @@
1766  Q_EXTERN float                         dirtScale Q_ASSIGN( 1.0f );
1767  Q_EXTERN float                         dirtGain Q_ASSIGN( 1.0f );
1768  
1769 +Q_EXTERN qboolean                      debugnormals Q_ASSIGN( qfalse );
1770 +Q_EXTERN qboolean                      floodlighty Q_ASSIGN( qfalse );
1771 +Q_EXTERN qboolean                      floodlight_lowquality Q_ASSIGN( qfalse );
1772 +Q_EXTERN vec3_t                                floodlightRGB;
1773 +Q_EXTERN float                         floodlightIntensity Q_ASSIGN( 512 );
1774 +Q_EXTERN float                         floodlightDistance Q_ASSIGN( 1024 );
1775 +
1776  Q_EXTERN qboolean                      dump Q_ASSIGN( qfalse );
1777  Q_EXTERN qboolean                      debug Q_ASSIGN( qfalse );
1778  Q_EXTERN qboolean                      debugUnused Q_ASSIGN( qfalse );
1779 Index: tools/quake3/q3map2/game_ja.h
1780 ===================================================================
1781 --- tools/quake3/q3map2/game_ja.h.orig  2008-09-06 15:32:04.000000000 +0200
1782 +++ tools/quake3/q3map2/game_ja.h       2008-09-06 15:32:16.000000000 +0200
1783 @@ -67,6 +67,7 @@
1784         qfalse,                         /* wolf lighting model? */
1785         128,                            /* lightmap width/height */
1786         1.0f,                           /* lightmap gamma */
1787 +       1.0f,                           /* lightmap exposure */
1788         1.0f,                           /* lightmap compensate */
1789         "RBSP",                         /* bsp file prefix */
1790         1,                                      /* bsp file version */
1791 Index: tools/quake3/q3map2/game_tremulous.h
1792 ===================================================================
1793 --- tools/quake3/q3map2/game_tremulous.h.orig   2008-09-06 15:32:04.000000000 +0200
1794 +++ tools/quake3/q3map2/game_tremulous.h        2008-09-06 15:32:16.000000000 +0200
1795 @@ -70,6 +70,7 @@
1796         qfalse,                         /* wolf lighting model? */
1797         128,                            /* lightmap width/height */
1798         1.0f,                           /* lightmap gamma */
1799 +       1.0f,                           /* lightmap exposure */
1800         1.0f,                           /* lightmap compensate */
1801         "IBSP",                         /* bsp file prefix */
1802         46,                                     /* bsp file version */
1803 Index: tools/quake3/q3map2/game_wolfet.h
1804 ===================================================================
1805 --- tools/quake3/q3map2/game_wolfet.h.orig      2008-09-06 15:32:04.000000000 +0200
1806 +++ tools/quake3/q3map2/game_wolfet.h   2008-09-06 15:32:16.000000000 +0200
1807 @@ -66,6 +66,7 @@
1808         qtrue,                          /* wolf lighting model? */
1809         128,                            /* lightmap width/height */
1810         1.0f,                           /* lightmap gamma */
1811 +       1.0f,                           /* lightmap exposure */
1812         1.0f,                           /* lightmap compensate */
1813         "IBSP",                         /* bsp file prefix */
1814         47,                                     /* bsp file version */
1815 Index: tools/quake3/q3map2/game_wolf.h
1816 ===================================================================
1817 --- tools/quake3/q3map2/game_wolf.h.orig        2008-09-06 15:32:04.000000000 +0200
1818 +++ tools/quake3/q3map2/game_wolf.h     2008-09-06 15:32:16.000000000 +0200
1819 @@ -129,6 +129,7 @@
1820         qtrue,                          /* wolf lighting model? */
1821         128,                            /* lightmap width/height */
1822         1.0f,                           /* lightmap gamma */
1823 +       1.0f,                           /* lightmap exposure */
1824         1.0f,                           /* lightmap compensate */
1825         "IBSP",                         /* bsp file prefix */
1826         47,                                     /* bsp file version */
1827 Index: tools/quake3/q3map2/game_sof2.h
1828 ===================================================================
1829 --- tools/quake3/q3map2/game_sof2.h.orig        2008-09-06 15:32:04.000000000 +0200
1830 +++ tools/quake3/q3map2/game_sof2.h     2008-09-06 15:32:16.000000000 +0200
1831 @@ -139,6 +139,7 @@
1832         qfalse,                                 /* wolf lighting model? */
1833         128,                                    /* lightmap width/height */
1834         1.0f,                                   /* lightmap gamma */
1835 +       1.0f,                                   /* lightmap exposure */
1836         1.0f,                                   /* lightmap compensate */
1837         "RBSP",                                 /* bsp file prefix */
1838         1,                                              /* bsp file version */
1839 Index: tools/quake3/q3map2/game_etut.h
1840 ===================================================================
1841 --- tools/quake3/q3map2/game_etut.h.orig        2008-09-06 15:32:04.000000000 +0200
1842 +++ tools/quake3/q3map2/game_etut.h     2008-09-06 15:32:16.000000000 +0200
1843 @@ -148,6 +148,7 @@
1844         qfalse,                         /* wolf lighting model? */
1845         128,                            /* lightmap width/height */
1846         2.2f,                           /* lightmap gamma */
1847 +       1.0f,                           /* lightmap exposure */
1848         1.0f,                           /* lightmap compensate */
1849         "IBSP",                         /* bsp file prefix */
1850         47,                                     /* bsp file version */
1851 Index: tools/quake3/q3map2/game_jk2.h
1852 ===================================================================
1853 --- tools/quake3/q3map2/game_jk2.h.orig 2008-09-06 15:32:04.000000000 +0200
1854 +++ tools/quake3/q3map2/game_jk2.h      2008-09-06 15:32:16.000000000 +0200
1855 @@ -64,6 +64,7 @@
1856         qfalse,                         /* wolf lighting model? */
1857         128,                            /* lightmap width/height */
1858         1.0f,                           /* lightmap gamma */
1859 +       1.0f,                           /* lightmap exposure */
1860         1.0f,                           /* lightmap compensate */
1861         "RBSP",                         /* bsp file prefix */
1862         1,                                      /* bsp file version */
1863 Index: tools/quake3/q3map2/game_qfusion.h
1864 ===================================================================
1865 --- tools/quake3/q3map2/game_qfusion.h.orig     2008-09-06 15:32:04.000000000 +0200
1866 +++ tools/quake3/q3map2/game_qfusion.h  2008-09-06 15:32:16.000000000 +0200
1867 @@ -115,6 +115,7 @@
1868         qfalse,                         /* wolf lighting model? */
1869         512,                            /* lightmap width/height */
1870         1.0f,                           /* lightmap gamma */
1871 +       1.0f,                           /* lightmap exposure */
1872         1.0f,                           /* lightmap compensate */
1873         "FBSP",                         /* bsp file prefix */
1874         1,                                      /* bsp file version */
1875 Index: tools/quake3/q3map2/game_tenebrae.h
1876 ===================================================================
1877 --- tools/quake3/q3map2/game_tenebrae.h.orig    2008-09-06 15:32:04.000000000 +0200
1878 +++ tools/quake3/q3map2/game_tenebrae.h 2008-09-06 15:32:16.000000000 +0200
1879 @@ -112,6 +112,7 @@
1880         qfalse,                         /* wolf lighting model? */
1881         512,                            /* lightmap width/height */
1882         2.0f,                           /* lightmap gamma */
1883 +       1.0f,                           /* lightmap exposure */
1884         1.0f,                           /* lightmap compensate */
1885         "IBSP",                         /* bsp file prefix */
1886         46,                                     /* bsp file version */
1887 Index: tools/quake3/q3map2/game_quake3.h
1888 ===================================================================
1889 --- tools/quake3/q3map2/game_quake3.h.orig      2008-09-06 15:32:04.000000000 +0200
1890 +++ tools/quake3/q3map2/game_quake3.h   2008-09-06 15:32:16.000000000 +0200
1891 @@ -112,6 +112,7 @@
1892         qfalse,                         /* wolf lighting model? */
1893         128,                            /* lightmap width/height */
1894         1.0f,                           /* lightmap gamma */
1895 +       1.0f,                           /* lightmap exposure */
1896         1.0f,                           /* lightmap compensate */
1897         "IBSP",                         /* bsp file prefix */
1898         47,                                     /* bsp file version */
1899 Index: tools/quake3/q3map2/game_ef.h
1900 ===================================================================
1901 --- tools/quake3/q3map2/game_ef.h.orig  2008-09-06 15:32:04.000000000 +0200
1902 +++ tools/quake3/q3map2/game_ef.h       2008-09-06 15:32:16.000000000 +0200
1903 @@ -113,6 +113,7 @@
1904         qfalse,                         /* wolf lighting model? */
1905         128,                            /* lightmap width/height */
1906         1.0f,                           /* lightmap gamma */
1907 +       1.0f,                           /* lightmap exposure */
1908         1.0f,                           /* lightmap compensate */
1909         "IBSP",                         /* bsp file prefix */
1910         46,                                     /* bsp file version */
1911 Index: tools/quake3/q3map2/light_ydnar.c
1912 ===================================================================
1913 --- tools/quake3/q3map2/light_ydnar.c.orig      2008-09-06 15:32:14.000000000 +0200
1914 +++ tools/quake3/q3map2/light_ydnar.c   2008-09-06 15:32:16.000000000 +0200
1915 @@ -49,6 +49,7 @@
1916         int             i;
1917         float   max, gamma;
1918         vec3_t  sample;
1919 +       float   inv, dif;
1920         
1921         
1922         /* ydnar: scaling necessary for simulating r_overbrightBits on external lightmaps */
1923 @@ -72,15 +73,50 @@
1924                 /* gamma */
1925                 sample[ i ] = pow( sample[ i ] / 255.0f, gamma ) * 255.0f;
1926         }
1927 -       
1928 -       /* clamp with color normalization */
1929 -       max = sample[ 0 ];
1930 -       if( sample[ 1 ] > max )
1931 -               max = sample[ 1 ];
1932 -       if( sample[ 2 ] > max )
1933 -               max = sample[ 2 ];
1934 -       if( max > 255.0f )
1935 -               VectorScale( sample, (255.0f / max), sample );
1936 +
1937 +       if (lightmapExposure == 1)
1938 +       {
1939 +               /* clamp with color normalization */
1940 +               max = sample[ 0 ];
1941 +               if( sample[ 1 ] > max )
1942 +                       max = sample[ 1 ];
1943 +               if( sample[ 2 ] > max )
1944 +                       max = sample[ 2 ];
1945 +               if( max > 255.0f )
1946 +                       VectorScale( sample, (255.0f / max), sample );
1947 +       }
1948 +       else
1949 +       {
1950 +               if (lightmapExposure==0)
1951 +               {
1952 +                       lightmapExposure=1.0f;
1953 +               }
1954 +               inv=1.f/lightmapExposure;
1955 +               //Exposure
1956 +
1957 +               max = sample[ 0 ];
1958 +               if( sample[ 1 ] > max )
1959 +                       max = sample[ 1 ];
1960 +               if( sample[ 2 ] > max )
1961 +                       max = sample[ 2 ];
1962 +
1963 +               dif = (1-  exp(-max * inv) )  *  255;
1964 +
1965 +               if (max >0)
1966 +               {
1967 +                       dif = dif / max;
1968 +               }
1969 +               else
1970 +               {
1971 +                       dif = 0;
1972 +               }
1973 +
1974 +               for (i=0;i<3;i++)
1975 +               {
1976 +                       sample[i]*=dif;
1977 +               }
1978 +       }
1979 +
1980         
1981         /* compensate for ingame overbrighting/bitshifting */
1982         VectorScale( sample, (1.0f / lightmapCompensate), sample );
1983 Index: tools/quake3/q3map2/q3map2.h
1984 ===================================================================
1985 --- tools/quake3/q3map2/q3map2.h.orig   2008-09-06 15:32:14.000000000 +0200
1986 +++ tools/quake3/q3map2/q3map2.h        2008-09-06 15:32:16.000000000 +0200
1987 @@ -553,6 +553,7 @@
1988         qboolean                        wolfLight;                                              /* when true, lights work like wolf q3map  */
1989         int                                     lightmapSize;                                   /* bsp lightmap width/height */
1990         float                           lightmapGamma;                                  /* default lightmap gamma */
1991 +       float                           lightmapExposure;                               /* default lightmap exposure */
1992         float                           lightmapCompensate;                             /* default lightmap compensate value */
1993         char                            *bspIdent;                                              /* 4-letter bsp file prefix */
1994         int                                     bspVersion;                                             /* bsp version to use */
1995 @@ -2139,6 +2140,7 @@
1996  
1997  /* ydnar: lightmap gamma/compensation */
1998  Q_EXTERN float                         lightmapGamma Q_ASSIGN( 1.0f );
1999 +Q_EXTERN float                         lightmapExposure Q_ASSIGN( 1.0f );
2000  Q_EXTERN float                         lightmapCompensate Q_ASSIGN( 1.0f );
2001  
2002  /* ydnar: for runtime tweaking of falloff tolerance */
2003 Index: tools/quake3/q3map2/light.c
2004 ===================================================================
2005 --- tools/quake3/q3map2/light.c.orig    2008-09-06 15:32:14.000000000 +0200
2006 +++ tools/quake3/q3map2/light.c 2008-09-06 15:32:16.000000000 +0200
2007 @@ -1893,6 +1893,14 @@
2008                         i++;
2009                 }
2010                 
2011 +               else if( !strcmp( argv[ i ], "-exposure" ) )
2012 +               {
2013 +                       f = atof( argv[ i + 1 ] );
2014 +                       lightmapExposure = f;
2015 +                       Sys_Printf( "Lighting exposure set to %f\n", lightmapExposure );
2016 +                       i++;
2017 +               }
2018 +
2019                 else if( !strcmp( argv[ i ], "-compensate" ) )
2020                 {
2021                         f = atof( argv[ i + 1 ] );
2022 Index: tools/quake3/q3map2/light_ydnar.c
2023 ===================================================================
2024 --- tools/quake3/q3map2/light_ydnar.c.orig      2008-09-06 15:32:16.000000000 +0200
2025 +++ tools/quake3/q3map2/light_ydnar.c   2008-09-06 15:32:18.000000000 +0200
2026 @@ -420,7 +420,7 @@
2027  #define NUDGE                  0.5f
2028  #define BOGUS_NUDGE            -99999.0f
2029  
2030 -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 ] )
2031 +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 ] )
2032  {
2033         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
2034         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
2035 @@ -428,6 +428,12 @@
2036         vec3_t                  pNormal;
2037         vec3_t                  vecs[ 3 ];
2038         vec3_t                  nudged;
2039 +       vec3_t                  cverts[ 3 ];
2040 +       vec3_t                  temp;
2041 +       vec4_t                  sideplane, hostplane;
2042 +       vec3_t                  origintwo;
2043 +       int                             j, next;
2044 +       float                   e;
2045         float                   *nudge;
2046         static float    nudges[][ 2 ] =
2047                                         {
2048 @@ -521,6 +527,51 @@
2049         /* non axial lightmap projection (explicit xyz) */
2050         else
2051                 VectorCopy( dv->xyz, origin );
2052 +
2053 +       //////////////////////
2054 +       //27's test to make sure samples stay within the triangle boundaries
2055 +       //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
2056 +       //2) if it does, nudge it onto the correct side.
2057 +
2058 +       if (worldverts!=NULL)
2059 +       {
2060 +               for (j=0;j<3;j++)
2061 +               {
2062 +                       VectorCopy(worldverts[j],cverts[j]);
2063 +               }
2064 +               PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2065 +
2066 +               for (j=0;j<3;j++)
2067 +               {
2068 +                       for (i=0;i<3;i++)
2069 +                       {
2070 +                               //build plane using 2 edges and a normal
2071 +                               next=(i+1)%3;
2072 +
2073 +                               VectorCopy(cverts[next],temp);
2074 +                               VectorAdd(temp,hostplane,temp);
2075 +                               PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2076 +
2077 +                               //planetest sample point
2078 +                               e=DotProduct(origin,sideplane);
2079 +                               e=e-sideplane[3];
2080 +                               if (e>0)
2081 +                               {
2082 +                                       //we're bad.
2083 +                                       //VectorClear(origin);
2084 +                                       //Move the sample point back inside triangle bounds
2085 +                                       origin[0]-=sideplane[0]*(e+1);
2086 +                                       origin[1]-=sideplane[1]*(e+1);
2087 +                                       origin[2]-=sideplane[2]*(e+1);
2088 +#ifdef DEBUG_27_1
2089 +                                       VectorClear(origin);
2090 +#endif
2091 +                               }
2092 +                       }
2093 +               }
2094 +       }
2095 +
2096 +       ////////////////////////
2097         
2098         /* planar surfaces have precalculated lightmap vectors for nudging */
2099         if( lm->plane != NULL )
2100 @@ -552,8 +603,13 @@
2101         else
2102                 origin[ lm->axisNum ] += lightmapSampleOffset;
2103         
2104 +       VectorCopy(origin,origintwo);
2105 +       origintwo[0]+=vecs[2][0];
2106 +       origintwo[1]+=vecs[2][1];
2107 +       origintwo[2]+=vecs[2][2];
2108 +
2109         /* get cluster */
2110 -       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2111 +       pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2112         
2113         /* another retarded hack, storing nudge count in luxel[ 1 ] */
2114         luxel[ 1 ] = 0.0f;      
2115 @@ -569,14 +625,14 @@
2116                         for( i = 0; i < 3; i++ )
2117                         {
2118                                 /* set nudged point*/
2119 -                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2120 +                               nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2121                         }
2122                         nudge += 2;
2123                         
2124                         /* get pvs cluster */
2125                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
2126 -                       if( pointCluster >= 0 ) 
2127 -                               VectorCopy( nudged, origin );
2128 +                       //if( pointCluster >= 0 )
2129 +                       //      VectorCopy( nudged, origin );
2130                         luxel[ 1 ] += 1.0f;
2131                 }
2132         }
2133 @@ -586,8 +642,8 @@
2134         {
2135                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
2136                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
2137 -               if( pointCluster >= 0 )
2138 -                       VectorCopy( nudged, origin );
2139 +               //if( pointCluster >= 0 )
2140 +               //      VectorCopy( nudged, origin );
2141                 luxel[ 1 ] += 1.0f;
2142         }
2143         
2144 @@ -633,7 +689,7 @@
2145  than the distance between two luxels (thanks jc :)
2146  */
2147  
2148 -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 ] )
2149 +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 ] )
2150  {
2151         bspDrawVert_t   mid, *dv2[ 3 ];
2152         int                             max;
2153 @@ -681,7 +737,7 @@
2154         
2155         /* split the longest edge and map it */
2156         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
2157 -       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
2158 +       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
2159         
2160         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
2161         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
2162 @@ -689,12 +745,12 @@
2163         /* recurse to first triangle */
2164         VectorCopy( dv, dv2 );
2165         dv2[ max ] = &mid;
2166 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2167 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2168         
2169         /* recurse to second triangle */
2170         VectorCopy( dv, dv2 );
2171         dv2[ (max + 1) % 3 ] = &mid;
2172 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2173 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2174  }
2175  
2176  
2177 @@ -710,6 +766,7 @@
2178         int                             i;
2179         vec4_t                  plane;
2180         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2181 +       vec3_t                  worldverts[ 3 ];
2182         
2183         
2184         /* get plane if possible */
2185 @@ -735,16 +792,20 @@
2186                 ttv = NULL;
2187         }
2188         
2189 +       VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2190 +       VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2191 +       VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
2192 +
2193         /* map the vertexes */
2194 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2195 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2196 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2197 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
2198 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
2199 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
2200         
2201         /* 2002-11-20: prefer axial triangle edges */
2202         if( mapNonAxial )
2203         {
2204                 /* subdivide the triangle */
2205 -               MapTriangle_r( lm, info, dv, plane, stv, ttv );
2206 +               MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2207                 return qtrue;
2208         }
2209         
2210 @@ -766,7 +827,7 @@
2211                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
2212                         
2213                         /* map the degenerate triangle */
2214 -                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2215 +                       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2216                 }
2217         }
2218         
2219 @@ -828,8 +889,8 @@
2220         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
2221         
2222         /* map the vertexes */
2223 -       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
2224 -       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
2225 +       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
2226 +       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
2227         
2228         /* 0 and 2 */
2229         if( max == 0 )
2230 @@ -914,10 +975,10 @@
2231         }
2232         
2233         /* map the vertexes */
2234 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2235 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2236 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2237 -       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
2238 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
2239 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
2240 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
2241 +       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
2242         
2243         /* subdivide the quad */
2244         MapQuad_r( lm, info, dv, plane, stv, ttv );
2245 @@ -1209,7 +1270,7 @@
2246                                         continue;
2247                                 
2248                                 /* map the fake vert */
2249 -                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
2250 +                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
2251                         }
2252                 }
2253         }
2254 @@ -2001,22 +2062,32 @@
2255                                         deluxel = SUPER_DELUXEL( x, y );
2256                                         origin = SUPER_ORIGIN( x, y );
2257                                         normal = SUPER_NORMAL( x, y );
2258 -                                       
2259 -                                       /* set contribution count */
2260 -                                       lightLuxel[ 3 ] = 1.0f;
2261 -                                       
2262 -                                       /* setup trace */
2263 -                                       trace.cluster = *cluster;
2264 -                                       VectorCopy( origin, trace.origin );
2265 -                                       VectorCopy( normal, trace.normal );
2266 -                                       
2267 -                                       /* get light for this sample */
2268 -                                       LightContributionToSample( &trace );
2269 -                                       VectorCopy( trace.color, lightLuxel );
2270 -                                       
2271 -                                       /* add to count */
2272 -                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2273 +
2274 +                                       ////////// 27's temp hack for testing edge clipping ////
2275 +                                       if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2276 +                                       {
2277 +                                               lightLuxel[ 1 ] = 255;
2278 +                                               lightLuxel[ 3 ] = 1.0f;
2279                                                 totalLighted++;
2280 +                                       }
2281 +                                       else
2282 +                                       {
2283 +                                               /* set contribution count */
2284 +                                               lightLuxel[ 3 ] = 1.0f;
2285 +
2286 +                                               /* setup trace */
2287 +                                               trace.cluster = *cluster;
2288 +                                               VectorCopy( origin, trace.origin );
2289 +                                               VectorCopy( normal, trace.normal );
2290 +
2291 +                                               /* get light for this sample */
2292 +                                               LightContributionToSample( &trace );
2293 +                                               VectorCopy( trace.color, lightLuxel );
2294 +
2295 +                                               /* add to count */
2296 +                                               if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2297 +                                                       totalLighted++;
2298 +                                       }
2299                                         
2300                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2301                                         if( deluxemap )
2302 Index: tools/quake3/q3map2/q3map2.h
2303 ===================================================================
2304 --- tools/quake3/q3map2/q3map2.h        (revision 303)
2305 +++ tools/quake3/q3map2/q3map2.h        (working copy)
2306 @@ -35,8 +35,8 @@
2307  
2308  
2309  /* version */
2310 -#define Q3MAP_VERSION  "2.5.17"
2311 -#define Q3MAP_MOTD             "Last one turns the lights off"
2312 +#define Q3MAP_VERSION  "2.5.17-div0-obj-decomptexcoords-format46-snapplane-UTavgcolorfix-UTfloodlight-UTlmexposure-UTtrianglecheck"
2313 +#define Q3MAP_MOTD             "Light some candles, put them on a wooden table, take a photo, and paste it on the lightmaps!"
2314  
2315  
2316  
2317 Index: include/version.default
2318 ===================================================================
2319 --- include/version.default     (revision 290)
2320 +++ include/version.default     (working copy)
2321 @@ -1 +1 @@
2322 -1.4.0\r
2323 +1.4.0-div0-obj-targetname\r