]> icculus.org git repositories - divverent/nexuiz.git/blob - misc/gtkradiant/gtkradiant-nexuiz-patchset.diff
add brush primitives fixes
[divverent/nexuiz.git] / misc / gtkradiant / gtkradiant-nexuiz-patchset.diff
1 NOTE: this patch set is autogenerated from the "singlepatches" subdirectory of nexuiz/trunk/misc.
2
3 Do not commit changes to THIS!
4
5 Always run
6         sh mergepatches.sh > gtkradiant-nexuiz-patchset.diff
7 before committing new singlepatches!
8
9
10
11 Index: libs/picomodel/pm_obj.c
12 ===================================================================
13 --- libs/picomodel/pm_obj.c     (revision 290)
14 +++ libs/picomodel/pm_obj.c     (working copy)
15 @@ -215,10 +215,9 @@
16         }
17  }
18  
19 -#if 0
20  static int _obj_mtl_load( picoModel_t *model )
21  {
22 -       //picoShader_t *curShader = NULL;
23 +       picoShader_t *curShader = NULL;
24         picoParser_t *p;
25         picoByte_t   *mtlBuffer;
26         int                       mtlBufSize;
27 @@ -266,7 +265,7 @@
28                 /* get next token in material file */
29                 if (_pico_parse( p,1 ) == NULL)
30                         break;
31 -#if 0
32 +#if 1
33  
34                 /* skip empty lines */
35                 if (p->token == NULL || !strlen( p->token ))
36 @@ -308,6 +307,7 @@
37                 else if (!_pico_stricmp(p->token,"map_kd"))
38                 {
39                         char *mapName;
40 +                       picoShader_t *shader;
41  
42                         /* pointer to current shader must be valid */
43                         if (curShader == NULL)
44 @@ -322,6 +322,10 @@
45                                 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
46                                 _obj_mtl_error_return;
47                         }
48 +                       /* create a new pico shader */
49 +                       shader = PicoNewShader( model );
50 +                       if (shader == NULL)
51 +                               _obj_mtl_error_return;
52                         /* set shader map name */
53                         PicoSetShaderMapName( shader,mapName );
54                 }
55 @@ -478,7 +482,6 @@
56         /* return with success */
57         return 1;
58  }
59 -#endif
60  
61  /* _obj_load:
62   *  loads a wavefront obj model file.
63 @@ -523,7 +526,7 @@
64         PicoSetModelFileName( model,fileName );
65  
66         /* try loading the materials; we don't handle the result */
67 -#if 0
68 +#if 1
69         _obj_mtl_load( model );
70  #endif
71  
72 @@ -832,6 +835,41 @@
73                                 curVertex += max;
74                         }
75                 }
76 +               else if (!_pico_stricmp(p->token,"usemtl"))
77 +               {
78 +                       picoShader_t *shader;
79 +                       char *name;
80 +
81 +                       /* get material name */
82 +                       name = _pico_parse( p,0 );
83 +
84 +                       /* validate material name */
85 +                       if (name == NULL || !strlen(name))
86 +                       {
87 +                               _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
88 +                       }
89 +                       else
90 +                       {
91 +                               shader = PicoFindShader( model, name, 1 );
92 +                               if (shader == NULL)
93 +                               {
94 +                                       _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
95 +
96 +                                       /* create a new pico shader */
97 +                                       shader = PicoNewShader( model );
98 +                                       if (shader != NULL)
99 +                                       {
100 +                                               PicoSetShaderName( shader,name );
101 +                                               PicoSetShaderMapName( shader,name );
102 +                                               PicoSetSurfaceShader( curSurface, shader );
103 +                                       }
104 +                               }
105 +                               else
106 +                               {
107 +                                       PicoSetSurfaceShader( curSurface, shader );
108 +                               }
109 +                       }
110 +               }
111                 /* skip unparsed rest of line and continue */
112                 _pico_parse_skip_rest( p );
113         }
114 Index: radiant/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: tools/quake3/q3map2/convert_map.c
763 ===================================================================
764 --- tools/quake3/q3map2/convert_map.c   (revision 290)
765 +++ tools/quake3/q3map2/convert_map.c   (working copy)
766 @@ -45,6 +45,105 @@
767  #define        SNAP_FLOAT_TO_INT       4
768  #define        SNAP_INT_TO_FLOAT       (1.0 / SNAP_FLOAT_TO_INT)
769  
770 +typedef vec_t vec2_t[2];
771 +
772 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
773 +                    vec_t a10, vec_t a11, vec_t a12,
774 +                    vec_t a20, vec_t a21, vec_t a22)
775 +{
776 +       return
777 +               a00 * (a11 * a22 - a12 * a21)
778 +       -       a01 * (a10 * a22 - a12 * a20)
779 +       +       a02 * (a10 * a21 - a11 * a20);
780 +}
781 +
782 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
783 +{
784 +       bspDrawSurface_t *s;
785 +       int i;
786 +       int t;
787 +       vec_t best = 0;
788 +       vec_t thisarea;
789 +       vec3_t normdiff;
790 +       vec3_t v1v0, v2v0, norm;
791 +       bspDrawVert_t *vert[3];
792 +       winding_t *polygon;
793 +       plane_t *buildPlane = &mapplanes[buildSide->planenum];
794 +       int matches = 0;
795 +
796 +       // first, start out with NULLs
797 +       bestVert[0] = bestVert[1] = bestVert[2] = NULL;
798 +
799 +       // brute force through all surfaces
800 +       for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
801 +       {
802 +               if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
803 +                       continue;
804 +               if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
805 +                       continue;
806 +               for(t = 0; t + 3 <= s->numIndexes; t += 3)
807 +               {
808 +                       vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
809 +                       vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
810 +                       vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
811 +                       if(s->surfaceType == MST_PLANAR)
812 +                       {
813 +                               VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
814 +                               VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
815 +                               VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
816 +                       }
817 +                       else
818 +                       {
819 +                               // this is more prone to roundoff errors, but with embedded
820 +                               // models, there is no better way
821 +                               VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
822 +                               VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
823 +                               CrossProduct(v2v0, v1v0, norm);
824 +                               VectorNormalize(norm, norm);
825 +                               VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
826 +                       }
827 +                       if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
828 +                       if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
829 +                       if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
830 +                       // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
831 +                       polygon = CopyWinding(buildSide->winding);
832 +                       for(i = 0; i < 3; ++i)
833 +                       {
834 +                               // 0: 1, 2
835 +                               // 1: 2, 0
836 +                               // 2; 0, 1
837 +                               vec3_t *v1 = &vert[(i+1)%3]->xyz;
838 +                               vec3_t *v2 = &vert[(i+2)%3]->xyz;
839 +                               vec3_t triNormal;
840 +                               vec_t triDist;
841 +                               vec3_t sideDirection;
842 +                               // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
843 +                               VectorSubtract(*v2, *v1, sideDirection);
844 +                               CrossProduct(sideDirection, buildPlane->normal, triNormal);
845 +                               triDist = DotProduct(*v1, triNormal);
846 +                               ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
847 +                               if(!polygon)
848 +                                       goto exwinding;
849 +                       }
850 +                       thisarea = WindingArea(polygon);
851 +                       if(thisarea > 0)
852 +                               ++matches;
853 +                       if(thisarea > best)
854 +                       {
855 +                               best = thisarea;
856 +                               bestVert[0] = vert[0];
857 +                               bestVert[1] = vert[1];
858 +                               bestVert[2] = vert[2];
859 +                       }
860 +                       FreeWinding(polygon);
861 +exwinding:
862 +                       ;
863 +               }
864 +       }
865 +       //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
866 +       //      fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
867 +}
868 +
869  static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
870  {
871         int                             i, j;
872 @@ -53,12 +152,17 @@
873         bspShader_t             *shader;
874         char                    *texture;
875         bspPlane_t              *plane;
876 +       plane_t         *buildPlane;
877         vec3_t                  pts[ 3 ];
878 +       bspDrawVert_t   *vert[3];
879 +       int valid;
880         
881         
882         /* start brush */
883         fprintf( f, "\t// brush %d\n", num );
884         fprintf( f, "\t{\n" );
885 +       fprintf( f, "\tbrushDef\n" );
886 +       fprintf( f, "\t{\n" );
887         
888         /* clear out build brush */
889         for( i = 0; i < buildBrush->numsides; i++ )
890 @@ -108,9 +212,88 @@
891                 /* get build side */
892                 buildSide = &buildBrush->sides[ i ];
893                 
894 +               /* get plane */
895 +               buildPlane = &mapplanes[ buildSide->planenum ];
896 +               
897                 /* dummy check */
898                 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
899                         continue;
900 +
901 +               // st-texcoords -> texMat block
902 +               // start out with dummy
903 +               VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
904 +               VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
905 +
906 +               // find surface for this side (by brute force)
907 +               // surface format:
908 +               //   - meshverts point in pairs of three into verts
909 +               //   - (triangles)
910 +               //   - find the triangle that has most in common with our side
911 +               GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
912 +               valid = 0;
913 +
914 +               if(vert[0] && vert[1] && vert[2])
915 +               {
916 +                       int i;
917 +                       vec3_t texX, texY;
918 +                       vec3_t xy1I, xy1J, xy1K;
919 +                       vec2_t stI, stJ, stK;
920 +                       vec_t D, D0, D1, D2;
921 +
922 +                       ComputeAxisBase(buildPlane->normal, texX, texY);
923 +
924 +                       VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
925 +                       VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
926 +                       VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
927 +                       stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
928 +                       stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
929 +                       stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
930 +
931 +                       //   - solve linear equations:
932 +                       //     - (x, y) := xyz . (texX, texY)
933 +                       //     - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
934 +                       //       (for three vertices)
935 +                       D = Det3x3(
936 +                               xy1I[0], xy1I[1], 1,
937 +                               xy1J[0], xy1J[1], 1,
938 +                               xy1K[0], xy1K[1], 1
939 +                       );
940 +                       if(D != 0)
941 +                       {
942 +                               for(i = 0; i < 2; ++i)
943 +                               {
944 +                                       D0 = Det3x3(
945 +                                               stI[i], xy1I[1], 1,
946 +                                               stJ[i], xy1J[1], 1,
947 +                                               stK[i], xy1K[1], 1
948 +                                       );
949 +                                       D1 = Det3x3(
950 +                                               xy1I[0], stI[i], 1,
951 +                                               xy1J[0], stJ[i], 1,
952 +                                               xy1K[0], stK[i], 1
953 +                                       );
954 +                                       D2 = Det3x3(
955 +                                               xy1I[0], xy1I[1], stI[i],
956 +                                               xy1J[0], xy1J[1], stJ[i],
957 +                                               xy1K[0], xy1K[1], stK[i]
958 +                                       );
959 +                                       VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
960 +                                       valid = 1;
961 +                               }
962 +                       }
963 +                       else
964 +                               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",
965 +                                       buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
966 +                                       vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2], 
967 +                                       texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
968 +                                       vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
969 +                                       vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
970 +                                       vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
971 +                                       );
972 +               }
973 +               else
974 +                       if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
975 +                               fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
976                 
977                 /* get texture name */
978                 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
979 @@ -129,14 +312,21 @@
980                 
981                 /* print brush side */
982                 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
983 -               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",
984 +               fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
985                         pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
986                         pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
987                         pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
988 -                       texture );
989 +                       buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
990 +                       buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
991 +                       texture,
992 +                       // DEBUG: valid ? 0 : C_DETAIL
993 +                       0
994 +                       );
995 +               // TODO write brush primitives format here
996         }
997         
998         /* end brush */
999 +       fprintf( f, "\t}\n" );
1000         fprintf( f, "\t}\n\n" );
1001  }
1002  
1003 Index: tools/quake3/q3map2/main.c
1004 ===================================================================
1005 --- tools/quake3/q3map2/main.c  (revision 290)
1006 +++ tools/quake3/q3map2/main.c  (working copy)
1007 @@ -276,6 +276,18 @@
1008                         else
1009                                 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
1010                 }
1011 +               else if( !strcmp( argv[ i ],  "-ne" ) )
1012 +               {
1013 +                       normalEpsilon = atof( argv[ i + 1 ] );
1014 +                       i++;
1015 +                       Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
1016 +               }
1017 +               else if( !strcmp( argv[ i ],  "-de" ) )
1018 +               {
1019 +                       distanceEpsilon = atof( argv[ i + 1 ] );
1020 +                       i++;
1021 +                       Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
1022 +               }
1023         }
1024         
1025         /* clean up map name */
1026 Index: tools/quake3/q3map2/model.c
1027 ===================================================================
1028 --- tools/quake3/q3map2/model.c (revision 290)
1029 +++ tools/quake3/q3map2/model.c (working copy)
1030 @@ -221,6 +221,8 @@
1031         byte                            *color;
1032         picoIndex_t                     *indexes;
1033         remap_t                         *rm, *glob;
1034 +       double                          normalEpsilon_save;
1035 +       double                          distanceEpsilon_save;
1036         
1037         
1038         /* get model */
1039 @@ -399,9 +401,8 @@
1040                 /* ydnar: giant hack land: generate clipping brushes for model triangles */
1041                 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
1042                 {
1043 -                       vec3_t          points[ 3 ], backs[ 3 ];
1044 +                       vec3_t          points[ 4 ], backs[ 3 ];
1045                         vec4_t          plane, reverse, pa, pb, pc;
1046 -                       vec3_t          nadir;
1047                         
1048                         
1049                         /* temp hack */
1050 @@ -437,90 +438,141 @@
1051                                         /* note: this doesn't work as well as simply using the plane of the triangle, below */
1052                                         for( k = 0; k < 3; k++ )
1053                                         {
1054 -                                               if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
1055 -                                                       fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
1056 +                                               if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
1057 +                                                       fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
1058                                                 {
1059                                                         backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
1060                                                         break;
1061                                                 }
1062                                         }
1063                                 }
1064 +
1065 +                               VectorCopy( points[0], points[3] ); // for cyclic usage
1066                                 
1067                                 /* make plane for triangle */
1068 +                               // div0: add some extra spawnflags:
1069 +                               //   0: snap normals to axial planes for extrusion
1070 +                               //   8: extrude with the original normals
1071 +                               //  16: extrude only with up/down normals (ideal for terrain)
1072 +                               //  24: extrude by distance zero (may need engine changes)
1073                                 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
1074                                 {
1075 +                                       vec3_t bestNormal;
1076 +                                       float backPlaneDistance = 2;
1077 +
1078 +                                       if(spawnFlags & 8) // use a DOWN normal
1079 +                                       {
1080 +                                               if(spawnFlags & 16)
1081 +                                               {
1082 +                                                       // 24: normal as is, and zero width (broken)
1083 +                                                       VectorCopy(plane, bestNormal);
1084 +                                               }
1085 +                                               else
1086 +                                               {
1087 +                                                       // 8: normal as is
1088 +                                                       VectorCopy(plane, bestNormal);
1089 +                                               }
1090 +                                       }
1091 +                                       else
1092 +                                       {
1093 +                                               if(spawnFlags & 16)
1094 +                                               {
1095 +                                                       // 16: UP/DOWN normal
1096 +                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1097 +                                               }
1098 +                                               else
1099 +                                               {
1100 +                                                       // 0: axial normal
1101 +                                                       if(fabs(plane[0]) > fabs(plane[1])) // x>y
1102 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
1103 +                                                                       VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1104 +                                                               else // x>y, z>=y
1105 +                                                                       if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
1106 +                                                                               VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1107 +                                                                       else // z>=x, x>y
1108 +                                                                               VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1109 +                                                       else // y>=x
1110 +                                                               if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
1111 +                                                                       VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
1112 +                                                               else // z>=y, y>=x
1113 +                                                                       VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1114 +                                               }
1115 +                                       }
1116 +
1117 +                                       /* build a brush */
1118 +                                       buildBrush = AllocBrush( 48 );
1119 +                                       buildBrush->entityNum = mapEntityNum;
1120 +                                       buildBrush->original = buildBrush;
1121 +                                       buildBrush->contentShader = si;
1122 +                                       buildBrush->compileFlags = si->compileFlags;
1123 +                                       buildBrush->contentFlags = si->contentFlags;
1124 +                                       normalEpsilon_save = normalEpsilon;
1125 +                                       distanceEpsilon_save = distanceEpsilon;
1126 +                                       if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
1127 +                                       {
1128 +                                               buildBrush->detail = qfalse;
1129 +
1130 +                                               // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
1131 +                                               if(normalEpsilon > 0)
1132 +                                                       normalEpsilon = 0;
1133 +                                               if(distanceEpsilon > 0)
1134 +                                                       distanceEpsilon = 0;
1135 +                                       }
1136 +                                       else
1137 +                                               buildBrush->detail = qtrue;
1138 +
1139                                         /* regenerate back points */
1140                                         for( j = 0; j < 3; j++ )
1141                                         {
1142                                                 /* get vertex */
1143                                                 dv = &ds->verts[ ds->indexes[ i + j ] ];
1144 -                                               
1145 -                                               /* copy xyz */
1146 -                                               VectorCopy( dv->xyz, backs[ j ] );
1147 -                                               
1148 -                                               /* find nearest axial to plane normal and push back points opposite */
1149 -                                               for( k = 0; k < 3; k++ )
1150 -                                               {
1151 -                                                       if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
1152 -                                                               fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
1153 -                                                       {
1154 -                                                               backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
1155 -                                                               break;
1156 -                                                       }
1157 -                                               }
1158 +
1159 +                                               // shift by some units
1160 +                                               VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
1161                                         }
1162 -                                       
1163 +
1164                                         /* make back plane */
1165                                         VectorScale( plane, -1.0f, reverse );
1166 -                                       reverse[ 3 ] = -(plane[ 3 ] - 1);
1167 -                                       
1168 -                                       /* make back pyramid point */
1169 -                                       VectorCopy( points[ 0 ], nadir );
1170 -                                       VectorAdd( nadir, points[ 1 ], nadir );
1171 -                                       VectorAdd( nadir, points[ 2 ], nadir );
1172 -                                       VectorScale( nadir, 0.3333333333333f, nadir );
1173 -                                       VectorMA( nadir, -2.0f, plane, nadir );
1174 -                                       
1175 -                                       /* make 3 more planes */
1176 -                                       //%     if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
1177 -                                       //%             PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
1178 -                                       //%             PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
1179 +                                       reverse[ 3 ] = -plane[ 3 ];
1180 +                                       if((spawnFlags & 24) != 24)
1181 +                                               reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
1182 +                                       // 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)
1183 +
1184                                         if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
1185 -                                               PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1186 -                                               PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1187 +                                                       PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1188 +                                                       PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1189                                         {
1190 -                                               /* build a brush */
1191 -                                               buildBrush = AllocBrush( 48 );
1192 -                                               
1193 -                                               buildBrush->entityNum = mapEntityNum;
1194 -                                               buildBrush->original = buildBrush;
1195 -                                               buildBrush->contentShader = si;
1196 -                                               buildBrush->compileFlags = si->compileFlags;
1197 -                                               buildBrush->contentFlags = si->contentFlags;
1198 -                                               buildBrush->detail = qtrue;
1199 -                                               
1200                                                 /* set up brush sides */
1201                                                 buildBrush->numsides = 5;
1202                                                 for( j = 0; j < buildBrush->numsides; j++ )
1203                                                         buildBrush->sides[ j ].shaderInfo = si;
1204 +
1205                                                 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1206 -                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
1207 -                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
1208 -                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
1209 -                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
1210 -                                               
1211 -                                               /* add to entity */
1212 -                                               if( CreateBrushWindings( buildBrush ) )
1213 -                                               {
1214 -                                                       AddBrushBevels();
1215 -                                                       //%     EmitBrushes( buildBrush, NULL, NULL );
1216 -                                                       buildBrush->next = entities[ mapEntityNum ].brushes;
1217 -                                                       entities[ mapEntityNum ].brushes = buildBrush;
1218 -                                                       entities[ mapEntityNum ].numBrushes++;
1219 -                                               }
1220 -                                               else
1221 -                                                       free( buildBrush );
1222 +                                               buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
1223 +                                               buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
1224 +                                               buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
1225 +                                               buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
1226                                         }
1227 +                                       else
1228 +                                       {
1229 +                                               free(buildBrush);
1230 +                                               continue;
1231 +                                       }
1232 +
1233 +                                       normalEpsilon = normalEpsilon_save;
1234 +                                       distanceEpsilon = distanceEpsilon_save;
1235 +
1236 +                                       /* add to entity */
1237 +                                       if( CreateBrushWindings( buildBrush ) )
1238 +                                       {
1239 +                                               AddBrushBevels();
1240 +                                               //%     EmitBrushes( buildBrush, NULL, NULL );
1241 +                                               buildBrush->next = entities[ mapEntityNum ].brushes;
1242 +                                               entities[ mapEntityNum ].brushes = buildBrush;
1243 +                                               entities[ mapEntityNum ].numBrushes++;
1244 +                                       }
1245 +                                       else
1246 +                                               free( buildBrush );
1247                                 }
1248                         }
1249                 }
1250 Index: tools/quake3/q3map2/map.c
1251 ===================================================================
1252 --- tools/quake3/q3map2/map.c   (revision 290)
1253 +++ tools/quake3/q3map2/map.c   (working copy)
1254 @@ -183,9 +183,15 @@
1255  snaps a plane to normal/distance epsilons
1256  */
1257  
1258 -void SnapPlane( vec3_t normal, vec_t *dist )
1259 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
1260  {
1261 -       SnapNormal( normal );
1262 +       // div0: ensure the point "center" stays on the plane (actually, this
1263 +       // rotates the plane around the point center).
1264 +       // if center lies on the plane, it is guaranteed to stay on the plane by
1265 +       // this fix.
1266 +       vec_t centerDist = DotProduct(normal, center);
1267 +       SnapNormal( normal );
1268 +       *dist += (DotProduct(normal, center) - centerDist);
1269  
1270         if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1271                 *dist = Q_rint( *dist );
1272 @@ -199,7 +205,7 @@
1273  must be within an epsilon distance of the plane
1274  */
1275  
1276 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
1277 +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?
1278  
1279  #ifdef USE_HASHING
1280  
1281 @@ -207,10 +213,14 @@
1282         int             i, j, hash, h;
1283         plane_t *p;
1284         vec_t   d;
1285 +       vec3_t centerofweight;
1286 +
1287 +       VectorClear(centerofweight);
1288 +       for(i = 0; i < numPoints; ++i)
1289 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1290         
1291 -       
1292         /* hash the plane */
1293 -       SnapPlane( normal, &dist );
1294 +       SnapPlane( normal, &dist, centerofweight );
1295         hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1296         
1297         /* search the border bins as well */
1298 @@ -251,7 +261,13 @@
1299         plane_t *p;
1300         
1301  
1302 -       SnapPlane( normal, &dist );
1303 +       vec3_t centerofweight;
1304 +
1305 +       VectorClear(centerofweight);
1306 +       for(i = 0; i < numPoints; ++i)
1307 +               VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1308 +       
1309 +       SnapPlane( normal, &dist, centerofweight );
1310         for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
1311         {
1312                 if( PlaneEqual( p, normal, dist ) )
1313 Index: tools/quake3/q3map2/shaders.c
1314 ===================================================================
1315 --- tools/quake3/q3map2/shaders.c       (revision 290)
1316 +++ tools/quake3/q3map2/shaders.c       (working copy)
1317 @@ -747,8 +747,14 @@
1318         }
1319         
1320         if( VectorLength( si->color ) <= 0.0f )
1321 +       {
1322                 ColorNormalize( color, si->color );
1323 -       VectorScale( color, (1.0f / count), si->averageColor );
1324 +               VectorScale( color, (1.0f / count), si->averageColor );
1325 +       }
1326 +       else
1327 +       {
1328 +               VectorCopy( si->color, si->averageColor );
1329 +       }
1330  }
1331  
1332  
1333 Index: tools/quake3/q3map2/light_ydnar.c
1334 ===================================================================
1335 --- tools/quake3/q3map2/light_ydnar.c   (revision 290)
1336 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1337 @@ -1449,6 +1449,8 @@
1338         vec3_t                          color, averageColor, averageDir, total, temp, temp2;
1339         float                           tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1340         trace_t                         trace;
1341 +       vec3_t                          flood;
1342 +       float                           *floodlight;
1343         
1344         
1345         /* bail if this number exceeds the number of raw lightmaps */
1346 @@ -1871,6 +1873,78 @@
1347         /* free light list */
1348         FreeTraceLights( &trace );
1349         
1350 +       /*      -----------------------------------------------------------------
1351 +               floodlight pass
1352 +               ----------------------------------------------------------------- */
1353 +
1354 +       if( floodlighty )
1355 +       {
1356 +               /* walk lightmaps */
1357 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1358 +               {
1359 +                       /* early out */
1360 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1361 +                               continue;
1362 +                       
1363 +                       /* apply floodlight to each luxel */
1364 +                       for( y = 0; y < lm->sh; y++ )
1365 +                       {
1366 +                               for( x = 0; x < lm->sw; x++ )
1367 +                               {
1368 +                                       /* get cluster */
1369 +                                       cluster = SUPER_CLUSTER( x, y );
1370 +                                       //%     if( *cluster < 0 )
1371 +                                       //%             continue;
1372 +                                       
1373 +                                       /* get particulars */
1374 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1375 +                                       floodlight = SUPER_FLOODLIGHT( x, y );
1376 +                                       
1377 +                                       flood[0]=floodlightRGB[0]*floodlightIntensity;
1378 +                                       flood[1]=floodlightRGB[1]*floodlightIntensity;
1379 +                                       flood[2]=floodlightRGB[2]*floodlightIntensity;
1380 +                                                    
1381 +                                       /* scale light value */
1382 +                                       VectorScale( flood, *floodlight, flood );
1383 +                                       luxel[0]+=flood[0];
1384 +                                       luxel[1]+=flood[1];
1385 +                                       luxel[2]+=flood[2];
1386 +                                       
1387 +                                       if (luxel[3]==0) luxel[3]=1;
1388 +                               }
1389 +                       }
1390 +               }
1391 +       }
1392 +
1393 +       if (debugnormals)
1394 +       {
1395 +               for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1396 +               {
1397 +                       /* early out */
1398 +                       if( lm->superLuxels[ lightmapNum ] == NULL )
1399 +                               continue;
1400 +                       
1401 +                       for( y = 0; y < lm->sh; y++ )
1402 +                       {
1403 +                               for( x = 0; x < lm->sw; x++ )
1404 +                               {
1405 +                                       /* get cluster */
1406 +                                       cluster = SUPER_CLUSTER( x, y );
1407 +                                       //%     if( *cluster < 0 )
1408 +                                       //%             continue;
1409 +                                       
1410 +                                       /* get particulars */
1411 +                                       luxel = SUPER_LUXEL( lightmapNum, x, y );
1412 +                                       normal = SUPER_NORMAL (  x, y );
1413 +               
1414 +                                       luxel[0]=(normal[0]*127)+127;
1415 +                                       luxel[1]=(normal[1]*127)+127;
1416 +                                       luxel[2]=(normal[2]*127)+127;
1417 +                               }
1418 +                       }
1419 +               }
1420 +       }
1421 +       
1422         /* -----------------------------------------------------------------
1423            filter pass
1424            ----------------------------------------------------------------- */
1425 @@ -3123,7 +3197,320 @@
1426         CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1427  }
1428  
1429 +/////////////////////////////////////////////////////////////
1430  
1431 +#define FLOODLIGHT_CONE_ANGLE                  88      /* degrees */
1432 +#define FLOODLIGHT_NUM_ANGLE_STEPS             16
1433 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
1434 +#define FLOODLIGHT_NUM_VECTORS                 (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
1435  
1436 +static vec3_t  floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1437 +static int             numFloodVectors = 0;
1438  
1439 +void SetupFloodLight( void )
1440 +{
1441 +       int             i, j;
1442 +       float   angle, elevation, angleStep, elevationStep;
1443 +       const char      *value;
1444 +       double v1,v2,v3,v4,v5;
1445 +       
1446 +       /* note it */
1447 +       Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1448 +       
1449 +       /* calculate angular steps */
1450 +       angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1451 +       elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1452 +       
1453 +       /* iterate angle */
1454 +       angle = 0.0f;
1455 +       for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1456 +       {
1457 +               /* iterate elevation */
1458 +               for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1459 +               {
1460 +                       floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1461 +                       floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1462 +                       floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1463 +                       numFloodVectors++;
1464 +               }
1465 +       }
1466 +       
1467 +       /* emit some statistics */
1468 +       Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1469  
1470 +      /* floodlight */
1471 +       value = ValueForKey( &entities[ 0 ], "_floodlight" );
1472 +       
1473 +       if( value[ 0 ] != '\0' )
1474 +       {
1475 +               v1=v2=v3=0;
1476 +               v4=floodlightDistance;
1477 +               v5=floodlightIntensity;
1478 +               
1479 +               sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1480 +               
1481 +               floodlightRGB[0]=v1;
1482 +               floodlightRGB[1]=v2;
1483 +               floodlightRGB[2]=v3;
1484 +               
1485 +               if (VectorLength(floodlightRGB)==0)
1486 +               {
1487 +                       VectorSet(floodlightRGB,240,240,255);
1488 +               }
1489 +               
1490 +               if (v4<1) v4=1024;
1491 +               if (v5<1) v5=128;
1492 +               
1493 +               floodlightDistance=v4;
1494 +               floodlightIntensity=v5;
1495 +    
1496 +               floodlighty = qtrue;
1497 +               Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1498 +       }
1499 +       else
1500 +       {
1501 +               VectorSet(floodlightRGB,240,240,255);
1502 +               //floodlighty = qtrue;
1503 +               //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1504 +       }
1505 +       VectorNormalize(floodlightRGB,floodlightRGB);
1506 +}
1507 +
1508 +//27 - lighttracer style ambient occlusion light hack.
1509 +//Kudos to the dirtmapping author for most of this source.
1510 +void FloodLightRawLightmap( int rawLightmapNum )
1511 +{
1512 +       int                                     i, x, y, sx, sy, *cluster;
1513 +       float                           *origin, *normal, *floodlight, *floodlight2, average, samples;
1514 +       rawLightmap_t           *lm;
1515 +       surfaceInfo_t           *info;
1516 +       trace_t                         trace;
1517 +       
1518 +       /* bail if this number exceeds the number of raw lightmaps */
1519 +       if( rawLightmapNum >= numRawLightmaps )
1520 +               return;
1521 +       
1522 +       /* get lightmap */
1523 +       lm = &rawLightmaps[ rawLightmapNum ];
1524 +       
1525 +       memset(&trace,0,sizeof(trace_t));
1526 +       /* setup trace */
1527 +       trace.testOcclusion = qtrue;
1528 +       trace.forceSunlight = qfalse;
1529 +       trace.twoSided = qtrue;
1530 +       trace.recvShadows = lm->recvShadows;
1531 +       trace.numSurfaces = lm->numLightSurfaces;
1532 +       trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1533 +       trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1534 +       trace.testAll = qfalse;
1535 +       trace.distance = 1024;
1536 +       
1537 +       /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1538 +       //trace.twoSided = qfalse;
1539 +       for( i = 0; i < trace.numSurfaces; i++ )
1540 +       {
1541 +               /* get surface */
1542 +               info = &surfaceInfos[ trace.surfaces[ i ] ];
1543 +               
1544 +               /* check twosidedness */
1545 +               if( info->si->twoSided )
1546 +               {
1547 +                       trace.twoSided = qtrue;
1548 +                       break;
1549 +               }
1550 +       }
1551 +       
1552 +       /* gather dirt */
1553 +       for( y = 0; y < lm->sh; y++ )
1554 +       {
1555 +               for( x = 0; x < lm->sw; x++ )
1556 +               {
1557 +                       /* get luxel */
1558 +                       cluster = SUPER_CLUSTER( x, y );
1559 +                       origin = SUPER_ORIGIN( x, y );
1560 +                       normal = SUPER_NORMAL( x, y );
1561 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1562 +                       
1563 +                       /* set default dirt */
1564 +                       *floodlight = 0.0f;
1565 +                       
1566 +                       /* only look at mapped luxels */
1567 +                       if( *cluster < 0 )
1568 +                               continue;
1569 +                       
1570 +                       /* copy to trace */
1571 +                       trace.cluster = *cluster;
1572 +                       VectorCopy( origin, trace.origin );
1573 +                       VectorCopy( normal, trace.normal );
1574 +         
1575 +
1576 +               
1577 +                       /* get dirt */
1578 +                       *floodlight = FloodLightForSample( &trace );
1579 +               }
1580 +       }
1581 +       
1582 +       /* testing no filtering */
1583 +       return;
1584 +       
1585 +       /* filter "dirt" */
1586 +       for( y = 0; y < lm->sh; y++ )
1587 +       {
1588 +               for( x = 0; x < lm->sw; x++ )
1589 +               {
1590 +                       /* get luxel */
1591 +                       cluster = SUPER_CLUSTER( x, y );
1592 +                       floodlight = SUPER_FLOODLIGHT( x, y );
1593 +                       
1594 +                       /* filter dirt by adjacency to unmapped luxels */
1595 +                       average = *floodlight;
1596 +                       samples = 1.0f;
1597 +                       for( sy = (y - 1); sy <= (y + 1); sy++ )
1598 +                       {
1599 +                               if( sy < 0 || sy >= lm->sh )
1600 +                                       continue;
1601 +                               
1602 +                               for( sx = (x - 1); sx <= (x + 1); sx++ )
1603 +                               {
1604 +                                       if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1605 +                                               continue;
1606 +                                       
1607 +                                       /* get neighboring luxel */
1608 +                                       cluster = SUPER_CLUSTER( sx, sy );
1609 +                                       floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1610 +                                       if( *cluster < 0 || *floodlight2 <= 0.0f )
1611 +                                               continue;
1612 +                                       
1613 +                                       /* add it */
1614 +                                       average += *floodlight2;
1615 +                                       samples += 1.0f;
1616 +                               }
1617 +                               
1618 +                               /* bail */
1619 +                               if( samples <= 0.0f )
1620 +                                       break;
1621 +                       }
1622 +                       
1623 +                       /* bail */
1624 +                       if( samples <= 0.0f )
1625 +                               continue;
1626 +                       
1627 +                       /* scale dirt */
1628 +                       *floodlight = average / samples;
1629 +               }
1630 +       }
1631 +}
1632 +
1633 +/*
1634 +FloodLightForSample()
1635 +calculates floodlight value for a given sample
1636 +once again, kudos to the dirtmapping coder
1637 +*/
1638 +float FloodLightForSample( trace_t *trace )
1639 +{
1640 +       int             i;
1641 +       float   d;
1642 +       float   contribution;
1643 +       int     sub = 0;
1644 +       float   gatherLight, outLight;
1645 +       vec3_t  normal, worldUp, myUp, myRt, direction, displacement;
1646 +       float   dd;
1647 +       int     vecs = 0;
1648
1649 +       gatherLight=0;
1650 +       /* dummy check */
1651 +       //if( !dirty )
1652 +       //      return 1.0f;
1653 +       if( trace == NULL || trace->cluster < 0 )
1654 +               return 0.0f;
1655 +       
1656 +
1657 +       /* setup */
1658 +       dd = floodlightDistance;
1659 +       VectorCopy( trace->normal, normal );
1660 +       
1661 +       /* check if the normal is aligned to the world-up */
1662 +       if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1663 +       {
1664 +               if( normal[ 2 ] == 1.0f )               
1665 +               {
1666 +                       VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1667 +                       VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1668 +               }
1669 +               else if( normal[ 2 ] == -1.0f )
1670 +               {
1671 +                       VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1672 +                       VectorSet( myUp,  0.0f, 1.0f, 0.0f );
1673 +               }
1674 +       }
1675 +       else
1676 +       {
1677 +               VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1678 +               CrossProduct( normal, worldUp, myRt );
1679 +               VectorNormalize( myRt, myRt );
1680 +               CrossProduct( myRt, normal, myUp );
1681 +               VectorNormalize( myUp, myUp );
1682 +       }
1683 +
1684 +       /* iterate through ordered vectors */
1685 +       for( i = 0; i < numFloodVectors; i++ )
1686 +       {
1687 +               if (floodlight_lowquality==qtrue)
1688 +        {
1689 +                       if (rand()%10 != 0 ) continue;
1690 +               }
1691 +
1692 +               vecs++;
1693 +         
1694 +               /* transform vector into tangent space */
1695 +               direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1696 +               direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1697 +               direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1698 +
1699 +               /* set endpoint */
1700 +               VectorMA( trace->origin, dd, direction, trace->end );
1701 +
1702 +               //VectorMA( trace->origin, 1, direction, trace->origin );
1703 +                       
1704 +               SetupTrace( trace );
1705 +               /* trace */
1706 +               TraceLine( trace );
1707 +               contribution=1;
1708 +
1709 +               if (trace->compileFlags & C_SKY )
1710 +               {
1711 +                       contribution=1.0f;
1712 +               }
1713 +               else if ( trace->opaque )
1714 +               {
1715 +                       VectorSubtract( trace->hit, trace->origin, displacement );
1716 +                       d=VectorLength( displacement );
1717 +
1718 +                       // d=trace->distance;            
1719 +                       //if (d>256) gatherDirt+=1;
1720 +                       contribution=d/dd;
1721 +                       if (contribution>1) contribution=1.0f; 
1722 +             
1723 +                       //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1724 +               }
1725 +         
1726 +               gatherLight+=contribution;
1727 +       }
1728 +   
1729 +       /* early out */
1730 +       if( gatherLight <= 0.0f )
1731 +               return 0.0f;
1732 +       
1733 +       sub=vecs;
1734 +
1735 +       if (sub<1) sub=1;
1736 +       gatherLight/=(sub);
1737 +
1738 +       outLight=gatherLight;
1739 +       if( outLight > 1.0f )
1740 +               outLight = 1.0f;
1741 +       
1742 +       /* return to sender */
1743 +       return outLight;
1744 +}
1745 +
1746 Index: tools/quake3/q3map2/light.c
1747 ===================================================================
1748 --- tools/quake3/q3map2/light.c (revision 290)
1749 +++ tools/quake3/q3map2/light.c (working copy)
1750 @@ -1363,6 +1363,56 @@
1751                         break;
1752         }
1753         
1754 +       /////// Floodlighting for point //////////////////
1755 +       //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1756 +       if (floodlighty)
1757 +       {
1758 +               int q;
1759 +               float addSize,f;
1760 +               vec3_t col,dir;
1761 +               col[0]=col[1]=col[2]=floodlightIntensity;
1762 +               dir[0]=dir[1]=0;
1763 +               dir[2]=1;
1764 +      
1765 +               trace.testOcclusion = qtrue;
1766 +               trace.forceSunlight = qfalse;
1767 +               trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1768 +               trace.testAll = qtrue;     
1769 +      
1770 +               for (q=0;q<2;q++)
1771 +               {
1772 +                       if (q==0) //upper hemisphere
1773 +                       {
1774 +                               trace.normal[0]=0;
1775 +                               trace.normal[1]=0;
1776 +                               trace.normal[2]=1;
1777 +                       }
1778 +                       else //lower hemisphere
1779 +                       {
1780 +                               trace.normal[0]=0;
1781 +                               trace.normal[1]=0;
1782 +                               trace.normal[2]=-1;
1783 +                       }
1784 +
1785 +                       f = FloodLightForSample(&trace);
1786 +
1787 +                       contributions[ numCon ].color[0]=col[0]*f;
1788 +                       contributions[ numCon ].color[1]=col[1]*f;
1789 +                       contributions[ numCon ].color[2]=col[2]*f;
1790 +
1791 +                       contributions[ numCon ].dir[0]=dir[0];
1792 +                       contributions[ numCon ].dir[1]=dir[1];
1793 +                       contributions[ numCon ].dir[2]=dir[2];
1794 +
1795 +                       contributions[ numCon ].style = 0;
1796 +                       numCon++;               
1797 +                       /* push average direction around */
1798 +                       addSize = VectorLength( col );
1799 +                       VectorMA( gp->dir, addSize, dir, gp->dir );
1800 +               }
1801 +       }
1802 +       /////////////////////
1803 +
1804         /* normalize to get primary light direction */
1805         VectorNormalize( gp->dir, gp->dir );
1806         
1807 @@ -1544,6 +1594,12 @@
1808         qboolean        minVertex, minGrid;
1809         const char      *value;
1810         
1811 +       /* floodlight them up */
1812 +       if( floodlighty )
1813 +       {
1814 +               Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1815 +               RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1816 +       }
1817  
1818         /* ydnar: smooth normals */
1819         if( shade )
1820 @@ -1675,6 +1731,7 @@
1821                 /* flag bouncing */
1822                 bouncing = qtrue;
1823                 VectorClear( ambientColor );
1824 +               floodlighty = qfalse;
1825                 
1826                 /* generate diffuse lights */
1827                 RadFreeLights();
1828 @@ -2114,6 +2171,21 @@
1829                         loMem = qtrue;
1830                         Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
1831                 }
1832 +               else if( !strcmp( argv[ i ], "-floodlight" ) )
1833 +               {
1834 +                       floodlighty = qtrue;
1835 +                       Sys_Printf( "FloodLighting enabled\n" );
1836 +               }
1837 +               else if( !strcmp( argv[ i ], "-debugnormals" ) )
1838 +               {
1839 +                       debugnormals = qtrue;
1840 +                       Sys_Printf( "DebugNormals enabled\n" );
1841 +               }
1842 +               else if( !strcmp( argv[ i ], "-lowquality" ) )
1843 +               {
1844 +                       floodlight_lowquality = qtrue;
1845 +                       Sys_Printf( "Low Quality FloodLighting enabled\n" );
1846 +               }
1847                 
1848                 else
1849                         Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
1850 @@ -2156,6 +2228,7 @@
1851         
1852         /* ydnar: set up optimization */
1853         SetupBrushes();
1854 +       SetupFloodLight();
1855         SetupSurfaceLightmaps();
1856         
1857         /* initialize the surface facet tracing */
1858 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1859 ===================================================================
1860 --- tools/quake3/q3map2/lightmaps_ydnar.c       (revision 290)
1861 +++ tools/quake3/q3map2/lightmaps_ydnar.c       (working copy)
1862 @@ -413,6 +413,12 @@
1863                 lm->superNormals = safe_malloc( size );
1864         memset( lm->superNormals, 0, size );
1865         
1866 +       /* allocate floodlight map storage */
1867 +       size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1868 +       if( lm->superFloodLight == NULL )
1869 +               lm->superFloodLight = safe_malloc( size );
1870 +       memset( lm->superFloodLight, 0, size );
1871 +       
1872         /* allocate cluster map storage */
1873         size = lm->sw * lm->sh * sizeof( int );
1874         if( lm->superClusters == NULL )
1875 Index: tools/quake3/q3map2/q3map2.h
1876 ===================================================================
1877 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1878 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1879 @@ -265,6 +265,7 @@
1880  #define SUPER_NORMAL_SIZE              3
1881  #define SUPER_DELUXEL_SIZE             3
1882  #define BSP_DELUXEL_SIZE               3
1883 +#define SUPER_FLOODLIGHT_SIZE  1
1884  
1885  #define VERTEX_LUXEL( s, v )   (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1886  #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1887 @@ -273,6 +274,7 @@
1888  #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1889  #define SUPER_ORIGIN( x, y )   (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1890  #define SUPER_NORMAL( x, y )   (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1891 +#define SUPER_FLOODLIGHT( x, y )       (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )       
1892  #define SUPER_CLUSTER( x, y )  (lm->superClusters + (((y) * lm->sw) + (x)))
1893  #define SUPER_DELUXEL( x, y )  (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1894  #define BSP_DELUXEL( x, y )            (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE))
1895 @@ -1364,6 +1366,7 @@
1896         
1897         float                                   *superDeluxels; /* average light direction */
1898         float                                   *bspDeluxels;
1899 +       float                                   *superFloodLight; 
1900  }
1901  rawLightmap_t;
1902  
1903 @@ -1670,6 +1673,9 @@
1904  void                                           SmoothNormals( void );
1905  
1906  void                                           MapRawLightmap( int num );
1907 +void                                           SetupFloodLight();
1908 +float                                          FloodLightForSample( trace_t *trace );
1909 +void                                           FloodLightRawLightmap( int num );
1910  void                                           IlluminateRawLightmap( int num );
1911  void                                           IlluminateVertexes( int num );
1912  
1913 @@ -2037,6 +2043,12 @@
1914  Q_EXTERN qboolean                      sunOnly;
1915  Q_EXTERN int                           approximateTolerance Q_ASSIGN( 0 );
1916  Q_EXTERN qboolean                      noCollapse;
1917 +Q_EXTERN qboolean                      debugnormals Q_ASSIGN( qfalse );
1918 +Q_EXTERN qboolean                      floodlighty Q_ASSIGN( qfalse );
1919 +Q_EXTERN qboolean                      floodlight_lowquality Q_ASSIGN( qfalse );
1920 +Q_EXTERN vec3_t                                floodlightRGB;
1921 +Q_EXTERN float                         floodlightIntensity Q_ASSIGN( 512 );
1922 +Q_EXTERN float                         floodlightDistance Q_ASSIGN( 1024 );
1923  Q_EXTERN qboolean                      debug;
1924  Q_EXTERN qboolean                      debugSurfaces;
1925  Q_EXTERN qboolean                      debugUnused;
1926 Index: tools/quake3/q3map2/q3map2.h
1927 ===================================================================
1928 --- tools/quake3/q3map2/q3map2.h        (revision 290)
1929 +++ tools/quake3/q3map2/q3map2.h        (working copy)
1930 @@ -1274,6 +1274,7 @@
1931         vec3_t                          color;                  /* starts out at full color, may be reduced if transparent surfaces are crossed */
1932         
1933         /* output */
1934 +       vec3_t                          hit;
1935         int                                     compileFlags;   /* for determining surface compile flags traced through */
1936         qboolean                        passSolid;
1937         qboolean                        opaque;
1938 Index: tools/quake3/q3map2/light_trace.c
1939 ===================================================================
1940 --- tools/quake3/q3map2/light_trace.c   (revision 290)
1941 +++ tools/quake3/q3map2/light_trace.c   (working copy)
1942 @@ -1596,6 +1596,7 @@
1943         /* bogus node number means solid, end tracing unless testing all */
1944         if( nodeNum < 0 )
1945         {
1946 +               VectorCopy( origin, trace->hit );
1947                 trace->passSolid = qtrue;
1948                 return qtrue;
1949         }
1950 @@ -1606,6 +1607,7 @@
1951         /* solid? */
1952         if( node->type == TRACE_LEAF_SOLID )
1953         {
1954 +               VectorCopy( origin, trace->hit );
1955                 trace->passSolid = qtrue;
1956                 return qtrue;
1957         }
1958 Index: tools/quake3/q3map2/light_ydnar.c
1959 ===================================================================
1960 --- tools/quake3/q3map2/light_ydnar.c   (revision 290)
1961 +++ tools/quake3/q3map2/light_ydnar.c   (working copy)
1962 @@ -372,7 +372,7 @@
1963  #define NUDGE                  0.5f
1964  #define BOGUS_NUDGE            -99999.0f
1965  
1966 -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 ] )
1967 +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 ] )
1968  {
1969         int                             i, x, y, numClusters, *clusters, pointCluster, *cluster;
1970         float                   *luxel, *origin, *normal, d, lightmapSampleOffset;
1971 @@ -380,6 +380,12 @@
1972         vec3_t                  pNormal;
1973         vec3_t                  vecs[ 3 ];
1974         vec3_t                  nudged;
1975 +       vec3_t                  cverts[ 3 ];
1976 +       vec3_t                  temp;
1977 +       vec4_t                  sideplane, hostplane;
1978 +       vec3_t                  origintwo;
1979 +       int                             j, next;
1980 +       float                   e;
1981         float                   *nudge;
1982         static float    nudges[][ 2 ] =
1983                                         {
1984 @@ -473,6 +479,51 @@
1985         /* non axial lightmap projection (explicit xyz) */
1986         else
1987                 VectorCopy( dv->xyz, origin );
1988 +
1989 +       //////////////////////
1990 +       //27's test to make sure samples stay within the triangle boundaries
1991 +       //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
1992 +       //2) if it does, nudge it onto the correct side.
1993 +
1994 +       if (worldverts!=NULL)
1995 +       {
1996 +               for (j=0;j<3;j++)
1997 +               {
1998 +                       VectorCopy(worldverts[j],cverts[j]);    
1999 +               }
2000 +               PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2001 +
2002 +               for (j=0;j<3;j++)
2003 +               {
2004 +                       for (i=0;i<3;i++)
2005 +                       {
2006 +                               //build plane using 2 edges and a normal
2007 +                               next=(i+1)%3;
2008 +
2009 +                               VectorCopy(cverts[next],temp);
2010 +                               VectorAdd(temp,hostplane,temp);
2011 +                               PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2012 +
2013 +                               //planetest sample point  
2014 +                               e=DotProduct(origin,sideplane);
2015 +                               e=e-sideplane[3];
2016 +                               if (e>0)
2017 +                               {
2018 +                                       //we're bad.
2019 +                                       //VectorClear(origin);
2020 +                                       //Move the sample point back inside triangle bounds
2021 +                                       origin[0]-=sideplane[0]*(e+1);
2022 +                                       origin[1]-=sideplane[1]*(e+1);
2023 +                                       origin[2]-=sideplane[2]*(e+1);
2024 +#ifdef DEBUG_27_1
2025 +                                       VectorClear(origin);
2026 +#endif 
2027 +                               }
2028 +                       }
2029 +               }
2030 +       }
2031 +
2032 +       ////////////////////////
2033         
2034         /* planar surfaces have precalculated lightmap vectors for nudging */
2035         if( lm->plane != NULL )
2036 @@ -504,8 +555,13 @@
2037         else
2038                 origin[ lm->axisNum ] += lightmapSampleOffset;
2039         
2040 +       VectorCopy(origin,origintwo);
2041 +       origintwo[0]+=vecs[2][0];
2042 +       origintwo[1]+=vecs[2][1];
2043 +       origintwo[2]+=vecs[2][2];
2044 +       
2045         /* get cluster */
2046 -       pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2047 +       pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2048         
2049         /* another retarded hack, storing nudge count in luxel[ 1 ] */
2050         luxel[ 1 ] = 0.0f;      
2051 @@ -521,14 +577,14 @@
2052                         for( i = 0; i < 3; i++ )
2053                         {
2054                                 /* set nudged point*/
2055 -                               nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2056 +                               nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2057                         }
2058                         nudge += 2;
2059                         
2060                         /* get pvs cluster */
2061                         pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
2062 -                       if( pointCluster >= 0 ) 
2063 -                               VectorCopy( nudged, origin );
2064 +                       //if( pointCluster >= 0 )       
2065 +                       //      VectorCopy( nudged, origin );
2066                         luxel[ 1 ] += 1.0f;
2067                 }
2068         }
2069 @@ -538,8 +594,8 @@
2070         {
2071                 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
2072                 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
2073 -               if( pointCluster >= 0 )
2074 -                       VectorCopy( nudged, origin );
2075 +               //if( pointCluster >= 0 )
2076 +               //      VectorCopy( nudged, origin );
2077                 luxel[ 1 ] += 1.0f;
2078         }
2079         
2080 @@ -585,7 +641,7 @@
2081  than the distance between two luxels (thanks jc :)
2082  */
2083  
2084 -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 ] )
2085 +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 ] )
2086  {
2087         bspDrawVert_t   mid, *dv2[ 3 ];
2088         int                             max;
2089 @@ -633,7 +689,7 @@
2090         
2091         /* split the longest edge and map it */
2092         LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
2093 -       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
2094 +       MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
2095         
2096         /* push the point up a little bit to account for fp creep (fixme: revisit this) */
2097         //%     VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
2098 @@ -641,12 +697,12 @@
2099         /* recurse to first triangle */
2100         VectorCopy( dv, dv2 );
2101         dv2[ max ] = &mid;
2102 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2103 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2104         
2105         /* recurse to second triangle */
2106         VectorCopy( dv, dv2 );
2107         dv2[ (max + 1) % 3 ] = &mid;
2108 -       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2109 +       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2110  }
2111  
2112  
2113 @@ -662,6 +718,7 @@
2114         int                             i;
2115         vec4_t                  plane;
2116         vec3_t                  *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2117 +       vec3_t                  worldverts[ 3 ];
2118         
2119         
2120         /* get plane if possible */
2121 @@ -687,16 +744,20 @@
2122                 ttv = NULL;
2123         }
2124         
2125 +       VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2126 +       VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2127 +       VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
2128 +       
2129         /* map the vertexes */
2130 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2131 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2132 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2133 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
2134 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
2135 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
2136         
2137         /* 2002-11-20: prefer axial triangle edges */
2138         if( mapNonAxial )
2139         {
2140                 /* subdivide the triangle */
2141 -               MapTriangle_r( lm, info, dv, plane, stv, ttv );
2142 +               MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2143                 return qtrue;
2144         }
2145         
2146 @@ -718,7 +779,7 @@
2147                         dv2[ 2 ] = dv[ (i + 1) % 3 ];
2148                         
2149                         /* map the degenerate triangle */
2150 -                       MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2151 +                       MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2152                 }
2153         }
2154         
2155 @@ -780,8 +841,8 @@
2156         LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
2157         
2158         /* map the vertexes */
2159 -       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
2160 -       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
2161 +       MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
2162 +       MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
2163         
2164         /* 0 and 2 */
2165         if( max == 0 )
2166 @@ -866,10 +927,10 @@
2167         }
2168         
2169         /* map the vertexes */
2170 -       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2171 -       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2172 -       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2173 -       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
2174 +       MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
2175 +       MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
2176 +       MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
2177 +       MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
2178         
2179         /* subdivide the quad */
2180         MapQuad_r( lm, info, dv, plane, stv, ttv );
2181 @@ -1161,7 +1222,7 @@
2182                                         continue;
2183                                 
2184                                 /* map the fake vert */
2185 -                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
2186 +                               MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
2187                         }
2188                 }
2189         }
2190 @@ -1636,22 +1697,32 @@
2191                                         deluxel = SUPER_DELUXEL( x, y );
2192                                         origin = SUPER_ORIGIN( x, y );
2193                                         normal = SUPER_NORMAL( x, y );
2194 -                                       
2195 -                                       /* set contribution count */
2196 -                                       lightLuxel[ 3 ] = 1.0f;
2197 -                                       
2198 -                                       /* setup trace */
2199 -                                       trace.cluster = *cluster;
2200 -                                       VectorCopy( origin, trace.origin );
2201 -                                       VectorCopy( normal, trace.normal );
2202 -                                       
2203 -                                       /* get light for this sample */
2204 -                                       LightContributionToSample( &trace );
2205 -                                       VectorCopy( trace.color, lightLuxel );
2206 -                                       
2207 -                                       /* add to count */
2208 -                                       if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2209 +
2210 +                                       ////////// 27's temp hack for testing edge clipping ////
2211 +                                       if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2212 +                                       {
2213 +                                               lightLuxel[ 1 ] = 255;
2214 +                                               lightLuxel[ 3 ] = 1.0f;
2215                                                 totalLighted++;
2216 +                                       }
2217 +                                       else
2218 +                                       {
2219 +                                               /* set contribution count */
2220 +                                               lightLuxel[ 3 ] = 1.0f;
2221 +                                               
2222 +                                               /* setup trace */
2223 +                                               trace.cluster = *cluster;
2224 +                                               VectorCopy( origin, trace.origin );
2225 +                                               VectorCopy( normal, trace.normal );
2226 +                                               
2227 +                                               /* get light for this sample */
2228 +                                               LightContributionToSample( &trace );
2229 +                                               VectorCopy( trace.color, lightLuxel );
2230 +                                               
2231 +                                               /* add to count */
2232 +                                               if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2233 +                                                       totalLighted++;
2234 +                                       }
2235                                         
2236                                         /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2237                                         if( deluxemap )
2238 Index: tools/quake3/q3map2/q3map2.h
2239 ===================================================================
2240 --- tools/quake3/q3map2/q3map2.h        (revision 290)
2241 +++ tools/quake3/q3map2/q3map2.h        (working copy)
2242 @@ -34,8 +34,8 @@
2243  
2244  
2245  /* version */
2246 -#define Q3MAP_VERSION  "2.5.11"
2247 -#define Q3MAP_MOTD             "A well-oiled toaster oven"
2248 +#define Q3MAP_VERSION  "2.5.11-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTtrianglecheck"
2249 +#define Q3MAP_MOTD             "Blackhole Box gives the light back"
2250  
2251  
2252  
2253 Index: include/version.default
2254 ===================================================================
2255 --- include/version.default     (revision 290)
2256 +++ include/version.default     (working copy)
2257 @@ -1 +1 @@
2258 -1.4.0\r
2259 +1.4.0-div0-obj-bp2texdeffix-bpsurfacedialog\r