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].xyz[j] < vMin[j])
01249         vMin[j] = pParent->ctrl[i][0].xyz[j];
01250       if (pParent->ctrl[i][0].xyz[j] > vMax[j])
01251         vMax[j] = pParent->ctrl[i][0].xyz[j];
01252     }
01253   }
01254 
01255   for (j = 0; j < 3; j++)
01256   {
01257     vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
01258   }
01259 
01260   for (i = 0; i < Interior3ByCount; i++)
01261   {
01262     VectorCopy(vTemp, p->ctrl[Interior3By[i][0]][Interior3By[i][1]].xyz);
01263   }
01264 
01265   Patch_CalcBounds(p, vMin, vMax);
01266   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
01267   Select_Brush(p->pSymbiot);
01268   return;
01269 
01270   bool bCreated = false;
01271 
01272   if (bInverted)
01273   {
01274     if (bBevel)
01275     {
01276       b = Patch_GenericMesh(3, 3, 2, false);
01277       p = b->pPatch;
01278       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][2].xyz);
01279       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[2][1].xyz);
01280       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[0][1].xyz);
01281       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][0].xyz);
01282       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][1].xyz);
01283       VectorCopy(p->ctrl[2][0].xyz, p->ctrl[0][0].xyz);
01284 
01285       b2 = Patch_GenericMesh(3, 3, 2, false);
01286       p2 = b2->pPatch;
01287       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][2].xyz);
01288       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[2][1].xyz);
01289       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[0][1].xyz);
01290       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][0].xyz);
01291       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][1].xyz);
01292       VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[0][0].xyz);
01293 
01294 
01295       bCreated = true;
01296 
01297     }
01298     else if (bEndcap)
01299     {
01300       b = Patch_GenericMesh(5, 5, 2, false);
01301       p = b->pPatch;
01302       VectorCopy(p->ctrl[4][4].xyz, p->ctrl[4][3].xyz);
01303       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[1][4].xyz);
01304       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[2][4].xyz);
01305       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[3][4].xyz);
01306 
01307       VectorCopy(p->ctrl[4][0].xyz, p->ctrl[4][1].xyz);
01308       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
01309       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
01310       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[3][0].xyz);
01311 
01312       for (i = 1; i < 4; i++)
01313       {
01314         for (j = 0; j < 4; j++)
01315         {
01316           VectorCopy(p->ctrl[4][i].xyz, p->ctrl[j][i].xyz);
01317         }
01318       }
01319 
01320 
01321       b2 = Patch_GenericMesh(5, 5, 2, false);
01322       p2 = b2->pPatch;
01323       VectorCopy(p2->ctrl[4][4].xyz, p2->ctrl[4][3].xyz);
01324       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[1][4].xyz);
01325       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[2][4].xyz);
01326       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[3][4].xyz);
01327 
01328       VectorCopy(p2->ctrl[4][0].xyz, p2->ctrl[4][1].xyz);
01329       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
01330       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
01331       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[3][0].xyz);
01332 
01333       for (i = 1; i < 4; i++)
01334       {
01335         for (j = 0; j < 4; j++)
01336         {
01337           VectorCopy(p2->ctrl[4][i].xyz, p2->ctrl[j][i].xyz);
01338         }
01339       }
01340 
01341 
01342       bCreated = true;
01343     }
01344   }
01345   else
01346   {
01347     if (bBevel)
01348     {
01349       b = Patch_GenericMesh(3, 3, 2, false);
01350       p = b->pPatch;
01351       VectorCopy(p->ctrl[2][0].xyz, p->ctrl[2][1].xyz);
01352       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
01353       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
01354 
01355       b2 = Patch_GenericMesh(3, 3, 2, false);
01356       p2 = b2->pPatch;
01357       VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[2][1].xyz);
01358       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
01359       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
01360       bCreated = true;
01361     }
01362     else if (bEndcap)
01363     {
01364       b = Patch_GenericMesh(5, 5, 2, false);
01365       p = b->pPatch;
01366       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
01367       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
01368       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[3][0].xyz);
01369       VectorCopy(p->ctrl[4][0].xyz, p->ctrl[4][1].xyz);
01370       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[4][0].xyz);
01371 
01372       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[1][4].xyz);
01373       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[2][4].xyz);
01374       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[3][4].xyz);
01375       VectorCopy(p->ctrl[4][4].xyz, p->ctrl[4][3].xyz);
01376       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[4][4].xyz);
01377 
01378       b2 = Patch_GenericMesh(5, 5, 2, false);
01379       p2 = b2->pPatch;
01380       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
01381       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
01382       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[3][0].xyz);
01383       VectorCopy(p2->ctrl[4][0].xyz, p2->ctrl[4][1].xyz);
01384       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[4][0].xyz);
01385 
01386       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[1][4].xyz);
01387       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[2][4].xyz);
01388       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[3][4].xyz);
01389       VectorCopy(p2->ctrl[4][4].xyz, p2->ctrl[4][3].xyz);
01390       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[4][4].xyz);
01391       bCreated = true;
01392     }
01393     else
01394     {
01395       b = Patch_GenericMesh(3, 3, 2, false);
01396       p = b->pPatch;
01397       
01398       VectorCopy(p->ctrl[0][1].xyz, vTemp);
01399       VectorCopy(p->ctrl[0][2].xyz, p->ctrl[0][1].xyz)
01400       VectorCopy(p->ctrl[1][2].xyz, p->ctrl[0][2].xyz)
01401       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][2].xyz)
01402       VectorCopy(p->ctrl[2][1].xyz, p->ctrl[2][2].xyz)
01403       VectorCopy(p->ctrl[2][0].xyz, p->ctrl[2][1].xyz)
01404       VectorCopy(p->ctrl[1][0].xyz, p->ctrl[2][0].xyz)
01405       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz)
01406       VectorCopy(vTemp, p->ctrl[0][0].xyz)
01407 
01408       b2 = Patch_GenericMesh(3, 3, 2, false);
01409       p2 = b2->pPatch;
01410       VectorCopy(p2->ctrl[0][1].xyz, vTemp);
01411       VectorCopy(p2->ctrl[0][2].xyz, p2->ctrl[0][1].xyz)
01412       VectorCopy(p2->ctrl[1][2].xyz, p2->ctrl[0][2].xyz)
01413       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][2].xyz)
01414       VectorCopy(p2->ctrl[2][1].xyz, p2->ctrl[2][2].xyz)
01415       VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[2][1].xyz)
01416       VectorCopy(p2->ctrl[1][0].xyz, p2->ctrl[2][0].xyz)
01417       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz)
01418       VectorCopy(vTemp, p2->ctrl[0][0].xyz)
01419       bCreated = true;
01420     }
01421   }
01422 
01423   if (bCreated)
01424   {
01425     drawVert_t vertTemp;
01426     for (i = 0; i < p->width; i++)
01427     {
01428       for (j = 0; j < p->height; j++)
01429       {
01430         p->ctrl[i][j].xyz[2] = vMin[2];
01431         p2->ctrl[i][j].xyz[2] = vMax[2];
01432       }
01433 
01434       for (j = 0; j < p->height / 2; j++)
01435       {
01436         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
01437         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
01438         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
01439       }
01440 
01441     }
01442     //Select_Delete();
01443 
01444     Patch_CalcBounds(p, vMin, vMax);
01445     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
01446     Patch_CalcBounds(p2, vMin, vMax);
01447     Brush_RebuildBrush(p2->pSymbiot, vMin, vMax);
01448     Select_Brush(p->pSymbiot);
01449     Select_Brush(p2->pSymbiot);
01450   }
01451   else
01452   {
01453     Select_Delete();
01454   }
01455   //Select_Brush(brushParent);
01456 
01457 }
01458 
01459 
01460 /*
01461 ===============
01462 BrushToPatchMesh
01463 ===============
01464 */
01465 void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight)
01466 {
01467     brush_t     *b;
01468     patchMesh_t *p;
01469     int         i,j;
01470 
01471     if (!QE_SingleBrush())
01472         return;
01473 
01474     b = selected_brushes.next;
01475 
01476     p = MakeNewPatch();
01477 
01478     p->d_texture = b->brush_faces->d_texture;
01479 
01480   p->height = nHeight;
01481 
01482   p->type = PATCH_CYLINDER;
01483   if (bBevel & !bSquare)
01484   {
01485     p->type = PATCH_BEVEL;
01486     p->width = 3;
01487     int nStep = (b->maxs[2] - b->mins[2]) / (p->height-1);
01488     int nStart = b->mins[2];
01489     for (i = 0; i < p->height; i++)
01490     {
01491         p->ctrl[0][i].xyz[0] =  b->mins[0];
01492         p->ctrl[0][i].xyz[1] =  b->mins[1];
01493       p->ctrl[0][i].xyz[2] = nStart;
01494 
01495         p->ctrl[1][i].xyz[0] =  b->maxs[0];
01496         p->ctrl[1][i].xyz[1] =  b->mins[1];
01497       p->ctrl[1][i].xyz[2] = nStart;
01498 
01499         p->ctrl[2][i].xyz[0] =  b->maxs[0];
01500         p->ctrl[2][i].xyz[1] =  b->maxs[1];
01501       p->ctrl[2][i].xyz[2] = nStart;
01502       nStart += nStep;
01503     }
01504   }
01505   else if (bEndcap & !bSquare)
01506   {
01507     p->type = PATCH_ENDCAP;
01508     p->width = 5;
01509     int nStep = (b->maxs[2] - b->mins[2]) / (p->height-1);
01510     int nStart = b->mins[2];
01511     for (i = 0; i < p->height; i++)
01512     {
01513         p->ctrl[0][i].xyz[0] =  b->mins[0];
01514         p->ctrl[0][i].xyz[1] =  b->mins[1];
01515       p->ctrl[0][i].xyz[2] = nStart;
01516 
01517         p->ctrl[1][i].xyz[0] =  b->mins[0];
01518         p->ctrl[1][i].xyz[1] =  b->maxs[1];
01519       p->ctrl[1][i].xyz[2] = nStart;
01520 
01521         p->ctrl[2][i].xyz[0] =  b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5);
01522         p->ctrl[2][i].xyz[1] =  b->maxs[1];
01523       p->ctrl[2][i].xyz[2] = nStart;
01524        
01525       p->ctrl[3][i].xyz[0] =  b->maxs[0];
01526         p->ctrl[3][i].xyz[1] =  b->maxs[1];
01527       p->ctrl[3][i].xyz[2] = nStart;
01528 
01529         p->ctrl[4][i].xyz[0] =  b->maxs[0];
01530         p->ctrl[4][i].xyz[1] =  b->mins[1];
01531       p->ctrl[4][i].xyz[2] = nStart;
01532       nStart += nStep;
01533     }
01534   }
01535   else
01536   {
01537     p->width = 9;
01538       p->ctrl[1][0].xyz[0] =  b->mins[0];
01539       p->ctrl[1][0].xyz[1] =  b->mins[1];
01540 
01541       p->ctrl[3][0].xyz[0] =  b->maxs[0];
01542       p->ctrl[3][0].xyz[1] =  b->mins[1];
01543 
01544       p->ctrl[5][0].xyz[0] =  b->maxs[0];
01545       p->ctrl[5][0].xyz[1] =  b->maxs[1];
01546 
01547       p->ctrl[7][0].xyz[0] =  b->mins[0];
01548       p->ctrl[7][0].xyz[1] =  b->maxs[1];
01549 
01550       for ( i = 1 ; i < p->width - 1 ; i += 2 ) 
01551     {
01552 
01553       p->ctrl[i][0].xyz[2] =  b->mins[2];
01554 
01555           VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz );
01556 
01557           p->ctrl[i][2].xyz[2] =  b->maxs[2];
01558 
01559           p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5;
01560           p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5;
01561           p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5;
01562       }
01563       InterpolateInteriorPoints( p );
01564 
01565     if (bSquare)
01566     {
01567       if (bBevel || bEndcap)
01568       {
01569         if (bBevel)
01570         {
01571           for (i = 0; i < p->height; i++)
01572           {
01573             VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
01574             VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
01575           }
01576         }
01577         else
01578         {
01579           for (i = 0; i < p->height; i++)
01580           {
01581             VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz);
01582             VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
01583             VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
01584             VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz);
01585           }
01586         }
01587       }
01588       else
01589       {
01590         for (i = 0; i < p->width-1; i ++)
01591         {
01592           for (j = 0; j < p->height; j++)
01593           {
01594             VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz);
01595           }
01596         }
01597         for (j = 0; j < p->height; j++)
01598         {
01599           VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz);
01600         }
01601       }
01602     }
01603   }
01604 
01605 
01606   Patch_Naturalize(p);
01607 
01608   if (bCone)
01609   {
01610     p->type = PATCH_CONE;
01611     float xc = (b->maxs[0] + b->mins[0]) * 0.5; 
01612     float yc = (b->maxs[1] + b->mins[1]) * 0.5; 
01613 
01614     for ( i = 0 ; i < p->width ; i ++)
01615     {
01616       p->ctrl[i][2].xyz[0] = xc;
01617       p->ctrl[i][2].xyz[1] = yc;
01618     }
01619   }
01620 /*
01621   if (bEndcap || bBevel)
01622   {
01623     if (bInverted)
01624     {
01625       for ( i = 0 ; i < p->height ; i ++)
01626       {
01627         if (bBevel)
01628         {
01629           VectorCopy(p->ctrl[7][i], p->ctrl[0][i]);
01630           VectorCopy(p->ctrl[7][i], p->ctrl[8][i]);
01631           VectorCopy(p->ctrl[3][i], p->ctrl[2][i]);
01632           VectorCopy(p->ctrl[5][i], p->ctrl[1][i]);
01633           VectorCopy(p->ctrl[5][i], p->ctrl[4][i]);
01634           VectorCopy(p->ctrl[5][i], p->ctrl[6][i]);
01635         }
01636         else
01637         {
01638           VectorCopy(p->ctrl[4][i], p->ctrl[8][i]);
01639           VectorCopy(p->ctrl[1][i], p->ctrl[0][i]);
01640           VectorCopy(p->ctrl[1][i], p->ctrl[10][i]);
01641           VectorCopy(p->ctrl[3][i], p->ctrl[2][i]);
01642           VectorCopy(p->ctrl[5][i], p->ctrl[4][i]);
01643           VectorCopy(p->ctrl[7][i], p->ctrl[6][i]);
01644           VectorCopy(p->ctrl[5][i], p->ctrl[7][i]);
01645           VectorCopy(p->ctrl[3][i], p->ctrl[9][i]);
01646         }
01647       }
01648     }
01649     else
01650     {
01651       for ( i = 0 ; i < p->height ; i ++)
01652       {
01653         VectorCopy(p->ctrl[1][i], p->ctrl[2][i]);
01654         VectorCopy(p->ctrl[7][i], p->ctrl[6][i]);
01655         if (bBevel)
01656         {
01657           VectorCopy(p->ctrl[5][i], p->ctrl[4][i]);
01658         }
01659       }
01660     }
01661   }
01662 */
01663   
01664   b = AddBrushForPatch(p);
01665 
01666 
01667 #if 1
01668     Select_Delete();
01669     Select_Brush(b);
01670 #else
01671   if (!bCone)
01672   {
01673     Select_Delete();
01674     Select_Brush(b);
01675     GenerateEndCaps(b, bBevel, bEndcap, bInverted);
01676     eclass_t *pecNew = Eclass_ForName("func_group", false);
01677     if (pecNew)
01678     {
01679       Entity_Create(pecNew);
01680     }
01681   }
01682   else
01683   {
01684     Select_Delete();
01685     Select_Brush(b);
01686   }
01687 #endif
01688 
01689 }
01690 
01691 /*
01692 ==================
01693 Patch_GenericMesh
01694 ==================
01695 */
01696 brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride)
01697 {
01698   int i,j;
01699 
01700   if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15)
01701   {
01702     Sys_Printf("Invalid patch width or height.\n");
01703     return NULL;
01704   }
01705 
01706     if (! bOverride && !QE_SingleBrush())
01707   {
01708     Sys_Printf("Cannot generate a patch from multiple selections.\n");
01709         return NULL;
01710   }
01711 
01712 
01713 
01714   patchMesh_t* p = MakeNewPatch();
01715     p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
01716 
01717     p->width = nWidth;
01718     p->height = nHeight;
01719   p->type = PATCH_GENERIC;
01720 
01721   int nFirst = 0;
01722   int nSecond = 1;
01723   if (nOrientation == 0)
01724   {
01725     nFirst = 1;
01726     nSecond = 2;
01727   }
01728   else if (nOrientation == 1)
01729   {
01730     nSecond = 2;
01731   }
01732 
01733     brush_t *b = selected_brushes.next;
01734 
01735   int xStep = b->mins[nFirst];
01736   float xAdj = abs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1));
01737   float yAdj = abs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1));
01738 
01739   for (i = 0; i < nWidth; i++)
01740   {
01741     int yStep = b->mins[nSecond];
01742     for (j = 0; j < nHeight; j++)
01743     {
01744       p->ctrl[i][j].xyz[nFirst] = xStep;
01745       p->ctrl[i][j].xyz[nSecond] = yStep;
01746       p->ctrl[i][j].xyz[nOrientation] = 0;
01747       yStep += yAdj;
01748     }
01749     xStep += xAdj;
01750   }
01751 
01752   Patch_Naturalize(p);
01753 
01754   b = AddBrushForPatch(p);
01755   if (bDeleteSource)
01756   {
01757     Select_Delete();
01758     Select_Brush(b);
01759   }
01760 
01761   return b;
01762   //g_qeglobals.d_select_mode = sel_curvepoint;
01763 }
01764 
01765 /*
01766 ==================
01767 PointInMoveList
01768 ==================
01769 */
01770 int PointInMoveList(float *pf)
01771 {
01772   for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
01773   {
01774     if (pf == &g_qeglobals.d_move_points[i][0])
01775       return i;
01776   }
01777   return -1;
01778 }
01779 
01780 /*
01781 ==================
01782 PointValueInMoveList
01783 ==================
01784 */
01785 int PointValueInMoveList(vec3_t v)
01786 {
01787   for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
01788   {
01789     if (VectorCompare(v, g_qeglobals.d_move_points[i]))
01790       return i;
01791   }
01792   return -1;
01793 }
01794 
01795 
01796 /*
01797 ==================
01798 RemovePointFromMoveList
01799 ==================
01800 */
01801 void RemovePointFromMoveList(vec3_t v)
01802 {
01803   int n;
01804   while ( (n = PointValueInMoveList(v)) >= 0)
01805   {
01806     for (int i = n; i < g_qeglobals.d_num_move_points-1; i++)
01807     {
01808       g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1];
01809     }
01810     g_qeglobals.d_num_move_points--;
01811   }
01812 }
01813 
01814 /*
01815 ==================
01816 ColumnSelected
01817 ==================
01818 */
01819 bool ColumnSelected(patchMesh_t* p, int nCol)
01820 {
01821   for (int i = 0; i < p->height; i++)
01822   {
01823     if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1)
01824       return false;
01825   }
01826   return true;
01827 }
01828 
01829 /*
01830 ==================
01831 AddPoint
01832 ==================
01833 */
01834 void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true)
01835 {
01836   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
01837   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
01838   g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v;
01839   if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill)
01840   {
01841       for ( int i = 0 ; i < p->width ; i++ ) 
01842     {
01843           for ( int j = 0 ; j < p->height ; j++ ) 
01844       {
01845         if (g_bPatchWeld)
01846         {
01847           if ( VectorCompare(v, p->ctrl[i][j].xyz)
01848             && PointInMoveList(p->ctrl[i][j].xyz) == -1)
01849           {
01850             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
01851             continue;
01852           }
01853         }
01854         if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA)
01855         {
01856           if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON) 
01857              &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON)) 
01858           {
01859             if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
01860             {
01861               g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
01862               continue;
01863             }
01864           }
01865 #if 0
01866           int l = 0;
01867             for ( int k = 0; k < 2; k++ )
01868           {
01869                 if (fabs(v[k] - p->ctrl[i][j].xyz[k]) > EQUAL_EPSILON)
01870               continue;
01871              l++;
01872           }
01873           if (l >= 2 && PointInMoveList(p->ctrl[i][j].xyz) == -1)
01874           {
01875             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
01876             continue;
01877           }
01878 #endif
01879         }
01880       }
01881     }
01882   }
01883 #if 0
01884   if (g_qeglobals.d_num_move_points == 1)
01885   {
01886     // single point selected
01887     // FIXME: the two loops can probably be reduced to one
01888       for ( int i = 0 ; i < p->width ; i++ ) 
01889     {
01890           for ( int j = 0 ; j < p->height ; j++ ) 
01891       {
01892         int n = PointInMoveList(v);
01893         if (n >= 0)
01894         {
01895           if (((i & 0x01) && (j & 0x01)) == 0)
01896           {
01897             // put any sibling fixed points
01898             // into the inverse list
01899             int p1, p2, p3, p4;
01900             p1 = i + 2;
01901             p2 = i - 2;
01902             p3 = j + 2;
01903             p4 = j - 2;
01904             if (p1 < p->width)
01905             {
01906 
01907             }
01908             if (p2 >= 0)
01909             {
01910             }
01911             if (p3 < p->height)
01912             {
01913             }
01914             if (p4 >= 0)
01915             {
01916             }
01917           }
01918         }
01919       }
01920     }
01921   }
01922 #endif
01923 }
01924 
01925 /*
01926 ==================
01927 SelectRow
01928 ==================
01929 */
01930 void SelectRow(patchMesh_t* p, int nRow, bool bMulti)
01931 {
01932   if (!bMulti)
01933     g_qeglobals.d_num_move_points = 0;
01934   for (int i = 0; i < p->width; i++)
01935   {
01936     AddPoint(p, p->ctrl[i][nRow].xyz, false);
01937   }
01938   //Sys_Printf("Selected Row %d\n", nRow);
01939 }
01940 
01941 /*
01942 ==================
01943 SelectColumn
01944 ==================
01945 */
01946 void SelectColumn(patchMesh_t* p, int nCol, bool bMulti)
01947 {
01948   if (!bMulti)
01949     g_qeglobals.d_num_move_points = 0;
01950   for (int i = 0; i < p->height; i++)
01951   {
01952     AddPoint(p, p->ctrl[nCol][i].xyz, false);
01953   }
01954   //Sys_Printf("Selected Col %d\n", nCol);
01955 }
01956 
01957 
01958 /*
01959 ==================
01960 AddPatchMovePoint
01961 ==================
01962 */
01963 void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull)
01964 {
01965   if (!g_bSameView && !bMulti && !bFull)
01966   {
01967     g_bSameView = true;
01968     return;
01969   }
01970 
01971     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
01972     {
01973     if (pb->patchBrush)
01974     {
01975         patchMesh_t* p = pb->pPatch;
01976         for ( int i = 0 ; i < p->width ; i++ ) 
01977       {
01978             for ( int j = 0 ; j < p->height ; j++ ) 
01979         {
01980           if (VectorCompare(v, p->ctrl[i][j].xyz))
01981           {
01982             if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
01983             {
01984               if (bFull)        // if we want the full row/col this is on
01985               {
01986                 SelectColumn(p, i, bMulti);
01987               }
01988               else
01989               {
01990                 if (!bMulti)
01991                   g_qeglobals.d_num_move_points = 0;
01992                 AddPoint(p, p->ctrl[i][j].xyz);
01993                 //Sys_Printf("Selected col:row %d:%d\n", i, j);
01994               }
01995               //--if (!bMulti)
01996               return;
01997             }
01998             else
01999             {
02000               if (bFull)
02001               {
02002                 if (ColumnSelected(p, i))
02003                 {
02004                   SelectRow(p, j, bMulti);
02005                 }
02006                 else
02007                 {
02008                   SelectColumn(p, i, bMulti);
02009                 }
02010                 return;
02011               }
02012               if (g_bSameView)
02013               {
02014                 RemovePointFromMoveList(v);
02015                 return;
02016               }
02017             }
02018           }
02019             }
02020         }
02021     }
02022   }
02023 }
02024 
02025 /*
02026 ==================
02027 Patch_UpdateSelected
02028 ==================
02029 */
02030 void Patch_UpdateSelected(vec3_t vMove)
02031 {
02032   int i, j;
02033   for (i=0 ; i < g_qeglobals.d_num_move_points ; i++)
02034   {
02035       VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]);
02036     if (g_qeglobals.d_num_move_points == 1)
02037     {
02038     }
02039   }
02040 
02041     //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch];
02042     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
02043     {
02044     if (pb->patchBrush)
02045     {
02046         patchMesh_t* p = pb->pPatch;
02047 
02048 
02049       g_qeglobals.d_numpoints = 0;
02050         for (i = 0 ; i < p->width ; i++ ) 
02051       {
02052             for ( j = 0 ; j < p->height ; j++ ) 
02053         {
02054             VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
02055           if (g_qeglobals.d_numpoints < MAX_POINTS-1)
02056           {
02057               g_qeglobals.d_numpoints++;
02058           }
02059             }
02060       }
02061         
02062       vec3_t vMin, vMax;
02063       Patch_CalcBounds(p, vMin, vMax);
02064       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
02065     }
02066   }
02067   //Brush_Free(p->pSymbiot);
02068   //Select_Brush(AddBrushForPatch(g_nSelectedPatch));
02069 }
02070 
02071 
02072 
02073 /*
02074 ===============
02075 SampleSinglePatch
02076 ===============
02077 */
02078 void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) {
02079     float   vCtrl[3][5];
02080     int     vPoint;
02081     int     axis;
02082 
02083     // find the control points for the v coordinate
02084     for (vPoint = 0 ; vPoint < 3 ; vPoint++) 
02085   {
02086         for (axis = 0 ; axis < 5 ; axis++) 
02087     {
02088             float   a, b, c;
02089             float   qA, qB, qC;
02090 
02091             a = ctrl[0][vPoint][axis];
02092             b = ctrl[1][vPoint][axis];
02093             c = ctrl[2][vPoint][axis];
02094             qA = a - 2 * b + c;
02095             qB = 2 * b - 2 * a;
02096             qC = a;
02097 
02098             vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
02099         }
02100     }
02101 
02102     // interpolate the v value
02103     for (axis = 0 ; axis < 5 ; axis++) 
02104   {
02105         float   a, b, c;
02106         float   qA, qB, qC;
02107 
02108         a = vCtrl[0][axis];
02109         b = vCtrl[1][axis];
02110         c = vCtrl[2][axis];
02111         qA = a - 2 * b + c;
02112         qB = 2 * b - 2 * a;
02113         qC = a;
02114 
02115         out[axis] = qA * v * v + qB * v + qC;
02116     }
02117 }
02118 
02119 /*
02120 ===================
02121 DrawSinglePatch
02122 ===================
02123 */
02124 void DrawSinglePatch (float ctrl[3][3][5], bool bPoints) 
02125 {
02126     int     i, j;
02127     float   u, v;
02128     float   verts[CBLOCK_SUBDIVISIONS+1][CBLOCK_SUBDIVISIONS+1][5];
02129 
02130     for (i = 0 ; i <= CBLOCK_SUBDIVISIONS ; i++) 
02131   {
02132         for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) 
02133     {
02134             u = (float)i / CBLOCK_SUBDIVISIONS;
02135             v = (float)j / CBLOCK_SUBDIVISIONS;
02136             SampleSinglePatch (ctrl, u, v, verts[i][j]);
02137         }
02138     }
02139   // at this point we have 
02140 
02141   int nCount = -1;
02142     for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++) 
02143   {
02144     qglBegin (GL_QUAD_STRIP);
02145 
02146         for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) 
02147     {
02148             qglTexCoord2fv( verts[i+1][j] + 3 );
02149             qglVertex3fv( verts[i+1][j] );
02150 /*
02151       if (nCount >= 0)
02152       {
02153         VectorCopy(verts[i+1][j], vNormals[nCount]);
02154       }
02155       nCount++;
02156       if (nCount == 3)
02157       {
02158         VectorSubtract(vNormals[0], vNormals[1], vNormals[0]);
02159         VectorSubtract(vNormals[1], vNormals[2], vNormals[1]);
02160         CrossProduct(vNormals[0], vNormals[1], vNormals[2]);
02161         //VectorNormalize(vNormals[2]);
02162         qglNormal3fv(vNormals[2]);
02163         nCount = -1;
02164       }
02165 */
02166       qglTexCoord2fv( verts[i][j] + 3 );
02167             qglVertex3fv( verts[i][j] );
02168 /*
02169       VectorCopy(verts[i][j], vNormals[nCount]);
02170       nCount++;
02171       if (nCount == 3)
02172       {
02173         VectorSubtract(vNormals[0], vNormals[1], vNormals[0]);
02174         VectorSubtract(vNormals[1], vNormals[2], vNormals[1]);
02175         CrossProduct(vNormals[0], vNormals[1], vNormals[2]);
02176         //VectorNormalize(vNormals[2]);
02177         qglNormal3fv(vNormals[2]);
02178         nCount = -1;
02179       }
02180 */
02181         }
02182       qglEnd ();
02183     }
02184 
02185 }
02186 
02187 /*
02188 =================
02189 DrawPatchMesh
02190 =================
02191 */
02192 //FIXME: this routine needs to be reorganized.. should be about 1/4 the size and complexity
02193 void DrawPatchMesh( patchMesh_t *pm, bool bPoints, bool bShade = false ) {
02194     int     i, j, k, l;
02195     float   ctrl[3][3][5];
02196 
02197   bool bOverlay = pm->bOverlay;
02198     int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
02199 
02200   //--float fColor[3];
02201   //--if (bShade)
02202   //--{
02203   //--  face_t *f = pm->pSymbiot->brush_faces;
02204   //--  _SetColor(f, fColor);
02205   //--}
02206   if (g_PrefsDlg.m_bDisplayLists)
02207   {
02208     if (pm->bDirty || pm->nListID <= 0)
02209     {
02210       if (pm->nListID <= 0)
02211         pm->nListID = qglGenLists(1);
02212       if (pm->nListID > 0)
02213       {
02214         qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE);
02215       }
02216       
02217 
02218 
02219       if (pm->type != PATCH_TRIANGLE)
02220       {
02221         //vec3_t *vMeshData = new vec3_t[pm->width * pm->height];
02222 
02223         // wasteful
02224         if (g_PrefsDlg.m_bGLLighting)
02225         {
02226           Patch_MeshNormals(pm);
02227           for (i = 0; i < pm->width; i++)
02228           {
02229             for (j = 0; j < pm->height; j++)
02230             {
02231               //VectorCopy(pm->ctrl[i][j].xyz, vMeshData[(j * pm->width) + i]);
02232               qglNormal3fv(pm->ctrl[i][j].normal);
02233             }
02234           }
02235         }
02236 
02237           for ( i = 0 ; i + 2 < pm->width ; i += 2 ) 
02238         {
02239               for ( j = 0 ; j + 2 < pm->height ; j += 2 ) 
02240           {
02241 
02242                   for ( k = 0 ; k < 3 ; k++ ) 
02243             {
02244               vec3_t vAvg;
02245               vAvg[0] = vAvg[1] = vAvg[2] = 0;
02246                       for ( l = 0 ; l < 3 ; l++ ) 
02247               {
02248                           ctrl[k][l][0] = pm->ctrl[ i + k ][ j + l ].xyz[ 0 ];
02249                           ctrl[k][l][1] = pm->ctrl[ i + k ][ j + l ].xyz[ 1 ];
02250                           ctrl[k][l][2] = pm->ctrl[ i + k ][ j + l ].xyz[ 2 ];
02251                           ctrl[k][l][3] = pm->ctrl[ i + k ][ j + l ].xyz[ 3 ];
02252                           ctrl[k][l][4] = pm->ctrl[ i + k ][ j + l ].xyz[ 4 ];
02253 
02254                 if (g_PrefsDlg.m_bGLLighting)
02255                 {
02256                   qglNormal3fv(pm->ctrl[i+k][j+l].normal);
02257                 }
02258                       }
02259 
02260                   }
02261 
02262 //--            if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture)
02263 //--            {
02264 //--              VectorCopy(pm->ctrl[i][j].normal, plane.normal);
02265 //--              float shade = SetShadeForPlane(&plane);
02266 //--              qtexture_t *q = pm->d_texture;
02267 //--              vec3_t vColor;
02268 //--
02269 //--              vColor[0] = shade;// * q->color[0];
02270 //--              vColor[1] = shade;// * q->color[1];
02271 //--              vColor[2] = shade;// * q->color[2];
02272 //--              qglColor3fv(vColor);
02273 //--            }
02274 
02275             
02276 //--            if (g_PrefsDlg.m_bGLLighting)
02277 //--            {
02278 //--              //qglNormal3fv(pm->ctrl[i][j].normal);
02279 //--            }
02280             DrawSinglePatch( ctrl, bPoints );
02281           }
02282         }
02283 
02284         // we have an array of clean control points
02285         //
02286         /*
02287         qglMap2f(GL_MAP2_NORMAL, 0, 1, 3, 3, 0, 1, 9, 3, (float*)&vMeshData);
02288         for (i = 0; i < pm->width; i++)
02289         {
02290           for (j = 0; j < pm->height; j++)
02291           {
02292             qglEvalPoint2(i, j);
02293           }
02294         }
02295 
02296         delete []vMeshData;
02297         */
02298       }
02299       else
02300       {
02301         qglBegin (GL_TRIANGLES);
02302         qglTexCoord2fv( pm->ctrl[0][0].st);
02303               qglVertex3fv( pm->ctrl[0][0].xyz);
02304               qglTexCoord2fv( pm->ctrl[2][0].st);
02305               qglVertex3fv( pm->ctrl[2][0].xyz);
02306               qglTexCoord2fv( pm->ctrl[2][2].st);
02307               qglVertex3fv( pm->ctrl[2][2].xyz);
02308         qglEnd();
02309       }
02310 
02311       if (pm->nListID > 0)
02312       {
02313         qglEndList();
02314         pm->bDirty = false;
02315       }
02316     }
02317     else
02318     {
02319       qglCallList(pm->nListID);
02320     }
02321   }
02322   else
02323   {
02324       for ( i = 0 ; i + 2 < pm->width ; i += 2 ) 
02325     {
02326           for ( j = 0 ; j + 2 < pm->height ; j += 2 ) 
02327       {
02328               for ( k = 0 ; k < 3 ; k++ ) 
02329         {
02330                   for ( l = 0 ; l < 3 ; l++ ) 
02331           {
02332                       ctrl[k][l][0] = pm->ctrl[ i + k ][ j + l ].xyz[ 0 ];
02333                       ctrl[k][l][1] = pm->ctrl[ i + k ][ j + l ].xyz[ 1 ];
02334                       ctrl[k][l][2] = pm->ctrl[ i + k ][ j + l ].xyz[ 2 ];
02335                       ctrl[k][l][3] = pm->ctrl[ i + k ][ j + l ].xyz[ 3 ];
02336                       ctrl[k][l][4] = pm->ctrl[ i + k ][ j + l ].xyz[ 4 ];
02337                   }
02338               }
02339         //--if (bShade)
02340         //--{
02341         //--  _DecColor(fColor);
02342         //--}
02343               DrawSinglePatch( ctrl, bPoints );
02344       }
02345     }
02346   }
02347 
02348   vec3_t* pSelectedPoints[256];
02349   int nIndex = 0;
02350 
02351   qglPushAttrib(GL_CURRENT_BIT);
02352   //--qglDisable(GL_BLEND);
02353   //--qglDisable (GL_DEPTH_TEST);
02354   //qglDisable (GL_TEXTURE_2D);
02355 
02356   bool bDisabledLighting = qglIsEnabled(GL_LIGHTING);
02357   if (bDisabledLighting)
02358   {
02359     qglDisable(GL_LIGHTING);
02360   }
02361 
02362 
02363   // FIXME: this bend painting code needs to be rolled up significantly as it is a cluster fuck right now
02364   if (bPoints && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area || g_bPatchBendMode || g_bPatchInsertMode))
02365   {
02366     bOverlay = false;
02367 
02368     // bending or inserting
02369     if (g_bPatchBendMode || g_bPatchInsertMode)
02370     {
02371       qglPointSize(6);
02372       if (g_bPatchAxisOnRow)
02373       {
02374         qglColor3f(1, 0, 1);
02375         qglBegin(GL_POINTS);
02376         for (i = 0; i < pm->width; i++)
02377         {
02378                 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex].xyz));
02379         }
02380         qglEnd();
02381       
02382         // could do all of this in one loop but it was pretty messy
02383         if (g_bPatchInsertMode)
02384         {
02385           qglColor3f(0, 0, 1);
02386           qglBegin(GL_POINTS);
02387           for (i = 0; i < pm->width; i++)
02388           {
02389                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex].xyz));
02390                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex+1].xyz));
02391           }
02392           qglEnd();
02393         }
02394         else
02395         {
02396           if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
02397           {
02398             qglColor3f(0, 0, 1);
02399             qglBegin(GL_POINTS);
02400             if (g_nPatchBendState == BEND_SELECT_ORIGIN)
02401             {
02402               qglVertex3fv(g_vBendOrigin);
02403             }
02404             else
02405             {
02406               for (i = 0; i < pm->width; i++)
02407               {
02408                 if (g_bPatchLowerEdge)
02409                 {
02410                   for (j = 0; j < g_nPatchAxisIndex; j++)
02411                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][j].xyz));
02412                 }
02413                 else
02414                 {
02415                   for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
02416                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][j].xyz));
02417                 }
02418               }
02419             }
02420             qglEnd();
02421           }
02422         }
02423       }
02424       else
02425       {
02426         qglColor3f(1, 0, 1);
02427         qglBegin(GL_POINTS);
02428         for (i = 0; i < pm->height; i++)
02429         {
02430                 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex][i].xyz));
02431         }
02432         qglEnd();
02433         
02434         // could do all of this in one loop but it was pretty messy
02435         if (g_bPatchInsertMode)
02436         {
02437           qglColor3f(0, 0, 1);
02438           qglBegin(GL_POINTS);
02439           for (i = 0; i < pm->height; i++)
02440           {
02441                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex][i].xyz));
02442                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex+1][i].xyz));
02443           }
02444           qglEnd();
02445         }
02446         else
02447         {
02448           if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
02449           {
02450             qglColor3f(0, 0, 1);
02451             qglBegin(GL_POINTS);
02452             for (i = 0; i < pm->height; i++)
02453             {
02454               if (g_nPatchBendState == BEND_SELECT_ORIGIN)
02455               {
02456                 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nBendOriginIndex][i].xyz));
02457               }
02458               else
02459               {
02460                 if (g_bPatchLowerEdge)
02461                 {
02462                   for (j = 0; j < g_nPatchAxisIndex; j++)
02463                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[j][i].xyz));
02464                 }
02465                 else
02466                 {
02467                   for (j = pm->width-1; j > g_nPatchAxisIndex; j--)
02468                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[j][i].xyz));
02469                 }
02470               }
02471             }
02472             qglEnd();
02473           }
02474         }
02475       }
02476     }
02477     else // just painting the grid for selection
02478     {
02479       qglPointSize(6);
02480         for ( i = 0 ; i < pm->width ; i++ )
02481       {
02482             for ( j = 0 ; j < pm->height ; j++ ) 
02483         {
02484             qglBegin(GL_POINTS);
02485           // FIXME: need to not do loop lookups inside here
02486           int n = PointValueInMoveList(pm->ctrl[i][j].xyz);
02487           if (n >= 0)
02488           {
02489             pSelectedPoints[nIndex++] = reinterpret_cast<float(*)[3]>(&pm->ctrl[i][j].xyz);
02490           }
02491 
02492           if (i & 0x01 || j & 0x01)
02493             qglColor3f(1, 0, 1);
02494           else
02495             qglColor3f(0, 1, 0);
02496                 qglVertex3fv(pm->ctrl[i][j].xyz);
02497             qglEnd();
02498         }
02499       }
02500     }
02501     if (nIndex > 0)
02502     {
02503       qglBegin(GL_POINTS);
02504       qglColor3f(0, 0, 1);
02505       while (nIndex-- > 0)
02506       {
02507               qglVertex3fv(*pSelectedPoints[nIndex]);
02508       }
02509       qglEnd();
02510     }
02511   }
02512 
02513   if (bOverlay)
02514   {
02515     qglPointSize(6);
02516     qglColor3f(0.5, 0.5, 0.5);
02517       for ( i = 0 ; i < pm->width ; i++ )
02518     {
02519       qglBegin(GL_POINTS);
02520           for ( j = 0 ; j < pm->height ; j++ ) 
02521       {
02522               if (i & 0x01 || j & 0x01)
02523           qglColor3f(0.5, 0, 0.5);
02524         else
02525           qglColor3f(0, 0.5, 0);
02526         qglVertex3fv(pm->ctrl[i][j].xyz);
02527       }
02528       qglEnd();
02529     }
02530   }
02531     //--qglEnable (GL_TEXTURE_2D);
02532     //--qglEnable (GL_DEPTH_TEST);
02533 
02534   if (bDisabledLighting)
02535   {
02536     qglEnable(GL_LIGHTING);
02537   }
02538 
02539     qglPopAttrib();
02540 
02541 }
02542 
02543 /*
02544 ==================
02545 Patch_DrawXY
02546 ==================
02547 */
02548 void Patch_DrawXY(patchMesh_t *pm)
02549 {
02550     qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02551   if (pm->bSelected)
02552   {
02553     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
02554     //qglDisable (GL_LINE_STIPPLE);
02555       //qglLineWidth (1);
02556   }
02557   else
02558     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]);
02559 
02560     DrawPatchMesh( pm , pm->bSelected );
02561     qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
02562   if (pm->bSelected)
02563   {
02564       //qglLineWidth (2);
02565     //qglEnable (GL_LINE_STIPPLE);
02566   }
02567 }
02568 
02569 /*
02570 ==================
02571 Patch_DrawCam
02572 ==================
02573 */
02574 void Patch_DrawCam(patchMesh_t *pm)
02575 {
02576     qglColor3f (1,1,1);
02577   qglPushAttrib(GL_ALL_ATTRIB_BITS);
02578 
02579   if (g_bPatchWireFrame)
02580   {
02581       qglDisable( GL_CULL_FACE );
02582       qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02583       qglDisable(GL_TEXTURE_2D);
02584     if (g_PrefsDlg.m_bGLLighting)
02585     {
02586       qglDisable(GL_LIGHTING);
02587     }
02588       DrawPatchMesh( pm , pm->bSelected, true );
02589     if (g_PrefsDlg.m_bGLLighting)
02590     {
02591       qglEnable(GL_LIGHTING);
02592     }
02593       qglEnable( GL_CULL_FACE );
02594   }
02595   else
02596   {
02597     if (g_PrefsDlg.m_bGLLighting)
02598     {
02599       //qglEnable(GL_NORMALIZE);
02600     }
02601       qglEnable( GL_CULL_FACE );
02602     qglCullFace(GL_FRONT);
02603     qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number);
02604 
02605     if (pm->d_texture->bFromShader && pm->d_texture->fTrans < 1.0)
02606     {
02607         //qglEnable ( GL_BLEND );
02608         //qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
02609       qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->d_texture->fTrans); 
02610     }
02611     DrawPatchMesh( pm , pm->bSelected, true );
02612     
02613     qglCullFace(GL_BACK);
02614       //qglDisable(GL_TEXTURE_2D);
02615       qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02616 
02617     qglDisable ( GL_BLEND );
02618       DrawPatchMesh( pm , pm->bSelected, true );
02619   }
02620 
02621 #if 0 // this paints normal indicators on the ctrl points
02622       //--qglDisable (GL_DEPTH_TEST);
02623       qglDisable (GL_TEXTURE_2D);
02624       qglColor3f (1,1,1);
02625 
02626       for (int i = 0; i < pm->width; i++)
02627       {
02628         for (int j = 0; j < pm->height; j++)
02629         {
02630           vec3_t temp;
02631             qglBegin (GL_LINES);
02632               qglVertex3fv (pm->ctrl[i][j].xyz);
02633               VectorMA (pm->ctrl[i][j].xyz, 8, pm->ctrl[i][j].normal, temp);
02634               qglVertex3fv (temp);
02635             qglEnd ();
02636         }
02637       }
02638       qglEnable (GL_TEXTURE_2D);
02639       //--qglEnable (GL_DEPTH_TEST);
02640 #endif
02641 
02642 
02643   qglPopAttrib();
02644 }
02645 
02646 
02647 
02648 
02649 void ConvexHullForSection( float section[2][4][7] ) {
02650 }
02651 
02652 void BrushesForSection( float section[2][4][7] ) {
02653 }
02654 
02655 //
02656 //================
02657 //Patch_BuildPoints
02658 //================
02659 void Patch_BuildPoints (brush_t *b) 
02660 {
02661     face_t      *f;
02662     b->patchBrush = false;
02663     for (f=b->brush_faces ; f ; f=f->next) 
02664   {
02665         if (f->texdef.flags & SURF_PATCH) 
02666     {
02667             b->patchBrush = true;
02668       //vec3_t vMin, vMax;
02669       //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax);
02670       //VectorCopy(vMin, b->mins);
02671       //VectorCopy(vMax, b->maxs);
02672             break;
02673         }
02674     }
02675 }
02676 
02677 
02678 
02679 //
02680 //===============
02681 //Patch_WriteFile
02682 //===============
02683 //
02684 #if 0
02685 void Patch_WriteFile (char *name) 
02686 {
02687     char patchName[1024];
02688   time_t ltime;
02689     strcpy(patchName, name);
02690     StripExtension (patchName);
02691     strcat (patchName, ".patch");
02692 
02693   FILE *file = fopen(patchName, "w");
02694   if (file)
02695   {
02696       time(&ltime);
02697       fprintf (file, "// %s saved on %s\n", name, ctime(&ltime) );
02698 
02699     for (int i = 0; i < numPatchMeshes; i++)
02700     {
02701           fprintf(file, "{\n");
02702       fprintf(file, " %s\n", patchMeshes[i].d_texture->name);
02703       fprintf(file, " ( %i %i %i ) \n", patchMeshes[i].width, patchMeshes[i].height, patchMeshes[i].negative);
02704       for (int w = 0; w < patchMeshes[i].width; w++)
02705       {
02706         for (int h = 0; h < patchMeshes[i].height; h++)
02707         {
02708           fprintf(file, " ( ");
02709           for (int k = 0; k < 5; k++)
02710           {
02711             float f = patchMeshes[i].ctrl[w][h][k];
02712             if (f == int(f))
02713               fprintf(file, "%i ", (int)f);
02714             else
02715               fprintf(file, "%f ", f);
02716           }
02717           fprintf(file, ")\n");
02718         }
02719       }
02720       fprintf(file, "}\n");
02721     }
02722     fclose(file);
02723   }
02724 }
02725 #endif
02726 
02727 /*
02728 ==================
02729 Patch_Move
02730 ==================
02731 */
02732 void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild)
02733 {
02734   pm->bDirty = true;
02735   for (int w = 0; w < pm->width; w++)
02736   {
02737     for (int h = 0; h < pm->height; h++)
02738     {
02739       VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz);
02740     }
02741   }
02742   if (bRebuild)
02743   {
02744     vec3_t vMin, vMax;
02745     Patch_CalcBounds(pm, vMin, vMax);
02746     //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax);
02747   }
02748   UpdatePatchInspector();
02749 
02750 }
02751 
02752 /*
02753 ==================
02754 Patch_ApplyMatrix
02755 ==================
02756 */
02757 void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap)
02758 {
02759   vec3_t vTemp;
02760 
02761   for (int w = 0; w < p->width; w++)
02762   {
02763     for (int h = 0; h < p->height; h++)
02764     {
02765       if ( (g_qeglobals.d_select_mode == sel_curvepoint || g_bPatchBendMode)
02766         && PointInMoveList(p->ctrl[w][h].xyz) == -1)
02767         continue;
02768             VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp);
02769             for (int j = 0; j < 3; j++)
02770       {
02771         p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j];
02772         if (bSnap)
02773         {
02774           p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5);
02775         }
02776       }
02777     }
02778   }
02779   vec3_t vMin, vMax;
02780   Patch_CalcBounds(p, vMin, vMax);
02781   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
02782 }
02783 
02784 /*
02785 ==================
02786 Patch_EditPatch
02787 ==================
02788 */
02789 void Patch_EditPatch()
02790 {
02791   //--patchMesh_t* p = &patchMeshes[n];
02792   g_qeglobals.d_numpoints = 0;
02793   g_qeglobals.d_num_move_points = 0;
02794     
02795   for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
02796     {
02797     if (pb->patchBrush)
02798     {
02799         patchMesh_t* p = pb->pPatch;
02800         for ( int i = 0 ; i < p->width ; i++ ) 
02801       {
02802             for ( int j = 0 ; j < p->height ; j++ ) 
02803         {
02804             VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
02805           if (g_qeglobals.d_numpoints < MAX_POINTS-1)
02806           {
02807               g_qeglobals.d_numpoints++;
02808           }
02809             }
02810       }
02811     }
02812   }
02813   g_qeglobals.d_select_mode = sel_curvepoint;
02814   //--g_nSelectedPatch = n;
02815 }
02816 
02817 
02818 
02819 /*
02820 ==================
02821 Patch_Deselect
02822 ==================
02823 */
02824 //FIXME: need all sorts of asserts throughout a lot of this crap
02825 void Patch_Deselect()
02826 {
02827   //--g_nSelectedPatch = -1;
02828     clearSelection();
02829 
02830     for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
02831   {
02832     if (b->patchBrush)
02833     {
02834       b->pPatch->bSelected = false;
02835     }
02836   }
02837 
02838   //for (int i = 0; i < numPatchMeshes; i++)
02839   //  patchMeshes[i].bSelected = false;
02840 
02841   if (g_bPatchBendMode)
02842     Patch_BendToggle();
02843   if (g_bPatchInsertMode)
02844     Patch_InsDelToggle();
02845 }
02846 
02847 
02848 /*
02849 ==================
02850 Patch_Select
02851 ==================
02852 */
02853 void Patch_Select(patchMesh_t *p)
02854 {
02855   // maintained for point manip.. which i need to fix as this 
02856   // is pf error prone
02857   //--g_nSelectedPatch = n;
02858   p->bSelected = true;
02859 }
02860 
02861 
02862 /*
02863 ==================
02864 Patch_Deselect
02865 ==================
02866 */
02867 void Patch_Deselect(patchMesh_t *p)
02868 {
02869   p->bSelected = false;
02870 }
02871 
02872 
02873 /*
02874 ==================
02875 Patch_Delete
02876 ==================
02877 */
02878 void Patch_Delete(patchMesh_t *p)
02879 {
02880   p->pSymbiot->pPatch = NULL;
02881   p->pSymbiot->patchBrush = false;
02882   if (g_qeglobals.bSurfacePropertiesPlugin)
02883   {
02884 #ifdef _DEBUG
02885         if (!p->pData)
02886             Sys_Printf("WARNING: unexpected IPluginTexdef* is NULL in Patch_Delete\n");
02887         else
02888 #endif
02889         {
02890             GETPLUGINTEXDEF(p)->DecRef();
02891             p->pData = NULL;
02892         }
02893   }
02894   free(p);
02895   p = NULL;
02896 
02897   // bump the array down
02898   //for (int i = n; i < numPatchMeshes; i++)
02899   //{
02900   //  patchMeshes[i].pSymbiot->nPatchID--;
02901   //  patchMeshes[i] = patchMeshes[i+1];
02902   //}
02903   //numPatchMeshes--;
02904   UpdatePatchInspector();
02905 }
02906 
02907 
02908 /*
02909 ==================
02910 Patch_Scale
02911 ==================
02912 */
02913 void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild)
02914 {
02915 
02916   for (int w = 0; w < p->width; w++)
02917   {
02918     for (int h = 0; h < p->height; h++)
02919     {
02920       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
02921         continue;
02922             for (int i=0 ; i<3 ; i++)
02923             {
02924         p->ctrl[w][h].xyz[i] -= vOrigin[i];
02925         p->ctrl[w][h].xyz[i] *= vAmt[i];
02926         p->ctrl[w][h].xyz[i] += vOrigin[i];
02927       }
02928     }
02929   }
02930   if (bRebuild)
02931   {
02932     vec3_t vMin, vMax;
02933     Patch_CalcBounds(p, vMin, vMax);
02934     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
02935   }
02936   UpdatePatchInspector();
02937 }
02938 
02939 
02940 /*
02941 ==================
02942 Patch_Cleanup
02943 ==================
02944 */
02945 void Patch_Cleanup()
02946 {
02947   //--g_nSelectedPatch = -1;
02948   //numPatchMeshes = 0;
02949 }
02950 
02951 
02952 
02953 /*
02954 ==================
02955 Patch_SetView
02956 ==================
02957 */
02958 void Patch_SetView(int n)
02959 {
02960   g_bSameView = (n == g_nPatchClickedView);
02961   g_nPatchClickedView = n;
02962 }
02963 
02964 
02965 /*
02966 ==================
02967 Patch_SetTexture
02968 ==================
02969 */
02970 // FIXME: need array validation throughout
02971 void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef)
02972 {
02973   p->d_texture = Texture_ForName(tex_def->name);
02974   if (g_qeglobals.bSurfacePropertiesPlugin)
02975   {
02976 #ifdef _DEBUG
02977       if (!p->pData)
02978           Sys_Printf("WARNING: unexpected p->pData is NULL in Patch_SetTexture\n");
02979       else
02980 #endif
02981           GETPLUGINTEXDEF(p)->DecRef();
02982       if (pPlugTexdef)
02983       {
02984         p->pData = pPlugTexdef->Copy();
02985         GETPLUGINTEXDEF(p)->Hook(p);
02986       }
02987       else
02988       {
02989           g_SurfaceTable.m_pfnPatchAlloc( p );
02990           GETPLUGINTEXDEF(p)->SetDefaultTexdef();
02991       }   
02992   }
02993   UpdatePatchInspector();
02994 }
02995 
02996 
02997 /*
02998 ==================
02999 Patch_DragScale
03000 ==================
03001 */
03002 bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove)
03003 {
03004   vec3_t vMin, vMax, vScale, vTemp, vMid;
03005   int i;
03006 
03007   Patch_CalcBounds(p, vMin, vMax);
03008 
03009   VectorSubtract(vMax, vMin, vTemp);
03010 
03011   // if we are scaling in the same dimension the patch has no depth
03012   for (i = 0; i < 3; i ++)
03013   {
03014     if (vTemp[i] == 0 && vMove[i] != 0)
03015     {
03016       //Patch_Move(n, vMove, true);
03017       return false;
03018     }
03019   }
03020   
03021   for (i=0 ; i<3 ; i++)
03022     vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2));
03023 
03024   for (i = 0; i < 3; i++)
03025   {
03026     if (vAmt[i] != 0)
03027     {
03028       vScale[i] = 1.0 + vAmt[i] / vTemp[i];
03029     }
03030     else
03031     {
03032       vScale[i] = 1.0;
03033     }
03034   }
03035 
03036   Patch_Scale(p, vMid, vScale, false);
03037 
03038   VectorSubtract(vMax, vMin, vTemp);
03039 
03040   Patch_CalcBounds(p, vMin, vMax);
03041   
03042   VectorSubtract(vMax, vMin, vMid);
03043 
03044   VectorSubtract(vMid, vTemp, vTemp);
03045 
03046   VectorScale(vTemp, 0.5, vTemp);
03047 
03048   // abs of both should always be equal
03049   if (!VectorCompare(vMove, vAmt))
03050   {
03051     for (i = 0; i < 3; i++)
03052     {
03053       if (vMove[i] != vAmt[i])
03054         vTemp[i] = -(vTemp[i]);
03055     }
03056   }
03057 
03058   Patch_Move(p, vTemp);
03059   return true;
03060 }
03061 
03062 
03063 /*
03064 ==================
03065 Patch_AddRow
03066 ==================
03067 */
03068 void Patch_AddRow(patchMesh_t *p)
03069 {
03070   vec3_t vMin, vMax, vTemp;
03071   int i, j;
03072 
03073 
03074   if (p->height+2 < MAX_PATCH_HEIGHT)
03075   {
03076     Patch_CalcBounds(p, vMin, vMax);
03077     VectorSubtract(vMax, vMin, vTemp);
03078     for (i = 0; i < 3; i++)
03079     {
03080       vTemp[i] /= p->height + 2;
03081     }
03082 
03083     for (j = 0; j < p->width; j++)
03084     {
03085       VectorCopy(p->ctrl[j][p->height].xyz, p->ctrl[j][p->height+1].xyz);
03086       VectorCopy(p->ctrl[j][p->height].xyz, p->ctrl[j][p->height+2].xyz);
03087       p->height += 2;
03088       i = 1;
03089       while (i < p->height)
03090       {
03091         VectorAdd(p->ctrl[j][i].xyz, vTemp, p->ctrl[j][i].xyz);
03092         i++;
03093       }
03094     }
03095     
03096     Patch_CalcBounds(p, vMin, vMax);
03097     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
03098   }
03099   UpdatePatchInspector();
03100 }
03101 
03102 /*
03103 ==================
03104 Patch_InsertColumn
03105 ==================
03106 */
03107 void Patch_InsertColumn(patchMesh_t *p, bool bAdd)
03108 {
03109   int h, w, i, j;
03110   vec3_t vTemp;
03111   
03112   if (p->width + 2 >= MAX_PATCH_WIDTH)
03113     return;
03114 
03115   if (bAdd) // add column?
03116   {
03117     for (h = 0; h < p->height; h++)
03118     {
03119       j = p->width-1;
03120       VectorSubtract(p->ctrl[j][h].xyz, p->ctrl[j-1][h].xyz, vTemp);
03121       for (i = 0; i < 3; i++)
03122         vTemp[i] /= 3;
03123 
03124       memcpy(&p->ctrl[j+2][h],&p->ctrl[j][h], sizeof(drawVert_t));
03125       memcpy(&p->ctrl[j][h],&p->ctrl[j-1][h], sizeof(drawVert_t));
03126 
03127       VectorAdd(p->ctrl[j][h].xyz, vTemp, p->ctrl[j][h].xyz);
03128       memcpy(&p->ctrl[j+1][h], &p->ctrl[j][h], sizeof(drawVert_t));
03129       VectorAdd(p->ctrl[j+1][h].xyz, vTemp, p->ctrl[j+1][h].xyz);
03130     }
03131   }
03132   else
03133   {
03134     for (h = 0; h < p->height; h++)
03135     {
03136       w = p->width-1;
03137       while (w >= 0)
03138       {
03139         memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t));
03140         w--;
03141       }
03142       VectorSubtract(p->ctrl[1][h].xyz, p->ctrl[0][h].xyz, vTemp);
03143       for (i = 0; i < 3; i++)
03144         vTemp[i] /= 3;
03145       VectorCopy(p->ctrl[0][h].xyz, p->ctrl[1][h].xyz);
03146       VectorAdd(p->ctrl[1][h].xyz, vTemp, p->ctrl[1][h].xyz);
03147       VectorCopy(p->ctrl[1][h].xyz, p->ctrl[2][h].xyz);
03148       VectorAdd(p->ctrl[2][h].xyz, vTemp, p->ctrl[2][h].xyz);
03149     }
03150   }
03151   p->width += 2;
03152   UpdatePatchInspector();
03153 }
03154 
03155 
03156 /*
03157 ==================
03158 Patch_InsertRow
03159 ==================
03160 */
03161 void Patch_InsertRow(patchMesh_t *p, bool bAdd)
03162 {
03163   int h, w, i, j;
03164   vec3_t vTemp;
03165   
03166   if (p->height + 2 >= MAX_PATCH_HEIGHT)
03167     return;
03168 
03169   if (bAdd) // add column?
03170   {
03171     for (w = 0; w < p->width; w++)
03172     {
03173       j = p->height-1;
03174       VectorSubtract(p->ctrl[w][j].xyz, p->ctrl[w][j-1].xyz, vTemp);
03175       for (i = 0; i < 3; i++)
03176         vTemp[i] /= 3;
03177 
03178       memcpy(&p->ctrl[w][j+2],&p->ctrl[w][j], sizeof(drawVert_t));
03179       memcpy(&p->ctrl[w][j],&p->ctrl[w][j-1], sizeof(drawVert_t));
03180 
03181       VectorAdd(p->ctrl[w][j].xyz, vTemp, p->ctrl[w][j].xyz);
03182       memcpy(&p->ctrl[w][j+1], &p->ctrl[w][j], sizeof(drawVert_t));
03183       VectorAdd(p->ctrl[w][j+1].xyz, vTemp, p->ctrl[w][j+1].xyz);
03184     }
03185   }
03186   else
03187   {
03188     for (w = 0; w < p->width; w++)
03189     {
03190       h = p->height-1;
03191       while (h >= 0)
03192       {
03193         memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t));
03194         h--;
03195       }
03196       VectorSubtract(p->ctrl[w][1].xyz, p->ctrl[w][0].xyz, vTemp);
03197       for (i = 0; i < 3; i++)
03198         vTemp[i] /= 3;
03199       VectorCopy(p->ctrl[w][0].xyz, p->ctrl[w][1].xyz);
03200       VectorAdd(p->ctrl[w][1].xyz, vTemp, p->ctrl[w][1].xyz);
03201       VectorCopy(p->ctrl[w][1].xyz, p->ctrl[w][2].xyz);
03202       VectorAdd(p->ctrl[w][2].xyz, vTemp, p->ctrl[w][2].xyz);
03203     }
03204   }
03205   p->height += 2;
03206   UpdatePatchInspector();
03207 }
03208 
03209 
03210 /*
03211 ==================
03212 Patch_RemoveRow
03213 ==================
03214 */
03215 void Patch_RemoveRow(patchMesh_t *p, bool bFirst)
03216 {
03217   
03218   if (p->height <= MIN_PATCH_HEIGHT)
03219     return;
03220 
03221   p->height -= 2;
03222 
03223   if (bFirst)
03224   {
03225     for (int w = 0; w < p->width; w++)
03226     {
03227       for (int h = 0; h < p->height; h++)
03228       {
03229         memcpy(&p->ctrl[w][h], &p->ctrl[w][h+2], sizeof(drawVert_t));
03230       }
03231     }
03232   }
03233   UpdatePatchInspector();
03234 }
03235 
03236 
03237 /*
03238 ==================
03239 Patch_RemoveColumn
03240 ==================
03241 */
03242 void Patch_RemoveColumn(patchMesh_t *p, bool bFirst)
03243 {
03244   
03245   if (p->width <= MIN_PATCH_WIDTH)
03246     return;
03247 
03248   p->width -= 2;
03249 
03250   if (bFirst)
03251   {
03252     for (int h = 0; h < p->height; h++)
03253     {
03254       for (int w = 0; w < p->width; w++)
03255       {
03256         memcpy(&p->ctrl[w][h], &p->ctrl[w+2][h], sizeof(drawVert_t));
03257       }
03258     }
03259   }
03260   UpdatePatchInspector();
03261 }
03262 
03263 
03264 /*
03265 ==================
03266 Patch_AdjustColumns
03267 ==================
03268 */
03269 void Patch_AdjustColumns(patchMesh_t *p, int nCols)
03270 {
03271   vec3_t vTemp, vTemp2;
03272   int i, w, h;
03273 
03274   if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH)
03275     return;
03276 
03277   // add in column adjustment
03278   p->width += nCols;
03279 
03280   for (h = 0; h < p->height; h++)
03281   {
03282     // for each column, we need to evenly disperse p->width number 
03283     // of points across the old bounds
03284     
03285     // calc total distance to interpolate 
03286     VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp);
03287 
03288     // amount per cycle
03289     for (i = 0; i < 3; i ++)
03290     {
03291       vTemp2[i] = vTemp[i] / (p->width - 1);
03292     }
03293 
03294     // move along
03295     for (w = 0; w < p->width-1; w++)
03296     {
03297       VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
03298     }
03299 
03300   }
03301     for ( w = 0 ; w < p->width ; w++ ) 
03302   {
03303         for ( h = 0 ; h < p->height ; h++ ) 
03304     {
03305             p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
03306             p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
03307         }
03308     }
03309   UpdatePatchInspector();
03310 }
03311 
03312 
03313 /*
03314 ==================
03315 Patch_AdjustRows
03316 ==================
03317 */
03318 void Patch_AdjustRows(patchMesh_t *p, int nRows)
03319 {
03320   vec3_t vTemp, vTemp2;
03321   int i, w, h;
03322 
03323   if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT)
03324     return;
03325 
03326   // add in column adjustment
03327   p->height += nRows;
03328 
03329   for (w = 0; w < p->width; w++)
03330   {
03331     // for each row, we need to evenly disperse p->height number 
03332     // of points across the old bounds
03333 
03334     // calc total distance to interpolate 
03335     VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp);
03336     
03337     //vTemp[0] = vTemp[1] = vTemp[2] = 0;
03338     //for (h = 0; h < p->height - nRows; h ++)
03339     //{
03340     //  VectorAdd(vTemp, p->ctrl[w][h], vTemp);
03341     //}
03342 
03343     // amount per cycle
03344     for (i = 0; i < 3; i ++)
03345     {
03346       vTemp2[i] = vTemp[i] / (p->height - 1);
03347     }
03348 
03349     // move along
03350     for (h = 0; h < p->height-1; h++)
03351     {
03352       VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
03353     }
03354 
03355   }
03356     for ( w = 0 ; w < p->width ; w++ ) 
03357   {
03358         for ( h = 0 ; h < p->height ; h++ ) 
03359     {
03360             p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
03361             p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
03362         }
03363     }
03364   UpdatePatchInspector();
03365 }
03366 
03367 
03368 void Patch_DisperseRows()
03369 {
03370   vec3_t vTemp, vTemp2;
03371   int i, w, h;
03372 
03373 
03374     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03375     {
03376     if (pb->patchBrush)
03377     {
03378       patchMesh_t *p = pb->pPatch;
03379       Patch_Rebuild(p);
03380       for (w = 0; w < p->width; w++)
03381       {
03382         // for each row, we need to evenly disperse p->height number 
03383         // of points across the old bounds
03384 
03385         // calc total distance to interpolate 
03386         VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp);
03387     
03388         //vTemp[0] = vTemp[1] = vTemp[2] = 0;
03389         //for (h = 0; h < p->height - nRows; h ++)
03390         //{
03391         //  VectorAdd(vTemp, p->ctrl[w][h], vTemp);
03392         //}
03393 
03394         // amount per cycle
03395         for (i = 0; i < 3; i ++)
03396         {
03397           vTemp2[i] = vTemp[i] / (p->height - 1);
03398         }
03399 
03400         // move along
03401         for (h = 0; h < p->height-1; h++)
03402         {
03403           VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
03404         }
03405         Patch_Naturalize(p);
03406 
03407       }
03408     }
03409   }
03410   UpdatePatchInspector();
03411 
03412 }
03413 
03414 /*
03415 ==================
03416 Patch_AdjustColumns
03417 ==================
03418 */
03419 void Patch_DisperseColumns()
03420 {
03421   vec3_t vTemp, vTemp2;
03422   int i, w, h;
03423 
03424     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03425     {
03426     if (pb->patchBrush)
03427     {
03428       patchMesh_t *p = pb->pPatch;
03429       Patch_Rebuild(p);
03430 
03431       for (h = 0; h < p->height; h++)
03432       {
03433         // for each column, we need to evenly disperse p->width number 
03434         // of points across the old bounds
03435     
03436         // calc total distance to interpolate 
03437         VectorSubtract(p->ctrl[p->width - 1][h].xyz, p->ctrl[0][h].xyz, vTemp);
03438 
03439         // amount per cycle
03440         for (i = 0; i < 3; i ++)
03441         {
03442           vTemp2[i] = vTemp[i] / (p->width - 1);
03443         }
03444 
03445         // move along
03446         for (w = 0; w < p->width-1; w++)
03447         {
03448           VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
03449         }
03450 
03451       }
03452       Patch_Naturalize(p);
03453     }
03454   }
03455   UpdatePatchInspector();
03456 }
03457 
03458 
03459 
03460 /*
03461 ==================
03462 Patch_AdjustSelected
03463 ==================
03464 */
03465 void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag)
03466 {
03467   bool bUpdate = false;
03468     for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03469     {
03470     if (pb->patchBrush)
03471     {
03472       if (bInsert)
03473       {
03474         if (bColumn)
03475         {
03476           Patch_InsertColumn(pb->pPatch, bFlag);
03477         }
03478         else
03479         {
03480           Patch_InsertRow(pb->pPatch, bFlag);
03481         }
03482       }
03483       else
03484       {
03485         if (bColumn)
03486         {
03487           Patch_RemoveColumn(pb->pPatch, bFlag);
03488         }
03489         else
03490         {
03491           Patch_RemoveRow(pb->pPatch, bFlag);
03492         }
03493       }
03494       bUpdate = true;
03495       vec3_t vMin, vMax;
03496       patchMesh_t *p = pb->pPatch;
03497       Patch_CalcBounds(p, vMin, vMax);
03498       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
03499     }
03500   }
03501   if (bUpdate)
03502   {
03503     Sys_UpdateWindows(W_ALL);
03504   }
03505 }
03506 
03507 
03508 /*
03509 ==================
03510 Patch_AdjustSelectedRowCols
03511 ==================
03512 */
03513 void Patch_AdjustSelectedRowCols(int nRows, int nCols)
03514 {
03515     for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03516     {
03517     if (pb->patchBrush)
03518     {
03519       Patch_InsertColumn(pb->pPatch, false);
03520       if (nRows != 0)
03521       {
03522         Patch_AdjustRows(pb->pPatch, nRows);
03523       }
03524       
03525       if (nCols != 0)
03526       {
03527         Patch_AdjustColumns(pb->pPatch, nCols);
03528       }
03529         }
03530   }
03531   UpdatePatchInspector();
03532 }
03533 
03534 
03535 
03536 void Parse1DMatrix(int x, float* p)
03537 {
03538   GetToken(true); // (
03539   for (int i = 0; i < x; i++)
03540   {
03541     GetToken(false);
03542     p[i] = atof(token);
03543   }
03544   GetToken(true); // )
03545 }
03546 
03547 void Parse2DMatrix(int y, int x, float* p)
03548 {
03549   GetToken(true); // (
03550   for (int i = 0; i < y; i++)
03551   {
03552     Parse1DMatrix(x, p + i*x);
03553   }
03554   GetToken(true); // )
03555 }
03556 
03557 void Parse3DMatrix(int z, int y, int x, float* p)
03558 {
03559   GetToken(true); // (
03560   for (int i = 0; i < z; i++)
03561   {
03562     Parse2DMatrix(y, x, p + i*(x*MAX_PATCH_HEIGHT));
03563   }
03564   GetToken(true); // )
03565 }
03566 
03567 // parses a patch
03568 brush_t* Patch_Parse(bool bOld)
03569 {
03570     //--if (bOld)
03571     //--{
03572     //--  return Patch_ParseOld();
03573     //--}
03574 
03575   GetToken(true);
03576     
03577   if (strcmp(token, "{"))
03578     return NULL;
03579 
03580     patchMesh_t *pm = MakeNewPatch();
03581 
03582     if (g_qeglobals.bSurfacePropertiesPlugin)
03583     {
03584         GETPLUGINTEXDEF(pm)->ParsePatchTexdef();
03585     }
03586     else
03587     {
03588         // texture def
03589         GetToken(true);
03590         
03591         // band-aid 
03592         if (strcmp(token, "("))
03593         {
03594             pm->d_texture = Texture_ForName(token);
03595             GetToken(true);
03596         }
03597         else
03598         {
03599             pm->d_texture = notexture;
03600             Sys_Printf("Warning: Patch read with no texture, using notexture... \n");
03601         }               
03602         
03603         if (strcmp(token, "("))
03604             return NULL;
03605         
03606         // width, height, flags (currently only negative)
03607         GetToken(false);
03608         pm->width = atoi(token);
03609         
03610         GetToken(false);
03611         pm->height = atoi(token);
03612         
03613         GetToken(false);
03614         pm->contents = atoi(token);
03615         
03616         GetToken(false);
03617         pm->flags = atoi(token);
03618         
03619         GetToken(false);
03620         pm->value = atoi(token);
03621         
03622         if (!bOld)
03623         {
03624             GetToken(false);
03625             pm->type = atoi(token);
03626         }
03627         
03628         GetToken(false);
03629         if (strcmp(token, ")"))
03630             return NULL;
03631         
03632     }
03633 
03634 
03635 
03636   float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
03637   Parse3DMatrix(pm->width, pm->height, 5, reinterpret_cast<float*>(&ctrl));
03638 
03639   int w, h;
03640 
03641   for (w = 0; w < pm->width; w++)
03642   {
03643     for (h = 0; h < pm->height; h++)
03644     {
03645       pm->ctrl[w][h].xyz[0] = ctrl[w][h][0];  
03646       pm->ctrl[w][h].xyz[1] = ctrl[w][h][1];  
03647       pm->ctrl[w][h].xyz[2] = ctrl[w][h][2];  
03648       pm->ctrl[w][h].st[0] = ctrl[w][h][3]; 
03649       pm->ctrl[w][h].st[1] = ctrl[w][h][4];  
03650     }
03651   }
03652 
03653   GetToken(true);
03654 
03655     if (g_qeglobals.m_bBrushPrimitMode)
03656   {
03657     // we are in brush primit mode, but maybe it's a classic patch that needs converting, test "}"
03658     if (strcmp(token, "}") && strcmp (token, "(") )
03659       {
03660           epair_t *ep = ParseEpair();
03661           ep->next = pm->epairs;
03662           pm->epairs = ep;
03663       GetToken(true);
03664       }
03665   }
03666 
03667   if (strcmp(token, "}"))
03668     return NULL;
03669 
03670   brush_t *b = AddBrushForPatch(pm, false);
03671 
03672   return b;
03673 }
03674 
03675 
03676 /*
03677 ==================
03678 Patch_Write 
03679 ==================
03680 */
03681 void Patch_Write (patchMesh_t *p, CMemFile *file)
03682 {
03683     if (g_qeglobals.bSurfacePropertiesPlugin)
03684     {
03685         Sys_Printf("WARNING: Patch_Write to a CMemFile and Surface Properties plugin not done\n");
03686     }
03687   //--MemFile_fprintf(file, " {\n  patchDef3\n  {\n");
03688   MemFile_fprintf(file, " {\n  patchDef2\n  {\n");
03689 
03690   MemFile_fprintf(file, "   %s\n",p->d_texture->name);
03691   //--MemFile_fprintf(file, "   ( %i %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value, p->type);
03692   MemFile_fprintf(file, "   ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
03693 
03694 
03695     float       ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
03696 
03697   int w, h;
03698   for (w = 0; w < p->width; w++)
03699   {
03700     for (h = 0; h < p->height; h++)
03701     {
03702       ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
03703       ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
03704       ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
03705       ctrl[w][h][3] = p->ctrl[w][h].st[0];
03706       ctrl[w][h][4] = p->ctrl[w][h].st[1];
03707     }
03708   }
03709 
03710   _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
03711 
03712     if (g_qeglobals.m_bBrushPrimitMode)
03713   {
03714       if (p->epairs)
03715     {
03716             for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
03717       {
03718                 MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
03719       }
03720     }
03721   }
03722 
03723   MemFile_fprintf(file, "  }\n }\n");
03724 }
03725 
03726 void Patch_Write (patchMesh_t *p, FILE *file)
03727 {
03728     fprintf(file, " {\n  patchDef2\n  {\n");
03729     if (g_qeglobals.bSurfacePropertiesPlugin)
03730     {
03731 #ifdef _DEBUG
03732         if ( !p->pData )
03733             Sys_Printf("ERROR: no IPluginTexdef in patch\n");
03734 #endif
03735         g_File = file;
03736         GETPLUGINTEXDEF(p)->WritePatchTexdef( QERApp_MapPrintf_FILE );
03737     }
03738     else
03739     {
03740         fprintf(file, "   %s\n",p->d_texture->name);
03741         fprintf(file, "   ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
03742     }
03743 
03744     float       ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
03745 
03746   int w, h;
03747   for (w = 0; w < p->width; w++)
03748   {
03749     for (h = 0; h < p->height; h++)
03750     {
03751       ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
03752       ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
03753       ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
03754       ctrl[w][h][3] = p->ctrl[w][h].st[0];
03755       ctrl[w][h][4] = p->ctrl[w][h].st[1];
03756     }
03757   }
03758 
03759   _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
03760 
03761     if (g_qeglobals.m_bBrushPrimitMode)
03762   {
03763       if (p->epairs)
03764     {
03765             for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
03766       {
03767                 fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
03768       }
03769     }
03770   }
03771 
03772   fprintf(file, "  }\n }\n");
03773 }
03774 
03775 
03776 /*
03777 ==================
03778 Patch_RotateTexture
03779 ==================
03780 */
03781 void Patch_RotateTexture(patchMesh_t *p, float fAngle)
03782 {
03783   vec3_t vMin, vMax;
03784   Patch_CalcBounds(p, vMin, vMax);
03785   p->bDirty = true;
03786   for (int w = 0; w < p->width; w++)
03787   {
03788     for (int h = 0; h < p->height; h++)
03789     {
03790       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
03791         continue;
03792 
03793       float x = p->ctrl[w][h].st[0];
03794       float y = p->ctrl[w][h].st[1];
03795       p->ctrl[w][h].st[0] = x * cos(fAngle * Q_PI / 180) - y * sin(fAngle * Q_PI / 180);
03796       p->ctrl[w][h].st[1] = y * cos(fAngle * Q_PI / 180) + x * sin(fAngle * Q_PI / 180);
03797     }
03798   }
03799 }
03800 
03801 
03802 /*
03803 ==================
03804 Patch_ScaleTexture
03805 ==================
03806 */
03807 void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup)
03808 {
03809   // FIXME:
03810   // this hack turns scales into 1.1 or 0.9
03811   if (bFixup)
03812   {
03813     fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10;
03814     fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10;
03815   }
03816   else
03817   {
03818     if (fx == 0)
03819       fx = 1.0;
03820     if (fy == 0)
03821       fy = 1.0;
03822   }
03823   
03824   for (int w = 0; w < p->width; w++)
03825   {
03826     for (int h = 0; h < p->height; h++)
03827     {
03828       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
03829         continue;
03830 
03831       p->ctrl[w][h].st[0] *= fx;
03832       p->ctrl[w][h].st[1] *= fy;
03833     }
03834   }
03835   p->bDirty = true;
03836 }
03837 
03838 
03839 /*
03840 ==================
03841 Patch_ShiftTexture
03842 ==================
03843 */
03844 void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy)
03845 {
03846   //if (fx)
03847   //  fx = (fx > 0) ? 0.1 : -0.1;
03848   //if (fy)
03849   //  fy = (fy > 0) ? 0.1 : -0.1;
03850 
03851   fx = (abs(fx) >= 1) ? fx / 10 : fx;
03852   fy = (abs(fy) >= 1) ? fy / 10 : fy;
03853 
03854   for (int w = 0; w < p->width; w++)
03855   {
03856     for (int h = 0; h < p->height; h++)
03857     {
03858       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
03859         continue;
03860 
03861       p->ctrl[w][h].st[0] += fx;
03862       p->ctrl[w][h].st[1] += fy;
03863     }
03864   }
03865   p->bDirty = true;
03866 }
03867 
03868 void patchInvert(patchMesh_t *p)
03869 {
03870   drawVert_t vertTemp;
03871   p->bDirty = true;
03872     for ( int i = 0 ; i < p->width ; i++ ) 
03873   {
03874     for (int j = 0; j < p->height / 2; j++)
03875     {
03876       memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
03877       memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
03878       memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
03879         }
03880     }
03881 }
03882 
03883 /*
03884 ==================
03885 Patch_ToggleInverted
03886 ==================
03887 */
03888 void Patch_ToggleInverted()
03889 {
03890   bool bUpdate = false;
03891 
03892     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03893     {
03894     if (pb->patchBrush)
03895     {
03896       bUpdate = true;
03897       patchInvert(pb->pPatch);
03898     }
03899   }
03900 
03901   if (bUpdate)
03902   {
03903     Sys_UpdateWindows(W_ALL);
03904   }
03905   UpdatePatchInspector();
03906 }
03907 
03908 /*
03909 ==================
03910 Patch_ToggleInverted
03911 ==================
03912 */
03913 void Patch_InvertTexture(bool bY)
03914 {
03915   bool bUpdate = false;
03916 
03917   float fTemp[2];
03918     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03919     {
03920     if (pb->patchBrush)
03921     {
03922       bUpdate = true;
03923       patchMesh_t *p = pb->pPatch;
03924       p->bDirty = true;
03925       if (bY)
03926       {
03927           for ( int i = 0 ; i < p->height ; i++ ) 
03928         {
03929           for (int j = 0; j < p->width / 2; j++)
03930           {
03931             memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2]));
03932             memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2]));
03933             memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2]));
03934               }
03935           }
03936       }
03937       else
03938       {
03939           for ( int i = 0 ; i < p->width ; i++ ) 
03940         {
03941           for (int j = 0; j < p->height / 2; j++)
03942           {
03943             memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2]));
03944             memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2]));
03945             memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2]));
03946               }
03947           }
03948       }
03949     }
03950   }
03951 
03952   if (bUpdate)
03953   {
03954     Sys_UpdateWindows(W_ALL);
03955   }
03956   UpdatePatchInspector();
03957 }
03958 
03959 
03960 
03961 
03962 /*
03963 ==================
03964 Patch_Save
03965 ==================
03966  Saves patch ctrl info (originally to deal with a 
03967  cancel in the surface dialog
03968 */
03969 void Patch_Save(patchMesh_t *p)
03970 {
03971   patchSave.width = p->width;
03972   patchSave.height = p->height;
03973   memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl));
03974 }
03975 
03976 
03977 /*
03978 ==================
03979 Patch_Restore
03980 ==================
03981 */
03982 void Patch_Restore(patchMesh_t *p)
03983 {
03984   p->width = patchSave.width;
03985   p->height = patchSave.height;
03986   memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl));
03987 }
03988 
03989 void Patch_ResetTexturing(float fx, float fy)
03990 {
03991     for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03992     {
03993     if (pb->patchBrush)
03994     {
03995       patchMesh_t *p = pb->pPatch;
03996       p->bDirty = true;
03997         for ( int i = 0 ; i < p->width ; i++ ) 
03998       {
03999             for ( int j = 0 ; j < p->height ; j++ ) 
04000         {
04001                 p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1);
04002                 p->ctrl[i][j].st[1] = fy * (float)j / (p->height - 1);
04003             }
04004         }
04005     }
04006   }
04007 }
04008 
04009 
04010 void Patch_FitTexturing()
04011 {
04012     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04013     {
04014     if (pb->patchBrush)
04015     {
04016       patchMesh_t *p = pb->pPatch;
04017       p->bDirty = true;
04018         for ( int i = 0 ; i < p->width ; i++ ) 
04019       {
04020             for ( int j = 0 ; j < p->height ; j++ ) 
04021         {
04022                 p->ctrl[i][j].st[0] = 1 * (float)i / (p->width - 1);
04023                 p->ctrl[i][j].st[1] = 1 * (float)j / (p->height - 1);
04024             }
04025         }
04026     }
04027   }
04028 }
04029 
04030 
04031 void Patch_SetTextureInfo(texdef_t *pt)
04032 {
04033     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04034     {
04035     if (pb->patchBrush)
04036     {
04037       if (pt->rotate)
04038         Patch_RotateTexture(pb->pPatch, pt->rotate);
04039 
04040       if (pt->shift[0] || pt->shift[1])
04041         Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]);
04042 
04043       if (pt->scale[0] || pt->scale[1])
04044         Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false);
04045 
04046       patchMesh_t *p = pb->pPatch;
04047       p->contents = pt->contents;
04048       p->flags = pt->flags;
04049       p->value = pt->value;
04050     }
04051   }
04052 }
04053 
04054 bool WINAPI OnlyPatchesSelected()
04055 {
04056   if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
04057     return false;
04058     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04059     {
04060     if (!pb->patchBrush)
04061     {
04062       return false;
04063     }
04064   }
04065   return true;
04066 }
04067 
04068 bool WINAPI AnyPatchesSelected()
04069 {
04070   if (g_ptrSelectedFaces.GetSize() > 0  || selected_brushes.next == &selected_brushes)
04071     return false;
04072     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04073     {
04074     if (pb->patchBrush)
04075     {
04076       return true;
04077     }
04078   }
04079   return false;
04080 }
04081 
04082 patchMesh_t* SinglePatchSelected()
04083 {
04084     if (selected_brushes.next->patchBrush)
04085   {
04086     return selected_brushes.next->pPatch;
04087   }
04088   return NULL;
04089 }
04090 
04091 void Patch_BendToggle()
04092 {
04093   if (g_bPatchBendMode)
04094   {
04095     g_bPatchBendMode = false;
04096     HideInfoDialog();
04097     g_pParentWnd->UpdatePatchToolbarButtons() ;
04098     return;
04099   }
04100 
04101     brush_t* b = selected_brushes.next;
04102 
04103   if (!QE_SingleBrush() || !b->patchBrush)
04104   {
04105     Sys_Printf("Must bend a single patch");
04106         return;
04107   }
04108 
04109   Patch_Save(b->pPatch);
04110     g_bPatchBendMode = true;
04111   g_nPatchBendState = BEND_SELECT_ROTATION;
04112   g_bPatchAxisOnRow = true;
04113   g_nPatchAxisIndex = 1;
04114   ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]);
04115 }
04116 
04117 void Patch_BendHandleTAB()
04118 {
04119   if (!g_bPatchBendMode)
04120   {
04121     return;
04122   }
04123 
04124     brush_t* b = selected_brushes.next;
04125   if (!QE_SingleBrush() || !b->patchBrush)
04126   {
04127     Patch_BendToggle();
04128     Sys_Printf("No patch to bend!");
04129         return;
04130   }
04131 
04132   patchMesh_t *p = b->pPatch;
04133 
04134   bool bShift = (GetKeyState(VK_SHIFT) & 0x8000);
04135 
04136   if (g_nPatchBendState == BEND_SELECT_ROTATION)
04137   {
04138     // only able to deal with odd numbered rows/cols
04139     g_nPatchAxisIndex += (bShift) ? -2 : 2;
04140     if (g_bPatchAxisOnRow)
04141     {
04142       if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height)
04143       {
04144         g_bPatchAxisOnRow = false;
04145         g_nPatchAxisIndex = (bShift) ? p->width-1 : 1;
04146       }
04147     }
04148     else
04149     {
04150       if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width)
04151       {
04152         g_bPatchAxisOnRow = true;
04153         g_nPatchAxisIndex = (bShift) ? p->height-1 : 1;
04154       }
04155     }
04156   }
04157   else
04158   if (g_nPatchBendState == BEND_SELECT_ORIGIN)
04159   {
04160     g_nBendOriginIndex += (bShift) ? -1 : 1;
04161     if (g_bPatchAxisOnRow)
04162     {
04163       if (bShift)
04164       {
04165         if (g_nBendOriginIndex < 0)
04166           g_nBendOriginIndex = p->width-1;
04167       }
04168       else
04169       {
04170         if (g_nBendOriginIndex > p->width-1)
04171           g_nBendOriginIndex = 0;
04172       }
04173       VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin);
04174     }
04175     else
04176     {
04177       if (bShift)
04178       {
04179         if (g_nBendOriginIndex < 0)
04180           g_nBendOriginIndex = p->height-1;
04181       }
04182       else
04183       {
04184         if (g_nBendOriginIndex > p->height-1)
04185           g_nBendOriginIndex = 0;
04186       }
04187       VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin);
04188     }
04189   }
04190   else
04191   if (g_nPatchBendState == BEND_SELECT_EDGE)
04192   {
04193     g_bPatchLowerEdge ^= 1;
04194   }
04195   Sys_UpdateWindows(W_ALL);
04196 }
04197 
04198 void Patch_BendHandleENTER()
04199 {
04200   if (!g_bPatchBendMode)
04201   {
04202     return;
04203   }
04204 
04205   if (g_nPatchBendState  < BEND_BENDIT)
04206   {
04207     g_nPatchBendState++;
04208     ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]);
04209     if (g_nPatchBendState == BEND_SELECT_ORIGIN)
04210     {
04211       g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0;
04212       g_nBendOriginIndex = 0;
04213       Patch_BendHandleTAB();
04214     }
04215     else
04216     if (g_nPatchBendState == BEND_SELECT_EDGE)
04217     {
04218       g_bPatchLowerEdge = true;
04219     }
04220     else
04221     if (g_nPatchBendState == BEND_BENDIT)
04222     {
04223       // basically we go into rotation mode, set the axis to the center of the 
04224     }
04225   }
04226   else
04227   {
04228     // done
04229     Patch_BendToggle();
04230   }
04231   Sys_UpdateWindows(W_ALL);
04232 
04233 }
04234 
04235 
04236 void Patch_BendHandleESC()
04237 {
04238   if (!g_bPatchBendMode)
04239   {
04240     return;
04241   }
04242   Patch_BendToggle();
04243     brush_t* b = selected_brushes.next;
04244   if (QE_SingleBrush() && b->patchBrush)
04245   {
04246     Patch_Restore(b->pPatch);
04247   }
04248   Sys_UpdateWindows(W_ALL);
04249 }
04250 
04251 void Patch_SetBendRotateOrigin(patchMesh_t *p)
04252 {
04253 #if 1
04254   int nType = g_pParentWnd->ActiveXY()->GetViewType();
04255   int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1;
04256 
04257   g_vBendOrigin[nDim3] = 0;
04258   VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin());
04259   return;
04260 #else
04261   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
04262   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
04263 
04264   float fxLo, fyLo, fxHi, fyHi;
04265   fxLo = fyLo = 9999;
04266   fxHi = fyHi = -9999;
04267 
04268   if (g_bPatchAxisOnRow)
04269   {
04270     for (int i = 0; i < p->width; i++)
04271     {
04272       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo)
04273         fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
04274 
04275       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi)
04276         fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
04277 
04278       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo)
04279         fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
04280 
04281       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi)
04282         fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
04283     }
04284   }
04285   else
04286   {
04287     for (int i = 0; i < p->height; i++)
04288     {
04289       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo)
04290         fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
04291 
04292       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi)
04293         fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
04294 
04295       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo)
04296         fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
04297 
04298       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi)
04299         fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
04300     }
04301   }
04302 
04303   g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0;
04304   g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5;
04305   g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5;
04306 #endif
04307 }
04308 
04309 // also sets the rotational origin
04310 void Patch_SelectBendAxis()
04311 {
04312     brush_t* b = selected_brushes.next;
04313   if (!QE_SingleBrush() || !b->patchBrush)
04314   {
04315     // should not ever happen
04316     Patch_BendToggle();
04317         return;
04318   }
04319 
04320   patchMesh_t *p = b->pPatch;
04321   if (g_bPatchAxisOnRow)
04322   {
04323     SelectRow(p, g_nPatchAxisIndex, false);
04324   }
04325   else
04326   {
04327     SelectColumn(p, g_nPatchAxisIndex, false);
04328   }
04329 
04330   //FIXME: this only needs to be set once... 
04331   Patch_SetBendRotateOrigin(p);
04332 
04333 }
04334 
04335 void Patch_SelectBendNormal()
04336 {
04337     brush_t* b = selected_brushes.next;
04338   if (!QE_SingleBrush() || !b->patchBrush)
04339   {
04340     // should not ever happen
04341     Patch_BendToggle();
04342         return;
04343   }
04344 
04345   patchMesh_t *p = b->pPatch;
04346 
04347   g_qeglobals.d_num_move_points = 0;
04348   if (g_bPatchAxisOnRow)
04349   {
04350     if (g_bPatchLowerEdge)
04351     {
04352       for (int j = 0; j < g_nPatchAxisIndex; j++)
04353         SelectRow(p, j, true);
04354     }
04355     else
04356     {
04357       for (int j = p->height-1; j > g_nPatchAxisIndex; j--)
04358         SelectRow(p, j, true);
04359     }
04360   }
04361   else
04362   {
04363     if (g_bPatchLowerEdge)
04364     {
04365       for (int j = 0; j < g_nPatchAxisIndex; j++)
04366         SelectColumn(p, j, true);
04367     }
04368     else
04369     {
04370       for (int j = p->width-1; j > g_nPatchAxisIndex; j--)
04371         SelectColumn(p, j, true);
04372     }
04373   }
04374   Patch_SetBendRotateOrigin(p);
04375 }
04376 
04377 
04378 
04379 void Patch_InsDelToggle()
04380 {
04381   if (g_bPatchInsertMode)
04382   {
04383     g_bPatchInsertMode = false;
04384     HideInfoDialog();
04385     g_pParentWnd->UpdatePatchToolbarButtons() ;
04386     return;
04387   }
04388 
04389     brush_t* b = selected_brushes.next;
04390 
04391   if (!QE_SingleBrush() || !b->patchBrush)
04392   {
04393     Sys_Printf("Must work with a single patch");
04394         return;
04395   }
04396 
04397   Patch_Save(b->pPatch);
04398     g_bPatchInsertMode = true;
04399   g_nPatchInsertState = INSERT_SELECT_EDGE;
04400   g_bPatchAxisOnRow = true;
04401   g_nPatchAxisIndex = 0;
04402   ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]);
04403 
04404 }
04405 
04406 void Patch_InsDelESC()
04407 {
04408   if (!g_bPatchInsertMode)
04409   {
04410     return;
04411   }
04412   Patch_InsDelToggle();
04413   Sys_UpdateWindows(W_ALL);
04414 }
04415 
04416 
04417 void Patch_InsDelHandleENTER()
04418 {
04419 }
04420 
04421 void Patch_InsDelHandleTAB()
04422 {
04423   if (!g_bPatchInsertMode)
04424   {
04425     Patch_InsDelToggle();
04426     return;
04427   }
04428 
04429     brush_t* b = selected_brushes.next;
04430   if (!QE_SingleBrush() || !b->patchBrush)
04431   {
04432     Patch_BendToggle();
04433     Sys_Printf("No patch to bend!");
04434         return;
04435   }
04436 
04437   patchMesh_t *p = b->pPatch;
04438 
04439   // only able to deal with odd numbered rows/cols
04440   g_nPatchAxisIndex += 2;
04441   if (g_bPatchAxisOnRow)
04442   {
04443     if (g_nPatchAxisIndex >= p->height-1)
04444     {
04445       g_bPatchAxisOnRow = false;
04446       g_nPatchAxisIndex = 0;
04447     }
04448   }
04449   else
04450   {
04451     if (g_nPatchAxisIndex >= p->width-1)
04452     {
04453       g_bPatchAxisOnRow = true;
04454       g_nPatchAxisIndex = 0;
04455     }
04456   }
04457   Sys_UpdateWindows(W_ALL);
04458 }
04459 
04460 
04461 void _Write1DMatrix (FILE *f, int x, float *m) {
04462     int     i;
04463 
04464     fprintf (f, "( ");
04465     for (i = 0 ; i < x ; i++) {
04466         if (m[i] == (int)m[i] ) {
04467             fprintf (f, "%i ", (int)m[i]);
04468         } else {
04469             fprintf (f, "%f ", m[i]);
04470         }
04471     }
04472     fprintf (f, ")");
04473 }
04474 
04475 void _Write2DMatrix (FILE *f, int y, int x, float *m) {
04476     int     i;
04477 
04478     fprintf (f, "( ");
04479     for (i = 0 ; i < y ; i++) {
04480         _Write1DMatrix (f, x, m + i*x);
04481         fprintf (f, " ");
04482     }
04483     fprintf (f, ")\n");
04484 }
04485 
04486 
04487 void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) {
04488     int     i;
04489 
04490     fprintf (f, "(\n");
04491     for (i = 0 ; i < z ; i++) {
04492         _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
04493     }
04494     fprintf (f, ")\n");
04495 }
04496 
04497 void _Write1DMatrix (CMemFile *f, int x, float *m) {
04498     int     i;
04499 
04500     MemFile_fprintf (f, "( ");
04501     for (i = 0 ; i < x ; i++) {
04502         if (m[i] == (int)m[i] ) {
04503             MemFile_fprintf (f, "%i ", (int)m[i]);
04504         } else {
04505             MemFile_fprintf (f, "%f ", m[i]);
04506         }
04507     }
04508     MemFile_fprintf (f, ")");
04509 }
04510 
04511 void _Write2DMatrix (CMemFile *f, int y, int x, float *m) {
04512     int     i;
04513 
04514     MemFile_fprintf (f, "( ");
04515     for (i = 0 ; i < y ; i++) {
04516         _Write1DMatrix (f, x, m + i*x);
04517         MemFile_fprintf (f, " ");
04518     }
04519     MemFile_fprintf (f, ")\n");
04520 }
04521 
04522 
04523 void _Write3DMatrix (CMemFile *f, int z, int y, int x, float *m) {
04524     int     i;
04525 
04526     MemFile_fprintf (f, "(\n");
04527     for (i = 0 ; i < z ; i++) {
04528         _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
04529     }
04530     MemFile_fprintf (f, ")\n");
04531 }
04532 
04533 
04534 void Patch_NaturalizeSelected(bool bCap, bool bCycleCap)
04535 {
04536     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04537     {
04538     if (pb->patchBrush)
04539     {
04540       if (bCap)
04541         Patch_CapTexture(pb->pPatch, bCycleCap);
04542       else
04543         Patch_Naturalize(pb->pPatch);
04544     }
04545   }
04546 }
04547 
04548 bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR)
04549 {
04550   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
04551   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
04552   if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) ||
04553       (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1]))
04554   {
04555     if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) ||
04556         (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2]))
04557       return true;
04558   }
04559   return false;
04560 }
04561 
04562 
04563 void Patch_SelectAreaPoints()
04564 {
04565   g_qeglobals.d_num_move_points = 0;
04566   g_nPatchClickedView = -1;
04567 
04568     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04569     {
04570     if (pb->patchBrush)
04571     {
04572       patchMesh_t *p = pb->pPatch;
04573       for (int i = 0; i < p->width; i++)
04574       {
04575         for (int j = 0; j < p->height; j++)
04576         {
04577           if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR))
04578           {
04579             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
04580           }
04581         }
04582       }
04583     }
04584   }
04585 }
04586 
04587 const char* Patch_GetTextureName()
04588 {
04589     brush_t* b = selected_brushes.next;
04590   if (b->patchBrush)
04591   {
04592     patchMesh_t *p = b->pPatch;
04593     if (p->d_texture->name)
04594       return p->d_texture->name;
04595   }
04596   return "";
04597 }
04598 
04599 patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom)
04600 {
04601   patchMesh_t* p = MakeNewPatch();
04602   memcpy(p, pFrom , sizeof(patchMesh_t));
04603   p->bSelected = false;
04604   p->bDirty = true;
04605   p->bOverlay = false;
04606   p->nListID = -1;
04607   // surface plugin
04608   if (g_qeglobals.bSurfacePropertiesPlugin)
04609   {
04610 #ifdef _DEBUG
04611     if (!pFrom->pData)
04612         Sys_Printf("WARNING: unexpected pFrom->pData is NULL in Patch_Duplicate\n");
04613     else
04614 #endif
04615         p->pData = GETPLUGINTEXDEF(pFrom)->Copy();
04616   }
04617   AddBrushForPatch(p);
04618   return p;
04619 }
04620 
04621 
04622 void Patch_Thicken(int nAmount, bool bSeam)
04623 {
04624   int i, j, h, w;
04625   brush_t *b;
04626   patchMesh_t *pSeam;
04627   vec3_t vMin, vMax;
04628   CPtrArray brushes;
04629 
04630   nAmount = -nAmount;
04631 
04632 
04633     if (!QE_SingleBrush())
04634   {
04635     Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n");
04636         return;
04637   }
04638 
04639     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04640     {
04641     if (pb->patchBrush)
04642     {
04643       patchMesh_t *p = pb->pPatch;
04644       Patch_MeshNormals(p);
04645       patchMesh_t *pNew = Patch_Duplicate(p);
04646       for (i = 0; i < p->width; i++)
04647       {
04648         for (j = 0; j < p->height; j++)
04649         {
04650               VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz);
04651         }
04652       }
04653 
04654       Patch_Rebuild(pNew);
04655       pNew->type |= PATCH_THICK;
04656       brushes.Add(pNew->pSymbiot);
04657 
04658       if (bSeam)
04659       {
04660 
04661         // FIXME: this should detect if any edges of the patch are closed and act appropriately
04662         // 
04663         if (!(p->type & PATCH_CYLINDER))
04664         {
04665           b = Patch_GenericMesh(3, p->height, 2, false, true);
04666           pSeam = b->pPatch;
04667           pSeam->type |= PATCH_SEAM;
04668           for (i = 0; i < p->height; i++)
04669           {
04670             VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz);
04671             VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz);
04672             VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
04673             VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
04674           }
04675 
04676 
04677           Patch_CalcBounds(pSeam, vMin, vMax);
04678           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04679           //--Patch_CapTexture(pSeam);
04680           Patch_Naturalize(pSeam);
04681           patchInvert(pSeam);
04682           brushes.Add(b);
04683 
04684           w = p->width - 1;
04685           b = Patch_GenericMesh(3, p->height, 2, false, true);
04686           pSeam = b->pPatch;
04687           pSeam->type |= PATCH_SEAM;
04688           for (i = 0; i < p->height; i++)
04689           {
04690             VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz);
04691             VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz);
04692             VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
04693             VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
04694           }
04695           Patch_CalcBounds(pSeam, vMin, vMax);
04696           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04697           //--Patch_CapTexture(pSeam);
04698           Patch_Naturalize(pSeam);
04699           brushes.Add(b);
04700         }
04701     
04702         //--{
04703           // otherwise we will add one per end
04704           b = Patch_GenericMesh(p->width, 3, 2, false, true);
04705           pSeam = b->pPatch;
04706           pSeam->type |= PATCH_SEAM;
04707           for (i = 0; i < p->width; i++)
04708           {
04709             VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz);
04710             VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz);
04711             VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
04712             VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
04713           }
04714 
04715 
04716           Patch_CalcBounds(pSeam, vMin, vMax);
04717           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04718           //--Patch_CapTexture(pSeam);
04719           Patch_Naturalize(pSeam);
04720           patchInvert(pSeam);
04721           brushes.Add(b);
04722 
04723           h = p->height - 1;
04724           b = Patch_GenericMesh(p->width, 3, 2, false, true);
04725           pSeam = b->pPatch;
04726           pSeam->type |= PATCH_SEAM;
04727           for (i = 0; i < p->width; i++)
04728           {
04729             VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz);
04730             VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz);
04731             VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
04732             VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
04733           }
04734           Patch_CalcBounds(pSeam, vMin, vMax);
04735           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04736           //--Patch_CapTexture(pSeam);
04737           Patch_Naturalize(pSeam);
04738           brushes.Add(b);
04739 
04740           eclass_t *pecNew = Eclass_ForName("func_group", false);
04741           if (pecNew)
04742           {
04743             entity_t *e = Entity_Create(pecNew);
04744             SetKeyValue(e, "type", "patchThick");
04745           }
04746 
04747         
04748         //--}
04749       }
04750       patchInvert(pNew);
04751     }
04752   }
04753 
04754   for (i = 0; i < brushes.GetSize(); i++)
04755   {
04756     Select_Brush(reinterpret_cast<brush_t*>(brushes.GetAt(i)));
04757   }
04758 
04759   UpdatePatchInspector();
04760 }
04761 
04762 
04763 /*
04764 lets get another list together as far as necessities..
04765 
04766 *snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything)
04767 
04768 capping bevels/endcaps
04769 
04770 hot keys
04771 
04772 texture fix for caps
04773 
04774 clear clipboard
04775 
04776 *region fix
04777 
04778 *surface dialog
04779 
04780 */
04781 
04782 void Patch_SetOverlays()
04783 {
04784     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04785     {
04786     if (pb->patchBrush)
04787     {
04788       pb->pPatch->bOverlay = true;
04789     }
04790   }
04791 }
04792 
04793 
04794 
04795 void Patch_ClearOverlays()
04796 {
04797   brush_t *pb;
04798     for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04799     {
04800     if (pb->patchBrush)
04801     {
04802       pb->pPatch->bOverlay = false;
04803     }
04804   }
04805 
04806     for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
04807     {
04808     if (pb->patchBrush)
04809     {
04810       pb->pPatch->bOverlay = false;
04811     }
04812   }
04813 
04814 }
04815 
04816 // freezes selected vertices
04817 void Patch_Freeze()
04818 {
04819   brush_t *pb;
04820     for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04821     {
04822     if (pb->patchBrush)
04823     {
04824       pb->pPatch->bOverlay = false;
04825     }
04826   }
04827 
04828     for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
04829     {
04830     if (pb->patchBrush)
04831     {
04832       pb->pPatch->bOverlay = false;
04833     }
04834   }
04835 
04836 }
04837 
04838 void Patch_UnFreeze(bool bAll)
04839 {
04840 }
04841 
04842 
04843 
04844 void Patch_Transpose()
04845 {
04846     int     i, j, w;
04847   drawVert_t dv;
04848     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04849     {
04850     if (pb->patchBrush)
04851     {
04852       patchMesh_t *p = pb->pPatch;
04853 
04854         if ( p->width > p->height ) 
04855       {
04856             for ( i = 0 ; i < p->height ; i++ ) 
04857         {
04858                 for ( j = i + 1 ; j < p->width ; j++ ) 
04859           {
04860                     if ( j < p->height ) 
04861             {
04862                         // swap the value
04863                         memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t));
04864                         memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
04865                         memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t));
04866                     } 
04867             else 
04868             {
04869                         // just copy
04870                         memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
04871                     }
04872                 }
04873           }
04874         } 
04875       else 
04876       {
04877             for ( i = 0 ; i < p->width ; i++ ) 
04878         {
04879               for ( j = i + 1 ; j < p->height ; j++ ) 
04880           {
04881                     if ( j < p->width ) 
04882             {
04883                         // swap the value
04884                         memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t));
04885               memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
04886                         memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t));
04887                     } 
04888             else 
04889             {
04890                         // just copy
04891                         memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
04892                     }
04893                 }
04894             }
04895         }
04896 
04897       w = p->width;
04898       p->width = p->height;
04899       p->height = w;
04900       patchInvert(p);
04901       Patch_Rebuild(p);
04902         }
04903     }
04904 }
04905 
04906 
04907 
04908 void Select_SnapToGrid()
04909 {
04910     int i,j, k;
04911     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04912     {
04913     if (pb->patchBrush)
04914     {
04915       patchMesh_t *p = pb->pPatch;
04916 #if 0
04917         float       ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
04918       memcpy(ctrl, p->ctrl, sizeof(p->ctrl));
04919       i = p->width;
04920       p->width = p->height;
04921       p->height = i;
04922       for (i = 0; i < p->width; i++)
04923       {
04924         int l = p->height-1;
04925         for (j = 0; j < p->height; j++)
04926         {
04927           for (k = 0; k < 5; k++)
04928           {
04929             p->ctrl[i][l][k] = ctrl[j][i][k];
04930           }
04931           l--;
04932         }
04933       }
04934 #else
04935       for (i = 0; i < p->width; i++)
04936       {
04937         for (j = 0; j < p->height; j++)
04938         {
04939           for (k = 0; k < 3; k++)
04940           {
04941             p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
04942           }
04943         }
04944       }
04945 #endif
04946       vec3_t vMin, vMax;
04947       Patch_CalcBounds(p, vMin, vMax);
04948       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
04949     }
04950     else
04951     {
04952       Brush_SnapToGrid(pb);
04953     }
04954   }
04955 }
04956 
04957 
04958 void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce)
04959 {
04960   if (pb->patchBrush)
04961   {
04962     patchMesh_t *p = pb->pPatch;
04963     if (bForce || strcmpi(p->d_texture->name, pFind) == 0)
04964     {
04965       p->d_texture = Texture_ForName(pReplace);
04966       //strcpy(p->d_texture->name, pReplace);
04967     }
04968   }
04969 }
04970 
04971 void Patch_ReplaceQTexture(brush_t *pb, qtexture_t *pOld, qtexture_t *pNew)
04972 {
04973   if (pb->patchBrush)
04974   {
04975     patchMesh_t *p = pb->pPatch;
04976     if (p->d_texture == pOld)
04977     {
04978       p->d_texture = pNew;
04979     }
04980   }
04981 }
04982 
04983 void Patch_Clone(patchMesh_t *p, brush_t *pNewOwner)
04984 {
04985 }
04986 
04987 void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz)
04988 {
04989   patchMesh_t* p = MakeNewPatch();
04990     p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
04991     p->width = 3;
04992     p->height = 3;
04993   p->type = PATCH_TRIANGLE;
04994 
04995   // 0 0 goes to x
04996   // 0 1 goes to x
04997   // 0 2 goes to x
04998 
04999   // 1 0 goes to mid of x and z
05000   // 1 1 goes to mid of x y and z
05001   // 1 2 goes to mid of x and y
05002 
05003   // 2 0 goes to z
05004   // 2 1 goes to mid of y and z
05005   // 2 2 goes to y
05006 
05007   vec5_t vMidXZ;
05008   vec5_t vMidXY;
05009   vec5_t vMidYZ;
05010 
05011 
05012   for (int j = 0; j < 3; j++)
05013   {
05014     _Vector5Add(vx, vz, vMidXZ);
05015     _Vector5Scale(vMidXZ, 0.5, vMidXZ);
05016     //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5);
05017   }
05018 
05019   for (j = 0; j < 3; j++)
05020   {
05021     _Vector5Add(vx, vy, vMidXY);
05022     _Vector5Scale(vMidXY, 0.5, vMidXY);
05023     //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5);
05024   }
05025 
05026   for (j = 0; j < 3; j++)
05027   {
05028     _Vector5Add(vy, vz, vMidYZ);
05029     _Vector5Scale(vMidYZ, 0.5, vMidYZ);
05030     //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5);
05031   }
05032 
05033   _Vector53Copy(vx, p->ctrl[0][0].xyz);
05034   _Vector53Copy(vx, p->ctrl[0][1].xyz);
05035   _Vector53Copy(vx, p->ctrl[0][2].xyz);
05036   p->ctrl[0][0].st[0] = vx[3];
05037   p->ctrl[0][0].st[1] = vx[4];
05038   p->ctrl[0][1].st[0] = vx[3];
05039   p->ctrl[0][1].st[1] = vx[4];
05040   p->ctrl[0][2].st[0] = vx[3];
05041   p->ctrl[0][2].st[1] = vx[4];
05042 
05043   _Vector53Copy(vMidXY, p->ctrl[1][0].xyz);
05044   _Vector53Copy(vx, p->ctrl[1][1].xyz);
05045   _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz);
05046   p->ctrl[1][0].st[0] = vMidXY[3];
05047   p->ctrl[1][0].st[1] = vMidXY[4];
05048   p->ctrl[1][1].st[0] = vx[3];
05049   p->ctrl[1][1].st[1] = vx[4];
05050   p->ctrl[1][2].st[0] = vMidXZ[3];
05051   p->ctrl[1][2].st[1] = vMidXZ[4];
05052 
05053   _Vector53Copy(vy, p->ctrl[2][0].xyz);
05054   _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz);
05055   _Vector53Copy(vz, p->ctrl[2][2].xyz);
05056   p->ctrl[2][0].st[0] = vy[3];
05057   p->ctrl[2][0].st[1] = vy[4];
05058   p->ctrl[2][1].st[0] = vMidYZ[3];
05059   p->ctrl[2][1].st[1] = vMidYZ[4];
05060   p->ctrl[2][2].st[0] = vz[3];
05061   p->ctrl[2][2].st[1] = vz[4];
05062 
05063 
05064   //Patch_Naturalize(p);
05065 
05066   brush_t *b = AddBrushForPatch(p);
05067 
05068 }
05069 
05070 
05071 /*
05072 ==============
05073 Patch_SetEpair
05074 sets an epair for the given patch
05075 ==============
05076 */
05077 void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue)
05078 {
05079     if (g_qeglobals.m_bBrushPrimitMode)
05080     {
05081         SetKeyValue(p->epairs, pKey, pValue);
05082     }
05083 }
05084 
05085 /* 
05086 =================
05087 Patch_GetKeyValue
05088 =================
05089 */
05090 const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey)
05091 {
05092     if (g_qeglobals.m_bBrushPrimitMode)
05093     {
05094     return ValueForKey(p->epairs, pKey);
05095     }
05096   return "";
05097 }
05098 
05099 
05100 //Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save)
05101 /*
05102 Feature addition.
05103 When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as;
05104 
05105 g:\quake3\baseq3\textures\common
05106 
05107  So that, when I'm reading in, lets say, my \eerie directory, it goes through and adds my textures to the palette, along with everything in common.
05108 
05109   Don't forget to add "Finer texture alignment" to the list. I'd like to be able to move in 0.1 increments using the Shift-Arrow Keys.
05110 
05111   No. Sometimes textures are drawn the wrong way on patches. We'd like the ability to flip a texture. Like the way X/Y scale -1 used to worked.
05112 
05113   1) Easier way of deleting rows, columns
05114 2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog)
05115 2) Patch matrix transposition
05116 
05117   1) Actually, bump texture flipping on patches to the top of the list of things to do.
05118 2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S
05119 3) Brandon has a wierd anomoly. He fine-tunes a patch with caps. It looks fine when the patch is selected, but as soon as he escapes out, it reverts to it's pre-tuned state. When he selects the patch again, it looks tuned
05120 
05121 
05122 *1) Flipping textures on patches
05123 *2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S
05124 3) Easier way of deleting rows columns
05125 *4) Thick Curves
05126 5) Patch matrix transposition
05127 6) Inverted cylinder capping
05128 *7) bugs
05129 *8) curve speed
05130 
05131   Have a new feature request. "Compute Bounding Box" for mapobjects (md3 files). This would be used for misc_mapobject (essentially, drop in 3DS Max models into our maps)
05132 
05133   Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model
05134 
05135   Feature Addition: View/Hide Hint Brushes -- This should be a specific case.
05136 */

Generated on Thu Aug 25 12:38:36 2005 for Quake III Arena by  doxygen 1.3.9.1