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