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: 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)
767 #define SNAP_FLOAT_TO_INT 4
768 #define SNAP_INT_TO_FLOAT (1.0 / SNAP_FLOAT_TO_INT)
770 +typedef vec_t vec2_t[2];
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)
777 + a00 * (a11 * a22 - a12 * a21)
778 + - a01 * (a10 * a22 - a12 * a20)
779 + + a02 * (a10 * a21 - a11 * a20);
782 +void GetBestSurfaceTriangleMatchForBrushside(side_t *buildSide, bspDrawVert_t *bestVert[3])
784 + bspDrawSurface_t *s;
790 + vec3_t v1v0, v2v0, norm;
791 + bspDrawVert_t *vert[3];
792 + winding_t *polygon;
793 + plane_t *buildPlane = &mapplanes[buildSide->planenum];
796 + // first, start out with NULLs
797 + bestVert[0] = bestVert[1] = bestVert[2] = NULL;
799 + // brute force through all surfaces
800 + for(s = bspDrawSurfaces; s != bspDrawSurfaces + numBSPDrawSurfaces; ++s)
802 + if(s->surfaceType != MST_PLANAR && s->surfaceType != MST_TRIANGLE_SOUP)
804 + if(strcmp(buildSide->shaderInfo->shader, bspShaders[s->shaderNum].shader))
806 + for(t = 0; t + 3 <= s->numIndexes; t += 3)
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)
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;
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;
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)
837 + vec3_t *v1 = &vert[(i+1)%3]->xyz;
838 + vec3_t *v2 = &vert[(i+2)%3]->xyz;
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);
850 + thisarea = WindingArea(polygon);
853 + if(thisarea > best)
856 + bestVert[0] = vert[0];
857 + bestVert[1] = vert[1];
858 + bestVert[2] = vert[2];
860 + FreeWinding(polygon);
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);
869 static void ConvertBrush( FILE *f, int num, bspBrush_t *brush, vec3_t origin )
876 + plane_t *buildPlane;
878 + bspDrawVert_t *vert[3];
883 fprintf( f, "\t// brush %d\n", num );
884 fprintf( f, "\t{\n" );
885 + fprintf( f, "\tbrushDef\n" );
886 + fprintf( f, "\t{\n" );
888 /* clear out build brush */
889 for( i = 0; i < buildBrush->numsides; i++ )
892 buildSide = &buildBrush->sides[ i ];
895 + buildPlane = &mapplanes[ buildSide->planenum ];
898 if( buildSide->shaderInfo == NULL || buildSide->winding == NULL )
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);
906 + // find surface for this side (by brute force)
908 + // - meshverts point in pairs of three into verts
910 + // - find the triangle that has most in common with our side
911 + GetBestSurfaceTriangleMatchForBrushside(buildSide, vert);
914 + if(vert[0] && vert[1] && vert[2])
918 + vec3_t xy1I, xy1J, xy1K;
919 + vec2_t stI, stJ, stK;
920 + vec_t D, D0, D1, D2;
922 + ComputeAxisBase(buildPlane->normal, texX, texY);
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];
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)
936 + xy1I[0], xy1I[1], 1,
937 + xy1J[0], xy1J[1], 1,
938 + xy1K[0], xy1K[1], 1
942 + for(i = 0; i < 2; ++i)
945 + stI[i], xy1I[1], 1,
946 + stJ[i], xy1J[1], 1,
950 + xy1I[0], stI[i], 1,
951 + xy1J[0], stJ[i], 1,
955 + xy1I[0], xy1I[1], stI[i],
956 + xy1J[0], xy1J[1], stJ[i],
957 + xy1K[0], xy1K[1], stK[i]
959 + VectorSet(buildSide->texMat[i], D0 / D, D1 / D, D2 / D);
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]
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);
977 /* get texture name */
978 if( !Q_strncasecmp( buildSide->shaderInfo->shader, "textures/", 9 ) )
979 @@ -129,14 +312,21 @@
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 ],
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],
992 + // DEBUG: valid ? 0 : C_DETAIL
995 + // TODO write brush primitives format here
999 + fprintf( f, "\t}\n" );
1000 fprintf( f, "\t}\n\n" );
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 @@
1009 Sys_Printf( "Unknown conversion format \"%s\". Defaulting to ASE.\n", argv[ i ] );
1011 + else if( !strcmp( argv[ i ], "-ne" ) )
1013 + normalEpsilon = atof( argv[ i + 1 ] );
1015 + Sys_Printf( "Normal epsilon set to %f\n", normalEpsilon );
1017 + else if( !strcmp( argv[ i ], "-de" ) )
1019 + distanceEpsilon = atof( argv[ i + 1 ] );
1021 + Sys_Printf( "Distance epsilon set to %f\n", distanceEpsilon );
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)
1032 picoIndex_t *indexes;
1034 + double normalEpsilon_save;
1035 + double distanceEpsilon_save;
1040 /* ydnar: giant hack land: generate clipping brushes for model triangles */
1041 if( si->clipModel || (spawnFlags & 2) ) /* 2nd bit */
1043 - vec3_t points[ 3 ], backs[ 3 ];
1044 + vec3_t points[ 4 ], backs[ 3 ];
1045 vec4_t plane, reverse, pa, pb, pc;
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++ )
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 ] ) )
1059 backs[ j ][ k ] += dv->normal[ k ] < 0.0f ? 64.0f : -64.0f;
1065 + VectorCopy( points[0], points[3] ); // for cyclic usage
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 ] ) )
1075 + vec3_t bestNormal;
1076 + float backPlaneDistance = 2;
1078 + if(spawnFlags & 8) // use a DOWN normal
1080 + if(spawnFlags & 16)
1082 + // 24: normal as is, and zero width (broken)
1083 + VectorCopy(plane, bestNormal);
1087 + // 8: normal as is
1088 + VectorCopy(plane, bestNormal);
1093 + if(spawnFlags & 16)
1095 + // 16: UP/DOWN normal
1096 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
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);
1105 + if(fabs(plane[0]) > fabs(plane[2])) // x>z, z>=y
1106 + VectorSet(bestNormal, (plane[0] >= 0 ? 1 : -1), 0, 0);
1108 + VectorSet(bestNormal, 0, 0, (plane[2] >= 0 ? 1 : -1));
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));
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
1128 + buildBrush->detail = qfalse;
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;
1137 + buildBrush->detail = qtrue;
1139 /* regenerate back points */
1140 for( j = 0; j < 3; j++ )
1143 dv = &ds->verts[ ds->indexes[ i + j ] ];
1146 - VectorCopy( dv->xyz, backs[ j ] );
1148 - /* find nearest axial to plane normal and push back points opposite */
1149 - for( k = 0; k < 3; k++ )
1151 - if( fabs( plane[ k ] ) > fabs( plane[ (k + 1) % 3 ] ) &&
1152 - fabs( plane[ k ] ) > fabs( plane[ (k + 2) % 3 ] ) )
1154 - backs[ j ][ k ] += plane[ k ] < 0.0f ? 64.0f : -64.0f;
1159 + // shift by some units
1160 + VectorMA(dv->xyz, -64.0f, bestNormal, backs[j]); // 64 prevents roundoff errors a bit
1164 /* make back plane */
1165 VectorScale( plane, -1.0f, reverse );
1166 - reverse[ 3 ] = -(plane[ 3 ] - 1);
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 );
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)
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 ] ) )
1190 - /* build a brush */
1191 - buildBrush = AllocBrush( 48 );
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;
1200 /* set up brush sides */
1201 buildBrush->numsides = 5;
1202 for( j = 0; j < buildBrush->numsides; j++ )
1203 buildBrush->sides[ j ].shaderInfo = si;
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 );
1211 - /* add to entity */
1212 - if( CreateBrushWindings( buildBrush ) )
1215 - //% EmitBrushes( buildBrush, NULL, NULL );
1216 - buildBrush->next = entities[ mapEntityNum ].brushes;
1217 - entities[ mapEntityNum ].brushes = buildBrush;
1218 - entities[ mapEntityNum ].numBrushes++;
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 );
1233 + normalEpsilon = normalEpsilon_save;
1234 + distanceEpsilon = distanceEpsilon_save;
1236 + /* add to entity */
1237 + if( CreateBrushWindings( buildBrush ) )
1240 + //% EmitBrushes( buildBrush, NULL, NULL );
1241 + buildBrush->next = entities[ mapEntityNum ].brushes;
1242 + entities[ mapEntityNum ].brushes = buildBrush;
1243 + entities[ mapEntityNum ].numBrushes++;
1246 + free( buildBrush );
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
1258 -void SnapPlane( vec3_t normal, vec_t *dist )
1259 +void SnapPlane( vec3_t normal, vec_t *dist, vec3_t center )
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
1266 + vec_t centerDist = DotProduct(normal, center);
1267 + SnapNormal( normal );
1268 + *dist += (DotProduct(normal, center) - centerDist);
1270 if( fabs( *dist - Q_rint( *dist ) ) < distanceEpsilon )
1271 *dist = Q_rint( *dist );
1273 must be within an epsilon distance of the plane
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?
1281 @@ -207,10 +213,14 @@
1285 + vec3_t centerofweight;
1287 + VectorClear(centerofweight);
1288 + for(i = 0; i < numPoints; ++i)
1289 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1292 /* hash the plane */
1293 - SnapPlane( normal, &dist );
1294 + SnapPlane( normal, &dist, centerofweight );
1295 hash = (PLANE_HASHES - 1) & (int) fabs( dist );
1297 /* search the border bins as well */
1298 @@ -251,7 +261,13 @@
1302 - SnapPlane( normal, &dist );
1303 + vec3_t centerofweight;
1305 + VectorClear(centerofweight);
1306 + for(i = 0; i < numPoints; ++i)
1307 + VectorMA(centerofweight, 1.0 / numPoints, points[i], centerofweight);
1309 + SnapPlane( normal, &dist, centerofweight );
1310 for( i = 0, p = mapplanes; i < nummapplanes; i++, p++ )
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 @@
1320 if( VectorLength( si->color ) <= 0.0f )
1322 ColorNormalize( color, si->color );
1323 - VectorScale( color, (1.0f / count), si->averageColor );
1324 + VectorScale( color, (1.0f / count), si->averageColor );
1328 + VectorCopy( si->color, si->averageColor );
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 } };
1342 + float *floodlight;
1345 /* bail if this number exceeds the number of raw lightmaps */
1346 @@ -1871,6 +1873,78 @@
1347 /* free light list */
1348 FreeTraceLights( &trace );
1350 + /* -----------------------------------------------------------------
1352 + ----------------------------------------------------------------- */
1356 + /* walk lightmaps */
1357 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1360 + if( lm->superLuxels[ lightmapNum ] == NULL )
1363 + /* apply floodlight to each luxel */
1364 + for( y = 0; y < lm->sh; y++ )
1366 + for( x = 0; x < lm->sw; x++ )
1369 + cluster = SUPER_CLUSTER( x, y );
1370 + //% if( *cluster < 0 )
1373 + /* get particulars */
1374 + luxel = SUPER_LUXEL( lightmapNum, x, y );
1375 + floodlight = SUPER_FLOODLIGHT( x, y );
1377 + flood[0]=floodlightRGB[0]*floodlightIntensity;
1378 + flood[1]=floodlightRGB[1]*floodlightIntensity;
1379 + flood[2]=floodlightRGB[2]*floodlightIntensity;
1381 + /* scale light value */
1382 + VectorScale( flood, *floodlight, flood );
1383 + luxel[0]+=flood[0];
1384 + luxel[1]+=flood[1];
1385 + luxel[2]+=flood[2];
1387 + if (luxel[3]==0) luxel[3]=1;
1395 + for( lightmapNum = 0; lightmapNum < MAX_LIGHTMAPS; lightmapNum++ )
1398 + if( lm->superLuxels[ lightmapNum ] == NULL )
1401 + for( y = 0; y < lm->sh; y++ )
1403 + for( x = 0; x < lm->sw; x++ )
1406 + cluster = SUPER_CLUSTER( x, y );
1407 + //% if( *cluster < 0 )
1410 + /* get particulars */
1411 + luxel = SUPER_LUXEL( lightmapNum, x, y );
1412 + normal = SUPER_NORMAL ( x, y );
1414 + luxel[0]=(normal[0]*127)+127;
1415 + luxel[1]=(normal[1]*127)+127;
1416 + luxel[2]=(normal[2]*127)+127;
1422 /* -----------------------------------------------------------------
1424 ----------------------------------------------------------------- */
1425 @@ -3123,7 +3197,320 @@
1426 CreateTraceLightsForBounds( mins, maxs, normal, info->numSurfaceClusters, &surfaceClusters[ info->firstSurfaceCluster ], LIGHT_SURFACES, trace );
1429 +/////////////////////////////////////////////////////////////
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)
1436 +static vec3_t floodVectors[ FLOODLIGHT_NUM_VECTORS ];
1437 +static int numFloodVectors = 0;
1439 +void SetupFloodLight( void )
1442 + float angle, elevation, angleStep, elevationStep;
1443 + const char *value;
1444 + double v1,v2,v3,v4,v5;
1447 + Sys_FPrintf( SYS_VRB, "--- SetupFloodLight ---\n" );
1449 + /* calculate angular steps */
1450 + angleStep = DEG2RAD( 360.0f / FLOODLIGHT_NUM_ANGLE_STEPS );
1451 + elevationStep = DEG2RAD( FLOODLIGHT_CONE_ANGLE / FLOODLIGHT_NUM_ELEVATION_STEPS );
1453 + /* iterate angle */
1455 + for( i = 0, angle = 0.0f; i < FLOODLIGHT_NUM_ANGLE_STEPS; i++, angle += angleStep )
1457 + /* iterate elevation */
1458 + for( j = 0, elevation = elevationStep * 0.5f; j < FLOODLIGHT_NUM_ELEVATION_STEPS; j++, elevation += elevationStep )
1460 + floodVectors[ numFloodVectors ][ 0 ] = sin( elevation ) * cos( angle );
1461 + floodVectors[ numFloodVectors ][ 1 ] = sin( elevation ) * sin( angle );
1462 + floodVectors[ numFloodVectors ][ 2 ] = cos( elevation );
1463 + numFloodVectors++;
1467 + /* emit some statistics */
1468 + Sys_FPrintf( SYS_VRB, "%9d numFloodVectors\n", numFloodVectors );
1471 + value = ValueForKey( &entities[ 0 ], "_floodlight" );
1473 + if( value[ 0 ] != '\0' )
1476 + v4=floodlightDistance;
1477 + v5=floodlightIntensity;
1479 + sscanf( value, "%lf %lf %lf %lf %lf", &v1, &v2, &v3, &v4, &v5);
1481 + floodlightRGB[0]=v1;
1482 + floodlightRGB[1]=v2;
1483 + floodlightRGB[2]=v3;
1485 + if (VectorLength(floodlightRGB)==0)
1487 + VectorSet(floodlightRGB,240,240,255);
1490 + if (v4<1) v4=1024;
1493 + floodlightDistance=v4;
1494 + floodlightIntensity=v5;
1496 + floodlighty = qtrue;
1497 + Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1501 + VectorSet(floodlightRGB,240,240,255);
1502 + //floodlighty = qtrue;
1503 + //Sys_Printf( "FloodLighting enabled via worldspawn _floodlight key.\n" );
1505 + VectorNormalize(floodlightRGB,floodlightRGB);
1508 +//27 - lighttracer style ambient occlusion light hack.
1509 +//Kudos to the dirtmapping author for most of this source.
1510 +void FloodLightRawLightmap( int rawLightmapNum )
1512 + int i, x, y, sx, sy, *cluster;
1513 + float *origin, *normal, *floodlight, *floodlight2, average, samples;
1514 + rawLightmap_t *lm;
1515 + surfaceInfo_t *info;
1518 + /* bail if this number exceeds the number of raw lightmaps */
1519 + if( rawLightmapNum >= numRawLightmaps )
1522 + /* get lightmap */
1523 + lm = &rawLightmaps[ rawLightmapNum ];
1525 + memset(&trace,0,sizeof(trace_t));
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;
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++ )
1542 + info = &surfaceInfos[ trace.surfaces[ i ] ];
1544 + /* check twosidedness */
1545 + if( info->si->twoSided )
1547 + trace.twoSided = qtrue;
1553 + for( y = 0; y < lm->sh; y++ )
1555 + for( x = 0; x < lm->sw; x++ )
1558 + cluster = SUPER_CLUSTER( x, y );
1559 + origin = SUPER_ORIGIN( x, y );
1560 + normal = SUPER_NORMAL( x, y );
1561 + floodlight = SUPER_FLOODLIGHT( x, y );
1563 + /* set default dirt */
1564 + *floodlight = 0.0f;
1566 + /* only look at mapped luxels */
1567 + if( *cluster < 0 )
1570 + /* copy to trace */
1571 + trace.cluster = *cluster;
1572 + VectorCopy( origin, trace.origin );
1573 + VectorCopy( normal, trace.normal );
1578 + *floodlight = FloodLightForSample( &trace );
1582 + /* testing no filtering */
1585 + /* filter "dirt" */
1586 + for( y = 0; y < lm->sh; y++ )
1588 + for( x = 0; x < lm->sw; x++ )
1591 + cluster = SUPER_CLUSTER( x, y );
1592 + floodlight = SUPER_FLOODLIGHT( x, y );
1594 + /* filter dirt by adjacency to unmapped luxels */
1595 + average = *floodlight;
1597 + for( sy = (y - 1); sy <= (y + 1); sy++ )
1599 + if( sy < 0 || sy >= lm->sh )
1602 + for( sx = (x - 1); sx <= (x + 1); sx++ )
1604 + if( sx < 0 || sx >= lm->sw || (sx == x && sy == y) )
1607 + /* get neighboring luxel */
1608 + cluster = SUPER_CLUSTER( sx, sy );
1609 + floodlight2 = SUPER_FLOODLIGHT( sx, sy );
1610 + if( *cluster < 0 || *floodlight2 <= 0.0f )
1614 + average += *floodlight2;
1619 + if( samples <= 0.0f )
1624 + if( samples <= 0.0f )
1628 + *floodlight = average / samples;
1634 +FloodLightForSample()
1635 +calculates floodlight value for a given sample
1636 +once again, kudos to the dirtmapping coder
1638 +float FloodLightForSample( trace_t *trace )
1642 + float contribution;
1644 + float gatherLight, outLight;
1645 + vec3_t normal, worldUp, myUp, myRt, direction, displacement;
1653 + if( trace == NULL || trace->cluster < 0 )
1658 + dd = floodlightDistance;
1659 + VectorCopy( trace->normal, normal );
1661 + /* check if the normal is aligned to the world-up */
1662 + if( normal[ 0 ] == 0.0f && normal[ 1 ] == 0.0f )
1664 + if( normal[ 2 ] == 1.0f )
1666 + VectorSet( myRt, 1.0f, 0.0f, 0.0f );
1667 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
1669 + else if( normal[ 2 ] == -1.0f )
1671 + VectorSet( myRt, -1.0f, 0.0f, 0.0f );
1672 + VectorSet( myUp, 0.0f, 1.0f, 0.0f );
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 );
1684 + /* iterate through ordered vectors */
1685 + for( i = 0; i < numFloodVectors; i++ )
1687 + if (floodlight_lowquality==qtrue)
1689 + if (rand()%10 != 0 ) continue;
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 ];
1699 + /* set endpoint */
1700 + VectorMA( trace->origin, dd, direction, trace->end );
1702 + //VectorMA( trace->origin, 1, direction, trace->origin );
1704 + SetupTrace( trace );
1706 + TraceLine( trace );
1709 + if (trace->compileFlags & C_SKY )
1711 + contribution=1.0f;
1713 + else if ( trace->opaque )
1715 + VectorSubtract( trace->hit, trace->origin, displacement );
1716 + d=VectorLength( displacement );
1718 + // d=trace->distance;
1719 + //if (d>256) gatherDirt+=1;
1720 + contribution=d/dd;
1721 + if (contribution>1) contribution=1.0f;
1723 + //gatherDirt += 1.0f - ooDepth * VectorLength( displacement );
1726 + gatherLight+=contribution;
1730 + if( gatherLight <= 0.0f )
1736 + gatherLight/=(sub);
1738 + outLight=gatherLight;
1739 + if( outLight > 1.0f )
1742 + /* return to sender */
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 @@
1754 + /////// Floodlighting for point //////////////////
1755 + //do our floodlight ambient occlusion loop, and add a single contribution based on the brightest dir
1761 + col[0]=col[1]=col[2]=floodlightIntensity;
1765 + trace.testOcclusion = qtrue;
1766 + trace.forceSunlight = qfalse;
1767 + trace.inhibitRadius = DEFAULT_INHIBIT_RADIUS;
1768 + trace.testAll = qtrue;
1772 + if (q==0) //upper hemisphere
1774 + trace.normal[0]=0;
1775 + trace.normal[1]=0;
1776 + trace.normal[2]=1;
1778 + else //lower hemisphere
1780 + trace.normal[0]=0;
1781 + trace.normal[1]=0;
1782 + trace.normal[2]=-1;
1785 + f = FloodLightForSample(&trace);
1787 + contributions[ numCon ].color[0]=col[0]*f;
1788 + contributions[ numCon ].color[1]=col[1]*f;
1789 + contributions[ numCon ].color[2]=col[2]*f;
1791 + contributions[ numCon ].dir[0]=dir[0];
1792 + contributions[ numCon ].dir[1]=dir[1];
1793 + contributions[ numCon ].dir[2]=dir[2];
1795 + contributions[ numCon ].style = 0;
1797 + /* push average direction around */
1798 + addSize = VectorLength( col );
1799 + VectorMA( gp->dir, addSize, dir, gp->dir );
1802 + /////////////////////
1804 /* normalize to get primary light direction */
1805 VectorNormalize( gp->dir, gp->dir );
1807 @@ -1544,6 +1594,12 @@
1808 qboolean minVertex, minGrid;
1811 + /* floodlight them up */
1814 + Sys_Printf( "--- FloodlightRawLightmap ---\n" );
1815 + RunThreadsOnIndividual( numRawLightmaps, qtrue, FloodLightRawLightmap );
1818 /* ydnar: smooth normals */
1820 @@ -1675,6 +1731,7 @@
1823 VectorClear( ambientColor );
1824 + floodlighty = qfalse;
1826 /* generate diffuse lights */
1828 @@ -2114,6 +2171,21 @@
1830 Sys_Printf( "Enabling low-memory (potentially slower) lighting mode\n" );
1832 + else if( !strcmp( argv[ i ], "-floodlight" ) )
1834 + floodlighty = qtrue;
1835 + Sys_Printf( "FloodLighting enabled\n" );
1837 + else if( !strcmp( argv[ i ], "-debugnormals" ) )
1839 + debugnormals = qtrue;
1840 + Sys_Printf( "DebugNormals enabled\n" );
1842 + else if( !strcmp( argv[ i ], "-lowquality" ) )
1844 + floodlight_lowquality = qtrue;
1845 + Sys_Printf( "Low Quality FloodLighting enabled\n" );
1849 Sys_Printf( "WARNING: Unknown option \"%s\"\n", argv[ i ] );
1850 @@ -2156,6 +2228,7 @@
1852 /* ydnar: set up optimization */
1854 + SetupFloodLight();
1855 SetupSurfaceLightmaps();
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 );
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 );
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)
1880 #define SUPER_NORMAL_SIZE 3
1881 #define SUPER_DELUXEL_SIZE 3
1882 #define BSP_DELUXEL_SIZE 3
1883 +#define SUPER_FLOODLIGHT_SIZE 1
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))
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 @@
1897 float *superDeluxels; /* average light direction */
1899 + float *superFloodLight;
1903 @@ -1670,6 +1673,9 @@
1904 void SmoothNormals( void );
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 );
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 */
1935 int compileFlags; /* for determining surface compile flags traced through */
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 */
1946 + VectorCopy( origin, trace->hit );
1947 trace->passSolid = qtrue;
1950 @@ -1606,6 +1607,7 @@
1952 if( node->type == TRACE_LEAF_SOLID )
1954 + VectorCopy( origin, trace->hit );
1955 trace->passSolid = qtrue;
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)
1964 #define BOGUS_NUDGE -99999.0f
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 ] )
1969 int i, x, y, numClusters, *clusters, pointCluster, *cluster;
1970 float *luxel, *origin, *normal, d, lightmapSampleOffset;
1971 @@ -380,6 +380,12 @@
1975 + vec3_t cverts[ 3 ];
1977 + vec4_t sideplane, hostplane;
1982 static float nudges[][ 2 ] =
1984 @@ -473,6 +479,51 @@
1985 /* non axial lightmap projection (explicit xyz) */
1987 VectorCopy( dv->xyz, origin );
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.
1994 + if (worldverts!=NULL)
1998 + VectorCopy(worldverts[j],cverts[j]);
2000 + PlaneFromPoints(hostplane,cverts[0],cverts[1],cverts[2]);
2006 + //build plane using 2 edges and a normal
2009 + VectorCopy(cverts[next],temp);
2010 + VectorAdd(temp,hostplane,temp);
2011 + PlaneFromPoints(sideplane,cverts[i],cverts[ next ], temp);
2013 + //planetest sample point
2014 + e=DotProduct(origin,sideplane);
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);
2025 + VectorClear(origin);
2032 + ////////////////////////
2034 /* planar surfaces have precalculated lightmap vectors for nudging */
2035 if( lm->plane != NULL )
2036 @@ -504,8 +555,13 @@
2038 origin[ lm->axisNum ] += lightmapSampleOffset;
2040 + VectorCopy(origin,origintwo);
2041 + origintwo[0]+=vecs[2][0];
2042 + origintwo[1]+=vecs[2][1];
2043 + origintwo[2]+=vecs[2][2];
2046 - pointCluster = ClusterForPointExtFilter( origin, LUXEL_EPSILON, numClusters, clusters );
2047 + pointCluster = ClusterForPointExtFilter( origintwo, LUXEL_EPSILON, numClusters, clusters );
2049 /* another retarded hack, storing nudge count in luxel[ 1 ] */
2051 @@ -521,14 +577,14 @@
2052 for( i = 0; i < 3; i++ )
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 ]);
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 );
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 );
2081 than the distance between two luxels (thanks jc :)
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 ] )
2087 bspDrawVert_t mid, *dv2[ 3 ];
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 );
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 );
2102 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2103 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2105 /* recurse to second triangle */
2106 VectorCopy( dv, dv2 );
2107 dv2[ (max + 1) % 3 ] = ∣
2108 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2109 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2116 vec3_t *stv, *ttv, stvStatic[ 3 ], ttvStatic[ 3 ];
2117 + vec3_t worldverts[ 3 ];
2120 /* get plane if possible */
2121 @@ -687,16 +744,20 @@
2125 + VectorCopy( dv[ 0 ]->xyz, worldverts[ 0 ] );
2126 + VectorCopy( dv[ 1 ]->xyz, worldverts[ 1 ] );
2127 + VectorCopy( dv[ 2 ]->xyz, worldverts[ 2 ] );
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 );
2137 /* 2002-11-20: prefer axial triangle edges */
2140 /* subdivide the triangle */
2141 - MapTriangle_r( lm, info, dv, plane, stv, ttv );
2142 + MapTriangle_r( lm, info, dv, plane, stv, ttv, worldverts );
2147 dv2[ 2 ] = dv[ (i + 1) % 3 ];
2149 /* map the degenerate triangle */
2150 - MapTriangle_r( lm, info, dv2, plane, stv, ttv );
2151 + MapTriangle_r( lm, info, dv2, plane, stv, ttv, worldverts );
2156 LerpDrawVert( dv[ max + 2 ], dv[ (max + 3) % 4 ], &mid[ 1 ] );
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 );
2166 @@ -866,10 +927,10 @@
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 );
2179 /* subdivide the quad */
2180 MapQuad_r( lm, info, dv, plane, stv, ttv );
2181 @@ -1161,7 +1222,7 @@
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 );
2190 @@ -1636,22 +1697,32 @@
2191 deluxel = SUPER_DELUXEL( x, y );
2192 origin = SUPER_ORIGIN( x, y );
2193 normal = SUPER_NORMAL( x, y );
2195 - /* set contribution count */
2196 - lightLuxel[ 3 ] = 1.0f;
2199 - trace.cluster = *cluster;
2200 - VectorCopy( origin, trace.origin );
2201 - VectorCopy( normal, trace.normal );
2203 - /* get light for this sample */
2204 - LightContributionToSample( &trace );
2205 - VectorCopy( trace.color, lightLuxel );
2207 - /* add to count */
2208 - if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2210 + ////////// 27's temp hack for testing edge clipping ////
2211 + if( origin[0]==0 && origin[1]==0 && origin[2]==0 )
2213 + lightLuxel[ 1 ] = 255;
2214 + lightLuxel[ 3 ] = 1.0f;
2219 + /* set contribution count */
2220 + lightLuxel[ 3 ] = 1.0f;
2223 + trace.cluster = *cluster;
2224 + VectorCopy( origin, trace.origin );
2225 + VectorCopy( normal, trace.normal );
2227 + /* get light for this sample */
2228 + LightContributionToSample( &trace );
2229 + VectorCopy( trace.color, lightLuxel );
2231 + /* add to count */
2232 + if( trace.color[ 0 ] || trace.color[ 1 ] || trace.color[ 2 ] )
2236 /* add to light direction map (fixme: use luxel normal as starting point for deluxel?) */
2238 Index: tools/quake3/q3map2/q3map2.h
2239 ===================================================================
2240 --- tools/quake3/q3map2/q3map2.h (revision 290)
2241 +++ tools/quake3/q3map2/q3map2.h (working copy)
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"
2253 Index: include/version.default
2254 ===================================================================
2255 --- include/version.default (revision 290)
2256 +++ include/version.default (working copy)
2259 +1.4.0-div0-obj-bp2texdeffix-bpsurfacedialog
\r