2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
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.
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.
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
23 // Preliminary patch stuff
30 #include "gtkr_list.h"
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);
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);
40 void Patch_InitialiseLODPointers(patchMesh_t *p)
43 int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT;
44 for (i=0; i<rowcount; i++)
46 int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH;
47 for (i=0; i<colcount; i++)
51 patchMesh_t* Patch_Alloc()
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;
61 pPatch->bSelected = false;
62 pPatch->bOverlay = false;
63 pPatch->bDirty = true;
64 pPatch->LODUpdated = false;
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;
75 patchMesh_t* MakeNewPatch()
77 patchMesh_t *pm = reinterpret_cast<patchMesh_t*>(qmalloc(sizeof(patchMesh_t)));
79 // spog - initialise patch LOD pointers
80 Patch_InitialiseLODPointers(pm);
87 // FIXME: this needs to be dynamic
88 //#define MAX_PATCH_MESHES 4096
89 //patchMesh_t patchMeshes[MAX_PATCH_MESHES];
90 //int numPatchMeshes = 0;
92 // used for a save spot
93 patchMesh_t patchSave;
95 // Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized
97 //--int g_nSelectedPatch = -1;
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;
105 //typedef enum XFormType { TRANSLATE, SCALE, ROTATE };
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;
120 bool g_bPatchAxisOnRow = true;
121 int g_nPatchAxisIndex = 0;
122 bool g_bPatchLowerEdge = true;
124 vec3_t g_vCycleCapNormal;
125 // cycles when we use Patch_CycleCapSelected
126 VIEWTYPE g_nCycleCapIndex = XY;
131 BEND_SELECT_ROTATION = 0,
138 const char *g_pBendStateMsg[] =
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",
150 INSERT_SELECT_EDGE = 0,
154 const char* g_pInsertStateMsg[] =
156 "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair"
160 float *g_InversePoints[1024];
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])
168 fColor[0] = f->d_color[0];
169 fColor[1] = f->d_color[1];
170 fColor[2] = f->d_color[2];
175 void _DecColor(float fColor[3])
181 for (int i = 0; i < 3; i++)
183 if (fColor[i] <= fLowerLimit)
185 fColor[0] = fFullBright;
186 fColor[1] = fFullBright;
187 fColor[2] = fFullBright;
194 vec_t __VectorNormalize (vec3_t in, vec3_t out)
196 vec_t length, ilength;
198 length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
205 ilength = 1.0/length;
206 out[0] = in[0]*ilength;
207 out[1] = in[1]*ilength;
208 out[2] = in[2]*ilength;
214 void Patch_SetType(patchMesh_t *p, int nType)
216 p->type = (p->type & PATCH_STYLEMASK) | nType;
219 void Patch_SetStyle(patchMesh_t *p, int nStyle)
221 p->type = (p->type & PATCH_TYPEMASK) | nStyle;
229 int Patch_MemorySize(patchMesh_t *p)
238 InterpolateInteriorPoints
241 void InterpolateInteriorPoints( patchMesh_t *p )
246 for ( i = 0 ; i < p->width ; i += 2 )
249 next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width;
250 prev = ( i == 0 ) ? p->width - 2 : i - 1;
255 next = ( i + 1 ) % p->width;
256 prev = p->width - 2; // joined wrap case
258 else if ( i == p->width - 1 )
265 next = ( i + 1 ) % p->width;
270 for ( j = 0 ; j < p->height ; j++ )
272 for ( k = 0 ; k < 3 ; k++ )
274 p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5;
286 int neighbors[8][2] = {
287 {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
290 void Patch_MeshNormals(patchMesh_t *in )
300 vec3_t around[8], temp;
302 qboolean wrapWidth, wrapHeight;
306 for ( i = 0 ; i < in->height ; i++ )
309 VectorSubtract( in->ctrl[0][i].xyz,
310 in->ctrl[in->width-1][i].xyz, delta );
311 len = VectorLength( delta );
317 if ( i == in->height )
323 for ( i = 0 ; i < in->width ; i++ )
325 VectorSubtract( in->ctrl[i][0].xyz,
326 in->ctrl[i][in->height-1].xyz, delta );
327 len = VectorLength( delta );
339 for ( i = 0 ; i < in->width ; i++ )
341 for ( j = 0 ; j < in->height ; j++ )
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++ )
349 VectorClear( around[k] );
352 for ( dist = 1 ; dist <= 3 ; dist++ )
354 x = i + neighbors[k][0] * dist;
355 y = j + neighbors[k][1] * dist;
360 x = in->width - 1 + x;
362 else if ( x >= in->width )
364 x = 1 + x - in->width;
371 y = in->height - 1 + y;
373 else if ( y >= in->height )
375 y = 1 + y - in->height;
379 if ( x < 0 || x >= in->width || y < 0 || y >= in->height )
381 break; // edge of patch
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 )
387 continue; // degenerate edge, get more dist
392 VectorCopy( temp, around[k] );
399 for ( k = 0 ; k < 8 ; k++ )
401 if ( !good[k] || !good[(k+1)&7] )
403 continue; // didn't get two points
405 CrossProduct( around[(k+1)&7], around[k], normal );
406 if ( __VectorNormalize( normal, normal ) == 0 )
410 VectorAdd( normal, sum, sum );
415 //printf("bad normal\n");
419 __VectorNormalize( sum, dv->normal );
432 void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax)
434 vMin[0] = vMin[1] = vMin[2] = 99999;
435 vMax[0] = vMax[1] = vMax[2] = -99999;
438 for (int w = 0; w < p->width; w++)
440 for (int h = 0; h < p->height; h++)
442 for (int j = 0; j < 3; j++)
444 float f = p->ctrl[w][h].xyz[j];
459 void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs)
470 for (j = 0; j < 3; j++)
472 if ((int)vMins[j] == (int)vMaxs[j])
480 for (f=b->brush_faces ; f ; f=next)
488 b->brush_faces = NULL;
490 // left the last face so we can use its texdef
492 for (i=0 ; i<3 ; i++)
493 if (vMaxs[i] < vMins[i])
494 Error ("Brush_RebuildBrush: backwards");
496 pts[0][0][0] = vMins[0];
497 pts[0][0][1] = vMins[1];
499 pts[1][0][0] = vMins[0];
500 pts[1][0][1] = vMaxs[1];
502 pts[2][0][0] = vMaxs[0];
503 pts[2][0][1] = vMaxs[1];
505 pts[3][0][0] = vMaxs[0];
506 pts[3][0][1] = vMins[1];
508 for (i=0 ; i<4 ; i++)
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];
516 for (i=0 ; i<4 ; i++)
520 f->texdef.flags &= ~SURF_KEEP;
521 f->texdef.contents &= ~CONTENTS_KEEP;
522 // f->texdef.flags |= SURF_PATCH;
523 f->next = b->brush_faces;
527 VectorCopy (pts[j][1], f->planepts[0]);
528 VectorCopy (pts[i][1], f->planepts[1]);
529 VectorCopy (pts[i][0], f->planepts[2]);
534 f->texdef.flags &= ~SURF_KEEP;
535 f->texdef.contents &= ~CONTENTS_KEEP;
536 // f->texdef.flags |= SURF_PATCH;
537 f->next = b->brush_faces;
540 VectorCopy (pts[0][1], f->planepts[0]);
541 VectorCopy (pts[1][1], f->planepts[1]);
542 VectorCopy (pts[2][1], f->planepts[2]);
546 f->texdef.flags &= ~SURF_KEEP;
547 f->texdef.contents &= ~CONTENTS_KEEP;
548 // f->texdef.flags |= SURF_PATCH;
549 f->next = b->brush_faces;
552 VectorCopy (pts[2][0], f->planepts[0]);
553 VectorCopy (pts[1][0], f->planepts[1]);
554 VectorCopy (pts[0][0], f->planepts[2]);
559 void WINAPI Patch_Rebuild(patchMesh_t *p)
562 Patch_CalcBounds(p, vMin, vMax);
563 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
571 adds a patch brush and ties it to this patch id
573 brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld )
575 // find the farthest points in x,y,z
577 Patch_CalcBounds(pm, vMin, vMax);
579 for (int j = 0; j < 3; j++)
581 if (vMin[j] == vMax[j])
588 brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
590 // FIXME: this entire type of linkage needs to be fixed
591 b->patchBrush = true;
594 pm->bSelected = false;
595 pm->bOverlay = false;
601 Brush_AddToList (b, &active_brushes);
602 Entity_LinkBrush (world_entity, b);
609 void Patch_SetPointIntensities(int n)
612 patchMesh_t *p = patchMeshes[n];
613 for (int i = 0; i < p->width; i++)
615 for (int j = 0; j < p->height; j++)
623 // very approximate widths and heights
630 float Patch_Width(patchMesh_t *p)
633 for (int i = 0; i < p->width-1; i++)
636 VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
637 f += VectorLength(vTemp);
642 float Patch_WidthDistanceTo(patchMesh_t *p, int j)
645 for (int i = 0; i < j; i++)
648 VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
649 f += VectorLength(vTemp);
661 float Patch_Height(patchMesh_t *p)
664 for (int i = 0; i < p->height-1; i++)
667 VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
668 f += VectorLength(vTemp);
673 float Patch_HeightDistanceTo(patchMesh_t *p, int j)
676 for (int i = p->height-1; i > j; i--)
679 VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i-1].xyz, vTemp); // reverse order for T coords
680 f += VectorLength(vTemp);
691 texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength
693 dist( this control point to first control point ) / dist ( last control pt to first)
695 void WINAPI Patch_Naturalize(patchMesh_t *p)
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);
703 for ( int i = 0; i < p->width ; i++ )
706 for ( int j = p->height-1; j >= 0 ; j-- )
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);
714 xAccum = Patch_WidthDistanceTo(p,i+1);
722 VectorCopy(p->ctrl[1][0], p->ctrl[1][1]);
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]);
781 int Interior3By[][2] =
786 int Interior5By[][2] =
799 int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]);
800 int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]);
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
806 void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false)
808 vec3_t vProjection, vX, vY;
809 qtexture_t *texture = p->pShader->getTexture();
810 plane_t Plane1, Plane2, Plane3;
814 VectorCopy (g_vCycleCapNormal, vProjection);
818 VectorClear ( vProjection );
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))
823 VectorClear ( Plane3.normal );
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))
832 VectorCopy ( Plane1.normal, Plane3.normal );
833 Plane3.dist = Plane1.dist;
840 // find average plane for all 4 corner points
842 for (int n = 0; n <= 2; n++)
844 Plane3.normal[n] = (Plane1.normal[n] + Plane2.normal[n]) / 2;
846 Plane3.dist = (Plane1.dist + Plane2.dist) / 2;
850 VectorCopy ( Plane2.normal, Plane3.normal );
851 Plane3.dist = Plane2.dist;
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);
862 for (int w = 0; w < p->width; w++)
864 for (int h = 0; h < p->height; h++)
866 if (vProjection[2] == 1.0f || (vX[0] == 1.0f && vY[1] == -1.0f))
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;
871 else if (vProjection[0] == 1.0f || (vX[1] == 1.0f && vY[2] == -1.0f))
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;
876 else if (vProjection[1] == 1.0f || (vX[0] == 1.0f && vY[2] == -1.0f))
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;
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);
886 // make sure it will rebuild
890 void FillPatch(patchMesh_t *p, vec3_t v)
892 for (int i = 0; i < p->width; i++)
894 for (int j = 0; j < p->height; j++)
896 VectorCopy(v, p->ctrl[i][j].xyz);
901 // temporarily moved function to allow use in Cap() and CapSpecial()
902 void patchInvert(patchMesh_t *p)
906 for ( int i = 0 ; i < p->width ; i++ )
908 for (int j = 0; j < p->height / 2; j++)
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));
917 brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst)
925 // make a generic patch
926 if (pParent->width <= 9)
928 b = Patch_GenericMesh(3, 3, 2, false);
932 b = Patch_GenericMesh(5, 5, 2, false);
938 Sys_Printf("Unable to cap. You may need to ungroup the patch.\n");
943 p->type |= PATCH_CAP;
945 vMin[0] = vMin[1] = vMin[2] = 9999;
946 vMax[0] = vMax[1] = vMax[2] = -9999;
948 // we seam the column edge, FIXME: this might need to be able to seem either edge
950 int nSize = (bByColumn) ? pParent->width : pParent->height;
951 int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1;
953 FillPatch(p, pParent->ctrl[0][nIndex].xyz);
955 for (i = 0; i < nSize; i++)
961 VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
965 VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
972 VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
976 VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
980 for (j = 0; j < 3; j++)
982 float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j];
991 for (j = 0; j < 3; j++)
993 vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5);
995 int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount;
996 for (j = 0; j < nCount; j++)
1000 VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz);
1004 VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz);
1012 drawVert_t vertTemp;
1013 for (i = 0; i < p->width; i++)
1015 for (j = 0; j < p->height / 2; j++)
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));
1026 Patch_CapTexture(p);
1030 brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst)
1035 vec3_t vMin, vMax, vTemp;
1038 if (nType == IENDCAP)
1039 b = Patch_GenericMesh(5, 3, 2, false);
1041 b = Patch_GenericMesh(3, 3, 2, false);
1045 Sys_Printf("Unable to cap. Make sure you ungroup before re-capping.");
1050 p->type |= PATCH_CAP;
1052 vMin[0] = vMin[1] = vMin[2] = 9999;
1053 vMax[0] = vMax[1] = vMax[2] = -9999;
1055 // int nSize = pParent->width;
1056 int nIndex = (bFirst) ? 0 : pParent->height-1;
1058 // parent bounds are used for some things
1059 Patch_CalcBounds(pParent, vMin, vMax);
1061 for (j = 0; j < 3; j++)
1063 vTemp[j] = vMin[j] + fabs((vMax[j] - vMin[j]) * 0.5);
1066 if (nType == IBEVEL)
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);
1078 else if (nType == BEVEL)
1080 vec3_t p1, p2, p3, p4; //, temp, dir;
1082 VectorCopy(pParent->ctrl[0][nIndex].xyz, p3);
1083 VectorCopy(pParent->ctrl[1][nIndex].xyz, p1);
1084 VectorCopy(pParent->ctrl[2][nIndex].xyz, p2);
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]);
1090 VectorSubtract(p2, p1, p4);
1091 VectorAdd(p3, p4, p4);
1092 // spog - use opposite-point-on-parallelogram to find p4
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);
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]);
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);
1121 else if (nType == ENDCAP)
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);
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);
1134 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
1135 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz);
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);
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);
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);
1161 drawVert_t vertTemp;
1162 for (i = 0; i < p->width; i++)
1164 for (j = 0; j < p->height / 2; j++)
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));
1173 //--Patch_CalcBounds(p, vMin, vMax);
1174 //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1176 Patch_CapTexture(p);
1180 void Patch_CapCurrent()
1182 patchMesh_t *pParent = NULL;
1184 brush_t *pCap = NULL;
1185 b[0] = b[1] = b[2] = b[3] = NULL;
1187 bool b_GroupResult = TRUE;
1189 if (!QE_SingleBrush(true))
1191 Sys_Printf("Patch_CapCurrent: you must have a single patch selected\n");
1196 for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next)
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))
1207 pCap = Cap(pParent, true, false);
1213 if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
1215 pCap = Cap(pParent, true, true);
1221 if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz))
1223 pCap = Cap(pParent, false, false);
1229 if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
1231 pCap = Cap(pParent, false, true);
1242 // if we did not cap anything with the above tests
1247 if (DoCapDlg (&type, &b_GroupResult) == IDOK)
1249 b[nIndex++] = CapSpecial(pParent, type, false);
1250 b[nIndex++] = CapSpecial(pParent, type, true);
1261 Select_Brush(b[nIndex]);
1264 // Gef: Added toggle for capped patch func_group
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);
1281 void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight)
1287 if (!QE_SingleBrush())
1290 b = selected_brushes.next;
1294 p->d_texture = b->brush_faces->d_texture;
1295 p->pShader = b->brush_faces->pShader;
1297 p->height = nHeight;
1299 p->type = PATCH_CYLINDER;
1300 if (bBevel & !bSquare)
1302 p->type = PATCH_BEVEL;
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++)
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;
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;
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;
1322 else if (bEndcap & !bSquare)
1324 p->type = PATCH_ENDCAP;
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++)
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;
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;
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;
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;
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;
1355 p->ctrl[1][0].xyz[0] = b->mins[0];
1356 p->ctrl[1][0].xyz[1] = b->mins[1];
1358 p->ctrl[3][0].xyz[0] = b->maxs[0];
1359 p->ctrl[3][0].xyz[1] = b->mins[1];
1361 p->ctrl[5][0].xyz[0] = b->maxs[0];
1362 p->ctrl[5][0].xyz[1] = b->maxs[1];
1364 p->ctrl[7][0].xyz[0] = b->mins[0];
1365 p->ctrl[7][0].xyz[1] = b->maxs[1];
1367 for ( i = 1 ; i < p->width - 1 ; i += 2 )
1370 p->ctrl[i][0].xyz[2] = b->mins[2];
1372 VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz );
1374 p->ctrl[i][2].xyz[2] = b->maxs[2];
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;
1380 InterpolateInteriorPoints( p );
1384 if (bBevel || bEndcap)
1388 for (i = 0; i < p->height; i++)
1390 VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
1391 VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
1396 for (i = 0; i < p->height; i++)
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);
1407 for (i = 0; i < p->width-1; i ++)
1409 for (j = 0; j < p->height; j++)
1411 VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz);
1414 for (j = 0; j < p->height; j++)
1416 VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz);
1423 Patch_Naturalize(p);
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;
1431 for ( i = 0 ; i < p->width ; i ++)
1433 p->ctrl[i][2].xyz[0] = xc;
1434 p->ctrl[i][2].xyz[1] = yc;
1438 b = AddBrushForPatch(p);
1450 brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride)
1454 if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15)
1456 Sys_Printf("Invalid patch width or height.\n");
1460 if (! bOverride && !QE_SingleBrush())
1462 Sys_Printf("Error: you must have a single brush selected\n");
1466 patchMesh_t* p = MakeNewPatch();
1467 p->pShader = g_qeglobals.d_texturewin.pShader;
1468 p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture();
1471 p->height = nHeight;
1472 p->type = PATCH_GENERIC;
1476 if (nOrientation == 0)
1481 else if (nOrientation == 1)
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 );
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));
1494 for (i = 0; i < nWidth; i++)
1496 int yStep = (int)(b->mins[nSecond]);
1497 for (j = 0; j < nHeight; j++)
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];
1508 Patch_Naturalize(p);
1510 b = AddBrushForPatch(p);
1518 //g_qeglobals.d_select_mode = sel_curvepoint;
1526 int PointInMoveList(float *pf)
1528 for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
1530 if (pf == &g_qeglobals.d_move_points[i][0])
1538 PointValueInMoveList
1541 int PointValueInMoveList(vec3_t v)
1543 for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
1545 if (VectorCompare(v, g_qeglobals.d_move_points[i]))
1554 RemovePointFromMoveList
1557 void RemovePointFromMoveList(vec3_t v)
1560 while ( (n = PointValueInMoveList(v)) >= 0)
1562 for (int i = n; i < g_qeglobals.d_num_move_points-1; i++)
1564 g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1];
1566 g_qeglobals.d_num_move_points--;
1575 bool ColumnSelected(patchMesh_t* p, int nCol)
1577 for (int i = 0; i < p->height; i++)
1579 if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1)
1590 void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true)
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)
1597 for ( int i = 0 ; i < p->width ; i++ )
1599 for ( int j = 0 ; j < p->height ; j++ )
1603 if ( VectorCompare(v, p->ctrl[i][j].xyz)
1604 && PointInMoveList(p->ctrl[i][j].xyz) == -1)
1606 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
1610 if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA)
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))
1615 if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
1617 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
1632 void SelectRow(patchMesh_t* p, int nRow, bool bMulti)
1635 g_qeglobals.d_num_move_points = 0;
1636 for (int i = 0; i < p->width; i++)
1638 AddPoint(p, p->ctrl[i][nRow].xyz, false);
1640 //Sys_Printf("Selected Row %d\n", nRow);
1648 void SelectColumn(patchMesh_t* p, int nCol, bool bMulti)
1651 g_qeglobals.d_num_move_points = 0;
1652 for (int i = 0; i < p->height; i++)
1654 AddPoint(p, p->ctrl[nCol][i].xyz, false);
1656 //Sys_Printf("Selected Col %d\n", nCol);
1665 void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull)
1667 if (!g_bSameView && !bMulti && !bFull)
1670 //return; // was causing odd behaviour on patch vertex selection
1673 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
1677 patchMesh_t* p = pb->pPatch;
1678 for ( int i = 0 ; i < p->width ; i++ )
1680 for ( int j = 0 ; j < p->height ; j++ )
1682 if (VectorCompare(v, p->ctrl[i][j].xyz))
1684 if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
1686 if (bFull) // if we want the full row/col this is on
1688 SelectColumn(p, i, 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);
1704 if (ColumnSelected(p, i))
1706 SelectRow(p, j, bMulti);
1710 SelectColumn(p, i, bMulti);
1716 // g_qeglobals.d_num_move_points = 0;
1717 // AddPoint(p, p->ctrl[i][j].xyz);
1719 if (bMulti)// if (g_bSameView) // this is not having desired effect
1721 RemovePointFromMoveList(v);
1734 Patch_UpdateSelected
1737 void Patch_UpdateSelected(vec3_t vMove)
1740 for (i=0 ; i < g_qeglobals.d_num_move_points ; i++)
1742 VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]);
1743 if (g_qeglobals.d_num_move_points == 1)
1748 //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch];
1749 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
1753 patchMesh_t* p = pb->pPatch;
1755 #if 0 //moving to SelectCurvePointByRay
1756 g_qeglobals.d_numpoints = 0;
1757 for (i = 0 ; i < p->width ; i++ )
1759 for ( j = 0 ; j < p->height ; j++ )
1761 VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
1762 if (g_qeglobals.d_numpoints < MAX_POINTS-1)
1764 g_qeglobals.d_numpoints++;
1770 Patch_CalcBounds(p, vMin, vMax);
1771 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1774 //Brush_Free(p->pSymbiot);
1775 //Select_Brush(AddBrushForPatch(g_nSelectedPatch));
1785 void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) {
1790 // find the control points for the v coordinate
1791 for (vPoint = 0 ; vPoint < 3 ; vPoint++)
1793 for (axis = 0 ; axis < 5 ; axis++)
1798 a = ctrl[0][vPoint][axis];
1799 b = ctrl[1][vPoint][axis];
1800 c = ctrl[2][vPoint][axis];
1805 vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
1809 // interpolate the v value
1810 for (axis = 0 ; axis < 5 ; axis++)
1822 out[axis] = qA * v * v + qB * v + qC;
1826 //spog - Curve LOD stuff starts
1828 float ShadeForNormal(vec3_t normal)
1838 // quick diffuse shading
1839 f = DotProduct(L, normal);
1843 //if (f < 0.0f) f = 0.0f;
1850 void ShadeVertex (drawVert_t &p)
1852 p.lightmap[0] = ShadeForNormal(p.normal);
1856 void Patch_DrawNormals(patchMesh_t *patch)
1861 qglBegin (GL_LINES);
1862 for (col=0; col<patch->width; col++)
1864 for (row=0; row<patch->height; row++)
1866 VectorAdd(patch->ctrl[col][row].xyz, patch->ctrl[col][row].normal, vNormal);
1867 qglVertex3fv (patch->ctrl[col][row].xyz);
1868 qglVertex3fv (vNormal);
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)
1884 drawVert_t v1, v2, v3;
1890 v1.xyz[i] = vCurve[1]->xyz[i] - vCurve[0]->xyz[i];
1891 v2.xyz[i] = vCurve[2]->xyz[i] - vCurve[1]->xyz[i];
1894 pLeft.xyz[i] = vCurve[0]->xyz[i] + v1.xyz[i];
1895 pRight.xyz[i] = vCurve[1]->xyz[i] + v2.xyz[i];
1897 v3.xyz[i] = pRight.xyz[i] - pLeft.xyz[i];
1899 pMid.xyz[i] = pLeft.xyz[i] + v3.xyz[i];
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));
1910 v1.st[i] = vCurve[1]->st[i] - vCurve[0]->st[i];
1911 v2.st[i] = vCurve[2]->st[i] - vCurve[1]->st[i];
1914 pLeft.st[i] = vCurve[0]->st[i] + v1.st[i];
1915 pRight.st[i] = vCurve[1]->st[i] + v2.st[i];
1917 v3.st[i] = pRight.st[i] - pLeft.st[i];
1919 pMid.st[i] = pLeft.st[i] + v3.st[i];
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[])
1927 vec3_t vTemp, v1, v2, v3, vClear;
1932 VectorClear(vClear);
1934 VectorSubtract(vCurve[2], vCurve[0], vTemp);
1935 VectorSubtract(vCurve[1], vCurve[0], v1);
1936 VectorSubtract(vCurve[2], vCurve[1], v2);
1938 if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return 0 if 1->2 == 0 or 1->2 == 1->3
1941 VectorNormalize(v1, v1);
1942 VectorNormalize(v2, v2);
1943 if (VectorCompare(v1, v2))
1946 VectorCopy(vTemp, v3);
1947 width = VectorNormalize(v3, v3);
1949 if (VectorCompare(v1, v3) && VectorCompare(v2, v3))
1952 dot = DotProduct(v1, v2);
1954 angle = acos(dot) / Q_PI;
1956 index = width * angle;
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)
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++)
1972 BTree->info.st[i] = info.st[i];
1973 BTree->vMid.st[i] = info.st[i];
1978 // take ownership of the subtree
1979 // delete the entire subtree
1980 // return a NULL pointer
1981 BTNode_t *BTree_Delete(BTNode_t *pBT)
1985 BTree_Delete(pBT->left);
1986 BTree_Delete(pBT->right);
1992 // NOT currently used
1993 BTNode_t *BTree_Clear(BTNode_t *pBT, bool bFirst = true)
1997 BTree_Clear(pBT->left, false);
1998 BTree_Clear(pBT->right, false);
1999 if (!bFirst) delete pBT;
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)
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++)
2019 newBTList->vLeft.st[i] = pLeft.st[i];
2020 newBTList->vRight.st[i] = pRight.st[i];
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)
2031 if (pBTList != NULL)
2033 BTree_DeleteList(pBTList->next);
2034 pBTList->pBT = BTree_Delete(pBTList->pBT);
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)
2045 if (pBTList != NULL)
2047 BTree_DeletePointerList(pBTList->next);
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)
2058 BTListList_t *newBTListList = new BTListList_t;
2059 newBTListList->next = pBTListList;
2060 newBTListList->list = pBTList;
2061 return newBTListList;
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)
2070 if (pBTListList != NULL)
2072 BTree_DeleteListFromList(pBTListList->next);
2073 pBTListList->list = BTree_DeletePointerList(pBTListList->list);
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)
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;
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)
2097 VectorSubtract(vCurve[2], vCurve[0], vTemp); // Start->End
2100 VectorAdd(vCurve[0], vTemp, vTemp); // midpoint of Start->End
2102 VectorSubtract(vTemp, vCurve[1], vTemp); // Mid->(midpoint of Start->End)
2105 VectorAdd(vCurve[1], vTemp, pMid); // midpoint of Mid->(midpoint of Start->End)
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)
2115 float index;//, bestindex = 0;
2120 for (p = pBTList; p != NULL; p = p->next->next)
2123 VectorCopy(p->vLeft.xyz, vCurve[0]);
2124 VectorCopy(p->pBT->info.xyz, vCurve[1]);
2125 VectorCopy(p->vRight.xyz, vCurve[2]);
2127 index = Patch_CurveIndex(vCurve);
2128 if (index > threshold)
2131 if (p->next == NULL)
2134 if (p->next->pBT == NULL) continue;
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]);
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]);
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]);
2151 index = Patch_CurveIndex(vRow);
2152 if (index > threshold)
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)
2166 BTreeList_t *leftBTList, *rightBTList;
2167 //drawVert_t pLeft, pRight, pMid;
2168 drawVert_t *vCurve[3];
2171 bool bFlipped = false;
2173 if (g_PrefsDlg.m_nSubdivisions >= 1)
2174 threshold = g_PrefsDlg.m_nSubdivisions;
2176 leftBTList = rightBTList = NULL;
2178 if (Patch_MostCurvedRow(pBTList, threshold)) // split all subtrees in list if any subtree is above threshold
2181 // traverse nodes in list
2182 for (p = pBTList; p != NULL; p=p->next)
2186 leftBTList = BTree_AddLinkToList(leftBTList, (p->vLeft.normal[0] == 1.0f));
2187 rightBTList = BTree_AddLinkToList(rightBTList, (p->vLeft.normal[0] == 1.0f));
2188 if (p->vLeft.normal[0] == 1.0f) bFlipped = (!bFlipped) ? true : false; // switch bFlipped if true
2192 // create left node for this subtree
2193 BTNode_t *newLeft = new BTNode_t;
2194 p->pBT->left = newLeft;
2195 newLeft->left = newLeft->right = NULL;
2197 // create right node for this subtree
2198 BTNode_t *newRight = new BTNode_t;
2199 p->pBT->right = newRight;
2200 newRight->left = newRight->right = NULL;
2203 vCurve[0] = &p->vLeft;
2204 vCurve[1] = &p->pBT->info;
2205 vCurve[2] = &p->vRight;
2206 Patch_CurveSplit(vCurve, newLeft->info, newRight->info, p->pBT->vMid, 0.5);
2208 memcpy(&newLeft->vMid, &newLeft->info, sizeof(drawVert_t));
2209 memcpy(&newRight->vMid, &newRight->info, sizeof(drawVert_t));
2214 // add new left subtree to left subtree list
2215 leftBTList = BTree_AddToList(leftBTList, newLeft, p->vLeft, p->pBT->vMid);
2217 // add new right subtree to right subtree list
2218 rightBTList = BTree_AddToList(rightBTList, newRight, p->pBT->vMid, p->vRight);
2222 // add new left subtree to right subtree list
2223 rightBTList = BTree_AddToList(rightBTList, newLeft, p->vLeft, p->pBT->vMid);
2225 // add new right subtree to left subtree list
2226 leftBTList = BTree_AddToList(leftBTList, newRight, p->pBT->vMid, p->vRight);
2230 // continue tree left
2231 BTree_ListCurveRecurse(leftBTList);
2232 leftBTList = BTree_DeletePointerList(leftBTList);
2234 // continue tree right
2235 BTree_ListCurveRecurse(rightBTList);
2236 rightBTList = BTree_DeletePointerList(rightBTList);
2240 // take mins and maxs values from two brushes
2241 // return true if they intersect on every axis
2242 bool TouchingAABBs(vec3_t mins1, vec3_t maxs1, vec3_t mins2, vec3_t maxs2)
2245 vec3_t v1, v2, p1, p2, T;
2246 for (int i=0; i<3; i++)
2248 v1[i] = maxs1[i] - mins1[i];
2249 v2[i] = maxs2[i] - mins2[i];
2252 p1[i] = mins1[i] + v1[i];
2253 p2[i] = mins2[i] + v2[i];
2254 // p1 == origin of aabb1
2255 // p2 == origin of aabb1
2256 // v1 == displacement of aabb1
2257 // v1 == displacement of aabb2
2258 T[i] = p2[i] - p1[i]; // T == vector from aabb1 to aabb2
2259 if ( fabs(T[i]) > (fabs(v1[i]) + fabs(v2[i])) )
2265 // take a pointer to the last item added to pBTList, a pointer to the patch, a row index (start) and a column index
2266 // 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
2267 // return a pointer to the last item added to the list
2268 BTreeList_t *Patch_CreateBTListForRows(BTreeList_t *pBTList, patchMesh_t *patch, int start, int col)
2271 patch->colDirty[(col-1)/2] = true;
2275 for (row=0; row<patch->height; row++)
2277 pos = (((col-1)/2)*patch->height)+row;
2278 patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]);
2279 patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2280 pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]);
2285 for (row=patch->height-1; row>=0; row--)
2287 pos = (((col-1)/2)*patch->height)+row;
2288 patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]);
2289 patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2290 pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]);
2296 // take a pointer to the last item added to pBTList, a pointer to the patch, a row index and a column index (start)
2297 // 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
2298 // return a pointer to the last item added to the list
2299 BTreeList_t *Patch_CreateBTListForCols(BTreeList_t *pBTList, patchMesh_t *patch, int row, int start)
2302 patch->rowDirty[(row-1)/2] = true;
2306 for (col=0; col<patch->width; col++)
2308 pos = (((row-1)/2)*patch->width)+col;
2309 patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]);
2310 patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2311 pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]);
2316 for (col=patch->width-1; col>=0; col--)
2318 pos = (((row-1)/2)*patch->width)+col;
2319 patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]);
2320 patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2321 pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]);
2328 bool BTree_IsInList(BTreeList_t *pBTList, BTNode_t *pBT)
2331 if (pBTList == NULL) return false;
2333 for (p=pBTList; p != NULL; p=p->next)
2344 int Patch_DegenCurve(vec3_t &start, vec3_t &mid, vec3_t &end)
2346 if (VectorCompare(start, mid) || VectorCompare(end, mid))
2348 if (VectorCompare(start, end)) return 2;
2354 // 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)
2355 // take the addresses of three drawVerts, and compare them with the edges of all patches that touch the patch
2356 // 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
2357 // return a pointer to the last item added
2358 BTreeList_t *Patch_FindLODMatches(patchMesh_t *patch, BTreeList_t *pBTList, drawVert_t &pMid, drawVert_t &pLeft, drawVert_t &pRight)
2360 brush_t *pb, *brushlist;
2361 int row, col, i;//, pos;
2362 vec3_t vTemp, v1, v2;//, vClear;
2365 //Sys_Printf("Patch_FindLODMatches: called\n");
2367 if (VectorCompare(pMid.xyz, pLeft.xyz) && VectorCompare(pMid.xyz, pRight.xyz))
2370 //VectorClear(vClear);
2371 VectorSubtract(pRight.xyz, pLeft.xyz, vTemp);
2372 VectorSubtract(pMid.xyz, pLeft.xyz, v1);
2373 VectorSubtract(pRight.xyz, pMid.xyz, v2);
2375 //if (VectorCompare(v1, vClear) || VectorCompare(vTemp, v1)) // return null if 1->2 == 0 or 1->2 == 1->3
2378 VectorNormalize(v1, v1);
2379 VectorNormalize(v2, v2);
2380 if (VectorCompare(v1, v2))
2383 VectorNormalize(vTemp, vTemp);
2384 if (VectorCompare(v1, vTemp) && VectorCompare(v2, vTemp))
2387 brushlist = &active_brushes;
2390 for (pb = brushlist->next; pb != brushlist; pb=pb->next)
2392 if (!pb->patchBrush || pb->pPatch == patch)
2395 // ignore this patch if its AABB does not touch the subject patch
2396 if (!TouchingAABBs(patch->pSymbiot->maxs, patch->pSymbiot->mins, pb->maxs, pb->mins))
2399 // all columns of curves
2400 for (col=1; col<pb->pPatch->width; col+=2)
2402 if (pb->pPatch->colDirty[(col-1)/2]) continue;
2404 bAlreadyAdded = false;
2406 // top and bottom curves of this column
2407 for (row=0; row<pb->pPatch->height; row+=pb->pPatch->height-1)
2411 //if (!BTree_IsInList(pBTList, pb->pPatch->rowLOD[(((col-1)/2)*patch->height)+row]))
2413 // ignore this curve if it shares no mid ctrl point with the test curve
2414 if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz))
2416 // ignore this curve if it is degenerate
2417 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))
2419 // if curve matches the test curve directly
2420 if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pRight.xyz))
2422 // add a blank link as separator
2423 pBTList = BTree_AddLinkToList(pBTList);
2424 // add this entire column, if top, top-to-bottom, else bottom to top
2425 pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col);
2426 // continue checking from last curve added to list
2427 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2429 pb->pPatch->LODUpdated = true;
2430 bAlreadyAdded = true;
2432 // if curve matches test curve but flipped
2433 else if (VectorCompare (pb->pPatch->ctrl[col-1][row].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col+1][row].xyz, pLeft.xyz))
2435 pBTList = BTree_AddLinkToList(pBTList, true); // flip
2436 pBTList = Patch_CreateBTListForRows(pBTList, pb->pPatch, row, col);
2437 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2438 pb->pPatch->LODUpdated = true;
2439 bAlreadyAdded = true;
2444 // all rows of curves
2445 for (row=1; row<pb->pPatch->height; row+=2)
2447 if (pb->pPatch->rowDirty[(row-1)/2]) continue;
2449 bAlreadyAdded = false;
2451 for (col=0; col<pb->pPatch->width; col+=pb->pPatch->width-1)
2455 //if (BTree_IsInList(pBTList, pb->pPatch->colLOD[(((row-1)/2)*patch->width)+col]))
2457 if (!VectorCompare (pb->pPatch->ctrl[col][row].xyz, pMid.xyz))
2459 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))
2461 if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pLeft.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pRight.xyz))
2463 pBTList = BTree_AddLinkToList(pBTList);
2464 pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col);
2465 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2466 pb->pPatch->LODUpdated = true;
2467 bAlreadyAdded = true;
2469 else if (VectorCompare (pb->pPatch->ctrl[col][row-1].xyz, pRight.xyz) && VectorCompare (pb->pPatch->ctrl[col][row+1].xyz, pLeft.xyz))
2471 pBTList = BTree_AddLinkToList(pBTList, true); // flip
2472 pBTList = Patch_CreateBTListForCols(pBTList, pb->pPatch, row, col);
2473 pBTList = Patch_FindLODMatches(pb->pPatch, pBTList, pBTList->pBT->info, pBTList->vLeft, pBTList->vRight);
2474 pb->pPatch->LODUpdated = true;
2475 bAlreadyAdded = true;
2480 brushlist = &selected_brushes;
2485 // take a pointer to a patch
2486 // create tree roots for all the rows and columns of curves in the patch, the patch takes ownership of these new tree roots
2487 // 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
2488 // store all the lists in a list of lists
2489 // recursively generate the rest of every tree in each list in the list
2490 void Patch_CreateLODTrees(patchMesh_t *patch)
2492 BTreeList_t *pBTList;
2493 int col, row, pos;//, rowcount, colcount;
2494 BTListList_t *pLists;
2496 //Sys_Printf("Patch_CreateMatchedLODTrees: called\n");
2498 BTListList_t *LODLists;
2503 patch->bDirty = false;
2504 patch->LODUpdated = true;
2506 for(col=1; col<patch->width; col+=2)
2508 if (patch->colDirty[(col-1)/2]) continue;
2509 else patch->colDirty[(col-1)/2] = true;
2511 // create list for rows of current patch
2512 for(row=0; row<patch->height; row++)
2514 pos = (((col-1)/2)*patch->height)+row;
2515 patch->rowLOD[pos] = BTree_Delete(patch->rowLOD[pos]);
2516 patch->rowLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2517 pBTList = BTree_AddToList(pBTList, patch->rowLOD[pos], patch->ctrl[col-1][row], patch->ctrl[col+1][row]);
2520 //create connection list for first row
2521 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][0], patch->ctrl[col-1][0], patch->ctrl[col+1][0]);
2522 //create connection list for last row
2523 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col][row-1], patch->ctrl[col-1][row-1], patch->ctrl[col+1][row-1]);
2525 LODLists = BTree_AddListToList(LODLists, pBTList);
2530 for(row=1; row<patch->height; row+=2)
2532 if (patch->rowDirty[(row-1)/2]) continue;
2533 else patch->rowDirty[(row-1)/2] = true;
2535 // create list for cols of current patch
2536 for(col=0; col<patch->width; col++)
2538 pos = (((row-1)/2)*patch->width)+col;
2539 patch->colLOD[pos] = BTree_Delete(patch->colLOD[pos]);
2540 patch->colLOD[pos] = BTree_Create(patch->ctrl[col][row]);
2541 pBTList = BTree_AddToList(pBTList, patch->colLOD[pos], patch->ctrl[col][row-1], patch->ctrl[col][row+1]);
2544 //create connection list for first col
2545 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[0][row], patch->ctrl[0][row-1], patch->ctrl[0][row+1]);
2546 //create connection list for last col
2547 pBTList = Patch_FindLODMatches(patch, pBTList, patch->ctrl[col-1][row], patch->ctrl[col-1][row-1], patch->ctrl[col-1][row+1]);
2549 LODLists = BTree_AddListToList(LODLists, pBTList);
2553 for (pLists = LODLists; pLists != NULL; pLists=pLists->next)
2554 BTree_ListCurveRecurse(pLists->list);
2555 LODLists = BTree_DeleteListFromList(LODLists);
2558 int Patch_GetCVTangent(vec3_t &v1, vec3_t &p1, vec3_t &p2, vec3_t &p3)
2560 if (VectorCompare(p1, p2))
2562 if (VectorCompare(p1, p3))
2566 else VectorSubtract(p3, p1, v1);
2569 else VectorSubtract(p2, p1, v1);
2573 void Patch_CVNormal(vec3_t ctrl[3][3], vec3_t &normal)
2575 vec3_t v1, v2, vTemp1, vTemp2;
2578 a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][0], ctrl[2][0]);
2579 b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[0][1], ctrl[0][2]);
2581 //Sys_Printf("p1: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f) p2: (%1.1f %1.1f %1.1f)\n",
2582 // 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]);
2586 a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[1][1], ctrl[1][2]);
2590 b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][1], ctrl[2][1]);
2595 a = Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]);
2599 b = Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]);
2602 CrossProduct(v1, v2, normal);
2605 if (normal[0] == 0.0f && normal[1] == 0.0f && normal[2] == 0.0f)
2607 // more degenerate cases
2611 if (VectorCompare(ctrl[0][0], ctrl[2][0])) // endcap left
2613 if (VectorCompare(ctrl[0][2], ctrl[1][2]))
2615 VectorSubtract(ctrl[2][2], ctrl[0][0], v2);
2617 else if (VectorCompare(ctrl[1][2], ctrl[2][2]))
2619 VectorSubtract(ctrl[0][2], ctrl[0][0], v2);
2622 a = Patch_DegenCurve(ctrl[0][2], ctrl[1][2], ctrl[2][2]);
2625 VectorCopy(ctrl[0][2], vCurve[0]);
2626 VectorCopy(ctrl[1][2], vCurve[1]);
2627 VectorCopy(ctrl[2][2], vCurve[2]);
2628 Patch_BezierInterpolate(vCurve, pMid);
2629 VectorSubtract(pMid, ctrl[0][0], v1);
2634 else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // endcap right
2637 if (VectorCompare(ctrl[2][0], ctrl[2][1]))
2639 VectorSubtract(ctrl[2][2], ctrl[0][0], v2);
2641 else if (VectorCompare(ctrl[2][1], ctrl[2][2]))
2643 VectorSubtract(ctrl[2][0], ctrl[0][0], v2);
2647 b = Patch_DegenCurve(ctrl[2][0], ctrl[2][1], ctrl[2][2]);
2650 VectorCopy(ctrl[2][0], vCurve[0]);
2651 VectorCopy(ctrl[2][1], vCurve[1]);
2652 VectorCopy(ctrl[2][2], vCurve[2]);
2653 Patch_BezierInterpolate(vCurve, pMid);
2654 VectorSubtract(pMid, ctrl[0][0], v2);
2659 if (VectorCompare(ctrl[0][0], ctrl[2][0])) // bottom degen
2661 Patch_GetCVTangent(v1, ctrl[0][0], ctrl[2][1], ctrl[2][2]);
2663 else if (VectorCompare(ctrl[0][0], ctrl[0][2])) // left degen
2665 Patch_GetCVTangent(v2, ctrl[0][0], ctrl[1][2], ctrl[2][2]);
2667 else if (VectorCompare(ctrl[0][2], ctrl[2][2])) // top degen
2669 VectorSubtract(ctrl[2][0], ctrl[0][0], v1);
2671 else if (VectorCompare(ctrl[2][0], ctrl[2][2])) // right degen
2673 VectorSubtract(ctrl[0][2], ctrl[0][0], v2);
2675 else // tangents parallel
2677 VectorCopy(v1, vTemp1);
2678 VectorCopy(v2, vTemp2);
2679 VectorNormalize(vTemp1, vTemp1);
2680 VectorNormalize(vTemp2, vTemp2);
2681 if (VectorCompare(vTemp1, vTemp2)) // parallel same way
2683 VectorSubtract(ctrl[2][0], ctrl[0][0], vTemp1);
2684 VectorNormalize(vTemp1, vTemp1);
2685 if (VectorCompare(vTemp1, vTemp2))
2687 VectorSubtract(ctrl[0][2], ctrl[0][0], v2);
2691 VectorCopy(vTemp1, v1);
2694 else // parallel opposite way
2696 VectorCopy(ctrl[2][0], vCurve[0]);
2697 VectorCopy(ctrl[1][1], vCurve[1]);
2698 VectorCopy(ctrl[0][2], vCurve[2]);
2699 Patch_BezierInterpolate(vCurve, pMid);
2700 VectorSubtract(pMid, ctrl[0][0], v2);
2704 CrossProduct(v1, v2, normal);
2708 void Patch_CalcCVNormals(patchMesh_t *patch)
2710 int row, col, i, j, n;
2714 for (col=0; col<patch->width; col+=2)
2716 for (row=0; row<patch->height; row+=2)
2719 if (col+1 != patch->width && row+1 != patch->height)
2723 VectorCopy (patch->ctrl[col+i][row+j].xyz, ctrl[i][j]);
2725 Patch_CVNormal(ctrl, normals[n]);
2726 VectorNormalize(normals[n], normals[n]);
2730 if (col-1 >= 0 && row-1 >= 0)
2734 VectorCopy (patch->ctrl[col-i][row-j].xyz, ctrl[i][j]);
2736 Patch_CVNormal(ctrl, normals[n]);
2737 VectorNormalize(normals[n], normals[n]);
2740 if (col-1 >= 0 && row+1 != patch->height)
2744 VectorCopy (patch->ctrl[col-i][row+j].xyz, ctrl[j][i]);
2746 Patch_CVNormal(ctrl, normals[n]);
2747 VectorNormalize(normals[n], normals[n]);
2750 if (col+1 != patch->width && row-1 >= 0)
2754 VectorCopy (patch->ctrl[col+i][row-j].xyz, ctrl[j][i]);
2756 Patch_CVNormal(ctrl, normals[n]);
2757 VectorNormalize(normals[n], normals[n]);
2763 if (n == 1) patch->ctrl[col][row].normal[i] = normals[0][i];
2764 if (n == 2) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i]) / n;
2765 //if (n == 3) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i]) / n;
2766 if (n == 4) patch->ctrl[col][row].normal[i] = (normals[0][i] + normals[1][i] + normals[2][i] + normals[3][i]) / n;
2768 VectorNormalize(patch->ctrl[col][row].normal, patch->ctrl[col][row].normal);
2769 //if (!g_PrefsDlg.m_bGLLighting)
2770 // ShadeVertex(patch->ctrl[col][row]);
2776 void BTree_SetNormals(BTNode_t *pBT, vec3_t &normal)
2780 if (pBT->left != NULL && pBT->right != NULL)
2782 VectorCopy(normal, pBT->vMid.normal);
2783 //if (!g_PrefsDlg.m_bGLLighting)
2784 // ShadeVertex(pBT->vMid);
2786 BTree_SetNormals(pBT->left, normal);
2787 BTree_SetNormals(pBT->right, normal);
2792 void NormalFromPoints(vec3_t p1, vec3_t p2, vec3_t p3, vec3_t &normal, bool flip = false)
2798 VectorSubtract(p2, p3, v1); //p3->p2
2799 VectorSubtract(p1, p2, v2); //p2->p1
2803 VectorSubtract(p2, p1, v1); //p1->p2
2804 VectorSubtract(p3, p2, v2); //p2->p3
2806 CrossProduct(v1, v2, normal);
2810 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)
2814 if (pBTMid->left != NULL && pBTMid->right != NULL)
2818 if (noleft) // left curve is degenerate
2820 if (nomid) // mid curve is degenerate
2822 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2823 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2827 // VectorCopy(n1, normal);
2828 // NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2832 NormalFromPoints(pBTMid->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2833 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2836 else if (noright) // right curve is degenerate
2838 if (nomid) // mid curve is degenerate
2840 NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2841 NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2845 // NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2846 // VectorCopy(n2, pBTRight->vMid.normal);
2850 NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2851 NormalFromPoints(pBTMid->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2856 if (flat) // all curves are semi-degenerate (flat) or degenerate
2858 NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.xyz, normal, flip);
2859 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTLeft->vMid.xyz, pBTRight->vMid.normal, flip);
2863 NormalFromPoints(pBTLeft->left->info.xyz, pBTLeft->vMid.xyz, pBTMid->vMid.xyz, normal, flip);
2864 NormalFromPoints(pBTRight->right->info.xyz, pBTRight->vMid.xyz, pBTMid->vMid.xyz, pBTRight->vMid.normal, flip);
2868 VectorNormalize(normal, normal);
2870 for (int i=0; i<3; i++)
2871 pBTLeft->vMid.normal[i] = (normal[i] + pBTLeft->vMid.normal[i]) / 2.0f;
2872 else VectorCopy(normal, pBTLeft->vMid.normal);
2874 VectorNormalize(pBTLeft->vMid.normal, pBTLeft->vMid.normal);
2875 VectorNormalize(pBTRight->vMid.normal, pBTRight->vMid.normal);
2878 BTree_GenerateNormals(pBTMid->left, pBTLeft->left, pBTRight->left, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip);
2879 BTree_GenerateNormals(pBTMid->right, pBTLeft->right, pBTRight->right, avg, flat, nomid, noleft, noright, /*endcap, n1, n2,*/ flip);
2885 void Patch_GenerateLODNormals(patchMesh_t *patch)
2887 int col, row, rowpos, colpos, i;
2888 BTNode_t *tree[2][3];
2890 bool rowAvg, colAvg;
2892 for(col=0; col+2<patch->width; col+=2)
2894 for(row=0; row+2<patch->height; row+=2)
2896 if (!patch->colDirty[col/2] && !patch->rowDirty[row/2]) continue;
2898 rowpos = ((col/2)*patch->height)+row;
2899 colpos = ((row/2)*patch->width)+col;
2901 if (row==0) rowAvg = false;
2903 if (col==0) colAvg = false;
2908 tree[0][i] = patch->rowLOD[rowpos+i];
2909 tree[1][i] = patch->colLOD[colpos+i];
2911 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);
2912 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);
2915 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);
2916 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);
2922 void Patch_ClearLODFlags(patchMesh_t *p)
2926 for (i=0;i<(p->width-1)/2; i++)
2927 p->colDirty[i] = false;
2929 for (i=0;i<(p->height-1)/2; i++)
2930 p->rowDirty[i] = false;
2933 // reset the lodDirty flags owned by all patches in the map
2934 // create new LOD trees for all dirty patches, matched with all other patches in the map
2935 void Patch_LODMatchAll()
2937 brush_t *pb, *brushlist;
2940 // create LOD tree roots and LOD tree lists for all patches that are dirty
2942 brushlist = &active_brushes;
2945 for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next)
2947 // create lod for selected patches when patches are filtered
2948 if (pb->bFiltered && (pb->patchBrush && !pb->pPatch->bSelected))
2950 if (!pb->patchBrush)
2952 if (!pb->pPatch->bDirty)
2955 Patch_CalcCVNormals(pb->pPatch);
2956 Patch_CreateLODTrees(pb->pPatch);
2958 brushlist = &selected_brushes;
2961 brushlist = &active_brushes;
2964 for (pb = brushlist->next; pb && (pb != brushlist); pb=pb->next)
2966 if (!pb->patchBrush)
2969 if (pb->pPatch->LODUpdated)
2970 Patch_GenerateLODNormals(pb->pPatch);
2972 Patch_ClearLODFlags(pb->pPatch);
2974 brushlist = &selected_brushes;
2979 void Vertex_TransformTexture(drawVert_t *pVert, float fx, float fy, transformtype xform)
2992 float x = pVert->st[0];
2993 float y = pVert->st[1];
2994 pVert->st[0] = x * fx - y * fy;
2995 pVert->st[1] = y * fx + x * fy;
2999 void BTree_TransformTexture(BTNode_t *pBT, float fx, float fy, transformtype xform)
3002 { // PreOrder traversal
3003 Vertex_TransformTexture(&pBT->info, fx, fy, xform);
3004 Vertex_TransformTexture(&pBT->vMid, fx, fy, xform);
3005 BTree_TransformTexture(pBT->left, fx, fy, xform);
3006 BTree_TransformTexture(pBT->right, fx, fy, xform);
3010 void Patch_TransformLODTexture(patchMesh_t *p, float fx, float fy, transformtype xform)
3014 for(col=1; col<p->width; col+=2)
3015 for(row=0; row<p->height; row++)
3016 BTree_TransformTexture(p->rowLOD[(((col-1)/2)*p->height)+row], fx, fy, xform);
3018 for(row=1; row<p->height; row+=2)
3019 for(col=0; col<p->width; col++)
3020 BTree_TransformTexture(p->colLOD[(((row-1)/2)*p->width)+col], fx, fy, xform);
3023 void Patch_AddBTreeToDrawListInOrder(list<drawVert_t> *drawList, BTNode_t *pBT)
3025 if (pBT != NULL) //traverse InOrder
3027 Patch_AddBTreeToDrawListInOrder(drawList, pBT->left);
3028 if (pBT->left != NULL && pBT->right != NULL)
3029 drawList->push_back(pBT->vMid);
3030 Patch_AddBTreeToDrawListInOrder(drawList, pBT->right);
3034 void Patch_InterpolateListFromRowBT(list<drawVert_t> *drawList, BTNode_t *rowBT, BTNode_t *rowBTLeft, drawVert_t *vCurve[], float u, float n, float v)
3038 Patch_InterpolateListFromRowBT(drawList, rowBT->left, rowBTLeft->left, vCurve, u-n, n*0.5f, v);
3039 if (rowBT->left != NULL && rowBT->right != NULL)
3042 drawVert_t newVert, vTemp1, vTemp2;
3043 Patch_CurveSplit(vCurve, vTemp1, vTemp2, newVert, u);
3044 for (int i=0; i<3; i++)
3046 v1[i] = rowBT->vMid.xyz[i] - rowBTLeft->vMid.xyz[i]; // left -> mid
3047 v1[i] = rowBTLeft->vMid.xyz[i] + (v1[i] * v);
3048 v1[i] = newVert.xyz[i] - v1[i];
3050 VectorSubtract(vTemp1.xyz, newVert.xyz, v2);
3051 CrossProduct(v1, v2, newVert.normal);
3052 VectorNormalize(newVert.normal, newVert.normal);
3053 //if (!g_PrefsDlg.m_bGLLighting)
3054 // ShadeVertex(newVert);
3055 drawList->push_back(newVert);
3057 Patch_InterpolateListFromRowBT(drawList, rowBT->right, rowBTLeft->right, vCurve, u+n, n*0.5f, v);
3061 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)
3065 //traverse subtree In Order
3066 Patch_TraverseColBTInOrder(iter, colBTLeft->left, colBT->left, colBTRight->left, rowBT, rowBTLeft, v-n, n*0.5f);
3067 if (colBT->left != NULL && colBT->right != NULL)
3069 drawVert_t *vCurve[3];
3070 vCurve[0] = &colBTLeft->vMid;
3071 vCurve[1] = &colBT->vMid;
3072 vCurve[2] = &colBTRight->vMid;
3073 Patch_InterpolateListFromRowBT((*iter), rowBT, rowBTLeft, vCurve, 0.5f, 0.25f, v);
3075 (*iter)->push_back(colBTRight->vMid);
3078 Patch_TraverseColBTInOrder(iter, colBTLeft->right, colBT->right, colBTRight->right, rowBT, rowBTLeft, v+n, n*0.5f);
3083 void Patch_StartDrawLists(list<list<drawVert_t>*> *drawLists, BTNode_t *colBT)
3087 //traverse subtree In Order
3088 Patch_StartDrawLists(drawLists, colBT->left);
3089 if (colBT->left != NULL && colBT->right != NULL)
3091 list<drawVert_t> *newList = new list<drawVert_t>;
3092 drawLists->push_back(newList); // add empty list to back
3093 drawLists->back()->push_back(colBT->vMid);
3095 Patch_StartDrawLists(drawLists, colBT->right);
3099 typedef list<drawVert_t> drawList_t;
3100 typedef list<list<drawVert_t>*> drawLists_t;
3102 void Patch_CreateDrawLists(patchMesh_t *patch)
3104 int col, row, colpos, rowpos;
3106 drawLists_t *drawLists = new drawLists_t;
3108 drawLists_t::iterator iter1, iter2;
3110 for (row=0; row<patch->height; row+=2)
3112 colpos = (row/2)*patch->width;
3113 drawList_t *newList = new drawList_t;
3114 drawLists->push_back(newList); // add a new empty list to back
3115 drawLists->back()->push_back(patch->ctrl[0][row]); // fill list at back
3117 if (row+1 == patch->height)
3119 Patch_StartDrawLists(drawLists, patch->colLOD[colpos]);
3122 iter1 = drawLists->begin();
3123 for (row=0; row<patch->height; row+=2)
3126 for (col=0; col+1<patch->width; col+=2)
3129 colpos = ((row/2)*patch->width)+col;
3130 rowpos = ((col/2)*patch->height)+row;
3132 Patch_AddBTreeToDrawListInOrder((*iter1), patch->rowLOD[rowpos]);
3133 (*iter1)->push_back(patch->ctrl[col+2][row]);
3135 if (row+1 == patch->height)
3140 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);
3144 patch->drawLists = drawLists;
3148 void Patch_DeleteDrawLists(patchMesh_t *patch)
3150 drawLists_t *drawLists;
3151 drawLists_t::iterator iter;
3153 if (patch->drawLists == NULL)
3156 drawLists = (drawLists_t *)patch->drawLists;
3158 for (iter=drawLists->begin(); iter != drawLists->end(); iter++)
3164 patch->drawLists = NULL;
3168 void Patch_DrawLODPatchMesh(patchMesh_t *patch)
3170 drawLists_t *drawLists;
3172 drawLists_t::iterator iterLists, iterListsNext;
3173 drawList_t::iterator iterList, iterListNext;
3175 //int nGLState = g_pParentWnd->GetCamera()->Camera()->draw_glstate;
3177 if (patch->drawLists == NULL)
3180 drawLists = (drawLists_t *)patch->drawLists;
3182 iterListsNext=drawLists->begin();
3184 for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++)
3186 // traverse two drawlists at once to draw a strip
3187 //if (nGLState & DRAW_GL_LINE)
3188 qglBegin(GL_QUAD_STRIP);
3190 // qglBegin(GL_TRIANGLE_STRIP);
3191 for (iterList=(*iterLists)->begin(), iterListNext=(*iterListsNext)->begin(); iterList != (*iterLists)->end() && iterListNext != (*iterListsNext)->end(); iterList++, iterListNext++)
3193 //if (g_PrefsDlg.m_bGLLighting)
3194 qglNormal3fv((*iterList).normal);
3195 //else if (bShade && !g_PrefsDlg.m_bDisplayLists)
3196 // qglColor3f((*iterList).lightmap[0], (*iterList).lightmap[0], (*iterList).lightmap[0]);
3198 qglTexCoord2fv((*iterList).st);
3199 qglVertex3fv((*iterList).xyz);
3201 //if (g_PrefsDlg.m_bGLLighting)
3202 qglNormal3fv((*iterListNext).normal);
3203 //else if (bShade && !g_PrefsDlg.m_bDisplayLists)
3204 // qglColor3f((*iterListNext).lightmap[0], (*iterListNext).lightmap[0], (*iterListNext).lightmap[0]);
3206 qglTexCoord2fv((*iterListNext).st);
3207 qglVertex3fv((*iterListNext).xyz);
3214 for (iterLists=drawLists->begin(); iterLists != drawLists->end(); iterLists++)
3216 qglBegin (GL_LINES); // draw normals
3217 //qglColor3f(1,1,1);
3218 for (iterList=(*iterLists)->begin(); iterList != (*iterLists)->end(); iterList++)
3220 VectorAdd((*iterList).xyz, (*iterList).normal, vNormal);
3221 qglVertex3fv ((*iterList).xyz);
3222 qglVertex3fv (vNormal);
3227 Patch_DrawNormals(patch);
3234 // fast memory-efficient ray-triangle intersection - MollerTrumbore97
3236 #define EPSILON 0.000001
3237 #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];}
3238 #define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
3239 #define SUB(dest,v1,v2) {dest[0]=v1[0]-v2[0];dest[1]=v1[1]-v2[1];dest[2]=v1[2]-v2[2];}
3241 int intersect_triangle(float orig[3], float dir[3],
3242 float vert0[3], float vert1[3], float vert2[3],
3243 double *t, double *u, double *v)
3245 double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
3248 // find vectors for two edges sharing vert0
3249 SUB(edge1, vert1, vert0);
3250 SUB(edge2, vert2, vert0);
3252 // begin calculating determinant - also used to calculate U parameter
3253 CROSS(pvec, dir, edge2);
3255 // if determinant is near zero, ray lies in plane of triangle
3256 det = DOT(edge1, pvec);
3258 #ifdef TEST_CULL // define TEST_CULL if culling is desired
3262 // calculate distance from vert0 to ray origin
3263 SUB(tvec, orig, vert0);
3265 // calculate U parameter and test bounds
3266 *u = DOT(tvec, pvec);
3267 if (*u < 0.0 || *u > det)
3270 // prepare to test V parameter
3271 CROSS(qvec, tvec, edge1);
3273 // calculate V parameter and test bounds
3274 *v = DOT(dir, qvec);
3275 if (*v < 0.0 || *u + *v > det)
3278 // calculate t, scale parameters, ray intersects triangle
3279 *t = DOT(edge2, qvec);
3280 inv_det = 1.0 / det;
3284 #else // the non-culling branch
3285 if (det > -EPSILON && det < EPSILON)
3287 inv_det = 1.0 / det;
3289 // calculate distance from vert0 to ray origin
3290 SUB(tvec, orig, vert0);
3292 // calculate U parameter and test bounds
3293 *u = DOT(tvec, pvec) * inv_det;
3294 if (*u < 0.0 || *u > 1.0)
3297 // prepare to test V parameter
3298 CROSS(qvec, tvec, edge1);
3300 // calculate V parameter and test bounds
3301 *v = DOT(dir, qvec) * inv_det;
3302 if (*v < 0.0 || *u + *v > 1.0)
3305 // calculate t, ray intersects triangle
3306 *t = DOT(edge2, qvec) * inv_det;
3312 int Triangle_Ray(float orig[3], float dir[3], bool bCullBack,
3313 float vert0[3], float vert1[3], float vert2[3],
3314 double *t, double *u, double *v)
3316 float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
3319 /* find vectors for two edges sharing vert0 */
3320 VectorSubtract(vert1, vert0, edge1);
3321 VectorSubtract(vert2, vert0, edge2);
3323 /* begin calculating determinant - also used to calculate U parameter */
3324 CrossProduct(dir, edge2, pvec);
3326 /* if determinant is near zero, ray lies in plane of triangle */
3327 det = DotProduct(edge1, pvec);
3334 // calculate distance from vert0 to ray origin
3335 VectorSubtract(orig, vert0, tvec);
3337 // calculate U parameter and test bounds
3338 *u = DotProduct(tvec, pvec);
3339 if (*u < 0.0 || *u > det)
3342 // prepare to test V parameter
3343 CrossProduct(tvec, edge1, qvec);
3345 // calculate V parameter and test bounds
3346 *v = DotProduct(dir, qvec);
3347 if (*v < 0.0 || *u + *v > det)
3350 // calculate t, scale parameters, ray intersects triangle
3351 *t = DotProduct(edge2, qvec);
3352 inv_det = 1.0 / det;
3359 /* the non-culling branch */
3360 if (det > -0.000001 && det < 0.000001)
3362 inv_det = 1.0 / det;
3364 /* calculate distance from vert0 to ray origin */
3365 VectorSubtract(orig, vert0, tvec);
3367 /* calculate U parameter and test bounds */
3368 *u = DotProduct(tvec, pvec) * inv_det;
3369 if (*u < 0.0 || *u > 1.0)
3372 /* prepare to test V parameter */
3373 CrossProduct(tvec, edge1, qvec);
3375 /* calculate V parameter and test bounds */
3376 *v = DotProduct(dir, qvec) * inv_det;
3377 if (*v < 0.0 || *u + *v > 1.0)
3380 /* calculate t, ray intersects triangle */
3381 *t = DotProduct(edge2, qvec) * inv_det;
3386 bool Patch_Ray(patchMesh_t *patch, vec3_t origin, vec3_t dir, double *t, double *u, double *v)
3388 drawLists_t *drawLists;
3390 drawLists_t::iterator iterLists, iterListsNext;
3391 drawList_t::iterator i1, i2, i3, i4;
3393 // vec3_t tris[2][3];
3394 bool bIntersect = false;
3395 float tBest = FLT_MAX;
3397 if (patch->drawLists == NULL)
3400 drawLists = (drawLists_t *)patch->drawLists;
3402 iterListsNext=drawLists->begin();
3404 for (iterLists=drawLists->begin(); iterLists != drawLists->end() && iterListsNext != drawLists->end(); iterLists++, iterListsNext++)
3406 // traverse two drawlists at once with two iterators each to triangulate
3407 i1 = i3 = (*iterLists)->begin();
3408 i2 = i4 = (*iterListsNext)->begin();
3411 while (i3 != (*iterLists)->end() && i4 != (*iterListsNext)->end())
3413 if (Triangle_Ray(origin, dir, false, (*i1).xyz, (*i2).xyz, (*i3).xyz, t, u, v))
3419 if (Triangle_Ray(origin, dir, false, (*i3).xyz, (*i4).xyz, (*i2).xyz, t, u, v))
3443 // spog - curve LOD stuff ends
3450 void DrawPatchMesh(patchMesh_t *pm)
3452 if (g_PrefsDlg.m_bDisplayLists)
3454 if (pm->bDirty || pm->nListID <= 0 || pm->LODUpdated)
3456 if (pm->nListID <= 0)
3457 pm->nListID = qglGenLists(1);
3458 if (pm->nListID > 0)
3460 qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE);
3463 Patch_DeleteDrawLists(pm);
3464 Patch_CreateDrawLists(pm);
3466 Patch_DrawLODPatchMesh(pm);
3468 if (pm->nListID > 0)
3474 pm->LODUpdated = false;
3478 qglCallList(pm->nListID);
3483 if (pm->bDirty || pm->LODUpdated)
3485 Patch_DeleteDrawLists(pm);
3486 Patch_CreateDrawLists(pm);
3488 pm->LODUpdated = false;
3490 Patch_DrawLODPatchMesh(pm);
3499 void DrawPatchControls(patchMesh_t *pm)
3502 bool bSelectedPoints[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT];
3504 bool bOverlay = pm->bOverlay;
3507 if (g_bPatchBendMode)
3510 if (g_bPatchAxisOnRow)
3512 qglColor3f(1, 0, 1);
3513 if(!g_PrefsDlg.m_bGlPtWorkaround)
3515 qglBegin(GL_POINTS);
3516 for (i = 0; i < pm->width; i++)
3518 qglVertex3fv(pm->ctrl[i][g_nPatchAxisIndex].xyz);
3526 for(i = 0; i < pm->width; i++)
3528 DrawAlternatePoint(pm->ctrl[i][g_nPatchAxisIndex].xyz, 0);
3534 if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
3536 if(!g_PrefsDlg.m_bGlPtWorkaround)
3538 qglColor3f(0, 0, 1);
3539 qglBegin(GL_POINTS);
3540 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
3542 qglVertex3fv(g_vBendOrigin);
3546 for (i = 0; i < pm->width; i++)
3548 if (g_bPatchLowerEdge)
3550 for (j = 0; j < g_nPatchAxisIndex; j++)
3551 qglVertex3fv(pm->ctrl[i][j].xyz);
3555 for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
3556 qglVertex3fv(pm->ctrl[i][j].xyz);
3563 qglColor3f(0, 0, 1);
3566 if(g_nPatchBendState == BEND_SELECT_ORIGIN)
3568 DrawAlternatePoint(g_vBendOrigin, 0);
3572 for(i = 0; i < pm->width; i++)
3574 if(g_bPatchLowerEdge)
3576 for(j = 0; j < g_nPatchAxisIndex; j++)
3578 DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3583 for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
3585 DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3597 if(!g_PrefsDlg.m_bGlPtWorkaround)
3599 qglColor3f(1, 0, 1);
3600 qglBegin(GL_POINTS);
3601 for (i = 0; i < pm->height; i++)
3603 qglVertex3fv(pm->ctrl[g_nPatchAxisIndex][i].xyz);
3608 qglColor3f(1, 0, 1);
3611 for(i = 0; i < pm->height; i++)
3613 DrawAlternatePoint(pm->ctrl[g_nPatchAxisIndex][i].xyz, 0);
3619 if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
3621 if(!g_PrefsDlg.m_bGlPtWorkaround)
3623 qglColor3f(0, 0, 1);
3624 qglBegin(GL_POINTS);
3625 for (i = 0; i < pm->height; i++)
3627 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
3629 qglVertex3fv(pm->ctrl[g_nBendOriginIndex][i].xyz);
3633 if (g_bPatchLowerEdge)
3635 for (j = 0; j < g_nPatchAxisIndex; j++)
3636 qglVertex3fv(pm->ctrl[j][i].xyz);
3640 for (j = pm->width-1; j > g_nPatchAxisIndex; j--)
3641 qglVertex3fv(pm->ctrl[j][i].xyz);
3648 qglColor3f(0, 0, 1);
3651 for(i = 0; i < pm->height; i++)
3653 if(g_nPatchBendState == BEND_SELECT_ORIGIN)
3655 DrawAlternatePoint(pm->ctrl[g_nBendOriginIndex][i].xyz, 0);
3659 if(g_bPatchLowerEdge)
3661 for(j = 0; j < g_nPatchAxisIndex; j++)
3663 DrawAlternatePoint(pm->ctrl[j][i].xyz, 0);
3668 for(j = pm->width-1; j > g_nPatchAxisIndex; j--)
3670 DrawAlternatePoint(pm->ctrl[j][i].xyz, 0);
3683 //qglDisable(GL_TEXTURE_2D); // stops point colours being multiplied by texture colour..
3684 //draw CV lattice - could be made optional
3685 //qglDisable( GL_CULL_FACE );
3686 // qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3687 qglEnable (GL_POLYGON_OFFSET_LINE);
3688 if (g_PrefsDlg.m_bNoStipple == FALSE)
3689 qglDisable (GL_LINE_STIPPLE);
3691 qglColor3f(1.0f, 0.75f, 0.0f);
3692 for ( i = 0 ; i+1 < pm->width ; i++ )
3694 qglBegin(GL_QUAD_STRIP);
3695 for ( j = 0 ; j < pm->height ; j++ )
3697 qglVertex3fv(pm->ctrl[i][j].xyz);
3698 qglVertex3fv(pm->ctrl[i+1][j].xyz);
3702 qglDisable (GL_POLYGON_OFFSET_LINE);
3703 //if (g_PrefsDlg.m_bNoStipple == FALSE)
3704 // qglEnable (GL_LINE_STIPPLE);
3706 // draw selection handles
3707 if(!g_PrefsDlg.m_bGlPtWorkaround)
3710 qglBegin(GL_POINTS);
3711 for ( i = 0 ; i < pm->width ; i++ )
3713 for ( j = 0 ; j < pm->height ; j++ )
3715 if (PointInMoveList(pm->ctrl[i][j].xyz) != -1)
3717 bSelectedPoints[i][j] = true;
3721 bSelectedPoints[i][j] = false;
3722 if (i & 0x01 || j & 0x01)
3723 qglColor3f(1, 0, 1);
3725 qglColor3f(0, 1, 0);
3727 qglVertex3fv(pm->ctrl[i][j].xyz);
3731 qglColor3f(0, 0, 1);
3732 for ( i = 0 ; i < pm->width ; i++ )
3734 for ( j = 0 ; j < pm->height ; j++ )
3736 if (bSelectedPoints[i][j])
3737 qglVertex3fv(pm->ctrl[i][j].xyz);
3746 for(i = 0; i < pm->width; i++)
3748 for(j = 0; j < pm->height; j++)
3750 if(PointInMoveList(pm->ctrl[i][j].xyz) != -1)
3752 bSelectedPoints[i][j] = true;
3756 bSelectedPoints[i][j] = false;
3757 if(i & 0x01 || j & 0x01)
3758 qglColor3f(1, 0, 1);
3760 qglColor3f(0, 1, 0);
3763 DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3767 qglColor3f(0, 0, 1);
3768 for(i = 0; i < pm->width; i++)
3770 for(j = 0; j < pm->height; j++)
3772 if(bSelectedPoints[i][j])
3775 DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3785 if(!g_PrefsDlg.m_bGlPtWorkaround)
3788 qglBegin(GL_POINTS);
3789 for ( i = 0 ; i < pm->width ; i++ )
3791 for ( j = 0 ; j < pm->height ; j++ )
3793 if (i & 0x01 || j & 0x01)
3794 qglColor3f(1, 0, 1);
3796 qglColor3f(0, 1, 0);
3797 qglVertex3fv(pm->ctrl[i][j].xyz);
3806 for ( i = 0 ; i < pm->width ; i++ )
3808 for ( j = 0 ; j < pm->height ; j++ )
3810 if (i & 0x01 || j & 0x01)
3811 qglColor3f(1, 0, 1);
3813 qglColor3f(0, 1, 0);
3815 DrawAlternatePoint(pm->ctrl[i][j].xyz, 0);
3830 void Patch_DrawXY(patchMesh_t *pm)
3832 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3836 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
3837 if (g_PrefsDlg.m_bNoStipple == FALSE)
3838 qglEnable (GL_LINE_STIPPLE);
3844 if ( (pm->bSelected && (g_qeglobals.d_select_mode == sel_curvepoint
3845 || g_qeglobals.d_select_mode == sel_area
3846 || g_bPatchBendMode))
3848 DrawPatchControls(pm);
3856 void Patch_DrawCam(patchMesh_t *pm)
3858 qglPushAttrib(GL_ALL_ATTRIB_BITS); // save the current state
3860 if (g_bPatchWireFrame)
3862 qglDisable( GL_CULL_FACE );
3863 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3864 qglDisable(GL_TEXTURE_2D);
3865 if (g_PrefsDlg.m_bGLLighting)
3866 qglDisable(GL_LIGHTING);
3870 //if (g_PrefsDlg.m_bGLLighting)
3871 // qglEnable(GL_LIGHTING);
3872 //qglEnable( GL_CULL_FACE );
3876 qglDisable(GL_CULL_FACE);
3877 qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number);
3878 qglPolygonMode (GL_FRONT, GL_FILL);
3879 qglPolygonMode (GL_BACK, GL_LINE);
3881 if (pm->pShader->getTrans() < 1.0f)
3883 qglEnable(GL_BLEND);
3884 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3885 qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->pShader->getTrans());
3888 DrawPatchMesh(pm); // both sides
3891 qglPopAttrib(); // restore saved state
3894 void ConvexHullForSection( float section[2][4][7] ) {
3897 void BrushesForSection( float section[2][4][7] ) {
3905 void Patch_BuildPoints (brush_t *b)
3908 b->patchBrush = false;
3909 for (f=b->brush_faces ; f ; f=f->next)
3911 if (f->texdef.flags & SURF_PATCH)
3913 b->patchBrush = true;
3914 //vec3_t vMin, vMax;
3915 //Patch_CalcBounds(&patchMeshes[b->nPatchID], vMin, vMax);
3916 //VectorCopy(vMin, b->mins);
3917 //VectorCopy(vMax, b->maxs);
3928 void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild)
3931 for (int w = 0; w < pm->width; w++)
3933 for (int h = 0; h < pm->height; h++)
3935 VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz);
3938 // bRebuild is never true
3942 Patch_CalcBounds(pm, vMin, vMax);
3943 //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax);
3945 UpdatePatchInspector();
3954 void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap)
3958 for (int w = 0; w < p->width; w++)
3960 for (int h = 0; h < p->height; h++)
3962 if (((g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0) || g_bPatchBendMode)
3963 && PointInMoveList(p->ctrl[w][h].xyz) == -1) // snap selected points only, if selected
3965 VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp);
3966 for (int j = 0; j < 3; j++)
3968 p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j];
3971 p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5);
3977 Patch_CalcBounds(p, vMin, vMax);
3978 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
3986 void Patch_EditPatch()
3988 //--patchMesh_t* p = &patchMeshes[n];
3989 g_qeglobals.d_numpoints = 0;
3990 g_qeglobals.d_num_move_points = 0;
3992 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
3996 patchMesh_t* p = pb->pPatch;
3997 for ( int i = 0 ; i < p->width ; i++ )
3999 for ( int j = 0 ; j < p->height ; j++ )
4001 VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
4002 if (g_qeglobals.d_numpoints < MAX_POINTS-1)
4004 g_qeglobals.d_numpoints++;
4010 g_qeglobals.d_select_mode = sel_curvepoint;
4011 //--g_nSelectedPatch = n;
4021 //FIXME: need all sorts of asserts throughout a lot of this crap
4022 void Patch_Deselect()
4024 //--g_nSelectedPatch = -1;
4025 g_qeglobals.d_select_mode = sel_brush;
4027 for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
4031 b->pPatch->bSelected = false;
4035 //for (int i = 0; i < numPatchMeshes; i++)
4036 // patchMeshes[i].bSelected = false;
4038 if (g_bPatchBendMode)
4040 // if (g_bPatchInsertMode)
4041 // Patch_InsDelToggle();
4050 void Patch_Select(patchMesh_t *p)
4052 // maintained for point manip.. which i need to fix as this
4053 // is pf error prone
4054 //--g_nSelectedPatch = n;
4055 p->bSelected = true;
4064 void Patch_Deselect(patchMesh_t *p)
4066 p->bSelected = false;
4075 extern BTNode_t *BTree_Delete(BTNode_t *pBT);
4076 extern BTListList_t *BTree_DeleteListFromList(BTListList_t *pBTListList);
4078 void Patch_Delete(patchMesh_t *p)
4080 if (p->pSymbiot) // Hydra - added a check to prevent access violations.
4082 p->pSymbiot->pPatch = NULL;
4083 p->pSymbiot->patchBrush = false;
4086 // spog - free dynamically allocated memory used by LODs
4087 int rowcount = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT;
4088 int colcount = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH;
4090 for (i=0; i<rowcount; i++)
4091 p->rowLOD[i] = BTree_Delete(p->rowLOD[i]);
4092 for (i=0; i<colcount; i++)
4093 p->colLOD[i] = BTree_Delete(p->colLOD[i]);
4095 // delete display list associated with patch
4096 if (p->nListID != -1)
4097 qglDeleteLists (p->nListID, 1); // list#, number of lists
4099 // delete LOD drawLists
4100 Patch_DeleteDrawLists(p);
4107 UpdatePatchInspector();
4116 void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild)
4119 for (int w = 0; w < p->width; w++)
4121 for (int h = 0; h < p->height; h++)
4123 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
4125 for (int i=0 ; i<3 ; i++)
4127 p->ctrl[w][h].xyz[i] -= vOrigin[i];
4128 p->ctrl[w][h].xyz[i] *= vAmt[i];
4129 p->ctrl[w][h].xyz[i] += vOrigin[i];
4136 Patch_CalcBounds(p, vMin, vMax);
4137 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
4139 UpdatePatchInspector();
4148 void Patch_SetView(int n)
4150 g_bSameView = (n == g_nPatchClickedView);
4151 g_nPatchClickedView = n;
4160 // FIXME: need array validation throughout
4161 void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef)
4163 // NOTE: I don't know for sure if this happens
4165 p->pShader->DecRef();
4166 p->pShader = QERApp_Shader_ForName(tex_def->GetName());
4167 p->pShader->IncRef();
4168 p->d_texture = p->pShader->getTexture();
4170 UpdatePatchInspector();
4179 bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove)
4181 vec3_t vMin, vMax, vScale, vTemp, vMid;
4184 Patch_CalcBounds(p, vMin, vMax);
4186 VectorSubtract(vMax, vMin, vTemp);
4188 // if we are scaling in the same dimension the patch has no depth
4189 for (i = 0; i < 3; i ++)
4191 if (vTemp[i] == 0 && vMove[i] != 0)
4193 //Patch_Move(n, vMove, true);
4198 for (i=0 ; i<3 ; i++)
4199 vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2));
4201 for (i = 0; i < 3; i++)
4205 vScale[i] = 1.0 + vAmt[i] / vTemp[i];
4213 Patch_Scale(p, vMid, vScale, false);
4215 VectorSubtract(vMax, vMin, vTemp);
4217 Patch_CalcBounds(p, vMin, vMax);
4219 VectorSubtract(vMax, vMin, vMid);
4221 VectorSubtract(vMid, vTemp, vTemp);
4223 VectorScale(vTemp, 0.5, vTemp);
4225 // abs of both should always be equal
4226 if (!VectorCompare(vMove, vAmt))
4228 for (i = 0; i < 3; i++)
4230 if (vMove[i] != vAmt[i])
4231 vTemp[i] = -(vTemp[i]);
4235 Patch_Move(p, vTemp);
4244 void Patch_InsertColumn(patchMesh_t *p, bool bAdd)
4250 if (p->width + 2 >= MAX_PATCH_WIDTH)
4253 // check for selected column points
4254 for (h = 0; h < p->height; h++)
4256 for (w = 1; w < p->width; w+=2)
4257 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4261 for (w = 0; w < p->width; w+=2)
4262 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4270 if (bAdd) w=p->width-1;
4277 for (h = 0; h < p->height; h++)
4279 for (width = p->width-1; width > w; width--)
4280 memcpy(&p->ctrl[width+2][h],&p->ctrl[width][h], sizeof(drawVert_t));
4282 // set two new column points
4283 memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t));
4284 memcpy(&p->ctrl[w+1][h],&p->ctrl[w-1][h], sizeof(drawVert_t));
4286 for (i=0; i<3; i++) // xyz
4288 vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4289 p->ctrl[w+1][h].xyz[i] = p->ctrl[w+1][h].xyz[i] + (vTemp[i] / 2);
4291 vTemp[i] = p->ctrl[w-2][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4292 p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2);
4294 vTemp[i] = p->ctrl[w+1][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4295 p->ctrl[w][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] / 2);
4297 for (i=0; i<2; i++) // st
4299 stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i];
4300 p->ctrl[w+1][h].st[i] = p->ctrl[w+1][h].st[i] + (stTemp[i] / 2);
4302 stTemp[i] = p->ctrl[w-2][h].st[i] - p->ctrl[w-1][h].st[i];
4303 p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2);
4305 stTemp[i] = p->ctrl[w+1][h].st[i] - p->ctrl[w-1][h].st[i];
4306 p->ctrl[w][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] / 2);
4311 // deselect all points to keep things neat
4312 if (g_qeglobals.d_select_mode == sel_curvepoint)
4315 UpdatePatchInspector();
4324 void Patch_InsertRow(patchMesh_t *p, bool bAdd)
4326 int h, w, i, height;
4330 if (p->height + 2 >= MAX_PATCH_HEIGHT)
4333 // check for selected row points
4334 for (w = 0; w < p->width; w++)
4336 for (h = 1; h < p->height; h+=2)
4337 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4341 for (h = 0; h < p->height; h+=2)
4342 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4349 if (bAdd) h=p->height-1;
4356 for (w = 0; w < p->width; w++)
4358 for (height = p->height-1; height > h; height--)
4359 memcpy(&p->ctrl[w][height+2],&p->ctrl[w][height], sizeof(drawVert_t));
4361 // set two new row points
4362 memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t));
4363 memcpy(&p->ctrl[w][h+1],&p->ctrl[w][h-1], sizeof(drawVert_t));
4365 for (i=0; i<3; i++) // xyz
4367 vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i];
4368 p->ctrl[w][h+1].xyz[i] = p->ctrl[w][h+1].xyz[i] + (vTemp[i] / 2);
4370 vTemp[i] = p->ctrl[w][h-2].xyz[i] - p->ctrl[w][h-1].xyz[i];
4371 p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2);
4373 vTemp[i] = p->ctrl[w][h+1].xyz[i] - p->ctrl[w][h-1].xyz[i];
4374 p->ctrl[w][h].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] / 2);
4376 for (i=0; i<2; i++) // st
4378 stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i];
4379 p->ctrl[w][h+1].st[i] = p->ctrl[w][h+1].st[i] + (stTemp[i] / 2);
4381 stTemp[i] = p->ctrl[w][h-2].st[i] - p->ctrl[w][h-1].st[i];
4382 p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2);
4384 stTemp[i] = p->ctrl[w][h+1].st[i] - p->ctrl[w][h-1].st[i];
4385 p->ctrl[w][h].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] / 2);
4390 // deselect all points to keep things neat
4391 if (g_qeglobals.d_select_mode == sel_curvepoint)
4394 UpdatePatchInspector();
4402 void Patch_RemoveRow(patchMesh_t *p, bool bFirst)
4404 int w, h, i, height;
4407 bool bExtrapolate = true;
4409 if (p->height <= MIN_PATCH_HEIGHT)
4412 for (w = 0; w < p->width; w++)
4414 for (h = 0; h < p->height; h+=2)
4415 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4419 for (h = 1; h < p->height; h+=2)
4420 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4428 bExtrapolate = false;
4429 if (bFirst) h=p->height-3;
4432 else if (h <= 0) h=2;
4433 else if (h > p->height-3) h = p->height-3;
4438 for (w = 0; w < p->width; w++)
4442 for (i = 0; i < 3; i++) // xyz
4444 vTemp[i] = p->ctrl[w][h+2].xyz[i] - p->ctrl[w][h-2].xyz[i];
4445 p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-2].xyz[i] + (vTemp[i] / 2);
4447 vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w][h-1].xyz[i];
4448 p->ctrl[w][h-1].xyz[i] = p->ctrl[w][h-1].xyz[i] + (vTemp[i] * 2);
4451 for (i = 0; i < 2; i++) // st
4453 stTemp[i] = p->ctrl[w][h+2].st[i] - p->ctrl[w][h-2].st[i];
4454 p->ctrl[w][h-1].st[i] = p->ctrl[w][h-2].st[i] + (stTemp[i] / 2);
4456 stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w][h-1].st[i];
4457 p->ctrl[w][h-1].st[i] = p->ctrl[w][h-1].st[i] + (stTemp[i] * 2);
4466 for (height = h; height < p->height; height++)
4467 memcpy(&p->ctrl[w][height], &p->ctrl[w][height+2], sizeof(drawVert_t));
4469 // deselect all points to keep things neat
4470 if (g_qeglobals.d_select_mode == sel_curvepoint)
4473 UpdatePatchInspector();
4481 void Patch_RemoveColumn(patchMesh_t *p, bool bFirst)
4486 bool bExtrapolate = true;
4488 if (p->width <= MIN_PATCH_WIDTH)
4491 for (h = 0; h < p->height; h++)
4493 for (w = 0; w < p->width; w+=2)
4494 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4498 for (w = 1; w < p->width; w+=2)
4499 if (PointInMoveList(p->ctrl[w][h].xyz) != -1)
4507 bExtrapolate = false;
4508 if (bFirst) w=p->width-3;
4512 else if (w > p->width-3) w = p->width-3;
4517 for (h = 0; h < p->height; h++)
4521 for (i = 0; i < 3; i++) // xyz
4523 vTemp[i] = p->ctrl[w+2][h].xyz[i] - p->ctrl[w-2][h].xyz[i];
4524 p->ctrl[w-1][h].xyz[i] = p->ctrl[w-2][h].xyz[i] + (vTemp[i] / 2);
4526 vTemp[i] = p->ctrl[w][h].xyz[i] - p->ctrl[w-1][h].xyz[i];
4527 p->ctrl[w-1][h].xyz[i] = p->ctrl[w-1][h].xyz[i] + (vTemp[i] * 2);
4530 for (i = 0; i < 2; i++) // st
4532 stTemp[i] = p->ctrl[w+2][h].st[i] - p->ctrl[w-2][h].st[i];
4533 p->ctrl[w-1][h].st[i] = p->ctrl[w-2][h].st[i] + (stTemp[i] / 2);
4535 stTemp[i] = p->ctrl[w][h].st[i] - p->ctrl[w-1][h].st[i];
4536 p->ctrl[w-1][h].st[i] = p->ctrl[w-1][h].st[i] + (stTemp[i] * 2);
4546 for (width = w; width < p->width; width++)
4547 memcpy(&p->ctrl[width][h], &p->ctrl[width+2][h], sizeof(drawVert_t));
4549 // deselect all points to keep things neat
4550 if (g_qeglobals.d_select_mode == sel_curvepoint)
4553 UpdatePatchInspector();
4562 void Patch_AdjustColumns(patchMesh_t *p, int nCols)
4564 vec3_t vTemp, vTemp2;
4567 if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH)
4570 // add in column adjustment
4573 for (h = 0; h < p->height; h++)
4575 // for each column, we need to evenly disperse p->width number
4576 // of points across the old bounds
4578 // calc total distance to interpolate
4579 VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp);
4582 for (i = 0; i < 3; i ++)
4584 vTemp2[i] = vTemp[i] / (p->width - 1);
4588 for (w = 0; w < p->width-1; w++)
4590 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
4594 for ( w = 0 ; w < p->width ; w++ )
4596 for ( h = 0 ; h < p->height ; h++ )
4598 p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
4599 p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
4602 UpdatePatchInspector();
4612 void Patch_AdjustRows(patchMesh_t *p, int nRows)
4614 vec3_t vTemp, vTemp2;
4617 if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT)
4620 // add in column adjustment
4623 for (w = 0; w < p->width; w++)
4625 // for each row, we need to evenly disperse p->height number
4626 // of points across the old bounds
4628 // calc total distance to interpolate
4629 VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp);
4631 //vTemp[0] = vTemp[1] = vTemp[2] = 0;
4632 //for (h = 0; h < p->height - nRows; h ++)
4634 // VectorAdd(vTemp, p->ctrl[w][h], vTemp);
4638 for (i = 0; i < 3; i ++)
4640 vTemp2[i] = vTemp[i] / (p->height - 1);
4644 for (h = 0; h < p->height-1; h++)
4646 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
4650 for ( w = 0 ; w < p->width ; w++ )
4652 for ( h = 0 ; h < p->height ; h++ )
4654 p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
4655 p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
4658 UpdatePatchInspector();
4668 void Patch_DisperseRows()
4670 vec3_t vTemp, vTemp2;
4674 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4678 patchMesh_t *p = pb->pPatch;
4680 for (w = 0; w < p->width; w++)
4682 // for each row, we need to evenly disperse p->height number
4683 // of points across the old bounds
4685 // calc total distance to interpolate
4686 VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp);
4688 //vTemp[0] = vTemp[1] = vTemp[2] = 0;
4689 //for (h = 0; h < p->height - nRows; h ++)
4691 // VectorAdd(vTemp, p->ctrl[w][h], vTemp);
4695 for (i = 0; i < 3; i ++)
4697 vTemp2[i] = vTemp[i] / (p->height - 1);
4701 for (h = 0; h < p->height-1; h++)
4703 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
4705 Patch_Naturalize(p);
4710 UpdatePatchInspector();
4715 Patch_DisperseIntermediateRows
4719 void Patch_DisperseIntermediateRows()
4721 vec3_t vTemp, vTemp2;
4725 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4729 patchMesh_t *p = pb->pPatch;
4731 for (w = 0; w < p->width; w++)
4734 for (h = 0; h < p->height; h+=2)
4736 // calc distance to interpolate
4737 VectorSubtract(p->ctrl[w][h+2].xyz, p->ctrl[w][h].xyz, vTemp);
4740 for (i = 0; i < 3; i ++)
4742 vTemp2[i] = vTemp[i] / 2;
4745 // move control points
4746 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
4751 UpdatePatchInspector();
4756 Patch_DisperseIntermediateColumns
4759 void Patch_DisperseIntermediateColumns()
4761 vec3_t vTemp, vTemp2;
4765 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4769 patchMesh_t *p = pb->pPatch;
4771 for (h = 0; h < p->height; h++)
4774 for (w = 0; w < p->width; w+=2)
4776 // calc distance to interpolate
4777 VectorSubtract(p->ctrl[w+2][h].xyz, p->ctrl[w][h].xyz, vTemp);
4780 for (i = 0; i < 3; i ++)
4782 vTemp2[i] = vTemp[i] / 2;
4785 // move control points
4786 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
4791 UpdatePatchInspector();
4798 Patch_AdjustSelected
4801 void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag)
4803 bool bUpdate = false;
4804 for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4812 Patch_InsertColumn(pb->pPatch, bFlag);
4816 Patch_InsertRow(pb->pPatch, bFlag);
4823 Patch_RemoveColumn(pb->pPatch, bFlag);
4827 Patch_RemoveRow(pb->pPatch, bFlag);
4832 patchMesh_t *p = pb->pPatch;
4833 Patch_CalcBounds(p, vMin, vMax);
4834 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
4835 pb->pPatch->bDirty = true; // rebuild LOD trees and their normals
4840 Sys_UpdateWindows(W_ALL);
4847 Patch_AdjustSelectedRowCols
4851 void Patch_AdjustSelectedRowCols(int nRows, int nCols)
4853 for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
4857 Patch_InsertColumn(pb->pPatch, false);
4860 Patch_AdjustRows(pb->pPatch, nRows);
4865 Patch_AdjustColumns(pb->pPatch, nCols);
4869 UpdatePatchInspector();
4876 temporary stuff, detect potential problems when saving the texture name
4877 will correct the patch on the fly if problem detected
4881 \todo performance issue with CheckName calls
4882 don't call this too much, only when absolutely necessary
4883 strategies that call here too much are known to be slow
4884 patch 84 to bug 253 adds an additionnal check for textures/
4886 void CheckName( patchMesh_t *p, char *pname )
4888 if(strncmp(p->pShader->getName(), "textures/", 9) != 0)
4889 p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND);
4891 // some manage to get long filename textures (with spaces) in their maps
4892 if (strchr( p->pShader->getName(), ' ' ))
4895 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() );
4896 Sys_Printf("%s\n", Msg1 );
4897 gtk_MessageBox(g_pParentWnd->m_pWidget, Msg1, "Error saving map", MB_OK );
4898 strcpy( pname, SHADER_NOT_FOUND );
4899 p->pShader = QERApp_Shader_ForName(SHADER_NOT_FOUND);
4900 p->d_texture = p->pShader->getTexture();
4903 strcpy( pname, p->pShader->getName()+9 ); // remove "textures/"
4911 void Patch_Write (patchMesh_t *p, MemStream *file)
4915 MemFile_fprintf(file, " {\n patchDef2\n {\n");
4917 CheckName( p, pname );
4918 MemFile_fprintf(file, " %s\n", pname );
4919 MemFile_fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
4922 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
4925 for (w = 0; w < p->width; w++)
4927 for (h = 0; h < p->height; h++)
4929 ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
4930 ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
4931 ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
4932 ctrl[w][h][3] = p->ctrl[w][h].st[0];
4933 ctrl[w][h][4] = p->ctrl[w][h].st[1];
4937 _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
4939 if (g_qeglobals.m_bBrushPrimitMode)
4943 for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
4945 MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
4950 MemFile_fprintf(file, " }\n }\n");
4953 void Patch_Write (patchMesh_t *p, FILE *file)
4957 fprintf(file, " {\n patchDef2\n {\n");
4959 CheckName( p, pname );
4960 fprintf(file, " %s\n", pname );
4961 fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
4964 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
4967 for (w = 0; w < p->width; w++)
4969 for (h = 0; h < p->height; h++)
4971 ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
4972 ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
4973 ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
4974 ctrl[w][h][3] = p->ctrl[w][h].st[0];
4975 ctrl[w][h][4] = p->ctrl[w][h].st[1];
4979 _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
4981 if (g_qeglobals.m_bBrushPrimitMode)
4985 for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
4987 fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
4992 fprintf(file, " }\n }\n");
5001 void Patch_RotateTexture(patchMesh_t *p, float fAngle)
5004 float c = cos(fAngle * Q_PI / 180);
5005 float s = sin(fAngle * Q_PI / 180);
5007 Patch_TransformLODTexture(p, c, s, ROTATE);
5009 for (int w = 0; w < p->width; w++)
5011 for (int h = 0; h < p->height; h++)
5013 //if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
5016 float x = p->ctrl[w][h].st[0];
5017 float y = p->ctrl[w][h].st[1];
5018 p->ctrl[w][h].st[0] = x * c - y * s;
5019 p->ctrl[w][h].st[1] = y * c + x * s;
5030 void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup)
5033 // this hack turns scales into 1.1 or 0.9
5036 fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10;
5037 fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10;
5047 for (int w = 0; w < p->width; w++)
5049 for (int h = 0; h < p->height; h++)
5051 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
5054 p->ctrl[w][h].st[0] *= fx;
5055 p->ctrl[w][h].st[1] *= fy;
5058 if (g_qeglobals.d_select_mode == sel_curvepoint)
5061 Patch_LODMatchAll();
5065 Patch_TransformLODTexture(p, fx, fy, SCALE);
5066 p->LODUpdated = true;
5074 shift a texture given a pixel count
5077 void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy)
5080 pTex = p->pShader->getTexture();
5081 fx = -1 * fx / pTex->width;
5082 fy = fy / pTex->height;
5083 Patch_ShiftTextureST(p, fx, fy);
5087 ====================
5088 Patch_ShiftTextureST
5089 shift a patch texture given an ST increment
5090 ====================
5092 void Patch_ShiftTextureST(patchMesh_t *p, float fx, float fy)
5095 // NOTE: when called by Patch_ShiftTexture this warning may be bogus
5096 if ((ABS(fx) >= 1) || (ABS(fy) >= 1))
5097 Sys_Printf("WARNING: increments exceed 1 in Patch_ShiftTextureST\n");
5099 for (int w = 0; w < p->width; w++)
5101 for (int h = 0; h < p->height; h++)
5103 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
5106 p->ctrl[w][h].st[0] += fx;
5107 p->ctrl[w][h].st[1] += fy;
5110 if (g_qeglobals.d_select_mode == sel_curvepoint)
5113 Patch_LODMatchAll();
5117 Patch_TransformLODTexture(p, fx, fy, TRANSLATE);
5118 p->LODUpdated = true;
5124 Patch_ToggleInverted
5127 void Patch_ToggleInverted()
5129 bool bUpdate = false;
5131 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5136 patchInvert(pb->pPatch);
5142 Sys_UpdateWindows(W_ALL);
5144 UpdatePatchInspector();
5149 Patch_ToggleInverted
5152 void Patch_InvertTexture(bool bY)
5154 bool bUpdate = false;
5157 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5162 patchMesh_t *p = pb->pPatch;
5166 for ( int i = 0 ; i < p->height ; i++ )
5168 for (int j = 0; j < p->width / 2; j++)
5170 memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2]));
5171 memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2]));
5172 memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2]));
5178 for ( int i = 0 ; i < p->width ; i++ )
5180 for (int j = 0; j < p->height / 2; j++)
5182 memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2]));
5183 memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2]));
5184 memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2]));
5193 Sys_UpdateWindows(W_ALL);
5195 UpdatePatchInspector();
5205 Saves patch ctrl info (originally to deal with a
5206 cancel in the surface dialog
5208 void Patch_Save(patchMesh_t *p)
5210 patchSave.width = p->width;
5211 patchSave.height = p->height;
5212 memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl));
5221 void Patch_Restore(patchMesh_t *p)
5223 p->width = patchSave.width;
5224 p->height = patchSave.height;
5225 memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl));
5228 void Patch_ResetTexturing(float fx, float fy)
5230 for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5234 patchMesh_t *p = pb->pPatch;
5236 for ( int i = 0 ; i < p->width ; i++ )
5238 for ( int j = 0 ; j < p->height ; j++ )
5240 p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1);
5241 p->ctrl[i][j].st[1] = 1 - fy * (float)j / (p->height - 1);
5249 void Patch_FitTexturing()
5251 Patch_ResetTexturing(1.0f, 1.0f);
5254 void Patch_SetTextureInfo(texdef_t *pt)
5256 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5261 Patch_RotateTexture(pb->pPatch, pt->rotate);
5263 if (pt->shift[0] || pt->shift[1])
5264 Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]);
5266 if (pt->scale[0] || pt->scale[1])
5267 Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false);
5269 patchMesh_t *p = pb->pPatch;
5270 p->contents = pt->contents;
5271 p->flags = pt->flags;
5272 p->value = pt->value;
5277 bool OnlyPatchesSelected()
5279 if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
5281 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5283 if (!pb->patchBrush)
5291 bool AnyPatchesSelected()
5293 if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
5295 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5305 patchMesh_t* SinglePatchSelected()
5307 if (selected_brushes.next->patchBrush)
5309 return selected_brushes.next->pPatch;
5314 void Patch_BendToggle()
5316 if (g_bPatchBendMode)
5318 g_bPatchBendMode = false;
5320 g_pParentWnd->UpdatePatchToolbarButtons() ;
5324 brush_t* b = selected_brushes.next;
5326 if (!QE_SingleBrush(true) || !b->patchBrush)
5328 Sys_Printf("Patch_BendToggle: you must have a single patch selected\n");
5332 Patch_Save(b->pPatch);
5333 g_bPatchBendMode = true;
5334 g_nPatchBendState = BEND_SELECT_ROTATION;
5335 g_bPatchAxisOnRow = true;
5336 g_nPatchAxisIndex = 1;
5337 ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]);
5340 void Patch_BendHandleTAB()
5342 if (!g_bPatchBendMode)
5347 brush_t* b = selected_brushes.next;
5348 if (!QE_SingleBrush() || !b->patchBrush)
5351 Sys_Printf("No patch to bend!");
5355 patchMesh_t *p = b->pPatch;
5357 bool bShift = Sys_ShiftDown ();
5359 if (g_nPatchBendState == BEND_SELECT_ROTATION)
5361 // only able to deal with odd numbered rows/cols
5362 g_nPatchAxisIndex += (bShift) ? -2 : 2;
5363 if (g_bPatchAxisOnRow)
5365 if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height)
5367 g_bPatchAxisOnRow = false;
5368 g_nPatchAxisIndex = (bShift) ? p->width-1 : 1;
5373 if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width)
5375 g_bPatchAxisOnRow = true;
5376 g_nPatchAxisIndex = (bShift) ? p->height-1 : 1;
5381 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
5383 g_nBendOriginIndex += (bShift) ? -1 : 1;
5384 if (g_bPatchAxisOnRow)
5388 if (g_nBendOriginIndex < 0)
5389 g_nBendOriginIndex = p->width-1;
5393 if (g_nBendOriginIndex > p->width-1)
5394 g_nBendOriginIndex = 0;
5396 VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin);
5402 if (g_nBendOriginIndex < 0)
5403 g_nBendOriginIndex = p->height-1;
5407 if (g_nBendOriginIndex > p->height-1)
5408 g_nBendOriginIndex = 0;
5410 VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin);
5414 if (g_nPatchBendState == BEND_SELECT_EDGE)
5416 g_bPatchLowerEdge ^= 1;
5418 Sys_UpdateWindows(W_ALL);
5421 void Patch_BendHandleENTER()
5423 if (!g_bPatchBendMode)
5428 if (g_nPatchBendState < BEND_BENDIT)
5430 g_nPatchBendState++;
5431 ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]);
5432 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
5434 g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0;
5435 g_nBendOriginIndex = 0;
5436 Patch_BendHandleTAB();
5439 if (g_nPatchBendState == BEND_SELECT_EDGE)
5441 g_bPatchLowerEdge = true;
5444 if (g_nPatchBendState == BEND_BENDIT)
5446 // basically we go into rotation mode, set the axis to the center of the
5454 Sys_UpdateWindows(W_ALL);
5459 void Patch_BendHandleESC()
5461 if (!g_bPatchBendMode)
5466 brush_t* b = selected_brushes.next;
5467 if (QE_SingleBrush() && b->patchBrush)
5469 Patch_Restore(b->pPatch);
5471 Sys_UpdateWindows(W_ALL);
5474 void Patch_SetBendRotateOrigin(patchMesh_t *p)
5477 int nType = g_pParentWnd->ActiveXY()->GetViewType();
5478 int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1;
5480 g_vBendOrigin[nDim3] = 0;
5481 VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin());
5484 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
5485 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
5487 float fxLo, fyLo, fxHi, fyHi;
5489 fxHi = fyHi = -9999;
5491 if (g_bPatchAxisOnRow)
5493 for (int i = 0; i < p->width; i++)
5495 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo)
5496 fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
5498 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi)
5499 fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
5501 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo)
5502 fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
5504 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi)
5505 fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
5510 for (int i = 0; i < p->height; i++)
5512 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo)
5513 fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
5515 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi)
5516 fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
5518 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo)
5519 fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
5521 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi)
5522 fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
5526 g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0;
5527 g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5;
5528 g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5;
5532 // also sets the rotational origin
5533 void Patch_SelectBendAxis()
5535 brush_t* b = selected_brushes.next;
5536 if (!QE_SingleBrush() || !b->patchBrush)
5538 // should not ever happen
5543 patchMesh_t *p = b->pPatch;
5544 if (g_bPatchAxisOnRow)
5546 SelectRow(p, g_nPatchAxisIndex, false);
5550 SelectColumn(p, g_nPatchAxisIndex, false);
5553 //FIXME: this only needs to be set once...
5554 Patch_SetBendRotateOrigin(p);
5558 void Patch_SelectBendNormal()
5560 brush_t* b = selected_brushes.next;
5561 if (!QE_SingleBrush() || !b->patchBrush)
5563 // should not ever happen
5568 patchMesh_t *p = b->pPatch;
5570 g_qeglobals.d_num_move_points = 0;
5571 if (g_bPatchAxisOnRow)
5573 if (g_bPatchLowerEdge)
5575 for (int j = 0; j < g_nPatchAxisIndex; j++)
5576 SelectRow(p, j, true);
5580 for (int j = p->height-1; j > g_nPatchAxisIndex; j--)
5581 SelectRow(p, j, true);
5586 if (g_bPatchLowerEdge)
5588 for (int j = 0; j < g_nPatchAxisIndex; j++)
5589 SelectColumn(p, j, true);
5593 for (int j = p->width-1; j > g_nPatchAxisIndex; j--)
5594 SelectColumn(p, j, true);
5597 Patch_SetBendRotateOrigin(p);
5603 void Patch_InsDelToggle()
5605 if (g_bPatchInsertMode)
5607 g_bPatchInsertMode = false;
5609 g_pParentWnd->UpdatePatchToolbarButtons() ;
5613 brush_t* b = selected_brushes.next;
5615 if (!QE_SingleBrush(true) || !b->patchBrush)
5617 Sys_Printf("Patch_InsDelToggle: you must have a single patch selected\n");
5621 Patch_Save(b->pPatch);
5622 g_bPatchInsertMode = true;
5623 g_nPatchInsertState = INSERT_SELECT_EDGE;
5624 g_bPatchAxisOnRow = true;
5625 g_nPatchAxisIndex = 0;
5626 ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]);
5630 void Patch_InsDelESC()
5632 if (!g_bPatchInsertMode)
5636 Patch_InsDelToggle();
5637 Sys_UpdateWindows(W_ALL);
5641 void Patch_InsDelHandleENTER()
5645 void Patch_InsDelHandleTAB()
5647 if (!g_bPatchInsertMode)
5649 Patch_InsDelToggle();
5653 brush_t* b = selected_brushes.next;
5654 if (!QE_SingleBrush() || !b->patchBrush)
5657 Sys_Printf("No patch to bend!");
5661 patchMesh_t *p = b->pPatch;
5663 // only able to deal with odd numbered rows/cols
5664 g_nPatchAxisIndex += 2;
5665 if (g_bPatchAxisOnRow)
5667 if (g_nPatchAxisIndex >= p->height-1)
5669 g_bPatchAxisOnRow = false;
5670 g_nPatchAxisIndex = 0;
5675 if (g_nPatchAxisIndex >= p->width-1)
5677 g_bPatchAxisOnRow = true;
5678 g_nPatchAxisIndex = 0;
5681 Sys_UpdateWindows(W_ALL);
5686 void _Write1DMatrix (FILE *f, int x, float *m) {
5690 for (i = 0 ; i < x ; i++) {
5691 if (m[i] == (int)m[i] ) {
5692 fprintf (f, "%i ", (int)m[i]);
5694 fprintf (f, "%f ", m[i]);
5700 void _Write2DMatrix (FILE *f, int y, int x, float *m) {
5704 for (i = 0 ; i < y ; i++) {
5705 _Write1DMatrix (f, x, m + i*x);
5712 void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) {
5716 for (i = 0 ; i < z ; i++) {
5717 _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
5722 void _Write1DMatrix (MemStream *f, int x, float *m) {
5725 MemFile_fprintf (f, "( ");
5726 for (i = 0 ; i < x ; i++) {
5727 if (m[i] == (int)m[i] ) {
5728 MemFile_fprintf (f, "%i ", (int)m[i]);
5730 MemFile_fprintf (f, "%f ", m[i]);
5733 MemFile_fprintf (f, ")");
5736 void _Write2DMatrix (MemStream *f, int y, int x, float *m) {
5739 MemFile_fprintf (f, "( ");
5740 for (i = 0 ; i < y ; i++) {
5741 _Write1DMatrix (f, x, m + i*x);
5742 MemFile_fprintf (f, " ");
5744 MemFile_fprintf (f, ")\n");
5748 void _Write3DMatrix (MemStream *f, int z, int y, int x, float *m) {
5751 MemFile_fprintf (f, "(\n");
5752 for (i = 0 ; i < z ; i++) {
5753 _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
5755 MemFile_fprintf (f, ")\n");
5758 // NOTE: why the hell is this called Naturalize?
5759 // we dispatch either to Patch+Naturalize or Patch_CapTexture..
5760 void Patch_NaturalizeSelected(bool bCap)
5762 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5767 Patch_CapTexture(pb->pPatch);//, bCycleCap);
5769 Patch_Naturalize(pb->pPatch);
5774 // go through the selected patches and call Patch_CapTexture
5775 // deal with cycling
5776 void Patch_CycleCapSelected()
5778 // compute the g_vCycleCapNormal according to g_nCycleCapIndex
5779 VectorClear (g_vCycleCapNormal);
5780 g_vCycleCapNormal[g_nCycleCapIndex] = 1.0f; // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY};
5781 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5785 Patch_CapTexture(pb->pPatch, true);
5788 switch (g_nCycleCapIndex)
5791 g_nCycleCapIndex = XZ;
5794 g_nCycleCapIndex = XY;
5797 g_nCycleCapIndex = YZ;
5802 bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR)
5804 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
5805 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
5806 if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) ||
5807 (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1]))
5809 if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) ||
5810 (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2]))
5817 void Patch_SelectAreaPoints(bool bMulti)
5820 g_qeglobals.d_num_move_points = 0;
5822 if( g_nPatchClickedView == W_CAMERA ) {
5823 // Clip against a pyramid
5824 // Create our 5 normals (that are pointing to the inside)
5825 camera_t *m_pCamera = g_pParentWnd->GetCamWnd()->Camera();
5827 float r[2], u[2], hh, hw;
5829 vec_t corners[2][2];
5833 VectorCopy( m_pCamera->vpn, norm[0] ); // only points in front of the camera
5835 // get our rectangle
5836 corners[0][0] = MIN( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] );
5837 corners[0][1] = MAX( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] );
5838 corners[1][0] = MAX( g_qeglobals.d_vAreaTL[0], g_qeglobals.d_vAreaBR[0] );
5839 corners[1][1] = MIN( g_qeglobals.d_vAreaTL[1], g_qeglobals.d_vAreaBR[1] );
5841 // calculate our four ray vectors
5842 hh = m_pCamera->height/2;
5843 hw = m_pCamera->width/2;
5844 u[0] = (float)(corners[0][1] - hh) / (hw);
5845 r[0] = (float)(corners[0][0] - hw) / (hw);
5846 u[1] = (float)(corners[1][1] - hh) / (hw);
5847 r[1] = (float)(corners[1][0] - hw) / (hw);
5849 for (idx=0 ; idx<3; idx++)
5850 ray[0][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[0];
5851 for (idx=0 ; idx<3; idx++)
5852 ray[1][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[0];
5853 for (idx=0 ; idx<3; idx++)
5854 ray[2][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[1] + m_pCamera->vup[idx] * u[1];
5855 for (idx=0 ; idx<3; idx++)
5856 ray[3][idx] = m_pCamera->vpn[idx] + m_pCamera->vright[idx] * r[0] + m_pCamera->vup[idx] * u[1];
5858 // Create our four other directions from these
5859 CrossProduct( ray[0], ray[1], norm[1] ); VectorNormalize( norm[1], norm[1] );
5860 CrossProduct( ray[1], ray[2], norm[2] ); VectorNormalize( norm[2], norm[2] );
5861 CrossProduct( ray[2], ray[3], norm[3] ); VectorNormalize( norm[3], norm[3] );
5862 CrossProduct( ray[3], ray[0], norm[4] ); VectorNormalize( norm[4], norm[4] );
5865 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5869 patchMesh_t *p = pb->pPatch;
5870 for (int i = 0; i < p->width; i++)
5872 for (int j = 0; j < p->height; j++)
5874 VectorSubtract( m_pCamera->origin, p->ctrl[i][j].xyz, check );
5875 VectorNormalize( check, check );
5876 for (idx=0 ; idx<5; idx++)
5878 if (DotProduct(check, norm[idx])>=0)
5881 if (idx == 5) // all test were good
5883 if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1)
5884 RemovePointFromMoveList(p->ctrl[i][j].xyz);
5886 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
5894 // Simple 2D clipping
5895 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5899 patchMesh_t *p = pb->pPatch;
5900 for (int i = 0; i < p->width; i++)
5902 for (int j = 0; j < p->height; j++)
5904 if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR))
5906 if (bMulti && PointInMoveList(p->ctrl[i][j].xyz) != -1)
5907 RemovePointFromMoveList(p->ctrl[i][j].xyz);
5909 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
5917 g_nPatchClickedView = -1;
5920 // TTimo: return the shader name for a patch
5921 const char* Patch_GetTextureName()
5923 brush_t* b = selected_brushes.next;
5926 patchMesh_t *p = b->pPatch;
5927 return p->pShader->getName();
5932 patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom)
5934 patchMesh_t* p = MakeNewPatch();
5935 memcpy(p, pFrom , sizeof(patchMesh_t));
5937 // spog - initialise patch LOD pointers (again)
5938 Patch_InitialiseLODPointers(p);
5939 p->drawLists = NULL;
5941 p->bSelected = false;
5943 p->bOverlay = false;
5945 AddBrushForPatch(p);
5951 void Patch_Thicken(int nAmount, bool bSeam, qboolean bGroupResult)
5962 if (!QE_SingleBrush())
5964 Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n");
5968 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
5972 patchMesh_t *p = pb->pPatch;
5973 Patch_MeshNormals(p);
5974 patchMesh_t *pNew = Patch_Duplicate(p);
5975 for (i = 0; i < p->width; i++)
5977 for (j = 0; j < p->height; j++)
5979 VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz);
5983 Patch_Rebuild(pNew);
5984 pNew->type |= PATCH_THICK;
5985 brushes.Add(pNew->pSymbiot);
5990 // FIXME: this should detect if any edges of the patch are closed and act appropriately
5992 if (!(p->type & PATCH_CYLINDER))
5994 b = Patch_GenericMesh(3, p->height, 2, false, true);
5996 pSeam->type |= PATCH_SEAM;
5997 for (i = 0; i < p->height; i++)
5999 VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz);
6000 VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz);
6001 VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
6002 VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
6006 Patch_CalcBounds(pSeam, vMin, vMax);
6007 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6008 //--Patch_CapTexture(pSeam);
6009 Patch_Naturalize(pSeam);
6014 b = Patch_GenericMesh(3, p->height, 2, false, true);
6016 pSeam->type |= PATCH_SEAM;
6017 for (i = 0; i < p->height; i++)
6019 VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz);
6020 VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz);
6021 VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
6022 VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
6024 Patch_CalcBounds(pSeam, vMin, vMax);
6025 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6026 //--Patch_CapTexture(pSeam);
6027 Patch_Naturalize(pSeam);
6032 // otherwise we will add one per end
6033 b = Patch_GenericMesh(p->width, 3, 2, false, true);
6035 pSeam->type |= PATCH_SEAM;
6036 for (i = 0; i < p->width; i++)
6038 VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz);
6039 VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz);
6040 VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
6041 VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
6045 Patch_CalcBounds(pSeam, vMin, vMax);
6046 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6047 //--Patch_CapTexture(pSeam);
6048 Patch_Naturalize(pSeam);
6053 b = Patch_GenericMesh(p->width, 3, 2, false, true);
6055 pSeam->type |= PATCH_SEAM;
6056 for (i = 0; i < p->width; i++)
6058 VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz);
6059 VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz);
6060 VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
6061 VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
6063 Patch_CalcBounds(pSeam, vMin, vMax);
6064 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
6065 //--Patch_CapTexture(pSeam);
6066 Patch_Naturalize(pSeam);
6074 for (i = 0; i < brushes.GetSize(); i++)
6076 Select_Brush(reinterpret_cast<brush_t*>(brushes.GetAt(i)));
6081 entity_t *e = Entity_Alloc();
6082 SetKeyValue(e, "classname", "func_group");
6083 SetKeyValue(e, "type", "patchThick");
6084 Select_GroupEntity(e);
6085 Entity_AddToList(e, &entities);
6088 UpdatePatchInspector();
6093 lets get another list together as far as necessities..
6095 *snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything)
6097 capping bevels/endcaps
6101 texture fix for caps
6111 void Patch_SetOverlays()
6113 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6117 pb->pPatch->bOverlay = true;
6124 void Patch_ClearOverlays()
6127 for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6131 pb->pPatch->bOverlay = false;
6135 for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
6139 pb->pPatch->bOverlay = false;
6145 // FIXME: spog - er, someone forgot to finish their patch point freezing feature?
6146 // freezes selected vertices
6150 for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6154 pb->pPatch->bOverlay = false;
6158 for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
6162 pb->pPatch->bOverlay = false;
6168 void Patch_UnFreeze(bool bAll)
6172 void Patch_Transpose()
6176 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
6180 patchMesh_t *p = pb->pPatch;
6182 if ( p->width > p->height )
6184 for ( i = 0 ; i < p->height ; i++ )
6186 for ( j = i + 1 ; j < p->width ; j++ )
6188 if ( j < p->height )
6191 memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t));
6192 memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
6193 memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t));
6198 memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
6205 for ( i = 0 ; i < p->width ; i++ )
6207 for ( j = i + 1 ; j < p->height ; j++ )
6212 memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t));
6213 memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
6214 memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t));
6219 memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
6226 p->width = p->height;
6236 void Patch_SnapToGrid(patchMesh_t *p)
6240 // if patch points selected, snap only selected points
6241 if (g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0)
6242 for (i=0; i<g_qeglobals.d_num_move_points; i++)
6243 for (j = 0; j < 3; j++)
6244 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;
6246 // else snap all patch points
6248 for (i = 0; i < p->width; i++)
6249 for (j = 0; j < p->height; j++)
6250 for (k = 0; k < 3; k++)
6251 p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
6254 Patch_CalcBounds(p, vMin, vMax);
6255 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
6259 void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce)
6263 patchMesh_t *p = pb->pPatch;
6264 if (bForce || strcmpi(p->pShader->getName(), pFind) == 0)
6266 p->pShader->DecRef();
6267 p->pShader = QERApp_Shader_ForName(pReplace);
6268 p->d_texture = p->pShader->getTexture();
6273 /* uncomment if necessary, currently not used
6274 void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz)
6276 patchMesh_t* p = MakeNewPatch();
6277 p->pShader = g_qeglobals.d_texturewin.pShader;
6278 p->d_texture = g_qeglobals.d_texturewin.pShader->getTexture();
6281 p->type = PATCH_TRIANGLE;
6287 // 1 0 goes to mid of x and z
6288 // 1 1 goes to mid of x y and z
6289 // 1 2 goes to mid of x and y
6292 // 2 1 goes to mid of y and z
6300 for (j = 0; j < 3; j++)
6302 _Vector5Add(vx, vz, vMidXZ);
6303 _Vector5Scale(vMidXZ, 0.5, vMidXZ);
6304 //vMidXZ[j] = vx[j] + abs((vx[j] - vz[j]) * 0.5);
6307 for (j = 0; j < 3; j++)
6309 _Vector5Add(vx, vy, vMidXY);
6310 _Vector5Scale(vMidXY, 0.5, vMidXY);
6311 //vMidXY[j] = vx[j] + abs((vx[j] - vy[j]) * 0.5);
6314 for (j = 0; j < 3; j++)
6316 _Vector5Add(vy, vz, vMidYZ);
6317 _Vector5Scale(vMidYZ, 0.5, vMidYZ);
6318 //vMidYZ[j] = vy[j] + abs((vy[j] - vz[j]) * 0.5);
6321 _Vector53Copy(vx, p->ctrl[0][0].xyz);
6322 _Vector53Copy(vx, p->ctrl[0][1].xyz);
6323 _Vector53Copy(vx, p->ctrl[0][2].xyz);
6324 p->ctrl[0][0].st[0] = vx[3];
6325 p->ctrl[0][0].st[1] = vx[4];
6326 p->ctrl[0][1].st[0] = vx[3];
6327 p->ctrl[0][1].st[1] = vx[4];
6328 p->ctrl[0][2].st[0] = vx[3];
6329 p->ctrl[0][2].st[1] = vx[4];
6331 _Vector53Copy(vMidXY, p->ctrl[1][0].xyz);
6332 _Vector53Copy(vx, p->ctrl[1][1].xyz);
6333 _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz);
6334 p->ctrl[1][0].st[0] = vMidXY[3];
6335 p->ctrl[1][0].st[1] = vMidXY[4];
6336 p->ctrl[1][1].st[0] = vx[3];
6337 p->ctrl[1][1].st[1] = vx[4];
6338 p->ctrl[1][2].st[0] = vMidXZ[3];
6339 p->ctrl[1][2].st[1] = vMidXZ[4];
6341 _Vector53Copy(vy, p->ctrl[2][0].xyz);
6342 _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz);
6343 _Vector53Copy(vz, p->ctrl[2][2].xyz);
6344 p->ctrl[2][0].st[0] = vy[3];
6345 p->ctrl[2][0].st[1] = vy[4];
6346 p->ctrl[2][1].st[0] = vMidYZ[3];
6347 p->ctrl[2][1].st[1] = vMidYZ[4];
6348 p->ctrl[2][2].st[0] = vz[3];
6349 p->ctrl[2][2].st[1] = vz[4];
6352 //Patch_Naturalize(p);
6355 AddBrushForPatch(p);
6360 #ifdef ENABLE_GROUPS
6364 sets an epair for the given patch
6367 void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue)
6369 if (g_qeglobals.m_bBrushPrimitMode)
6371 SetKeyValue(p->epairs, pKey, pValue);
6380 const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey)
6382 if (g_qeglobals.m_bBrushPrimitMode)
6384 return ValueForKey(p->epairs, pKey);
6391 //Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save)
6394 When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as;
6396 g:\quake3\baseq3\textures\common
6398 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.
6400 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.
6402 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.
6404 1) Easier way of deleting rows, columns
6405 2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog)
6406 2) Patch matrix transposition
6408 1) Actually, bump texture flipping on patches to the top of the list of things to do.
6409 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
6410 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
6413 *1) Flipping textures on patches
6414 *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
6415 3) Easier way of deleting rows columns
6417 5) Patch matrix transposition
6418 6) Inverted cylinder capping
6422 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)
6424 Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model
6426 Feature Addition: View/Hide Hint Brushes -- This should be a specific case.