2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
\r
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
\r
5 This file is part of GtkRadiant.
\r
7 GtkRadiant is free software; you can redistribute it and/or modify
\r
8 it under the terms of the GNU General Public License as published by
\r
9 the Free Software Foundation; either version 2 of the License, or
\r
10 (at your option) any later version.
\r
12 GtkRadiant is distributed in the hope that it will be useful,
\r
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
\r
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\r
15 GNU General Public License for more details.
\r
17 You should have received a copy of the GNU General Public License
\r
18 along with GtkRadiant; if not, write to the Free Software
\r
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
\r
24 #include "winding.h"
\r
26 #include "filters.h"
\r
28 extern MainFrame* g_pParentWnd;
\r
29 extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...);
\r
35 #ifdef ENABLE_GROUPS
\r
36 const char* Brush_Name(brush_t *b)
\r
38 static char cBuff[1024];
\r
39 b->numberId = g_nBrushId++;
\r
40 if (g_qeglobals.m_bBrushPrimitMode)
\r
42 sprintf(cBuff, "Brush %i", b->numberId);
\r
43 Brush_SetEpair(b, "Name", cBuff);
\r
49 brush_t *Brush_Alloc()
\r
51 brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));
\r
55 void Brush_Free(brush_t *b)
\r
60 void PrintWinding (winding_t *w)
\r
64 Sys_Printf ("-------------\n");
\r
65 for (i=0 ; i<w->numpoints ; i++)
\r
66 Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
\r
67 , w->points[i][1], w->points[i][2]);
\r
70 void PrintPlane (plane_t *p)
\r
72 Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1],
\r
73 p->normal[2], p->dist);
\r
76 void PrintVector (vec3_t v)
\r
78 Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]);
\r
83 =============================================================================
\r
87 =============================================================================
\r
93 textureAxisFromPlane
\r
96 vec3_t baseaxis[18] =
\r
98 {0,0,1}, {1,0,0}, {0,-1,0}, // floor
\r
99 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling
\r
100 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall
\r
101 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall
\r
102 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall
\r
103 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall
\r
106 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
\r
115 for (i=0 ; i<6 ; i++)
\r
117 dot = DotProduct (pln->normal, baseaxis[i*3]);
\r
118 if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best)
\r
125 VectorCopy (baseaxis[bestaxis*3+1], xv);
\r
126 VectorCopy (baseaxis[bestaxis*3+2], yv);
\r
131 float lightaxis[3] = {0.6f, 0.8f, 1.0f};
\r
136 Light different planes differently to
\r
137 improve recognition
\r
140 extern float ShadeForNormal(vec3_t normal);
\r
142 float SetShadeForPlane (plane_t *p)
\r
144 //return ShadeForNormal(p->normal);
\r
151 for (i=0 ; i<3 ; i++)
\r
152 if (fabs(p->normal[i]) > 0.9)
\r
158 // between two axial planes
\r
159 for (i=0 ; i<3 ; i++)
\r
160 if (fabs(p->normal[i]) < 0.1)
\r
162 f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
\r
167 f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
\r
180 face_t *Face_Alloc( void )
\r
182 face_t *f = (face_t*)qmalloc( sizeof( *f ) );
\r
191 void Face_Free( face_t *f )
\r
195 if ( f->face_winding )
\r
197 free( f->face_winding );
\r
198 f->face_winding = 0;
\r
200 f->texdef.~texdef_t();;
\r
210 face_t *Face_Clone (face_t *f)
\r
215 n->texdef = f->texdef;
\r
216 n->brushprimit_texdef = f->brushprimit_texdef;
\r
218 memcpy (n->planepts, f->planepts, sizeof(n->planepts));
\r
220 // all other fields are derived, and will be set by Brush_Build
\r
221 // FIXME: maybe not, for example n->pData!
\r
229 makes an exact copy of the face
\r
232 face_t *Face_FullClone (face_t *f)
\r
237 n->texdef = f->texdef;
\r
238 n->brushprimit_texdef = f->brushprimit_texdef;
\r
239 memcpy(n->planepts, f->planepts, sizeof(n->planepts));
\r
240 memcpy(&n->plane, &f->plane, sizeof(plane_t));
\r
241 if (f->face_winding)
\r
242 n->face_winding = Winding_Clone(f->face_winding);
\r
244 n->face_winding = NULL;
\r
245 n->pShader = f->pShader;
\r
246 n->pShader->IncRef();
\r
247 n->d_texture = n->pShader->getTexture();
\r
251 void Face_SetShader(face_t *face, const char *name)
\r
253 if(face->pShader != NULL)
\r
254 face->pShader->DecRef();
\r
255 face->texdef.SetName(name);
\r
256 face->pShader = QERApp_Shader_ForName(name);
\r
257 face->pShader->IncRef();
\r
258 face->d_texture = face->pShader->getTexture();
\r
259 face->texdef.flags = face->pShader->getFlags();
\r
262 void Face_SetShader(face_t *face, IShader *shader)
\r
264 if(face->pShader != NULL)
\r
265 face->pShader->DecRef();
\r
266 face->texdef.SetName(shader->getName());
\r
267 face->d_texture = shader->getTexture();
\r
268 face->texdef.flags = shader->getFlags();
\r
269 face->pShader = shader;
\r
270 face->pShader->IncRef();
\r
278 void Clamp(float& f, int nClamp)
\r
280 float fFrac = f - static_cast<int>(f);
\r
281 f = static_cast<int>(f) % nClamp;
\r
290 void Face_MoveTexture(face_t *f, vec3_t delta)
\r
294 if (g_qeglobals.m_bBrushPrimitMode)
\r
295 ShiftTextureGeometric_BrushPrimit( f, delta );
\r
298 TextureAxisFromPlane(&f->plane, vX, vY);
\r
300 vec3_t vDP, vShift;
\r
301 vDP[0] = DotProduct(delta, vX);
\r
302 vDP[1] = DotProduct(delta, vY);
\r
304 double fAngle = f->texdef.rotate / 180 * Q_PI;
\r
305 double c = cos(fAngle);
\r
306 double s = sin(fAngle);
\r
308 vShift[0] = vDP[0] * c - vDP[1] * s;
\r
309 vShift[1] = vDP[0] * s + vDP[1] * c;
\r
311 if (!f->texdef.scale[0])
\r
312 f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale;
\r
313 if (!f->texdef.scale[1])
\r
314 f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale;
\r
316 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
\r
317 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
\r
319 // clamp the shifts
\r
320 Clamp(f->texdef.shift[0], f->d_texture->width);
\r
321 Clamp(f->texdef.shift[1], f->d_texture->height);
\r
330 /*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/
\r
331 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor)
\r
333 // set shading for face
\r
334 f->d_shade = SetShadeForPlane (&f->plane);
\r
335 f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade;
\r
336 f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade;
\r
337 f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade;
\r
342 Face_TextureVectors
\r
345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])
\r
349 float ang, sinv, cosv;
\r
356 // this code is not supposed to be used while in BP mode, warning here can help spot the problem
\r
357 if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)
\r
358 Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
\r
364 memset (STfromXYZ, 0, 8*sizeof(float));
\r
367 td->scale[0] = g_pGameDescription->mTextureDefaultScale;
\r
369 td->scale[1] = g_pGameDescription->mTextureDefaultScale;
\r
371 // get natural texture axis
\r
372 TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
\r
375 if (td->rotate == 0)
\r
376 { sinv = 0 ; cosv = 1; }
\r
377 else if (td->rotate == 90)
\r
378 { sinv = 1 ; cosv = 0; }
\r
379 else if (td->rotate == 180)
\r
380 { sinv = 0 ; cosv = -1; }
\r
381 else if (td->rotate == 270)
\r
382 { sinv = -1 ; cosv = 0; }
\r
385 ang = td->rotate / 180 * Q_PI;
\r
392 else if (pvecs[0][1])
\r
399 else if (pvecs[1][1])
\r
404 for (i=0 ; i<2 ; i++) {
\r
405 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
\r
406 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
\r
407 STfromXYZ[i][sv] = ns;
\r
408 STfromXYZ[i][tv] = nt;
\r
412 for (i=0 ; i<2 ; i++)
\r
413 for (j=0 ; j<3 ; j++)
\r
414 STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
\r
417 STfromXYZ[0][3] = td->shift[0];
\r
418 STfromXYZ[1][3] = td->shift[1];
\r
420 for (j=0 ; j<4 ; j++) {
\r
421 STfromXYZ[0][j] /= q->width;
\r
422 STfromXYZ[1][j] /= q->height;
\r
431 void Face_MakePlane (face_t *f)
\r
436 // convert to a vector / dist plane
\r
437 for (j=0 ; j<3 ; j++)
\r
439 t1[j] = f->planepts[0][j] - f->planepts[1][j];
\r
440 t2[j] = f->planepts[2][j] - f->planepts[1][j];
\r
441 t3[j] = f->planepts[1][j];
\r
444 CrossProduct(t1,t2, f->plane.normal);
\r
445 if (VectorCompare (f->plane.normal, vec3_origin))
\r
446 Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n");
\r
447 VectorNormalize (f->plane.normal, f->plane.normal);
\r
448 f->plane.dist = DotProduct (t3, f->plane.normal);
\r
453 EmitTextureCoordinates
\r
456 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
\r
458 float STfromXYZ[2][4];
\r
460 Face_TextureVectors (f, STfromXYZ);
\r
461 xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
\r
462 xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
\r
465 //==========================================================================
\r
469 Brush_MakeFacePlanes
\r
472 void Brush_MakeFacePlanes (brush_t *b)
\r
476 for (f=b->brush_faces ; f ; f=f->next)
\r
478 Face_MakePlane (f);
\r
484 DrawBrushEntityName
\r
487 void DrawBrushEntityName (brush_t *b)
\r
495 return; // during contruction
\r
497 if (b->owner == world_entity)
\r
500 if (b != b->owner->brushes.onext)
\r
501 return; // not key brush
\r
503 // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views
\r
504 // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job?
\r
505 // Brush_DrawFacingAngle() works when called, but is not being called.
\r
506 if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))
\r
508 // draw the angle pointer
\r
509 a = FloatForKey (b->owner, "angle");
\r
510 s = sin (a/180*Q_PI);
\r
511 c = cos (a/180*Q_PI);
\r
512 for (i=0 ; i<3 ; i++)
\r
513 mid[i] = (b->mins[i] + b->maxs[i])*0.5;
\r
515 qglBegin (GL_LINE_STRIP);
\r
516 qglVertex3fv (mid);
\r
520 qglVertex3fv (mid);
\r
527 qglVertex3fv (mid);
\r
534 qglVertex3fv (mid);
\r
541 qglVertex3fv (mid);
\r
545 if (g_qeglobals.d_savedinfo.show_names)
\r
547 name = ValueForKey (b->owner, "classname");
\r
548 qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
\r
549 gtk_glwidget_print_string(name);
\r
555 Brush_MakeFaceWinding
\r
557 returns the visible polygon on a face
\r
560 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)
\r
567 // get a poly that covers an effectively infinite area
\r
568 w = Winding_BaseForPlane (&face->plane);
\r
570 // chop the poly by all of the other faces
\r
572 for (clip = b->brush_faces ; clip && w ; clip=clip->next)
\r
579 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
\r
580 && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
\r
581 { // identical plane, use the later one
\r
590 // flip the plane, because we want to keep the back side
\r
591 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
\r
592 plane.dist = -clip->plane.dist;
\r
594 w = Winding_Clip (w, &plane, false);
\r
599 if (w->numpoints < 3)
\r
606 Sys_FPrintf (SYS_WRN, "unused plane\n");
\r
616 void Brush_SnapPlanepts (brush_t *b)
\r
621 if (g_PrefsDlg.m_bNoClamp)
\r
624 if (g_qeglobals.d_bSmallGrid)
\r
626 for (f=b->brush_faces ; f; f=f->next)
\r
627 for (i=0 ; i<3 ; i++)
\r
628 for (j=0 ; j<3 ; j++)
\r
629 f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize;
\r
633 for (f=b->brush_faces ; f; f=f->next)
\r
634 for (i=0 ; i<3 ; i++)
\r
635 for (j=0 ; j<3 ; j++)
\r
636 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
\r
643 ** Builds a brush rendering data and also sets the min/max bounds
\r
646 // added a bConvert flag to convert between old and new brush texture formats
\r
648 // brush grouping: update the group treeview if necessary
\r
649 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest)
\r
651 bool bLocalConvert;
\r
655 if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
\r
656 Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
\r
659 // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
\r
660 if (bConvert && !g_qeglobals.bNeedConvert)
\r
663 //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes
\r
664 // back and forth in one format or the other .. more when mixing BP / noBP in the same maps.
\r
666 bLocalConvert = true;
\r
667 g_qeglobals.bNeedConvert = true;
\r
670 bLocalConvert = false;
\r
673 ** build the windings and generate the bounding box
\r
675 Brush_BuildWindings(b, bSnap);
\r
677 if(b->owner->model.pRender)
\r
679 const aabb_t *aabb = b->owner->model.pRender->GetAABB();
\r
680 VectorAdd(aabb->origin, aabb->extents, b->maxs);
\r
681 VectorSubtract(aabb->origin, aabb->extents, b->mins);
\r
684 //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH !
\r
687 ** move the points and edges if in select mode
\r
689 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
\r
690 SetupVertexSelection ();
\r
692 if (b->itemOwner == 0) //NULL)
\r
693 Group_AddToProperGroup(b);
\r
697 Sys_MarkMapModified();
\r
701 g_qeglobals.bNeedConvert = false;
\r
703 // spog - applying filters to brush during brush_build instead of during redraw
\r
705 b->bFiltered = FilterBrush( b );
\r
710 Brush_SplitBrushByFace
\r
712 The incoming brush is NOT freed.
\r
713 The incoming face is NOT left referenced.
\r
716 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk)
\r
722 b = Brush_Clone (in);
\r
723 nf = Face_Clone (f);
\r
725 nf->texdef = b->brush_faces->texdef;
\r
728 nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
\r
730 nf->next = b->brush_faces;
\r
731 b->brush_faces = nf;
\r
734 Brush_RemoveEmptyFaces ( b );
\r
735 if ( !b->brush_faces )
\r
736 { // completely clipped away
\r
742 Entity_LinkBrush (in->owner, b);
\r
746 b = Brush_Clone (in);
\r
747 nf = Face_Clone (f);
\r
748 // swap the plane winding
\r
749 VectorCopy (nf->planepts[0], temp);
\r
750 VectorCopy (nf->planepts[1], nf->planepts[0]);
\r
751 VectorCopy (temp, nf->planepts[1]);
\r
753 nf->texdef = b->brush_faces->texdef;
\r
756 nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer());
\r
758 nf->next = b->brush_faces;
\r
759 b->brush_faces = nf;
\r
762 Brush_RemoveEmptyFaces ( b );
\r
763 if ( !b->brush_faces )
\r
764 { // completely clipped away
\r
770 Entity_LinkBrush (in->owner, b);
\r
777 Brush_BestSplitFace
\r
779 returns the best face to split the brush with.
\r
780 return NULL if the brush is convex
\r
783 face_t *Brush_BestSplitFace(brush_t *b)
\r
785 face_t *face, *f, *bestface;
\r
786 winding_t *front, *back;
\r
787 int splits, tinywindings, value, bestvalue;
\r
789 bestvalue = 999999;
\r
791 for (face = b->brush_faces; face; face = face->next)
\r
795 for (f = b->brush_faces; f; f = f->next)
\r
797 if (f == face) continue;
\r
799 Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back);
\r
803 Winding_Free(back);
\r
807 Winding_Free(front);
\r
812 if (Winding_IsTiny(front)) tinywindings++;
\r
813 if (Winding_IsTiny(back)) tinywindings++;
\r
818 value = splits + 50 * tinywindings;
\r
819 if (value < bestvalue)
\r
831 Brush_MakeConvexBrushes
\r
833 MrE FIXME: this doesn't work because the old
\r
834 Brush_SplitBrushByFace is used
\r
835 Turns the brush into a minimal number of convex brushes.
\r
836 If the input brush is convex then it will be returned.
\r
837 Otherwise the input brush will be freed.
\r
838 NOTE: the input brush should have windings for the faces.
\r
841 brush_t *Brush_MakeConvexBrushes(brush_t *b)
\r
843 brush_t *front, *back, *end;
\r
847 face = Brush_BestSplitFace(b);
\r
848 if (!face) return b;
\r
849 Brush_SplitBrushByFace(b, face, &front, &back);
\r
850 //this should never happen
\r
851 if (!front && !back) return b;
\r
854 return Brush_MakeConvexBrushes(back);
\r
855 b = Brush_MakeConvexBrushes(front);
\r
858 for (end = b; end->next; end = end->next);
\r
859 end->next = Brush_MakeConvexBrushes(back);
\r
869 int Brush_Convex(brush_t *b)
\r
871 face_t *face1, *face2;
\r
873 for (face1 = b->brush_faces; face1; face1 = face1->next)
\r
875 if (!face1->face_winding) continue;
\r
876 for (face2 = b->brush_faces; face2; face2 = face2->next)
\r
878 if (face1 == face2) continue;
\r
879 if (!face2->face_winding) continue;
\r
880 if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
\r
881 face1->plane.normal, face2->plane.normal,
\r
882 face1->plane.dist, face2->plane.dist))
\r
895 - The input brush must be convex
\r
896 - The input brush must have face windings.
\r
897 - The output brush will be convex.
\r
898 - Returns true if the WHOLE vertex movement is performed.
\r
902 // define this to debug the vertex editing mode
\r
907 #define MAX_MOVE_FACES 64
\r
909 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
\r
911 face_t *f, *face, *newface, *lastface, *nextface;
\r
912 face_t *movefaces[MAX_MOVE_FACES];
\r
913 int movefacepoints[MAX_MOVE_FACES];
\r
914 winding_t *w, tmpw;
\r
917 int i, j, k, nummovefaces, result, done;
\r
918 float dot, front, back, frac, smallestfrac;
\r
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" );
\r
926 tmpw.numpoints = 3;
\r
927 tmpw.maxpoints = 3;
\r
928 VectorCopy(vertex, start);
\r
929 VectorAdd(vertex, delta, end);
\r
932 for (i = 0; i < 3; i++)
\r
933 end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize;
\r
935 VectorCopy(end, mid);
\r
936 //if the start and end are the same
\r
937 if (Point_Equal(start, end, 0.3f)) return false;
\r
938 //the end point may not be the same as another vertex
\r
939 for (face = b->brush_faces; face; face = face->next)
\r
941 w = face->face_winding;
\r
943 for (i = 0; i < w->numpoints; i++)
\r
945 if (Point_Equal(w->points[i], end, 0.3f))
\r
947 VectorCopy(vertex, end);
\r
956 //chop off triangles from all brush faces that use the to be moved vertex
\r
957 //store pointers to these chopped off triangles in movefaces[]
\r
959 for (face = b->brush_faces; face; face = face->next)
\r
961 w = face->face_winding;
\r
963 for (i = 0; i < w->numpoints; i++)
\r
965 if (Point_Equal(w->points[i], start, 0.2f))
\r
967 if (face->face_winding->numpoints <= 3)
\r
969 movefacepoints[nummovefaces] = i;
\r
970 movefaces[nummovefaces++] = face;
\r
973 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
\r
974 //if the end point is in front of the face plane
\r
977 //fanout triangle subdivision
\r
978 for (k = i; k < i + w->numpoints-3; k++)
\r
980 VectorCopy(w->points[i], tmpw.points[0]);
\r
981 VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
\r
982 VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
\r
984 newface = Face_Clone(face);
\r
986 for (f = face; f->original; f = f->original) ;
\r
987 newface->original = f;
\r
988 //store the new winding
\r
989 if (newface->face_winding) Winding_Free(newface->face_winding);
\r
990 newface->face_winding = Winding_Clone(&tmpw);
\r
991 //get the texture information
\r
992 newface->pShader = face->pShader;
\r
993 newface->d_texture = face->d_texture;
\r
995 //add the face to the brush
\r
996 newface->next = b->brush_faces;
\r
997 b->brush_faces = newface;
\r
998 //add this new triangle to the move faces
\r
999 movefacepoints[nummovefaces] = 0;
\r
1000 movefaces[nummovefaces++] = newface;
\r
1002 //give the original face a new winding
\r
1003 VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
\r
1004 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
\r
1005 VectorCopy(w->points[i], tmpw.points[2]);
\r
1006 Winding_Free(face->face_winding);
\r
1007 face->face_winding = Winding_Clone(&tmpw);
\r
1008 //add the original face to the move faces
\r
1009 movefacepoints[nummovefaces] = 2;
\r
1010 movefaces[nummovefaces++] = face;
\r
1014 //chop a triangle off the face
\r
1015 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
\r
1016 VectorCopy(w->points[i], tmpw.points[1]);
\r
1017 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
\r
1018 //remove the point from the face winding
\r
1019 Winding_RemovePoint(w, i);
\r
1020 //get texture crap right
\r
1021 Face_SetColor(b, face, 1.0);
\r
1022 for (j = 0; j < w->numpoints; j++)
\r
1023 EmitTextureCoordinates(w->points[j], face->d_texture, face);
\r
1024 //make a triangle face
\r
1025 newface = Face_Clone(face);
\r
1026 //get the original
\r
1027 for (f = face; f->original; f = f->original) ;
\r
1028 newface->original = f;
\r
1029 //store the new winding
\r
1030 if (newface->face_winding) Winding_Free(newface->face_winding);
\r
1031 newface->face_winding = Winding_Clone(&tmpw);
\r
1033 newface->pShader = face->pShader;
\r
1034 newface->d_texture = newface->pShader->getTexture();
\r
1035 // newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name );
\r
1036 //add the face to the brush
\r
1037 newface->next = b->brush_faces;
\r
1038 b->brush_faces = newface;
\r
1040 movefacepoints[nummovefaces] = 1;
\r
1041 movefaces[nummovefaces++] = newface;
\r
1047 //now movefaces contains pointers to triangle faces that
\r
1048 //contain the to be moved vertex
\r
1051 VectorCopy(end, mid);
\r
1053 for (face = b->brush_faces; face; face = face->next)
\r
1055 //check if there is a move face that has this face as the original
\r
1056 for (i = 0; i < nummovefaces; i++)
\r
1058 if (movefaces[i]->original == face) break;
\r
1060 if (i >= nummovefaces) continue;
\r
1061 //check if the original is not a move face itself
\r
1062 for (j = 0; j < nummovefaces; j++)
\r
1064 if (face == movefaces[j]) break;
\r
1066 //if the original is not a move face itself
\r
1067 if (j >= nummovefaces)
\r
1069 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));
\r
1073 k = movefacepoints[j];
\r
1074 w = movefaces[j]->face_winding;
\r
1075 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);
\r
1076 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);
\r
1078 k = movefacepoints[i];
\r
1079 w = movefaces[i]->face_winding;
\r
1080 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);
\r
1081 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
\r
1083 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);
\r
1084 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
\r
1085 //this should never happen otherwise the face merge did a crappy job a previous pass
\r
1089 //now we've got the plane to check agains
\r
1090 front = DotProduct(start, plane.normal) - plane.dist;
\r
1091 back = DotProduct(end, plane.normal) - plane.dist;
\r
1092 //if the whole move is at one side of the plane
\r
1093 if (front < 0.01 && back < 0.01) continue;
\r
1094 if (front > -0.01 && back > -0.01) continue;
\r
1095 //if there's no movement orthogonal to this plane at all
\r
1096 if (fabs(front-back) < 0.001) continue;
\r
1097 //ok first only move till the plane is hit
\r
1098 frac = front/(front-back);
\r
1099 if (frac < smallestfrac)
\r
1101 mid[0] = start[0] + (end[0] - start[0]) * frac;
\r
1102 mid[1] = start[1] + (end[1] - start[1]) * frac;
\r
1103 mid[2] = start[2] + (end[2] - start[2]) * frac;
\r
1104 smallestfrac = frac;
\r
1111 for (i = 0; i < nummovefaces; i++)
\r
1113 //move vertex to end position
\r
1114 VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);
\r
1115 //create new face plane
\r
1116 for (j = 0; j < 3; j++)
\r
1118 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
\r
1120 Face_MakePlane(movefaces[i]);
\r
1121 if (VectorLength(movefaces[i]->plane.normal) < 0.1)
\r
1124 //if the brush is no longer convex
\r
1125 if (!result || !Brush_Convex(b))
\r
1127 for (i = 0; i < nummovefaces; i++)
\r
1129 //move the vertex back to the initial position
\r
1130 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);
\r
1131 //create new face plane
\r
1132 for (j = 0; j < 3; j++)
\r
1134 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
\r
1136 Face_MakePlane(movefaces[i]);
\r
1139 VectorCopy(start, end);
\r
1144 VectorCopy(mid, start);
\r
1146 //get texture crap right
\r
1147 for (i = 0; i < nummovefaces; i++)
\r
1149 Face_SetColor(b, movefaces[i], 1.0);
\r
1150 for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
\r
1151 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
\r
1154 //now try to merge faces with their original faces
\r
1156 for (face = b->brush_faces; face; face = nextface)
\r
1158 nextface = face->next;
\r
1159 if (!face->original)
\r
1164 if (!Plane_Equal(&face->plane, &face->original->plane, false))
\r
1169 w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
\r
1175 Winding_Free(face->original->face_winding);
\r
1176 face->original->face_winding = w;
\r
1177 //get texture crap right
\r
1178 Face_SetColor(b, face->original, 1.0);
\r
1179 for (j = 0; j < face->original->face_winding->numpoints; j++)
\r
1180 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
\r
1181 //remove the face that was merged with the original
\r
1182 if (lastface) lastface->next = face->next;
\r
1183 else b->brush_faces = face->next;
\r
1192 Brush_InsertVertexBetween
\r
1195 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)
\r
1198 winding_t *w, *neww;
\r
1202 if (Point_Equal(p1, p2, 0.4f))
\r
1204 VectorAdd(p1, p2, point);
\r
1205 VectorScale(point, 0.5f, point);
\r
1207 //the end point may not be the same as another vertex
\r
1208 for (face = b->brush_faces; face; face = face->next)
\r
1210 w = face->face_winding;
\r
1213 for (i = 0; i < w->numpoints; i++)
\r
1215 if (!Point_Equal(w->points[i], p1, 0.1f))
\r
1217 if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f))
\r
1219 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);
\r
1222 else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f))
\r
1224 neww = Winding_InsertPoint(w, point, i);
\r
1230 Winding_Free(face->face_winding);
\r
1231 face->face_winding = neww;
\r
1241 Brush_ResetFaceOriginals
\r
1244 void Brush_ResetFaceOriginals(brush_t *b)
\r
1248 for (face = b->brush_faces; face; face = face->next)
\r
1250 face->original = NULL;
\r
1254 #ifdef ENABLE_GROUPS
\r
1258 sets an epair for the given brush
\r
1261 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)
\r
1263 if (g_qeglobals.m_bBrushPrimitMode)
\r
1265 if (b->patchBrush)
\r
1267 Patch_SetEpair(b->pPatch, pKey, pValue);
\r
1271 SetKeyValue(b->epairs, pKey, pValue);
\r
1276 Sys_Printf("Can only set key/values in Brush primitive mode\n");
\r
1285 const char* Brush_GetKeyValue(brush_t *b, const char *pKey)
\r
1287 if (g_qeglobals.m_bBrushPrimitMode)
\r
1289 if (b->patchBrush)
\r
1291 return Patch_GetKeyValue(b->pPatch, pKey);
\r
1295 return ValueForKey(b->epairs, pKey);
\r
1300 Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");
\r
1308 temporary stuff, detect potential problems when saving the texture name
\r
1311 void CheckName( face_t *fa, char *pname )
\r
1313 if (!strlen(fa->texdef.GetName()))
\r
1316 Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n");
\r
1318 fa->texdef.SetName(SHADER_NOT_FOUND);
\r
1319 strcpy(pname, SHADER_NOT_FOUND);
\r
1323 // some people manage to get long filename textures (with spaces) in their maps
\r
1324 if (strchr( fa->texdef.GetName(), ' ' ))
\r
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() );
\r
1330 Sys_Printf("%s\n", Msg1 );
\r
1331 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
\r
1332 strcpy( pname, SHADER_NOT_FOUND );
\r
1336 //++timo FIXME: bug #103494 detection attempt
\r
1337 // TODO: clean this detection part when bug will have disappeared
\r
1338 if (fa->texdef.GetName()[0] == '(')
\r
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.";
\r
1341 Sys_Printf("%s\n", text);
\r
1342 gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK );
\r
1343 // need to cleanup this dead face name or we may loop endlessly
\r
1344 fa->texdef.SetName(SHADER_NOT_FOUND);
\r
1345 strcpy( pname, SHADER_NOT_FOUND );
\r
1348 strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/"
\r
1355 Create non-textured blocks for entities
\r
1356 The brush is NOT linked to any list
\r
1359 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
\r
1367 // brush primitive mode : convert texdef to brushprimit_texdef ?
\r
1368 // most of the time texdef is empty
\r
1369 if (g_qeglobals.m_bBrushPrimitMode)
\r
1371 // check texdef is empty .. if there are cases it's not we need to write some conversion code
\r
1372 if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)
\r
1373 Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");
\r
1377 for (i=0 ; i<3 ; i++)
\r
1379 if (maxs[i] < mins[i])
\r
1380 Error ("Brush_InitSolid: backwards");
\r
1383 b = Brush_Alloc();
\r
1385 pts[0][0][0] = mins[0];
\r
1386 pts[0][0][1] = mins[1];
\r
1388 pts[1][0][0] = mins[0];
\r
1389 pts[1][0][1] = maxs[1];
\r
1391 pts[2][0][0] = maxs[0];
\r
1392 pts[2][0][1] = maxs[1];
\r
1394 pts[3][0][0] = maxs[0];
\r
1395 pts[3][0][1] = mins[1];
\r
1397 for (i=0 ; i<4 ; i++)
\r
1399 pts[i][0][2] = mins[2];
\r
1400 pts[i][1][0] = pts[i][0][0];
\r
1401 pts[i][1][1] = pts[i][0][1];
\r
1402 pts[i][1][2] = maxs[2];
\r
1405 for (i=0 ; i<4 ; i++)
\r
1408 f->texdef = *texdef;
\r
1409 f->texdef.flags &= ~SURF_KEEP;
\r
1410 f->texdef.contents &= ~CONTENTS_KEEP;
\r
1411 f->next = b->brush_faces;
\r
1412 b->brush_faces = f;
\r
1415 VectorCopy (pts[j][1], f->planepts[0]);
\r
1416 VectorCopy (pts[i][1], f->planepts[1]);
\r
1417 VectorCopy (pts[i][0], f->planepts[2]);
\r
1421 f->texdef = *texdef;
\r
1422 f->texdef.flags &= ~SURF_KEEP;
\r
1423 f->texdef.contents &= ~CONTENTS_KEEP;
\r
1424 f->next = b->brush_faces;
\r
1425 b->brush_faces = f;
\r
1427 VectorCopy (pts[0][1], f->planepts[0]);
\r
1428 VectorCopy (pts[1][1], f->planepts[1]);
\r
1429 VectorCopy (pts[2][1], f->planepts[2]);
\r
1432 f->texdef = *texdef;
\r
1433 f->texdef.flags &= ~SURF_KEEP;
\r
1434 f->texdef.contents &= ~CONTENTS_KEEP;
\r
1435 f->next = b->brush_faces;
\r
1436 b->brush_faces = f;
\r
1438 VectorCopy (pts[2][0], f->planepts[0]);
\r
1439 VectorCopy (pts[1][0], f->planepts[1]);
\r
1440 VectorCopy (pts[0][0], f->planepts[2]);
\r
1447 Brush_CreatePyramid
\r
1449 Create non-textured pyramid for light entities
\r
1450 The brush is NOT linked to any list
\r
1453 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)
\r
1457 //++timo handle new brush primitive ? return here ??
\r
1458 return Brush_Create(mins, maxs, texdef);
\r
1460 for (i=0 ; i<3 ; i++)
\r
1461 if (maxs[i] < mins[i])
\r
1462 Error ("Brush_InitSolid: backwards");
\r
1464 brush_t* b = Brush_Alloc();
\r
1466 vec3_t corners[4];
\r
1468 float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2)));
\r
1470 corners[0][0] = mins[0];
\r
1471 corners[0][1] = mins[1];
\r
1472 corners[0][2] = fMid;
\r
1474 corners[1][0] = mins[0];
\r
1475 corners[1][1] = maxs[1];
\r
1476 corners[1][2] = fMid;
\r
1478 corners[2][0] = maxs[0];
\r
1479 corners[2][1] = maxs[1];
\r
1480 corners[2][2] = fMid;
\r
1482 corners[3][0] = maxs[0];
\r
1483 corners[3][1] = mins[1];
\r
1484 corners[3][2] = fMid;
\r
1486 vec3_t top, bottom;
\r
1488 top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2));
\r
1489 top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2));
\r
1490 top[2] = Rad_rint(maxs[2]);
\r
1492 VectorCopy(top, bottom);
\r
1493 bottom[2] = mins[2];
\r
1496 for (i = 0; i < 4; i++)
\r
1498 face_t* f = Face_Alloc();
\r
1499 f->texdef = *texdef;
\r
1500 f->texdef.flags &= ~SURF_KEEP;
\r
1501 f->texdef.contents &= ~CONTENTS_KEEP;
\r
1502 f->next = b->brush_faces;
\r
1503 b->brush_faces = f;
\r
1506 VectorCopy (top, f->planepts[0]);
\r
1507 VectorCopy (corners[i], f->planepts[1]);
\r
1508 VectorCopy(corners[j], f->planepts[2]);
\r
1511 f->texdef = *texdef;
\r
1512 f->texdef.flags &= ~SURF_KEEP;
\r
1513 f->texdef.contents &= ~CONTENTS_KEEP;
\r
1514 f->next = b->brush_faces;
\r
1515 b->brush_faces = f;
\r
1517 VectorCopy (bottom, f->planepts[2]);
\r
1518 VectorCopy (corners[i], f->planepts[1]);
\r
1519 VectorCopy(corners[j], f->planepts[0]);
\r
1532 Makes the current brush have the given number of 2d sides
\r
1535 void Brush_MakeSided (int sides)
\r
1538 vec3_t mins, maxs;
\r
1548 Sys_Status ("Bad sides number", 0);
\r
1552 if (sides >= MAX_POINTS_ON_WINDING-4)
\r
1554 Sys_Printf("too many sides.\n");
\r
1558 if (!QE_SingleBrush ())
\r
1560 Sys_Status ("Must have a single brush selected", 0 );
\r
1564 b = selected_brushes.next;
\r
1565 VectorCopy (b->mins, mins);
\r
1566 VectorCopy (b->maxs, maxs);
\r
1567 texdef = &g_qeglobals.d_texturewin.texdef;
\r
1571 if (g_pParentWnd->ActiveXY())
\r
1573 switch(g_pParentWnd->ActiveXY()->GetViewType())
\r
1575 case XY: axis = 2; break;
\r
1576 case XZ: axis = 1; break;
\r
1577 case YZ: axis = 0; break;
\r
1585 // find center of brush
\r
1587 for (i = 0; i < 3; i++)
\r
1589 mid[i] = (maxs[i] + mins[i]) * 0.5;
\r
1590 if (i == axis) continue;
\r
1591 if ((maxs[i] - mins[i]) * 0.5 > width)
\r
1592 width = (maxs[i] - mins[i]) * 0.5;
\r
1595 b = Brush_Alloc();
\r
1597 // create top face
\r
1599 f->texdef = *texdef;
\r
1600 f->next = b->brush_faces;
\r
1601 b->brush_faces = f;
\r
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];
\r
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];
\r
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];
\r
1607 // create bottom face
\r
1609 f->texdef = *texdef;
\r
1610 f->next = b->brush_faces;
\r
1611 b->brush_faces = f;
\r
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];
\r
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];
\r
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];
\r
1617 for (i=0 ; i<sides ; i++)
\r
1620 f->texdef = *texdef;
\r
1621 f->next = b->brush_faces;
\r
1622 b->brush_faces = f;
\r
1624 sv = sin (i*3.14159265*2/sides);
\r
1625 cv = cos (i*3.14159265*2/sides);
\r
1627 f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);
\r
1628 f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);
\r
1629 f->planepts[0][axis] = mins[axis];
\r
1631 f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];
\r
1632 f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];
\r
1633 f->planepts[1][axis] = maxs[axis];
\r
1635 f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);
\r
1636 f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);
\r
1637 f->planepts[2][axis] = maxs[axis];
\r
1640 Brush_AddToList (b, &selected_brushes);
\r
1642 Entity_LinkBrush (world_entity, b);
\r
1646 Sys_UpdateWindows (W_ALL);
\r
1655 Frees the brush with all of its faces and display list.
\r
1656 Unlinks the brush from whichever chain it is in.
\r
1657 Decrements the owner entity's brushcount.
\r
1658 Removes owner entity if this was the last brush
\r
1659 unless owner is the world.
\r
1660 Removes from groups
\r
1663 void Brush_Free (brush_t *b, bool bRemoveNode)
\r
1666 epair_t *ep, *enext;
\r
1668 // remove from group
\r
1670 Group_RemoveBrush(b);
\r
1672 // free the patch if it's there
\r
1673 if (b->patchBrush)
\r
1675 Patch_Delete(b->pPatch);
\r
1679 for (f=b->brush_faces ; f ; f=next)
\r
1685 // TTimo : free brush epairs
\r
1686 for (ep = b->epairs ; ep ; ep=enext )
\r
1694 // unlink from active/selected list
\r
1696 Brush_RemoveFromList (b);
\r
1698 // unlink from entity list
\r
1700 Entity_UnlinkBrush (b);
\r
1710 int Face_MemorySize(face_t *f )
\r
1714 if (f->face_winding)
\r
1716 // size += _msize(f->face_winding);
\r
1717 size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int);
\r
1719 // size += _msize(f);
\r
1720 size += sizeof(face_t);
\r
1729 int Brush_MemorySize(brush_t *b)
\r
1736 if (b->patchBrush)
\r
1738 size += Patch_MemorySize(b->pPatch);
\r
1741 for (f = b->brush_faces; f; f = f->next)
\r
1743 size += Face_MemorySize(f);
\r
1746 for (ep = b->epairs; ep; ep = ep->next )
\r
1748 // size += _msize(ep->key);
\r
1749 size += strlen(ep->key);
\r
1750 // size += _msize(ep->value);
\r
1751 size += strlen(ep->value);
\r
1752 // size += _msize(ep);
\r
1753 size += sizeof(epair_t);
\r
1755 // size += _msize(b);
\r
1756 size += sizeof(brush_t);
\r
1765 Does NOT add the new brush to any lists
\r
1768 brush_t *Brush_Clone (brush_t *b)
\r
1770 brush_t *n = NULL;
\r
1773 if (b->patchBrush)
\r
1775 patchMesh_t *p = Patch_Duplicate(b->pPatch);
\r
1776 Brush_RemoveFromList(p->pSymbiot);
\r
1777 Entity_UnlinkBrush(p->pSymbiot);
\r
1782 n = Brush_Alloc();
\r
1783 n->numberId = g_nBrushId++;
\r
1784 n->owner = b->owner;
\r
1785 for (f=b->brush_faces ; f ; f=f->next)
\r
1787 nf = Face_Clone( f );
\r
1788 nf->next = n->brush_faces;
\r
1789 n->brush_faces = nf;
\r
1800 Does NOT add the new brush to any lists
\r
1803 brush_t *Brush_FullClone(brush_t *b)
\r
1805 brush_t *n = NULL;
\r
1806 face_t *f, *nf, *f2, *nf2;
\r
1809 if (b->patchBrush)
\r
1811 patchMesh_t *p = Patch_Duplicate(b->pPatch);
\r
1812 Brush_RemoveFromList(p->pSymbiot);
\r
1813 Entity_UnlinkBrush(p->pSymbiot);
\r
1815 n->owner = b->owner;
\r
1820 n = Brush_Alloc();
\r
1821 n->numberId = g_nBrushId++;
\r
1822 n->owner = b->owner;
\r
1823 VectorCopy(b->mins, n->mins);
\r
1824 VectorCopy(b->maxs, n->maxs);
\r
1826 for (f = b->brush_faces; f; f = f->next)
\r
1828 if (f->original) continue;
\r
1829 nf = Face_FullClone(f);
\r
1830 nf->next = n->brush_faces;
\r
1831 n->brush_faces = nf;
\r
1832 //copy all faces that have the original set to this face
\r
1833 for (f2 = b->brush_faces; f2; f2 = f2->next)
\r
1835 if (f2->original == f)
\r
1837 nf2 = Face_FullClone(f2);
\r
1838 nf2->next = n->brush_faces;
\r
1839 n->brush_faces = nf2;
\r
1841 nf2->original = nf;
\r
1845 for (nf = n->brush_faces; nf; nf = nf->next)
\r
1847 Face_SetColor(n, nf, 1.0);
\r
1848 if (nf->face_winding)
\r
1850 if (g_qeglobals.m_bBrushPrimitMode)
\r
1851 EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);
\r
1854 for (j = 0; j < nf->face_winding->numpoints; j++)
\r
1855 EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);
\r
1863 // FIXME - spog - finish this later..
\r
1865 bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3)
\r
1868 vec3_t v1, v2, normal[3];
\r
1871 //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]);
\r
1872 //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]);
\r
1873 //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]);
\r
1874 //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]);
\r
1876 // test ray against triangle
\r
1877 // get triangle plane normal
\r
1878 //VectorSubtract(p1, p2, v1);
\r
1879 //VectorSubtract(p1, p3, v2);
\r
1880 //CrossProduct(v1, v2, v1);
\r
1881 // check normal against direction
\r
1882 //if (DotProduct(dir, v1) >= 0)
\r
1884 // generate cone normals
\r
1885 VectorSubtract(origin, p1, v1);
\r
1886 VectorSubtract(origin, p2, v2);
\r
1887 CrossProduct(v1, v2, normal[0]);
\r
1888 VectorSubtract(origin, p2, v1);
\r
1889 VectorSubtract(origin, p3, v2);
\r
1890 CrossProduct(v1, v2, normal[1]);
\r
1891 VectorSubtract(origin, p3, v1);
\r
1892 VectorSubtract(origin, p1, v2);
\r
1893 CrossProduct(v1, v2, normal[2]);
\r
1897 // flip normals if triangle faces away
\r
1898 // Sys_Printf("flipped\n");
\r
1899 // VectorSubtract(origin, p1, v1);
\r
1900 // VectorSubtract(origin, p3, v2);
\r
1901 // CrossProduct(v1, v2, normal[0]);
\r
1902 // VectorSubtract(origin, p3, v1);
\r
1903 // VectorSubtract(origin, p2, v2);
\r
1904 // CrossProduct(v1, v2, normal[1]);
\r
1905 // VectorSubtract(origin, p2, v1);
\r
1906 // VectorSubtract(origin, p1, v2);
\r
1907 // CrossProduct(v1, v2, normal[2]);
\r
1910 for (i=0; i<3; i++)
\r
1912 VectorNormalize(normal[i]);
\r
1913 //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]);
\r
1914 //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]);
\r
1915 d = DotProduct(dir, normal[i]);
\r
1916 //Sys_Printf("dotproduct: %f\n",d);
\r
1925 extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
\r
1926 float vert0[3], float vert1[3], float vert2[3],
\r
1927 double *t, double *u, double *v);
\r
1929 bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
\r
1931 bool bIntersect = false;
\r
1932 float tBest = FLT_MAX;
\r
1937 float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set
\r
1939 VectorSubtract (origin, b->owner->origin, vRay[0]);
\r
1940 VectorCopy (dir, vRay[1]);
\r
1948 s = sin (-angle/180*Q_PI);
\r
1949 c = cos (-angle/180*Q_PI);
\r
1951 for (i=0; i<2; i++)
\r
1955 vRay[i][0] = (x * c) - (y * s);
\r
1956 vRay[i][1] = (x * s) + (y * c);
\r
1960 entitymodel *model = b->owner->md3Class->model;
\r
1962 while (model != NULL)
\r
1964 for (i = 0; i < model->nTriCount; i++)
\r
1966 for (j = 0; j < 3; j++)
\r
1967 VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]);
\r
1969 if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v))
\r
1971 bIntersect = true;
\r
1976 model = model->pNext;
\r
1995 Itersects a ray with a brush
\r
1996 Returns the face hit and the distance along the ray the intersection occured at
\r
1997 Returns NULL and 0 if not hit at all
\r
1999 http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556
\r
2002 extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v);
\r
2003 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags)
\r
2005 face_t *f, *firstface = NULL;
\r
2007 float frac, d1, d2;
\r
2010 if (b->owner->eclass->fixedsize
\r
2011 && b->owner->model.pSelect
\r
2012 && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))
\r
2013 && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX)
\r
2016 vec_t dist_local = FLT_MAX;
\r
2017 ray_construct_for_vec3(&ray_local, origin, dir);
\r
2018 if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local))
\r
2020 *dist = dist_local;
\r
2021 return b->brush_faces;
\r
2030 VectorCopy (origin, p1);
\r
2031 for (i=0 ; i<3 ; i++)
\r
2032 p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord;
\r
2034 for (f=b->brush_faces ; f ; f=f->next)
\r
2036 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
\r
2037 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
\r
2038 if (d1 >= 0 && d2 >= 0)
\r
2041 return NULL; // ray is on front side of face
\r
2043 if (d1 <=0 && d2 <= 0)
\r
2045 // clip the ray to the plane
\r
2046 frac = d1 / (d1 - d2);
\r
2050 for (i=0 ; i<3 ; i++)
\r
2051 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
\r
2055 for (i=0 ; i<3 ; i++)
\r
2056 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
\r
2060 // find distance p1 is along dir
\r
2061 VectorSubtract (p1, origin, p1);
\r
2062 d1 = DotProduct (p1, dir);
\r
2066 // new test stuff for patches
\r
2067 if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush)
\r
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
\r
2070 if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v))
\r
2078 //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v);
\r
2082 // IMPORTANT NOTE:
\r
2083 // modifications to the discarding code here should be matched in the selection code
\r
2084 // see Brush_Draw
\r
2086 // do some last minute filtering
\r
2087 if (firstface && nFlags & SF_CAMERA)
\r
2089 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
\r
2091 if (strstr(firstface->texdef.GetName(), "caulk"))
\r
2097 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
\r
2099 if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster"))
\r
2105 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
\r
2107 if (strstr(firstface->texdef.GetName(), "clip"))
\r
2119 face_t *Brush_Point (vec3_t origin, brush_t *b)
\r
2124 for (f=b->brush_faces ; f ; f=f->next)
\r
2126 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;
\r
2129 return NULL; // point is on front side of face
\r
2133 return b->brush_faces;
\r
2138 void Brush_AddToList (brush_t *b, brush_t *blist)
\r
2140 if (b->next || b->prev)
\r
2141 Error ("Brush_AddToList: already linked");
\r
2143 if (blist == &selected_brushes || blist == &active_brushes)
\r
2145 if (b->patchBrush && blist == &selected_brushes)
\r
2147 Patch_Select(b->pPatch);
\r
2150 b->next = blist->next;
\r
2151 blist->next->prev = b;
\r
2155 // TTimo messaging
\r
2156 DispatchRadiantMsg( RADIANT_SELECTION );
\r
2159 void Brush_RemoveFromList (brush_t *b)
\r
2161 if (!b->next || !b->prev)
\r
2162 Error ("Brush_RemoveFromList: not linked");
\r
2164 if (b->patchBrush)
\r
2166 Patch_Deselect(b->pPatch);
\r
2168 b->next->prev = b->prev;
\r
2169 b->prev->next = b->next;
\r
2170 b->next = b->prev = NULL;
\r
2177 Doesn't set the curve flags
\r
2180 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
\r
2181 use Texture_ForName() to find the right shader
\r
2182 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
\r
2184 TTimo: surface plugin, added an IPluginTexdef* parameter
\r
2185 if not NULL, get ->Copy() of it into the face ( and remember to hook )
\r
2186 if NULL, ask for a default
\r
2188 TTimo - shader code cleanup
\r
2189 added IShader* parameter
\r
2192 void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
\r
2197 oldFlags = f->texdef.flags;
\r
2198 oldContents = f->texdef.contents;
\r
2199 if (g_qeglobals.m_bBrushPrimitMode)
\r
2201 f->texdef = *texdef;
\r
2202 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
\r
2207 f->texdef = *texdef;
\r
2208 // fit the scaling of the texture on the actual plane
\r
2209 vec3_t p1,p2,p3; // absolute coordinates
\r
2210 // compute absolute coordinates
\r
2211 ComputeAbsolute(f,p1,p2,p3);
\r
2212 // compute the scale
\r
2214 VectorSubtract(p2,p1,vx);
\r
2215 VectorNormalize(vx, vx);
\r
2216 VectorSubtract(p3,p1,vy);
\r
2217 VectorNormalize(vy, vy);
\r
2219 VectorScale(vx,texdef->scale[0],vx);
\r
2220 VectorScale(vy,texdef->scale[1],vy);
\r
2221 VectorAdd(p1,vx,p2);
\r
2222 VectorAdd(p1,vy,p3);
\r
2223 // compute back shift scale rot
\r
2224 AbsoluteToLocal(f->plane,f,p1,p2,p3);
\r
2227 f->texdef = *texdef;
\r
2228 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
\r
2229 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
\r
2231 // if this is a curve face, set all other curve faces to the same texdef
\r
2232 if (f->texdef.flags & SURF_CURVE)
\r
2234 for (tf = b->brush_faces ; tf ; tf = tf->next)
\r
2236 if (tf->texdef.flags & SURF_CURVE)
\r
2237 tf->texdef = f->texdef;
\r
2246 Doesn't set the curve flags
\r
2249 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
\r
2250 use Texture_ForName() to find the right shader
\r
2251 FIXME : send the right shader ( qtexture_t * ) in the parameters ?
\r
2253 TTimo: surface plugin, added an IPluginTexdef* parameter
\r
2254 if not NULL, get ->Copy() of it into the face ( and remember to hook )
\r
2255 if NULL, ask for a default
\r
2258 void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
\r
2262 oldFlags = f->texdef.flags;
\r
2263 oldContents = f->texdef.contents;
\r
2265 if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build
\r
2266 Face_SetShader(f, texdef->GetName());
\r
2268 if (g_qeglobals.m_bBrushPrimitMode)
\r
2270 f->texdef = *texdef;
\r
2271 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() );
\r
2277 f->texdef = *texdef;
\r
2278 // fit the scaling of the texture on the actual plane
\r
2279 vec3_t p1,p2,p3; // absolute coordinates
\r
2280 // compute absolute coordinates
\r
2281 ComputeAbsolute(f,p1,p2,p3);
\r
2282 // compute the scale
\r
2284 VectorSubtract(p2,p1,vx);
\r
2285 VectorNormalize(vx, vx);
\r
2286 VectorSubtract(p3,p1,vy);
\r
2287 VectorNormalize(vy, vy);
\r
2289 VectorScale(vx,texdef->scale[0],vx);
\r
2290 VectorScale(vy,texdef->scale[1],vy);
\r
2291 VectorAdd(p1,vx,p2);
\r
2292 VectorAdd(p1,vy,p3);
\r
2293 // compute back shift scale rot
\r
2294 AbsoluteToLocal(f->plane,f,p1,p2,p3);
\r
2298 f->texdef = *texdef;
\r
2301 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
\r
2302 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
\r
2306 void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
\r
2308 for (face_t* f = b->brush_faces ; f ; f = f->next)
\r
2309 SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef);
\r
2311 if (b->patchBrush)
\r
2313 Patch_SetTexture(b->pPatch, texdef, pTexdef );
\r
2314 b->bFiltered = FilterBrush( b );
\r
2319 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
\r
2321 for (face_t* f = b->brush_faces ; f ; f = f->next)
\r
2322 SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef);
\r
2324 if (b->patchBrush)
\r
2326 Patch_SetTexture(b->pPatch, texdef, pTexdef );
\r
2327 b->bFiltered = FilterBrush( b );
\r
2332 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
\r
2338 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
\r
2339 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
\r
2341 if (d1 >= 0 && d2 >= 0)
\r
2342 return false; // totally outside
\r
2343 if (d1 <= 0 && d2 <= 0)
\r
2344 return true; // totally inside
\r
2346 fr = d1 / (d1 - d2);
\r
2353 for (i=0 ; i<3 ; i++)
\r
2354 v[i] = p1[i] + fr*(p2[i] - p1[i]);
\r
2360 int AddPlanept (float *f)
\r
2364 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
\r
2365 if (g_qeglobals.d_move_points[i] == f)
\r
2367 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
\r
2373 Brush_SelectFaceForDragging
\r
2375 Adds the faces planepts to move_points, and
\r
2376 rotates and adds the planepts of adjacent face if shear is set
\r
2379 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
\r
2388 if (b->owner->eclass->fixedsize)
\r
2392 for (i=0 ; i<3 ; i++)
\r
2393 c += AddPlanept (f->planepts[i]);
\r
2395 return; // already completely added
\r
2397 // select all points on this plane in all brushes the selection
\r
2398 for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
\r
2402 for (f2=b2->brush_faces ; f2 ; f2=f2->next)
\r
2404 for (i=0 ; i<3 ; i++)
\r
2405 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
\r
2406 -f->plane.dist) > ON_EPSILON)
\r
2409 { // move this face as well
\r
2410 Brush_SelectFaceForDragging (b2, f2, shear);
\r
2417 // if shearing, take all the planes adjacent to
\r
2418 // selected faces and rotate their points so the
\r
2419 // edge clipped by a selcted face has two of the points
\r
2423 for (f2=b->brush_faces ; f2 ; f2=f2->next)
\r
2427 w = Brush_MakeFaceWinding (b, f2);
\r
2431 // any points on f will become new control points
\r
2432 for (i=0 ; i<w->numpoints ; i++)
\r
2434 d = DotProduct (w->points[i], f->plane.normal)
\r
2436 if (d > -ON_EPSILON && d < ON_EPSILON)
\r
2441 // if none of the points were on the plane,
\r
2444 if (i != w->numpoints)
\r
2447 { // see if the first clockwise point was the
\r
2448 // last point on the winding
\r
2449 d = DotProduct (w->points[w->numpoints-1]
\r
2450 , f->plane.normal) - f->plane.dist;
\r
2451 if (d > -ON_EPSILON && d < ON_EPSILON)
\r
2452 i = w->numpoints - 1;
\r
2455 AddPlanept (f2->planepts[0]);
\r
2457 VectorCopy (w->points[i], f2->planepts[0]);
\r
2458 if (++i == w->numpoints)
\r
2461 // see if the next point is also on the plane
\r
2462 d = DotProduct (w->points[i]
\r
2463 , f->plane.normal) - f->plane.dist;
\r
2464 if (d > -ON_EPSILON && d < ON_EPSILON)
\r
2465 AddPlanept (f2->planepts[1]);
\r
2467 VectorCopy (w->points[i], f2->planepts[1]);
\r
2468 if (++i == w->numpoints)
\r
2471 // the third point is never on the plane
\r
2473 VectorCopy (w->points[i], f2->planepts[2]);
\r
2484 The mouse click did not hit the brush, so grab one or more side
\r
2485 planes for dragging
\r
2488 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
\r
2494 for (f=b->brush_faces ; f ; f=f->next)
\r
2496 VectorCopy (origin, p1);
\r
2497 VectorMA (origin, 2*g_MaxWorldCoord, dir, p2);
\r
2499 for (f2=b->brush_faces ; f2 ; f2=f2->next)
\r
2503 ClipLineToFace (p1, p2, f2);
\r
2509 if (VectorCompare (p1, origin))
\r
2511 if (ClipLineToFace (p1, p2, f))
\r
2514 Brush_SelectFaceForDragging (b, f, shear);
\r
2518 bool g_bBuildWindingsNoTexBuild = false;
\r
2520 void Brush_SetBuildWindingsNoTexBuild(bool bBuild)
\r
2522 g_bBuildWindingsNoTexBuild = bBuild;
\r
2525 // TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary
\r
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
\r
2527 // ie when we want to update a shader
\r
2528 // default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild
\r
2529 void Brush_BuildWindings( brush_t *b, bool bSnap )
\r
2536 Brush_SnapPlanepts( b );
\r
2538 // clear the mins/maxs bounds
\r
2539 b->mins[0] = b->mins[1] = b->mins[2] = 99999;
\r
2540 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
\r
2542 Brush_MakeFacePlanes (b);
\r
2544 face = b->brush_faces;
\r
2546 float fCurveColor = 1.0;
\r
2548 for ( ; face ; face=face->next)
\r
2551 free(face->face_winding);
\r
2552 w = face->face_winding = Brush_MakeFaceWinding (b, face);
\r
2554 if (!g_bBuildWindingsNoTexBuild || !face->d_texture)
\r
2557 // if there's no d_texture, then we expect pShader to be empty
\r
2558 if (!face->d_texture && face->pShader)
\r
2559 Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n");
\r
2561 if ((!face->d_texture && !face->pShader) || !face->pShader)
\r
2564 // patch 84 for bug 253 doesn't dec ref the potential face->pShader
\r
2565 // add a debug check to make sure this is actually not necessary
\r
2567 if (face->pShader)
\r
2569 Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n");
\r
2572 face->pShader = QERApp_Shader_ForName( face->texdef.GetName() );
\r
2573 face->pShader->IncRef();
\r
2574 face->d_texture = face->pShader->getTexture();
\r
2581 for (i=0 ; i<w->numpoints ; i++)
\r
2583 // add to bounding box
\r
2584 for (j=0 ; j<3 ; j++)
\r
2586 v = w->points[i][j];
\r
2587 if (v > b->maxs[j])
\r
2589 if (v < b->mins[j])
\r
2593 Face_SetColor (b, face, fCurveColor);
\r
2595 fCurveColor -= .10f;
\r
2596 if (fCurveColor <= 0)
\r
2597 fCurveColor = 1.0f;
\r
2599 // computing ST coordinates for the windings
\r
2600 if (g_qeglobals.m_bBrushPrimitMode)
\r
2602 if (g_qeglobals.bNeedConvert)
\r
2604 // we have parsed old brushes format and need conversion
\r
2605 // convert old brush texture representation to new format
\r
2606 FaceToBrushPrimitFace(face);
\r
2608 // use old texture coordinates code to check against
\r
2609 for (i=0 ; i<w->numpoints ; i++)
\r
2610 EmitTextureCoordinates( w->points[i], face->d_texture, face);
\r
2613 // use new texture representation to compute texture coordinates
\r
2614 // in debug mode we will check against old code and warn if there are differences
\r
2615 EmitBrushPrimitTextureCoordinates(face,w);
\r
2619 if (g_qeglobals.bNeedConvert)
\r
2621 BrushPrimitFaceToFace(face);
\r
2623 // we have parsed brush primitives and need conversion back to standard format
\r
2624 // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it
\r
2625 // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling
\r
2626 // I tried various tweaks, no luck .. seems shifting is lost
\r
2627 brushprimit_texdef_t aux;
\r
2628 ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL );
\r
2629 TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale );
\r
2630 face->texdef.scale[0]/=2.0;
\r
2631 face->texdef.scale[1]/=2.0;
\r
2634 for (i=0 ; i<w->numpoints ; i++)
\r
2635 EmitTextureCoordinates( w->points[i], face->d_texture, face);
\r
2641 ==================
\r
2642 Brush_RemoveEmptyFaces
\r
2644 Frees any overconstraining faces
\r
2645 ==================
\r
2647 void Brush_RemoveEmptyFaces ( brush_t *b )
\r
2651 f = b->brush_faces;
\r
2652 b->brush_faces = NULL;
\r
2654 for ( ; f ; f=next)
\r
2657 if (!f->face_winding)
\r
2661 f->next = b->brush_faces;
\r
2662 b->brush_faces = f;
\r
2668 void Brush_SnapToGrid(brush_t *pb)
\r
2675 // TTimo: some brushes are "special" and should not be snapped
\r
2676 // specially fixed-size entity ones
\r
2677 if (pb->owner->eclass->fixedsize)
\r
2679 // save current origin
\r
2680 VectorCopy (pb->owner->origin, temp);
\r
2681 // snap the origin
\r
2682 VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize);
\r
2683 // return if amount is zero
\r
2684 if (VectorCompare (pb->owner->origin, temp))
\r
2686 // transform brush faces same amount
\r
2687 VectorSubtract (pb->owner->origin, temp, temp);
\r
2688 for (f = pb->brush_faces; f; f = f->next)
\r
2690 for (i=0 ; i<3 ; i++)
\r
2691 VectorAdd (f->planepts[i], temp, f->planepts[i]);
\r
2696 for (f = pb->brush_faces ; f; f = f->next)
\r
2698 for (j=0; j<2; j++)
\r
2700 // spog - move planepts apart just far enough to avoid snapping two together
\r
2701 VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]);
\r
2702 for (i=0; i<3; i++)
\r
2704 if (diff[j][i] == 0.0f)
\r
2705 mult[i] = 2; // next value up from 1
\r
2706 else // multiplier = gridsize / component difference, rounded up
\r
2707 mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i]));
\r
2710 if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1
\r
2712 n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2;
\r
2713 for (i=0; i<3; i++)
\r
2714 diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component
\r
2716 VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]);
\r
2719 for (i=0; i<3; i++)
\r
2720 VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize);
\r
2724 Brush_Build(pb,true,true,false,false); // don't filter
\r
2727 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)
\r
2729 for (face_t* f=b->brush_faces ; f ; f=f->next)
\r
2731 for (int i=0 ; i<3 ; i++)
\r
2733 VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]);
\r
2738 Brush_Build(b,false,false,false,false); // don't filter
\r
2742 void Brush_Center(brush_t *b, vec3_t vNewCenter)
\r
2745 // get center of the brush
\r
2746 for (int j = 0; j < 3; j++)
\r
2748 vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5);
\r
2750 // calc distance between centers
\r
2751 VectorSubtract(vNewCenter, vMid, vMid);
\r
2752 Brush_Move(b, vMid, true);
\r
2756 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)
\r
2761 short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } };
\r
2763 for (i=0 ; i<3 ; i++)
\r
2764 if (vMax[i] < vMin[i])
\r
2765 Error ("Brush_Resize: invalid input");
\r
2767 if(b->brush_faces != NULL)
\r
2768 texdef = b->brush_faces->texdef;
\r
2770 texdef = g_qeglobals.d_texturewin.texdef;
\r
2772 while (b->brush_faces != NULL)
\r
2774 f = b->brush_faces->next;
\r
2775 Face_Free(b->brush_faces);
\r
2776 b->brush_faces = f;
\r
2779 for(i=0; i<3; i++)
\r
2781 f = b->brush_faces;
\r
2782 b->brush_faces = Face_Alloc();
\r
2783 b->brush_faces->next = f;
\r
2784 f = b->brush_faces;
\r
2785 f->texdef = texdef;
\r
2786 VectorCopy(vMax, f->planepts[0]);
\r
2787 VectorCopy(vMax, f->planepts[1]);
\r
2788 VectorCopy(vMax, f->planepts[2]);
\r
2789 f->planepts[2][box[i][0]] = vMin[box[i][0]];
\r
2790 f->planepts[1][box[i][1]] = vMin[box[i][1]];
\r
2792 for(i=0; i<3; i++)
\r
2794 f = b->brush_faces;
\r
2795 b->brush_faces = Face_Alloc();
\r
2796 b->brush_faces->next = f;
\r
2797 f = b->brush_faces;
\r
2798 f->texdef = texdef;
\r
2799 VectorCopy(vMin, f->planepts[0]);
\r
2800 VectorCopy(vMin, f->planepts[1]);
\r
2801 VectorCopy(vMin, f->planepts[2]);
\r
2802 f->planepts[1][box[i][0]] = vMax[box[i][0]];
\r
2803 f->planepts[2][box[i][1]] = vMax[box[i][1]];
\r
2807 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)
\r
2812 angleVal = IntForKey(e, "angle");
\r
2813 if (angleVal == -1) // up
\r
2815 VectorSet(angles, 270, 0, 0);
\r
2817 else if(angleVal == -2) // down
\r
2819 VectorSet(angles, 90, 0, 0);
\r
2823 VectorSet(angles, 0, angleVal, 0);
\r
2826 AngleVectors(angles, forward, right, up);
\r
2829 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)
\r
2831 vec3_t forward, right, up;
\r
2832 vec3_t endpoint, tip1, tip2;
\r
2836 VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
\r
2837 VectorScale(start, 0.5, start);
\r
2838 dist = (b->maxs[0] - start[0]) * 2.5;
\r
2840 FacingVectors (e, forward, right, up);
\r
2841 VectorMA (start, dist, forward, endpoint);
\r
2843 dist = (b->maxs[0] - start[0]) * 0.5;
\r
2844 VectorMA (endpoint, -dist, forward, tip1);
\r
2845 VectorMA (tip1, -dist, up, tip1);
\r
2846 VectorMA (tip1, 2*dist, up, tip2);
\r
2848 qglColor4f (1, 1, 1, 1);
\r
2850 qglBegin (GL_LINES);
\r
2851 qglVertex3fv (start);
\r
2852 qglVertex3fv (endpoint);
\r
2853 qglVertex3fv (endpoint);
\r
2854 qglVertex3fv (tip1);
\r
2855 qglVertex3fv (endpoint);
\r
2856 qglVertex3fv (tip2);
\r
2861 void Brush_FaceDraw(face_t *face, int nGLState)
\r
2863 const winding_t *w = face->face_winding;
\r
2864 if (w == NULL) return;
\r
2865 if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting)
\r
2866 qglNormal3fv(face->plane.normal);
\r
2868 if (mode & DRAW_GL_TEXTURE_2D)
\r
2869 qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]);
\r
2870 qglVertexPointer(3, GL_FLOAT, 5, w->points);
\r
2872 if (mode & DRAW_GL_FILL)
\r
2873 qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints);
\r
2875 qglDrawArrays(GL_POLYGON, 0, w->numpoints);
\r
2878 if (nGLState & DRAW_GL_FILL)
\r
2879 qglBegin(GL_TRIANGLE_FAN);
\r
2881 qglBegin(GL_POLYGON);
\r
2883 for (int i=0 ; i<w->numpoints ; i++)
\r
2885 if (nGLState & DRAW_GL_TEXTURE_2D)
\r
2886 qglTexCoord2fv( &w->points[i][3] );
\r
2887 qglVertex3fv(w->points[i]);
\r
2892 void Brush_Draw(brush_t *b)
\r
2896 qtexture_t *prev = 0;
\r
2899 int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode;
\r
2900 int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate;
\r
2902 GLfloat material[4], identity[4];
\r
2903 VectorSet(identity, 0.8f, 0.8f, 0.8f);
\r
2905 qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT);
\r
2906 qglDisableClientState(GL_NORMAL_ARRAY);
\r
2908 // guarantee the texture will be set first
\r
2911 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
\r
2913 w = face->face_winding;
\r
2916 continue; // freed face
\r
2919 bTrans = (face->pShader->getFlags() & QER_TRANS);
\r
2921 if (bTrans && !(nGLState & DRAW_GL_BLEND))
\r
2923 if (!bTrans && nGLState & DRAW_GL_BLEND)
\r
2926 // IMPORTANT NOTE:
\r
2927 // modifications to the discarding code here should be matched in the selection code
\r
2930 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
\r
2932 if (strstr(face->texdef.GetName(), "caulk"))
\r
2936 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP)
\r
2938 if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster"))
\r
2942 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
\r
2944 if (strstr(face->texdef.GetName(), "clip"))
\r
2948 if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(')
\r
2951 qglDisable(GL_TEXTURE_2D);
\r
2953 else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)
\r
2955 // set the texture for this face
\r
2956 prev = face->d_texture;
\r
2957 qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
\r
2960 if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting)
\r
2962 if (!b->owner->eclass->fixedsize)
\r
2963 material[3] = face->pShader->getTrans();
\r
2966 VectorCopy(face->d_color, material);
\r
2968 if (nGLState & DRAW_GL_TEXTURE_2D)
\r
2969 qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]);
\r
2971 qglColor4fv(material);
\r
2973 else if (!b->owner->eclass->fixedsize)
\r
2975 pShader = face->pShader;
\r
2976 VectorCopy(pShader->getTexture()->color, material);
\r
2977 material[3] = identity[3] = pShader->getTrans();
\r
2979 if (nGLState & DRAW_GL_TEXTURE_2D)
\r
2980 qglColor4fv(identity);
\r
2982 qglColor4fv(material);
\r
2985 // draw the polygon
\r
2987 Brush_FaceDraw(face, nGLState);
\r
2989 qglPopClientAttrib();
\r
2992 void Face_Draw( face_t *f )
\r
2996 if ( f->face_winding == 0 )
\r
2998 qglBegin(GL_POLYGON);
\r
2999 for ( i = 0 ; i < f->face_winding->numpoints; i++)
\r
3000 qglVertex3fv( f->face_winding->points[i] );
\r
3004 entity_t *FindEntity(const char *pszKey, const char *pszValue)
\r
3008 pe = entities.next;
\r
3010 for (; pe != NULL && pe != &entities ; pe = pe->next)
\r
3012 if (!strcmp(ValueForKey(pe, pszKey), pszValue))
\r
3019 void Brush_DrawXY(brush_t *b, int nViewType)
\r
3026 if (b->patchBrush)
\r
3028 Patch_DrawXY(b->pPatch);
\r
3029 if (!g_bPatchShowBounds)
\r
3033 if (b->owner->eclass->fixedsize)
\r
3035 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
\r
3037 #if 1 // requires vertex arrays enabled
\r
3038 DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType);
\r
3040 vec3_t vCorners[4];
\r
3041 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
\r
3043 vCorners[0][0] = b->mins[0];
\r
3044 vCorners[0][1] = b->mins[1];
\r
3045 vCorners[0][2] = fMid;
\r
3047 vCorners[1][0] = b->mins[0];
\r
3048 vCorners[1][1] = b->maxs[1];
\r
3049 vCorners[1][2] = fMid;
\r
3051 vCorners[2][0] = b->maxs[0];
\r
3052 vCorners[2][1] = b->maxs[1];
\r
3053 vCorners[2][2] = fMid;
\r
3055 vCorners[3][0] = b->maxs[0];
\r
3056 vCorners[3][1] = b->mins[1];
\r
3057 vCorners[3][2] = fMid;
\r
3059 vec3_t vTop, vBottom;
\r
3061 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
\r
3062 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
\r
3063 vTop[2] = b->maxs[2];
\r
3065 VectorCopy(vTop, vBottom);
\r
3066 vBottom[2] = b->mins[2];
\r
3068 qglBegin(GL_LINES);
\r
3069 qglVertex3fv(vTop);
\r
3070 qglVertex3fv(vCorners[0]);
\r
3071 qglVertex3fv(vTop);
\r
3072 qglVertex3fv(vCorners[1]);
\r
3073 qglVertex3fv(vTop);
\r
3074 qglVertex3fv(vCorners[2]);
\r
3075 qglVertex3fv(vTop);
\r
3076 qglVertex3fv(vCorners[3]);
\r
3079 qglBegin(GL_LINES);
\r
3080 qglVertex3fv(vBottom);
\r
3081 qglVertex3fv(vCorners[0]);
\r
3082 qglVertex3fv(vBottom);
\r
3083 qglVertex3fv(vCorners[1]);
\r
3084 qglVertex3fv(vBottom);
\r
3085 qglVertex3fv(vCorners[2]);
\r
3086 qglVertex3fv(vBottom);
\r
3087 qglVertex3fv(vCorners[3]);
\r
3090 qglBegin(GL_LINE_LOOP);
\r
3091 qglVertex3fv(vCorners[0]);
\r
3092 qglVertex3fv(vCorners[1]);
\r
3093 qglVertex3fv(vCorners[2]);
\r
3094 qglVertex3fv(vCorners[3]);
\r
3097 DrawBrushEntityName (b);
\r
3100 else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)))
\r
3102 qglPushAttrib(GL_CURRENT_BIT); // save brush colour
\r
3103 qglColor3fv(b->owner->eclass->color);
\r
3104 if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX )
\r
3105 b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY);
\r
3106 aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE);
\r
3113 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
\r
3115 // moved so check occurs earlier
\r
3116 w = face->face_winding;
\r
3119 // only draw polygons facing in a direction we care about
\r
3120 if (nViewType == XY)
\r
3122 if (face->plane.normal[2] <= 0)
\r
3127 if (nViewType == XZ)
\r
3129 if (face->plane.normal[1] >= 0) // stop axes being mirrored
\r
3134 if (face->plane.normal[0] <= 0)
\r
3139 // draw the polygon
\r
3140 qglBegin(GL_LINE_LOOP);
\r
3141 for (i=0 ; i<w->numpoints ; i++)
\r
3142 qglVertex3fv(w->points[i]);
\r
3146 DrawBrushEntityName (b);
\r
3155 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)
\r
3160 for (f=b->brush_faces ; f ; f=f->next)
\r
3161 for (i=0 ; i<3 ; i++)
\r
3162 VectorAdd (f->planepts[i], move, f->planepts[i]);
\r
3164 if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize)
\r
3166 for (f=b->brush_faces ; f ; f=f->next)
\r
3169 VectorCopy(move, vTemp);
\r
3170 Face_MoveTexture(f, vTemp);
\r
3174 Brush_Build( b, bSnap,true,false,false); // don't filter
\r
3177 if (b->patchBrush)
\r
3179 //Patch_Move(b->nPatchID, move);
\r
3180 Patch_Move(b->pPatch, move);
\r
3184 // PGM - keep the origin vector up to date on fixed size entities.
\r
3185 if(b->owner->eclass->fixedsize)
\r
3188 VectorAdd(b->owner->origin, move, b->owner->origin);
\r
3189 sprintf (text, "%i %i %i",
\r
3190 (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
\r
3191 SetKeyValue(b->owner, "origin", text);
\r
3192 //VectorAdd(b->maxs, b->mins, b->owner->origin);
\r
3193 //VectorScale(b->owner->origin, 0.5, b->owner->origin);
\r
3199 void Brush_Print(brush_t* b)
\r
3202 for (face_t* f = b->brush_faces ; f ; f=f->next)
\r
3204 Sys_Printf("Face %i\n", nFace++);
\r
3205 Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
\r
3206 Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
\r
3207 Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
\r
3217 Makes the current brushhave the given number of 2d sides and turns it into a cone
\r
3220 void Brush_MakeSidedCone(int sides)
\r
3223 vec3_t mins, maxs;
\r
3231 if (sides < 3 || sides > 32)
\r
3233 Sys_Status ("Bad sides number", 0);
\r
3237 if (!QE_SingleBrush ())
\r
3239 Sys_Status ("Must have a single brush selected", 0 );
\r
3243 b = selected_brushes.next;
\r
3244 VectorCopy (b->mins, mins);
\r
3245 VectorCopy (b->maxs, maxs);
\r
3246 texdef = &g_qeglobals.d_texturewin.texdef;
\r
3250 // find center of brush
\r
3252 for (i=0 ; i<2 ; i++)
\r
3254 mid[i] = (maxs[i] + mins[i])*0.5;
\r
3255 if (maxs[i] - mins[i] > width)
\r
3256 width = maxs[i] - mins[i];
\r
3260 b = Brush_Alloc();
\r
3262 // create bottom face
\r
3264 f->texdef = *texdef;
\r
3265 f->next = b->brush_faces;
\r
3266 b->brush_faces = f;
\r
3268 f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
\r
3269 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
\r
3270 f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
\r
3272 for (i=0 ; i<sides ; i++)
\r
3275 f->texdef = *texdef;
\r
3276 f->next = b->brush_faces;
\r
3277 b->brush_faces = f;
\r
3279 sv = sin (i*3.14159265*2/sides);
\r
3280 cv = cos (i*3.14159265*2/sides);
\r
3283 f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
\r
3284 f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
\r
3285 f->planepts[0][2] = mins[2];
\r
3287 f->planepts[1][0] = mid[0];
\r
3288 f->planepts[1][1] = mid[1];
\r
3289 f->planepts[1][2] = maxs[2];
\r
3291 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);
\r
3292 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);
\r
3293 f->planepts[2][2] = maxs[2];
\r
3297 Brush_AddToList (b, &selected_brushes);
\r
3299 Entity_LinkBrush (world_entity, b);
\r
3303 Sys_UpdateWindows (W_ALL);
\r
3310 Makes the current brushhave the given number of 2d sides and turns it into a sphere
\r
3314 void Brush_MakeSidedSphere(int sides)
\r
3317 vec3_t mins, maxs;
\r
3323 if (sides < 4 || sides > 32)
\r
3325 Sys_Status ("Bad sides number", 0);
\r
3329 if (!QE_SingleBrush ())
\r
3331 Sys_Status ("Must have a single brush selected", 0 );
\r
3335 b = selected_brushes.next;
\r
3336 VectorCopy (b->mins, mins);
\r
3337 VectorCopy (b->maxs, maxs);
\r
3338 texdef = &g_qeglobals.d_texturewin.texdef;
\r
3342 // find center of brush
\r
3344 for (i=0 ; i<2 ; i++)
\r
3346 mid[i] = (maxs[i] + mins[i])*0.5;
\r
3347 if (maxs[i] - mins[i] > radius)
\r
3348 radius = maxs[i] - mins[i];
\r
3352 b = Brush_Alloc();
\r
3354 float dt = float(2 * Q_PI / sides);
\r
3355 float dp = float(Q_PI / sides);
\r
3357 for(i=0; i <= sides-1; i++)
\r
3359 for(j=0;j <= sides-2; j++)
\r
3362 p = float(j * dp - Q_PI / 2);
\r
3365 f->texdef = *texdef;
\r
3366 f->next = b->brush_faces;
\r
3367 b->brush_faces = f;
\r
3369 VectorPolar(f->planepts[0], radius, t, p);
\r
3370 VectorPolar(f->planepts[1], radius, t, p + dp);
\r
3371 VectorPolar(f->planepts[2], radius, t + dt, p + dp);
\r
3373 for (int k = 0; k < 3; k++)
\r
3374 VectorAdd(f->planepts[k], mid, f->planepts[k]);
\r
3378 p = float((sides - 1) * dp - Q_PI / 2);
\r
3379 for(i = 0; i <= sides-1; i++)
\r
3384 f->texdef = *texdef;
\r
3385 f->next = b->brush_faces;
\r
3386 b->brush_faces = f;
\r
3388 VectorPolar(f->planepts[0], radius, t, p);
\r
3389 VectorPolar(f->planepts[1], radius, t + dt, p + dp);
\r
3390 VectorPolar(f->planepts[2], radius, t + dt, p);
\r
3392 for (int k = 0; k < 3; k++)
\r
3393 VectorAdd(f->planepts[k], mid, f->planepts[k]);
\r
3396 Brush_AddToList (b, &selected_brushes);
\r
3398 Entity_LinkBrush (world_entity, b);
\r
3402 Sys_UpdateWindows (W_ALL);
\r
3405 void Face_FitTexture( face_t * face, int nHeight, int nWidth )
\r
3410 float width, height, temp;
\r
3411 float rot_width, rot_height;
\r
3412 float cosv,sinv,ang;
\r
3413 float min_t, min_s, max_t, max_s;
\r
3424 ClearBounds (mins, maxs);
\r
3426 w = face->face_winding;
\r
3431 for (i=0 ; i<w->numpoints ; i++)
\r
3433 AddPointToBounds( w->points[i], mins, maxs );
\r
3436 if (g_qeglobals.m_bBrushPrimitMode)
\r
3437 Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth );
\r
3441 td = &face->texdef;
\r
3443 // get the current angle
\r
3445 ang = td->rotate / 180 * Q_PI;
\r
3449 // get natural texture axis
\r
3450 TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);
\r
3452 min_s = DotProduct( mins, vecs[0] );
\r
3453 min_t = DotProduct( mins, vecs[1] );
\r
3454 max_s = DotProduct( maxs, vecs[0] );
\r
3455 max_t = DotProduct( maxs, vecs[1] );
\r
3456 width = max_s - min_s;
\r
3457 height = max_t - min_t;
\r
3458 coords[0][0] = min_s;
\r
3459 coords[0][1] = min_t;
\r
3460 coords[1][0] = max_s;
\r
3461 coords[1][1] = min_t;
\r
3462 coords[2][0] = min_s;
\r
3463 coords[2][1] = max_t;
\r
3464 coords[3][0] = max_s;
\r
3465 coords[3][1] = max_t;
\r
3466 min_s = min_t = 99999;
\r
3467 max_s = max_t = -99999;
\r
3468 for (i=0; i<4; i++)
\r
3470 s = cosv * coords[i][0] - sinv * coords[i][1];
\r
3471 t = sinv * coords[i][0] + cosv * coords[i][1];
\r
3501 rot_width = (max_s - min_s);
\r
3502 rot_height = (max_t - min_t);
\r
3503 td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));
\r
3504 td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));
\r
3506 td->shift[0] = min_s/td->scale[0];
\r
3507 temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));
\r
3508 temp = (temp+1)*face->d_texture->width*nWidth;
\r
3509 td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);
\r
3511 td->shift[1] = min_t/td->scale[1];
\r
3512 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
\r
3513 temp = (temp+1)*(face->d_texture->height*nHeight);
\r
3514 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
\r
3516 td->shift[1] = min_t/td->scale[1];
\r
3517 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
\r
3518 temp = (temp+1)*(face->d_texture->height*nHeight);
\r
3519 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
\r
3524 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )
\r
3528 for (face = b->brush_faces ; face ; face=face->next)
\r
3530 Face_FitTexture( face, nHeight, nWidth );
\r
3534 void aabb_draw(const aabb_t *aabb, int mode)
\r
3536 vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } };
\r
3538 vec3_t vMin, vMax;
\r
3539 VectorSubtract(aabb->origin, aabb->extents, vMin);
\r
3540 VectorAdd(aabb->origin, aabb->extents, vMax);
\r
3541 VectorSet(points[0], vMin[0], vMax[1], vMax[2]);
\r
3542 VectorSet(points[1], vMax[0], vMax[1], vMax[2]);
\r
3543 VectorSet(points[2], vMax[0], vMin[1], vMax[2]);
\r
3544 VectorSet(points[3], vMin[0], vMin[1], vMax[2]);
\r
3545 VectorSet(points[4], vMin[0], vMax[1], vMin[2]);
\r
3546 VectorSet(points[5], vMax[0], vMax[1], vMin[2]);
\r
3547 VectorSet(points[6], vMax[0], vMin[1], vMin[2]);
\r
3548 VectorSet(points[7], vMin[0], vMin[1], vMin[2]);
\r
3550 qglBegin(GL_QUADS);
\r
3552 qglNormal3fv(normals[0]);
\r
3553 qglVertex3fv(points[2]);
\r
3554 qglVertex3fv(points[1]);
\r
3555 qglVertex3fv(points[5]);
\r
3556 qglVertex3fv(points[6]);
\r
3558 qglNormal3fv(normals[1]);
\r
3559 qglVertex3fv(points[1]);
\r
3560 qglVertex3fv(points[0]);
\r
3561 qglVertex3fv(points[4]);
\r
3562 qglVertex3fv(points[5]);
\r
3564 qglNormal3fv(normals[2]);
\r
3565 qglVertex3fv(points[0]);
\r
3566 qglVertex3fv(points[1]);
\r
3567 qglVertex3fv(points[2]);
\r
3568 qglVertex3fv(points[3]);
\r
3570 qglNormal3fv(normals[3]);
\r
3571 qglVertex3fv(points[3]);
\r
3572 qglVertex3fv(points[7]);
\r
3573 qglVertex3fv(points[4]);
\r
3574 qglVertex3fv(points[0]);
\r
3576 qglNormal3fv(normals[4]);
\r
3577 qglVertex3fv(points[3]);
\r
3578 qglVertex3fv(points[2]);
\r
3579 qglVertex3fv(points[6]);
\r
3580 qglVertex3fv(points[7]);
\r
3582 qglNormal3fv(normals[5]);
\r
3583 qglVertex3fv(points[7]);
\r
3584 qglVertex3fv(points[6]);
\r
3585 qglVertex3fv(points[5]);
\r
3586 qglVertex3fv(points[4]);
\r
3595 vec3_t vMin, vMax;
\r
3596 VectorSubtract(aabb->origin, aabb->extents, vMin);
\r
3597 VectorAdd(aabb->origin, aabb->extents, vMax);
\r
3598 VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]);
\r
3599 VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]);
\r
3600 VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]);
\r
3601 VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]);
\r
3602 VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]);
\r
3603 VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]);
\r
3604 VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]);
\r
3605 VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]);
\r
3607 vec3_t Normals[8] = { {-1, 0, 0 },
\r
3616 unsigned short Indices[24] = { 2, 1, 5, 6,
\r
3623 qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays
\r
3624 qglNormalPointer(GL_FLOAT, 0, Normals);
\r
3626 //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array
\r
3628 qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices);
\r
3630 //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array
\r
3634 qboolean IsBrushSelected(brush_t* bSel)
\r
3636 for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next)
\r