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 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
1999 http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556
2002 extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);
2003 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)
2005 face_t *f, *firstface = NULL;
2010 if (b->owner->eclass->fixedsize
2011 && b->owner->model.pSelect
2012 && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))
2013 && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
2016 vec_t dist_local = FLT_MAX;
2017 ray_construct_for_vec3(&ray_local, origin, dir);
2018 if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))
2021 return b->brush_faces;
2030 VectorCopy (origin, p1);
2031 for (i=0 ; i<3 ; i++)
2032 p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;
2034 for (f=b->brush_faces ; f ; f=f->next)
2036 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2037 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2038 if (d1 >= 0 && d2 >= 0)
2041 return NULL; // ray is on front side of face
2043 if (d1 <=0 && d2 <= 0)
2045 // clip the ray to the plane
2046 frac = d1 / (d1 - d2);
2050 for (i=0 ; i<3 ; i++)
2051 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
2055 for (i=0 ; i<3 ; i++)
2056 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
2060 // find distance p1 is along dir
2061 VectorSubtract (p1, origin, p1);
2062 d1 = DotProduct (p1, dir);
2066 // new test stuff for patches
2067 if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)
2069 double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are
2070 if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))
2078 //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);
2083 // modifications to the discarding code here should be matched in the selection code
2086 // do some last minute filtering
2087 if (firstface && nFlags & SF_CAMERA)
2089 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2091 if (strstr(firstface->texdef.GetName(), "caulk"))
2097 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2099 if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))
2105 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2107 if (strstr(firstface->texdef.GetName(), "clip"))
2119 face_t *Brush_Point (vec3_t origin, brush_t *b)
2124 for (f=b->brush_faces ; f ; f=f->next)
2126 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;
2129 return NULL; // point is on front side of face
2133 return b->brush_faces;
2138 void Brush_AddToList (brush_t *b, brush_t *blist)
2140 if (b->next || b->prev)
2141 Error ("Brush_AddToList: already linked");
2143 if (blist == &selected_brushes || blist == &active_brushes)
2145 if (b->patchBrush && blist == &selected_brushes)
2147 Patch_Select(b->pPatch);
2150 b->next = blist->next;
2151 blist->next->prev = b;
2156 DispatchRadiantMsg( RADIANT_SELECTION );
2159 void Brush_RemoveFromList (brush_t *b)
2161 if (!b->next || !b->prev)
2162 Error ("Brush_RemoveFromList: not linked");
2166 Patch_Deselect(b->pPatch);
2168 b->next->prev = b->prev;
2169 b->prev->next = b->next;
2170 b->next = b->prev = NULL;
2177 Doesn't set the curve flags
2180 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2181 use Texture_ForName() to find the right shader
2182 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2184 TTimo: surface plugin, added an IPluginTexdef* parameter
2185 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2186 if NULL, ask for a default
2188 TTimo - shader code cleanup
2189 added IShader* parameter
2192 void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2197 oldFlags = f->texdef.flags;
2198 oldContents = f->texdef.contents;
2199 if (g_qeglobals.m_bBrushPrimitMode)
2201 f->texdef = *texdef;
2202 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2207 f->texdef = *texdef;
2208 // fit the scaling of the texture on the actual plane
2209 vec3_t p1,p2,p3; // absolute coordinates
2210 // compute absolute coordinates
2211 ComputeAbsolute(f,p1,p2,p3);
2212 // compute the scale
2214 VectorSubtract(p2,p1,vx);
2215 VectorNormalize(vx, vx);
2216 VectorSubtract(p3,p1,vy);
2217 VectorNormalize(vy, vy);
2219 VectorScale(vx,texdef->scale[0],vx);
2220 VectorScale(vy,texdef->scale[1],vy);
2221 VectorAdd(p1,vx,p2);
2222 VectorAdd(p1,vy,p3);
2223 // compute back shift scale rot
2224 AbsoluteToLocal(f->plane,f,p1,p2,p3);
2227 f->texdef = *texdef;
2228 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2229 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2231 // if this is a curve face, set all other curve faces to the same texdef
2232 if (f->texdef.flags & SURF_CURVE)
2234 for (tf = b->brush_faces ; tf ; tf = tf->next)
2236 if (tf->texdef.flags & SURF_CURVE)
2237 tf->texdef = f->texdef;
2246 Doesn't set the curve flags
2249 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
2250 use Texture_ForName() to find the right shader
2251 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
2253 TTimo: surface plugin, added an IPluginTexdef* parameter
2254 if not NULL, get ->Copy() of it into the face ( and remember to hook )
2255 if NULL, ask for a default
2258 void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
2262 oldFlags = f->texdef.flags;
2263 oldContents = f->texdef.contents;
2265 if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build
2266 Face_SetShader(f, texdef->GetName());
2268 if (g_qeglobals.m_bBrushPrimitMode)
2270 f->texdef = *texdef;
2271 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
2277 f->texdef = *texdef;
2278 // fit the scaling of the texture on the actual plane
2279 vec3_t p1,p2,p3; // absolute coordinates
2280 // compute absolute coordinates
2281 ComputeAbsolute(f,p1,p2,p3);
2282 // compute the scale
2284 VectorSubtract(p2,p1,vx);
2285 VectorNormalize(vx, vx);
2286 VectorSubtract(p3,p1,vy);
2287 VectorNormalize(vy, vy);
2289 VectorScale(vx,texdef->scale[0],vx);
2290 VectorScale(vy,texdef->scale[1],vy);
2291 VectorAdd(p1,vx,p2);
2292 VectorAdd(p1,vy,p3);
2293 // compute back shift scale rot
2294 AbsoluteToLocal(f->plane,f,p1,p2,p3);
2298 f->texdef = *texdef;
2301 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
2302 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
2306 void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2308 for (face_t* f = b->brush_faces ; f ; f = f->next)
2309 SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);
2313 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2314 b->bFiltered = FilterBrush( b );
2319 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
2321 for (face_t* f = b->brush_faces ; f ; f = f->next)
2322 SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);
2326 Patch_SetTexture(b->pPatch, texdef, pTexdef );
2327 b->bFiltered = FilterBrush( b );
2332 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
2338 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
2339 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
2341 if (d1 >= 0 && d2 >= 0)
2342 return false; // totally outside
2343 if (d1 <= 0 && d2 <= 0)
2344 return true; // totally inside
2346 fr = d1 / (d1 - d2);
2353 for (i=0 ; i<3 ; i++)
2354 v[i] = p1[i] + fr*(p2[i] - p1[i]);
2360 int AddPlanept (float *f)
2364 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
2365 if (g_qeglobals.d_move_points[i] == f)
2367 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2373 Brush_SelectFaceForDragging
2375 Adds the faces planepts to move_points, and
2376 rotates and adds the planepts of adjacent face if shear is set
2379 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
2388 if (b->owner->eclass->fixedsize)
2392 for (i=0 ; i<3 ; i++)
2393 c += AddPlanept (f->planepts[i]);
2395 return; // already completely added
2397 // select all points on this plane in all brushes the selection
2398 for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
2402 for (f2=b2->brush_faces ; f2 ; f2=f2->next)
2404 for (i=0 ; i<3 ; i++)
2405 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
2406 -f->plane.dist) > ON_EPSILON)
2409 { // move this face as well
2410 Brush_SelectFaceForDragging (b2, f2, shear);
2417 // if shearing, take all the planes adjacent to
2418 // selected faces and rotate their points so the
2419 // edge clipped by a selcted face has two of the points
2423 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2427 w = Brush_MakeFaceWinding (b, f2);
2431 // any points on f will become new control points
2432 for (i=0 ; i<w->numpoints ; i++)
2434 d = DotProduct (w->points[i], f->plane.normal)
2436 if (d > -ON_EPSILON && d < ON_EPSILON)
2441 // if none of the points were on the plane,
2444 if (i != w->numpoints)
2447 { // see if the first clockwise point was the
2448 // last point on the winding
2449 d = DotProduct (w->points[w->numpoints-1]
2450 , f->plane.normal) - f->plane.dist;
2451 if (d > -ON_EPSILON && d < ON_EPSILON)
2452 i = w->numpoints - 1;
2455 AddPlanept (f2->planepts[0]);
2457 VectorCopy (w->points[i], f2->planepts[0]);
2458 if (++i == w->numpoints)
2461 // see if the next point is also on the plane
2462 d = DotProduct (w->points[i]
2463 , f->plane.normal) - f->plane.dist;
2464 if (d > -ON_EPSILON && d < ON_EPSILON)
2465 AddPlanept (f2->planepts[1]);
2467 VectorCopy (w->points[i], f2->planepts[1]);
2468 if (++i == w->numpoints)
2471 // the third point is never on the plane
2473 VectorCopy (w->points[i], f2->planepts[2]);
2484 The mouse click did not hit the brush, so grab one or more side
2488 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
2494 for (f=b->brush_faces ; f ; f=f->next)
2496 VectorCopy (origin, p1);
2497 VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);
2499 for (f2=b->brush_faces ; f2 ; f2=f2->next)
2503 ClipLineToFace (p1, p2, f2);
2509 if (VectorCompare (p1, origin))
2511 if (ClipLineToFace (p1, p2, f))
2514 Brush_SelectFaceForDragging (b, f, shear);
2518 bool g_bBuildWindingsNoTexBuild = false;
2520 void Brush_SetBuildWindingsNoTexBuild(bool bBuild)
2522 g_bBuildWindingsNoTexBuild = bBuild;
2525 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary
2526 // saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases
2527 // ie when we want to update a shader
2528 // default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild
2529 void Brush_BuildWindings( brush_t *b, bool bSnap )
2536 Brush_SnapPlanepts( b );
2538 // clear the mins/maxs bounds
2539 b->mins[0] = b->mins[1] = b->mins[2] = 99999;
2540 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
2542 Brush_MakeFacePlanes (b);
2544 face = b->brush_faces;
2546 float fCurveColor = 1.0;
2548 for ( ; face ; face=face->next)
2551 free(face->face_winding);
2552 w = face->face_winding = Brush_MakeFaceWinding (b, face);
2554 if (!g_bBuildWindingsNoTexBuild || !face->d_texture)
2557 // if there's no d_texture, then we expect pShader to be empty
2558 if (!face->d_texture && face->pShader)
2559 Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");
2561 if ((!face->d_texture && !face->pShader) || !face->pShader)
2564 // patch 84 for bug 253 doesn't dec ref the potential face->pShader
2565 // add a debug check to make sure this is actually not necessary
2569 Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");
2572 face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );
2573 face->pShader->IncRef();
2574 face->d_texture = face->pShader->getTexture();
2581 for (i=0 ; i<w->numpoints ; i++)
2583 // add to bounding box
2584 for (j=0 ; j<3 ; j++)
2586 v = w->points[i][j];
2593 Face_SetColor (b, face, fCurveColor);
2595 fCurveColor -= .10f;
2596 if (fCurveColor <= 0)
2599 // computing ST coordinates for the windings
2600 if (g_qeglobals.m_bBrushPrimitMode)
2602 if (g_qeglobals.bNeedConvert)
2604 // we have parsed old brushes format and need conversion
2605 // convert old brush texture representation to new format
2606 FaceToBrushPrimitFace(face);
2608 // use old texture coordinates code to check against
2609 for (i=0 ; i<w->numpoints ; i++)
2610 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2613 // use new texture representation to compute texture coordinates
2614 // in debug mode we will check against old code and warn if there are differences
2615 EmitBrushPrimitTextureCoordinates(face,w);
2619 if (g_qeglobals.bNeedConvert)
2621 BrushPrimitFaceToFace(face);
2623 // we have parsed brush primitives and need conversion back to standard format
2624 // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
2625 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
2626 // I tried various tweaks, no luck .. seems shifting is lost
2627 brushprimit_texdef_t aux;
2628 ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
2629 TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
2630 face->texdef.scale[0]/=2.0;
2631 face->texdef.scale[1]/=2.0;
2634 for (i=0 ; i<w->numpoints ; i++)
2635 EmitTextureCoordinates( w->points[i], face->d_texture, face);
2642 Brush_RemoveEmptyFaces
2644 Frees any overconstraining faces
2647 void Brush_RemoveEmptyFaces ( brush_t *b )
2652 b->brush_faces = NULL;
2657 if (!f->face_winding)
2661 f->next = b->brush_faces;
2668 void Brush_SnapToGrid(brush_t *pb)
2675 // TTimo: some brushes are "special" and should not be snapped
2676 // specially fixed-size entity ones
2677 if (pb->owner->eclass->fixedsize)
2679 // save current origin
2680 VectorCopy (pb->owner->origin, temp);
2682 VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);
2683 // return if amount is zero
2684 if (VectorCompare (pb->owner->origin, temp))
2686 // transform brush faces same amount
2687 VectorSubtract (pb->owner->origin, temp, temp);
2688 for (f = pb->brush_faces; f; f = f->next)
2690 for (i=0 ; i<3 ; i++)
2691 VectorAdd (f->planepts[i], temp, f->planepts[i]);
2696 for (f = pb->brush_faces ; f; f = f->next)
2700 // spog - move planepts apart just far enough to avoid snapping two together
2701 VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);
2704 if (diff[j][i] == 0.0f)
2705 mult[i] = 2; // next value up from 1
2706 else // multiplier = gridsize / component difference, rounded up
2707 mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));
2710 if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1
2712 n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;
2714 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component
2716 VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);
2720 VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);
2724 Brush_Build(pb,true,true,false,false); // don't filter
2727 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)
2729 for (face_t* f=b->brush_faces ; f ; f=f->next)
2731 for (int i=0 ; i<3 ; i++)
2733 VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);
2738 Brush_Build(b,false,false,false,false); // don't filter
2742 void Brush_Center(brush_t *b, vec3_t vNewCenter)
2745 // get center of the brush
2746 for (int j = 0; j < 3; j++)
2748 vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);
2750 // calc distance between centers
2751 VectorSubtract(vNewCenter, vMid, vMid);
2752 Brush_Move(b, vMid, true);
2756 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)
2761 short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
2763 for (i=0 ; i<3 ; i++)
2764 if (vMax[i] < vMin[i])
2765 Error ("Brush_Resize: invalid input");
2767 if(b->brush_faces != NULL)
2768 texdef = b->brush_faces->texdef;
2770 texdef = g_qeglobals.d_texturewin.texdef;
2772 while (b->brush_faces != NULL)
2774 f = b->brush_faces->next;
2775 Face_Free(b->brush_faces);
2782 b->brush_faces = Face_Alloc();
2783 b->brush_faces->next = f;
2786 VectorCopy(vMax, f->planepts[0]);
2787 VectorCopy(vMax, f->planepts[1]);
2788 VectorCopy(vMax, f->planepts[2]);
2789 f->planepts[2][box[i][0]] = vMin[box[i][0]];
2790 f->planepts[1][box[i][1]] = vMin[box[i][1]];
2795 b->brush_faces = Face_Alloc();
2796 b->brush_faces->next = f;
2799 VectorCopy(vMin, f->planepts[0]);
2800 VectorCopy(vMin, f->planepts[1]);
2801 VectorCopy(vMin, f->planepts[2]);
2802 f->planepts[1][box[i][0]] = vMax[box[i][0]];
2803 f->planepts[2][box[i][1]] = vMax[box[i][1]];
2807 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)
2812 angleVal = IntForKey(e, "angle");
2813 if (angleVal == -1) // up
2815 VectorSet(angles, 270, 0, 0);
2817 else if(angleVal == -2) // down
2819 VectorSet(angles, 90, 0, 0);
2823 VectorSet(angles, 0, angleVal, 0);
2826 AngleVectors(angles, forward, right, up);
2829 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)
2831 vec3_t forward, right, up;
2832 vec3_t endpoint, tip1, tip2;
2836 VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
2837 VectorScale(start, 0.5, start);
2838 dist = (b->maxs[0] - start[0]) * 2.5;
2840 FacingVectors (e, forward, right, up);
2841 VectorMA (start, dist, forward, endpoint);
2843 dist = (b->maxs[0] - start[0]) * 0.5;
2844 VectorMA (endpoint, -dist, forward, tip1);
2845 VectorMA (tip1, -dist, up, tip1);
2846 VectorMA (tip1, 2*dist, up, tip2);
2848 qglColor4f (1, 1, 1, 1);
2850 qglBegin (GL_LINES);
2851 qglVertex3fv (start);
2852 qglVertex3fv (endpoint);
2853 qglVertex3fv (endpoint);
2854 qglVertex3fv (tip1);
2855 qglVertex3fv (endpoint);
2856 qglVertex3fv (tip2);
2861 void Brush_FaceDraw(face_t *face, int nGLState)
2863 const winding_t *w = face->face_winding;
2864 if (w == NULL) return;
2865 if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)
2866 qglNormal3fv(face->plane.normal);
2868 if (mode & DRAW_GL_TEXTURE_2D)
2869 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);
2870 qglVertexPointer(3, GL_FLOAT, 5, w->points);
2872 if (mode & DRAW_GL_FILL)
2873 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);
2875 qglDrawArrays(GL_POLYGON, 0, w->numpoints);
2878 if (nGLState & DRAW_GL_FILL)
2879 qglBegin(GL_TRIANGLE_FAN);
2881 qglBegin(GL_POLYGON);
2883 for (int i=0 ; i<w->numpoints ; i++)
2885 if (nGLState & DRAW_GL_TEXTURE_2D)
2886 qglTexCoord2fv( &w->points[i][3] );
2887 qglVertex3fv(w->points[i]);
2892 void Brush_Draw(brush_t *b)
2896 qtexture_t *prev = 0;
2899 int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;
2900 int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;
2902 GLfloat material[4], identity[4];
2903 VectorSet(identity, 0.8f, 0.8f, 0.8f);
2905 qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
2906 qglDisableClientState(GL_NORMAL_ARRAY);
2908 // guarantee the texture will be set first
2911 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
2913 w = face->face_winding;
2916 continue; // freed face
2919 bTrans = (face->pShader->getFlags() & QER_TRANS);
2921 if (bTrans && !(nGLState & DRAW_GL_BLEND))
2923 if (!bTrans && nGLState & DRAW_GL_BLEND)
2927 // modifications to the discarding code here should be matched in the selection code
2930 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
2932 if (strstr(face->texdef.GetName(), "caulk"))
2936 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
2938 if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))
2942 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
2944 if (strstr(face->texdef.GetName(), "clip"))
2948 if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')
2951 qglDisable(GL_TEXTURE_2D);
2953 else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)
2955 // set the texture for this face
2956 prev = face->d_texture;
2957 qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
2960 if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)
2962 if (!b->owner->eclass->fixedsize)
2963 material[3] = face->pShader->getTrans();
2966 VectorCopy(face->d_color, material);
2968 if (nGLState & DRAW_GL_TEXTURE_2D)
2969 qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);
2971 qglColor4fv(material);
2973 else if (!b->owner->eclass->fixedsize)
2975 pShader = face->pShader;
2976 VectorCopy(pShader->getTexture()->color, material);
2977 material[3] = identity[3] = pShader->getTrans();
2979 if (nGLState & DRAW_GL_TEXTURE_2D)
2980 qglColor4fv(identity);
2982 qglColor4fv(material);
2987 Brush_FaceDraw(face, nGLState);
2989 qglPopClientAttrib();
2992 void Face_Draw( face_t *f )
2996 if ( f->face_winding == 0 )
2998 qglBegin(GL_POLYGON);
2999 for ( i = 0 ; i < f->face_winding->numpoints; i++)
3000 qglVertex3fv( f->face_winding->points[i] );
3004 entity_t *FindEntity(const char *pszKey, const char *pszValue)
3010 for (; pe != NULL && pe != &entities ; pe = pe->next)
3012 if (!strcmp(ValueForKey(pe, pszKey), pszValue))
3019 void Brush_DrawXY(brush_t *b, int nViewType)
3028 Patch_DrawXY(b->pPatch);
3029 if (!g_bPatchShowBounds)
3033 if (b->owner->eclass->fixedsize)
3035 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
3037 #if 1 // requires vertex arrays enabled
3038 DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);
3041 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3043 vCorners[0][0] = b->mins[0];
3044 vCorners[0][1] = b->mins[1];
3045 vCorners[0][2] = fMid;
3047 vCorners[1][0] = b->mins[0];
3048 vCorners[1][1] = b->maxs[1];
3049 vCorners[1][2] = fMid;
3051 vCorners[2][0] = b->maxs[0];
3052 vCorners[2][1] = b->maxs[1];
3053 vCorners[2][2] = fMid;
3055 vCorners[3][0] = b->maxs[0];
3056 vCorners[3][1] = b->mins[1];
3057 vCorners[3][2] = fMid;
3059 vec3_t vTop, vBottom;
3061 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3062 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3063 vTop[2] = b->maxs[2];
3065 VectorCopy(vTop, vBottom);
3066 vBottom[2] = b->mins[2];
3070 qglVertex3fv(vCorners[0]);
3072 qglVertex3fv(vCorners[1]);
3074 qglVertex3fv(vCorners[2]);
3076 qglVertex3fv(vCorners[3]);
3080 qglVertex3fv(vBottom);
3081 qglVertex3fv(vCorners[0]);
3082 qglVertex3fv(vBottom);
3083 qglVertex3fv(vCorners[1]);
3084 qglVertex3fv(vBottom);
3085 qglVertex3fv(vCorners[2]);
3086 qglVertex3fv(vBottom);
3087 qglVertex3fv(vCorners[3]);
3090 qglBegin(GL_LINE_LOOP);
3091 qglVertex3fv(vCorners[0]);
3092 qglVertex3fv(vCorners[1]);
3093 qglVertex3fv(vCorners[2]);
3094 qglVertex3fv(vCorners[3]);
3097 DrawBrushEntityName (b);
3100 else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))
3102 qglPushAttrib(GL_CURRENT_BIT); // save brush colour
3103 qglColor3fv(b->owner->eclass->color);
3104 if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )
3105 b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);
3106 aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
3113 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
3115 // moved so check occurs earlier
3116 w = face->face_winding;
3119 // only draw polygons facing in a direction we care about
3120 if (nViewType == XY)
3122 if (face->plane.normal[2] <= 0)
3127 if (nViewType == XZ)
3129 if (face->plane.normal[1] >= 0) // stop axes being mirrored
3134 if (face->plane.normal[0] <= 0)
3140 qglBegin(GL_LINE_LOOP);
3141 for (i=0 ; i<w->numpoints ; i++)
3142 qglVertex3fv(w->points[i]);
3146 DrawBrushEntityName (b);
3155 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)
3160 for (f=b->brush_faces ; f ; f=f->next)
3161 for (i=0 ; i<3 ; i++)
3162 VectorAdd (f->planepts[i], move, f->planepts[i]);
3164 if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)
3166 for (f=b->brush_faces ; f ; f=f->next)
3169 VectorCopy(move, vTemp);
3170 Face_MoveTexture(f, vTemp);
3174 Brush_Build( b, bSnap,true,false,false); // don't filter
3179 //Patch_Move(b->nPatchID, move);
3180 Patch_Move(b->pPatch, move);
3184 // PGM - keep the origin vector up to date on fixed size entities.
3185 if(b->owner->eclass->fixedsize)
3188 VectorAdd(b->owner->origin, move, b->owner->origin);
3189 sprintf (text, "%i %i %i",
3190 (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
3191 SetKeyValue(b->owner, "origin", text);
3192 //VectorAdd(b->maxs, b->mins, b->owner->origin);
3193 //VectorScale(b->owner->origin, 0.5, b->owner->origin);
3199 void Brush_Print(brush_t* b)
3202 for (face_t* f = b->brush_faces ; f ; f=f->next)
3204 Sys_Printf("Face %i\n", nFace++);
3205 Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
3206 Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
3207 Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
3217 Makes the current brushhave the given number of 2d sides and turns it into a cone
3220 void Brush_MakeSidedCone(int sides)
3231 if (sides < 3 || sides > 32)
3233 Sys_Status ("Bad sides number", 0);
3237 if (!QE_SingleBrush ())
3239 Sys_Status ("Must have a single brush selected", 0 );
3243 b = selected_brushes.next;
3244 VectorCopy (b->mins, mins);
3245 VectorCopy (b->maxs, maxs);
3246 texdef = &g_qeglobals.d_texturewin.texdef;
3250 // find center of brush
3252 for (i=0 ; i<2 ; i++)
3254 mid[i] = (maxs[i] + mins[i])*0.5;
3255 if (maxs[i] - mins[i] > width)
3256 width = maxs[i] - mins[i];
3262 // create bottom face
3264 f->texdef = *texdef;
3265 f->next = b->brush_faces;
3268 f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
3269 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
3270 f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
3272 for (i=0 ; i<sides ; i++)
3275 f->texdef = *texdef;
3276 f->next = b->brush_faces;
3279 sv = sin (i*3.14159265*2/sides);
3280 cv = cos (i*3.14159265*2/sides);
3283 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
3284 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
3285 f->planepts[0][2] = mins[2];
3287 f->planepts[1][0] = mid[0];
3288 f->planepts[1][1] = mid[1];
3289 f->planepts[1][2] = maxs[2];
3291 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);
3292 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);
3293 f->planepts[2][2] = maxs[2];
3297 Brush_AddToList (b, &selected_brushes);
3299 Entity_LinkBrush (world_entity, b);
3303 Sys_UpdateWindows (W_ALL);
3310 Makes the current brushhave the given number of 2d sides and turns it into a sphere
3314 void Brush_MakeSidedSphere(int sides)
3323 if (sides < 4 || sides > 32)
3325 Sys_Status ("Bad sides number", 0);
3329 if (!QE_SingleBrush ())
3331 Sys_Status ("Must have a single brush selected", 0 );
3335 b = selected_brushes.next;
3336 VectorCopy (b->mins, mins);
3337 VectorCopy (b->maxs, maxs);
3338 texdef = &g_qeglobals.d_texturewin.texdef;
3342 // find center of brush
3344 for (i=0 ; i<2 ; i++)
3346 mid[i] = (maxs[i] + mins[i])*0.5;
3347 if (maxs[i] - mins[i] > radius)
3348 radius = maxs[i] - mins[i];
3354 float dt = float(2 * Q_PI / sides);
3355 float dp = float(Q_PI / sides);
3357 for(i=0; i <= sides-1; i++)
3359 for(j=0;j <= sides-2; j++)
3362 p = float(j * dp - Q_PI / 2);
3365 f->texdef = *texdef;
3366 f->next = b->brush_faces;
3369 VectorPolar(f->planepts[0], radius, t, p);
3370 VectorPolar(f->planepts[1], radius, t, p + dp);
3371 VectorPolar(f->planepts[2], radius, t + dt, p + dp);
3373 for (int k = 0; k < 3; k++)
3374 VectorAdd(f->planepts[k], mid, f->planepts[k]);
3378 p = float((sides - 1) * dp - Q_PI / 2);
3379 for(i = 0; i <= sides-1; i++)
3384 f->texdef = *texdef;
3385 f->next = b->brush_faces;
3388 VectorPolar(f->planepts[0], radius, t, p);
3389 VectorPolar(f->planepts[1], radius, t + dt, p + dp);
3390 VectorPolar(f->planepts[2], radius, t + dt, p);
3392 for (int k = 0; k < 3; k++)
3393 VectorAdd(f->planepts[k], mid, f->planepts[k]);
3396 Brush_AddToList (b, &selected_brushes);
3398 Entity_LinkBrush (world_entity, b);
3402 Sys_UpdateWindows (W_ALL);
3405 void Face_FitTexture( face_t * face, int nHeight, int nWidth )
3410 float width, height, temp;
3411 float rot_width, rot_height;
3412 float cosv,sinv,ang;
3413 float min_t, min_s, max_t, max_s;
3424 ClearBounds (mins, maxs);
3426 w = face->face_winding;