-// 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 ; i<w->numpoints ; 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<int>(f);
- f = static_cast<int>(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 ; i<sides ; i++)
- {
- f = Face_Alloc();
- f->texdef = *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 ; i<g_qeglobals.d_num_move_points ; i++)
- if (g_qeglobals.d_move_points[i] == f)
- return 0;
- g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
- return 1;
-}
-
-/*
-==============
-Brush_SelectFaceForDragging
-
-Adds the faces planepts to move_points, and
-rotates and adds the planepts of adjacent face if shear is set
-==============
-*/
-void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
-{
- int i;
- face_t *f2;
- winding_t *w;
- float d;
- brush_t *b2;
- int c;
-
- if (b->owner->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 ; i<w->numpoints ; 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);
- }