X-Git-Url: https://de.git.xonotic.org/?a=blobdiff_plain;f=radiant%2Fbrush.cpp;h=5e38cc1d62e785797468ceb7a103bf26cbd5f40a;hb=89f86ebc45c0f0375d55b4c56bf95dca6891426f;hp=d6d1b95ca11a1df2ab55bdfabd924916c5bccc06;hpb=33efc9089296fc4e5f54d43581a0db81576ba848;p=xonotic%2Fnetradiant.git diff --git a/radiant/brush.cpp b/radiant/brush.cpp index d6d1b95c..5e38cc1d 100644 --- a/radiant/brush.cpp +++ b/radiant/brush.cpp @@ -1,3644 +1,388 @@ /* -Copyright (C) 1999-2007 id Software, Inc. and contributors. -For a list of contributors, see the accompanying CONTRIBUTORS file. + Copyright (C) 1999-2006 Id Software, Inc. and contributors. + For a list of contributors, see the accompanying CONTRIBUTORS file. -This file is part of GtkRadiant. + This file is part of GtkRadiant. -GtkRadiant is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by -the Free Software Foundation; either version 2 of the License, or -(at your option) any later version. + GtkRadiant is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. -GtkRadiant is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -GNU General Public License for more details. + GtkRadiant is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. -You should have received a copy of the GNU General Public License -along with GtkRadiant; if not, write to the Free Software -Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -*/ + You should have received a copy of the GNU General Public License + along with GtkRadiant; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ -#include "stdafx.h" -#include -#include "winding.h" -#include -#include "filters.h" +#include "brush.h" +#include "signal/signal.h" -extern MainFrame* g_pParentWnd; -extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...); +Signal0 g_brushTextureChangedCallbacks; -// globals - -int g_nBrushId = 0; - -#ifdef ENABLE_GROUPS -const char* Brush_Name(brush_t *b) -{ - static char cBuff[1024]; - b->numberId = g_nBrushId++; - if (g_qeglobals.m_bBrushPrimitMode) - { - sprintf(cBuff, "Brush %i", b->numberId); - Brush_SetEpair(b, "Name", cBuff); - } - return cBuff; -} -#endif - -brush_t *Brush_Alloc() -{ - brush_t *b = (brush_t*)qmalloc(sizeof(brush_t)); - return b; -} -/* -void Brush_Free(brush_t *b) -{ - free(b); -} -*/ -void PrintWinding (winding_t *w) -{ - int i; - - Sys_Printf ("-------------\n"); - for (i=0 ; inumpoints ; i++) - Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] - , w->points[i][1], w->points[i][2]); -} - -void PrintPlane (plane_t *p) -{ - Sys_Printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], - p->normal[2], p->dist); -} - -void PrintVector (vec3_t v) -{ - Sys_Printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); -} - - -/* -============================================================================= - - TEXTURE COORDINATES - -============================================================================= -*/ - - -/* -================== -textureAxisFromPlane -================== -*/ -vec3_t baseaxis[18] = -{ -{0,0,1}, {1,0,0}, {0,-1,0}, // floor -{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling -{1,0,0}, {0,1,0}, {0,0,-1}, // west wall -{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall -{0,1,0}, {1,0,0}, {0,0,-1}, // south wall -{0,-1,0}, {1,0,0}, {0,0,-1} // north wall -}; - -void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) -{ - int bestaxis; - float dot,best; - int i; - - best = 0; - bestaxis = 0; - - for (i=0 ; i<6 ; i++) - { - dot = DotProduct (pln->normal, baseaxis[i*3]); - if (g_PrefsDlg.m_bQ3Map2Texturing && dot > best + 0.0001f || dot > best) - { - best = dot; - bestaxis = i; - } - } - - VectorCopy (baseaxis[bestaxis*3+1], xv); - VectorCopy (baseaxis[bestaxis*3+2], yv); -} - - - -float lightaxis[3] = {0.6f, 0.8f, 1.0f}; -/* -================ -SetShadeForPlane - -Light different planes differently to -improve recognition -================ -*/ -extern float ShadeForNormal(vec3_t normal); - -float SetShadeForPlane (plane_t *p) -{ - //return ShadeForNormal(p->normal); - - - int i; - float f; - - // axial plane - for (i=0 ; i<3 ; i++) - if (fabs(p->normal[i]) > 0.9) - { - f = lightaxis[i]; - return f; - } - - // between two axial planes - for (i=0 ; i<3 ; i++) - if (fabs(p->normal[i]) < 0.1) - { - f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; - return f; - } - - // other - f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; - return f; - -} - -vec3_t vecs[2]; -float shift[2]; - -/* -================ -Face_Alloc -================ -*/ -face_t *Face_Alloc( void ) -{ - face_t *f = (face_t*)qmalloc( sizeof( *f ) ); - return f; -} - -/* -================ -Face_Free -================ -*/ -void Face_Free( face_t *f ) -{ - assert( f != 0 ); - - if ( f->face_winding ) - { - free( f->face_winding ); - f->face_winding = 0; - } - f->texdef.~texdef_t();; - - free( f ); -} - -/* -================ -Face_Clone -================ -*/ -face_t *Face_Clone (face_t *f) -{ - face_t *n; - - n = Face_Alloc(); - n->texdef = f->texdef; - n->brushprimit_texdef = f->brushprimit_texdef; - - memcpy (n->planepts, f->planepts, sizeof(n->planepts)); - - // all other fields are derived, and will be set by Brush_Build - // FIXME: maybe not, for example n->pData! - return n; -} - -/* -================ -Face_FullClone - -makes an exact copy of the face -================ -*/ -face_t *Face_FullClone (face_t *f) -{ - face_t *n; - - n = Face_Alloc(); - n->texdef = f->texdef; - n->brushprimit_texdef = f->brushprimit_texdef; - memcpy(n->planepts, f->planepts, sizeof(n->planepts)); - memcpy(&n->plane, &f->plane, sizeof(plane_t)); - if (f->face_winding) - n->face_winding = Winding_Clone(f->face_winding); - else - n->face_winding = NULL; - n->pShader = f->pShader; - n->pShader->IncRef(); - n->d_texture = n->pShader->getTexture(); - return n; -} - -void Face_SetShader(face_t *face, const char *name) -{ - if(face->pShader != NULL) - face->pShader->DecRef(); - face->texdef.SetName(name); - face->pShader = QERApp_Shader_ForName(name); - face->pShader->IncRef(); - face->d_texture = face->pShader->getTexture(); - face->texdef.flags = face->pShader->getFlags(); -} - -void Face_SetShader(face_t *face, IShader *shader) -{ - if(face->pShader != NULL) - face->pShader->DecRef(); - face->texdef.SetName(shader->getName()); - face->d_texture = shader->getTexture(); - face->texdef.flags = shader->getFlags(); - face->pShader = shader; - face->pShader->IncRef(); -} - -/* -================ -Clamp -================ -*/ -void Clamp(float& f, int nClamp) -{ - float fFrac = f - static_cast(f); - f = static_cast(f) % nClamp; - f += fFrac; -} - -/* -================ -Face_MoveTexture -================ -*/ -void Face_MoveTexture(face_t *f, vec3_t delta) -{ - vec3_t vX, vY; - - if (g_qeglobals.m_bBrushPrimitMode) - ShiftTextureGeometric_BrushPrimit( f, delta ); - else - { - TextureAxisFromPlane(&f->plane, vX, vY); - - vec3_t vDP, vShift; - vDP[0] = DotProduct(delta, vX); - vDP[1] = DotProduct(delta, vY); - - double fAngle = f->texdef.rotate / 180 * Q_PI; - double c = cos(fAngle); - double s = sin(fAngle); - - vShift[0] = vDP[0] * c - vDP[1] * s; - vShift[1] = vDP[0] * s + vDP[1] * c; - - if (!f->texdef.scale[0]) - f->texdef.scale[0] = g_pGameDescription->mTextureDefaultScale; - if (!f->texdef.scale[1]) - f->texdef.scale[1] = g_pGameDescription->mTextureDefaultScale; - - f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0]; - f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1]; - - // clamp the shifts - Clamp(f->texdef.shift[0], f->d_texture->width); - Clamp(f->texdef.shift[1], f->d_texture->height); - } -} - -/* -================ -Face_SetColor -================ -*/ -/*!\todo Replace all face_t::d_texture access with face_t::pShader::GetTexture.*/ -void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) -{ - // set shading for face - f->d_shade = SetShadeForPlane (&f->plane); - f->d_color[0] = f->pShader->getTexture()->color[0] * f->d_shade; - f->d_color[1] = f->pShader->getTexture()->color[1] * f->d_shade; - f->d_color[2] = f->pShader->getTexture()->color[2] * f->d_shade; -} - -/* -================ -Face_TextureVectors -================ -*/ -void Face_TextureVectors (face_t *f, float STfromXYZ[2][4]) -{ - vec3_t pvecs[2]; - int sv, tv; - float ang, sinv, cosv; - float ns, nt; - int i,j; - qtexture_t *q; - texdef_t *td; - -#ifdef _DEBUG - // this code is not supposed to be used while in BP mode, warning here can help spot the problem - if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) - Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n"); -#endif - - td = &f->texdef; - q = f->d_texture; - - memset (STfromXYZ, 0, 8*sizeof(float)); - - if (!td->scale[0]) - td->scale[0] = g_pGameDescription->mTextureDefaultScale; - if (!td->scale[1]) - td->scale[1] = g_pGameDescription->mTextureDefaultScale; - - // get natural texture axis - TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); - - // rotate axis - if (td->rotate == 0) - { sinv = 0 ; cosv = 1; } - else if (td->rotate == 90) - { sinv = 1 ; cosv = 0; } - else if (td->rotate == 180) - { sinv = 0 ; cosv = -1; } - else if (td->rotate == 270) - { sinv = -1 ; cosv = 0; } - else - { - ang = td->rotate / 180 * Q_PI; - sinv = sin(ang); - cosv = cos(ang); - } - - if (pvecs[0][0]) - sv = 0; - else if (pvecs[0][1]) - sv = 1; - else - sv = 2; - - if (pvecs[1][0]) - tv = 0; - else if (pvecs[1][1]) - tv = 1; - else - tv = 2; - - for (i=0 ; i<2 ; i++) { - ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; - nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; - STfromXYZ[i][sv] = ns; - STfromXYZ[i][tv] = nt; - } - - // scale - for (i=0 ; i<2 ; i++) - for (j=0 ; j<3 ; j++) - STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i]; - - // shift - STfromXYZ[0][3] = td->shift[0]; - STfromXYZ[1][3] = td->shift[1]; - - for (j=0 ; j<4 ; j++) { - STfromXYZ[0][j] /= q->width; - STfromXYZ[1][j] /= q->height; - } -} - -/* -================ -Face_MakePlane -================ -*/ -void Face_MakePlane (face_t *f) -{ - int j; - vec3_t t1, t2, t3; - - // convert to a vector / dist plane - for (j=0 ; j<3 ; j++) - { - t1[j] = f->planepts[0][j] - f->planepts[1][j]; - t2[j] = f->planepts[2][j] - f->planepts[1][j]; - t3[j] = f->planepts[1][j]; - } - - CrossProduct(t1,t2, f->plane.normal); - if (VectorCompare (f->plane.normal, vec3_origin)) - Sys_FPrintf (SYS_WRN, "WARNING: brush plane with no normal\n"); - VectorNormalize (f->plane.normal, f->plane.normal); - f->plane.dist = DotProduct (t3, f->plane.normal); -} - -/* -================ -EmitTextureCoordinates -================ -*/ -void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) -{ - float STfromXYZ[2][4]; - - Face_TextureVectors (f, STfromXYZ); - xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3]; - xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3]; -} - -//========================================================================== - -/* -================ -Brush_MakeFacePlanes -================ -*/ -void Brush_MakeFacePlanes (brush_t *b) -{ - face_t *f; - - for (f=b->brush_faces ; f ; f=f->next) - { - Face_MakePlane (f); - } -} - -/* -================ -DrawBrushEntityName -================ -*/ -void DrawBrushEntityName (brush_t *b) -{ - const char *name; - float a, s, c; - vec3_t mid; - int i; - - if (!b->owner) - return; // during contruction - - if (b->owner == world_entity) - return; - - if (b != b->owner->brushes.onext) - return; // not key brush - - // TTimo: Brush_DrawFacingAngle is for camera view rendering, this function is called for 2D views - // FIXME - spog - not sure who put this here.. Brush_DrawFacingAngle() does this job? - // Brush_DrawFacingAngle() works when called, but is not being called. - if (g_qeglobals.d_savedinfo.show_angles && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) - { - // draw the angle pointer - a = FloatForKey (b->owner, "angle"); - s = sin (a/180*Q_PI); - c = cos (a/180*Q_PI); - for (i=0 ; i<3 ; i++) - mid[i] = (b->mins[i] + b->maxs[i])*0.5; - - qglBegin (GL_LINE_STRIP); - qglVertex3fv (mid); - mid[0] += c*8; - mid[1] += s*8; - mid[2] += s*8; - qglVertex3fv (mid); - mid[0] -= c*4; - mid[1] -= s*4; - mid[2] -= s*4; - mid[0] -= s*4; - mid[1] += c*4; - mid[2] += c*4; - qglVertex3fv (mid); - mid[0] += c*4; - mid[1] += s*4; - mid[2] += s*4; - mid[0] += s*4; - mid[1] -= c*4; - mid[2] -= c*4; - qglVertex3fv (mid); - mid[0] -= c*4; - mid[1] -= s*4; - mid[2] -= s*4; - mid[0] += s*4; - mid[1] -= c*4; - mid[2] -= c*4; - qglVertex3fv (mid); - qglEnd (); - } - - if (g_qeglobals.d_savedinfo.show_names) - { - name = ValueForKey (b->owner, "classname"); - qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4); - gtk_glwidget_print_string(name); - } -} - -/* -================= -Brush_MakeFaceWinding - -returns the visible polygon on a face -================= -*/ -winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face) -{ - winding_t *w; - face_t *clip; - plane_t plane; - qboolean past; - - // get a poly that covers an effectively infinite area - w = Winding_BaseForPlane (&face->plane); - - // chop the poly by all of the other faces - past = false; - for (clip = b->brush_faces ; clip && w ; clip=clip->next) - { - if (clip == face) - { - past = true; - continue; - } - if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 - && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) - { // identical plane, use the later one - if (past) - { - free (w); - return NULL; - } - continue; - } - - // flip the plane, because we want to keep the back side - VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); - plane.dist = -clip->plane.dist; - - w = Winding_Clip (w, &plane, false); - if (!w) - return w; - } - - if (w->numpoints < 3) - { - free(w); - w = NULL; - } - - if (!w) - Sys_FPrintf (SYS_WRN, "unused plane\n"); - - return w; -} - -/* -================= -Brush_SnapPlanepts -================= -*/ -void Brush_SnapPlanepts (brush_t *b) -{ - int i, j; - face_t *f; - - if (g_PrefsDlg.m_bNoClamp) - return; - - if (g_qeglobals.d_bSmallGrid) - { - for (f=b->brush_faces ; f; f=f->next) - for (i=0 ; i<3 ; i++) - for (j=0 ; j<3 ; j++) - f->planepts[i][j] = floor (f->planepts[i][j]/g_qeglobals.d_gridsize + 0.5)*g_qeglobals.d_gridsize; - } - else - { - for (f=b->brush_faces ; f; f=f->next) - for (i=0 ; i<3 ; i++) - for (j=0 ; j<3 ; j++) - f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); - } -} - -/* -** Brush_Build -** -** Builds a brush rendering data and also sets the min/max bounds -*/ -// TTimo -// added a bConvert flag to convert between old and new brush texture formats -// TTimo -// brush grouping: update the group treeview if necessary -void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest) -{ - bool bLocalConvert; - - -#ifdef _DEBUG - if (!g_qeglobals.m_bBrushPrimitMode && bConvert) - Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n"); -#endif - - // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only - if (bConvert && !g_qeglobals.bNeedConvert) - { -#ifdef _DEBUG - //++timo FIXME: it's not very clear when this can happen, I guess while dealing with plugins that send brushes - // back and forth in one format or the other .. more when mixing BP / noBP in the same maps. -#endif - bLocalConvert = true; - g_qeglobals.bNeedConvert = true; - } - else - bLocalConvert = false; - - /* - ** build the windings and generate the bounding box - */ - Brush_BuildWindings(b, bSnap); - - if(b->owner->model.pRender) - { - const aabb_t *aabb = b->owner->model.pRender->GetAABB(); - VectorAdd(aabb->origin, aabb->extents, b->maxs); - VectorSubtract(aabb->origin, aabb->extents, b->mins); - } - - //Patch_BuildPoints (b); // does nothing but set b->patchBrush true if the texdef contains SURF_PATCH ! - - /* - ** move the points and edges if in select mode - */ - if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) - SetupVertexSelection (); - - if (b->itemOwner == 0) //NULL) - Group_AddToProperGroup(b); - - if (bMarkMap) - { - Sys_MarkMapModified(); - } - - if (bLocalConvert) - g_qeglobals.bNeedConvert = false; - - // spog - applying filters to brush during brush_build instead of during redraw - if (bFilterTest) - b->bFiltered = FilterBrush( b ); -} - -/* -============== -Brush_SplitBrushByFace - -The incoming brush is NOT freed. -The incoming face is NOT left referenced. -============== -*/ -void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back, boolean bCaulk) -{ - brush_t *b; - face_t *nf; - vec3_t temp; - - b = Brush_Clone (in); - nf = Face_Clone (f); - - nf->texdef = b->brush_faces->texdef; - if (bCaulk) - { - nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); - } - nf->next = b->brush_faces; - b->brush_faces = nf; - - Brush_Build( b ); - Brush_RemoveEmptyFaces ( b ); - if ( !b->brush_faces ) - { // completely clipped away - Brush_Free (b); - *back = NULL; - } - else - { - Entity_LinkBrush (in->owner, b); - *back = b; - } - - b = Brush_Clone (in); - nf = Face_Clone (f); - // swap the plane winding - VectorCopy (nf->planepts[0], temp); - VectorCopy (nf->planepts[1], nf->planepts[0]); - VectorCopy (temp, nf->planepts[1]); - - nf->texdef = b->brush_faces->texdef; - if (bCaulk) - { - nf->texdef.SetName(g_pGameDescription->mCaulkShader.GetBuffer()); - } - nf->next = b->brush_faces; - b->brush_faces = nf; - - Brush_Build( b ); - Brush_RemoveEmptyFaces ( b ); - if ( !b->brush_faces ) - { // completely clipped away - Brush_Free (b); - *front = NULL; - } - else - { - Entity_LinkBrush (in->owner, b); - *front = b; - } -} - -/* -================= -Brush_BestSplitFace - -returns the best face to split the brush with. -return NULL if the brush is convex -================= -*/ -face_t *Brush_BestSplitFace(brush_t *b) -{ - face_t *face, *f, *bestface; - winding_t *front, *back; - int splits, tinywindings, value, bestvalue; - - bestvalue = 999999; - bestface = NULL; - for (face = b->brush_faces; face; face = face->next) - { - splits = 0; - tinywindings = 0; - for (f = b->brush_faces; f; f = f->next) - { - if (f == face) continue; - // - Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1f, &front, &back); - - if (!front) - { - Winding_Free(back); - } - else if (!back) - { - Winding_Free(front); - } - else - { - splits++; - if (Winding_IsTiny(front)) tinywindings++; - if (Winding_IsTiny(back)) tinywindings++; - } - } - if (splits) - { - value = splits + 50 * tinywindings; - if (value < bestvalue) - { - bestvalue = value; - bestface = face; - } - } - } - return bestface; -} - -/* -================= -Brush_MakeConvexBrushes - -MrE FIXME: this doesn't work because the old - Brush_SplitBrushByFace is used -Turns the brush into a minimal number of convex brushes. -If the input brush is convex then it will be returned. -Otherwise the input brush will be freed. -NOTE: the input brush should have windings for the faces. -================= -*/ -brush_t *Brush_MakeConvexBrushes(brush_t *b) -{ - brush_t *front, *back, *end; - face_t *face; - - b->next = NULL; - face = Brush_BestSplitFace(b); - if (!face) return b; - Brush_SplitBrushByFace(b, face, &front, &back); - //this should never happen - if (!front && !back) return b; - Brush_Free(b); - if (!front) - return Brush_MakeConvexBrushes(back); - b = Brush_MakeConvexBrushes(front); - if (back) - { - for (end = b; end->next; end = end->next); - end->next = Brush_MakeConvexBrushes(back); - } - return b; -} - -/* -================= -Brush_Convex -================= -*/ -int Brush_Convex(brush_t *b) -{ - face_t *face1, *face2; - - for (face1 = b->brush_faces; face1; face1 = face1->next) - { - if (!face1->face_winding) continue; - for (face2 = b->brush_faces; face2; face2 = face2->next) - { - if (face1 == face2) continue; - if (!face2->face_winding) continue; - if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, - face1->plane.normal, face2->plane.normal, - face1->plane.dist, face2->plane.dist)) - { - return false; - } - } - } - return true; -} - -/* -================= -Brush_MoveVertexes - -- The input brush must be convex -- The input brush must have face windings. -- The output brush will be convex. -- Returns true if the WHOLE vertex movement is performed. -================= -*/ - -// define this to debug the vertex editing mode -#ifdef _DEBUG -//#define DBG_VERT -#endif - -#define MAX_MOVE_FACES 64 - -int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) -{ - face_t *f, *face, *newface, *lastface, *nextface; - face_t *movefaces[MAX_MOVE_FACES]; - int movefacepoints[MAX_MOVE_FACES]; - winding_t *w, tmpw; - vec3_t start, mid; - plane_t plane; - int i, j, k, nummovefaces, result, done; - float dot, front, back, frac, smallestfrac; - -#ifdef DBG_VERT - 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" ); -#endif - - result = true; - // - tmpw.numpoints = 3; - tmpw.maxpoints = 3; - VectorCopy(vertex, start); - VectorAdd(vertex, delta, end); - //snap or not? - if (bSnap) - for (i = 0; i < 3; i++) - end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.1) * g_qeglobals.d_gridsize; - // - VectorCopy(end, mid); - //if the start and end are the same - if (Point_Equal(start, end, 0.3f)) return false; - //the end point may not be the same as another vertex - for (face = b->brush_faces; face; face = face->next) - { - w = face->face_winding; - if (!w) continue; - for (i = 0; i < w->numpoints; i++) - { - if (Point_Equal(w->points[i], end, 0.3f)) - { - VectorCopy(vertex, end); - return false; - } - } - } - // - done = false; - while(!done) - { - //chop off triangles from all brush faces that use the to be moved vertex - //store pointers to these chopped off triangles in movefaces[] - nummovefaces = 0; - for (face = b->brush_faces; face; face = face->next) - { - w = face->face_winding; - if (!w) continue; - for (i = 0; i < w->numpoints; i++) - { - if (Point_Equal(w->points[i], start, 0.2f)) - { - if (face->face_winding->numpoints <= 3) - { - movefacepoints[nummovefaces] = i; - movefaces[nummovefaces++] = face; - break; - } - dot = DotProduct(end, face->plane.normal) - face->plane.dist; - //if the end point is in front of the face plane - if (dot > 0.1) - { - //fanout triangle subdivision - for (k = i; k < i + w->numpoints-3; k++) - { - VectorCopy(w->points[i], tmpw.points[0]); - VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); - VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); - // - newface = Face_Clone(face); - //get the original - for (f = face; f->original; f = f->original) ; - newface->original = f; - //store the new winding - if (newface->face_winding) Winding_Free(newface->face_winding); - newface->face_winding = Winding_Clone(&tmpw); - //get the texture information - newface->pShader = face->pShader; - newface->d_texture = face->d_texture; - - //add the face to the brush - newface->next = b->brush_faces; - b->brush_faces = newface; - //add this new triangle to the move faces - movefacepoints[nummovefaces] = 0; - movefaces[nummovefaces++] = newface; - } - //give the original face a new winding - VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); - VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); - VectorCopy(w->points[i], tmpw.points[2]); - Winding_Free(face->face_winding); - face->face_winding = Winding_Clone(&tmpw); - //add the original face to the move faces - movefacepoints[nummovefaces] = 2; - movefaces[nummovefaces++] = face; - } - else - { - //chop a triangle off the face - VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); - VectorCopy(w->points[i], tmpw.points[1]); - VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); - //remove the point from the face winding - Winding_RemovePoint(w, i); - //get texture crap right - Face_SetColor(b, face, 1.0); - for (j = 0; j < w->numpoints; j++) - EmitTextureCoordinates(w->points[j], face->d_texture, face); - //make a triangle face - newface = Face_Clone(face); - //get the original - for (f = face; f->original; f = f->original) ; - newface->original = f; - //store the new winding - if (newface->face_winding) Winding_Free(newface->face_winding); - newface->face_winding = Winding_Clone(&tmpw); - //get the texture - newface->pShader = face->pShader; - newface->d_texture = newface->pShader->getTexture(); -// newface->d_texture = QERApp_Texture_ForName2( newface->texdef.name ); - //add the face to the brush - newface->next = b->brush_faces; - b->brush_faces = newface; - // - movefacepoints[nummovefaces] = 1; - movefaces[nummovefaces++] = newface; - } - break; - } - } - } - //now movefaces contains pointers to triangle faces that - //contain the to be moved vertex - // - done = true; - VectorCopy(end, mid); - smallestfrac = 1; - for (face = b->brush_faces; face; face = face->next) - { - //check if there is a move face that has this face as the original - for (i = 0; i < nummovefaces; i++) - { - if (movefaces[i]->original == face) break; - } - if (i >= nummovefaces) continue; - //check if the original is not a move face itself - for (j = 0; j < nummovefaces; j++) - { - if (face == movefaces[j]) break; - } - //if the original is not a move face itself - if (j >= nummovefaces) - { - memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t)); - } - else - { - k = movefacepoints[j]; - w = movefaces[j]->face_winding; - VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]); - VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]); - // - k = movefacepoints[i]; - w = movefaces[i]->face_winding; - VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]); - if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) - { - VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]); - if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) - //this should never happen otherwise the face merge did a crappy job a previous pass - continue; - } - } - //now we've got the plane to check agains - front = DotProduct(start, plane.normal) - plane.dist; - back = DotProduct(end, plane.normal) - plane.dist; - //if the whole move is at one side of the plane - if (front < 0.01 && back < 0.01) continue; - if (front > -0.01 && back > -0.01) continue; - //if there's no movement orthogonal to this plane at all - if (fabs(front-back) < 0.001) continue; - //ok first only move till the plane is hit - frac = front/(front-back); - if (frac < smallestfrac) - { - mid[0] = start[0] + (end[0] - start[0]) * frac; - mid[1] = start[1] + (end[1] - start[1]) * frac; - mid[2] = start[2] + (end[2] - start[2]) * frac; - smallestfrac = frac; - } - // - done = false; - } - - //move the vertex - for (i = 0; i < nummovefaces; i++) - { - //move vertex to end position - VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]); - //create new face plane - for (j = 0; j < 3; j++) - { - VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); - } - Face_MakePlane(movefaces[i]); - if (VectorLength(movefaces[i]->plane.normal) < 0.1) - result = false; - } - //if the brush is no longer convex - if (!result || !Brush_Convex(b)) - { - for (i = 0; i < nummovefaces; i++) - { - //move the vertex back to the initial position - VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]); - //create new face plane - for (j = 0; j < 3; j++) - { - VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); - } - Face_MakePlane(movefaces[i]); - } - result = false; - VectorCopy(start, end); - done = true; - } - else - { - VectorCopy(mid, start); - } - //get texture crap right - for (i = 0; i < nummovefaces; i++) - { - Face_SetColor(b, movefaces[i], 1.0); - for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) - EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); - } - - //now try to merge faces with their original faces - lastface = NULL; - for (face = b->brush_faces; face; face = nextface) - { - nextface = face->next; - if (!face->original) - { - lastface = face; - continue; - } - if (!Plane_Equal(&face->plane, &face->original->plane, false)) - { - lastface = face; - continue; - } - w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); - if (!w) - { - lastface = face; - continue; - } - Winding_Free(face->original->face_winding); - face->original->face_winding = w; - //get texture crap right - Face_SetColor(b, face->original, 1.0); - for (j = 0; j < face->original->face_winding->numpoints; j++) - EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); - //remove the face that was merged with the original - if (lastface) lastface->next = face->next; - else b->brush_faces = face->next; - Face_Free(face); - } - } - return result; -} - -/* -================= -Brush_InsertVertexBetween -================= -*/ -int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2) -{ - face_t *face; - winding_t *w, *neww; - vec3_t point; - int i, insert; - - if (Point_Equal(p1, p2, 0.4f)) - return false; - VectorAdd(p1, p2, point); - VectorScale(point, 0.5f, point); - insert = false; - //the end point may not be the same as another vertex - for (face = b->brush_faces; face; face = face->next) - { - w = face->face_winding; - if (!w) continue; - neww = NULL; - for (i = 0; i < w->numpoints; i++) - { - if (!Point_Equal(w->points[i], p1, 0.1f)) - continue; - if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1f)) - { - neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints); - break; - } - else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3f)) - { - neww = Winding_InsertPoint(w, point, i); - break; - } - } - if (neww) - { - Winding_Free(face->face_winding); - face->face_winding = neww; - insert = true; - } - } - return insert; -} - - -/* -================= -Brush_ResetFaceOriginals -================= -*/ -void Brush_ResetFaceOriginals(brush_t *b) -{ - face_t *face; - - for (face = b->brush_faces; face; face = face->next) - { - face->original = NULL; - } -} - -#ifdef ENABLE_GROUPS -/* -============== -Brush_SetEpair -sets an epair for the given brush -============== -*/ -void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - if (b->patchBrush) - { - Patch_SetEpair(b->pPatch, pKey, pValue); - } - else - { - SetKeyValue(b->epairs, pKey, pValue); - } - } - else - { - Sys_Printf("Can only set key/values in Brush primitive mode\n"); - } -} - -/* -================= -Brush_GetKeyValue -================= -*/ -const char* Brush_GetKeyValue(brush_t *b, const char *pKey) -{ - if (g_qeglobals.m_bBrushPrimitMode) - { - if (b->patchBrush) - { - return Patch_GetKeyValue(b->pPatch, pKey); - } - else - { - return ValueForKey(b->epairs, pKey); - } - } - else - { - Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n"); - } - return ""; -} -#endif -/* -================= -CheckName -temporary stuff, detect potential problems when saving the texture name -================= -*/ -void CheckName( face_t *fa, char *pname ) -{ - if (!strlen(fa->texdef.GetName())) - { -#ifdef _DEBUG - Sys_Printf("WARNING: unexpected texdef.name is empty in Brush.cpp CheckName\n"); -#endif - fa->texdef.SetName(SHADER_NOT_FOUND); - strcpy(pname, SHADER_NOT_FOUND); - return; - } - - // some people manage to get long filename textures (with spaces) in their maps - if (strchr( fa->texdef.GetName(), ' ' )) - { - char Msg1[1024]; - - 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() ); - - Sys_Printf("%s\n", Msg1 ); - gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK ); - strcpy( pname, SHADER_NOT_FOUND ); - return; - } - - //++timo FIXME: bug #103494 detection attempt - // TODO: clean this detection part when bug will have disappeared - if (fa->texdef.GetName()[0] == '(') - { - 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."; - Sys_Printf("%s\n", text); - gtk_MessageBox(g_pParentWnd->m_pWidget, text, "Error saving map", MB_OK ); - // need to cleanup this dead face name or we may loop endlessly - fa->texdef.SetName(SHADER_NOT_FOUND); - strcpy( pname, SHADER_NOT_FOUND ); - return; - } - strcpy( pname, fa->texdef.GetName()+9 ); // remove "textures/" -} - -/* -============= -Brush_Create - -Create non-textured blocks for entities -The brush is NOT linked to any list -============= -*/ -brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) -{ - int i, j; - vec3_t pts[4][2]; - face_t *f; - brush_t *b; - -#if DBG_BP - // brush primitive mode : convert texdef to brushprimit_texdef ? - // most of the time texdef is empty - if (g_qeglobals.m_bBrushPrimitMode) - { - // check texdef is empty .. if there are cases it's not we need to write some conversion code - if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0) - Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n"); - } -#endif - - for (i=0 ; i<3 ; i++) - { - if (maxs[i] < mins[i]) - Error ("Brush_InitSolid: backwards"); - } - - b = Brush_Alloc(); - - pts[0][0][0] = mins[0]; - pts[0][0][1] = mins[1]; - - pts[1][0][0] = mins[0]; - pts[1][0][1] = maxs[1]; - - pts[2][0][0] = maxs[0]; - pts[2][0][1] = maxs[1]; - - pts[3][0][0] = maxs[0]; - pts[3][0][1] = mins[1]; - - for (i=0 ; i<4 ; i++) - { - pts[i][0][2] = mins[2]; - pts[i][1][0] = pts[i][0][0]; - pts[i][1][1] = pts[i][0][1]; - pts[i][1][2] = maxs[2]; - } - - for (i=0 ; i<4 ; i++) - { - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - j = (i+1)%4; - - VectorCopy (pts[j][1], f->planepts[0]); - VectorCopy (pts[i][1], f->planepts[1]); - VectorCopy (pts[i][0], f->planepts[2]); - } - - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (pts[0][1], f->planepts[0]); - VectorCopy (pts[1][1], f->planepts[1]); - VectorCopy (pts[2][1], f->planepts[2]); - - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (pts[2][0], f->planepts[0]); - VectorCopy (pts[1][0], f->planepts[1]); - VectorCopy (pts[0][0], f->planepts[2]); - - return b; -} - -/* -============= -Brush_CreatePyramid - -Create non-textured pyramid for light entities -The brush is NOT linked to any list -============= -*/ -brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef) -{ - int i; - - //++timo handle new brush primitive ? return here ?? - return Brush_Create(mins, maxs, texdef); - - for (i=0 ; i<3 ; i++) - if (maxs[i] < mins[i]) - Error ("Brush_InitSolid: backwards"); - - brush_t* b = Brush_Alloc(); - - vec3_t corners[4]; - - float fMid = Rad_rint(mins[2] + (Rad_rint((maxs[2] - mins[2]) / 2))); - - corners[0][0] = mins[0]; - corners[0][1] = mins[1]; - corners[0][2] = fMid; - - corners[1][0] = mins[0]; - corners[1][1] = maxs[1]; - corners[1][2] = fMid; - - corners[2][0] = maxs[0]; - corners[2][1] = maxs[1]; - corners[2][2] = fMid; - - corners[3][0] = maxs[0]; - corners[3][1] = mins[1]; - corners[3][2] = fMid; - - vec3_t top, bottom; - - top[0] = Rad_rint(mins[0] + ((maxs[0] - mins[0]) / 2)); - top[1] = Rad_rint(mins[1] + ((maxs[1] - mins[1]) / 2)); - top[2] = Rad_rint(maxs[2]); - - VectorCopy(top, bottom); - bottom[2] = mins[2]; - - // sides - for (i = 0; i < 4; i++) - { - face_t* f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - int j = (i+1)%4; - - VectorCopy (top, f->planepts[0]); - VectorCopy (corners[i], f->planepts[1]); - VectorCopy(corners[j], f->planepts[2]); - - f = Face_Alloc(); - f->texdef = *texdef; - f->texdef.flags &= ~SURF_KEEP; - f->texdef.contents &= ~CONTENTS_KEEP; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorCopy (bottom, f->planepts[2]); - VectorCopy (corners[i], f->planepts[1]); - VectorCopy(corners[j], f->planepts[0]); - } - - return b; -} - - - - -/* -============= -Brush_MakeSided - -Makes the current brush have the given number of 2d sides -============= -*/ -void Brush_MakeSided (int sides) -{ - int i, axis; - vec3_t mins, maxs; - brush_t *b; - texdef_t *texdef; - face_t *f; - vec3_t mid; - float width; - float sv, cv; - - if (sides < 3) - { - Sys_Status ("Bad sides number", 0); - return; - } - - if (sides >= MAX_POINTS_ON_WINDING-4) - { - Sys_Printf("too many sides.\n"); - return; - } - - if (!QE_SingleBrush ()) - { - Sys_Status ("Must have a single brush selected", 0 ); - return; - } - - b = selected_brushes.next; - VectorCopy (b->mins, mins); - VectorCopy (b->maxs, maxs); - texdef = &g_qeglobals.d_texturewin.texdef; - - Brush_Free (b); - - if (g_pParentWnd->ActiveXY()) - { - switch(g_pParentWnd->ActiveXY()->GetViewType()) - { - case XY: axis = 2; break; - case XZ: axis = 1; break; - case YZ: axis = 0; break; - } - } - else - { - axis = 2; - } - - // find center of brush - width = 8; - for (i = 0; i < 3; i++) - { - mid[i] = (maxs[i] + mins[i]) * 0.5; - if (i == axis) continue; - if ((maxs[i] - mins[i]) * 0.5 > width) - width = (maxs[i] - mins[i]) * 0.5; - } - - b = Brush_Alloc(); - - // create top face - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - 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]; - 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]; - 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]; - - // create bottom face - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - 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]; - 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]; - 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]; - - for (i=0 ; itexdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - sv = sin (i*3.14159265*2/sides); - cv = cos (i*3.14159265*2/sides); - - f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5); - f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5); - f->planepts[0][axis] = mins[axis]; - - f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3]; - f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3]; - f->planepts[1][axis] = maxs[axis]; - - f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5); - f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5); - f->planepts[2][axis] = maxs[axis]; - } - - Brush_AddToList (b, &selected_brushes); - - Entity_LinkBrush (world_entity, b); - - Brush_Build( b ); - - Sys_UpdateWindows (W_ALL); -} - - - -/* -============= -Brush_Free - -Frees the brush with all of its faces and display list. -Unlinks the brush from whichever chain it is in. -Decrements the owner entity's brushcount. -Removes owner entity if this was the last brush -unless owner is the world. -Removes from groups -============= -*/ -void Brush_Free (brush_t *b, bool bRemoveNode) -{ - face_t *f, *next; - epair_t *ep, *enext; - - // remove from group - if (bRemoveNode) - Group_RemoveBrush(b); - - // free the patch if it's there - if (b->patchBrush) - { - Patch_Delete(b->pPatch); - } - - // free faces - for (f=b->brush_faces ; f ; f=next) - { - next = f->next; - Face_Free( f ); - } - - // TTimo : free brush epairs - for (ep = b->epairs ; ep ; ep=enext ) - { - enext = ep->next; - free (ep->key); - free (ep->value); - free (ep); - } - - // unlink from active/selected list - if (b->next) - Brush_RemoveFromList (b); - - // unlink from entity list - if (b->onext) - Entity_UnlinkBrush (b); - - free (b); -} - -/* -============= -Face_MemorySize -============= -*/ -int Face_MemorySize(face_t *f ) -{ - int size = 0; - - if (f->face_winding) - { -// size += _msize(f->face_winding); - size += sizeof(vec3_t)*f->face_winding->numpoints+2*sizeof(int); - } -// size += _msize(f); - size += sizeof(face_t); - return size; -} - -/* -============= -Brush_MemorySize -============= -*/ -int Brush_MemorySize(brush_t *b) -{ - face_t *f; - epair_t *ep; - int size = 0; - - // - if (b->patchBrush) - { - size += Patch_MemorySize(b->pPatch); - } - // - for (f = b->brush_faces; f; f = f->next) - { - size += Face_MemorySize(f); - } - // - for (ep = b->epairs; ep; ep = ep->next ) - { -// size += _msize(ep->key); - size += strlen(ep->key); -// size += _msize(ep->value); - size += strlen(ep->value); -// size += _msize(ep); - size += sizeof(epair_t); - } -// size += _msize(b); - size += sizeof(brush_t); - return size; -} - - -/* -============ -Brush_Clone - -Does NOT add the new brush to any lists -============ -*/ -brush_t *Brush_Clone (brush_t *b) -{ - brush_t *n = NULL; - face_t *f, *nf; - - if (b->patchBrush) - { - patchMesh_t *p = Patch_Duplicate(b->pPatch); - Brush_RemoveFromList(p->pSymbiot); - Entity_UnlinkBrush(p->pSymbiot); - n = p->pSymbiot; - } - else - { - n = Brush_Alloc(); - n->numberId = g_nBrushId++; - n->owner = b->owner; - for (f=b->brush_faces ; f ; f=f->next) - { - nf = Face_Clone( f ); - nf->next = n->brush_faces; - n->brush_faces = nf; - } - } - - return n; -} - -/* -============ -Brush_Clone - -Does NOT add the new brush to any lists -============ -*/ -brush_t *Brush_FullClone(brush_t *b) -{ - brush_t *n = NULL; - face_t *f, *nf, *f2, *nf2; - int j; - - if (b->patchBrush) - { - patchMesh_t *p = Patch_Duplicate(b->pPatch); - Brush_RemoveFromList(p->pSymbiot); - Entity_UnlinkBrush(p->pSymbiot); - n = p->pSymbiot; - n->owner = b->owner; - Brush_Build(n); - } - else - { - n = Brush_Alloc(); - n->numberId = g_nBrushId++; - n->owner = b->owner; - VectorCopy(b->mins, n->mins); - VectorCopy(b->maxs, n->maxs); - // - for (f = b->brush_faces; f; f = f->next) - { - if (f->original) continue; - nf = Face_FullClone(f); - nf->next = n->brush_faces; - n->brush_faces = nf; - //copy all faces that have the original set to this face - for (f2 = b->brush_faces; f2; f2 = f2->next) - { - if (f2->original == f) - { - nf2 = Face_FullClone(f2); - nf2->next = n->brush_faces; - n->brush_faces = nf2; - //set original - nf2->original = nf; - } - } - } - for (nf = n->brush_faces; nf; nf = nf->next) - { - Face_SetColor(n, nf, 1.0); - if (nf->face_winding) - { - if (g_qeglobals.m_bBrushPrimitMode) - EmitBrushPrimitTextureCoordinates(nf,nf->face_winding); - else - { - for (j = 0; j < nf->face_winding->numpoints; j++) - EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf); - } - } - } - } - return n; -} - - // FIXME - spog - finish this later.. - /* -bool Triangle_Ray(vec3_t origin, vec3_t dir, vec3_t p1, vec3_t p2, vec3_t p3) -{ - int i; - vec3_t v1, v2, normal[3]; - float d; - - //Sys_Printf("p1: %f %f %f\n",p1[0],p1[1],p1[2]); - //Sys_Printf("p2: %f %f %f\n",p2[0],p2[1],p2[2]); - //Sys_Printf("p3: %f %f %f\n",p3[0],p3[1],p3[2]); - //Sys_Printf("origin: %f %f %f\n",origin[0],origin[1],origin[2]); - - // test ray against triangle - // get triangle plane normal - //VectorSubtract(p1, p2, v1); - //VectorSubtract(p1, p3, v2); - //CrossProduct(v1, v2, v1); - // check normal against direction - //if (DotProduct(dir, v1) >= 0) - //{ - // generate cone normals - VectorSubtract(origin, p1, v1); - VectorSubtract(origin, p2, v2); - CrossProduct(v1, v2, normal[0]); - VectorSubtract(origin, p2, v1); - VectorSubtract(origin, p3, v2); - CrossProduct(v1, v2, normal[1]); - VectorSubtract(origin, p3, v1); - VectorSubtract(origin, p1, v2); - CrossProduct(v1, v2, normal[2]); - //} - //else - //{ - // flip normals if triangle faces away - // Sys_Printf("flipped\n"); - // VectorSubtract(origin, p1, v1); - // VectorSubtract(origin, p3, v2); - // CrossProduct(v1, v2, normal[0]); - // VectorSubtract(origin, p3, v1); - // VectorSubtract(origin, p2, v2); - // CrossProduct(v1, v2, normal[1]); - // VectorSubtract(origin, p2, v1); - // VectorSubtract(origin, p1, v2); - // CrossProduct(v1, v2, normal[2]); - //} - - for (i=0; i<3; i++) - { - VectorNormalize(normal[i]); - //Sys_Printf("direction: %f %f %f\n",dir[0],dir[1],dir[2]); - //Sys_Printf("normal: %f %f %f\n",normal[i][0],normal[i][1],normal[i][2]); - d = DotProduct(dir, normal[i]); - //Sys_Printf("dotproduct: %f\n",d); - if (d < 0) - return false; - } - return true; -} -*/ - -/* -extern int Triangle_Ray(float orig[3], float dir[3], bool bCullBack, - float vert0[3], float vert1[3], float vert2[3], - double *t, double *u, double *v); - -bool Model_Ray(brush_t *b, vec3_t origin, vec3_t dir, double *t, double *u, double *v) -{ - bool bIntersect = false; - float tBest = FLT_MAX; - int i, j; - vec3_t xyz[3]; - vec3_t vRay[2]; - - float angle = FloatForKey (b->owner, "angle"); // FIXME: should be set when this entity key is set - - VectorSubtract (origin, b->owner->origin, vRay[0]); - VectorCopy (dir, vRay[1]); - - if (angle > 0) - { - int i; - float s, c; - float x, y; - - s = sin (-angle/180*Q_PI); - c = cos (-angle/180*Q_PI); - - for (i=0; i<2; i++) - { - x = vRay[i][0]; - y = vRay[i][1]; - vRay[i][0] = (x * c) - (y * s); - vRay[i][1] = (x * s) + (y * c); - } - } - - entitymodel *model = b->owner->md3Class->model; - - while (model != NULL) - { - for (i = 0; i < model->nTriCount; i++) - { - for (j = 0; j < 3; j++) - VectorCopy(model->pVertList[model->pTriList[i].indexes[j]].v, xyz[j]); - - if (Triangle_Ray(vRay[0], vRay[1], true, xyz[0], xyz[2], xyz[1], t, u, v)) - { - bIntersect = true; - if (*t < tBest) - tBest = *t; - } - } - model = model->pNext; - } - if (bIntersect) - { - *t = tBest; - return true; - } - else - { - *t = 0; - return false; - } -} -*/ - -/* -============== -Brush_Ray - -Itersects a ray with a brush -Returns the face hit and the distance along the ray the intersection occured at -Returns NULL and 0 if not hit at all - -http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 -============== -*/ -extern bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v); -face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist, int nFlags) -{ - face_t *f, *firstface = NULL; - vec3_t p1, p2; - float frac, d1, d2; - int i; - - if (b->owner->eclass->fixedsize - && b->owner->model.pSelect - && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)) - && g_PrefsDlg.m_nEntityShowState != ENTITY_BOX) - { - ray_t ray_local; - vec_t dist_local = FLT_MAX; - ray_construct_for_vec3(&ray_local, origin, dir); - if (b->owner->model.pSelect->TestRay(&ray_local, &dist_local)) - { - *dist = dist_local; - return b->brush_faces; - } - else - { - *dist = 0.0f; - return NULL; - } - } - - VectorCopy (origin, p1); - for (i=0 ; i<3 ; i++) - p2[i] = p1[i] + dir[i]*2*g_MaxWorldCoord; - - for (f=b->brush_faces ; f ; f=f->next) - { - d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; - d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; - if (d1 >= 0 && d2 >= 0) - { - *dist = 0; - return NULL; // ray is on front side of face - } - if (d1 <=0 && d2 <= 0) - continue; - // clip the ray to the plane - frac = d1 / (d1 - d2); - if (d1 > 0) - { - firstface = f; - for (i=0 ; i<3 ; i++) - p1[i] = p1[i] + frac *(p2[i] - p1[i]); - } - else - { - for (i=0 ; i<3 ; i++) - p2[i] = p1[i] + frac *(p2[i] - p1[i]); - } - } - - // find distance p1 is along dir - VectorSubtract (p1, origin, p1); - d1 = DotProduct (p1, dir); - - *dist = d1; - - // new test stuff for patches - if (!g_PrefsDlg.m_bPatchBBoxSelect && b->patchBrush) - { - double t, u, v; // t is the distance from origin to point-of-intersection.. er.. i don't know what u and v are - if (!Patch_Ray(b->pPatch, origin, dir, &t, &u, &v)) - { - *dist = 0; - return NULL; - } - else - { - *dist = (float)t; - //Sys_Printf("t: %f, u: %f, v: %f\n", t, u, v); - } - } - - // IMPORTANT NOTE: - // modifications to the discarding code here should be matched in the selection code - // see Brush_Draw - - // do some last minute filtering - if (firstface && nFlags & SF_CAMERA) - { - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) - { - if (strstr(firstface->texdef.GetName(), "caulk")) - { - *dist = 0; - return NULL; - } - } - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) - { - if (strstr(firstface->texdef.GetName(), "botclip") || strstr(firstface->texdef.GetName(), "clipmonster")) - { - *dist = 0; - return NULL; - } - } - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) - { - if (strstr(firstface->texdef.GetName(), "clip")) - { - *dist = 0; - return NULL; - } - } - } - - return firstface; -} - -//PGM -face_t *Brush_Point (vec3_t origin, brush_t *b) -{ - face_t *f; - float d1; - - for (f=b->brush_faces ; f ; f=f->next) - { - d1 = DotProduct (origin, f->plane.normal) - f->plane.dist; - if (d1 > 0) - { - return NULL; // point is on front side of face - } - } - - return b->brush_faces; -} -//PGM - - -void Brush_AddToList (brush_t *b, brush_t *blist) -{ - if (b->next || b->prev) - Error ("Brush_AddToList: already linked"); - - if (blist == &selected_brushes || blist == &active_brushes) - { - if (b->patchBrush && blist == &selected_brushes) - { - Patch_Select(b->pPatch); - } - } - b->next = blist->next; - blist->next->prev = b; - blist->next = b; - b->prev = blist; - - // TTimo messaging - DispatchRadiantMsg( RADIANT_SELECTION ); -} - -void Brush_RemoveFromList (brush_t *b) -{ - if (!b->next || !b->prev) - Error ("Brush_RemoveFromList: not linked"); - - if (b->patchBrush) - { - Patch_Deselect(b->pPatch); - } - b->next->prev = b->prev; - b->prev->next = b->next; - b->next = b->prev = NULL; -} - -/* -=============== -SetFaceTexdef - -Doesn't set the curve flags - -NOTE : ( TTimo ) - never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture - use Texture_ForName() to find the right shader - FIXME : send the right shader ( qtexture_t * ) in the parameters ? - -TTimo: surface plugin, added an IPluginTexdef* parameter - if not NULL, get ->Copy() of it into the face ( and remember to hook ) - if NULL, ask for a default - - TTimo - shader code cleanup - added IShader* parameter - =============== -*/ -void SetFaceTexdef2 (brush_t *b, face_t *f, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { - int oldFlags; - int oldContents; - face_t *tf; - - oldFlags = f->texdef.flags; - oldContents = f->texdef.contents; - if (g_qeglobals.m_bBrushPrimitMode) - { - f->texdef = *texdef; - ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); - } - else - if (bFitScale) - { - f->texdef = *texdef; - // fit the scaling of the texture on the actual plane - vec3_t p1,p2,p3; // absolute coordinates - // compute absolute coordinates - ComputeAbsolute(f,p1,p2,p3); - // compute the scale - vec3_t vx,vy; - VectorSubtract(p2,p1,vx); - VectorNormalize(vx, vx); - VectorSubtract(p3,p1,vy); - VectorNormalize(vy, vy); - // assign scale - VectorScale(vx,texdef->scale[0],vx); - VectorScale(vy,texdef->scale[1],vy); - VectorAdd(p1,vx,p2); - VectorAdd(p1,vy,p3); - // compute back shift scale rot - AbsoluteToLocal(f->plane,f,p1,p2,p3); - } - else - f->texdef = *texdef; - f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); - f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); - - // if this is a curve face, set all other curve faces to the same texdef - if (f->texdef.flags & SURF_CURVE) - { - for (tf = b->brush_faces ; tf ; tf = tf->next) - { - if (tf->texdef.flags & SURF_CURVE) - tf->texdef = f->texdef; - } - } -} - -/* -=============== -SetFaceTexdef - -Doesn't set the curve flags - -NOTE : ( TTimo ) - never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture - use Texture_ForName() to find the right shader - FIXME : send the right shader ( qtexture_t * ) in the parameters ? - - TTimo: surface plugin, added an IPluginTexdef* parameter - if not NULL, get ->Copy() of it into the face ( and remember to hook ) - if NULL, ask for a default -=============== -*/ -void SetFaceTexdef (face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { - int oldFlags; - int oldContents; - - oldFlags = f->texdef.flags; - oldContents = f->texdef.contents; - - if(strcmp(f->texdef.GetName(), texdef->GetName()) != 0) // set shader here instead of Brush_Build - Face_SetShader(f, texdef->GetName()); - - if (g_qeglobals.m_bBrushPrimitMode) - { - f->texdef = *texdef; - ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, QERApp_Shader_ForName( f->texdef.GetName() )->getTexture() ); - } - else - { - if (bFitScale) - { - f->texdef = *texdef; - // fit the scaling of the texture on the actual plane - vec3_t p1,p2,p3; // absolute coordinates - // compute absolute coordinates - ComputeAbsolute(f,p1,p2,p3); - // compute the scale - vec3_t vx,vy; - VectorSubtract(p2,p1,vx); - VectorNormalize(vx, vx); - VectorSubtract(p3,p1,vy); - VectorNormalize(vy, vy); - // assign scale - VectorScale(vx,texdef->scale[0],vx); - VectorScale(vy,texdef->scale[1],vy); - VectorAdd(p1,vx,p2); - VectorAdd(p1,vy,p3); - // compute back shift scale rot - AbsoluteToLocal(f->plane,f,p1,p2,p3); - } - else - { - f->texdef = *texdef; - } - } - f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); - f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); -} - -#ifdef _DEBUG -void Brush_SetTexture2 (brush_t *b, IShader *pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) -{ - for (face_t* f = b->brush_faces ; f ; f = f->next) - SetFaceTexdef2 (b, f, pShader, texdef, brushprimit_texdef, bFitScale, pTexdef); - Brush_Build( b ); - if (b->patchBrush) - { - Patch_SetTexture(b->pPatch, texdef, pTexdef ); - b->bFiltered = FilterBrush( b ); - } -} -#endif - -void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) -{ - for (face_t* f = b->brush_faces ; f ; f = f->next) - SetFaceTexdef (f, texdef, brushprimit_texdef, bFitScale, pTexdef); - Brush_Build( b ); - if (b->patchBrush) - { - Patch_SetTexture(b->pPatch, texdef, pTexdef ); - b->bFiltered = FilterBrush( b ); - } -} - - -qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) -{ - float d1, d2, fr; - int i; - float *v; - - d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; - d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; - - if (d1 >= 0 && d2 >= 0) - return false; // totally outside - if (d1 <= 0 && d2 <= 0) - return true; // totally inside - - fr = d1 / (d1 - d2); - - if (d1 > 0) - v = p1; - else - v = p2; - - for (i=0 ; i<3 ; i++) - v[i] = p1[i] + fr*(p2[i] - p1[i]); - - return true; -} - - -int AddPlanept (float *f) -{ - int i; - - for (i=0 ; iowner->eclass->fixedsize) - return; - - c = 0; - for (i=0 ; i<3 ; i++) - c += AddPlanept (f->planepts[i]); - if (c == 0) - return; // already completely added - - // select all points on this plane in all brushes the selection - for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) - { - if (b2 == b) - continue; - for (f2=b2->brush_faces ; f2 ; f2=f2->next) - { - for (i=0 ; i<3 ; i++) - if (fabs(DotProduct(f2->planepts[i], f->plane.normal) - -f->plane.dist) > ON_EPSILON) - break; - if (i==3) - { // move this face as well - Brush_SelectFaceForDragging (b2, f2, shear); - break; - } - } - } - - - // if shearing, take all the planes adjacent to - // selected faces and rotate their points so the - // edge clipped by a selcted face has two of the points - if (!shear) - return; - - for (f2=b->brush_faces ; f2 ; f2=f2->next) - { - if (f2 == f) - continue; - w = Brush_MakeFaceWinding (b, f2); - if (!w) - continue; - - // any points on f will become new control points - for (i=0 ; inumpoints ; i++) - { - d = DotProduct (w->points[i], f->plane.normal) - - f->plane.dist; - if (d > -ON_EPSILON && d < ON_EPSILON) - break; - } - - // - // if none of the points were on the plane, - // leave it alone - // - if (i != w->numpoints) - { - if (i == 0) - { // see if the first clockwise point was the - // last point on the winding - d = DotProduct (w->points[w->numpoints-1] - , f->plane.normal) - f->plane.dist; - if (d > -ON_EPSILON && d < ON_EPSILON) - i = w->numpoints - 1; - } - - AddPlanept (f2->planepts[0]); - - VectorCopy (w->points[i], f2->planepts[0]); - if (++i == w->numpoints) - i = 0; - - // see if the next point is also on the plane - d = DotProduct (w->points[i] - , f->plane.normal) - f->plane.dist; - if (d > -ON_EPSILON && d < ON_EPSILON) - AddPlanept (f2->planepts[1]); - - VectorCopy (w->points[i], f2->planepts[1]); - if (++i == w->numpoints) - i = 0; - - // the third point is never on the plane - - VectorCopy (w->points[i], f2->planepts[2]); - } - - free(w); - } +void Brush_addTextureChangedCallback( const SignalHandler& handler ){ + g_brushTextureChangedCallbacks.connectLast( handler ); } -/* -============== -Brush_SideSelect - -The mouse click did not hit the brush, so grab one or more side -planes for dragging -============== -*/ -void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir - , qboolean shear) -{ - face_t *f, *f2; - vec3_t p1, p2; - - for (f=b->brush_faces ; f ; f=f->next) - { - VectorCopy (origin, p1); - VectorMA (origin, 2*g_MaxWorldCoord, dir, p2); - - for (f2=b->brush_faces ; f2 ; f2=f2->next) - { - if (f2 == f) - continue; - ClipLineToFace (p1, p2, f2); - } +void Brush_textureChanged(){ + g_brushTextureChangedCallbacks(); +} - if (f2) - continue; +QuantiseFunc Face::m_quantise; +EBrushType Face::m_type; +EBrushType FacePlane::m_type; +bool g_brush_texturelock_enabled = true; - if (VectorCompare (p1, origin)) - continue; - if (ClipLineToFace (p1, p2, f)) - continue; +EBrushType Brush::m_type; +double Brush::m_maxWorldCoord = 0; +Shader* Brush::m_state_point; +Shader* BrushClipPlane::m_state = 0; +Shader* BrushInstance::m_state_selpoint; +Counter* BrushInstance::m_counter = 0; - Brush_SelectFaceForDragging (b, f, shear); - } -} +FaceInstanceSet g_SelectedFaceInstances; -bool g_bBuildWindingsNoTexBuild = false; -void Brush_SetBuildWindingsNoTexBuild(bool bBuild) +struct SListNode { - g_bBuildWindingsNoTexBuild = bBuild; -} + SListNode* m_next; +}; -// TTimo: don't rebuild pShader and d_texture if it doesn't seem necessary -// saves quite a lot of time, but on the other hand we've gotta make sure we clean the d_texture in some cases -// ie when we want to update a shader -// default will make Radiant rebuild the texture, but it can be turned off by setting the flag g_bBuildWindingsNoTexBuild -void Brush_BuildWindings( brush_t *b, bool bSnap ) +class ProximalVertex { - winding_t *w; - face_t *face; - vec_t v; - - if (bSnap) - Brush_SnapPlanepts( b ); - - // clear the mins/maxs bounds - b->mins[0] = b->mins[1] = b->mins[2] = 99999; - b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; - - Brush_MakeFacePlanes (b); +public: +const SListNode* m_vertices; - face = b->brush_faces; - - float fCurveColor = 1.0; - - for ( ; face ; face=face->next) - { - int i, j; - free(face->face_winding); - w = face->face_winding = Brush_MakeFaceWinding (b, face); - - if (!g_bBuildWindingsNoTexBuild || !face->d_texture) - { -#ifdef _DEBUG - // if there's no d_texture, then we expect pShader to be empty - if (!face->d_texture && face->pShader) - Sys_FPrintf(SYS_ERR, "ERROR: unexpected face->pShader != NULL with face->d_texture == NULL in Brush_BuildWindings\n"); -#endif - if ((!face->d_texture && !face->pShader) || !face->pShader) - { - // NOTE TTimo - // patch 84 for bug 253 doesn't dec ref the potential face->pShader - // add a debug check to make sure this is actually not necessary -#ifdef _DEBUG - if (face->pShader) - { - Sys_FPrintf(SYS_ERR, "ERROR: face->pShader != NULL in Brush_BuildWindings\n"); - } -#endif - face->pShader = QERApp_Shader_ForName( face->texdef.GetName() ); - face->pShader->IncRef(); - face->d_texture = face->pShader->getTexture(); - } - } - - if (!w) - continue; - - for (i=0 ; inumpoints ; i++) - { - // add to bounding box - for (j=0 ; j<3 ; j++) - { - v = w->points[i][j]; - if (v > b->maxs[j]) - b->maxs[j] = v; - if (v < b->mins[j]) - b->mins[j] = v; - } - } - Face_SetColor (b, face, fCurveColor); - - fCurveColor -= .10f; - if (fCurveColor <= 0) - fCurveColor = 1.0f; - - // computing ST coordinates for the windings - if (g_qeglobals.m_bBrushPrimitMode) - { - if (g_qeglobals.bNeedConvert) - { - // we have parsed old brushes format and need conversion - // convert old brush texture representation to new format - FaceToBrushPrimitFace(face); -#ifdef _DEBUG - // use old texture coordinates code to check against - for (i=0 ; inumpoints ; i++) - EmitTextureCoordinates( w->points[i], face->d_texture, face); -#endif - } - // use new texture representation to compute texture coordinates - // in debug mode we will check against old code and warn if there are differences - EmitBrushPrimitTextureCoordinates(face,w); - } - else - { - if (g_qeglobals.bNeedConvert) - { - BrushPrimitFaceToFace(face); -/* - // we have parsed brush primitives and need conversion back to standard format - // NOTE: converting back is a quick hack, there's some information lost and we can't do anything about it - // FIXME: if we normalize the texture matrix to a standard 2x2 size, we end up with wrong scaling - // I tried various tweaks, no luck .. seems shifting is lost - brushprimit_texdef_t aux; - ConvertTexMatWithQTexture( &face->brushprimit_texdef, face->d_texture, &aux, NULL ); - TexMatToFakeTexCoords( aux.coords, face->texdef.shift, &face->texdef.rotate, face->texdef.scale ); - face->texdef.scale[0]/=2.0; - face->texdef.scale[1]/=2.0; -*/ - } - for (i=0 ; inumpoints ; i++) - EmitTextureCoordinates( w->points[i], face->d_texture, face); - } - } +ProximalVertex( const SListNode* next ) + : m_vertices( next ){ } -/* -================== -Brush_RemoveEmptyFaces - -Frees any overconstraining faces -================== -*/ -void Brush_RemoveEmptyFaces ( brush_t *b ) -{ - face_t *f, *next; - - f = b->brush_faces; - b->brush_faces = NULL; - - for ( ; f ; f=next) - { - next = f->next; - if (!f->face_winding) - Face_Free (f); - else - { - f->next = b->brush_faces; - b->brush_faces = f; - } - +bool operator<( const ProximalVertex& other ) const { + if ( !( operator==( other ) ) ) { + return m_vertices < other.m_vertices; } + return false; } - -void Brush_SnapToGrid(brush_t *pb) -{ - face_t *f; - vec3_t temp; - vec3_t diff[2]; - int mult[3]; - int i, j, n; - // TTimo: some brushes are "special" and should not be snapped - // specially fixed-size entity ones - if (pb->owner->eclass->fixedsize) - { - // save current origin - VectorCopy (pb->owner->origin, temp); - // snap the origin - VectorFSnap(pb->owner->origin, g_qeglobals.d_gridsize); - // return if amount is zero - if (VectorCompare (pb->owner->origin, temp)) - return; - // transform brush faces same amount - VectorSubtract (pb->owner->origin, temp, temp); - for (f = pb->brush_faces; f; f = f->next) - { - for (i=0 ; i<3 ; i++) - VectorAdd (f->planepts[i], temp, f->planepts[i]); - } - } - else +bool operator==( const ProximalVertex& other ) const { + const SListNode* v = m_vertices; + std::size_t DEBUG_LOOP = 0; + do { - for (f = pb->brush_faces ; f; f = f->next) - { - for (j=0; j<2; j++) - { - // spog - move planepts apart just far enough to avoid snapping two together - VectorSubtract (f->planepts[j+1], f->planepts[j], diff[j]); - for (i=0; i<3; i++) - { - if (diff[j][i] == 0.0f) - mult[i] = 2; // next value up from 1 - else // multiplier = gridsize / component difference, rounded up - mult[i] = (int)ceil(fabs(g_qeglobals.d_gridsize / diff[j][i])); - } - - if (mult[0] > 1 && mult[1] > 1 && mult[2] > 1) // if all multipliers are greater than 1 - { - n = (mult[0] >= mult[1] && mult[0] >= mult[2]) ? 0 : (mult[1] >= mult[0] && mult[1] >= mult[2]) ? 1 : 2; - for (i=0; i<3; i++) - diff[j][i] *= mult[n]; // multiply difference by multiplier of smallest component - } - VectorAdd (f->planepts[j], diff[j], f->planepts[j+1]); - } - - for (i=0; i<3; i++) - VectorFSnap(f->planepts[i], g_qeglobals.d_gridsize); - + if ( v == other.m_vertices ) { + return true; } - } - Brush_Build(pb,true,true,false,false); // don't filter -} - -void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild) -{ - for (face_t* f=b->brush_faces ; f ; f=f->next) - { - for (int i=0 ; i<3 ; i++) - { - VectorRotateOrigin (f->planepts[i], vAngle, vOrigin, f->planepts[i]); + v = v->m_next; + //ASSERT_MESSAGE(DEBUG_LOOP < c_brush_maxFaces, "infinite loop"); + if ( !( DEBUG_LOOP < c_brush_maxFaces ) ) { + break; } + ++DEBUG_LOOP; } - if (bBuild) - { - Brush_Build(b,false,false,false,false); // don't filter - } + while ( v != m_vertices ); + return false; } +}; -void Brush_Center(brush_t *b, vec3_t vNewCenter) -{ - vec3_t vMid; - // get center of the brush - for (int j = 0; j < 3; j++) - { - vMid[j] = b->mins[j] + fabs((b->maxs[j] - b->mins[j]) * 0.5); - } - // calc distance between centers - VectorSubtract(vNewCenter, vMid, vMid); - Brush_Move(b, vMid, true); - +typedef Array ProximalVertexArray; +std::size_t ProximalVertexArray_index( const ProximalVertexArray& array, const ProximalVertex& vertex ){ + return vertex.m_vertices - array.data(); } -void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax) -{ - face_t *f; - texdef_t texdef; - int i; - short box[3][2] = { { 0, 1 }, { 2, 0 }, { 1, 2 } }; - - for (i=0 ; i<3 ; i++) - if (vMax[i] < vMin[i]) - Error ("Brush_Resize: invalid input"); - - if(b->brush_faces != NULL) - texdef = b->brush_faces->texdef; - else - texdef = g_qeglobals.d_texturewin.texdef; - - while (b->brush_faces != NULL) - { - f = b->brush_faces->next; - Face_Free(b->brush_faces); - b->brush_faces = f; - } - - for(i=0; i<3; i++) - { - f = b->brush_faces; - b->brush_faces = Face_Alloc(); - b->brush_faces->next = f; - f = b->brush_faces; - f->texdef = texdef; - VectorCopy(vMax, f->planepts[0]); - VectorCopy(vMax, f->planepts[1]); - VectorCopy(vMax, f->planepts[2]); - f->planepts[2][box[i][0]] = vMin[box[i][0]]; - f->planepts[1][box[i][1]] = vMin[box[i][1]]; - } - for(i=0; i<3; i++) - { - f = b->brush_faces; - b->brush_faces = Face_Alloc(); - b->brush_faces->next = f; - f = b->brush_faces; - f->texdef = texdef; - VectorCopy(vMin, f->planepts[0]); - VectorCopy(vMin, f->planepts[1]); - VectorCopy(vMin, f->planepts[2]); - f->planepts[1][box[i][0]] = vMax[box[i][0]]; - f->planepts[2][box[i][1]] = vMax[box[i][1]]; - } -} -void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up) -{ - int angleVal; - vec3_t angles; - angleVal = IntForKey(e, "angle"); - if (angleVal == -1) // up - { - VectorSet(angles, 270, 0, 0); - } - else if(angleVal == -2) // down - { - VectorSet(angles, 90, 0, 0); - } - else +inline bool Brush_isBounded( const Brush& brush ){ + for ( Brush::const_iterator i = brush.begin(); i != brush.end(); ++i ) { - VectorSet(angles, 0, angleVal, 0); + if ( !( *i )->is_bounded() ) { + return false; + } } - - AngleVectors(angles, forward, right, up); -} - -void Brush_DrawFacingAngle (brush_t *b, entity_t *e) -{ - vec3_t forward, right, up; - vec3_t endpoint, tip1, tip2; - vec3_t start; - float dist; - - VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start); - VectorScale(start, 0.5, start); - dist = (b->maxs[0] - start[0]) * 2.5; - - FacingVectors (e, forward, right, up); - VectorMA (start, dist, forward, endpoint); - - dist = (b->maxs[0] - start[0]) * 0.5; - VectorMA (endpoint, -dist, forward, tip1); - VectorMA (tip1, -dist, up, tip1); - VectorMA (tip1, 2*dist, up, tip2); - - qglColor4f (1, 1, 1, 1); - qglLineWidth (4); - qglBegin (GL_LINES); - qglVertex3fv (start); - qglVertex3fv (endpoint); - qglVertex3fv (endpoint); - qglVertex3fv (tip1); - qglVertex3fv (endpoint); - qglVertex3fv (tip2); - qglEnd (); - qglLineWidth (1); + return true; } -void Brush_FaceDraw(face_t *face, int nGLState) -{ - const winding_t *w = face->face_winding; - if (w == NULL) return; - if (nGLState & DRAW_GL_LIGHTING && g_PrefsDlg.m_bGLLighting) - qglNormal3fv(face->plane.normal); - /* - if (mode & DRAW_GL_TEXTURE_2D) - qglTexCoordPointer(2, GL_FLOAT, 5, &w->points[3]); - qglVertexPointer(3, GL_FLOAT, 5, w->points); - - if (mode & DRAW_GL_FILL) - qglDrawArrays(GL_TRIANGLE_FAN, 0, w->numpoints); - else - qglDrawArrays(GL_POLYGON, 0, w->numpoints); - */ - - if (nGLState & DRAW_GL_FILL) - qglBegin(GL_TRIANGLE_FAN); - else - qglBegin(GL_POLYGON); - - for (int i=0 ; inumpoints ; i++) - { - if (nGLState & DRAW_GL_TEXTURE_2D) - qglTexCoord2fv( &w->points[i][3] ); - qglVertex3fv(w->points[i]); - } - qglEnd(); -} +void Brush::buildBRep(){ + bool degenerate = buildWindings(); -void Brush_Draw(brush_t *b) -{ - face_t *face; - int order; - qtexture_t *prev = 0; - winding_t *w; - - int nDrawMode = g_pParentWnd->GetCamWnd()->Camera()->draw_mode; - int nGLState = g_pParentWnd->GetCamWnd()->Camera()->draw_glstate; - - GLfloat material[4], identity[4]; - VectorSet(identity, 0.8f, 0.8f, 0.8f); - IShader *pShader; - qglPushClientAttrib(GL_CLIENT_VERTEX_ARRAY_BIT); - qglDisableClientState(GL_NORMAL_ARRAY); - - // guarantee the texture will be set first - bool bTrans; - prev = NULL; - for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + std::size_t faces_size = 0; + std::size_t faceVerticesCount = 0; + for ( Faces::const_iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { - w = face->face_winding; - if (!w) - { - continue; // freed face + if ( ( *i )->contributes() ) { + ++faces_size; } + faceVerticesCount += ( *i )->getWinding().numpoints; + } - bTrans = (face->pShader->getFlags() & QER_TRANS); + if ( degenerate || faces_size < 4 || faceVerticesCount != ( faceVerticesCount >> 1 ) << 1 ) { // sum of vertices for each face of a valid polyhedron is always even + m_uniqueVertexPoints.resize( 0 ); - if (bTrans && !(nGLState & DRAW_GL_BLEND)) - continue; - if (!bTrans && nGLState & DRAW_GL_BLEND) - continue; - - // IMPORTANT NOTE: - // modifications to the discarding code here should be matched in the selection code - // see Brush_Ray + vertex_clear(); + edge_clear(); - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) - { - if (strstr(face->texdef.GetName(), "caulk")) - continue; - } + m_edge_indices.resize( 0 ); + m_edge_faces.resize( 0 ); - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_BOTCLIP) - { - if (strstr(face->texdef.GetName(), "botclip") || strstr(face->texdef.GetName(), "clipmonster")) - continue; - } + m_faceCentroidPoints.resize( 0 ); + m_uniqueEdgePoints.resize( 0 ); + m_uniqueVertexPoints.resize( 0 ); - if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) - { - if (strstr(face->texdef.GetName(), "clip")) - continue; - } - - if (nGLState & DRAW_GL_TEXTURE_2D && face->d_texture->name[0] == '(') - { - prev = NULL; - qglDisable(GL_TEXTURE_2D); - } - else if (nGLState & DRAW_GL_TEXTURE_2D && (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev) - { - // set the texture for this face - prev = face->d_texture; - qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); - } - - if (nGLState & DRAW_GL_LIGHTING && !g_PrefsDlg.m_bGLLighting) - { - if (!b->owner->eclass->fixedsize) - material[3] = face->pShader->getTrans(); - else - material[3] = 1; - VectorCopy(face->d_color, material); - - if (nGLState & DRAW_GL_TEXTURE_2D) - qglColor4f(face->d_shade, face->d_shade, face->d_shade, material[3]); - else - qglColor4fv(material); - } - else if (!b->owner->eclass->fixedsize) + for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i ) { - pShader = face->pShader; - VectorCopy(pShader->getTexture()->color, material); - material[3] = identity[3] = pShader->getTrans(); - - if (nGLState & DRAW_GL_TEXTURE_2D) - qglColor4fv(identity); - else - qglColor4fv(material); + ( *i )->getWinding().resize( 0 ); } - - // draw the polygon - - Brush_FaceDraw(face, nGLState); - } - qglPopClientAttrib(); -} - -void Face_Draw( face_t *f ) -{ - int i; - - if ( f->face_winding == 0 ) - return; - qglBegin(GL_POLYGON); - for ( i = 0 ; i < f->face_winding->numpoints; i++) - qglVertex3fv( f->face_winding->points[i] ); - qglEnd(); -} - -entity_t *FindEntity(const char *pszKey, const char *pszValue) -{ - entity_t *pe; - - pe = entities.next; - - for (; pe != NULL && pe != &entities ; pe = pe->next) - { - if (!strcmp(ValueForKey(pe, pszKey), pszValue)) - return pe; } - - return NULL; -} - -void Brush_DrawXY(brush_t *b, int nViewType) -{ - face_t *face; - int order; - winding_t *w; - int i; - - if (b->patchBrush) - { - Patch_DrawXY(b->pPatch); - if (!g_bPatchShowBounds) - return; - } - - if (b->owner->eclass->fixedsize) - { - if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT)) - { -#if 1 // requires vertex arrays enabled - DrawLight(b->owner, DRAW_GL_WIRE, (IsBrushSelected(b)) ? g_PrefsDlg.m_nLightRadiuses : 0, nViewType); -#else - vec3_t vCorners[4]; - float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2; - - vCorners[0][0] = b->mins[0]; - vCorners[0][1] = b->mins[1]; - vCorners[0][2] = fMid; - - vCorners[1][0] = b->mins[0]; - vCorners[1][1] = b->maxs[1]; - vCorners[1][2] = fMid; - - vCorners[2][0] = b->maxs[0]; - vCorners[2][1] = b->maxs[1]; - vCorners[2][2] = fMid; - - vCorners[3][0] = b->maxs[0]; - vCorners[3][1] = b->mins[1]; - vCorners[3][2] = fMid; - - vec3_t vTop, vBottom; - - vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2); - vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2); - vTop[2] = b->maxs[2]; - - VectorCopy(vTop, vBottom); - vBottom[2] = b->mins[2]; - - qglBegin(GL_LINES); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[0]); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[1]); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[2]); - qglVertex3fv(vTop); - qglVertex3fv(vCorners[3]); - qglEnd(); - - qglBegin(GL_LINES); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[0]); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[1]); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[2]); - qglVertex3fv(vBottom); - qglVertex3fv(vCorners[3]); - qglEnd(); - - qglBegin(GL_LINE_LOOP); - qglVertex3fv(vCorners[0]); - qglVertex3fv(vCorners[1]); - qglVertex3fv(vCorners[2]); - qglVertex3fv(vCorners[3]); - qglEnd(); -#endif - DrawBrushEntityName (b); - return; - } - else if (b->owner->model.pRender && !(!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))) - { - qglPushAttrib(GL_CURRENT_BIT); // save brush colour - qglColor3fv(b->owner->eclass->color); - if( g_PrefsDlg.m_nEntityShowState != ENTITY_BOX ) - b->owner->model.pRender->Draw(DRAW_GL_WIRE, DRAW_RF_XY); - aabb_draw(b->owner->model.pRender->GetAABB(), DRAW_GL_WIRE); - qglPopAttrib(); - return; - } - //} - } - - for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + else { - // moved so check occurs earlier - w = face->face_winding; - if (!w) - continue; - // only draw polygons facing in a direction we care about - if (nViewType == XY) - { - if (face->plane.normal[2] <= 0) - continue; - } - else - { - if (nViewType == XZ) - { - if (face->plane.normal[1] >= 0) // stop axes being mirrored - continue; - } - else - { - if (face->plane.normal[0] <= 0) - continue; - } - } - - // draw the polygon - qglBegin(GL_LINE_LOOP); - for (i=0 ; inumpoints ; i++) - qglVertex3fv(w->points[i]); - qglEnd(); - } + { + typedef std::vector FaceVertices; + FaceVertices faceVertices; + faceVertices.reserve( faceVerticesCount ); - DrawBrushEntityName (b); + { + for ( std::size_t i = 0; i != m_faces.size(); ++i ) + { + for ( std::size_t j = 0; j < m_faces[i]->getWinding().numpoints; ++j ) + { + faceVertices.push_back( FaceVertexId( i, j ) ); + } + } + } -} + IndexBuffer uniqueEdgeIndices; + typedef VertexBuffer UniqueEdges; + UniqueEdges uniqueEdges; -/* -============ -Brush_Move -============ -*/ -void Brush_Move (brush_t *b, const vec3_t move, bool bSnap) -{ - int i; - face_t *f; - - for (f=b->brush_faces ; f ; f=f->next) - for (i=0 ; i<3 ; i++) - VectorAdd (f->planepts[i], move, f->planepts[i]); - - if (g_PrefsDlg.m_bTextureLock && !b->owner->eclass->fixedsize) - { - for (f=b->brush_faces ; f ; f=f->next) - { - vec3_t vTemp; - VectorCopy(move, vTemp); - Face_MoveTexture(f, vTemp); - } - } - - Brush_Build( b, bSnap,true,false,false); // don't filter - - - if (b->patchBrush) - { - //Patch_Move(b->nPatchID, move); - Patch_Move(b->pPatch, move); - } - - - // PGM - keep the origin vector up to date on fixed size entities. - if(b->owner->eclass->fixedsize) - { - char text[64]; - VectorAdd(b->owner->origin, move, b->owner->origin); - sprintf (text, "%i %i %i", - (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]); - SetKeyValue(b->owner, "origin", text); - //VectorAdd(b->maxs, b->mins, b->owner->origin); - //VectorScale(b->owner->origin, 0.5, b->owner->origin); - } -} + uniqueEdgeIndices.reserve( faceVertices.size() ); + uniqueEdges.reserve( faceVertices.size() ); + { + ProximalVertexArray edgePairs; + edgePairs.resize( faceVertices.size() ); + { + for ( std::size_t i = 0; i < faceVertices.size(); ++i ) + { + edgePairs[i].m_next = edgePairs.data() + absoluteIndex( next_edge( m_faces, faceVertices[i] ) ); + } + } -void Brush_Print(brush_t* b) -{ - int nFace = 0; - for (face_t* f = b->brush_faces ; f ; f=f->next) - { - Sys_Printf("Face %i\n", nFace++); - Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]); - Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]); - Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]); - } - } + { + UniqueVertexBuffer inserter( uniqueEdges ); + for ( ProximalVertexArray::iterator i = edgePairs.begin(); i != edgePairs.end(); ++i ) + { + uniqueEdgeIndices.insert( inserter.insert( ProximalVertex( &( *i ) ) ) ); + } + } + { + edge_clear(); + m_select_edges.reserve( uniqueEdges.size() ); + for ( UniqueEdges::iterator i = uniqueEdges.begin(); i != uniqueEdges.end(); ++i ) + { + edge_push_back( faceVertices[ProximalVertexArray_index( edgePairs, *i )] ); + } + } + { + m_edge_faces.resize( uniqueEdges.size() ); + for ( std::size_t i = 0; i < uniqueEdges.size(); ++i ) + { + FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( edgePairs, uniqueEdges[i] )]; + m_edge_faces[i] = EdgeFaces( faceVertex.getFace(), m_faces[faceVertex.getFace()]->getWinding()[faceVertex.getVertex()].adjacent ); + } + } -/* -============= -Brush_MakeSided + { + m_uniqueEdgePoints.resize( uniqueEdges.size() ); + for ( std::size_t i = 0; i < uniqueEdges.size(); ++i ) + { + FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( edgePairs, uniqueEdges[i] )]; -Makes the current brushhave the given number of 2d sides and turns it into a cone -============= -*/ -void Brush_MakeSidedCone(int sides) -{ - int i; - vec3_t mins, maxs; - brush_t *b; - texdef_t *texdef; - face_t *f; - vec3_t mid; - float width; - float sv, cv; - - if (sides < 3 || sides > 32) - { - Sys_Status ("Bad sides number", 0); - return; - } + const Winding& w = m_faces[faceVertex.getFace()]->getWinding(); + Vector3 edge = vector3_mid( w[faceVertex.getVertex()].vertex, w[Winding_next( w, faceVertex.getVertex() )].vertex ); + m_uniqueEdgePoints[i] = pointvertex_for_windingpoint( edge, colour_vertex ); + } + } - if (!QE_SingleBrush ()) - { - Sys_Status ("Must have a single brush selected", 0 ); - return; - } + } - b = selected_brushes.next; - VectorCopy (b->mins, mins); - VectorCopy (b->maxs, maxs); - texdef = &g_qeglobals.d_texturewin.texdef; - Brush_Free (b); + IndexBuffer uniqueVertexIndices; + typedef VertexBuffer UniqueVertices; + UniqueVertices uniqueVertices; - // find center of brush - width = 8; - for (i=0 ; i<2 ; i++) - { - mid[i] = (maxs[i] + mins[i])*0.5; - if (maxs[i] - mins[i] > width) - width = maxs[i] - mins[i]; - } - width /= 2; + uniqueVertexIndices.reserve( faceVertices.size() ); + uniqueVertices.reserve( faceVertices.size() ); - b = Brush_Alloc(); + { + ProximalVertexArray vertexRings; + vertexRings.resize( faceVertices.size() ); - // create bottom face - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; + { + for ( std::size_t i = 0; i < faceVertices.size(); ++i ) + { + vertexRings[i].m_next = vertexRings.data() + absoluteIndex( next_vertex( m_faces, faceVertices[i] ) ); + } + } - f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; - f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; - f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; + { + UniqueVertexBuffer inserter( uniqueVertices ); + for ( ProximalVertexArray::iterator i = vertexRings.begin(); i != vertexRings.end(); ++i ) + { + uniqueVertexIndices.insert( inserter.insert( ProximalVertex( &( *i ) ) ) ); + } + } - for (i=0 ; itexdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; + { + vertex_clear(); + m_select_vertices.reserve( uniqueVertices.size() ); + for ( UniqueVertices::iterator i = uniqueVertices.begin(); i != uniqueVertices.end(); ++i ) + { + vertex_push_back( faceVertices[ProximalVertexArray_index( vertexRings, ( *i ) )] ); + } + } - sv = sin (i*3.14159265*2/sides); - cv = cos (i*3.14159265*2/sides); + { + m_uniqueVertexPoints.resize( uniqueVertices.size() ); + for ( std::size_t i = 0; i < uniqueVertices.size(); ++i ) + { + FaceVertexId faceVertex = faceVertices[ProximalVertexArray_index( vertexRings, uniqueVertices[i] )]; + const Winding& winding = m_faces[faceVertex.getFace()]->getWinding(); + m_uniqueVertexPoints[i] = pointvertex_for_windingpoint( winding[faceVertex.getVertex()].vertex, colour_vertex ); + } + } + } - f->planepts[0][0] = floor(mid[0]+width*cv+0.5); - f->planepts[0][1] = floor(mid[1]+width*sv+0.5); - f->planepts[0][2] = mins[2]; + if ( ( uniqueVertices.size() + faces_size ) - uniqueEdges.size() != 2 ) { + globalErrorStream() << "Final B-Rep: inconsistent vertex count\n"; + } - f->planepts[1][0] = mid[0]; - f->planepts[1][1] = mid[1]; - f->planepts[1][2] = maxs[2]; +#if BRUSH_CONNECTIVITY_DEBUG + if ( ( uniqueVertices.size() + faces_size ) - uniqueEdges.size() != 2 ) { + for ( Faces::iterator i = m_faces.begin(); i != m_faces.end(); ++i ) + { + std::size_t faceIndex = std::distance( m_faces.begin(), i ); - f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5); - f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5); - f->planepts[2][2] = maxs[2]; + if ( !( *i )->contributes() ) { + globalOutputStream() << "face: " << Unsigned( faceIndex ) << " does not contribute\n"; + } - } + Winding_printConnectivity( ( *i )->getWinding() ); + } + } +#endif - Brush_AddToList (b, &selected_brushes); + // edge-index list for wireframe rendering + { + m_edge_indices.resize( uniqueEdgeIndices.size() ); - Entity_LinkBrush (world_entity, b); + for ( std::size_t i = 0, count = 0; i < m_faces.size(); ++i ) + { + const Winding& winding = m_faces[i]->getWinding(); + for ( std::size_t j = 0; j < winding.numpoints; ++j ) + { + const RenderIndex edge_index = uniqueEdgeIndices[count + j]; - Brush_Build( b ); + m_edge_indices[edge_index].first = uniqueVertexIndices[count + j]; + m_edge_indices[edge_index].second = uniqueVertexIndices[count + Winding_next( winding, j )]; + } + count += winding.numpoints; + } + } + } - Sys_UpdateWindows (W_ALL); + { + m_faceCentroidPoints.resize( m_faces.size() ); + for ( std::size_t i = 0; i < m_faces.size(); ++i ) + { + m_faces[i]->construct_centroid(); + m_faceCentroidPoints[i] = pointvertex_for_windingpoint( m_faces[i]->centroid(), colour_vertex ); + } + } + } } -/* -============= -Brush_MakeSided - -Makes the current brushhave the given number of 2d sides and turns it into a sphere -============= -*/ -void Brush_MakeSidedSphere(int sides) +class FaceFilterWrapper : public Filter { - int i,j; - vec3_t mins, maxs; - brush_t *b; - texdef_t *texdef; - face_t *f; - vec3_t mid; - - if (sides < 4 || sides > 32) - { - Sys_Status ("Bad sides number", 0); - return; - } +FaceFilter& m_filter; +bool m_active; +bool m_invert; +public: +FaceFilterWrapper( FaceFilter& filter, bool invert ) : + m_filter( filter ), + m_invert( invert ){ +} +void setActive( bool active ){ + m_active = active; +} +bool active(){ + return m_active; +} +bool filter( const Face& face ){ + return m_invert ^ m_filter.filter( face ); +} +}; - if (!QE_SingleBrush ()) - { - Sys_Status ("Must have a single brush selected", 0 ); - return; - } - b = selected_brushes.next; - VectorCopy (b->mins, mins); - VectorCopy (b->maxs, maxs); - texdef = &g_qeglobals.d_texturewin.texdef; +typedef std::list FaceFilters; +FaceFilters g_faceFilters; - Brush_Free (b); +void add_face_filter( FaceFilter& filter, int mask, bool invert ){ + g_faceFilters.push_back( FaceFilterWrapper( filter, invert ) ); + GlobalFilterSystem().addFilter( g_faceFilters.back(), mask ); +} - // find center of brush - float radius = 8; - for (i=0 ; i<2 ; i++) +bool face_filtered( Face& face ){ + for ( FaceFilters::iterator i = g_faceFilters.begin(); i != g_faceFilters.end(); ++i ) { - mid[i] = (maxs[i] + mins[i])*0.5; - if (maxs[i] - mins[i] > radius) - radius = maxs[i] - mins[i]; - } - radius /= 2; - - b = Brush_Alloc(); - - float dt = float(2 * Q_PI / sides); - float dp = float(Q_PI / sides); - float t,p; - for(i=0; i <= sides-1; i++) - { - for(j=0;j <= sides-2; j++) - { - t = i * dt; - p = float(j * dp - Q_PI / 2); - - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorPolar(f->planepts[0], radius, t, p); - VectorPolar(f->planepts[1], radius, t, p + dp); - VectorPolar(f->planepts[2], radius, t + dt, p + dp); - - for (int k = 0; k < 3; k++) - VectorAdd(f->planepts[k], mid, f->planepts[k]); + if ( ( *i ).active() && ( *i ).filter( face ) ) { + return true; } - } - - p = float((sides - 1) * dp - Q_PI / 2); - for(i = 0; i <= sides-1; i++) - { - t = i * dt; - - f = Face_Alloc(); - f->texdef = *texdef; - f->next = b->brush_faces; - b->brush_faces = f; - - VectorPolar(f->planepts[0], radius, t, p); - VectorPolar(f->planepts[1], radius, t + dt, p + dp); - VectorPolar(f->planepts[2], radius, t + dt, p); - - for (int k = 0; k < 3; k++) - VectorAdd(f->planepts[k], mid, f->planepts[k]); } - - Brush_AddToList (b, &selected_brushes); - - Entity_LinkBrush (world_entity, b); - - Brush_Build( b ); - - Sys_UpdateWindows (W_ALL); + return false; } -void Face_FitTexture( face_t * face, int nHeight, int nWidth ) -{ - winding_t *w; - vec3_t mins,maxs; - int i; - float width, height, temp; - float rot_width, rot_height; - float cosv,sinv,ang; - float min_t, min_s, max_t, max_s; - float s,t; - vec3_t vecs[2]; - vec3_t coords[4]; - texdef_t *td; - - if (nHeight < 1) - nHeight = 1; - if (nWidth < 1) - nWidth = 1; - - ClearBounds (mins, maxs); - - w = face->face_winding; - if (!w) - { - return; - } - for (i=0 ; inumpoints ; i++) - { - AddPointToBounds( w->points[i], mins, maxs ); - } - - if (g_qeglobals.m_bBrushPrimitMode) - Face_FitTexture_BrushPrimit( face, mins, maxs, nHeight, nWidth ); - else - { - - td = &face->texdef; - // - // get the current angle - // - ang = td->rotate / 180 * Q_PI; - sinv = sin(ang); - cosv = cos(ang); - - // get natural texture axis - TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); - - min_s = DotProduct( mins, vecs[0] ); - min_t = DotProduct( mins, vecs[1] ); - max_s = DotProduct( maxs, vecs[0] ); - max_t = DotProduct( maxs, vecs[1] ); - width = max_s - min_s; - height = max_t - min_t; - coords[0][0] = min_s; - coords[0][1] = min_t; - coords[1][0] = max_s; - coords[1][1] = min_t; - coords[2][0] = min_s; - coords[2][1] = max_t; - coords[3][0] = max_s; - coords[3][1] = max_t; - min_s = min_t = 99999; - max_s = max_t = -99999; - for (i=0; i<4; i++) - { - s = cosv * coords[i][0] - sinv * coords[i][1]; - t = sinv * coords[i][0] + cosv * coords[i][1]; - if (i&1) - { - if (s > max_s) - { - max_s = s; - } - } - else - { - if (s < min_s) - { - min_s = s; - } - if (i<2) - { - if (t < min_t) - { - min_t = t; - } - } - else - { - if (t > max_t) - { - max_t = t; - } - } - } - } - rot_width = (max_s - min_s); - rot_height = (max_t - min_t); - td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth))); - td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight))); - - td->shift[0] = min_s/td->scale[0]; - temp = (int)(td->shift[0] / (face->d_texture->width*nWidth)); - temp = (temp+1)*face->d_texture->width*nWidth; - td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth); - - td->shift[1] = min_t/td->scale[1]; - temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); - temp = (temp+1)*(face->d_texture->height*nHeight); - td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); - - td->shift[1] = min_t/td->scale[1]; - temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); - temp = (temp+1)*(face->d_texture->height*nHeight); - td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); - - } -} -void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ) +class BrushFilterWrapper : public Filter { - face_t *face; - - for (face = b->brush_faces ; face ; face=face->next) - { - Face_FitTexture( face, nHeight, nWidth ); - } +bool m_active; +bool m_invert; +BrushFilter& m_filter; +public: +BrushFilterWrapper( BrushFilter& filter, bool invert ) : m_invert( invert ), m_filter( filter ){ } +void setActive( bool active ){ + m_active = active; +} +bool active(){ + return m_active; +} +bool filter( const Brush& brush ){ + return m_invert ^ m_filter.filter( brush ); +} +}; -void aabb_draw(const aabb_t *aabb, int mode) -{ - vec3_t normals[6] = { { 1, 0, 0}, { 0, 1, 0 }, { 0, 0, 1 }, {-1, 0, 0}, { 0,-1, 0 }, { 0, 0,-1 } }; - vec3_t points[8]; - vec3_t vMin, vMax; - VectorSubtract(aabb->origin, aabb->extents, vMin); - VectorAdd(aabb->origin, aabb->extents, vMax); - VectorSet(points[0], vMin[0], vMax[1], vMax[2]); - VectorSet(points[1], vMax[0], vMax[1], vMax[2]); - VectorSet(points[2], vMax[0], vMin[1], vMax[2]); - VectorSet(points[3], vMin[0], vMin[1], vMax[2]); - VectorSet(points[4], vMin[0], vMax[1], vMin[2]); - VectorSet(points[5], vMax[0], vMax[1], vMin[2]); - VectorSet(points[6], vMax[0], vMin[1], vMin[2]); - VectorSet(points[7], vMin[0], vMin[1], vMin[2]); - - qglBegin(GL_QUADS); - - qglNormal3fv(normals[0]); - qglVertex3fv(points[2]); - qglVertex3fv(points[1]); - qglVertex3fv(points[5]); - qglVertex3fv(points[6]); - - qglNormal3fv(normals[1]); - qglVertex3fv(points[1]); - qglVertex3fv(points[0]); - qglVertex3fv(points[4]); - qglVertex3fv(points[5]); - - qglNormal3fv(normals[2]); - qglVertex3fv(points[0]); - qglVertex3fv(points[1]); - qglVertex3fv(points[2]); - qglVertex3fv(points[3]); - - qglNormal3fv(normals[3]); - qglVertex3fv(points[3]); - qglVertex3fv(points[7]); - qglVertex3fv(points[4]); - qglVertex3fv(points[0]); - - qglNormal3fv(normals[4]); - qglVertex3fv(points[3]); - qglVertex3fv(points[2]); - qglVertex3fv(points[6]); - qglVertex3fv(points[7]); - - qglNormal3fv(normals[5]); - qglVertex3fv(points[7]); - qglVertex3fv(points[6]); - qglVertex3fv(points[5]); - qglVertex3fv(points[4]); - - qglEnd(); - -/* +typedef std::list BrushFilters; +BrushFilters g_brushFilters; - vec3_t Coords[8]; - - vec3_t vMin, vMax; - VectorSubtract(aabb->origin, aabb->extents, vMin); - VectorAdd(aabb->origin, aabb->extents, vMax); - VectorSet(Coords[0], vMin[0], vMax[1], vMax[2]); - VectorSet(Coords[1], vMax[0], vMax[1], vMax[2]); - VectorSet(Coords[2], vMax[0], vMin[1], vMax[2]); - VectorSet(Coords[3], vMin[0], vMin[1], vMax[2]); - VectorSet(Coords[4], vMin[0], vMax[1], vMin[2]); - VectorSet(Coords[5], vMax[0], vMax[1], vMin[2]); - VectorSet(Coords[6], vMax[0], vMin[1], vMin[2]); - VectorSet(Coords[7], vMin[0], vMin[1], vMin[2]); - - vec3_t Normals[8] = { {-1, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 0 }, - { 0, 0, 1 }, - { 0, 0,-1 }, - { 0, 1, 0 }, - { 1, 0, 0 }, - { 0,-1, 0 } }; - - unsigned short Indices[24] = { 2, 1, 5, 6, - 1, 0, 4, 5, - 0, 1, 2, 3, - 3, 7, 4, 0, - 3, 2, 6, 7, - 7, 6, 5, 4 }; - - qglVertexPointer(3, GL_FLOAT, 0, Coords); // filling the arrays - qglNormalPointer(GL_FLOAT, 0, Normals); - - //glLockArraysEXT(0, count); // extension GL_EXT_compiled_vertex_array - - qglDrawElements(GL_QUADS, 24, GL_UNSIGNED_SHORT, Indices); - - //glUnlockArraysEXT; // extension GL_EXT_compiled_vertex_array -*/ +void add_brush_filter( BrushFilter& filter, int mask, bool invert ){ + g_brushFilters.push_back( BrushFilterWrapper( filter, invert ) ); + GlobalFilterSystem().addFilter( g_brushFilters.back(), mask ); } -qboolean IsBrushSelected(brush_t* bSel) -{ - for (brush_t* b = selected_brushes.next ;b != NULL && b != &selected_brushes; b = b->next) - { - if (b == bSel) - return true; - } - return false; +bool brush_filtered( Brush& brush ){ + for ( BrushFilters::iterator i = g_brushFilters.begin(); i != g_brushFilters.end(); ++i ) + { + if ( ( *i ).active() && ( *i ).filter( brush ) ) { + return true; + } + } + return false; } - -