1 NOTE: this patch set is autogenerated from the "singlepatches" subdirectory of nexuiz/trunk/misc.
3 Do not commit changes to THIS!
6 sh mergepatches.sh > gtkradiant-nexuiz-patchset.diff
7 before committing new singlepatches!
11 Index: libs/picomodel/pm_obj.c
12 ===================================================================
13 --- libs/picomodel/pm_obj.c (revision 290)
14 +++ libs/picomodel/pm_obj.c (working copy)
20 static int _obj_mtl_load( picoModel_t *model )
22 - //picoShader_t *curShader = NULL;
23 + picoShader_t *curShader = NULL;
25 picoByte_t *mtlBuffer;
28 /* get next token in material file */
29 if (_pico_parse( p,1 ) == NULL)
34 /* skip empty lines */
35 if (p->token == NULL || !strlen( p->token ))
37 else if (!_pico_stricmp(p->token,"map_kd"))
40 + picoShader_t *shader;
42 /* pointer to current shader must be valid */
43 if (curShader == NULL)
45 _pico_printf( PICO_ERROR,"Missing material map name in MTL, line %d.",p->curLine);
46 _obj_mtl_error_return;
48 + /* create a new pico shader */
49 + shader = PicoNewShader( model );
51 + _obj_mtl_error_return;
52 /* set shader map name */
53 PicoSetShaderMapName( shader,mapName );
56 /* return with success */
62 * loads a wavefront obj model file.
64 PicoSetModelFileName( model,fileName );
66 /* try loading the materials; we don't handle the result */
69 _obj_mtl_load( model );
76 + else if (!_pico_stricmp(p->token,"usemtl"))
78 + picoShader_t *shader;
81 + /* get material name */
82 + name = _pico_parse( p,0 );
84 + /* validate material name */
85 + if (name == NULL || !strlen(name))
87 + _pico_printf( PICO_ERROR,"Missing material name in OBJ, line %d.",p->curLine);
91 + shader = PicoFindShader( model, name, 1 );
94 + _pico_printf( PICO_ERROR,"Undefined material name in OBJ, line %d. Making a default shader.",p->curLine);
96 + /* create a new pico shader */
97 + shader = PicoNewShader( model );
100 + PicoSetShaderName( shader,name );
101 + PicoSetShaderMapName( shader,name );
102 + PicoSetSurfaceShader( curSurface, shader );
107 + PicoSetSurfaceShader( curSurface, shader );
111 /* skip unparsed rest of line and continue */
112 _pico_parse_skip_rest( p );
114 Index: radiant/brush_primit.cpp
115 ===================================================================
116 --- radiant/brush_primit.cpp (revision 297)
117 +++ radiant/brush_primit.cpp (working copy)
119 // ConvertTexMatWithQTexture( &f->brushprimit_texdef, NULL, &f->brushprimit_texdef, f->d_texture );
122 -void BrushPrimitFaceToFace(face_t *face)
123 +void BrushPrimitFaceToFace(face_t *f)
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
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;
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]);
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];
154 + Face_TexdefFromTextureCoordinates(ST[0], ST[1], ST[2], f->d_texture, f);
157 // TEXTURE LOCKING -----------------------------------------------------------------------------------------------------
158 Index: radiant/brush.cpp
159 ===================================================================
160 --- radiant/brush.cpp (revision 297)
161 +++ radiant/brush.cpp (working copy)
166 +long double HighestImpactSign(long double a, long double b)
168 + // returns the sign of the value with larger abs
175 +void Face_TexdefFromTextureVectors (face_t *f, long double STfromXYZ[2][4], vec3_t pvecs[2], int sv, int tv)
185 + // undo the texture transform
186 + for (j=0 ; j<4 ; j++) {
187 + STfromXYZ[0][j] *= q->width;
188 + STfromXYZ[1][j] *= q->height;
192 + td->shift[0] = STfromXYZ[0][3];
193 + td->shift[1] = STfromXYZ[1][3];
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];
202 + sinv, cosv, td->scale[0], td->scale[1]
204 + sinv^2 + cosv^2 = 1
205 + pvecs[0][sv] is +/-1
208 + pvecs[1][tv] is +/-1
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];
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]);
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];
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[
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
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!
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];
248 + td->rotate = ang * 180 / Q_PI; // FIXME possibly snap this to 0/90/180 (270 can't happen)?
256 @@ -462,6 +548,135 @@
257 xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
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)
262 + return a1 * b2 * c3 + a2 * b3 * c1 + a3 * b1 * c2
263 + - a1 * c2 * b3 - a2 * c3 * b1 - a3 * c1 * b2;
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)
269 + det = SarrusDetScalar(a1, b1, c1,
272 + *a = SarrusDetScalar(d1, b1, c1,
275 + *b = SarrusDetScalar(a1, d1, c1,
278 + *c = SarrusDetScalar(a1, b1, d1,
283 +void Face_TexdefFromTextureCoordinates ( float *xyzst1, float *xyzst2, float *xyzst3, qtexture_t *q, face_t *f)
288 + long double STfromXYZ[2][4];
290 + // get natural texture axis
291 + TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
295 + else if (pvecs[0][1])
302 + else if (pvecs[1][1])
307 + uv = 3 - sv - tv; // the "other one"
309 + // find the STfromXYZ 4-vectors
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];
316 + GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
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];
322 + GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
325 + STfromXYZ[0][uv] = 0;
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]
333 + STfromXYZ[1][uv] = 0;
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]
342 + printf("%s\n", q->name);
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]);
351 + float newSTfromXYZ[2][4];
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]);
358 + Face_TexdefFromTextureVectors (f, STfromXYZ, pvecs, sv, tv);
361 + Face_TextureVectors(f, newSTfromXYZ);
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]);
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
389 //==========================================================================
393 ===================================================================
394 --- radiant/qe3.h (revision 297)
395 +++ radiant/qe3.h (working copy)
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] );
405 ===================================================================
406 --- config.py (revision 297)
407 +++ config.py (working copy)
410 env.Append( LIBS = 'z' )
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 );
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);
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);
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)
453 bool m_bPluginToolbar;
455 //++timo this is most likely broken, I don't know what it's supposed to do
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);
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"));
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);
482 @@ -5686,12 +5686,12 @@
484 void MainFrame::OnSnaptogrid()
486 - g_PrefsDlg.m_bNoClamp ^= 1;
487 + g_PrefsDlg.m_bSnap ^= 1;
488 g_PrefsDlg.SavePrefs ();
490 GtkWidget *item = GTK_WIDGET (g_object_get_data (G_OBJECT (m_pWidget), "menu_snaptogrid"));
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);
497 Index: radiant/preferences.cpp
498 ===================================================================
499 --- radiant/preferences.cpp (revision 297)
500 +++ radiant/preferences.cpp (working copy)
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"
510 m_bWideToolbar = TRUE;
511 m_bPluginToolbar = TRUE;
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);
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);
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;
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)
545 texdef_to_face_t *position, *prev_pos;
546 + brushprimit_texdef_t bp;
548 if(selected_brushes.next != &selected_brushes)
554 - position->texdef = f->texdef;
555 - position->orig_texdef = f->texdef;
556 + position->texdef = f->texdef;
557 + if(g_qeglobals.m_bBrushPrimitMode)
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;
563 + position->orig_texdef = position->texdef;
564 prev_pos->next = position;
570 position->texdef = f->texdef;
571 - position->orig_texdef = f->texdef;
572 + if(g_qeglobals.m_bBrushPrimitMode)
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;
578 + position->orig_texdef = position->texdef;
580 for(i=1; i<g_ptrSelectedFaces.GetSize(); i++)
585 position->texdef = f->texdef;
586 - position->orig_texdef = f->texdef;
587 + if(g_qeglobals.m_bBrushPrimitMode)
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;
593 + position->orig_texdef = position->texdef;
594 prev_pos->next = position;
599 SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->orig_texdef, bFit_to_Scale);
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);
604 Undo_Start("set facelist texdefs");
608 SetFaceTexdef_Q2(texdef_to_face->face, &texdef_to_face->texdef, bFit_to_Scale);
610 - SetFaceTexdef(texdef_to_face->face, &texdef_to_face->texdef, NULL , bFit_to_Scale);
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);
616 Brush_Build(texdef_to_face->brush);
618 texdef_to_face->texdef = texdef_to_face->face->texdef;
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)
624 texdef_to_face->orig_texdef = texdef_to_face->texdef;
625 + texdef_to_face->orig_bp_texdef = texdef_to_face->face->brushprimit_texdef;
631 void SI_FaceList_FitTexture(texdef_to_face_t* si_texdef_face_list, int nHeight, int nWidth)
633 texdef_to_face_t* temp_texdef_face_list;
634 + brushprimit_texdef_t bp;
636 if (!si_texdef_face_list)
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
643 + if(g_qeglobals.m_bBrushPrimitMode)
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);
648 temp_texdef_face_list->texdef = temp_texdef_face_list->face->texdef;
651 Index: radiant/drag.cpp
652 ===================================================================
653 --- radiant/drag.cpp (revision 297)
654 +++ radiant/drag.cpp (working copy)
656 for (i=0 ; i<3 ; i++)
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)
662 move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
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++)
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)
675 delta[i] = floor(delta[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
677 @@ -2135,13 +2135,13 @@
679 void XYWnd::SnapToPoint (int x, int y, vec3_t point)
681 - if (g_PrefsDlg.m_bNoClamp)
682 + if (g_PrefsDlg.m_bSnap)
684 - XY_ToPoint(x, y, point);
685 + XY_ToGridPoint(x, y, point);
689 - XY_ToGridPoint(x, y, point);
690 + XY_ToPoint(x, y, point);
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 @@
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");
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]);
711 if (scale[0]<ZERO_EPSILON || scale[1]<ZERO_EPSILON)
712 Sys_Printf("Warning : unexpected scale==0 in TexMatToFakeTexCoords\n");
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];
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] )
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];
737 Index: radiant/select.cpp
738 ===================================================================
739 --- radiant/select.cpp (revision 297)
740 +++ radiant/select.cpp (working copy)
745 - if (g_PrefsDlg.m_bNoClamp)
746 + if (!g_PrefsDlg.m_bSnap)
748 Select_GetTrueMid(mid);
750 Index: include/isurfaceplugin.h
751 ===================================================================
752 --- include/isurfaceplugin.h (revision 297)
753 +++ include/isurfaceplugin.h (working copy)
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
762 Index: radiant/groupdialog.cpp
763 ===================================================================
764 --- radiant/groupdialog.cpp (revision 297)
765 +++ radiant/groupdialog.cpp (working copy)
766 @@ -1328,7 +1328,7 @@
769 // Spawnflags (4 colums wide max, or window gets too wide.)
770 - GtkWidget* LayoutTable = gtk_table_new (4, 4, FALSE);
771 + LayoutTable = gtk_table_new (4, 4, FALSE);
772 gtk_box_pack_start (GTK_BOX (vbox2), LayoutTable, FALSE, TRUE, 0);
773 gtk_widget_show(LayoutTable);
775 Index: tools/quake3/q3map2/convert_map.c
776 ===================================================================
777 --- tools/quake3/q3map2/convert_map.c (revision 290)
778 +++ tools/quake3/q3map2/convert_map.c (working copy)
780 #define SNAP_FLOAT_TO_INT 4
781 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
783 +typedef vec_t vec2_t[2];
785 +static vec_t Det3x3(vec_t a00, vec_t a01, vec_t a02,
786 + vec_t a10, vec_t a11, vec_t a12,
787 + vec_t a20, vec_t a21, vec_t a22)
790 + a00 * (a11 * a22 - a12 * a21)
791 + - a01 * (a10 * a22 - a12 * a20)
792 + + a02 * (a10 * a21 - a11 * a20);
795 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
797 + bspDrawSurface_t *s;
803 + vec3_t v1v0, v2v0, norm;
804 + bspDrawVert_t *vert[3];
805 + winding_t *polygon;
806 + plane_t *buildPlane = &mapplanes[buildSide->planenum];
809 + // first, start out with NULLs
810 + bestVert[0] = bestVert[1] = bestVert[2] = NULL;
812 + // brute force through all surfaces
813 + for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
815 + if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
817 + if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
819 + for(t = 0; t + 3 <= s->numIndexes; t += 3)
821 + vert[0] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 0]];
822 + vert[1] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 1]];
823 + vert[2] = &bspDrawVerts[s->firstVert + bspDrawIndexes[s->firstIndex + t + 2]];
824 + if(s->surfaceType == MST_PLANAR)
826 + VectorSubtract(vert[0]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
827 + VectorSubtract(vert[1]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
828 + VectorSubtract(vert[2]->normal, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
832 + // this is more prone to roundoff errors, but with embedded
833 + // models, there is no better way
834 + VectorSubtract(vert[1]->xyz, vert[0]->xyz, v1v0);
835 + VectorSubtract(vert[2]->xyz, vert[0]->xyz, v2v0);
836 + CrossProduct(v2v0, v1v0, norm);
837 + VectorNormalize(norm, norm);
838 + VectorSubtract(norm, buildPlane->normal, normdiff); if(VectorLength(normdiff) >= normalEpsilon) continue;
840 + if(abs(DotProduct(vert[0]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
841 + if(abs(DotProduct(vert[1]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
842 + if(abs(DotProduct(vert[2]->xyz, buildPlane->normal) - buildPlane->dist) >= distanceEpsilon) continue;
843 + // Okay. Correct surface type, correct shader, correct plane. Let's start with the business...
844 + polygon = CopyWinding(buildSide->winding);
845 + for(i = 0; i < 3; ++i)
850 + vec3_t *v1 = &vert[(i+1)%3]->xyz;
851 + vec3_t *v2 = &vert[(i+2)%3]->xyz;
854 + vec3_t sideDirection;
855 + // we now need to generate triNormal and triDist so that they represent the plane spanned by normal and (v2 - v1).
856 + VectorSubtract(*v2, *v1, sideDirection);
857 + CrossProduct(sideDirection, buildPlane->normal, triNormal);
858 + triDist = DotProduct(*v1, triNormal);
859 + ChopWindingInPlace(&polygon, triNormal, triDist, distanceEpsilon);
863 + thisarea = WindingArea(polygon);
866 + if(thisarea > best)
869 + bestVert[0] = vert[0];
870 + bestVert[1] = vert[1];
871 + bestVert[2] = vert[2];
873 + FreeWinding(polygon);
878 + //if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
879 + // fprintf(stderr, "brushside with %s: %d matches (%f area)\n", buildSide->shaderInfo->shader, matches, best);
882 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
889 + plane_t *buildPlane;
891 + bspDrawVert_t *vert[3];
896 fprintf( f, "\t// brush %d\n", num );
897 fprintf( f, "\t{\n" );
898 + fprintf( f, "\tbrushDef\n" );
899 + fprintf( f, "\t{\n" );
901 /* clear out build brush */
902 for( i = 0; i < buildBrush->numsides; i++ )
905 buildSide = &buildBrush->sides[ i ];
908 + buildPlane = &mapplanes[ buildSide->planenum ];
911 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
914 + // st-texcoords -> texMat block
915 + // start out with dummy
916 + VectorSet(buildSide->texMat[0], 1/32.0, 0, 0);
917 + VectorSet(buildSide->texMat[1], 0, 1/32.0, 0);
919 + // find surface for this side (by brute force)
921 + // - meshverts point in pairs of three into verts
923 + // - find the triangle that has most in common with our side
924 + GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
927 + if(vert[0] && vert[1] && vert[2])
931 + vec3_t xy1I, xy1J, xy1K;
932 + vec2_t stI, stJ, stK;
933 + vec_t D, D0, D1, D2;
935 + ComputeAxisBase(buildPlane->normal, texX, texY);
937 + VectorSet(xy1I, DotProduct(vert[0]->xyz, texX), DotProduct(vert[0]->xyz, texY), 1);
938 + VectorSet(xy1J, DotProduct(vert[1]->xyz, texX), DotProduct(vert[1]->xyz, texY), 1);
939 + VectorSet(xy1K, DotProduct(vert[2]->xyz, texX), DotProduct(vert[2]->xyz, texY), 1);
940 + stI[0] = vert[0]->st[0]; stI[1] = vert[0]->st[1];
941 + stJ[0] = vert[1]->st[0]; stJ[1] = vert[1]->st[1];
942 + stK[0] = vert[2]->st[0]; stK[1] = vert[2]->st[1];
944 + // - solve linear equations:
945 + // - (x, y) := xyz . (texX, texY)
946 + // - st[i] = texMat[i][0]*x + texMat[i][1]*y + texMat[i][2]
947 + // (for three vertices)
949 + xy1I[0], xy1I[1], 1,
950 + xy1J[0], xy1J[1], 1,
951 + xy1K[0], xy1K[1], 1
955 + for(i = 0; i < 2; ++i)
958 + stI[i], xy1I[1], 1,
959 + stJ[i], xy1J[1], 1,
963 + xy1I[0], stI[i], 1,
964 + xy1J[0], stJ[i], 1,
968 + xy1I[0], xy1I[1], stI[i],
969 + xy1J[0], xy1J[1], stJ[i],
970 + xy1K[0], xy1K[1], stK[i]
972 + VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
977 + fprintf(stderr, "degenerate triangle found when solving texMat equations for\n(%f %f %f) (%f %f %f) (%f %f %f)\n( %f %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n( %f %f %f ) -> ( %f %f )\n",
978 + buildPlane->normal[0], buildPlane->normal[1], buildPlane->normal[2],
979 + vert[0]->normal[0], vert[0]->normal[1], vert[0]->normal[2],
980 + texX[0], texX[1], texX[2], texY[0], texY[1], texY[2],
981 + vert[0]->xyz[0], vert[0]->xyz[1], vert[0]->xyz[2], xy1I[0], xy1I[1],
982 + vert[1]->xyz[0], vert[1]->xyz[1], vert[1]->xyz[2], xy1J[0], xy1J[1],
983 + vert[2]->xyz[0], vert[2]->xyz[1], vert[2]->xyz[2], xy1K[0], xy1K[1]
987 + if(strncmp(buildSide->shaderInfo->shader, "textures/common/", 16))
988 + fprintf(stderr, "no matching triangle for brushside using %s (hopefully nobody can see this side anyway)\n", buildSide->shaderInfo->shader);
990 /* get texture name */
991 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
992 @@ -129,14 +312,21 @@
994 /* print brush side */
995 /* ( 640 24 -224 ) ( 448 24 -224 ) ( 448 -232 -224 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 */
996 - fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) %s 0 0 0 0.5 0.5 0 0 0\n",
997 + fprintf( f, "\t\t( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( %.3f %.3f %.3f ) ( ( %.8f %.8f %.8f ) ( %.8f %.8f %.8f ) ) %s %d 0 0\n",
998 pts[ 0 ][ 0 ], pts[ 0 ][ 1 ], pts[ 0 ][ 2 ],
999 pts[ 1 ][ 0 ], pts[ 1 ][ 1 ], pts[ 1 ][ 2 ],
1000 pts[ 2 ][ 0 ], pts[ 2 ][ 1 ], pts[ 2 ][ 2 ],
1002 + buildSide->texMat[0][0], buildSide->texMat[0][1], buildSide->texMat[0][2],
1003 + buildSide->texMat[1][0], buildSide->texMat[1][1], buildSide->texMat[1][2],
1005 + // DEBUG: valid ? 0 : C_DETAIL
1008 + // TODO write brush primitives format here
1012 + fprintf( f, "\t}\n" );
1013 fprintf( f, "\t}\n\n" );
1016 Index: tools/quake3/q3map2/main.c
1017 ===================================================================
1018 --- tools/quake3/q3map2/main.c (revision 290)
1019 +++ tools/quake3/q3map2/main.c (working copy)
1020 @@ -276,6 +276,18 @@
1022 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
1024 + else if( !strcmp( argv[ i ], "-ne" ) )
1026 + normalEpsilon = atof( argv[ i + 1 ] );
1028 + Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
1030 + else if( !strcmp( argv[ i ], "-de" ) )
1032 + distanceEpsilon = atof( argv[ i + 1 ] );
1034 + Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
1038 /* clean up map name */
1039 Index: tools/quake3/q3map2/model.c
1040 ===================================================================
1041 --- tools/quake3/q3map2/model.c (revision 290)
1042 +++ tools/quake3/q3map2/model.c (working copy)
1045 picoIndex_t *indexes;
1047 + double normalEpsilon_save;
1048 + double distanceEpsilon_save;
1053 /* ydnar: giant hack land: generate clipping brushes for model triangles */
1054 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
1056 - vec3_t points[ 3 ], backs[ 3 ];
1057 + vec3_t points[ 4 ], backs[ 3 ];
1058 vec4_t plane, reverse, pa, pb, pc;
1063 @@ -437,90 +438,141 @@
1064 /* note: this doesn't work as well as simply using the plane of the triangle, below */
1065 for( k = 0; k < 3; k++ )
1067 - if( fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 1) % 3 ] ) &&
1068 - fabs( dv->normal[ k ] ) > fabs( dv->normal[ (k + 2) % 3 ] ) )
1069 + if( fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 1) % 3 ] ) &&
1070 + fabs( dv->normal[ k ] ) >= fabs( dv->normal[ (k + 2) % 3 ] ) )
1072 backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
1078 + VectorCopy( points[0], points[3] ); // for cyclic usage
1080 /* make plane for triangle */
1081 + // div0: add some extra spawnflags:
1082 + // 0: snap normals to axial planes for extrusion
1083 + // 8: extrude with the original normals
1084 + // 16: extrude only with up/down normals (ideal for terrain)
1085 + // 24: extrude by distance zero (may need engine changes)
1086 if( PlaneFromPoints( plane, points[ 0 ], points[ 1 ], points[ 2 ] ) )
1088 + vec3_t bestNormal;
1089 + float backPlaneDistance = 2;
1091 + if(spawnFlags & 8) // use a DOWN normal
1093 + if(spawnFlags & 16)
1095 + // 24: normal as is, and zero width (broken)
1096 + VectorCopy(plane, bestNormal);
1100 + // 8: normal as is
1101 + VectorCopy(plane, bestNormal);
1106 + if(spawnFlags & 16)
1108 + // 16: UP/DOWN normal
1109 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1113 + // 0: axial normal
1114 + if(fabs(plane[0]) > fabs(plane[1])) // x>y
1115 + if(fabs(plane[1]) > fabs(plane[2])) // x>y, y>z
1116 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1118 + if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
1119 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1121 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1123 + if(fabs(plane[1]) > fabs(plane[2])) // y>z, y>=x
1124 + VectorSet(bestNormal, 0, (plane[1] >= 0 ? 1 : -1), 0);
1125 + else // z>=y, y>=x
1126 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
1130 + /* build a brush */
1131 + buildBrush = AllocBrush( 48 );
1132 + buildBrush->entityNum = mapEntityNum;
1133 + buildBrush->original = buildBrush;
1134 + buildBrush->contentShader = si;
1135 + buildBrush->compileFlags = si->compileFlags;
1136 + buildBrush->contentFlags = si->contentFlags;
1137 + normalEpsilon_save = normalEpsilon;
1138 + distanceEpsilon_save = distanceEpsilon;
1139 + if(si->compileFlags & C_STRUCTURAL) // allow forced structural brushes here
1141 + buildBrush->detail = qfalse;
1143 + // only allow EXACT matches when snapping for these (this is mostly for caulk brushes inside a model)
1144 + if(normalEpsilon > 0)
1145 + normalEpsilon = 0;
1146 + if(distanceEpsilon > 0)
1147 + distanceEpsilon = 0;
1150 + buildBrush->detail = qtrue;
1152 /* regenerate back points */
1153 for( j = 0; j < 3; j++ )
1156 dv = &ds->verts[ ds->indexes[ i + j ] ];
1159 - VectorCopy( dv->xyz, backs[ j ] );
1161 - /* find nearest axial to plane normal and push back points opposite */
1162 - for( k = 0; k < 3; k++ )
1164 - if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
1165 - fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
1167 - backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
1172 + // shift by some units
1173 + VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
1177 /* make back plane */
1178 VectorScale( plane, -1.0f, reverse );
1179 - reverse[ 3 ] = -(plane[ 3 ] - 1);
1181 - /* make back pyramid point */
1182 - VectorCopy( points[ 0 ], nadir );
1183 - VectorAdd( nadir, points[ 1 ], nadir );
1184 - VectorAdd( nadir, points[ 2 ], nadir );
1185 - VectorScale( nadir, 0.3333333333333f, nadir );
1186 - VectorMA( nadir, -2.0f, plane, nadir );
1188 - /* make 3 more planes */
1189 - //% if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], nadir ) &&
1190 - //% PlaneFromPoints( pb, points[ 1 ], points[ 0 ], nadir ) &&
1191 - //% PlaneFromPoints( pc, points[ 0 ], points[ 2 ], nadir ) )
1192 + reverse[ 3 ] = -plane[ 3 ];
1193 + if((spawnFlags & 24) != 24)
1194 + reverse[3] += DotProduct(bestNormal, plane) * backPlaneDistance;
1195 + // that's at least sqrt(1/3) backPlaneDistance, unless in DOWN mode; in DOWN mode, we are screwed anyway if we encounter a plane that's perpendicular to the xy plane)
1197 if( PlaneFromPoints( pa, points[ 2 ], points[ 1 ], backs[ 1 ] ) &&
1198 - PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1199 - PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1200 + PlaneFromPoints( pb, points[ 1 ], points[ 0 ], backs[ 0 ] ) &&
1201 + PlaneFromPoints( pc, points[ 0 ], points[ 2 ], backs[ 2 ] ) )
1203 - /* build a brush */
1204 - buildBrush = AllocBrush( 48 );
1206 - buildBrush->entityNum = mapEntityNum;
1207 - buildBrush->original = buildBrush;
1208 - buildBrush->contentShader = si;
1209 - buildBrush->compileFlags = si->compileFlags;
1210 - buildBrush->contentFlags = si->contentFlags;
1211 - buildBrush->detail = qtrue;
1213 /* set up brush sides */
1214 buildBrush->numsides = 5;
1215 for( j = 0; j < buildBrush->numsides; j++ )
1216 buildBrush->sides[ j ].shaderInfo = si;
1218 buildBrush->sides[ 0 ].planenum = FindFloatPlane( plane, plane[ 3 ], 3, points );
1219 - buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 1, &points[ 2 ] );
1220 - buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 1, &points[ 1 ] );
1221 - buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 1, &points[ 0 ] );
1222 - buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, points );
1224 - /* add to entity */
1225 - if( CreateBrushWindings( buildBrush ) )
1228 - //% EmitBrushes( buildBrush, NULL, NULL );
1229 - buildBrush->next = entities[ mapEntityNum ].brushes;
1230 - entities[ mapEntityNum ].brushes = buildBrush;
1231 - entities[ mapEntityNum ].numBrushes++;
1234 - free( buildBrush );
1235 + buildBrush->sides[ 1 ].planenum = FindFloatPlane( pa, pa[ 3 ], 2, &points[ 1 ] ); // pa contains points[1] and points[2]
1236 + buildBrush->sides[ 2 ].planenum = FindFloatPlane( pb, pb[ 3 ], 2, &points[ 0 ] ); // pb contains points[0] and points[1]
1237 + buildBrush->sides[ 3 ].planenum = FindFloatPlane( pc, pc[ 3 ], 2, &points[ 2 ] ); // pc contains points[2] and points[0] (copied to points[3]
1238 + buildBrush->sides[ 4 ].planenum = FindFloatPlane( reverse, reverse[ 3 ], 3, backs );
1246 + normalEpsilon = normalEpsilon_save;
1247 + distanceEpsilon = distanceEpsilon_save;
1249 + /* add to entity */
1250 + if( CreateBrushWindings( buildBrush ) )
1253 + //% EmitBrushes( buildBrush, NULL, NULL );
1254 + buildBrush->next = entities[ mapEntityNum ].brushes;
1255 + entities[ mapEntityNum ].brushes = buildBrush;
1256 + entities[ mapEntityNum ].numBrushes++;
1259 + free( buildBrush );
1263 Index: tools/quake3/q3map2/map.c
1264 ===================================================================
1265 --- tools/quake3/q3map2/map.c (revision 290)
1266 +++ tools/quake3/q3map2/map.c (working copy)
1267 @@ -183,9 +183,15 @@
1268 snaps a plane to normal/distance epsilons
1271 -void SnapPlane( vec3_t normal, vec_t *dist )
1272 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
1274 - SnapNormal( normal );
1275 + // div0: ensure the point "center" stays on the plane (actually, this
1276 + // rotates the plane around the point center).
1277 + // if center lies on the plane, it is guaranteed to stay on the plane by
1279 + vec_t centerDist = DotProduct(normal, center);
1280 + SnapNormal( normal );
1281 + *dist += (DotProduct(normal, center) - centerDist);
1283 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1284 *dist = Q_rint( *dist );
1286 must be within an epsilon distance of the plane
1289 -int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points )
1290 +int FindFloatPlane( vec3_t normal, vec_t dist, int numPoints, vec3_t *points ) // NOTE: this has a side effect on the normal. Good or bad?
1294 @@ -207,10 +213,14 @@
1298 + vec3_t centerofweight;
1300 + VectorClear(centerofweight);
1301 + for(i = 0; i < numPoints; ++i)
1302 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1305 /* hash the plane */
1306 - SnapPlane( normal, &dist );
1307 + SnapPlane( normal, &dist, centerofweight );
1308 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1310 /* search the border bins as well */
1311 @@ -251,7 +261,13 @@
1315 - SnapPlane( normal, &dist );
1316 + vec3_t centerofweight;
1318 + VectorClear(centerofweight);
1319 + for(i = 0; i < numPoints; ++i)
1320 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1322 + SnapPlane( normal, &dist, centerofweight );
1323 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
1325 if( PlaneEqual( p, normal, dist ) )
1326 Index: tools/quake3/q3map2/shaders.c
1327 ===================================================================
1328 --- tools/quake3/q3map2/shaders.c (revision 290)
1329 +++ tools/quake3/q3map2/shaders.c (working copy)
1330 @@ -747,8 +747,14 @@
1333 if( VectorLength( si->color ) <= 0.0f )
1335 ColorNormalize( color, si->color );
1336 - VectorScale( color, (1.0f / count), si->averageColor );
1337 + VectorScale( color, (1.0f / count), si->averageColor );
1341 + VectorCopy( si->color, si->averageColor );
1346 Index: tools/quake3/q3map2/light_ydnar.c
1347 ===================================================================
1348 --- tools/quake3/q3map2/light_ydnar.c (revision 290)
1349 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
1350 @@ -1449,6 +1449,8 @@
1351 vec3_t color, averageColor, averageDir, total, temp, temp2;
1352 float tests[ 4 ][ 2 ] = { { 0.0f, 0 }, { 1, 0 }, { 0, 1 }, { 1, 1 } };
1355 + float *floodlight;
1358 /* bail if this number exceeds the number of raw lightmaps */
1359 @@ -1871,6 +1873,78 @@
1360 /* free light list */
1361 FreeTraceLights( &trace );
1363 + /* -----------------------------------------------------------------
1365 + ----------------------------------------------------------------- */
1369 + /* walk lightmaps */
1370 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1373 + if( lm->superLuxels[ lightmapNum ] == NULL )
1376 + /* apply floodlight to each luxel */
1377 + for( y = 0; y < lm->sh; y++ )
1379 + for( x = 0; x < lm->sw; x++ )
1382 + cluster = SUPER_CLUSTER( x, y );
1383 + //% if( *cluster < 0 )
1386 + /* get particulars */
1387 + luxel = SUPER_LUXEL( lightmapNum, x, y );
1388 + floodlight = SUPER_FLOODLIGHT( x, y );
1390 + flood[0]=floodlightRGB[0]*floodlightIntensity;
1391 + flood[1]=floodlightRGB[1]*floodlightIntensity;
1392 + flood[2]=floodlightRGB[2]*floodlightIntensity;
1394 + /* scale light value */
1395 + VectorScale( flood, *floodlight, flood );
1396 + luxel[0]+=flood[0];
1397 + luxel[1]+=flood[1];
1398 + luxel[2]+=flood[2];
1400 + if (luxel[3]==0) luxel[3]=1;
1408 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1411 + if( lm->superLuxels[ lightmapNum ] == NULL )
1414 + for( y = 0; y < lm->sh; y++ )
1416 + for( x = 0; x < lm->sw; x++ )
1419 + cluster = SUPER_CLUSTER( x, y );
1420 + //% if( *cluster < 0 )
1423 + /* get particulars */
1424 + luxel = SUPER_LUXEL( lightmapNum, x, y );
1425 + normal = SUPER_NORMAL ( x, y );
1427 + luxel[0]=(normal[0]*127)+127;
1428 + luxel[1]=(normal[1]*127)+127;
1429 + luxel[2]=(normal[2]*127)+127;
1435 /* -----------------------------------------------------------------
1437 ----------------------------------------------------------------- */
1438 @@ -3123,7 +3197,320 @@
1439 CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1442 +/////////////////////////////////////////////////////////////
1444 +#define FLOODLIGHT_CONE_ANGLE 88 /* degrees */
1445 +#define FLOODLIGHT_NUM_ANGLE_STEPS 16
1446 +#define FLOODLIGHT_NUM_ELEVATION_STEPS 4
1447 +#define FLOODLIGHT_NUM_VECTORS (FLOODLIGHT_NUM_ANGLE_STEPS * FLOODLIGHT_NUM_ELEVATION_STEPS)
1449 +static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1450 +static int numFloodVectors = 0;
1452 +void SetupFloodLight( void )
1455 + float angle, elevation, angleStep, elevationStep;
1456 + const char *value;
1457 + double v1,v2,v3,v4,v5;
1460 + Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1462 + /* calculate angular steps */
1463 + angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1464 + elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1466 + /* iterate angle */
1468 + for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1470 + /* iterate elevation */
1471 + for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1473 + floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1474 + floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1475 + floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1476 + numFloodVectors++;
1480 + /* emit some statistics */
1481 + Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1484 + value = ValueForKey( &entities[ 0 ], "_floodlight" );
1486 + if( value[ 0 ] != '\0' )
1489 + v4=floodlightDistance;
1490 + v5=floodlightIntensity;
1492 + sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1494 + floodlightRGB[0]=v1;
1495 + floodlightRGB[1]=v2;
1496 + floodlightRGB[2]=v3;
1498 + if (VectorLength(floodlightRGB)==0)
1500 + VectorSet(floodlightRGB,240,240,255);
1503 + if (v4<1) v4=1024;
1506 + floodlightDistance=v4;
1507 + floodlightIntensity=v5;
1509 + floodlighty = qtrue;
1510 + Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1514 + VectorSet(floodlightRGB,240,240,255);
1515 + //floodlighty = qtrue;
1516 + //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1518 + VectorNormalize(floodlightRGB,floodlightRGB);
1521 +//27 - lighttracer style ambient occlusion light hack.
1522 +//Kudos to the dirtmapping author for most of this source.
1523 +void FloodLightRawLightmap( int rawLightmapNum )
1525 + int i, x, y, sx, sy, *cluster;
1526 + float *origin, *normal, *floodlight, *floodlight2, average, samples;
1527 + rawLightmap_t *lm;
1528 + surfaceInfo_t *info;
1531 + /* bail if this number exceeds the number of raw lightmaps */
1532 + if( rawLightmapNum >= numRawLightmaps )
1535 + /* get lightmap */
1536 + lm = &rawLightmaps[ rawLightmapNum ];
1538 + memset(&trace,0,sizeof(trace_t));
1540 + trace.testOcclusion = qtrue;
1541 + trace.forceSunlight = qfalse;
1542 + trace.twoSided = qtrue;
1543 + trace.recvShadows = lm->recvShadows;
1544 + trace.numSurfaces = lm->numLightSurfaces;
1545 + trace.surfaces = &lightSurfaces[ lm->firstLightSurface ];
1546 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1547 + trace.testAll = qfalse;
1548 + trace.distance = 1024;
1550 + /* twosided lighting (may or may not be a good idea for lightmapped stuff) */
1551 + //trace.twoSided = qfalse;
1552 + for( i = 0; i < trace.numSurfaces; i++ )
1555 + info = &surfaceInfos[ trace.surfaces[ i ] ];
1557 + /* check twosidedness */
1558 + if( info->si->twoSided )
1560 + trace.twoSided = qtrue;
1566 + for( y = 0; y < lm->sh; y++ )
1568 + for( x = 0; x < lm->sw; x++ )
1571 + cluster = SUPER_CLUSTER( x, y );
1572 + origin = SUPER_ORIGIN( x, y );
1573 + normal = SUPER_NORMAL( x, y );
1574 + floodlight = SUPER_FLOODLIGHT( x, y );
1576 + /* set default dirt */
1577 + *floodlight = 0.0f;
1579 + /* only look at mapped luxels */
1580 + if( *cluster < 0 )
1583 + /* copy to trace */
1584 + trace.cluster = *cluster;
1585 + VectorCopy( origin, trace.origin );
1586 + VectorCopy( normal, trace.normal );
1591 + *floodlight = FloodLightForSample( &trace );
1595 + /* testing no filtering */
1598 + /* filter "dirt" */
1599 + for( y = 0; y < lm->sh; y++ )
1601 + for( x = 0; x < lm->sw; x++ )
1604 + cluster = SUPER_CLUSTER( x, y );
1605 + floodlight = SUPER_FLOODLIGHT( x, y );
1607 + /* filter dirt by adjacency to unmapped luxels */
1608 + average = *floodlight;
1610 + for( sy = (y - 1); sy <= (y + 1); sy++ )
1612 + if( sy < 0 || sy >= lm->sh )
1615 + for( sx = (x - 1); sx <= (x + 1); sx++ )
1617 + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1620 + /* get neighboring luxel */
1621 + cluster = SUPER_CLUSTER( sx, sy );
1622 + floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1623 + if( *cluster < 0 || *floodlight2 <= 0.0f )
1627 + average += *floodlight2;
1632 + if( samples <= 0.0f )
1637 + if( samples <= 0.0f )
1641 + *floodlight = average / samples;
1647 +FloodLightForSample()
1648 +calculates floodlight value for a given sample
1649 +once again, kudos to the dirtmapping coder
1651 +float FloodLightForSample( trace_t *trace )
1655 + float contribution;
1657 + float gatherLight, outLight;
1658 + vec3_t normal, worldUp, myUp, myRt, direction, displacement;
1666 + if( trace == NULL || trace->cluster < 0 )
1671 + dd = floodlightDistance;
1672 + VectorCopy( trace->normal, normal );
1674 + /* check if the normal is aligned to the world-up */
1675 + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1677 + if( normal[ 2 ] == 1.0f )
1679 + VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1680 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1682 + else if( normal[ 2 ] == -1.0f )
1684 + VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1685 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1690 + VectorSet( worldUp, 0.0f, 0.0f, 1.0f );
1691 + CrossProduct( normal, worldUp, myRt );
1692 + VectorNormalize( myRt, myRt );
1693 + CrossProduct( myRt, normal, myUp );
1694 + VectorNormalize( myUp, myUp );
1697 + /* iterate through ordered vectors */
1698 + for( i = 0; i < numFloodVectors; i++ )
1700 + if (floodlight_lowquality==qtrue)
1702 + if (rand()%10 != 0 ) continue;
1707 + /* transform vector into tangent space */
1708 + direction[ 0 ] = myRt[ 0 ] * floodVectors[ i ][ 0 ] + myUp[ 0 ] * floodVectors[ i ][ 1 ] + normal[ 0 ] * floodVectors[ i ][ 2 ];
1709 + direction[ 1 ] = myRt[ 1 ] * floodVectors[ i ][ 0 ] + myUp[ 1 ] * floodVectors[ i ][ 1 ] + normal[ 1 ] * floodVectors[ i ][ 2 ];
1710 + direction[ 2 ] = myRt[ 2 ] * floodVectors[ i ][ 0 ] + myUp[ 2 ] * floodVectors[ i ][ 1 ] + normal[ 2 ] * floodVectors[ i ][ 2 ];
1712 + /* set endpoint */
1713 + VectorMA( trace->origin, dd, direction, trace->end );
1715 + //VectorMA( trace->origin, 1, direction, trace->origin );
1717 + SetupTrace( trace );
1719 + TraceLine( trace );
1722 + if (trace->compileFlags & C_SKY )
1724 + contribution=1.0f;
1726 + else if ( trace->opaque )
1728 + VectorSubtract( trace->hit, trace->origin, displacement );
1729 + d=VectorLength( displacement );
1731 + // d=trace->distance;
1732 + //if (d>256) gatherDirt+=1;
1733 + contribution=d/dd;
1734 + if (contribution>1) contribution=1.0f;
1736 + //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1739 + gatherLight+=contribution;
1743 + if( gatherLight <= 0.0f )
1749 + gatherLight/=(sub);
1751 + outLight=gatherLight;
1752 + if( outLight > 1.0f )
1755 + /* return to sender */
1759 Index: tools/quake3/q3map2/light.c
1760 ===================================================================
1761 --- tools/quake3/q3map2/light.c (revision 290)
1762 +++ tools/quake3/q3map2/light.c (working copy)
1763 @@ -1363,6 +1363,56 @@
1767 + /////// Floodlighting for point //////////////////
1768 + //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1774 + col[0]=col[1]=col[2]=floodlightIntensity;
1778 + trace.testOcclusion = qtrue;
1779 + trace.forceSunlight = qfalse;
1780 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1781 + trace.testAll = qtrue;
1785 + if (q==0) //upper hemisphere
1787 + trace.normal[0]=0;
1788 + trace.normal[1]=0;
1789 + trace.normal[2]=1;
1791 + else //lower hemisphere
1793 + trace.normal[0]=0;
1794 + trace.normal[1]=0;
1795 + trace.normal[2]=-1;
1798 + f = FloodLightForSample(&trace);
1800 + contributions[ numCon ].color[0]=col[0]*f;
1801 + contributions[ numCon ].color[1]=col[1]*f;
1802 + contributions[ numCon ].color[2]=col[2]*f;
1804 + contributions[ numCon ].dir[0]=dir[0];
1805 + contributions[ numCon ].dir[1]=dir[1];
1806 + contributions[ numCon ].dir[2]=dir[2];
1808 + contributions[ numCon ].style = 0;
1810 + /* push average direction around */
1811 + addSize = VectorLength( col );
1812 + VectorMA( gp->dir, addSize, dir, gp->dir );
1815 + /////////////////////
1817 /* normalize to get primary light direction */
1818 VectorNormalize( gp->dir, gp->dir );
1820 @@ -1544,6 +1594,12 @@
1821 qboolean minVertex, minGrid;
1824 + /* floodlight them up */
1827 + Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1828 + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1831 /* ydnar: smooth normals */
1833 @@ -1675,6 +1731,7 @@
1836 VectorClear( ambientColor );
1837 + floodlighty = qfalse;
1839 /* generate diffuse lights */
1841 @@ -2114,6 +2171,21 @@
1843 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
1845 + else if( !strcmp( argv[ i ], "-floodlight" ) )
1847 + floodlighty = qtrue;
1848 + Sys_Printf( "FloodLighting enabled\n" );
1850 + else if( !strcmp( argv[ i ], "-debugnormals" ) )
1852 + debugnormals = qtrue;
1853 + Sys_Printf( "DebugNormals enabled\n" );
1855 + else if( !strcmp( argv[ i ], "-lowquality" ) )
1857 + floodlight_lowquality = qtrue;
1858 + Sys_Printf( "Low Quality FloodLighting enabled\n" );
1862 Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
1863 @@ -2156,6 +2228,7 @@
1865 /* ydnar: set up optimization */
1867 + SetupFloodLight();
1868 SetupSurfaceLightmaps();
1870 /* initialize the surface facet tracing */
1871 Index: tools/quake3/q3map2/lightmaps_ydnar.c
1872 ===================================================================
1873 --- tools/quake3/q3map2/lightmaps_ydnar.c (revision 290)
1874 +++ tools/quake3/q3map2/lightmaps_ydnar.c (working copy)
1875 @@ -413,6 +413,12 @@
1876 lm->superNormals = safe_malloc( size );
1877 memset( lm->superNormals, 0, size );
1879 + /* allocate floodlight map storage */
1880 + size = lm->sw * lm->sh * SUPER_FLOODLIGHT_SIZE * sizeof( float );
1881 + if( lm->superFloodLight == NULL )
1882 + lm->superFloodLight = safe_malloc( size );
1883 + memset( lm->superFloodLight, 0, size );
1885 /* allocate cluster map storage */
1886 size = lm->sw * lm->sh * sizeof( int );
1887 if( lm->superClusters == NULL )
1888 Index: tools/quake3/q3map2/q3map2.h
1889 ===================================================================
1890 --- tools/quake3/q3map2/q3map2.h (revision 290)
1891 +++ tools/quake3/q3map2/q3map2.h (working copy)
1893 #define SUPER_NORMAL_SIZE 3
1894 #define SUPER_DELUXEL_SIZE 3
1895 #define BSP_DELUXEL_SIZE 3
1896 +#define SUPER_FLOODLIGHT_SIZE 1
1898 #define VERTEX_LUXEL( s, v ) (vertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1899 #define RAD_VERTEX_LUXEL( s, v )(radVertexLuxels[ s ] + ((v) * VERTEX_LUXEL_SIZE))
1901 #define SUPER_LUXEL( s, x, y ) (lm->superLuxels[ s ] + ((((y) * lm->sw) + (x)) * SUPER_LUXEL_SIZE))
1902 #define SUPER_ORIGIN( x, y ) (lm->superOrigins + ((((y) * lm->sw) + (x)) * SUPER_ORIGIN_SIZE))
1903 #define SUPER_NORMAL( x, y ) (lm->superNormals + ((((y) * lm->sw) + (x)) * SUPER_NORMAL_SIZE))
1904 +#define SUPER_FLOODLIGHT( x, y ) (lm->superFloodLight + ((((y) * lm->sw) + (x)) * SUPER_FLOODLIGHT_SIZE) )
1905 #define SUPER_CLUSTER( x, y ) (lm->superClusters + (((y) * lm->sw) + (x)))
1906 #define SUPER_DELUXEL( x, y ) (lm->superDeluxels + ((((y) * lm->sw) + (x)) * SUPER_DELUXEL_SIZE))
1907 #define BSP_DELUXEL( x, y ) (lm->bspDeluxels + ((((y) * lm->w) + (x)) * BSP_DELUXEL_SIZE))
1908 @@ -1364,6 +1366,7 @@
1910 float *superDeluxels; /* average light direction */
1912 + float *superFloodLight;
1916 @@ -1670,6 +1673,9 @@
1917 void SmoothNormals( void );
1919 void MapRawLightmap( int num );
1920 +void SetupFloodLight();
1921 +float FloodLightForSample( trace_t *trace );
1922 +void FloodLightRawLightmap( int num );
1923 void IlluminateRawLightmap( int num );
1924 void IlluminateVertexes( int num );
1926 @@ -2037,6 +2043,12 @@
1927 Q_EXTERN qboolean sunOnly;
1928 Q_EXTERN int approximateTolerance Q_ASSIGN( 0 );
1929 Q_EXTERN qboolean noCollapse;
1930 +Q_EXTERN qboolean debugnormals Q_ASSIGN( qfalse );
1931 +Q_EXTERN qboolean floodlighty Q_ASSIGN( qfalse );
1932 +Q_EXTERN qboolean floodlight_lowquality Q_ASSIGN( qfalse );
1933 +Q_EXTERN vec3_t floodlightRGB;
1934 +Q_EXTERN float floodlightIntensity Q_ASSIGN( 512 );
1935 +Q_EXTERN float floodlightDistance Q_ASSIGN( 1024 );
1936 Q_EXTERN qboolean debug;
1937 Q_EXTERN qboolean debugSurfaces;
1938 Q_EXTERN qboolean debugUnused;
1939 Index: tools/quake3/q3map2/q3map2.h
1940 ===================================================================
1941 --- tools/quake3/q3map2/q3map2.h (revision 290)
1942 +++ tools/quake3/q3map2/q3map2.h (working copy)
1943 @@ -1274,6 +1274,7 @@
1944 vec3_t color; /* starts out at full color, may be reduced if transparent surfaces are crossed */
1948 int compileFlags; /* for determining surface compile flags traced through */
1951 Index: tools/quake3/q3map2/light_trace.c
1952 ===================================================================
1953 --- tools/quake3/q3map2/light_trace.c (revision 290)
1954 +++ tools/quake3/q3map2/light_trace.c (working copy)
1955 @@ -1596,6 +1596,7 @@
1956 /* bogus node number means solid, end tracing unless testing all */
1959 + VectorCopy( origin, trace->hit );
1960 trace->passSolid = qtrue;
1963 @@ -1606,6 +1607,7 @@
1965 if( node->type == TRACE_LEAF_SOLID )
1967 + VectorCopy( origin, trace->hit );
1968 trace->passSolid = qtrue;
1971 Index: tools/quake3/q3map2/light_ydnar.c
1972 ===================================================================
1973 --- tools/quake3/q3map2/light_ydnar.c (revision 290)
1974 +++ tools/quake3/q3map2/light_ydnar.c (working copy)
1977 #define BOGUS_NUDGE -99999.0f
1979 -static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
1980 +static int MapSingleLuxel( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv, vec4_t plane, float pass, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
1982 int i, x, y, numClusters, *clusters, pointCluster, *cluster;
1983 float *luxel, *origin, *normal, d, lightmapSampleOffset;
1984 @@ -380,6 +380,12 @@
1988 + vec3_t cverts[ 3 ];
1990 + vec4_t sideplane, hostplane;
1995 static float nudges[][ 2 ] =
1997 @@ -473,6 +479,51 @@
1998 /* non axial lightmap projection (explicit xyz) */
2000 VectorCopy( dv->xyz, origin );
2002 + //////////////////////
2003 + //27's test to make sure samples stay within the triangle boundaries
2004 + //1) Test the sample origin to see if it lays on the wrong side of any edge (x/y)
2005 + //2) if it does, nudge it onto the correct side.
2007 + if (worldverts!=NULL)
2011 + VectorCopy(worldverts[j],cverts[j]);
2013 + PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2019 + //build plane using 2 edges and a normal
2022 + VectorCopy(cverts[next],temp);
2023 + VectorAdd(temp,hostplane,temp);
2024 + PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2026 + //planetest sample point
2027 + e=DotProduct(origin,sideplane);
2032 + //VectorClear(origin);
2033 + //Move the sample point back inside triangle bounds
2034 + origin[0]-=sideplane[0]*(e+1);
2035 + origin[1]-=sideplane[1]*(e+1);
2036 + origin[2]-=sideplane[2]*(e+1);
2038 + VectorClear(origin);
2045 + ////////////////////////
2047 /* planar surfaces have precalculated lightmap vectors for nudging */
2048 if( lm->plane != NULL )
2049 @@ -504,8 +555,13 @@
2051 origin[ lm->axisNum ] += lightmapSampleOffset;
2053 + VectorCopy(origin,origintwo);
2054 + origintwo[0]+=vecs[2][0];
2055 + origintwo[1]+=vecs[2][1];
2056 + origintwo[2]+=vecs[2][2];
2059 - pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2060 + pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2062 /* another retarded hack, storing nudge count in luxel[ 1 ] */
2064 @@ -521,14 +577,14 @@
2065 for( i = 0; i < 3; i++ )
2067 /* set nudged point*/
2068 - nudged[ i ] = origin[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2069 + nudged[ i ] = origintwo[ i ] + (nudge[ 0 ] * vecs[ 0 ][ i ]) + (nudge[ 1 ] * vecs[ 1 ][ i ]);
2073 /* get pvs cluster */
2074 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters ); //% + 0.625 );
2075 - if( pointCluster >= 0 )
2076 - VectorCopy( nudged, origin );
2077 + //if( pointCluster >= 0 )
2078 + // VectorCopy( nudged, origin );
2084 VectorMA( dv->xyz, lightmapSampleOffset, dv->normal, nudged );
2085 pointCluster = ClusterForPointExtFilter( nudged, LUXEL_EPSILON, numClusters, clusters );
2086 - if( pointCluster >= 0 )
2087 - VectorCopy( nudged, origin );
2088 + //if( pointCluster >= 0 )
2089 + // VectorCopy( nudged, origin );
2094 than the distance between two luxels (thanks jc :)
2097 -static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ] )
2098 +static void MapTriangle_r( rawLightmap_t *lm, surfaceInfo_t *info, bspDrawVert_t *dv[ 3 ], vec4_t plane, vec3_t stv[ 3 ], vec3_t ttv[ 3 ], vec3_t worldverts[ 3 ] )
2100 bspDrawVert_t mid, *dv2[ 3 ];
2104 /* split the longest edge and map it */
2105 LerpDrawVert( dv[ max ], dv[ (max + 1) % 3 ], &mid );
2106 - MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv );
2107 + MapSingleLuxel( lm, info, &mid, plane, 1, stv, ttv, worldverts );
2109 /* push the point up a little bit to account for fp creep (fixme: revisit this) */
2110 //% VectorMA( mid.xyz, 2.0f, mid.normal, mid.xyz );
2111 @@ -641,12 +697,12 @@
2112 /* recurse to first triangle */
2113 VectorCopy( dv, dv2 );
2115 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2116 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2118 /* recurse to second triangle */
2119 VectorCopy( dv, dv2 );
2120 dv2[ (max + 1) % 3 ] = ∣
2121 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2122 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2129 vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2130 + vec3_t worldverts[ 3 ];
2133 /* get plane if possible */
2134 @@ -687,16 +744,20 @@
2138 + VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2139 + VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2140 + VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
2142 /* map the vertexes */
2143 - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2144 - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2145 - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2146 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, worldverts );
2147 + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, worldverts );
2148 + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, worldverts );
2150 /* 2002-11-20: prefer axial triangle edges */
2153 /* subdivide the triangle */
2154 - MapTriangle_r( lm, info, dv, plane, stv, ttv );
2155 + MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2160 dv2[ 2 ] = dv[ (i + 1) % 3 ];
2162 /* map the degenerate triangle */
2163 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2164 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2169 LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
2171 /* map the vertexes */
2172 - MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv );
2173 - MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv );
2174 + MapSingleLuxel( lm, info, &mid[ 0 ], plane, 1, stv, ttv, NULL );
2175 + MapSingleLuxel( lm, info, &mid[ 1 ], plane, 1, stv, ttv, NULL );
2179 @@ -866,10 +927,10 @@
2182 /* map the vertexes */
2183 - MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv );
2184 - MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv );
2185 - MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv );
2186 - MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv );
2187 + MapSingleLuxel( lm, info, dv[ 0 ], plane, 1, stv, ttv, NULL );
2188 + MapSingleLuxel( lm, info, dv[ 1 ], plane, 1, stv, ttv, NULL );
2189 + MapSingleLuxel( lm, info, dv[ 2 ], plane, 1, stv, ttv, NULL );
2190 + MapSingleLuxel( lm, info, dv[ 3 ], plane, 1, stv, ttv, NULL );
2192 /* subdivide the quad */
2193 MapQuad_r( lm, info, dv, plane, stv, ttv );
2194 @@ -1161,7 +1222,7 @@
2197 /* map the fake vert */
2198 - MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL );
2199 + MapSingleLuxel( lm, NULL, &fake, lm->plane, pass, NULL, NULL, NULL );
2203 @@ -1636,22 +1697,32 @@
2204 deluxel = SUPER_DELUXEL( x, y );
2205 origin = SUPER_ORIGIN( x, y );
2206 normal = SUPER_NORMAL( x, y );
2208 - /* set contribution count */
2209 - lightLuxel[ 3 ] = 1.0f;
2212 - trace.cluster = *cluster;
2213 - VectorCopy( origin, trace.origin );
2214 - VectorCopy( normal, trace.normal );
2216 - /* get light for this sample */
2217 - LightContributionToSample( &trace );
2218 - VectorCopy( trace.color, lightLuxel );
2220 - /* add to count */
2221 - if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2223 + ////////// 27's temp hack for testing edge clipping ////
2224 + if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2226 + lightLuxel[ 1 ] = 255;
2227 + lightLuxel[ 3 ] = 1.0f;
2232 + /* set contribution count */
2233 + lightLuxel[ 3 ] = 1.0f;
2236 + trace.cluster = *cluster;
2237 + VectorCopy( origin, trace.origin );
2238 + VectorCopy( normal, trace.normal );
2240 + /* get light for this sample */
2241 + LightContributionToSample( &trace );
2242 + VectorCopy( trace.color, lightLuxel );
2244 + /* add to count */
2245 + if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2249 /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2251 Index: tools/quake3/q3map2/q3map2.h
2252 ===================================================================
2253 --- tools/quake3/q3map2/q3map2.h (revision 290)
2254 +++ tools/quake3/q3map2/q3map2.h (working copy)
2259 -#define Q3MAP_VERSION "2.5.11"
2260 -#define Q3MAP_MOTD "A well-oiled toaster oven"
2261 +#define Q3MAP_VERSION "2.5.11-div0-obj-decomptexcoords-snapplane-UTavgcolorfix-UTfloodlight-UTtrianglecheck"
2262 +#define Q3MAP_MOTD "Blackhole Box gives the light back"
2266 Index: include/version.default
2267 ===================================================================
2268 --- include/version.default (revision 290)
2269 +++ include/version.default (working copy)
2272 +1.4.0-div0-obj-bp2texdeffix-bpsurfacedialog-spawnflagsboxes
\r