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;
431 void Face_MakePlane (face_t *f)
436 // convert to a vector / dist plane
437 for (j=0 ; j<3 ; j++)
439 t1[j] = f->planepts[0][j] - f->planepts[1][j];
440 t2[j] = f->planepts[2][j] - f->planepts[1][j];
441 t3[j] = f->planepts[1][j];
444 CrossProduct(t1,t2, f->plane.normal);
445 if (VectorCompare (f->plane.normal, vec3_origin))
446 Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n");
447 VectorNormalize (f->plane.normal, f->plane.normal);
448 f->plane.dist = DotProduct (t3, f->plane.normal);
453 EmitTextureCoordinates
456 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
458 float STfromXYZ[2][4];
460 Face_TextureVectors (f, STfromXYZ);
461 xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
462 xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
465 //==========================================================================
472 void Brush_MakeFacePlanes (brush_t *b)
476 for (f=b->brush_faces ; f ; f=f->next)
487 void DrawBrushEntityName (brush_t *b)
495 return; // during contruction
497 if (b->owner == world_entity)
500 if (b != b->owner->brushes.onext)
501 return; // not key brush
503 // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views
504 // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?
505 // Brush_DrawFacingAngle() works when called, but is not being called.
506 if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))
508 // draw the angle pointer
509 a = FloatForKey (b->owner, "angle");
510 s = sin (a/180*Q_PI);
511 c = cos (a/180*Q_PI);
512 for (i=0 ; i<3 ; i++)
513 mid[i] = (b->mins[i] + b->maxs[i])*0.5;
515 qglBegin (GL_LINE_STRIP);
545 if (g_qeglobals.d_savedinfo.show_names)
547 name = ValueForKey (b->owner, "classname");
548 qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
549 gtk_glwidget_print_string(name);
555 Brush_MakeFaceWinding
557 returns the visible polygon on a face
560 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)
567 // get a poly that covers an effectively infinite area
568 w = Winding_BaseForPlane (&face->plane);
570 // chop the poly by all of the other faces
572 for (clip = b->brush_faces ; clip && w ; clip=clip->next)
579 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
580 && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
581 { // identical plane, use the later one
590 // flip the plane, because we want to keep the back side
591 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
592 plane.dist = -clip->plane.dist;
594 w = Winding_Clip (w, &plane, false);
599 if (w->numpoints < 3)
606 Sys_FPrintf (SYS_WRN, "unused plane\n");
616 void Brush_SnapPlanepts (brush_t *b)
621 if (g_PrefsDlg.m_bNoClamp)
624 if (g_qeglobals.d_bSmallGrid)
626 for (f=b->brush_faces ; f; f=f->next)
627 for (i=0 ; i<3 ; i++)
628 for (j=0 ; j<3 ; j++)
629 f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize;
633 for (f=b->brush_faces ; f; f=f->next)
634 for (i=0 ; i<3 ; i++)
635 for (j=0 ; j<3 ; j++)
636 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
643 ** Builds a brush rendering data and also sets the min/max bounds
646 // added a bConvert flag to convert between old and new brush texture formats
648 // brush grouping: update the group treeview if necessary
649 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest)
655 if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
656 Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
659 // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
660 if (bConvert && !g_qeglobals.bNeedConvert)
663 //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes
664 // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.
666 bLocalConvert = true;
667 g_qeglobals.bNeedConvert = true;
670 bLocalConvert = false;
673 ** build the windings and generate the bounding box
675 Brush_BuildWindings(b, bSnap);
677 if(b->owner->model.pRender)
679 const aabb_t *aabb = b->owner->model.pRender->GetAABB();
680 VectorAdd(aabb->origin, aabb->extents, b->maxs);
681 VectorSubtract(aabb->origin, aabb->extents, b->mins);
684 //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !
687 ** move the points and edges if in select mode
689 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
690 SetupVertexSelection ();
692 if (b->itemOwner == 0) //NULL)
693 Group_AddToProperGroup(b);
697 Sys_MarkMapModified();
701 g_qeglobals.bNeedConvert = false;
703 // spog - applying filters to brush during brush_build instead of during redraw
705 b->bFiltered = FilterBrush( b );
710 Brush_SplitBrushByFace
712 The incoming brush is NOT freed.
713 The incoming face is NOT left referenced.
716 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk)
722 b = Brush_Clone (in);
725 nf->texdef = b->brush_faces->texdef;
728 nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
730 nf->next = b->brush_faces;
734 Brush_RemoveEmptyFaces ( b );
735 if ( !b->brush_faces )
736 { // completely clipped away
742 Entity_LinkBrush (in->owner, b);
746 b = Brush_Clone (in);
748 // swap the plane winding
749 VectorCopy (nf->planepts[0], temp);
750 VectorCopy (nf->planepts[1], nf->planepts[0]);
751 VectorCopy (temp, nf->planepts[1]);
753 nf->texdef = b->brush_faces->texdef;
756 nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
758 nf->next = b->brush_faces;
762 Brush_RemoveEmptyFaces ( b );
763 if ( !b->brush_faces )
764 { // completely clipped away
770 Entity_LinkBrush (in->owner, b);
779 returns the best face to split the brush with.
780 return NULL if the brush is convex
783 face_t *Brush_BestSplitFace(brush_t *b)
785 face_t *face, *f, *bestface;
786 winding_t *front, *back;
787 int splits, tinywindings, value, bestvalue;
791 for (face = b->brush_faces; face; face = face->next)
795 for (f = b->brush_faces; f; f = f->next)
797 if (f == face) continue;
799 Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back);
812 if (Winding_IsTiny(front)) tinywindings++;
813 if (Winding_IsTiny(back)) tinywindings++;
818 value = splits + 50 * tinywindings;
819 if (value < bestvalue)
831 Brush_MakeConvexBrushes
833 MrE FIXME: this doesn't work because the old
834 Brush_SplitBrushByFace is used
835 Turns the brush into a minimal number of convex brushes.
836 If the input brush is convex then it will be returned.
837 Otherwise the input brush will be freed.
838 NOTE: the input brush should have windings for the faces.
841 brush_t *Brush_MakeConvexBrushes(brush_t *b)
843 brush_t *front, *back, *end;
847 face = Brush_BestSplitFace(b);
849 Brush_SplitBrushByFace(b, face, &front, &back);
850 //this should never happen
851 if (!front && !back) return b;
854 return Brush_MakeConvexBrushes(back);
855 b = Brush_MakeConvexBrushes(front);
858 for (end = b; end->next; end = end->next);
859 end->next = Brush_MakeConvexBrushes(back);
869 int Brush_Convex(brush_t *b)
871 face_t *face1, *face2;
873 for (face1 = b->brush_faces; face1; face1 = face1->next)
875 if (!face1->face_winding) continue;
876 for (face2 = b->brush_faces; face2; face2 = face2->next)
878 if (face1 == face2) continue;
879 if (!face2->face_winding) continue;
880 if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
881 face1->plane.normal, face2->plane.normal,
882 face1->plane.dist, face2->plane.dist))
895 - The input brush must be convex
896 - The input brush must have face windings.
897 - The output brush will be convex.
898 - Returns true if the WHOLE vertex movement is performed.
902 // define this to debug the vertex editing mode
907 #define MAX_MOVE_FACES 64
909 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
911 face_t *f, *face, *newface, *lastface, *nextface;
912 face_t *movefaces[MAX_MOVE_FACES];
913 int movefacepoints[MAX_MOVE_FACES];
917 int i, j, k, nummovefaces, result, done;
918 float dot, front, back, frac, smallestfrac;
921 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" );
928 VectorCopy(vertex, start);
929 VectorAdd(vertex, delta, end);
932 for (i = 0; i < 3; i++)
933 end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize;
935 VectorCopy(end, mid);
936 //if the start and end are the same
937 if (Point_Equal(start, end, 0.3f)) return false;
938 //the end point may not be the same as another vertex
939 for (face = b->brush_faces; face; face = face->next)
941 w = face->face_winding;
943 for (i = 0; i < w->numpoints; i++)
945 if (Point_Equal(w->points[i], end, 0.3f))
947 VectorCopy(vertex, end);
956 //chop off triangles from all brush faces that use the to be moved vertex
957 //store pointers to these chopped off triangles in movefaces[]
959 for (face = b->brush_faces; face; face = face->next)
961 w = face->face_winding;
963 for (i = 0; i < w->numpoints; i++)
965 if (Point_Equal(w->points[i], start, 0.2f))
967 if (face->face_winding->numpoints <= 3)
969 movefacepoints[nummovefaces] = i;
970 movefaces[nummovefaces++] = face;
973 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
974 //if the end point is in front of the face plane
977 //fanout triangle subdivision
978 for (k = i; k < i + w->numpoints-3; k++)
980 VectorCopy(w->points[i], tmpw.points[0]);
981 VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
982 VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
984 newface = Face_Clone(face);
986 for (f = face; f->original; f = f->original) ;
987 newface->original = f;
988 //store the new winding
989 if (newface->face_winding) Winding_Free(newface->face_winding);
990 newface->face_winding = Winding_Clone(&tmpw);
991 //get the texture information
992 newface->pShader = face->pShader;
993 newface->d_texture = face->d_texture;
995 //add the face to the brush
996 newface->next = b->brush_faces;
997 b->brush_faces = newface;
998 //add this new triangle to the move faces
999 movefacepoints[nummovefaces] = 0;
1000 movefaces[nummovefaces++] = newface;
1002 //give the original face a new winding
1003 VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
1004 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
1005 VectorCopy(w->points[i], tmpw.points[2]);
1006 Winding_Free(face->face_winding);
1007 face->face_winding = Winding_Clone(&tmpw);
1008 //add the original face to the move faces
1009 movefacepoints[nummovefaces] = 2;
1010 movefaces[nummovefaces++] = face;
1014 //chop a triangle off the face
1015 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
1016 VectorCopy(w->points[i], tmpw.points[1]);
1017 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
1018 //remove the point from the face winding
1019 Winding_RemovePoint(w, i);
1020 //get texture crap right
1021 Face_SetColor(b, face, 1.0);
1022 for (j = 0; j < w->numpoints; j++)
1023 EmitTextureCoordinates(w->points[j], face->d_texture, face);
1024 //make a triangle face
1025 newface = Face_Clone(face);
1027 for (f = face; f->original; f = f->original) ;
1028 newface->original = f;
1029 //store the new winding
1030 if (newface->face_winding) Winding_Free(newface->face_winding);
1031 newface->face_winding = Winding_Clone(&tmpw);
1033 newface->pShader = face->pShader;
1034 newface->d_texture = newface->pShader->getTexture();
1035 // newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );
1036 //add the face to the brush
1037 newface->next = b->brush_faces;
1038 b->brush_faces = newface;
1040 movefacepoints[nummovefaces] = 1;
1041 movefaces[nummovefaces++] = newface;
1047 //now movefaces contains pointers to triangle faces that
1048 //contain the to be moved vertex
1051 VectorCopy(end, mid);
1053 for (face = b->brush_faces; face; face = face->next)
1055 //check if there is a move face that has this face as the original
1056 for (i = 0; i < nummovefaces; i++)
1058 if (movefaces[i]->original == face) break;
1060 if (i >= nummovefaces) continue;
1061 //check if the original is not a move face itself
1062 for (j = 0; j < nummovefaces; j++)
1064 if (face == movefaces[j]) break;
1066 //if the original is not a move face itself
1067 if (j >= nummovefaces)
1069 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));
1073 k = movefacepoints[j];
1074 w = movefaces[j]->face_winding;
1075 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);
1076 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);
1078 k = movefacepoints[i];
1079 w = movefaces[i]->face_winding;
1080 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);
1081 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
1083 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);
1084 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
1085 //this should never happen otherwise the face merge did a crappy job a previous pass
1089 //now we've got the plane to check agains
1090 front = DotProduct(start, plane.normal) - plane.dist;
1091 back = DotProduct(end, plane.normal) - plane.dist;
1092 //if the whole move is at one side of the plane
1093 if (front < 0.01 && back < 0.01) continue;
1094 if (front > -0.01 && back > -0.01) continue;
1095 //if there's no movement orthogonal to this plane at all
1096 if (fabs(front-back) < 0.001) continue;
1097 //ok first only move till the plane is hit
1098 frac = front/(front-back);
1099 if (frac < smallestfrac)
1101 mid[0] = start[0] + (end[0] - start[0]) * frac;
1102 mid[1] = start[1] + (end[1] - start[1]) * frac;
1103 mid[2] = start[2] + (end[2] - start[2]) * frac;
1104 smallestfrac = frac;
1111 for (i = 0; i < nummovefaces; i++)
1113 //move vertex to end position
1114 VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);
1115 //create new face plane
1116 for (j = 0; j < 3; j++)
1118 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
1120 Face_MakePlane(movefaces[i]);
1121 if (VectorLength(movefaces[i]->plane.normal) < 0.1)
1124 //if the brush is no longer convex
1125 if (!result || !Brush_Convex(b))
1127 for (i = 0; i < nummovefaces; i++)
1129 //move the vertex back to the initial position
1130 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);
1131 //create new face plane
1132 for (j = 0; j < 3; j++)
1134 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
1136 Face_MakePlane(movefaces[i]);
1139 VectorCopy(start, end);
1144 VectorCopy(mid, start);
1146 //get texture crap right
1147 for (i = 0; i < nummovefaces; i++)
1149 Face_SetColor(b, movefaces[i], 1.0);
1150 for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
1151 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
1154 //now try to merge faces with their original faces
1156 for (face = b->brush_faces; face; face = nextface)
1158 nextface = face->next;
1159 if (!face->original)
1164 if (!Plane_Equal(&face->plane, &face->original->plane, false))
1169 w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
1175 Winding_Free(face->original->face_winding);
1176 face->original->face_winding = w;
1177 //get texture crap right
1178 Face_SetColor(b, face->original, 1.0);
1179 for (j = 0; j < face->original->face_winding->numpoints; j++)
1180 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
1181 //remove the face that was merged with the original
1182 if (lastface) lastface->next = face->next;
1183 else b->brush_faces = face->next;
1192 Brush_InsertVertexBetween
1195 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)
1198 winding_t *w, *neww;
1202 if (Point_Equal(p1, p2, 0.4f))
1204 VectorAdd(p1, p2, point);
1205 VectorScale(point, 0.5f, point);
1207 //the end point may not be the same as another vertex
1208 for (face = b->brush_faces; face; face = face->next)
1210 w = face->face_winding;
1213 for (i = 0; i < w->numpoints; i++)
1215 if (!Point_Equal(w->points[i], p1, 0.1f))
1217 if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f))
1219 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);
1222 else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f))
1224 neww = Winding_InsertPoint(w, point, i);
1230 Winding_Free(face->face_winding);
1231 face->face_winding = neww;
1241 Brush_ResetFaceOriginals
1244 void Brush_ResetFaceOriginals(brush_t *b)
1248 for (face = b->brush_faces; face; face = face->next)
1250 face->original = NULL;
1254 #ifdef ENABLE_GROUPS
1258 sets an epair for the given brush
1261 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)
1263 if (g_qeglobals.m_bBrushPrimitMode)
1267 Patch_SetEpair(b->pPatch, pKey, pValue);
1271 SetKeyValue(b->epairs, pKey, pValue);
1276 Sys_Printf("Can only set key/values in Brush primitive mode\n");
1285 const char* Brush_GetKeyValue(brush_t *b, const char *pKey)
1287 if (g_qeglobals.m_bBrushPrimitMode)
1291 return Patch_GetKeyValue(b->pPatch, pKey);
1295 return ValueForKey(b->epairs, pKey);
1300 Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");
1308 temporary stuff, detect potential problems when saving the texture name
1311 void CheckName( face_t *fa, char *pname )
1313 if (!strlen(fa->texdef.GetName()))
1316 Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n");
1318 fa->texdef.SetName(SHADER_NOT_FOUND);
1319 strcpy(pname, SHADER_NOT_FOUND);
1323 // some people manage to get long filename textures (with spaces) in their maps
1324 if (strchr( fa->texdef.GetName(), ' ' ))
1328 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() );
1330 Sys_Printf("%s\n", Msg1 );
1331 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
1332 strcpy( pname, SHADER_NOT_FOUND );
1336 //++timo FIXME: bug #103494 detection attempt
1337 // TODO: clean this detection part when bug will have disappeared
1338 if (fa->texdef.GetName()[0] == '(')
1340 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.";
1341 Sys_Printf("%s\n", text);
1342 gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );
1343 // need to cleanup this dead face name or we may loop endlessly
1344 fa->texdef.SetName(SHADER_NOT_FOUND);
1345 strcpy( pname, SHADER_NOT_FOUND );
1348 strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/"
1355 Create non-textured blocks for entities
1356 The brush is NOT linked to any list
1359 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
1367 // brush primitive mode : convert texdef to brushprimit_texdef ?
1368 // most of the time texdef is empty
1369 if (g_qeglobals.m_bBrushPrimitMode)
1371 // check texdef is empty .. if there are cases it's not we need to write some conversion code
1372 if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)
1373 Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");
1377 for (i=0 ; i<3 ; i++)
1379 if (maxs[i] < mins[i])
1380 Error ("Brush_InitSolid: backwards");
1385 pts[0][0][0] = mins[0];
1386 pts[0][0][1] = mins[1];
1388 pts[1][0][0] = mins[0];
1389 pts[1][0][1] = maxs[1];
1391 pts[2][0][0] = maxs[0];
1392 pts[2][0][1] = maxs[1];
1394 pts[3][0][0] = maxs[0];
1395 pts[3][0][1] = mins[1];
1397 for (i=0 ; i<4 ; i++)
1399 pts[i][0][2] = mins[2];
1400 pts[i][1][0] = pts[i][0][0];
1401 pts[i][1][1] = pts[i][0][1];
1402 pts[i][1][2] = maxs[2];
1405 for (i=0 ; i<4 ; i++)
1408 f->texdef = *texdef;
1409 f->texdef.flags &= ~SURF_KEEP;
1410 f->texdef.contents &= ~CONTENTS_KEEP;
1411 f->next = b->brush_faces;
1415 VectorCopy (pts[j][1], f->planepts[0]);
1416 VectorCopy (pts[i][1], f->planepts[1]);
1417 VectorCopy (pts[i][0], f->planepts[2]);
1421 f->texdef = *texdef;
1422 f->texdef.flags &= ~SURF_KEEP;
1423 f->texdef.contents &= ~CONTENTS_KEEP;
1424 f->next = b->brush_faces;
1427 VectorCopy (pts[0][1], f->planepts[0]);
1428 VectorCopy (pts[1][1], f->planepts[1]);
1429 VectorCopy (pts[2][1], f->planepts[2]);
1432 f->texdef = *texdef;
1433 f->texdef.flags &= ~SURF_KEEP;
1434 f->texdef.contents &= ~CONTENTS_KEEP;
1435 f->next = b->brush_faces;
1438 VectorCopy (pts[2][0], f->planepts[0]);
1439 VectorCopy (pts[1][0], f->planepts[1]);
1440 VectorCopy (pts[0][0], f->planepts[2]);
1449 Create non-textured pyramid for light entities
1450 The brush is NOT linked to any list
1453 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)
1457 //++timo handle new brush primitive ? return here ??
1458 return Brush_Create(mins, maxs, texdef);
1460 for (i=0 ; i<3 ; i++)
1461 if (maxs[i] < mins[i])
1462 Error ("Brush_InitSolid: backwards");
1464 brush_t* b = Brush_Alloc();
1468 float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2)));
1470 corners[0][0] = mins[0];
1471 corners[0][1] = mins[1];
1472 corners[0][2] = fMid;
1474 corners[1][0] = mins[0];
1475 corners[1][1] = maxs[1];
1476 corners[1][2] = fMid;
1478 corners[2][0] = maxs[0];
1479 corners[2][1] = maxs[1];
1480 corners[2][2] = fMid;
1482 corners[3][0] = maxs[0];
1483 corners[3][1] = mins[1];
1484 corners[3][2] = fMid;
1488 top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2));
1489 top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2));
1490 top[2] = Rad_rint(maxs[2]);
1492 VectorCopy(top, bottom);
1493 bottom[2] = mins[2];
1496 for (i = 0; i < 4; i++)
1498 face_t* f = Face_Alloc();
1499 f->texdef = *texdef;
1500 f->texdef.flags &= ~SURF_KEEP;
1501 f->texdef.contents &= ~CONTENTS_KEEP;
1502 f->next = b->brush_faces;
1506 VectorCopy (top, f->planepts[0]);
1507 VectorCopy (corners[i], f->planepts[1]);
1508 VectorCopy(corners[j], f->planepts[2]);
1511 f->texdef = *texdef;
1512 f->texdef.flags &= ~SURF_KEEP;
1513 f->texdef.contents &= ~CONTENTS_KEEP;
1514 f->next = b->brush_faces;
1517 VectorCopy (bottom, f->planepts[2]);
1518 VectorCopy (corners[i], f->planepts[1]);
1519 VectorCopy(corners[j], f->planepts[0]);
1532 Makes the current brush have the given number of 2d sides
1535 void Brush_MakeSided (int sides)
1548 Sys_Status ("Bad sides number", 0);
1552 if (sides >= MAX_POINTS_ON_WINDING-4)
1554 Sys_Printf("too many sides.\n");
1558 if (!QE_SingleBrush ())
1560 Sys_Status ("Must have a single brush selected", 0 );
1564 b = selected_brushes.next;
1565 VectorCopy (b->mins, mins);
1566 VectorCopy (b->maxs, maxs);
1567 texdef = &g_qeglobals.d_texturewin.texdef;
1571 if (g_pParentWnd->ActiveXY())
1573 switch(g_pParentWnd->ActiveXY()->GetViewType())
1575 case XY: axis = 2; break;
1576 case XZ: axis = 1; break;
1577 case YZ: axis = 0; break;
1585 // find center of brush
1587 for (i = 0; i < 3; i++)
1589 mid[i] = (maxs[i] + mins[i]) * 0.5;
1590 if (i == axis) continue;
1591 if ((maxs[i] - mins[i]) * 0.5 > width)
1592 width = (maxs[i] - mins[i]) * 0.5;
1599 f->texdef = *texdef;
1600 f->next = b->brush_faces;
1603 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];
1604 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];
1605 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];
1607 // create bottom face
1609 f->texdef = *texdef;
1610 f->next = b->brush_faces;
1613 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];
1614 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];
1615 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];
1617 for (i=0 ; i<sides ; i++)
1620 f->texdef = *texdef;
1621 f->next = b->brush_faces;
1624 sv = sin (i*3.14159265*2/sides);
1625 cv = cos (i*3.14159265*2/sides);
1627 f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);
1628 f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);
1629 f->planepts[0][axis] = mins[axis];
1631 f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];
1632 f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];
1633 f->planepts[1][axis] = maxs[axis];
1635 f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);
1636 f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);
1637 f->planepts[2][axis] = maxs[axis];
1640 Brush_AddToList (b, &selected_brushes);
1642 Entity_LinkBrush (world_entity, b);
1646 Sys_UpdateWindows (W_ALL);
1655 Frees the brush with all of its faces and display list.
1656 Unlinks the brush from whichever chain it is in.
1657 Decrements the owner entity's brushcount.
1658 Removes owner entity if this was the last brush
1659 unless owner is the world.
1663 void Brush_Free (brush_t *b, bool bRemoveNode)
1666 epair_t *ep, *enext;
1668 // remove from group
1670 Group_RemoveBrush(b);
1672 // free the patch if it's there
1675 Patch_Delete(b->pPatch);
1679 for (f=b->brush_faces ; f ; f=next)
1685 // TTimo : free brush epairs
1686 for (ep = b->epairs ; ep ; ep=enext )
1694 // unlink from active/selected list
1696 Brush_RemoveFromList (b);
1698 // unlink from entity list
1700 Entity_UnlinkBrush (b);
1710 int Face_MemorySize(face_t *f )
1714 if (f->face_winding)
1716 // size += _msize(f->face_winding);
1717 size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int);
1719 // size += _msize(f);
1720 size += sizeof(face_t);
1729 int Brush_MemorySize(brush_t *b)
1738 size += Patch_MemorySize(b->pPatch);
1741 for (f = b->brush_faces; f; f = f->next)
1743 size += Face_MemorySize(f);
1746 for (ep = b->epairs; ep; ep = ep->next )
1748 // size += _msize(ep->key);
1749 size += strlen(ep->key);
1750 // size += _msize(ep->value);
1751 size += strlen(ep->value);
1752 // size += _msize(ep);
1753 size += sizeof(epair_t);
1755 // size += _msize(b);
1756 size += sizeof(brush_t);
1765 Does NOT add the new brush to any lists
1768 brush_t *Brush_Clone (brush_t *b)
1775 patchMesh_t *p = Patch_Duplicate(b->pPatch);
1776 Brush_RemoveFromList(p->pSymbiot);
1777 Entity_UnlinkBrush(p->pSymbiot);
1783 n->numberId = g_nBrushId++;
1784 n->owner = b->owner;
1785 for (f=b->brush_faces ; f ; f=f->next)
1787 nf = Face_Clone( f );
1788 nf->next = n->brush_faces;
1789 n->brush_faces = nf;
1800 Does NOT add the new brush to any lists
1803 brush_t *Brush_FullClone(brush_t *b)
1806 face_t *f, *nf, *f2, *nf2;
1811 patchMesh_t *p = Patch_Duplicate(b->pPatch);
1812 Brush_RemoveFromList(p->pSymbiot);
1813 Entity_UnlinkBrush(p->pSymbiot);
1815 n->owner = b->owner;
1821 n->numberId = g_nBrushId++;
1822 n->owner = b->owner;
1823 VectorCopy(b->mins, n->mins);
1824 VectorCopy(b->maxs, n->maxs);
1826 for (f = b->brush_faces; f; f = f->next)
1828 if (f->original) continue;
1829 nf = Face_FullClone(f);
1830 nf->next = n->brush_faces;
1831 n->brush_faces = nf;
1832 //copy all faces that have the original set to this face
1833 for (f2 = b->brush_faces; f2; f2 = f2->next)
1835 if (f2->original == f)
1837 nf2 = Face_FullClone(f2);
1838 nf2->next = n->brush_faces;
1839 n->brush_faces = nf2;
1845 for (nf = n->brush_faces; nf; nf = nf->next)
1847 Face_SetColor(n, nf, 1.0);
1848 if (nf->face_winding)
1850 if (g_qeglobals.m_bBrushPrimitMode)
1851 EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);
1854 for (j = 0; j < nf->face_winding->numpoints; j++)
1855 EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);
1863 // FIXME - spog - finish this later..
1865 bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)
1868 vec3_t v1, v2, normal[3];
1871 //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);
1872 //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);
1873 //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);
1874 //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);
1876 // test ray against triangle
1877 // get triangle plane normal
1878 //VectorSubtract(p1, p2, v1);
1879 //VectorSubtract(p1, p3, v2);
1880 //CrossProduct(v1, v2, v1);
1881 // check normal against direction
1882 //if (DotProduct(dir, v1) >= 0)
1884 // generate cone normals
1885 VectorSubtract(origin, p1, v1);
1886 VectorSubtract(origin, p2, v2);
1887 CrossProduct(v1, v2, normal[0]);
1888 VectorSubtract(origin, p2, v1);
1889 VectorSubtract(origin, p3, v2);
1890 CrossProduct(v1, v2, normal[1]);
1891 VectorSubtract(origin, p3, v1);
1892 VectorSubtract(origin, p1, v2);
1893 CrossProduct(v1, v2, normal[2]);
1897 // flip normals if triangle faces away
1898 // Sys_Printf("flipped\n");
1899 // VectorSubtract(origin, p1, v1);
1900 // VectorSubtract(origin, p3, v2);
1901 // CrossProduct(v1, v2, normal[0]);
1902 // VectorSubtract(origin, p3, v1);
1903 // VectorSubtract(origin, p2, v2);
1904 // CrossProduct(v1, v2, normal[1]);
1905 // VectorSubtract(origin, p2, v1);
1906 // VectorSubtract(origin, p1, v2);
1907 // CrossProduct(v1, v2, normal[2]);
1912 VectorNormalize(normal[i]);
1913 //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);
1914 //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);
1915 d = DotProduct(dir, normal[i]);
1916 //Sys_Printf("dotproduct: %f\n",d);
1925 extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
1926 float vert0[3], float vert1[3], float vert2[3],
1927 double *t, double *u, double *v);
1929 bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
1931 bool bIntersect = false;
1932 float tBest = FLT_MAX;
1937 float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set
1939 VectorSubtract (origin, b->owner->origin, vRay[0]);
1940 VectorCopy (dir, vRay[1]);
1948 s = sin (-angle/180*Q_PI);
1949 c = cos (-angle/180*Q_PI);
1955 vRay[i][0] = (x * c) - (y * s);
1956 vRay[i][1] = (x * s) + (y * c);
1960 entitymodel *model = b->owner->md3Class->model;
1962 while (model != NULL)
1964 for (i = 0; i < model->nTriCount; i++)
1966 for (j = 0; j < 3; j++)
1967 VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);
1969 if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))
1976 model = model->pNext;
1995 Itersects a ray with a brush
1996 Returns the face hit and the distance along the ray the intersection occured at
1997 Returns NULL and 0 if not hit at all
2000 extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);
2001 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)
2003 face_t *f, *firstface = NULL;
2008 if (b->owner->eclass->fixedsize
2009 && b->owner->model.pSelect
2010 && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))
2011 && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
2014 vec_t dist_local = FLT_MAX;
2015 ray_construct_for_vec3(&ray_local, origin, dir);
2016 if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))
2019 return b->brush_faces;
2028 VectorCopy (origin, p1);
2029 for (i=0 ; i<3 ; i++)
2030 p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;
2032 for (f=b->brush_faces ; f ; f=f->next)
2034 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2035 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2036 if (d1 >= 0 && d2 >= 0)
2039 return NULL; // ray is on front side of face
2041 if (d1 <=0 && d2 <= 0)
2043 // clip the ray to the plane
2044 frac = d1 / (d1 - d2);
2048 for (i=0 ; i<3 ; i++)
2049 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
2053 for (i=0 ; i<3 ; i++)
2054 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
2058 // find distance p1 is along dir
2059 VectorSubtract (p1, origin, p1);
2060 d1 = DotProduct (p1, dir);
2064 // new test stuff for patches
2065 if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)
2067 double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are
2068 if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))
2076 //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);
2081 // modifications to the discarding code here should be matched in the selection code
2084 // do some last minute filtering
2085 if (firstface && nFlags & SF_CAMERA)
2087 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2089 if (strstr(firstface->texdef.GetName(), "caulk"))
2095 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2097 if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))
2103 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2105 if (strstr(firstface->texdef.GetName(), "clip"))
2117 face_t *Brush_Point (vec3_t origin, brush_t *b)
2122 for (f=b->brush_faces ; f ; f=f->next)
2124 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;
2127 return NULL; // point is on front side of face
2131 return b->brush_faces;
2136 void Brush_AddToList (brush_t *b, brush_t *blist)
2138 if (b->next || b->prev)
2139 Error ("Brush_AddToList: already linked");
2141 if (blist == &selected_brushes || blist == &active_brushes)
2143 if (b->patchBrush && blist == &selected_brushes)
2145 Patch_Select(b->pPatch);
2148 b->next = blist->next;
2149 blist->next->prev = b;
2154 DispatchRadiantMsg( RADIANT_SELECTION );
2157 void Brush_RemoveFromList (brush_t *b)
2159 if (!b->next || !b->prev)
2160 Error ("Brush_RemoveFromList: not linked");
2164 Patch_Deselect(b->pPatch);
2166 b->next->prev = b->prev;
2167 b->prev->next = b->next;
2168 b->next = b->prev = NULL;
2175 Doesn't set the curve flags
2178 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2179 use Texture_ForName() to find the right shader
2180 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2182 TTimo: surface plugin, added an IPluginTexdef* parameter
2183 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2184 if NULL, ask for a default
2186 TTimo - shader code cleanup
2187 added IShader* parameter
2190 void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2195 oldFlags = f->texdef.flags;
2196 oldContents = f->texdef.contents;
2197 if (g_qeglobals.m_bBrushPrimitMode)
2199 f->texdef = *texdef;
2200 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2205 f->texdef = *texdef;
2206 // fit the scaling of the texture on the actual plane
2207 vec3_t p1,p2,p3; // absolute coordinates
2208 // compute absolute coordinates
2209 ComputeAbsolute(f,p1,p2,p3);
2210 // compute the scale
2212 VectorSubtract(p2,p1,vx);
2213 VectorNormalize(vx, vx);
2214 VectorSubtract(p3,p1,vy);
2215 VectorNormalize(vy, vy);
2217 VectorScale(vx,texdef->scale[0],vx);
2218 VectorScale(vy,texdef->scale[1],vy);
2219 VectorAdd(p1,vx,p2);
2220 VectorAdd(p1,vy,p3);
2221 // compute back shift scale rot
2222 AbsoluteToLocal(f->plane,f,p1,p2,p3);
2225 f->texdef = *texdef;
2226 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2227 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2229 // if this is a curve face, set all other curve faces to the same texdef
2230 if (f->texdef.flags & SURF_CURVE)
2232 for (tf = b->brush_faces ; tf ; tf = tf->next)
2234 if (tf->texdef.flags & SURF_CURVE)
2235 tf->texdef = f->texdef;
2244 Doesn't set the curve flags
2247 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2248 use Texture_ForName() to find the right shader
2249 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2251 TTimo: surface plugin, added an IPluginTexdef* parameter
2252 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2253 if NULL, ask for a default
2256 void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2260 oldFlags = f->texdef.flags;
2261 oldContents = f->texdef.contents;
2263 if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build
2264 Face_SetShader(f, texdef->GetName());
2266 if (g_qeglobals.m_bBrushPrimitMode)
2268 f->texdef = *texdef;
2269 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2275 f->texdef = *texdef;
2276 // fit the scaling of the texture on the actual plane
2277 vec3_t p1,p2,p3; // absolute coordinates
2278 // compute absolute coordinates
2279 ComputeAbsolute(f,p1,p2,p3);
2280 // compute the scale
2282 VectorSubtract(p2,p1,vx);
2283 VectorNormalize(vx, vx);
2284 VectorSubtract(p3,p1,vy);
2285 VectorNormalize(vy, vy);
2287 VectorScale(vx,texdef->scale[0],vx);
2288 VectorScale(vy,texdef->scale[1],vy);
2289 VectorAdd(p1,vx,p2);
2290 VectorAdd(p1,vy,p3);
2291 // compute back shift scale rot
2292 AbsoluteToLocal(f->plane,f,p1,p2,p3);
2296 f->texdef = *texdef;
2299 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2300 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2304 void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2306 for (face_t* f = b->brush_faces ; f ; f = f->next)
2307 SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);
2311 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2312 b->bFiltered = FilterBrush( b );
2317 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2319 for (face_t* f = b->brush_faces ; f ; f = f->next)
2320 SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);
2324 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2325 b->bFiltered = FilterBrush( b );
2330 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
2336 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2337 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2339 if (d1 >= 0 && d2 >= 0)
2340 return false; // totally outside
2341 if (d1 <= 0 && d2 <= 0)
2342 return true; // totally inside
2344 fr = d1 / (d1 - d2);
2351 for (i=0 ; i<3 ; i++)
2352 v[i] = p1[i] + fr*(p2[i] - p1[i]);
2358 int AddPlanept (float *f)
2362 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
2363 if (g_qeglobals.d_move_points[i] == f)
2365 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2371 Brush_SelectFaceForDragging
2373 Adds the faces planepts to move_points, and
2374 rotates and adds the planepts of adjacent face if shear is set
2377 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
2386 if (b->owner->eclass->fixedsize)
2390 for (i=0 ; i<3 ; i++)
2391 c += AddPlanept (f->planepts[i]);
2393 return; // already completely added
2395 // select all points on this plane in all brushes the selection
2396 for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
2400 for (f2=b2->brush_faces ; f2 ; f2=f2->next)
2402 for (i=0 ; i<3 ; i++)
2403 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
2404 -f->plane.dist) > ON_EPSILON)
2407 { // move this face as well
2408 Brush_SelectFaceForDragging (b2, f2, shear);
2415 // if shearing, take all the planes adjacent to
2416 // selected faces and rotate their points so the
2417 // edge clipped by a selcted face has two of the points
2421 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2425 w = Brush_MakeFaceWinding (b, f2);
2429 // any points on f will become new control points
2430 for (i=0 ; i<w->numpoints ; i++)
2432 d = DotProduct (w->points[i], f->plane.normal)
2434 if (d > -ON_EPSILON && d < ON_EPSILON)
2439 // if none of the points were on the plane,
2442 if (i != w->numpoints)
2445 { // see if the first clockwise point was the
2446 // last point on the winding
2447 d = DotProduct (w->points[w->numpoints-1]
2448 , f->plane.normal) - f->plane.dist;
2449 if (d > -ON_EPSILON && d < ON_EPSILON)
2450 i = w->numpoints - 1;
2453 AddPlanept (f2->planepts[0]);
2455 VectorCopy (w->points[i], f2->planepts[0]);
2456 if (++i == w->numpoints)
2459 // see if the next point is also on the plane
2460 d = DotProduct (w->points[i]
2461 , f->plane.normal) - f->plane.dist;
2462 if (d > -ON_EPSILON && d < ON_EPSILON)
2463 AddPlanept (f2->planepts[1]);
2465 VectorCopy (w->points[i], f2->planepts[1]);
2466 if (++i == w->numpoints)
2469 // the third point is never on the plane
2471 VectorCopy (w->points[i], f2->planepts[2]);
2482 The mouse click did not hit the brush, so grab one or more side
2486 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
2492 for (f=b->brush_faces ; f ; f=f->next)
2494 VectorCopy (origin, p1);
2495 VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);
2497 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2501 ClipLineToFace (p1, p2, f2);
2507 if (VectorCompare (p1, origin))
2509 if (ClipLineToFace (p1, p2, f))
2512 Brush_SelectFaceForDragging (b, f, shear);
2516 bool g_bBuildWindingsNoTexBuild = false;
2518 void Brush_SetBuildWindingsNoTexBuild(bool bBuild)
2520 g_bBuildWindingsNoTexBuild = bBuild;
2523 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary
2524 // saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases
2525 // ie when we want to update a shader
2526 // default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild
2527 void Brush_BuildWindings( brush_t *b, bool bSnap )
2534 Brush_SnapPlanepts( b );
2536 // clear the mins/maxs bounds
2537 b->mins[0] = b->mins[1] = b->mins[2] = 99999;
2538 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
2540 Brush_MakeFacePlanes (b);
2542 face = b->brush_faces;
2544 float fCurveColor = 1.0;
2546 for ( ; face ; face=face->next)
2549 free(face->face_winding);
2550 w = face->face_winding = Brush_MakeFaceWinding (b, face);
2552 if (!g_bBuildWindingsNoTexBuild || !face->d_texture)
2555 // if there's no d_texture, then we expect pShader to be empty
2556 if (!face->d_texture && face->pShader)
2557 Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");
2559 if ((!face->d_texture && !face->pShader) || !face->pShader)
2562 // patch 84 for bug 253 doesn't dec ref the potential face->pShader
2563 // add a debug check to make sure this is actually not necessary
2567 Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");
2570 face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );
2571 face->pShader->IncRef();
2572 face->d_texture = face->pShader->getTexture();
2579 for (i=0 ; i<w->numpoints ; i++)
2581 // add to bounding box
2582 for (j=0 ; j<3 ; j++)
2584 v = w->points[i][j];
2591 Face_SetColor (b, face, fCurveColor);
2593 fCurveColor -= .10f;
2594 if (fCurveColor <= 0)
2597 // computing ST coordinates for the windings
2598 if (g_qeglobals.m_bBrushPrimitMode)
2600 if (g_qeglobals.bNeedConvert)
2602 // we have parsed old brushes format and need conversion
2603 // convert old brush texture representation to new format
2604 FaceToBrushPrimitFace(face);
2606 // use old texture coordinates code to check against
2607 for (i=0 ; i<w->numpoints ; i++)
2608 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2611 // use new texture representation to compute texture coordinates
2612 // in debug mode we will check against old code and warn if there are differences
2613 EmitBrushPrimitTextureCoordinates(face,w);
2617 if (g_qeglobals.bNeedConvert)
2619 BrushPrimitFaceToFace(face);
2621 // we have parsed brush primitives and need conversion back to standard format
2622 // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
2623 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
2624 // I tried various tweaks, no luck .. seems shifting is lost
2625 brushprimit_texdef_t aux;
2626 ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
2627 TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
2628 face->texdef.scale[0]/=2.0;
2629 face->texdef.scale[1]/=2.0;
2632 for (i=0 ; i<w->numpoints ; i++)
2633 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2640 Brush_RemoveEmptyFaces
2642 Frees any overconstraining faces
2645 void Brush_RemoveEmptyFaces ( brush_t *b )
2650 b->brush_faces = NULL;
2655 if (!f->face_winding)
2659 f->next = b->brush_faces;
2666 void Brush_SnapToGrid(brush_t *pb)
2673 // TTimo: some brushes are "special" and should not be snapped
2674 // specially fixed-size entity ones
2675 if (pb->owner->eclass->fixedsize)
2677 // save current origin
2678 VectorCopy (pb->owner->origin, temp);
2680 VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);
2681 // return if amount is zero
2682 if (VectorCompare (pb->owner->origin, temp))
2684 // transform brush faces same amount
2685 VectorSubtract (pb->owner->origin, temp, temp);
2686 for (f = pb->brush_faces; f; f = f->next)
2688 for (i=0 ; i<3 ; i++)
2689 VectorAdd (f->planepts[i], temp, f->planepts[i]);
2694 for (f = pb->brush_faces ; f; f = f->next)
2698 // spog - move planepts apart just far enough to avoid snapping two together
2699 VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);
2702 if (diff[j][i] == 0.0f)
2703 mult[i] = 2; // next value up from 1
2704 else // multiplier = gridsize / component difference, rounded up
2705 mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));
2708 if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1
2710 n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;
2712 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component
2714 VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);
2718 VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);
2722 Brush_Build(pb,true,true,false,false); // don't filter
2725 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)
2727 for (face_t* f=b->brush_faces ; f ; f=f->next)
2729 for (int i=0 ; i<3 ; i++)
2731 VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);
2736 Brush_Build(b,false,false,false,false); // don't filter
2740 void Brush_Center(brush_t *b, vec3_t vNewCenter)
2743 // get center of the brush
2744 for (int j = 0; j < 3; j++)
2746 vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);
2748 // calc distance between centers
2749 VectorSubtract(vNewCenter, vMid, vMid);
2750 Brush_Move(b, vMid, true);
2754 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)
2759 short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
2761 for (i=0 ; i<3 ; i++)
2762 if (vMax[i] < vMin[i])
2763 Error ("Brush_Resize: invalid input");
2765 if(b->brush_faces != NULL)
2766 texdef = b->brush_faces->texdef;
2768 texdef = g_qeglobals.d_texturewin.texdef;
2770 while (b->brush_faces != NULL)
2772 f = b->brush_faces->next;
2773 Face_Free(b->brush_faces);
2780 b->brush_faces = Face_Alloc();
2781 b->brush_faces->next = f;
2784 VectorCopy(vMax, f->planepts[0]);
2785 VectorCopy(vMax, f->planepts[1]);
2786 VectorCopy(vMax, f->planepts[2]);
2787 f->planepts[2][box[i][0]] = vMin[box[i][0]];
2788 f->planepts[1][box[i][1]] = vMin[box[i][1]];
2793 b->brush_faces = Face_Alloc();
2794 b->brush_faces->next = f;
2797 VectorCopy(vMin, f->planepts[0]);
2798 VectorCopy(vMin, f->planepts[1]);
2799 VectorCopy(vMin, f->planepts[2]);
2800 f->planepts[1][box[i][0]] = vMax[box[i][0]];
2801 f->planepts[2][box[i][1]] = vMax[box[i][1]];
2805 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)
2810 angleVal = IntForKey(e, "angle");
2811 if (angleVal == -1) // up
2813 VectorSet(angles, 270, 0, 0);
2815 else if(angleVal == -2) // down
2817 VectorSet(angles, 90, 0, 0);
2821 VectorSet(angles, 0, angleVal, 0);
2824 AngleVectors(angles, forward, right, up);
2827 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)
2829 vec3_t forward, right, up;
2830 vec3_t endpoint, tip1, tip2;
2834 VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
2835 VectorScale(start, 0.5, start);
2836 dist = (b->maxs[0] - start[0]) * 2.5;
2838 FacingVectors (e, forward, right, up);
2839 VectorMA (start, dist, forward, endpoint);
2841 dist = (b->maxs[0] - start[0]) * 0.5;
2842 VectorMA (endpoint, -dist, forward, tip1);
2843 VectorMA (tip1, -dist, up, tip1);
2844 VectorMA (tip1, 2*dist, up, tip2);
2846 qglColor4f (1, 1, 1, 1);
2848 qglBegin (GL_LINES);
2849 qglVertex3fv (start);
2850 qglVertex3fv (endpoint);
2851 qglVertex3fv (endpoint);
2852 qglVertex3fv (tip1);
2853 qglVertex3fv (endpoint);
2854 qglVertex3fv (tip2);
2859 void Brush_FaceDraw(face_t *face, int nGLState)
2861 const winding_t *w = face->face_winding;
2862 if (w == NULL) return;
2863 if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)
2864 qglNormal3fv(face->plane.normal);
2866 if (mode & DRAW_GL_TEXTURE_2D)
2867 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);
2868 qglVertexPointer(3, GL_FLOAT, 5, w->points);
2870 if (mode & DRAW_GL_FILL)
2871 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);
2873 qglDrawArrays(GL_POLYGON, 0, w->numpoints);
2876 if (nGLState & DRAW_GL_FILL)
2877 qglBegin(GL_TRIANGLE_FAN);
2879 qglBegin(GL_POLYGON);
2881 for (int i=0 ; i<w->numpoints ; i++)
2883 if (nGLState & DRAW_GL_TEXTURE_2D)
2884 qglTexCoord2fv( &w->points[i][3] );
2885 qglVertex3fv(w->points[i]);
2890 #define Q2_SURF_TRANS33 0x00000010
2891 #define Q2_SURF_TRANS66 0x00000020
2893 void Brush_Draw(brush_t *b)
2897 qtexture_t *prev = 0;
2900 int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;
2901 int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;
2903 GLfloat material[4], identity[4];
2904 VectorSet(identity, 0.8f, 0.8f, 0.8f);
2906 qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
2907 qglDisableClientState(GL_NORMAL_ARRAY);
2909 // guarantee the texture will be set first
2913 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
2915 w = face->face_winding;
2918 continue; // freed face
2921 bTrans = (face->pShader->getFlags() & QER_TRANS);
2922 transVal = face->pShader->getTrans();
2923 // try to read the texture def surface flags to get trans
2925 if (face->texdef.flags & Q2_SURF_TRANS33) {
2928 } else if (face->texdef.flags & Q2_SURF_TRANS66) {
2934 if (bTrans && !(nGLState & DRAW_GL_BLEND))
2936 if (!bTrans && nGLState & DRAW_GL_BLEND)
2940 // modifications to the discarding code here should be matched in the selection code
2943 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2945 if (strstr(face->texdef.GetName(), "caulk"))
2949 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2951 if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))
2955 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2957 if (strstr(face->texdef.GetName(), "clip"))
2961 if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')
2964 qglDisable(GL_TEXTURE_2D);
2966 else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)
2968 // set the texture for this face
2969 prev = face->d_texture;
2970 qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
2973 if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)
2975 if (!b->owner->eclass->fixedsize)
2976 material[3] = transVal;
2979 VectorCopy(face->d_color, material);
2981 if (nGLState & DRAW_GL_TEXTURE_2D)
2982 qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);
2984 qglColor4fv(material);
2986 else if (!b->owner->eclass->fixedsize)
2988 pShader = face->pShader;
2989 VectorCopy(pShader->getTexture()->color, material);
2990 material[3] = identity[3] = transVal;
2992 if (nGLState & DRAW_GL_TEXTURE_2D)
2993 qglColor4fv(identity);
2995 qglColor4fv(material);
3000 Brush_FaceDraw(face, nGLState);
3002 qglPopClientAttrib();
3005 void Face_Draw( face_t *f )
3009 if ( f->face_winding == 0 )
3011 qglBegin(GL_POLYGON);
3012 for ( i = 0 ; i < f->face_winding->numpoints; i++)
3013 qglVertex3fv( f->face_winding->points[i] );
3017 entity_t *FindEntity(const char *pszKey, const char *pszValue)
3023 for (; pe != NULL && pe != &entities ; pe = pe->next)
3025 if (!strcmp(ValueForKey(pe, pszKey), pszValue))
3032 void Brush_DrawXY(brush_t *b, int nViewType)
3041 Patch_DrawXY(b->pPatch);
3042 if (!g_bPatchShowBounds)
3046 if (b->owner->eclass->fixedsize)
3048 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
3050 #if 1 // requires vertex arrays enabled
3051 DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);
3054 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3056 vCorners[0][0] = b->mins[0];
3057 vCorners[0][1] = b->mins[1];
3058 vCorners[0][2] = fMid;
3060 vCorners[1][0] = b->mins[0];
3061 vCorners[1][1] = b->maxs[1];
3062 vCorners[1][2] = fMid;
3064 vCorners[2][0] = b->maxs[0];
3065 vCorners[2][1] = b->maxs[1];
3066 vCorners[2][2] = fMid;
3068 vCorners[3][0] = b->maxs[0];
3069 vCorners[3][1] = b->mins[1];
3070 vCorners[3][2] = fMid;
3072 vec3_t vTop, vBottom;
3074 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3075 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3076 vTop[2] = b->maxs[2];
3078 VectorCopy(vTop, vBottom);
3079 vBottom[2] = b->mins[2];
3083 qglVertex3fv(vCorners[0]);
3085 qglVertex3fv(vCorners[1]);
3087 qglVertex3fv(vCorners[2]);
3089 qglVertex3fv(vCorners[3]);
3093 qglVertex3fv(vBottom);
3094 qglVertex3fv(vCorners[0]);
3095 qglVertex3fv(vBottom);
3096 qglVertex3fv(vCorners[1]);
3097 qglVertex3fv(vBottom);
3098 qglVertex3fv(vCorners[2]);
3099 qglVertex3fv(vBottom);
3100 qglVertex3fv(vCorners[3]);
3103 qglBegin(GL_LINE_LOOP);
3104 qglVertex3fv(vCorners[0]);
3105 qglVertex3fv(vCorners[1]);
3106 qglVertex3fv(vCorners[2]);
3107 qglVertex3fv(vCorners[3]);
3110 DrawBrushEntityName (b);
3113 else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))
3115 qglPushAttrib(GL_CURRENT_BIT); // save brush colour
3116 qglColor3fv(b->owner->eclass->color);
3117 if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )
3118 b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);
3119 aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
3126 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
3128 // moved so check occurs earlier
3129 w = face->face_winding;
3132 // only draw polygons facing in a direction we care about
3133 if (nViewType == XY)
3135 if (face->plane.normal[2] <= 0)
3140 if (nViewType == XZ)
3142 if (face->plane.normal[1] >= 0) // stop axes being mirrored
3147 if (face->plane.normal[0] <= 0)
3153 qglBegin(GL_LINE_LOOP);
3154 for (i=0 ; i<w->numpoints ; i++)
3155 qglVertex3fv(w->points[i]);
3159 DrawBrushEntityName (b);
3168 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)
3173 for (f=b->brush_faces ; f ; f=f->next)
3174 for (i=0 ; i<3 ; i++)
3175 VectorAdd (f->planepts[i], move, f->planepts[i]);
3177 if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)
3179 for (f=b->brush_faces ; f ; f=f->next)
3182 VectorCopy(move, vTemp);
3183 Face_MoveTexture(f, vTemp);
3187 Brush_Build( b, bSnap,true,false,false); // don't filter
3192 //Patch_Move(b->nPatchID, move);
3193 Patch_Move(b->pPatch, move);
3197 // PGM - keep the origin vector up to date on fixed size entities.
3198 if(b->owner->eclass->fixedsize)
3201 VectorAdd(b->owner->origin, move, b->owner->origin);
3202 sprintf (text, "%i %i %i",
3203 (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
3204 SetKeyValue(b->owner, "origin", text);
3205 //VectorAdd(b->maxs, b->mins, b->owner->origin);
3206 //VectorScale(b->owner->origin, 0.5, b->owner->origin);
3212 void Brush_Print(brush_t* b)
3215 for (face_t* f = b->brush_faces ; f ; f=f->next)
3217 Sys_Printf("Face %i\n", nFace++);
3218 Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
3219 Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
3220 Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
3230 Makes the current brushhave the given number of 2d sides and turns it into a cone
3233 void Brush_MakeSidedCone(int sides)
3244 if (sides < 3 || sides > 32)
3246 Sys_Status ("Bad sides number", 0);
3250 if (!QE_SingleBrush ())
3252 Sys_Status ("Must have a single brush selected", 0 );
3256 b = selected_brushes.next;
3257 VectorCopy (b->mins, mins);
3258 VectorCopy (b->maxs, maxs);
3259 texdef = &g_qeglobals.d_texturewin.texdef;
3263 // find center of brush
3265 for (i=0 ; i<2 ; i++)
3267 mid[i] = (maxs[i] + mins[i])*0.5;
3268 if (maxs[i] - mins[i] > width)
3269 width = maxs[i] - mins[i];
3275 // create bottom face
3277 f->texdef = *texdef;
3278 f->next = b->brush_faces;
3281 f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
3282 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
3283 f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
3285 for (i=0 ; i<sides ; i++)
3288 f->texdef = *texdef;
3289 f->next = b->brush_faces;
3292 sv = sin (i*3.14159265*2/sides);
3293 cv = cos (i*3.14159265*2/sides);
3296 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
3297 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
3298 f->planepts[0][2] = mins[2];
3300 f->planepts[1][0] = mid[0];
3301 f->planepts[1][1] = mid[1];
3302 f->planepts[1][2] = maxs[2];
3304 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);
3305 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);
3306 f->planepts[2][2] = maxs[2];
3310 Brush_AddToList (b, &selected_brushes);
3312 Entity_LinkBrush (world_entity, b);
3316 Sys_UpdateWindows (W_ALL);
3323 Makes the current brushhave the given number of 2d sides and turns it into a sphere
3327 void Brush_MakeSidedSphere(int sides)
3336 if (sides < 4 || sides > 32)
3338 Sys_Status ("Bad sides number", 0);
3342 if (!QE_SingleBrush ())
3344 Sys_Status ("Must have a single brush selected", 0 );
3348 b = selected_brushes.next;
3349 VectorCopy (b->mins, mins);
3350 VectorCopy (b->maxs, maxs);
3351 texdef = &g_qeglobals.d_texturewin.texdef;
3355 // find center of brush
3357 for (i=0 ; i<2 ; i++)
3359 mid[i] = (maxs[i] + mins[i])*0.5;
3360 if (maxs[i] - mins[i] > radius)
3361 radius = maxs[i] - mins[i];
3367 float dt = float(2 * Q_PI / sides);
3368 float dp = float(Q_PI / sides);
3370 for(i=0; i <= sides-1; i++)
3372 for(j=0;j <= sides-2; j++)
3375 p = float(j * dp - Q_PI / 2);
3378 f->texdef = *texdef;
3379 f->next = b->brush_faces;
3382 VectorPolar(f->planepts[0], radius, t, p);
3383 VectorPolar(f->planepts[1], radius, t, p + dp);
3384 VectorPolar(f->planepts[2], radius, t + dt, p + dp);
3386 for (int k = 0; k < 3; k++)
3387 VectorAdd(f->planepts[k], mid, f->planepts[k]);
3391 p = float((sides - 1) * dp - Q_PI / 2);
3392 for(i = 0; i <= sides-1; i++)
3397 f->texdef = *texdef;
3398 f->next = b->brush_faces;
3401 VectorPolar(f->planepts[0], radius, t, p);
3402 VectorPolar(f->planepts[1], radius, t + dt, p + dp);
3403 VectorPolar(f->planepts[2], radius, t + dt, p);
3405 for (int k = 0; k < 3; k++)
3406 VectorAdd(f->planepts[k], mid, f->planepts[k]);
3409 Brush_AddToList (b, &selected_brushes);
3411 Entity_LinkBrush (world_entity, b);
3415 Sys_UpdateWindows (W_ALL);
3418 void Face_FitTexture( face_t * face, int nHeight, int nWidth )
3423 float width, height, temp;
3424 float rot_width, rot_height;
3425 float cosv,sinv,ang;
3426 float min_t, min_s, max_t, max_s;
3437 ClearBounds (mins, maxs);
3439 w = face->face_winding;
3444 for (i=0 ; i<w->numpoints ; i++)
3446 AddPointToBounds( w->points[i], mins, maxs );
3449 if (g_qeglobals.m_bBrushPrimitMode)
3450 Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );
3456 // get the current angle
3458 ang = td->rotate / 180 * Q_PI;
3462 // get natural texture axis
3463 TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);
3465 min_s = DotProduct( mins, vecs[0] );
3466 min_t = DotProduct( mins, vecs[1] );
3467 max_s = DotProduct( maxs, vecs[0] );
3468 max_t = DotProduct( maxs, vecs[1] );
3469 width = max_s - min_s;
3470 height = max_t - min_t;
3471 coords[0][0] = min_s;
3472 coords[0][1] = min_t;
3473 coords[1][0] = max_s;
3474 coords[1][1] = min_t;
3475 coords[2][0] = min_s;
3476 coords[2][1] = max_t;
3477 coords[3][0] = max_s;
3478 coords[3][1] = max_t;
3479 min_s = min_t = 99999;
3480 max_s = max_t = -99999;
3483 s = cosv * coords[i][0] - sinv * coords[i][1];
3484 t = sinv * coords[i][0] + cosv * coords[i][1];
3514 rot_width = (max_s - min_s);
3515 rot_height = (max_t - min_t);
3516 td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));
3517 td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));
3519 td->shift[0] = min_s/td->scale[0];
3520 temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));
3521 temp = (temp+1)*face->d_texture->width*nWidth;
3522 td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);
3524 td->shift[1] = min_t/td->scale[1];
3525 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
3526 temp = (temp+1)*(face->d_texture->height*nHeight);
3527 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
3529 td->shift[1] = min_t/td->scale[1];
3530 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
3531 temp = (temp+1)*(face->d_texture->height*nHeight);
3532 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
3537 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )
3541 for (face = b->brush_faces ; face ; face=face->next)
3543 Face_FitTexture( face, nHeight, nWidth );
3547 void aabb_draw(const aabb_t *aabb, int mode)
3549 vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };
3552 VectorSubtract(aabb->origin, aabb->extents, vMin);
3553 VectorAdd(aabb->origin, aabb->extents, vMax);
3554 VectorSet(points[0], vMin[0], vMax[1], vMax[2]);
3555 VectorSet(points[1], vMax[0], vMax[1], vMax[2]);
3556 VectorSet(points[2], vMax[0], vMin[1], vMax[2]);
3557 VectorSet(points[3], vMin[0], vMin[1], vMax[2]);
3558 VectorSet(points[4], vMin[0], vMax[1], vMin[2]);
3559 VectorSet(points[5], vMax[0], vMax[1], vMin[2]);
3560 VectorSet(points[6], vMax[0], vMin[1], vMin[2]);
3561 VectorSet(points[7], vMin[0], vMin[1], vMin[2]);
3565 qglNormal3fv(normals[0]);
3566 qglVertex3fv(points[2]);
3567 qglVertex3fv(points[1]);
3568 qglVertex3fv(points[5]);
3569 qglVertex3fv(points[6]);
3571 qglNormal3fv(normals[1]);
3572 qglVertex3fv(points[1]);
3573 qglVertex3fv(points[0]);
3574 qglVertex3fv(points[4]);
3575 qglVertex3fv(points[5]);
3577 qglNormal3fv(normals[2]);
3578 qglVertex3fv(points[0]);
3579 qglVertex3fv(points[1]);
3580 qglVertex3fv(points[2]);
3581 qglVertex3fv(points[3]);
3583 qglNormal3fv(normals[3]);
3584 qglVertex3fv(points[3]);
3585 qglVertex3fv(points[7]);
3586 qglVertex3fv(points[4]);
3587 qglVertex3fv(points[0]);
3589 qglNormal3fv(normals[4]);
3590 qglVertex3fv(points[3]);
3591 qglVertex3fv(points[2]);
3592 qglVertex3fv(points[6]);
3593 qglVertex3fv(points[7]);
3595 qglNormal3fv(normals[5]);
3596 qglVertex3fv(points[7]);
3597 qglVertex3fv(points[6]);
3598 qglVertex3fv(points[5]);
3599 qglVertex3fv(points[4]);
3609 VectorSubtract(aabb->origin, aabb->extents, vMin);
3610 VectorAdd(aabb->origin, aabb->extents, vMax);
3611 VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);
3612 VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);
3613 VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);
3614 VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);
3615 VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);
3616 VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);
3617 VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);
3618 VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);
3620 vec3_t Normals[8] = { {-1, 0, 0 },
3629 unsigned short Indices[24] = { 2, 1, 5, 6,
3636 qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays
3637 qglNormalPointer(GL_FLOAT, 0, Normals);
3639 //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array
3641 qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);
3643 //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array
3647 qboolean IsBrushSelected(brush_t* bSel)
3649 for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)