home *** CD-ROM | disk | FTP | other *** search
/ PC PowerPlay 58 / pcpp58a.iso / extras / quake 3 source / Q3A_ToolSource.exe / Main / PMESH.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  2001-01-02  |  119.7 KB  |  5,107 lines

  1. // 
  2. // Preliminary patch stuff
  3. //
  4. // 
  5.  
  6. #include "stdafx.h"
  7. #include "qe3.h"
  8. #include "DialogInfo.h"
  9. #include "CapDialog.h"
  10.  
  11. // externs
  12. extern void MemFile_fprintf(CMemFile* pMemFile, const char* pText, ...);
  13. extern face_t *Face_Alloc( void );
  14. void _Write3DMatrix (FILE *f, int y, int x, int z, float *m);
  15. void _Write3DMatrix (CMemFile *f, int y, int x, int z, float *m);
  16.  
  17.  
  18.  
  19. #define    CBLOCK_SUBDIVISIONS    6 
  20.  
  21.  
  22. patchMesh_t* MakeNewPatch()
  23. {
  24.   patchMesh_t *pm = reinterpret_cast<patchMesh_t*>(qmalloc(sizeof(patchMesh_t)));
  25.   if (g_qeglobals.bSurfacePropertiesPlugin)
  26.   {
  27.       pm->pData = static_cast<void *>( g_SurfaceTable.m_pfnPatchAlloc( pm ) );
  28.   }
  29.   return pm;
  30. }
  31.  
  32. // FIXME: this needs to be dynamic
  33. //#define    MAX_PATCH_MESHES    4096
  34. //patchMesh_t        patchMeshes[MAX_PATCH_MESHES];
  35. //int numPatchMeshes = 0;
  36.  
  37. // used for a save spot
  38. patchMesh_t patchSave;
  39.  
  40. // Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized 
  41. // brush approach
  42. //--int  g_nSelectedPatch = -1;  
  43.  
  44. // HACK: for tracking which view generated the click
  45. // as we dont want to deselect a point on a same point
  46. // click if it is from a different view
  47. int  g_nPatchClickedView = -1;
  48. bool g_bSameView = false;
  49.  
  50.  
  51. // globals
  52. bool g_bPatchShowBounds = true;
  53. bool g_bPatchWireFrame = false;
  54. bool g_bPatchWeld = true;
  55. bool g_bPatchDrillDown = true;
  56. bool g_bPatchInsertMode = false;
  57. bool g_bPatchBendMode = false;
  58. int  g_nPatchBendState = -1;
  59. int  g_nPatchInsertState = -1;
  60. int  g_nBendOriginIndex = 0;
  61. vec3_t g_vBendOrigin;
  62.  
  63. bool g_bPatchAxisOnRow = true;
  64. int  g_nPatchAxisIndex = 0;
  65. bool g_bPatchLowerEdge = true;
  66.  
  67. // BEND states
  68. enum
  69. {
  70.   BEND_SELECT_ROTATION = 0,
  71.   BEND_SELECT_ORIGIN,
  72.   BEND_SELECT_EDGE,
  73.   BEND_BENDIT,
  74.   BEND_STATE_COUNT
  75. };
  76.  
  77. const char *g_pBendStateMsg[] =
  78. {
  79.   "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.",
  80.   "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",
  81.   "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.",
  82.   "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",
  83.   ""
  84. };
  85.  
  86. // INSERT states
  87. enum
  88. {
  89.   INSERT_SELECT_EDGE = 0,
  90.   INSERT_STATE_COUNT
  91. };
  92.  
  93. const char* g_pInsertStateMsg[] =
  94. {
  95.   "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair"
  96. };
  97.  
  98.  
  99. float *g_InversePoints[1024];
  100.  
  101. const float fFullBright = 1.0;
  102. const float fLowerLimit = .50;
  103. const float fDec = .05;
  104. void _SetColor(face_t* f, float fColor[3])
  105. {
  106.   return;
  107.   fColor[0] = f->d_color[0];
  108.   fColor[1] = f->d_color[1];
  109.   fColor[2] = f->d_color[2];
  110.   qglColor3fv(fColor);
  111. }
  112.  
  113.  
  114. void _DecColor(float fColor[3])
  115. {
  116.   return;
  117.   fColor[0] -= fDec;
  118.   fColor[1] -= fDec ;
  119.   fColor[2] -= fDec;
  120.   for (int i = 0; i < 3; i++)
  121.   {
  122.     if (fColor[i] <= fLowerLimit)
  123.     {
  124.       fColor[0] = fFullBright;
  125.       fColor[1] = fFullBright;
  126.       fColor[2] = fFullBright;
  127.       break;
  128.     }
  129.   }
  130.     qglColor3fv(fColor);
  131. }
  132.  
  133. vec_t __VectorNormalize (vec3_t in, vec3_t out)
  134. {
  135.     vec_t    length, ilength;
  136.  
  137.     length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
  138.     if (length == 0)
  139.     {
  140.         VectorClear (out);
  141.         return 0;
  142.     }
  143.  
  144.     ilength = 1.0/length;
  145.     out[0] = in[0]*ilength;
  146.     out[1] = in[1]*ilength;
  147.     out[2] = in[2]*ilength;
  148.  
  149.     return length;
  150. }
  151.  
  152.  
  153. void Patch_SetType(patchMesh_t *p, int nType)
  154. {
  155.   p->type = (p->type & PATCH_STYLEMASK) | nType;
  156. }
  157.  
  158. void Patch_SetStyle(patchMesh_t *p, int nStyle)
  159. {
  160.   p->type = (p->type & PATCH_TYPEMASK) | nStyle;
  161. }
  162.  
  163. /*
  164. ==================
  165. Patch_MemorySize
  166. ==================
  167. */
  168. int Patch_MemorySize(patchMesh_t *p)
  169. {
  170.     return _msize(p);
  171. }
  172.  
  173.  
  174.  
  175. /*
  176. ===============
  177. InterpolateInteriorPoints
  178. ===============
  179. */
  180. void InterpolateInteriorPoints( patchMesh_t *p ) 
  181. {
  182.     int        i, j, k;
  183.     int        next, prev;
  184.  
  185.     for ( i = 0 ; i < p->width ; i += 2 ) 
  186.   {
  187.  
  188.     next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width;
  189.     prev = ( i == 0 ) ? p->width - 2 : i - 1;
  190.  
  191. #if 0
  192.         if ( i == 0 ) 
  193.     {
  194.             next = ( i + 1 ) % p->width;
  195.             prev = p->width - 2;              // joined wrap case
  196.         } 
  197.     else if ( i == p->width - 1 ) 
  198.     {
  199.             next = 1;
  200.             prev = i - 1;
  201.         } 
  202.     else 
  203.     {
  204.             next = ( i + 1 ) % p->width;
  205.             prev = i - 1;
  206.         }
  207. #endif
  208.  
  209.         for ( j = 0 ; j < p->height ; j++ ) 
  210.     {
  211.             for ( k = 0 ; k < 3 ; k++ ) 
  212.       {
  213.                 p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5;
  214.             }
  215.         }
  216.     }
  217. }
  218.  
  219. /*
  220. =================
  221. MakeMeshNormals
  222.  
  223. =================
  224. */
  225. int    neighbors[8][2] = {
  226.     {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
  227. };
  228.  
  229. void Patch_MeshNormals(patchMesh_t *in ) 
  230. {
  231.     int        i, j, k, dist;
  232.     vec3_t    normal;
  233.     vec3_t    sum;
  234.     int        count;
  235.     vec3_t    base;
  236.     vec3_t    delta;
  237.     int        x, y;
  238.     drawVert_t    *dv;
  239.     vec3_t        around[8], temp;
  240.     qboolean    good[8];
  241.     qboolean    wrapWidth, wrapHeight;
  242.     float        len;
  243.  
  244.     wrapWidth = false;
  245.     for ( i = 0 ; i < in->height ; i++ ) 
  246.   {
  247.  
  248.         VectorSubtract( in->ctrl[0][i].xyz, 
  249.                           in->ctrl[in->width-1][i].xyz, delta );
  250.         len = VectorLength( delta );
  251.         if ( len > 1.0 ) 
  252.     {
  253.             break;
  254.         }
  255.     }
  256.     if ( i == in->height ) 
  257.   {
  258.         wrapWidth = true;
  259.     }
  260.  
  261.     wrapHeight = false;
  262.     for ( i = 0 ; i < in->width ; i++ ) 
  263.   {
  264.         VectorSubtract( in->ctrl[i][0].xyz, 
  265.                           in->ctrl[i][in->height-1].xyz, delta );
  266.         len = VectorLength( delta );
  267.         if ( len > 1.0 ) 
  268.     {
  269.             break;
  270.         }
  271.     }
  272.     if ( i == in->width) 
  273.   {
  274.         wrapHeight = true;
  275.     }
  276.  
  277.  
  278.     for ( i = 0 ; i < in->width ; i++ ) 
  279.   {
  280.         for ( j = 0 ; j < in->height ; j++ ) 
  281.     {
  282.             count = 0;
  283.             //--dv = reinterpret_cast<drawVert_t*>(in.ctrl[j*in.width+i]);
  284.             dv = &in->ctrl[i][j];
  285.             VectorCopy( dv->xyz, base );
  286.             for ( k = 0 ; k < 8 ; k++ ) 
  287.       {
  288.                 VectorClear( around[k] );
  289.                 good[k] = false;
  290.  
  291.                 for ( dist = 1 ; dist <= 3 ; dist++ ) 
  292.         {
  293.                     x = i + neighbors[k][0] * dist;
  294.                     y = j + neighbors[k][1] * dist;
  295.                     if ( wrapWidth ) 
  296.           {
  297.                         if ( x < 0 ) 
  298.             {
  299.                             x = in->width - 1 + x;
  300.                         } 
  301.             else if ( x >= in->width ) 
  302.             {
  303.                             x = 1 + x - in->width;
  304.                         }
  305.                     }
  306.                     if ( wrapHeight ) 
  307.           {
  308.                         if ( y < 0 ) 
  309.             {
  310.                             y = in->height - 1 + y;
  311.                         } 
  312.             else if ( y >= in->height ) 
  313.             {
  314.                             y = 1 + y - in->height;
  315.                         }
  316.                     }
  317.  
  318.                     if ( x < 0 || x >= in->width || y < 0 || y >= in->height ) 
  319.           {
  320.                         break;                    // edge of patch
  321.                     }
  322.                     //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp );
  323.                     VectorSubtract( in->ctrl[x][y].xyz, base, temp );
  324.                     if ( __VectorNormalize( temp, temp ) == 0 ) 
  325.           {
  326.                         continue;                // degenerate edge, get more dist
  327.                     } 
  328.           else                 
  329.           {
  330.                         good[k] = true;
  331.                         VectorCopy( temp, around[k] );
  332.                         break;                    // good edge
  333.                     }
  334.                 }
  335.             }
  336.  
  337.             VectorClear( sum );
  338.             for ( k = 0 ; k < 8 ; k++ ) 
  339.       {
  340.                 if ( !good[k] || !good[(k+1)&7] ) 
  341.         {
  342.                     continue;    // didn't get two points
  343.                 }
  344.                 CrossProduct( around[(k+1)&7], around[k], normal );
  345.                 if ( __VectorNormalize( normal, normal ) == 0 ) 
  346.         {
  347.                     continue;
  348.                 }
  349.                 VectorAdd( normal, sum, sum );
  350.                 count++;
  351.             }
  352.             if ( count == 0 ) 
  353.       {
  354.         //printf("bad normal\n");
  355.                 count = 1;
  356.         //continue;
  357.             }
  358.             __VectorNormalize( sum, dv->normal );
  359.         }
  360.     }
  361. }
  362.  
  363.  
  364.  
  365.  
  366. /*
  367. ==================
  368. Patch_CalcBounds
  369. ==================
  370. */
  371. void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax)
  372. {
  373.   vMin[0] = vMin[1] = vMin[2] = 99999;
  374.   vMax[0] = vMax[1] = vMax[2] = -99999;
  375.  
  376.   p->bDirty = true;
  377.   for (int w = 0; w < p->width; w++)
  378.   {
  379.     for (int h = 0; h < p->height; h++)
  380.     {
  381.       for (int j = 0; j < 3; j++)
  382.       {
  383.         float f = p->ctrl[w][h].xyz[j];
  384.         if (f < vMin[j])
  385.           vMin[j] = f;
  386.         if (f > vMax[j])
  387.           vMax[j] = f;
  388.       }
  389.     }
  390.   }
  391. }
  392.  
  393. /*
  394. ==================
  395. Brush_RebuildBrush
  396. ==================
  397. */
  398. void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs)
  399. {
  400.   //
  401.   // Total hack job 
  402.   // Rebuilds a brush
  403.     int        i, j;
  404.     face_t    *f, *next;
  405.     vec3_t    pts[4][2];
  406.   texdef_t    texdef;
  407.     // free faces
  408.  
  409.   for (j = 0; j < 3; j++)
  410.   {
  411.     if ((int)vMins[j] == (int)vMaxs[j])
  412.     {
  413.       vMins[j] -= 4;
  414.       vMaxs[j] += 4;
  415.     }
  416.   }
  417.  
  418.   
  419.   for (f=b->brush_faces ; f ; f=next)
  420.     {
  421.         next = f->next;
  422.     if (f)
  423.       texdef = f->texdef;
  424.     Face_Free( f );
  425.     }
  426.  
  427.   b->brush_faces = NULL;
  428.  
  429.   // left the last face so we can use its texdef
  430.  
  431.     for (i=0 ; i<3 ; i++)
  432.         if (vMaxs[i] < vMins[i])
  433.             Error ("Brush_RebuildBrush: backwards");
  434.  
  435.     pts[0][0][0] = vMins[0];
  436.     pts[0][0][1] = vMins[1];
  437.     
  438.     pts[1][0][0] = vMins[0];
  439.     pts[1][0][1] = vMaxs[1];
  440.     
  441.     pts[2][0][0] = vMaxs[0];
  442.     pts[2][0][1] = vMaxs[1];
  443.     
  444.     pts[3][0][0] = vMaxs[0];
  445.     pts[3][0][1] = vMins[1];
  446.     
  447.     for (i=0 ; i<4 ; i++)
  448.     {
  449.         pts[i][0][2] = vMins[2];
  450.         pts[i][1][0] = pts[i][0][0];
  451.         pts[i][1][1] = pts[i][0][1];
  452.         pts[i][1][2] = vMaxs[2];
  453.     }
  454.  
  455.     for (i=0 ; i<4 ; i++)
  456.     {
  457.         f = Face_Alloc();
  458.         f->texdef = texdef;
  459.         f->texdef.flags &= ~SURF_KEEP;
  460.         f->texdef.contents &= ~CONTENTS_KEEP;
  461.         f->texdef.flags |= SURF_PATCH; 
  462.         f->next = b->brush_faces;
  463.         b->brush_faces = f;
  464.         j = (i+1)%4;
  465.  
  466.         VectorCopy (pts[j][1], f->planepts[0]);
  467.         VectorCopy (pts[i][1], f->planepts[1]);
  468.         VectorCopy (pts[i][0], f->planepts[2]);
  469.     }
  470.     
  471.     f = Face_Alloc();
  472.     f->texdef = texdef;
  473.   f->texdef.flags &= ~SURF_KEEP;
  474.     f->texdef.contents &= ~CONTENTS_KEEP;
  475.   f->texdef.flags |= SURF_PATCH; 
  476.     f->next = b->brush_faces;
  477.     b->brush_faces = f;
  478.  
  479.     VectorCopy (pts[0][1], f->planepts[0]);
  480.     VectorCopy (pts[1][1], f->planepts[1]);
  481.     VectorCopy (pts[2][1], f->planepts[2]);
  482.  
  483.     f = Face_Alloc();
  484.     f->texdef = texdef;
  485.   f->texdef.flags &= ~SURF_KEEP;
  486.     f->texdef.contents &= ~CONTENTS_KEEP;
  487.   f->texdef.flags |= SURF_PATCH; 
  488.     f->next = b->brush_faces;
  489.     b->brush_faces = f;
  490.  
  491.     VectorCopy (pts[2][0], f->planepts[0]);
  492.     VectorCopy (pts[1][0], f->planepts[1]);
  493.     VectorCopy (pts[0][0], f->planepts[2]);
  494.  
  495.   Brush_Build(b);
  496. }
  497.  
  498. void WINAPI Patch_Rebuild(patchMesh_t *p)
  499. {
  500.   vec3_t vMin, vMax;
  501.   Patch_CalcBounds(p, vMin, vMax);
  502.   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  503.   p->bDirty = true;
  504. }
  505.  
  506. /*
  507. ==================
  508. AddBrushForPatch
  509. ==================
  510.  adds a patch brush and ties it to this patch id
  511. */
  512. brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld )
  513. {
  514.   // find the farthest points in x,y,z
  515.   vec3_t vMin, vMax;
  516.   Patch_CalcBounds(pm, vMin, vMax);
  517.  
  518.   for (int j = 0; j < 3; j++)
  519.   {
  520.     if (vMin[j] == vMax[j])
  521.     {
  522.       vMin[j] -= 4;
  523.       vMax[j] += 4;
  524.     }
  525.   }
  526.  
  527.   brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
  528.     face_t        *f;
  529.     for (f=b->brush_faces ; f ; f=f->next) 
  530.   {
  531.         f->texdef.flags |= SURF_PATCH; 
  532.     }
  533.  
  534.   // FIXME: this entire type of linkage needs to be fixed
  535.   b->pPatch = pm;
  536.   pm->pSymbiot = b;
  537.   pm->bSelected = false;
  538.   pm->bOverlay = false;
  539.   pm->bDirty = true;
  540.   pm->nListID = -1;
  541.  
  542.   if (bLinkToWorld)
  543.   {
  544.     Brush_AddToList (b, &active_brushes);
  545.       Entity_LinkBrush (world_entity, b);
  546.     Brush_Build(b);
  547.   }
  548.  
  549.   return b;
  550. }
  551.  
  552. void Patch_SetPointIntensities(int n)
  553. {
  554. #if 0
  555.     patchMesh_t    *p = patchMeshes[n];
  556.   for (int i = 0; i < p->width; i++)
  557.   {
  558.     for (int j = 0; j < p->height; j++)
  559.     {
  560.  
  561.     }
  562.   }
  563. #endif
  564. }
  565.  
  566. // very approximate widths and heights
  567.  
  568. /*
  569. ==================
  570. Patch_Width
  571. ==================
  572. */
  573. float Patch_Width(patchMesh_t *p)
  574. {
  575.   float f = 0;
  576.   for (int i = 0; i < p->width-1; i++)
  577.   {
  578.     vec3_t vTemp;
  579.     VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
  580.     f += VectorLength(vTemp);
  581.   }
  582.   return f;
  583. }
  584.  
  585. float Patch_WidthDistanceTo(patchMesh_t *p, int j)
  586. {
  587.   float f = 0;
  588.   for (int i = 0; i < j; i++)
  589.   {
  590.     vec3_t vTemp;
  591.     VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
  592.     f += VectorLength(vTemp);
  593.   }
  594.   return f;
  595. }
  596.  
  597.  
  598.  
  599. /*
  600. ==================
  601. Patch_Height
  602. ==================
  603. */
  604. float Patch_Height(patchMesh_t *p)
  605. {
  606.   float f = 0;
  607.   for (int i = 0; i < p->height-1; i++)
  608.   {
  609.     vec3_t vTemp;
  610.     VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
  611.     f += VectorLength(vTemp);
  612.   }
  613.   return f;
  614. }
  615.  
  616. float Patch_HeightDistanceTo(patchMesh_t *p, int j)
  617. {
  618.   float f = 0;
  619.   for (int i = 0; i < j; i++)
  620.   {
  621.     vec3_t vTemp;
  622.     VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
  623.     f += VectorLength(vTemp);
  624.   }
  625.   return f;
  626. }
  627.  
  628.  
  629.  
  630. /*
  631. ==================
  632. Patch_Naturalize
  633. ==================
  634. texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength
  635.  
  636. dist( this control point to first control point ) / dist ( last control pt to first)
  637. */
  638. void Patch_Naturalize(patchMesh_t *p)
  639. {
  640.   int nWidth = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? p->d_texture->width * 0.5 : p->d_texture->width;
  641.   int nHeight = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? p->d_texture->height * 0.5 : p->d_texture->height;
  642.   float fPWidth = Patch_Width(p);
  643.   float fPHeight = Patch_Height(p);
  644.   float xAccum = 0;
  645.   for ( int i = 0 ; i < p->width ; i++ ) 
  646.   {
  647.     float yAccum = 0;
  648.       for ( int j = 0 ; j < p->height ; j++ ) 
  649.     {
  650.           p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth;
  651.           p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight;
  652.           yAccum = Patch_HeightDistanceTo(p,j+1);
  653.       //p->ctrl[i][j][3] = (fPWidth / nWidth) * (float)i / (p->width - 1);
  654.           //p->ctrl[i][j][4] = (fPHeight/ nHeight) * (float)j / (p->height - 1);
  655.       }
  656.     xAccum = Patch_WidthDistanceTo(p,i+1);
  657.   }
  658.   p->bDirty = true;
  659. }
  660.  
  661. /*
  662.   if (bIBevel)
  663.   {
  664.     VectorCopy(p->ctrl[1][0], p->ctrl[1][1]);
  665.   }
  666.  
  667.   if (bIEndcap)
  668.   {
  669.     VectorCopy(p->ctrl[3][0], p->ctrl[4][1]);
  670.     VectorCopy(p->ctrl[2][0], p->ctrl[3][1]);
  671.     VectorCopy(p->ctrl[2][0], p->ctrl[2][1]);
  672.     VectorCopy(p->ctrl[2][0], p->ctrl[1][1]);
  673.     VectorCopy(p->ctrl[1][0], p->ctrl[0][1]);
  674.     VectorCopy(p->ctrl[1][0], p->ctrl[0][2]);
  675.     VectorCopy(p->ctrl[1][0], p->ctrl[1][2]);
  676.     VectorCopy(p->ctrl[2][0], p->ctrl[2][2]);
  677.     VectorCopy(p->ctrl[3][0], p->ctrl[3][2]);
  678.     VectorCopy(p->ctrl[3][0], p->ctrl[4][2]);
  679.   }
  680. */
  681.  
  682. int Index3By[][2] =
  683. {
  684.   {0,0},
  685.   {1,0},
  686.   {2,0},
  687.   {2,1},
  688.   {2,2},
  689.   {1,2},
  690.   {0,2},
  691.   {0,1},
  692.   {0,0},
  693.   {0,0},
  694.   {0,0},
  695.   {0,0},
  696.   {0,0},
  697.   {0,0},
  698.   {0,0}
  699. };
  700.  
  701. int Index5By[][2] =
  702. {
  703.   {0,0},
  704.   {1,0},
  705.   {2,0},
  706.   {3,0},
  707.   {4,0},
  708.   {4,1},
  709.   {4,2},
  710.   {4,3},
  711.   {4,4},
  712.   {3,4},
  713.   {2,4},
  714.   {1,4},
  715.   {0,4},
  716.   {0,3},
  717.   {0,2},
  718.   {0,1}
  719. };
  720.  
  721.  
  722.  
  723. int Interior3By[][2] =
  724. {
  725.   {1,1}
  726. };
  727.  
  728. int Interior5By[][2] =
  729. {
  730.   {1,1},
  731.   {2,1},
  732.   {3,1},
  733.   {1,2},
  734.   {2,2},
  735.   {3,2},
  736.   {1,3},
  737.   {2,3},
  738.   {3,3}
  739. };
  740.  
  741. int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]);
  742. int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]);
  743.  
  744. face_t* Patch_GetAxisFace(patchMesh_t *p)
  745. {
  746.   face_t *f = NULL;
  747.   vec3_t vTemp;
  748.   brush_t *b = p->pSymbiot;
  749.  
  750.     for (f = b->brush_faces ; f ; f = f->next) 
  751.   {
  752.     VectorSubtract(f->face_winding->points[1], f->face_winding->points[0], vTemp);
  753.     int nScore = 0;
  754.  
  755.     // default edge faces on caps are 8 high so
  756.     // as soon as we hit one that is bigger it should be on the right axis
  757.     for (int j = 0; j < 3; j++)
  758.     {
  759.       if (vTemp[j] > 8)
  760.         nScore++;
  761.     }
  762.  
  763.     if (nScore > 0)
  764.       break;
  765.   }
  766.  
  767.   if (f == NULL)
  768.     f = b->brush_faces;
  769.   return f;
  770. }
  771.  
  772. int g_nFaceCycle = 0;
  773.  
  774. face_t* nextFace(patchMesh_t *p)
  775. {
  776.   brush_t *b = p->pSymbiot;
  777.   face_t *f = NULL;
  778.   int n = 0;
  779.     for (f = b->brush_faces ; f && n <= g_nFaceCycle; f = f->next) 
  780.   {
  781.     n++;
  782.   }
  783.   g_nFaceCycle++;
  784.   if (g_nFaceCycle > 5)
  785.   {
  786.     g_nFaceCycle =0;
  787.     f = b->brush_faces;
  788.   }
  789.  
  790.   return f;
  791. }
  792.  
  793.  
  794. extern void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f);
  795. void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false)
  796. {
  797.   Patch_MeshNormals(p);
  798.   face_t *f = (bFaceCycle) ? nextFace(p) : Patch_GetAxisFace(p);
  799.   vec3_t vSave;
  800.   VectorCopy(f->plane.normal, vSave);
  801.   
  802.   float fRotate = f->texdef.rotate;
  803.   f->texdef.rotate = 0;
  804.   float fScale[2];
  805.   fScale[0] = f->texdef.scale[0];
  806.   fScale[1] = f->texdef.scale[1];
  807.   f->texdef.scale[0] = 0.5;
  808.   f->texdef.scale[1] = 0.5;
  809.   float fShift[2];
  810.   fShift[0] = f->texdef.shift[0];
  811.   fShift[1] = f->texdef.shift[1];
  812.   f->texdef.shift[0] = 0;
  813.   f->texdef.shift[1] = 0;
  814.   
  815.   for (int i = 0; i < p->width; i++)
  816.   {
  817.     for (int j = 0; j < p->height; j++)
  818.     {
  819.       if (!bFaceCycle)
  820.       {
  821.         VectorCopy(p->ctrl[i][j].normal, f->plane.normal);
  822.       }
  823.           EmitTextureCoordinates( p->ctrl[i][j].xyz, f->d_texture, f);
  824.     }
  825.   }
  826.   VectorCopy(vSave, f->plane.normal);
  827.   f->texdef.rotate = fRotate;
  828.   f->texdef.scale[0] = fScale[0];
  829.   f->texdef.scale[1] = fScale[1];
  830.   f->texdef.shift[0] = fShift[0];
  831.   f->texdef.shift[1] = fShift[1];
  832.   p->bDirty = true;
  833. }
  834.  
  835. void FillPatch(patchMesh_t *p, vec3_t v)
  836. {
  837.   for (int i = 0; i < p->width; i++)
  838.   {
  839.     for (int j = 0; j < p->height; j++)
  840.     {
  841.       VectorCopy(v, p->ctrl[i][j].xyz);
  842.     }
  843.   }
  844. }
  845.  
  846. brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst)
  847. {
  848.   brush_t *b;
  849.   patchMesh_t *p;
  850.   vec3_t vMin, vMax;
  851.   int i, j;
  852.  
  853.   bool bSmall = true;
  854.   // make a generic patch
  855.   if (pParent->width <= 9)
  856.   {
  857.     b = Patch_GenericMesh(3, 3, 2, false);
  858.   }
  859.   else
  860.   {
  861.     b = Patch_GenericMesh(5, 5, 2, false);
  862.     bSmall = false;
  863.   }
  864.  
  865.   if (!b)
  866.   {
  867.     Sys_Printf("Unable to cap. You may need to ungroup the patch.\n");
  868.     return NULL;
  869.   }
  870.  
  871.   p = b->pPatch;
  872.   p->type |= PATCH_CAP;
  873.  
  874.   vMin[0] = vMin[1] = vMin[2] = 9999;
  875.   vMax[0] = vMax[1] = vMax[2] = -9999;
  876.  
  877.   // we seam the column edge, FIXME: this might need to be able to seem either edge
  878.   // 
  879.   int nSize = (bByColumn) ? pParent->width : pParent->height;
  880.   int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1;
  881.  
  882.   FillPatch(p, pParent->ctrl[0][nIndex].xyz);
  883.  
  884.   for (i = 0; i < nSize; i++)
  885.   {
  886.     if (bByColumn)
  887.     {
  888.       if (bSmall)
  889.       {
  890.         VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
  891.       }
  892.       else
  893.       {
  894.         VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
  895.       }
  896.     }
  897.     else
  898.     {
  899.       if (bSmall)
  900.       {
  901.         VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
  902.       }
  903.       else
  904.       {
  905.         VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
  906.       }
  907.     }
  908.   
  909.     for (j = 0; j < 3; j++)
  910.     {
  911.       float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j];
  912.       if (f < vMin[j])
  913.         vMin[j] = f;
  914.       if (f > vMax[j])
  915.         vMax[j] = f;
  916.     }
  917.   }
  918.  
  919.   vec3_t vTemp;
  920.   for (j = 0; j < 3; j++)
  921.   {
  922.     vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
  923.   }
  924.  
  925.   int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount;
  926.   for (j = 0; j < nCount; j++)
  927.   {
  928.     if (bSmall)
  929.     {
  930.       VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz);
  931.     }
  932.     else
  933.     {
  934.       VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz);
  935.     }
  936.   }
  937.  
  938.   if (bFirst)
  939.   {
  940.     drawVert_t vertTemp;
  941.     for (i = 0; i < p->width; i++)
  942.     {
  943.       for (j = 0; j < p->height / 2; j++)
  944.       {
  945.         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
  946.         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
  947.         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
  948.       }
  949.     }
  950.   }
  951.  
  952.   Patch_Rebuild(p);
  953.   Patch_CapTexture(p);
  954.   return p->pSymbiot;
  955. }
  956.  
  957. brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst)
  958. {
  959.   brush_t *b;
  960.   patchMesh_t *p;
  961.   vec3_t vMin, vMax, vTemp;
  962.   int i, j;
  963.  
  964.   if (nType == CCapDialog::IENDCAP)
  965.     b = Patch_GenericMesh(5, 3, 2, false);
  966.   else
  967.     b = Patch_GenericMesh(3, 3, 2, false);
  968.  
  969.   if (!b)
  970.   {
  971.     Sys_Printf("Unable to cap. Make sure you ungroup before re-capping.");
  972.     return NULL;
  973.   }
  974.  
  975.   p = b->pPatch;
  976.   p->type |= PATCH_CAP;
  977.  
  978.   vMin[0] = vMin[1] = vMin[2] = 9999;
  979.   vMax[0] = vMax[1] = vMax[2] = -9999;
  980.  
  981.   int nSize = pParent->width;
  982.   int nIndex = (bFirst) ? 0 : pParent->height-1;
  983.  
  984.   // parent bounds are used for some things
  985.   Patch_CalcBounds(pParent, vMin, vMax);
  986.  
  987.   for (j = 0; j < 3; j++)
  988.   {
  989.     vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
  990.   }
  991.  
  992.   if (nType == CCapDialog::IBEVEL)
  993.   {
  994.     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
  995.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
  996.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
  997.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz);
  998.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
  999.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
  1000.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
  1001.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz);
  1002.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz);
  1003.   }
  1004.   else if (nType == CCapDialog::BEVEL)
  1005.   {
  1006.     vec3_t p1, p2, p3, p4, temp, dir;
  1007.  
  1008.     VectorCopy(pParent->ctrl[0][nIndex].xyz, p3);
  1009.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p1);
  1010.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p2);
  1011.  
  1012.     VectorSubtract(p3, p2, dir);
  1013.     VectorNormalize(dir);
  1014.     VectorSubtract(p1, p2, temp);
  1015.     vec_t dist = _DotProduct(temp, dir);
  1016.  
  1017.     VectorScale(dir, dist, temp);
  1018.  
  1019.     VectorAdd(p2, temp, temp);
  1020.  
  1021.     VectorSubtract(temp, p1, temp);
  1022.     VectorScale(temp, 2, temp);
  1023.     VectorAdd(p1, temp, p4);
  1024.  
  1025.     VectorCopy(p4, p->ctrl[0][0].xyz);
  1026.     VectorCopy(p4, p->ctrl[1][0].xyz);
  1027.     VectorCopy(p4, p->ctrl[0][1].xyz);
  1028.     VectorCopy(p4, p->ctrl[1][1].xyz);
  1029.     VectorCopy(p4, p->ctrl[0][2].xyz);
  1030.     VectorCopy(p4, p->ctrl[1][2].xyz);
  1031.     VectorCopy(p3, p->ctrl[2][0].xyz);
  1032.     VectorCopy(p1, p->ctrl[2][1].xyz);
  1033.     VectorCopy(p2, p->ctrl[2][2].xyz);
  1034.  
  1035.   }
  1036.   else if (nType == CCapDialog::ENDCAP)
  1037.   {
  1038.     VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp);
  1039.     VectorScale(vTemp, 0.5, vTemp);
  1040.     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
  1041.                        VectorCopy(vTemp, p->ctrl[1][0].xyz);
  1042.     VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz);
  1043.  
  1044.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
  1045.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz);
  1046.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
  1047.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz);
  1048.     
  1049.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
  1050.     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz);
  1051.   }
  1052.   else
  1053.   {
  1054.     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
  1055.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
  1056.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz);
  1057.     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][0].xyz);
  1058.     VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[4][0].xyz);
  1059.     
  1060.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
  1061.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
  1062.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz);
  1063.     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][1].xyz);
  1064.     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[4][1].xyz);
  1065.  
  1066.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][2].xyz);
  1067.     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
  1068.     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
  1069.     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][2].xyz);
  1070.     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[4][2].xyz);
  1071.   }
  1072.  
  1073.  
  1074.   bool bEndCap = (nType == CCapDialog::ENDCAP || nType == CCapDialog::IENDCAP);
  1075.   if ((!bFirst && !bEndCap) || (bFirst && bEndCap))
  1076.   {
  1077.     drawVert_t vertTemp;
  1078.     for (i = 0; i < p->width; i++)
  1079.     {
  1080.       for (j = 0; j < p->height / 2; j++)
  1081.       {
  1082.         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
  1083.         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
  1084.         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
  1085.       }
  1086.     }
  1087.   }
  1088.  
  1089.   //--Patch_CalcBounds(p, vMin, vMax);
  1090.   //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  1091.   Patch_Rebuild(p);
  1092.   Patch_CapTexture(p);
  1093.   return p->pSymbiot;
  1094. }
  1095.  
  1096.  
  1097. void Patch_CapCurrent(bool bInvertedBevel, bool bInvertedEndcap)
  1098. {
  1099.   patchMesh_t *pParent = NULL;
  1100.   brush_t *b[4];
  1101.   brush_t *pCap = NULL;
  1102.   b[0] = b[1] = b[2] = b[3] = NULL;
  1103.   int nIndex = 0;
  1104.  
  1105.     if (!QE_SingleBrush())
  1106.   {
  1107.     Sys_Printf("Cannot cap multiple selection. Please select a single patch.\n");
  1108.         return;
  1109.   }
  1110.  
  1111.  
  1112.     for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next)
  1113.     {
  1114.     if (pb->patchBrush)
  1115.     {
  1116.       pParent = pb->pPatch;
  1117.       // decide which if any ends we are going to cap
  1118.       // if any of these compares hit, it is a closed patch and as such
  1119.       // the generic capping will work.. if we do not find a closed edge 
  1120.       // then we need to ask which kind of cap to add
  1121.       if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz))
  1122.       {
  1123.         pCap = Cap(pParent, true, false);
  1124.         if (pCap != NULL)
  1125.         {
  1126.           b[nIndex++] = pCap;
  1127.         }
  1128.       }
  1129.       if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
  1130.       {
  1131.         pCap = Cap(pParent, true, true);
  1132.         if (pCap != NULL)
  1133.         {
  1134.           b[nIndex++] = pCap;
  1135.         }
  1136.       }
  1137.       if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz))
  1138.       {
  1139.         pCap = Cap(pParent, false, false);
  1140.         if (pCap != NULL)
  1141.         {
  1142.           b[nIndex++] = pCap;
  1143.         }
  1144.       }
  1145.       if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
  1146.       {
  1147.         pCap = Cap(pParent, false, true);
  1148.         if (pCap != NULL)
  1149.         {
  1150.           b[nIndex++] = pCap;
  1151.         }
  1152.       }
  1153.     }
  1154.   }
  1155.  
  1156.   if (pParent)
  1157.   {
  1158.     // if we did not cap anything with the above tests
  1159.     if (nIndex == 0)
  1160.     {
  1161.       CCapDialog dlg;
  1162.       if (dlg.DoModal() == IDOK)
  1163.       {
  1164.         b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), false);
  1165.         b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), true);
  1166.       }
  1167.     }
  1168.  
  1169.     if (nIndex > 0)
  1170.     {
  1171.       while (nIndex > 0)
  1172.       {
  1173.         nIndex--;
  1174.         if (b[nIndex])
  1175.         {
  1176.           Select_Brush(b[nIndex]);
  1177.         }
  1178.       }
  1179.       eclass_t *pecNew = Eclass_ForName("func_group", false);
  1180.       if (pecNew)
  1181.       {
  1182.         entity_t *e = Entity_Create(pecNew);
  1183.         SetKeyValue(e, "type", "patchCapped");
  1184.       }
  1185.     }
  1186.   }
  1187. }
  1188.  
  1189.  
  1190. //FIXME: Table drive all this crap
  1191. //
  1192. void GenerateEndCaps(brush_t *brushParent, bool bBevel, bool bEndcap, bool bInverted)
  1193. {
  1194.   brush_t *b, *b2;
  1195.   patchMesh_t *p, *p2, *pParent;
  1196.   vec3_t vTemp, vMin, vMax;
  1197.   int i, j;
  1198.  
  1199.   pParent = brushParent->pPatch;
  1200.  
  1201.   Patch_CalcBounds(pParent, vMin, vMax);
  1202.   // basically generate two endcaps, place them, and link the three brushes with a func_group
  1203.  
  1204.   if (pParent->width > 9)
  1205.     b = Patch_GenericMesh(5, 3, 2, false);
  1206.   else
  1207.     b = Patch_GenericMesh(3, 3, 2, false);
  1208.   p = b->pPatch;
  1209.  
  1210.   vMin[0] = vMin[1] = vMin[2] = 9999;
  1211.   vMax[0] = vMax[1] = vMax[2] = -9999;
  1212.  
  1213.   for (i = 0; i < pParent->width; i++)
  1214.   {
  1215.     VectorCopy(pParent->ctrl[i][0].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
  1216.     for (j = 0; j < 3; j++)
  1217.     {
  1218.       if (pParent->ctrl[i][0].xyz[j] < vMin[j])
  1219.         vMin[j] = pParent->ctrl[i][0].xyz[j];
  1220.       if (pParent->ctrl[i][0].xyz[j] > vMax[j])
  1221.         vMax[j] = pParent->ctrl[i][0].xyz[j];
  1222.     }
  1223.   }
  1224.  
  1225.   for (j = 0; j < 3; j++)
  1226.   {
  1227.     vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
  1228.   }
  1229.  
  1230.   for (i = 0; i < Interior3ByCount; i++)
  1231.   {
  1232.     VectorCopy(vTemp, p->ctrl[Interior3By[i][0]][Interior3By[i][1]].xyz);
  1233.   }
  1234.  
  1235.   Patch_CalcBounds(p, vMin, vMax);
  1236.   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  1237.   Select_Brush(p->pSymbiot);
  1238.   return;
  1239.  
  1240.   bool bCreated = false;
  1241.  
  1242.   if (bInverted)
  1243.   {
  1244.     if (bBevel)
  1245.     {
  1246.       b = Patch_GenericMesh(3, 3, 2, false);
  1247.       p = b->pPatch;
  1248.       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][2].xyz);
  1249.       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[2][1].xyz);
  1250.       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[0][1].xyz);
  1251.       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][0].xyz);
  1252.       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][1].xyz);
  1253.       VectorCopy(p->ctrl[2][0].xyz, p->ctrl[0][0].xyz);
  1254.  
  1255.       b2 = Patch_GenericMesh(3, 3, 2, false);
  1256.       p2 = b2->pPatch;
  1257.       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][2].xyz);
  1258.       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[2][1].xyz);
  1259.       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[0][1].xyz);
  1260.       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][0].xyz);
  1261.       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][1].xyz);
  1262.       VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[0][0].xyz);
  1263.  
  1264.  
  1265.       bCreated = true;
  1266.  
  1267.     }
  1268.     else if (bEndcap)
  1269.     {
  1270.       b = Patch_GenericMesh(5, 5, 2, false);
  1271.       p = b->pPatch;
  1272.       VectorCopy(p->ctrl[4][4].xyz, p->ctrl[4][3].xyz);
  1273.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[1][4].xyz);
  1274.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[2][4].xyz);
  1275.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[3][4].xyz);
  1276.  
  1277.       VectorCopy(p->ctrl[4][0].xyz, p->ctrl[4][1].xyz);
  1278.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
  1279.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
  1280.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[3][0].xyz);
  1281.  
  1282.       for (i = 1; i < 4; i++)
  1283.       {
  1284.         for (j = 0; j < 4; j++)
  1285.         {
  1286.           VectorCopy(p->ctrl[4][i].xyz, p->ctrl[j][i].xyz);
  1287.         }
  1288.       }
  1289.  
  1290.  
  1291.       b2 = Patch_GenericMesh(5, 5, 2, false);
  1292.       p2 = b2->pPatch;
  1293.       VectorCopy(p2->ctrl[4][4].xyz, p2->ctrl[4][3].xyz);
  1294.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[1][4].xyz);
  1295.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[2][4].xyz);
  1296.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[3][4].xyz);
  1297.  
  1298.       VectorCopy(p2->ctrl[4][0].xyz, p2->ctrl[4][1].xyz);
  1299.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
  1300.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
  1301.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[3][0].xyz);
  1302.  
  1303.       for (i = 1; i < 4; i++)
  1304.       {
  1305.         for (j = 0; j < 4; j++)
  1306.         {
  1307.           VectorCopy(p2->ctrl[4][i].xyz, p2->ctrl[j][i].xyz);
  1308.         }
  1309.       }
  1310.  
  1311.  
  1312.       bCreated = true;
  1313.     }
  1314.   }
  1315.   else
  1316.   {
  1317.     if (bBevel)
  1318.     {
  1319.       b = Patch_GenericMesh(3, 3, 2, false);
  1320.       p = b->pPatch;
  1321.       VectorCopy(p->ctrl[2][0].xyz, p->ctrl[2][1].xyz);
  1322.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
  1323.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
  1324.  
  1325.       b2 = Patch_GenericMesh(3, 3, 2, false);
  1326.       p2 = b2->pPatch;
  1327.       VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[2][1].xyz);
  1328.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
  1329.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
  1330.       bCreated = true;
  1331.     }
  1332.     else if (bEndcap)
  1333.     {
  1334.       b = Patch_GenericMesh(5, 5, 2, false);
  1335.       p = b->pPatch;
  1336.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
  1337.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
  1338.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[3][0].xyz);
  1339.       VectorCopy(p->ctrl[4][0].xyz, p->ctrl[4][1].xyz);
  1340.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[4][0].xyz);
  1341.  
  1342.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[1][4].xyz);
  1343.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[2][4].xyz);
  1344.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[3][4].xyz);
  1345.       VectorCopy(p->ctrl[4][4].xyz, p->ctrl[4][3].xyz);
  1346.       VectorCopy(p->ctrl[0][4].xyz, p->ctrl[4][4].xyz);
  1347.  
  1348.       b2 = Patch_GenericMesh(5, 5, 2, false);
  1349.       p2 = b2->pPatch;
  1350.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
  1351.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
  1352.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[3][0].xyz);
  1353.       VectorCopy(p2->ctrl[4][0].xyz, p2->ctrl[4][1].xyz);
  1354.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[4][0].xyz);
  1355.  
  1356.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[1][4].xyz);
  1357.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[2][4].xyz);
  1358.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[3][4].xyz);
  1359.       VectorCopy(p2->ctrl[4][4].xyz, p2->ctrl[4][3].xyz);
  1360.       VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[4][4].xyz);
  1361.       bCreated = true;
  1362.     }
  1363.     else
  1364.     {
  1365.       b = Patch_GenericMesh(3, 3, 2, false);
  1366.       p = b->pPatch;
  1367.       
  1368.       VectorCopy(p->ctrl[0][1].xyz, vTemp);
  1369.       VectorCopy(p->ctrl[0][2].xyz, p->ctrl[0][1].xyz)
  1370.       VectorCopy(p->ctrl[1][2].xyz, p->ctrl[0][2].xyz)
  1371.       VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][2].xyz)
  1372.       VectorCopy(p->ctrl[2][1].xyz, p->ctrl[2][2].xyz)
  1373.       VectorCopy(p->ctrl[2][0].xyz, p->ctrl[2][1].xyz)
  1374.       VectorCopy(p->ctrl[1][0].xyz, p->ctrl[2][0].xyz)
  1375.       VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz)
  1376.       VectorCopy(vTemp, p->ctrl[0][0].xyz)
  1377.  
  1378.       b2 = Patch_GenericMesh(3, 3, 2, false);
  1379.       p2 = b2->pPatch;
  1380.       VectorCopy(p2->ctrl[0][1].xyz, vTemp);
  1381.       VectorCopy(p2->ctrl[0][2].xyz, p2->ctrl[0][1].xyz)
  1382.       VectorCopy(p2->ctrl[1][2].xyz, p2->ctrl[0][2].xyz)
  1383.       VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][2].xyz)
  1384.       VectorCopy(p2->ctrl[2][1].xyz, p2->ctrl[2][2].xyz)
  1385.       VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[2][1].xyz)
  1386.       VectorCopy(p2->ctrl[1][0].xyz, p2->ctrl[2][0].xyz)
  1387.       VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz)
  1388.       VectorCopy(vTemp, p2->ctrl[0][0].xyz)
  1389.       bCreated = true;
  1390.     }
  1391.   }
  1392.  
  1393.   if (bCreated)
  1394.   {
  1395.     drawVert_t vertTemp;
  1396.     for (i = 0; i < p->width; i++)
  1397.     {
  1398.       for (j = 0; j < p->height; j++)
  1399.       {
  1400.         p->ctrl[i][j].xyz[2] = vMin[2];
  1401.         p2->ctrl[i][j].xyz[2] = vMax[2];
  1402.       }
  1403.  
  1404.       for (j = 0; j < p->height / 2; j++)
  1405.       {
  1406.         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
  1407.         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
  1408.         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
  1409.       }
  1410.  
  1411.     }
  1412.     //Select_Delete();
  1413.  
  1414.     Patch_CalcBounds(p, vMin, vMax);
  1415.     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  1416.     Patch_CalcBounds(p2, vMin, vMax);
  1417.     Brush_RebuildBrush(p2->pSymbiot, vMin, vMax);
  1418.     Select_Brush(p->pSymbiot);
  1419.     Select_Brush(p2->pSymbiot);
  1420.   }
  1421.   else
  1422.   {
  1423.     Select_Delete();
  1424.   }
  1425.   //Select_Brush(brushParent);
  1426.  
  1427. }
  1428.  
  1429.  
  1430. /*
  1431. ===============
  1432. BrushToPatchMesh
  1433. ===============
  1434. */
  1435. void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight)
  1436. {
  1437.     brush_t        *b;
  1438.     patchMesh_t    *p;
  1439.     int            i,j;
  1440.  
  1441.     if (!QE_SingleBrush())
  1442.         return;
  1443.  
  1444.     b = selected_brushes.next;
  1445.  
  1446.     p = MakeNewPatch();
  1447.  
  1448.     p->d_texture = b->brush_faces->d_texture;
  1449.  
  1450.   p->height = nHeight;
  1451.  
  1452.   p->type = PATCH_CYLINDER;
  1453.   if (bBevel & !bSquare)
  1454.   {
  1455.     p->type = PATCH_BEVEL;
  1456.     p->width = 3;
  1457.     int nStep = (b->maxs[2] - b->mins[2]) / (p->height-1);
  1458.     int nStart = b->mins[2];
  1459.     for (i = 0; i < p->height; i++)
  1460.     {
  1461.         p->ctrl[0][i].xyz[0] =  b->mins[0];
  1462.         p->ctrl[0][i].xyz[1] =  b->mins[1];
  1463.       p->ctrl[0][i].xyz[2] = nStart;
  1464.  
  1465.         p->ctrl[1][i].xyz[0] =  b->maxs[0];
  1466.         p->ctrl[1][i].xyz[1] =  b->mins[1];
  1467.       p->ctrl[1][i].xyz[2] = nStart;
  1468.  
  1469.         p->ctrl[2][i].xyz[0] =  b->maxs[0];
  1470.         p->ctrl[2][i].xyz[1] =  b->maxs[1];
  1471.       p->ctrl[2][i].xyz[2] = nStart;
  1472.       nStart += nStep;
  1473.     }
  1474.   }
  1475.   else if (bEndcap & !bSquare)
  1476.   {
  1477.     p->type = PATCH_ENDCAP;
  1478.     p->width = 5;
  1479.     int nStep = (b->maxs[2] - b->mins[2]) / (p->height-1);
  1480.     int nStart = b->mins[2];
  1481.     for (i = 0; i < p->height; i++)
  1482.     {
  1483.         p->ctrl[0][i].xyz[0] =  b->mins[0];
  1484.         p->ctrl[0][i].xyz[1] =  b->mins[1];
  1485.       p->ctrl[0][i].xyz[2] = nStart;
  1486.  
  1487.         p->ctrl[1][i].xyz[0] =  b->mins[0];
  1488.         p->ctrl[1][i].xyz[1] =  b->maxs[1];
  1489.       p->ctrl[1][i].xyz[2] = nStart;
  1490.  
  1491.         p->ctrl[2][i].xyz[0] =  b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5);
  1492.         p->ctrl[2][i].xyz[1] =  b->maxs[1];
  1493.       p->ctrl[2][i].xyz[2] = nStart;
  1494.        
  1495.       p->ctrl[3][i].xyz[0] =  b->maxs[0];
  1496.         p->ctrl[3][i].xyz[1] =  b->maxs[1];
  1497.       p->ctrl[3][i].xyz[2] = nStart;
  1498.  
  1499.         p->ctrl[4][i].xyz[0] =  b->maxs[0];
  1500.         p->ctrl[4][i].xyz[1] =  b->mins[1];
  1501.       p->ctrl[4][i].xyz[2] = nStart;
  1502.       nStart += nStep;
  1503.     }
  1504.   }
  1505.   else
  1506.   {
  1507.     p->width = 9;
  1508.       p->ctrl[1][0].xyz[0] =  b->mins[0];
  1509.       p->ctrl[1][0].xyz[1] =  b->mins[1];
  1510.  
  1511.       p->ctrl[3][0].xyz[0] =  b->maxs[0];
  1512.       p->ctrl[3][0].xyz[1] =  b->mins[1];
  1513.  
  1514.       p->ctrl[5][0].xyz[0] =  b->maxs[0];
  1515.       p->ctrl[5][0].xyz[1] =  b->maxs[1];
  1516.  
  1517.       p->ctrl[7][0].xyz[0] =  b->mins[0];
  1518.       p->ctrl[7][0].xyz[1] =  b->maxs[1];
  1519.  
  1520.       for ( i = 1 ; i < p->width - 1 ; i += 2 ) 
  1521.     {
  1522.  
  1523.       p->ctrl[i][0].xyz[2] =  b->mins[2];
  1524.  
  1525.           VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz );
  1526.  
  1527.           p->ctrl[i][2].xyz[2] =  b->maxs[2];
  1528.  
  1529.           p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5;
  1530.           p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5;
  1531.           p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5;
  1532.       }
  1533.       InterpolateInteriorPoints( p );
  1534.  
  1535.     if (bSquare)
  1536.     {
  1537.       if (bBevel || bEndcap)
  1538.       {
  1539.         if (bBevel)
  1540.         {
  1541.           for (i = 0; i < p->height; i++)
  1542.           {
  1543.             VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
  1544.             VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
  1545.           }
  1546.         }
  1547.         else
  1548.         {
  1549.           for (i = 0; i < p->height; i++)
  1550.           {
  1551.             VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz);
  1552.             VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
  1553.             VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
  1554.             VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz);
  1555.           }
  1556.         }
  1557.       }
  1558.       else
  1559.       {
  1560.         for (i = 0; i < p->width-1; i ++)
  1561.         {
  1562.           for (j = 0; j < p->height; j++)
  1563.           {
  1564.             VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz);
  1565.           }
  1566.         }
  1567.         for (j = 0; j < p->height; j++)
  1568.         {
  1569.           VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz);
  1570.         }
  1571.       }
  1572.     }
  1573.   }
  1574.  
  1575.  
  1576.   Patch_Naturalize(p);
  1577.  
  1578.   if (bCone)
  1579.   {
  1580.     p->type = PATCH_CONE;
  1581.     float xc = (b->maxs[0] + b->mins[0]) * 0.5; 
  1582.     float yc = (b->maxs[1] + b->mins[1]) * 0.5; 
  1583.  
  1584.     for ( i = 0 ; i < p->width ; i ++)
  1585.     {
  1586.       p->ctrl[i][2].xyz[0] = xc;
  1587.       p->ctrl[i][2].xyz[1] = yc;
  1588.     }
  1589.   }
  1590. /*
  1591.   if (bEndcap || bBevel)
  1592.   {
  1593.     if (bInverted)
  1594.     {
  1595.       for ( i = 0 ; i < p->height ; i ++)
  1596.       {
  1597.         if (bBevel)
  1598.         {
  1599.           VectorCopy(p->ctrl[7][i], p->ctrl[0][i]);
  1600.           VectorCopy(p->ctrl[7][i], p->ctrl[8][i]);
  1601.           VectorCopy(p->ctrl[3][i], p->ctrl[2][i]);
  1602.           VectorCopy(p->ctrl[5][i], p->ctrl[1][i]);
  1603.           VectorCopy(p->ctrl[5][i], p->ctrl[4][i]);
  1604.           VectorCopy(p->ctrl[5][i], p->ctrl[6][i]);
  1605.         }
  1606.         else
  1607.         {
  1608.           VectorCopy(p->ctrl[4][i], p->ctrl[8][i]);
  1609.           VectorCopy(p->ctrl[1][i], p->ctrl[0][i]);
  1610.           VectorCopy(p->ctrl[1][i], p->ctrl[10][i]);
  1611.           VectorCopy(p->ctrl[3][i], p->ctrl[2][i]);
  1612.           VectorCopy(p->ctrl[5][i], p->ctrl[4][i]);
  1613.           VectorCopy(p->ctrl[7][i], p->ctrl[6][i]);
  1614.           VectorCopy(p->ctrl[5][i], p->ctrl[7][i]);
  1615.           VectorCopy(p->ctrl[3][i], p->ctrl[9][i]);
  1616.         }
  1617.       }
  1618.     }
  1619.     else
  1620.     {
  1621.       for ( i = 0 ; i < p->height ; i ++)
  1622.       {
  1623.         VectorCopy(p->ctrl[1][i], p->ctrl[2][i]);
  1624.         VectorCopy(p->ctrl[7][i], p->ctrl[6][i]);
  1625.         if (bBevel)
  1626.         {
  1627.           VectorCopy(p->ctrl[5][i], p->ctrl[4][i]);
  1628.         }
  1629.       }
  1630.     }
  1631.   }
  1632. */
  1633.   
  1634.   b = AddBrushForPatch(p);
  1635.  
  1636.  
  1637. #if 1
  1638.     Select_Delete();
  1639.     Select_Brush(b);
  1640. #else
  1641.   if (!bCone)
  1642.   {
  1643.     Select_Delete();
  1644.     Select_Brush(b);
  1645.     GenerateEndCaps(b, bBevel, bEndcap, bInverted);
  1646.     eclass_t *pecNew = Eclass_ForName("func_group", false);
  1647.     if (pecNew)
  1648.     {
  1649.       Entity_Create(pecNew);
  1650.     }
  1651.   }
  1652.   else
  1653.   {
  1654.     Select_Delete();
  1655.     Select_Brush(b);
  1656.   }
  1657. #endif
  1658.  
  1659. }
  1660.  
  1661. /*
  1662. ==================
  1663. Patch_GenericMesh
  1664. ==================
  1665. */
  1666. brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride)
  1667. {
  1668.   int i,j;
  1669.  
  1670.   if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15)
  1671.   {
  1672.     Sys_Printf("Invalid patch width or height.\n");
  1673.     return NULL;
  1674.   }
  1675.  
  1676.     if (! bOverride && !QE_SingleBrush())
  1677.   {
  1678.     Sys_Printf("Cannot generate a patch from multiple selections.\n");
  1679.         return NULL;
  1680.   }
  1681.  
  1682.  
  1683.  
  1684.   patchMesh_t* p = MakeNewPatch();
  1685.     p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
  1686.  
  1687.     p->width = nWidth;
  1688.     p->height = nHeight;
  1689.   p->type = PATCH_GENERIC;
  1690.  
  1691.   int nFirst = 0;
  1692.   int nSecond = 1;
  1693.   if (nOrientation == 0)
  1694.   {
  1695.     nFirst = 1;
  1696.     nSecond = 2;
  1697.   }
  1698.   else if (nOrientation == 1)
  1699.   {
  1700.     nSecond = 2;
  1701.   }
  1702.  
  1703.     brush_t *b = selected_brushes.next;
  1704.  
  1705.   int xStep = b->mins[nFirst];
  1706.   float xAdj = abs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1));
  1707.   float yAdj = abs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1));
  1708.  
  1709.   for (i = 0; i < nWidth; i++)
  1710.   {
  1711.     int yStep = b->mins[nSecond];
  1712.     for (j = 0; j < nHeight; j++)
  1713.     {
  1714.       p->ctrl[i][j].xyz[nFirst] = xStep;
  1715.       p->ctrl[i][j].xyz[nSecond] = yStep;
  1716.       p->ctrl[i][j].xyz[nOrientation] = 0;
  1717.       yStep += yAdj;
  1718.     }
  1719.     xStep += xAdj;
  1720.   }
  1721.  
  1722.   Patch_Naturalize(p);
  1723.  
  1724.   b = AddBrushForPatch(p);
  1725.   if (bDeleteSource)
  1726.   {
  1727.     Select_Delete();
  1728.     Select_Brush(b);
  1729.   }
  1730.  
  1731.   return b;
  1732.   //g_qeglobals.d_select_mode = sel_curvepoint;
  1733. }
  1734.  
  1735. /*
  1736. ==================
  1737. PointInMoveList
  1738. ==================
  1739. */
  1740. int PointInMoveList(float *pf)
  1741. {
  1742.   for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
  1743.   {
  1744.     if (pf == &g_qeglobals.d_move_points[i][0])
  1745.       return i;
  1746.   }
  1747.   return -1;
  1748. }
  1749.  
  1750. /*
  1751. ==================
  1752. PointValueInMoveList
  1753. ==================
  1754. */
  1755. int PointValueInMoveList(vec3_t v)
  1756. {
  1757.   for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
  1758.   {
  1759.     if (VectorCompare(v, g_qeglobals.d_move_points[i]))
  1760.       return i;
  1761.   }
  1762.   return -1;
  1763. }
  1764.  
  1765.  
  1766. /*
  1767. ==================
  1768. RemovePointFromMoveList
  1769. ==================
  1770. */
  1771. void RemovePointFromMoveList(vec3_t v)
  1772. {
  1773.   int n;
  1774.   while ( (n = PointValueInMoveList(v)) >= 0)
  1775.   {
  1776.     for (int i = n; i < g_qeglobals.d_num_move_points-1; i++)
  1777.     {
  1778.       g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1];
  1779.     }
  1780.     g_qeglobals.d_num_move_points--;
  1781.   }
  1782. }
  1783.  
  1784. /*
  1785. ==================
  1786. ColumnSelected
  1787. ==================
  1788. */
  1789. bool ColumnSelected(patchMesh_t* p, int nCol)
  1790. {
  1791.   for (int i = 0; i < p->height; i++)
  1792.   {
  1793.     if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1)
  1794.       return false;
  1795.   }
  1796.   return true;
  1797. }
  1798.  
  1799. /*
  1800. ==================
  1801. AddPoint
  1802. ==================
  1803. */
  1804. void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true)
  1805. {
  1806.   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
  1807.   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
  1808.   g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v;
  1809.   if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill)
  1810.   {
  1811.       for ( int i = 0 ; i < p->width ; i++ ) 
  1812.     {
  1813.           for ( int j = 0 ; j < p->height ; j++ ) 
  1814.       {
  1815.         if (g_bPatchWeld)
  1816.         {
  1817.           if ( VectorCompare(v, p->ctrl[i][j].xyz)
  1818.             && PointInMoveList(p->ctrl[i][j].xyz) == -1)
  1819.           {
  1820.             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
  1821.             continue;
  1822.           }
  1823.         }
  1824.         if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA)
  1825.         {
  1826.           if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON) 
  1827.              &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON)) 
  1828.           {
  1829.             if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
  1830.             {
  1831.               g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
  1832.               continue;
  1833.             }
  1834.           }
  1835. #if 0
  1836.           int l = 0;
  1837.             for ( int k = 0; k < 2; k++ )
  1838.           {
  1839.                 if (fabs(v[k] - p->ctrl[i][j].xyz[k]) > EQUAL_EPSILON)
  1840.               continue;
  1841.              l++;
  1842.           }
  1843.           if (l >= 2 && PointInMoveList(p->ctrl[i][j].xyz) == -1)
  1844.           {
  1845.             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
  1846.             continue;
  1847.           }
  1848. #endif
  1849.         }
  1850.       }
  1851.     }
  1852.   }
  1853. #if 0
  1854.   if (g_qeglobals.d_num_move_points == 1)
  1855.   {
  1856.     // single point selected
  1857.     // FIXME: the two loops can probably be reduced to one
  1858.       for ( int i = 0 ; i < p->width ; i++ ) 
  1859.     {
  1860.           for ( int j = 0 ; j < p->height ; j++ ) 
  1861.       {
  1862.         int n = PointInMoveList(v);
  1863.         if (n >= 0)
  1864.         {
  1865.           if (((i & 0x01) && (j & 0x01)) == 0)
  1866.           {
  1867.             // put any sibling fixed points
  1868.             // into the inverse list
  1869.             int p1, p2, p3, p4;
  1870.             p1 = i + 2;
  1871.             p2 = i - 2;
  1872.             p3 = j + 2;
  1873.             p4 = j - 2;
  1874.             if (p1 < p->width)
  1875.             {
  1876.  
  1877.             }
  1878.             if (p2 >= 0)
  1879.             {
  1880.             }
  1881.             if (p3 < p->height)
  1882.             {
  1883.             }
  1884.             if (p4 >= 0)
  1885.             {
  1886.             }
  1887.           }
  1888.         }
  1889.       }
  1890.     }
  1891.   }
  1892. #endif
  1893. }
  1894.  
  1895. /*
  1896. ==================
  1897. SelectRow
  1898. ==================
  1899. */
  1900. void SelectRow(patchMesh_t* p, int nRow, bool bMulti)
  1901. {
  1902.   if (!bMulti)
  1903.     g_qeglobals.d_num_move_points = 0;
  1904.   for (int i = 0; i < p->width; i++)
  1905.   {
  1906.     AddPoint(p, p->ctrl[i][nRow].xyz, false);
  1907.   }
  1908.   //Sys_Printf("Selected Row %d\n", nRow);
  1909. }
  1910.  
  1911. /*
  1912. ==================
  1913. SelectColumn
  1914. ==================
  1915. */
  1916. void SelectColumn(patchMesh_t* p, int nCol, bool bMulti)
  1917. {
  1918.   if (!bMulti)
  1919.     g_qeglobals.d_num_move_points = 0;
  1920.   for (int i = 0; i < p->height; i++)
  1921.   {
  1922.     AddPoint(p, p->ctrl[nCol][i].xyz, false);
  1923.   }
  1924.   //Sys_Printf("Selected Col %d\n", nCol);
  1925. }
  1926.  
  1927.  
  1928. /*
  1929. ==================
  1930. AddPatchMovePoint
  1931. ==================
  1932. */
  1933. void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull)
  1934. {
  1935.   if (!g_bSameView && !bMulti && !bFull)
  1936.   {
  1937.     g_bSameView = true;
  1938.     return;
  1939.   }
  1940.  
  1941.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  1942.     {
  1943.     if (pb->patchBrush)
  1944.     {
  1945.         patchMesh_t* p = pb->pPatch;
  1946.         for ( int i = 0 ; i < p->width ; i++ ) 
  1947.       {
  1948.             for ( int j = 0 ; j < p->height ; j++ ) 
  1949.         {
  1950.           if (VectorCompare(v, p->ctrl[i][j].xyz))
  1951.           {
  1952.             if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
  1953.             {
  1954.               if (bFull)        // if we want the full row/col this is on
  1955.               {
  1956.                 SelectColumn(p, i, bMulti);
  1957.               }
  1958.               else
  1959.               {
  1960.                 if (!bMulti)
  1961.                   g_qeglobals.d_num_move_points = 0;
  1962.                 AddPoint(p, p->ctrl[i][j].xyz);
  1963.                 //Sys_Printf("Selected col:row %d:%d\n", i, j);
  1964.               }
  1965.               //--if (!bMulti)
  1966.               return;
  1967.             }
  1968.             else
  1969.             {
  1970.               if (bFull)
  1971.               {
  1972.                 if (ColumnSelected(p, i))
  1973.                 {
  1974.                   SelectRow(p, j, bMulti);
  1975.                 }
  1976.                 else
  1977.                 {
  1978.                   SelectColumn(p, i, bMulti);
  1979.                 }
  1980.                 return;
  1981.               }
  1982.               if (g_bSameView)
  1983.               {
  1984.                 RemovePointFromMoveList(v);
  1985.                 return;
  1986.               }
  1987.             }
  1988.           }
  1989.             }
  1990.         }
  1991.     }
  1992.   }
  1993. }
  1994.  
  1995. /*
  1996. ==================
  1997. Patch_UpdateSelected
  1998. ==================
  1999. */
  2000. void Patch_UpdateSelected(vec3_t vMove)
  2001. {
  2002.   int i, j;
  2003.   for (i=0 ; i < g_qeglobals.d_num_move_points ; i++)
  2004.   {
  2005.       VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]);
  2006.     if (g_qeglobals.d_num_move_points == 1)
  2007.     {
  2008.     }
  2009.   }
  2010.  
  2011.     //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch];
  2012.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  2013.     {
  2014.     if (pb->patchBrush)
  2015.     {
  2016.         patchMesh_t* p = pb->pPatch;
  2017.  
  2018.  
  2019.       g_qeglobals.d_numpoints = 0;
  2020.         for (i = 0 ; i < p->width ; i++ ) 
  2021.       {
  2022.             for ( j = 0 ; j < p->height ; j++ ) 
  2023.         {
  2024.             VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
  2025.           if (g_qeglobals.d_numpoints < MAX_POINTS-1)
  2026.           {
  2027.               g_qeglobals.d_numpoints++;
  2028.           }
  2029.             }
  2030.       }
  2031.         
  2032.       vec3_t vMin, vMax;
  2033.       Patch_CalcBounds(p, vMin, vMax);
  2034.       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  2035.     }
  2036.   }
  2037.   //Brush_Free(p->pSymbiot);
  2038.   //Select_Brush(AddBrushForPatch(g_nSelectedPatch));
  2039. }
  2040.  
  2041.  
  2042.  
  2043. /*
  2044. ===============
  2045. SampleSinglePatch
  2046. ===============
  2047. */
  2048. void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) {
  2049.     float    vCtrl[3][5];
  2050.     int        vPoint;
  2051.     int        axis;
  2052.  
  2053.     // find the control points for the v coordinate
  2054.     for (vPoint = 0 ; vPoint < 3 ; vPoint++) 
  2055.   {
  2056.         for (axis = 0 ; axis < 5 ; axis++) 
  2057.     {
  2058.             float    a, b, c;
  2059.             float    qA, qB, qC;
  2060.  
  2061.             a = ctrl[0][vPoint][axis];
  2062.             b = ctrl[1][vPoint][axis];
  2063.             c = ctrl[2][vPoint][axis];
  2064.             qA = a - 2 * b + c;
  2065.             qB = 2 * b - 2 * a;
  2066.             qC = a;
  2067.  
  2068.             vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
  2069.         }
  2070.     }
  2071.  
  2072.     // interpolate the v value
  2073.     for (axis = 0 ; axis < 5 ; axis++) 
  2074.   {
  2075.         float    a, b, c;
  2076.         float    qA, qB, qC;
  2077.  
  2078.         a = vCtrl[0][axis];
  2079.         b = vCtrl[1][axis];
  2080.         c = vCtrl[2][axis];
  2081.         qA = a - 2 * b + c;
  2082.         qB = 2 * b - 2 * a;
  2083.         qC = a;
  2084.  
  2085.         out[axis] = qA * v * v + qB * v + qC;
  2086.     }
  2087. }
  2088.  
  2089. /*
  2090. ===================
  2091. DrawSinglePatch
  2092. ===================
  2093. */
  2094. void DrawSinglePatch (float ctrl[3][3][5], bool bPoints) 
  2095. {
  2096.     int        i, j;
  2097.     float    u, v;
  2098.     float    verts[CBLOCK_SUBDIVISIONS+1][CBLOCK_SUBDIVISIONS+1][5];
  2099.  
  2100.     for (i = 0 ; i <= CBLOCK_SUBDIVISIONS ; i++) 
  2101.   {
  2102.         for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) 
  2103.     {
  2104.             u = (float)i / CBLOCK_SUBDIVISIONS;
  2105.             v = (float)j / CBLOCK_SUBDIVISIONS;
  2106.             SampleSinglePatch (ctrl, u, v, verts[i][j]);
  2107.         }
  2108.     }
  2109.   // at this point we have 
  2110.  
  2111.   int nCount = -1;
  2112.     for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++) 
  2113.   {
  2114.     qglBegin (GL_QUAD_STRIP);
  2115.  
  2116.         for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++) 
  2117.     {
  2118.             qglTexCoord2fv( verts[i+1][j] + 3 );
  2119.             qglVertex3fv( verts[i+1][j] );
  2120. /*
  2121.       if (nCount >= 0)
  2122.       {
  2123.         VectorCopy(verts[i+1][j], vNormals[nCount]);
  2124.       }
  2125.       nCount++;
  2126.       if (nCount == 3)
  2127.       {
  2128.         VectorSubtract(vNormals[0], vNormals[1], vNormals[0]);
  2129.         VectorSubtract(vNormals[1], vNormals[2], vNormals[1]);
  2130.         CrossProduct(vNormals[0], vNormals[1], vNormals[2]);
  2131.         //VectorNormalize(vNormals[2]);
  2132.         qglNormal3fv(vNormals[2]);
  2133.         nCount = -1;
  2134.       }
  2135. */
  2136.       qglTexCoord2fv( verts[i][j] + 3 );
  2137.             qglVertex3fv( verts[i][j] );
  2138. /*
  2139.       VectorCopy(verts[i][j], vNormals[nCount]);
  2140.       nCount++;
  2141.       if (nCount == 3)
  2142.       {
  2143.         VectorSubtract(vNormals[0], vNormals[1], vNormals[0]);
  2144.         VectorSubtract(vNormals[1], vNormals[2], vNormals[1]);
  2145.         CrossProduct(vNormals[0], vNormals[1], vNormals[2]);
  2146.         //VectorNormalize(vNormals[2]);
  2147.         qglNormal3fv(vNormals[2]);
  2148.         nCount = -1;
  2149.       }
  2150. */
  2151.         }
  2152.       qglEnd ();
  2153.     }
  2154.  
  2155. }
  2156.  
  2157. /*
  2158. =================
  2159. DrawPatchMesh
  2160. =================
  2161. */
  2162. //FIXME: this routine needs to be reorganized.. should be about 1/4 the size and complexity
  2163. void DrawPatchMesh( patchMesh_t *pm, bool bPoints, bool bShade = false ) {
  2164.     int        i, j, k, l;
  2165.     float    ctrl[3][3][5];
  2166.  
  2167.   bool bOverlay = pm->bOverlay;
  2168.     int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
  2169.  
  2170.   //--float fColor[3];
  2171.   //--if (bShade)
  2172.   //--{
  2173.   //--  face_t *f = pm->pSymbiot->brush_faces;
  2174.   //--  _SetColor(f, fColor);
  2175.   //--}
  2176.   if (g_PrefsDlg.m_bDisplayLists)
  2177.   {
  2178.     if (pm->bDirty || pm->nListID <= 0)
  2179.     {
  2180.       if (pm->nListID <= 0)
  2181.         pm->nListID = qglGenLists(1);
  2182.       if (pm->nListID > 0)
  2183.       {
  2184.         qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE);
  2185.       }
  2186.       
  2187.  
  2188.  
  2189.       if (pm->type != PATCH_TRIANGLE)
  2190.       {
  2191.         //vec3_t *vMeshData = new vec3_t[pm->width * pm->height];
  2192.  
  2193.         // wasteful
  2194.         if (g_PrefsDlg.m_bGLLighting)
  2195.         {
  2196.           Patch_MeshNormals(pm);
  2197.           for (i = 0; i < pm->width; i++)
  2198.           {
  2199.             for (j = 0; j < pm->height; j++)
  2200.             {
  2201.               //VectorCopy(pm->ctrl[i][j].xyz, vMeshData[(j * pm->width) + i]);
  2202.               qglNormal3fv(pm->ctrl[i][j].normal);
  2203.             }
  2204.           }
  2205.         }
  2206.  
  2207.           for ( i = 0 ; i + 2 < pm->width ; i += 2 ) 
  2208.         {
  2209.               for ( j = 0 ; j + 2 < pm->height ; j += 2 ) 
  2210.           {
  2211.  
  2212.                   for ( k = 0 ; k < 3 ; k++ ) 
  2213.             {
  2214.               vec3_t vAvg;
  2215.               vAvg[0] = vAvg[1] = vAvg[2] = 0;
  2216.                       for ( l = 0 ; l < 3 ; l++ ) 
  2217.               {
  2218.                           ctrl[k][l][0] = pm->ctrl[ i + k ][ j + l ].xyz[ 0 ];
  2219.                           ctrl[k][l][1] = pm->ctrl[ i + k ][ j + l ].xyz[ 1 ];
  2220.                           ctrl[k][l][2] = pm->ctrl[ i + k ][ j + l ].xyz[ 2 ];
  2221.                           ctrl[k][l][3] = pm->ctrl[ i + k ][ j + l ].xyz[ 3 ];
  2222.                           ctrl[k][l][4] = pm->ctrl[ i + k ][ j + l ].xyz[ 4 ];
  2223.  
  2224.                 if (g_PrefsDlg.m_bGLLighting)
  2225.                 {
  2226.                   qglNormal3fv(pm->ctrl[i+k][j+l].normal);
  2227.                 }
  2228.                       }
  2229.  
  2230.                   }
  2231.  
  2232. //--            if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture)
  2233. //--            {
  2234. //--              VectorCopy(pm->ctrl[i][j].normal, plane.normal);
  2235. //--              float shade = SetShadeForPlane(&plane);
  2236. //--              qtexture_t *q = pm->d_texture;
  2237. //--              vec3_t vColor;
  2238. //--
  2239. //--              vColor[0] = shade;// * q->color[0];
  2240. //--              vColor[1] = shade;// * q->color[1];
  2241. //--              vColor[2] = shade;// * q->color[2];
  2242. //--              qglColor3fv(vColor);
  2243. //--            }
  2244.  
  2245.             
  2246. //--            if (g_PrefsDlg.m_bGLLighting)
  2247. //--            {
  2248. //--              //qglNormal3fv(pm->ctrl[i][j].normal);
  2249. //--            }
  2250.             DrawSinglePatch( ctrl, bPoints );
  2251.           }
  2252.         }
  2253.  
  2254.         // we have an array of clean control points
  2255.         //
  2256.         /*
  2257.         qglMap2f(GL_MAP2_NORMAL, 0, 1, 3, 3, 0, 1, 9, 3, (float*)&vMeshData);
  2258.         for (i = 0; i < pm->width; i++)
  2259.         {
  2260.           for (j = 0; j < pm->height; j++)
  2261.           {
  2262.             qglEvalPoint2(i, j);
  2263.           }
  2264.         }
  2265.  
  2266.         delete []vMeshData;
  2267.         */
  2268.       }
  2269.       else
  2270.       {
  2271.         qglBegin (GL_TRIANGLES);
  2272.            qglTexCoord2fv( pm->ctrl[0][0].st);
  2273.               qglVertex3fv( pm->ctrl[0][0].xyz);
  2274.               qglTexCoord2fv( pm->ctrl[2][0].st);
  2275.               qglVertex3fv( pm->ctrl[2][0].xyz);
  2276.               qglTexCoord2fv( pm->ctrl[2][2].st);
  2277.               qglVertex3fv( pm->ctrl[2][2].xyz);
  2278.         qglEnd();
  2279.       }
  2280.  
  2281.       if (pm->nListID > 0)
  2282.       {
  2283.         qglEndList();
  2284.         pm->bDirty = false;
  2285.       }
  2286.     }
  2287.     else
  2288.     {
  2289.       qglCallList(pm->nListID);
  2290.     }
  2291.   }
  2292.   else
  2293.   {
  2294.       for ( i = 0 ; i + 2 < pm->width ; i += 2 ) 
  2295.     {
  2296.           for ( j = 0 ; j + 2 < pm->height ; j += 2 ) 
  2297.       {
  2298.               for ( k = 0 ; k < 3 ; k++ ) 
  2299.         {
  2300.                   for ( l = 0 ; l < 3 ; l++ ) 
  2301.           {
  2302.                       ctrl[k][l][0] = pm->ctrl[ i + k ][ j + l ].xyz[ 0 ];
  2303.                       ctrl[k][l][1] = pm->ctrl[ i + k ][ j + l ].xyz[ 1 ];
  2304.                       ctrl[k][l][2] = pm->ctrl[ i + k ][ j + l ].xyz[ 2 ];
  2305.                       ctrl[k][l][3] = pm->ctrl[ i + k ][ j + l ].xyz[ 3 ];
  2306.                       ctrl[k][l][4] = pm->ctrl[ i + k ][ j + l ].xyz[ 4 ];
  2307.                   }
  2308.               }
  2309.         //--if (bShade)
  2310.         //--{
  2311.         //--  _DecColor(fColor);
  2312.         //--}
  2313.               DrawSinglePatch( ctrl, bPoints );
  2314.       }
  2315.     }
  2316.   }
  2317.  
  2318.   vec3_t* pSelectedPoints[256];
  2319.   int nIndex = 0;
  2320.  
  2321.   qglPushAttrib(GL_CURRENT_BIT);
  2322.   //--qglDisable(GL_BLEND);
  2323.   //--qglDisable (GL_DEPTH_TEST);
  2324.   //qglDisable (GL_TEXTURE_2D);
  2325.  
  2326.   bool bDisabledLighting = qglIsEnabled(GL_LIGHTING);
  2327.   if (bDisabledLighting)
  2328.   {
  2329.     qglDisable(GL_LIGHTING);
  2330.   }
  2331.  
  2332.  
  2333.   // FIXME: this bend painting code needs to be rolled up significantly as it is a cluster fuck right now
  2334.   if (bPoints && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area || g_bPatchBendMode || g_bPatchInsertMode))
  2335.   {
  2336.     bOverlay = false;
  2337.  
  2338.     // bending or inserting
  2339.     if (g_bPatchBendMode || g_bPatchInsertMode)
  2340.     {
  2341.       qglPointSize(6);
  2342.       if (g_bPatchAxisOnRow)
  2343.       {
  2344.         qglColor3f(1, 0, 1);
  2345.         qglBegin(GL_POINTS);
  2346.         for (i = 0; i < pm->width; i++)
  2347.         {
  2348.                 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex].xyz));
  2349.         }
  2350.         qglEnd();
  2351.       
  2352.         // could do all of this in one loop but it was pretty messy
  2353.         if (g_bPatchInsertMode)
  2354.         {
  2355.           qglColor3f(0, 0, 1);
  2356.           qglBegin(GL_POINTS);
  2357.           for (i = 0; i < pm->width; i++)
  2358.           {
  2359.                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex].xyz));
  2360.                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex+1].xyz));
  2361.           }
  2362.           qglEnd();
  2363.         }
  2364.         else
  2365.         {
  2366.           if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
  2367.           {
  2368.             qglColor3f(0, 0, 1);
  2369.             qglBegin(GL_POINTS);
  2370.             if (g_nPatchBendState == BEND_SELECT_ORIGIN)
  2371.             {
  2372.               qglVertex3fv(g_vBendOrigin);
  2373.             }
  2374.             else
  2375.             {
  2376.               for (i = 0; i < pm->width; i++)
  2377.               {
  2378.                 if (g_bPatchLowerEdge)
  2379.                 {
  2380.                   for (j = 0; j < g_nPatchAxisIndex; j++)
  2381.                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][j].xyz));
  2382.                 }
  2383.                 else
  2384.                 {
  2385.                   for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
  2386.                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][j].xyz));
  2387.                 }
  2388.               }
  2389.             }
  2390.             qglEnd();
  2391.           }
  2392.         }
  2393.       }
  2394.       else
  2395.       {
  2396.         qglColor3f(1, 0, 1);
  2397.         qglBegin(GL_POINTS);
  2398.         for (i = 0; i < pm->height; i++)
  2399.         {
  2400.                 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex][i].xyz));
  2401.         }
  2402.         qglEnd();
  2403.         
  2404.         // could do all of this in one loop but it was pretty messy
  2405.         if (g_bPatchInsertMode)
  2406.         {
  2407.           qglColor3f(0, 0, 1);
  2408.           qglBegin(GL_POINTS);
  2409.           for (i = 0; i < pm->height; i++)
  2410.           {
  2411.                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex][i].xyz));
  2412.                   qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex+1][i].xyz));
  2413.           }
  2414.           qglEnd();
  2415.         }
  2416.         else
  2417.         {
  2418.           if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
  2419.           {
  2420.             qglColor3f(0, 0, 1);
  2421.             qglBegin(GL_POINTS);
  2422.             for (i = 0; i < pm->height; i++)
  2423.             {
  2424.               if (g_nPatchBendState == BEND_SELECT_ORIGIN)
  2425.               {
  2426.                 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nBendOriginIndex][i].xyz));
  2427.               }
  2428.               else
  2429.               {
  2430.                 if (g_bPatchLowerEdge)
  2431.                 {
  2432.                   for (j = 0; j < g_nPatchAxisIndex; j++)
  2433.                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[j][i].xyz));
  2434.                 }
  2435.                 else
  2436.                 {
  2437.                   for (j = pm->width-1; j > g_nPatchAxisIndex; j--)
  2438.                           qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[j][i].xyz));
  2439.                 }
  2440.               }
  2441.             }
  2442.             qglEnd();
  2443.           }
  2444.         }
  2445.       }
  2446.     }
  2447.     else // just painting the grid for selection
  2448.     {
  2449.       qglPointSize(6);
  2450.         for ( i = 0 ; i < pm->width ; i++ )
  2451.       {
  2452.             for ( j = 0 ; j < pm->height ; j++ ) 
  2453.         {
  2454.             qglBegin(GL_POINTS);
  2455.           // FIXME: need to not do loop lookups inside here
  2456.           int n = PointValueInMoveList(pm->ctrl[i][j].xyz);
  2457.           if (n >= 0)
  2458.           {
  2459.             pSelectedPoints[nIndex++] = reinterpret_cast<float(*)[3]>(&pm->ctrl[i][j].xyz);
  2460.           }
  2461.  
  2462.           if (i & 0x01 || j & 0x01)
  2463.             qglColor3f(1, 0, 1);
  2464.           else
  2465.             qglColor3f(0, 1, 0);
  2466.                 qglVertex3fv(pm->ctrl[i][j].xyz);
  2467.             qglEnd();
  2468.         }
  2469.       }
  2470.     }
  2471.     if (nIndex > 0)
  2472.     {
  2473.       qglBegin(GL_POINTS);
  2474.       qglColor3f(0, 0, 1);
  2475.       while (nIndex-- > 0)
  2476.       {
  2477.               qglVertex3fv(*pSelectedPoints[nIndex]);
  2478.       }
  2479.       qglEnd();
  2480.     }
  2481.   }
  2482.  
  2483.   if (bOverlay)
  2484.   {
  2485.     qglPointSize(6);
  2486.     qglColor3f(0.5, 0.5, 0.5);
  2487.       for ( i = 0 ; i < pm->width ; i++ )
  2488.     {
  2489.       qglBegin(GL_POINTS);
  2490.           for ( j = 0 ; j < pm->height ; j++ ) 
  2491.       {
  2492.               if (i & 0x01 || j & 0x01)
  2493.           qglColor3f(0.5, 0, 0.5);
  2494.         else
  2495.           qglColor3f(0, 0.5, 0);
  2496.         qglVertex3fv(pm->ctrl[i][j].xyz);
  2497.       }
  2498.       qglEnd();
  2499.     }
  2500.   }
  2501.     //--qglEnable (GL_TEXTURE_2D);
  2502.     //--qglEnable (GL_DEPTH_TEST);
  2503.  
  2504.   if (bDisabledLighting)
  2505.   {
  2506.     qglEnable(GL_LIGHTING);
  2507.   }
  2508.  
  2509.     qglPopAttrib();
  2510.  
  2511. }
  2512.  
  2513. /*
  2514. ==================
  2515. Patch_DrawXY
  2516. ==================
  2517. */
  2518. void Patch_DrawXY(patchMesh_t *pm)
  2519. {
  2520.     qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
  2521.   if (pm->bSelected)
  2522.   {
  2523.     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
  2524.     //qglDisable (GL_LINE_STIPPLE);
  2525.       //qglLineWidth (1);
  2526.   }
  2527.   else
  2528.     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]);
  2529.  
  2530.     DrawPatchMesh( pm , pm->bSelected );
  2531.     qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
  2532.   if (pm->bSelected)
  2533.   {
  2534.       //qglLineWidth (2);
  2535.     //qglEnable (GL_LINE_STIPPLE);
  2536.   }
  2537. }
  2538.  
  2539. /*
  2540. ==================
  2541. Patch_DrawCam
  2542. ==================
  2543. */
  2544. void Patch_DrawCam(patchMesh_t *pm)
  2545. {
  2546.     qglColor3f (1,1,1);
  2547.   qglPushAttrib(GL_ALL_ATTRIB_BITS);
  2548.  
  2549.   if (g_bPatchWireFrame)
  2550.   {
  2551.       qglDisable( GL_CULL_FACE );
  2552.       qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
  2553.       qglDisable(GL_TEXTURE_2D);
  2554.     if (g_PrefsDlg.m_bGLLighting)
  2555.     {
  2556.       qglDisable(GL_LIGHTING);
  2557.     }
  2558.       DrawPatchMesh( pm , pm->bSelected, true );
  2559.     if (g_PrefsDlg.m_bGLLighting)
  2560.     {
  2561.       qglEnable(GL_LIGHTING);
  2562.     }
  2563.       qglEnable( GL_CULL_FACE );
  2564.   }
  2565.   else
  2566.   {
  2567.     if (g_PrefsDlg.m_bGLLighting)
  2568.     {
  2569.       //qglEnable(GL_NORMALIZE);
  2570.     }
  2571.       qglEnable( GL_CULL_FACE );
  2572.     qglCullFace(GL_FRONT);
  2573.     qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number);
  2574.  
  2575.     if (pm->d_texture->bFromShader && pm->d_texture->fTrans < 1.0)
  2576.     {
  2577.         //qglEnable ( GL_BLEND );
  2578.         //qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  2579.       qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->d_texture->fTrans); 
  2580.     }
  2581.     DrawPatchMesh( pm , pm->bSelected, true );
  2582.     
  2583.     qglCullFace(GL_BACK);
  2584.       //qglDisable(GL_TEXTURE_2D);
  2585.       qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
  2586.  
  2587.     qglDisable ( GL_BLEND );
  2588.       DrawPatchMesh( pm , pm->bSelected, true );
  2589.   }
  2590.  
  2591. #if 0 // this paints normal indicators on the ctrl points
  2592.       //--qglDisable (GL_DEPTH_TEST);
  2593.       qglDisable (GL_TEXTURE_2D);
  2594.       qglColor3f (1,1,1);
  2595.  
  2596.       for (int i = 0; i < pm->width; i++)
  2597.       {
  2598.         for (int j = 0; j < pm->height; j++)
  2599.         {
  2600.           vec3_t temp;
  2601.             qglBegin (GL_LINES);
  2602.               qglVertex3fv (pm->ctrl[i][j].xyz);
  2603.               VectorMA (pm->ctrl[i][j].xyz, 8, pm->ctrl[i][j].normal, temp);
  2604.               qglVertex3fv (temp);
  2605.             qglEnd ();
  2606.         }
  2607.       }
  2608.       qglEnable (GL_TEXTURE_2D);
  2609.       //--qglEnable (GL_DEPTH_TEST);
  2610. #endif
  2611.  
  2612.  
  2613.   qglPopAttrib();
  2614. }
  2615.  
  2616.  
  2617.  
  2618.  
  2619. void ConvexHullForSection( float section[2][4][7] ) {
  2620. }
  2621.  
  2622. void BrushesForSection( float section[2][4][7] ) {
  2623. }
  2624.  
  2625. //
  2626. //================
  2627. //Patch_BuildPoints
  2628. //================
  2629. void Patch_BuildPoints (brush_t *b) 
  2630. {
  2631.     face_t        *f;
  2632.     b->patchBrush = false;
  2633.     for (f=b->brush_faces ; f ; f=f->next) 
  2634.   {
  2635.         if (f->texdef.flags & SURF_PATCH) 
  2636.     {
  2637.             b->patchBrush = true;
  2638.       //vec3_t vMin, vMax;
  2639.       //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax);
  2640.       //VectorCopy(vMin, b->mins);
  2641.       //VectorCopy(vMax, b->maxs);
  2642.             break;
  2643.         }
  2644.     }
  2645. }
  2646.  
  2647.  
  2648.  
  2649. //
  2650. //===============
  2651. //Patch_WriteFile
  2652. //===============
  2653. //
  2654. #if 0
  2655. void Patch_WriteFile (char *name) 
  2656. {
  2657.     char patchName[1024];
  2658.   time_t ltime;
  2659.     strcpy(patchName, name);
  2660.     StripExtension (patchName);
  2661.     strcat (patchName, ".patch");
  2662.  
  2663.   FILE *file = fopen(patchName, "w");
  2664.   if (file)
  2665.   {
  2666.       time(<ime);
  2667.       fprintf (file, "// %s saved on %s\n", name, ctime(<ime) );
  2668.  
  2669.     for (int i = 0; i < numPatchMeshes; i++)
  2670.     {
  2671.           fprintf(file, "{\n");
  2672.       fprintf(file, " %s\n", patchMeshes[i].d_texture->name);
  2673.       fprintf(file, " ( %i %i %i ) \n", patchMeshes[i].width, patchMeshes[i].height, patchMeshes[i].negative);
  2674.       for (int w = 0; w < patchMeshes[i].width; w++)
  2675.       {
  2676.         for (int h = 0; h < patchMeshes[i].height; h++)
  2677.         {
  2678.           fprintf(file, " ( ");
  2679.           for (int k = 0; k < 5; k++)
  2680.           {
  2681.             float f = patchMeshes[i].ctrl[w][h][k];
  2682.             if (f == int(f))
  2683.               fprintf(file, "%i ", (int)f);
  2684.             else
  2685.               fprintf(file, "%f ", f);
  2686.           }
  2687.           fprintf(file, ")\n");
  2688.         }
  2689.       }
  2690.       fprintf(file, "}\n");
  2691.     }
  2692.     fclose(file);
  2693.   }
  2694. }
  2695. #endif
  2696.  
  2697. /*
  2698. ==================
  2699. Patch_Move
  2700. ==================
  2701. */
  2702. void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild)
  2703. {
  2704.   pm->bDirty = true;
  2705.   for (int w = 0; w < pm->width; w++)
  2706.   {
  2707.     for (int h = 0; h < pm->height; h++)
  2708.     {
  2709.       VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz);
  2710.     }
  2711.   }
  2712.   if (bRebuild)
  2713.   {
  2714.     vec3_t vMin, vMax;
  2715.     Patch_CalcBounds(pm, vMin, vMax);
  2716.     //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax);
  2717.   }
  2718.   UpdatePatchInspector();
  2719.  
  2720. }
  2721.  
  2722. /*
  2723. ==================
  2724. Patch_ApplyMatrix
  2725. ==================
  2726. */
  2727. void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap)
  2728. {
  2729.   vec3_t vTemp;
  2730.  
  2731.   for (int w = 0; w < p->width; w++)
  2732.   {
  2733.     for (int h = 0; h < p->height; h++)
  2734.     {
  2735.       if ( (g_qeglobals.d_select_mode == sel_curvepoint || g_bPatchBendMode)
  2736.         && PointInMoveList(p->ctrl[w][h].xyz) == -1)
  2737.         continue;
  2738.             VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp);
  2739.             for (int j = 0; j < 3; j++)
  2740.       {
  2741.         p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j];
  2742.         if (bSnap)
  2743.         {
  2744.           p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5);
  2745.         }
  2746.       }
  2747.     }
  2748.   }
  2749.   vec3_t vMin, vMax;
  2750.   Patch_CalcBounds(p, vMin, vMax);
  2751.   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  2752. }
  2753.  
  2754. /*
  2755. ==================
  2756. Patch_EditPatch
  2757. ==================
  2758. */
  2759. void Patch_EditPatch()
  2760. {
  2761.   //--patchMesh_t* p = &patchMeshes[n];
  2762.   g_qeglobals.d_numpoints = 0;
  2763.   g_qeglobals.d_num_move_points = 0;
  2764.     
  2765.   for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  2766.     {
  2767.     if (pb->patchBrush)
  2768.     {
  2769.         patchMesh_t* p = pb->pPatch;
  2770.         for ( int i = 0 ; i < p->width ; i++ ) 
  2771.       {
  2772.             for ( int j = 0 ; j < p->height ; j++ ) 
  2773.         {
  2774.             VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
  2775.           if (g_qeglobals.d_numpoints < MAX_POINTS-1)
  2776.           {
  2777.               g_qeglobals.d_numpoints++;
  2778.           }
  2779.             }
  2780.       }
  2781.     }
  2782.   }
  2783.   g_qeglobals.d_select_mode = sel_curvepoint;
  2784.   //--g_nSelectedPatch = n;
  2785. }
  2786.  
  2787.  
  2788.  
  2789. /*
  2790. ==================
  2791. Patch_Deselect
  2792. ==================
  2793. */
  2794. //FIXME: need all sorts of asserts throughout a lot of this crap
  2795. void Patch_Deselect()
  2796. {
  2797.   //--g_nSelectedPatch = -1;
  2798.   g_qeglobals.d_select_mode = sel_brush;
  2799.  
  2800.     for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
  2801.   {
  2802.     if (b->patchBrush)
  2803.     {
  2804.       b->pPatch->bSelected = false;
  2805.     }
  2806.   }
  2807.  
  2808.   //for (int i = 0; i < numPatchMeshes; i++)
  2809.   //  patchMeshes[i].bSelected = false;
  2810.  
  2811.   if (g_bPatchBendMode)
  2812.     Patch_BendToggle();
  2813.   if (g_bPatchInsertMode)
  2814.     Patch_InsDelToggle();
  2815. }
  2816.  
  2817.  
  2818. /*
  2819. ==================
  2820. Patch_Select
  2821. ==================
  2822. */
  2823. void Patch_Select(patchMesh_t *p)
  2824. {
  2825.   // maintained for point manip.. which i need to fix as this 
  2826.   // is pf error prone
  2827.   //--g_nSelectedPatch = n;
  2828.   p->bSelected = true;
  2829. }
  2830.  
  2831.  
  2832. /*
  2833. ==================
  2834. Patch_Deselect
  2835. ==================
  2836. */
  2837. void Patch_Deselect(patchMesh_t *p)
  2838. {
  2839.   p->bSelected = false;
  2840. }
  2841.  
  2842.  
  2843. /*
  2844. ==================
  2845. Patch_Delete
  2846. ==================
  2847. */
  2848. void Patch_Delete(patchMesh_t *p)
  2849. {
  2850.   p->pSymbiot->pPatch = NULL;
  2851.   p->pSymbiot->patchBrush = false;
  2852.   if (g_qeglobals.bSurfacePropertiesPlugin)
  2853.   {
  2854. #ifdef _DEBUG
  2855.         if (!p->pData)
  2856.             Sys_Printf("WARNING: unexpected IPluginTexdef* is NULL in Patch_Delete\n");
  2857.         else
  2858. #endif
  2859.         {
  2860.             GETPLUGINTEXDEF(p)->DecRef();
  2861.             p->pData = NULL;
  2862.         }
  2863.   }
  2864.   free(p);
  2865.   p = NULL;
  2866.  
  2867.   // bump the array down
  2868.   //for (int i = n; i < numPatchMeshes; i++)
  2869.   //{
  2870.   //  patchMeshes[i].pSymbiot->nPatchID--;
  2871.   //  patchMeshes[i] = patchMeshes[i+1];
  2872.   //}
  2873.   //numPatchMeshes--;
  2874.   UpdatePatchInspector();
  2875. }
  2876.  
  2877.  
  2878. /*
  2879. ==================
  2880. Patch_Scale
  2881. ==================
  2882. */
  2883. void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild)
  2884. {
  2885.  
  2886.   for (int w = 0; w < p->width; w++)
  2887.   {
  2888.     for (int h = 0; h < p->height; h++)
  2889.     {
  2890.       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
  2891.         continue;
  2892.             for (int i=0 ; i<3 ; i++)
  2893.             {
  2894.         p->ctrl[w][h].xyz[i] -= vOrigin[i];
  2895.         p->ctrl[w][h].xyz[i] *= vAmt[i];
  2896.         p->ctrl[w][h].xyz[i] += vOrigin[i];
  2897.       }
  2898.     }
  2899.   }
  2900.   if (bRebuild)
  2901.   {
  2902.     vec3_t vMin, vMax;
  2903.     Patch_CalcBounds(p, vMin, vMax);
  2904.     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  2905.   }
  2906.   UpdatePatchInspector();
  2907. }
  2908.  
  2909.  
  2910. /*
  2911. ==================
  2912. Patch_Cleanup
  2913. ==================
  2914. */
  2915. void Patch_Cleanup()
  2916. {
  2917.   //--g_nSelectedPatch = -1;
  2918.   //numPatchMeshes = 0;
  2919. }
  2920.  
  2921.  
  2922.  
  2923. /*
  2924. ==================
  2925. Patch_SetView
  2926. ==================
  2927. */
  2928. void Patch_SetView(int n)
  2929. {
  2930.   g_bSameView = (n == g_nPatchClickedView);
  2931.   g_nPatchClickedView = n;
  2932. }
  2933.  
  2934.  
  2935. /*
  2936. ==================
  2937. Patch_SetTexture
  2938. ==================
  2939. */
  2940. // FIXME: need array validation throughout
  2941. void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef)
  2942. {
  2943.   p->d_texture = Texture_ForName(tex_def->name);
  2944.   if (g_qeglobals.bSurfacePropertiesPlugin)
  2945.   {
  2946. #ifdef _DEBUG
  2947.       if (!p->pData)
  2948.           Sys_Printf("WARNING: unexpected p->pData is NULL in Patch_SetTexture\n");
  2949.       else
  2950. #endif
  2951.           GETPLUGINTEXDEF(p)->DecRef();
  2952.       if (pPlugTexdef)
  2953.       {
  2954.         p->pData = pPlugTexdef->Copy();
  2955.         GETPLUGINTEXDEF(p)->Hook(p);
  2956.       }
  2957.       else
  2958.       {
  2959.           g_SurfaceTable.m_pfnPatchAlloc( p );
  2960.           GETPLUGINTEXDEF(p)->SetDefaultTexdef();
  2961.       }      
  2962.   }
  2963.   UpdatePatchInspector();
  2964. }
  2965.  
  2966.  
  2967. /*
  2968. ==================
  2969. Patch_DragScale
  2970. ==================
  2971. */
  2972. bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove)
  2973. {
  2974.   vec3_t vMin, vMax, vScale, vTemp, vMid;
  2975.   int i;
  2976.  
  2977.   Patch_CalcBounds(p, vMin, vMax);
  2978.  
  2979.   VectorSubtract(vMax, vMin, vTemp);
  2980.  
  2981.   // if we are scaling in the same dimension the patch has no depth
  2982.   for (i = 0; i < 3; i ++)
  2983.   {
  2984.     if (vTemp[i] == 0 && vMove[i] != 0)
  2985.     {
  2986.       //Patch_Move(n, vMove, true);
  2987.       return false;
  2988.     }
  2989.   }
  2990.   
  2991.   for (i=0 ; i<3 ; i++)
  2992.     vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2));
  2993.  
  2994.   for (i = 0; i < 3; i++)
  2995.   {
  2996.     if (vAmt[i] != 0)
  2997.     {
  2998.       vScale[i] = 1.0 + vAmt[i] / vTemp[i];
  2999.     }
  3000.     else
  3001.     {
  3002.       vScale[i] = 1.0;
  3003.     }
  3004.   }
  3005.  
  3006.   Patch_Scale(p, vMid, vScale, false);
  3007.  
  3008.   VectorSubtract(vMax, vMin, vTemp);
  3009.  
  3010.   Patch_CalcBounds(p, vMin, vMax);
  3011.   
  3012.   VectorSubtract(vMax, vMin, vMid);
  3013.  
  3014.   VectorSubtract(vMid, vTemp, vTemp);
  3015.  
  3016.   VectorScale(vTemp, 0.5, vTemp);
  3017.  
  3018.   // abs of both should always be equal
  3019.   if (!VectorCompare(vMove, vAmt))
  3020.   {
  3021.     for (i = 0; i < 3; i++)
  3022.     {
  3023.       if (vMove[i] != vAmt[i])
  3024.         vTemp[i] = -(vTemp[i]);
  3025.     }
  3026.   }
  3027.  
  3028.   Patch_Move(p, vTemp);
  3029.   return true;
  3030. }
  3031.  
  3032.  
  3033. /*
  3034. ==================
  3035. Patch_AddRow
  3036. ==================
  3037. */
  3038. void Patch_AddRow(patchMesh_t *p)
  3039. {
  3040.   vec3_t vMin, vMax, vTemp;
  3041.   int i, j;
  3042.  
  3043.  
  3044.   if (p->height+2 < MAX_PATCH_HEIGHT)
  3045.   {
  3046.     Patch_CalcBounds(p, vMin, vMax);
  3047.     VectorSubtract(vMax, vMin, vTemp);
  3048.     for (i = 0; i < 3; i++)
  3049.     {
  3050.       vTemp[i] /= p->height + 2;
  3051.     }
  3052.  
  3053.     for (j = 0; j < p->width; j++)
  3054.     {
  3055.       VectorCopy(p->ctrl[j][p->height].xyz, p->ctrl[j][p->height+1].xyz);
  3056.       VectorCopy(p->ctrl[j][p->height].xyz, p->ctrl[j][p->height+2].xyz);
  3057.       p->height += 2;
  3058.       i = 1;
  3059.       while (i < p->height)
  3060.       {
  3061.         VectorAdd(p->ctrl[j][i].xyz, vTemp, p->ctrl[j][i].xyz);
  3062.         i++;
  3063.       }
  3064.     }
  3065.     
  3066.     Patch_CalcBounds(p, vMin, vMax);
  3067.     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  3068.   }
  3069.   UpdatePatchInspector();
  3070. }
  3071.  
  3072. /*
  3073. ==================
  3074. Patch_InsertColumn
  3075. ==================
  3076. */
  3077. void Patch_InsertColumn(patchMesh_t *p, bool bAdd)
  3078. {
  3079.   int h, w, i, j;
  3080.   vec3_t vTemp;
  3081.   
  3082.   if (p->width + 2 >= MAX_PATCH_WIDTH)
  3083.     return;
  3084.  
  3085.   if (bAdd) // add column?
  3086.   {
  3087.     for (h = 0; h < p->height; h++)
  3088.     {
  3089.       j = p->width-1;
  3090.       VectorSubtract(p->ctrl[j][h].xyz, p->ctrl[j-1][h].xyz, vTemp);
  3091.       for (i = 0; i < 3; i++)
  3092.         vTemp[i] /= 3;
  3093.  
  3094.       memcpy(&p->ctrl[j+2][h],&p->ctrl[j][h], sizeof(drawVert_t));
  3095.       memcpy(&p->ctrl[j][h],&p->ctrl[j-1][h], sizeof(drawVert_t));
  3096.  
  3097.       VectorAdd(p->ctrl[j][h].xyz, vTemp, p->ctrl[j][h].xyz);
  3098.       memcpy(&p->ctrl[j+1][h], &p->ctrl[j][h], sizeof(drawVert_t));
  3099.       VectorAdd(p->ctrl[j+1][h].xyz, vTemp, p->ctrl[j+1][h].xyz);
  3100.     }
  3101.   }
  3102.   else
  3103.   {
  3104.     for (h = 0; h < p->height; h++)
  3105.     {
  3106.       w = p->width-1;
  3107.       while (w >= 0)
  3108.       {
  3109.         memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t));
  3110.         w--;
  3111.       }
  3112.       VectorSubtract(p->ctrl[1][h].xyz, p->ctrl[0][h].xyz, vTemp);
  3113.       for (i = 0; i < 3; i++)
  3114.         vTemp[i] /= 3;
  3115.       VectorCopy(p->ctrl[0][h].xyz, p->ctrl[1][h].xyz);
  3116.       VectorAdd(p->ctrl[1][h].xyz, vTemp, p->ctrl[1][h].xyz);
  3117.       VectorCopy(p->ctrl[1][h].xyz, p->ctrl[2][h].xyz);
  3118.       VectorAdd(p->ctrl[2][h].xyz, vTemp, p->ctrl[2][h].xyz);
  3119.     }
  3120.   }
  3121.   p->width += 2;
  3122.   UpdatePatchInspector();
  3123. }
  3124.  
  3125.  
  3126. /*
  3127. ==================
  3128. Patch_InsertRow
  3129. ==================
  3130. */
  3131. void Patch_InsertRow(patchMesh_t *p, bool bAdd)
  3132. {
  3133.   int h, w, i, j;
  3134.   vec3_t vTemp;
  3135.   
  3136.   if (p->height + 2 >= MAX_PATCH_HEIGHT)
  3137.     return;
  3138.  
  3139.   if (bAdd) // add column?
  3140.   {
  3141.     for (w = 0; w < p->width; w++)
  3142.     {
  3143.       j = p->height-1;
  3144.       VectorSubtract(p->ctrl[w][j].xyz, p->ctrl[w][j-1].xyz, vTemp);
  3145.       for (i = 0; i < 3; i++)
  3146.         vTemp[i] /= 3;
  3147.  
  3148.       memcpy(&p->ctrl[w][j+2],&p->ctrl[w][j], sizeof(drawVert_t));
  3149.       memcpy(&p->ctrl[w][j],&p->ctrl[w][j-1], sizeof(drawVert_t));
  3150.  
  3151.       VectorAdd(p->ctrl[w][j].xyz, vTemp, p->ctrl[w][j].xyz);
  3152.       memcpy(&p->ctrl[w][j+1], &p->ctrl[w][j], sizeof(drawVert_t));
  3153.       VectorAdd(p->ctrl[w][j+1].xyz, vTemp, p->ctrl[w][j+1].xyz);
  3154.     }
  3155.   }
  3156.   else
  3157.   {
  3158.     for (w = 0; w < p->width; w++)
  3159.     {
  3160.       h = p->height-1;
  3161.       while (h >= 0)
  3162.       {
  3163.         memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t));
  3164.         h--;
  3165.       }
  3166.       VectorSubtract(p->ctrl[w][1].xyz, p->ctrl[w][0].xyz, vTemp);
  3167.       for (i = 0; i < 3; i++)
  3168.         vTemp[i] /= 3;
  3169.       VectorCopy(p->ctrl[w][0].xyz, p->ctrl[w][1].xyz);
  3170.       VectorAdd(p->ctrl[w][1].xyz, vTemp, p->ctrl[w][1].xyz);
  3171.       VectorCopy(p->ctrl[w][1].xyz, p->ctrl[w][2].xyz);
  3172.       VectorAdd(p->ctrl[w][2].xyz, vTemp, p->ctrl[w][2].xyz);
  3173.     }
  3174.   }
  3175.   p->height += 2;
  3176.   UpdatePatchInspector();
  3177. }
  3178.  
  3179.  
  3180. /*
  3181. ==================
  3182. Patch_RemoveRow
  3183. ==================
  3184. */
  3185. void Patch_RemoveRow(patchMesh_t *p, bool bFirst)
  3186. {
  3187.   
  3188.   if (p->height <= MIN_PATCH_HEIGHT)
  3189.     return;
  3190.  
  3191.   p->height -= 2;
  3192.  
  3193.   if (bFirst)
  3194.   {
  3195.     for (int w = 0; w < p->width; w++)
  3196.     {
  3197.       for (int h = 0; h < p->height; h++)
  3198.       {
  3199.         memcpy(&p->ctrl[w][h], &p->ctrl[w][h+2], sizeof(drawVert_t));
  3200.       }
  3201.     }
  3202.   }
  3203.   UpdatePatchInspector();
  3204. }
  3205.  
  3206.  
  3207. /*
  3208. ==================
  3209. Patch_RemoveColumn
  3210. ==================
  3211. */
  3212. void Patch_RemoveColumn(patchMesh_t *p, bool bFirst)
  3213. {
  3214.   
  3215.   if (p->width <= MIN_PATCH_WIDTH)
  3216.     return;
  3217.  
  3218.   p->width -= 2;
  3219.  
  3220.   if (bFirst)
  3221.   {
  3222.     for (int h = 0; h < p->height; h++)
  3223.     {
  3224.       for (int w = 0; w < p->width; w++)
  3225.       {
  3226.         memcpy(&p->ctrl[w][h], &p->ctrl[w+2][h], sizeof(drawVert_t));
  3227.       }
  3228.     }
  3229.   }
  3230.   UpdatePatchInspector();
  3231. }
  3232.  
  3233.  
  3234. /*
  3235. ==================
  3236. Patch_AdjustColumns
  3237. ==================
  3238. */
  3239. void Patch_AdjustColumns(patchMesh_t *p, int nCols)
  3240. {
  3241.   vec3_t vTemp, vTemp2;
  3242.   int i, w, h;
  3243.  
  3244.   if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH)
  3245.     return;
  3246.  
  3247.   // add in column adjustment
  3248.   p->width += nCols;
  3249.  
  3250.   for (h = 0; h < p->height; h++)
  3251.   {
  3252.     // for each column, we need to evenly disperse p->width number 
  3253.     // of points across the old bounds
  3254.     
  3255.     // calc total distance to interpolate 
  3256.     VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp);
  3257.  
  3258.     // amount per cycle
  3259.     for (i = 0; i < 3; i ++)
  3260.     {
  3261.       vTemp2[i] = vTemp[i] / (p->width - 1);
  3262.     }
  3263.  
  3264.     // move along
  3265.     for (w = 0; w < p->width-1; w++)
  3266.     {
  3267.       VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
  3268.     }
  3269.  
  3270.   }
  3271.     for ( w = 0 ; w < p->width ; w++ ) 
  3272.   {
  3273.         for ( h = 0 ; h < p->height ; h++ ) 
  3274.     {
  3275.             p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
  3276.             p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
  3277.         }
  3278.     }
  3279.   UpdatePatchInspector();
  3280. }
  3281.  
  3282.  
  3283. /*
  3284. ==================
  3285. Patch_AdjustRows
  3286. ==================
  3287. */
  3288. void Patch_AdjustRows(patchMesh_t *p, int nRows)
  3289. {
  3290.   vec3_t vTemp, vTemp2;
  3291.   int i, w, h;
  3292.  
  3293.   if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT)
  3294.     return;
  3295.  
  3296.   // add in column adjustment
  3297.   p->height += nRows;
  3298.  
  3299.   for (w = 0; w < p->width; w++)
  3300.   {
  3301.     // for each row, we need to evenly disperse p->height number 
  3302.     // of points across the old bounds
  3303.  
  3304.     // calc total distance to interpolate 
  3305.     VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp);
  3306.     
  3307.     //vTemp[0] = vTemp[1] = vTemp[2] = 0;
  3308.     //for (h = 0; h < p->height - nRows; h ++)
  3309.     //{
  3310.     //  VectorAdd(vTemp, p->ctrl[w][h], vTemp);
  3311.     //}
  3312.  
  3313.     // amount per cycle
  3314.     for (i = 0; i < 3; i ++)
  3315.     {
  3316.       vTemp2[i] = vTemp[i] / (p->height - 1);
  3317.     }
  3318.  
  3319.     // move along
  3320.     for (h = 0; h < p->height-1; h++)
  3321.     {
  3322.       VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
  3323.     }
  3324.  
  3325.   }
  3326.     for ( w = 0 ; w < p->width ; w++ ) 
  3327.   {
  3328.         for ( h = 0 ; h < p->height ; h++ ) 
  3329.     {
  3330.             p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
  3331.             p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
  3332.         }
  3333.     }
  3334.   UpdatePatchInspector();
  3335. }
  3336.  
  3337.  
  3338. void Patch_DisperseRows()
  3339. {
  3340.   vec3_t vTemp, vTemp2;
  3341.   int i, w, h;
  3342.  
  3343.  
  3344.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3345.     {
  3346.     if (pb->patchBrush)
  3347.     {
  3348.       patchMesh_t *p = pb->pPatch;
  3349.       Patch_Rebuild(p);
  3350.       for (w = 0; w < p->width; w++)
  3351.       {
  3352.         // for each row, we need to evenly disperse p->height number 
  3353.         // of points across the old bounds
  3354.  
  3355.         // calc total distance to interpolate 
  3356.         VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp);
  3357.     
  3358.         //vTemp[0] = vTemp[1] = vTemp[2] = 0;
  3359.         //for (h = 0; h < p->height - nRows; h ++)
  3360.         //{
  3361.         //  VectorAdd(vTemp, p->ctrl[w][h], vTemp);
  3362.         //}
  3363.  
  3364.         // amount per cycle
  3365.         for (i = 0; i < 3; i ++)
  3366.         {
  3367.           vTemp2[i] = vTemp[i] / (p->height - 1);
  3368.         }
  3369.  
  3370.         // move along
  3371.         for (h = 0; h < p->height-1; h++)
  3372.         {
  3373.           VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
  3374.         }
  3375.         Patch_Naturalize(p);
  3376.  
  3377.       }
  3378.     }
  3379.   }
  3380.   UpdatePatchInspector();
  3381.  
  3382. }
  3383.  
  3384. /*
  3385. ==================
  3386. Patch_AdjustColumns
  3387. ==================
  3388. */
  3389. void Patch_DisperseColumns()
  3390. {
  3391.   vec3_t vTemp, vTemp2;
  3392.   int i, w, h;
  3393.  
  3394.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3395.     {
  3396.     if (pb->patchBrush)
  3397.     {
  3398.       patchMesh_t *p = pb->pPatch;
  3399.       Patch_Rebuild(p);
  3400.  
  3401.       for (h = 0; h < p->height; h++)
  3402.       {
  3403.         // for each column, we need to evenly disperse p->width number 
  3404.         // of points across the old bounds
  3405.     
  3406.         // calc total distance to interpolate 
  3407.         VectorSubtract(p->ctrl[p->width - 1][h].xyz, p->ctrl[0][h].xyz, vTemp);
  3408.  
  3409.         // amount per cycle
  3410.         for (i = 0; i < 3; i ++)
  3411.         {
  3412.           vTemp2[i] = vTemp[i] / (p->width - 1);
  3413.         }
  3414.  
  3415.         // move along
  3416.         for (w = 0; w < p->width-1; w++)
  3417.         {
  3418.           VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
  3419.         }
  3420.  
  3421.       }
  3422.       Patch_Naturalize(p);
  3423.     }
  3424.   }
  3425.   UpdatePatchInspector();
  3426. }
  3427.  
  3428.  
  3429.  
  3430. /*
  3431. ==================
  3432. Patch_AdjustSelected
  3433. ==================
  3434. */
  3435. void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag)
  3436. {
  3437.   bool bUpdate = false;
  3438.     for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3439.     {
  3440.     if (pb->patchBrush)
  3441.     {
  3442.       if (bInsert)
  3443.       {
  3444.         if (bColumn)
  3445.         {
  3446.           Patch_InsertColumn(pb->pPatch, bFlag);
  3447.         }
  3448.         else
  3449.         {
  3450.           Patch_InsertRow(pb->pPatch, bFlag);
  3451.         }
  3452.       }
  3453.       else
  3454.       {
  3455.         if (bColumn)
  3456.         {
  3457.           Patch_RemoveColumn(pb->pPatch, bFlag);
  3458.         }
  3459.         else
  3460.         {
  3461.           Patch_RemoveRow(pb->pPatch, bFlag);
  3462.         }
  3463.       }
  3464.       bUpdate = true;
  3465.       vec3_t vMin, vMax;
  3466.       patchMesh_t *p = pb->pPatch;
  3467.       Patch_CalcBounds(p, vMin, vMax);
  3468.       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  3469.     }
  3470.   }
  3471.   if (bUpdate)
  3472.   {
  3473.     Sys_UpdateWindows(W_ALL);
  3474.   }
  3475. }
  3476.  
  3477.  
  3478. /*
  3479. ==================
  3480. Patch_AdjustSelectedRowCols
  3481. ==================
  3482. */
  3483. void Patch_AdjustSelectedRowCols(int nRows, int nCols)
  3484. {
  3485.     for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3486.     {
  3487.     if (pb->patchBrush)
  3488.     {
  3489.       Patch_InsertColumn(pb->pPatch, false);
  3490.       if (nRows != 0)
  3491.       {
  3492.         Patch_AdjustRows(pb->pPatch, nRows);
  3493.       }
  3494.       
  3495.       if (nCols != 0)
  3496.       {
  3497.         Patch_AdjustColumns(pb->pPatch, nCols);
  3498.       }
  3499.         }
  3500.   }
  3501.   UpdatePatchInspector();
  3502. }
  3503.  
  3504.  
  3505.  
  3506. void Parse1DMatrix(int x, float* p)
  3507. {
  3508.   GetToken(true); // (
  3509.   for (int i = 0; i < x; i++)
  3510.   {
  3511.     GetToken(false);
  3512.     p[i] = atof(token);
  3513.   }
  3514.   GetToken(true); // )
  3515. }
  3516.  
  3517. void Parse2DMatrix(int y, int x, float* p)
  3518. {
  3519.   GetToken(true); // (
  3520.   for (int i = 0; i < y; i++)
  3521.   {
  3522.     Parse1DMatrix(x, p + i*x);
  3523.   }
  3524.   GetToken(true); // )
  3525. }
  3526.  
  3527. void Parse3DMatrix(int z, int y, int x, float* p)
  3528. {
  3529.   GetToken(true); // (
  3530.   for (int i = 0; i < z; i++)
  3531.   {
  3532.     Parse2DMatrix(y, x, p + i*(x*MAX_PATCH_HEIGHT));
  3533.   }
  3534.   GetToken(true); // )
  3535. }
  3536.  
  3537. // parses a patch
  3538. brush_t* Patch_Parse(bool bOld)
  3539. {
  3540.     //--if (bOld)
  3541.     //--{
  3542.     //--  return Patch_ParseOld();
  3543.     //--}
  3544.  
  3545.   GetToken(true);
  3546.     
  3547.   if (strcmp(token, "{"))
  3548.     return NULL;
  3549.  
  3550.     patchMesh_t *pm = MakeNewPatch();
  3551.  
  3552.     if (g_qeglobals.bSurfacePropertiesPlugin)
  3553.     {
  3554.         GETPLUGINTEXDEF(pm)->ParsePatchTexdef();
  3555.     }
  3556.     else
  3557.     {
  3558.         // texture def
  3559.         GetToken(true);
  3560.         
  3561.         // band-aid 
  3562.         if (strcmp(token, "("))
  3563.         {
  3564.             pm->d_texture = Texture_ForName(token);
  3565.             GetToken(true);
  3566.         }
  3567.         else
  3568.         {
  3569.             pm->d_texture = notexture;
  3570.             Sys_Printf("Warning: Patch read with no texture, using notexture... \n");
  3571.         }               
  3572.         
  3573.         if (strcmp(token, "("))
  3574.             return NULL;
  3575.         
  3576.         // width, height, flags (currently only negative)
  3577.         GetToken(false);
  3578.         pm->width = atoi(token);
  3579.         
  3580.         GetToken(false);
  3581.         pm->height = atoi(token);
  3582.         
  3583.         GetToken(false);
  3584.         pm->contents = atoi(token);
  3585.         
  3586.         GetToken(false);
  3587.         pm->flags = atoi(token);
  3588.         
  3589.         GetToken(false);
  3590.         pm->value = atoi(token);
  3591.         
  3592.         if (!bOld)
  3593.         {
  3594.             GetToken(false);
  3595.             pm->type = atoi(token);
  3596.         }
  3597.         
  3598.         GetToken(false);
  3599.         if (strcmp(token, ")"))
  3600.             return NULL;
  3601.         
  3602.     }
  3603.  
  3604.  
  3605.  
  3606.   float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
  3607.   Parse3DMatrix(pm->width, pm->height, 5, reinterpret_cast<float*>(&ctrl));
  3608.  
  3609.   int w, h;
  3610.  
  3611.   for (w = 0; w < pm->width; w++)
  3612.   {
  3613.     for (h = 0; h < pm->height; h++)
  3614.     {
  3615.       pm->ctrl[w][h].xyz[0] = ctrl[w][h][0];  
  3616.       pm->ctrl[w][h].xyz[1] = ctrl[w][h][1];  
  3617.       pm->ctrl[w][h].xyz[2] = ctrl[w][h][2];  
  3618.       pm->ctrl[w][h].st[0] = ctrl[w][h][3]; 
  3619.       pm->ctrl[w][h].st[1] = ctrl[w][h][4];  
  3620.     }
  3621.   }
  3622.  
  3623.   GetToken(true);
  3624.  
  3625.     if (g_qeglobals.m_bBrushPrimitMode)
  3626.   {
  3627.     // we are in brush primit mode, but maybe it's a classic patch that needs converting, test "}"
  3628.     if (strcmp(token, "}") && strcmp (token, "(") )
  3629.       {
  3630.           epair_t *ep = ParseEpair();
  3631.           ep->next = pm->epairs;
  3632.           pm->epairs = ep;
  3633.       GetToken(true);
  3634.       }
  3635.   }
  3636.  
  3637.   if (strcmp(token, "}"))
  3638.     return NULL;
  3639.  
  3640.   brush_t *b = AddBrushForPatch(pm, false);
  3641.  
  3642.   return b;
  3643. }
  3644.  
  3645.  
  3646. /*
  3647. ==================
  3648. Patch_Write 
  3649. ==================
  3650. */
  3651. void Patch_Write (patchMesh_t *p, CMemFile *file)
  3652. {
  3653.     if (g_qeglobals.bSurfacePropertiesPlugin)
  3654.     {
  3655.         Sys_Printf("WARNING: Patch_Write to a CMemFile and Surface Properties plugin not done\n");
  3656.     }
  3657.   //--MemFile_fprintf(file, " {\n  patchDef3\n  {\n");
  3658.   MemFile_fprintf(file, " {\n  patchDef2\n  {\n");
  3659.  
  3660.   MemFile_fprintf(file, "   %s\n",p->d_texture->name);
  3661.   //--MemFile_fprintf(file, "   ( %i %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value, p->type);
  3662.   MemFile_fprintf(file, "   ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
  3663.  
  3664.  
  3665.     float        ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
  3666.  
  3667.   int w, h;
  3668.   for (w = 0; w < p->width; w++)
  3669.   {
  3670.     for (h = 0; h < p->height; h++)
  3671.     {
  3672.       ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
  3673.       ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
  3674.       ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
  3675.       ctrl[w][h][3] = p->ctrl[w][h].st[0];
  3676.       ctrl[w][h][4] = p->ctrl[w][h].st[1];
  3677.     }
  3678.   }
  3679.  
  3680.   _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
  3681.  
  3682.     if (g_qeglobals.m_bBrushPrimitMode)
  3683.   {
  3684.       if (p->epairs)
  3685.     {
  3686.             for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
  3687.       {
  3688.                 MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
  3689.       }
  3690.     }
  3691.   }
  3692.  
  3693.   MemFile_fprintf(file, "  }\n }\n");
  3694. }
  3695.  
  3696. void Patch_Write (patchMesh_t *p, FILE *file)
  3697. {
  3698.     fprintf(file, " {\n  patchDef2\n  {\n");
  3699.     if (g_qeglobals.bSurfacePropertiesPlugin)
  3700.     {
  3701. #ifdef _DEBUG
  3702.         if ( !p->pData )
  3703.             Sys_Printf("ERROR: no IPluginTexdef in patch\n");
  3704. #endif
  3705.         g_File = file;
  3706.         GETPLUGINTEXDEF(p)->WritePatchTexdef( QERApp_MapPrintf_FILE );
  3707.     }
  3708.     else
  3709.     {
  3710.         fprintf(file, "   %s\n",p->d_texture->name);
  3711.         fprintf(file, "   ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
  3712.     }
  3713.  
  3714.     float        ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
  3715.  
  3716.   int w, h;
  3717.   for (w = 0; w < p->width; w++)
  3718.   {
  3719.     for (h = 0; h < p->height; h++)
  3720.     {
  3721.       ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
  3722.       ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
  3723.       ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
  3724.       ctrl[w][h][3] = p->ctrl[w][h].st[0];
  3725.       ctrl[w][h][4] = p->ctrl[w][h].st[1];
  3726.     }
  3727.   }
  3728.  
  3729.   _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
  3730.  
  3731.     if (g_qeglobals.m_bBrushPrimitMode)
  3732.   {
  3733.       if (p->epairs)
  3734.     {
  3735.             for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
  3736.       {
  3737.                 fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
  3738.       }
  3739.     }
  3740.   }
  3741.  
  3742.   fprintf(file, "  }\n }\n");
  3743. }
  3744.  
  3745.  
  3746. /*
  3747. ==================
  3748. Patch_RotateTexture
  3749. ==================
  3750. */
  3751. void Patch_RotateTexture(patchMesh_t *p, float fAngle)
  3752. {
  3753.   vec3_t vMin, vMax;
  3754.   Patch_CalcBounds(p, vMin, vMax);
  3755.   p->bDirty = true;
  3756.   for (int w = 0; w < p->width; w++)
  3757.   {
  3758.     for (int h = 0; h < p->height; h++)
  3759.     {
  3760.       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
  3761.         continue;
  3762.  
  3763.       float x = p->ctrl[w][h].st[0];
  3764.       float y = p->ctrl[w][h].st[1];
  3765.       p->ctrl[w][h].st[0] = x * cos(fAngle * Q_PI / 180) - y * sin(fAngle * Q_PI / 180);
  3766.       p->ctrl[w][h].st[1] = y * cos(fAngle * Q_PI / 180) + x * sin(fAngle * Q_PI / 180);
  3767.     }
  3768.   }
  3769. }
  3770.  
  3771.  
  3772. /*
  3773. ==================
  3774. Patch_ScaleTexture
  3775. ==================
  3776. */
  3777. void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup)
  3778. {
  3779.   // FIXME:
  3780.   // this hack turns scales into 1.1 or 0.9
  3781.   if (bFixup)
  3782.   {
  3783.     fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10;
  3784.     fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10;
  3785.   }
  3786.   else
  3787.   {
  3788.     if (fx == 0)
  3789.       fx = 1.0;
  3790.     if (fy == 0)
  3791.       fy = 1.0;
  3792.   }
  3793.   
  3794.   for (int w = 0; w < p->width; w++)
  3795.   {
  3796.     for (int h = 0; h < p->height; h++)
  3797.     {
  3798.       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
  3799.         continue;
  3800.  
  3801.       p->ctrl[w][h].st[0] *= fx;
  3802.       p->ctrl[w][h].st[1] *= fy;
  3803.     }
  3804.   }
  3805.   p->bDirty = true;
  3806. }
  3807.  
  3808.  
  3809. /*
  3810. ==================
  3811. Patch_ShiftTexture
  3812. ==================
  3813. */
  3814. void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy)
  3815. {
  3816.   //if (fx)
  3817.   //  fx = (fx > 0) ? 0.1 : -0.1;
  3818.   //if (fy)
  3819.   //  fy = (fy > 0) ? 0.1 : -0.1;
  3820.  
  3821.   fx = (abs(fx) >= 1) ? fx / 10 : fx;
  3822.   fy = (abs(fy) >= 1) ? fy / 10 : fy;
  3823.  
  3824.   for (int w = 0; w < p->width; w++)
  3825.   {
  3826.     for (int h = 0; h < p->height; h++)
  3827.     {
  3828.       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
  3829.         continue;
  3830.  
  3831.       p->ctrl[w][h].st[0] += fx;
  3832.       p->ctrl[w][h].st[1] += fy;
  3833.     }
  3834.   }
  3835.   p->bDirty = true;
  3836. }
  3837.  
  3838. void patchInvert(patchMesh_t *p)
  3839. {
  3840.   drawVert_t vertTemp;
  3841.   p->bDirty = true;
  3842.     for ( int i = 0 ; i < p->width ; i++ ) 
  3843.   {
  3844.     for (int j = 0; j < p->height / 2; j++)
  3845.     {
  3846.       memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
  3847.       memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
  3848.       memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
  3849.         }
  3850.     }
  3851. }
  3852.  
  3853. /*
  3854. ==================
  3855. Patch_ToggleInverted
  3856. ==================
  3857. */
  3858. void Patch_ToggleInverted()
  3859. {
  3860.   bool bUpdate = false;
  3861.  
  3862.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3863.     {
  3864.     if (pb->patchBrush)
  3865.     {
  3866.       bUpdate = true;
  3867.       patchInvert(pb->pPatch);
  3868.     }
  3869.   }
  3870.  
  3871.   if (bUpdate)
  3872.   {
  3873.     Sys_UpdateWindows(W_ALL);
  3874.   }
  3875.   UpdatePatchInspector();
  3876. }
  3877.  
  3878. /*
  3879. ==================
  3880. Patch_ToggleInverted
  3881. ==================
  3882. */
  3883. void Patch_InvertTexture(bool bY)
  3884. {
  3885.   bool bUpdate = false;
  3886.  
  3887.   float fTemp[2];
  3888.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3889.     {
  3890.     if (pb->patchBrush)
  3891.     {
  3892.       bUpdate = true;
  3893.       patchMesh_t *p = pb->pPatch;
  3894.       p->bDirty = true;
  3895.       if (bY)
  3896.       {
  3897.           for ( int i = 0 ; i < p->height ; i++ ) 
  3898.         {
  3899.           for (int j = 0; j < p->width / 2; j++)
  3900.           {
  3901.             memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2]));
  3902.             memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2]));
  3903.             memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2]));
  3904.               }
  3905.           }
  3906.       }
  3907.       else
  3908.       {
  3909.           for ( int i = 0 ; i < p->width ; i++ ) 
  3910.         {
  3911.           for (int j = 0; j < p->height / 2; j++)
  3912.           {
  3913.             memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2]));
  3914.             memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2]));
  3915.             memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2]));
  3916.               }
  3917.           }
  3918.       }
  3919.     }
  3920.   }
  3921.  
  3922.   if (bUpdate)
  3923.   {
  3924.     Sys_UpdateWindows(W_ALL);
  3925.   }
  3926.   UpdatePatchInspector();
  3927. }
  3928.  
  3929.  
  3930.  
  3931.  
  3932. /*
  3933. ==================
  3934. Patch_Save
  3935. ==================
  3936.  Saves patch ctrl info (originally to deal with a 
  3937.  cancel in the surface dialog
  3938. */
  3939. void Patch_Save(patchMesh_t *p)
  3940. {
  3941.   patchSave.width = p->width;
  3942.   patchSave.height = p->height;
  3943.   memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl));
  3944. }
  3945.  
  3946.  
  3947. /*
  3948. ==================
  3949. Patch_Restore
  3950. ==================
  3951. */
  3952. void Patch_Restore(patchMesh_t *p)
  3953. {
  3954.   p->width = patchSave.width;
  3955.   p->height = patchSave.height;
  3956.   memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl));
  3957. }
  3958.  
  3959. void Patch_ResetTexturing(float fx, float fy)
  3960. {
  3961.     for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3962.     {
  3963.     if (pb->patchBrush)
  3964.     {
  3965.       patchMesh_t *p = pb->pPatch;
  3966.       p->bDirty = true;
  3967.         for ( int i = 0 ; i < p->width ; i++ ) 
  3968.       {
  3969.             for ( int j = 0 ; j < p->height ; j++ ) 
  3970.         {
  3971.                 p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1);
  3972.                 p->ctrl[i][j].st[1] = fy * (float)j / (p->height - 1);
  3973.             }
  3974.         }
  3975.     }
  3976.   }
  3977. }
  3978.  
  3979.  
  3980. void Patch_FitTexturing()
  3981. {
  3982.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  3983.     {
  3984.     if (pb->patchBrush)
  3985.     {
  3986.       patchMesh_t *p = pb->pPatch;
  3987.       p->bDirty = true;
  3988.         for ( int i = 0 ; i < p->width ; i++ ) 
  3989.       {
  3990.             for ( int j = 0 ; j < p->height ; j++ ) 
  3991.         {
  3992.                 p->ctrl[i][j].st[0] = 1 * (float)i / (p->width - 1);
  3993.                 p->ctrl[i][j].st[1] = 1 * (float)j / (p->height - 1);
  3994.             }
  3995.         }
  3996.     }
  3997.   }
  3998. }
  3999.  
  4000.  
  4001. void Patch_SetTextureInfo(texdef_t *pt)
  4002. {
  4003.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4004.     {
  4005.     if (pb->patchBrush)
  4006.     {
  4007.       if (pt->rotate)
  4008.         Patch_RotateTexture(pb->pPatch, pt->rotate);
  4009.  
  4010.       if (pt->shift[0] || pt->shift[1])
  4011.         Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]);
  4012.  
  4013.       if (pt->scale[0] || pt->scale[1])
  4014.         Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false);
  4015.  
  4016.       patchMesh_t *p = pb->pPatch;
  4017.       p->contents = pt->contents;
  4018.       p->flags = pt->flags;
  4019.       p->value = pt->value;
  4020.     }
  4021.   }
  4022. }
  4023.  
  4024. bool WINAPI OnlyPatchesSelected()
  4025. {
  4026.   if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
  4027.     return false;
  4028.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4029.     {
  4030.     if (!pb->patchBrush)
  4031.     {
  4032.       return false;
  4033.     }
  4034.   }
  4035.   return true;
  4036. }
  4037.  
  4038. bool WINAPI AnyPatchesSelected()
  4039. {
  4040.   if (g_ptrSelectedFaces.GetSize() > 0  || selected_brushes.next == &selected_brushes)
  4041.     return false;
  4042.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4043.     {
  4044.     if (pb->patchBrush)
  4045.     {
  4046.       return true;
  4047.     }
  4048.   }
  4049.   return false;
  4050. }
  4051.  
  4052. patchMesh_t* SinglePatchSelected()
  4053. {
  4054.     if (selected_brushes.next->patchBrush)
  4055.   {
  4056.     return selected_brushes.next->pPatch;
  4057.   }
  4058.   return NULL;
  4059. }
  4060.  
  4061. void Patch_BendToggle()
  4062. {
  4063.   if (g_bPatchBendMode)
  4064.   {
  4065.     g_bPatchBendMode = false;
  4066.     HideInfoDialog();
  4067.     g_pParentWnd->UpdatePatchToolbarButtons() ;
  4068.     return;
  4069.   }
  4070.  
  4071.     brush_t* b = selected_brushes.next;
  4072.  
  4073.   if (!QE_SingleBrush() || !b->patchBrush)
  4074.   {
  4075.     Sys_Printf("Must bend a single patch");
  4076.         return;
  4077.   }
  4078.  
  4079.   Patch_Save(b->pPatch);
  4080.     g_bPatchBendMode = true;
  4081.   g_nPatchBendState = BEND_SELECT_ROTATION;
  4082.   g_bPatchAxisOnRow = true;
  4083.   g_nPatchAxisIndex = 1;
  4084.   ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]);
  4085. }
  4086.  
  4087. void Patch_BendHandleTAB()
  4088. {
  4089.   if (!g_bPatchBendMode)
  4090.   {
  4091.     return;
  4092.   }
  4093.  
  4094.     brush_t* b = selected_brushes.next;
  4095.   if (!QE_SingleBrush() || !b->patchBrush)
  4096.   {
  4097.     Patch_BendToggle();
  4098.     Sys_Printf("No patch to bend!");
  4099.         return;
  4100.   }
  4101.  
  4102.   patchMesh_t *p = b->pPatch;
  4103.  
  4104.   bool bShift = (GetKeyState(VK_SHIFT) & 0x8000);
  4105.  
  4106.   if (g_nPatchBendState == BEND_SELECT_ROTATION)
  4107.   {
  4108.     // only able to deal with odd numbered rows/cols
  4109.     g_nPatchAxisIndex += (bShift) ? -2 : 2;
  4110.     if (g_bPatchAxisOnRow)
  4111.     {
  4112.       if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height)
  4113.       {
  4114.         g_bPatchAxisOnRow = false;
  4115.         g_nPatchAxisIndex = (bShift) ? p->width-1 : 1;
  4116.       }
  4117.     }
  4118.     else
  4119.     {
  4120.       if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width)
  4121.       {
  4122.         g_bPatchAxisOnRow = true;
  4123.         g_nPatchAxisIndex = (bShift) ? p->height-1 : 1;
  4124.       }
  4125.     }
  4126.   }
  4127.   else
  4128.   if (g_nPatchBendState == BEND_SELECT_ORIGIN)
  4129.   {
  4130.     g_nBendOriginIndex += (bShift) ? -1 : 1;
  4131.     if (g_bPatchAxisOnRow)
  4132.     {
  4133.       if (bShift)
  4134.       {
  4135.         if (g_nBendOriginIndex < 0)
  4136.           g_nBendOriginIndex = p->width-1;
  4137.       }
  4138.       else
  4139.       {
  4140.         if (g_nBendOriginIndex > p->width-1)
  4141.           g_nBendOriginIndex = 0;
  4142.       }
  4143.       VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin);
  4144.     }
  4145.     else
  4146.     {
  4147.       if (bShift)
  4148.       {
  4149.         if (g_nBendOriginIndex < 0)
  4150.           g_nBendOriginIndex = p->height-1;
  4151.       }
  4152.       else
  4153.       {
  4154.         if (g_nBendOriginIndex > p->height-1)
  4155.           g_nBendOriginIndex = 0;
  4156.       }
  4157.       VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin);
  4158.     }
  4159.   }
  4160.   else
  4161.   if (g_nPatchBendState == BEND_SELECT_EDGE)
  4162.   {
  4163.     g_bPatchLowerEdge ^= 1;
  4164.   }
  4165.   Sys_UpdateWindows(W_ALL);
  4166. }
  4167.  
  4168. void Patch_BendHandleENTER()
  4169. {
  4170.   if (!g_bPatchBendMode)
  4171.   {
  4172.     return;
  4173.   }
  4174.  
  4175.   if (g_nPatchBendState  < BEND_BENDIT)
  4176.   {
  4177.     g_nPatchBendState++;
  4178.     ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]);
  4179.     if (g_nPatchBendState == BEND_SELECT_ORIGIN)
  4180.     {
  4181.       g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0;
  4182.       g_nBendOriginIndex = 0;
  4183.       Patch_BendHandleTAB();
  4184.     }
  4185.     else
  4186.     if (g_nPatchBendState == BEND_SELECT_EDGE)
  4187.     {
  4188.       g_bPatchLowerEdge = true;
  4189.     }
  4190.     else
  4191.     if (g_nPatchBendState == BEND_BENDIT)
  4192.     {
  4193.       // basically we go into rotation mode, set the axis to the center of the 
  4194.     }
  4195.   }
  4196.   else
  4197.   {
  4198.     // done
  4199.     Patch_BendToggle();
  4200.   }
  4201.   Sys_UpdateWindows(W_ALL);
  4202.  
  4203. }
  4204.  
  4205.  
  4206. void Patch_BendHandleESC()
  4207. {
  4208.   if (!g_bPatchBendMode)
  4209.   {
  4210.     return;
  4211.   }
  4212.   Patch_BendToggle();
  4213.     brush_t* b = selected_brushes.next;
  4214.   if (QE_SingleBrush() && b->patchBrush)
  4215.   {
  4216.     Patch_Restore(b->pPatch);
  4217.   }
  4218.   Sys_UpdateWindows(W_ALL);
  4219. }
  4220.  
  4221. void Patch_SetBendRotateOrigin(patchMesh_t *p)
  4222. {
  4223. #if 1
  4224.   int nType = g_pParentWnd->ActiveXY()->GetViewType();
  4225.   int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1;
  4226.  
  4227.   g_vBendOrigin[nDim3] = 0;
  4228.   VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin());
  4229.   return;
  4230. #else
  4231.   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
  4232.   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
  4233.  
  4234.   float fxLo, fyLo, fxHi, fyHi;
  4235.   fxLo = fyLo = 9999;
  4236.   fxHi = fyHi = -9999;
  4237.  
  4238.   if (g_bPatchAxisOnRow)
  4239.   {
  4240.     for (int i = 0; i < p->width; i++)
  4241.     {
  4242.       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo)
  4243.         fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
  4244.  
  4245.       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi)
  4246.         fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
  4247.  
  4248.       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo)
  4249.         fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
  4250.  
  4251.       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi)
  4252.         fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
  4253.     }
  4254.   }
  4255.   else
  4256.   {
  4257.     for (int i = 0; i < p->height; i++)
  4258.     {
  4259.       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo)
  4260.         fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
  4261.  
  4262.       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi)
  4263.         fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
  4264.  
  4265.       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo)
  4266.         fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
  4267.  
  4268.       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi)
  4269.         fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
  4270.     }
  4271.   }
  4272.  
  4273.   g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0;
  4274.   g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5;
  4275.   g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5;
  4276. #endif
  4277. }
  4278.  
  4279. // also sets the rotational origin
  4280. void Patch_SelectBendAxis()
  4281. {
  4282.     brush_t* b = selected_brushes.next;
  4283.   if (!QE_SingleBrush() || !b->patchBrush)
  4284.   {
  4285.     // should not ever happen
  4286.     Patch_BendToggle();
  4287.         return;
  4288.   }
  4289.  
  4290.   patchMesh_t *p = b->pPatch;
  4291.   if (g_bPatchAxisOnRow)
  4292.   {
  4293.     SelectRow(p, g_nPatchAxisIndex, false);
  4294.   }
  4295.   else
  4296.   {
  4297.     SelectColumn(p, g_nPatchAxisIndex, false);
  4298.   }
  4299.  
  4300.   //FIXME: this only needs to be set once... 
  4301.   Patch_SetBendRotateOrigin(p);
  4302.  
  4303. }
  4304.  
  4305. void Patch_SelectBendNormal()
  4306. {
  4307.     brush_t* b = selected_brushes.next;
  4308.   if (!QE_SingleBrush() || !b->patchBrush)
  4309.   {
  4310.     // should not ever happen
  4311.     Patch_BendToggle();
  4312.         return;
  4313.   }
  4314.  
  4315.   patchMesh_t *p = b->pPatch;
  4316.  
  4317.   g_qeglobals.d_num_move_points = 0;
  4318.   if (g_bPatchAxisOnRow)
  4319.   {
  4320.     if (g_bPatchLowerEdge)
  4321.     {
  4322.       for (int j = 0; j < g_nPatchAxisIndex; j++)
  4323.         SelectRow(p, j, true);
  4324.     }
  4325.     else
  4326.     {
  4327.       for (int j = p->height-1; j > g_nPatchAxisIndex; j--)
  4328.         SelectRow(p, j, true);
  4329.     }
  4330.   }
  4331.   else
  4332.   {
  4333.     if (g_bPatchLowerEdge)
  4334.     {
  4335.       for (int j = 0; j < g_nPatchAxisIndex; j++)
  4336.         SelectColumn(p, j, true);
  4337.     }
  4338.     else
  4339.     {
  4340.       for (int j = p->width-1; j > g_nPatchAxisIndex; j--)
  4341.         SelectColumn(p, j, true);
  4342.     }
  4343.   }
  4344.   Patch_SetBendRotateOrigin(p);
  4345. }
  4346.  
  4347.  
  4348.  
  4349. void Patch_InsDelToggle()
  4350. {
  4351.   if (g_bPatchInsertMode)
  4352.   {
  4353.     g_bPatchInsertMode = false;
  4354.     HideInfoDialog();
  4355.     g_pParentWnd->UpdatePatchToolbarButtons() ;
  4356.     return;
  4357.   }
  4358.  
  4359.     brush_t* b = selected_brushes.next;
  4360.  
  4361.   if (!QE_SingleBrush() || !b->patchBrush)
  4362.   {
  4363.     Sys_Printf("Must work with a single patch");
  4364.         return;
  4365.   }
  4366.  
  4367.   Patch_Save(b->pPatch);
  4368.     g_bPatchInsertMode = true;
  4369.   g_nPatchInsertState = INSERT_SELECT_EDGE;
  4370.   g_bPatchAxisOnRow = true;
  4371.   g_nPatchAxisIndex = 0;
  4372.   ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]);
  4373.  
  4374. }
  4375.  
  4376. void Patch_InsDelESC()
  4377. {
  4378.   if (!g_bPatchInsertMode)
  4379.   {
  4380.     return;
  4381.   }
  4382.   Patch_InsDelToggle();
  4383.   Sys_UpdateWindows(W_ALL);
  4384. }
  4385.  
  4386.  
  4387. void Patch_InsDelHandleENTER()
  4388. {
  4389. }
  4390.  
  4391. void Patch_InsDelHandleTAB()
  4392. {
  4393.   if (!g_bPatchInsertMode)
  4394.   {
  4395.     Patch_InsDelToggle();
  4396.     return;
  4397.   }
  4398.  
  4399.     brush_t* b = selected_brushes.next;
  4400.   if (!QE_SingleBrush() || !b->patchBrush)
  4401.   {
  4402.     Patch_BendToggle();
  4403.     Sys_Printf("No patch to bend!");
  4404.         return;
  4405.   }
  4406.  
  4407.   patchMesh_t *p = b->pPatch;
  4408.  
  4409.   // only able to deal with odd numbered rows/cols
  4410.   g_nPatchAxisIndex += 2;
  4411.   if (g_bPatchAxisOnRow)
  4412.   {
  4413.     if (g_nPatchAxisIndex >= p->height-1)
  4414.     {
  4415.       g_bPatchAxisOnRow = false;
  4416.       g_nPatchAxisIndex = 0;
  4417.     }
  4418.   }
  4419.   else
  4420.   {
  4421.     if (g_nPatchAxisIndex >= p->width-1)
  4422.     {
  4423.       g_bPatchAxisOnRow = true;
  4424.       g_nPatchAxisIndex = 0;
  4425.     }
  4426.   }
  4427.   Sys_UpdateWindows(W_ALL);
  4428. }
  4429.  
  4430.  
  4431. void _Write1DMatrix (FILE *f, int x, float *m) {
  4432.     int        i;
  4433.  
  4434.     fprintf (f, "( ");
  4435.     for (i = 0 ; i < x ; i++) {
  4436.         if (m[i] == (int)m[i] ) {
  4437.             fprintf (f, "%i ", (int)m[i]);
  4438.         } else {
  4439.             fprintf (f, "%f ", m[i]);
  4440.         }
  4441.     }
  4442.     fprintf (f, ")");
  4443. }
  4444.  
  4445. void _Write2DMatrix (FILE *f, int y, int x, float *m) {
  4446.     int        i;
  4447.  
  4448.     fprintf (f, "( ");
  4449.     for (i = 0 ; i < y ; i++) {
  4450.         _Write1DMatrix (f, x, m + i*x);
  4451.         fprintf (f, " ");
  4452.     }
  4453.     fprintf (f, ")\n");
  4454. }
  4455.  
  4456.  
  4457. void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) {
  4458.     int        i;
  4459.  
  4460.     fprintf (f, "(\n");
  4461.     for (i = 0 ; i < z ; i++) {
  4462.         _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
  4463.     }
  4464.     fprintf (f, ")\n");
  4465. }
  4466.  
  4467. void _Write1DMatrix (CMemFile *f, int x, float *m) {
  4468.     int        i;
  4469.  
  4470.     MemFile_fprintf (f, "( ");
  4471.     for (i = 0 ; i < x ; i++) {
  4472.         if (m[i] == (int)m[i] ) {
  4473.             MemFile_fprintf (f, "%i ", (int)m[i]);
  4474.         } else {
  4475.             MemFile_fprintf (f, "%f ", m[i]);
  4476.         }
  4477.     }
  4478.     MemFile_fprintf (f, ")");
  4479. }
  4480.  
  4481. void _Write2DMatrix (CMemFile *f, int y, int x, float *m) {
  4482.     int        i;
  4483.  
  4484.     MemFile_fprintf (f, "( ");
  4485.     for (i = 0 ; i < y ; i++) {
  4486.         _Write1DMatrix (f, x, m + i*x);
  4487.         MemFile_fprintf (f, " ");
  4488.     }
  4489.     MemFile_fprintf (f, ")\n");
  4490. }
  4491.  
  4492.  
  4493. void _Write3DMatrix (CMemFile *f, int z, int y, int x, float *m) {
  4494.     int        i;
  4495.  
  4496.     MemFile_fprintf (f, "(\n");
  4497.     for (i = 0 ; i < z ; i++) {
  4498.         _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
  4499.     }
  4500.     MemFile_fprintf (f, ")\n");
  4501. }
  4502.  
  4503.  
  4504. void Patch_NaturalizeSelected(bool bCap, bool bCycleCap)
  4505. {
  4506.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4507.     {
  4508.     if (pb->patchBrush)
  4509.     {
  4510.       if (bCap)
  4511.         Patch_CapTexture(pb->pPatch, bCycleCap);
  4512.       else
  4513.         Patch_Naturalize(pb->pPatch);
  4514.     }
  4515.   }
  4516. }
  4517.  
  4518. bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR)
  4519. {
  4520.   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
  4521.   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
  4522.   if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) ||
  4523.       (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1]))
  4524.   {
  4525.     if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) ||
  4526.         (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2]))
  4527.       return true;
  4528.   }
  4529.   return false;
  4530. }
  4531.  
  4532.  
  4533. void Patch_SelectAreaPoints()
  4534. {
  4535.   g_qeglobals.d_num_move_points = 0;
  4536.   g_nPatchClickedView = -1;
  4537.  
  4538.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4539.     {
  4540.     if (pb->patchBrush)
  4541.     {
  4542.       patchMesh_t *p = pb->pPatch;
  4543.       for (int i = 0; i < p->width; i++)
  4544.       {
  4545.         for (int j = 0; j < p->height; j++)
  4546.         {
  4547.           if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR))
  4548.           {
  4549.             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
  4550.           }
  4551.         }
  4552.       }
  4553.     }
  4554.   }
  4555. }
  4556.  
  4557. const char* Patch_GetTextureName()
  4558. {
  4559.     brush_t* b = selected_brushes.next;
  4560.   if (b->patchBrush)
  4561.   {
  4562.     patchMesh_t *p = b->pPatch;
  4563.     if (p->d_texture->name)
  4564.       return p->d_texture->name;
  4565.   }
  4566.   return "";
  4567. }
  4568.  
  4569. patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom)
  4570. {
  4571.   patchMesh_t* p = MakeNewPatch();
  4572.   memcpy(p, pFrom , sizeof(patchMesh_t));
  4573.   p->bSelected = false;
  4574.   p->bDirty = true;
  4575.   p->bOverlay = false;
  4576.   p->nListID = -1;
  4577.   // surface plugin
  4578.   if (g_qeglobals.bSurfacePropertiesPlugin)
  4579.   {
  4580. #ifdef _DEBUG
  4581.     if (!pFrom->pData)
  4582.         Sys_Printf("WARNING: unexpected pFrom->pData is NULL in Patch_Duplicate\n");
  4583.     else
  4584. #endif
  4585.         p->pData = GETPLUGINTEXDEF(pFrom)->Copy();
  4586.   }
  4587.   AddBrushForPatch(p);
  4588.   return p;
  4589. }
  4590.  
  4591.  
  4592. void Patch_Thicken(int nAmount, bool bSeam)
  4593. {
  4594.   int i, j, h, w;
  4595.   brush_t *b;
  4596.   patchMesh_t *pSeam;
  4597.   vec3_t vMin, vMax;
  4598.   CPtrArray brushes;
  4599.  
  4600.   nAmount = -nAmount;
  4601.  
  4602.  
  4603.     if (!QE_SingleBrush())
  4604.   {
  4605.     Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n");
  4606.         return;
  4607.   }
  4608.  
  4609.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4610.     {
  4611.     if (pb->patchBrush)
  4612.     {
  4613.       patchMesh_t *p = pb->pPatch;
  4614.       Patch_MeshNormals(p);
  4615.       patchMesh_t *pNew = Patch_Duplicate(p);
  4616.       for (i = 0; i < p->width; i++)
  4617.       {
  4618.         for (j = 0; j < p->height; j++)
  4619.         {
  4620.               VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz);
  4621.         }
  4622.       }
  4623.  
  4624.       Patch_Rebuild(pNew);
  4625.       pNew->type |= PATCH_THICK;
  4626.       brushes.Add(pNew->pSymbiot);
  4627.  
  4628.       if (bSeam)
  4629.       {
  4630.  
  4631.         // FIXME: this should detect if any edges of the patch are closed and act appropriately
  4632.         // 
  4633.         if (!(p->type & PATCH_CYLINDER))
  4634.         {
  4635.           b = Patch_GenericMesh(3, p->height, 2, false, true);
  4636.           pSeam = b->pPatch;
  4637.           pSeam->type |= PATCH_SEAM;
  4638.           for (i = 0; i < p->height; i++)
  4639.           {
  4640.             VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz);
  4641.             VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz);
  4642.             VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
  4643.             VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
  4644.           }
  4645.  
  4646.  
  4647.           Patch_CalcBounds(pSeam, vMin, vMax);
  4648.           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
  4649.           //--Patch_CapTexture(pSeam);
  4650.           Patch_Naturalize(pSeam);
  4651.           patchInvert(pSeam);
  4652.           brushes.Add(b);
  4653.  
  4654.           w = p->width - 1;
  4655.           b = Patch_GenericMesh(3, p->height, 2, false, true);
  4656.           pSeam = b->pPatch;
  4657.           pSeam->type |= PATCH_SEAM;
  4658.           for (i = 0; i < p->height; i++)
  4659.           {
  4660.             VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz);
  4661.             VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz);
  4662.             VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
  4663.             VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
  4664.           }
  4665.           Patch_CalcBounds(pSeam, vMin, vMax);
  4666.           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
  4667.           //--Patch_CapTexture(pSeam);
  4668.           Patch_Naturalize(pSeam);
  4669.           brushes.Add(b);
  4670.         }
  4671.     
  4672.         //--{
  4673.           // otherwise we will add one per end
  4674.           b = Patch_GenericMesh(p->width, 3, 2, false, true);
  4675.           pSeam = b->pPatch;
  4676.           pSeam->type |= PATCH_SEAM;
  4677.           for (i = 0; i < p->width; i++)
  4678.           {
  4679.             VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz);
  4680.             VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz);
  4681.             VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
  4682.             VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
  4683.           }
  4684.  
  4685.  
  4686.           Patch_CalcBounds(pSeam, vMin, vMax);
  4687.           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
  4688.           //--Patch_CapTexture(pSeam);
  4689.           Patch_Naturalize(pSeam);
  4690.           patchInvert(pSeam);
  4691.           brushes.Add(b);
  4692.  
  4693.           h = p->height - 1;
  4694.           b = Patch_GenericMesh(p->width, 3, 2, false, true);
  4695.           pSeam = b->pPatch;
  4696.           pSeam->type |= PATCH_SEAM;
  4697.           for (i = 0; i < p->width; i++)
  4698.           {
  4699.             VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz);
  4700.             VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz);
  4701.             VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
  4702.             VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
  4703.           }
  4704.           Patch_CalcBounds(pSeam, vMin, vMax);
  4705.           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
  4706.           //--Patch_CapTexture(pSeam);
  4707.           Patch_Naturalize(pSeam);
  4708.           brushes.Add(b);
  4709.  
  4710.           eclass_t *pecNew = Eclass_ForName("func_group", false);
  4711.           if (pecNew)
  4712.           {
  4713.             entity_t *e = Entity_Create(pecNew);
  4714.             SetKeyValue(e, "type", "patchThick");
  4715.           }
  4716.  
  4717.         
  4718.         //--}
  4719.       }
  4720.       patchInvert(pNew);
  4721.     }
  4722.   }
  4723.  
  4724.   for (i = 0; i < brushes.GetSize(); i++)
  4725.   {
  4726.     Select_Brush(reinterpret_cast<brush_t*>(brushes.GetAt(i)));
  4727.   }
  4728.  
  4729.   UpdatePatchInspector();
  4730. }
  4731.  
  4732.  
  4733. /*
  4734. lets get another list together as far as necessities..
  4735.  
  4736. *snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything)
  4737.  
  4738. capping bevels/endcaps
  4739.  
  4740. hot keys
  4741.  
  4742. texture fix for caps
  4743.  
  4744. clear clipboard
  4745.  
  4746. *region fix
  4747.  
  4748. *surface dialog
  4749.  
  4750. */
  4751.  
  4752. void Patch_SetOverlays()
  4753. {
  4754.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4755.     {
  4756.     if (pb->patchBrush)
  4757.     {
  4758.       pb->pPatch->bOverlay = true;
  4759.     }
  4760.   }
  4761. }
  4762.  
  4763.  
  4764.  
  4765. void Patch_ClearOverlays()
  4766. {
  4767.   brush_t *pb;
  4768.     for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4769.     {
  4770.     if (pb->patchBrush)
  4771.     {
  4772.       pb->pPatch->bOverlay = false;
  4773.     }
  4774.   }
  4775.  
  4776.     for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
  4777.     {
  4778.     if (pb->patchBrush)
  4779.     {
  4780.       pb->pPatch->bOverlay = false;
  4781.     }
  4782.   }
  4783.  
  4784. }
  4785.  
  4786. // freezes selected vertices
  4787. void Patch_Freeze()
  4788. {
  4789.   brush_t *pb;
  4790.     for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4791.     {
  4792.     if (pb->patchBrush)
  4793.     {
  4794.       pb->pPatch->bOverlay = false;
  4795.     }
  4796.   }
  4797.  
  4798.     for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
  4799.     {
  4800.     if (pb->patchBrush)
  4801.     {
  4802.       pb->pPatch->bOverlay = false;
  4803.     }
  4804.   }
  4805.  
  4806. }
  4807.  
  4808. void Patch_UnFreeze(bool bAll)
  4809. {
  4810. }
  4811.  
  4812.  
  4813.  
  4814. void Patch_Transpose()
  4815. {
  4816.     int        i, j, w;
  4817.   drawVert_t dv;
  4818.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4819.     {
  4820.     if (pb->patchBrush)
  4821.     {
  4822.       patchMesh_t *p = pb->pPatch;
  4823.  
  4824.         if ( p->width > p->height ) 
  4825.       {
  4826.             for ( i = 0 ; i < p->height ; i++ ) 
  4827.         {
  4828.                 for ( j = i + 1 ; j < p->width ; j++ ) 
  4829.           {
  4830.                     if ( j < p->height ) 
  4831.             {
  4832.                         // swap the value
  4833.                         memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t));
  4834.                         memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
  4835.                         memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t));
  4836.                     } 
  4837.             else 
  4838.             {
  4839.                         // just copy
  4840.                         memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
  4841.                     }
  4842.                 }
  4843.             }
  4844.         } 
  4845.       else 
  4846.       {
  4847.             for ( i = 0 ; i < p->width ; i++ ) 
  4848.         {
  4849.                 for ( j = i + 1 ; j < p->height ; j++ ) 
  4850.           {
  4851.                     if ( j < p->width ) 
  4852.             {
  4853.                         // swap the value
  4854.                         memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t));
  4855.               memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
  4856.                         memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t));
  4857.                     } 
  4858.             else 
  4859.             {
  4860.                         // just copy
  4861.                         memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
  4862.                     }
  4863.                 }
  4864.             }
  4865.         }
  4866.  
  4867.       w = p->width;
  4868.       p->width = p->height;
  4869.       p->height = w;
  4870.       patchInvert(p);
  4871.       Patch_Rebuild(p);
  4872.         }
  4873.     }
  4874. }
  4875.  
  4876.  
  4877.  
  4878. void Select_SnapToGrid()
  4879. {
  4880.     int i,j, k;
  4881.     for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
  4882.     {
  4883.     if (pb->patchBrush)
  4884.     {
  4885.       patchMesh_t *p = pb->pPatch;
  4886. #if 0
  4887.         float        ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
  4888.       memcpy(ctrl, p->ctrl, sizeof(p->ctrl));
  4889.       i = p->width;
  4890.       p->width = p->height;
  4891.       p->height = i;
  4892.       for (i = 0; i < p->width; i++)
  4893.       {
  4894.         int l = p->height-1;
  4895.         for (j = 0; j < p->height; j++)
  4896.         {
  4897.           for (k = 0; k < 5; k++)
  4898.           {
  4899.             p->ctrl[i][l][k] = ctrl[j][i][k];
  4900.           }
  4901.           l--;
  4902.         }
  4903.       }
  4904. #else
  4905.       for (i = 0; i < p->width; i++)
  4906.       {
  4907.         for (j = 0; j < p->height; j++)
  4908.         {
  4909.           for (k = 0; k < 3; k++)
  4910.           {
  4911.             p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
  4912.           }
  4913.         }
  4914.       }
  4915. #endif
  4916.       vec3_t vMin, vMax;
  4917.       Patch_CalcBounds(p, vMin, vMax);
  4918.       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
  4919.     }
  4920.     else
  4921.     {
  4922.       Brush_SnapToGrid(pb);
  4923.     }
  4924.   }
  4925. }
  4926.  
  4927.  
  4928. void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce)
  4929. {
  4930.   if (pb->patchBrush)
  4931.   {
  4932.     patchMesh_t *p = pb->pPatch;
  4933.     if (bForce || strcmpi(p->d_texture->name, pFind) == 0)
  4934.     {
  4935.       p->d_texture = Texture_ForName(pReplace);
  4936.       //strcpy(p->d_texture->name, pReplace);
  4937.     }
  4938.   }
  4939. }
  4940.  
  4941. void Patch_ReplaceQTexture(brush_t *pb, qtexture_t *pOld, qtexture_t *pNew)
  4942. {
  4943.   if (pb->patchBrush)
  4944.   {
  4945.     patchMesh_t *p = pb->pPatch;
  4946.     if (p->d_texture == pOld)
  4947.     {
  4948.       p->d_texture = pNew;
  4949.     }
  4950.   }
  4951. }
  4952.  
  4953. void Patch_Clone(patchMesh_t *p, brush_t *pNewOwner)
  4954. {
  4955. }
  4956.  
  4957. void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz)
  4958. {
  4959.   patchMesh_t* p = MakeNewPatch();
  4960.     p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
  4961.     p->width = 3;
  4962.     p->height = 3;
  4963.   p->type = PATCH_TRIANGLE;
  4964.  
  4965.   // 0 0 goes to x
  4966.   // 0 1 goes to x
  4967.   // 0 2 goes to x
  4968.  
  4969.   // 1 0 goes to mid of x and z
  4970.   // 1 1 goes to mid of x y and z
  4971.   // 1 2 goes to mid of x and y
  4972.  
  4973.   // 2 0 goes to z
  4974.   // 2 1 goes to mid of y and z
  4975.   // 2 2 goes to y
  4976.  
  4977.   vec5_t vMidXZ;
  4978.   vec5_t vMidXY;
  4979.   vec5_t vMidYZ;
  4980.  
  4981.  
  4982.   for (int j = 0; j < 3; j++)
  4983.   {
  4984.     _Vector5Add(vx, vz, vMidXZ);
  4985.     _Vector5Scale(vMidXZ, 0.5, vMidXZ);
  4986.     //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5);
  4987.   }
  4988.  
  4989.   for (j = 0; j < 3; j++)
  4990.   {
  4991.     _Vector5Add(vx, vy, vMidXY);
  4992.     _Vector5Scale(vMidXY, 0.5, vMidXY);
  4993.     //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5);
  4994.   }
  4995.  
  4996.   for (j = 0; j < 3; j++)
  4997.   {
  4998.     _Vector5Add(vy, vz, vMidYZ);
  4999.     _Vector5Scale(vMidYZ, 0.5, vMidYZ);
  5000.     //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5);
  5001.   }
  5002.  
  5003.   _Vector53Copy(vx, p->ctrl[0][0].xyz);
  5004.   _Vector53Copy(vx, p->ctrl[0][1].xyz);
  5005.   _Vector53Copy(vx, p->ctrl[0][2].xyz);
  5006.   p->ctrl[0][0].st[0] = vx[3];
  5007.   p->ctrl[0][0].st[1] = vx[4];
  5008.   p->ctrl[0][1].st[0] = vx[3];
  5009.   p->ctrl[0][1].st[1] = vx[4];
  5010.   p->ctrl[0][2].st[0] = vx[3];
  5011.   p->ctrl[0][2].st[1] = vx[4];
  5012.  
  5013.   _Vector53Copy(vMidXY, p->ctrl[1][0].xyz);
  5014.   _Vector53Copy(vx, p->ctrl[1][1].xyz);
  5015.   _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz);
  5016.   p->ctrl[1][0].st[0] = vMidXY[3];
  5017.   p->ctrl[1][0].st[1] = vMidXY[4];
  5018.   p->ctrl[1][1].st[0] = vx[3];
  5019.   p->ctrl[1][1].st[1] = vx[4];
  5020.   p->ctrl[1][2].st[0] = vMidXZ[3];
  5021.   p->ctrl[1][2].st[1] = vMidXZ[4];
  5022.  
  5023.   _Vector53Copy(vy, p->ctrl[2][0].xyz);
  5024.   _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz);
  5025.   _Vector53Copy(vz, p->ctrl[2][2].xyz);
  5026.   p->ctrl[2][0].st[0] = vy[3];
  5027.   p->ctrl[2][0].st[1] = vy[4];
  5028.   p->ctrl[2][1].st[0] = vMidYZ[3];
  5029.   p->ctrl[2][1].st[1] = vMidYZ[4];
  5030.   p->ctrl[2][2].st[0] = vz[3];
  5031.   p->ctrl[2][2].st[1] = vz[4];
  5032.  
  5033.  
  5034.   //Patch_Naturalize(p);
  5035.  
  5036.   brush_t *b = AddBrushForPatch(p);
  5037.  
  5038. }
  5039.  
  5040.  
  5041. /*
  5042. ==============
  5043. Patch_SetEpair
  5044. sets an epair for the given patch
  5045. ==============
  5046. */
  5047. void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue)
  5048. {
  5049.     if (g_qeglobals.m_bBrushPrimitMode)
  5050.     {
  5051.         SetKeyValue(p->epairs, pKey, pValue);
  5052.     }
  5053. }
  5054.  
  5055. /* 
  5056. =================
  5057. Patch_GetKeyValue
  5058. =================
  5059. */
  5060. const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey)
  5061. {
  5062.     if (g_qeglobals.m_bBrushPrimitMode)
  5063.     {
  5064.     return ValueForKey(p->epairs, pKey);
  5065.     }
  5066.   return "";
  5067. }
  5068.  
  5069.  
  5070. //Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save)
  5071. /*
  5072. Feature addition.
  5073. When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as;
  5074.  
  5075. g:\quake3\baseq3\textures\common
  5076.  
  5077.  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.
  5078.  
  5079.   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.
  5080.  
  5081.   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.
  5082.  
  5083.   1) Easier way of deleting rows, columns
  5084. 2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog)
  5085. 2) Patch matrix transposition
  5086.  
  5087.   1) Actually, bump texture flipping on patches to the top of the list of things to do.
  5088. 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
  5089. 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
  5090.  
  5091.  
  5092. *1) Flipping textures on patches
  5093. *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
  5094. 3) Easier way of deleting rows columns
  5095. *4) Thick Curves
  5096. 5) Patch matrix transposition
  5097. 6) Inverted cylinder capping
  5098. *7) bugs
  5099. *8) curve speed
  5100.  
  5101.   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)
  5102.  
  5103.   Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model
  5104.  
  5105.   Feature Addition: View/Hide Hint Brushes -- This should be a specific case.
  5106. */
  5107.