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