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