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)
38 static char cBuff[1024];
39 b->numberId = g_nBrushId++;
40 if (g_qeglobals.m_bBrushPrimitMode)
42 sprintf(cBuff, "Brush %i", b->numberId);
43 Brush_SetEpair(b, "Name", cBuff);
49 brush_t *Brush_Alloc()
51 brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));
55 void Brush_Free(brush_t *b)
60 void PrintWinding (winding_t *w)
64 Sys_Printf ("-------------\n");
65 for (i=0 ; i<w->numpoints ; i++)
66 Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
67 , w->points[i][1], w->points[i][2]);
70 void PrintPlane (plane_t *p)
72 Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
73 p->normal[2], p->dist);
76 void PrintVector (vec3_t v)
78 Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]);
83 =============================================================================
87 =============================================================================
98 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
99 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
100 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
101 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
102 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
103 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
106 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
115 for (i=0 ; i<6 ; i++)
117 dot = DotProduct (pln->normal, baseaxis[i*3]);
118 if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best)
125 VectorCopy (baseaxis[bestaxis*3+1], xv);
126 VectorCopy (baseaxis[bestaxis*3+2], yv);
131 float lightaxis[3] = {0.6f, 0.8f, 1.0f};
136 Light different planes differently to
140 extern float ShadeForNormal(vec3_t normal);
142 float SetShadeForPlane (plane_t *p)
144 //return ShadeForNormal(p->normal);
151 for (i=0 ; i<3 ; i++)
152 if (fabs(p->normal[i]) > 0.9)
158 // between two axial planes
159 for (i=0 ; i<3 ; i++)
160 if (fabs(p->normal[i]) < 0.1)
162 f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
167 f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
180 face_t *Face_Alloc( void )
182 face_t *f = (face_t*)qmalloc( sizeof( *f ) );
191 void Face_Free( face_t *f )
195 if ( f->face_winding )
197 free( f->face_winding );
200 f->texdef.~texdef_t();;
210 face_t *Face_Clone (face_t *f)
215 n->texdef = f->texdef;
216 n->brushprimit_texdef = f->brushprimit_texdef;
218 memcpy (n->planepts, f->planepts, sizeof(n->planepts));
220 // all other fields are derived, and will be set by Brush_Build
221 // FIXME: maybe not, for example n->pData!
229 makes an exact copy of the face
232 face_t *Face_FullClone (face_t *f)
237 n->texdef = f->texdef;
238 n->brushprimit_texdef = f->brushprimit_texdef;
239 memcpy(n->planepts, f->planepts, sizeof(n->planepts));
240 memcpy(&n->plane, &f->plane, sizeof(plane_t));
242 n->face_winding = Winding_Clone(f->face_winding);
244 n->face_winding = NULL;
245 n->pShader = f->pShader;
246 n->pShader->IncRef();
247 n->d_texture = n->pShader->getTexture();
251 void Face_SetShader(face_t *face, const char *name)
253 if(face->pShader != NULL)
254 face->pShader->DecRef();
255 face->texdef.SetName(name);
256 face->pShader = QERApp_Shader_ForName(name);
257 face->pShader->IncRef();
258 face->d_texture = face->pShader->getTexture();
259 face->texdef.flags = face->pShader->getFlags();
262 void Face_SetShader(face_t *face, IShader *shader)
264 if(face->pShader != NULL)
265 face->pShader->DecRef();
266 face->texdef.SetName(shader->getName());
267 face->d_texture = shader->getTexture();
268 face->texdef.flags = shader->getFlags();
269 face->pShader = shader;
270 face->pShader->IncRef();
278 void Clamp(float& f, int nClamp)
280 float fFrac = f - static_cast<int>(f);
281 f = static_cast<int>(f) % nClamp;
290 void Face_MoveTexture(face_t *f, vec3_t delta)
294 if (g_qeglobals.m_bBrushPrimitMode)
295 ShiftTextureGeometric_BrushPrimit( f, delta );
298 TextureAxisFromPlane(&f->plane, vX, vY);
301 vDP[0] = DotProduct(delta, vX);
302 vDP[1] = DotProduct(delta, vY);
304 double fAngle = f->texdef.rotate / 180 * Q_PI;
305 double c = cos(fAngle);
306 double s = sin(fAngle);
308 vShift[0] = vDP[0] * c - vDP[1] * s;
309 vShift[1] = vDP[0] * s + vDP[1] * c;
311 if (!f->texdef.scale[0])
312 f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale;
313 if (!f->texdef.scale[1])
314 f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale;
316 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
317 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
320 Clamp(f->texdef.shift[0], f->d_texture->width);
321 Clamp(f->texdef.shift[1], f->d_texture->height);
330 /*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/
331 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor)
333 // set shading for face
334 f->d_shade = SetShadeForPlane (&f->plane);
335 f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade;
336 f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade;
337 f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade;
345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])
349 float ang, sinv, cosv;
356 // this code is not supposed to be used while in BP mode, warning here can help spot the problem
357 if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)
358 Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
364 memset (STfromXYZ, 0, 8*sizeof(float));
367 td->scale[0] = g_pGameDescription->mTextureDefaultScale;
369 td->scale[1] = g_pGameDescription->mTextureDefaultScale;
371 // get natural texture axis
372 TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
376 { sinv = 0 ; cosv = 1; }
377 else if (td->rotate == 90)
378 { sinv = 1 ; cosv = 0; }
379 else if (td->rotate == 180)
380 { sinv = 0 ; cosv = -1; }
381 else if (td->rotate == 270)
382 { sinv = -1 ; cosv = 0; }
385 ang = td->rotate / 180 * Q_PI;
392 else if (pvecs[0][1])
399 else if (pvecs[1][1])
404 for (i=0 ; i<2 ; i++) {
405 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
406 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
407 STfromXYZ[i][sv] = ns;
408 STfromXYZ[i][tv] = nt;
412 for (i=0 ; i<2 ; i++)
413 for (j=0 ; j<3 ; j++)
414 STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
417 STfromXYZ[0][3] = td->shift[0];
418 STfromXYZ[1][3] = td->shift[1];
420 for (j=0 ; j<4 ; j++) {
421 STfromXYZ[0][j] /= q->width;
422 STfromXYZ[1][j] /= q->height;
426 long double HighestImpactSign (long double a, long double b)
428 // returns the sign of the value with larger abs
435 void Face_TexdefFromTextureVectors (face_t *f, long double STfromXYZ[2][4], vec3_t pvecs[2], int sv, int tv)
445 // undo the texture transform
446 for (j=0 ; j<4 ; j++) {
447 STfromXYZ[0][j] *= q->width;
448 STfromXYZ[1][j] *= q->height;
452 td->shift[0] = STfromXYZ[0][3];
453 td->shift[1] = STfromXYZ[1][3];
457 * STfromXYZ[0][sv] = (cosv * pvecs[0][sv] - sinv * pvecs[0][tv]) / td->scale[0];
458 * STfromXYZ[0][tv] = (sinv * pvecs[0][sv] + cosv * pvecs[0][tv]) / td->scale[0];
459 * STfromXYZ[1][sv] = (cosv * pvecs[1][sv] - sinv * pvecs[1][tv]) / td->scale[1];
460 * STfromXYZ[1][tv] = (sinv * pvecs[1][sv] + cosv * pvecs[1][tv]) / td->scale[1];
462 * sinv, cosv, td->scale[0], td->scale[1]
464 * sinv^2 + cosv^2 = 1
465 * pvecs[0][sv] is +/-1
468 * pvecs[1][tv] is +/-1
470 * STfromXYZ[0][sv] = +cosv * pvecs[0][sv] / td->scale[0];
471 * STfromXYZ[0][tv] = +sinv * pvecs[0][sv] / td->scale[0];
472 * STfromXYZ[1][sv] = -sinv * pvecs[1][tv] / td->scale[1];
473 * STfromXYZ[1][tv] = +cosv * pvecs[1][tv] / td->scale[1];
476 td->scale[0] = sqrt(STfromXYZ[0][sv]*STfromXYZ[0][sv] + STfromXYZ[0][tv]*STfromXYZ[0][tv]);
477 td->scale[1] = sqrt(STfromXYZ[1][sv]*STfromXYZ[1][sv] + STfromXYZ[1][tv]*STfromXYZ[1][tv]);
480 td->scale[0] = 1 / td->scale[0]; // avoid NaNs
482 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)
524 // convert to a vector / dist plane
525 for (j=0 ; j<3 ; j++)
527 t1[j] = f->planepts[0][j] - f->planepts[1][j];
528 t2[j] = f->planepts[2][j] - f->planepts[1][j];
529 t3[j] = f->planepts[1][j];
532 CrossProduct(t1,t2, f->plane.normal);
533 if (VectorCompare (f->plane.normal, vec3_origin))
534 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)
546 float STfromXYZ[2][4];
548 Face_TextureVectors (f, STfromXYZ);
549 xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
550 xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
553 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)
555 return a1 * b2 * c3 + a2 * b3 * c1 + a3 * b1 * c2
556 - a1 * c2 * b3 - a2 * c3 * b1 - a3 * c1 * b2;
559 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)
562 det = SarrusDetScalar(a1, b1, c1,
565 *a = SarrusDetScalar(d1, b1, c1,
568 *b = SarrusDetScalar(a1, d1, c1,
571 *c = SarrusDetScalar(a1, b1, d1,
576 void Face_TexdefFromTextureCoordinates ( float *xyzst1, float *xyzst2, float *xyzst3, qtexture_t *q, face_t *f)
581 long double STfromXYZ[2][4];
583 // get natural texture axis
584 TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
588 else if (pvecs[0][1])
595 else if (pvecs[1][1])
600 uv = 3 - sv - tv; // the "other one"
602 // find the STfromXYZ 4-vectors
605 xyzst1[3] == xyzst1[sv] * STfromXYZ[0][sv] + xyzst1[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
606 xyzst2[3] == xyzst2[sv] * STfromXYZ[0][sv] + xyzst2[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
607 xyzst3[3] == xyzst3[sv] * STfromXYZ[0][sv] + xyzst3[tv] * STfromXYZ[0][tv] + STfromXYZ[0][3];
609 GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
611 xyzst1[4] == xyzst1[sv] * STfromXYZ[1][sv] + xyzst1[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
612 xyzst2[4] == xyzst2[sv] * STfromXYZ[1][sv] + xyzst2[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
613 xyzst3[4] == xyzst3[sv] * STfromXYZ[1][sv] + xyzst3[tv] * STfromXYZ[1][tv] + STfromXYZ[1][3];
615 GIVEN: one coord of them (uv) is empty (see Face_TextureVectors)
618 STfromXYZ[0][uv] = 0;
620 xyzst1[sv], xyzst1[tv], 1, xyzst1[3],
621 xyzst2[sv], xyzst2[tv], 1, xyzst2[3],
622 xyzst3[sv], xyzst3[tv], 1, xyzst3[3],
623 &STfromXYZ[0][sv], &STfromXYZ[0][tv], &STfromXYZ[0][3]
626 STfromXYZ[1][uv] = 0;
628 xyzst1[sv], xyzst1[tv], 1, xyzst1[4],
629 xyzst2[sv], xyzst2[tv], 1, xyzst2[4],
630 xyzst3[sv], xyzst3[tv], 1, xyzst3[4],
631 &STfromXYZ[1][sv], &STfromXYZ[1][tv], &STfromXYZ[1][3]
635 printf("%s\n", q->name);
637 printf("%f == %Lf\n", xyzst1[3], DotProduct (xyzst1, STfromXYZ[0]) + STfromXYZ[0][3]);
638 printf("%f == %Lf\n", xyzst2[3], DotProduct (xyzst2, STfromXYZ[0]) + STfromXYZ[0][3]);
639 printf("%f == %Lf\n", xyzst3[3], DotProduct (xyzst3, STfromXYZ[0]) + STfromXYZ[0][3]);
640 printf("%f == %Lf\n", xyzst1[4], DotProduct (xyzst1, STfromXYZ[1]) + STfromXYZ[1][3]);
641 printf("%f == %Lf\n", xyzst2[4], DotProduct (xyzst2, STfromXYZ[1]) + STfromXYZ[1][3]);
642 printf("%f == %Lf\n", xyzst3[4], DotProduct (xyzst3, STfromXYZ[1]) + STfromXYZ[1][3]);
644 float newSTfromXYZ[2][4];
646 printf("old: %Lf,%Lf,%Lf,%Lf %Lf,%Lf,%Lf,%Lf\n",
647 STfromXYZ[0][0], STfromXYZ[0][1], STfromXYZ[0][2], STfromXYZ[0][3],
648 STfromXYZ[1][0], STfromXYZ[1][1], STfromXYZ[1][2], STfromXYZ[1][3]);
651 Face_TexdefFromTextureVectors (f, STfromXYZ, pvecs, sv, tv);
654 Face_TextureVectors(f, newSTfromXYZ);
656 printf("new: %f,%f,%f,%f %f,%f,%f,%f\n",
657 newSTfromXYZ[0][0], newSTfromXYZ[0][1], newSTfromXYZ[0][2], newSTfromXYZ[0][3],
658 newSTfromXYZ[1][0], newSTfromXYZ[1][1], newSTfromXYZ[1][2], newSTfromXYZ[1][3]);
663 VectorCopy(xyzst1, newxyzst1);
664 VectorCopy(xyzst2, newxyzst2);
665 VectorCopy(xyzst3, newxyzst3);
666 EmitTextureCoordinates (newxyzst1, q, f);
667 EmitTextureCoordinates (newxyzst2, q, f);
668 EmitTextureCoordinates (newxyzst3, q, f);
669 printf("Face_TexdefFromTextureCoordinates: %f,%f %f,%f %f,%f -> %f,%f %f,%f %f,%f\n",
670 xyzst1[3], xyzst1[4],
671 xyzst2[3], xyzst2[4],
672 xyzst3[3], xyzst3[4],
673 newxyzst1[3], newxyzst1[4],
674 newxyzst2[3], newxyzst2[4],
675 newxyzst3[3], newxyzst3[4]);
676 // TODO why do these differ, but not the previous ones? this makes no sense whatsoever
682 //==========================================================================
689 void Brush_MakeFacePlanes (brush_t *b)
693 for (f=b->brush_faces ; f ; f=f->next)
704 void DrawBrushEntityName (brush_t *b)
712 return; // during contruction
714 if (b->owner == world_entity)
717 if (b != b->owner->brushes.onext)
718 return; // not key brush
720 // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views
721 // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?
722 // Brush_DrawFacingAngle() works when called, but is not being called.
723 if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))
725 // draw the angle pointer
726 a = FloatForKey (b->owner, "angle");
727 s = sin (a/180*Q_PI);
728 c = cos (a/180*Q_PI);
729 for (i=0 ; i<3 ; i++)
730 mid[i] = (b->mins[i] + b->maxs[i])*0.5;
732 qglBegin (GL_LINE_STRIP);
762 if (g_qeglobals.d_savedinfo.show_names)
764 name = ValueForKey (b->owner, "classname");
765 qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
766 gtk_glwidget_print_string(name);
772 Brush_MakeFaceWinding
774 returns the visible polygon on a face
777 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)
796 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
797 && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
798 { // identical plane, use the later one
807 // flip the plane, because we want to keep the back side
808 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
809 plane.dist = -clip->plane.dist;
811 w = Winding_Clip (w, &plane, false);
816 if (w->numpoints < 3)
823 Sys_FPrintf (SYS_WRN, "unused plane\n");
833 void Brush_SnapPlanepts (brush_t *b)
838 if (g_PrefsDlg.m_bNoClamp)
841 if (g_qeglobals.d_bSmallGrid)
843 for (f=b->brush_faces ; f; f=f->next)
844 for (i=0 ; i<3 ; i++)
845 for (j=0 ; j<3 ; j++)
846 f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize;
850 for (f=b->brush_faces ; f; f=f->next)
851 for (i=0 ; i<3 ; i++)
852 for (j=0 ; j<3 ; j++)
853 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
860 ** Builds a brush rendering data and also sets the min/max bounds
863 // added a bConvert flag to convert between old and new brush texture formats
865 // brush grouping: update the group treeview if necessary
866 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest)
872 if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
873 Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
876 // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
877 if (bConvert && !g_qeglobals.bNeedConvert)
880 //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes
881 // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.
883 bLocalConvert = true;
884 g_qeglobals.bNeedConvert = true;
887 bLocalConvert = false;
890 ** build the windings and generate the bounding box
892 Brush_BuildWindings(b, bSnap);
894 if(b->owner->model.pRender)
896 const aabb_t *aabb = b->owner->model.pRender->GetAABB();
897 VectorAdd(aabb->origin, aabb->extents, b->maxs);
898 VectorSubtract(aabb->origin, aabb->extents, b->mins);
901 //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !
904 ** move the points and edges if in select mode
906 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
907 SetupVertexSelection ();
909 if (b->itemOwner == 0) //NULL)
910 Group_AddToProperGroup(b);
914 Sys_MarkMapModified();
918 g_qeglobals.bNeedConvert = false;
920 // spog - applying filters to brush during brush_build instead of during redraw
922 b->bFiltered = FilterBrush( b );
927 Brush_SplitBrushByFace
929 The incoming brush is NOT freed.
930 The incoming face is NOT left referenced.
933 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk)
939 b = Brush_Clone (in);
942 nf->texdef = b->brush_faces->texdef;
945 nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
947 nf->next = b->brush_faces;
951 Brush_RemoveEmptyFaces ( b );
952 if ( !b->brush_faces )
953 { // completely clipped away
959 Entity_LinkBrush (in->owner, b);
963 b = Brush_Clone (in);
965 // swap the plane winding
966 VectorCopy (nf->planepts[0], temp);
967 VectorCopy (nf->planepts[1], nf->planepts[0]);
968 VectorCopy (temp, nf->planepts[1]);
970 nf->texdef = b->brush_faces->texdef;
973 nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
975 nf->next = b->brush_faces;
979 Brush_RemoveEmptyFaces ( b );
980 if ( !b->brush_faces )
981 { // completely clipped away
987 Entity_LinkBrush (in->owner, b);
996 returns the best face to split the brush with.
997 return NULL if the brush is convex
1000 face_t *Brush_BestSplitFace(brush_t *b)
1002 face_t *face, *f, *bestface;
1003 winding_t *front, *back;
1004 int splits, tinywindings, value, bestvalue;
1008 for (face = b->brush_faces; face; face = face->next)
1012 for (f = b->brush_faces; f; f = f->next)
1014 if (f == face) continue;
1016 Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back);
1024 Winding_Free(front);
1029 if (Winding_IsTiny(front)) tinywindings++;
1030 if (Winding_IsTiny(back)) tinywindings++;
1035 value = splits + 50 * tinywindings;
1036 if (value < bestvalue)
1048 Brush_MakeConvexBrushes
1050 MrE FIXME: this doesn't work because the old
1051 Brush_SplitBrushByFace is used
1052 Turns the brush into a minimal number of convex brushes.
1053 If the input brush is convex then it will be returned.
1054 Otherwise the input brush will be freed.
1055 NOTE: the input brush should have windings for the faces.
1058 brush_t *Brush_MakeConvexBrushes(brush_t *b)
1060 brush_t *front, *back, *end;
1064 face = Brush_BestSplitFace(b);
1065 if (!face) return b;
1066 Brush_SplitBrushByFace(b, face, &front, &back);
1067 //this should never happen
1068 if (!front && !back) return b;
1071 return Brush_MakeConvexBrushes(back);
1072 b = Brush_MakeConvexBrushes(front);
1075 for (end = b; end->next; end = end->next);
1076 end->next = Brush_MakeConvexBrushes(back);
1086 int Brush_Convex(brush_t *b)
1088 face_t *face1, *face2;
1090 for (face1 = b->brush_faces; face1; face1 = face1->next)
1092 if (!face1->face_winding) continue;
1093 for (face2 = b->brush_faces; face2; face2 = face2->next)
1095 if (face1 == face2) continue;
1096 if (!face2->face_winding) continue;
1097 if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
1098 face1->plane.normal, face2->plane.normal,
1099 face1->plane.dist, face2->plane.dist))
1112 - The input brush must be convex
1113 - The input brush must have face windings.
1114 - The output brush will be convex.
1115 - Returns true if the WHOLE vertex movement is performed.
1119 // define this to debug the vertex editing mode
1124 #define MAX_MOVE_FACES 64
1126 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
1128 face_t *f, *face, *newface, *lastface, *nextface;
1129 face_t *movefaces[MAX_MOVE_FACES];
1130 int movefacepoints[MAX_MOVE_FACES];
1134 int i, j, k, nummovefaces, result, done;
1135 float dot, front, back, frac, smallestfrac;
1138 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" );
1145 VectorCopy(vertex, start);
1146 VectorAdd(vertex, delta, end);
1149 for (i = 0; i < 3; i++)
1150 end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize;
1152 VectorCopy(end, mid);
1153 //if the start and end are the same
1154 if (Point_Equal(start, end, 0.3f)) return false;
1155 //the end point may not be the same as another vertex
1156 for (face = b->brush_faces; face; face = face->next)
1158 w = face->face_winding;
1160 for (i = 0; i < w->numpoints; i++)
1162 if (Point_Equal(w->points[i], end, 0.3f))
1164 VectorCopy(vertex, end);
1173 //chop off triangles from all brush faces that use the to be moved vertex
1174 //store pointers to these chopped off triangles in movefaces[]
1176 for (face = b->brush_faces; face; face = face->next)
1178 w = face->face_winding;
1180 for (i = 0; i < w->numpoints; i++)
1182 if (Point_Equal(w->points[i], start, 0.2f))
1184 if (face->face_winding->numpoints <= 3)
1186 movefacepoints[nummovefaces] = i;
1187 movefaces[nummovefaces++] = face;
1190 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
1191 //if the end point is in front of the face plane
1194 //fanout triangle subdivision
1195 for (k = i; k < i + w->numpoints-3; k++)
1197 VectorCopy(w->points[i], tmpw.points[0]);
1198 VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
1199 VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
1201 newface = Face_Clone(face);
1203 for (f = face; f->original; f = f->original) ;
1204 newface->original = f;
1205 //store the new winding
1206 if (newface->face_winding) Winding_Free(newface->face_winding);
1207 newface->face_winding = Winding_Clone(&tmpw);
1208 //get the texture information
1209 newface->pShader = face->pShader;
1210 newface->d_texture = face->d_texture;
1212 //add the face to the brush
1213 newface->next = b->brush_faces;
1214 b->brush_faces = newface;
1215 //add this new triangle to the move faces
1216 movefacepoints[nummovefaces] = 0;
1217 movefaces[nummovefaces++] = newface;
1219 //give the original face a new winding
1220 VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
1221 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
1222 VectorCopy(w->points[i], tmpw.points[2]);
1223 Winding_Free(face->face_winding);
1224 face->face_winding = Winding_Clone(&tmpw);
1225 //add the original face to the move faces
1226 movefacepoints[nummovefaces] = 2;
1227 movefaces[nummovefaces++] = face;
1231 //chop a triangle off the face
1232 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
1233 VectorCopy(w->points[i], tmpw.points[1]);
1234 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
1235 //remove the point from the face winding
1236 Winding_RemovePoint(w, i);
1237 //get texture crap right
1238 Face_SetColor(b, face, 1.0);
1239 for (j = 0; j < w->numpoints; j++)
1240 EmitTextureCoordinates(w->points[j], face->d_texture, face);
1241 //make a triangle face
1242 newface = Face_Clone(face);
1244 for (f = face; f->original; f = f->original) ;
1245 newface->original = f;
1246 //store the new winding
1247 if (newface->face_winding) Winding_Free(newface->face_winding);
1248 newface->face_winding = Winding_Clone(&tmpw);
1250 newface->pShader = face->pShader;
1251 newface->d_texture = newface->pShader->getTexture();
1252 // newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );
1253 //add the face to the brush
1254 newface->next = b->brush_faces;
1255 b->brush_faces = newface;
1257 movefacepoints[nummovefaces] = 1;
1258 movefaces[nummovefaces++] = newface;
1264 //now movefaces contains pointers to triangle faces that
1265 //contain the to be moved vertex
1268 VectorCopy(end, mid);
1270 for (face = b->brush_faces; face; face = face->next)
1272 //check if there is a move face that has this face as the original
1273 for (i = 0; i < nummovefaces; i++)
1275 if (movefaces[i]->original == face) break;
1277 if (i >= nummovefaces) continue;
1278 //check if the original is not a move face itself
1279 for (j = 0; j < nummovefaces; j++)
1281 if (face == movefaces[j]) break;
1283 //if the original is not a move face itself
1284 if (j >= nummovefaces)
1286 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));
1290 k = movefacepoints[j];
1291 w = movefaces[j]->face_winding;
1292 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);
1293 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);
1295 k = movefacepoints[i];
1296 w = movefaces[i]->face_winding;
1297 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);
1298 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
1300 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);
1301 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
1302 //this should never happen otherwise the face merge did a crappy job a previous pass
1306 //now we've got the plane to check agains
1307 front = DotProduct(start, plane.normal) - plane.dist;
1308 back = DotProduct(end, plane.normal) - plane.dist;
1309 //if the whole move is at one side of the plane
1310 if (front < 0.01 && back < 0.01) continue;
1311 if (front > -0.01 && back > -0.01) continue;
1312 //if there's no movement orthogonal to this plane at all
1313 if (fabs(front-back) < 0.001) continue;
1314 //ok first only move till the plane is hit
1315 frac = front/(front-back);
1316 if (frac < smallestfrac)
1318 mid[0] = start[0] + (end[0] - start[0]) * frac;
1319 mid[1] = start[1] + (end[1] - start[1]) * frac;
1320 mid[2] = start[2] + (end[2] - start[2]) * frac;
1321 smallestfrac = frac;
1328 for (i = 0; i < nummovefaces; i++)
1330 //move vertex to end position
1331 VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);
1332 //create new face plane
1333 for (j = 0; j < 3; j++)
1335 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
1337 Face_MakePlane(movefaces[i]);
1338 if (VectorLength(movefaces[i]->plane.normal) < 0.1)
1341 //if the brush is no longer convex
1342 if (!result || !Brush_Convex(b))
1344 for (i = 0; i < nummovefaces; i++)
1346 //move the vertex back to the initial position
1347 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);
1348 //create new face plane
1349 for (j = 0; j < 3; j++)
1351 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
1353 Face_MakePlane(movefaces[i]);
1356 VectorCopy(start, end);
1361 VectorCopy(mid, start);
1363 //get texture crap right
1364 for (i = 0; i < nummovefaces; i++)
1366 Face_SetColor(b, movefaces[i], 1.0);
1367 for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
1368 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
1371 //now try to merge faces with their original faces
1373 for (face = b->brush_faces; face; face = nextface)
1375 nextface = face->next;
1376 if (!face->original)
1381 if (!Plane_Equal(&face->plane, &face->original->plane, false))
1386 w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
1392 Winding_Free(face->original->face_winding);
1393 face->original->face_winding = w;
1394 //get texture crap right
1395 Face_SetColor(b, face->original, 1.0);
1396 for (j = 0; j < face->original->face_winding->numpoints; j++)
1397 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
1398 //remove the face that was merged with the original
1399 if (lastface) lastface->next = face->next;
1400 else b->brush_faces = face->next;
1409 Brush_InsertVertexBetween
1412 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)
1415 winding_t *w, *neww;
1419 if (Point_Equal(p1, p2, 0.4f))
1421 VectorAdd(p1, p2, point);
1422 VectorScale(point, 0.5f, point);
1424 //the end point may not be the same as another vertex
1425 for (face = b->brush_faces; face; face = face->next)
1427 w = face->face_winding;
1430 for (i = 0; i < w->numpoints; i++)
1432 if (!Point_Equal(w->points[i], p1, 0.1f))
1434 if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f))
1436 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);
1439 else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f))
1441 neww = Winding_InsertPoint(w, point, i);
1447 Winding_Free(face->face_winding);
1448 face->face_winding = neww;
1458 Brush_ResetFaceOriginals
1461 void Brush_ResetFaceOriginals(brush_t *b)
1465 for (face = b->brush_faces; face; face = face->next)
1467 face->original = NULL;
1471 #ifdef ENABLE_GROUPS
1475 sets an epair for the given brush
1478 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)
1480 if (g_qeglobals.m_bBrushPrimitMode)
1484 Patch_SetEpair(b->pPatch, pKey, pValue);
1488 SetKeyValue(b->epairs, pKey, pValue);
1493 Sys_Printf("Can only set key/values in Brush primitive mode\n");
1502 const char* Brush_GetKeyValue(brush_t *b, const char *pKey)
1504 if (g_qeglobals.m_bBrushPrimitMode)
1508 return Patch_GetKeyValue(b->pPatch, pKey);
1512 return ValueForKey(b->epairs, pKey);
1517 Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");
1525 temporary stuff, detect potential problems when saving the texture name
1528 void CheckName( face_t *fa, char *pname )
1530 if (!strlen(fa->texdef.GetName()))
1533 Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n");
1535 fa->texdef.SetName(SHADER_NOT_FOUND);
1536 strcpy(pname, SHADER_NOT_FOUND);
1540 // some people manage to get long filename textures (with spaces) in their maps
1541 if (strchr( fa->texdef.GetName(), ' ' ))
1545 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() );
1547 Sys_Printf("%s\n", Msg1 );
1548 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
1549 strcpy( pname, SHADER_NOT_FOUND );
1553 //++timo FIXME: bug #103494 detection attempt
1554 // TODO: clean this detection part when bug will have disappeared
1555 if (fa->texdef.GetName()[0] == '(')
1557 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.";
1558 Sys_Printf("%s\n", text);
1559 gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );
1560 // need to cleanup this dead face name or we may loop endlessly
1561 fa->texdef.SetName(SHADER_NOT_FOUND);
1562 strcpy( pname, SHADER_NOT_FOUND );
1565 strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/"
1572 Create non-textured blocks for entities
1573 The brush is NOT linked to any list
1576 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
1584 // brush primitive mode : convert texdef to brushprimit_texdef ?
1585 // most of the time texdef is empty
1586 if (g_qeglobals.m_bBrushPrimitMode)
1588 // check texdef is empty .. if there are cases it's not we need to write some conversion code
1589 if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)
1590 Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");
1594 for (i=0 ; i<3 ; i++)
1596 if (maxs[i] < mins[i])
1597 Error ("Brush_InitSolid: backwards");
1602 pts[0][0][0] = mins[0];
1603 pts[0][0][1] = mins[1];
1605 pts[1][0][0] = mins[0];
1606 pts[1][0][1] = maxs[1];
1608 pts[2][0][0] = maxs[0];
1609 pts[2][0][1] = maxs[1];
1611 pts[3][0][0] = maxs[0];
1612 pts[3][0][1] = mins[1];
1614 for (i=0 ; i<4 ; i++)
1616 pts[i][0][2] = mins[2];
1617 pts[i][1][0] = pts[i][0][0];
1618 pts[i][1][1] = pts[i][0][1];
1619 pts[i][1][2] = maxs[2];
1622 for (i=0 ; i<4 ; i++)
1625 f->texdef = *texdef;
1626 f->texdef.flags &= ~SURF_KEEP;
1627 f->texdef.contents &= ~CONTENTS_KEEP;
1628 f->next = b->brush_faces;
1632 VectorCopy (pts[j][1], f->planepts[0]);
1633 VectorCopy (pts[i][1], f->planepts[1]);
1634 VectorCopy (pts[i][0], f->planepts[2]);
1638 f->texdef = *texdef;
1639 f->texdef.flags &= ~SURF_KEEP;
1640 f->texdef.contents &= ~CONTENTS_KEEP;
1641 f->next = b->brush_faces;
1644 VectorCopy (pts[0][1], f->planepts[0]);
1645 VectorCopy (pts[1][1], f->planepts[1]);
1646 VectorCopy (pts[2][1], f->planepts[2]);
1649 f->texdef = *texdef;
1650 f->texdef.flags &= ~SURF_KEEP;
1651 f->texdef.contents &= ~CONTENTS_KEEP;
1652 f->next = b->brush_faces;
1655 VectorCopy (pts[2][0], f->planepts[0]);
1656 VectorCopy (pts[1][0], f->planepts[1]);
1657 VectorCopy (pts[0][0], f->planepts[2]);
1666 Create non-textured pyramid for light entities
1667 The brush is NOT linked to any list
1670 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)
1674 //++timo handle new brush primitive ? return here ??
1675 return Brush_Create(mins, maxs, texdef);
1677 for (i=0 ; i<3 ; i++)
1678 if (maxs[i] < mins[i])
1679 Error ("Brush_InitSolid: backwards");
1681 brush_t* b = Brush_Alloc();
1685 float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2)));
1687 corners[0][0] = mins[0];
1688 corners[0][1] = mins[1];
1689 corners[0][2] = fMid;
1691 corners[1][0] = mins[0];
1692 corners[1][1] = maxs[1];
1693 corners[1][2] = fMid;
1695 corners[2][0] = maxs[0];
1696 corners[2][1] = maxs[1];
1697 corners[2][2] = fMid;
1699 corners[3][0] = maxs[0];
1700 corners[3][1] = mins[1];
1701 corners[3][2] = fMid;
1705 top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2));
1706 top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2));
1707 top[2] = Rad_rint(maxs[2]);
1709 VectorCopy(top, bottom);
1710 bottom[2] = mins[2];
1713 for (i = 0; i < 4; i++)
1715 face_t* f = Face_Alloc();
1716 f->texdef = *texdef;
1717 f->texdef.flags &= ~SURF_KEEP;
1718 f->texdef.contents &= ~CONTENTS_KEEP;
1719 f->next = b->brush_faces;
1723 VectorCopy (top, f->planepts[0]);
1724 VectorCopy (corners[i], f->planepts[1]);
1725 VectorCopy(corners[j], f->planepts[2]);
1728 f->texdef = *texdef;
1729 f->texdef.flags &= ~SURF_KEEP;
1730 f->texdef.contents &= ~CONTENTS_KEEP;
1731 f->next = b->brush_faces;
1734 VectorCopy (bottom, f->planepts[2]);
1735 VectorCopy (corners[i], f->planepts[1]);
1736 VectorCopy(corners[j], f->planepts[0]);
1749 Makes the current brush have the given number of 2d sides
1752 void Brush_MakeSided (int sides)
1765 Sys_Status ("Bad sides number", 0);
1769 if (sides >= MAX_POINTS_ON_WINDING-4)
1771 Sys_Printf("too many sides.\n");
1775 if (!QE_SingleBrush ())
1777 Sys_Status ("Must have a single brush selected", 0 );
1781 b = selected_brushes.next;
1782 VectorCopy (b->mins, mins);
1783 VectorCopy (b->maxs, maxs);
1784 texdef = &g_qeglobals.d_texturewin.texdef;
1788 if (g_pParentWnd->ActiveXY())
1790 switch(g_pParentWnd->ActiveXY()->GetViewType())
1792 case XY: axis = 2; break;
1793 case XZ: axis = 1; break;
1794 case YZ: axis = 0; break;
1802 // find center of brush
1804 for (i = 0; i < 3; i++)
1806 mid[i] = (maxs[i] + mins[i]) * 0.5;
1807 if (i == axis) continue;
1808 if ((maxs[i] - mins[i]) * 0.5 > width)
1809 width = (maxs[i] - mins[i]) * 0.5;
1816 f->texdef = *texdef;
1817 f->next = b->brush_faces;
1820 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];
1821 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];
1822 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];
1824 // create bottom face
1826 f->texdef = *texdef;
1827 f->next = b->brush_faces;
1830 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];
1831 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];
1832 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];
1834 for (i=0 ; i<sides ; i++)
1837 f->texdef = *texdef;
1838 f->next = b->brush_faces;
1841 sv = sin (i*3.14159265*2/sides);
1842 cv = cos (i*3.14159265*2/sides);
1844 f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);
1845 f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);
1846 f->planepts[0][axis] = mins[axis];
1848 f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];
1849 f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];
1850 f->planepts[1][axis] = maxs[axis];
1852 f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);
1853 f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);
1854 f->planepts[2][axis] = maxs[axis];
1857 Brush_AddToList (b, &selected_brushes);
1859 Entity_LinkBrush (world_entity, b);
1863 Sys_UpdateWindows (W_ALL);
1872 Frees the brush with all of its faces and display list.
1873 Unlinks the brush from whichever chain it is in.
1874 Decrements the owner entity's brushcount.
1875 Removes owner entity if this was the last brush
1876 unless owner is the world.
1880 void Brush_Free (brush_t *b, bool bRemoveNode)
1883 epair_t *ep, *enext;
1885 // remove from group
1887 Group_RemoveBrush(b);
1889 // free the patch if it's there
1892 Patch_Delete(b->pPatch);
1896 for (f=b->brush_faces ; f ; f=next)
1902 // TTimo : free brush epairs
1903 for (ep = b->epairs ; ep ; ep=enext )
1911 // unlink from active/selected list
1913 Brush_RemoveFromList (b);
1915 // unlink from entity list
1917 Entity_UnlinkBrush (b);
1927 int Face_MemorySize(face_t *f )
1931 if (f->face_winding)
1933 // size += _msize(f->face_winding);
1934 size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int);
1936 // size += _msize(f);
1937 size += sizeof(face_t);
1946 int Brush_MemorySize(brush_t *b)
1955 size += Patch_MemorySize(b->pPatch);
1958 for (f = b->brush_faces; f; f = f->next)
1960 size += Face_MemorySize(f);
1963 for (ep = b->epairs; ep; ep = ep->next )
1965 // size += _msize(ep->key);
1966 size += strlen(ep->key);
1967 // size += _msize(ep->value);
1968 size += strlen(ep->value);
1969 // size += _msize(ep);
1970 size += sizeof(epair_t);
1972 // size += _msize(b);
1973 size += sizeof(brush_t);
1982 Does NOT add the new brush to any lists
1985 brush_t *Brush_Clone (brush_t *b)
1992 patchMesh_t *p = Patch_Duplicate(b->pPatch);
1993 Brush_RemoveFromList(p->pSymbiot);
1994 Entity_UnlinkBrush(p->pSymbiot);
2000 n->numberId = g_nBrushId++;
2001 n->owner = b->owner;
2002 for (f=b->brush_faces ; f ; f=f->next)
2004 nf = Face_Clone( f );
2005 nf->next = n->brush_faces;
2006 n->brush_faces = nf;
2017 Does NOT add the new brush to any lists
2020 brush_t *Brush_FullClone(brush_t *b)
2023 face_t *f, *nf, *f2, *nf2;
2028 patchMesh_t *p = Patch_Duplicate(b->pPatch);
2029 Brush_RemoveFromList(p->pSymbiot);
2030 Entity_UnlinkBrush(p->pSymbiot);
2032 n->owner = b->owner;
2038 n->numberId = g_nBrushId++;
2039 n->owner = b->owner;
2040 VectorCopy(b->mins, n->mins);
2041 VectorCopy(b->maxs, n->maxs);
2043 for (f = b->brush_faces; f; f = f->next)
2045 if (f->original) continue;
2046 nf = Face_FullClone(f);
2047 nf->next = n->brush_faces;
2048 n->brush_faces = nf;
2049 //copy all faces that have the original set to this face
2050 for (f2 = b->brush_faces; f2; f2 = f2->next)
2052 if (f2->original == f)
2054 nf2 = Face_FullClone(f2);
2055 nf2->next = n->brush_faces;
2056 n->brush_faces = nf2;
2062 for (nf = n->brush_faces; nf; nf = nf->next)
2064 Face_SetColor(n, nf, 1.0);
2065 if (nf->face_winding)
2067 if (g_qeglobals.m_bBrushPrimitMode)
2068 EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);
2071 for (j = 0; j < nf->face_winding->numpoints; j++)
2072 EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);
2080 // FIXME - spog - finish this later..
2082 bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)
2085 vec3_t v1, v2, normal[3];
2088 //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);
2089 //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);
2090 //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);
2091 //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);
2093 // test ray against triangle
2094 // get triangle plane normal
2095 //VectorSubtract(p1, p2, v1);
2096 //VectorSubtract(p1, p3, v2);
2097 //CrossProduct(v1, v2, v1);
2098 // check normal against direction
2099 //if (DotProduct(dir, v1) >= 0)
2101 // generate cone normals
2102 VectorSubtract(origin, p1, v1);
2103 VectorSubtract(origin, p2, v2);
2104 CrossProduct(v1, v2, normal[0]);
2105 VectorSubtract(origin, p2, v1);
2106 VectorSubtract(origin, p3, v2);
2107 CrossProduct(v1, v2, normal[1]);
2108 VectorSubtract(origin, p3, v1);
2109 VectorSubtract(origin, p1, v2);
2110 CrossProduct(v1, v2, normal[2]);
2114 // flip normals if triangle faces away
2115 // Sys_Printf("flipped\n");
2116 // VectorSubtract(origin, p1, v1);
2117 // VectorSubtract(origin, p3, v2);
2118 // CrossProduct(v1, v2, normal[0]);
2119 // VectorSubtract(origin, p3, v1);
2120 // VectorSubtract(origin, p2, v2);
2121 // CrossProduct(v1, v2, normal[1]);
2122 // VectorSubtract(origin, p2, v1);
2123 // VectorSubtract(origin, p1, v2);
2124 // CrossProduct(v1, v2, normal[2]);
2129 VectorNormalize(normal[i]);
2130 //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);
2131 //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);
2132 d = DotProduct(dir, normal[i]);
2133 //Sys_Printf("dotproduct: %f\n",d);
2142 extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
2143 float vert0[3], float vert1[3], float vert2[3],
2144 double *t, double *u, double *v);
2146 bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
2148 bool bIntersect = false;
2149 float tBest = FLT_MAX;
2154 float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set
2156 VectorSubtract (origin, b->owner->origin, vRay[0]);
2157 VectorCopy (dir, vRay[1]);
2165 s = sin (-angle/180*Q_PI);
2166 c = cos (-angle/180*Q_PI);
2172 vRay[i][0] = (x * c) - (y * s);
2173 vRay[i][1] = (x * s) + (y * c);
2177 entitymodel *model = b->owner->md3Class->model;
2179 while (model != NULL)
2181 for (i = 0; i < model->nTriCount; i++)
2183 for (j = 0; j < 3; j++)
2184 VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);
2186 if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))
2193 model = model->pNext;
2212 Itersects a ray with a brush
2213 Returns the face hit and the distance along the ray the intersection occured at
2214 Returns NULL and 0 if not hit at all
2217 extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);
2218 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)
2220 face_t *f, *firstface = NULL;
2225 if (b->owner->eclass->fixedsize
2226 && b->owner->model.pSelect
2227 && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))
2228 && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
2231 vec_t dist_local = FLT_MAX;
2232 ray_construct_for_vec3(&ray_local, origin, dir);
2233 if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))
2236 return b->brush_faces;
2245 VectorCopy (origin, p1);
2246 for (i=0 ; i<3 ; i++)
2247 p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;
2249 for (f=b->brush_faces ; f ; f=f->next)
2251 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2252 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2253 if (d1 >= 0 && d2 >= 0)
2256 return NULL; // ray is on front side of face
2258 if (d1 <=0 && d2 <= 0)
2260 // clip the ray to the plane
2261 frac = d1 / (d1 - d2);
2265 for (i=0 ; i<3 ; i++)
2266 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
2270 for (i=0 ; i<3 ; i++)
2271 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
2275 // find distance p1 is along dir
2276 VectorSubtract (p1, origin, p1);
2277 d1 = DotProduct (p1, dir);
2281 // new test stuff for patches
2282 if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)
2284 double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are
2285 if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))
2293 //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);
2298 // modifications to the discarding code here should be matched in the selection code
2301 // do some last minute filtering
2302 if (firstface && nFlags & SF_CAMERA)
2304 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2306 if (strstr(firstface->texdef.GetName(), "caulk"))
2312 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2314 if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))
2320 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2322 if (strstr(firstface->texdef.GetName(), "clip"))
2334 face_t *Brush_Point (vec3_t origin, brush_t *b)
2339 for (f=b->brush_faces ; f ; f=f->next)
2341 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;
2344 return NULL; // point is on front side of face
2348 return b->brush_faces;
2353 void Brush_AddToList (brush_t *b, brush_t *blist)
2355 if (b->next || b->prev)
2356 Error ("Brush_AddToList: already linked");
2358 if (blist == &selected_brushes || blist == &active_brushes)
2360 if (b->patchBrush && blist == &selected_brushes)
2362 Patch_Select(b->pPatch);
2365 b->next = blist->next;
2366 blist->next->prev = b;
2371 DispatchRadiantMsg( RADIANT_SELECTION );
2374 void Brush_RemoveFromList (brush_t *b)
2376 if (!b->next || !b->prev)
2377 Error ("Brush_RemoveFromList: not linked");
2381 Patch_Deselect(b->pPatch);
2383 b->next->prev = b->prev;
2384 b->prev->next = b->next;
2385 b->next = b->prev = NULL;
2392 Doesn't set the curve flags
2395 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2396 use Texture_ForName() to find the right shader
2397 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2399 TTimo: surface plugin, added an IPluginTexdef* parameter
2400 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2401 if NULL, ask for a default
2403 TTimo - shader code cleanup
2404 added IShader* parameter
2407 void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2412 oldFlags = f->texdef.flags;
2413 oldContents = f->texdef.contents;
2414 if (g_qeglobals.m_bBrushPrimitMode)
2416 f->texdef = *texdef;
2417 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2422 f->texdef = *texdef;
2423 // fit the scaling of the texture on the actual plane
2424 vec3_t p1,p2,p3; // absolute coordinates
2425 // compute absolute coordinates
2426 ComputeAbsolute(f,p1,p2,p3);
2427 // compute the scale
2429 VectorSubtract(p2,p1,vx);
2430 VectorNormalize(vx, vx);
2431 VectorSubtract(p3,p1,vy);
2432 VectorNormalize(vy, vy);
2434 VectorScale(vx,texdef->scale[0],vx);
2435 VectorScale(vy,texdef->scale[1],vy);
2436 VectorAdd(p1,vx,p2);
2437 VectorAdd(p1,vy,p3);
2438 // compute back shift scale rot
2439 AbsoluteToLocal(f->plane,f,p1,p2,p3);
2442 f->texdef = *texdef;
2443 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2444 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2446 // if this is a curve face, set all other curve faces to the same texdef
2447 if (f->texdef.flags & SURF_CURVE)
2449 for (tf = b->brush_faces ; tf ; tf = tf->next)
2451 if (tf->texdef.flags & SURF_CURVE)
2452 tf->texdef = f->texdef;
2461 Doesn't set the curve flags
2464 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2465 use Texture_ForName() to find the right shader
2466 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2468 TTimo: surface plugin, added an IPluginTexdef* parameter
2469 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2470 if NULL, ask for a default
2473 void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2477 oldFlags = f->texdef.flags;
2478 oldContents = f->texdef.contents;
2480 if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build
2481 Face_SetShader(f, texdef->GetName());
2483 if (g_qeglobals.m_bBrushPrimitMode)
2485 f->texdef = *texdef;
2486 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2492 f->texdef = *texdef;
2493 // fit the scaling of the texture on the actual plane
2494 vec3_t p1,p2,p3; // absolute coordinates
2495 // compute absolute coordinates
2496 ComputeAbsolute(f,p1,p2,p3);
2497 // compute the scale
2499 VectorSubtract(p2,p1,vx);
2500 VectorNormalize(vx, vx);
2501 VectorSubtract(p3,p1,vy);
2502 VectorNormalize(vy, vy);
2504 VectorScale(vx,texdef->scale[0],vx);
2505 VectorScale(vy,texdef->scale[1],vy);
2506 VectorAdd(p1,vx,p2);
2507 VectorAdd(p1,vy,p3);
2508 // compute back shift scale rot
2509 AbsoluteToLocal(f->plane,f,p1,p2,p3);
2513 f->texdef = *texdef;
2516 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2517 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2521 void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2523 for (face_t* f = b->brush_faces ; f ; f = f->next)
2524 SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);
2528 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2529 b->bFiltered = FilterBrush( b );
2534 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2536 for (face_t* f = b->brush_faces ; f ; f = f->next)
2537 SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);
2541 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2542 b->bFiltered = FilterBrush( b );
2547 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
2553 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2554 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2556 if (d1 >= 0 && d2 >= 0)
2557 return false; // totally outside
2558 if (d1 <= 0 && d2 <= 0)
2559 return true; // totally inside
2561 fr = d1 / (d1 - d2);
2568 for (i=0 ; i<3 ; i++)
2569 v[i] = p1[i] + fr*(p2[i] - p1[i]);
2575 int AddPlanept (float *f)
2579 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
2580 if (g_qeglobals.d_move_points[i] == f)
2582 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2588 Brush_SelectFaceForDragging
2590 Adds the faces planepts to move_points, and
2591 rotates and adds the planepts of adjacent face if shear is set
2594 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
2603 if (b->owner->eclass->fixedsize)
2607 for (i=0 ; i<3 ; i++)
2608 c += AddPlanept (f->planepts[i]);
2610 return; // already completely added
2612 // select all points on this plane in all brushes the selection
2613 for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
2617 for (f2=b2->brush_faces ; f2 ; f2=f2->next)
2619 for (i=0 ; i<3 ; i++)
2620 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
2621 -f->plane.dist) > ON_EPSILON)
2624 { // move this face as well
2625 Brush_SelectFaceForDragging (b2, f2, shear);
2632 // if shearing, take all the planes adjacent to
2633 // selected faces and rotate their points so the
2634 // edge clipped by a selcted face has two of the points
2638 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2642 w = Brush_MakeFaceWinding (b, f2);
2646 // any points on f will become new control points
2647 for (i=0 ; i<w->numpoints ; i++)
2649 d = DotProduct (w->points[i], f->plane.normal)
2651 if (d > -ON_EPSILON && d < ON_EPSILON)
2656 // if none of the points were on the plane,
2659 if (i != w->numpoints)
2662 { // see if the first clockwise point was the
2663 // last point on the winding
2664 d = DotProduct (w->points[w->numpoints-1]
2665 , f->plane.normal) - f->plane.dist;
2666 if (d > -ON_EPSILON && d < ON_EPSILON)
2667 i = w->numpoints - 1;
2670 AddPlanept (f2->planepts[0]);
2672 VectorCopy (w->points[i], f2->planepts[0]);
2673 if (++i == w->numpoints)
2676 // see if the next point is also on the plane
2677 d = DotProduct (w->points[i]
2678 , f->plane.normal) - f->plane.dist;
2679 if (d > -ON_EPSILON && d < ON_EPSILON)
2680 AddPlanept (f2->planepts[1]);
2682 VectorCopy (w->points[i], f2->planepts[1]);
2683 if (++i == w->numpoints)
2686 // the third point is never on the plane
2688 VectorCopy (w->points[i], f2->planepts[2]);
2699 The mouse click did not hit the brush, so grab one or more side
2703 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
2709 for (f=b->brush_faces ; f ; f=f->next)
2711 VectorCopy (origin, p1);
2712 VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);
2714 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2718 ClipLineToFace (p1, p2, f2);
2724 if (VectorCompare (p1, origin))
2726 if (ClipLineToFace (p1, p2, f))
2729 Brush_SelectFaceForDragging (b, f, shear);
2733 bool g_bBuildWindingsNoTexBuild = false;
2735 void Brush_SetBuildWindingsNoTexBuild(bool bBuild)
2737 g_bBuildWindingsNoTexBuild = bBuild;
2740 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary
2741 // saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases
2742 // ie when we want to update a shader
2743 // default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild
2744 void Brush_BuildWindings( brush_t *b, bool bSnap )
2751 Brush_SnapPlanepts( b );
2753 // clear the mins/maxs bounds
2754 b->mins[0] = b->mins[1] = b->mins[2] = 99999;
2755 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
2757 Brush_MakeFacePlanes (b);
2759 face = b->brush_faces;
2761 float fCurveColor = 1.0;
2763 for ( ; face ; face=face->next)
2766 free(face->face_winding);
2767 w = face->face_winding = Brush_MakeFaceWinding (b, face);
2769 if (!g_bBuildWindingsNoTexBuild || !face->d_texture)
2772 // if there's no d_texture, then we expect pShader to be empty
2773 if (!face->d_texture && face->pShader)
2774 Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");
2776 if ((!face->d_texture && !face->pShader) || !face->pShader)
2779 // patch 84 for bug 253 doesn't dec ref the potential face->pShader
2780 // add a debug check to make sure this is actually not necessary
2784 Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");
2787 face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );
2788 face->pShader->IncRef();
2789 face->d_texture = face->pShader->getTexture();
2796 for (i=0 ; i<w->numpoints ; i++)
2798 // add to bounding box
2799 for (j=0 ; j<3 ; j++)
2801 v = w->points[i][j];
2808 Face_SetColor (b, face, fCurveColor);
2810 fCurveColor -= .10f;
2811 if (fCurveColor <= 0)
2814 // computing ST coordinates for the windings
2815 if (g_qeglobals.m_bBrushPrimitMode)
2817 if (g_qeglobals.bNeedConvert)
2819 // we have parsed old brushes format and need conversion
2820 // convert old brush texture representation to new format
2821 FaceToBrushPrimitFace(face);
2823 // use old texture coordinates code to check against
2824 for (i=0 ; i<w->numpoints ; i++)
2825 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2828 // use new texture representation to compute texture coordinates
2829 // in debug mode we will check against old code and warn if there are differences
2830 EmitBrushPrimitTextureCoordinates(face,w);
2834 if (g_qeglobals.bNeedConvert)
2836 BrushPrimitFaceToFace(face);
2838 // we have parsed brush primitives and need conversion back to standard format
2839 // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
2840 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
2841 // I tried various tweaks, no luck .. seems shifting is lost
2842 brushprimit_texdef_t aux;
2843 ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
2844 TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
2845 face->texdef.scale[0]/=2.0;
2846 face->texdef.scale[1]/=2.0;
2849 for (i=0 ; i<w->numpoints ; i++)
2850 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2857 Brush_RemoveEmptyFaces
2859 Frees any overconstraining faces
2862 void Brush_RemoveEmptyFaces ( brush_t *b )
2867 b->brush_faces = NULL;
2872 if (!f->face_winding)
2876 f->next = b->brush_faces;
2883 void Brush_SnapToGrid(brush_t *pb)
2890 // TTimo: some brushes are "special" and should not be snapped
2891 // specially fixed-size entity ones
2892 if (pb->owner->eclass->fixedsize)
2894 // save current origin
2895 VectorCopy (pb->owner->origin, temp);
2897 VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);
2898 // return if amount is zero
2899 if (VectorCompare (pb->owner->origin, temp))
2901 // transform brush faces same amount
2902 VectorSubtract (pb->owner->origin, temp, temp);
2903 for (f = pb->brush_faces; f; f = f->next)
2905 for (i=0 ; i<3 ; i++)
2906 VectorAdd (f->planepts[i], temp, f->planepts[i]);
2911 for (f = pb->brush_faces ; f; f = f->next)
2915 // spog - move planepts apart just far enough to avoid snapping two together
2916 VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);
2919 if (diff[j][i] == 0.0f)
2920 mult[i] = 2; // next value up from 1
2921 else // multiplier = gridsize / component difference, rounded up
2922 mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));
2925 if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1
2927 n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;
2929 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component
2931 VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);
2935 VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);
2939 Brush_Build(pb,true,true,false,false); // don't filter
2942 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)
2944 for (face_t* f=b->brush_faces ; f ; f=f->next)
2946 for (int i=0 ; i<3 ; i++)
2948 VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);
2953 Brush_Build(b,false,false,false,false); // don't filter
2957 void Brush_Center(brush_t *b, vec3_t vNewCenter)
2960 // get center of the brush
2961 for (int j = 0; j < 3; j++)
2963 vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);
2965 // calc distance between centers
2966 VectorSubtract(vNewCenter, vMid, vMid);
2967 Brush_Move(b, vMid, true);
2971 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)
2976 short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
2978 for (i=0 ; i<3 ; i++)
2979 if (vMax[i] < vMin[i])
2980 Error ("Brush_Resize: invalid input");
2982 if(b->brush_faces != NULL)
2983 texdef = b->brush_faces->texdef;
2985 texdef = g_qeglobals.d_texturewin.texdef;
2987 while (b->brush_faces != NULL)
2989 f = b->brush_faces->next;
2990 Face_Free(b->brush_faces);
2997 b->brush_faces = Face_Alloc();
2998 b->brush_faces->next = f;
3001 VectorCopy(vMax, f->planepts[0]);
3002 VectorCopy(vMax, f->planepts[1]);
3003 VectorCopy(vMax, f->planepts[2]);
3004 f->planepts[2][box[i][0]] = vMin[box[i][0]];
3005 f->planepts[1][box[i][1]] = vMin[box[i][1]];
3010 b->brush_faces = Face_Alloc();
3011 b->brush_faces->next = f;
3014 VectorCopy(vMin, f->planepts[0]);
3015 VectorCopy(vMin, f->planepts[1]);
3016 VectorCopy(vMin, f->planepts[2]);
3017 f->planepts[1][box[i][0]] = vMax[box[i][0]];
3018 f->planepts[2][box[i][1]] = vMax[box[i][1]];
3022 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)
3027 angleVal = IntForKey(e, "angle");
3028 if (angleVal == -1) // up
3030 VectorSet(angles, 270, 0, 0);
3032 else if(angleVal == -2) // down
3034 VectorSet(angles, 90, 0, 0);
3038 VectorSet(angles, 0, angleVal, 0);
3041 AngleVectors(angles, forward, right, up);
3044 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)
3046 vec3_t forward, right, up;
3047 vec3_t endpoint, tip1, tip2;
3051 VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
3052 VectorScale(start, 0.5, start);
3053 dist = (b->maxs[0] - start[0]) * 2.5;
3055 FacingVectors (e, forward, right, up);
3056 VectorMA (start, dist, forward, endpoint);
3058 dist = (b->maxs[0] - start[0]) * 0.5;
3059 VectorMA (endpoint, -dist, forward, tip1);
3060 VectorMA (tip1, -dist, up, tip1);
3061 VectorMA (tip1, 2*dist, up, tip2);
3063 qglColor4f (1, 1, 1, 1);
3065 qglBegin (GL_LINES);
3066 qglVertex3fv (start);
3067 qglVertex3fv (endpoint);
3068 qglVertex3fv (endpoint);
3069 qglVertex3fv (tip1);
3070 qglVertex3fv (endpoint);
3071 qglVertex3fv (tip2);
3076 void Brush_FaceDraw(face_t *face, int nGLState)
3078 const winding_t *w = face->face_winding;
3079 if (w == NULL) return;
3080 if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)
3081 qglNormal3fv(face->plane.normal);
3083 if (mode & DRAW_GL_TEXTURE_2D)
3084 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);
3085 qglVertexPointer(3, GL_FLOAT, 5, w->points);
3087 if (mode & DRAW_GL_FILL)
3088 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);
3090 qglDrawArrays(GL_POLYGON, 0, w->numpoints);
3093 if (nGLState & DRAW_GL_FILL)
3094 qglBegin(GL_TRIANGLE_FAN);
3096 qglBegin(GL_POLYGON);
3098 for (int i=0 ; i<w->numpoints ; i++)
3100 if (nGLState & DRAW_GL_TEXTURE_2D)
3101 qglTexCoord2fv( &w->points[i][3] );
3102 qglVertex3fv(w->points[i]);
3107 #define Q2_SURF_TRANS33 0x00000010
3108 #define Q2_SURF_TRANS66 0x00000020
3110 void Brush_Draw(brush_t *b)
3114 qtexture_t *prev = 0;
3117 int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;
3118 int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;
3120 GLfloat material[4], identity[4];
3121 VectorSet(identity, 0.8f, 0.8f, 0.8f);
3123 qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
3124 qglDisableClientState(GL_NORMAL_ARRAY);
3126 // guarantee the texture will be set first
3130 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
3132 w = face->face_winding;
3135 continue; // freed face
3138 bTrans = (face->pShader->getFlags() & QER_TRANS);
3139 transVal = face->pShader->getTrans();
3140 // try to read the texture def surface flags to get trans
3142 if (face->texdef.flags & Q2_SURF_TRANS33) {
3145 } else if (face->texdef.flags & Q2_SURF_TRANS66) {
3151 if (bTrans && !(nGLState & DRAW_GL_BLEND))
3153 if (!bTrans && nGLState & DRAW_GL_BLEND)
3157 // modifications to the discarding code here should be matched in the selection code
3160 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
3162 if (strstr(face->texdef.GetName(), "caulk"))
3166 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
3168 if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))
3172 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
3174 if (strstr(face->texdef.GetName(), "clip"))
3178 if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')
3181 qglDisable(GL_TEXTURE_2D);
3183 else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)
3185 // set the texture for this face
3186 prev = face->d_texture;
3187 qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
3190 if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)
3192 if (!b->owner->eclass->fixedsize)
3193 material[3] = transVal;
3196 VectorCopy(face->d_color, material);
3198 if (nGLState & DRAW_GL_TEXTURE_2D)
3199 qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);
3201 qglColor4fv(material);
3203 else if (!b->owner->eclass->fixedsize)
3205 pShader = face->pShader;
3206 VectorCopy(pShader->getTexture()->color, material);
3207 material[3] = identity[3] = transVal;
3209 if (nGLState & DRAW_GL_TEXTURE_2D)
3210 qglColor4fv(identity);
3212 qglColor4fv(material);
3217 Brush_FaceDraw(face, nGLState);
3219 qglPopClientAttrib();
3222 void Face_Draw( face_t *f )
3226 if ( f->face_winding == 0 )
3228 qglBegin(GL_POLYGON);
3229 for ( i = 0 ; i < f->face_winding->numpoints; i++)
3230 qglVertex3fv( f->face_winding->points[i] );
3234 entity_t *FindEntity(const char *pszKey, const char *pszValue)
3240 for (; pe != NULL && pe != &entities ; pe = pe->next)
3242 if (!strcmp(ValueForKey(pe, pszKey), pszValue))
3249 void Brush_DrawXY(brush_t *b, int nViewType)
3258 Patch_DrawXY(b->pPatch);
3259 if (!g_bPatchShowBounds)
3263 if (b->owner->eclass->fixedsize)
3265 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
3267 #if 1 // requires vertex arrays enabled
3268 DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);
3271 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3273 vCorners[0][0] = b->mins[0];
3274 vCorners[0][1] = b->mins[1];
3275 vCorners[0][2] = fMid;
3277 vCorners[1][0] = b->mins[0];
3278 vCorners[1][1] = b->maxs[1];
3279 vCorners[1][2] = fMid;
3281 vCorners[2][0] = b->maxs[0];
3282 vCorners[2][1] = b->maxs[1];
3283 vCorners[2][2] = fMid;
3285 vCorners[3][0] = b->maxs[0];
3286 vCorners[3][1] = b->mins[1];
3287 vCorners[3][2] = fMid;
3289 vec3_t vTop, vBottom;
3291 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3292 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3293 vTop[2] = b->maxs[2];
3295 VectorCopy(vTop, vBottom);
3296 vBottom[2] = b->mins[2];
3300 qglVertex3fv(vCorners[0]);
3302 qglVertex3fv(vCorners[1]);
3304 qglVertex3fv(vCorners[2]);
3306 qglVertex3fv(vCorners[3]);
3310 qglVertex3fv(vBottom);
3311 qglVertex3fv(vCorners[0]);
3312 qglVertex3fv(vBottom);
3313 qglVertex3fv(vCorners[1]);
3314 qglVertex3fv(vBottom);
3315 qglVertex3fv(vCorners[2]);
3316 qglVertex3fv(vBottom);
3317 qglVertex3fv(vCorners[3]);
3320 qglBegin(GL_LINE_LOOP);
3321 qglVertex3fv(vCorners[0]);
3322 qglVertex3fv(vCorners[1]);
3323 qglVertex3fv(vCorners[2]);
3324 qglVertex3fv(vCorners[3]);
3327 DrawBrushEntityName (b);
3330 else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))
3332 qglPushAttrib(GL_CURRENT_BIT); // save brush colour
3333 qglColor3fv(b->owner->eclass->color);
3334 if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )
3335 b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);
3336 aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
3343 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
3345 // moved so check occurs earlier
3346 w = face->face_winding;
3349 // only draw polygons facing in a direction we care about
3350 if (nViewType == XY)
3352 if (face->plane.normal[2] <= 0)
3357 if (nViewType == XZ)
3359 if (face->plane.normal[1] >= 0) // stop axes being mirrored
3364 if (face->plane.normal[0] <= 0)
3370 qglBegin(GL_LINE_LOOP);
3371 for (i=0 ; i<w->numpoints ; i++)
3372 qglVertex3fv(w->points[i]);
3376 DrawBrushEntityName (b);
3385 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)
3390 for (f=b->brush_faces ; f ; f=f->next)
3391 for (i=0 ; i<3 ; i++)
3392 VectorAdd (f->planepts[i], move, f->planepts[i]);
3394 if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)
3396 for (f=b->brush_faces ; f ; f=f->next)
3399 VectorCopy(move, vTemp);
3400 Face_MoveTexture(f, vTemp);
3404 Brush_Build( b, bSnap,true,false,false); // don't filter
3409 //Patch_Move(b->nPatchID, move);
3410 Patch_Move(b->pPatch, move);
3414 // PGM - keep the origin vector up to date on fixed size entities.
3415 if(b->owner->eclass->fixedsize)
3418 VectorAdd(b->owner->origin, move, b->owner->origin);
3419 sprintf (text, "%i %i %i",
3420 (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
3421 SetKeyValue(b->owner, "origin", text);
3422 //VectorAdd(b->maxs, b->mins, b->owner->origin);
3423 //VectorScale(b->owner->origin, 0.5, b->owner->origin);
3429 void Brush_Print(brush_t* b)
3432 for (face_t* f = b->brush_faces ; f ; f=f->next)
3434 Sys_Printf("Face %i\n", nFace++);
3435 Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
3436 Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
3437 Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
3447 Makes the current brushhave the given number of 2d sides and turns it into a cone
3450 void Brush_MakeSidedCone(int sides)
3461 if (sides < 3 || sides > 32)
3463 Sys_Status ("Bad sides number", 0);
3467 if (!QE_SingleBrush ())
3469 Sys_Status ("Must have a single brush selected", 0 );
3473 b = selected_brushes.next;
3474 VectorCopy (b->mins, mins);
3475 VectorCopy (b->maxs, maxs);
3476 texdef = &g_qeglobals.d_texturewin.texdef;
3480 // find center of brush
3482 for (i=0 ; i<2 ; i++)
3484 mid[i] = (maxs[i] + mins[i])*0.5;
3485 if (maxs[i] - mins[i] > width)
3486 width = maxs[i] - mins[i];
3492 // create bottom face
3494 f->texdef = *texdef;
3495 f->next = b->brush_faces;
3498 f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
3499 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
3500 f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
3502 for (i=0 ; i<sides ; i++)
3505 f->texdef = *texdef;
3506 f->next = b->brush_faces;
3509 sv = sin (i*3.14159265*2/sides);
3510 cv = cos (i*3.14159265*2/sides);
3513 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
3514 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
3515 f->planepts[0][2] = mins[2];
3517 f->planepts[1][0] = mid[0];
3518 f->planepts[1][1] = mid[1];
3519 f->planepts[1][2] = maxs[2];
3521 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);
3522 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);
3523 f->planepts[2][2] = maxs[2];
3527 Brush_AddToList (b, &selected_brushes);
3529 Entity_LinkBrush (world_entity, b);
3533 Sys_UpdateWindows (W_ALL);
3540 Makes the current brushhave the given number of 2d sides and turns it into a sphere
3544 void Brush_MakeSidedSphere(int sides)
3553 if (sides < 4 || sides > 32)
3555 Sys_Status ("Bad sides number", 0);
3559 if (!QE_SingleBrush ())
3561 Sys_Status ("Must have a single brush selected", 0 );
3565 b = selected_brushes.next;
3566 VectorCopy (b->mins, mins);
3567 VectorCopy (b->maxs, maxs);
3568 texdef = &g_qeglobals.d_texturewin.texdef;
3572 // find center of brush
3574 for (i=0 ; i<2 ; i++)
3576 mid[i] = (maxs[i] + mins[i])*0.5;
3577 if (maxs[i] - mins[i] > radius)
3578 radius = maxs[i] - mins[i];
3584 float dt = float(2 * Q_PI / sides);
3585 float dp = float(Q_PI / sides);
3587 for(i=0; i <= sides-1; i++)
3589 for(j=0;j <= sides-2; j++)
3592 p = float(j * dp - Q_PI / 2);
3595 f->texdef = *texdef;
3596 f->next = b->brush_faces;
3599 VectorPolar(f->planepts[0], radius, t, p);
3600 VectorPolar(f->planepts[1], radius, t, p + dp);
3601 VectorPolar(f->planepts[2], radius, t + dt, p + dp);
3603 for (int k = 0; k < 3; k++)
3604 VectorAdd(f->planepts[k], mid, f->planepts[k]);
3608 p = float((sides - 1) * dp - Q_PI / 2);
3609 for(i = 0; i <= sides-1; i++)
3614 f->texdef = *texdef;
3615 f->next = b->brush_faces;
3618 VectorPolar(f->planepts[0], radius, t, p);
3619 VectorPolar(f->planepts[1], radius, t + dt, p + dp);
3620 VectorPolar(f->planepts[2], radius, t + dt, p);
3622 for (int k = 0; k < 3; k++)
3623 VectorAdd(f->planepts[k], mid, f->planepts[k]);
3626 Brush_AddToList (b, &selected_brushes);
3628 Entity_LinkBrush (world_entity, b);
3632 Sys_UpdateWindows (W_ALL);
3635 void Face_FitTexture( face_t * face, int nHeight, int nWidth )
3640 float width, height, temp;
3641 float rot_width, rot_height;
3642 float cosv,sinv,ang;
3643 float min_t, min_s, max_t, max_s;
3654 ClearBounds (mins, maxs);
3656 w = face->face_winding;
3661 for (i=0 ; i<w->numpoints ; i++)
3663 AddPointToBounds( w->points[i], mins, maxs );
3666 if (g_qeglobals.m_bBrushPrimitMode)
3667 Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );
3673 // get the current angle
3675 ang = td->rotate / 180 * Q_PI;
3679 // get natural texture axis
3680 TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);
3682 min_s = DotProduct( mins, vecs[0] );
3683 min_t = DotProduct( mins, vecs[1] );
3684 max_s = DotProduct( maxs, vecs[0] );
3685 max_t = DotProduct( maxs, vecs[1] );
3686 width = max_s - min_s;
3687 height = max_t - min_t;
3688 coords[0][0] = min_s;
3689 coords[0][1] = min_t;
3690 coords[1][0] = max_s;
3691 coords[1][1] = min_t;
3692 coords[2][0] = min_s;
3693 coords[2][1] = max_t;
3694 coords[3][0] = max_s;
3695 coords[3][1] = max_t;
3696 min_s = min_t = 99999;
3697 max_s = max_t = -99999;
3700 s = cosv * coords[i][0] - sinv * coords[i][1];
3701 t = sinv * coords[i][0] + cosv * coords[i][1];
3731 rot_width = (max_s - min_s);
3732 rot_height = (max_t - min_t);
3733 td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));
3734 td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));
3736 td->shift[0] = min_s/td->scale[0];
3737 temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));
3738 temp = (temp+1)*face->d_texture->width*nWidth;
3739 td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);
3741 td->shift[1] = min_t/td->scale[1];
3742 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
3743 temp = (temp+1)*(face->d_texture->height*nHeight);
3744 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
3746 td->shift[1] = min_t/td->scale[1];
3747 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
3748 temp = (temp+1)*(face->d_texture->height*nHeight);
3749 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
3754 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )
3758 for (face = b->brush_faces ; face ; face=face->next)
3760 Face_FitTexture( face, nHeight, nWidth );
3764 void aabb_draw(const aabb_t *aabb, int mode)
3766 vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };
3769 VectorSubtract(aabb->origin, aabb->extents, vMin);
3770 VectorAdd(aabb->origin, aabb->extents, vMax);
3771 VectorSet(points[0], vMin[0], vMax[1], vMax[2]);
3772 VectorSet(points[1], vMax[0], vMax[1], vMax[2]);
3773 VectorSet(points[2], vMax[0], vMin[1], vMax[2]);
3774 VectorSet(points[3], vMin[0], vMin[1], vMax[2]);
3775 VectorSet(points[4], vMin[0], vMax[1], vMin[2]);
3776 VectorSet(points[5], vMax[0], vMax[1], vMin[2]);
3777 VectorSet(points[6], vMax[0], vMin[1], vMin[2]);
3778 VectorSet(points[7], vMin[0], vMin[1], vMin[2]);
3782 qglNormal3fv(normals[0]);
3783 qglVertex3fv(points[2]);
3784 qglVertex3fv(points[1]);
3785 qglVertex3fv(points[5]);
3786 qglVertex3fv(points[6]);
3788 qglNormal3fv(normals[1]);
3789 qglVertex3fv(points[1]);
3790 qglVertex3fv(points[0]);
3791 qglVertex3fv(points[4]);
3792 qglVertex3fv(points[5]);
3794 qglNormal3fv(normals[2]);
3795 qglVertex3fv(points[0]);
3796 qglVertex3fv(points[1]);
3797 qglVertex3fv(points[2]);
3798 qglVertex3fv(points[3]);
3800 qglNormal3fv(normals[3]);
3801 qglVertex3fv(points[3]);
3802 qglVertex3fv(points[7]);
3803 qglVertex3fv(points[4]);
3804 qglVertex3fv(points[0]);
3806 qglNormal3fv(normals[4]);
3807 qglVertex3fv(points[3]);
3808 qglVertex3fv(points[2]);
3809 qglVertex3fv(points[6]);
3810 qglVertex3fv(points[7]);
3812 qglNormal3fv(normals[5]);
3813 qglVertex3fv(points[7]);
3814 qglVertex3fv(points[6]);
3815 qglVertex3fv(points[5]);
3816 qglVertex3fv(points[4]);
3826 VectorSubtract(aabb->origin, aabb->extents, vMin);
3827 VectorAdd(aabb->origin, aabb->extents, vMax);
3828 VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);
3829 VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);
3830 VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);
3831 VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);
3832 VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);
3833 VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);
3834 VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);
3835 VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);
3837 vec3_t Normals[8] = { {-1, 0, 0 },
3846 unsigned short Indices[24] = { 2, 1, 5, 6,
3853 qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays
3854 qglNormalPointer(GL_FLOAT, 0, Normals);
3856 //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array
3858 qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);
3860 //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array
3864 qboolean IsBrushSelected(brush_t* bSel)
3866 for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)