2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 extern MainFrame* g_pParentWnd;
29 extern void MemFile_fprintf( MemStream* pMemFile, const char* pText, ... );
36 const char* Brush_Name( brush_t *b ){
37 static char cBuff[1024];
38 b->numberId = g_nBrushId++;
39 if ( g_qeglobals.m_bBrushPrimitMode ) {
40 sprintf( cBuff, "Brush %i", b->numberId );
41 Brush_SetEpair( b, "Name", cBuff );
47 brush_t *Brush_Alloc(){
48 brush_t *b = (brush_t*)qmalloc( sizeof( brush_t ) );
52 void Brush_Free(brush_t *b)
57 void PrintWinding( winding_t *w ){
60 Sys_Printf( "-------------\n" );
61 for ( i = 0 ; i < w->numpoints ; i++ )
62 Sys_Printf( "(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
63 , w->points[i][1], w->points[i][2] );
66 void PrintPlane( plane_t *p ){
67 Sys_Printf( "(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
68 p->normal[2], p->dist );
71 void PrintVector( vec3_t v ){
72 Sys_Printf( "(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2] );
77 =============================================================================
81 =============================================================================
92 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
93 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
94 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
95 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
96 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
97 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
100 void TextureAxisFromPlane( plane_t *pln, vec3_t xv, vec3_t yv ){
108 for ( i = 0 ; i < 6 ; i++ )
110 dot = DotProduct( pln->normal, baseaxis[i * 3] );
111 if ( g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best ) {
117 VectorCopy( baseaxis[bestaxis * 3 + 1], xv );
118 VectorCopy( baseaxis[bestaxis * 3 + 2], yv );
123 float lightaxis[3] = {0.6f, 0.8f, 1.0f};
128 Light different planes differently to
132 extern float ShadeForNormal( vec3_t normal );
134 float SetShadeForPlane( plane_t *p ){
135 //return ShadeForNormal(p->normal);
142 for ( i = 0 ; i < 3 ; i++ )
143 if ( fabs( p->normal[i] ) > 0.9 ) {
148 // between two axial planes
149 for ( i = 0 ; i < 3 ; i++ )
150 if ( fabs( p->normal[i] ) < 0.1 ) {
151 f = ( lightaxis[( i + 1 ) % 3] + lightaxis[( i + 2 ) % 3] ) / 2;
156 f = ( lightaxis[0] + lightaxis[1] + lightaxis[2] ) / 3;
169 face_t *Face_Alloc( void ){
170 face_t *f = (face_t*)qmalloc( sizeof( *f ) );
179 void Face_Free( face_t *f ){
182 if ( f->face_winding ) {
183 free( f->face_winding );
186 f->texdef.~texdef_t();;
196 face_t *Face_Clone( face_t *f ){
200 n->texdef = f->texdef;
201 n->brushprimit_texdef = f->brushprimit_texdef;
203 memcpy( n->planepts, f->planepts, sizeof( n->planepts ) );
205 // all other fields are derived, and will be set by Brush_Build
206 // FIXME: maybe not, for example n->pData!
214 makes an exact copy of the face
217 face_t *Face_FullClone( face_t *f ){
221 n->texdef = f->texdef;
222 n->brushprimit_texdef = f->brushprimit_texdef;
223 memcpy( n->planepts, f->planepts, sizeof( n->planepts ) );
224 memcpy( &n->plane, &f->plane, sizeof( plane_t ) );
225 if ( f->face_winding ) {
226 n->face_winding = Winding_Clone( f->face_winding );
229 n->face_winding = NULL;
231 n->pShader = f->pShader;
232 n->pShader->IncRef();
233 n->d_texture = n->pShader->getTexture();
237 void Face_SetShader( face_t *face, const char *name ){
238 if ( face->pShader != NULL ) {
239 face->pShader->DecRef();
241 face->texdef.SetName( name );
242 face->pShader = QERApp_Shader_ForName( name );
243 face->pShader->IncRef();
244 face->d_texture = face->pShader->getTexture();
245 face->texdef.flags = face->pShader->getFlags();
248 void Face_SetShader( face_t *face, IShader *shader ){
249 if ( face->pShader != NULL ) {
250 face->pShader->DecRef();
252 face->texdef.SetName( shader->getName() );
253 face->d_texture = shader->getTexture();
254 face->texdef.flags = shader->getFlags();
255 face->pShader = shader;
256 face->pShader->IncRef();
264 void Clamp( float& f, int nClamp ){
265 float fFrac = f - static_cast<int>( f );
266 f = static_cast<int>( f ) % nClamp;
275 void Face_MoveTexture( face_t *f, vec3_t delta ){
278 if ( g_qeglobals.m_bBrushPrimitMode ) {
279 ShiftTextureGeometric_BrushPrimit( f, delta );
283 TextureAxisFromPlane( &f->plane, vX, vY );
286 vDP[0] = DotProduct( delta, vX );
287 vDP[1] = DotProduct( delta, vY );
289 double fAngle = f->texdef.rotate / 180 * Q_PI;
290 double c = cos( fAngle );
291 double s = sin( fAngle );
293 vShift[0] = vDP[0] * c - vDP[1] * s;
294 vShift[1] = vDP[0] * s + vDP[1] * c;
296 if ( !f->texdef.scale[0] ) {
297 f->texdef.scale[0] = g_PrefsDlg.m_fDefTextureScale;
299 if ( !f->texdef.scale[1] ) {
300 f->texdef.scale[1] = g_PrefsDlg.m_fDefTextureScale;
303 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
304 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
307 Clamp( f->texdef.shift[0], f->d_texture->width );
308 Clamp( f->texdef.shift[1], f->d_texture->height );
317 /*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/
318 void Face_SetColor( brush_t *b, face_t *f, float fCurveColor ){
319 // set shading for face
320 f->d_shade = SetShadeForPlane( &f->plane );
321 f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade;
322 f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade;
323 f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade;
331 void Face_TextureVectors( face_t *f, float STfromXYZ[2][4] ){
334 float ang, sinv, cosv;
341 // this code is not supposed to be used while in BP mode, warning here can help spot the problem
342 if ( g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert ) {
343 Sys_Printf( "Warning : illegal call of Face_TextureVectors in brush primitive mode\n" );
350 memset( STfromXYZ, 0, 8 * sizeof( float ) );
352 if ( !td->scale[0] ) {
353 td->scale[0] = g_PrefsDlg.m_fDefTextureScale;
355 if ( !td->scale[1] ) {
356 td->scale[1] = g_PrefsDlg.m_fDefTextureScale;
359 // get natural texture axis
360 TextureAxisFromPlane( &f->plane, pvecs[0], pvecs[1] );
363 if ( td->rotate == 0 ) {
366 else if ( td->rotate == 90 ) {
369 else if ( td->rotate == 180 ) {
370 sinv = 0 ; cosv = -1;
372 else if ( td->rotate == 270 ) {
373 sinv = -1 ; cosv = 0;
377 ang = td->rotate / 180 * Q_PI;
385 else if ( pvecs[0][1] ) {
395 else if ( pvecs[1][1] ) {
402 for ( i = 0 ; i < 2 ; i++ ) {
403 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
404 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
405 STfromXYZ[i][sv] = ns;
406 STfromXYZ[i][tv] = nt;
410 for ( i = 0 ; i < 2 ; i++ )
411 for ( j = 0 ; j < 3 ; j++ )
412 STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
415 STfromXYZ[0][3] = td->shift[0];
416 STfromXYZ[1][3] = td->shift[1];
418 for ( j = 0 ; j < 4 ; j++ ) {
419 STfromXYZ[0][j] /= q->width;
420 STfromXYZ[1][j] /= q->height;
424 long double HighestImpactSign( long double a, long double b ){
425 // returns the sign of the value with larger abs
434 void Face_TexdefFromTextureVectors( face_t *f, long double STfromXYZ[2][4], vec3_t pvecs[2], int sv, int tv ){
443 // undo the texture transform
444 for ( j = 0 ; j < 4 ; j++ ) {
445 STfromXYZ[0][j] *= q->width;
446 STfromXYZ[1][j] *= q->height;
450 td->shift[0] = STfromXYZ[0][3];
451 td->shift[1] = STfromXYZ[1][3];
455 * STfromXYZ[0][sv] = (cosv * pvecs[0][sv] - sinv * pvecs[0][tv]) / td->scale[0];
456 * STfromXYZ[0][tv] = (sinv * pvecs[0][sv] + cosv * pvecs[0][tv]) / td->scale[0];
457 * STfromXYZ[1][sv] = (cosv * pvecs[1][sv] - sinv * pvecs[1][tv]) / td->scale[1];
458 * STfromXYZ[1][tv] = (sinv * pvecs[1][sv] + cosv * pvecs[1][tv]) / td->scale[1];
460 * sinv, cosv, td->scale[0], td->scale[1]
462 * sinv^2 + cosv^2 = 1
463 * pvecs[0][sv] is +/-1
466 * pvecs[1][tv] is +/-1
468 * STfromXYZ[0][sv] = +cosv * pvecs[0][sv] / td->scale[0];
469 * STfromXYZ[0][tv] = +sinv * pvecs[0][sv] / td->scale[0];
470 * STfromXYZ[1][sv] = -sinv * pvecs[1][tv] / td->scale[1];
471 * STfromXYZ[1][tv] = +cosv * pvecs[1][tv] / td->scale[1];
474 td->scale[0] = sqrt( STfromXYZ[0][sv] * STfromXYZ[0][sv] + STfromXYZ[0][tv] * STfromXYZ[0][tv] );
475 td->scale[1] = sqrt( STfromXYZ[1][sv] * STfromXYZ[1][sv] + STfromXYZ[1][tv] * STfromXYZ[1][tv] );
477 if ( td->scale[0] ) {
478 td->scale[0] = 1 / td->scale[0]; // avoid NaNs
480 if ( td->scale[1] ) {
481 td->scale[1] = 1 / td->scale[1];
484 long double sign0tv = ( STfromXYZ[0][tv] > 0 ) ? +1 : -1;
485 ang = atan2( sign0tv * STfromXYZ[0][tv], sign0tv * STfromXYZ[0][sv] ); // atan2(y, x) with y positive is in [0, PI[
488 // We have until now ignored the fact that td->scale[0] or td->scale[1] may
489 // have either sign (+ or -). Due to roundoff errors, our choice of
490 // sign0tv may even have been wrong in a sense.
491 // sign0tv may NOT indicate the appropriate sign for td->scale[0] (namely,
492 // if cosv is near zero)!
493 // let's look at the signs again
494 // sign0sv = signcosv * pvecs[0][sv] / td->scale[0]sign
495 // sign0tv = pvecs[0][sv] / td->scale[0]sign
496 // sign1sv = -1 * pvecs[1][tv] / td->scale[1]sign
497 // sign1tv = signcosv * pvecs[1][tv] / td->scale[1]sign
499 // td->scale[1]sign = sign1tv * signcosv * pvecs[1][tv]
500 // td->scale[1]sign = -sign1sv * signsinv * pvecs[1][tv]
501 // td->scale[0]sign = sign0tv * signsinv * pvecs[0][sv]
502 // td->scale[0]sign = sign0sv * signcosv * pvecs[0][sv]
504 // the one with the larger impact on the original texcoords, of course
505 // to minimize the effect of roundoff errors that may flip the signs!
507 td->scale[0] *= HighestImpactSign( STfromXYZ[0][tv] * +sin( ang ), STfromXYZ[0][sv] * cos( ang ) ) * pvecs[0][sv];
508 td->scale[1] *= HighestImpactSign( STfromXYZ[1][sv] * -sin( ang ), STfromXYZ[1][tv] * cos( ang ) ) * pvecs[1][tv];
510 td->rotate = ang * 180 / Q_PI; // FIXME possibly snap this to 0/90/180 (270 can't happen)?
519 void Face_MakePlane( face_t *f ){
523 // convert to a vector / dist plane
524 for ( j = 0 ; j < 3 ; j++ )
526 t1[j] = f->planepts[0][j] - f->planepts[1][j];
527 t2[j] = f->planepts[2][j] - f->planepts[1][j];
528 t3[j] = f->planepts[1][j];
531 CrossProduct( t1,t2, f->plane.normal );
532 if ( VectorCompare( f->plane.normal, vec3_origin ) ) {
533 Sys_FPrintf( SYS_WRN, "WARNING: brush plane with no normal\n" );
535 VectorNormalize( f->plane.normal, f->plane.normal );
536 f->plane.dist = DotProduct( t3, f->plane.normal );
541 EmitTextureCoordinates
544 void EmitTextureCoordinates( float *xyzst, qtexture_t *q, face_t *f ){
545 float STfromXYZ[2][4];
547 Face_TextureVectors( f, STfromXYZ );
548 xyzst[3] = DotProduct( xyzst, STfromXYZ[0] ) + STfromXYZ[0][3];
549 xyzst[4] = DotProduct( xyzst, STfromXYZ[1] ) + STfromXYZ[1][3];
552 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 ){
553 return a1 * b2 * c3 + a2 * b3 * c1 + a3 * b1 * c2
554 - a1 * c2 * b3 - a2 * c3 * b1 - a3 * c1 * b2;
557 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 ){
559 det = SarrusDetScalar( a1, b1, c1,
562 *a = SarrusDetScalar( d1, b1, c1,
565 *b = SarrusDetScalar( a1, d1, c1,
568 *c = SarrusDetScalar( a1, b1, d1,
573 void Face_TexdefFromTextureCoordinates( float *xyzst1, float *xyzst2, float *xyzst3, qtexture_t *q, face_t *f ){
577 long double STfromXYZ[2][4];
579 // get natural texture axis
580 TextureAxisFromPlane( &f->plane, pvecs[0], pvecs[1] );
585 else if ( pvecs[0][1] ) {
595 else if ( pvecs[1][1] ) {
602 uv = 3 - sv - tv; // the "other one"
604 // find the STfromXYZ 4-vectors
607 xyzst1[3] == xyzst1[sv] * STfromXYZ[0][sv] + xyzst1[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
608 xyzst2[3] == xyzst2[sv] * STfromXYZ[0][sv] + xyzst2[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
609 xyzst3[3] == xyzst3[sv] * STfromXYZ[0][sv] + xyzst3[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
611 GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
613 xyzst1[4] == xyzst1[sv] * STfromXYZ[1][sv] + xyzst1[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
614 xyzst2[4] == xyzst2[sv] * STfromXYZ[1][sv] + xyzst2[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
615 xyzst3[4] == xyzst3[sv] * STfromXYZ[1][sv] + xyzst3[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
617 GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
620 STfromXYZ[0][uv] = 0;
622 xyzst1[sv], xyzst1[tv], 1, xyzst1[3],
623 xyzst2[sv], xyzst2[tv], 1, xyzst2[3],
624 xyzst3[sv], xyzst3[tv], 1, xyzst3[3],
625 &STfromXYZ[0][sv], &STfromXYZ[0][tv], &STfromXYZ[0][3]
628 STfromXYZ[1][uv] = 0;
630 xyzst1[sv], xyzst1[tv], 1, xyzst1[4],
631 xyzst2[sv], xyzst2[tv], 1, xyzst2[4],
632 xyzst3[sv], xyzst3[tv], 1, xyzst3[4],
633 &STfromXYZ[1][sv], &STfromXYZ[1][tv], &STfromXYZ[1][3]
637 printf("%s\n", q->name);
639 printf("%f == %Lf\n", xyzst1[3], DotProduct (xyzst1, STfromXYZ[0]) + STfromXYZ[0][3]);
640 printf("%f == %Lf\n", xyzst2[3], DotProduct (xyzst2, STfromXYZ[0]) + STfromXYZ[0][3]);
641 printf("%f == %Lf\n", xyzst3[3], DotProduct (xyzst3, STfromXYZ[0]) + STfromXYZ[0][3]);
642 printf("%f == %Lf\n", xyzst1[4], DotProduct (xyzst1, STfromXYZ[1]) + STfromXYZ[1][3]);
643 printf("%f == %Lf\n", xyzst2[4], DotProduct (xyzst2, STfromXYZ[1]) + STfromXYZ[1][3]);
644 printf("%f == %Lf\n", xyzst3[4], DotProduct (xyzst3, STfromXYZ[1]) + STfromXYZ[1][3]);
646 float newSTfromXYZ[2][4];
648 printf("old: %Lf,%Lf,%Lf,%Lf %Lf,%Lf,%Lf,%Lf\n",
649 STfromXYZ[0][0], STfromXYZ[0][1], STfromXYZ[0][2], STfromXYZ[0][3],
650 STfromXYZ[1][0], STfromXYZ[1][1], STfromXYZ[1][2], STfromXYZ[1][3]);
653 Face_TexdefFromTextureVectors( f, STfromXYZ, pvecs, sv, tv );
656 Face_TextureVectors(f, newSTfromXYZ);
658 printf("new: %f,%f,%f,%f %f,%f,%f,%f\n",
659 newSTfromXYZ[0][0], newSTfromXYZ[0][1], newSTfromXYZ[0][2], newSTfromXYZ[0][3],
660 newSTfromXYZ[1][0], newSTfromXYZ[1][1], newSTfromXYZ[1][2], newSTfromXYZ[1][3]);
665 VectorCopy(xyzst1, newxyzst1);
666 VectorCopy(xyzst2, newxyzst2);
667 VectorCopy(xyzst3, newxyzst3);
668 EmitTextureCoordinates (newxyzst1, q, f);
669 EmitTextureCoordinates (newxyzst2, q, f);
670 EmitTextureCoordinates (newxyzst3, q, f);
671 printf("Face_TexdefFromTextureCoordinates: %f,%f %f,%f %f,%f -> %f,%f %f,%f %f,%f\n",
672 xyzst1[3], xyzst1[4],
673 xyzst2[3], xyzst2[4],
674 xyzst3[3], xyzst3[4],
675 newxyzst1[3], newxyzst1[4],
676 newxyzst2[3], newxyzst2[4],
677 newxyzst3[3], newxyzst3[4]);
678 // TODO why do these differ, but not the previous ones? this makes no sense whatsoever
684 //==========================================================================
691 void Brush_MakeFacePlanes( brush_t *b ){
694 for ( f = b->brush_faces ; f ; f = f->next )
705 void DrawBrushEntityName( brush_t *b ){
712 return; // during contruction
715 if ( b->owner == world_entity ) {
719 if ( b != b->owner->brushes.onext ) {
720 return; // not key brush
723 // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views
724 // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?
725 // Brush_DrawFacingAngle() works when called, but is not being called.
726 if ( g_qeglobals.d_savedinfo.show_angles && ( b->owner->eclass->nShowFlags & ECLASS_ANGLE ) ) {
727 // draw the angle pointer
728 a = FloatForKey( b->owner, "angle" );
729 s = sin( a / 180 * Q_PI );
730 c = cos( a / 180 * Q_PI );
731 for ( i = 0 ; i < 3 ; i++ )
732 mid[i] = ( b->mins[i] + b->maxs[i] ) * 0.5;
734 qglBegin( GL_LINE_STRIP );
764 if ( g_qeglobals.d_savedinfo.show_names ) {
765 name = ValueForKey( b->owner, "classname" );
766 qglRasterPos3f( b->mins[0] + 4, b->mins[1] + 4, b->mins[2] + 4 );
767 gtk_glwidget_print_string( name );
773 Brush_MakeFaceWinding
775 returns the visible polygon on a face
778 winding_t *Brush_MakeFaceWinding( brush_t *b, face_t *face ){
784 // get a poly that covers an effectively infinite area
785 w = Winding_BaseForPlane( &face->plane );
787 // chop the poly by all of the other faces
789 for ( clip = b->brush_faces ; clip && w ; clip = clip->next )
791 if ( clip == face ) {
795 if ( DotProduct( face->plane.normal, clip->plane.normal ) > 0.999
796 && fabs( face->plane.dist - clip->plane.dist ) < 0.01 ) { // identical plane, use the later one
804 // flip the plane, because we want to keep the back side
805 VectorSubtract( vec3_origin,clip->plane.normal, plane.normal );
806 plane.dist = -clip->plane.dist;
808 w = Winding_Clip( w, &plane, false );
814 if ( w->numpoints < 3 ) {
820 Sys_FPrintf( SYS_WRN, "unused plane\n" );
831 void Brush_SnapPlanepts( brush_t *b ){
835 if ( g_PrefsDlg.m_bNoClamp ) {
839 if ( g_qeglobals.d_bSmallGrid ) {
840 for ( f = b->brush_faces ; f; f = f->next )
841 for ( i = 0 ; i < 3 ; i++ )
842 for ( j = 0 ; j < 3 ; j++ )
843 f->planepts[i][j] = floor( f->planepts[i][j] / g_qeglobals.d_gridsize + 0.5 ) * g_qeglobals.d_gridsize;
847 for ( f = b->brush_faces ; f; f = f->next )
848 for ( i = 0 ; i < 3 ; i++ )
849 for ( j = 0 ; j < 3 ; j++ )
850 f->planepts[i][j] = floor( f->planepts[i][j] + 0.5 );
857 ** Builds a brush rendering data and also sets the min/max bounds
860 // added a bConvert flag to convert between old and new brush texture formats
862 // brush grouping: update the group treeview if necessary
863 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest ){
868 if ( !g_qeglobals.m_bBrushPrimitMode && bConvert ) {
869 Sys_Printf( "Warning : conversion from brush primitive to old brush format not implemented\n" );
873 // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
874 if ( bConvert && !g_qeglobals.bNeedConvert ) {
876 //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes
877 // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.
879 bLocalConvert = true;
880 g_qeglobals.bNeedConvert = true;
883 bLocalConvert = false;
887 ** build the windings and generate the bounding box
889 Brush_BuildWindings( b, bSnap );
891 if ( b->owner->model.pRender ) {
892 const aabb_t *aabb = b->owner->model.pRender->GetAABB();
893 VectorAdd( aabb->origin, aabb->extents, b->maxs );
894 VectorSubtract( aabb->origin, aabb->extents, b->mins );
897 //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !
900 ** move the points and edges if in select mode
902 if ( g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge ) {
903 SetupVertexSelection();
906 if ( b->itemOwner == 0 ) { //NULL)
907 Group_AddToProperGroup( b );
911 Sys_MarkMapModified();
914 if ( bLocalConvert ) {
915 g_qeglobals.bNeedConvert = false;
918 // spog - applying filters to brush during brush_build instead of during redraw
920 b->bFiltered = FilterBrush( b );
926 Brush_SplitBrushByFace
928 The incoming brush is NOT freed.
929 The incoming face is NOT left referenced.
932 void Brush_SplitBrushByFace( brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk ){
937 b = Brush_Clone( in );
938 nf = Face_Clone( f );
940 nf->texdef = b->brush_faces->texdef;
942 nf->texdef.SetName( g_pGameDescription->mCaulkShader.GetBuffer() );
944 nf->next = b->brush_faces;
948 Brush_RemoveEmptyFaces( b );
949 if ( !b->brush_faces ) { // completely clipped away
955 Entity_LinkBrush( in->owner, b );
959 b = Brush_Clone( in );
960 nf = Face_Clone( f );
961 // swap the plane winding
962 VectorCopy( nf->planepts[0], temp );
963 VectorCopy( nf->planepts[1], nf->planepts[0] );
964 VectorCopy( temp, nf->planepts[1] );
966 nf->texdef = b->brush_faces->texdef;
968 nf->texdef.SetName( g_pGameDescription->mCaulkShader.GetBuffer() );
970 nf->next = b->brush_faces;
974 Brush_RemoveEmptyFaces( b );
975 if ( !b->brush_faces ) { // completely clipped away
981 Entity_LinkBrush( in->owner, b );
990 returns the best face to split the brush with.
991 return NULL if the brush is convex
994 face_t *Brush_BestSplitFace( brush_t *b ){
995 face_t *face, *f, *bestface;
996 winding_t *front, *back;
997 int splits, tinywindings, value, bestvalue;
1001 for ( face = b->brush_faces; face; face = face->next )
1005 for ( f = b->brush_faces; f; f = f->next )
1011 Winding_SplitEpsilon( f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back );
1014 Winding_Free( back );
1017 Winding_Free( front );
1022 if ( Winding_IsTiny( front ) ) {
1025 if ( Winding_IsTiny( back ) ) {
1031 value = splits + 50 * tinywindings;
1032 if ( value < bestvalue ) {
1043 Brush_MakeConvexBrushes
1045 MrE FIXME: this doesn't work because the old
1046 Brush_SplitBrushByFace is used
1047 Turns the brush into a minimal number of convex brushes.
1048 If the input brush is convex then it will be returned.
1049 Otherwise the input brush will be freed.
1050 NOTE: the input brush should have windings for the faces.
1053 brush_t *Brush_MakeConvexBrushes( brush_t *b ){
1054 brush_t *front, *back, *end;
1058 face = Brush_BestSplitFace( b );
1062 Brush_SplitBrushByFace( b, face, &front, &back );
1063 //this should never happen
1064 if ( !front && !back ) {
1069 return Brush_MakeConvexBrushes( back );
1071 b = Brush_MakeConvexBrushes( front );
1073 for ( end = b; end->next; end = end->next ) ;
1074 end->next = Brush_MakeConvexBrushes( back );
1084 int Brush_Convex( brush_t *b ){
1085 face_t *face1, *face2;
1087 for ( face1 = b->brush_faces; face1; face1 = face1->next )
1089 if ( !face1->face_winding ) {
1092 for ( face2 = b->brush_faces; face2; face2 = face2->next )
1094 if ( face1 == face2 ) {
1097 if ( !face2->face_winding ) {
1100 if ( Winding_PlanesConcave( face1->face_winding, face2->face_winding,
1101 face1->plane.normal, face2->plane.normal,
1102 face1->plane.dist, face2->plane.dist ) ) {
1114 - The input brush must be convex
1115 - The input brush must have face windings.
1116 - The output brush will be convex.
1117 - Returns true if the WHOLE vertex movement is performed.
1121 // define this to debug the vertex editing mode
1126 #define MAX_MOVE_FACES 64
1128 int Brush_MoveVertex( brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap ){
1129 face_t *f, *face, *newface, *lastface, *nextface;
1130 face_t *movefaces[MAX_MOVE_FACES];
1131 int movefacepoints[MAX_MOVE_FACES];
1135 int i, j, k, nummovefaces, result, done;
1136 float dot, front, back, frac, smallestfrac;
1139 Sys_Printf( "Bursh_MoveVertex: %p vertex: %g %g %g delta: %g %g %g end: %g %g %g snap: %s\n", b, vertex[0], vertex[1], vertex[2], delta[0], delta[1], delta[2], end[0], end[1], end[2], bSnap ? "true" : "false" );
1146 VectorCopy( vertex, start );
1147 VectorAdd( vertex, delta, end );
1150 for ( i = 0; i < 3; i++ )
1151 end[i] = floor( end[i] / g_qeglobals.d_gridsize + 0.1 ) * g_qeglobals.d_gridsize;
1154 VectorCopy( end, mid );
1155 //if the start and end are the same
1156 if ( Point_Equal( start, end, 0.3f ) ) {
1159 //the end point may not be the same as another vertex
1160 for ( face = b->brush_faces; face; face = face->next )
1162 w = face->face_winding;
1166 for ( i = 0; i < w->numpoints; i++ )
1168 if ( Point_Equal( w->points[i], end, 0.3f ) ) {
1169 VectorCopy( vertex, end );
1178 //chop off triangles from all brush faces that use the to be moved vertex
1179 //store pointers to these chopped off triangles in movefaces[]
1181 for ( face = b->brush_faces; face; face = face->next )
1183 w = face->face_winding;
1187 for ( i = 0; i < w->numpoints; i++ )
1189 if ( Point_Equal( w->points[i], start, 0.2f ) ) {
1190 if ( face->face_winding->numpoints <= 3 ) {
1191 movefacepoints[nummovefaces] = i;
1192 movefaces[nummovefaces++] = face;
1195 dot = DotProduct( end, face->plane.normal ) - face->plane.dist;
1196 //if the end point is in front of the face plane
1198 //fanout triangle subdivision
1199 for ( k = i; k < i + w->numpoints - 3; k++ )
1201 VectorCopy( w->points[i], tmpw.points[0] );
1202 VectorCopy( w->points[( k + 1 ) % w->numpoints], tmpw.points[1] );
1203 VectorCopy( w->points[( k + 2 ) % w->numpoints], tmpw.points[2] );
1205 newface = Face_Clone( face );
1207 for ( f = face; f->original; f = f->original ) ;
1208 newface->original = f;
1209 //store the new winding
1210 if ( newface->face_winding ) {
1211 Winding_Free( newface->face_winding );
1213 newface->face_winding = Winding_Clone( &tmpw );
1214 //get the texture information
1215 newface->pShader = face->pShader;
1216 newface->d_texture = face->d_texture;
1218 //add the face to the brush
1219 newface->next = b->brush_faces;
1220 b->brush_faces = newface;
1221 //add this new triangle to the move faces
1222 movefacepoints[nummovefaces] = 0;
1223 movefaces[nummovefaces++] = newface;
1225 //give the original face a new winding
1226 VectorCopy( w->points[( i - 2 + w->numpoints ) % w->numpoints], tmpw.points[0] );
1227 VectorCopy( w->points[( i - 1 + w->numpoints ) % w->numpoints], tmpw.points[1] );
1228 VectorCopy( w->points[i], tmpw.points[2] );
1229 Winding_Free( face->face_winding );
1230 face->face_winding = Winding_Clone( &tmpw );
1231 //add the original face to the move faces
1232 movefacepoints[nummovefaces] = 2;
1233 movefaces[nummovefaces++] = face;
1237 //chop a triangle off the face
1238 VectorCopy( w->points[( i - 1 + w->numpoints ) % w->numpoints], tmpw.points[0] );
1239 VectorCopy( w->points[i], tmpw.points[1] );
1240 VectorCopy( w->points[( i + 1 ) % w->numpoints], tmpw.points[2] );
1241 //remove the point from the face winding
1242 Winding_RemovePoint( w, i );
1243 //get texture crap right
1244 Face_SetColor( b, face, 1.0 );
1245 for ( j = 0; j < w->numpoints; j++ )
1246 EmitTextureCoordinates( w->points[j], face->d_texture, face );
1247 //make a triangle face
1248 newface = Face_Clone( face );
1250 for ( f = face; f->original; f = f->original ) ;
1251 newface->original = f;
1252 //store the new winding
1253 if ( newface->face_winding ) {
1254 Winding_Free( newface->face_winding );
1256 newface->face_winding = Winding_Clone( &tmpw );
1258 newface->pShader = face->pShader;
1259 newface->d_texture = newface->pShader->getTexture();
1260 // newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );
1261 //add the face to the brush
1262 newface->next = b->brush_faces;
1263 b->brush_faces = newface;
1265 movefacepoints[nummovefaces] = 1;
1266 movefaces[nummovefaces++] = newface;
1272 //now movefaces contains pointers to triangle faces that
1273 //contain the to be moved vertex
1276 VectorCopy( end, mid );
1278 for ( face = b->brush_faces; face; face = face->next )
1280 //check if there is a move face that has this face as the original
1281 for ( i = 0; i < nummovefaces; i++ )
1283 if ( movefaces[i]->original == face ) {
1287 if ( i >= nummovefaces ) {
1290 //check if the original is not a move face itself
1291 for ( j = 0; j < nummovefaces; j++ )
1293 if ( face == movefaces[j] ) {
1297 //if the original is not a move face itself
1298 if ( j >= nummovefaces ) {
1299 memcpy( &plane, &movefaces[i]->original->plane, sizeof( plane_t ) );
1303 k = movefacepoints[j];
1304 w = movefaces[j]->face_winding;
1305 VectorCopy( w->points[( k + 1 ) % w->numpoints], tmpw.points[0] );
1306 VectorCopy( w->points[( k + 2 ) % w->numpoints], tmpw.points[1] );
1308 k = movefacepoints[i];
1309 w = movefaces[i]->face_winding;
1310 VectorCopy( w->points[( k + 1 ) % w->numpoints], tmpw.points[2] );
1311 if ( !Plane_FromPoints( tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane ) ) {
1312 VectorCopy( w->points[( k + 2 ) % w->numpoints], tmpw.points[2] );
1313 if ( !Plane_FromPoints( tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane ) ) {
1314 //this should never happen otherwise the face merge did a crappy job a previous pass
1319 //now we've got the plane to check agains
1320 front = DotProduct( start, plane.normal ) - plane.dist;
1321 back = DotProduct( end, plane.normal ) - plane.dist;
1322 //if the whole move is at one side of the plane
1323 if ( front < 0.01 && back < 0.01 ) {
1326 if ( front > -0.01 && back > -0.01 ) {
1329 //if there's no movement orthogonal to this plane at all
1330 if ( fabs( front - back ) < 0.001 ) {
1333 //ok first only move till the plane is hit
1334 frac = front / ( front - back );
1335 if ( frac < smallestfrac ) {
1336 mid[0] = start[0] + ( end[0] - start[0] ) * frac;
1337 mid[1] = start[1] + ( end[1] - start[1] ) * frac;
1338 mid[2] = start[2] + ( end[2] - start[2] ) * frac;
1339 smallestfrac = frac;
1346 for ( i = 0; i < nummovefaces; i++ )
1348 //move vertex to end position
1349 VectorCopy( mid, movefaces[i]->face_winding->points[movefacepoints[i]] );
1350 //create new face plane
1351 for ( j = 0; j < 3; j++ )
1353 VectorCopy( movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j] );
1355 Face_MakePlane( movefaces[i] );
1356 if ( VectorLength( movefaces[i]->plane.normal ) < 0.1 ) {
1360 //if the brush is no longer convex
1361 if ( !result || !Brush_Convex( b ) ) {
1362 for ( i = 0; i < nummovefaces; i++ )
1364 //move the vertex back to the initial position
1365 VectorCopy( start, movefaces[i]->face_winding->points[movefacepoints[i]] );
1366 //create new face plane
1367 for ( j = 0; j < 3; j++ )
1369 VectorCopy( movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j] );
1371 Face_MakePlane( movefaces[i] );
1374 VectorCopy( start, end );
1379 VectorCopy( mid, start );
1381 //get texture crap right
1382 for ( i = 0; i < nummovefaces; i++ )
1384 Face_SetColor( b, movefaces[i], 1.0 );
1385 for ( j = 0; j < movefaces[i]->face_winding->numpoints; j++ )
1386 EmitTextureCoordinates( movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i] );
1389 //now try to merge faces with their original faces
1391 for ( face = b->brush_faces; face; face = nextface )
1393 nextface = face->next;
1394 if ( !face->original ) {
1398 if ( !Plane_Equal( &face->plane, &face->original->plane, false ) ) {
1402 w = Winding_TryMerge( face->face_winding, face->original->face_winding, face->plane.normal, true );
1407 Winding_Free( face->original->face_winding );
1408 face->original->face_winding = w;
1409 //get texture crap right
1410 Face_SetColor( b, face->original, 1.0 );
1411 for ( j = 0; j < face->original->face_winding->numpoints; j++ )
1412 EmitTextureCoordinates( face->original->face_winding->points[j], face->original->d_texture, face->original );
1413 //remove the face that was merged with the original
1415 lastface->next = face->next;
1417 else{b->brush_faces = face->next; }
1426 Brush_InsertVertexBetween
1429 int Brush_InsertVertexBetween( brush_t *b, vec3_t p1, vec3_t p2 ){
1431 winding_t *w, *neww;
1435 if ( Point_Equal( p1, p2, 0.4f ) ) {
1438 VectorAdd( p1, p2, point );
1439 VectorScale( point, 0.5f, point );
1441 //the end point may not be the same as another vertex
1442 for ( face = b->brush_faces; face; face = face->next )
1444 w = face->face_winding;
1449 for ( i = 0; i < w->numpoints; i++ )
1451 if ( !Point_Equal( w->points[i], p1, 0.1f ) ) {
1454 if ( Point_Equal( w->points[( i + 1 ) % w->numpoints], p2, 0.1f ) ) {
1455 neww = Winding_InsertPoint( w, point, ( i + 1 ) % w->numpoints );
1458 else if ( Point_Equal( w->points[( i - 1 + w->numpoints ) % w->numpoints], p2, 0.3f ) ) {
1459 neww = Winding_InsertPoint( w, point, i );
1464 Winding_Free( face->face_winding );
1465 face->face_winding = neww;
1475 Brush_ResetFaceOriginals
1478 void Brush_ResetFaceOriginals( brush_t *b ){
1481 for ( face = b->brush_faces; face; face = face->next )
1483 face->original = NULL;
1487 #ifdef ENABLE_GROUPS
1491 sets an epair for the given brush
1494 void Brush_SetEpair( brush_t *b, const char *pKey, const char *pValue ){
1495 if ( g_qeglobals.m_bBrushPrimitMode ) {
1496 if ( b->patchBrush ) {
1497 Patch_SetEpair( b->pPatch, pKey, pValue );
1501 SetKeyValue( b->epairs, pKey, pValue );
1506 Sys_Printf( "Can only set key/values in Brush primitive mode\n" );
1515 const char* Brush_GetKeyValue( brush_t *b, const char *pKey ){
1516 if ( g_qeglobals.m_bBrushPrimitMode ) {
1517 if ( b->patchBrush ) {
1518 return Patch_GetKeyValue( b->pPatch, pKey );
1522 return ValueForKey( b->epairs, pKey );
1527 Sys_Printf( "Can only set brush/patch key/values in Brush primitive mode\n" );
1535 temporary stuff, detect potential problems when saving the texture name
1538 void CheckName( face_t *fa, char *pname ){
1539 if ( !strlen( fa->texdef.GetName() ) ) {
1541 Sys_Printf( "WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n" );
1543 fa->texdef.SetName( SHADER_NOT_FOUND );
1544 strcpy( pname, SHADER_NOT_FOUND );
1548 // some people manage to get long filename textures (with spaces) in their maps
1549 if ( strchr( fa->texdef.GetName(), ' ' ) ) {
1552 sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", fa->texdef.GetName() );
1554 Sys_Printf( "%s\n", Msg1 );
1555 gtk_MessageBox( g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
1556 strcpy( pname, SHADER_NOT_FOUND );
1560 //++timo FIXME: bug #103494 detection attempt
1561 // TODO: clean this detection part when bug will have disappeared
1562 if ( fa->texdef.GetName()[0] == '(' ) {
1563 const char *text = "Bug #103494 detected, dropping texture. Please report to timo@qeradiant.com if you have a way to reproduce!\nNOTE: this message may popup several times .. once for each buggy face detected.";
1564 Sys_Printf( "%s\n", text );
1565 gtk_MessageBox( g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );
1566 // need to cleanup this dead face name or we may loop endlessly
1567 fa->texdef.SetName( SHADER_NOT_FOUND );
1568 strcpy( pname, SHADER_NOT_FOUND );
1571 strcpy( pname, fa->texdef.GetName() + 9 ); // remove "textures/"
1578 Create non-textured blocks for entities
1579 The brush is NOT linked to any list
1582 brush_t *Brush_Create( vec3_t mins, vec3_t maxs, texdef_t *texdef ){
1589 // brush primitive mode : convert texdef to brushprimit_texdef ?
1590 // most of the time texdef is empty
1591 if ( g_qeglobals.m_bBrushPrimitMode ) {
1592 // check texdef is empty .. if there are cases it's not we need to write some conversion code
1593 if ( texdef->shift[0] != 0 || texdef->shift[1] != 0 || texdef->scale[0] != 0 || texdef->scale[1] != 0 || texdef->rotate != 0 ) {
1594 Sys_Printf( "Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n" );
1599 for ( i = 0 ; i < 3 ; i++ )
1601 if ( maxs[i] < mins[i] ) {
1602 Error( "Brush_InitSolid: backwards" );
1608 pts[0][0][0] = mins[0];
1609 pts[0][0][1] = mins[1];
1611 pts[1][0][0] = mins[0];
1612 pts[1][0][1] = maxs[1];
1614 pts[2][0][0] = maxs[0];
1615 pts[2][0][1] = maxs[1];
1617 pts[3][0][0] = maxs[0];
1618 pts[3][0][1] = mins[1];
1620 for ( i = 0 ; i < 4 ; i++ )
1622 pts[i][0][2] = mins[2];
1623 pts[i][1][0] = pts[i][0][0];
1624 pts[i][1][1] = pts[i][0][1];
1625 pts[i][1][2] = maxs[2];
1628 for ( i = 0 ; i < 4 ; i++ )
1631 f->texdef = *texdef;
1632 f->texdef.flags &= ~SURF_KEEP;
1633 f->texdef.contents &= ~CONTENTS_KEEP;
1634 f->next = b->brush_faces;
1638 VectorCopy( pts[j][1], f->planepts[0] );
1639 VectorCopy( pts[i][1], f->planepts[1] );
1640 VectorCopy( pts[i][0], f->planepts[2] );
1644 f->texdef = *texdef;
1645 f->texdef.flags &= ~SURF_KEEP;
1646 f->texdef.contents &= ~CONTENTS_KEEP;
1647 f->next = b->brush_faces;
1650 VectorCopy( pts[0][1], f->planepts[0] );
1651 VectorCopy( pts[1][1], f->planepts[1] );
1652 VectorCopy( pts[2][1], f->planepts[2] );
1655 f->texdef = *texdef;
1656 f->texdef.flags &= ~SURF_KEEP;
1657 f->texdef.contents &= ~CONTENTS_KEEP;
1658 f->next = b->brush_faces;
1661 VectorCopy( pts[2][0], f->planepts[0] );
1662 VectorCopy( pts[1][0], f->planepts[1] );
1663 VectorCopy( pts[0][0], f->planepts[2] );
1672 Create non-textured pyramid for light entities
1673 The brush is NOT linked to any list
1676 brush_t *Brush_CreatePyramid( vec3_t mins, vec3_t maxs, texdef_t *texdef ){
1679 //++timo handle new brush primitive ? return here ??
1680 return Brush_Create( mins, maxs, texdef );
1682 for ( i = 0 ; i < 3 ; i++ )
1683 if ( maxs[i] < mins[i] ) {
1684 Error( "Brush_InitSolid: backwards" );
1687 brush_t* b = Brush_Alloc();
1691 float fMid = Rad_rint( mins[2] + ( Rad_rint( ( maxs[2] - mins[2] ) / 2 ) ) );
1693 corners[0][0] = mins[0];
1694 corners[0][1] = mins[1];
1695 corners[0][2] = fMid;
1697 corners[1][0] = mins[0];
1698 corners[1][1] = maxs[1];
1699 corners[1][2] = fMid;
1701 corners[2][0] = maxs[0];
1702 corners[2][1] = maxs[1];
1703 corners[2][2] = fMid;
1705 corners[3][0] = maxs[0];
1706 corners[3][1] = mins[1];
1707 corners[3][2] = fMid;
1711 top[0] = Rad_rint( mins[0] + ( ( maxs[0] - mins[0] ) / 2 ) );
1712 top[1] = Rad_rint( mins[1] + ( ( maxs[1] - mins[1] ) / 2 ) );
1713 top[2] = Rad_rint( maxs[2] );
1715 VectorCopy( top, bottom );
1716 bottom[2] = mins[2];
1719 for ( i = 0; i < 4; i++ )
1721 face_t* f = Face_Alloc();
1722 f->texdef = *texdef;
1723 f->texdef.flags &= ~SURF_KEEP;
1724 f->texdef.contents &= ~CONTENTS_KEEP;
1725 f->next = b->brush_faces;
1727 int j = ( i + 1 ) % 4;
1729 VectorCopy( top, f->planepts[0] );
1730 VectorCopy( corners[i], f->planepts[1] );
1731 VectorCopy( corners[j], f->planepts[2] );
1734 f->texdef = *texdef;
1735 f->texdef.flags &= ~SURF_KEEP;
1736 f->texdef.contents &= ~CONTENTS_KEEP;
1737 f->next = b->brush_faces;
1740 VectorCopy( bottom, f->planepts[2] );
1741 VectorCopy( corners[i], f->planepts[1] );
1742 VectorCopy( corners[j], f->planepts[0] );
1755 Makes the current brush have the given number of 2d sides
1758 void Brush_MakeSided( int sides ){
1769 Sys_Status( "Bad sides number", 0 );
1773 if ( sides >= MAX_POINTS_ON_WINDING - 4 ) {
1774 Sys_Printf( "too many sides.\n" );
1778 if ( !QE_SingleBrush() ) {
1779 Sys_Status( "Must have a single brush selected", 0 );
1783 b = selected_brushes.next;
1784 VectorCopy( b->mins, mins );
1785 VectorCopy( b->maxs, maxs );
1786 texdef = &g_qeglobals.d_texturewin.texdef;
1790 if ( g_pParentWnd->ActiveXY() ) {
1791 switch ( g_pParentWnd->ActiveXY()->GetViewType() )
1793 case XY: axis = 2; break;
1794 case XZ: axis = 1; break;
1795 case YZ: axis = 0; break;
1803 // find center of brush
1805 for ( i = 0; i < 3; i++ )
1807 mid[i] = ( maxs[i] + mins[i] ) * 0.5;
1811 if ( ( maxs[i] - mins[i] ) * 0.5 > width ) {
1812 width = ( maxs[i] - mins[i] ) * 0.5;
1820 f->texdef = *texdef;
1821 f->next = b->brush_faces;
1824 f->planepts[2][( axis + 1 ) % 3] = mins[( axis + 1 ) % 3]; f->planepts[2][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3]; f->planepts[2][axis] = maxs[axis];
1825 f->planepts[1][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3]; f->planepts[1][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3]; f->planepts[1][axis] = maxs[axis];
1826 f->planepts[0][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3]; f->planepts[0][( axis + 2 ) % 3] = maxs[( axis + 2 ) % 3]; f->planepts[0][axis] = maxs[axis];
1828 // create bottom face
1830 f->texdef = *texdef;
1831 f->next = b->brush_faces;
1834 f->planepts[0][( axis + 1 ) % 3] = mins[( axis + 1 ) % 3]; f->planepts[0][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3]; f->planepts[0][axis] = mins[axis];
1835 f->planepts[1][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3]; f->planepts[1][( axis + 2 ) % 3] = mins[( axis + 2 ) % 3]; f->planepts[1][axis] = mins[axis];
1836 f->planepts[2][( axis + 1 ) % 3] = maxs[( axis + 1 ) % 3]; f->planepts[2][( axis + 2 ) % 3] = maxs[( axis + 2 ) % 3]; f->planepts[2][axis] = mins[axis];
1838 for ( i = 0 ; i < sides ; i++ )
1841 f->texdef = *texdef;
1842 f->next = b->brush_faces;
1845 sv = sin( i * 3.14159265 * 2 / sides );
1846 cv = cos( i * 3.14159265 * 2 / sides );
1848 f->planepts[0][( axis + 1 ) % 3] = floor( mid[( axis + 1 ) % 3] + width * cv + 0.5 );
1849 f->planepts[0][( axis + 2 ) % 3] = floor( mid[( axis + 2 ) % 3] + width * sv + 0.5 );
1850 f->planepts[0][axis] = mins[axis];
1852 f->planepts[1][( axis + 1 ) % 3] = f->planepts[0][( axis + 1 ) % 3];
1853 f->planepts[1][( axis + 2 ) % 3] = f->planepts[0][( axis + 2 ) % 3];
1854 f->planepts[1][axis] = maxs[axis];
1856 f->planepts[2][( axis + 1 ) % 3] = floor( f->planepts[0][( axis + 1 ) % 3] - width * sv + 0.5 );
1857 f->planepts[2][( axis + 2 ) % 3] = floor( f->planepts[0][( axis + 2 ) % 3] + width * cv + 0.5 );
1858 f->planepts[2][axis] = maxs[axis];
1861 Brush_AddToList( b, &selected_brushes );
1863 Entity_LinkBrush( world_entity, b );
1867 Sys_UpdateWindows( W_ALL );
1876 Frees the brush with all of its faces and display list.
1877 Unlinks the brush from whichever chain it is in.
1878 Decrements the owner entity's brushcount.
1879 Removes owner entity if this was the last brush
1880 unless owner is the world.
1884 void Brush_Free( brush_t *b, bool bRemoveNode ){
1886 epair_t *ep, *enext;
1888 // remove from group
1889 if ( bRemoveNode ) {
1890 Group_RemoveBrush( b );
1893 // free the patch if it's there
1894 if ( b->patchBrush ) {
1895 Patch_Delete( b->pPatch );
1899 for ( f = b->brush_faces ; f ; f = next )
1905 // TTimo : free brush epairs
1906 for ( ep = b->epairs ; ep ; ep = enext )
1914 // unlink from active/selected list
1916 Brush_RemoveFromList( b );
1919 // unlink from entity list
1921 Entity_UnlinkBrush( b );
1932 int Face_MemorySize( face_t *f ){
1935 if ( f->face_winding ) {
1936 // size += _msize(f->face_winding);
1937 size += sizeof( vec3_t ) * f->face_winding->numpoints + 2 * sizeof( int );
1939 // size += _msize(f);
1940 size += sizeof( face_t );
1949 int Brush_MemorySize( brush_t *b ){
1955 if ( b->patchBrush ) {
1956 size += Patch_MemorySize( b->pPatch );
1959 for ( f = b->brush_faces; f; f = f->next )
1961 size += Face_MemorySize( f );
1964 for ( ep = b->epairs; ep; ep = ep->next )
1966 // size += _msize(ep->key);
1967 size += strlen( ep->key );
1968 // size += _msize(ep->value);
1969 size += strlen( ep->value );
1970 // size += _msize(ep);
1971 size += sizeof( epair_t );
1973 // size += _msize(b);
1974 size += sizeof( brush_t );
1983 Does NOT add the new brush to any lists
1986 brush_t *Brush_Clone( brush_t *b ){
1990 if ( b->patchBrush ) {
1991 patchMesh_t *p = Patch_Duplicate( b->pPatch );
1992 Brush_RemoveFromList( p->pSymbiot );
1993 Entity_UnlinkBrush( p->pSymbiot );
1999 n->numberId = g_nBrushId++;
2000 n->owner = b->owner;
2001 for ( f = b->brush_faces ; f ; f = f->next )
2003 nf = Face_Clone( f );
2004 nf->next = n->brush_faces;
2005 n->brush_faces = nf;
2016 Does NOT add the new brush to any lists
2019 brush_t *Brush_FullClone( brush_t *b ){
2021 face_t *f, *nf, *f2, *nf2;
2024 if ( b->patchBrush ) {
2025 patchMesh_t *p = Patch_Duplicate( b->pPatch );
2026 Brush_RemoveFromList( p->pSymbiot );
2027 Entity_UnlinkBrush( p->pSymbiot );
2029 n->owner = b->owner;
2035 n->numberId = g_nBrushId++;
2036 n->owner = b->owner;
2037 VectorCopy( b->mins, n->mins );
2038 VectorCopy( b->maxs, n->maxs );
2040 for ( f = b->brush_faces; f; f = f->next )
2042 if ( f->original ) {
2045 nf = Face_FullClone( f );
2046 nf->next = n->brush_faces;
2047 n->brush_faces = nf;
2048 //copy all faces that have the original set to this face
2049 for ( f2 = b->brush_faces; f2; f2 = f2->next )
2051 if ( f2->original == f ) {
2052 nf2 = Face_FullClone( f2 );
2053 nf2->next = n->brush_faces;
2054 n->brush_faces = nf2;
2060 for ( nf = n->brush_faces; nf; nf = nf->next )
2062 Face_SetColor( n, nf, 1.0 );
2063 if ( nf->face_winding ) {
2064 if ( g_qeglobals.m_bBrushPrimitMode ) {
2065 EmitBrushPrimitTextureCoordinates( nf,nf->face_winding );
2069 for ( j = 0; j < nf->face_winding->numpoints; j++ )
2070 EmitTextureCoordinates( nf->face_winding->points[j], nf->d_texture, nf );
2078 // FIXME - spog - finish this later..
2080 bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)
2083 vec3_t v1, v2, normal[3];
2086 //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);
2087 //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);
2088 //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);
2089 //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);
2091 // test ray against triangle
2092 // get triangle plane normal
2093 //VectorSubtract(p1, p2, v1);
2094 //VectorSubtract(p1, p3, v2);
2095 //CrossProduct(v1, v2, v1);
2096 // check normal against direction
2097 //if (DotProduct(dir, v1) >= 0)
2099 // generate cone normals
2100 VectorSubtract(origin, p1, v1);
2101 VectorSubtract(origin, p2, v2);
2102 CrossProduct(v1, v2, normal[0]);
2103 VectorSubtract(origin, p2, v1);
2104 VectorSubtract(origin, p3, v2);
2105 CrossProduct(v1, v2, normal[1]);
2106 VectorSubtract(origin, p3, v1);
2107 VectorSubtract(origin, p1, v2);
2108 CrossProduct(v1, v2, normal[2]);
2112 // flip normals if triangle faces away
2113 // Sys_Printf("flipped\n");
2114 // VectorSubtract(origin, p1, v1);
2115 // VectorSubtract(origin, p3, v2);
2116 // CrossProduct(v1, v2, normal[0]);
2117 // VectorSubtract(origin, p3, v1);
2118 // VectorSubtract(origin, p2, v2);
2119 // CrossProduct(v1, v2, normal[1]);
2120 // VectorSubtract(origin, p2, v1);
2121 // VectorSubtract(origin, p1, v2);
2122 // CrossProduct(v1, v2, normal[2]);
2127 VectorNormalize(normal[i]);
2128 //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);
2129 //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);
2130 d = DotProduct(dir, normal[i]);
2131 //Sys_Printf("dotproduct: %f\n",d);
2140 extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
2141 float vert0[3], float vert1[3], float vert2[3],
2142 double *t, double *u, double *v);
2144 bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
2146 bool bIntersect = false;
2147 float tBest = FLT_MAX;
2152 float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set
2154 VectorSubtract (origin, b->owner->origin, vRay[0]);
2155 VectorCopy (dir, vRay[1]);
2163 s = sin (-angle/180*Q_PI);
2164 c = cos (-angle/180*Q_PI);
2170 vRay[i][0] = (x * c) - (y * s);
2171 vRay[i][1] = (x * s) + (y * c);
2175 entitymodel *model = b->owner->md3Class->model;
2177 while (model != NULL)
2179 for (i = 0; i < model->nTriCount; i++)
2181 for (j = 0; j < 3; j++)
2182 VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);
2184 if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))
2191 model = model->pNext;
2210 Itersects a ray with a brush
2211 Returns the face hit and the distance along the ray the intersection occured at
2212 Returns NULL and 0 if not hit at all
2215 extern bool Patch_Ray( patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v );
2216 face_t *Brush_Ray( vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags ){
2217 face_t *f, *firstface = NULL;
2222 if ( b->owner->eclass->fixedsize
2223 && b->owner->model.pSelect
2224 && !( !IsBrushSelected( b ) && ( g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY ) )
2225 && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX ) {
2227 vec_t dist_local = FLT_MAX;
2228 ray_construct_for_vec3( &ray_local, origin, dir );
2229 if ( b->owner->model.pSelect->TestRay( &ray_local, &dist_local ) ) {
2231 return b->brush_faces;
2240 VectorCopy( origin, p1 );
2241 for ( i = 0 ; i < 3 ; i++ )
2242 p2[i] = p1[i] + dir[i] * 2 * g_MaxWorldCoord;
2244 for ( f = b->brush_faces ; f ; f = f->next )
2246 d1 = DotProduct( p1, f->plane.normal ) - f->plane.dist;
2247 d2 = DotProduct( p2, f->plane.normal ) - f->plane.dist;
2248 if ( d1 >= 0 && d2 >= 0 ) {
2250 return NULL; // ray is on front side of face
2252 if ( d1 <= 0 && d2 <= 0 ) {
2255 // clip the ray to the plane
2256 frac = d1 / ( d1 - d2 );
2259 for ( i = 0 ; i < 3 ; i++ )
2260 p1[i] = p1[i] + frac * ( p2[i] - p1[i] );
2264 for ( i = 0 ; i < 3 ; i++ )
2265 p2[i] = p1[i] + frac * ( p2[i] - p1[i] );
2269 // find distance p1 is along dir
2270 VectorSubtract( p1, origin, p1 );
2271 d1 = DotProduct( p1, dir );
2275 // new test stuff for patches
2276 if ( !g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush ) {
2277 double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are
2278 if ( !Patch_Ray( b->pPatch, origin, dir, &t, &u, &v ) ) {
2285 //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);
2290 // modifications to the discarding code here should be matched in the selection code
2293 // do some last minute filtering
2294 if ( firstface && nFlags & SF_CAMERA ) {
2295 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK ) {
2296 if ( strstr( firstface->texdef.GetName(), "caulk" ) ) {
2301 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP ) {
2302 if ( strstr( firstface->texdef.GetName(), "botclip" ) || strstr( firstface->texdef.GetName(), "clipmonster" ) ) {
2307 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP ) {
2308 if ( strstr( firstface->texdef.GetName(), "clip" ) ) {
2319 face_t *Brush_Point( vec3_t origin, brush_t *b ){
2323 for ( f = b->brush_faces ; f ; f = f->next )
2325 d1 = DotProduct( origin, f->plane.normal ) - f->plane.dist;
2327 return NULL; // point is on front side of face
2331 return b->brush_faces;
2336 void Brush_AddToList( brush_t *b, brush_t *blist ){
2337 if ( b->next || b->prev ) {
2338 Error( "Brush_AddToList: already linked" );
2341 if ( blist == &selected_brushes || blist == &active_brushes ) {
2342 if ( b->patchBrush && blist == &selected_brushes ) {
2343 Patch_Select( b->pPatch );
2346 b->next = blist->next;
2347 blist->next->prev = b;
2352 DispatchRadiantMsg( RADIANT_SELECTION );
2355 void Brush_RemoveFromList( brush_t *b ){
2356 if ( !b->next || !b->prev ) {
2357 Error( "Brush_RemoveFromList: not linked" );
2360 if ( b->patchBrush ) {
2361 Patch_Deselect( b->pPatch );
2363 b->next->prev = b->prev;
2364 b->prev->next = b->next;
2365 b->next = b->prev = NULL;
2372 Doesn't set the curve flags
2375 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2376 use Texture_ForName() to find the right shader
2377 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2379 TTimo: surface plugin, added an IPluginTexdef* parameter
2380 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2381 if NULL, ask for a default
2383 TTimo - shader code cleanup
2384 added IShader* parameter
2387 void SetFaceTexdef2( brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef ) {
2392 oldFlags = f->texdef.flags;
2393 oldContents = f->texdef.contents;
2394 if ( g_qeglobals.m_bBrushPrimitMode ) {
2395 f->texdef = *texdef;
2396 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2400 f->texdef = *texdef;
2401 // fit the scaling of the texture on the actual plane
2402 vec3_t p1,p2,p3; // absolute coordinates
2403 // compute absolute coordinates
2404 ComputeAbsolute( f,p1,p2,p3 );
2405 // compute the scale
2407 VectorSubtract( p2,p1,vx );
2408 VectorNormalize( vx, vx );
2409 VectorSubtract( p3,p1,vy );
2410 VectorNormalize( vy, vy );
2412 VectorScale( vx,texdef->scale[0],vx );
2413 VectorScale( vy,texdef->scale[1],vy );
2414 VectorAdd( p1,vx,p2 );
2415 VectorAdd( p1,vy,p3 );
2416 // compute back shift scale rot
2417 AbsoluteToLocal( f->plane,f,p1,p2,p3 );
2420 f->texdef = *texdef;
2422 f->texdef.flags = ( f->texdef.flags & ~SURF_KEEP ) | ( oldFlags & SURF_KEEP );
2423 f->texdef.contents = ( f->texdef.contents & ~CONTENTS_KEEP ) | ( oldContents & CONTENTS_KEEP );
2425 // if this is a curve face, set all other curve faces to the same texdef
2426 if ( f->texdef.flags & SURF_CURVE ) {
2427 for ( tf = b->brush_faces ; tf ; tf = tf->next )
2429 if ( tf->texdef.flags & SURF_CURVE ) {
2430 tf->texdef = f->texdef;
2440 Doesn't set the curve flags
2443 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2444 use Texture_ForName() to find the right shader
2445 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2447 TTimo: surface plugin, added an IPluginTexdef* parameter
2448 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2449 if NULL, ask for a default
2452 void SetFaceTexdef( face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef ) {
2456 oldFlags = f->texdef.flags;
2457 oldContents = f->texdef.contents;
2459 if ( strcmp( f->texdef.GetName(), texdef->GetName() ) != 0 ) { // set shader here instead of Brush_Build
2460 Face_SetShader( f, texdef->GetName() );
2463 if ( g_qeglobals.m_bBrushPrimitMode ) {
2464 f->texdef = *texdef;
2465 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2470 f->texdef = *texdef;
2471 // fit the scaling of the texture on the actual plane
2472 vec3_t p1,p2,p3; // absolute coordinates
2473 // compute absolute coordinates
2474 ComputeAbsolute( f,p1,p2,p3 );
2475 // compute the scale
2477 VectorSubtract( p2,p1,vx );
2478 VectorNormalize( vx, vx );
2479 VectorSubtract( p3,p1,vy );
2480 VectorNormalize( vy, vy );
2482 VectorScale( vx,texdef->scale[0],vx );
2483 VectorScale( vy,texdef->scale[1],vy );
2484 VectorAdd( p1,vx,p2 );
2485 VectorAdd( p1,vy,p3 );
2486 // compute back shift scale rot
2487 AbsoluteToLocal( f->plane,f,p1,p2,p3 );
2491 f->texdef = *texdef;
2494 f->texdef.flags = ( f->texdef.flags & ~SURF_KEEP ) | ( oldFlags & SURF_KEEP );
2495 f->texdef.contents = ( f->texdef.contents & ~CONTENTS_KEEP ) | ( oldContents & CONTENTS_KEEP );
2499 void Brush_SetTexture2( brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef ){
2500 for ( face_t* f = b->brush_faces ; f ; f = f->next )
2501 SetFaceTexdef2( b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef );
2503 if ( b->patchBrush ) {
2504 Patch_SetTexture( b->pPatch, texdef, pTexdef );
2505 b->bFiltered = FilterBrush( b );
2510 void Brush_SetTexture( brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef ){
2511 for ( face_t* f = b->brush_faces ; f ; f = f->next )
2512 SetFaceTexdef( f, texdef, brushprimit_texdef, bFitScale, pTexdef );
2514 if ( b->patchBrush ) {
2515 Patch_SetTexture( b->pPatch, texdef, pTexdef );
2516 b->bFiltered = FilterBrush( b );
2521 qboolean ClipLineToFace( vec3_t p1, vec3_t p2, face_t *f ){
2526 d1 = DotProduct( p1, f->plane.normal ) - f->plane.dist;
2527 d2 = DotProduct( p2, f->plane.normal ) - f->plane.dist;
2529 if ( d1 >= 0 && d2 >= 0 ) {
2530 return false; // totally outside
2532 if ( d1 <= 0 && d2 <= 0 ) {
2533 return true; // totally inside
2536 fr = d1 / ( d1 - d2 );
2545 for ( i = 0 ; i < 3 ; i++ )
2546 v[i] = p1[i] + fr * ( p2[i] - p1[i] );
2552 int AddPlanept( float *f ){
2555 for ( i = 0 ; i < g_qeglobals.d_num_move_points ; i++ )
2556 if ( g_qeglobals.d_move_points[i] == f ) {
2559 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2565 Brush_SelectFaceForDragging
2567 Adds the faces planepts to move_points, and
2568 rotates and adds the planepts of adjacent face if shear is set
2571 void Brush_SelectFaceForDragging( brush_t *b, face_t *f, qboolean shear ){
2579 if ( b->owner->eclass->fixedsize ) {
2584 for ( i = 0 ; i < 3 ; i++ )
2585 c += AddPlanept( f->planepts[i] );
2587 return; // already completely added
2590 // select all points on this plane in all brushes the selection
2591 for ( b2 = selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next )
2596 for ( f2 = b2->brush_faces ; f2 ; f2 = f2->next )
2598 for ( i = 0 ; i < 3 ; i++ )
2599 if ( fabs( DotProduct( f2->planepts[i], f->plane.normal )
2600 - f->plane.dist ) > ON_EPSILON ) {
2603 if ( i == 3 ) { // move this face as well
2604 Brush_SelectFaceForDragging( b2, f2, shear );
2611 // if shearing, take all the planes adjacent to
2612 // selected faces and rotate their points so the
2613 // edge clipped by a selcted face has two of the points
2618 for ( f2 = b->brush_faces ; f2 ; f2 = f2->next )
2623 w = Brush_MakeFaceWinding( b, f2 );
2628 // any points on f will become new control points
2629 for ( i = 0 ; i < w->numpoints ; i++ )
2631 d = DotProduct( w->points[i], f->plane.normal )
2633 if ( d > -ON_EPSILON && d < ON_EPSILON ) {
2639 // if none of the points were on the plane,
2642 if ( i != w->numpoints ) {
2643 if ( i == 0 ) { // see if the first clockwise point was the
2644 // last point on the winding
2645 d = DotProduct( w->points[w->numpoints - 1]
2646 , f->plane.normal ) - f->plane.dist;
2647 if ( d > -ON_EPSILON && d < ON_EPSILON ) {
2648 i = w->numpoints - 1;
2652 AddPlanept( f2->planepts[0] );
2654 VectorCopy( w->points[i], f2->planepts[0] );
2655 if ( ++i == w->numpoints ) {
2659 // see if the next point is also on the plane
2660 d = DotProduct( w->points[i]
2661 , f->plane.normal ) - f->plane.dist;
2662 if ( d > -ON_EPSILON && d < ON_EPSILON ) {
2663 AddPlanept( f2->planepts[1] );
2666 VectorCopy( w->points[i], f2->planepts[1] );
2667 if ( ++i == w->numpoints ) {
2671 // the third point is never on the plane
2673 VectorCopy( w->points[i], f2->planepts[2] );
2684 The mouse click did not hit the brush, so grab one or more side
2688 void Brush_SideSelect( brush_t *b, vec3_t origin, vec3_t dir
2693 for ( f = b->brush_faces ; f ; f = f->next )
2695 VectorCopy( origin, p1 );
2696 VectorMA( origin, 2 * g_MaxWorldCoord, dir, p2 );
2698 for ( f2 = b->brush_faces ; f2 ; f2 = f2->next )
2703 ClipLineToFace( p1, p2, f2 );
2710 if ( VectorCompare( p1, origin ) ) {
2713 if ( ClipLineToFace( p1, p2, f ) ) {
2717 Brush_SelectFaceForDragging( b, f, shear );
2721 bool g_bBuildWindingsNoTexBuild = false;
2723 void Brush_SetBuildWindingsNoTexBuild( bool bBuild ){
2724 g_bBuildWindingsNoTexBuild = bBuild;
2727 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary
2728 // saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases
2729 // ie when we want to update a shader
2730 // default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild
2731 void Brush_BuildWindings( brush_t *b, bool bSnap ){
2737 Brush_SnapPlanepts( b );
2740 // clear the mins/maxs bounds
2741 b->mins[0] = b->mins[1] = b->mins[2] = 99999;
2742 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
2744 Brush_MakeFacePlanes( b );
2746 face = b->brush_faces;
2748 float fCurveColor = 1.0;
2750 for ( ; face ; face = face->next )
2753 free( face->face_winding );
2754 w = face->face_winding = Brush_MakeFaceWinding( b, face );
2756 if ( !g_bBuildWindingsNoTexBuild || !face->d_texture ) {
2758 // if there's no d_texture, then we expect pShader to be empty
2759 if ( !face->d_texture && face->pShader ) {
2760 Sys_FPrintf( SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n" );
2763 if ( ( !face->d_texture && !face->pShader ) || !face->pShader ) {
2765 // patch 84 for bug 253 doesn't dec ref the potential face->pShader
2766 // add a debug check to make sure this is actually not necessary
2768 if ( face->pShader ) {
2769 Sys_FPrintf( SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n" );
2772 face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );
2773 face->pShader->IncRef();
2774 face->d_texture = face->pShader->getTexture();
2782 for ( i = 0 ; i < w->numpoints ; i++ )
2784 // add to bounding box
2785 for ( j = 0 ; j < 3 ; j++ )
2787 v = w->points[i][j];
2788 if ( v > b->maxs[j] ) {
2791 if ( v < b->mins[j] ) {
2796 Face_SetColor( b, face, fCurveColor );
2798 fCurveColor -= .10f;
2799 if ( fCurveColor <= 0 ) {
2803 // computing ST coordinates for the windings
2804 if ( g_qeglobals.m_bBrushPrimitMode ) {
2805 if ( g_qeglobals.bNeedConvert ) {
2806 // we have parsed old brushes format and need conversion
2807 // convert old brush texture representation to new format
2808 FaceToBrushPrimitFace( face );
2810 // use old texture coordinates code to check against
2811 for ( i = 0 ; i < w->numpoints ; i++ )
2812 EmitTextureCoordinates( w->points[i], face->d_texture, face );
2815 // use new texture representation to compute texture coordinates
2816 // in debug mode we will check against old code and warn if there are differences
2817 EmitBrushPrimitTextureCoordinates( face,w );
2821 if ( g_qeglobals.bNeedConvert ) {
2822 BrushPrimitFaceToFace( face );
2824 // we have parsed brush primitives and need conversion back to standard format
2825 // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
2826 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
2827 // I tried various tweaks, no luck .. seems shifting is lost
2828 brushprimit_texdef_t aux;
2829 ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
2830 TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
2831 face->texdef.scale[0]/=2.0;
2832 face->texdef.scale[1]/=2.0;
2835 for ( i = 0 ; i < w->numpoints ; i++ )
2836 EmitTextureCoordinates( w->points[i], face->d_texture, face );
2843 Brush_RemoveEmptyFaces
2845 Frees any overconstraining faces
2848 void Brush_RemoveEmptyFaces( brush_t *b ){
2852 b->brush_faces = NULL;
2854 for ( ; f ; f = next )
2857 if ( !f->face_winding ) {
2862 f->next = b->brush_faces;
2869 void Brush_SnapToGrid( brush_t *pb ){
2875 // TTimo: some brushes are "special" and should not be snapped
2876 // specially fixed-size entity ones
2877 if ( pb->owner->eclass->fixedsize ) {
2878 // save current origin
2879 VectorCopy( pb->owner->origin, temp );
2881 VectorFSnap( pb->owner->origin, g_qeglobals.d_gridsize );
2882 // return if amount is zero
2883 if ( VectorCompare( pb->owner->origin, temp ) ) {
2886 // transform brush faces same amount
2887 VectorSubtract( pb->owner->origin, temp, temp );
2888 for ( f = pb->brush_faces; f; f = f->next )
2890 for ( i = 0 ; i < 3 ; i++ )
2891 VectorAdd( f->planepts[i], temp, f->planepts[i] );
2896 for ( f = pb->brush_faces ; f; f = f->next )
2898 for ( j = 0; j < 2; j++ )
2900 // spog - move planepts apart just far enough to avoid snapping two together
2901 VectorSubtract( f->planepts[j + 1], f->planepts[j], diff[j] );
2902 for ( i = 0; i < 3; i++ )
2904 if ( diff[j][i] == 0.0f ) {
2905 mult[i] = 2; // next value up from 1
2907 else{ // multiplier = gridsize / component difference, rounded up
2908 mult[i] = (int)ceil( fabs( g_qeglobals.d_gridsize / diff[j][i] ) );
2912 if ( mult[0] > 1 && mult[1] > 1 && mult[2] > 1 ) { // if all multipliers are greater than 1
2913 n = ( mult[0] >= mult[1] && mult[0] >= mult[2] ) ? 0 : ( mult[1] >= mult[0] && mult[1] >= mult[2] ) ? 1 : 2;
2914 for ( i = 0; i < 3; i++ )
2915 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component
2917 VectorAdd( f->planepts[j], diff[j], f->planepts[j + 1] );
2920 for ( i = 0; i < 3; i++ )
2921 VectorFSnap( f->planepts[i], g_qeglobals.d_gridsize );
2925 Brush_Build( pb,true,true,false,false ); // don't filter
2928 void Brush_Rotate( brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild ){
2929 for ( face_t* f = b->brush_faces ; f ; f = f->next )
2931 for ( int i = 0 ; i < 3 ; i++ )
2933 VectorRotateOrigin( f->planepts[i], vAngle, vOrigin, f->planepts[i] );
2937 Brush_Build( b,false,false,false,false ); // don't filter
2941 void Brush_Center( brush_t *b, vec3_t vNewCenter ){
2943 // get center of the brush
2944 for ( int j = 0; j < 3; j++ )
2946 vMid[j] = b->mins[j] + fabs( ( b->maxs[j] - b->mins[j] ) * 0.5 );
2948 // calc distance between centers
2949 VectorSubtract( vNewCenter, vMid, vMid );
2950 Brush_Move( b, vMid, true );
2954 void Brush_Resize( brush_t *b, vec3_t vMin, vec3_t vMax ){
2958 short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
2960 for ( i = 0 ; i < 3 ; i++ )
2961 if ( vMax[i] < vMin[i] ) {
2962 Error( "Brush_Resize: invalid input" );
2965 if ( b->brush_faces != NULL ) {
2966 texdef = b->brush_faces->texdef;
2969 texdef = g_qeglobals.d_texturewin.texdef;
2972 while ( b->brush_faces != NULL )
2974 f = b->brush_faces->next;
2975 Face_Free( b->brush_faces );
2979 for ( i = 0; i < 3; i++ )
2982 b->brush_faces = Face_Alloc();
2983 b->brush_faces->next = f;
2986 VectorCopy( vMax, f->planepts[0] );
2987 VectorCopy( vMax, f->planepts[1] );
2988 VectorCopy( vMax, f->planepts[2] );
2989 f->planepts[2][box[i][0]] = vMin[box[i][0]];
2990 f->planepts[1][box[i][1]] = vMin[box[i][1]];
2992 for ( i = 0; i < 3; i++ )
2995 b->brush_faces = Face_Alloc();
2996 b->brush_faces->next = f;
2999 VectorCopy( vMin, f->planepts[0] );
3000 VectorCopy( vMin, f->planepts[1] );
3001 VectorCopy( vMin, f->planepts[2] );
3002 f->planepts[1][box[i][0]] = vMax[box[i][0]];
3003 f->planepts[2][box[i][1]] = vMax[box[i][1]];
3007 void FacingVectors( entity_t *e, vec3_t forward, vec3_t right, vec3_t up ){
3011 angleVal = IntForKey( e, "angle" );
3012 if ( angleVal == -1 ) { // up
3013 VectorSet( angles, 270, 0, 0 );
3015 else if ( angleVal == -2 ) { // down
3016 VectorSet( angles, 90, 0, 0 );
3020 VectorSet( angles, 0, angleVal, 0 );
3023 AngleVectors( angles, forward, right, up );
3026 void Brush_DrawFacingAngle( brush_t *b, entity_t *e ){
3027 vec3_t forward, right, up;
3028 vec3_t endpoint, tip1, tip2;
3032 VectorAdd( e->brushes.onext->mins, e->brushes.onext->maxs, start );
3033 VectorScale( start, 0.5, start );
3034 dist = ( b->maxs[0] - start[0] ) * 2.5;
3036 FacingVectors( e, forward, right, up );
3037 VectorMA( start, dist, forward, endpoint );
3039 dist = ( b->maxs[0] - start[0] ) * 0.5;
3040 VectorMA( endpoint, -dist, forward, tip1 );
3041 VectorMA( tip1, -dist, up, tip1 );
3042 VectorMA( tip1, 2 * dist, up, tip2 );
3044 qglColor4f( 1, 1, 1, 1 );
3046 qglBegin( GL_LINES );
3047 qglVertex3fv( start );
3048 qglVertex3fv( endpoint );
3049 qglVertex3fv( endpoint );
3050 qglVertex3fv( tip1 );
3051 qglVertex3fv( endpoint );
3052 qglVertex3fv( tip2 );
3057 void Brush_FaceDraw( face_t *face, int nGLState ){
3058 const winding_t *w = face->face_winding;
3062 if ( nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting ) {
3063 qglNormal3fv( face->plane.normal );
3066 if (mode & DRAW_GL_TEXTURE_2D)
3067 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);
3068 qglVertexPointer(3, GL_FLOAT, 5, w->points);
3070 if (mode & DRAW_GL_FILL)
3071 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);
3073 qglDrawArrays(GL_POLYGON, 0, w->numpoints);
3076 if ( nGLState & DRAW_GL_FILL ) {
3077 qglBegin( GL_TRIANGLE_FAN );
3080 qglBegin( GL_POLYGON );
3083 for ( int i = 0 ; i < w->numpoints ; i++ )
3085 if ( nGLState & DRAW_GL_TEXTURE_2D ) {
3086 qglTexCoord2fv( &w->points[i][3] );
3088 qglVertex3fv( w->points[i] );
3093 #define Q2_SURF_TRANS33 0x00000010
3094 #define Q2_SURF_TRANS66 0x00000020
3096 void Brush_Draw( brush_t *b ){
3099 qtexture_t *prev = 0;
3102 int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;
3103 int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;
3105 GLfloat material[4], identity[4];
3106 VectorSet( identity, 0.8f, 0.8f, 0.8f );
3108 qglPushClientAttrib( GL_CLIENT_VERTEX_ARRAY_BIT );
3109 qglDisableClientState( GL_NORMAL_ARRAY );
3111 // guarantee the texture will be set first
3115 for ( face = b->brush_faces,order = 0 ; face ; face = face->next, order++ )
3117 w = face->face_winding;
3119 continue; // freed face
3122 bTrans = ( face->pShader->getFlags() & QER_TRANS );
3123 transVal = face->pShader->getTrans();
3124 // try to read the texture def surface flags to get trans
3126 if ( face->texdef.flags & Q2_SURF_TRANS33 ) {
3130 else if ( face->texdef.flags & Q2_SURF_TRANS66 ) {
3136 if ( bTrans && !( nGLState & DRAW_GL_BLEND ) ) {
3139 if ( !bTrans && nGLState & DRAW_GL_BLEND ) {
3144 // modifications to the discarding code here should be matched in the selection code
3147 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK ) {
3148 if ( strstr( face->texdef.GetName(), "caulk" ) ) {
3153 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP ) {
3154 if ( strstr( face->texdef.GetName(), "botclip" ) || strstr( face->texdef.GetName(), "clipmonster" ) ) {
3159 if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP ) {
3160 if ( strstr( face->texdef.GetName(), "clip" ) ) {
3165 if ( nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(' ) {
3167 qglDisable( GL_TEXTURE_2D );
3169 else if ( nGLState & DRAW_GL_TEXTURE_2D && ( nDrawMode == cd_texture || nDrawMode == cd_light ) && face->d_texture != prev ) {
3170 // set the texture for this face
3171 prev = face->d_texture;
3172 qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
3175 if ( nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting ) {
3176 if ( !b->owner->eclass->fixedsize ) {
3177 material[3] = transVal;
3182 VectorCopy( face->d_color, material );
3184 if ( nGLState & DRAW_GL_TEXTURE_2D ) {
3185 qglColor4f( face->d_shade, face->d_shade, face->d_shade, material[3] );
3188 qglColor4fv( material );
3191 else if ( !b->owner->eclass->fixedsize ) {
3192 pShader = face->pShader;
3193 VectorCopy( pShader->getTexture()->color, material );
3194 material[3] = identity[3] = transVal;
3196 if ( nGLState & DRAW_GL_TEXTURE_2D ) {
3197 qglColor4fv( identity );
3200 qglColor4fv( material );
3206 Brush_FaceDraw( face, nGLState );
3208 qglPopClientAttrib();
3211 void Face_Draw( face_t *f ){
3214 if ( f->face_winding == 0 ) {
3217 qglBegin( GL_POLYGON );
3218 for ( i = 0 ; i < f->face_winding->numpoints; i++ )
3219 qglVertex3fv( f->face_winding->points[i] );
3223 entity_t *FindEntity( const char *pszKey, const char *pszValue ){
3228 for (; pe != NULL && pe != &entities ; pe = pe->next )
3230 if ( !strcmp( ValueForKey( pe, pszKey ), pszValue ) ) {
3238 void Brush_DrawXY( brush_t *b, int nViewType ){
3244 if ( b->patchBrush ) {
3245 Patch_DrawXY( b->pPatch );
3246 if ( !g_bPatchShowBounds ) {
3251 if ( b->owner->eclass->fixedsize ) {
3252 if ( g_PrefsDlg.m_bNewLightDraw && ( b->owner->eclass->nShowFlags & ECLASS_LIGHT ) ) {
3253 #if 1 // requires vertex arrays enabled
3254 DrawLight( b->owner, DRAW_GL_WIRE, ( IsBrushSelected( b ) ) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType );
3257 float fMid = b->mins[2] + ( b->maxs[2] - b->mins[2] ) / 2;
3259 vCorners[0][0] = b->mins[0];
3260 vCorners[0][1] = b->mins[1];
3261 vCorners[0][2] = fMid;
3263 vCorners[1][0] = b->mins[0];
3264 vCorners[1][1] = b->maxs[1];
3265 vCorners[1][2] = fMid;
3267 vCorners[2][0] = b->maxs[0];
3268 vCorners[2][1] = b->maxs[1];
3269 vCorners[2][2] = fMid;
3271 vCorners[3][0] = b->maxs[0];
3272 vCorners[3][1] = b->mins[1];
3273 vCorners[3][2] = fMid;
3275 vec3_t vTop, vBottom;
3277 vTop[0] = b->mins[0] + ( ( b->maxs[0] - b->mins[0] ) / 2 );
3278 vTop[1] = b->mins[1] + ( ( b->maxs[1] - b->mins[1] ) / 2 );
3279 vTop[2] = b->maxs[2];
3281 VectorCopy( vTop, vBottom );
3282 vBottom[2] = b->mins[2];
3284 qglBegin( GL_LINES );
3285 qglVertex3fv( vTop );
3286 qglVertex3fv( vCorners[0] );
3287 qglVertex3fv( vTop );
3288 qglVertex3fv( vCorners[1] );
3289 qglVertex3fv( vTop );
3290 qglVertex3fv( vCorners[2] );
3291 qglVertex3fv( vTop );
3292 qglVertex3fv( vCorners[3] );
3295 qglBegin( GL_LINES );
3296 qglVertex3fv( vBottom );
3297 qglVertex3fv( vCorners[0] );
3298 qglVertex3fv( vBottom );
3299 qglVertex3fv( vCorners[1] );
3300 qglVertex3fv( vBottom );
3301 qglVertex3fv( vCorners[2] );
3302 qglVertex3fv( vBottom );
3303 qglVertex3fv( vCorners[3] );
3306 qglBegin( GL_LINE_LOOP );
3307 qglVertex3fv( vCorners[0] );
3308 qglVertex3fv( vCorners[1] );
3309 qglVertex3fv( vCorners[2] );
3310 qglVertex3fv( vCorners[3] );
3313 DrawBrushEntityName( b );
3316 else if ( b->owner->model.pRender && !( !IsBrushSelected( b ) && ( g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY ) ) ) {
3317 qglPushAttrib( GL_CURRENT_BIT ); // save brush colour
3318 qglColor3fv( b->owner->eclass->color );
3319 if ( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX ) {
3320 b->owner->model.pRender->Draw( DRAW_GL_WIRE, DRAW_RF_XY );
3322 aabb_draw( b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE );
3329 for ( face = b->brush_faces,order = 0 ; face ; face = face->next, order++ )
3331 // moved so check occurs earlier
3332 w = face->face_winding;
3336 // only draw polygons facing in a direction we care about
3337 if ( nViewType == XY ) {
3338 if ( face->plane.normal[2] <= 0 ) {
3344 if ( nViewType == XZ ) {
3345 if ( face->plane.normal[1] >= 0 ) { // stop axes being mirrored
3351 if ( face->plane.normal[0] <= 0 ) {
3358 qglBegin( GL_LINE_LOOP );
3359 for ( i = 0 ; i < w->numpoints ; i++ )
3360 qglVertex3fv( w->points[i] );
3364 DrawBrushEntityName( b );
3373 void Brush_Move( brush_t *b, const vec3_t move, bool bSnap ){
3377 for ( f = b->brush_faces ; f ; f = f->next )
3378 for ( i = 0 ; i < 3 ; i++ )
3379 VectorAdd( f->planepts[i], move, f->planepts[i] );
3381 if ( g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize ) {
3382 for ( f = b->brush_faces ; f ; f = f->next )
3385 VectorCopy( move, vTemp );
3386 Face_MoveTexture( f, vTemp );
3390 Brush_Build( b, bSnap,true,false,false ); // don't filter
3393 if ( b->patchBrush ) {
3394 //Patch_Move(b->nPatchID, move);
3395 Patch_Move( b->pPatch, move );
3399 // PGM - keep the origin vector up to date on fixed size entities.
3400 if ( b->owner->eclass->fixedsize ) {
3402 VectorAdd( b->owner->origin, move, b->owner->origin );
3403 sprintf( text, "%i %i %i",
3404 (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2] );
3405 SetKeyValue( b->owner, "origin", text );
3406 //VectorAdd(b->maxs, b->mins, b->owner->origin);
3407 //VectorScale(b->owner->origin, 0.5, b->owner->origin);
3413 void Brush_Print( brush_t* b ){
3415 for ( face_t* f = b->brush_faces ; f ; f = f->next )
3417 Sys_Printf( "Face %i\n", nFace++ );
3418 Sys_Printf( "%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2] );
3419 Sys_Printf( "%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2] );
3420 Sys_Printf( "%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2] );
3430 Makes the current brushhave the given number of 2d sides and turns it into a cone
3433 void Brush_MakeSidedCone( int sides ){
3443 if ( sides < 3 || sides > 32 ) {
3444 Sys_Status( "Bad sides number", 0 );
3448 if ( !QE_SingleBrush() ) {
3449 Sys_Status( "Must have a single brush selected", 0 );
3453 b = selected_brushes.next;
3454 VectorCopy( b->mins, mins );
3455 VectorCopy( b->maxs, maxs );
3456 texdef = &g_qeglobals.d_texturewin.texdef;
3460 // find center of brush
3462 for ( i = 0 ; i < 2 ; i++ )
3464 mid[i] = ( maxs[i] + mins[i] ) * 0.5;
3465 if ( maxs[i] - mins[i] > width ) {
3466 width = maxs[i] - mins[i];
3473 // create bottom face
3475 f->texdef = *texdef;
3476 f->next = b->brush_faces;
3479 f->planepts[0][0] = mins[0]; f->planepts[0][1] = mins[1]; f->planepts[0][2] = mins[2];
3480 f->planepts[1][0] = maxs[0]; f->planepts[1][1] = mins[1]; f->planepts[1][2] = mins[2];
3481 f->planepts[2][0] = maxs[0]; f->planepts[2][1] = maxs[1]; f->planepts[2][2] = mins[2];
3483 for ( i = 0 ; i < sides ; i++ )
3486 f->texdef = *texdef;
3487 f->next = b->brush_faces;
3490 sv = sin( i * 3.14159265 * 2 / sides );
3491 cv = cos( i * 3.14159265 * 2 / sides );
3494 f->planepts[0][0] = floor( mid[0] + width * cv + 0.5 );
3495 f->planepts[0][1] = floor( mid[1] + width * sv + 0.5 );
3496 f->planepts[0][2] = mins[2];
3498 f->planepts[1][0] = mid[0];
3499 f->planepts[1][1] = mid[1];
3500 f->planepts[1][2] = maxs[2];
3502 f->planepts[2][0] = floor( f->planepts[0][0] - width * sv + 0.5 );
3503 f->planepts[2][1] = floor( f->planepts[0][1] + width * cv + 0.5 );
3504 f->planepts[2][2] = maxs[2];
3508 Brush_AddToList( b, &selected_brushes );
3510 Entity_LinkBrush( world_entity, b );
3514 Sys_UpdateWindows( W_ALL );
3521 Makes the current brushhave the given number of 2d sides and turns it into a sphere
3525 void Brush_MakeSidedSphere( int sides ){
3533 if ( sides < 4 || sides > 32 ) {
3534 Sys_Status( "Bad sides number", 0 );
3538 if ( !QE_SingleBrush() ) {
3539 Sys_Status( "Must have a single brush selected", 0 );
3543 b = selected_brushes.next;
3544 VectorCopy( b->mins, mins );
3545 VectorCopy( b->maxs, maxs );
3546 texdef = &g_qeglobals.d_texturewin.texdef;
3550 // find center of brush
3552 for ( i = 0 ; i < 2 ; i++ )
3554 mid[i] = ( maxs[i] + mins[i] ) * 0.5;
3555 if ( maxs[i] - mins[i] > radius ) {
3556 radius = maxs[i] - mins[i];
3563 float dt = float(2 * Q_PI / sides);
3564 float dp = float(Q_PI / sides);
3566 for ( i = 0; i <= sides - 1; i++ )
3568 for ( j = 0; j <= sides - 2; j++ )
3571 p = float(j * dp - Q_PI / 2);
3574 f->texdef = *texdef;
3575 f->next = b->brush_faces;
3578 VectorPolar( f->planepts[0], radius, t, p );
3579 VectorPolar( f->planepts[1], radius, t, p + dp );
3580 VectorPolar( f->planepts[2], radius, t + dt, p + dp );
3582 for ( int k = 0; k < 3; k++ )
3583 VectorAdd( f->planepts[k], mid, f->planepts[k] );
3587 p = float( ( sides - 1 ) * dp - Q_PI / 2);
3588 for ( i = 0; i <= sides - 1; i++ )
3593 f->texdef = *texdef;
3594 f->next = b->brush_faces;
3597 VectorPolar( f->planepts[0], radius, t, p );
3598 VectorPolar( f->planepts[1], radius, t + dt, p + dp );
3599 VectorPolar( f->planepts[2], radius, t + dt, p );
3601 for ( int k = 0; k < 3; k++ )
3602 VectorAdd( f->planepts[k], mid, f->planepts[k] );
3605 Brush_AddToList( b, &selected_brushes );
3607 Entity_LinkBrush( world_entity, b );
3611 Sys_UpdateWindows( W_ALL );
3614 void Face_FitTexture( face_t * face, int nHeight, int nWidth ){
3618 float width, height, temp;
3619 float rot_width, rot_height;
3620 float cosv,sinv,ang;
3621 float min_t, min_s, max_t, max_s;
3627 if ( nHeight < 1 ) {
3634 ClearBounds( mins, maxs );
3636 w = face->face_winding;
3640 for ( i = 0 ; i < w->numpoints ; i++ )
3642 AddPointToBounds( w->points[i], mins, maxs );
3645 if ( g_qeglobals.m_bBrushPrimitMode ) {
3646 Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );
3653 // get the current angle
3655 ang = td->rotate / 180 * Q_PI;
3659 // get natural texture axis
3660 TextureAxisFromPlane( &face->plane, vecs[0], vecs[1] );
3662 min_s = DotProduct( mins, vecs[0] );
3663 min_t = DotProduct( mins, vecs[1] );
3664 max_s = DotProduct( maxs, vecs[0] );
3665 max_t = DotProduct( maxs, vecs[1] );
3666 width = max_s - min_s;
3667 height = max_t - min_t;
3668 coords[0][0] = min_s;
3669 coords[0][1] = min_t;
3670 coords[1][0] = max_s;
3671 coords[1][1] = min_t;
3672 coords[2][0] = min_s;
3673 coords[2][1] = max_t;
3674 coords[3][0] = max_s;
3675 coords[3][1] = max_t;
3676 min_s = min_t = 99999;
3677 max_s = max_t = -99999;
3678 for ( i = 0; i < 4; i++ )
3680 s = cosv * coords[i][0] - sinv * coords[i][1];
3681 t = sinv * coords[i][0] + cosv * coords[i][1];
3705 rot_width = ( max_s - min_s );
3706 rot_height = ( max_t - min_t );
3707 td->scale[0] = -( rot_width / ( (float)( face->d_texture->width * nWidth ) ) );
3708 td->scale[1] = -( rot_height / ( (float)( face->d_texture->height * nHeight ) ) );
3710 td->shift[0] = min_s / td->scale[0];
3711 temp = (int)( td->shift[0] / ( face->d_texture->width * nWidth ) );
3712 temp = ( temp + 1 ) * face->d_texture->width * nWidth;
3713 td->shift[0] = (int)( temp - td->shift[0] ) % ( face->d_texture->width * nWidth );
3715 td->shift[1] = min_t / td->scale[1];
3716 temp = (int)( td->shift[1] / ( face->d_texture->height * nHeight ) );
3717 temp = ( temp + 1 ) * ( face->d_texture->height * nHeight );
3718 td->shift[1] = (int)( temp - td->shift[1] ) % ( face->d_texture->height * nHeight );
3720 td->shift[1] = min_t / td->scale[1];
3721 temp = (int)( td->shift[1] / ( face->d_texture->height * nHeight ) );
3722 temp = ( temp + 1 ) * ( face->d_texture->height * nHeight );
3723 td->shift[1] = (int)( temp - td->shift[1] ) % ( face->d_texture->height * nHeight );
3728 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ){
3731 for ( face = b->brush_faces ; face ; face = face->next )
3733 Face_FitTexture( face, nHeight, nWidth );
3737 void aabb_draw( const aabb_t *aabb, int mode ){
3738 vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };
3741 VectorSubtract( aabb->origin, aabb->extents, vMin );
3742 VectorAdd( aabb->origin, aabb->extents, vMax );
3743 VectorSet( points[0], vMin[0], vMax[1], vMax[2] );
3744 VectorSet( points[1], vMax[0], vMax[1], vMax[2] );
3745 VectorSet( points[2], vMax[0], vMin[1], vMax[2] );
3746 VectorSet( points[3], vMin[0], vMin[1], vMax[2] );
3747 VectorSet( points[4], vMin[0], vMax[1], vMin[2] );
3748 VectorSet( points[5], vMax[0], vMax[1], vMin[2] );
3749 VectorSet( points[6], vMax[0], vMin[1], vMin[2] );
3750 VectorSet( points[7], vMin[0], vMin[1], vMin[2] );
3752 qglBegin( GL_QUADS );
3754 qglNormal3fv( normals[0] );
3755 qglVertex3fv( points[2] );
3756 qglVertex3fv( points[1] );
3757 qglVertex3fv( points[5] );
3758 qglVertex3fv( points[6] );
3760 qglNormal3fv( normals[1] );
3761 qglVertex3fv( points[1] );
3762 qglVertex3fv( points[0] );
3763 qglVertex3fv( points[4] );
3764 qglVertex3fv( points[5] );
3766 qglNormal3fv( normals[2] );
3767 qglVertex3fv( points[0] );
3768 qglVertex3fv( points[1] );
3769 qglVertex3fv( points[2] );
3770 qglVertex3fv( points[3] );
3772 qglNormal3fv( normals[3] );
3773 qglVertex3fv( points[3] );
3774 qglVertex3fv( points[7] );
3775 qglVertex3fv( points[4] );
3776 qglVertex3fv( points[0] );
3778 qglNormal3fv( normals[4] );
3779 qglVertex3fv( points[3] );
3780 qglVertex3fv( points[2] );
3781 qglVertex3fv( points[6] );
3782 qglVertex3fv( points[7] );
3784 qglNormal3fv( normals[5] );
3785 qglVertex3fv( points[7] );
3786 qglVertex3fv( points[6] );
3787 qglVertex3fv( points[5] );
3788 qglVertex3fv( points[4] );
3798 VectorSubtract(aabb->origin, aabb->extents, vMin);
3799 VectorAdd(aabb->origin, aabb->extents, vMax);
3800 VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);
3801 VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);
3802 VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);
3803 VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);
3804 VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);
3805 VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);
3806 VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);
3807 VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);
3809 vec3_t Normals[8] = { {-1, 0, 0 },
3818 unsigned short Indices[24] = { 2, 1, 5, 6,
3825 qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays
3826 qglNormalPointer(GL_FLOAT, 0, Normals);
3828 //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array
3830 qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);
3832 //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array
3836 qboolean IsBrushSelected( brush_t* bSel ){
3837 for ( brush_t* b = selected_brushes.next ; b != NULL && b != &selected_brushes; b = b->next )