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

PMESH.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 // Preliminary patch stuff
00024 //
00025 // 
00026 
00027 #include "stdafx.h"
00028 #include "qe3.h"
00029 #include "DialogInfo.h"
00030 #include "CapDialog.h"
00031 
00032 // externs
00033 extern void MemFile_fprintf(CMemFile* pMemFile, const char* pText, ...);
00034 extern face_t *Face_Alloc( void );
00035 void _Write3DMatrix (FILE *f, int y, int x, int z, float *m);
00036 void _Write3DMatrix (CMemFile *f, int y, int x, int z, float *m);
00037 
00038 
00039 
00040 #define CBLOCK_SUBDIVISIONS 6 
00041 
00042 
00043 patchMesh_t* MakeNewPatch()
00044 {
00045   patchMesh_t *pm = reinterpret_cast<patchMesh_t*>(qmalloc(sizeof(patchMesh_t)));
00046   if (g_qeglobals.bSurfacePropertiesPlugin)
00047   {
00048       pm->pData = static_cast<void *>( g_SurfaceTable.m_pfnPatchAlloc( pm ) );
00049   }
00050   return pm;
00051 }
00052 
00053 // FIXME: this needs to be dynamic
00054 //#define   MAX_PATCH_MESHES    4096
00055 //patchMesh_t       patchMeshes[MAX_PATCH_MESHES];
00056 //int numPatchMeshes = 0;
00057 
00058 // used for a save spot
00059 patchMesh_t patchSave;
00060 
00061 // Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized 
00062 // brush approach
00063 //--int  g_nSelectedPatch = -1;  
00064 
00065 // HACK: for tracking which view generated the click
00066 // as we dont want to deselect a point on a same point
00067 // click if it is from a different view
00068 int  g_nPatchClickedView = -1;
00069 bool g_bSameView = false;
00070 
00071 
00072 // globals
00073 bool g_bPatchShowBounds = true;
00074 bool g_bPatchWireFrame = false;
00075 bool g_bPatchWeld = true;
00076 bool g_bPatchDrillDown = true;
00077 bool g_bPatchInsertMode = false;
00078 bool g_bPatchBendMode = false;
00079 int  g_nPatchBendState = -1;
00080 int  g_nPatchInsertState = -1;
00081 int  g_nBendOriginIndex = 0;
00082 vec3_t g_vBendOrigin;
00083 
00084 bool g_bPatchAxisOnRow = true;
00085 int  g_nPatchAxisIndex = 0;
00086 bool g_bPatchLowerEdge = true;
00087 
00088 // BEND states
00089 enum
00090 {
00091   BEND_SELECT_ROTATION = 0,
00092   BEND_SELECT_ORIGIN,
00093   BEND_SELECT_EDGE,
00094   BEND_BENDIT,
00095   BEND_STATE_COUNT
00096 };
00097 
00098 const char *g_pBendStateMsg[] =
00099 {
00100   "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.",
00101   "Use TAB to cycle through available rotation axis. This will LOCK around that point. You may also use Shift + Middle Click to select an arbitrary point. Press ENTER when the desired one is highlighted",
00102   "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.",
00103   "Use the MOUSE to bend the patch. It uses the same ui rules as Free Rotation. Press ENTER to accept the bend, press ESC to abandon it and exit Bend mode",
00104   ""
00105 };
00106 
00107 // INSERT states
00108 enum
00109 {
00110   INSERT_SELECT_EDGE = 0,
00111   INSERT_STATE_COUNT
00112 };
00113 
00114 const char* g_pInsertStateMsg[] =
00115 {
00116   "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair"
00117 };
00118 
00119 
00120 float *g_InversePoints[1024];
00121 
00122 const float fFullBright = 1.0;
00123 const float fLowerLimit = .50;
00124 const float fDec = .05;
00125 void _SetColor(face_t* f, float fColor[3])
00126 {
00127   return;
00128   fColor[0] = f->d_color[0];
00129   fColor[1] = f->d_color[1];
00130   fColor[2] = f->d_color[2];
00131   qglColor3fv(fColor);
00132 }
00133 
00134 
00135 void _DecColor(float fColor[3])
00136 {
00137   return;
00138   fColor[0] -= fDec;
00139   fColor[1] -= fDec ;
00140   fColor[2] -= fDec;
00141   for (int i = 0; i < 3; i++)
00142   {
00143     if (fColor[i] <= fLowerLimit)
00144     {
00145       fColor[0] = fFullBright;
00146       fColor[1] = fFullBright;
00147       fColor[2] = fFullBright;
00148       break;
00149     }
00150   }
00151     qglColor3fv(fColor);
00152 }
00153 
00154 vec_t __VectorNormalize (vec3_t in, vec3_t out)
00155 {
00156     vec_t   length, ilength;
00157 
00158     length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
00159     if (length == 0)
00160     {
00161         VectorClear (out);
00162         return 0;
00163     }
00164 
00165     ilength = 1.0/length;
00166     out[0] = in[0]*ilength;
00167     out[1] = in[1]*ilength;
00168     out[2] = in[2]*ilength;
00169 
00170     return length;
00171 }
00172 
00173 
00174 void Patch_SetType(patchMesh_t *p, int nType)
00175 {
00176   p->type = (p->type & PATCH_STYLEMASK) | nType;
00177 }
00178 
00179 void Patch_SetStyle(patchMesh_t *p, int nStyle)
00180 {
00181   p->type = (p->type & PATCH_TYPEMASK) | nStyle;
00182 }
00183 
00184 /*
00185 ==================
00186 Patch_MemorySize
00187 ==================
00188 */
00189 int Patch_MemorySize(patchMesh_t *p)
00190 {
00191     return _msize(p);
00192 }
00193 
00194 
00195 
00196 /*
00197 ===============
00198 InterpolateInteriorPoints
00199 ===============
00200 */
00201 void InterpolateInteriorPoints( patchMesh_t *p ) 
00202 {
00203     int     i, j, k;
00204     int     next, prev;
00205 
00206     for ( i = 0 ; i < p->width ; i += 2 ) 
00207   {
00208 
00209     next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width;
00210     prev = ( i == 0 ) ? p->width - 2 : i - 1;
00211 
00212 #if 0
00213         if ( i == 0 ) 
00214     {
00215             next = ( i + 1 ) % p->width;
00216             prev = p->width - 2;              // joined wrap case
00217         } 
00218     else if ( i == p->width - 1 ) 
00219     {
00220             next = 1;
00221             prev = i - 1;
00222         } 
00223     else 
00224     {
00225             next = ( i + 1 ) % p->width;
00226             prev = i - 1;
00227         }
00228 #endif
00229 
00230         for ( j = 0 ; j < p->height ; j++ ) 
00231     {
00232             for ( k = 0 ; k < 3 ; k++ ) 
00233       {
00234                 p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5;
00235             }
00236         }
00237     }
00238 }
00239 
00240 /*
00241 =================
00242 MakeMeshNormals
00243 
00244 =================
00245 */
00246 int neighbors[8][2] = {
00247     {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
00248 };
00249 
00250 void Patch_MeshNormals(patchMesh_t *in ) 
00251 {
00252     int     i, j, k, dist;
00253     vec3_t  normal;
00254     vec3_t  sum;
00255     int     count;
00256     vec3_t  base;
00257     vec3_t  delta;
00258     int     x, y;
00259     drawVert_t  *dv;
00260     vec3_t      around[8], temp;
00261     qboolean    good[8];
00262     qboolean    wrapWidth, wrapHeight;
00263     float       len;
00264 
00265     wrapWidth = false;
00266     for ( i = 0 ; i < in->height ; i++ ) 
00267   {
00268 
00269         VectorSubtract( in->ctrl[0][i].xyz, 
00270                           in->ctrl[in->width-1][i].xyz, delta );
00271         len = VectorLength( delta );
00272         if ( len > 1.0 ) 
00273     {
00274             break;
00275         }
00276     }
00277     if ( i == in->height ) 
00278   {
00279         wrapWidth = true;
00280     }
00281 
00282     wrapHeight = false;
00283     for ( i = 0 ; i < in->width ; i++ ) 
00284   {
00285         VectorSubtract( in->ctrl[i][0].xyz, 
00286                           in->ctrl[i][in->height-1].xyz, delta );
00287         len = VectorLength( delta );
00288         if ( len > 1.0 ) 
00289     {
00290             break;
00291         }
00292     }
00293     if ( i == in->width) 
00294   {
00295         wrapHeight = true;
00296     }
00297 
00298 
00299     for ( i = 0 ; i < in->width ; i++ ) 
00300   {
00301         for ( j = 0 ; j < in->height ; j++ ) 
00302     {
00303             count = 0;
00304             //--dv = reinterpret_cast<drawVert_t*>(in.ctrl[j*in.width+i]);
00305             dv = &in->ctrl[i][j];
00306             VectorCopy( dv->xyz, base );
00307             for ( k = 0 ; k < 8 ; k++ ) 
00308       {
00309                 VectorClear( around[k] );
00310                 good[k] = false;
00311 
00312                 for ( dist = 1 ; dist <= 3 ; dist++ ) 
00313         {
00314                     x = i + neighbors[k][0] * dist;
00315                     y = j + neighbors[k][1] * dist;
00316                     if ( wrapWidth ) 
00317           {
00318                         if ( x < 0 ) 
00319             {
00320                             x = in->width - 1 + x;
00321                         } 
00322             else if ( x >= in->width ) 
00323             {
00324                             x = 1 + x - in->width;
00325                         }
00326                     }
00327                     if ( wrapHeight ) 
00328           {
00329                         if ( y < 0 ) 
00330             {
00331                             y = in->height - 1 + y;
00332                         } 
00333             else if ( y >= in->height ) 
00334             {
00335                             y = 1 + y - in->height;
00336                         }
00337                     }
00338 
00339                     if ( x < 0 || x >= in->width || y < 0 || y >= in->height ) 
00340           {
00341                         break;                  // edge of patch
00342                     }
00343                     //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp );
00344                     VectorSubtract( in->ctrl[x][y].xyz, base, temp );
00345                     if ( __VectorNormalize( temp, temp ) == 0 ) 
00346           {
00347                         continue;               // degenerate edge, get more dist
00348                     } 
00349           else                 
00350           {
00351                         good[k] = true;
00352                         VectorCopy( temp, around[k] );
00353                         break;                  // good edge
00354                     }
00355                 }
00356             }
00357 
00358             VectorClear( sum );
00359             for ( k = 0 ; k < 8 ; k++ ) 
00360       {
00361                 if ( !good[k] || !good[(k+1)&7] ) 
00362         {
00363                     continue;   // didn't get two points
00364                 }
00365                 CrossProduct( around[(k+1)&7], around[k], normal );
00366                 if ( __VectorNormalize( normal, normal ) == 0 ) 
00367         {
00368                     continue;
00369                 }
00370                 VectorAdd( normal, sum, sum );
00371                 count++;
00372             }
00373             if ( count == 0 ) 
00374       {
00375         //printf("bad normal\n");
00376                 count = 1;
00377         //continue;
00378             }
00379             __VectorNormalize( sum, dv->normal );
00380         }
00381     }
00382 }
00383 
00384 
00385 
00386 
00387 /*
00388 ==================
00389 Patch_CalcBounds
00390 ==================
00391 */
00392 void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax)
00393 {
00394   vMin[0] = vMin[1] = vMin[2] = 99999;
00395   vMax[0] = vMax[1] = vMax[2] = -99999;
00396 
00397   p->bDirty = true;
00398   for (int w = 0; w < p->width; w++)
00399   {
00400     for (int h = 0; h < p->height; h++)
00401     {
00402       for (int j = 0; j < 3; j++)
00403       {
00404         float f = p->ctrl[w][h].xyz[j];
00405         if (f < vMin[j])
00406           vMin[j] = f;
00407         if (f > vMax[j])
00408           vMax[j] = f;
00409       }
00410     }
00411   }
00412 }
00413 
00414 /*
00415 ==================
00416 Brush_RebuildBrush
00417 ==================
00418 */
00419 void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs)
00420 {
00421   //
00422   // Total hack job 
00423   // Rebuilds a brush
00424     int     i, j;
00425     face_t  *f, *next;
00426     vec3_t  pts[4][2];
00427   texdef_t  texdef;
00428     // free faces
00429 
00430   for (j = 0; j < 3; j++)
00431   {
00432     if ((int)vMins[j] == (int)vMaxs[j])
00433     {
00434       vMins[j] -= 4;
00435       vMaxs[j] += 4;
00436     }
00437   }
00438 
00439   
00440   for (f=b->brush_faces ; f ; f=next)
00441     {
00442         next = f->next;
00443     if (f)
00444       texdef = f->texdef;
00445     Face_Free( f );
00446     }
00447 
00448   b->brush_faces = NULL;
00449 
00450   // left the last face so we can use its texdef
00451 
00452     for (i=0 ; i<3 ; i++)
00453         if (vMaxs[i] < vMins[i])
00454             Error ("Brush_RebuildBrush: backwards");
00455 
00456     pts[0][0][0] = vMins[0];
00457     pts[0][0][1] = vMins[1];
00458     
00459     pts[1][0][0] = vMins[0];
00460     pts[1][0][1] = vMaxs[1];
00461     
00462     pts[2][0][0] = vMaxs[0];
00463     pts[2][0][1] = vMaxs[1];
00464     
00465     pts[3][0][0] = vMaxs[0];
00466     pts[3][0][1] = vMins[1];
00467     
00468     for (i=0 ; i<4 ; i++)
00469     {
00470         pts[i][0][2] = vMins[2];
00471         pts[i][1][0] = pts[i][0][0];
00472         pts[i][1][1] = pts[i][0][1];
00473         pts[i][1][2] = vMaxs[2];
00474     }
00475 
00476     for (i=0 ; i<4 ; i++)
00477     {
00478         f = Face_Alloc();
00479         f->texdef = texdef;
00480         f->texdef.flags &= ~SURF_KEEP;
00481         f->texdef.contents &= ~CONTENTS_KEEP;
00482         if ( b->patchBrush )
00483         {
00484             f->texdef.flags |= SURF_PATCH; 
00485         }
00486         f->next = b->brush_faces;
00487         b->brush_faces = f;
00488         j = (i+1)%4;
00489 
00490         VectorCopy (pts[j][1], f->planepts[0]);
00491         VectorCopy (pts[i][1], f->planepts[1]);
00492         VectorCopy (pts[i][0], f->planepts[2]);
00493     }
00494     
00495     f = Face_Alloc();
00496     f->texdef = texdef;
00497     f->texdef.flags &= ~SURF_KEEP;
00498     f->texdef.contents &= ~CONTENTS_KEEP;
00499     if ( b->patchBrush )
00500     {
00501         f->texdef.flags |= SURF_PATCH; 
00502     }
00503     f->next = b->brush_faces;
00504     b->brush_faces = f;
00505 
00506     VectorCopy (pts[0][1], f->planepts[0]);
00507     VectorCopy (pts[1][1], f->planepts[1]);
00508     VectorCopy (pts[2][1], f->planepts[2]);
00509 
00510     f = Face_Alloc();
00511     f->texdef = texdef;
00512     f->texdef.flags &= ~SURF_KEEP;
00513     f->texdef.contents &= ~CONTENTS_KEEP;
00514     if ( b->patchBrush )
00515     {
00516         f->texdef.flags |= SURF_PATCH; 
00517     }
00518     f->next = b->brush_faces;
00519     b->brush_faces = f;
00520 
00521     VectorCopy (pts[2][0], f->planepts[0]);
00522     VectorCopy (pts[1][0], f->planepts[1]);
00523     VectorCopy (pts[0][0], f->planepts[2]);
00524 
00525   Brush_Build(b);
00526 }
00527 
00528 void WINAPI Patch_Rebuild(patchMesh_t *p)
00529 {
00530   vec3_t vMin, vMax;
00531   Patch_CalcBounds(p, vMin, vMax);
00532   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
00533   p->bDirty = true;
00534 }
00535 
00536 /*
00537 ==================
00538 AddBrushForPatch
00539 ==================
00540  adds a patch brush and ties it to this patch id
00541 */
00542 brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld )
00543 {
00544   // find the farthest points in x,y,z
00545   vec3_t vMin, vMax;
00546   Patch_CalcBounds(pm, vMin, vMax);
00547 
00548   for (int j = 0; j < 3; j++)
00549   {
00550     if (vMin[j] == vMax[j])
00551     {
00552       vMin[j] -= 4;
00553       vMax[j] += 4;
00554     }
00555   }
00556 
00557   brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
00558     face_t      *f;
00559     for (f=b->brush_faces ; f ; f=f->next) 
00560   {
00561         f->texdef.flags |= SURF_PATCH; 
00562     }
00563 
00564   // FIXME: this entire type of linkage needs to be fixed
00565   b->pPatch = pm;
00566   pm->pSymbiot = b;
00567   pm->bSelected = false;
00568   pm->bOverlay = false;
00569   pm->bDirty = true;
00570   pm->nListID = -1;
00571 
00572   if (bLinkToWorld)
00573   {
00574     Brush_AddToList (b, &active_brushes);
00575       Entity_LinkBrush (world_entity, b);
00576     Brush_Build(b);
00577   }
00578 
00579   return b;
00580 }
00581 
00582 void Patch_SetPointIntensities(int n)
00583 {
00584 #if 0
00585     patchMesh_t *p = patchMeshes[n];
00586   for (int i = 0; i < p->width; i++)
00587   {
00588     for (int j = 0; j < p->height; j++)
00589     {
00590 
00591     }
00592   }
00593 #endif
00594 }
00595 
00596 // very approximate widths and heights
00597 
00598 /*
00599 ==================
00600 Patch_Width
00601 ==================
00602 */
00603 float Patch_Width(patchMesh_t *p)
00604 {
00605   float f = 0;
00606   for (int i = 0; i < p->width-1; i++)
00607   {
00608     vec3_t vTemp;
00609     VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
00610     f += VectorLength(vTemp);
00611   }
00612   return f;
00613 }
00614 
00615 float Patch_WidthDistanceTo(patchMesh_t *p, int j)
00616 {
00617   float f = 0;
00618   for (int i = 0; i < j; i++)
00619   {
00620     vec3_t vTemp;
00621     VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
00622     f += VectorLength(vTemp);
00623   }
00624   return f;
00625 }
00626 
00627 
00628 
00629 /*
00630 ==================
00631 Patch_Height
00632 ==================
00633 */
00634 float Patch_Height(patchMesh_t *p)
00635 {
00636   float f = 0;
00637   for (int i = 0; i < p->height-1; i++)
00638   {
00639     vec3_t vTemp;
00640     VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
00641     f += VectorLength(vTemp);
00642   }
00643   return f;
00644 }
00645 
00646 float Patch_HeightDistanceTo(patchMesh_t *p, int j)
00647 {
00648   float f = 0;
00649   for (int i = 0; i < j; i++)
00650   {
00651     vec3_t vTemp;
00652     VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
00653     f += VectorLength(vTemp);
00654   }
00655   return f;
00656 }
00657 
00658 
00659 
00660 /*
00661 ==================
00662 Patch_Naturalize
00663 ==================
00664 texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength
00665 
00666 dist( this control point to first control point ) / dist ( last control pt to first)
00667 */
00668 void Patch_Naturalize(patchMesh_t *p)
00669 {
00670   int nWidth = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? p->d_texture->width * 0.5 : p->d_texture->width;
00671   int nHeight = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? p->d_texture->height * 0.5 : p->d_texture->height;
00672   float fPWidth = Patch_Width(p);
00673   float fPHeight = Patch_Height(p);
00674   float xAccum = 0;
00675   for ( int i = 0 ; i < p->width ; i++ ) 
00676   {
00677     float yAccum = 0;
00678       for ( int j = 0 ; j < p->height ; j++ ) 
00679     {
00680           p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth;
00681           p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight;
00682           yAccum = Patch_HeightDistanceTo(p,j+1);
00683       //p->ctrl[i][j][3] = (fPWidth / nWidth) * (float)i / (p->width - 1);
00684           //p->ctrl[i][j][4] = (fPHeight/ nHeight) * (float)j / (p->height - 1);
00685       }
00686     xAccum = Patch_WidthDistanceTo(p,i+1);
00687   }
00688   p->bDirty = true;
00689 }
00690 
00691 /*
00692   if (bIBevel)
00693   {
00694     VectorCopy(p->ctrl[1][0], p->ctrl[1][1]);
00695   }
00696 
00697   if (bIEndcap)
00698   {
00699     VectorCopy(p->ctrl[3][0], p->ctrl[4][1]);
00700     VectorCopy(p->ctrl[2][0], p->ctrl[3][1]);
00701     VectorCopy(p->ctrl[2][0], p->ctrl[2][1]);
00702     VectorCopy(p->ctrl[2][0], p->ctrl[1][1]);
00703     VectorCopy(p->ctrl[1][0], p->ctrl[0][1]);
00704     VectorCopy(p->ctrl[1][0], p->ctrl[0][2]);
00705     VectorCopy(p->ctrl[1][0], p->ctrl[1][2]);
00706     VectorCopy(p->ctrl[2][0], p->ctrl[2][2]);
00707     VectorCopy(p->ctrl[3][0], p->ctrl[3][2]);
00708     VectorCopy(p->ctrl[3][0], p->ctrl[4][2]);
00709   }
00710 */
00711 
00712 int Index3By[][2] =
00713 {
00714   {0,0},
00715   {1,0},
00716   {2,0},
00717   {2,1},
00718   {2,2},
00719   {1,2},
00720   {0,2},
00721   {0,1},
00722   {0,0},
00723   {0,0},
00724   {0,0},
00725   {0,0},
00726   {0,0},
00727   {0,0},
00728   {0,0}
00729 };
00730 
00731 int Index5By[][2] =
00732 {
00733   {0,0},
00734   {1,0},
00735   {2,0},
00736   {3,0},
00737   {4,0},
00738   {4,1},
00739   {4,2},
00740   {4,3},
00741   {4,4},
00742   {3,4},
00743   {2,4},
00744   {1,4},
00745   {0,4},
00746   {0,3},
00747   {0,2},
00748   {0,1}
00749 };
00750 
00751 
00752 
00753 int Interior3By[][2] =
00754 {
00755   {1,1}
00756 };
00757 
00758 int Interior5By[][2] =
00759 {
00760   {1,1},
00761   {2,1},
00762   {3,1},
00763   {1,2},
00764   {2,2},
00765   {3,2},
00766   {1,3},
00767   {2,3},
00768   {3,3}
00769 };
00770 
00771 int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]);
00772 int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]);
00773 
00774 face_t* Patch_GetAxisFace(patchMesh_t *p)
00775 {
00776   face_t *f = NULL;
00777   vec3_t vTemp;
00778   brush_t *b = p->pSymbiot;
00779 
00780     for (f = b->brush_faces ; f ; f = f->next) 
00781   {
00782     VectorSubtract(f->face_winding->points[1], f->face_winding->points[0], vTemp);
00783     int nScore = 0;
00784 
00785     // default edge faces on caps are 8 high so
00786     // as soon as we hit one that is bigger it should be on the right axis
00787     for (int j = 0; j < 3; j++)
00788     {
00789       if (vTemp[j] > 8)
00790         nScore++;
00791     }
00792 
00793     if (nScore > 0)
00794       break;
00795   }
00796 
00797   if (f == NULL)
00798     f = b->brush_faces;
00799   return f;
00800 }
00801 
00802 int g_nFaceCycle = 0;
00803 
00804 face_t* nextFace(patchMesh_t *p)
00805 {
00806   brush_t *b = p->pSymbiot;
00807   face_t *f = NULL;
00808   int n = 0;
00809     for (f = b->brush_faces ; f && n <= g_nFaceCycle; f = f->next) 
00810   {
00811     n++;
00812   }
00813   g_nFaceCycle++;
00814   if (g_nFaceCycle > 5)
00815   {
00816     g_nFaceCycle =0;
00817     f = b->brush_faces;
00818   }
00819 
00820   return f;
00821 }
00822 
00823 
00824 extern void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f);
00825 void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false)
00826 {
00827   Patch_MeshNormals(p);
00828   face_t *f = (bFaceCycle) ? nextFace(p) : Patch_GetAxisFace(p);
00829   vec3_t vSave;
00830   VectorCopy(f->plane.normal, vSave);
00831   
00832   float fRotate = f->texdef.rotate;
00833   f->texdef.rotate = 0;
00834   float fScale[2];
00835   fScale[0] = f->texdef.scale[0];
00836   fScale[1] = f->texdef.scale[1];
00837   f->texdef.scale[0] = 0.5;
00838   f->texdef.scale[1] = 0.5;
00839   float fShift[2];
00840   fShift[0] = f->texdef.shift[0];
00841   fShift[1] = f->texdef.shift[1];
00842   f->texdef.shift[0] = 0;
00843   f->texdef.shift[1] = 0;
00844   
00845   for (int i = 0; i < p->width; i++)
00846   {
00847     for (int j = 0; j < p->height; j++)
00848     {
00849       if (!bFaceCycle)
00850       {
00851         VectorCopy(p->ctrl[i][j].normal, f->plane.normal);
00852       }
00853           EmitTextureCoordinates( p->ctrl[i][j].xyz, f->d_texture, f);
00854     }
00855   }
00856   VectorCopy(vSave, f->plane.normal);
00857   f->texdef.rotate = fRotate;
00858   f->texdef.scale[0] = fScale[0];
00859   f->texdef.scale[1] = fScale[1];
00860   f->texdef.shift[0] = fShift[0];
00861   f->texdef.shift[1] = fShift[1];
00862   p->bDirty = true;
00863 }
00864 
00865 void FillPatch(patchMesh_t *p, vec3_t v)
00866 {
00867   for (int i = 0; i < p->width; i++)
00868   {
00869     for (int j = 0; j < p->height; j++)
00870     {
00871       VectorCopy(v, p->ctrl[i][j].xyz);
00872     }
00873   }
00874 }
00875 
00876 brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst)
00877 {
00878   brush_t *b;
00879   patchMesh_t *p;
00880   vec3_t vMin, vMax;
00881   int i, j;
00882 
00883   bool bSmall = true;
00884   // make a generic patch
00885   if (pParent->width <= 9)
00886   {
00887     b = Patch_GenericMesh(3, 3, 2, false);
00888   }
00889   else
00890   {
00891     b = Patch_GenericMesh(5, 5, 2, false);
00892     bSmall = false;
00893   }
00894 
00895   if (!b)
00896   {
00897     Sys_Printf("Unable to cap. You may need to ungroup the patch.\n");
00898     return NULL;
00899   }
00900 
00901   p = b->pPatch;
00902   p->type |= PATCH_CAP;
00903 
00904   vMin[0] = vMin[1] = vMin[2] = 9999;
00905   vMax[0] = vMax[1] = vMax[2] = -9999;
00906 
00907   // we seam the column edge, FIXME: this might need to be able to seem either edge
00908   // 
00909   int nSize = (bByColumn) ? pParent->width : pParent->height;
00910   int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1;
00911 
00912   FillPatch(p, pParent->ctrl[0][nIndex].xyz);
00913 
00914   for (i = 0; i < nSize; i++)
00915   {
00916     if (bByColumn)
00917     {
00918       if (bSmall)
00919       {
00920         VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
00921       }
00922       else
00923       {
00924         VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
00925       }
00926     }
00927     else
00928     {
00929       if (bSmall)
00930       {
00931         VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
00932       }
00933       else
00934       {
00935         VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
00936       }
00937     }
00938   
00939     for (j = 0; j < 3; j++)
00940     {
00941       float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j];
00942       if (f < vMin[j])
00943         vMin[j] = f;
00944       if (f > vMax[j])
00945         vMax[j] = f;
00946     }
00947   }
00948 
00949   vec3_t vTemp;
00950   for (j = 0; j < 3; j++)
00951   {
00952     vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
00953   }
00954 
00955   int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount;
00956   for (j = 0; j < nCount; j++)
00957   {
00958     if (bSmall)
00959     {
00960       VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz);
00961     }
00962     else
00963     {
00964       VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz);
00965     }
00966   }
00967 
00968   if (bFirst)
00969   {
00970     drawVert_t vertTemp;
00971     for (i = 0; i < p->width; i++)
00972     {
00973       for (j = 0; j < p->height / 2; j++)
00974       {
00975         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
00976         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
00977         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
00978       }
00979     }
00980   }
00981 
00982   Patch_Rebuild(p);
00983   Patch_CapTexture(p);
00984   return p->pSymbiot;
00985 }
00986 
00987 brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst)
00988 {
00989   brush_t *b;
00990   patchMesh_t *p;
00991   vec3_t vMin, vMax, vTemp;
00992   int i, j;
00993 
00994   if (nType == CCapDialog::IENDCAP)
00995     b = Patch_GenericMesh(5, 3, 2, false);
00996   else
00997     b = Patch_GenericMesh(3, 3, 2, false);
00998 
00999   if (!b)
01000   {
01001     Sys_Printf("Unable to cap. Make sure you ungroup before re-capping.");
01002     return NULL;
01003   }
01004 
01005   p = b->pPatch;
01006   p->type |= PATCH_CAP;
01007 
01008   vMin[0] = vMin[1] = vMin[2] = 9999;
01009   vMax[0] = vMax[1] = vMax[2] = -9999;
01010 
01011   int nSize = pParent->width;
01012   int nIndex = (bFirst) ? 0 : pParent->height-1;
01013 
01014   // parent bounds are used for some things
01015   Patch_CalcBounds(pParent, vMin, vMax);
01016 
01017   for (j = 0; j < 3; j++)
01018   {
01019     vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
01020   }
01021 
01022   if (nType == CCapDialog::IBEVEL)
01023   {
01024     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
01025     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
01026     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
01027     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz);
01028     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
01029     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
01030     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
01031     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz);
01032     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz);
01033   }
01034   else if (nType == CCapDialog::BEVEL)
01035   {
01036     vec3_t p1, p2, p3, p4, temp, dir;
01037 
01038     VectorCopy(pParent->ctrl[0][nIndex].xyz, p3);
01039     VectorCopy(pParent->ctrl[1][nIndex].xyz, p1);
01040     VectorCopy(pParent->ctrl[2][nIndex].xyz, p2);
01041 
01042     VectorSubtract(p3, p2, dir);
01043     VectorNormalize(dir);
01044     VectorSubtract(p1, p2, temp);
01045     vec_t dist = _DotProduct(temp, dir);
01046 
01047     VectorScale(dir, dist, temp);
01048 
01049     VectorAdd(p2, temp, temp);
01050 
01051     VectorSubtract(temp, p1, temp);
01052     VectorScale(temp, 2, temp);
01053     VectorAdd(p1, temp, p4);
01054 
01055     VectorCopy(p4, p->ctrl[0][0].xyz);
01056     VectorCopy(p4, p->ctrl[1][0].xyz);
01057     VectorCopy(p4, p->ctrl[0][1].xyz);
01058     VectorCopy(p4, p->ctrl[1][1].xyz);
01059     VectorCopy(p4, p->ctrl[0][2].xyz);
01060     VectorCopy(p4, p->ctrl[1][2].xyz);
01061     VectorCopy(p3, p->ctrl[2][0].xyz);
01062     VectorCopy(p1, p->ctrl[2][1].xyz);
01063     VectorCopy(p2, p->ctrl[2][2].xyz);
01064 
01065   }
01066   else if (nType == CCapDialog::ENDCAP)
01067   {
01068     VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp);
01069     VectorScale(vTemp, 0.5, vTemp);
01070     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
01071                        VectorCopy(vTemp, p->ctrl[1][0].xyz);
01072     VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz);
01073 
01074     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
01075     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz);
01076     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
01077     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz);
01078     
01079     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
01080     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz);
01081   }
01082   else
01083   {
01084     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
01085     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
01086     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz);
01087     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][0].xyz);
01088     VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[4][0].xyz);
01089     
01090     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
01091     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
01092     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz);
01093     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][1].xyz);
01094     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[4][1].xyz);
01095 
01096     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][2].xyz);
01097     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
01098     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
01099     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][2].xyz);
01100     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[4][2].xyz);
01101   }
01102 
01103 
01104   bool bEndCap = (nType == CCapDialog::ENDCAP || nType == CCapDialog::IENDCAP);
01105   if ((!bFirst && !bEndCap) || (bFirst && bEndCap))
01106   {
01107     drawVert_t vertTemp;
01108     for (i = 0; i < p->width; i++)
01109     {
01110       for (j = 0; j < p->height / 2; j++)
01111       {
01112         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
01113         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
01114         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
01115       }
01116     }
01117   }
01118 
01119   //--Patch_CalcBounds(p, vMin, vMax);
01120   //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
01121   Patch_Rebuild(p);
01122   Patch_CapTexture(p);
01123   return p->pSymbiot;
01124 }
01125 
01126 
01127 void Patch_CapCurrent(bool bInvertedBevel, bool bInvertedEndcap)
01128 {
01129   patchMesh_t *pParent = NULL;
01130   brush_t *b[4];
01131   brush_t *pCap = NULL;
01132   b[0] = b[1] = b[2] = b[3] = NULL;
01133   int nIndex = 0;
01134 
01135     if (!QE_SingleBrush())
01136   {
01137     Sys_Printf("Cannot cap multiple selection. Please select a single patch.\n");
01138         return;
01139   }
01140 
01141 
01142     for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next)
01143     {
01144     if (pb->patchBrush)
01145     {
01146       pParent = pb->pPatch;
01147       // decide which if any ends we are going to cap
01148       // if any of these compares hit, it is a closed patch and as such
01149       // the generic capping will work.. if we do not find a closed edge 
01150       // then we need to ask which kind of cap to add
01151       if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz))
01152       {
01153         pCap = Cap(pParent, true, false);
01154         if (pCap != NULL)
01155         {
01156           b[nIndex++] = pCap;
01157         }
01158       }
01159       if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
01160       {
01161         pCap = Cap(pParent, true, true);
01162         if (pCap != NULL)
01163         {
01164           b[nIndex++] = pCap;
01165         }
01166       }
01167       if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz))
01168       {
01169         pCap = Cap(pParent, false, false);
01170         if (pCap != NULL)
01171         {
01172           b[nIndex++] = pCap;
01173         }
01174       }
01175       if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
01176       {
01177         pCap = Cap(pParent, false, true);
01178         if (pCap != NULL)
01179         {
01180           b[nIndex++] = pCap;
01181         }
01182       }
01183     }
01184   }
01185 
01186   if (pParent)
01187   {
01188     // if we did not cap anything with the above tests
01189     if (nIndex == 0)
01190     {
01191       CCapDialog dlg;
01192       if (dlg.DoModal() == IDOK)
01193       {
01194         b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), false);
01195         b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), true);
01196       }
01197     }
01198 
01199     if (nIndex > 0)
01200     {
01201       while (nIndex > 0)
01202       {
01203         nIndex--;
01204         if (b[nIndex])
01205         {
01206           Select_Brush(b[nIndex]);
01207         }
01208       }
01209       eclass_t *pecNew = Eclass_ForName("func_group", false);
01210       if (pecNew)
01211       {
01212         entity_t *e = Entity_Create(pecNew);
01213         SetKeyValue(e, "type", "patchCapped");
01214       }
01215     }
01216   }
01217 }
01218 
01219 
01220 //FIXME: Table drive all this crap
01221 //
01222 void GenerateEndCaps(brush_t *brushParent, bool bBevel, bool bEndcap, bool bInverted)
01223 {
01224   brush_t *b, *b2;
01225   patchMesh_t *p, *p2, *pParent;
01226   vec3_t vTemp, vMin, vMax;
01227   int i, j;
01228 
01229   pParent = brushParent->pPatch;
01230 
01231   Patch_CalcBounds(pParent, vMin, vMax);
01232   // basically generate two endcaps, place them, and link the three brushes with a func_group
01233 
01234   if (pParent->width > 9)
01235     b = Patch_GenericMesh(5, 3, 2, false);
01236   else
01237     b = Patch_GenericMesh(3, 3, 2, false);
01238   p = b->pPatch;
01239 
01240   vMin[0] = vMin[1] = vMin[2] = 9999;
01241   vMax[0] = vMax[1] = vMax[2] = -9999;
01242 
01243   for (i = 0; i < pParent->width; i++)
01244   {
01245     VectorCopy(pParent->ctrl[i][0].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
01246     for (j = 0; j < 3; j++)
01247     {
01248       if (pParent->ctrl[i][0].