Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

Brush.cpp

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 
00024 #include "stdafx.h"
00025 #include <assert.h>
00026 #include "qe3.h"
00027 #include "winding.h"
00028 
00029 
00030 // globals
00031 
00032 int g_nBrushId = 0;
00033 
00034 const char* Brush_Name(brush_t *b)
00035 {
00036   static char cBuff[1024];
00037     b->numberId = g_nBrushId++;
00038     if (g_qeglobals.m_bBrushPrimitMode)
00039   {
00040     sprintf(cBuff, "Brush %i", b->numberId);
00041     Brush_SetEpair(b, "Name", cBuff);
00042   }
00043   return cBuff;
00044 }
00045 
00046 brush_t *Brush_Alloc()
00047 {
00048   brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));
00049   return b;
00050 }
00051 
00052 
00053 
00054 
00055 void PrintWinding (winding_t *w)
00056 {
00057     int     i;
00058     
00059     printf ("-------------\n");
00060     for (i=0 ; i<w->numpoints ; i++)
00061         printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
00062         , w->points[i][1], w->points[i][2]);
00063 }
00064 
00065 void PrintPlane (plane_t *p)
00066 {
00067   printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n",  p->normal[0],  p->normal[1], 
00068   p->normal[2],  p->dist);
00069 }
00070 
00071 void PrintVector (vec3_t v)
00072 {
00073   printf ("(%5.2f, %5.2f, %5.2f)\n",  v[0],  v[1], v[2]);
00074 }
00075 
00076 
00077 /*
00078 =============================================================================
00079 
00080             TEXTURE COORDINATES
00081 
00082 =============================================================================
00083 */
00084 
00085 
00086 /*
00087 ==================
00088 textureAxisFromPlane
00089 ==================
00090 */
00091 vec3_t  baseaxis[18] =
00092 {
00093 {0,0,1}, {1,0,0}, {0,-1,0},         // floor
00094 {0,0,-1}, {1,0,0}, {0,-1,0},        // ceiling
00095 {1,0,0}, {0,1,0}, {0,0,-1},         // west wall
00096 {-1,0,0}, {0,1,0}, {0,0,-1},        // east wall
00097 {0,1,0}, {1,0,0}, {0,0,-1},         // south wall
00098 {0,-1,0}, {1,0,0}, {0,0,-1}         // north wall
00099 };
00100 
00101 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
00102 {
00103     int     bestaxis;
00104     float   dot,best;
00105     int     i;
00106     
00107     best = 0;
00108     bestaxis = 0;
00109     
00110     for (i=0 ; i<6 ; i++)
00111     {
00112         dot = DotProduct (pln->normal, baseaxis[i*3]);
00113         if (dot > best)
00114         {
00115             best = dot;
00116             bestaxis = i;
00117         }
00118     }
00119     
00120     VectorCopy (baseaxis[bestaxis*3+1], xv);
00121     VectorCopy (baseaxis[bestaxis*3+2], yv);
00122 }
00123 
00124 
00125 
00126 float   lightaxis[3] = {0.6, 0.8, 1.0};
00127 /*
00128 ================
00129 SetShadeForPlane
00130 
00131 Light different planes differently to
00132 improve recognition
00133 ================
00134 */
00135 float SetShadeForPlane (plane_t *p)
00136 {
00137     int     i;
00138     float   f;
00139 
00140     // axial plane
00141     for (i=0 ; i<3 ; i++)
00142         if (fabs(p->normal[i]) > 0.9)
00143         {
00144             f = lightaxis[i];
00145             return f;
00146         }
00147 
00148     // between two axial planes
00149     for (i=0 ; i<3 ; i++)
00150         if (fabs(p->normal[i]) < 0.1)
00151         {
00152             f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
00153             return f;
00154         }
00155 
00156     // other
00157     f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
00158     return f;
00159 }
00160 
00161 vec3_t  vecs[2];
00162 float   shift[2];
00163 
00164 /*
00165 ================
00166 Face_Alloc
00167 ================
00168 */
00169 face_t *Face_Alloc( void )
00170 {
00171     face_t *f = (face_t*)qmalloc( sizeof( *f ) );
00172     
00173     if (g_qeglobals.bSurfacePropertiesPlugin)
00174         f->pData = static_cast<void *>( g_SurfaceTable.m_pfnTexdefAlloc( f ) );
00175 
00176     return f;
00177 }
00178 
00179 /*
00180 ================
00181 Face_Free
00182 ================
00183 */
00184 void Face_Free( face_t *f )
00185 {
00186     assert( f != 0 );
00187 
00188     if ( f->face_winding )
00189     {
00190         free( f->face_winding );
00191         f->face_winding = 0;
00192     }
00193 
00194     if (g_qeglobals.bSurfacePropertiesPlugin)
00195     {
00196 #ifdef _DEBUG
00197         if ( !f->pData )
00198         {
00199             Sys_Printf("WARNING: unexpected IPluginTexdef is NULL in Face_Free\n");
00200         }
00201         else
00202 #endif
00203         GETPLUGINTEXDEF(f)->DecRef();
00204     }
00205 
00206     f->texdef.~texdef_t();;
00207 
00208     free( f );
00209 }
00210 
00211 /*
00212 ================
00213 Face_Clone
00214 ================
00215 */
00216 face_t  *Face_Clone (face_t *f)
00217 {
00218     face_t  *n;
00219 
00220     n = Face_Alloc();
00221     n->texdef = f->texdef;
00222 
00223     memcpy (n->planepts, f->planepts, sizeof(n->planepts));
00224 
00225     // all other fields are derived, and will be set by Brush_Build
00226     return n;
00227 }
00228 
00229 /*
00230 ================
00231 Face_FullClone
00232 
00233 makes an exact copy of the face
00234 ================
00235 */
00236 face_t  *Face_FullClone (face_t *f)
00237 {
00238     face_t  *n;
00239 
00240     n = Face_Alloc();
00241     n->texdef = f->texdef;
00242     memcpy(n->planepts, f->planepts, sizeof(n->planepts));
00243     memcpy(&n->plane, &f->plane, sizeof(plane_t));
00244     if (f->face_winding)
00245         n->face_winding = Winding_Clone(f->face_winding);
00246     else
00247         n->face_winding = NULL;
00248     n->d_texture = Texture_ForName( n->texdef.name );
00249     return n;
00250 }
00251 
00252 /*
00253 ================
00254 Clamp
00255 ================
00256 */
00257 void Clamp(float& f, int nClamp)
00258 {
00259   float fFrac = f - static_cast<int>(f);
00260   f = static_cast<int>(f) % nClamp;
00261   f += fFrac;
00262 }
00263 
00264 /*
00265 ================
00266 Face_MoveTexture
00267 ================
00268 */
00269 void Face_MoveTexture(face_t *f, vec3_t delta)
00270 {
00271     vec3_t vX, vY;
00272 /*
00273 #ifdef _DEBUG
00274     if (g_PrefsDlg.m_bBrushPrimitMode)
00275         Sys_Printf("Warning : Face_MoveTexture not done in brush primitive mode\n");
00276 #endif
00277 */
00278     if (g_qeglobals.m_bBrushPrimitMode)
00279         Face_MoveTexture_BrushPrimit( f, delta );
00280     else
00281     {
00282         TextureAxisFromPlane(&f->plane, vX, vY);
00283 
00284         vec3_t vDP, vShift;
00285         vDP[0] = DotProduct(delta, vX);
00286         vDP[1] = DotProduct(delta, vY);
00287 
00288         double fAngle = f->texdef.rotate  / 180 * Q_PI;
00289         double c = cos(fAngle);
00290         double s = sin(fAngle);
00291 
00292         vShift[0] = vDP[0] * c - vDP[1] * s;
00293         vShift[1] = vDP[0] * s + vDP[1] * c;
00294 
00295         if (!f->texdef.scale[0])
00296             f->texdef.scale[0] = 1;
00297         if (!f->texdef.scale[1])
00298             f->texdef.scale[1] = 1;
00299 
00300         f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
00301         f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
00302   
00303         // clamp the shifts
00304         Clamp(f->texdef.shift[0], f->d_texture->width);
00305         Clamp(f->texdef.shift[1], f->d_texture->height);
00306     }
00307 }
00308 
00309 /*
00310 ================
00311 Face_SetColor
00312 ================
00313 */
00314 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) 
00315 {
00316     float   shade;
00317     qtexture_t *q;
00318 
00319     q = f->d_texture;
00320 
00321     // set shading for face
00322     shade = SetShadeForPlane (&f->plane);
00323     if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture && !b->owner->eclass->fixedsize)
00324     {
00325         //if (b->curveBrush)
00326         //  shade = fCurveColor;
00327         f->d_color[0] = 
00328         f->d_color[1] = 
00329         f->d_color[2] = shade;
00330     }
00331     else
00332     {
00333         f->d_color[0] = shade*q->color[0];
00334         f->d_color[1] = shade*q->color[1];
00335         f->d_color[2] = shade*q->color[2];
00336     }
00337 }
00338 
00339 /*
00340 ================
00341 Face_TextureVectors
00342 TTimo: NOTE: this is never to get called while in brush primitives mode
00343 ================
00344 */
00345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])
00346 {
00347     vec3_t      pvecs[2];
00348     int         sv, tv;
00349     float       ang, sinv, cosv;
00350     float       ns, nt;
00351     int         i,j;
00352     qtexture_t *q;
00353     texdef_t    *td;
00354 
00355 #ifdef _DEBUG
00356     //++timo when playing with patches, this sometimes get called and the Warning is displayed
00357     // find some way out ..
00358     if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)
00359         Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
00360 #endif
00361 
00362     td = &f->texdef;
00363     q = f->d_texture;
00364 
00365     memset (STfromXYZ, 0, 8*sizeof(float));
00366 
00367     if (!td->scale[0])
00368         td->scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1;
00369     if (!td->scale[1])
00370         td->scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1;
00371 
00372     // get natural texture axis
00373     TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
00374 
00375     // rotate axis
00376     if (td->rotate == 0)
00377         { sinv = 0 ; cosv = 1; }
00378     else if (td->rotate == 90)
00379         { sinv = 1 ; cosv = 0; }
00380     else if (td->rotate == 180)
00381         { sinv = 0 ; cosv = -1; }
00382     else if (td->rotate == 270)
00383         { sinv = -1 ; cosv = 0; }
00384     else
00385     {   
00386         ang = td->rotate / 180 * Q_PI;
00387         sinv = sin(ang);
00388         cosv = cos(ang);
00389     }
00390 
00391     if (pvecs[0][0])
00392         sv = 0;
00393     else if (pvecs[0][1])
00394         sv = 1;
00395     else
00396         sv = 2;
00397                 
00398     if (pvecs[1][0])
00399         tv = 0;
00400     else if (pvecs[1][1])
00401         tv = 1;
00402     else
00403         tv = 2;
00404                     
00405     for (i=0 ; i<2 ; i++) {
00406         ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
00407         nt = sinv * pvecs[i][sv] +  cosv * pvecs[i][tv];
00408         STfromXYZ[i][sv] = ns;
00409         STfromXYZ[i][tv] = nt;
00410     }
00411 
00412     // scale
00413     for (i=0 ; i<2 ; i++)
00414         for (j=0 ; j<3 ; j++)
00415             STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
00416 
00417     // shift
00418     STfromXYZ[0][3] = td->shift[0];
00419     STfromXYZ[1][3] = td->shift[1];
00420 
00421     for (j=0 ; j<4 ; j++) {
00422         STfromXYZ[0][j] /= q->width;
00423         STfromXYZ[1][j] /= q->height;
00424     }
00425 }
00426 
00427 /*
00428 ================
00429 Face_MakePlane
00430 ================
00431 */
00432 void Face_MakePlane (face_t *f)
00433 {
00434     int     j;
00435     vec3_t  t1, t2, t3;
00436 
00437     // convert to a vector / dist plane
00438     for (j=0 ; j<3 ; j++)
00439     {
00440         t1[j] = f->planepts[0][j] - f->planepts[1][j];
00441         t2[j] = f->planepts[2][j] - f->planepts[1][j];
00442         t3[j] = f->planepts[1][j];
00443     }
00444     
00445     CrossProduct(t1,t2, f->plane.normal);
00446     if (VectorCompare (f->plane.normal, vec3_origin))
00447         printf ("WARNING: brush plane with no normal\n");
00448     VectorNormalize (f->plane.normal);
00449     f->plane.dist = DotProduct (t3, f->plane.normal);
00450 }
00451 
00452 /*
00453 ================
00454 EmitTextureCoordinates
00455 ================
00456 */
00457 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
00458 {
00459     float   STfromXYZ[2][4];
00460 
00461     Face_TextureVectors (f,  STfromXYZ);
00462     xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
00463     xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
00464 }
00465 
00466 //==========================================================================
00467 
00468 /*
00469 ================
00470 Brush_MakeFacePlanes
00471 ================
00472 */
00473 void Brush_MakeFacePlanes (brush_t *b)
00474 {
00475     face_t  *f;
00476 
00477     for (f=b->brush_faces ; f ; f=f->next)
00478     {
00479         Face_MakePlane (f);
00480     }
00481 }
00482 
00483 /*
00484 ================
00485 DrawBrushEntityName
00486 ================
00487 */
00488 void DrawBrushEntityName (brush_t *b)
00489 {
00490     char    *name;
00491     //float a, s, c;
00492     //vec3_t    mid;
00493     //int       i;
00494 
00495     if (!b->owner)
00496         return;     // during contruction
00497 
00498     if (b->owner == world_entity)
00499         return;
00500 
00501     if (b != b->owner->brushes.onext)
00502         return; // not key brush
00503 
00504 // MERGEME
00505 #if 0
00506     if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES))
00507     {
00508         // draw the angle pointer
00509         a = FloatForKey (b->owner, "angle");
00510         if (a)
00511         {
00512             s = sin (a/180*Q_PI);
00513             c = cos (a/180*Q_PI);
00514             for (i=0 ; i<3 ; i++)
00515                 mid[i] = (b->mins[i] + b->maxs[i])*0.5; 
00516 
00517             qglBegin (GL_LINE_STRIP);
00518             qglVertex3fv (mid);
00519             mid[0] += c*8;
00520             mid[1] += s*8;
00521             mid[2] += s*8;
00522             qglVertex3fv (mid);
00523             mid[0] -= c*4;
00524             mid[1] -= s*4;
00525             mid[2] -= s*4;
00526             mid[0] -= s*4;
00527             mid[1] += c*4;
00528             mid[2] += c*4;
00529             qglVertex3fv (mid);
00530             mid[0] += c*4;
00531             mid[1] += s*4;
00532             mid[2] += s*4;
00533             mid[0] += s*4;
00534             mid[1] -= c*4;
00535             mid[2] -= c*4;
00536             qglVertex3fv (mid);
00537             mid[0] -= c*4;
00538             mid[1] -= s*4;
00539             mid[2] -= s*4;
00540             mid[0] += s*4;
00541             mid[1] -= c*4;
00542             mid[2] -= c*4;
00543             qglVertex3fv (mid);
00544             qglEnd ();
00545         }
00546     }
00547 #endif
00548 
00549     if (g_qeglobals.d_savedinfo.show_names)
00550     {
00551         name = ValueForKey (b->owner, "classname");
00552         qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
00553         qglCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
00554     }
00555 }
00556 
00557 /*
00558 =================
00559 Brush_MakeFaceWinding
00560 
00561 returns the visible polygon on a face
00562 =================
00563 */
00564 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)
00565 {
00566     winding_t   *w;
00567     face_t      *clip;
00568     plane_t         plane;
00569     qboolean        past;
00570 
00571     // get a poly that covers an effectively infinite area
00572     w = Winding_BaseForPlane (&face->plane);
00573 
00574     // chop the poly by all of the other faces
00575     past = false;
00576     for (clip = b->brush_faces ; clip && w ; clip=clip->next)
00577     {
00578         if (clip == face)
00579         {
00580             past = true;
00581             continue;
00582         }
00583         if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
00584             && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
00585         {   // identical plane, use the later one
00586             if (past)
00587             {
00588                 free (w);
00589                 return NULL;
00590             }
00591             continue;
00592         }
00593 
00594         // flip the plane, because we want to keep the back side
00595         VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
00596         plane.dist = -clip->plane.dist;
00597         
00598         w = Winding_Clip (w, &plane, false);
00599         if (!w)
00600             return w;
00601     }
00602     
00603     if (w->numpoints < 3)
00604     {
00605         free(w);
00606         w = NULL;
00607     }
00608 
00609     if (!w)
00610         printf ("unused plane\n");
00611 
00612     return w;
00613 }
00614 
00615 /*
00616 =================
00617 Brush_SnapPlanepts
00618 =================
00619 */
00620 void Brush_SnapPlanepts (brush_t *b)
00621 {
00622     int     i, j;
00623     face_t  *f;
00624 
00625   if (g_PrefsDlg.m_bNoClamp)
00626     return;
00627 
00628     for (f=b->brush_faces ; f; f=f->next)
00629         for (i=0 ; i<3 ; i++)
00630             for (j=0 ; j<3 ; j++)
00631                 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
00632 }
00633     
00634 /*
00635 ** Brush_Build
00636 **
00637 ** Builds a brush rendering data and also sets the min/max bounds
00638 */
00639 // TTimo
00640 // added a bConvert flag to convert between old and new brush texture formats
00641 // TTimo
00642 // brush grouping: update the group treeview if necessary
00643 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert )
00644 {
00645     bool        bLocalConvert;
00646 
00647 #ifdef _DEBUG
00648     if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
00649         Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
00650 #endif
00651 
00652     // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
00653     if (bConvert && !g_qeglobals.bNeedConvert)
00654     {
00655         bLocalConvert = true;
00656         g_qeglobals.bNeedConvert = true;
00657     }
00658 
00659     /*
00660     ** build the windings and generate the bounding box
00661     */
00662     Brush_BuildWindings(b, bSnap);
00663 
00664     Patch_BuildPoints (b);
00665 
00666     /*
00667     ** move the points and edges if in select mode
00668     */
00669     if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
00670         SetupVertexSelection ();
00671 
00672     if (b->itemOwner == NULL)
00673       Group_AddToProperGroup(b);
00674 
00675     if (bMarkMap)
00676     {
00677         Sys_MarkMapModified();
00678     }
00679 
00680     if (bLocalConvert)
00681         g_qeglobals.bNeedConvert = false;
00682 }
00683 
00684 /*
00685 ==============
00686 Brush_SplitBrushByFace
00687 
00688 The incoming brush is NOT freed.
00689 The incoming face is NOT left referenced.
00690 ==============
00691 */
00692 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back)
00693 {
00694     brush_t *b;
00695     face_t  *nf;
00696     vec3_t  temp;
00697 
00698     b = Brush_Clone (in);
00699     nf = Face_Clone (f);
00700 
00701     nf->texdef = b->brush_faces->texdef;
00702     nf->next = b->brush_faces;
00703     b->brush_faces = nf;
00704 
00705     Brush_Build( b );
00706     Brush_RemoveEmptyFaces ( b );
00707     if ( !b->brush_faces )
00708     {   // completely clipped away
00709         Brush_Free (b);
00710         *back = NULL;
00711     }
00712     else
00713     {
00714         Entity_LinkBrush (in->owner, b);
00715         *back = b;
00716     }
00717 
00718     b = Brush_Clone (in);
00719     nf = Face_Clone (f);
00720     // swap the plane winding
00721     VectorCopy (nf->planepts[0], temp);
00722     VectorCopy (nf->planepts[1], nf->planepts[0]);
00723     VectorCopy (temp, nf->planepts[1]);
00724 
00725     nf->texdef = b->brush_faces->texdef;
00726     nf->next = b->brush_faces;
00727     b->brush_faces = nf;
00728 
00729     Brush_Build( b );
00730     Brush_RemoveEmptyFaces ( b );
00731     if ( !b->brush_faces )
00732     {   // completely clipped away
00733         Brush_Free (b);
00734         *front = NULL;
00735     }
00736     else
00737     {
00738         Entity_LinkBrush (in->owner, b);
00739         *front = b;
00740     }
00741 }
00742 
00743 /*
00744 =================
00745 Brush_BestSplitFace
00746 
00747 returns the best face to split the brush with.
00748 return NULL if the brush is convex
00749 =================
00750 */
00751 face_t *Brush_BestSplitFace(brush_t *b)
00752 {
00753     face_t *face, *f, *bestface;
00754     winding_t *front, *back;
00755     int splits, tinywindings, value, bestvalue;
00756 
00757     bestvalue = 999999;
00758     bestface = NULL;
00759     for (face = b->brush_faces; face; face = face->next)
00760     {
00761         splits = 0;
00762         tinywindings = 0;
00763         for (f = b->brush_faces; f; f = f->next)
00764         {
00765             if (f == face) continue;
00766             //
00767             Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1, &front, &back);
00768 
00769             if (!front)
00770             {
00771                 Winding_Free(back);
00772             }
00773             else if (!back)
00774             {
00775                 Winding_Free(front);
00776             }
00777             else
00778             {
00779                 splits++;
00780                 if (Winding_IsTiny(front)) tinywindings++;
00781                 if (Winding_IsTiny(back)) tinywindings++;
00782             }
00783         }
00784         if (splits)
00785         {
00786             value = splits + 50 * tinywindings;
00787             if (value < bestvalue)
00788             {
00789                 bestvalue = value;
00790                 bestface = face;
00791             }
00792         }
00793     }
00794     return bestface;
00795 }
00796 
00797 /*
00798 =================
00799 Brush_MakeConvexBrushes
00800 
00801 MrE FIXME: this doesn't work because the old
00802            Brush_SplitBrushByFace is used
00803 Turns the brush into a minimal number of convex brushes.
00804 If the input brush is convex then it will be returned.
00805 Otherwise the input brush will be freed.
00806 NOTE: the input brush should have windings for the faces.
00807 =================
00808 */
00809 brush_t *Brush_MakeConvexBrushes(brush_t *b)
00810 {
00811     brush_t *front, *back, *end;
00812     face_t *face;
00813 
00814     b->next = NULL;
00815     face = Brush_BestSplitFace(b);
00816     if (!face) return b;
00817     Brush_SplitBrushByFace(b, face, &front, &back);
00818     //this should never happen
00819     if (!front && !back) return b;
00820     Brush_Free(b);
00821     if (!front)
00822         return Brush_MakeConvexBrushes(back);
00823     b = Brush_MakeConvexBrushes(front);
00824     if (back)
00825     {
00826         for (end = b; end->next; end = end->next);
00827         end->next = Brush_MakeConvexBrushes(back);
00828     }
00829     return b;
00830 }
00831 
00832 /*
00833 =================
00834 Brush_Convex
00835 =================
00836 */
00837 int Brush_Convex(brush_t *b)
00838 {
00839     face_t *face1, *face2;
00840 
00841     for (face1 = b->brush_faces; face1; face1 = face1->next)
00842     {
00843         if (!face1->face_winding) continue;
00844         for (face2 = b->brush_faces; face2; face2 = face2->next)
00845         {
00846             if (face1 == face2) continue;
00847             if (!face2->face_winding) continue;
00848             if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
00849                                         face1->plane.normal, face2->plane.normal,
00850                                         face1->plane.dist, face2->plane.dist))
00851             {
00852                 return false;
00853             }
00854         }
00855     }
00856     return true;
00857 }
00858 
00859 /*
00860 =================
00861 Brush_MoveVertexes_old1
00862 
00863 - The input brush must have face windings.
00864 - The input brush must be a brush with faces that do not intersect.
00865 - The input brush does not have to be convex.
00866 - The vertex will not be moved if the movement either causes the
00867   brush to have faces that intersect or causes the brush to be
00868   flipped inside out.
00869   (For instance a tetrahedron can easily be flipped inside out
00870   without having faces that intersect.)
00871 - The created brush does not have to be convex.
00872 - Returns true if the vertex movement is performed.
00873 =================
00874 */
00875 
00876 #define MAX_MOVE_FACES      64
00877 #define INTERSECT_EPSILON   0.1
00878 #define POINT_EPSILON       0.3
00879 
00880 int Brush_MoveVertex_old1(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
00881 {
00882     face_t *f, *face, *newface, *lastface, *nextface;
00883     face_t *movefaces[MAX_MOVE_FACES];
00884     int movefacepoints[MAX_MOVE_FACES];
00885     winding_t *w, tmpw;
00886     int i, j, k, nummovefaces, result;
00887     float dot;
00888 
00889     result = false;
00890     //
00891     tmpw.numpoints = 3;
00892     tmpw.maxpoints = 3;
00893     VectorAdd(vertex, delta, end);
00894     //snap or not?
00895     if (bSnap)
00896         for (i = 0; i < 3; i++)
00897             end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
00898     //chop off triangles from all brush faces that use the to be moved vertex
00899     //store pointers to these chopped off triangles in movefaces[]
00900     nummovefaces = 0;
00901     for (face = b->brush_faces; face; face = face->next)
00902     {
00903         w = face->face_winding;
00904         if (!w) continue;
00905         for (i = 0; i < w->numpoints; i++)
00906         {
00907             if (Point_Equal(w->points[i], vertex, POINT_EPSILON))
00908             {
00909                 if (face->face_winding->numpoints <= 3)
00910                 {
00911                     movefacepoints[nummovefaces] = i;
00912                     movefaces[nummovefaces++] = face;
00913                     break;
00914                 }
00915                 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
00916                 //if the end point is in front of the face plane
00917                 if (dot > 0.1)
00918                 {
00919                     //fanout triangle subdivision
00920                     for (k = i; k < i + w->numpoints-3; k++)
00921                     {
00922                         VectorCopy(w->points[i], tmpw.points[0]);
00923                         VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
00924                         VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
00925                         //
00926                         newface = Face_Clone(face);
00927                         //get the original
00928                         for (f = face; f->original; f = f->original) ;
00929                         newface->original = f;
00930                         //store the new winding
00931                         if (newface->face_winding) Winding_Free(newface->face_winding);
00932                         newface->face_winding = Winding_Clone(&tmpw);
00933                         //get the texture
00934                         newface->d_texture = Texture_ForName( newface->texdef.name );
00935                         //add the face to the brush
00936                         newface->next = b->brush_faces;
00937                         b->brush_faces = newface;
00938                         //add this new triangle to the move faces
00939                         movefacepoints[nummovefaces] = 0;
00940                         movefaces[nummovefaces++] = newface;
00941                     }
00942                     //give the original face a new winding
00943                     VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
00944                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
00945                     VectorCopy(w->points[i], tmpw.points[2]);
00946                     Winding_Free(face->face_winding);
00947                     face->face_winding = Winding_Clone(&tmpw);
00948                     //add the original face to the move faces
00949                     movefacepoints[nummovefaces] = 2;
00950                     movefaces[nummovefaces++] = face;
00951                 }
00952                 else
00953                 {
00954                     //chop a triangle off the face
00955                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
00956                     VectorCopy(w->points[i], tmpw.points[1]);
00957                     VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
00958                     //remove the point from the face winding
00959                     Winding_RemovePoint(w, i);
00960                     //get texture crap right
00961                     Face_SetColor(b, face, 1.0);
00962                     for (j = 0; j < w->numpoints; j++)
00963                         EmitTextureCoordinates(w->points[j], face->d_texture, face);
00964                     //make a triangle face
00965                     newface = Face_Clone(face);
00966                     //get the original
00967                     for (f = face; f->original; f = f->original) ;
00968                     newface->original = f;
00969                     //store the new winding
00970                     if (newface->face_winding) Winding_Free(newface->face_winding);
00971                     newface->face_winding = Winding_Clone(&tmpw);
00972                     //get the texture
00973                     newface->d_texture = Texture_ForName( newface->texdef.name );
00974                     //add the face to the brush
00975                     newface->next = b->brush_faces;
00976                     b->brush_faces = newface;
00977                     //
00978                     movefacepoints[nummovefaces] = 1;
00979                     movefaces[nummovefaces++] = newface;
00980                 }
00981                 break;
00982             }
00983         }
00984     }
00985     //now movefaces contains pointers to triangle faces that
00986     //contain the to be moved vertex
00987 
00988     //check if the move is valid
00989     int l;
00990     vec3_t p1, p2;
00991     winding_t *w2;
00992     plane_t plane;
00993 
00994     face = NULL;
00995     VectorCopy(vertex, tmpw.points[1]);
00996     VectorCopy(end, tmpw.points[2]);
00997     for (face = b->brush_faces; face; face = face->next)
00998     {
00999         for (i = 0; i < nummovefaces; i++)
01000         {
01001             if (face == movefaces[i])
01002                 break;
01003         }
01004         if (i < nummovefaces)
01005             continue;
01006         //the delta vector may not intersect with any of the not move faces
01007         if (Winding_VectorIntersect(face->face_winding, &face->plane, vertex, end, INTERSECT_EPSILON))
01008             break;
01009         //if the end point of the to be moved vertex is near this not move face
01010         if (abs(DotProduct(face->plane.normal, end) - face->plane.dist) < 0.5)
01011         {
01012             //the end point may not be inside or very close to the not move face winding
01013             if (Winding_PointInside(face->face_winding, &face->plane, end, 0.5))
01014                 break;
01015         }
01016         for (i = 0; i < nummovefaces; i++)
01017         {
01018             w = movefaces[i]->face_winding;
01019             j = movefacepoints[i];
01020             for (k = -1; k <= 1; k += 2)
01021             {
01022                 //check if the new edge will not intersect with the not move face
01023                 VectorCopy(w->points[(j + k + w->numpoints) % w->numpoints], tmpw.points[0]);
01024                 if (Winding_VectorIntersect(face->face_winding, &face->plane, tmpw.points[0], end, INTERSECT_EPSILON))
01025                 {
01026                     //ok the new edge instersects with the not move face
01027                     //we can't perform the vertex movement
01028                     //break;
01029                 }
01030                 //check if the not move face intersects the "movement winding"
01031                 Winding_Plane(&tmpw, plane.normal, &plane.dist);
01032                 w2 = face->face_winding;
01033                 for (l = 0; l < w2->numpoints; l++)
01034                 {
01035                     VectorCopy(w2->points[l], p1);
01036                     if (Point_Equal(p1, tmpw.points[0], POINT_EPSILON)) continue;
01037                     VectorCopy(w2->points[(l+1) % w2->numpoints], p2);
01038                     if (Point_Equal(p2, tmpw.points[0], POINT_EPSILON)) continue;
01039                     if (Winding_VectorIntersect(&tmpw, &plane, p1, p2, INTERSECT_EPSILON))
01040                         break;
01041                 }
01042                 if (l < w2->numpoints)
01043                 {
01044                     //ok this not move face intersects the "movement winding"
01045                     //we can't perform the vertex movement
01046                     break;
01047                 }
01048             }
01049             if (k <= 1) break;
01050         }
01051         if (i < nummovefaces)
01052             break;
01053     }
01054     if (!face)
01055     {
01056         //ok the move was valid
01057         //now move all the vertexes of the movefaces
01058         for (i = 0; i < nummovefaces; i++)
01059         {
01060             VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]);
01061             //create new face plane
01062             for (j = 0; j < 3; j++)
01063             {
01064                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01065             }
01066             Face_MakePlane(movefaces[i]);
01067         }
01068         result = true;
01069     }
01070     //get texture crap right
01071     for (i = 0; i < nummovefaces; i++)
01072     {
01073         Face_SetColor(b, movefaces[i], 1.0);
01074         for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
01075             EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
01076     }
01077 
01078     //now try to merge faces with their original faces
01079     lastface = NULL;
01080     for (face = b->brush_faces; face; face = nextface)
01081     {
01082         nextface = face->next;
01083         if (!face->original)
01084         {
01085             lastface = face;
01086             continue;
01087         }
01088         if (!Plane_Equal(&face->plane, &face->original->plane, false))
01089         {
01090             lastface = face;
01091             continue;
01092         }
01093         w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
01094         if (!w)
01095         {
01096             lastface = face;
01097             continue;
01098         }
01099         Winding_Free(face->original->face_winding);
01100         face->original->face_winding = w;
01101         //get texture crap right
01102         Face_SetColor(b, face->original, 1.0);
01103         for (j = 0; j < face->original->face_winding->numpoints; j++)
01104             EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
01105         //remove the face that was merged with the original
01106         if (lastface) lastface->next = face->next;
01107         else b->brush_faces = face->next;
01108         Face_Free(face);
01109     }
01110     return result;
01111 }
01112 
01113 /*
01114 =================
01115 Brush_MoveVertexes_old2
01116 
01117 - The input brush must be convex
01118 - The input brush must have face windings.
01119 - The output brush will be convex.
01120 - Returns true if the vertex movement is performed.
01121 =================
01122 */
01123 
01124 #define MAX_MOVE_FACES      64
01125 #define INTERSECT_EPSILON   0.1
01126 #define POINT_EPSILON       0.3
01127 
01128 int Brush_MoveVertex_old2(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
01129 {
01130     face_t *f, *face, *newface, *lastface, *nextface;
01131     face_t *movefaces[MAX_MOVE_FACES];
01132     int movefacepoints[MAX_MOVE_FACES];
01133     winding_t *w, tmpw;
01134     int i, j, k, nummovefaces, result;
01135     float dot;
01136 
01137     result = true;
01138     //
01139     tmpw.numpoints = 3;
01140     tmpw.maxpoints = 3;
01141     VectorAdd(vertex, delta, end);
01142     //snap or not?
01143     if (bSnap)
01144         for (i = 0; i < 3; i++)
01145             end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
01146     //chop off triangles from all brush faces that use the to be moved vertex
01147     //store pointers to these chopped off triangles in movefaces[]
01148     nummovefaces = 0;
01149     for (face = b->brush_faces; face; face = face->next)
01150     {
01151         w = face->face_winding;
01152         if (!w) continue;
01153         for (i = 0; i < w->numpoints; i++)
01154         {
01155             if (Point_Equal(w->points[i], vertex, POINT_EPSILON))
01156             {
01157                 if (face->face_winding->numpoints <= 3)
01158                 {
01159                     movefacepoints[nummovefaces] = i;
01160                     movefaces[nummovefaces++] = face;
01161                     break;
01162                 }
01163                 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
01164                 //if the end point is in front of the face plane
01165                 if (dot > 0.1)
01166                 {
01167                     //fanout triangle subdivision
01168                     for (k = i; k < i + w->numpoints-3; k++)
01169                     {
01170                         VectorCopy(w->points[i], tmpw.points[0]);
01171                         VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
01172                         VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
01173                         //
01174                         newface = Face_Clone(face);
01175                         //get the original
01176                         for (f = face; f->original; f = f->original) ;
01177                         newface->original = f;
01178                         //store the new winding
01179                         if (newface->face_winding) Winding_Free(newface->face_winding);
01180                         newface->face_winding = Winding_Clone(&tmpw);
01181                         //get the texture
01182                         newface->d_texture = Texture_ForName( newface->texdef.name );
01183                         //add the face to the brush
01184                         newface->next = b->brush_faces;
01185                         b->brush_faces = newface;
01186                         //add this new triangle to the move faces
01187                         movefacepoints[nummovefaces] = 0;
01188                         movefaces[nummovefaces++] = newface;
01189                     }
01190                     //give the original face a new winding
01191                     VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
01192                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
01193                     VectorCopy(w->points[i], tmpw.points[2]);
01194                     Winding_Free(face->face_winding);
01195                     face->face_winding = Winding_Clone(&tmpw);
01196                     //add the original face to the move faces
01197                     movefacepoints[nummovefaces] = 2;
01198                     movefaces[nummovefaces++] = face;
01199                 }
01200                 else
01201                 {
01202                     //chop a triangle off the face
01203                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
01204                     VectorCopy(w->points[i], tmpw.points[1]);
01205                     VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
01206                     //remove the point from the face winding
01207                     Winding_RemovePoint(w, i);
01208                     //get texture crap right
01209                     Face_SetColor(b, face, 1.0);
01210                     for (j = 0; j < w->numpoints; j++)
01211                         EmitTextureCoordinates(w->points[j], face->d_texture, face);
01212                     //make a triangle face
01213                     newface = Face_Clone(face);
01214                     //get the original
01215                     for (f = face; f->original; f = f->original) ;
01216                     newface->original = f;
01217                     //store the new winding
01218                     if (newface->face_winding) Winding_Free(newface->face_winding);
01219                     newface->face_winding = Winding_Clone(&tmpw);
01220                     //get the texture
01221                     newface->d_texture = Texture_ForName( newface->texdef.name );
01222                     //add the face to the brush
01223                     newface->next = b->brush_faces;
01224                     b->brush_faces = newface;
01225                     //
01226                     movefacepoints[nummovefaces] = 1;
01227                     movefaces[nummovefaces++] = newface;
01228                 }
01229                 break;
01230             }
01231         }
01232     }
01233     //now movefaces contains pointers to triangle faces that
01234     //contain the to be moved vertex
01235 
01236     //move the vertex
01237     for (i = 0; i < nummovefaces; i++)
01238     {
01239         //move vertex to end position
01240         VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]);
01241         //create new face plane
01242         for (j = 0; j < 3; j++)
01243         {
01244             VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01245         }
01246         Face_MakePlane(movefaces[i]);
01247     }
01248     //if the brush is no longer convex
01249     if (!Brush_Convex(b))
01250     {
01251         for (i = 0; i < nummovefaces; i++)
01252         {
01253             //move the vertex back to the initial position
01254             VectorCopy(vertex, movefaces[i]->face_winding->points[movefacepoints[i]]);
01255             //create new face plane
01256             for (j = 0; j < 3; j++)
01257             {
01258                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01259             }
01260             Face_MakePlane(movefaces[i]);
01261         }
01262         result = false;
01263     }
01264     //get texture crap right
01265     for (i = 0; i < nummovefaces; i++)
01266     {
01267         Face_SetColor(b, movefaces[i], 1.0);
01268         for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
01269             EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
01270     }
01271 
01272     //now try to merge faces with their original faces
01273     lastface = NULL;
01274     for (face = b->brush_faces; face; face = nextface)
01275     {
01276         nextface = face->next;
01277         if (!face->original)
01278         {
01279             lastface = face;
01280             continue;
01281         }
01282         if (!Plane_Equal(&face->plane, &face->original->plane, false))
01283         {
01284             lastface = face;
01285             continue;
01286         }
01287         w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
01288         if (!w)
01289         {
01290             lastface = face;
01291             continue;
01292         }
01293         Winding_Free(face->original->face_winding);
01294         face->original->face_winding = w;
01295         //get texture crap right
01296         Face_SetColor(b, face->original, 1.0);
01297         for (j = 0; j < face->original->face_winding->numpoints; j++)
01298             EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
01299         //remove the face that was merged with the original
01300         if (lastface) lastface->next = face->next;
01301         else b->brush_faces = face->next;
01302         Face_Free(face);
01303     }
01304     return result;
01305 }
01306 
01307 /*
01308 =================
01309 Brush_MoveVertexes
01310 
01311 - The input brush must be convex
01312 - The input brush must have face windings.
01313 - The output brush will be convex.
01314 - Returns true if the WHOLE vertex movement is performed.
01315 =================
01316 */
01317 
01318 #define MAX_MOVE_FACES      64
01319 
01320 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
01321 {
01322     face_t *f, *face, *newface, *lastface, *nextface;
01323     face_t *movefaces[MAX_MOVE_FACES];
01324     int movefacepoints[MAX_MOVE_FACES];
01325     winding_t *w, tmpw;
01326     vec3_t start, mid;
01327     plane_t plane;
01328     int i, j, k, nummovefaces, result, done;
01329     float dot, front, back, frac, smallestfrac;
01330 
01331     result = true;
01332     //
01333     tmpw.numpoints = 3;
01334     tmpw.maxpoints = 3;
01335     VectorCopy(vertex, start);
01336     VectorAdd(vertex, delta, end);
01337     //snap or not?
01338     if (bSnap)
01339         for (i = 0; i < 3; i++)
01340             end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
01341     //
01342     VectorCopy(end, mid);
01343     //if the start and end are the same
01344     if (Point_Equal(start, end, 0.3)) return false;
01345     //the end point may not be the same as another vertex
01346     for (face = b->brush_faces; face; face = face->next)
01347     {
01348         w = face->face_winding;
01349         if (!w) continue;
01350         for (i = 0; i < w->numpoints; i++)
01351         {
01352             if (Point_Equal(w->points[i], end, 0.3))
01353             {
01354                 VectorCopy(vertex, end);
01355                 return false;
01356             }
01357         }
01358     }
01359     //
01360     done = false;
01361     while(!done)
01362     {
01363         //chop off triangles from all brush faces that use the to be moved vertex
01364         //store pointers to these chopped off triangles in movefaces[]
01365         nummovefaces = 0;
01366         for (face = b->brush_faces; face; face = face->next)
01367         {
01368             w = face->face_winding;
01369             if (!w) continue;
01370             for (i = 0; i < w->numpoints; i++)
01371             {
01372                 if (Point_Equal(w->points[i], start, 0.2))
01373                 {
01374                     if (face->face_winding->numpoints <= 3)
01375                     {
01376                         movefacepoints[nummovefaces] = i;
01377                         movefaces[nummovefaces++] = face;
01378                         break;
01379                     }
01380                     dot = DotProduct(end, face->plane.normal) - face->plane.dist;
01381                     //if the end point is in front of the face plane
01382                     if (dot > 0.1)
01383                     {
01384                         //fanout triangle subdivision
01385                         for (k = i; k < i + w->numpoints-3; k++)
01386                         {
01387                             VectorCopy(w->points[i], tmpw.points[0]);
01388                             VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
01389                             VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
01390                             //
01391                             newface = Face_Clone(face);
01392                             //get the original
01393                             for (f = face; f->original; f = f->original) ;
01394                             newface->original = f;
01395                             //store the new winding
01396                             if (newface->face_winding) Winding_Free(newface->face_winding);
01397                             newface->face_winding = Winding_Clone(&tmpw);
01398                             //get the texture
01399                             newface->d_texture = Texture_ForName( newface->texdef.name );
01400                             //add the face to the brush
01401                             newface->next = b->brush_faces;
01402                             b->brush_faces = newface;
01403                             //add this new triangle to the move faces
01404                             movefacepoints[nummovefaces] = 0;
01405                             movefaces[nummovefaces++] = newface;
01406                         }
01407                         //give the original face a new winding
01408                         VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
01409                         VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
01410                         VectorCopy(w->points[i], tmpw.points[2]);
01411                         Winding_Free(face->face_winding);
01412                         face->face_winding = Winding_Clone(&tmpw);
01413                         //add the original face to the move faces
01414                         movefacepoints[nummovefaces] = 2;
01415                         movefaces[nummovefaces++] = face;
01416                     }
01417                     else
01418                     {
01419                         //chop a triangle off the face
01420                         VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
01421                         VectorCopy(