]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - radiant/pmesh.cpp
rebuilt gtk binary dependencies file
[xonotic/netradiant.git] / radiant / pmesh.cpp
1 /*
2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20 */
21
22 //
23 // Preliminary patch stuff
24 //
25 //
26
27 #include "stdafx.h"
28 #include "gtkmisc.h"
29
30 #include "gtkr_list.h"
31
32 // externs
33 extern void MemFile_fprintf(MemStream* pMemFile, const char* pText, ...);
34 extern face_t *Face_Alloc( void );
35 extern void DrawAlternatePoint(vec3_t v, float scale);
36
37 void _Write3DMatrix (FILE *f, int y, int x, int z, float *m);
38 void _Write3DMatrix (MemStream *f, int y, int x, int z, float *m);
39
40 void Patch_InitialiseLODPointers(patchMesh_t *p)
41 {
42         int i;
43         int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT;
44         for (i=0; i<rowcount; i++)
45                 p->rowLOD[i] = NULL;
46         int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH;
47         for (i=0; i<colcount; i++)
48                 p->colLOD[i] = NULL;
49 }
50
51 patchMesh_t* Patch_Alloc()
52 {
53   patchMesh_t *pPatch = (patchMesh_t *)malloc(sizeof(patchMesh_t));
54   pPatch->pShader = NULL;
55   pPatch->pSymbiot = NULL; // Hydra: added missing initialiser.
56         // spog - initialise patch LOD pointers
57   Patch_InitialiseLODPointers(pPatch);
58   pPatch->drawLists = NULL;
59   pPatch->bDirty = true;
60   pPatch->nListID = -1;
61   pPatch->bSelected = false;
62   pPatch->bOverlay = false;
63   pPatch->bDirty = true;
64   pPatch->LODUpdated = false;
65
66   int i;
67   for (i=0; i<(((MAX_PATCH_WIDTH-1)-1)/2); i++)
68     pPatch->rowDirty[i] = false;
69   for (i=0; i<(((MAX_PATCH_HEIGHT-1)-1)/2); i++)
70     pPatch->colDirty[i] = false;
71
72   return pPatch;
73 }
74
75 patchMesh_t* MakeNewPatch()
76 {
77   patchMesh_t *pm = reinterpret_cast<patchMesh_t*>(qmalloc(sizeof(patchMesh_t)));
78
79   // spog - initialise patch LOD pointers
80   Patch_InitialiseLODPointers(pm);
81   pm->drawLists = NULL;
82   pm->bDirty = true;
83
84   return pm;
85 }
86
87 // FIXME: this needs to be dynamic
88 //#define       MAX_PATCH_MESHES        4096
89 //patchMesh_t           patchMeshes[MAX_PATCH_MESHES];
90 //int numPatchMeshes = 0;
91
92 // used for a save spot
93 patchMesh_t patchSave;
94
95 // Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized
96 // brush approach
97 //--int  g_nSelectedPatch = -1;
98
99 // HACK: for tracking which view generated the click
100 // as we dont want to deselect a point on a same point
101 // click if it is from a different view
102 int  g_nPatchClickedView = -1;
103 bool g_bSameView = false;
104
105 //typedef enum XFormType { TRANSLATE, SCALE, ROTATE };
106
107
108 // globals
109 bool g_bPatchShowBounds = true;
110 bool g_bPatchWireFrame = false;
111 bool g_bPatchWeld = true;
112 bool g_bPatchDrillDown = true;
113 //bool g_bPatchInsertMode = false;
114 bool g_bPatchBendMode = false;
115 int  g_nPatchBendState = -1;
116 int  g_nPatchInsertState = -1;
117 int  g_nBendOriginIndex = 0;
118 vec3_t g_vBendOrigin;
119
120 bool g_bPatchAxisOnRow = true;
121 int  g_nPatchAxisIndex = 0;
122 bool g_bPatchLowerEdge = true;
123
124 vec3_t g_vCycleCapNormal;
125 // cycles when we use Patch_CycleCapSelected
126 VIEWTYPE g_nCycleCapIndex = XY;
127
128 // BEND states
129 enum
130 {
131   BEND_SELECT_ROTATION = 0,
132   BEND_SELECT_ORIGIN,
133   BEND_SELECT_EDGE,
134   BEND_BENDIT,
135   BEND_STATE_COUNT
136 };
137
138 const char *g_pBendStateMsg[] =
139 {
140   "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.",
141   "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",
142   "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.",
143   "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",
144   ""
145 };
146
147 // INSERT states
148 enum
149 {
150   INSERT_SELECT_EDGE = 0,
151   INSERT_STATE_COUNT
152 };
153
154 const char* g_pInsertStateMsg[] =
155 {
156   "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair"
157 };
158
159
160 float *g_InversePoints[1024];
161
162 const float fFullBright = 1.0;
163 const float fLowerLimit = .50;
164 const float fDec = .05f;
165 void _SetColor(face_t* f, float fColor[3])
166 {
167   return;
168   fColor[0] = f->d_color[0];
169   fColor[1] = f->d_color[1];
170   fColor[2] = f->d_color[2];
171   qglColor3fv(fColor);
172 }
173
174
175 void _DecColor(float fColor[3])
176 {
177   return;
178   fColor[0] -= fDec;
179   fColor[1] -= fDec ;
180   fColor[2] -= fDec;
181   for (int i = 0; i < 3; i++)
182   {
183     if (fColor[i] <= fLowerLimit)
184     {
185       fColor[0] = fFullBright;
186       fColor[1] = fFullBright;
187       fColor[2] = fFullBright;
188       break;
189     }
190   }
191         qglColor3fv(fColor);
192 }
193
194 vec_t __VectorNormalize (vec3_t in, vec3_t out)
195 {
196         vec_t   length, ilength;
197
198         length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
199         if (length == 0)
200         {
201                 VectorClear (out);
202                 return 0;
203         }
204
205         ilength = 1.0/length;
206         out[0] = in[0]*ilength;
207         out[1] = in[1]*ilength;
208         out[2] = in[2]*ilength;
209
210         return length;
211 }
212
213
214 void Patch_SetType(patchMesh_t *p, int nType)
215 {
216   p->type = (p->type & PATCH_STYLEMASK) | nType;
217 }
218
219 void Patch_SetStyle(patchMesh_t *p, int nStyle)
220 {
221   p->type = (p->type & PATCH_TYPEMASK) | nStyle;
222 }
223
224 /*
225 ==================
226 Patch_MemorySize
227 ==================
228 */
229 int Patch_MemorySize(patchMesh_t *p)
230 {
231   //    return _msize(p);
232   return 0;
233 }
234
235
236 /*
237 ===============
238 InterpolateInteriorPoints
239 ===============
240 */
241 void InterpolateInteriorPoints( patchMesh_t *p )
242 {
243         int             i, j, k;
244         int             next, prev;
245
246         for ( i = 0 ; i < p->width ; i += 2 )
247   {
248
249     next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width;
250     prev = ( i == 0 ) ? p->width - 2 : i - 1;
251
252 #if 0
253                 if ( i == 0 )
254     {
255                         next = ( i + 1 ) % p->width;
256                         prev = p->width - 2;                  // joined wrap case
257                 }
258     else if ( i == p->width - 1 )
259     {
260                         next = 1;
261                         prev = i - 1;
262                 }
263     else
264     {
265                         next = ( i + 1 ) % p->width;
266                         prev = i - 1;
267                 }
268 #endif
269
270                 for ( j = 0 ; j < p->height ; j++ )
271     {
272                         for ( k = 0 ; k < 3 ; k++ )
273       {
274                                 p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5;
275                         }
276                 }
277         }
278 }
279
280 /*
281 =================
282 MakeMeshNormals
283
284 =================
285 */
286 int     neighbors[8][2] = {
287         {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
288 };
289
290 void Patch_MeshNormals(patchMesh_t *in )
291 {
292         int             i, j, k, dist;
293         vec3_t  normal;
294         vec3_t  sum;
295         int             count;
296         vec3_t  base;
297         vec3_t  delta;
298         int             x, y;
299         drawVert_t      *dv;
300         vec3_t          around[8], temp;
301         qboolean        good[8];
302         qboolean        wrapWidth, wrapHeight;
303         float           len;
304
305         wrapWidth = false;
306         for ( i = 0 ; i < in->height ; i++ )
307         {
308
309                 VectorSubtract( in->ctrl[0][i].xyz,
310                                       in->ctrl[in->width-1][i].xyz, delta );
311                 len = VectorLength( delta );
312                 if ( len > 1.0 )
313                 {
314                         break;
315                 }
316         }
317         if ( i == in->height )
318         {
319                 wrapWidth = true;
320         }
321
322         wrapHeight = false;
323         for ( i = 0 ; i < in->width ; i++ )
324         {
325                 VectorSubtract( in->ctrl[i][0].xyz,
326                                       in->ctrl[i][in->height-1].xyz, delta );
327                 len = VectorLength( delta );
328                 if ( len > 1.0 )
329                 {
330                         break;
331                 }
332         }
333         if ( i == in->width)
334         {
335                 wrapHeight = true;
336         }
337
338
339         for ( i = 0 ; i < in->width ; i++ )
340         {
341                 for ( j = 0 ; j < in->height ; j++ )
342                 {
343                         count = 0;
344                         //--dv = reinterpret_cast<drawVert_t*>(in.ctrl[j*in.width+i]);
345                         dv = &in->ctrl[i][j];
346                         VectorCopy( dv->xyz, base );
347                         for ( k = 0 ; k < 8 ; k++ )
348                         {
349                                 VectorClear( around[k] );
350                                 good[k] = false;
351
352                                 for ( dist = 1 ; dist <= 3 ; dist++ )
353                                 {
354                                         x = i + neighbors[k][0] * dist;
355                                         y = j + neighbors[k][1] * dist;
356                                         if ( wrapWidth )
357                                         {
358                                                 if ( x < 0 )
359                                                 {
360                                                         x = in->width - 1 + x;
361                                                 }
362                                                 else if ( x >= in->width )
363                                                 {
364                                                         x = 1 + x - in->width;
365                                                 }
366                                         }
367                                         if ( wrapHeight )
368                                         {
369                                                 if ( y < 0 )
370                                                 {
371                                                         y = in->height - 1 + y;
372                                                 }
373                                                 else if ( y >= in->height )
374                                                 {
375                                                         y = 1 + y - in->height;
376                                                 }
377                                         }
378
379                                         if ( x < 0 || x >= in->width || y < 0 || y >= in->height )
380                                         {
381                                                 break;                                  // edge of patch
382                                         }
383                                         //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp );
384                                         VectorSubtract( in->ctrl[x][y].xyz, base, temp );
385                                         if ( __VectorNormalize( temp, temp ) == 0 )
386                                         {
387                                                 continue;                               // degenerate edge, get more dist
388                                         }
389                                         else
390                                         {
391                                                 good[k] = true;
392                                                 VectorCopy( temp, around[k] );
393                                                 break;                                  // good edge
394                                         }
395                                 }
396                         }
397
398                         VectorClear( sum );
399                         for ( k = 0 ; k < 8 ; k++ )
400                         {
401                                 if ( !good[k] || !good[(k+1)&7] )
402                                 {
403                                         continue;       // didn't get two points
404                                 }
405                                 CrossProduct( around[(k+1)&7], around[k], normal );
406                                 if ( __VectorNormalize( normal, normal ) == 0 )
407                                 {
408                                         continue;
409                                 }
410                                 VectorAdd( normal, sum, sum );
411                                 count++;
412                         }
413                         if ( count == 0 )
414                         {
415         //printf("bad normal\n");
416                                 count = 1;
417         //continue;
418                         }
419                         __VectorNormalize( sum, dv->normal );
420                 }
421         }
422 }
423
424
425
426
427 /*
428 ==================
429 Patch_CalcBounds
430 ==================
431 */
432 void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax)
433 {
434   vMin[0] = vMin[1] = vMin[2] = 99999;
435   vMax[0] = vMax[1] = vMax[2] = -99999;
436
437   p->bDirty = true;
438   for (int w = 0; w < p->width; w++)
439   {
440     for (int h = 0; h < p->height; h++)
441     {
442       for (int j = 0; j < 3; j++)
443       {
444         float f = p->ctrl[w][h].xyz[j];
445         if (f < vMin[j])
446           vMin[j] = f;
447         if (f > vMax[j])
448           vMax[j] = f;
449       }
450     }
451   }
452 }
453
454 /*
455 ==================
456 Brush_RebuildBrush
457 ==================
458 */
459 void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs)
460 {
461   //
462   // Total hack job
463   // Rebuilds a brush
464         int             i, j;
465         face_t  *f, *next;
466         vec3_t  pts[4][2];
467   texdef_t      texdef;
468         // free faces
469
470   for (j = 0; j < 3; j++)
471   {
472     if ((int)vMins[j] == (int)vMaxs[j])
473     {
474       vMins[j] -= 4;
475       vMaxs[j] += 4;
476     }
477   }
478
479
480   for (f=b->brush_faces ; f ; f=next)
481         {
482                 next = f->next;
483     if (f)
484       texdef = f->texdef;
485     Face_Free( f );
486         }
487
488   b->brush_faces = NULL;
489
490   // left the last face so we can use its texdef
491
492         for (i=0 ; i<3 ; i++)
493                 if (vMaxs[i] < vMins[i])
494                         Error ("Brush_RebuildBrush: backwards");
495
496         pts[0][0][0] = vMins[0];
497         pts[0][0][1] = vMins[1];
498
499         pts[1][0][0] = vMins[0];
500         pts[1][0][1] = vMaxs[1];
501
502         pts[2][0][0] = vMaxs[0];
503         pts[2][0][1] = vMaxs[1];
504
505         pts[3][0][0] = vMaxs[0];
506         pts[3][0][1] = vMins[1];
507
508         for (i=0 ; i<4 ; i++)
509         {
510                 pts[i][0][2] = vMins[2];
511                 pts[i][1][0] = pts[i][0][0];
512                 pts[i][1][1] = pts[i][0][1];
513                 pts[i][1][2] = vMaxs[2];
514         }
515
516         for (i=0 ; i<4 ; i++)
517         {
518                 f = Face_Alloc();
519                 f->texdef = texdef;
520                 f->texdef.flags &= ~SURF_KEEP;
521                 f->texdef.contents &= ~CONTENTS_KEEP;
522 //              f->texdef.flags |= SURF_PATCH;
523                 f->next = b->brush_faces;
524                 b->brush_faces = f;
525                 j = (i+1)%4;
526
527                 VectorCopy (pts[j][1], f->planepts[0]);
528                 VectorCopy (pts[i][1], f->planepts[1]);
529                 VectorCopy (pts[i][0], f->planepts[2]);
530         }
531
532         f = Face_Alloc();
533         f->texdef = texdef;
534   f->texdef.flags &= ~SURF_KEEP;
535         f->texdef.contents &= ~CONTENTS_KEEP;
536 //  f->texdef.flags |= SURF_PATCH;
537         f->next = b->brush_faces;
538         b->brush_faces = f;
539
540         VectorCopy (pts[0][1], f->planepts[0]);
541         VectorCopy (pts[1][1], f->planepts[1]);
542         VectorCopy (pts[2][1], f->planepts[2]);
543
544         f = Face_Alloc();
545         f->texdef = texdef;
546   f->texdef.flags &= ~SURF_KEEP;
547         f->texdef.contents &= ~CONTENTS_KEEP;
548 //  f->texdef.flags |= SURF_PATCH;
549         f->next = b->brush_faces;
550         b->brush_faces = f;
551
552         VectorCopy (pts[2][0], f->planepts[0]);
553         VectorCopy (pts[1][0], f->planepts[1]);
554         VectorCopy (pts[0][0], f->planepts[2]);
555
556   Brush_Build(b);
557 }
558
559 void WINAPI Patch_Rebuild(patchMesh_t *p)
560 {
561   vec3_t vMin, vMax;
562   Patch_CalcBounds(p, vMin, vMax);
563   Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
564   p->bDirty = true;
565 }
566
567 /*
568 ==================
569 AddBrushForPatch
570 ==================
571  adds a patch brush and ties it to this patch id
572 */
573 brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld )
574 {
575   // find the farthest points in x,y,z
576   vec3_t vMin, vMax;
577   Patch_CalcBounds(pm, vMin, vMax);
578
579   for (int j = 0; j < 3; j++)
580   {
581     if (vMin[j] == vMax[j])
582     {
583       vMin[j] -= 4;
584       vMax[j] += 4;
585     }
586   }
587
588   brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
589
590   // FIXME: this entire type of linkage needs to be fixed
591   b->patchBrush = true;
592   b->pPatch = pm;
593   pm->pSymbiot = b;
594   pm->bSelected = false;
595   pm->bOverlay = false;
596   pm->bDirty = true;
597   pm->nListID = -1;
598
599   if (bLinkToWorld)
600   {
601     Brush_AddToList (b, &active_brushes);
602           Entity_LinkBrush (world_entity, b);
603     Brush_Build(b);
604   }
605
606   return b;
607 }
608
609 void Patch_SetPointIntensities(int n)
610 {
611 #if 0
612         patchMesh_t     *p = patchMeshes[n];
613   for (int i = 0; i < p->width; i++)
614   {
615     for (int j = 0; j < p->height; j++)
616     {
617
618     }
619   }
620 #endif
621 }
622
623 // very approximate widths and heights
624
625 /*
626 ==================
627 Patch_Width
628 ==================
629 */
630 float Patch_Width(patchMesh_t *p)
631 {
632   float f = 0;
633   for (int i = 0; i < p->width-1; i++)
634   {
635     vec3_t vTemp;
636     VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
637     f += VectorLength(vTemp);
638   }
639   return f;
640 }
641
642 float Patch_WidthDistanceTo(patchMesh_t *p, int j)
643 {
644   float f = 0;
645   for (int i = 0; i < j; i++)
646   {
647     vec3_t vTemp;
648     VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
649     f += VectorLength(vTemp);
650   }
651   return f;
652 }
653
654
655
656 /*
657 ==================
658 Patch_Height
659 ==================
660 */
661 float Patch_Height(patchMesh_t *p)
662 {
663   float f = 0;
664   for (int i = 0; i < p->height-1; i++)
665   {
666     vec3_t vTemp;
667     VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
668     f += VectorLength(vTemp);
669   }
670   return f;
671 }
672
673 float Patch_HeightDistanceTo(patchMesh_t *p, int j)
674 {
675   float f = 0;
676   for (int i = p->height-1; i > j; i--)
677   {
678     vec3_t vTemp;
679     VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i-1].xyz, vTemp); // reverse order for T coords
680     f += VectorLength(vTemp);
681   }
682   return f;
683 }
684
685
686
687 /*
688 ==================
689 Patch_Naturalize
690 ==================
691 texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength
692
693 dist( this control point to first control point ) / dist ( last control pt to first)
694 */
695 void WINAPI Patch_Naturalize(patchMesh_t *p)
696 {
697   int nWidth = (int)(p->d_texture->width * g_pGameDescription->mTextureDefaultScale);
698   int nHeight = (int)(p->d_texture->height * g_pGameDescription->mTextureDefaultScale);
699   float fPWidth = Patch_Width(p);
700   float fPHeight = Patch_Height(p);
701   float xAccum = 0.0f;
702
703   for ( int i = 0; i < p->width ; i++ )
704   {
705         float yAccum = 0.0f;
706         for ( int j = p->height-1; j >= 0 ; j-- )
707         {
708           p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth;
709           p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight;
710            yAccum = Patch_HeightDistanceTo(p,j-1);
711           //p->ctrl[i][j][3] = (fPWidth / nWidth) * (float)i / (p->width - 1);
712           //p->ctrl[i][j][4] = (fPHeight/ nHeight) * (float)j / (p->height - 1);
713         }
714         xAccum = Patch_WidthDistanceTo(p,i+1);
715   }
716   p->bDirty = true;
717 }
718
719 /*
720   if (bIBevel)
721   {
722     VectorCopy(p->ctrl[1][0], p->ctrl[1][1]);
723   }
724
725   if (bIEndcap)
726   {
727     VectorCopy(p->ctrl[3][0], p->ctrl[4][1]);
728     VectorCopy(p->ctrl[2][0], p->ctrl[3][1]);
729     VectorCopy(p->ctrl[2][0], p->ctrl[2][1]);
730     VectorCopy(p->ctrl[2][0], p->ctrl[1][1]);
731     VectorCopy(p->ctrl[1][0], p->ctrl[0][1]);
732     VectorCopy(p->ctrl[1][0], p->ctrl[0][2]);
733     VectorCopy(p->ctrl[1][0], p->ctrl[1][2]);
734     VectorCopy(p->ctrl[2][0], p->ctrl[2][2]);
735     VectorCopy(p->ctrl[3][0], p->ctrl[3][2]);
736     VectorCopy(p->ctrl[3][0], p->ctrl[4][2]);
737   }
738 */
739
740 int Index3By[][2] =
741 {
742   {0,0},
743   {1,0},
744   {2,0},
745   {2,1},
746   {2,2},
747   {1,2},
748   {0,2},
749   {0,1},
750   {0,0},
751   {0,0},
752   {0,0},
753   {0,0},
754   {0,0},
755   {0,0},
756   {0,0}
757 };
758
759 int Index5By[][2] =
760 {
761   {0,0},
762   {1,0},
763   {2,0},
764   {3,0},
765   {4,0},
766   {4,1},
767   {4,2},
768   {4,3},
769   {4,4},
770   {3,4},
771   {2,4},
772   {1,4},
773   {0,4},
774   {0,3},
775   {0,2},
776   {0,1}
777 };
778
779
780
781 int Interior3By[][2] =
782 {
783   {1,1}
784 };
785
786 int Interior5By[][2] =
787 {
788   {1,1},
789   {2,1},
790   {3,1},
791   {1,2},
792   {2,2},
793   {3,2},
794   {1,3},
795   {2,3},
796   {3,3}
797 };
798
799 int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]);
800 int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]);
801
802 extern int Plane_FromPoints(vec3_t p1, vec3_t p2, vec3_t p3, plane_t *plane);
803 // the bFaceCycle only means we are going through a patch cycling loop
804 // then we rely on g_vCycleCapNormal to compute the cap
805
806 void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false)
807 {
808         vec3_t vProjection, vX, vY;
809         qtexture_t *texture = p->pShader->getTexture();
810         plane_t Plane1, Plane2, Plane3;
811         bool bThing=true;
812
813         if (bFaceCycle)
814                 VectorCopy (g_vCycleCapNormal, vProjection);
815
816         else
817         {
818                 VectorClear ( vProjection );
819
820                 // find normal for plane from first 3 corner points
821                 if (!Plane_FromPoints(p->ctrl[0][0].xyz,p->ctrl[0][p->height-1].xyz,p->ctrl[p->width-1][p->height-1].xyz,&Plane1))
822                 {
823                         VectorClear ( Plane3.normal );
824                         bThing = false;
825                 }
826
827                 // find normal for plane from next 3 corner points
828                 if (!Plane_FromPoints(p->ctrl[p->width-1][p->height-1].xyz,p->ctrl[p->width-1][0].xyz,p->ctrl[0][0].xyz,&Plane2))
829                 {
830                         if (bThing)
831                         {
832                                 VectorCopy ( Plane1.normal, Plane3.normal );
833                                 Plane3.dist = Plane1.dist;
834                         }
835                 }
836
837                 else
838                 {
839                         if (bThing)
840                                 // find average plane for all 4 corner points
841                         {
842                                 for (int n = 0; n <= 2; n++)
843                                 {
844                                         Plane3.normal[n] = (Plane1.normal[n] + Plane2.normal[n]) / 2;
845                                 }
846                                 Plane3.dist = (Plane1.dist + Plane2.dist) / 2;
847                         }
848                         else
849                         {
850                                 VectorCopy ( Plane2.normal, Plane3.normal );
851                                 Plane3.dist = Plane2.dist;
852                         }
853                 }
854
855                 // get best axis for projection from average plane
856                 //Sys_Printf("surface normal1: (%f,%f,%f)\n",Plane1.normal[0],Plane1.normal[1],Plane1.normal[0]);
857                 //Sys_Printf("surface normal2: (%f,%f,%f)\n",Plane2.normal[0],Plane2.normal[1],Plane2.normal[0]);
858                 //Sys_Printf("surface normal3: (%f,%f,%f)\n",Plane3.normal[0],Plane3.normal[1],Plane3.normal[0]);
859                 TextureAxisFromPlane(&Plane3, vX, vY);
860         }
861
862         for (int w = 0; w < p->width; w++)
863         {
864                 for (int h = 0; h < p->height; h++)
865                 {
866                         if (vProjection[2] == 1.0f || (vX[0] == 1.0f && vY[1] == -1.0f))
867                         {
868                                 p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale);
869                                 p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[1] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1;
870                         }
871                         else if (vProjection[0] == 1.0f || (vX[1] == 1.0f && vY[2] == -1.0f))
872                         {
873                                 p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[1] / (texture->width * g_pGameDescription->mTextureDefaultScale);
874                                 p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1;
875                         }
876                         else if (vProjection[1] == 1.0f || (vX[0] == 1.0f && vY[2] == -1.0f))
877                         {
878                                 p->ctrl[w][h].st[0] = p->ctrl[w][h].xyz[0] / (texture->width * g_pGameDescription->mTextureDefaultScale);
879                                 p->ctrl[w][h].st[1] = p->ctrl[w][h].xyz[2] / (texture->height * g_pGameDescription->mTextureDefaultScale) * -1;
880                         }
881                         //Sys_Printf("(%i,%i) (%f,%f,%f) (%f,%f) %f\n",w,h,
882                         //      p->ctrl[w][h].xyz[0],p->ctrl[w][h].xyz[1],p->ctrl[w][h].xyz[2],
883                         //      p->ctrl[w][h].st[0],p->ctrl[w][h].st[1],p->ctrl[w][h].normal);
884                 }
885         }
886         // make sure it will rebuild
887         p->bDirty = true;
888 }
889
890 void FillPatch(patchMesh_t *p, vec3_t v)
891 {
892   for (int i = 0; i < p->width; i++)
893   {
894     for (int j = 0; j < p->height; j++)
895     {
896       VectorCopy(v, p->ctrl[i][j].xyz);
897     }
898   }
899 }
900
901 // temporarily moved function to allow use in Cap() and CapSpecial()
902 void patchInvert(patchMesh_t *p)
903 {
904   drawVert_t vertTemp;
905   p->bDirty = true;
906         for ( int i = 0 ; i < p->width ; i++ )
907   {
908     for (int j = 0; j < p->height / 2; j++)
909     {
910       memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
911       memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
912       memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
913                 }
914         }
915 }
916
917 brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst)
918 {
919   brush_t *b;
920   patchMesh_t *p;
921   vec3_t vMin, vMax;
922   int i, j;
923
924   bool bSmall = true;
925   // make a generic patch
926   if (pParent->width <= 9)
927   {
928     b = Patch_GenericMesh(3, 3, 2, false);
929   }
930   else
931   {
932     b = Patch_GenericMesh(5, 5, 2, false);
933     bSmall = false;
934   }
935
936   if (!b)
937   {
938     Sys_Printf("Unable to cap. You may need to ungroup the patch.\n");
939     return NULL;
940   }
941
942   p = b->pPatch;
943   p->type |= PATCH_CAP;
944
945   vMin[0] = vMin[1] = vMin[2] = 9999;
946   vMax[0] = vMax[1] = vMax[2] = -9999;
947
948   // we seam the column edge, FIXME: this might need to be able to seem either edge
949   //
950   int nSize = (bByColumn) ? pParent->width : pParent->height;
951   int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1;
952
953   FillPatch(p, pParent->ctrl[0][nIndex].xyz);
954
955   for (i = 0; i < nSize; i++)
956   {
957     if (bByColumn)
958     {
959       if (bSmall)
960       {
961         VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
962       }
963       else
964       {
965         VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
966       }
967     }
968     else
969     {
970       if (bSmall)
971       {
972         VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
973       }
974       else
975       {
976         VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
977       }
978     }
979
980     for (j = 0; j < 3; j++)
981     {
982       float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j];
983       if (f < vMin[j])
984         vMin[j] = f;
985       if (f > vMax[j])
986         vMax[j] = f;
987     }
988   }
989
990   vec3_t vTemp;
991   for (j = 0; j < 3; j++)
992   {
993     vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5);
994   }
995   int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount;
996   for (j = 0; j < nCount; j++)
997   {
998     if (bSmall)
999     {
1000       VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz);
1001     }
1002     else
1003     {
1004       VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz);
1005     }
1006   }
1007
1008   if (bFirst)
1009           patchInvert(p);
1010   /*
1011   {
1012     drawVert_t vertTemp;
1013     for (i = 0; i < p->width; i++)
1014     {
1015       for (j = 0; j < p->height / 2; j++)
1016       {
1017         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
1018         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
1019         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
1020       }
1021     }
1022   }
1023   */
1024
1025   Patch_Rebuild(p);
1026   Patch_CapTexture(p);
1027   return p->pSymbiot;
1028 }
1029
1030 brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst)
1031 {
1032
1033   brush_t *b;
1034   patchMesh_t *p;
1035   vec3_t vMin, vMax, vTemp;
1036   int i, j;
1037
1038   if (nType == IENDCAP)
1039     b = Patch_GenericMesh(5, 3, 2, false);
1040   else
1041     b = Patch_GenericMesh(3, 3, 2, false);
1042
1043   if (!b)
1044   {
1045     Sys_Printf("Unable to cap. Make sure you ungroup before re-capping.");
1046     return NULL;
1047   }
1048
1049   p = b->pPatch;
1050   p->type |= PATCH_CAP;
1051
1052   vMin[0] = vMin[1] = vMin[2] = 9999;
1053   vMax[0] = vMax[1] = vMax[2] = -9999;
1054
1055   //  int nSize = pParent->width;
1056   int nIndex = (bFirst) ? 0 : pParent->height-1;
1057
1058   // parent bounds are used for some things
1059   Patch_CalcBounds(pParent, vMin, vMax);
1060
1061   for (j = 0; j < 3; j++)
1062   {
1063     vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5);
1064   }
1065
1066   if (nType == IBEVEL)
1067   {
1068     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
1069     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
1070     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
1071     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz);
1072     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
1073     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
1074     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
1075     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz);
1076     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz);
1077   }
1078   else if (nType == BEVEL)
1079   {
1080     vec3_t p1, p2, p3, p4; //, temp, dir;
1081
1082     VectorCopy(pParent->ctrl[0][nIndex].xyz, p3);
1083     VectorCopy(pParent->ctrl[1][nIndex].xyz, p1);
1084     VectorCopy(pParent->ctrl[2][nIndex].xyz, p2);
1085
1086         //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]);
1087         //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]);
1088         //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]);
1089
1090         VectorSubtract(p2, p1, p4);
1091         VectorAdd(p3, p4, p4);
1092         // spog - use opposite-point-on-parallelogram to find p4
1093         /*
1094     VectorSubtract(p3, p2, dir);
1095     VectorNormalize(dir);
1096     VectorSubtract(p1, p2, temp);
1097     vec_t dist = _DotProduct(temp, dir);
1098     VectorScale(dir, dist, temp);
1099     VectorAdd(p2, temp, temp);
1100     VectorSubtract(temp, p1, temp);
1101     VectorScale(temp, 2, temp);
1102     VectorAdd(p1, temp, p4);
1103         */
1104
1105         //Sys_Printf("CapSpecial() p1: %f %f %f\n",p1[0],p1[1],p1[2]);
1106         //Sys_Printf("CapSpecial() p2: %f %f %f\n",p2[0],p2[1],p2[2]);
1107         //Sys_Printf("CapSpecial() p3: %f %f %f\n",p3[0],p3[1],p3[2]);
1108         //Sys_Printf("CapSpecial() p4: %f %f %f\n",p4[0],p4[1],p4[2]);
1109
1110     VectorCopy(p4, p->ctrl[0][0].xyz);
1111     VectorCopy(p4, p->ctrl[1][0].xyz);
1112     VectorCopy(p4, p->ctrl[0][1].xyz);
1113     VectorCopy(p4, p->ctrl[1][1].xyz);
1114     VectorCopy(p4, p->ctrl[0][2].xyz);
1115     VectorCopy(p4, p->ctrl[1][2].xyz);
1116     VectorCopy(p2, p->ctrl[2][0].xyz);
1117     VectorCopy(p1, p->ctrl[2][1].xyz);
1118     VectorCopy(p3, p->ctrl[2][2].xyz);
1119
1120   }
1121   else if (nType == ENDCAP)
1122   {
1123     VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp);
1124     VectorScale(vTemp, 0.5, vTemp);
1125     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
1126                                                    VectorCopy(vTemp, p->ctrl[1][0].xyz);
1127     VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz);
1128
1129     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
1130     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz);
1131     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
1132     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz);
1133
1134     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
1135     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz);
1136   }
1137   else
1138   {
1139     VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[0][0].xyz);
1140     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][0].xyz);
1141     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz);
1142     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][0].xyz);
1143     VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[4][0].xyz);
1144
1145     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][1].xyz);
1146     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][1].xyz);
1147     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz);
1148     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][1].xyz);
1149     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][1].xyz);
1150
1151     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[0][2].xyz);
1152     VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[1][2].xyz);
1153     VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
1154     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[3][2].xyz);
1155     VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[4][2].xyz);
1156   }
1157
1158
1159   if (!bFirst)
1160   {
1161     drawVert_t vertTemp;
1162     for (i = 0; i < p->width; i++)
1163     {
1164       for (j = 0; j < p->height / 2; j++)
1165       {
1166         memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
1167         memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
1168         memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
1169       }
1170     }
1171   }
1172
1173   //--Patch_CalcBounds(p, vMin, vMax);
1174   //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1175   Patch_Rebuild(p);
1176   Patch_CapTexture(p);
1177   return p->pSymbiot;
1178 }
1179
1180 void Patch_CapCurrent()
1181 {
1182   patchMesh_t *pParent = NULL;
1183   brush_t *b[4];
1184   brush_t *pCap = NULL;
1185   b[0] = b[1] = b[2] = b[3] = NULL;
1186   int nIndex = 0;
1187   bool b_GroupResult = TRUE;
1188
1189   if (!QE_SingleBrush(true))
1190   {
1191     Sys_Printf("Patch_CapCurrent: you must have a single patch selected\n");
1192     return;
1193   }
1194
1195
1196   for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next)
1197   {
1198     if (pb->patchBrush)
1199     {
1200       pParent = pb->pPatch;
1201       // decide which if any ends we are going to cap
1202       // if any of these compares hit, it is a closed patch and as such
1203       // the generic capping will work.. if we do not find a closed edge
1204       // then we need to ask which kind of cap to add
1205       if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz))
1206       {
1207         pCap = Cap(pParent, true, false);
1208         if (pCap != NULL)
1209         {
1210           b[nIndex++] = pCap;
1211         }
1212       }
1213       if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
1214       {
1215         pCap = Cap(pParent, true, true);
1216         if (pCap != NULL)
1217         {
1218           b[nIndex++] = pCap;
1219         }
1220       }
1221       if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz))
1222       {
1223         pCap = Cap(pParent, false, false);
1224         if (pCap != NULL)
1225         {
1226           b[nIndex++] = pCap;
1227         }
1228       }
1229       if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
1230       {
1231         pCap = Cap(pParent, false, true);
1232         if (pCap != NULL)
1233         {
1234           b[nIndex++] = pCap;
1235         }
1236       }
1237     }
1238   }
1239
1240   if (pParent)
1241   {
1242     // if we did not cap anything with the above tests
1243     if (nIndex == 0)
1244     {
1245       int type;
1246
1247       if (DoCapDlg (&type, &b_GroupResult) == IDOK)
1248       {
1249         b[nIndex++] = CapSpecial(pParent, type, false);
1250         b[nIndex++] = CapSpecial(pParent, type, true);
1251       }
1252     }
1253
1254     if (nIndex > 0)
1255     {
1256       while (nIndex > 0)
1257       {
1258         nIndex--;
1259         if (b[nIndex])
1260         {
1261           Select_Brush(b[nIndex]);
1262         }
1263       }
1264       // Gef: Added toggle for capped patch func_group
1265       if(b_GroupResult) {
1266         entity_t *e = Entity_Alloc();
1267         SetKeyValue(e, "classname", "func_group");
1268         SetKeyValue(e, "type", "patchCapped");
1269         Select_GroupEntity(e);
1270         Entity_AddToList(e, &entities);
1271       }
1272     }
1273   }
1274 }
1275
1276 /*
1277 ===============
1278 BrushToPatchMesh
1279 ===============
1280 */
1281 void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight)
1282 {
1283         brush_t         *b;
1284         patchMesh_t     *p;
1285         int                     i,j;
1286
1287         if (!QE_SingleBrush())
1288                 return;
1289
1290         b = selected_brushes.next;
1291
1292         p = MakeNewPatch();
1293
1294         p->d_texture = b->brush_faces->d_texture;
1295         p->pShader = b->brush_faces->pShader;
1296
1297   p->height = nHeight;
1298
1299   p->type = PATCH_CYLINDER;
1300   if (bBevel & !bSquare)
1301   {
1302     p->type = PATCH_BEVEL;
1303     p->width = 3;
1304     int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1));
1305     int nStart = (int)(b->mins[2]);
1306     for (i = 0; i < p->height; i++)
1307     {
1308             p->ctrl[0][i].xyz[0] =  b->mins[0];
1309             p->ctrl[0][i].xyz[1] =  b->mins[1];
1310       p->ctrl[0][i].xyz[2] = nStart;
1311
1312             p->ctrl[1][i].xyz[0] =  b->maxs[0];
1313             p->ctrl[1][i].xyz[1] =  b->mins[1];
1314       p->ctrl[1][i].xyz[2] = nStart;
1315
1316             p->ctrl[2][i].xyz[0] =  b->maxs[0];
1317             p->ctrl[2][i].xyz[1] =  b->maxs[1];
1318       p->ctrl[2][i].xyz[2] = nStart;
1319       nStart += nStep;
1320     }
1321   }
1322   else if (bEndcap & !bSquare)
1323   {
1324     p->type = PATCH_ENDCAP;
1325     p->width = 5;
1326     int nStep = (int)((b->maxs[2] - b->mins[2]) / (p->height-1));
1327     int nStart = (int)(b->mins[2]);
1328     for (i = 0; i < p->height; i++)
1329     {
1330       p->ctrl[0][i].xyz[0] =  b->mins[0];
1331       p->ctrl[0][i].xyz[1] =  b->mins[1];
1332       p->ctrl[0][i].xyz[2] = nStart;
1333
1334       p->ctrl[1][i].xyz[0] =  b->mins[0];
1335       p->ctrl[1][i].xyz[1] =  b->maxs[1];
1336       p->ctrl[1][i].xyz[2] = nStart;
1337
1338       p->ctrl[2][i].xyz[0] =  b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5);
1339       p->ctrl[2][i].xyz[1] =  b->maxs[1];
1340       p->ctrl[2][i].xyz[2] = nStart;
1341
1342       p->ctrl[3][i].xyz[0] =  b->maxs[0];
1343       p->ctrl[3][i].xyz[1] =  b->maxs[1];
1344       p->ctrl[3][i].xyz[2] = nStart;
1345
1346       p->ctrl[4][i].xyz[0] =  b->maxs[0];
1347       p->ctrl[4][i].xyz[1] =  b->mins[1];
1348       p->ctrl[4][i].xyz[2] = nStart;
1349       nStart += nStep;
1350     }
1351   }
1352   else
1353   {
1354     p->width = 9;
1355     p->ctrl[1][0].xyz[0] =  b->mins[0];
1356     p->ctrl[1][0].xyz[1] =  b->mins[1];
1357
1358     p->ctrl[3][0].xyz[0] =  b->maxs[0];
1359     p->ctrl[3][0].xyz[1] =  b->mins[1];
1360
1361     p->ctrl[5][0].xyz[0] =  b->maxs[0];
1362     p->ctrl[5][0].xyz[1] =  b->maxs[1];
1363
1364     p->ctrl[7][0].xyz[0] =  b->mins[0];
1365     p->ctrl[7][0].xyz[1] =  b->maxs[1];
1366
1367     for ( i = 1 ; i < p->width - 1 ; i += 2 )
1368     {
1369
1370       p->ctrl[i][0].xyz[2] =  b->mins[2];
1371
1372                   VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz );
1373
1374                   p->ctrl[i][2].xyz[2] =  b->maxs[2];
1375
1376                   p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5;
1377                   p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5;
1378                   p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5;
1379           }
1380           InterpolateInteriorPoints( p );
1381
1382     if (bSquare)
1383     {
1384       if (bBevel || bEndcap)
1385       {
1386         if (bBevel)
1387         {
1388           for (i = 0; i < p->height; i++)
1389           {
1390             VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
1391             VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
1392           }
1393         }
1394         else
1395         {
1396           for (i = 0; i < p->height; i++)
1397           {
1398             VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz);
1399             VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
1400             VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
1401             VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz);
1402           }
1403         }
1404       }
1405       else
1406       {
1407         for (i = 0; i < p->width-1; i ++)
1408         {
1409           for (j = 0; j < p->height; j++)
1410           {
1411             VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz);
1412           }
1413         }
1414         for (j = 0; j < p->height; j++)
1415         {
1416           VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz);
1417         }
1418       }
1419     }
1420   }
1421
1422
1423   Patch_Naturalize(p);
1424
1425   if (bCone)
1426   {
1427     p->type = PATCH_CONE;
1428     float xc = (b->maxs[0] + b->mins[0]) * 0.5;
1429     float yc = (b->maxs[1] + b->mins[1]) * 0.5;
1430
1431     for ( i = 0 ; i < p->width ; i ++)
1432     {
1433       p->ctrl[i][2].xyz[0] = xc;
1434       p->ctrl[i][2].xyz[1] = yc;
1435     }
1436   }
1437
1438   b = AddBrushForPatch(p);
1439
1440   Select_Delete();
1441   Select_Brush(b);
1442
1443 }
1444
1445 /*
1446 ==================
1447 Patch_GenericMesh
1448 ==================
1449 */
1450 brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride)
1451 {
1452   int i,j;
1453
1454   if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15)
1455   {
1456     Sys_Printf("Invalid patch width or height.\n");
1457     return NULL;
1458   }
1459
1460         if (! bOverride && !QE_SingleBrush())
1461   {
1462     Sys_Printf("Error: you must have a single brush selected\n");
1463                 return NULL;
1464   }
1465
1466   patchMesh_t* p = MakeNewPatch();
1467   p->pShader = g_qeglobals.d_texturewin.pShader;
1468   p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture();
1469
1470         p->width = nWidth;
1471         p->height = nHeight;
1472   p->type = PATCH_GENERIC;
1473
1474   int nFirst = 0;
1475   int nSecond = 1;
1476   if (nOrientation == 0)
1477   {
1478     nFirst = 1;
1479     nSecond = 2;
1480   }
1481   else if (nOrientation == 1)
1482   {
1483     nSecond = 2;
1484   }
1485
1486         brush_t *b = selected_brushes.next;
1487         // set the workzone to this brush, use it later to create the patch points
1488         UpdateWorkzone_ForBrush( b );
1489
1490   int xStep = (int)(b->mins[nFirst]);
1491   float xAdj = fabs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1));
1492   float yAdj = fabs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1));
1493
1494   for (i = 0; i < nWidth; i++)
1495   {
1496     int yStep = (int)(b->mins[nSecond]);
1497     for (j = 0; j < nHeight; j++)
1498     {
1499       p->ctrl[i][j].xyz[nFirst] = xStep;
1500       p->ctrl[i][j].xyz[nSecond] = yStep;
1501       // create patch based on workzone
1502       p->ctrl[i][j].xyz[nOrientation] = g_qeglobals.d_work_max[nOrientation];
1503       yStep += (int)yAdj;
1504     }
1505     xStep += (int)xAdj;
1506   }
1507
1508   Patch_Naturalize(p);
1509
1510   b = AddBrushForPatch(p);
1511   if (bDeleteSource)
1512   {
1513     Select_Delete();
1514     Select_Brush(b);
1515   }
1516
1517   return b;
1518   //g_qeglobals.d_select_mode = sel_curvepoint;
1519 }
1520
1521 /*
1522 ==================
1523 PointInMoveList
1524 ==================
1525 */
1526 int PointInMoveList(float *pf)
1527 {
1528   for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
1529   {
1530     if (pf == &g_qeglobals.d_move_points[i][0])
1531       return i;
1532   }
1533   return -1;
1534 }
1535
1536 /*
1537 ==================
1538 PointValueInMoveList
1539 ==================
1540 */
1541 int PointValueInMoveList(vec3_t v)
1542 {
1543   for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
1544   {
1545     if (VectorCompare(v, g_qeglobals.d_move_points[i]))
1546       return i;
1547   }
1548   return -1;
1549 }
1550
1551
1552 /*
1553 ==================
1554 RemovePointFromMoveList
1555 ==================
1556 */
1557 void RemovePointFromMoveList(vec3_t v)
1558 {
1559   int n;
1560   while ( (n = PointValueInMoveList(v)) >= 0)
1561   {
1562     for (int i = n; i < g_qeglobals.d_num_move_points-1; i++)
1563     {
1564       g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1];
1565     }
1566     g_qeglobals.d_num_move_points--;
1567   }
1568 }
1569
1570 /*
1571 ==================
1572 ColumnSelected
1573 ==================
1574 */
1575 bool ColumnSelected(patchMesh_t* p, int nCol)
1576 {
1577   for (int i = 0; i < p->height; i++)
1578   {
1579     if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1)
1580       return false;
1581   }
1582   return true;
1583 }
1584
1585 /*
1586 ==================
1587 AddPoint
1588 ==================
1589 */
1590 void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true)
1591 {
1592   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
1593   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
1594   g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v;
1595   if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill)
1596   {
1597           for ( int i = 0 ; i < p->width ; i++ )
1598     {
1599                   for ( int j = 0 ; j < p->height ; j++ )
1600       {
1601         if (g_bPatchWeld)
1602         {
1603           if ( VectorCompare(v, p->ctrl[i][j].xyz)
1604             && PointInMoveList(p->ctrl[i][j].xyz) == -1)
1605           {
1606             g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
1607             continue;
1608           }
1609         }
1610         if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA)
1611         {
1612           if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON)
1613              &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON))
1614           {
1615             if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
1616             {
1617               g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
1618               continue;
1619             }
1620           }
1621         }
1622       }
1623     }
1624   }
1625 }
1626
1627 /*
1628 ==================
1629 SelectRow
1630 ==================
1631 */
1632 void SelectRow(patchMesh_t* p, int nRow, bool bMulti)
1633 {
1634   if (!bMulti)
1635     g_qeglobals.d_num_move_points = 0;
1636   for (int i = 0; i < p->width; i++)
1637   {
1638     AddPoint(p, p->ctrl[i][nRow].xyz, false);
1639   }
1640   //Sys_Printf("Selected Row %d\n", nRow);
1641 }
1642
1643 /*
1644 ==================
1645 SelectColumn
1646 ==================
1647 */
1648 void SelectColumn(patchMesh_t* p, int nCol, bool bMulti)
1649 {
1650   if (!bMulti)
1651     g_qeglobals.d_num_move_points = 0;
1652   for (int i = 0; i < p->height; i++)
1653   {
1654     AddPoint(p, p->ctrl[nCol][i].xyz, false);
1655   }
1656   //Sys_Printf("Selected Col %d\n", nCol);
1657 }
1658
1659
1660 /*
1661 ==================
1662 AddPatchMovePoint
1663 ==================
1664 */
1665 void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull)
1666 {
1667   if (!g_bSameView && !bMulti && !bFull)
1668   {
1669     g_bSameView = true;
1670     //return; // was causing odd behaviour on patch vertex selection
1671   }
1672
1673         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
1674         {
1675     if (pb->patchBrush)
1676     {
1677             patchMesh_t* p = pb->pPatch;
1678             for ( int i = 0 ; i < p->width ; i++ )
1679       {
1680                     for ( int j = 0 ; j < p->height ; j++ )
1681         {
1682           if (VectorCompare(v, p->ctrl[i][j].xyz))
1683           {
1684             if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
1685             {
1686               if (bFull)        // if we want the full row/col this is on
1687               {
1688                 SelectColumn(p, i, bMulti);
1689               }
1690               else
1691               {
1692                 if (!bMulti)
1693                   g_qeglobals.d_num_move_points = 0;
1694                 AddPoint(p, p->ctrl[i][j].xyz);
1695                 //Sys_Printf("Selected col:row %d:%d\n", i, j);
1696               }
1697               //--if (!bMulti)
1698               return;
1699             }
1700             else
1701             {
1702               if (bFull)
1703               {
1704                 if (ColumnSelected(p, i))
1705                 {
1706                   SelectRow(p, j, bMulti);
1707                 }
1708                 else
1709                 {
1710                   SelectColumn(p, i, bMulti);
1711                 }
1712                 return;
1713               }
1714                           //if (!bMulti)
1715                           //{
1716               //    g_qeglobals.d_num_move_points = 0;
1717               //    AddPoint(p, p->ctrl[i][j].xyz);
1718                           //}
1719               if (bMulti)// if (g_bSameView) // this is not having desired effect
1720               {
1721                 RemovePointFromMoveList(v);
1722                 return;
1723               }
1724             }
1725           }
1726                     }
1727             }
1728     }
1729   }
1730 }
1731
1732 /*
1733 ==================
1734 Patch_UpdateSelected
1735 ==================
1736 */
1737 void Patch_UpdateSelected(vec3_t vMove)
1738 {
1739         int i;//, j;
1740         for (i=0 ; i < g_qeglobals.d_num_move_points ; i++)
1741         {
1742                 VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]);
1743                 if (g_qeglobals.d_num_move_points == 1)
1744                 {
1745                 }
1746         }
1747
1748         //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch];
1749         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
1750         {
1751                 if (pb->patchBrush)
1752                 {
1753                         patchMesh_t* p = pb->pPatch;
1754
1755 #if 0 //moving to SelectCurvePointByRay
1756                         g_qeglobals.d_numpoints = 0;
1757                         for (i = 0 ; i < p->width ; i++ )
1758                         {
1759                                 for ( j = 0 ; j < p->height ; j++ )
1760                                 {
1761                                         VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
1762                                         if (g_qeglobals.d_numpoints < MAX_POINTS-1)
1763                                         {
1764                                                 g_qeglobals.d_numpoints++;
1765                                         }
1766                                 }
1767                         }
1768 #endif
1769                         vec3_t vMin, vMax;
1770                         Patch_CalcBounds(p, vMin, vMax);
1771                         Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1772                 }
1773         }
1774   //Brush_Free(p->pSymbiot);
1775   //Select_Brush(AddBrushForPatch(g_nSelectedPatch));
1776 }
1777
1778
1779
1780 /*
1781 ===============
1782 SampleSinglePatch
1783 ===============
1784 */
1785 void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) {
1786         float   vCtrl[3][5];
1787         int             vPoint;
1788         int             axis;
1789
1790         // find the control points for the v coordinate
1791         for (vPoint = 0 ; vPoint < 3 ; vPoint++)
1792         {
1793                 for (axis = 0 ; axis < 5 ; axis++)
1794                 {
1795                         float   a, b, c;
1796                         float   qA, qB, qC;
1797
1798                         a = ctrl[0][vPoint][axis];
1799                         b = ctrl[1][vPoint][axis];
1800                         c = ctrl[2][vPoint][axis];
1801                         qA = a - 2 * b + c;
1802                         qB = 2 * b - 2 * a;
1803                         qC = a;
1804
1805                         vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
1806                 }
1807         }
1808
1809         // interpolate the v value
1810         for (axis = 0 ; axis < 5 ; axis++)
1811         {
1812                 float   a, b, c;
1813                 float   qA, qB, qC;
1814
1815                 a = vCtrl[0][axis];
1816                 b = vCtrl[1][axis];
1817                 c = vCtrl[2][axis];
1818                 qA = a - 2 * b + c;
1819                 qB = 2 * b - 2 * a;
1820                 qC = a;
1821
1822                 out[axis] = qA * v * v + qB * v + qC;
1823         }
1824 }
1825
1826 //spog - Curve LOD stuff starts
1827
1828 float ShadeForNormal(vec3_t normal)
1829 {
1830   float f;
1831
1832         vec3_t L;
1833         L[0] = 1.0f;
1834         L[1] = 1.0f;
1835         L[2] = 1.0f;
1836
1837
1838         // quick diffuse shading
1839   f = DotProduct(L, normal);
1840
1841   // range 0.5 to 1.0
1842         f = (f+1)/4.0f;
1843   //if (f < 0.0f) f = 0.0f;
1844
1845         f += 0.5f;
1846
1847   return f;
1848 }
1849
1850 void ShadeVertex (drawVert_t &p)
1851 {
1852         p.lightmap[0] = ShadeForNormal(p.normal);
1853 }
1854
1855
1856 void Patch_DrawNormals(patchMesh_t *patch)
1857 {
1858         int row, col;
1859         vec3_t vNormal;
1860
1861         qglBegin (GL_LINES);
1862         for (col=0; col<patch->width; col++)
1863         {
1864                 for (row=0; row<patch->height; row++)
1865                 {
1866                         VectorAdd(patch->ctrl[col][row].xyz, patch->ctrl[col][row].normal, vNormal);
1867                         qglVertex3fv (patch->ctrl[col][row].xyz);
1868                         qglVertex3fv (vNormal);
1869                 }
1870         }
1871         qglEnd ();
1872 }
1873
1874
1875 // take an array of three drawVerts, and the addresses of three more drawVerts
1876 // interpolate new XYZST values from the three drawVerts, these are:
1877 // the left sub-control-point, the right sub-control-point and the midpoint of the curve respectively
1878 // store these values in the drawVerts passed to the function
1879 void Patch_CurveSplit(drawVert_t *vCurve[3], drawVert_t &pLeft, drawVert_t &pRight, drawVert_t &pMid, float u)
1880 {
1881         int i;
1882         //float u = 0.5f;
1883 //      float a, b;
1884         drawVert_t v1, v2, v3;
1885 //      vec3_t v4;
1886
1887         for (i=0; i<3; i++)
1888         {
1889                  // xyz
1890                 v1.xyz[i] = vCurve[1]->xyz[i] - vCurve[0]->xyz[i];
1891                 v2.xyz[i] = vCurve[2]->xyz[i] - vCurve[1]->xyz[i];
1892                 v1.xyz[i] *= u;
1893                 v2.xyz[i] *= u;
1894                 pLeft.xyz[i] = vCurve[0]->xyz[i] + v1.xyz[i];
1895                 pRight.xyz[i] = vCurve[1]->xyz[i] + v2.xyz[i];
1896
1897                 v3.xyz[i] = pRight.xyz[i] - pLeft.xyz[i];
1898                 v3.xyz[i] *= u;
1899                 pMid.xyz[i] = pLeft.xyz[i] + v3.xyz[i];
1900
1901                 // normal (weighted average) // no, that's b0rked
1902                 //a = 1 / u; // total
1903                 //b = u * a; // component 2
1904                 //a = u - b; // component 1
1905                 //pMid.normal[i] = u * ((vCurve[0]->normal[i] * b) + (vCurve[2]->normal[i] * a));
1906
1907                 if (i==2) continue;
1908
1909                 // st
1910                 v1.st[i] = vCurve[1]->st[i] - vCurve[0]->st[i];
1911                 v2.st[i] = vCurve[2]->st[i] - vCurve[1]->st[i];
1912                 v1.st[i] *= u;
1913                 v2.st[i] *= u;
1914                 pLeft.st[i] = vCurve[0]->st[i] + v1.st[i];
1915                 pRight.st[i] = vCurve[1]->st[i] + v2.st[i];
1916
1917                 v3.st[i] = pRight.st[i] - pLeft.st[i];
1918                 v3.st[i] *= u;
1919                 pMid.st[i] = pLeft.st[i] + v3.st[i];
1920         }
1921 }
1922
1923 // take an array of three points, return an index representing the curvature of those three points
1924 // return zero if the curve is a straight line, unless the midpoint is not between the endpoints
1925 float Patch_CurveIndex(vec3_t vCurve[])
1926 {
1927         vec3_t vTemp, v1, v2, v3, vClear;
1928 //      int i;
1929         float width, angle;
1930         float index, dot;
1931
1932         VectorClear(vClear);
1933
1934         VectorSubtract(vCurve[2], vCurve[0], vTemp);
1935         VectorSubtract(vCurve[1], vCurve[0], v1);
1936         VectorSubtract(vCurve[2], vCurve[1], v2);
1937
1938         if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return 0 if 1->2 == 0 or 1->2 == 1->3
1939                 return 0.0f;
1940
1941         VectorNormalize(v1, v1);
1942         VectorNormalize(v2, v2);
1943         if (VectorCompare(v1, v2))
1944                 return 0.0f;
1945
1946         VectorCopy(vTemp, v3);
1947         width = VectorNormalize(v3, v3);
1948
1949         if (VectorCompare(v1, v3) && VectorCompare(v2, v3))
1950                 return 0.0f;
1951
1952         dot = DotProduct(v1, v2);
1953
1954         angle = acos(dot) / Q_PI;
1955
1956         index = width * angle;
1957
1958         return index;
1959 }
1960
1961
1962 // create a new tree root, give it the coordinate values of the drawVert
1963 // return a pointer to the new tree root
1964 BTNode_t *BTree_Create(drawVert_t info)
1965 {
1966         BTNode_t *BTree = new BTNode_t;
1967         BTree->left = BTree->right = NULL;
1968         VectorCopy(info.xyz, BTree->info.xyz);
1969         VectorCopy(info.xyz, BTree->vMid.xyz);
1970         for (int i=0; i<2; i++)
1971         {
1972                 BTree->info.st[i] = info.st[i];
1973                 BTree->vMid.st[i] = info.st[i];
1974         }
1975         return BTree;
1976 }
1977
1978 // take ownership of the subtree
1979 // delete the entire subtree
1980 // return a NULL pointer
1981 BTNode_t *BTree_Delete(BTNode_t *pBT)
1982 {
1983         if (pBT != NULL)
1984         {
1985                 BTree_Delete(pBT->left);
1986                 BTree_Delete(pBT->right);
1987                 delete pBT;
1988         }
1989         return NULL;
1990 }
1991
1992 // NOT currently used
1993 BTNode_t *BTree_Clear(BTNode_t *pBT, bool bFirst = true)
1994 {
1995         if (pBT != NULL)
1996         {
1997                 BTree_Clear(pBT->left, false);
1998                 BTree_Clear(pBT->right, false);
1999                 if (!bFirst) delete pBT;
2000         }
2001         return pBT;
2002 }
2003
2004 // take a pointer to the last item added to the list (this can also be a NULL pointer)
2005 // take a pointer to the root of a subtree, and the patch points to the left and right of it
2006 // add a new item to the subtree list, and add the subtree and its adjacent points to the new item
2007 // return a pointer to the last item added to the subtree list
2008 BTreeList_t *BTree_AddToList(BTreeList_t *pBTList, BTNode_t *pBT, drawVert_t &pLeft, drawVert_t &pRight)
2009 {
2010         BTreeList_t *newBTList = new BTreeList_t;
2011         newBTList->next = pBTList;
2012         newBTList->pBT = pBT;
2013         VectorCopy(pLeft.xyz, newBTList->vLeft.xyz);
2014         VectorCopy(pRight.xyz, newBTList->vRight.xyz);
2015         VectorCopy(pLeft.normal, newBTList->vLeft.normal);
2016         VectorCopy(pRight.normal, newBTList->vRight.normal);
2017         for (int i=0; i<2; i++)
2018         {
2019                 newBTList->vLeft.st[i] = pLeft.st[i];
2020                 newBTList->vRight.st[i] = pRight.st[i];
2021         }
2022         return newBTList;
2023 }
2024
2025 // NOT currently used, subtrees are now stored on the patch
2026 // take ownership of the subtree list
2027 // delete the entire list and the subtrees it points to
2028 // return a NULL pointer
2029 BTreeList_t *BTree_DeleteList(BTreeList_t *pBTList)
2030 {
2031         if (pBTList != NULL)
2032         {
2033                 BTree_DeleteList(pBTList->next);
2034                 pBTList->pBT = BTree_Delete(pBTList->pBT);
2035                 delete pBTList;
2036         }
2037         return NULL;
2038 }
2039
2040 // take ownership of the subtree list
2041 // delete the entire subtree list, but not the subtrees themselves
2042 // return a NULL pointer
2043 BTreeList_t *BTree_DeletePointerList(BTreeList_t *pBTList)
2044 {
2045         if (pBTList != NULL)
2046         {
2047                 BTree_DeletePointerList(pBTList->next);
2048                 delete pBTList;
2049         }
2050         return NULL;
2051 }
2052
2053 // take a pointer to the last item added to the list of subtree lists
2054 // add a subtree list to the list
2055 // return a pointer to the last item added
2056 BTListList_t *BTree_AddListToList(BTListList_t *pBTListList, BTreeList_t *pBTList)
2057 {
2058         BTListList_t *newBTListList = new BTListList_t;
2059         newBTListList->next = pBTListList;
2060         newBTListList->list = pBTList;
2061         return newBTListList;
2062 }
2063
2064
2065 // take ownership of the list of subtree lists
2066 // delete the entire list of lists, but not the subtrees themselves
2067 // return a NULL pointer
2068 BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList)
2069 {
2070         if (pBTListList != NULL)
2071         {
2072                 BTree_DeleteListFromList(pBTListList->next);
2073                 pBTListList->list = BTree_DeletePointerList(pBTListList->list);
2074                 delete pBTListList;
2075         }
2076         return NULL;
2077 }
2078
2079 // take a pointer to the last item in the list
2080 // add a NULL linker subtree to the list, setting the "flipped" flag using the left curvepoint normal .. er.. hacky?
2081 BTreeList_t *BTree_AddLinkToList(BTreeList_t *pBTList, bool bFlipped = false)
2082 {
2083         BTreeList_t *linkBTList = new BTreeList_t;
2084         linkBTList->pBT = NULL;
2085         linkBTList->next = pBTList;
2086         linkBTList->vLeft.normal[0] = (bFlipped) ? 1.0f : 0.0f;
2087         return linkBTList;
2088 }
2089
2090
2091 // take an array of three points and the address of a vector
2092 // store midpoint of the bezier curve formed by the three points, in the vector
2093 void Patch_BezierInterpolate(vec3_t vCurve[], vec3_t &pMid)
2094 {
2095         vec3_t vTemp;
2096         int i;
2097         VectorSubtract(vCurve[2], vCurve[0], vTemp); // Start->End
2098         for (i=0; i<3; i++)
2099                 vTemp[i] /= 2;
2100         VectorAdd(vCurve[0], vTemp, vTemp); // midpoint of Start->End
2101
2102         VectorSubtract(vTemp, vCurve[1], vTemp); // Mid->(midpoint of Start->End)
2103         for (i=0; i<3; i++)
2104                 vTemp[i] /= 2;
2105         VectorAdd(vCurve[1], vTemp, pMid); // midpoint of Mid->(midpoint of Start->End)
2106 }
2107
2108
2109 // take a pointer to the list of subtrees, and a threshold value
2110 // generate REAL surface curvature for the subtree curves, using bezier interpolation
2111 // if any of the real curves has an index greater than the threshold, return true
2112 bool Patch_MostCurvedRow(BTreeList_t *pBTList, int threshold)
2113 {
2114         BTreeList_t *p;
2115         float index;//, bestindex = 0;
2116         vec3_t vCurve[3];
2117         vec3_t vRow[3];
2118 //      int i;
2119
2120         for (p = pBTList; p != NULL; p = p->next->next)
2121         {
2122                 // this row
2123                 VectorCopy(p->vLeft.xyz, vCurve[0]);
2124                 VectorCopy(p->pBT->info.xyz, vCurve[1]);
2125                 VectorCopy(p->vRight.xyz, vCurve[2]);
2126
2127                 index = Patch_CurveIndex(vCurve);
2128                 if (index > threshold)
2129                         return true;
2130
2131                 if (p->next == NULL)
2132                         break;
2133
2134                 if (p->next->pBT == NULL) continue;
2135
2136                 VectorCopy(p->vLeft.xyz, vCurve[0]);
2137                 VectorCopy(p->next->vLeft.xyz, vCurve[1]);
2138                 VectorCopy(p->next->next->vLeft.xyz, vCurve[2]);
2139                 Patch_BezierInterpolate(vCurve, vRow[0]);
2140
2141                 VectorCopy(p->pBT->info.xyz, vCurve[0]);
2142                 VectorCopy(p->next->pBT->info.xyz, vCurve[1]);
2143                 VectorCopy(p->next->next->pBT->info.xyz, vCurve[2]);
2144                 Patch_BezierInterpolate(vCurve, vRow[1]);
2145
2146                 VectorCopy(p->vRight.xyz, vCurve[0]);
2147                 VectorCopy(p->next->vRight.xyz, vCurve[1]);
2148                 VectorCopy(p->next->next->vRight.xyz, vCurve[2]);
2149                 Patch_BezierInterpolate(vCurve, vRow[2]);
2150
2151                 index = Patch_CurveIndex(vRow);
2152                 if (index > threshold)
2153                         return true;
2154         }
2155         return false;
2156 }
2157
2158
2159 // take a pointer to a list of subtrees.. each subtree in the list is a 3-point bezier curve formed by two endpoints owned by the list, and a midpoint subtree node owned by a patch.
2160 // if any of the subtrees are curved above a threshold, create a left and right subsubtree for each subtree in the list.
2161 // if a NULL linker subtree is found, check for an orientation flip - ie. an inverted LOD-match - and create a NULL subsubtree with the same orientation flip
2162 // this effectively generates trees for multiple patches at the same time.. the subtrees are always owned by their respective patches though
2163 void BTree_ListCurveRecurse(BTreeList_t *pBTList)
2164 {
2165         BTreeList_t *p;
2166         BTreeList_t *leftBTList, *rightBTList;
2167         //drawVert_t pLeft, pRight, pMid;
2168         drawVert_t *vCurve[3];
2169         int threshold;
2170         //int i;
2171         bool bFlipped = false;
2172
2173         if (g_PrefsDlg.m_nSubdivisions >= 1)
2174                 threshold = g_PrefsDlg.m_nSubdivisions;
2175         else
2176                 threshold = 0;
2177
2178         leftBTList = rightBTList = NULL;
2179
2180         if (Patch_MostCurvedRow(pBTList, threshold)) // split all subtrees in list if any subtree is above threshold
2181         {
2182                 //Sys_Printf("| ");
2183                 // traverse nodes in list
2184                 for (p = pBTList; p != NULL; p=p->next)
2185                 {
2186                         if (p->pBT == NULL)
2187                         {
2188                                 leftBTList = BTree_AddLinkToList(leftBTList, (p->vLeft.normal[0] == 1.0f));
2189                                 rightBTList = BTree_AddLinkToList(rightBTList, (p->vLeft.normal[0] == 1.0f));
2190                                 if (p->vLeft.normal[0] == 1.0f) bFlipped = (!bFlipped) ? true : false; // switch bFlipped if true
2191                                 continue;
2192                         }
2193
2194                         // create left node for this subtree
2195                         BTNode_t *newLeft = new BTNode_t;
2196                         p->pBT->left = newLeft;
2197                         newLeft->left = newLeft->right = NULL;
2198
2199                         // create right node for this subtree
2200                         BTNode_t *newRight = new BTNode_t;
2201                         p->pBT->right = newRight;
2202                         newRight->left = newRight->right = NULL;
2203
2204                         // split this node
2205                         vCurve[0] = &p->vLeft;
2206                         vCurve[1] = &p->pBT->info;
2207                         vCurve[2] = &p->vRight;
2208                         Patch_CurveSplit(vCurve, newLeft->info, newRight->info, p->pBT->vMid, 0.5);
2209
2210                         memcpy(&newLeft->vMid, &newLeft->info, sizeof(drawVert_t));
2211                         memcpy(&newRight->vMid, &newRight->info, sizeof(drawVert_t));
2212
2213
2214                         if (!bFlipped)
2215                         {
2216                                 // add new left subtree to left subtree list
2217                                 leftBTList = BTree_AddToList(leftBTList, newLeft, p->vLeft, p->pBT->vMid);
2218
2219                                 // add new right subtree to right subtree list
2220                                 rightBTList = BTree_AddToList(rightBTList, newRight, p->pBT->vMid, p->vRight);
2221                         }
2222                         else
2223                         {
2224                                 // add new left subtree to right subtree list
2225                                 rightBTList = BTree_AddToList(rightBTList, newLeft, p->vLeft, p->pBT->vMid);
2226
2227                                 // add new right subtree to left subtree list
2228                                 leftBTList = BTree_AddToList(leftBTList, newRight, p->pBT->vMid, p->vRight);
2229                         }
2230                 }
2231
2232                 // continue tree left
2233                 BTree_ListCurveRecurse(leftBTList);
2234                 leftBTList = BTree_DeletePointerList(leftBTList);
2235
2236                 // continue tree right
2237                 BTree_ListCurveRecurse(rightBTList);
2238                 rightBTList = BTree_DeletePointerList(rightBTList);
2239         }
2240 }
2241
2242 // take mins and maxs values from two brushes
2243 // return true if they intersect on every axis
2244 bool TouchingAABBs(vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2)
2245 {
2246         //bool xyz[3];
2247         vec3_t v1, v2, p1, p2, T;
2248         for (int i=0; i<3; i++)
2249         {
2250                 v1[i] = maxs1[i] - mins1[i];
2251                 v2[i] = maxs2[i] - mins2[i];
2252                 v1[i] /=2;
2253                 v2[i] /=2;
2254                 p1[i] = mins1[i] + v1[i];
2255                 p2[i] = mins2[i] + v2[i];
2256                 // p1 == origin of aabb1
2257                 // p2 == origin of aabb1
2258                 // v1 == displacement of aabb1
2259                 // v1 == displacement of aabb2
2260                 T[i] = p2[i] - p1[i]; // T == vector from aabb1 to aabb2
2261                 if ( fabs(T[i]) > (fabs(v1[i]) + fabs(v2[i])) )
2262                         return false;
2263         }
2264         return true;
2265 }
2266
2267 // take a pointer to the last item added to pBTList, a pointer to the patch, a row index (start) and a column index
2268 // generate a row of row-curve tree roots, owned by the patch and add the entire column of row-curves to the list, using the row index to decide the order to add
2269 // return a pointer to the last item added to the list
2270 BTreeList_t *Patch_CreateBTListForRows(BTreeList_t *pBTList, patchMesh_t *patch, int start, int col)
2271 {
2272         int row, pos;
2273         patch->colDirty[(col-1)/2] = true;
2274
2275         if (start == 0)
2276         {
2277                 for (row=0; row<patch->height; row++)
2278                 {
2279                         pos = (((col-1)/2)*patch->height)+row;
2280                         patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]);
2281                         patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2282                         pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]);
2283                 }
2284         }
2285         else
2286         {
2287                 for (row=patch->height-1; row>=0; row--)
2288                 {
2289                         pos = (((col-1)/2)*patch->height)+row;
2290                         patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]);
2291                         patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2292                         pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]);
2293                 }
2294         }
2295         return pBTList;
2296 }
2297
2298 // take a pointer to the last item added to pBTList, a pointer to the patch, a row index and a column index (start)
2299 // generate a row of column-curve tree roots, owned by the patch and add the entire row of column-curves to the list, using the column index to decide the order to add
2300 // return a pointer to the last item added to the list
2301 BTreeList_t *Patch_CreateBTListForCols(BTreeList_t *pBTList, patchMesh_t *patch, int row, int start)
2302 {
2303         int col, pos;
2304         patch->rowDirty[(row-1)/2] = true;
2305
2306         if (start == 0)
2307         {
2308                 for (col=0; col<patch->width; col++)
2309                 {
2310                         pos = (((row-1)/2)*patch->width)+col;
2311                         patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]);
2312                         patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2313                         pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]);
2314                 }
2315         }
2316         else
2317         {
2318                 for (col=patch->width-1; col>=0; col--)
2319                 {
2320                         pos = (((row-1)/2)*patch->width)+col;
2321                         patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]);
2322                         patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2323                         pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]);
2324                 }
2325
2326         }
2327         return pBTList;
2328 }
2329
2330 bool BTree_IsInList(BTreeList_t *pBTList, BTNode_t *pBT)
2331 {
2332         BTreeList_t *p;
2333         if (pBTList == NULL) return false;
2334
2335         for (p=pBTList; p != NULL; p=p->next)
2336         {
2337                 if (p->pBT != NULL)
2338                 {
2339                         if (p->pBT == pBT)
2340         return true;
2341                 }
2342         }
2343         return false;
2344 }
2345
2346 int Patch_DegenCurve(vec3_t &start, vec3_t &mid, vec3_t &end)
2347 {
2348   if (VectorCompare(start, mid) || VectorCompare(end, mid))
2349   {
2350     if (VectorCompare(start, end)) return 2;
2351     else return 1;
2352   }
2353   else return 0;
2354 }
2355
2356 // take a pointer to the last item added to the list, and a pointer to a patch (this patch is the owner of the three drawverts)
2357 // take the addresses of three drawVerts, and compare them with the edges of all patches that touch the patch
2358 // if they match an edge, add the tree roots for that section of the matched patch to the list, and recurse for the opposite edge of that patch section. Also, set the matched patch Dirty, so that its drawlists will be rebuilt
2359 // return a pointer to the last item added
2360 BTreeList_t *Patch_FindLODMatches(patchMesh_t *patch, BTreeList_t *pBTList, drawVert_t &pMid, drawVert_t &pLeft, drawVert_t &pRight)
2361 {
2362         brush_t *pb, *brushlist;
2363         int row, col, i;//, pos;
2364         vec3_t vTemp, v1, v2;//, vClear;
2365   bool bAlreadyAdded;
2366
2367         //Sys_Printf("Patch_FindLODMatches: called\n");
2368
2369         if (VectorCompare(pMid.xyz, pLeft.xyz) && VectorCompare(pMid.xyz, pRight.xyz))
2370                 return pBTList;
2371
2372         //VectorClear(vClear);
2373         VectorSubtract(pRight.xyz, pLeft.xyz, vTemp);
2374         VectorSubtract(pMid.xyz, pLeft.xyz, v1);
2375         VectorSubtract(pRight.xyz, pMid.xyz, v2);
2376
2377         //if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return null if 1->2 == 0 or 1->2 == 1->3
2378         //      return pBTList;
2379
2380         VectorNormalize(v1, v1);
2381         VectorNormalize(v2, v2);
2382         if (VectorCompare(v1, v2))
2383                 return pBTList;
2384
2385         VectorNormalize(vTemp, vTemp);
2386         if (VectorCompare(v1, vTemp) && VectorCompare(v2, vTemp))
2387                 return pBTList;
2388
2389         brushlist = &active_brushes;
2390         for (i=0; i<2; i++)
2391         {
2392                 for (pb = brushlist->next; pb != brushlist; pb=pb->next)
2393                 {
2394                         if (!pb->patchBrush || pb->pPatch == patch)
2395                                 continue;
2396
2397                         // ignore this patch if its AABB does not touch the subject patch
2398                         if (!TouchingAABBs(patch->pSymbiot->maxs, patch->pSymbiot->mins, pb->maxs, pb->mins))
2399                                 continue;
2400
2401       // all columns of curves
2402                         for (col=1; col<pb->pPatch->width; col+=2)
2403                         {
2404                                 if (pb->pPatch->colDirty[(col-1)/2]) continue;
2405
2406                                 bAlreadyAdded = false;
2407
2408                           // top and bottom curves of this column
2409                                 for (row=0; row<pb->pPatch->height; row+=pb->pPatch->height-1)
2410                                 {
2411           if (bAlreadyAdded)
2412             continue;
2413           //if (!BTree_IsInList(pBTList, pb->pPatch->rowLOD[(((col-1)/2)*patch->height)+row]))
2414           //  continue;
2415                                         // ignore this curve if it shares no mid ctrl point with the test curve
2416                                         if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz))
2417                                                 continue;
2418                                         // ignore this curve if it is degenerate
2419                                         if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col-1][row].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col+1][row].xyz))
2420                                                 continue;
2421                                         // if curve matches the test curve directly
2422                                         if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pRight.xyz))
2423                                         {
2424                                                 // add a blank link as separator
2425                                                 pBTList = BTree_AddLinkToList(pBTList);
2426                                                 // add this entire column, if top, top-to-bottom, else bottom to top
2427                                                 pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col);
2428                                                 // continue checking from last curve added to list
2429                                           pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2430                                                 // set flag
2431                                                 pb->pPatch->LODUpdated = true;
2432             bAlreadyAdded = true;
2433                                         }
2434                                         // if curve matches test curve but flipped
2435                                         else if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pLeft.xyz))
2436                                         {
2437                                                 pBTList = BTree_AddLinkToList(pBTList, true); // flip
2438                                                 pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col);
2439                                                 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2440                                                 pb->pPatch->LODUpdated = true;
2441             bAlreadyAdded = true;
2442                                         }
2443                                 }
2444                         }
2445
2446                         // all rows of curves
2447                         for (row=1; row<pb->pPatch->height; row+=2)
2448                         {
2449                                 if (pb->pPatch->rowDirty[(row-1)/2]) continue;
2450
2451                                 bAlreadyAdded = false;
2452
2453                           for (col=0; col<pb->pPatch->width; col+=pb->pPatch->width-1)
2454                                 {
2455           if (bAlreadyAdded)
2456             continue;
2457           //if (BTree_IsInList(pBTList, pb->pPatch->colLOD[(((row-1)/2)*patch->width)+col]))
2458           //  continue;
2459                                         if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz))
2460                                                 continue;
2461                                         if (VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row-1].xyz) || VectorCompare (pb->pPatch->ctrl[col][row].xyz, pb->pPatch->ctrl[col][row+1].xyz))
2462                                                 continue;
2463                                         if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pRight.xyz))
2464                                         {
2465                                                 pBTList = BTree_AddLinkToList(pBTList);
2466                                                 pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col);
2467                                                 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2468                                                 pb->pPatch->LODUpdated = true;
2469             bAlreadyAdded = true;
2470                                         }
2471                                         else if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pLeft.xyz))
2472                                         {
2473                                                 pBTList = BTree_AddLinkToList(pBTList, true); // flip
2474                                                 pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col);
2475                                                 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2476             pb->pPatch->LODUpdated = true;
2477             bAlreadyAdded = true;
2478                                         }
2479                                 }
2480                         }
2481                 }
2482                 brushlist = &selected_brushes;
2483         }
2484         return pBTList;
2485 }
2486
2487 // take a pointer to a patch
2488 // create tree roots for all the rows and columns of curves in the patch, the patch takes ownership of these new tree roots
2489 // generate lists of pointers to all the trees in all the patches in the map which need to match the LOD of trees owned by this patch
2490 // store all the lists in a list of lists
2491 // recursively generate the rest of every tree in each list in the list
2492 void Patch_CreateLODTrees(patchMesh_t *patch)
2493 {
2494         BTreeList_t *pBTList;
2495         int col, row, pos;//, rowcount, colcount;
2496         BTListList_t *pLists;
2497
2498         //Sys_Printf("Patch_CreateMatchedLODTrees: called\n");
2499
2500         BTListList_t *LODLists;
2501         LODLists = NULL;
2502
2503         pBTList = NULL;
2504
2505         patch->bDirty = false;
2506         patch->LODUpdated = true;
2507
2508         for(col=1; col<patch->width; col+=2)
2509         {
2510                 if (patch->colDirty[(col-1)/2]) continue;
2511                 else patch->colDirty[(col-1)/2] = true;
2512
2513                 // create list for rows of current patch
2514                 for(row=0; row<patch->height; row++)
2515                 {
2516                         pos = (((col-1)/2)*patch->height)+row;
2517                         patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]);
2518                         patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2519                         pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]);
2520                 }
2521
2522                 //create connection list for first row
2523                 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][0], patch->ctrl[col-1][0], patch->ctrl[col+1][0]);
2524                 //create connection list for last row
2525                 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][row-1], patch->ctrl[col-1][row-1], patch->ctrl[col+1][row-1]);
2526
2527                 LODLists = BTree_AddListToList(LODLists, pBTList);
2528                 pBTList = NULL;
2529         }
2530
2531         pBTList = NULL;
2532         for(row=1; row<patch->height; row+=2)
2533         {
2534                 if (patch->rowDirty[(row-1)/2]) continue;
2535                 else patch->rowDirty[(row-1)/2] = true;
2536
2537                 // create list for cols of current patch
2538                 for(col=0; col<patch->width; col++)
2539                 {
2540                         pos = (((row-1)/2)*patch->width)+col;
2541                         patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]);
2542                         patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2543                         pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]);
2544                 }
2545
2546                 //create connection list for first col
2547                 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[0][row], patch->ctrl[0][row-1], patch->ctrl[0][row+1]);
2548                 //create connection list for last col
2549                 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col-1][row], patch->ctrl[col-1][row-1], patch->ctrl[col-1][row+1]);
2550
2551                 LODLists = BTree_AddListToList(LODLists, pBTList);
2552                 pBTList = NULL;
2553         }
2554
2555         for (pLists = LODLists; pLists != NULL; pLists=pLists->next)
2556                 BTree_ListCurveRecurse(pLists->list);
2557         LODLists = BTree_DeleteListFromList(LODLists);
2558 }
2559
2560 int Patch_GetCVTangent(vec3_t &v1, vec3_t &p1, vec3_t &p2, vec3_t &p3)
2561 {
2562         if (VectorCompare(p1, p2))
2563         {
2564                 if (VectorCompare(p1, p3))
2565                 {
2566                         return 2;
2567                 }
2568                 else VectorSubtract(p3, p1, v1);
2569     return 1;
2570         }
2571         else VectorSubtract(p2, p1, v1);
2572   return 0;
2573 }
2574
2575 void Patch_CVNormal(vec3_t ctrl[3][3], vec3_t &normal)
2576 {
2577         vec3_t v1, v2, vTemp1, vTemp2;
2578   int a, b;
2579
2580   a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][0], ctrl[2][0]);
2581         b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[0][1], ctrl[0][2]);
2582
2583         //Sys_Printf("p1: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f)\n",
2584         //      ctrl[0][0][0], ctrl[0][0][1], ctrl[0][0][2], ctrl[0][2][0], ctrl[0][2][1], ctrl[0][2][2], ctrl[2][0][0], ctrl[2][0][1], ctrl[2][0][2]);
2585
2586         v1[0] = v1[1] = v1[2] = v2[0] = v2[1] = v2[2] = 0;
2587
2588   if (a == 2)
2589   {
2590     a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][1], ctrl[1][2]);
2591   }
2592   if (b == 2)
2593   {
2594     b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][1], ctrl[2][1]);
2595   }
2596
2597   if (a == 2)
2598   {
2599     a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]);
2600   }
2601   if (b == 2)
2602   {
2603     b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]);
2604   }
2605
2606         CrossProduct(v1, v2, normal);
2607
2608
2609   if (normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f)
2610   {
2611     // more degenerate cases
2612     vec3_t pMid;
2613     vec3_t vCurve[3];
2614     /*
2615     if (VectorCompare(ctrl[0][0], ctrl[2][0])) // endcap left
2616     {
2617       if (VectorCompare(ctrl[0][2], ctrl[1][2]))
2618       {
2619         VectorSubtract(ctrl[2][2], ctrl[0][0], v2);
2620       }
2621       else if (VectorCompare(ctrl[1][2], ctrl[2][2]))
2622       {
2623         VectorSubtract(ctrl[0][2], ctrl[0][0], v2);
2624       }
2625       else
2626       a = Patch_DegenCurve(ctrl[0][2], ctrl[1][2], ctrl[2][2]);
2627       if (a == 0)
2628       {
2629         VectorCopy(ctrl[0][2], vCurve[0]);
2630         VectorCopy(ctrl[1][2], vCurve[1]);
2631         VectorCopy(ctrl[2][2], vCurve[2]);
2632         Patch_BezierInterpolate(vCurve, pMid);
2633                           VectorSubtract(pMid, ctrl[0][0], v1);
2634       }
2635
2636
2637                 }
2638           else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // endcap right
2639                 {
2640
2641       if (VectorCompare(ctrl[2][0], ctrl[2][1]))
2642       {
2643         VectorSubtract(ctrl[2][2], ctrl[0][0], v2);
2644       }
2645       else if (VectorCompare(ctrl[2][1], ctrl[2][2]))
2646       {
2647         VectorSubtract(ctrl[2][0], ctrl[0][0], v2);
2648       }
2649       else
2650
2651       b = Patch_DegenCurve(ctrl[2][0], ctrl[2][1], ctrl[2][2]);
2652       if (b == 0)
2653       {
2654                     VectorCopy(ctrl[2][0], vCurve[0]);
2655         VectorCopy(ctrl[2][1], vCurve[1]);
2656         VectorCopy(ctrl[2][2], vCurve[2]);
2657         Patch_BezierInterpolate(vCurve, pMid);
2658                           VectorSubtract(pMid, ctrl[0][0], v2);
2659       }
2660
2661                 }
2662     */
2663     if (VectorCompare(ctrl[0][0], ctrl[2][0])) // bottom degen
2664     {
2665       Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]);
2666     }
2667     else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // left degen
2668     {
2669       Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]);
2670     }
2671     else if (VectorCompare(ctrl[0][2], ctrl[2][2])) // top degen
2672     {
2673       VectorSubtract(ctrl[2][0], ctrl[0][0], v1);
2674     }
2675     else if (VectorCompare(ctrl[2][0], ctrl[2][2])) // right degen
2676     {
2677       VectorSubtract(ctrl[0][2], ctrl[0][0], v2);
2678     }
2679     else // tangents parallel
2680     {
2681       VectorCopy(v1, vTemp1);
2682       VectorCopy(v2, vTemp2);
2683       VectorNormalize(vTemp1, vTemp1);
2684       VectorNormalize(vTemp2, vTemp2);
2685       if (VectorCompare(vTemp1, vTemp2)) // parallel same way
2686       {
2687         VectorSubtract(ctrl[2][0], ctrl[0][0], vTemp1);
2688         VectorNormalize(vTemp1, vTemp1);
2689         if (VectorCompare(vTemp1, vTemp2))
2690         {
2691           VectorSubtract(ctrl[0][2], ctrl[0][0], v2);
2692         }
2693         else
2694         {
2695           VectorCopy(vTemp1, v1);
2696         }
2697       }
2698       else // parallel opposite way
2699       {
2700                     VectorCopy(ctrl[2][0], vCurve[0]);
2701         VectorCopy(ctrl[1][1], vCurve[1]);
2702         VectorCopy(ctrl[0][2], vCurve[2]);
2703         Patch_BezierInterpolate(vCurve, pMid);
2704                           VectorSubtract(pMid, ctrl[0][0], v2);
2705                   }
2706     }
2707
2708     CrossProduct(v1, v2, normal);
2709   }
2710 }
2711
2712 void Patch_CalcCVNormals(patchMesh_t *patch)
2713 {
2714         int row, col, i, j, n;
2715         vec3_t ctrl[3][3];
2716         vec3_t normals[4];
2717
2718         for (col=0; col<patch->width; col+=2)
2719         {
2720                 for (row=0; row<patch->height; row+=2)
2721                 {
2722                         n=0;
2723                         if (col+1 != patch->width && row+1 != patch->height)
2724                         {
2725                                 for (i=0; i<3; i++)
2726                                         for (j=0; j<3; j++)
2727                                                 VectorCopy (patch->ctrl[col+i][row+j].xyz, ctrl[i][j]);
2728
2729                                 Patch_CVNormal(ctrl, normals[n]);
2730         VectorNormalize(normals[n], normals[n]);
2731                                 n++;
2732                         }
2733
2734                         if (col-1 >= 0 && row-1 >= 0)
2735                         {
2736                                 for (i=0; i<3; i++)
2737                                         for (j=0; j<3; j++)
2738                                                 VectorCopy (patch->ctrl[col-i][row-j].xyz, ctrl[i][j]);
2739
2740                                 Patch_CVNormal(ctrl, normals[n]);
2741         VectorNormalize(normals[n], normals[n]);
2742                                 n++;
2743                         }
2744                         if (col-1 >= 0 && row+1 != patch->height)
2745                         {
2746                                 for (i=0; i<3; i++)
2747                                         for (j=0; j<3; j++)
2748                                                 VectorCopy (patch->ctrl[col-i][row+j].xyz, ctrl[j][i]);
2749
2750                                 Patch_CVNormal(ctrl, normals[n]);
2751         VectorNormalize(normals[n], normals[n]);
2752                                 n++;
2753                         }
2754                         if (col+1 != patch->width && row-1 >= 0)
2755                         {
2756                                 for (i=0; i<3; i++)
2757                                         for (j=0; j<3; j++)
2758                                                 VectorCopy (patch->ctrl[col+i][row-j].xyz, ctrl[j][i]);
2759
2760                                 Patch_CVNormal(ctrl, normals[n]);
2761         VectorNormalize(normals[n], normals[n]);
2762                                 n++;
2763                         }
2764
2765                         for (i=0; i<3; i++)
2766                         {
2767                                 if (n == 1) patch->ctrl[col][row].normal[i] = normals[0][i];
2768                                 if (n == 2) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i]) / n;
2769                                 //if (n == 3) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i]) / n;
2770                                 if (n == 4) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i] + normals[3][i]) / n;
2771                         }
2772                         VectorNormalize(patch->ctrl[col][row].normal, patch->ctrl[col][row].normal);
2773                         //if (!g_PrefsDlg.m_bGLLighting)
2774                         //      ShadeVertex(patch->ctrl[col][row]);
2775                 }
2776         }
2777 }
2778
2779
2780 void BTree_SetNormals(BTNode_t *pBT, vec3_t &normal)
2781 {
2782         if (pBT != NULL)
2783         {
2784                 if (pBT->left != NULL && pBT->right != NULL)
2785                 {
2786                         VectorCopy(normal, pBT->vMid.normal);
2787                         //if (!g_PrefsDlg.m_bGLLighting)
2788                         //      ShadeVertex(pBT->vMid);
2789                 }
2790                 BTree_SetNormals(pBT->left, normal);
2791                 BTree_SetNormals(pBT->right, normal);
2792         }
2793 }
2794
2795
2796 void NormalFromPoints(vec3_t p1, vec3_t p2, vec3_t p3, vec3_t &normal, bool flip = false)
2797 {
2798   vec3_t v1, v2;
2799
2800   if (flip)
2801   {
2802     VectorSubtract(p2, p3, v1); //p3->p2
2803           VectorSubtract(p1, p2, v2); //p2->p1
2804   }
2805   else
2806   {
2807     VectorSubtract(p2, p1, v1); //p1->p2
2808           VectorSubtract(p3, p2, v2); //p2->p3
2809   }
2810         CrossProduct(v1, v2, normal);
2811 }
2812
2813
2814 void BTree_GenerateNormals(BTNode_t *pBTMid, BTNode_t *pBTLeft, BTNode_t *pBTRight, bool avg, bool flat, bool nomid, bool noleft, bool noright, /*bool endcap, vec3_t &n1, vec3_t &n2,*/ bool flip)
2815 {
2816         if (pBTMid != NULL)
2817         {
2818                 if (pBTMid->left != NULL && pBTMid->right != NULL)
2819                 {
2820                         vec3_t normal;
2821
2822       if (noleft) // left curve is degenerate
2823       {
2824         if (nomid) // mid curve is degenerate
2825         {
2826           NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2827                 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2828         }
2829         //else if (endcap)
2830         //{
2831         //  VectorCopy(n1, normal);
2832         //  NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2833         //}
2834         else
2835         {
2836           NormalFromPoints(pBTMid->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2837                 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2838         }
2839       }
2840       else if (noright) // right curve is degenerate
2841       {
2842         if (nomid) // mid curve is degenerate
2843         {
2844           NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2845                 NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2846         }
2847         //else if (endcap)
2848         //{
2849         //  NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2850         //  VectorCopy(n2, pBTRight->vMid.normal);
2851         //}
2852         else
2853         {
2854           NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2855                 NormalFromPoints(pBTMid->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2856         }
2857       }
2858       else
2859       {
2860         if (flat) // all curves are semi-degenerate (flat) or degenerate
2861         {
2862           NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.xyz, normal, flip);
2863                 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.normal, flip);
2864         }
2865         else
2866         {
2867                       NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2868                 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2869         }
2870       }
2871
2872       VectorNormalize(normal, normal);
2873                         if (avg)
2874                                 for (int i=0; i<3; i++)
2875                                         pBTLeft->vMid.normal[i] = (normal[i] + pBTLeft->vMid.normal[i]) / 2.0f;
2876                         else VectorCopy(normal, pBTLeft->vMid.normal);
2877
2878                         VectorNormalize(pBTLeft->vMid.normal, pBTLeft->vMid.normal);
2879       VectorNormalize(pBTRight->vMid.normal, pBTRight->vMid.normal);
2880
2881                 }
2882                 BTree_GenerateNormals(pBTMid->left, pBTLeft->left, pBTRight->left, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip);
2883                 BTree_GenerateNormals(pBTMid->right, pBTLeft->right, pBTRight->right, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip);
2884         }
2885 }
2886
2887
2888
2889 void Patch_GenerateLODNormals(patchMesh_t *patch)
2890 {
2891   int col, row, rowpos, colpos, i;
2892   BTNode_t *tree[2][3];
2893   int degen[2][3];
2894   bool rowAvg, colAvg;
2895
2896   for(col=0; col+2<patch->width; col+=2)
2897         {
2898                 for(row=0; row+2<patch->height; row+=2)
2899                 {
2900       if (!patch->colDirty[col/2] && !patch->rowDirty[row/2]) continue;
2901
2902                 rowpos = ((col/2)*patch->height)+row;
2903       colpos = ((row/2)*patch->width)+col;
2904
2905       if (row==0) rowAvg = false;
2906       else rowAvg = true;
2907       if (col==0) colAvg = false;
2908       else colAvg = true;
2909
2910       for (i=0; i<3; i++)
2911       {
2912         tree[0][i] = patch->rowLOD[rowpos+i];
2913         tree[1][i] = patch->colLOD[colpos+i];
2914
2915         degen[0][i] = Patch_DegenCurve(patch->ctrl[col][row+i].xyz, patch->ctrl[col+1][row+i].xyz, patch->ctrl[col+2][row+i].xyz);
2916         degen[1][i] = Patch_DegenCurve(patch->ctrl[col+i][row].xyz, patch->ctrl[col+i][row+1].xyz, patch->ctrl[col+i][row+2].xyz);
2917       }
2918
2919       BTree_GenerateNormals(tree[0][1], tree[0][0], tree[0][2], rowAvg, (degen[1][0] && degen[1][1] && degen[1][2]), degen[0][1] == 2, degen[0][0] == 2, degen[0][2] == 2, /*degen[1][1], patch->ctrl[col][row].normal, patch->ctrl[col][row+2].normal,*/ false);
2920       BTree_GenerateNormals(tree[1][1], tree[1][0], tree[1][2], colAvg, (degen[0][0] && degen[0][1] && degen[0][2]), degen[1][1] == 2, degen[1][0] == 2, degen[1][2] == 2, /*degen[0][1], patch->ctrl[col][row].normal, patch->ctrl[col+2][row].normal,*/ true);
2921     }
2922   }
2923 }
2924
2925
2926 void Patch_ClearLODFlags(patchMesh_t *p)
2927 {
2928         int i;
2929
2930         for (i=0;i<(p->width-1)/2; i++)
2931                 p->colDirty[i] = false;
2932
2933         for (i=0;i<(p->height-1)/2; i++)
2934                 p->rowDirty[i] = false;
2935 }
2936
2937 // reset the lodDirty flags owned by all patches in the map
2938 // create new LOD trees for all dirty patches, matched with all other patches in the map
2939 void Patch_LODMatchAll()
2940 {
2941         brush_t *pb, *brushlist;
2942         int i;
2943
2944         // create LOD tree roots and LOD tree lists for all patches that are dirty
2945
2946         brushlist = &active_brushes;
2947         for (i=0; i<2; i++)
2948         {
2949                 for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next)
2950                 {
2951       // create lod for selected patches when patches are filtered
2952                         if (pb->bFiltered && (pb->patchBrush && !pb->pPatch->bSelected))
2953                                 continue;
2954                         if (!pb->patchBrush)
2955                                 continue;
2956                         if (!pb->pPatch->bDirty)
2957                                 continue;
2958
2959       Patch_CalcCVNormals(pb->pPatch);
2960                         Patch_CreateLODTrees(pb->pPatch);
2961                 }
2962                 brushlist = &selected_brushes;
2963         }
2964
2965         brushlist = &active_brushes;
2966         for (i=0; i<2; i++)
2967         {
2968                 for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next)
2969                 {
2970                         if (!pb->patchBrush)
2971                                 continue;
2972
2973       if (pb->pPatch->LODUpdated)
2974                           Patch_GenerateLODNormals(pb->pPatch);
2975
2976       Patch_ClearLODFlags(pb->pPatch);
2977     }
2978                 brushlist = &selected_brushes;
2979         }
2980
2981 }
2982
2983 void Vertex_TransformTexture(drawVert_t *pVert, float fx, float fy, transformtype xform)
2984 {
2985   switch(xform)
2986   {
2987   case TRANSLATE:
2988     pVert->st[0] += fx;
2989     pVert->st[1] += fy;
2990     break;
2991   case SCALE:
2992     pVert->st[0] *= fx;
2993     pVert->st[1] *= fy;
2994     break;
2995   case ROTATE:
2996     float x = pVert->st[0];
2997     float y = pVert->st[1];
2998     pVert->st[0] = x * fx - y * fy;
2999     pVert->st[1] = y * fx + x * fy;
3000   }
3001 }
3002
3003 void BTree_TransformTexture(BTNode_t *pBT, float fx, float fy, transformtype xform)
3004 {
3005         if (pBT != NULL)
3006         {       // PreOrder traversal
3007                 Vertex_TransformTexture(&pBT->info, fx, fy, xform);
3008     Vertex_TransformTexture(&pBT->vMid, fx, fy, xform);
3009                 BTree_TransformTexture(pBT->left, fx, fy, xform);
3010                 BTree_TransformTexture(pBT->right, fx, fy, xform);
3011         }
3012 }
3013
3014 void Patch_TransformLODTexture(patchMesh_t *p, float fx, float fy, transformtype xform)
3015 {
3016         int col, row;
3017
3018         for(col=1; col<p->width; col+=2)
3019                 for(row=0; row<p->height; row++)
3020                         BTree_TransformTexture(p->rowLOD[(((col-1)/2)*p->height)+row], fx, fy, xform);
3021
3022         for(row=1; row<p->height; row+=2)
3023                 for(col=0; col<p->width; col++)
3024                         BTree_TransformTexture(p->colLOD[(((row-1)/2)*p->width)+col], fx, fy, xform);
3025 }
3026
3027 void Patch_AddBTreeToDrawListInOrder(list<drawVert_t> *drawList, BTNode_t *pBT)
3028 {
3029         if (pBT != NULL) //traverse InOrder
3030         {
3031                 Patch_AddBTreeToDrawListInOrder(drawList, pBT->left);
3032                 if (pBT->left != NULL && pBT->right != NULL)
3033                         drawList->push_back(pBT->vMid);
3034                 Patch_AddBTreeToDrawListInOrder(drawList, pBT->right);
3035         }
3036 }
3037
3038 void Patch_InterpolateListFromRowBT(list<drawVert_t> *drawList, BTNode_t *rowBT, BTNode_t *rowBTLeft, drawVert_t *vCurve[], float u, float n, float v)
3039 {
3040         if (rowBT != NULL)
3041         {
3042                 Patch_InterpolateListFromRowBT(drawList, rowBT->left, rowBTLeft->left, vCurve, u-n, n*0.5f, v);
3043                 if (rowBT->left != NULL && rowBT->right != NULL)
3044                 {
3045                         vec3_t v1, v2;
3046                         drawVert_t newVert, vTemp1, vTemp2;
3047                         Patch_CurveSplit(vCurve, vTemp1, vTemp2, newVert, u);
3048                         for (int i=0; i<3; i++)
3049                         {
3050                                 v1[i] = rowBT->vMid.xyz[i] - rowBTLeft->vMid.xyz[i]; // left -> mid
3051                                 v1[i] = rowBTLeft->vMid.xyz[i] + (v1[i] * v);
3052                                 v1[i] = newVert.xyz[i] - v1[i];
3053                         }
3054                         VectorSubtract(vTemp1.xyz, newVert.xyz, v2);
3055                         CrossProduct(v1, v2, newVert.normal);
3056                         VectorNormalize(newVert.normal, newVert.normal);
3057                         //if (!g_PrefsDlg.m_bGLLighting)
3058                         //      ShadeVertex(newVert);
3059                         drawList->push_back(newVert);
3060                 }
3061                 Patch_InterpolateListFromRowBT(drawList, rowBT->right, rowBTLeft->right, vCurve, u+n, n*0.5f, v);
3062         }
3063 }
3064
3065 void Patch_TraverseColBTInOrder(list<list<drawVert_t>*>::iterator& iter, BTNode_t *colBTLeft, BTNode_t *colBT, BTNode_t *colBTRight, BTNode_t *rowBT, BTNode_t *rowBTLeft, float v, float n)
3066 {
3067         if (colBT != NULL)
3068         {
3069                  //traverse subtree In Order
3070                 Patch_TraverseColBTInOrder(iter, colBTLeft->left, colBT->left, colBTRight->left, rowBT, rowBTLeft, v-n, n*0.5f);
3071                 if (colBT->left != NULL && colBT->right != NULL)
3072                 {
3073                         drawVert_t *vCurve[3];
3074                         vCurve[0] = &colBTLeft->vMid;
3075                         vCurve[1] = &colBT->vMid;
3076                         vCurve[2] = &colBTRight->vMid;
3077                         Patch_InterpolateListFromRowBT((*iter), rowBT, rowBTLeft, vCurve, 0.5f, 0.25f, v);
3078
3079                         (*iter)->push_back(colBTRight->vMid);
3080                         iter++;
3081                 }
3082                 Patch_TraverseColBTInOrder(iter, colBTLeft->right, colBT->right, colBTRight->right, rowBT, rowBTLeft, v+n, n*0.5f);
3083         }
3084 }
3085
3086
3087 void Patch_StartDrawLists(list<list<drawVert_t>*> *drawLists, BTNode_t *colBT)
3088 {
3089         if (colBT != NULL)
3090         {
3091                  //traverse subtree In Order
3092                 Patch_StartDrawLists(drawLists, colBT->left);
3093                 if (colBT->left != NULL && colBT->right != NULL)
3094                 {
3095                         list<drawVert_t> *newList = new list<drawVert_t>;
3096                         drawLists->push_back(newList); // add empty list to back
3097                         drawLists->back()->push_back(colBT->vMid);
3098                 }
3099                 Patch_StartDrawLists(drawLists, colBT->right);
3100         }
3101 }
3102
3103 typedef list<drawVert_t> drawList_t;
3104 typedef list<list<drawVert_t>*> drawLists_t;
3105
3106 void Patch_CreateDrawLists(patchMesh_t *patch)
3107 {
3108   int col, row, colpos, rowpos;
3109
3110         drawLists_t *drawLists = new drawLists_t;
3111
3112         drawLists_t::iterator iter1, iter2;
3113
3114         for (row=0; row<patch->height; row+=2)
3115         {
3116                 colpos = (row/2)*patch->width;
3117                 drawList_t *newList = new drawList_t;
3118                 drawLists->push_back(newList); // add a new empty list to back
3119                 drawLists->back()->push_back(patch->ctrl[0][row]); // fill list at back
3120
3121                 if (row+1 == patch->height)
3122                         continue;
3123                 Patch_StartDrawLists(drawLists, patch->colLOD[colpos]);
3124         }
3125
3126         iter1 = drawLists->begin();
3127         for (row=0; row<patch->height; row+=2)
3128         {
3129                 iter2 = iter1;
3130                 for (col=0; col+1<patch->width; col+=2)
3131                 {
3132                         iter1 = iter2;
3133                         colpos = ((row/2)*patch->width)+col;
3134                         rowpos = ((col/2)*patch->height)+row;
3135
3136       Patch_AddBTreeToDrawListInOrder((*iter1), patch->rowLOD[rowpos]);
3137                         (*iter1)->push_back(patch->ctrl[col+2][row]);
3138
3139                         if (row+1 == patch->height)
3140                                 continue;
3141
3142                         iter1++;
3143
3144       Patch_TraverseColBTInOrder(iter1, patch->colLOD[colpos], patch->colLOD[colpos+1], patch->colLOD[colpos+2], patch->rowLOD[rowpos+1], patch->rowLOD[rowpos], 0.5, 0.25);
3145                 }
3146         }
3147
3148   patch->drawLists = drawLists;
3149 }
3150
3151
3152 void Patch_DeleteDrawLists(patchMesh_t *patch)
3153 {
3154   drawLists_t *drawLists;
3155   drawLists_t::iterator iter;
3156
3157   if (patch->drawLists == NULL)
3158     return;
3159
3160   drawLists = (drawLists_t *)patch->drawLists;
3161
3162         for (iter=drawLists->begin(); iter != drawLists->end(); iter++)
3163         {
3164                 delete (*iter);
3165         }
3166
3167   delete drawLists;
3168   patch->drawLists = NULL;
3169 }
3170
3171
3172 void Patch_DrawLODPatchMesh(patchMesh_t *patch)
3173 {
3174         drawLists_t *drawLists;
3175
3176         drawLists_t::iterator iterLists, iterListsNext;
3177         drawList_t::iterator iterList, iterListNext;
3178
3179   //int nGLState = g_pParentWnd->GetCamera()->Camera()->draw_glstate;
3180
3181   if (patch->drawLists == NULL)
3182     return;
3183
3184   drawLists = (drawLists_t *)patch->drawLists;
3185
3186         iterListsNext=drawLists->begin();
3187         iterListsNext++;
3188         for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++)
3189   {
3190                 // traverse two drawlists at once to draw a strip
3191     //if (nGLState & DRAW_GL_LINE)
3192                   qglBegin(GL_QUAD_STRIP);
3193     //else
3194     //  qglBegin(GL_TRIANGLE_STRIP);
3195                 for (iterList=(*iterLists)->begin(), iterListNext=(*iterListsNext)->begin(); iterList != (*iterLists)->end() && iterListNext != (*iterListsNext)->end(); iterList++, iterListNext++)
3196                 {
3197                         //if (g_PrefsDlg.m_bGLLighting)
3198                                 qglNormal3fv((*iterList).normal);
3199                         //else if (bShade && !g_PrefsDlg.m_bDisplayLists)
3200                         //      qglColor3f((*iterList).lightmap[0], (*iterList).lightmap[0], (*iterList).lightmap[0]);
3201
3202                         qglTexCoord2fv((*iterList).st);
3203                         qglVertex3fv((*iterList).xyz);
3204
3205                   //if (g_PrefsDlg.m_bGLLighting)
3206                                 qglNormal3fv((*iterListNext).normal);
3207                         //else if (bShade && !g_PrefsDlg.m_bDisplayLists)
3208                         //      qglColor3f((*iterListNext).lightmap[0], (*iterListNext).lightmap[0], (*iterListNext).lightmap[0]);
3209
3210                         qglTexCoord2fv((*iterListNext).st);
3211                         qglVertex3fv((*iterListNext).xyz);
3212     }
3213                 qglEnd();
3214   }
3215 /*
3216 #ifdef _DEBUG
3217   vec3_t vNormal;
3218   for (iterLists=drawLists->begin(); iterLists != drawLists->end(); iterLists++)
3219   {
3220                 qglBegin (GL_LINES); // draw normals
3221                 //qglColor3f(1,1,1);
3222                 for (iterList=(*iterLists)->begin(); iterList != (*iterLists)->end(); iterList++)
3223                 {
3224                         VectorAdd((*iterList).xyz, (*iterList).normal, vNormal);
3225                         qglVertex3fv ((*iterList).xyz);
3226                         qglVertex3fv (vNormal);
3227                 }
3228                 qglEnd ();
3229   }
3230
3231         Patch_DrawNormals(patch);
3232
3233 #endif
3234   */
3235 }
3236
3237 /*
3238 // fast memory-efficient ray-triangle intersection - MollerTrumbore97
3239
3240 #define EPSILON 0.000001
3241 #define CROSS(dest,v1,v2) {dest[0]=v1[1]*v2[2]-v1[2]*v2[1];dest[1]=v1[2]*v2[0]-v1[0]*v2[2];dest[2]=v1[0]*v2[1]-v1[1]*v2[0];}
3242 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
3243 #define SUB(dest,v1,v2) {dest[0]=v1[0]-v2[0];dest[1]=v1[1]-v2[1];dest[2]=v1[2]-v2[2];}
3244
3245 int intersect_triangle(float orig[3], float dir[3],
3246                    float vert0[3], float vert1[3], float vert2[3],
3247                    double *t, double *u, double *v)
3248 {
3249    double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
3250    double det,inv_det;
3251
3252    // find vectors for two edges sharing vert0
3253    SUB(edge1, vert1, vert0);
3254    SUB(edge2, vert2, vert0);
3255
3256    // begin calculating determinant - also used to calculate U parameter
3257    CROSS(pvec, dir, edge2);
3258
3259    // if determinant is near zero, ray lies in plane of triangle
3260    det = DOT(edge1, pvec);
3261
3262 #ifdef TEST_CULL           // define TEST_CULL if culling is desired
3263    if (det < EPSILON)
3264       return 0;
3265
3266    // calculate distance from vert0 to ray origin
3267    SUB(tvec, orig, vert0);
3268
3269    // calculate U parameter and test bounds
3270    *u = DOT(tvec, pvec);
3271    if (*u < 0.0 || *u > det)
3272       return 0;
3273
3274    // prepare to test V parameter
3275    CROSS(qvec, tvec, edge1);
3276
3277     // calculate V parameter and test bounds
3278    *v = DOT(dir, qvec);
3279    if (*v < 0.0 || *u + *v > det)
3280       return 0;
3281
3282    // calculate t, scale parameters, ray intersects triangle
3283    *t = DOT(edge2, qvec);
3284    inv_det = 1.0 / det;
3285    *t *= inv_det;
3286    *u *= inv_det;
3287    *v *= inv_det;
3288 #else                    // the non-culling branch
3289    if (det > -EPSILON && det < EPSILON)
3290      return 0;
3291    inv_det = 1.0 / det;
3292
3293    // calculate distance from vert0 to ray origin
3294    SUB(tvec, orig, vert0);
3295
3296    // calculate U parameter and test bounds
3297    *u = DOT(tvec, pvec) * inv_det;
3298    if (*u < 0.0 || *u > 1.0)
3299      return 0;
3300
3301    // prepare to test V parameter
3302    CROSS(qvec, tvec, edge1);
3303
3304    // calculate V parameter and test bounds
3305    *v = DOT(dir, qvec) * inv_det;
3306    if (*v < 0.0 || *u + *v > 1.0)
3307      return 0;
3308
3309    // calculate t, ray intersects triangle
3310    *t = DOT(edge2, qvec) * inv_det;
3311 #endif
3312    return 1;
3313 }
3314 */
3315
3316 int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
3317                  float vert0[3], float vert1[3], float vert2[3],
3318                  double *t, double *u, double *v)
3319 {
3320   float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
3321   double det,inv_det;
3322
3323   /* find vectors for two edges sharing vert0 */
3324   VectorSubtract(vert1, vert0, edge1);
3325   VectorSubtract(vert2, vert0, edge2);
3326
3327   /* begin calculating determinant - also used to calculate U parameter */
3328   CrossProduct(dir, edge2, pvec);
3329
3330   /* if determinant is near zero, ray lies in plane of triangle */
3331   det = DotProduct(edge1, pvec);
3332
3333   if (bCullBack)
3334   {
3335     if (det < 0.000001)
3336       return 0;
3337
3338     // calculate distance from vert0 to ray origin
3339     VectorSubtract(orig, vert0, tvec);
3340
3341     // calculate U parameter and test bounds
3342     *u = DotProduct(tvec, pvec);
3343     if (*u < 0.0 || *u > det)
3344       return 0;
3345
3346     // prepare to test V parameter
3347     CrossProduct(tvec, edge1, qvec);
3348
3349     // calculate V parameter and test bounds
3350     *v = DotProduct(dir, qvec);
3351     if (*v < 0.0 || *u + *v > det)
3352       return 0;
3353
3354     // calculate t, scale parameters, ray intersects triangle
3355     *t = DotProduct(edge2, qvec);
3356     inv_det = 1.0 / det;
3357     *t *= inv_det;
3358     *u *= inv_det;
3359     *v *= inv_det;
3360   }
3361   else
3362   {
3363     /* the non-culling branch */
3364     if (det > -0.000001 && det < 0.000001)
3365       return 0;
3366     inv_det = 1.0 / det;
3367
3368     /* calculate distance from vert0 to ray origin */
3369     VectorSubtract(orig, vert0, tvec);
3370
3371     /* calculate U parameter and test bounds */
3372     *u = DotProduct(tvec, pvec) * inv_det;
3373     if (*u < 0.0 || *u > 1.0)
3374       return 0;
3375
3376     /* prepare to test V parameter */
3377     CrossProduct(tvec, edge1, qvec);
3378
3379     /* calculate V parameter and test bounds */
3380     *v = DotProduct(dir, qvec) * inv_det;
3381     if (*v < 0.0 || *u + *v > 1.0)
3382       return 0;
3383
3384     /* calculate t, ray intersects triangle */
3385     *t = DotProduct(edge2, qvec) * inv_det;
3386   }
3387   return 1;
3388 }
3389
3390 bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
3391 {
3392         drawLists_t *drawLists;
3393
3394         drawLists_t::iterator iterLists, iterListsNext;
3395         drawList_t::iterator i1, i2, i3, i4;
3396
3397 //  vec3_t tris[2][3];
3398   bool bIntersect = false;
3399   float tBest = FLT_MAX;
3400
3401   if (patch->drawLists == NULL)
3402     return false;
3403
3404   drawLists = (drawLists_t *)patch->drawLists;
3405
3406         iterListsNext=drawLists->begin();
3407         iterListsNext++;
3408         for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++)
3409   {
3410                 // traverse two drawlists at once with two iterators each to triangulate
3411     i1 = i3 = (*iterLists)->begin();
3412     i2 = i4 = (*iterListsNext)->begin();
3413     i3++;
3414     i4++;
3415                 while (i3 != (*iterLists)->end() && i4 != (*iterListsNext)->end())
3416                 {
3417       if (Triangle_Ray(origin, dir, false, (*i1).xyz, (*i2).xyz, (*i3).xyz, t, u, v))
3418       {
3419         bIntersect = true;
3420         if (*t < tBest)
3421           tBest = *t;
3422       }
3423       if (Triangle_Ray(origin, dir, false, (*i3).xyz, (*i4).xyz, (*i2).xyz, t, u, v))
3424       {
3425         bIntersect = true;
3426         if (*t < tBest)
3427           tBest = *t;
3428       }
3429       i1++;
3430       i2++;
3431       i3++;
3432       i4++;
3433                 }
3434   }
3435   if (bIntersect)
3436   {
3437     *t = tBest;
3438     return true;
3439   }
3440   else
3441   {
3442     *t = 0;
3443     return false;
3444   }
3445 }
3446
3447 // spog - curve LOD stuff ends
3448
3449 /*
3450 =================
3451 DrawPatchMesh
3452 =================
3453 */
3454 void DrawPatchMesh(patchMesh_t *pm)
3455 {
3456   if (g_PrefsDlg.m_bDisplayLists)
3457   {
3458     if (pm->bDirty || pm->nListID <= 0 || pm->LODUpdated)
3459     {
3460       if (pm->nListID <= 0)
3461         pm->nListID = qglGenLists(1);
3462       if (pm->nListID > 0)
3463       {
3464         qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE);
3465       }
3466
3467       Patch_DeleteDrawLists(pm);
3468       Patch_CreateDrawLists(pm);
3469
3470                   Patch_DrawLODPatchMesh(pm);
3471
3472       if (pm->nListID > 0)
3473       {
3474         qglEndList();
3475             }
3476
3477             pm->bDirty = false;
3478             pm->LODUpdated = false;
3479     }
3480     else
3481     {
3482       qglCallList(pm->nListID);
3483     }
3484   }
3485   else
3486   {
3487     if (pm->bDirty || pm->LODUpdated)
3488     {
3489       Patch_DeleteDrawLists(pm);
3490       Patch_CreateDrawLists(pm);
3491       pm->bDirty = false;
3492       pm->LODUpdated = false;
3493     }
3494           Patch_DrawLODPatchMesh(pm);
3495   }
3496 }
3497
3498 /*
3499 =================
3500 DrawPatchControls
3501 =================
3502 */
3503 void DrawPatchControls(patchMesh_t *pm)
3504 {
3505   int i, j;
3506   bool bSelectedPoints[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT];
3507
3508   bool bOverlay = pm->bOverlay;
3509
3510   // bending
3511   if (g_bPatchBendMode)
3512   {
3513     qglPointSize(6);
3514     if (g_bPatchAxisOnRow)
3515     {
3516       qglColor3f(1, 0, 1);
3517       if(!g_PrefsDlg.m_bGlPtWorkaround)
3518       {
3519         qglBegin(GL_POINTS);
3520         for (i = 0; i < pm->width; i++)
3521         {
3522           qglVertex3fv(pm->ctrl[i][g_nPatchAxisIndex].xyz);
3523         }
3524         qglEnd();
3525       }
3526       else
3527       {
3528         qglLineWidth(2.0);
3529         qglBegin(GL_LINES);
3530         for(i = 0; i < pm->width; i++)
3531         {
3532           DrawAlternatePoint(pm->ctrl[i][g_nPatchAxisIndex].xyz, 0);
3533         }
3534         qglEnd();
3535         qglLineWidth(1.0);
3536       }
3537
3538       if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
3539       {
3540         if(!g_PrefsDlg.m_bGlPtWorkaround)
3541         {
3542           qglColor3f(0, 0, 1);
3543           qglBegin(GL_POINTS);
3544           if (g_nPatchBendState == BEND_SELECT_ORIGIN)
3545           {
3546             qglVertex3fv(g_vBendOrigin);
3547           }
3548           else
3549           {
3550             for (i = 0; i < pm->width; i++)
3551             {
3552               if (g_bPatchLowerEdge)
3553               {
3554                 for (j = 0; j < g_nPatchAxisIndex; j++)
3555                   qglVertex3fv(pm->ctrl[i][j].xyz);
3556               }
3557               else
3558               {
3559                 for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
3560                   qglVertex3fv(pm->ctrl[i][j].xyz);
3561               }
3562             }
3563           }
3564           qglEnd();
3565         }
3566         else {
3567           qglColor3f(0, 0, 1);
3568           qglLineWidth(2.0);
3569           qglBegin(GL_LINES);
3570           if(g_nPatchBendState == BEND_SELECT_ORIGIN)
3571           {
3572             DrawAlternatePoint(g_vBendOrigin, 0);
3573           }
3574           else
3575           {
3576             for(i = 0; i < pm->width; i++)
3577             {
3578               if(g_bPatchLowerEdge)
3579               {
3580                 for(j = 0; j < g_nPatchAxisIndex; j++)
3581                 {
3582                   DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3583                 }
3584               }
3585               else
3586               {
3587                 for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
3588                 {
3589                   DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3590                 }
3591               }
3592             }
3593           }
3594           qglEnd();
3595           qglLineWidth(1.0);
3596         }
3597       }
3598     }
3599     else
3600     {
3601       if(!g_PrefsDlg.m_bGlPtWorkaround)
3602       {
3603         qglColor3f(1, 0, 1);
3604         qglBegin(GL_POINTS);
3605         for (i = 0; i < pm->height; i++)
3606         {
3607           qglVertex3fv(pm->ctrl[g_nPatchAxisIndex][i].xyz);
3608         }
3609         qglEnd();
3610       }
3611       else {
3612         qglColor3f(1, 0, 1);
3613         qglLineWidth(2.0);
3614         qglBegin(GL_LINES);
3615         for(i = 0; i < pm->height; i++)
3616         {
3617           DrawAlternatePoint(pm->ctrl[g_nPatchAxisIndex][i].xyz, 0);
3618         }
3619         qglEnd();
3620         qglLineWidth(1.0);
3621       }
3622
3623       if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
3624       {
3625         if(!g_PrefsDlg.m_bGlPtWorkaround)
3626         {
3627           qglColor3f(0, 0, 1);
3628           qglBegin(GL_POINTS);
3629           for (i = 0; i < pm->height; i++)
3630           {
3631             if (g_nPatchBendState == BEND_SELECT_ORIGIN)
3632             {
3633               qglVertex3fv(pm->ctrl[g_nBendOriginIndex][i].xyz);
3634             }
3635             else
3636             {
3637               if (g_bPatchLowerEdge)
3638               {
3639                 for (j = 0; j < g_nPatchAxisIndex; j++)
3640                   qglVertex3fv(pm->ctrl[j][i].xyz);
3641               }
3642               else
3643               {
3644                 for (j = pm->width-1; j > g_nPatchAxisIndex; j--)
3645                   qglVertex3fv(pm->ctrl[j][i].xyz);
3646               }
3647             }
3648           }
3649           qglEnd();
3650         }
3651         else {
3652           qglColor3f(0, 0, 1);
3653           qglLineWidth(2.0);
3654           qglBegin(GL_LINES);
3655           for(i = 0; i < pm->height; i++)
3656           {
3657             if(g_nPatchBendState == BEND_SELECT_ORIGIN)
3658             {
3659               DrawAlternatePoint(pm->ctrl[g_nBendOriginIndex][i].xyz, 0);
3660             }
3661             else
3662             {
3663               if(g_bPatchLowerEdge)
3664               {
3665                 for(j = 0; j < g_nPatchAxisIndex; j++)
3666                 {
3667                   DrawAlternatePoint(pm->ctrl[j][i].xyz, 0);
3668                 }
3669               }
3670               else
3671               {
3672                 for(j = pm->width-1; j > g_nPatchAxisIndex; j--)
3673                 {
3674                   DrawAlternatePoint(pm->ctrl[j][i].xyz, 0);
3675                 }
3676               }
3677             }
3678           }
3679           qglEnd();
3680           qglLineWidth(1.0);
3681         }
3682       }
3683     }
3684   }
3685   else
3686   {
3687     //qglDisable(GL_TEXTURE_2D); // stops point colours being multiplied by texture colour..
3688     //draw CV lattice - could be made optional
3689     //qglDisable( GL_CULL_FACE );
3690     //    qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3691     qglEnable (GL_POLYGON_OFFSET_LINE);
3692     if (g_PrefsDlg.m_bNoStipple == FALSE)
3693       qglDisable (GL_LINE_STIPPLE);
3694     qglLineWidth (1);
3695     qglColor3f(1.0f, 0.75f, 0.0f);
3696     for ( i = 0 ; i+1 < pm->width ; i++ )
3697     {
3698       qglBegin(GL_QUAD_STRIP);
3699       for ( j = 0 ; j < pm->height ; j++ )
3700       {
3701         qglVertex3fv(pm->ctrl[i][j].xyz);
3702         qglVertex3fv(pm->ctrl[i+1][j].xyz);
3703       }
3704       qglEnd();
3705     }
3706     qglDisable (GL_POLYGON_OFFSET_LINE);
3707     //if (g_PrefsDlg.m_bNoStipple == FALSE)
3708     //  qglEnable (GL_LINE_STIPPLE);
3709
3710     // draw selection handles
3711     if(!g_PrefsDlg.m_bGlPtWorkaround)
3712     {
3713       qglPointSize(6);
3714       qglBegin(GL_POINTS);
3715       for ( i = 0 ; i < pm->width ; i++ )
3716       {
3717         for ( j = 0 ; j < pm->height ; j++ )
3718         {
3719           if (PointInMoveList(pm->ctrl[i][j].xyz) != -1)
3720           {
3721             bSelectedPoints[i][j] = true;
3722           }
3723           else
3724           {
3725             bSelectedPoints[i][j] = false;
3726             if (i & 0x01 || j & 0x01)
3727               qglColor3f(1, 0, 1);
3728             else
3729               qglColor3f(0, 1, 0);
3730
3731             qglVertex3fv(pm->ctrl[i][j].xyz);
3732           }
3733         }
3734       }
3735       qglColor3f(0, 0, 1);
3736       for ( i = 0 ; i < pm->width ; i++ )
3737       {
3738         for ( j = 0 ; j < pm->height ; j++ )
3739         {
3740           if (bSelectedPoints[i][j])
3741             qglVertex3fv(pm->ctrl[i][j].xyz);
3742         }
3743       }
3744       qglEnd();
3745     }
3746     else
3747     {
3748       qglLineWidth(2.0);
3749       qglBegin(GL_LINES);
3750       for(i = 0; i < pm->width; i++)
3751       {
3752         for(j = 0; j < pm->height; j++)
3753         {
3754           if(PointInMoveList(pm->ctrl[i][j].xyz) != -1)
3755           {
3756             bSelectedPoints[i][j] = true;
3757           }
3758           else
3759           {
3760             bSelectedPoints[i][j] = false;
3761             if(i & 0x01 || j & 0x01)
3762               qglColor3f(1, 0, 1);
3763             else
3764               qglColor3f(0, 1, 0);
3765
3766             // draw verts
3767             DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3768           }
3769         }
3770       }
3771       qglColor3f(0, 0, 1);
3772       for(i = 0; i < pm->width; i++)
3773       {
3774         for(j = 0; j < pm->height; j++)
3775         {
3776           if(bSelectedPoints[i][j])
3777           {
3778             // draw verts
3779             DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3780           }
3781         }
3782       }
3783       qglEnd();
3784       qglLineWidth(1.0);
3785     }
3786   }
3787   if (bOverlay)
3788   {
3789     if(!g_PrefsDlg.m_bGlPtWorkaround)
3790     {
3791       qglPointSize(6);
3792       qglBegin(GL_POINTS);
3793       for ( i = 0 ; i < pm->width ; i++ )
3794       {
3795         for ( j = 0 ; j < pm->height ; j++ )
3796         {
3797           if (i & 0x01 || j & 0x01)
3798             qglColor3f(1, 0, 1);
3799           else
3800             qglColor3f(0, 1, 0);
3801           qglVertex3fv(pm->ctrl[i][j].xyz);
3802         }
3803       }
3804       qglEnd();
3805     }
3806     else
3807     {
3808       qglLineWidth(2.0);
3809       qglBegin(GL_LINES);
3810       for ( i = 0 ; i < pm->width ; i++ )
3811       {
3812         for ( j = 0 ; j < pm->height ; j++ )
3813         {
3814           if (i & 0x01 || j & 0x01)
3815             qglColor3f(1, 0, 1);
3816           else
3817             qglColor3f(0, 1, 0);
3818           // draw verts
3819           DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3820         }
3821       }
3822       qglEnd();
3823       qglLineWidth(1.0);
3824     }
3825   }
3826   //qglPopAttrib();
3827 }
3828
3829 /*
3830 ==================
3831 Patch_DrawXY
3832 ==================
3833 */
3834 void Patch_DrawXY(patchMesh_t *pm)
3835 {
3836   qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3837
3838   if (pm->bSelected)
3839   {
3840     qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
3841     if (g_PrefsDlg.m_bNoStipple == FALSE)
3842       qglEnable (GL_LINE_STIPPLE);
3843     qglLineWidth (2);
3844   }
3845
3846   DrawPatchMesh(pm);
3847
3848   if ( (pm->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint
3849     || g_qeglobals.d_select_mode == sel_area
3850     || g_bPatchBendMode))
3851     || pm->bOverlay )
3852     DrawPatchControls(pm);
3853 }
3854
3855 /*
3856 ==================
3857 Patch_DrawCam
3858 ==================
3859 */
3860 void Patch_DrawCam(patchMesh_t *pm)
3861 {
3862         qglPushAttrib(GL_ALL_ATTRIB_BITS); // save the current state
3863
3864   if (g_bPatchWireFrame)
3865   {
3866     qglDisable( GL_CULL_FACE );
3867     qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3868     qglDisable(GL_TEXTURE_2D);
3869     if (g_PrefsDlg.m_bGLLighting)
3870       qglDisable(GL_LIGHTING);
3871
3872     DrawPatchMesh(pm);
3873
3874     //if (g_PrefsDlg.m_bGLLighting)
3875     //  qglEnable(GL_LIGHTING);
3876     //qglEnable( GL_CULL_FACE );
3877   }
3878   else
3879   {
3880     qglDisable(GL_CULL_FACE);
3881     qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number);
3882     qglPolygonMode (GL_FRONT, GL_FILL);
3883     qglPolygonMode (GL_BACK, GL_LINE);
3884
3885     if (pm->pShader->getTrans() < 1.0f)
3886     {
3887       qglEnable(GL_BLEND);
3888       qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3889       qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->pShader->getTrans());
3890     }
3891
3892     DrawPatchMesh(pm); // both sides
3893   }
3894
3895   qglPopAttrib(); // restore saved state
3896 }
3897
3898 void ConvexHullForSection( float section[2][4][7] ) {
3899 }
3900
3901 void BrushesForSection( float section[2][4][7] ) {
3902 }
3903
3904 /*
3905 ================
3906 Patch_BuildPoints
3907 ================
3908 */
3909 void Patch_BuildPoints (brush_t *b)
3910 {
3911         face_t          *f;
3912         b->patchBrush = false;
3913         for (f=b->brush_faces ; f ; f=f->next)
3914   {
3915                 if (f->texdef.flags & SURF_PATCH)
3916     {
3917                         b->patchBrush = true;
3918       //vec3_t vMin, vMax;
3919       //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax);
3920       //VectorCopy(vMin, b->mins);
3921       //VectorCopy(vMax, b->maxs);
3922                         break;
3923                 }
3924         }
3925 }
3926
3927 /*
3928 ==================
3929 Patch_Move
3930 ==================
3931 */
3932 void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild)
3933 {
3934   pm->bDirty = true;
3935   for (int w = 0; w < pm->width; w++)
3936   {
3937     for (int h = 0; h < pm->height; h++)
3938     {
3939       VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz);
3940     }
3941   }
3942   // bRebuild is never true
3943   if (bRebuild)
3944   {
3945     vec3_t vMin, vMax;
3946     Patch_CalcBounds(pm, vMin, vMax);
3947     //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax);
3948   }
3949   UpdatePatchInspector();
3950
3951 }
3952
3953 /*
3954 ==================
3955 Patch_ApplyMatrix
3956 ==================
3957 */
3958 void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap)
3959 {
3960         vec3_t vTemp;
3961
3962         for (int w = 0; w < p->width; w++)
3963         {
3964                 for (int h = 0; h < p->height; h++)
3965                 {
3966                         if (((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode)
3967                                 && PointInMoveList(p->ctrl[w][h].xyz) == -1) // snap selected points only, if selected
3968                                 continue;
3969                         VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp);
3970                         for (int j = 0; j < 3; j++)
3971                         {
3972                                 p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j];
3973                                 if (bSnap)
3974                                 {
3975                                         p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5);
3976                                 }
3977                         }
3978                 }
3979         }
3980         vec3_t vMin, vMax;
3981         Patch_CalcBounds(p, vMin, vMax);
3982         Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
3983 }
3984
3985 /*
3986 ==================
3987 Patch_EditPatch
3988 ==================
3989 */
3990 void Patch_EditPatch()
3991 {
3992   //--patchMesh_t* p = &patchMeshes[n];
3993   g_qeglobals.d_numpoints = 0;
3994   g_qeglobals.d_num_move_points = 0;
3995
3996   for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
3997         {
3998     if (pb->patchBrush)
3999     {
4000             patchMesh_t* p = pb->pPatch;
4001             for ( int i = 0 ; i < p->width ; i++ )
4002       {
4003                     for ( int j = 0 ; j < p->height ; j++ )
4004         {
4005                 VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
4006           if (g_qeglobals.d_numpoints < MAX_POINTS-1)
4007           {
4008                   g_qeglobals.d_numpoints++;
4009           }
4010                     }
4011       }
4012     }
4013   }
4014   g_qeglobals.d_select_mode = sel_curvepoint;
4015   //--g_nSelectedPatch = n;
4016 }
4017
4018
4019
4020 /*
4021 ==================
4022 Patch_Deselect
4023 ==================
4024 */
4025 //FIXME: need all sorts of asserts throughout a lot of this crap
4026 void Patch_Deselect()
4027 {
4028   //--g_nSelectedPatch = -1;
4029   g_qeglobals.d_select_mode = sel_brush;
4030
4031         for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
4032   {
4033     if (b->patchBrush)
4034     {
4035       b->pPatch->bSelected = false;
4036     }
4037   }
4038
4039   //for (int i = 0; i < numPatchMeshes; i++)
4040   //  patchMeshes[i].bSelected = false;
4041
4042   if (g_bPatchBendMode)
4043     Patch_BendToggle();
4044 //  if (g_bPatchInsertMode)
4045 //    Patch_InsDelToggle();
4046 }
4047
4048
4049 /*
4050 ==================
4051 Patch_Select
4052 ==================
4053 */
4054 void Patch_Select(patchMesh_t *p)
4055 {
4056   // maintained for point manip.. which i need to fix as this
4057   // is pf error prone
4058   //--g_nSelectedPatch = n;
4059   p->bSelected = true;
4060 }
4061
4062
4063 /*
4064 ==================
4065 Patch_Deselect
4066 ==================
4067 */
4068 void Patch_Deselect(patchMesh_t *p)
4069 {
4070   p->bSelected = false;
4071 }
4072
4073
4074 /*
4075 ==================
4076 Patch_Delete
4077 ==================
4078 */
4079 extern BTNode_t *BTree_Delete(BTNode_t *pBT);
4080 extern BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList);
4081
4082 void Patch_Delete(patchMesh_t *p)
4083 {
4084   if (p->pSymbiot) // Hydra - added a check to prevent access violations.
4085   {
4086   p->pSymbiot->pPatch = NULL;
4087   p->pSymbiot->patchBrush = false;
4088   }
4089
4090   // spog - free dynamically allocated memory used by LODs
4091   int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT;
4092         int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH;
4093         int i;
4094         for (i=0; i<rowcount; i++)
4095                 p->rowLOD[i] = BTree_Delete(p->rowLOD[i]);
4096         for (i=0; i<colcount; i++)
4097                 p->colLOD[i] = BTree_Delete(p->colLOD[i]);
4098
4099   // delete display list associated with patch
4100   if (p->nListID != -1)
4101     qglDeleteLists (p->nListID, 1); // list#, number of lists
4102
4103   // delete LOD drawLists
4104   Patch_DeleteDrawLists(p);
4105
4106
4107   free(p);
4108   p = NULL;
4109
4110
4111   UpdatePatchInspector();
4112 }
4113
4114
4115 /*
4116 ==================
4117 Patch_Scale
4118 ==================
4119 */
4120 void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild)
4121 {
4122
4123   for (int w = 0; w < p->width; w++)
4124   {
4125     for (int h = 0; h < p->height; h++)
4126     {
4127       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
4128         continue;
4129                         for (int i=0 ; i<3 ; i++)
4130                         {
4131         p->ctrl[w][h].xyz[i] -= vOrigin[i];
4132         p->ctrl[w][h].xyz[i] *= vAmt[i];
4133         p->ctrl[w][h].xyz[i] += vOrigin[i];
4134       }
4135     }
4136   }
4137   if (bRebuild)
4138   {
4139     vec3_t vMin, vMax;
4140     Patch_CalcBounds(p, vMin, vMax);
4141     Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
4142   }
4143   UpdatePatchInspector();
4144 }
4145
4146
4147 /*
4148 ==================
4149 Patch_SetView
4150 ==================
4151 */
4152 void Patch_SetView(int n)
4153 {
4154   g_bSameView = (n == g_nPatchClickedView);
4155   g_nPatchClickedView = n;
4156 }
4157
4158
4159 /*
4160 ==================
4161 Patch_SetTexture
4162 ==================
4163 */
4164 // FIXME: need array validation throughout
4165 void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef)
4166 {
4167   // NOTE: I don't know for sure if this happens
4168   if (p->pShader)
4169     p->pShader->DecRef();
4170   p->pShader = QERApp_Shader_ForName(tex_def->GetName());
4171   p->pShader->IncRef();
4172   p->d_texture = p->pShader->getTexture();
4173
4174   UpdatePatchInspector();
4175 }
4176
4177
4178 /*
4179 ==================
4180 Patch_DragScale
4181 ==================
4182 */
4183 bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove)
4184 {
4185   vec3_t vMin, vMax, vScale, vTemp, vMid;
4186   int i;
4187
4188   Patch_CalcBounds(p, vMin, vMax);
4189
4190   VectorSubtract(vMax, vMin, vTemp);
4191
4192   // if we are scaling in the same dimension the patch has no depth
4193   for (i = 0; i < 3; i ++)
4194   {
4195     if (vTemp[i] == 0 && vMove[i] != 0)
4196     {
4197       //Patch_Move(n, vMove, true);
4198       return false;
4199     }
4200   }
4201
4202   for (i=0 ; i<3 ; i++)
4203     vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2));
4204
4205   for (i = 0; i < 3; i++)
4206   {
4207     if (vAmt[i] != 0)
4208     {
4209       vScale[i] = 1.0 + vAmt[i] / vTemp[i];
4210     }
4211     else
4212     {
4213       vScale[i] = 1.0;
4214     }
4215   }
4216
4217   Patch_Scale(p, vMid, vScale, false);
4218
4219   VectorSubtract(vMax, vMin, vTemp);
4220
4221   Patch_CalcBounds(p, vMin, vMax);
4222
4223   VectorSubtract(vMax, vMin, vMid);
4224
4225   VectorSubtract(vMid, vTemp, vTemp);
4226
4227   VectorScale(vTemp, 0.5, vTemp);
4228
4229   // abs of both should always be equal
4230   if (!VectorCompare(vMove, vAmt))
4231   {
4232     for (i = 0; i < 3; i++)
4233     {
4234       if (vMove[i] != vAmt[i])
4235         vTemp[i] = -(vTemp[i]);
4236     }
4237   }
4238
4239   Patch_Move(p, vTemp);
4240   return true;
4241 }
4242
4243 /*
4244 ==================
4245 Patch_InsertColumn
4246 ==================
4247 */
4248 void Patch_InsertColumn(patchMesh_t *p, bool bAdd)
4249 {
4250         int w, h, i, width;
4251         vec3_t vTemp;
4252         float stTemp[2];
4253
4254         if (p->width + 2 >= MAX_PATCH_WIDTH)
4255                 return;
4256
4257         w = 1;
4258         // check for selected column points
4259         for (h = 0; h < p->height; h++)
4260         {
4261                 for (w = 1; w < p->width; w+=2)
4262                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4263                                 break;
4264                 if (w < p->width)
4265                         break;
4266                 for (w = 0; w < p->width; w+=2)
4267                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4268                                 break;
4269                 if (w < p->width)
4270                         break;
4271         }
4272
4273         if (w >= p->width)
4274         {
4275                 if (bAdd) w=p->width-1;
4276                 else w=2;
4277         }
4278         else if (w==0) w=2;
4279         else if (w%2) w++;
4280
4281         // add columns at w
4282         for (h = 0; h < p->height; h++)
4283         {
4284                 for (width = p->width-1; width > w; width--)
4285                         memcpy(&p->ctrl[width+2][h],&p->ctrl[width][h], sizeof(drawVert_t));
4286
4287                 // set two new column points
4288                 memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t));
4289                 memcpy(&p->ctrl[w+1][h],&p->ctrl[w-1][h], sizeof(drawVert_t));
4290
4291                 for (i=0; i<3; i++) // xyz
4292                 {
4293                         vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4294                         p->ctrl[w+1][h].xyz[i] = p->ctrl[w+1][h].xyz[i] + (vTemp[i] / 2);
4295
4296                         vTemp[i] = p->ctrl[w-2][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4297                         p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2);
4298
4299                         vTemp[i] = p->ctrl[w+1][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4300                         p->ctrl[w][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2);
4301                 }
4302                 for (i=0; i<2; i++) // st
4303                 {
4304                         stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i];
4305                         p->ctrl[w+1][h].st[i] = p->ctrl[w+1][h].st[i] + (stTemp[i] / 2);
4306
4307                         stTemp[i] = p->ctrl[w-2][h].st[i] - p->ctrl[w-1][h].st[i];
4308                         p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2);
4309
4310                         stTemp[i] = p->ctrl[w+1][h].st[i] - p->ctrl[w-1][h].st[i];
4311                         p->ctrl[w][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2);
4312                 }
4313         }
4314
4315         p->width += 2;
4316         // deselect all points to keep things neat
4317         if (g_qeglobals.d_select_mode == sel_curvepoint)
4318                 Patch_EditPatch();
4319
4320         UpdatePatchInspector();
4321 }
4322
4323 /*
4324 ==================
4325 Patch_InsertRow
4326 ==================
4327 */
4328
4329 void Patch_InsertRow(patchMesh_t *p, bool bAdd)
4330 {
4331         int h, w, i, height;
4332         vec3_t vTemp;
4333         float stTemp[2];
4334
4335         if (p->height + 2 >= MAX_PATCH_HEIGHT)
4336                 return;
4337
4338         h = 1;
4339         // check for selected row points
4340         for (w = 0; w < p->width; w++)
4341         {
4342                 for (h = 1; h < p->height; h+=2)
4343                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4344                                 break;
4345                 if (h < p->height)
4346                         break;
4347                 for (h = 0; h < p->height; h+=2)
4348                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4349                                 break;
4350                 if (h < p->height)
4351                         break;
4352         }
4353         if (h >= p->height)
4354         {
4355                 if (bAdd) h=p->height-1;
4356                 else h=2;
4357         }
4358         else if (h==0) h=2;
4359         else if (h%2) h++;
4360
4361         // add rows at h
4362         for (w = 0; w < p->width; w++)
4363         {
4364                 for (height = p->height-1; height > h; height--)
4365                         memcpy(&p->ctrl[w][height+2],&p->ctrl[w][height], sizeof(drawVert_t));
4366
4367                 // set two new row points
4368                 memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t));
4369                 memcpy(&p->ctrl[w][h+1],&p->ctrl[w][h-1], sizeof(drawVert_t));
4370
4371                 for (i=0; i<3; i++) // xyz
4372                 {
4373                         vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i];
4374                         p->ctrl[w][h+1].xyz[i] = p->ctrl[w][h+1].xyz[i] + (vTemp[i] / 2);
4375
4376                         vTemp[i] = p->ctrl[w][h-2].xyz[i] - p->ctrl[w][h-1].xyz[i];
4377                         p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2);
4378
4379                         vTemp[i] = p->ctrl[w][h+1].xyz[i] - p->ctrl[w][h-1].xyz[i];
4380                         p->ctrl[w][h].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2);
4381                 }
4382                 for (i=0; i<2; i++) // st
4383                 {
4384                         stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i];
4385                         p->ctrl[w][h+1].st[i] = p->ctrl[w][h+1].st[i] + (stTemp[i] / 2);
4386
4387                         stTemp[i] = p->ctrl[w][h-2].st[i] - p->ctrl[w][h-1].st[i];
4388                         p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2);
4389
4390                         stTemp[i] = p->ctrl[w][h+1].st[i] - p->ctrl[w][h-1].st[i];
4391                         p->ctrl[w][h].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2);
4392                 }
4393         }
4394
4395         p->height += 2;
4396         // deselect all points to keep things neat
4397         if (g_qeglobals.d_select_mode == sel_curvepoint)
4398                 Patch_EditPatch();
4399
4400         UpdatePatchInspector();
4401 }
4402
4403 /*
4404 ==================
4405 Patch_RemoveRow
4406 ==================
4407 */
4408 void Patch_RemoveRow(patchMesh_t *p, bool bFirst)
4409 {
4410         int w, h, i, height;
4411         vec3_t vTemp;
4412         float stTemp[2];
4413         bool bExtrapolate = true;
4414
4415         if (p->height <= MIN_PATCH_HEIGHT)
4416                 return;
4417
4418         h = 0;
4419         for (w = 0; w < p->width; w++)
4420         {
4421                 for (h = 0; h < p->height; h+=2)
4422                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4423                                 break;
4424                 if (h < p->height)
4425                         break;
4426                 for (h = 1; h < p->height; h+=2)
4427                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4428                                 break;
4429                 if (h < p->height)
4430                         break;
4431         }
4432
4433         if (h >= p->height)
4434         {
4435                 bExtrapolate = false;
4436                 if (bFirst) h=p->height-3;
4437                 else h=2;
4438         }
4439         else if (h <= 0) h=2;
4440         else if (h > p->height-3) h = p->height-3;
4441         else if (h%2) h++;
4442
4443         p->height -= 2;
4444
4445         for (w = 0; w < p->width; w++)
4446         {
4447                 if (bExtrapolate)
4448                 {
4449                         for (i = 0; i < 3; i++) // xyz
4450                         {
4451                                 vTemp[i] = p->ctrl[w][h+2].xyz[i] - p->ctrl[w][h-2].xyz[i];
4452                                 p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-2].xyz[i] + (vTemp[i] / 2);
4453
4454                                 vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i];
4455                                 p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] * 2);
4456                         }
4457
4458                         for (i = 0; i < 2; i++) // st
4459                         {
4460                                 stTemp[i] = p->ctrl[w][h+2].st[i] - p->ctrl[w][h-2].st[i];
4461                                 p->ctrl[w][h-1].st[i] = p->ctrl[w][h-2].st[i] + (stTemp[i] / 2);
4462
4463                                 stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i];
4464                                 p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] * 2);
4465                         }
4466                 }
4467                 else
4468                 {
4469                         if (!bFirst)
4470                         continue;
4471                         else h=0;
4472                 }
4473                 for (height = h; height < p->height; height++)
4474                         memcpy(&p->ctrl[w][height], &p->ctrl[w][height+2], sizeof(drawVert_t));
4475         }
4476         // deselect all points to keep things neat
4477         if (g_qeglobals.d_select_mode == sel_curvepoint)
4478                 Patch_EditPatch();
4479
4480         UpdatePatchInspector();
4481 }
4482
4483 /*
4484 ==================
4485 Patch_RemoveColumn
4486 ==================
4487 */
4488 void Patch_RemoveColumn(patchMesh_t *p, bool bFirst)
4489 {
4490         int w, h, i, width;
4491         vec3_t vTemp;
4492         float stTemp[2];
4493         bool bExtrapolate = true;
4494
4495         if (p->width <= MIN_PATCH_WIDTH)
4496                 return;
4497
4498         w = 0;
4499         for (h = 0; h < p->height; h++)
4500         {
4501                 for (w = 0; w < p->width; w+=2)
4502                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4503                                 break;
4504                 if (w < p->width)
4505                         break;
4506                 for (w = 1; w < p->width; w+=2)
4507                         if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4508                                 break;
4509                 if (w < p->width)
4510                         break;
4511         }
4512
4513         if (w >= p->width)
4514         {
4515                 bExtrapolate = false;
4516                 if (bFirst) w=p->width-3;
4517                 else w=2;
4518         }
4519         else if (w<=0) w=2;
4520         else if (w > p->width-3) w = p->width-3;
4521         else if (w%2) w++;
4522
4523         p->width -= 2;
4524
4525         for (h = 0; h < p->height; h++)
4526         {
4527                 if (bExtrapolate)
4528                 {
4529                         for (i = 0; i < 3; i++) // xyz
4530                         {
4531                                 vTemp[i] = p->ctrl[w+2][h].xyz[i] - p->ctrl[w-2][h].xyz[i];
4532                                 p->ctrl[w-1][h].xyz[i] = p->ctrl[w-2][h].xyz[i] + (vTemp[i] / 2);
4533
4534                                 vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4535                                 p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] * 2);
4536                         }
4537
4538                         for (i = 0; i < 2; i++) // st
4539                         {
4540                                 stTemp[i] = p->ctrl[w+2][h].st[i] - p->ctrl[w-2][h].st[i];
4541                                 p->ctrl[w-1][h].st[i] = p->ctrl[w-2][h].st[i] + (stTemp[i] / 2);
4542
4543                                 stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i];
4544                                 p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] * 2);
4545                         }
4546                 }
4547                 else
4548                 {
4549                         if (!bFirst)
4550                         continue;
4551                         else w=0;
4552                 }
4553
4554                 for (width = w; width < p->width; width++)
4555                         memcpy(&p->ctrl[width][h], &p->ctrl[width+2][h], sizeof(drawVert_t));
4556         }
4557         // deselect all points to keep things neat
4558         if (g_qeglobals.d_select_mode == sel_curvepoint)
4559                 Patch_EditPatch();
4560
4561         UpdatePatchInspector();
4562 }
4563
4564 /*
4565 ==================
4566 Patch_AdjustColumns
4567 ==================
4568 */
4569 /*
4570 void Patch_AdjustColumns(patchMesh_t *p, int nCols)
4571 {
4572   vec3_t vTemp, vTemp2;
4573   int i, w, h;
4574
4575   if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH)
4576     return;
4577
4578   // add in column adjustment
4579   p->width += nCols;
4580
4581   for (h = 0; h < p->height; h++)
4582   {
4583     // for each column, we need to evenly disperse p->width number
4584     // of points across the old bounds
4585
4586     // calc total distance to interpolate
4587     VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp);
4588
4589     // amount per cycle
4590     for (i = 0; i < 3; i ++)
4591     {
4592       vTemp2[i] = vTemp[i] / (p->width - 1);
4593     }
4594
4595     // move along
4596     for (w = 0; w < p->width-1; w++)
4597     {
4598       VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
4599     }
4600
4601   }
4602         for ( w = 0 ; w < p->width ; w++ )
4603   {
4604                 for ( h = 0 ; h < p->height ; h++ )
4605     {
4606                         p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
4607                         p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
4608                 }
4609         }
4610   UpdatePatchInspector();
4611 }
4612 */
4613
4614 /*
4615 ==================
4616 Patch_AdjustRows
4617 ==================
4618 */
4619 /*
4620 void Patch_AdjustRows(patchMesh_t *p, int nRows)
4621 {
4622   vec3_t vTemp, vTemp2;
4623   int i, w, h;
4624
4625   if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT)
4626     return;
4627
4628   // add in column adjustment
4629   p->height += nRows;
4630
4631   for (w = 0; w < p->width; w++)
4632   {
4633     // for each row, we need to evenly disperse p->height number
4634     // of points across the old bounds
4635
4636     // calc total distance to interpolate
4637     VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp);
4638
4639     //vTemp[0] = vTemp[1] = vTemp[2] = 0;
4640     //for (h = 0; h < p->height - nRows; h ++)
4641     //{
4642     //  VectorAdd(vTemp, p->ctrl[w][h], vTemp);
4643     //}
4644
4645     // amount per cycle
4646     for (i = 0; i < 3; i ++)
4647     {
4648       vTemp2[i] = vTemp[i] / (p->height - 1);
4649     }
4650
4651     // move along
4652     for (h = 0; h < p->height-1; h++)
4653     {
4654       VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
4655     }
4656
4657   }
4658         for ( w = 0 ; w < p->width ; w++ )
4659   {
4660                 for ( h = 0 ; h < p->height ; h++ )
4661     {
4662                         p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
4663                         p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
4664                 }
4665         }
4666   UpdatePatchInspector();
4667 }
4668 */
4669
4670 /*
4671 ==================
4672 Patch_DisperseRows
4673 ==================
4674 */
4675
4676 void Patch_DisperseRows()
4677 {
4678         vec3_t vTemp, vTemp2;
4679         int i, w, h;
4680
4681
4682         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4683         {
4684      if (pb->patchBrush)
4685      {
4686        patchMesh_t *p = pb->pPatch;
4687        Patch_Rebuild(p);
4688        for (w = 0; w < p->width; w++)
4689        {
4690          // for each row, we need to evenly disperse p->height number
4691          // of points across the old bounds
4692
4693          // calc total distance to interpolate
4694          VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp);
4695
4696          //vTemp[0] = vTemp[1] = vTemp[2] = 0;
4697          //for (h = 0; h < p->height - nRows; h ++)
4698          //{
4699          //  VectorAdd(vTemp, p->ctrl[w][h], vTemp);
4700          //}
4701
4702          // amount per cycle
4703          for (i = 0; i < 3; i ++)
4704          {
4705            vTemp2[i] = vTemp[i] / (p->height - 1);
4706          }
4707
4708          // move along
4709          for (h = 0; h < p->height-1; h++)
4710          {
4711            VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
4712          }
4713          Patch_Naturalize(p);
4714
4715        }
4716      }
4717    }
4718                 UpdatePatchInspector();
4719 }
4720
4721 /*
4722 ==================
4723 Patch_DisperseIntermediateRows
4724 ==================
4725 */
4726
4727 void Patch_DisperseIntermediateRows()
4728 {
4729         vec3_t vTemp, vTemp2;
4730         int i, w, h;
4731
4732
4733         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4734         {
4735                 if (pb->patchBrush)
4736                 {
4737                         patchMesh_t *p = pb->pPatch;
4738                         Patch_Rebuild(p);
4739                         for (w = 0; w < p->width; w++)
4740                         {
4741                                 // move along
4742                                 for (h = 0; h < p->height; h+=2)
4743                                 {
4744                                         // calc distance to interpolate
4745                                         VectorSubtract(p->ctrl[w][h+2].xyz, p->ctrl[w][h].xyz, vTemp);
4746
4747                                         // halve distance
4748                                         for (i = 0; i < 3; i ++)
4749                                         {
4750                                                 vTemp2[i] = vTemp[i] / 2;
4751                                         }
4752
4753                                         // move control points
4754                                         VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
4755                                 }
4756                         }
4757                 }
4758         }
4759         UpdatePatchInspector();
4760 }
4761
4762 /*
4763 ==================
4764 Patch_DisperseIntermediateColumns
4765 ==================
4766 */
4767 void Patch_DisperseIntermediateColumns()
4768 {
4769         vec3_t vTemp, vTemp2;
4770         int i, w, h;
4771
4772
4773         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4774         {
4775                 if (pb->patchBrush)
4776                 {
4777                         patchMesh_t *p = pb->pPatch;
4778                         Patch_Rebuild(p);
4779                         for (h = 0; h < p->height; h++)
4780                         {
4781                                         // move along
4782                                 for (w = 0; w < p->width; w+=2)
4783                                 {
4784                                         // calc distance to interpolate
4785                                         VectorSubtract(p->ctrl[w+2][h].xyz, p->ctrl[w][h].xyz, vTemp);
4786
4787                                         // halve distance
4788                                         for (i = 0; i < 3; i ++)
4789                                         {
4790                                                 vTemp2[i] = vTemp[i] / 2;
4791                                         }
4792
4793                                         // move control points
4794                                         VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
4795                                 }
4796                         }
4797                 }
4798         }
4799         UpdatePatchInspector();
4800 }
4801
4802
4803
4804 /*
4805 ==================
4806 Patch_AdjustSelected
4807 ==================
4808 */
4809 void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag)
4810 {
4811   bool bUpdate = false;
4812         for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4813         {
4814     if (pb->patchBrush)
4815     {
4816       if (bInsert)
4817       {
4818         if (bColumn)
4819         {
4820           Patch_InsertColumn(pb->pPatch, bFlag);
4821         }
4822         else
4823         {
4824           Patch_InsertRow(pb->pPatch, bFlag);
4825         }
4826       }
4827       else
4828       {
4829         if (bColumn)
4830         {
4831           Patch_RemoveColumn(pb->pPatch, bFlag);
4832         }
4833         else
4834         {
4835           Patch_RemoveRow(pb->pPatch, bFlag);
4836         }
4837       }
4838       bUpdate = true;
4839       vec3_t vMin, vMax;
4840       patchMesh_t *p = pb->pPatch;
4841       Patch_CalcBounds(p, vMin, vMax);
4842       Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
4843       pb->pPatch->bDirty = true; // rebuild LOD trees and their normals
4844     }
4845   }
4846   if (bUpdate)
4847   {
4848     Sys_UpdateWindows(W_ALL);
4849   }
4850 }
4851
4852
4853 /*
4854 ==================
4855 Patch_AdjustSelectedRowCols
4856 ==================
4857 */
4858 /*
4859 void Patch_AdjustSelectedRowCols(int nRows, int nCols)
4860 {
4861         for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4862         {
4863     if (pb->patchBrush)
4864     {
4865       Patch_InsertColumn(pb->pPatch, false);
4866       if (nRows != 0)
4867       {
4868         Patch_AdjustRows(pb->pPatch, nRows);
4869       }
4870
4871       if (nCols != 0)
4872       {
4873         Patch_AdjustColumns(pb->pPatch, nCols);
4874       }
4875                 }
4876   }
4877   UpdatePatchInspector();
4878 }
4879 */
4880
4881 /*
4882 =================
4883 CheckName
4884 temporary stuff, detect potential problems when saving the texture name
4885 will correct the patch on the fly if problem detected
4886 =================
4887 */
4888 /*!
4889 \todo performance issue with CheckName calls
4890 don't call this too much, only when absolutely necessary
4891 strategies that call here too much are known to be slow
4892 patch 84 to bug 253 adds an additionnal check for textures/
4893 */
4894 void CheckName( patchMesh_t *p, char *pname )
4895 {
4896   if(strncmp(p->pShader->getName(), "textures/", 9) != 0)
4897     p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND);
4898
4899         // some manage to get long filename textures (with spaces) in their maps
4900         if (strchr( p->pShader->getName(), ' ' ))
4901         {
4902                 char Msg1[1024];
4903                 sprintf( Msg1, "Can't save texture with spaces in name. Rename %s\nNOTE: This message may popup several times .. once for each buggy face detected.", p->pShader->getName() );
4904                 Sys_Printf("%s\n", Msg1 );
4905                 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
4906                 strcpy( pname, SHADER_NOT_FOUND );
4907                 p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND);
4908     p->d_texture = p->pShader->getTexture();
4909                 return;
4910         }
4911         strcpy( pname, p->pShader->getName()+9 ); // remove "textures/"
4912 }
4913
4914 /*
4915 ==================
4916 Patch_Write
4917 ==================
4918 */
4919 void Patch_Write (patchMesh_t *p, MemStream *file)
4920 {
4921   char pname[1024];
4922
4923   MemFile_fprintf(file, " {\n  patchDef2\n  {\n");
4924
4925   CheckName( p, pname );
4926   MemFile_fprintf(file, "   %s\n", pname );
4927   MemFile_fprintf(file, "   ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
4928
4929
4930         float           ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
4931
4932   int w, h;
4933   for (w = 0; w < p->width; w++)
4934   {
4935     for (h = 0; h < p->height; h++)
4936     {
4937       ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
4938       ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
4939       ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
4940       ctrl[w][h][3] = p->ctrl[w][h].st[0];
4941       ctrl[w][h][4] = p->ctrl[w][h].st[1];
4942     }
4943   }
4944
4945   _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
4946
4947         if (g_qeglobals.m_bBrushPrimitMode)
4948   {
4949           if (p->epairs)
4950     {
4951                         for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
4952       {
4953                                 MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
4954       }
4955     }
4956   }
4957
4958   MemFile_fprintf(file, "  }\n }\n");
4959 }
4960
4961 void Patch_Write (patchMesh_t *p, FILE *file)
4962 {
4963   char pname[1024];
4964
4965         fprintf(file, " {\n  patchDef2\n  {\n");
4966   {
4967           CheckName( p, pname );
4968           fprintf(file, "   %s\n", pname );
4969           fprintf(file, "   ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
4970         }
4971
4972         float           ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
4973
4974   int w, h;
4975   for (w = 0; w < p->width; w++)
4976   {
4977     for (h = 0; h < p->height; h++)
4978     {
4979       ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
4980       ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
4981       ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
4982       ctrl[w][h][3] = p->ctrl[w][h].st[0];
4983       ctrl[w][h][4] = p->ctrl[w][h].st[1];
4984     }
4985   }
4986
4987   _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
4988
4989         if (g_qeglobals.m_bBrushPrimitMode)
4990   {
4991           if (p->epairs)
4992     {
4993                         for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
4994       {
4995                                 fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
4996       }
4997     }
4998   }
4999
5000   fprintf(file, "  }\n }\n");
5001 }
5002
5003
5004 /*
5005 ==================
5006 Patch_RotateTexture
5007 ==================
5008 */
5009 void Patch_RotateTexture(patchMesh_t *p, float fAngle)
5010 {
5011   p->bDirty = true;
5012   float c = cos(fAngle * Q_PI / 180);
5013   float s = sin(fAngle * Q_PI / 180);
5014
5015   Patch_TransformLODTexture(p, c, s, ROTATE);
5016
5017   for (int w = 0; w < p->width; w++)
5018   {
5019     for (int h = 0; h < p->height; h++)
5020     {
5021       //if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
5022       //  continue;
5023
5024       float x = p->ctrl[w][h].st[0];
5025       float y = p->ctrl[w][h].st[1];
5026       p->ctrl[w][h].st[0] = x * c - y * s;
5027       p->ctrl[w][h].st[1] = y * c + x * s;
5028     }
5029   }
5030 }
5031
5032
5033 /*
5034 ==================
5035 Patch_ScaleTexture
5036 ==================
5037 */
5038 void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup)
5039 {
5040   // FIXME:
5041   // this hack turns scales into 1.1 or 0.9
5042   if (bFixup)
5043   {
5044     fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10;
5045     fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10;
5046   }
5047   else
5048   {
5049     if (fx == 0)
5050       fx = 1.0;
5051     if (fy == 0)
5052       fy = 1.0;
5053   }
5054
5055   for (int w = 0; w < p->width; w++)
5056   {
5057     for (int h = 0; h < p->height; h++)
5058     {
5059       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
5060         continue;
5061
5062       p->ctrl[w][h].st[0] *= fx;
5063       p->ctrl[w][h].st[1] *= fy;
5064     }
5065   }
5066   if (g_qeglobals.d_select_mode == sel_curvepoint)
5067   {
5068           p->bDirty = true;
5069           Patch_LODMatchAll();
5070   }
5071   else
5072   {
5073     Patch_TransformLODTexture(p, fx, fy, SCALE);
5074           p->LODUpdated = true;
5075   }
5076 }
5077
5078
5079 /*
5080 ==================
5081 Patch_ShiftTexture
5082 shift a texture given a pixel count
5083 ==================
5084 */
5085 void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy)
5086 {
5087         qtexture_t *pTex;
5088         pTex = p->pShader->getTexture();
5089         fx = -1 * fx / pTex->width;
5090         fy = fy / pTex->height;
5091         Patch_ShiftTextureST(p, fx, fy);
5092 }
5093
5094 /*
5095 ====================
5096 Patch_ShiftTextureST
5097 shift a patch texture given an ST increment
5098 ====================
5099 */
5100 void Patch_ShiftTextureST(patchMesh_t *p, float fx, float fy)
5101 {
5102 #ifdef _DEBUG
5103         // NOTE: when called by Patch_ShiftTexture this warning may be bogus
5104         if ((ABS(fx) >= 1) || (ABS(fy) >= 1))
5105                 Sys_Printf("WARNING: increments exceed 1 in Patch_ShiftTextureST\n");
5106 #endif
5107   for (int w = 0; w < p->width; w++)
5108   {
5109     for (int h = 0; h < p->height; h++)
5110     {
5111       if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
5112         continue;
5113
5114       p->ctrl[w][h].st[0] += fx;
5115       p->ctrl[w][h].st[1] += fy;
5116     }
5117   }
5118   if (g_qeglobals.d_select_mode == sel_curvepoint)
5119   {
5120           p->bDirty = true;
5121           Patch_LODMatchAll();
5122   }
5123   else
5124   {
5125           Patch_TransformLODTexture(p, fx, fy, TRANSLATE);
5126           p->LODUpdated = true;
5127   }
5128 }
5129
5130 /*
5131 ==================
5132 Patch_ToggleInverted
5133 ==================
5134 */
5135 void Patch_ToggleInverted()
5136 {
5137   bool bUpdate = false;
5138
5139         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5140         {
5141     if (pb->patchBrush)
5142     {
5143       bUpdate = true;
5144       patchInvert(pb->pPatch);
5145     }
5146   }
5147
5148   if (bUpdate)
5149   {
5150     Sys_UpdateWindows(W_ALL);
5151   }
5152   UpdatePatchInspector();
5153 }
5154
5155 /*
5156 ==================
5157 Patch_ToggleInverted
5158 ==================
5159 */
5160 void Patch_InvertTexture(bool bY)
5161 {
5162   bool bUpdate = false;
5163
5164   float fTemp[2];
5165         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5166         {
5167     if (pb->patchBrush)
5168     {
5169       bUpdate = true;
5170       patchMesh_t *p = pb->pPatch;
5171       p->bDirty = true;
5172       if (bY)
5173       {
5174               for ( int i = 0 ; i < p->height ; i++ )
5175         {
5176           for (int j = 0; j < p->width / 2; j++)
5177           {
5178             memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2]));
5179             memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2]));
5180             memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2]));
5181                       }
5182               }
5183       }
5184       else
5185       {
5186               for ( int i = 0 ; i < p->width ; i++ )
5187         {
5188           for (int j = 0; j < p->height / 2; j++)
5189           {
5190             memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2]));
5191             memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2]));
5192             memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2]));
5193                       }
5194               }
5195       }
5196     }
5197   }
5198
5199   if (bUpdate)
5200   {
5201     Sys_UpdateWindows(W_ALL);
5202   }
5203   UpdatePatchInspector();
5204 }
5205
5206
5207
5208
5209 /*
5210 ==================
5211 Patch_Save
5212 ==================
5213  Saves patch ctrl info (originally to deal with a
5214  cancel in the surface dialog
5215 */
5216 void Patch_Save(patchMesh_t *p)
5217 {
5218   patchSave.width = p->width;
5219   patchSave.height = p->height;
5220   memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl));
5221 }
5222
5223
5224 /*
5225 ==================
5226 Patch_Restore
5227 ==================
5228 */
5229 void Patch_Restore(patchMesh_t *p)
5230 {
5231   p->width = patchSave.width;
5232   p->height = patchSave.height;
5233   memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl));
5234 }
5235
5236 void Patch_ResetTexturing(float fx, float fy)
5237 {
5238         for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5239         {
5240     if (pb->patchBrush)
5241     {
5242       patchMesh_t *p = pb->pPatch;
5243       p->bDirty = true;
5244             for ( int i = 0 ; i < p->width ; i++ )
5245       {
5246                     for ( int j = 0 ; j < p->height ; j++ )
5247         {
5248                             p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1);
5249                             p->ctrl[i][j].st[1] = 1 - fy * (float)j / (p->height - 1);
5250                     }
5251             }
5252     }
5253   }
5254 }
5255
5256 // NOTE TTimo stub!
5257 void Patch_FitTexturing()
5258 {
5259   Patch_ResetTexturing(1.0f, 1.0f);
5260 }
5261
5262 void Patch_SetTextureInfo(texdef_t *pt)
5263 {
5264         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5265         {
5266     if (pb->patchBrush)
5267     {
5268       if (pt->rotate)
5269         Patch_RotateTexture(pb->pPatch, pt->rotate);
5270
5271       if (pt->shift[0] || pt->shift[1])
5272         Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]);
5273
5274       if (pt->scale[0] || pt->scale[1])
5275         Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false);
5276
5277       patchMesh_t *p = pb->pPatch;
5278       p->contents = pt->contents;
5279       p->flags = pt->flags;
5280       p->value = pt->value;
5281     }
5282   }
5283 }
5284
5285 bool OnlyPatchesSelected()
5286 {
5287   if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
5288     return false;
5289         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5290         {
5291     if (!pb->patchBrush)
5292     {
5293       return false;
5294     }
5295   }
5296   return true;
5297 }
5298
5299 bool AnyPatchesSelected()
5300 {
5301   if (g_ptrSelectedFaces.GetSize() > 0  || selected_brushes.next == &selected_brushes)
5302     return false;
5303         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5304         {
5305     if (pb->patchBrush)
5306     {
5307       return true;
5308     }
5309   }
5310   return false;
5311 }
5312
5313 patchMesh_t* SinglePatchSelected()
5314 {
5315   if (selected_brushes.next->patchBrush)
5316   {
5317     return selected_brushes.next->pPatch;
5318   }
5319   return NULL;
5320 }
5321
5322 void Patch_BendToggle()
5323 {
5324   if (g_bPatchBendMode)
5325   {
5326     g_bPatchBendMode = false;
5327     HideInfoDialog();
5328     g_pParentWnd->UpdatePatchToolbarButtons() ;
5329     return;
5330   }
5331
5332         brush_t* b = selected_brushes.next;
5333
5334   if (!QE_SingleBrush(true) || !b->patchBrush)
5335   {
5336     Sys_Printf("Patch_BendToggle: you must have a single patch selected\n");
5337                 return;
5338   }
5339
5340   Patch_Save(b->pPatch);
5341         g_bPatchBendMode = true;
5342   g_nPatchBendState = BEND_SELECT_ROTATION;
5343   g_bPatchAxisOnRow = true;
5344   g_nPatchAxisIndex = 1;
5345   ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]);
5346 }
5347
5348 void Patch_BendHandleTAB()
5349 {
5350   if (!g_bPatchBendMode)
5351   {
5352     return;
5353   }
5354
5355         brush_t* b = selected_brushes.next;
5356   if (!QE_SingleBrush() || !b->patchBrush)
5357   {
5358     Patch_BendToggle();
5359     Sys_Printf("No patch to bend!");
5360                 return;
5361   }
5362
5363   patchMesh_t *p = b->pPatch;
5364
5365   bool bShift = Sys_ShiftDown ();
5366
5367   if (g_nPatchBendState == BEND_SELECT_ROTATION)
5368   {
5369     // only able to deal with odd numbered rows/cols
5370     g_nPatchAxisIndex += (bShift) ? -2 : 2;
5371     if (g_bPatchAxisOnRow)
5372     {
5373       if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height)
5374       {
5375         g_bPatchAxisOnRow = false;
5376         g_nPatchAxisIndex = (bShift) ? p->width-1 : 1;
5377       }
5378     }
5379     else
5380     {
5381       if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width)
5382       {
5383         g_bPatchAxisOnRow = true;
5384         g_nPatchAxisIndex = (bShift) ? p->height-1 : 1;
5385       }
5386     }
5387   }
5388   else
5389   if (g_nPatchBendState == BEND_SELECT_ORIGIN)
5390   {
5391     g_nBendOriginIndex += (bShift) ? -1 : 1;
5392     if (g_bPatchAxisOnRow)
5393     {
5394       if (bShift)
5395       {
5396         if (g_nBendOriginIndex < 0)
5397           g_nBendOriginIndex = p->width-1;
5398       }
5399       else
5400       {
5401         if (g_nBendOriginIndex > p->width-1)
5402           g_nBendOriginIndex = 0;
5403       }
5404       VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin);
5405     }
5406     else
5407     {
5408       if (bShift)
5409       {
5410         if (g_nBendOriginIndex < 0)
5411           g_nBendOriginIndex = p->height-1;
5412       }
5413       else
5414       {
5415         if (g_nBendOriginIndex > p->height-1)
5416           g_nBendOriginIndex = 0;
5417       }
5418       VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin);
5419     }
5420   }
5421   else
5422   if (g_nPatchBendState == BEND_SELECT_EDGE)
5423   {
5424     g_bPatchLowerEdge ^= 1;
5425   }
5426   Sys_UpdateWindows(W_ALL);
5427 }
5428
5429 void Patch_BendHandleENTER()
5430 {
5431   if (!g_bPatchBendMode)
5432   {
5433     return;
5434   }
5435
5436   if (g_nPatchBendState  < BEND_BENDIT)
5437   {
5438     g_nPatchBendState++;
5439     ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]);
5440     if (g_nPatchBendState == BEND_SELECT_ORIGIN)
5441     {
5442       g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0;
5443       g_nBendOriginIndex = 0;
5444       Patch_BendHandleTAB();
5445     }
5446     else
5447     if (g_nPatchBendState == BEND_SELECT_EDGE)
5448     {
5449       g_bPatchLowerEdge = true;
5450     }
5451     else
5452     if (g_nPatchBendState == BEND_BENDIT)
5453     {
5454       // basically we go into rotation mode, set the axis to the center of the
5455     }
5456   }
5457   else
5458   {
5459     // done
5460     Patch_BendToggle();
5461   }
5462   Sys_UpdateWindows(W_ALL);
5463
5464 }
5465
5466
5467 void Patch_BendHandleESC()
5468 {
5469   if (!g_bPatchBendMode)
5470   {
5471     return;
5472   }
5473   Patch_BendToggle();
5474         brush_t* b = selected_brushes.next;
5475   if (QE_SingleBrush() && b->patchBrush)
5476   {
5477     Patch_Restore(b->pPatch);
5478   }
5479   Sys_UpdateWindows(W_ALL);
5480 }
5481
5482 void Patch_SetBendRotateOrigin(patchMesh_t *p)
5483 {
5484 #if 1
5485   int nType = g_pParentWnd->ActiveXY()->GetViewType();
5486   int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1;
5487
5488   g_vBendOrigin[nDim3] = 0;
5489   VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin());
5490   return;
5491 #else
5492   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
5493   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
5494
5495   float fxLo, fyLo, fxHi, fyHi;
5496   fxLo = fyLo = 9999;
5497   fxHi = fyHi = -9999;
5498
5499   if (g_bPatchAxisOnRow)
5500   {
5501     for (int i = 0; i < p->width; i++)
5502     {
5503       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo)
5504         fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
5505
5506       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi)
5507         fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
5508
5509       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo)
5510         fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
5511
5512       if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi)
5513         fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
5514     }
5515   }
5516   else
5517   {
5518     for (int i = 0; i < p->height; i++)
5519     {
5520       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo)
5521         fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
5522
5523       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi)
5524         fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
5525
5526       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo)
5527         fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
5528
5529       if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi)
5530         fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
5531     }
5532   }
5533
5534   g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0;
5535   g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5;
5536   g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5;
5537 #endif
5538 }
5539
5540 // also sets the rotational origin
5541 void Patch_SelectBendAxis()
5542 {
5543         brush_t* b = selected_brushes.next;
5544   if (!QE_SingleBrush() || !b->patchBrush)
5545   {
5546     // should not ever happen
5547     Patch_BendToggle();
5548                 return;
5549   }
5550
5551   patchMesh_t *p = b->pPatch;
5552   if (g_bPatchAxisOnRow)
5553   {
5554     SelectRow(p, g_nPatchAxisIndex, false);
5555   }
5556   else
5557   {
5558     SelectColumn(p, g_nPatchAxisIndex, false);
5559   }
5560
5561   //FIXME: this only needs to be set once...
5562   Patch_SetBendRotateOrigin(p);
5563
5564 }
5565
5566 void Patch_SelectBendNormal()
5567 {
5568         brush_t* b = selected_brushes.next;
5569   if (!QE_SingleBrush() || !b->patchBrush)
5570   {
5571     // should not ever happen
5572     Patch_BendToggle();
5573                 return;
5574   }
5575
5576   patchMesh_t *p = b->pPatch;
5577
5578   g_qeglobals.d_num_move_points = 0;
5579   if (g_bPatchAxisOnRow)
5580   {
5581     if (g_bPatchLowerEdge)
5582     {
5583       for (int j = 0; j < g_nPatchAxisIndex; j++)
5584         SelectRow(p, j, true);
5585     }
5586     else
5587     {
5588       for (int j = p->height-1; j > g_nPatchAxisIndex; j--)
5589         SelectRow(p, j, true);
5590     }
5591   }
5592   else
5593   {
5594     if (g_bPatchLowerEdge)
5595     {
5596       for (int j = 0; j < g_nPatchAxisIndex; j++)
5597         SelectColumn(p, j, true);
5598     }
5599     else
5600     {
5601       for (int j = p->width-1; j > g_nPatchAxisIndex; j--)
5602         SelectColumn(p, j, true);
5603     }
5604   }
5605   Patch_SetBendRotateOrigin(p);
5606 }
5607
5608
5609
5610 /*
5611 void Patch_InsDelToggle()
5612 {
5613   if (g_bPatchInsertMode)
5614   {
5615     g_bPatchInsertMode = false;
5616     HideInfoDialog();
5617     g_pParentWnd->UpdatePatchToolbarButtons() ;
5618     return;
5619   }
5620
5621         brush_t* b = selected_brushes.next;
5622
5623   if (!QE_SingleBrush(true) || !b->patchBrush)
5624   {
5625     Sys_Printf("Patch_InsDelToggle: you must have a single patch selected\n");
5626                 return;
5627   }
5628
5629   Patch_Save(b->pPatch);
5630         g_bPatchInsertMode = true;
5631   g_nPatchInsertState = INSERT_SELECT_EDGE;
5632   g_bPatchAxisOnRow = true;
5633   g_nPatchAxisIndex = 0;
5634   ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]);
5635
5636 }
5637
5638 void Patch_InsDelESC()
5639 {
5640   if (!g_bPatchInsertMode)
5641   {
5642     return;
5643   }
5644   Patch_InsDelToggle();
5645   Sys_UpdateWindows(W_ALL);
5646 }
5647
5648
5649 void Patch_InsDelHandleENTER()
5650 {
5651 }
5652
5653 void Patch_InsDelHandleTAB()
5654 {
5655   if (!g_bPatchInsertMode)
5656   {
5657     Patch_InsDelToggle();
5658     return;
5659   }
5660
5661         brush_t* b = selected_brushes.next;
5662   if (!QE_SingleBrush() || !b->patchBrush)
5663   {
5664     Patch_BendToggle();
5665     Sys_Printf("No patch to bend!");
5666                 return;
5667   }
5668
5669   patchMesh_t *p = b->pPatch;
5670
5671   // only able to deal with odd numbered rows/cols
5672   g_nPatchAxisIndex += 2;
5673   if (g_bPatchAxisOnRow)
5674   {
5675     if (g_nPatchAxisIndex >= p->height-1)
5676     {
5677       g_bPatchAxisOnRow = false;
5678       g_nPatchAxisIndex = 0;
5679     }
5680   }
5681   else
5682   {
5683     if (g_nPatchAxisIndex >= p->width-1)
5684     {
5685       g_bPatchAxisOnRow = true;
5686       g_nPatchAxisIndex = 0;
5687     }
5688   }
5689   Sys_UpdateWindows(W_ALL);
5690 }
5691 */
5692
5693
5694 void _Write1DMatrix (FILE *f, int x, float *m) {
5695         int             i;
5696
5697         fprintf (f, "( ");
5698         for (i = 0 ; i < x ; i++) {
5699                 if (m[i] == (int)m[i] ) {
5700                         fprintf (f, "%i ", (int)m[i]);
5701                 } else {
5702                         fprintf (f, "%f ", m[i]);
5703                 }
5704         }
5705         fprintf (f, ")");
5706 }
5707
5708 void _Write2DMatrix (FILE *f, int y, int x, float *m) {
5709         int             i;
5710
5711         fprintf (f, "( ");
5712         for (i = 0 ; i < y ; i++) {
5713                 _Write1DMatrix (f, x, m + i*x);
5714                 fprintf (f, " ");
5715         }
5716         fprintf (f, ")\n");
5717 }
5718
5719
5720 void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) {
5721         int             i;
5722
5723         fprintf (f, "(\n");
5724         for (i = 0 ; i < z ; i++) {
5725                 _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
5726         }
5727         fprintf (f, ")\n");
5728 }
5729
5730 void _Write1DMatrix (MemStream *f, int x, float *m) {
5731         int             i;
5732
5733         MemFile_fprintf (f, "( ");
5734         for (i = 0 ; i < x ; i++) {
5735                 if (m[i] == (int)m[i] ) {
5736                         MemFile_fprintf (f, "%i ", (int)m[i]);
5737                 } else {
5738                         MemFile_fprintf (f, "%f ", m[i]);
5739                 }
5740         }
5741         MemFile_fprintf (f, ")");
5742 }
5743
5744 void _Write2DMatrix (MemStream *f, int y, int x, float *m) {
5745         int             i;
5746
5747         MemFile_fprintf (f, "( ");
5748         for (i = 0 ; i < y ; i++) {
5749                 _Write1DMatrix (f, x, m + i*x);
5750                 MemFile_fprintf (f, " ");
5751         }
5752         MemFile_fprintf (f, ")\n");
5753 }
5754
5755
5756 void _Write3DMatrix (MemStream *f, int z, int y, int x, float *m) {
5757         int             i;
5758
5759         MemFile_fprintf (f, "(\n");
5760         for (i = 0 ; i < z ; i++) {
5761                 _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
5762         }
5763         MemFile_fprintf (f, ")\n");
5764 }
5765
5766 // NOTE: why the hell is this called Naturalize?
5767 // we dispatch either to Patch+Naturalize or Patch_CapTexture..
5768 void Patch_NaturalizeSelected(bool bCap)
5769 {
5770         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5771         {
5772     if (pb->patchBrush)
5773     {
5774       if (bCap)
5775         Patch_CapTexture(pb->pPatch);//, bCycleCap);
5776       else
5777         Patch_Naturalize(pb->pPatch);
5778     }
5779   }
5780 }
5781
5782 // go through the selected patches and call Patch_CapTexture
5783 // deal with cycling
5784 void Patch_CycleCapSelected()
5785 {
5786   // compute the g_vCycleCapNormal according to g_nCycleCapIndex
5787   VectorClear (g_vCycleCapNormal);
5788   g_vCycleCapNormal[g_nCycleCapIndex] = 1.0f; // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY};
5789         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5790         {
5791     if (pb->patchBrush)
5792     {
5793       Patch_CapTexture(pb->pPatch, true);
5794     }
5795   }
5796   switch (g_nCycleCapIndex)
5797   {
5798   case YZ:
5799     g_nCycleCapIndex = XZ;
5800     break;
5801   case XZ:
5802     g_nCycleCapIndex = XY;
5803     break;
5804   case XY:
5805     g_nCycleCapIndex = YZ;
5806     break;
5807   }
5808 }
5809
5810 bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR)
5811 {
5812   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
5813   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
5814   if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) ||
5815       (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1]))
5816   {
5817     if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) ||
5818         (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2]))
5819       return true;
5820   }
5821   return false;
5822 }
5823
5824
5825 void Patch_SelectAreaPoints(bool bMulti)
5826 {
5827   if (!bMulti)
5828     g_qeglobals.d_num_move_points = 0;
5829
5830   if( g_nPatchClickedView == W_CAMERA ) {
5831     // Clip against a pyramid
5832     // Create our 5 normals (that are pointing to the inside)
5833     camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
5834     vec3_t      norm[5];
5835     float               r[2], u[2], hh, hw;
5836     int                 idx;
5837     vec_t               corners[2][2];
5838     vec3_t      ray[4];
5839     vec3_t  check;
5840
5841     VectorCopy( m_pCamera->vpn, norm[0] ); // only points in front of the camera
5842
5843     // get our rectangle
5844     corners[0][0] = MIN( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] );
5845     corners[0][1] = MAX( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] );
5846     corners[1][0] = MAX( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] );
5847     corners[1][1] = MIN( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] );
5848
5849     // calculate our four ray vectors
5850     hh = m_pCamera->height/2;
5851     hw = m_pCamera->width/2;
5852     u[0] = (float)(corners[0][1] - hh) / (hw);
5853     r[0] = (float)(corners[0][0] - hw) / (hw);
5854     u[1] = (float)(corners[1][1] - hh) / (hw);
5855     r[1] = (float)(corners[1][0] - hw) / (hw);
5856
5857     for (idx=0 ; idx<3; idx++)
5858             ray[0][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[0];
5859     for (idx=0 ; idx<3; idx++)
5860             ray[1][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[0];
5861     for (idx=0 ; idx<3; idx++)
5862             ray[2][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[1];
5863     for (idx=0 ; idx<3; idx++)
5864             ray[3][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[1];
5865
5866     // Create our four other directions from these
5867     CrossProduct( ray[0], ray[1], norm[1] ); VectorNormalize( norm[1], norm[1] );
5868     CrossProduct( ray[1], ray[2], norm[2] ); VectorNormalize( norm[2], norm[2] );
5869     CrossProduct( ray[2], ray[3], norm[3] ); VectorNormalize( norm[3], norm[3] );
5870     CrossProduct( ray[3], ray[0], norm[4] ); VectorNormalize( norm[4], norm[4] );
5871
5872                 // 3D clipping
5873                 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5874                 {
5875                         if (pb->patchBrush)
5876                         {
5877                                 patchMesh_t *p = pb->pPatch;
5878                                 for (int i = 0; i < p->width; i++)
5879                                 {
5880                                         for (int j = 0; j < p->height; j++)
5881                                         {
5882                                                 VectorSubtract( m_pCamera->origin, p->ctrl[i][j].xyz, check );
5883                                                 VectorNormalize( check, check );
5884                                                 for (idx=0 ; idx<5; idx++)
5885                                                 {
5886                                                         if (DotProduct(check, norm[idx])>=0)
5887                                                                 break;
5888                                                 }
5889                                                 if (idx == 5) // all test were good
5890             {
5891                                                         if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1)
5892                                                                 RemovePointFromMoveList(p->ctrl[i][j].xyz);
5893               else
5894                                                           g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
5895             }
5896                                         }
5897                                 }
5898                         }
5899                 }
5900         } else
5901         {
5902                 // Simple 2D clipping
5903                 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5904                 {
5905                         if (pb->patchBrush)
5906                         {
5907                                 patchMesh_t *p = pb->pPatch;
5908                                 for (int i = 0; i < p->width; i++)
5909                                 {
5910                                         for (int j = 0; j < p->height; j++)
5911                                         {
5912                                                 if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR))
5913                                                 {
5914                                                         if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1)
5915                                                                 RemovePointFromMoveList(p->ctrl[i][j].xyz);
5916                                                         else
5917                                                                 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
5918                                                 }
5919                                         }
5920                                 }
5921                         }
5922                 }
5923         }
5924
5925         g_nPatchClickedView = -1;
5926 }
5927
5928 // TTimo: return the shader name for a patch
5929 const char* Patch_GetTextureName()
5930 {
5931         brush_t* b = selected_brushes.next;
5932   if (b->patchBrush)
5933   {
5934     patchMesh_t *p = b->pPatch;
5935     return p->pShader->getName();
5936   }
5937   return "";
5938 }
5939
5940 patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom)
5941 {
5942   patchMesh_t* p = MakeNewPatch();
5943   memcpy(p, pFrom , sizeof(patchMesh_t));
5944
5945         // spog - initialise patch LOD pointers (again)
5946   Patch_InitialiseLODPointers(p);
5947   p->drawLists = NULL;
5948
5949   p->bSelected = false;
5950   p->bDirty = true;
5951   p->bOverlay = false;
5952   p->nListID = -1;
5953   AddBrushForPatch(p);
5954
5955   return p;
5956 }
5957
5958
5959 void Patch_Thicken(int nAmount, bool bSeam, qboolean bGroupResult)
5960 {
5961   int i, j, h, w;
5962   brush_t *b;
5963   patchMesh_t *pSeam;
5964   vec3_t vMin, vMax;
5965   CPtrArray brushes;
5966
5967   nAmount = -nAmount;
5968
5969
5970         if (!QE_SingleBrush())
5971   {
5972     Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n");
5973                 return;
5974   }
5975
5976         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5977         {
5978     if (pb->patchBrush)
5979     {
5980       patchMesh_t *p = pb->pPatch;
5981       Patch_MeshNormals(p);
5982       patchMesh_t *pNew = Patch_Duplicate(p);
5983       for (i = 0; i < p->width; i++)
5984       {
5985         for (j = 0; j < p->height; j++)
5986         {
5987                       VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz);
5988         }
5989       }
5990
5991       Patch_Rebuild(pNew);
5992       pNew->type |= PATCH_THICK;
5993       brushes.Add(pNew->pSymbiot);
5994
5995       if (bSeam)
5996       {
5997
5998         // FIXME: this should detect if any edges of the patch are closed and act appropriately
5999         //
6000         if (!(p->type & PATCH_CYLINDER))
6001         {
6002           b = Patch_GenericMesh(3, p->height, 2, false, true);
6003           pSeam = b->pPatch;
6004           pSeam->type |= PATCH_SEAM;
6005           for (i = 0; i < p->height; i++)
6006           {
6007             VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz);
6008             VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz);
6009             VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
6010             VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
6011           }
6012
6013
6014           Patch_CalcBounds(pSeam, vMin, vMax);
6015           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6016           //--Patch_CapTexture(pSeam);
6017           Patch_Naturalize(pSeam);
6018           patchInvert(pSeam);
6019           brushes.Add(b);
6020
6021           w = p->width - 1;
6022           b = Patch_GenericMesh(3, p->height, 2, false, true);
6023           pSeam = b->pPatch;
6024           pSeam->type |= PATCH_SEAM;
6025           for (i = 0; i < p->height; i++)
6026           {
6027             VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz);
6028             VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz);
6029             VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
6030             VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
6031           }
6032           Patch_CalcBounds(pSeam, vMin, vMax);
6033           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6034           //--Patch_CapTexture(pSeam);
6035           Patch_Naturalize(pSeam);
6036           brushes.Add(b);
6037         }
6038
6039         //--{
6040           // otherwise we will add one per end
6041           b = Patch_GenericMesh(p->width, 3, 2, false, true);
6042           pSeam = b->pPatch;
6043           pSeam->type |= PATCH_SEAM;
6044           for (i = 0; i < p->width; i++)
6045           {
6046             VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz);
6047             VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz);
6048             VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
6049             VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
6050           }
6051
6052
6053           Patch_CalcBounds(pSeam, vMin, vMax);
6054           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6055           //--Patch_CapTexture(pSeam);
6056           Patch_Naturalize(pSeam);
6057           patchInvert(pSeam);
6058           brushes.Add(b);
6059
6060           h = p->height - 1;
6061           b = Patch_GenericMesh(p->width, 3, 2, false, true);
6062           pSeam = b->pPatch;
6063           pSeam->type |= PATCH_SEAM;
6064           for (i = 0; i < p->width; i++)
6065           {
6066             VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz);
6067             VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz);
6068             VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
6069             VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
6070           }
6071           Patch_CalcBounds(pSeam, vMin, vMax);
6072           Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6073           //--Patch_CapTexture(pSeam);
6074           Patch_Naturalize(pSeam);
6075           brushes.Add(b);
6076
6077       }
6078       patchInvert(pNew);
6079     }
6080   }
6081
6082   for (i = 0; i < brushes.GetSize(); i++)
6083   {
6084     Select_Brush(reinterpret_cast<brush_t*>(brushes.GetAt(i)));
6085   }
6086
6087   if(bGroupResult)
6088   {
6089     entity_t *e = Entity_Alloc();
6090     SetKeyValue(e, "classname", "func_group");
6091     SetKeyValue(e, "type", "patchThick");
6092     Select_GroupEntity(e);
6093     Entity_AddToList(e, &entities);
6094   }
6095
6096   UpdatePatchInspector();
6097 }
6098
6099
6100 /*
6101 lets get another list together as far as necessities..
6102
6103 *snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything)
6104
6105 capping bevels/endcaps
6106
6107 hot keys
6108
6109 texture fix for caps
6110
6111 clear clipboard
6112
6113 *region fix
6114
6115 *surface dialog
6116
6117 */
6118
6119 void Patch_SetOverlays()
6120 {
6121         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6122         {
6123     if (pb->patchBrush)
6124     {
6125       pb->pPatch->bOverlay = true;
6126     }
6127   }
6128 }
6129
6130
6131
6132 void Patch_ClearOverlays()
6133 {
6134   brush_t *pb;
6135         for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6136         {
6137     if (pb->patchBrush)
6138     {
6139       pb->pPatch->bOverlay = false;
6140     }
6141   }
6142
6143         for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
6144         {
6145     if (pb->patchBrush)
6146     {
6147       pb->pPatch->bOverlay = false;
6148     }
6149   }
6150
6151 }
6152
6153 // FIXME: spog - er, someone forgot to finish their patch point freezing feature?
6154 // freezes selected vertices
6155 void Patch_Freeze()
6156 {
6157   brush_t *pb;
6158         for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6159         {
6160     if (pb->patchBrush)
6161     {
6162       pb->pPatch->bOverlay = false;
6163     }
6164   }
6165
6166         for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
6167         {
6168     if (pb->patchBrush)
6169     {
6170       pb->pPatch->bOverlay = false;
6171     }
6172   }
6173
6174 }
6175
6176 void Patch_UnFreeze(bool bAll)
6177 {
6178 }
6179
6180 void Patch_Transpose()
6181 {
6182         int             i, j, w;
6183   drawVert_t dv;
6184         for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6185         {
6186     if (pb->patchBrush)
6187     {
6188       patchMesh_t *p = pb->pPatch;
6189
6190       if ( p->width > p->height )
6191       {
6192         for ( i = 0 ; i < p->height ; i++ )
6193         {
6194           for ( j = i + 1 ; j < p->width ; j++ )
6195           {
6196             if ( j < p->height )
6197             {
6198               // swap the value
6199               memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t));
6200               memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
6201               memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t));
6202             }
6203             else
6204             {
6205                                         // just copy
6206                                         memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
6207                                 }
6208                         }
6209                   }
6210             }
6211       else
6212       {
6213                 for ( i = 0 ; i < p->width ; i++ )
6214         {
6215                           for ( j = i + 1 ; j < p->height ; j++ )
6216           {
6217                                 if ( j < p->width )
6218             {
6219                                             // swap the value
6220                                             memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t));
6221               memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
6222                                         memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t));
6223                                 }
6224             else
6225             {
6226                                         // just copy
6227                                         memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
6228                                 }
6229                         }
6230                 }
6231         }
6232
6233       w = p->width;
6234       p->width = p->height;
6235       p->height = w;
6236       patchInvert(p);
6237       Patch_Rebuild(p);
6238                 }
6239         }
6240 }
6241
6242
6243
6244 void Patch_SnapToGrid(patchMesh_t *p)
6245 {
6246         int i,j,k;
6247
6248         // if patch points selected, snap only selected points
6249         if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0)
6250                 for (i=0; i<g_qeglobals.d_num_move_points; i++)
6251                         for (j = 0; j < 3; j++)
6252                                 g_qeglobals.d_move_points[i][j] = floor(g_qeglobals.d_move_points[i][j] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
6253
6254         // else snap all patch points
6255         else
6256                 for (i = 0; i < p->width; i++)
6257                         for (j = 0; j < p->height; j++)
6258                                 for (k = 0; k < 3; k++)
6259                                         p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
6260
6261         vec3_t vMin, vMax;
6262         Patch_CalcBounds(p, vMin, vMax);
6263         Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
6264 }
6265
6266
6267 void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce)
6268 {
6269   if (pb->patchBrush)
6270   {
6271     patchMesh_t *p = pb->pPatch;
6272     if (bForce || strcmpi(p->pShader->getName(), pFind) == 0)
6273     {
6274       p->pShader->DecRef();
6275       p->pShader = QERApp_Shader_ForName(pReplace);
6276       p->d_texture = p->pShader->getTexture();
6277     }
6278   }
6279 }
6280
6281 /* uncomment if necessary, currently not used
6282 void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz)
6283 {
6284   patchMesh_t* p = MakeNewPatch();
6285   p->pShader = g_qeglobals.d_texturewin.pShader;
6286   p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture();
6287   p->width = 3;
6288   p->height = 3;
6289   p->type = PATCH_TRIANGLE;
6290
6291   // 0 0 goes to x
6292   // 0 1 goes to x
6293   // 0 2 goes to x
6294
6295   // 1 0 goes to mid of x and z
6296   // 1 1 goes to mid of x y and z
6297   // 1 2 goes to mid of x and y
6298
6299   // 2 0 goes to z
6300   // 2 1 goes to mid of y and z
6301   // 2 2 goes to y
6302
6303   vec5_t vMidXZ;
6304   vec5_t vMidXY;
6305   vec5_t vMidYZ;
6306   int j;
6307
6308   for (j = 0; j < 3; j++)
6309   {
6310     _Vector5Add(vx, vz, vMidXZ);
6311     _Vector5Scale(vMidXZ, 0.5, vMidXZ);
6312     //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5);
6313   }
6314
6315   for (j = 0; j < 3; j++)
6316   {
6317     _Vector5Add(vx, vy, vMidXY);
6318     _Vector5Scale(vMidXY, 0.5, vMidXY);
6319     //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5);
6320   }
6321
6322   for (j = 0; j < 3; j++)
6323   {
6324     _Vector5Add(vy, vz, vMidYZ);
6325     _Vector5Scale(vMidYZ, 0.5, vMidYZ);
6326     //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5);
6327   }
6328
6329   _Vector53Copy(vx, p->ctrl[0][0].xyz);
6330   _Vector53Copy(vx, p->ctrl[0][1].xyz);
6331   _Vector53Copy(vx, p->ctrl[0][2].xyz);
6332   p->ctrl[0][0].st[0] = vx[3];
6333   p->ctrl[0][0].st[1] = vx[4];
6334   p->ctrl[0][1].st[0] = vx[3];
6335   p->ctrl[0][1].st[1] = vx[4];
6336   p->ctrl[0][2].st[0] = vx[3];
6337   p->ctrl[0][2].st[1] = vx[4];
6338
6339   _Vector53Copy(vMidXY, p->ctrl[1][0].xyz);
6340   _Vector53Copy(vx, p->ctrl[1][1].xyz);
6341   _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz);
6342   p->ctrl[1][0].st[0] = vMidXY[3];
6343   p->ctrl[1][0].st[1] = vMidXY[4];
6344   p->ctrl[1][1].st[0] = vx[3];
6345   p->ctrl[1][1].st[1] = vx[4];
6346   p->ctrl[1][2].st[0] = vMidXZ[3];
6347   p->ctrl[1][2].st[1] = vMidXZ[4];
6348
6349   _Vector53Copy(vy, p->ctrl[2][0].xyz);
6350   _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz);
6351   _Vector53Copy(vz, p->ctrl[2][2].xyz);
6352   p->ctrl[2][0].st[0] = vy[3];
6353   p->ctrl[2][0].st[1] = vy[4];
6354   p->ctrl[2][1].st[0] = vMidYZ[3];
6355   p->ctrl[2][1].st[1] = vMidYZ[4];
6356   p->ctrl[2][2].st[0] = vz[3];
6357   p->ctrl[2][2].st[1] = vz[4];
6358
6359
6360   //Patch_Naturalize(p);
6361
6362   //  brush_t *b =
6363   AddBrushForPatch(p);
6364
6365 }
6366 */
6367
6368 #ifdef ENABLE_GROUPS
6369 /*
6370 ==============
6371 Patch_SetEpair
6372 sets an epair for the given patch
6373 ==============
6374 */
6375 void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue)
6376 {
6377         if (g_qeglobals.m_bBrushPrimitMode)
6378         {
6379                 SetKeyValue(p->epairs, pKey, pValue);
6380         }
6381 }
6382
6383 /*
6384 =================
6385 Patch_GetKeyValue
6386 =================
6387 */
6388 const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey)
6389 {
6390         if (g_qeglobals.m_bBrushPrimitMode)
6391         {
6392     return ValueForKey(p->epairs, pKey);
6393         }
6394   return "";
6395 }
6396 #endif
6397
6398
6399 //Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save)
6400 /*
6401 Feature addition.
6402 When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as;
6403
6404 g:\quake3\baseq3\textures\common
6405
6406  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.
6407
6408   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.
6409
6410   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.
6411
6412   1) Easier way of deleting rows, columns
6413 2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog)
6414 2) Patch matrix transposition
6415
6416   1) Actually, bump texture flipping on patches to the top of the list of things to do.
6417 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
6418 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
6419
6420
6421 *1) Flipping textures on patches
6422 *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
6423 3) Easier way of deleting rows columns
6424 *4) Thick Curves
6425 5) Patch matrix transposition
6426 6) Inverted cylinder capping
6427 *7) bugs
6428 *8) curve speed
6429
6430   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)
6431
6432   Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model
6433
6434   Feature Addition: View/Hide Hint Brushes -- This should be a specific case.
6435 */