]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
add spawnflag boxes
[divverent/nexuiz.git] / misc / gtkradiant / gtkradiant-nexuiz-patchset.diff
1 NOTE: this patch set is autogenerated from the "singlepatches" subdirectory of nexuiz/trunk/misc.
2
3 Do not commit changes to THIS!
4
5 Always run
6         sh mergepatches.sh > gtkradiant-nexuiz-patchset.diff
7 before committing new singlepatches!
8
9
10
11 Index: libs/picomodel/pm_obj.c
12 ===================================================================
13 --- libs/picomodel/pm_obj.c     (revision 290)
14 +++ libs/picomodel/pm_obj.c     (working copy)
15 @@ -215,10 +215,9 @@
16         }
17  }
18  
19 -#if 0
20  static int _obj_mtl_load( picoModel_t *model )
21  {
22 -       //picoShader_t *curShader = NULL;
23 +       picoShader_t *curShader = NULL;
24         picoParser_t *p;
25         picoByte_t   *mtlBuffer;
26         int                       mtlBufSize;
27 @@ -266,7 +265,7 @@
28                 /* get next token in material file */
29                 if (_pico_parse( p,1 ) == NULL)
30                         break;
31 -#if 0
32 +#if 1
33  
34                 /* skip empty lines */
35                 if (p->token == NULL || !strlen( p->token ))
36 @@ -308,6 +307,7 @@
37                 else if (!_pico_stricmp(p->token,"map_kd"))
38                 {
39                         char *mapName;
40 +                       picoShader_t *shader;
41  
42                         /* pointer to current shader must be valid */
43                         if (curShader == NULL)
44 @@ -322,6 +322,10 @@
45                                 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
46                                 _obj_mtl_error_return;
47                         }
48 +                       /* create a new pico shader */
49 +                       shader = PicoNewShader( model );
50 +                       if (shader == NULL)
51 +                               _obj_mtl_error_return;
52                         /* set shader map name */
53                         PicoSetShaderMapName( shader,mapName );
54                 }
55 @@ -478,7 +482,6 @@
56         /* return with success */
57         return 1;
58  }
59 -#endif
60  
61  /* _obj_load:
62   *  loads a wavefront obj model file.
63 @@ -523,7 +526,7 @@
64         PicoSetModelFileName( model,fileName );
65  
66         /* try loading the materials; we don't handle the result */
67 -#if 0
68 +#if 1
69         _obj_mtl_load( model );
70  #endif
71  
72 @@ -832,6 +835,41 @@
73                                 curVertex += max;
74                         }
75                 }
76 +               else if (!_pico_stricmp(p->token,"usemtl"))
77 +               {
78 +                       picoShader_t *shader;
79 +                       char *name;
80 +
81 +                       /* get material name */
82 +                       name = _pico_parse( p,0 );
83 +
84 +                       /* validate material name */
85 +                       if (name == NULL || !strlen(name))
86 +                       {
87 +                               _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
88 +                       }
89 +                       else
90 +                       {
91 +                               shader = PicoFindShader( model, name, 1 );
92 +                               if (shader == NULL)
93 +                               {
94 +                                       _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
95 +
96 +                                       /* create a new pico shader */
97 +                                       shader = PicoNewShader( model );
98 +                                       if (shader != NULL)
99 +                                       {
100 +                                               PicoSetShaderName( shader,name );
101 +                                               PicoSetShaderMapName( shader,name );
102 +                                               PicoSetSurfaceShader( curSurface, shader );
103 +                                       }
104 +                               }
105 +                               else
106 +                               {
107 +                                       PicoSetSurfaceShader( curSurface, shader );
108 +                               }
109 +                       }
110 +               }
111                 /* skip unparsed rest of line and continue */
112                 _pico_parse_skip_rest( p );
113         }
114 Index: radiant/brush_primit.cpp
115 ===================================================================
116 --- radiant/brush_primit.cpp    (revision 297)
117 +++ radiant/brush_primit.cpp    (working copy)
118 @@ -388,8 +388,9 @@
119  //     ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture );
120  }
121  
122 -void BrushPrimitFaceToFace(face_t *face)
123 +void BrushPrimitFaceToFace(face_t *f)
124  {
125 +  /*
126    // we have parsed brush primitives and need conversion back to standard format
127    // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
128    // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
129 @@ -399,6 +400,28 @@
130    TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
131    face->texdef.scale[0]/=2.0;
132    face->texdef.scale[1]/=2.0;
133 +  */
134 +    vec3_t texX,texY;
135 +    vec3_t proj;
136 +    vec_t ST[3][5];
137 +
138 +    ComputeAxisBase(f->plane.normal,texX,texY);
139 +    VectorCopy(f->plane.normal,proj);
140 +    VectorScale(proj,f->plane.dist,proj);
141 +    VectorCopy(proj,ST[0]);
142 +    VectorCopy(texX,ST[1]);
143 +    VectorAdd(ST[1],proj,ST[1]);
144 +    VectorCopy(texY,ST[2]);
145 +    VectorAdd(ST[2],proj,ST[2]);
146 +
147 +       ST[0][3] = f->brushprimit_texdef.coords[0][2];
148 +       ST[0][4] = f->brushprimit_texdef.coords[1][2];
149 +       ST[1][3] = f->brushprimit_texdef.coords[0][0] + ST[0][3];
150 +       ST[1][4] = f->brushprimit_texdef.coords[1][0] + ST[0][4];
151 +       ST[2][3] = f->brushprimit_texdef.coords[0][1] + ST[0][3];
152 +       ST[2][4] = f->brushprimit_texdef.coords[1][1] + ST[0][4];
153 +
154 +       Face_TexdefFromTextureCoordinates(ST[0], ST[1], ST[2], f->d_texture, f);
155  }
156  
157  // TEXTURE LOCKING -----------------------------------------------------------------------------------------------------
158 Index: radiant/brush.cpp
159 ===================================================================
160 --- radiant/brush.cpp   (revision 297)
161 +++ radiant/brush.cpp   (working copy)
162 @@ -423,7 +423,93 @@
163         }
164  }
165  
166 +long double HighestImpactSign(long double a, long double b)
167 +{
168 +       // returns the sign of the value with larger abs
169 +       if(a+b > 0)
170 +               return +1;
171 +       else
172 +               return -1;
173 +}
174 +
175 +void Face_TexdefFromTextureVectors (face_t *f, long double STfromXYZ[2][4], vec3_t pvecs[2], int sv, int tv)
176 +{
177 +       texdef_t *td;
178 +       qtexture_t *q;
179 +       int j;
180 +       long double ang;
181 +
182 +    td = &f->texdef;
183 +    q = f->d_texture;
184 +
185 +       // undo the texture transform
186 +    for (j=0 ; j<4 ; j++) {
187 +        STfromXYZ[0][j] *= q->width;
188 +        STfromXYZ[1][j] *= q->height;
189 +    }
190 +
191 +    // shift
192 +    td->shift[0] = STfromXYZ[0][3];
193 +    td->shift[1] = STfromXYZ[1][3];
194 +
195  /*
196 +       SOLVE:
197 +               STfromXYZ[0][sv] = (cosv * pvecs[0][sv] - sinv * pvecs[0][tv]) / td->scale[0];
198 +               STfromXYZ[0][tv] = (sinv * pvecs[0][sv] + cosv * pvecs[0][tv]) / td->scale[0];
199 +               STfromXYZ[1][sv] = (cosv * pvecs[1][sv] - sinv * pvecs[1][tv]) / td->scale[1];
200 +               STfromXYZ[1][tv] = (sinv * pvecs[1][sv] + cosv * pvecs[1][tv]) / td->scale[1];
201 +       FOR:
202 +               sinv, cosv, td->scale[0], td->scale[1]
203 +       WE KNOW:
204 +               sinv^2 + cosv^2 = 1
205 +               pvecs[0][sv] is +/-1
206 +               pvecs[0][tv] is 0
207 +               pvecs[1][sv] is 0
208 +               pvecs[1][tv] is +/-1
209 +       THUS:
210 +               STfromXYZ[0][sv] = +cosv * pvecs[0][sv] / td->scale[0];
211 +               STfromXYZ[0][tv] = +sinv * pvecs[0][sv] / td->scale[0];
212 +               STfromXYZ[1][sv] = -sinv * pvecs[1][tv] / td->scale[1];
213 +               STfromXYZ[1][tv] = +cosv * pvecs[1][tv] / td->scale[1];
214 +*/
215 +
216 +       td->scale[0] = sqrt(STfromXYZ[0][sv]*STfromXYZ[0][sv] + STfromXYZ[0][tv]*STfromXYZ[0][tv]);
217 +       td->scale[1] = sqrt(STfromXYZ[1][sv]*STfromXYZ[1][sv] + STfromXYZ[1][tv]*STfromXYZ[1][tv]);
218 +
219 +       if(td->scale[0]) td->scale[0] = 1 / td->scale[0]; // avoid NaNs
220 +       if(td->scale[1]) td->scale[1] = 1 / td->scale[1];
221 +
222 +       long double sign0tv = (STfromXYZ[0][tv] > 0) ? +1 : -1;
223 +       ang = atan2( sign0tv * STfromXYZ[0][tv], sign0tv * STfromXYZ[0][sv]); // atan2(y, x) with y positive is in [0, PI[
224 +
225 +       // STOP
226 +       // We have until now ignored the fact that td->scale[0] or td->scale[1] may
227 +       // have either sign (+ or -). Due to roundoff errors, our choice of
228 +       // sign0tv may even have been wrong in a sense. 
229 +       // sign0tv may NOT indicate the appropriate sign for td->scale[0] (namely,
230 +       // if cosv is near zero)!
231 +       // let's look at the signs again
232 +       //   sign0sv =  signcosv * pvecs[0][sv] / td->scale[0]sign
233 +       //   sign0tv =             pvecs[0][sv] / td->scale[0]sign
234 +       //   sign1sv = -1        * pvecs[1][tv] / td->scale[1]sign
235 +       //   sign1tv =  signcosv * pvecs[1][tv] / td->scale[1]sign
236 +       // -->
237 +       //   td->scale[1]sign =  sign1tv * signcosv * pvecs[1][tv]
238 +       //   td->scale[1]sign = -sign1sv * signsinv * pvecs[1][tv]
239 +       //   td->scale[0]sign =  sign0tv * signsinv * pvecs[0][sv]
240 +       //   td->scale[0]sign =  sign0sv * signcosv * pvecs[0][sv]
241 +       // which to choose?
242 +       // the one with the larger impact on the original texcoords, of course
243 +       // to minimize the effect of roundoff errors that may flip the signs!
244 +       
245 +       td->scale[0] *= HighestImpactSign(STfromXYZ[0][tv] * +sin(ang), STfromXYZ[0][sv] * cos(ang)) * pvecs[0][sv];
246 +       td->scale[1] *= HighestImpactSign(STfromXYZ[1][sv] * -sin(ang), STfromXYZ[1][tv] * cos(ang)) * pvecs[1][tv];
247 +
248 +       td->rotate = ang * 180 / Q_PI; // FIXME possibly snap this to 0/90/180 (270 can't happen)?
249 +}
250 +
251 +
252 +/*
253  ================
254  Face_MakePlane
255  ================
256 @@ -462,6 +548,135 @@
257         xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
258  }
259  
260 +long double SarrusDetScalar(long double a1, long double b1, long double c1, long double a2, long double b2, long double c2, long double a3, long double b3, long double c3)
261 +{
262 +       return a1 * b2 * c3 + a2 * b3 * c1 + a3 * b1 * c2
263 +            - a1 * c2 * b3 - a2 * c3 * b1 - a3 * c1 * b2;
264 +}
265 +
266 +void SarrusSolve(long double a1, long double b1, long double c1, long double d1, long double a2, long double b2, long double c2, long double d2, long double a3, long double b3, long double c3, long double d3, long double *a, long double *b, long double *c)
267 +{
268 +       long double det;
269 +       det = SarrusDetScalar(a1, b1, c1,
270 +                             a2, b2, c2,
271 +                                                 a3, b3, c3);
272 +       *a =  SarrusDetScalar(d1, b1, c1,
273 +                             d2, b2, c2,
274 +                                                 d3, b3, c3) / det;
275 +       *b =  SarrusDetScalar(a1, d1, c1,
276 +                             a2, d2, c2,
277 +                                                 a3, d3, c3) / det;
278 +       *c =  SarrusDetScalar(a1, b1, d1,
279 +                             a2, b2, d2,
280 +                                                 a3, b3, d3) / det;
281 +}
282 +
283 +void Face_TexdefFromTextureCoordinates ( float *xyzst1, float *xyzst2, float *xyzst3, qtexture_t *q, face_t *f)
284 +{
285 +       vec3_t          pvecs[2];
286 +       int sv, tv, uv;
287 +
288 +    long double   STfromXYZ[2][4];
289 +
290 +    // get natural texture axis
291 +    TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
292 +
293 +    if (pvecs[0][0])
294 +        sv = 0;
295 +    else if (pvecs[0][1])
296 +        sv = 1;
297 +    else
298 +        sv = 2;
299 +
300 +    if (pvecs[1][0])
301 +        tv = 0;
302 +    else if (pvecs[1][1])
303 +        tv = 1;
304 +    else
305 +        tv = 2;
306 +
307 +       uv = 3 - sv - tv; // the "other one"
308 +
309 +    // find the STfromXYZ 4-vectors
310 +       /*
311 +       SARRUS-SOLVE:
312 +               xyzst1[3] == xyzst1[sv] * STfromXYZ[0][sv] + xyzst1[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
313 +               xyzst2[3] == xyzst2[sv] * STfromXYZ[0][sv] + xyzst2[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
314 +               xyzst3[3] == xyzst3[sv] * STfromXYZ[0][sv] + xyzst3[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
315 +       FOR: STfromXYZ[0]
316 +       GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
317 +       SARRUS-SOLVE:
318 +               xyzst1[4] == xyzst1[sv] * STfromXYZ[1][sv] + xyzst1[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
319 +               xyzst2[4] == xyzst2[sv] * STfromXYZ[1][sv] + xyzst2[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
320 +               xyzst3[4] == xyzst3[sv] * STfromXYZ[1][sv] + xyzst3[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
321 +       FOR: STfromXYZ[1]
322 +       GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
323 +       */
324 +
325 +       STfromXYZ[0][uv] = 0;
326 +       SarrusSolve(
327 +               xyzst1[sv],        xyzst1[tv],        1,               xyzst1[3],
328 +               xyzst2[sv],        xyzst2[tv],        1,               xyzst2[3],
329 +               xyzst3[sv],        xyzst3[tv],        1,               xyzst3[3],
330 +               &STfromXYZ[0][sv], &STfromXYZ[0][tv], &STfromXYZ[0][3]
331 +       );
332 +
333 +       STfromXYZ[1][uv] = 0;
334 +       SarrusSolve(
335 +               xyzst1[sv],        xyzst1[tv],        1,               xyzst1[4],
336 +               xyzst2[sv],        xyzst2[tv],        1,               xyzst2[4],
337 +               xyzst3[sv],        xyzst3[tv],        1,               xyzst3[4],
338 +               &STfromXYZ[1][sv], &STfromXYZ[1][tv], &STfromXYZ[1][3]
339 +       );
340 +
341 +       /*
342 +       printf("%s\n", q->name);
343 +
344 +       printf("%f == %Lf\n", xyzst1[3], DotProduct (xyzst1, STfromXYZ[0]) + STfromXYZ[0][3]);
345 +       printf("%f == %Lf\n", xyzst2[3], DotProduct (xyzst2, STfromXYZ[0]) + STfromXYZ[0][3]);
346 +       printf("%f == %Lf\n", xyzst3[3], DotProduct (xyzst3, STfromXYZ[0]) + STfromXYZ[0][3]);
347 +       printf("%f == %Lf\n", xyzst1[4], DotProduct (xyzst1, STfromXYZ[1]) + STfromXYZ[1][3]);
348 +       printf("%f == %Lf\n", xyzst2[4], DotProduct (xyzst2, STfromXYZ[1]) + STfromXYZ[1][3]);
349 +       printf("%f == %Lf\n", xyzst3[4], DotProduct (xyzst3, STfromXYZ[1]) + STfromXYZ[1][3]);
350 +
351 +    float   newSTfromXYZ[2][4];
352 +
353 +       printf("old: %Lf,%Lf,%Lf,%Lf %Lf,%Lf,%Lf,%Lf\n",
354 +               STfromXYZ[0][0], STfromXYZ[0][1], STfromXYZ[0][2], STfromXYZ[0][3],
355 +               STfromXYZ[1][0], STfromXYZ[1][1], STfromXYZ[1][2], STfromXYZ[1][3]);
356 +       */
357 +
358 +       Face_TexdefFromTextureVectors (f,  STfromXYZ, pvecs, sv, tv);
359 +
360 +       /*
361 +       Face_TextureVectors(f, newSTfromXYZ);
362 +
363 +       printf("new: %f,%f,%f,%f %f,%f,%f,%f\n",
364 +               newSTfromXYZ[0][0], newSTfromXYZ[0][1], newSTfromXYZ[0][2], newSTfromXYZ[0][3],
365 +               newSTfromXYZ[1][0], newSTfromXYZ[1][1], newSTfromXYZ[1][2], newSTfromXYZ[1][3]);
366 +
367 +       float newxyzst1[5];
368 +       float newxyzst2[5];
369 +       float newxyzst3[5];
370 +       VectorCopy(xyzst1, newxyzst1);
371 +       VectorCopy(xyzst2, newxyzst2);
372 +       VectorCopy(xyzst3, newxyzst3);
373 +       EmitTextureCoordinates (newxyzst1, q, f);
374 +       EmitTextureCoordinates (newxyzst2, q, f);
375 +       EmitTextureCoordinates (newxyzst3, q, f);
376 +       printf("Face_TexdefFromTextureCoordinates: %f,%f %f,%f %f,%f -> %f,%f %f,%f %f,%f\n",
377 +               xyzst1[3], xyzst1[4],
378 +               xyzst2[3], xyzst2[4],
379 +               xyzst3[3], xyzst3[4],
380 +               newxyzst1[3], newxyzst1[4],
381 +               newxyzst2[3], newxyzst2[4],
382 +               newxyzst3[3], newxyzst3[4]);
383 +       // TODO why do these differ, but not the previous ones? this makes no sense whatsoever
384 +       */
385 +}
386 +
387 +
388 +
389  //==========================================================================
390  
391  /*
392 Index: radiant/qe3.h
393 ===================================================================
394 --- radiant/qe3.h       (revision 297)
395 +++ radiant/qe3.h       (working copy)
396 @@ -535,6 +535,7 @@
397  void EmitBrushPrimitTextureCoordinates(face_t *, winding_t *);
398  // EmitTextureCoordinates, is old code used for brush to brush primitive conversion
399  void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f);
400 +void Face_TexdefFromTextureCoordinates ( float *xyzst1, float *xyzst2, float *xyzst3, qtexture_t *q, face_t *f);
401  //void BrushPrimit_Parse(brush_t *);
402  // compute a fake shift scale rot representation from the texture matrix
403  void TexMatToFakeTexCoords( vec_t texMat[2][3], float shift[2], float *rot, float scale[2] );
404 Index: config.py
405 ===================================================================
406 --- config.py   (revision 297)
407 +++ config.py   (working copy)
408 @@ -236,7 +236,7 @@
409                 if ( useZ ):
410                         env.Append( LIBS = 'z' )
411  
412 -               env.Append( CFLAGS = baseflags )
413 +               env.Append( CCFLAGS = baseflags )
414                 env.Append( CXXFLAGS = baseflags + [ '-fpermissive', '-fvisibility-inlines-hidden' ] )
415                 env.Append( CPPPATH = [ 'include', 'libs' ] )
416                 env.Append( CPPDEFINES = [ 'Q_NO_STLPORT' ] )
417 Index: plugins/surface/surfacedialog.cpp
418 ===================================================================
419 --- plugins/surface/surfacedialog.cpp   (revision 297)
420 +++ plugins/surface/surfacedialog.cpp   (working copy)
421 @@ -1027,7 +1027,7 @@
422    gtk_widget_set_sensitive( GTK_WIDGET( vscale_value_spinbutton ), FALSE );
423  
424    rotate_value_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0);
425 -  rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 0);
426 +  rotate_value_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_value_spinbutton_adj), 1, 4);
427    gtk_widget_show (rotate_value_spinbutton);
428    gtk_table_attach (GTK_TABLE (table1), rotate_value_spinbutton, 1, 2, 10, 11,
429                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
430 @@ -1078,7 +1078,7 @@
431    gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (vscale_offset_spinbutton), TRUE);
432  
433    rotate_offset_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0);
434 -  rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 2);
435 +  rotate_offset_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_offset_spinbutton_adj), 0, 4);
436    gtk_widget_show (rotate_offset_spinbutton);
437    gtk_table_attach (GTK_TABLE (table1), rotate_offset_spinbutton, 2, 3, 10, 11,
438                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
439 @@ -1121,7 +1121,7 @@
440    gtk_spin_button_set_update_policy (GTK_SPIN_BUTTON (vscale_step_spinbutton), GTK_UPDATE_IF_VALID);
441  
442    rotate_step_spinbutton_adj = gtk_adjustment_new (0.0, -360.0, 360.0, 1.0, 10.0, 10.0);
443 -  rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 2);
444 +  rotate_step_spinbutton = gtk_spin_button_new (GTK_ADJUSTMENT (rotate_step_spinbutton_adj), 1, 4);
445    gtk_widget_show (rotate_step_spinbutton);
446    gtk_table_attach (GTK_TABLE (table1), rotate_step_spinbutton, 3, 4, 10, 11,
447                      (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
448 Index: radiant/preferences.h
449 ===================================================================
450 --- radiant/preferences.h       (revision 297)
451 +++ radiant/preferences.h       (working copy)
452 @@ -579,6 +579,7 @@
453    bool  m_bPluginToolbar;
454    bool  m_bNoClamp;
455         //++timo this is most likely broken, I don't know what it's supposed to do
456 +  bool  m_bSnap;
457    Str   m_strUserPath;
458    int   m_nRotation;
459    bool  m_bChaseMouse;
460 Index: radiant/mainframe.cpp
461 ===================================================================
462 --- radiant/mainframe.cpp       (revision 297)
463 +++ radiant/mainframe.cpp       (working copy)
464 @@ -3824,7 +3824,7 @@
465    item  = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_view_opengllighting"));
466    gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bGLLighting) ? TRUE : FALSE);
467    item  = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid"));
468 -  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE);
469 +  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), (g_PrefsDlg.m_bSnap) ? TRUE : FALSE);
470  
471    item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "tb_view_cubicclipping"));
472    gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (item), (g_PrefsDlg.m_bCubicClipping) ? TRUE : FALSE);
473 @@ -4658,7 +4658,7 @@
474      GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid"));
475      g_bIgnoreCommands++;
476      gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item),
477 -                                    (!g_PrefsDlg.m_bNoClamp) ? TRUE : FALSE);
478 +                                    (g_PrefsDlg.m_bSnap) ? TRUE : FALSE);
479      g_bIgnoreCommands--;
480    }
481  }
482 @@ -5686,12 +5686,12 @@
483  
484  void MainFrame::OnSnaptogrid()
485  {
486 -  g_PrefsDlg.m_bNoClamp ^= 1;
487 +  g_PrefsDlg.m_bSnap ^= 1;
488    g_PrefsDlg.SavePrefs ();
489  
490    GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid"));
491    g_bIgnoreCommands++;
492 -  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bNoClamp ? FALSE : TRUE);
493 +  gtk_check_menu_item_set_active (GTK_CHECK_MENU_ITEM (item), g_PrefsDlg.m_bSnap ? TRUE : FALSE);
494    g_bIgnoreCommands--;
495  }
496  
497 Index: radiant/preferences.cpp
498 ===================================================================
499 --- radiant/preferences.cpp     (revision 297)
500 +++ radiant/preferences.cpp     (working copy)
501 @@ -96,6 +96,7 @@
502  #define WIDETOOLBAR_KEY         "WideToolBar"
503  #define PLUGINTOOLBAR_KEY "PluginToolBar"
504  #define NOCLAMP_KEY             "NoClamp"
505 +#define SNAP_KEY                "Snap"
506  #define PREFAB_KEY              "PrefabPath"
507  #define USERINI_KEY             "UserINIPath"
508  #define ROTATION_KEY            "Rotation"
509 @@ -635,6 +636,7 @@
510    m_bWideToolbar = TRUE;
511    m_bPluginToolbar = TRUE;
512    m_bNoClamp = FALSE;
513 +  m_bSnap = TRUE;
514    m_strUserPath = "";
515    m_nRotation = 0;
516    m_bChaseMouse = FALSE;
517 @@ -2342,6 +2344,12 @@
518    gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
519    AddDialogData (check, &m_bNoClamp, DLG_CHECK_BOOL);
520  
521 +  // Snap to grid
522 +  check = gtk_check_button_new_with_label (_("Snap to grid"));
523 +  gtk_widget_show (check);
524 +  gtk_box_pack_start(GTK_BOX(vbox), check, FALSE, FALSE, 0);
525 +  AddDialogData (check, &m_bSnap, DLG_CHECK_BOOL);
526 +
527    // Select patch by bounding box
528    check = gtk_check_button_new_with_label (_("Select patches by bounding box"));
529    gtk_widget_show (check);
530 @@ -2912,6 +2920,7 @@
531    m_nShader = m_nLatchedShader;
532  
533    mLocalPrefs.GetPref(NOCLAMP_KEY,            &m_bNoClamp,                    FALSE);
534 +  mLocalPrefs.GetPref(SNAP_KEY,               &m_bSnap,                       TRUE);
535    mLocalPrefs.GetPref(USERINI_KEY,            &m_strUserPath,                 "");
536    mLocalPrefs.GetPref(ROTATION_KEY,           &m_nRotation,                   45);
537    mLocalPrefs.GetPref(CHASEMOUSE_KEY,         &m_bChaseMouse,                 TRUE);
538 Index: radiant/surfaceplugin.cpp
539 ===================================================================
540 --- radiant/surfaceplugin.cpp   (revision 297)
541 +++ radiant/surfaceplugin.cpp   (working copy)
542 @@ -73,6 +73,7 @@
543    face_t       *f;
544    brush_t      *b;
545    texdef_to_face_t *position, *prev_pos;
546 +  brushprimit_texdef_t bp;
547  
548    if(selected_brushes.next != &selected_brushes)
549    {
550 @@ -85,8 +86,14 @@
551          {
552              position->face = f;
553              position->brush = b;
554 -            position->texdef = f->texdef;
555 -            position->orig_texdef = f->texdef;
556 +                       position->texdef = f->texdef;
557 +                       if(g_qeglobals.m_bBrushPrimitMode)
558 +                       {
559 +                               ConvertTexMatWithQTexture(&f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture(), &bp, NULL);
560 +                               TexMatToFakeTexCoords(bp.coords, position->texdef.shift, &position->texdef.rotate, position->texdef.scale);
561 +                               position->orig_bp_texdef = bp;
562 +                       }
563 +                       position->orig_texdef = position->texdef;
564              prev_pos->next = position;
565              prev_pos = position;
566              position++;
567 @@ -103,7 +110,13 @@
568      position->face = f;
569      position->brush = b;
570      position->texdef = f->texdef;
571 -    position->orig_texdef = f->texdef;
572 +       if(g_qeglobals.m_bBrushPrimitMode)
573 +       {
574 +               ConvertTexMatWithQTexture(&f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture(), &bp, NULL);
575 +               TexMatToFakeTexCoords(bp.coords, position->texdef.shift, &position->texdef.rotate, position->texdef.scale);
576 +               position->orig_bp_texdef = bp;
577 +       }
578 +    position->orig_texdef = position->texdef;
579      prev_pos = position;
580      for(i=1; i<g_ptrSelectedFaces.GetSize(); i++)
581      {
582 @@ -113,7 +126,13 @@
583        position->face = f;
584        position->brush = b;
585        position->texdef = f->texdef;
586 -      position->orig_texdef = f->texdef;
587 +         if(g_qeglobals.m_bBrushPrimitMode)
588 +         {
589 +                 ConvertTexMatWithQTexture(&f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture(), &bp, NULL);
590 +                 TexMatToFakeTexCoords(bp.coords, position->texdef.shift, &position->texdef.rotate, position->texdef.scale);
591 +                 position->orig_bp_texdef = bp;
592 +         }
593 +      position->orig_texdef = position->texdef;
594        prev_pos->next = position;
595        prev_pos = position;
596      }
597 @@ -187,7 +206,7 @@
598        if (b_isQuake2)
599          SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->orig_texdef, bFit_to_Scale);
600        else
601 -        SetFaceTexdef(texdef_to_face->face, &texdef_to_face->orig_texdef, NULL);
602 +        SetFaceTexdef(texdef_to_face->face, &texdef_to_face->orig_texdef, &texdef_to_face->orig_bp_texdef, bFit_to_Scale);
603  
604        Undo_Start("set facelist texdefs");
605  
606 @@ -204,7 +223,11 @@
607      if (b_isQuake2)
608        SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->texdef,  bFit_to_Scale);
609      else
610 -      SetFaceTexdef(texdef_to_face->face, &texdef_to_face->texdef, NULL , bFit_to_Scale);
611 +       {
612 +         brushprimit_texdef_t brushprimit_texdef;
613 +         FakeTexCoordsToTexMat(texdef_to_face->texdef.shift, texdef_to_face->texdef.rotate, texdef_to_face->texdef.scale, brushprimit_texdef.coords);
614 +      SetFaceTexdef(texdef_to_face->face, &texdef_to_face->texdef, &brushprimit_texdef , bFit_to_Scale);
615 +       }
616      Brush_Build(texdef_to_face->brush);
617      if(bFit_to_Scale)
618        texdef_to_face->texdef = texdef_to_face->face->texdef;
619 @@ -222,7 +245,10 @@
620          Undo_End();
621         // Over-write the orig_texdef list, cementing the change.
622         for(texdef_to_face = texdef_face_list; texdef_to_face; texdef_to_face = texdef_to_face->next)
623 +       {
624           texdef_to_face->orig_texdef = texdef_to_face->texdef;
625 +         texdef_to_face->orig_bp_texdef = texdef_to_face->face->brushprimit_texdef;
626 +       }
627        }
628    }
629  
630 @@ -232,6 +258,7 @@
631  void SI_FaceList_FitTexture(texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth)
632  {
633    texdef_to_face_t* temp_texdef_face_list;
634 +  brushprimit_texdef_t bp;
635  
636    if (!si_texdef_face_list)
637      return;
638 @@ -241,6 +268,12 @@
639      Face_FitTexture(temp_texdef_face_list->face, nHeight, nWidth);
640      Brush_Build(temp_texdef_face_list->brush,true,true,false,false);
641      // Write changes to our working Texdef list
642 +       
643 +       if(g_qeglobals.m_bBrushPrimitMode)
644 +       {
645 +               ConvertTexMatWithQTexture(&temp_texdef_face_list->face->brushprimit_texdef, QERApp_Shader_ForName( temp_texdef_face_list->face->texdef.GetName() )->getTexture(), &bp, NULL);
646 +               TexMatToFakeTexCoords(bp.coords, temp_texdef_face_list->face->texdef.shift, &temp_texdef_face_list->face->texdef.rotate, temp_texdef_face_list->face->texdef.scale);
647 +       }
648      temp_texdef_face_list->texdef = temp_texdef_face_list->face->texdef;
649    }
650  
651 Index: radiant/drag.cpp
652 ===================================================================
653 --- radiant/drag.cpp    (revision 297)
654 +++ radiant/drag.cpp    (working copy)
655 @@ -770,7 +770,7 @@
656                 for (i=0 ; i<3 ; i++)
657                 {
658                         move[i] = drag_xvec[i]*(x - pressx)     + drag_yvec[i]*(y - pressy);
659 -                       if (!g_PrefsDlg.m_bNoClamp)
660 +                       if (g_PrefsDlg.m_bSnap)
661                         {
662                                 move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
663                         }
664 Index: radiant/xywindow.cpp
665 ===================================================================
666 --- radiant/xywindow.cpp        (revision 297)
667 +++ radiant/xywindow.cpp        (working copy)
668 @@ -1501,7 +1501,7 @@
669    for (i=0 ; i<3 ; i++)
670    {
671      delta[i] = xvec[i] * (x - m_nPressx) + yvec[i] * (y - m_nPressy);
672 -    if (!g_PrefsDlg.m_bNoClamp)
673 +    if (g_PrefsDlg.m_bSnap)
674      {
675        delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
676      }
677 @@ -2135,13 +2135,13 @@
678  
679  void XYWnd::SnapToPoint (int x, int y, vec3_t point)
680  {
681 -  if (g_PrefsDlg.m_bNoClamp)
682 +  if (g_PrefsDlg.m_bSnap)
683    {
684 -    XY_ToPoint(x, y, point);
685 +    XY_ToGridPoint(x, y, point);
686    }
687    else
688    {
689 -    XY_ToGridPoint(x, y, point);
690 +    XY_ToPoint(x, y, point);
691    }
692  }
693  
694 Index: radiant/brush_primit.cpp
695 ===================================================================
696 --- radiant/brush_primit.cpp    (revision 297)
697 +++ radiant/brush_primit.cpp    (working copy)
698 @@ -186,11 +186,11 @@
699  {
700  #ifdef DBG_BP
701         // check this matrix is orthogonal
702 -       if (fabs(texMat[0][0]*texMat[0][1]+texMat[1][0]*texMat[1][1])>ZERO_EPSILON)
703 +       if (fabs(texMat[0][0]*1.0L*texMat[0][1]+texMat[1][0]*1.0L*texMat[1][1])>ZERO_EPSILON)
704                 Sys_Printf("Warning : non orthogonal texture matrix in TexMatToFakeTexCoords\n");
705  #endif
706 -       scale[0]=sqrt(texMat[0][0]*texMat[0][0]+texMat[1][0]*texMat[1][0]);
707 -       scale[1]=sqrt(texMat[0][1]*texMat[0][1]+texMat[1][1]*texMat[1][1]);
708 +       scale[0]=sqrt(texMat[0][0]*1.0L*texMat[0][0]+texMat[1][0]*1.0L*texMat[1][0]);
709 +       scale[1]=sqrt(texMat[0][1]*1.0L*texMat[0][1]+texMat[1][1]*1.0L*texMat[1][1]);
710  #ifdef DBG_BP
711         if (scale[0]<ZERO_EPSILON || scale[1]<ZERO_EPSILON)
712                 Sys_Printf("Warning : unexpected scale==0 in TexMatToFakeTexCoords\n");
713 @@ -210,7 +210,7 @@
714                         *rot=-90.0f;
715         }
716         else
717 -       *rot = RAD2DEG( atan2( texMat[1][0], texMat[0][0] ) );
718 +       *rot = RAD2DEG( atan2( texMat[1][0]*1.0L, texMat[0][0]*1.0L ) );
719         shift[0] = -texMat[0][2];
720         shift[1] = texMat[1][2];
721  }
722 @@ -219,10 +219,10 @@
723  // the matrix returned must be understood as a qtexture_t with width=2 height=2 ( the default one )
724  void FakeTexCoordsToTexMat( float shift[2], float rot, float scale[2], vec_t texMat[2][3] )
725  {
726 -       texMat[0][0] = scale[0] * cos( DEG2RAD( rot ) );
727 -       texMat[1][0] = scale[0] * sin( DEG2RAD( rot ) );
728 -       texMat[0][1] = -1.0f * scale[1] * sin( DEG2RAD( rot ) );
729 -       texMat[1][1] = scale[1] * cos( DEG2RAD( rot ) );
730 +       texMat[0][0] = scale[0] *1.0L* cos( DEG2RAD( 1.0L*rot ) );
731 +       texMat[1][0] = scale[0] *1.0L* sin( DEG2RAD( 1.0L*rot ) );
732 +       texMat[0][1] = -scale[1] *1.0L* sin( DEG2RAD( 1.0L*rot ) );
733 +       texMat[1][1] = scale[1] *1.0L* cos( DEG2RAD( 1.0L*rot ) );
734         texMat[0][2] = -shift[0];
735         texMat[1][2] = shift[1];
736  }
737 Index: radiant/select.cpp
738 ===================================================================
739 --- radiant/select.cpp  (revision 297)
740 +++ radiant/select.cpp  (working copy)
741 @@ -735,7 +735,7 @@
742         vec3_t  mins, maxs;
743         int             i;
744  
745 -  if (g_PrefsDlg.m_bNoClamp)
746 +  if (!g_PrefsDlg.m_bSnap)
747    {
748      Select_GetTrueMid(mid);
749      return;
750 Index: include/isurfaceplugin.h
751 ===================================================================
752 --- include/isurfaceplugin.h    (revision 297)
753 +++ include/isurfaceplugin.h    (working copy)
754 @@ -62,6 +62,7 @@
755    face_t *face;     // Face of Texdef
756    texdef_t texdef;  // Working texdef
757    texdef_t orig_texdef;  // Original, for baselining changes
758 +  brushprimit_texdef_t orig_bp_texdef; // Original, for undo
759  };
760  
761  
762 Index: radiant/groupdialog.cpp
763 ===================================================================
764 --- radiant/groupdialog.cpp     (revision 297)
765 +++ radiant/groupdialog.cpp     (working copy)
766 @@ -1328,7 +1328,7 @@
767  
768              {
769                // Spawnflags (4 colums wide max, or window gets too wide.)
770 -              GtkWidget* LayoutTable = gtk_table_new (4, 4, FALSE);
771 +              LayoutTable = gtk_table_new (4, 4, FALSE);
772                gtk_box_pack_start (GTK_BOX (vbox2), LayoutTable, FALSE, TRUE, 0);
773                gtk_widget_show(LayoutTable);
774  
775 Index: tools/quake3/q3map2/convert_map.c
776 ===================================================================
777 --- tools/quake3/q3map2/convert_map.c   (revision 290)
778 +++ tools/quake3/q3map2/convert_map.c   (working copy)
779 @@ -45,6 +45,105 @@
780  #define        SNAP_FLOAT_TO_INT       4
781  #define        SNAP_INT_TO_FLOAT       (1.0 / SNAP_FLOAT_TO_INT)
782  
783 +typedef vec_t vec2_t[2];
784 +
785 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
786 +                    vec_t a10, vec_t a11, vec_t a12,
787 +                    vec_t a20, vec_t a21, vec_t a22)
788 +{
789 +       return
790 +               a00 * (a11 * a22 - a12 * a21)
791 +       -       a01 * (a10 * a22 - a12 * a20)
792 +       +       a02 * (a10 * a21 - a11 * a20);
793 +}
794 +
795 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
796 +{
797 +       bspDrawSurface_t *s;
798 +       int i;
799 +       int t;
800 +       vec_t best = 0;
801 +       vec_t thisarea;
802 +       vec3_t normdiff;
803 +       vec3_t v1v0, v2v0, norm;
804 +       bspDrawVert_t *vert[3];
805 +       winding_t *polygon;
806 +       plane_t *buildPlane = &mapplanes[buildSide->planenum];
807 +       int matches = 0;
808 +
809 +       // first, start out with NULLs
810 +       bestVert[0] = bestVert[1] = bestVert[2] = NULL;
811 +
812 +       // brute force through all surfaces
813 +       for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
814 +       {
815 +               if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
816 +                       continue;
817 +               if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
818 +                       continue;
819 +               for(t = 0; t + 3 <= s->numIndexes; t += 3)
820 +               {
821 +                       vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
822 +                       vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
823 +                       vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
824 +                       if(s->surfaceType == MST_PLANAR)
825 +                       {
826 +                               VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
827 +                               VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
828 +                               VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
829 +                       }
830 +                       else
831 +                       {
832 +                               // this is more prone to roundoff errors, but with embedded
833 +                               // models, there is no better way
834 +                               VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
835 +                               VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
836 +                               CrossProduct(v2v0, v1v0, norm);
837 +                               VectorNormalize(norm, norm);
838 +                               VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
839 +                       }
840 +                       if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
841 +                       if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
842 +                       if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
843 +                       // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
844 +                       polygon = CopyWinding(buildSide->winding);
845 +                       for(i = 0; i < 3; ++i)
846 +                       {
847 +                               // 0: 1, 2
848 +                               // 1: 2, 0
849 +                               // 2; 0, 1
850 +                               vec3_t *v1 = &vert[(i+1)%3]->xyz;
851 +                               vec3_t *v2 = &vert[(i+2)%3]->xyz;
852 +                               vec3_t triNormal;
853 +                               vec_t triDist;
854 +                               vec3_t sideDirection;
855 +                               // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
856 +                               VectorSubtract(*v2, *v1, sideDirection);
857 +                               CrossProduct(sideDirection, buildPlane->normal, triNormal);
858 +                               triDist = DotProduct(*v1, triNormal);
859 +                               ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
860 +                               if(!polygon)
861 +                                       goto exwinding;
862 +                       }
863 +                       thisarea = WindingArea(polygon);
864 +                       if(thisarea > 0)
865 +                               ++matches;
866 +                       if(thisarea > best)
867 +                       {
868 +                               best = thisarea;
869 +                               bestVert[0] = vert[0];
870 +                               bestVert[1] = vert[1];
871 +                               bestVert[2] = vert[2];
872 +                       }
873 +                       FreeWinding(polygon);
874 +exwinding:
875 +                       ;
876 +               }
877 +       }
878 +       //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
879 +       //      fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
880 +}
881 +
882  static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
883  {
884         int                             i, j;
885 @@ -53,12 +152,17 @@
886         bspShader_t             *shader;
887         char                    *texture;
888         bspPlane_t              *plane;
889 +       plane_t         *buildPlane;
890         vec3_t                  pts[ 3 ];
891 +       bspDrawVert_t   *vert[3];
892 +       int valid;
893         
894         
895         /* start brush */
896         fprintf( f, "\t// brush %d\n", num );
897         fprintf( f, "\t{\n" );
898 +       fprintf( f, "\tbrushDef\n" );
899 +       fprintf( f, "\t{\n" );
900         
901         /* clear out build brush */
902         for( i = 0; i < buildBrush->numsides; i++ )
903 @@ -108,9 +212,88 @@
904                 /* get build side */
905                 buildSide = &buildBrush->sides[ i ];
906                 
907 +               /* get plane */
908 +               buildPlane = &mapplanes[ buildSide->planenum ];
909 +               
910                 /* dummy check */
911                 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
912                         continue;
913 +
914 +               // st-texcoords -> texMat block
915 +               // start out with dummy
916 +               VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
917 +               VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
918 +
919 +               // find surface for this side (by brute force)
920 +               // surface format:
921 +               //   - meshverts point in pairs of three into verts
922 +               //   - (triangles)
923 +               //   - find the triangle that has most in common with our side
924 +               GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
925 +               valid = 0;
926 +
927 +               if(vert[0] && vert[1] && vert[2])
928 +               {
929 +                       int i;
930 +                       vec3_t texX, texY;
931 +                       vec3_t xy1I, xy1J, xy1K;
932 +                       vec2_t stI, stJ, stK;
933 +                       vec_t D, D0, D1, D2;
934 +
935 +                       ComputeAxisBase(buildPlane->normal, texX, texY);
936 +
937 +                       VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
938 +                       VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
939 +                       VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
940 +                       stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
941 +                       stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
942 +                       stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
943 +
944 +                       //   - solve linear equations:
945 +                       //     - (x, y) := xyz . (texX, texY)
946 +                       //     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
947 +                       //       (for three vertices)
948 +                       D = Det3x3(
949 +                               xy1I[0], xy1I[1], 1,
950 +                               xy1J[0], xy1J[1], 1,
951 +                               xy1K[0], xy1K[1], 1
952 +                       );
953 +                       if(D != 0)
954 +                       {
955 +                               for(i = 0; i < 2; ++i)
956 +                               {
957 +                                       D0 = Det3x3(
958 +                                               stI[i], xy1I[1], 1,
959 +                                               stJ[i], xy1J[1], 1,
960 +                                               stK[i], xy1K[1], 1
961 +                                       );
962 +                                       D1 = Det3x3(
963 +                                               xy1I[0], stI[i], 1,
964 +                                               xy1J[0], stJ[i], 1,
965 +                                               xy1K[0], stK[i], 1
966 +                                       );
967 +                                       D2 = Det3x3(
968 +                                               xy1I[0], xy1I[1], stI[i],
969 +                                               xy1J[0], xy1J[1], stJ[i],
970 +                                               xy1K[0], xy1K[1], stK[i]
971 +                                       );
972 +                                       VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
973 +                                       valid = 1;
974 +                               }
975 +                       }
976 +                       else
977 +                               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",
978 +                                       buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
979 +                                       vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], 
980 +                                       texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
981 +                                       vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
982 +                                       vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
983 +                                       vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
984 +                                       );
985 +               }
986 +               else
987 +                       if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
988 +                               fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
989                 
990                 /* get texture name */
991                 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
992 @@ -129,14 +312,21 @@
993                 
994                 /* print brush side */
995                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
996 -               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",
997 +               fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
998                         pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
999                         pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
1000                         pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
1001 -                       texture );
1002 +                       buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
1003 +                       buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
1004 +                       texture,
1005 +                       // DEBUG: valid ? 0 : C_DETAIL
1006 +                       0
1007 +                       );
1008 +               // TODO write brush primitives format here
1009         }
1010         
1011         /* end brush */
1012 +       fprintf( f, "\t}\n" );
1013         fprintf( f, "\t}\n\n" );
1014  }
1015  
1016 Index: tools/quake3/q3map2/main.c
1017 ===================================================================
1018 --- tools/quake3/q3map2/main.c  (revision 290)
1019 +++ tools/quake3/q3map2/main.c  (working copy)
1020 @@ -276,6 +276,18 @@
1021                         else
1022                                 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
1023                 }
1024 +               else if( !strcmp( argv[ i ],  "-ne" ) )
1025 +               {
1026 +                       normalEpsilon = atof( argv[ i + 1 ] );
1027 +                       i++;
1028 +                       Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
1029 +               }
1030 +               else if( !strcmp( argv[ i ],  "-de" ) )
1031 +               {
1032 +                       distanceEpsilon = atof( argv[ i + 1 ] );
1033 +                       i++;
1034 +                       Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
1035 +               }
1036         }
1037         
1038         /* clean up map name */
1039 Index: tools/quake3/q3map2/model.c
1040 ===================================================================
1041 --- tools/quake3/q3map2/model.c (revision 290)
1042 +++ tools/quake3/q3map2/model.c (working copy)
1043 @@ -221,6 +221,8 @@
1044         byte                            *color;
1045         picoIndex_t                     *indexes;
1046         remap_t                         *rm, *glob;
1047 +       double                          normalEpsilon_save;
1048 +       double                          distanceEpsilon_save;
1049         
1050         
1051         /* get model */
1052 @@ -399,9 +401,8 @@
1053                 /* ydnar: giant hack land: generate clipping brushes for model triangles */
1054                 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
1055                 {
1056 -                       vec3_t          points[ 3 ], backs[ 3 ];
1057 +                       vec3_t          points[ 4 ], backs[ 3 ];
1058                         vec4_t          plane, reverse, pa, pb, pc;
1059 -                       vec3_t          nadir;
1060                         
1061                         
1062                         /* temp hack */
1063 @@ -437,90 +438,141 @@
1064                                         /* note: this doesn't work as well as simply using the plane of the triangle, below */
1065                                         for( k = 0; k < 3; k++ )
1066                                         {
1067 -                                               if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
1068 -                                                       fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
1069 +                                               if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
1070 +                                                       fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
1071                                                 {
1072                                                         backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
1073                                                         break;
1074                                                 }
1075                                         }
1076                                 }
1077 +
1078 +                               VectorCopy( points[0], points[3] ); // for cyclic usage
1079                                 
1080                                 /* make plane for triangle */
1081 +                               // div0: add some extra spawnflags:
1082 +                               //   0: snap normals to axial planes for extrusion
1083 +                               //   8: extrude with the original normals
1084 +                               //  16: extrude only with up/down normals (ideal for terrain)
1085 +                               //  24: extrude by distance zero (may need engine changes)
1086                                 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
1087                                 {
1088 +                                       vec3_t bestNormal;
1089 +                                       float backPlaneDistance = 2;
1090 +
1091 +                                       if(spawnFlags & 8) // use a DOWN normal
1092 +                                       {
1093 +                                               if(spawnFlags & 16)
1094 +                                               {
1095 +                                                       // 24: normal as is, and zero width (broken)
1096 +                                                       VectorCopy(plane, bestNormal);
1097 +                                               }
1098 +                                               else
1099 +                                               {
1100 +                                                       // 8: normal as is
1101 +                                                       VectorCopy(plane, bestNormal);
1102 +                                               }
1103 +                                       }
1104 +                                       else
1105 +                                       {
1106 +                                               if(spawnFlags & 16)
1107 +                                               {
1108 +                                                       // 16: UP/DOWN normal
1109 +                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1110 +                                               }
1111 +                                               else
1112 +                                               {
1113 +                                                       // 0: axial normal
1114 +                                                       if(fabs(plane[0]) > fabs(plane[1])) // x>y
1115 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
1116 +                                                                       VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1117 +                                                               else // x>y, z>=y
1118 +                                                                       if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
1119 +                                                                               VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1120 +                                                                       else // z>=x, x>y
1121 +                                                                               VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1122 +                                                       else // y>=x
1123 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
1124 +                                                                       VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
1125 +                                                               else // z>=y, y>=x
1126 +                                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1127 +                                               }
1128 +                                       }
1129 +
1130 +                                       /* build a brush */
1131 +                                       buildBrush = AllocBrush( 48 );
1132 +                                       buildBrush->entityNum = mapEntityNum;
1133 +                                       buildBrush->original = buildBrush;
1134 +                                       buildBrush->contentShader = si;
1135 +                                       buildBrush->compileFlags = si->compileFlags;
1136 +                                       buildBrush->contentFlags = si->contentFlags;
1137 +                                       normalEpsilon_save = normalEpsilon;
1138 +                                       distanceEpsilon_save = distanceEpsilon;
1139 +                                       if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
1140 +                                       {
1141 +                                               buildBrush->detail = qfalse;
1142 +
1143 +                                               // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
1144 +                                               if(normalEpsilon > 0)
1145 +                                                       normalEpsilon = 0;
1146 +                                               if(distanceEpsilon > 0)
1147 +                                                       distanceEpsilon = 0;
1148 +                                       }
1149 +                                       else
1150 +                                               buildBrush->detail = qtrue;
1151 +
1152                                         /* regenerate back points */
1153                                         for( j = 0; j < 3; j++ )
1154                                         {
1155                                                 /* get vertex */
1156                                                 dv = &ds->verts[ ds->indexes[ i + j ] ];
1157 -                                               
1158 -                                               /* copy xyz */
1159 -                                               VectorCopy( dv->xyz, backs[ j ] );
1160 -                                               
1161 -                                               /* find nearest axial to plane normal and push back points opposite */
1162 -                                               for( k = 0; k < 3; k++ )
1163 -                                               {
1164 -                                                       if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
1165 -                                                               fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
1166 -                                                       {
1167 -                                                               backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
1168 -                                                               break;
1169 -                                                       }
1170 -                                               }
1171 +
1172 +                                               // shift by some units
1173 +                                               VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
1174                                         }
1175 -                                       
1176 +
1177                                         /* make back plane */
1178                                         VectorScale( plane, -1.0f, reverse );
1179 -                                       reverse[ 3 ] = -(plane[ 3 ] - 1);
1180 -                                       
1181 -                                       /* make back pyramid point */
1182 -                                       VectorCopy( points[ 0 ], nadir );
1183 -                                       VectorAdd( nadir, points[ 1 ], nadir );
1184 -                                       VectorAdd( nadir, points[ 2 ], nadir );
1185 -                                       VectorScale( nadir, 0.3333333333333f, nadir );
1186 -                                       VectorMA( nadir, -2.0f, plane, nadir );
1187 -                                       
1188 -                                       /* make 3 more planes */
1189 -                                       //%     if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
1190 -                                       //%             PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
1191 -                                       //%             PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
1192 +                                       reverse[ 3 ] = -plane[ 3 ];
1193 +                                       if((spawnFlags & 24) != 24)
1194 +                                               reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
1195 +                                       // 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)
1196 +
1197                                         if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
1198 -                                               PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1199 -                                               PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1200 +                                                       PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1201 +                                                       PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1202                                         {
1203 -                                               /* build a brush */
1204 -                                               buildBrush = AllocBrush( 48 );
1205 -                                               
1206 -                                               buildBrush->entityNum = mapEntityNum;
1207 -                                               buildBrush->original = buildBrush;
1208 -                                               buildBrush->contentShader = si;
1209 -                                               buildBrush->compileFlags = si->compileFlags;
1210 -                                               buildBrush->contentFlags = si->contentFlags;
1211 -                                               buildBrush->detail = qtrue;
1212 -                                               
1213                                                 /* set up brush sides */
1214                                                 buildBrush->numsides = 5;
1215                                                 for( j = 0; j < buildBrush->numsides; j++ )
1216                                                         buildBrush->sides[ j ].shaderInfo = si;
1217 +
1218                                                 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1219 -                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
1220 -                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
1221 -                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
1222 -                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
1223 -                                               
1224 -                                               /* add to entity */
1225 -                                               if( CreateBrushWindings( buildBrush ) )
1226 -                                               {
1227 -                                                       AddBrushBevels();
1228 -                                                       //%     EmitBrushes( buildBrush, NULL, NULL );
1229 -                                                       buildBrush->next = entities[ mapEntityNum ].brushes;
1230 -                                                       entities[ mapEntityNum ].brushes = buildBrush;
1231 -                                                       entities[ mapEntityNum ].numBrushes++;
1232 -                                               }
1233 -                                               else
1234 -                                                       free( buildBrush );
1235 +                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
1236 +                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
1237 +                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
1238 +                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
1239                                         }
1240 +                                       else
1241 +                                       {
1242 +                                               free(buildBrush);
1243 +                                               continue;
1244 +                                       }
1245 +
1246 +                                       normalEpsilon = normalEpsilon_save;
1247 +                                       distanceEpsilon = distanceEpsilon_save;
1248 +
1249 +                                       /* add to entity */
1250 +                                       if( CreateBrushWindings( buildBrush ) )
1251 +                                       {
1252 +                                               AddBrushBevels();
1253 +                                               //%     EmitBrushes( buildBrush, NULL, NULL );
1254 +                                               buildBrush->next = entities[ mapEntityNum ].brushes;
1255 +                                               entities[ mapEntityNum ].brushes = buildBrush;
1256 +                                               entities[ mapEntityNum ].numBrushes++;
1257 +                                       }
1258 +                                       else
1259 +                                               free( buildBrush );
1260                                 }
1261                         }
1262                 }
1263 Index: tools/quake3/q3map2/map.c
1264 ===================================================================
1265 --- tools/quake3/q3map2/map.c   (revision 290)
1266 +++ tools/quake3/q3map2/map.c   (working copy)
1267 @@ -183,9 +183,15 @@
1268  snaps a plane to normal/distance epsilons
1269  */
1270  
1271 -void SnapPlane( vec3_t normal, vec_t *dist )
1272 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
1273  {
1274 -       SnapNormal( normal );
1275 +       // div0: ensure the point "center" stays on the plane (actually, this
1276 +       // rotates the plane around the point center).
1277 +       // if center lies on the plane, it is guaranteed to stay on the plane by
1278 +       // this fix.
1279 +       vec_t centerDist = DotProduct(normal, center);
1280 +       SnapNormal( normal );
1281 +       *dist += (DotProduct(normal, center) - centerDist);
1282  
1283         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1284                 *dist = Q_rint( *dist );
1285 @@ -199,7 +205,7 @@
1286  must be within an epsilon distance of the plane
1287  */
1288  
1289 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
1290 +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?
1291  
1292  #ifdef USE_HASHING
1293  
1294 @@ -207,10 +213,14 @@
1295         int             i, j, hash, h;
1296         plane_t *p;
1297         vec_t   d;
1298 +       vec3_t centerofweight;
1299 +
1300 +       VectorClear(centerofweight);
1301 +       for(i = 0; i < numPoints; ++i)
1302 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1303         
1304 -       
1305         /* hash the plane */
1306 -       SnapPlane( normal, &dist );
1307 +       SnapPlane( normal, &dist, centerofweight );
1308         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1309         
1310         /* search the border bins as well */
1311 @@ -251,7 +261,13 @@
1312         plane_t *p;
1313         
1314  
1315 -       SnapPlane( normal, &dist );
1316 +       vec3_t centerofweight;
1317 +
1318 +       VectorClear(centerofweight);
1319 +       for(i = 0; i < numPoints; ++i)
1320 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1321 +       
1322 +       SnapPlane( normal, &dist, centerofweight );
1323         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
1324         {
1325                 if( PlaneEqual( p, normal, dist ) )
1326 Index: tools/quake3/q3map2/shaders.c
1327 ===================================================================
1328 --- tools/quake3/q3map2/shaders.c       (revision 290)
1329 +++ tools/quake3/q3map2/shaders.c       (working copy)
1330 @@ -747,8 +747,14 @@
1331         }
1332         
1333         if( VectorLength( si->color ) <= 0.0f )
1334 +       {
1335                 ColorNormalize( color, si->color );
1336 -       VectorScale( color, (1.0f / count), si->averageColor );
1337 +               VectorScale( color, (1.0f / count), si->averageColor );
1338 +       }
1339 +       else
1340 +       {
1341 +               VectorCopy( si->color, si->averageColor );
1342 +       }
1343  }
1344  
1345  
1346 Index: tools/quake3/q3map2/light_ydnar.c
1347 ===================================================================
1348 --- tools/quake3/q3map2/light_ydnar.c   (revision 290)
1349 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1350 @@ -1449,6 +1449,8 @@
1351         vec3_t                          color, averageColor, averageDir, total, temp, temp2;
1352         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1353         trace_t                         trace;
1354 +       vec3_t                          flood;
1355 +       float                           *floodlight;
1356         
1357         
1358         /* bail if this number exceeds the number of raw lightmaps */
1359 @@ -1871,6 +1873,78 @@
1360         /* free light list */
1361         FreeTraceLights( &trace );
1362         
1363 +       /*      -----------------------------------------------------------------
1364 +               floodlight pass
1365 +               ----------------------------------------------------------------- */
1366 +
1367 +       if( floodlighty )
1368 +       {
1369 +               /* walk lightmaps */
1370 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1371 +               {
1372 +                       /* early out */
1373 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1374 +                               continue;
1375 +                       
1376 +                       /* apply floodlight to each luxel */
1377 +                       for( y = 0; y < lm->sh; y++ )
1378 +                       {
1379 +                               for( x = 0; x < lm->sw; x++ )
1380 +                               {
1381 +                                       /* get cluster */
1382 +                                       cluster = SUPER_CLUSTER( x, y );
1383 +                                       //%     if( *cluster < 0 )
1384 +                                       //%             continue;
1385 +                                       
1386 +                                       /* get particulars */
1387 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1388 +                                       floodlight = SUPER_FLOODLIGHT( x, y );
1389 +                                       
1390 +                                       flood[0]=floodlightRGB[0]*floodlightIntensity;
1391 +                                       flood[1]=floodlightRGB[1]*floodlightIntensity;
1392 +                                       flood[2]=floodlightRGB[2]*floodlightIntensity;
1393 +                                                    
1394 +                                       /* scale light value */
1395 +                                       VectorScale( flood, *floodlight, flood );
1396 +                                       luxel[0]+=flood[0];
1397 +                                       luxel[1]+=flood[1];
1398 +                                       luxel[2]+=flood[2];
1399 +                                       
1400 +                                       if (luxel[3]==0) luxel[3]=1;
1401 +                               }
1402 +                       }
1403 +               }
1404 +       }
1405 +
1406 +       if (debugnormals)
1407 +       {
1408 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1409 +               {
1410 +                       /* early out */
1411 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1412 +                               continue;
1413 +                       
1414 +                       for( y = 0; y < lm->sh; y++ )
1415 +                       {
1416 +                               for( x = 0; x < lm->sw; x++ )
1417 +                               {
1418 +                                       /* get cluster */
1419 +                                       cluster = SUPER_CLUSTER( x, y );
1420 +                                       //%     if( *cluster < 0 )
1421 +                                       //%             continue;
1422 +                                       
1423 +                                       /* get particulars */
1424 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1425 +                                       normal = SUPER_NORMAL (  x, y );
1426 +               
1427 +                                       luxel[0]=(normal[0]*127)+127;
1428 +                                       luxel[1]=(normal[1]*127)+127;
1429 +                                       luxel[2]=(normal[2]*127)+127;
1430 +                               }
1431 +                       }
1432 +               }
1433 +       }
1434 +       
1435         /* -----------------------------------------------------------------
1436            filter pass
1437            ----------------------------------------------------------------- */
1438 @@ -3123,7 +3197,320 @@
1439         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1440  }
1441  
1442 +/////////////////////////////////////////////////////////////
1443  
1444 +#define FLOODLIGHT_CONE_ANGLE                  88      /* degrees */
1445 +#define FLOODLIGHT_NUM_ANGLE_STEPS             16
1446 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
1447 +#define FLOODLIGHT_NUM_VECTORS                 (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
1448  
1449 +static vec3_t  floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1450 +static int             numFloodVectors = 0;
1451  
1452 +void SetupFloodLight( void )
1453 +{
1454 +       int             i, j;
1455 +       float   angle, elevation, angleStep, elevationStep;
1456 +       const char      *value;
1457 +       double v1,v2,v3,v4,v5;
1458 +       
1459 +       /* note it */
1460 +       Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1461 +       
1462 +       /* calculate angular steps */
1463 +       angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1464 +       elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1465 +       
1466 +       /* iterate angle */
1467 +       angle = 0.0f;
1468 +       for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1469 +       {
1470 +               /* iterate elevation */
1471 +               for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1472 +               {
1473 +                       floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1474 +                       floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1475 +                       floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1476 +                       numFloodVectors++;
1477 +               }
1478 +       }
1479 +       
1480 +       /* emit some statistics */
1481 +       Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1482  
1483 +      /* floodlight */
1484 +       value = ValueForKey( &entities[ 0 ], "_floodlight" );
1485 +       
1486 +       if( value[ 0 ] != '\0' )
1487 +       {
1488 +               v1=v2=v3=0;
1489 +               v4=floodlightDistance;
1490 +               v5=floodlightIntensity;
1491 +               
1492 +               sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1493 +               
1494 +               floodlightRGB[0]=v1;
1495 +               floodlightRGB[1]=v2;
1496 +               floodlightRGB[2]=v3;
1497 +               
1498 +               if (VectorLength(floodlightRGB)==0)
1499 +               {
1500 +                       VectorSet(floodlightRGB,240,240,255);
1501 +               }
1502 +               
1503 +               if (v4<1) v4=1024;
1504 +               if (v5<1) v5=128;
1505 +               
1506 +               floodlightDistance=v4;
1507 +               floodlightIntensity=v5;
1508 +    
1509 +               floodlighty = qtrue;
1510 +               Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1511 +       }
1512 +       else
1513 +       {
1514 +               VectorSet(floodlightRGB,240,240,255);
1515 +               //floodlighty = qtrue;
1516 +               //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1517 +       }
1518 +       VectorNormalize(floodlightRGB,floodlightRGB);
1519 +}
1520 +
1521 +//27 - lighttracer style ambient occlusion light hack.
1522 +//Kudos to the dirtmapping author for most of this source.
1523 +void FloodLightRawLightmap( int rawLightmapNum )
1524 +{
1525 +       int                                     i, x, y, sx, sy, *cluster;
1526 +       float                           *origin, *normal, *floodlight, *floodlight2, average, samples;
1527 +       rawLightmap_t           *lm;
1528 +       surfaceInfo_t           *info;
1529 +       trace_t                         trace;
1530 +       
1531 +       /* bail if this number exceeds the number of raw lightmaps */
1532 +       if( rawLightmapNum >= numRawLightmaps )
1533 +               return;
1534 +       
1535 +       /* get lightmap */
1536 +       lm = &rawLightmaps[ rawLightmapNum ];
1537 +       
1538 +       memset(&trace,0,sizeof(trace_t));
1539 +       /* setup trace */
1540 +       trace.testOcclusion = qtrue;
1541 +       trace.forceSunlight = qfalse;
1542 +       trace.twoSided = qtrue;
1543 +       trace.recvShadows = lm->recvShadows;
1544 +       trace.numSurfaces = lm->numLightSurfaces;
1545 +       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1546 +       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1547 +       trace.testAll = qfalse;
1548 +       trace.distance = 1024;
1549 +       
1550 +       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1551 +       //trace.twoSided = qfalse;
1552 +       for( i = 0; i < trace.numSurfaces; i++ )
1553 +       {
1554 +               /* get surface */
1555 +               info = &surfaceInfos[ trace.surfaces[ i ] ];
1556 +               
1557 +               /* check twosidedness */
1558 +               if( info->si->twoSided )
1559 +               {
1560 +                       trace.twoSided = qtrue;
1561 +                       break;
1562 +               }
1563 +       }
1564 +       
1565 +       /* gather dirt */
1566 +       for( y = 0; y < lm->sh; y++ )
1567 +       {
1568 +               for( x = 0; x < lm->sw; x++ )
1569 +               {
1570 +                       /* get luxel */
1571 +                       cluster = SUPER_CLUSTER( x, y );
1572 +                       origin = SUPER_ORIGIN( x, y );
1573 +                       normal = SUPER_NORMAL( x, y );
1574 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1575 +                       
1576 +                       /* set default dirt */
1577 +                       *floodlight = 0.0f;
1578 +                       
1579 +                       /* only look at mapped luxels */
1580 +                       if( *cluster < 0 )
1581 +                               continue;
1582 +                       
1583 +                       /* copy to trace */
1584 +                       trace.cluster = *cluster;
1585 +                       VectorCopy( origin, trace.origin );
1586 +                       VectorCopy( normal, trace.normal );
1587 +         
1588 +
1589 +               
1590 +                       /* get dirt */
1591 +                       *floodlight = FloodLightForSample( &trace );
1592 +               }
1593 +       }
1594 +       
1595 +       /* testing no filtering */
1596 +       return;
1597 +       
1598 +       /* filter "dirt" */
1599 +       for( y = 0; y < lm->sh; y++ )
1600 +       {
1601 +               for( x = 0; x < lm->sw; x++ )
1602 +               {
1603 +                       /* get luxel */
1604 +                       cluster = SUPER_CLUSTER( x, y );
1605 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1606 +                       
1607 +                       /* filter dirt by adjacency to unmapped luxels */
1608 +                       average = *floodlight;
1609 +                       samples = 1.0f;
1610 +                       for( sy = (y - 1); sy <= (y + 1); sy++ )
1611 +                       {
1612 +                               if( sy < 0 || sy >= lm->sh )
1613 +                                       continue;
1614 +                               
1615 +                               for( sx = (x - 1); sx <= (x + 1); sx++ )
1616 +                               {
1617 +                                       if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1618 +                                               continue;
1619 +                                       
1620 +                                       /* get neighboring luxel */
1621 +                                       cluster = SUPER_CLUSTER( sx, sy );
1622 +                                       floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1623 +                                       if( *cluster < 0 || *floodlight2 <= 0.0f )
1624 +                                               continue;
1625 +                                       
1626 +                                       /* add it */
1627 +                                       average += *floodlight2;
1628 +                                       samples += 1.0f;
1629 +                               }
1630 +                               
1631 +                               /* bail */
1632 +                               if( samples <= 0.0f )
1633 +                                       break;
1634 +                       }
1635 +                       
1636 +                       /* bail */
1637 +                       if( samples <= 0.0f )
1638 +                               continue;
1639 +                       
1640 +                       /* scale dirt */
1641 +                       *floodlight = average / samples;
1642 +               }
1643 +       }
1644 +}
1645 +
1646 +/*
1647 +FloodLightForSample()
1648 +calculates floodlight value for a given sample
1649 +once again, kudos to the dirtmapping coder
1650 +*/
1651 +float FloodLightForSample( trace_t *trace )
1652 +{
1653 +       int             i;
1654 +       float   d;
1655 +       float   contribution;
1656 +       int     sub = 0;
1657 +       float   gatherLight, outLight;
1658 +       vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
1659 +       float   dd;
1660 +       int     vecs = 0;
1661
1662 +       gatherLight=0;
1663 +       /* dummy check */
1664 +       //if( !dirty )
1665 +       //      return 1.0f;
1666 +       if( trace == NULL || trace->cluster < 0 )
1667 +               return 0.0f;
1668 +       
1669 +
1670 +       /* setup */
1671 +       dd = floodlightDistance;
1672 +       VectorCopy( trace->normal, normal );
1673 +       
1674 +       /* check if the normal is aligned to the world-up */
1675 +       if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1676 +       {
1677 +               if( normal[ 2 ] == 1.0f )               
1678 +               {
1679 +                       VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1680 +                       VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1681 +               }
1682 +               else if( normal[ 2 ] == -1.0f )
1683 +               {
1684 +                       VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1685 +                       VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1686 +               }
1687 +       }
1688 +       else
1689 +       {
1690 +               VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1691 +               CrossProduct( normal, worldUp, myRt );
1692 +               VectorNormalize( myRt, myRt );
1693 +               CrossProduct( myRt, normal, myUp );
1694 +               VectorNormalize( myUp, myUp );
1695 +       }
1696 +
1697 +       /* iterate through ordered vectors */
1698 +       for( i = 0; i < numFloodVectors; i++ )
1699 +       {
1700 +               if (floodlight_lowquality==qtrue)
1701 +        {
1702 +                       if (rand()%10 != 0 ) continue;
1703 +               }
1704 +
1705 +               vecs++;
1706 +         
1707 +               /* transform vector into tangent space */
1708 +               direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1709 +               direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1710 +               direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1711 +
1712 +               /* set endpoint */
1713 +               VectorMA( trace->origin, dd, direction, trace->end );
1714 +
1715 +               //VectorMA( trace->origin, 1, direction, trace->origin );
1716 +                       
1717 +               SetupTrace( trace );
1718 +               /* trace */
1719 +               TraceLine( trace );
1720 +               contribution=1;
1721 +
1722 +               if (trace->compileFlags & C_SKY )
1723 +               {
1724 +                       contribution=1.0f;
1725 +               }
1726 +               else if ( trace->opaque )
1727 +               {
1728 +                       VectorSubtract( trace->hit, trace->origin, displacement );
1729 +                       d=VectorLength( displacement );
1730 +
1731 +                       // d=trace->distance;            
1732 +                       //if (d>256) gatherDirt+=1;
1733 +                       contribution=d/dd;
1734 +                       if (contribution>1) contribution=1.0f; 
1735 +             
1736 +                       //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1737 +               }
1738 +         
1739 +               gatherLight+=contribution;
1740 +       }
1741 +   
1742 +       /* early out */
1743 +       if( gatherLight <= 0.0f )
1744 +               return 0.0f;
1745 +       
1746 +       sub=vecs;
1747 +
1748 +       if (sub<1) sub=1;
1749 +       gatherLight/=(sub);
1750 +
1751 +       outLight=gatherLight;
1752 +       if( outLight > 1.0f )
1753 +               outLight = 1.0f;
1754 +       
1755 +       /* return to sender */
1756 +       return outLight;
1757 +}
1758 +
1759 Index: tools/quake3/q3map2/light.c
1760 ===================================================================
1761 --- tools/quake3/q3map2/light.c (revision 290)
1762 +++ tools/quake3/q3map2/light.c (working copy)
1763 @@ -1363,6 +1363,56 @@
1764                         break;
1765         }
1766         
1767 +       /////// Floodlighting for point //////////////////
1768 +       //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1769 +       if (floodlighty)
1770 +       {
1771 +               int q;
1772 +               float addSize,f;
1773 +               vec3_t col,dir;
1774 +               col[0]=col[1]=col[2]=floodlightIntensity;
1775 +               dir[0]=dir[1]=0;
1776 +               dir[2]=1;
1777 +      
1778 +               trace.testOcclusion = qtrue;
1779 +               trace.forceSunlight = qfalse;
1780 +               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1781 +               trace.testAll = qtrue;     
1782 +      
1783 +               for (q=0;q<2;q++)
1784 +               {
1785 +                       if (q==0) //upper hemisphere
1786 +                       {
1787 +                               trace.normal[0]=0;
1788 +                               trace.normal[1]=0;
1789 +                               trace.normal[2]=1;
1790 +                       }
1791 +                       else //lower hemisphere
1792 +                       {
1793 +                               trace.normal[0]=0;
1794 +                               trace.normal[1]=0;
1795 +                               trace.normal[2]=-1;
1796 +                       }
1797 +
1798 +                       f = FloodLightForSample(&trace);
1799 +
1800 +                       contributions[ numCon ].color[0]=col[0]*f;
1801 +                       contributions[ numCon ].color[1]=col[1]*f;
1802 +                       contributions[ numCon ].color[2]=col[2]*f;
1803 +
1804 +                       contributions[ numCon ].dir[0]=dir[0];
1805 +                       contributions[ numCon ].dir[1]=dir[1];
1806 +                       contributions[ numCon ].dir[2]=dir[2];
1807 +
1808 +                       contributions[ numCon ].style = 0;
1809 +                       numCon++;               
1810 +                       /* push average direction around */
1811 +                       addSize = VectorLength( col );
1812 +                       VectorMA( gp->dir, addSize, dir, gp->dir );
1813 +               }
1814 +       }
1815 +       /////////////////////
1816 +
1817         /* normalize to get primary light direction */
1818         VectorNormalize( gp->dir, gp->dir );
1819         
1820 @@ -1544,6 +1594,12 @@
1821         qboolean        minVertex, minGrid;
1822         const char      *value;
1823         
1824 +       /* floodlight them up */
1825 +       if( floodlighty )
1826 +       {
1827 +               Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1828 +               RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1829 +       }
1830  
1831         /* ydnar: smooth normals */
1832         if( shade )
1833 @@ -1675,6 +1731,7 @@
1834                 /* flag bouncing */
1835                 bouncing = qtrue;
1836                 VectorClear( ambientColor );
1837 +               floodlighty = qfalse;
1838                 
1839                 /* generate diffuse lights */
1840                 RadFreeLights();
1841 @@ -2114,6 +2171,21 @@
1842                         loMem = qtrue;
1843                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
1844                 }
1845 +               else if( !strcmp( argv[ i ], "-floodlight" ) )
1846 +               {
1847 +                       floodlighty = qtrue;
1848 +                       Sys_Printf( "FloodLighting enabled\n" );
1849 +               }
1850 +               else if( !strcmp( argv[ i ], "-debugnormals" ) )
1851 +               {
1852 +                       debugnormals = qtrue;
1853 +                       Sys_Printf( "DebugNormals enabled\n" );
1854 +               }
1855 +               else if( !strcmp( argv[ i ], "-lowquality" ) )
1856 +               {
1857 +                       floodlight_lowquality = qtrue;
1858 +                       Sys_Printf( "Low Quality FloodLighting enabled\n" );
1859 +               }
1860                 
1861                 else
1862                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
1863 @@ -2156,6 +2228,7 @@
1864         
1865         /* ydnar: set up optimization */
1866         SetupBrushes();
1867 +       SetupFloodLight();
1868         SetupSurfaceLightmaps();
1869         
1870         /* initialize the surface facet tracing */
1871 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1872 ===================================================================
1873 --- tools/quake3/q3map2/lightmaps_ydnar.c       (revision 290)
1874 +++ tools/quake3/q3map2/lightmaps_ydnar.c       (working copy)
1875 @@ -413,6 +413,12 @@
1876                 lm->superNormals = safe_malloc( size );
1877         memset( lm->superNormals, 0, size );
1878         
1879 +       /* allocate floodlight map storage */
1880 +       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1881 +       if( lm->superFloodLight == NULL )
1882 +               lm->superFloodLight = safe_malloc( size );
1883 +       memset( lm->superFloodLight, 0, size );
1884 +       
1885         /* allocate cluster map storage */
1886         size = lm->sw * lm->sh * sizeof( int );
1887         if( lm->superClusters == NULL )
1888 Index: tools/quake3/q3map2/q3map2.h
1889 ===================================================================
1890 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1891 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1892 @@ -265,6 +265,7 @@
1893  #define SUPER_NORMAL_SIZE              3
1894  #define SUPER_DELUXEL_SIZE             3
1895  #define BSP_DELUXEL_SIZE               3
1896 +#define SUPER_FLOODLIGHT_SIZE  1
1897  
1898  #define VERTEX_LUXEL( s, v )   (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1899  #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1900 @@ -273,6 +274,7 @@
1901  #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1902  #define SUPER_ORIGIN( x, y )   (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1903  #define SUPER_NORMAL( x, y )   (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1904 +#define SUPER_FLOODLIGHT( x, y )       (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )       
1905  #define SUPER_CLUSTER( x, y )  (lm->superClusters + (((y) * lm->sw) + (x)))
1906  #define SUPER_DELUXEL( x, y )  (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1907  #define BSP_DELUXEL( x, y )            (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE))
1908 @@ -1364,6 +1366,7 @@
1909         
1910         float                                   *superDeluxels; /* average light direction */
1911         float                                   *bspDeluxels;
1912 +       float                                   *superFloodLight; 
1913  }
1914  rawLightmap_t;
1915  
1916 @@ -1670,6 +1673,9 @@
1917  void                                           SmoothNormals( void );
1918  
1919  void                                           MapRawLightmap( int num );
1920 +void                                           SetupFloodLight();
1921 +float                                          FloodLightForSample( trace_t *trace );
1922 +void                                           FloodLightRawLightmap( int num );
1923  void                                           IlluminateRawLightmap( int num );
1924  void                                           IlluminateVertexes( int num );
1925  
1926 @@ -2037,6 +2043,12 @@
1927  Q_EXTERN qboolean                      sunOnly;
1928  Q_EXTERN int                           approximateTolerance Q_ASSIGN( 0 );
1929  Q_EXTERN qboolean                      noCollapse;
1930 +Q_EXTERN qboolean                      debugnormals Q_ASSIGN( qfalse );
1931 +Q_EXTERN qboolean                      floodlighty Q_ASSIGN( qfalse );
1932 +Q_EXTERN qboolean                      floodlight_lowquality Q_ASSIGN( qfalse );
1933 +Q_EXTERN vec3_t                                floodlightRGB;
1934 +Q_EXTERN float                         floodlightIntensity Q_ASSIGN( 512 );
1935 +Q_EXTERN float                         floodlightDistance Q_ASSIGN( 1024 );
1936  Q_EXTERN qboolean                      debug;
1937  Q_EXTERN qboolean                      debugSurfaces;
1938  Q_EXTERN qboolean                      debugUnused;
1939 Index: tools/quake3/q3map2/q3map2.h
1940 ===================================================================
1941 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1942 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1943 @@ -1274,6 +1274,7 @@
1944         vec3_t                          color;                  /* starts out at full color, may be reduced if transparent surfaces are crossed */
1945         
1946         /* output */
1947 +       vec3_t                          hit;
1948         int                                     compileFlags;   /* for determining surface compile flags traced through */
1949         qboolean                        passSolid;
1950         qboolean                        opaque;
1951 Index: tools/quake3/q3map2/light_trace.c
1952 ===================================================================
1953 --- tools/quake3/q3map2/light_trace.c   (revision 290)
1954 +++ tools/quake3/q3map2/light_trace.c   (working copy)
1955 @@ -1596,6 +1596,7 @@
1956         /* bogus node number means solid, end tracing unless testing all */
1957         if( nodeNum < 0 )
1958         {
1959 +               VectorCopy( origin, trace->hit );
1960                 trace->passSolid = qtrue;
1961                 return qtrue;
1962         }
1963 @@ -1606,6 +1607,7 @@
1964         /* solid? */
1965         if( node->type == TRACE_LEAF_SOLID )
1966         {
1967 +               VectorCopy( origin, trace->hit );
1968                 trace->passSolid = qtrue;
1969                 return qtrue;
1970         }
1971 Index: tools/quake3/q3map2/light_ydnar.c
1972 ===================================================================
1973 --- tools/quake3/q3map2/light_ydnar.c   (revision 290)
1974 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1975 @@ -372,7 +372,7 @@
1976  #define NUDGE                  0.5f
1977  #define BOGUS_NUDGE            -99999.0f
1978  
1979 -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 ] )
1980 +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 ] )
1981  {
1982         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
1983         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
1984 @@ -380,6 +380,12 @@
1985         vec3_t                  pNormal;
1986         vec3_t                  vecs[ 3 ];
1987         vec3_t                  nudged;
1988 +       vec3_t                  cverts[ 3 ];
1989 +       vec3_t                  temp;
1990 +       vec4_t                  sideplane, hostplane;
1991 +       vec3_t                  origintwo;
1992 +       int                             j, next;
1993 +       float                   e;
1994         float                   *nudge;
1995         static float    nudges[][ 2 ] =
1996                                         {
1997 @@ -473,6 +479,51 @@
1998         /* non axial lightmap projection (explicit xyz) */
1999         else
2000                 VectorCopy( dv->xyz, origin );
2001 +
2002 +       //////////////////////
2003 +       //27's test to make sure samples stay within the triangle boundaries
2004 +       //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
2005 +       //2) if it does, nudge it onto the correct side.
2006 +
2007 +       if (worldverts!=NULL)
2008 +       {
2009 +               for (j=0;j<3;j++)
2010 +               {
2011 +                       VectorCopy(worldverts[j],cverts[j]);    
2012 +               }
2013 +               PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2014 +
2015 +               for (j=0;j<3;j++)
2016 +               {
2017 +                       for (i=0;i<3;i++)
2018 +                       {
2019 +                               //build plane using 2 edges and a normal
2020 +                               next=(i+1)%3;
2021 +
2022 +                               VectorCopy(cverts[next],temp);
2023 +                               VectorAdd(temp,hostplane,temp);
2024 +                               PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2025 +
2026 +                               //planetest sample point  
2027 +                               e=DotProduct(origin,sideplane);
2028 +                               e=e-sideplane[3];
2029 +                               if (e>0)
2030 +                               {
2031 +                                       //we're bad.
2032 +                                       //VectorClear(origin);
2033 +                                       //Move the sample point back inside triangle bounds
2034 +                                       origin[0]-=sideplane[0]*(e+1);
2035 +                                       origin[1]-=sideplane[1]*(e+1);
2036 +                                       origin[2]-=sideplane[2]*(e+1);
2037 +#ifdef DEBUG_27_1
2038 +                                       VectorClear(origin);
2039 +#endif 
2040 +                               }
2041 +                       }
2042 +               }
2043 +       }
2044 +
2045 +       ////////////////////////
2046         
2047         /* planar surfaces have precalculated lightmap vectors for nudging */
2048         if( lm->plane != NULL )
2049 @@ -504,8 +555,13 @@
2050         else
2051                 origin[ lm->axisNum ] += lightmapSampleOffset;
2052         
2053 +       VectorCopy(origin,origintwo);
2054 +       origintwo[0]+=vecs[2][0];
2055 +       origintwo[1]+=vecs[2][1];
2056 +       origintwo[2]+=vecs[2][2];
2057 +       
2058         /* get cluster */
2059 -       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2060 +       pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2061         
2062         /* another retarded hack, storing nudge count in luxel[ 1 ] */
2063         luxel[ 1 ] = 0.0f;      
2064 @@ -521,14 +577,14 @@
2065                         for( i = 0; i < 3; i++ )
2066                         {
2067                                 /* set nudged point*/
2068 -                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2069 +                               nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2070                         }
2071                         nudge += 2;
2072                         
2073                         /* get pvs cluster */
2074                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
2075 -                       if( pointCluster >= 0 ) 
2076 -                               VectorCopy( nudged, origin );
2077 +                       //if( pointCluster >= 0 )       
2078 +                       //      VectorCopy( nudged, origin );
2079                         luxel[ 1 ] += 1.0f;
2080                 }
2081         }
2082 @@ -538,8 +594,8 @@
2083         {
2084                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
2085                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
2086 -               if( pointCluster >= 0 )
2087 -                       VectorCopy( nudged, origin );
2088 +               //if( pointCluster >= 0 )
2089 +               //      VectorCopy( nudged, origin );
2090                 luxel[ 1 ] += 1.0f;
2091         }
2092         
2093 @@ -585,7 +641,7 @@
2094  than the distance between two luxels (thanks jc :)
2095  */
2096  
2097 -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 ] )
2098 +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 ] )
2099  {
2100         bspDrawVert_t   mid, *dv2[ 3 ];
2101         int                             max;
2102 @@ -633,7 +689,7 @@
2103         
2104         /* split the longest edge and map it */
2105         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
2106 -       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
2107 +       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
2108         
2109         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
2110         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
2111 @@ -641,12 +697,12 @@
2112         /* recurse to first triangle */
2113         VectorCopy( dv, dv2 );
2114         dv2[ max ] = &mid;
2115 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2116 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2117         
2118         /* recurse to second triangle */
2119         VectorCopy( dv, dv2 );
2120         dv2[ (max + 1) % 3 ] = &mid;
2121 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2122 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2123  }
2124  
2125  
2126 @@ -662,6 +718,7 @@
2127         int                             i;
2128         vec4_t                  plane;
2129         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2130 +       vec3_t                  worldverts[ 3 ];
2131         
2132         
2133         /* get plane if possible */
2134 @@ -687,16 +744,20 @@
2135                 ttv = NULL;
2136         }
2137         
2138 +       VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2139 +       VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2140 +       VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
2141 +       
2142         /* map the vertexes */
2143 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2144 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2145 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2146 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
2147 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
2148 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
2149         
2150         /* 2002-11-20: prefer axial triangle edges */
2151         if( mapNonAxial )
2152         {
2153                 /* subdivide the triangle */
2154 -               MapTriangle_r( lm, info, dv, plane, stv, ttv );
2155 +               MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2156                 return qtrue;
2157         }
2158         
2159 @@ -718,7 +779,7 @@
2160                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
2161                         
2162                         /* map the degenerate triangle */
2163 -                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2164 +                       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2165                 }
2166         }
2167         
2168 @@ -780,8 +841,8 @@
2169         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
2170         
2171         /* map the vertexes */
2172 -       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
2173 -       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
2174 +       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
2175 +       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
2176         
2177         /* 0 and 2 */
2178         if( max == 0 )
2179 @@ -866,10 +927,10 @@
2180         }
2181         
2182         /* map the vertexes */
2183 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2184 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2185 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2186 -       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
2187 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
2188 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
2189 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
2190 +       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
2191         
2192         /* subdivide the quad */
2193         MapQuad_r( lm, info, dv, plane, stv, ttv );
2194 @@ -1161,7 +1222,7 @@
2195                                         continue;
2196                                 
2197                                 /* map the fake vert */
2198 -                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
2199 +                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
2200                         }
2201                 }
2202         }
2203 @@ -1636,22 +1697,32 @@
2204                                         deluxel = SUPER_DELUXEL( x, y );
2205                                         origin = SUPER_ORIGIN( x, y );
2206                                         normal = SUPER_NORMAL( x, y );
2207 -                                       
2208 -                                       /* set contribution count */
2209 -                                       lightLuxel[ 3 ] = 1.0f;
2210 -                                       
2211 -                                       /* setup trace */
2212 -                                       trace.cluster = *cluster;
2213 -                                       VectorCopy( origin, trace.origin );
2214 -                                       VectorCopy( normal, trace.normal );
2215 -                                       
2216 -                                       /* get light for this sample */
2217 -                                       LightContributionToSample( &trace );
2218 -                                       VectorCopy( trace.color, lightLuxel );
2219 -                                       
2220 -                                       /* add to count */
2221 -                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2222 +
2223 +                                       ////////// 27's temp hack for testing edge clipping ////
2224 +                                       if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2225 +                                       {
2226 +                                               lightLuxel[ 1 ] = 255;
2227 +                                               lightLuxel[ 3 ] = 1.0f;
2228                                                 totalLighted++;
2229 +                                       }
2230 +                                       else
2231 +                                       {
2232 +                                               /* set contribution count */
2233 +                                               lightLuxel[ 3 ] = 1.0f;
2234 +                                               
2235 +                                               /* setup trace */
2236 +                                               trace.cluster = *cluster;
2237 +                                               VectorCopy( origin, trace.origin );
2238 +                                               VectorCopy( normal, trace.normal );
2239 +                                               
2240 +                                               /* get light for this sample */
2241 +                                               LightContributionToSample( &trace );
2242 +                                               VectorCopy( trace.color, lightLuxel );
2243 +                                               
2244 +                                               /* add to count */
2245 +                                               if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2246 +                                                       totalLighted++;
2247 +                                       }
2248                                         
2249                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2250                                         if( deluxemap )
2251 Index: tools/quake3/q3map2/q3map2.h
2252 ===================================================================
2253 --- tools/quake3/q3map2/q3map2.h        (revision 290)
2254 +++ tools/quake3/q3map2/q3map2.h        (working copy)
2255 @@ -34,8 +34,8 @@
2256  
2257  
2258  /* version */
2259 -#define Q3MAP_VERSION  "2.5.11"
2260 -#define Q3MAP_MOTD             "A well-oiled toaster oven"
2261 +#define Q3MAP_VERSION  "2.5.11-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTtrianglecheck"
2262 +#define Q3MAP_MOTD             "Blackhole Box gives the light back"
2263  
2264  
2265  
2266 Index: include/version.default
2267 ===================================================================
2268 --- include/version.default     (revision 290)
2269 +++ include/version.default     (working copy)
2270 @@ -1 +1 @@
2271 -1.4.0\r
2272 +1.4.0-div0-obj-bp2texdeffix-bpsurfacedialog-spawnflagsboxes\r