2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
33 #include "DialogInfo.h"
34 #include "CapDialog.h"
37 extern void MemFile_fprintf( CMemFile *pMemFile,const char *pText,... );
38 extern face_t *Face_Alloc( void );
39 void _Write3DMatrix( FILE *f,int y,int x,int z,float *m );
40 void _Write3DMatrix( CMemFile *f,int y,int x,int z,float *m );
41 extern void SamplePatch( float ctrl[3][3][5],int baseCol,int baseRow,int width,int horzSub,int vertSub,idDrawVert *outVerts,idDrawVert *drawVerts );
42 patchMesh_t *Patch_GenerateGeneric( int width,int height,int orientation,const idVec3 &mins,const idVec3 &maxs );
46 patchMesh_t * MakeNewPatch( int width,int height ) {
47 patchMesh_t *pm = reinterpret_cast< patchMesh_t*>(Mem_ClearedAlloc(sizeof(patchMesh_t)));
48 pm->horzSubdivisions = DEFAULT_CURVE_SUBDIVISION;
49 pm->vertSubdivisions = DEFAULT_CURVE_SUBDIVISION;
50 pm->explicitSubdivisions = false;
53 pm->verts = reinterpret_cast< idDrawVert*>(Mem_ClearedAlloc(sizeof(idDrawVert) * width * height));
54 //pm->ctrl = reinterpret_cast<idDrawVert*>(Mem_ClearedAlloc(sizeof(idDrawVert) * width * height));
55 //pm->ctrl = &pm->verts;
60 void Patch_AdjustSize( patchMesh_t *p,int wadj,int hadj ) {
61 idDrawVert *newverts = reinterpret_cast< idDrawVert*>(Mem_ClearedAlloc(sizeof(idDrawVert) * (p->width + wadj) * (p->height + hadj)));
62 int copyWidth = (wadj < 0) ? p->width + wadj : p->width;
63 int copyHeight = (hadj < 0) ? p->height + hadj : p->height;
64 int copysize = copyWidth *copyHeight * sizeof(idDrawVert);
66 for ( int i = 0; i < p->width; i++ ) {
67 for ( int j = 0; j < p->height; j++ ) {
68 newverts[j * (p->width + wadj) + i] = p->ctrl(i, j);
78 // algorithm from Journal of graphics tools, 2(1):21-28, 1997
79 bool RayIntersectsTri( const idVec3 &origin,const idVec3 &direction,const idVec3 &vert0,const idVec3 &vert1,const idVec3 &vert2,float &scale ) {
80 idVec3 edge1, edge2, tvec, pvec, qvec;
84 /* find vectors for two edges sharing vert0 */
85 edge1 = vert1 - vert0;
86 edge2 = vert2 - vert0;
88 /* begin calculating determinant - also used to calculate U parameter */
89 pvec.Cross(direction, edge2);
91 /* if determinant is near zero, ray lies in plane of triangle */
94 if ( det > -VECTOR_EPSILON && det < VECTOR_EPSILON ) {
100 /* calculate distance from vert0 to ray origin */
101 tvec = origin - vert0;
103 /* calculate U parameter and test bounds */
104 float u = (tvec *pvec) * inv_det;
105 if ( u < 0.0f || u> 1.0f ) {
109 /* prepare to test V parameter */
110 qvec.Cross(tvec, edge1);
112 /* calculate V parameter and test bounds */
113 float v = (direction *qvec) * inv_det;
114 if ( v < 0.0f || u + v> 1.0f ) {
118 scale = tvec.Length();
122 bool Patch_Intersect( patchMesh_t *pm,idVec3 origin,idVec3 direction,float &scale ) {
125 idSurface_Patch cp (pm->width * 6, pm->height * 6);
127 cp.SetSize(pm->width, pm->height);
128 for ( i = 0; i < pm->width; i++ ) {
129 for ( j = 0; j < pm->height; j++ ) {
130 (cp)[j * cp.GetWidth() + i].xyz = pm->ctrl(i, j).xyz;
131 (cp)[j * cp.GetWidth() + i].st = pm->ctrl(i, j).st;
135 if ( pm->explicitSubdivisions ) {
136 cp.SubdivideExplicit(pm->horzSubdivisions, pm->vertSubdivisions, false);
138 cp.Subdivide(DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, false);
141 if ( cp.RayIntersection(origin, direction, scale) ) {
148 int width = cp.GetWidth();
149 int height = cp.GetHeight();
150 for ( i = 0 ; i < width - 1; i++ ) {
151 for ( j = 0 ; j < height - 1; j++ ) {
152 // v1-v2-v3-v4 makes a quad
158 if (RayIntersectsTri(origin, direction, (cp)[v1].xyz, (cp)[v2].xyz, (cp)[v3].xyz)) {
161 if (RayIntersectsTri(origin, direction, (cp)[v3].xyz, (cp)[v4].xyz, (cp)[v1].xyz)) {
170 patchMesh_t * Patch_MakeNew( patchMesh_t *p,int newWidth,int newHeight ) {
171 patchMesh_t *newPatch = MakeNewPatch(newWidth, newHeight);
172 newPatch->d_texture = p->d_texture;
173 newPatch->horzSubdivisions = p->horzSubdivisions;
174 newPatch->vertSubdivisions = p->vertSubdivisions;
175 newPatch->explicitSubdivisions = p->explicitSubdivisions;
179 void Patch_Combine( patchMesh_t *p,patchMesh_t *p2,int sourceCol1,int sourceCol2,int sourceRow1,int sourceRow2,bool invert1,bool invert2 ) {
181 patchMesh_t *newPatch = NULL;
182 if ( sourceCol1 >= 0 ) {
184 if ( sourceCol2 >= 0 ) {
186 newPatch = Patch_MakeNew(p, p->width + p2->width - 1, p->height);
191 if ( sourceCol1 != 0 ) {
195 if ( sourceCol2 != 0 ) {
197 col2 = p2->width - 2;
201 for ( i = 0; i < p->width; i++, col1 += adj1 ) {
202 int in = (invert1) ? p->height - 1 : 0;
203 for ( j = 0; j < p->height; j++ ) {
204 newPatch->ctrl(out, j) = p->ctrl(col1, in);
205 in += (invert1) ? -1 : 1;
210 for ( i = 1; i < p2->width; i++, col2 += adj2 ) {
211 int in = (invert2) ? p2->height - 1 : 0;
212 for ( j = 0; j < p2->height; j++ ) {
213 newPatch->ctrl(out, j) = p2->ctrl(col2, in);
214 in += (invert2) ? -1 : 1;
220 newPatch = Patch_MakeNew(p, p->width + p2->height - 1, p->height);
225 if ( sourceCol1 != 0 ) {
229 if ( sourceRow2 != 0 ) {
231 row2 = p2->height - 2;
235 for ( i = 0; i < p->width; i++, col1 += adj1 ) {
236 int in = (invert1) ? p->height - 1 : 0;
237 for ( j = 0; j < p->height; j++ ) {
238 newPatch->ctrl(out, j) = p->ctrl(col1, in);
239 in += (invert1) ? -1 : 1;
244 for ( i = 1; i < p2->height; i++, row2 += adj2 ) {
245 int in = (invert2) ? p2->width - 1 : 0;
246 for ( j = 0; j < p2->width; j++ ) {
247 newPatch->ctrl(out, j) = p2->ctrl(in, row2);
248 in += (invert2) ? -1 : 1;
255 if ( sourceRow1 >= 0 ) {
257 newPatch = Patch_MakeNew(p, p->width, p->height + p2->height - 1);
262 if ( sourceRow1 != 0 ) {
264 row1 = p->height - 1;
266 if ( sourceRow2 != 0 ) {
268 row2 = p2->height - 2;
272 for ( i = 0; i < p->height; i++, row1 += adj1 ) {
273 int in = (invert1) ? p->width - 1 : 0;
274 for ( j = 0; j < p->width; j++ ) {
275 newPatch->ctrl(j, out) = p->ctrl(in, row1);
276 in += (invert1) ? -1 : 1;
281 for ( i = 1; i < p2->height; i++, row2 += adj2 ) {
282 int in = (invert2) ? p->width - 1 : 0;
283 for ( j = 0; j < p2->width; j++ ) {
284 newPatch->ctrl(j, out) = p2->ctrl(in, row2);
285 in += (invert1) ? -1 : 1;
291 newPatch = Patch_MakeNew(p, p->width, p->height + p2->width - 1);
296 if ( sourceRow1 != 0 ) {
298 row1 = p->height - 1;
300 if ( sourceCol2 != 0 ) {
302 col2 = p2->width - 2;
306 for ( i = 0; i < p->height; i++, row1 += adj1 ) {
307 int in = (invert1) ? p->width - 1 : 0;
308 for ( j = 0; j < p->width; j++ ) {
309 newPatch->ctrl(j, out) = p->ctrl(in, row1);
310 in += (invert1) ? -1 : 1;
315 for ( i = 1; i < p2->width; i++, col2 += adj2 ) {
316 int in = (invert2) ? p->height - 1 : 0;
317 for ( j = 0; j < p2->height; j++ ) {
318 newPatch->ctrl(j, out) = p2->ctrl(col2, in);
319 in += (invert1) ? -1 : 1;
326 AddBrushForPatch(newPatch, true);
327 Brush_Free(p->pSymbiot, true);
328 Brush_Free(p2->pSymbiot, true);
329 Patch_Naturalize(newPatch, true, true);
333 #define WELD_EPSILON 0.001f
335 void Patch_Weld( patchMesh_t *p,patchMesh_t *p2 ) {
336 // check against all 4 edges of p2
337 // could roll this up but left it out for some semblence of clarity
340 if ( p->width == p2->width ) {
346 // need to see if any of the corners match then run down or up based
347 // on the match edges
352 if ( p->ctrl(0, row).xyz.Compare(p2->ctrl(0, row2).xyz, WELD_EPSILON) ) {
353 } else if ( p->ctrl(0, row).xyz.Compare(p2->ctrl(p2->width - 1, row2).xyz, WELD_EPSILON) ) {
354 col2 = p2->width - 1;
356 } else if ( p->ctrl(p->width - 1, row).xyz.Compare(p2->ctrl(p2->width - 1, row2).xyz, WELD_EPSILON) ) {
357 col2 = p2->width - 1;
361 } else if ( p->ctrl(p->width - 1, row).xyz.Compare(p2->ctrl(0, row2).xyz, WELD_EPSILON) ) {
369 for ( int col = 0; col < p->width; col++, col2 += adj2, col1 += adj1 ) {
370 if ( !p->ctrl(col1, row).xyz.Compare(p2->ctrl(col2, row2).xyz, WELD_EPSILON) ) {
380 // have a match weld these edges
381 common->Printf("Welding row %i with row %i\n", row, row2);
382 row = (row == 0) ? p->height - 1 : 0;
383 Patch_Combine(p, p2, -1, -1, row, row2, (adj1 == -1), (adj2 == -1));
385 } else if ( row2 == 0 ) {
386 row2 = p2->height - 1;
387 } else if ( row == 0 ) {
396 if ( p->width == p2->height ) {
406 if ( p->ctrl(0, row).xyz.Compare(p2->ctrl(col2, 0).xyz, WELD_EPSILON) ) {
407 } else if ( p->ctrl(0, row).xyz.Compare(p2->ctrl(col2, p2->height - 1).xyz, WELD_EPSILON) ) {
408 row2 = p2->height - 1;
410 } else if ( p->ctrl(p->width - 1, row).xyz.Compare(p2->ctrl(col2, p2->height - 1).xyz, WELD_EPSILON) ) {
411 row2 = p2->height - 1;
415 } else if ( p->ctrl(p->width - 1, row).xyz.Compare(p2->ctrl(col2, 0).xyz, WELD_EPSILON) ) {
423 for ( int col = 0; col < p->width; col++, col1 += adj1, row2 += adj2 ) {
424 if ( !p->ctrl(col1, row).xyz.Compare(p2->ctrl(col2, row2).xyz, WELD_EPSILON) ) {
434 // have a match weld these edges
435 common->Printf("Welding row %i with col %i\n", row, col2);
436 row = (row == 0) ? p->height - 1 : 0;
437 Patch_Combine(p, p2, -1, col2, row, -1, (adj1 == -1), (adj2 == -1));
439 } else if ( col2 == 0 ) {
440 col2 = p2->width - 1;
441 } else if ( row == 0 ) {
450 if ( p->height == p2->width ) {
461 if ( p->ctrl(col, 0).xyz.Compare(p2->ctrl(0, row2).xyz, WELD_EPSILON) ) {
462 } else if ( p->ctrl(col, 0).xyz.Compare(p2->ctrl(p2->width - 1, row2).xyz, WELD_EPSILON) ) {
463 col2 = p2->width - 1;
465 } else if ( p->ctrl(col, p->height - 1).xyz.Compare(p2->ctrl(p2->width - 1, row2).xyz, WELD_EPSILON) ) {
466 col2 = p2->width - 1;
468 row1 = p2->height - 1;
470 } else if ( p->ctrl(col, p->height - 1).xyz.Compare(p2->ctrl(0, row2).xyz, WELD_EPSILON) ) {
471 row1 = p2->height - 1;
478 for ( int row = 0; row < p->height; row++, row1 += adj1, col2 += adj2 ) {
479 if ( !p->ctrl(col, row1).xyz.Compare(p2->ctrl(col2, row2).xyz, WELD_EPSILON) ) {
489 // have a match weld these edges
490 common->Printf("Welding col %i with row %i\n", col, row2);
491 col = (col == 0) ? p->width - 1 : 0;
492 Patch_Combine(p, p2, col, -1, -1, row2, (adj1 == -1), (adj2 == -1));
494 } else if ( row2 == 0 ) {
495 row2 = p2->height - 1;
496 } else if ( col == 0 ) {
505 if ( p->height == p2->height ) {
516 if ( p->ctrl(col, 0).xyz.Compare(p2->ctrl(col2, 0).xyz, WELD_EPSILON) ) {
517 } else if ( p->ctrl(col, 0).xyz.Compare(p2->ctrl(col2, p2->height - 1).xyz, WELD_EPSILON) ) {
518 row2 = p2->height - 1;
520 } else if ( p->ctrl(col, p2->height - 1).xyz.Compare(p2->ctrl(col2, p2->height - 1).xyz, WELD_EPSILON) ) {
521 row2 = p2->height - 1;
523 row1 = p->height - 1;
525 } else if ( p->ctrl(col, p2->height - 1).xyz.Compare(p2->ctrl(col2, 0).xyz, WELD_EPSILON) ) {
526 row1 = p->height - 1;
533 for ( int row = 0; row < p->height; row++, row1 += adj1, row2 += adj2 ) {
534 if ( !p->ctrl(col, row1).xyz.Compare(p2->ctrl(col2, row2).xyz, WELD_EPSILON) ) {
544 // have a match weld these edges
545 common->Printf("Welding col %i with col %i\n", col, col2);
546 col = (col == 0) ? p->width - 1 : 0;
547 Patch_Combine(p, p2, col, col2, -1, -1, (adj1 == -1), (adj2 == -1));
549 } else if ( col2 == 0 ) {
550 col2 = p2->width - 1;
551 } else if ( col == 0 ) {
561 Sys_Status("Unable to weld patches, no common sized edges.\n");
565 // used for a save spot
566 patchMesh_t *patchSave = NULL;
568 // Tracks the selected patch for point manipulation/update. FIXME: Need to revert back to a generalized
570 //--int g_nSelectedPatch = -1;
572 // HACK: for tracking which view generated the click
573 // as we dont want to deselect a point on a same point
574 // click if it is from a different view
575 int g_nPatchClickedView = -1;
576 bool g_bSameView = false;
580 bool g_bPatchShowBounds = false;
581 bool g_bPatchWireFrame = false;
582 bool g_bPatchWeld = true;
583 bool g_bPatchDrillDown = true;
584 bool g_bPatchInsertMode = false;
585 bool g_bPatchBendMode = false;
586 int g_nPatchBendState = -1;
587 int g_nPatchInsertState = -1;
588 int g_nBendOriginIndex = 0;
589 idVec3 g_vBendOrigin;
591 bool g_bPatchAxisOnRow = true;
592 int g_nPatchAxisIndex = 0;
593 bool g_bPatchLowerEdge = true;
597 BEND_SELECT_ROTATION = 0,
604 const char *g_pBendStateMsg[] = {
605 "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.", "Use TAB to cycle through available rotation axis. This will LOCK around that point. You may also use Shift + Middle Click to select an arbitrary point. Press ENTER when the desired one is highlighted", "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.", "Use the MOUSE to bend the patch. It uses the same ui rules as Free Rotation. Press ENTER to accept the bend, press ESC to abandon it and exit Bend mode", ""
610 INSERT_SELECT_EDGE = 0,
614 const char *g_pInsertStateMsg[] = {
615 "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair"
619 float *g_InversePoints[1024];
621 const float fFullBright = 1.0f;
622 const float fLowerLimit = 0.5f;
623 const float fDec = 0.05f;
626 void Patch_SetType( patchMesh_t *p,int nType ) {
627 p->type = (p->type & PATCH_STYLEMASK) | nType;
630 void Patch_SetStyle( patchMesh_t *p,int nStyle ) {
631 p->type = (p->type & PATCH_TYPEMASK) | nStyle;
639 int Patch_MemorySize( patchMesh_t *p ) {
640 return (sizeof(patchMesh_t) + p->width * p->height * sizeof(idDrawVert));
647 InterpolateInteriorPoints
650 void InterpolateInteriorPoints( patchMesh_t *p ) {
654 for ( i = 0 ; i < p->width ; i += 2 ) {
655 next = (i == p->width - 1) ? 1 : (i + 1) % p->width;
656 prev = (i == 0) ? p->width - 2 : i - 1;
657 for ( j = 0 ; j < p->height ; j++ ) {
658 for ( k = 0 ; k < 3 ; k++ ) {
659 p->ctrl(i, j).xyz[k] = (p->ctrl(next, j).xyz[k] + p->ctrl(prev, j).xyz[k]) * 0.5;
671 int neighbors[8][2] = {
672 {0,1}, {1,1}, {1,0}, {1, -1}, {0, -1}, { - 1, -1}, { - 1,0}, { - 1,1}
675 void Patch_MeshNormals( patchMesh_t *in ) {
684 idVec3 around[8], temp;
686 bool wrapWidth, wrapHeight;
690 for ( i = 0 ; i < in->height ; i++ ) {
691 VectorSubtract(in->ctrl(0, i).xyz, in->ctrl(in->width - 1, i).xyz, delta);
692 len = delta.Length();
697 if ( i == in->height ) {
702 for ( i = 0 ; i < in->width ; i++ ) {
703 VectorSubtract(in->ctrl(i, 0).xyz, in->ctrl(i, in->height - 1).xyz, delta);
704 len = delta.Length();
709 if ( i == in->width ) {
714 for ( i = 0 ; i < in->width ; i++ ) {
715 for ( j = 0 ; j < in->height ; j++ ) {
717 //--dv = reinterpret_cast<idDrawVert*>(in.ctrl[j*in.width+i]);
718 dv = &in->ctrl(i, j);
719 VectorCopy(dv->xyz, base);
720 for ( k = 0 ; k < 8 ; k++ ) {
721 around[k] = vec3_origin;
724 for ( dist = 1 ; dist <= 3 ; dist++ ) {
725 x = i + neighbors[k][0] * dist;
726 y = j + neighbors[k][1] * dist;
729 x = in->width - 1 + x;
730 } else if ( x >= in->width ) {
731 x = 1 + x - in->width;
736 y = in->height - 1 + y;
737 } else if ( y >= in->height ) {
738 y = 1 + y - in->height;
742 if ( x < 0 || x >= in->width || y < 0 || y >= in->height ) {
743 break; // edge of patch
745 //--VectorSubtract( in.ctrl[y*in.width+x]->xyz, base, temp );
746 VectorSubtract(in->ctrl(x, y).xyz, base, temp);
747 if ( temp.Normalize() == 0 ) {
748 continue; // degenerate edge, get more dist
751 VectorCopy(temp, around[k]);
758 for ( k = 0 ; k < 8 ; k++ ) {
759 if ( !good[k] || !good[(k + 1) & 7] ) {
760 continue; // didn't get two points
762 normal = around[(k + 1) & 7].Cross(around[k]);
763 if ( normal.Normalize() == 0 ) {
766 VectorAdd(normal, sum, sum);
770 //printf("bad normal\n");
775 dv->normal.Normalize();
780 void Patch_MakeDirty( patchMesh_t *p ) {
784 p->nListSelected = -1;
793 void Patch_CalcBounds( patchMesh_t *p,idVec3 &vMin,idVec3 &vMax ) {
794 vMin[0] = vMin[1] = vMin[2] = 999999;
795 vMax[0] = vMax[1] = vMax[2] = -999999;
798 for ( int w = 0; w < p->width; w++ ) {
799 for ( int h = 0; h < p->height; h++ ) {
800 for ( int j = 0; j < 3; j++ ) {
801 float f = p->ctrl(w, h).xyz[j];
816 void Brush_RebuildBrush( brush_t *b,idVec3 vMins,idVec3 vMaxs,bool patch ) {
826 for ( j = 0; j < 3; j++ ) {
827 if ( (int) vMins[j] == (int) vMaxs[j] ) {
834 for ( f = b->brush_faces ; f ; f = next ) {
842 b->brush_faces = NULL;
844 // left the last face so we can use its texdef
846 for ( i = 0 ; i < 3 ; i++ ) {
847 if ( vMaxs[i] < vMins[i] ) {
848 Error("Brush_RebuildBrush: backwards");
852 pts[0][0][0] = vMins[0];
853 pts[0][0][1] = vMins[1];
855 pts[1][0][0] = vMins[0];
856 pts[1][0][1] = vMaxs[1];
858 pts[2][0][0] = vMaxs[0];
859 pts[2][0][1] = vMaxs[1];
861 pts[3][0][0] = vMaxs[0];
862 pts[3][0][1] = vMins[1];
864 for ( i = 0 ; i < 4 ; i++ ) {
865 pts[i][0][2] = vMins[2];
866 pts[i][1][0] = pts[i][0][0];
867 pts[i][1][1] = pts[i][0][1];
868 pts[i][1][2] = vMaxs[2];
871 for ( i = 0 ; i < 4 ; i++ ) {
874 f->next = b->brush_faces;
878 VectorCopy(pts[j][1], f->planepts[0]);
879 VectorCopy(pts[i][1], f->planepts[1]);
880 VectorCopy(pts[i][0], f->planepts[2]);
885 f->next = b->brush_faces;
888 VectorCopy(pts[0][1], f->planepts[0]);
889 VectorCopy(pts[1][1], f->planepts[1]);
890 VectorCopy(pts[2][1], f->planepts[2]);
894 f->next = b->brush_faces;
897 VectorCopy(pts[2][0], f->planepts[0]);
898 VectorCopy(pts[1][0], f->planepts[1]);
899 VectorCopy(pts[0][0], f->planepts[2]);
904 void WINAPI Patch_Rebuild( patchMesh_t *p ) {
906 Patch_CalcBounds(p, vMin, vMax);
907 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
915 adds a patch brush and ties it to this patch id
917 brush_t * AddBrushForPatch( patchMesh_t *pm,bool bLinkToWorld ) {
918 // find the farthest points in x,y,z
920 Patch_CalcBounds(pm, vMin, vMax);
922 for ( int j = 0; j < 3; j++ ) {
923 if ( idMath::Fabs(vMin[j] - vMax[j]) <= VECTOR_EPSILON ) {
930 //td.SetName(pm->d_texture->getName());
931 brush_t *b = Brush_Create(vMin, vMax, &td);
932 //brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
934 // FIXME: this entire type of linkage needs to be fixed
937 pm->bSelected = false;
938 pm->bOverlay = false;
942 if ( bLinkToWorld ) {
943 Brush_AddToList(b, &active_brushes);
944 Entity_LinkBrush(world_entity, b);
951 void Patch_SetPointIntensities( int n ) {
953 patchMesh_t *p = patchMeshes[n];
954 for (int i = 0; i < p->width; i++) {
955 for (int j = 0; j < p->height; j++) {
962 // very approximate widths and heights
969 float Patch_Width( patchMesh_t *p ) {
971 for ( int j = 0; j < p->height - 1; j++ ) {
973 for ( int i = 0; i < p->width - 1; i++ ) {
975 vTemp = p->ctrl(i, j).xyz - p->ctrl(i + 1, j).xyz;
990 float Patch_Height( patchMesh_t *p ) {
992 for ( int j = 0; j < p->width - 1; j++ ) {
994 for ( int i = 0; i < p->height - 1; i++ ) {
996 vTemp = p->ctrl(j, i).xyz - p->ctrl(j, i + 1).xyz;
1008 Patch_WidthDistanceTo
1011 float Patch_WidthDistanceTo( patchMesh_t *p,int j ) {
1013 for ( int i = 0; i < j ; i++ ) {
1015 vTemp = p->ctrl(i, 0).xyz - p->ctrl(i + 1, 0).xyz;
1016 f += vTemp.Length();
1023 Patch_HeightDistanceTo
1026 float Patch_HeightDistanceTo( patchMesh_t *p,int j ) {
1028 for ( int i = 0; i < j ; i++ ) {
1030 vTemp = p->ctrl(0, i).xyz - p->ctrl(0, i + 1).xyz;
1031 f += vTemp.Length();
1042 texture = TotalTexture * LengthToThisControlPoint / TotalControlPointLength
1044 dist( this control point to first control point ) / dist ( last control pt to first)
1046 void Patch_Naturalize( patchMesh_t *p,bool horz,bool vert,bool alt ) {
1049 int nWidth = p->d_texture->GetEditorImage()->uploadWidth * 0.5;
1050 int nHeight = p->d_texture->GetEditorImage()->uploadHeight * 0.5;
1051 float fPWidth = Patch_Width(p);
1052 float fPHeight = Patch_Height(p);
1054 for ( i = 0 ; i < ((alt) ? p->height : p->width) ; i++ ) {
1056 for ( j = 0 ; j < ((alt) ? p->width : p->height) ; j++ ) {
1057 int r = ((alt) ? j : i);
1058 int c = ((alt) ? i : j);
1059 p->ctrl(r, c).st[0] = (fPWidth / nWidth) * xAccum / fPWidth;
1060 p->ctrl(r, c).st[1] = (fPHeight / nHeight) * yAccum / fPHeight;
1062 yAccum = Patch_WidthDistanceTo(p, j + 1);
1064 yAccum = Patch_HeightDistanceTo(p, j + 1);
1068 xAccum = Patch_HeightDistanceTo(p, i + 1);
1070 xAccum = Patch_WidthDistanceTo(p, i + 1);
1080 VectorCopy(p->ctrl(1,0], p->ctrl(1,1]);
1085 VectorCopy(p->ctrl(3,0], p->ctrl(4,1]);
1086 VectorCopy(p->ctrl(2,0], p->ctrl(3,1]);
1087 VectorCopy(p->ctrl(2,0], p->ctrl(2,1]);
1088 VectorCopy(p->ctrl(2,0], p->ctrl(1,1]);
1089 VectorCopy(p->ctrl(1,0], p->ctrl(0,1]);
1090 VectorCopy(p->ctrl(1,0], p->ctrl(0,2]);
1091 VectorCopy(p->ctrl(1,0], p->ctrl(1,2]);
1092 VectorCopy(p->ctrl(2,0], p->ctrl(2,2]);
1093 VectorCopy(p->ctrl(3,0], p->ctrl(3,2]);
1094 VectorCopy(p->ctrl(3,0], p->ctrl(4,2]);
1098 int Index3By[][2] = {
1099 {0,0}, {1,0}, {2,0}, {2,1}, {2,2}, {1,2}, {0,2}, {0,1}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}, {0,0}
1102 int Index5By[][2] = {
1103 {0,0}, {1,0}, {2,0}, {3,0}, {4,0}, {4,1}, {4,2}, {4,3}, {4,4}, {3,4}, {2,4}, {1,4}, {0,4}, {0,3}, {0,2}, {0,1}
1108 int Interior3By[][2] = {
1112 int Interior5By[][2] = {
1113 {1,1}, {2,1}, {3,1}, {1,2}, {2,2}, {3,2}, {1,3}, {2,3}, {3,3}
1116 int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]);
1117 int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]);
1119 face_t * Patch_GetAxisFace( patchMesh_t *p ) {
1122 brush_t *b = p->pSymbiot;
1124 for ( f = b->brush_faces ; f ; f = f->next ) {
1125 vTemp = (*f->face_winding)[1].ToVec3() - (*f->face_winding)[0].ToVec3();
1128 // default edge faces on caps are 8 high so
1129 // as soon as we hit one that is bigger it should be on the right axis
1130 for ( int j = 0; j < 3; j++ ) {
1146 int g_nFaceCycle = 0;
1148 face_t * nextFace( patchMesh_t *p ) {
1149 brush_t *b = p->pSymbiot;
1152 for ( f = b->brush_faces ; f && n <= g_nFaceCycle; f = f->next ) {
1158 if ( g_nFaceCycle > 5 ) {
1167 void Patch_CapTexture( patchMesh_t *p,bool bFaceCycle = false,bool alt = false ) {
1168 Patch_MeshNormals(p);
1169 face_t *f = (bFaceCycle) ? nextFace(p) : Patch_GetAxisFace(p);
1171 VectorCopy(f->plane, vSave);
1172 float fRotate = f->texdef.rotate;
1173 f->texdef.rotate = 0;
1175 fScale[0] = f->texdef.scale[0];
1176 fScale[1] = f->texdef.scale[1];
1177 f->texdef.scale[0] = (float) p->d_texture->GetEditorImage()->uploadWidth / 32.0f;
1178 f->texdef.scale[1] = (float) p->d_texture->GetEditorImage()->uploadHeight / 32.0f;
1180 fShift[0] = f->texdef.shift[0];
1181 fShift[1] = f->texdef.shift[1];
1182 f->texdef.shift[0] = 0;
1183 f->texdef.shift[1] = 0;
1185 for ( int i = 0 ; i < p->width; i++ ) {
1186 for ( int j = 0 ; j < p->height ; j++ ) {
1187 if ( !bFaceCycle ) {
1188 VectorCopy(p->ctrl(i, j).normal, f->plane);
1191 temp.x = p->ctrl(i, j).xyz.x;
1192 temp.y = p->ctrl(i, j).xyz.y;
1193 temp.z = p->ctrl(i, j).xyz.z;
1194 EmitTextureCoordinates(temp, f->d_texture, f, true);
1195 p->ctrl(i, j).st.x = temp.s;
1196 p->ctrl(i, j).st.y = temp.t;
1200 VectorCopy(vSave, f->plane);
1201 f->texdef.rotate = fRotate;
1202 f->texdef.scale[0] = fScale[0];
1203 f->texdef.scale[1] = fScale[1];
1204 f->texdef.shift[0] = fShift[0];
1205 f->texdef.shift[1] = fShift[1];
1206 Patch_ScaleTexture(p, 1.0f, -1.0f, false);
1210 void FillPatch( patchMesh_t *p,idVec3 v ) {
1211 for ( int i = 0; i < p->width; i++ ) {
1212 for ( int j = 0; j < p->height; j++ ) {
1213 VectorCopy(v, p->ctrl(i, j).xyz);
1218 brush_t * Cap( patchMesh_t *pParent,bool bByColumn,bool bFirst ) {
1225 // make a generic patch
1226 if ( pParent->width <= 9 ) {
1227 b = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1229 b = Patch_GenericMesh(5, 5, 2, false, false, pParent);
1234 Sys_Status("Unable to cap. You may need to ungroup the patch.\n");
1239 p->type |= PATCH_CAP;
1241 vMin[0] = vMin[1] = vMin[2] = 99999;
1242 vMax[0] = vMax[1] = vMax[2] = -99999;
1244 // we seam the column edge, FIXME: this might need to be able to seem either edge
1246 int nSize = (bByColumn) ? pParent->width : pParent->height;
1247 int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height - 1 : pParent->width - 1;
1249 FillPatch(p, pParent->ctrl(0, nIndex).xyz);
1251 for ( i = 0; i < nSize; i++ ) {
1254 VectorCopy(pParent->ctrl(i, nIndex).xyz, p->ctrl(Index3By[i][0], Index3By[i][1]).xyz);
1256 VectorCopy(pParent->ctrl(i, nIndex).xyz, p->ctrl(Index5By[i][0], Index5By[i][1]).xyz);
1260 VectorCopy(pParent->ctrl(nIndex, i).xyz, p->ctrl(Index3By[i][0], Index3By[i][1]).xyz);
1262 VectorCopy(pParent->ctrl(nIndex, i).xyz, p->ctrl(Index5By[i][0], Index5By[i][1]).xyz);
1266 for ( j = 0; j < 3; j++ ) {
1267 float f = (bSmall) ? p->ctrl(Index3By[i][0], Index3By[i][1]).xyz[j] : p->ctrl(Index5By[i][0], Index5By[i][1]).xyz[j];
1276 for ( j = 0; j < 3; j++ ) {
1277 vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
1280 int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount;
1281 for ( j = 0; j < nCount; j++ ) {
1283 VectorCopy(vTemp, p->ctrl(Interior3By[j][0], Interior3By[j][1]).xyz);
1285 VectorCopy(vTemp, p->ctrl(Interior5By[j][0], Interior5By[j][1]).xyz);
1290 idDrawVert vertTemp;
1291 for ( i = 0; i < p->width; i++ ) {
1292 for ( j = 0; j < p->height / 2; j++ ) {
1293 memcpy(&vertTemp, &p->ctrl(i, p->height - 1 - j), sizeof(idDrawVert));
1294 memcpy(&p->ctrl(i, p->height - 1 - j), &p->ctrl(i, j), sizeof(idDrawVert));
1295 memcpy(&p->ctrl(i, j), &vertTemp, sizeof(idDrawVert));
1301 Patch_CapTexture(p);
1305 brush_t * CapSpecial( patchMesh_t *pParent,int nType,bool bFirst ) {
1308 idVec3 vMin, vMax, vTemp;
1311 if ( nType == CCapDialog::IENDCAP ) {
1312 b = Patch_GenericMesh(5, 3, 2, false, false, pParent);
1314 b = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1318 Sys_Status("Unable to cap. Make sure you ungroup before re-capping.");
1323 p->type |= PATCH_CAP;
1325 vMin[0] = vMin[1] = vMin[2] = 99999;
1326 vMax[0] = vMax[1] = vMax[2] = -99999;
1328 int nSize = pParent->width;
1329 int nIndex = (bFirst) ? 0 : pParent->height - 1;
1331 // parent bounds are used for some things
1332 Patch_CalcBounds(pParent, vMin, vMax);
1334 for ( j = 0; j < 3; j++ ) {
1335 vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
1338 if ( nType == CCapDialog::IBEVEL ) {
1339 VectorCopy(pParent->ctrl(0, nIndex).xyz, p->ctrl(0, 0).xyz);
1340 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(0, 2).xyz);
1341 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(0, 1).xyz);
1342 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(2, 2).xyz);
1343 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(1, 0).xyz);
1344 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(1, 1).xyz);
1345 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(1, 2).xyz);
1346 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(2, 0).xyz);
1347 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(2, 1).xyz);
1348 } else if ( nType == CCapDialog::BEVEL ) {
1349 idVec3 p1, p2, p3, p4, temp, dir;
1351 VectorCopy(pParent->ctrl(0, nIndex).xyz, p3);
1352 VectorCopy(pParent->ctrl(1, nIndex).xyz, p1);
1353 VectorCopy(pParent->ctrl(2, nIndex).xyz, p2);
1355 VectorSubtract(p3, p2, dir);
1357 VectorSubtract(p1, p2, temp);
1358 float dist = DotProduct(temp, dir);
1360 VectorScale(dir, dist, temp);
1362 VectorAdd(p2, temp, temp);
1364 VectorSubtract(temp, p1, temp);
1365 VectorScale(temp, 2, temp);
1366 VectorAdd(p1, temp, p4);
1368 VectorCopy(p4, p->ctrl(0, 0).xyz);
1369 VectorCopy(p4, p->ctrl(1, 0).xyz);
1370 VectorCopy(p4, p->ctrl(0, 1).xyz);
1371 VectorCopy(p4, p->ctrl(1, 1).xyz);
1372 VectorCopy(p4, p->ctrl(0, 2).xyz);
1373 VectorCopy(p4, p->ctrl(1, 2).xyz);
1374 VectorCopy(p3, p->ctrl(2, 0).xyz);
1375 VectorCopy(p1, p->ctrl(2, 1).xyz);
1376 VectorCopy(p2, p->ctrl(2, 2).xyz);
1377 } else if ( nType == CCapDialog::ENDCAP ) {
1378 VectorAdd(pParent->ctrl(4, nIndex).xyz, pParent->ctrl(0, nIndex).xyz, vTemp);
1379 VectorScale(vTemp, 0.5, vTemp);
1380 VectorCopy(pParent->ctrl(0, nIndex).xyz, p->ctrl(0, 0).xyz);
1381 VectorCopy(vTemp, p->ctrl(1, 0).xyz);
1382 VectorCopy(pParent->ctrl(4, nIndex).xyz, p->ctrl(2, 0).xyz);
1384 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(0, 2).xyz);
1385 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(1, 2).xyz);
1386 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(2, 2).xyz);
1387 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(1, 1).xyz);
1389 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(0, 1).xyz);
1390 VectorCopy(pParent->ctrl(3, nIndex).xyz, p->ctrl(2, 1).xyz);
1392 VectorCopy(pParent->ctrl(0, nIndex).xyz, p->ctrl(0, 0).xyz);
1393 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(1, 0).xyz);
1394 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(2, 0).xyz);
1395 VectorCopy(pParent->ctrl(3, nIndex).xyz, p->ctrl(3, 0).xyz);
1396 VectorCopy(pParent->ctrl(4, nIndex).xyz, p->ctrl(4, 0).xyz);
1398 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(0, 1).xyz);
1399 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(1, 1).xyz);
1400 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(2, 1).xyz);
1401 VectorCopy(pParent->ctrl(3, nIndex).xyz, p->ctrl(3, 1).xyz);
1402 VectorCopy(pParent->ctrl(3, nIndex).xyz, p->ctrl(4, 1).xyz);
1404 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(0, 2).xyz);
1405 VectorCopy(pParent->ctrl(1, nIndex).xyz, p->ctrl(1, 2).xyz);
1406 VectorCopy(pParent->ctrl(2, nIndex).xyz, p->ctrl(2, 2).xyz);
1407 VectorCopy(pParent->ctrl(3, nIndex).xyz, p->ctrl(3, 2).xyz);
1408 VectorCopy(pParent->ctrl(3, nIndex).xyz, p->ctrl(4, 2).xyz);
1412 bool bEndCap = (nType == CCapDialog::ENDCAP || nType == CCapDialog::IENDCAP);
1413 if ( (!bFirst && !bEndCap) || (bFirst && bEndCap) ) {
1414 idDrawVert vertTemp;
1415 for ( i = 0; i < p->width; i++ ) {
1416 for ( j = 0; j < p->height / 2; j++ ) {
1417 memcpy(&vertTemp, &p->ctrl(i, p->height - 1 - j), sizeof(idDrawVert));
1418 memcpy(&p->ctrl(i, p->height - 1 - j), &p->ctrl(i, j), sizeof(idDrawVert));
1419 memcpy(&p->ctrl(i, j), &vertTemp, sizeof(idDrawVert));
1424 //--Patch_CalcBounds(p, vMin, vMax);
1425 //--Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1427 Patch_CapTexture(p);
1432 void Patch_CapCurrent( bool bInvertedBevel,bool bInvertedEndcap ) {
1433 patchMesh_t *pParent = NULL;
1435 brush_t *pCap = NULL;
1436 b[0] = b[1] = b[2] = b[3] = NULL;
1439 if ( !QE_SingleBrush() ) {
1440 Sys_Status("Cannot cap multiple selection. Please select a single patch.\n");
1445 for ( brush_t*pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next ) {
1447 pParent = pb->pPatch;
1448 // decide which if any ends we are going to cap
1449 // if any of these compares hit, it is a closed patch and as such
1450 // the generic capping will work.. if we do not find a closed edge
1451 // then we need to ask which kind of cap to add
1452 if ( pParent->ctrl(0, 0).xyz.Compare(pParent->ctrl(pParent->width - 1, 0).xyz) ) {
1453 pCap = Cap(pParent, true, false);
1454 if ( pCap != NULL ) {
1458 if ( pParent->ctrl(0, pParent->height - 1).xyz.Compare(pParent->ctrl(pParent->width - 1, pParent->height - 1).xyz) ) {
1459 pCap = Cap(pParent, true, true);
1460 if ( pCap != NULL ) {
1464 if ( pParent->ctrl(0, 0).xyz.Compare(pParent->ctrl(0, pParent->height - 1).xyz) ) {
1465 pCap = Cap(pParent, false, false);
1466 if ( pCap != NULL ) {
1470 if ( pParent->ctrl(pParent->width - 1, 0).xyz.Compare(pParent->ctrl(pParent->width - 1, pParent->height - 1).xyz) ) {
1471 pCap = Cap(pParent, false, true);
1472 if ( pCap != NULL ) {
1480 // if we did not cap anything with the above tests
1481 if ( nIndex == 0 ) {
1483 if ( dlg.DoModal() == IDOK ) {
1484 b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), false);
1485 b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), true);
1490 while ( nIndex > 0 ) {
1493 Select_Brush(b[nIndex]);
1496 eclass_t*pecNew = Eclass_ForName("func_static", false);
1498 entity_t*e = Entity_Create(pecNew);
1499 SetKeyValue(e, "type", "patchCapped");
1506 //FIXME: Table drive all this crap
1508 void GenerateEndCaps( brush_t *brushParent,bool bBevel,bool bEndcap,bool bInverted ) {
1510 patchMesh_t *p, *p2, *pParent;
1511 idVec3 vTemp, vMin, vMax;
1514 pParent = brushParent->pPatch;
1516 Patch_CalcBounds(pParent, vMin, vMax);
1517 // basically generate two endcaps, place them, and link the three brushes with a func_group
1519 if ( pParent->width > 9 ) {
1520 b = Patch_GenericMesh(5, 3, 2, false, false, pParent);
1522 b = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1526 vMin[0] = vMin[1] = vMin[2] = 99999;
1527 vMax[0] = vMax[1] = vMax[2] = -99999;
1529 for ( i = 0; i < pParent->width; i++ ) {
1530 VectorCopy(pParent->ctrl(i, 0).xyz, p->ctrl(Index3By[i][0], Index3By[i][1]).xyz);
1531 for ( j = 0; j < 3; j++ ) {
1532 if ( pParent->ctrl(i, 0).xyz[j] < vMin[j] )
1533 vMin[j] = pParent->ctrl(i, 0).xyz[j];
1534 if ( pParent->ctrl(i, 0).xyz[j] > vMax[j] )
1535 vMax[j] = pParent->ctrl(i, 0).xyz[j];
1539 for ( j = 0; j < 3; j++ ) {
1540 vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
1543 for ( i = 0; i < Interior3ByCount; i++ ) {
1544 VectorCopy(vTemp, p->ctrl(Interior3By[i][0], Interior3By[i][1]).xyz);
1547 Patch_CalcBounds(p, vMin, vMax);
1548 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1549 Select_Brush(p->pSymbiot);
1552 bool bCreated = false;
1556 b = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1558 VectorCopy(p->ctrl(2, 2).xyz, p->ctrl(1, 2).xyz);
1559 VectorCopy(p->ctrl(2, 2).xyz, p->ctrl(2, 1).xyz);
1560 VectorCopy(p->ctrl(2, 2).xyz, p->ctrl(0, 1).xyz);
1561 VectorCopy(p->ctrl(2, 2).xyz, p->ctrl(1, 0).xyz);
1562 VectorCopy(p->ctrl(2, 2).xyz, p->ctrl(1, 1).xyz);
1563 VectorCopy(p->ctrl(2, 0).xyz, p->ctrl(0, 0).xyz);
1565 b2 = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1567 VectorCopy(p2->ctrl(2, 2).xyz, p2->ctrl(1, 2).xyz);
1568 VectorCopy(p2->ctrl(2, 2).xyz, p2->ctrl(2, 1).xyz);
1569 VectorCopy(p2->ctrl(2, 2).xyz, p2->ctrl(0, 1).xyz);
1570 VectorCopy(p2->ctrl(2, 2).xyz, p2->ctrl(1, 0).xyz);
1571 VectorCopy(p2->ctrl(2, 2).xyz, p2->ctrl(1, 1).xyz);
1572 VectorCopy(p2->ctrl(2, 0).xyz, p2->ctrl(0, 0).xyz);
1576 } else if ( bEndcap ) {
1577 b = Patch_GenericMesh(5, 5, 2, false, false, pParent);
1579 VectorCopy(p->ctrl(4, 4).xyz, p->ctrl(4, 3).xyz);
1580 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(1, 4).xyz);
1581 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(2, 4).xyz);
1582 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(3, 4).xyz);
1584 VectorCopy(p->ctrl(4, 0).xyz, p->ctrl(4, 1).xyz);
1585 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(1, 0).xyz);
1586 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(2, 0).xyz);
1587 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(3, 0).xyz);
1589 for ( i = 1; i < 4; i++ ) {
1590 for ( j = 0; j < 4; j++ ) {
1591 VectorCopy(p->ctrl(4, i).xyz, p->ctrl(j, i).xyz);
1596 b2 = Patch_GenericMesh(5, 5, 2, false, false, pParent);
1598 VectorCopy(p2->ctrl(4, 4).xyz, p2->ctrl(4, 3).xyz);
1599 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(1, 4).xyz);
1600 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(2, 4).xyz);
1601 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(3, 4).xyz);
1603 VectorCopy(p2->ctrl(4, 0).xyz, p2->ctrl(4, 1).xyz);
1604 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(1, 0).xyz);
1605 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(2, 0).xyz);
1606 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(3, 0).xyz);
1608 for ( i = 1; i < 4; i++ ) {
1609 for ( j = 0; j < 4; j++ ) {
1610 VectorCopy(p2->ctrl(4, i).xyz, p2->ctrl(j, i).xyz);
1619 b = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1621 VectorCopy(p->ctrl(2, 0).xyz, p->ctrl(2, 1).xyz);
1622 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(1, 0).xyz);
1623 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(2, 0).xyz);
1625 b2 = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1627 VectorCopy(p2->ctrl(2, 0).xyz, p2->ctrl(2, 1).xyz);
1628 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(1, 0).xyz);
1629 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(2, 0).xyz);
1631 } else if ( bEndcap ) {
1632 b = Patch_GenericMesh(5, 5, 2, false, false, pParent);
1634 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(1, 0).xyz);
1635 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(2, 0).xyz);
1636 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(3, 0).xyz);
1637 VectorCopy(p->ctrl(4, 0).xyz, p->ctrl(4, 1).xyz);
1638 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(4, 0).xyz);
1640 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(1, 4).xyz);
1641 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(2, 4).xyz);
1642 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(3, 4).xyz);
1643 VectorCopy(p->ctrl(4, 4).xyz, p->ctrl(4, 3).xyz);
1644 VectorCopy(p->ctrl(0, 4).xyz, p->ctrl(4, 4).xyz);
1646 b2 = Patch_GenericMesh(5, 5, 2, false, false, pParent);
1648 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(1, 0).xyz);
1649 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(2, 0).xyz);
1650 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(3, 0).xyz);
1651 VectorCopy(p2->ctrl(4, 0).xyz, p2->ctrl(4, 1).xyz);
1652 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(4, 0).xyz);
1654 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(1, 4).xyz);
1655 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(2, 4).xyz);
1656 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(3, 4).xyz);
1657 VectorCopy(p2->ctrl(4, 4).xyz, p2->ctrl(4, 3).xyz);
1658 VectorCopy(p2->ctrl(0, 4).xyz, p2->ctrl(4, 4).xyz);
1661 b = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1664 VectorCopy(p->ctrl(0, 1).xyz, vTemp);
1665 VectorCopy(p->ctrl(0, 2).xyz, p->ctrl(0, 1).xyz);
1666 VectorCopy(p->ctrl(1, 2).xyz, p->ctrl(0, 2).xyz);
1667 VectorCopy(p->ctrl(2, 2).xyz, p->ctrl(1, 2).xyz);
1668 VectorCopy(p->ctrl(2, 1).xyz, p->ctrl(2, 2).xyz);
1669 VectorCopy(p->ctrl(2, 0).xyz, p->ctrl(2, 1).xyz);
1670 VectorCopy(p->ctrl(1, 0).xyz, p->ctrl(2, 0).xyz);
1671 VectorCopy(p->ctrl(0, 0).xyz, p->ctrl(1, 0).xyz);
1672 VectorCopy(vTemp, p->ctrl(0, 0).xyz);
1674 b2 = Patch_GenericMesh(3, 3, 2, false, false, pParent);
1676 VectorCopy(p2->ctrl(0, 1).xyz, vTemp);
1677 VectorCopy(p2->ctrl(0, 2).xyz, p2->ctrl(0, 1).xyz);
1678 VectorCopy(p2->ctrl(1, 2).xyz, p2->ctrl(0, 2).xyz);
1679 VectorCopy(p2->ctrl(2, 2).xyz, p2->ctrl(1, 2).xyz);
1680 VectorCopy(p2->ctrl(2, 1).xyz, p2->ctrl(2, 2).xyz);
1681 VectorCopy(p2->ctrl(2, 0).xyz, p2->ctrl(2, 1).xyz);
1682 VectorCopy(p2->ctrl(1, 0).xyz, p2->ctrl(2, 0).xyz);
1683 VectorCopy(p2->ctrl(0, 0).xyz, p2->ctrl(1, 0).xyz);
1684 VectorCopy(vTemp, p2->ctrl(0, 0).xyz);
1690 idDrawVert vertTemp;
1691 for ( i = 0; i < p->width; i++ ) {
1692 for ( j = 0; j < p->height; j++ ) {
1693 p->ctrl(i, j).xyz[2] = vMin[2];
1694 p2->ctrl(i, j).xyz[2] = vMax[2];
1697 for ( j = 0; j < p->height / 2; j++ ) {
1698 memcpy(&vertTemp, &p->ctrl(i, p->height - 1 - j), sizeof(idDrawVert));
1699 memcpy(&p->ctrl(i, p->height - 1 - j), &p->ctrl(i, j), sizeof(idDrawVert));
1700 memcpy(&p->ctrl(i, j), &vertTemp, sizeof(idDrawVert));
1705 Patch_CalcBounds(p, vMin, vMax);
1706 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
1707 Patch_CalcBounds(p2, vMin, vMax);
1708 Brush_RebuildBrush(p2->pSymbiot, vMin, vMax);
1709 Select_Brush(p->pSymbiot);
1710 Select_Brush(p2->pSymbiot);
1714 //Select_Brush(brushParent);
1724 void Patch_BrushToMesh( bool bCone,bool bBevel,bool bEndcap,bool bSquare,int nHeight ) {
1730 if ( bBevel & !bSquare ) {
1732 } else if ( bEndcap & !bSquare ) {
1736 if ( !QE_SingleBrush() ) {
1740 b = selected_brushes.next;
1742 p = MakeNewPatch(width, nHeight);
1744 p->d_texture = b->brush_faces->d_texture;
1746 p->type = PATCH_CYLINDER;
1747 if ( bBevel & !bSquare ) {
1748 p->type = PATCH_BEVEL;
1749 int nStep = (b->maxs[2] - b->mins[2]) / (p->height - 1);
1750 int nStart = b->mins[2];
1751 for ( i = 0; i < p->height; i++ ) {
1752 p->ctrl(0, i).xyz[0] = b->mins[0];
1753 p->ctrl(0, i).xyz[1] = b->mins[1];
1754 p->ctrl(0, i).xyz[2] = nStart;
1756 p->ctrl(1, i).xyz[0] = b->maxs[0];
1757 p->ctrl(1, i).xyz[1] = b->mins[1];
1758 p->ctrl(1, i).xyz[2] = nStart;
1760 p->ctrl(2, i).xyz[0] = b->maxs[0];
1761 p->ctrl(2, i).xyz[1] = b->maxs[1];
1762 p->ctrl(2, i).xyz[2] = nStart;
1765 } else if ( bEndcap & !bSquare ) {
1766 p->type = PATCH_ENDCAP;
1767 int nStep = (b->maxs[2] - b->mins[2]) / (p->height - 1);
1768 int nStart = b->mins[2];
1769 for ( i = 0; i < p->height; i++ ) {
1770 p->ctrl(0, i).xyz[0] = b->mins[0];
1771 p->ctrl(0, i).xyz[1] = b->mins[1];
1772 p->ctrl(0, i).xyz[2] = nStart;
1774 p->ctrl(1, i).xyz[0] = b->mins[0];
1775 p->ctrl(1, i).xyz[1] = b->maxs[1];
1776 p->ctrl(1, i).xyz[2] = nStart;
1778 p->ctrl(2, i).xyz[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5);
1779 p->ctrl(2, i).xyz[1] = b->maxs[1];
1780 p->ctrl(2, i).xyz[2] = nStart;
1782 p->ctrl(3, i).xyz[0] = b->maxs[0];
1783 p->ctrl(3, i).xyz[1] = b->maxs[1];
1784 p->ctrl(3, i).xyz[2] = nStart;
1786 p->ctrl(4, i).xyz[0] = b->maxs[0];
1787 p->ctrl(4, i).xyz[1] = b->mins[1];
1788 p->ctrl(4, i).xyz[2] = nStart;
1792 p->ctrl(1, 0).xyz[0] = b->mins[0];
1793 p->ctrl(1, 0).xyz[1] = b->mins[1];
1795 p->ctrl(3, 0).xyz[0] = b->maxs[0];
1796 p->ctrl(3, 0).xyz[1] = b->mins[1];
1798 p->ctrl(5, 0).xyz[0] = b->maxs[0];
1799 p->ctrl(5, 0).xyz[1] = b->maxs[1];
1801 p->ctrl(7, 0).xyz[0] = b->mins[0];
1802 p->ctrl(7, 0).xyz[1] = b->maxs[1];
1804 for ( i = 1 ; i < p->width - 1 ; i += 2 ) {
1805 p->ctrl(i, 0).xyz[2] = b->mins[2];
1807 VectorCopy(p->ctrl(i, 0).xyz, p->ctrl(i, 2).xyz);
1809 p->ctrl(i, 2).xyz[2] = b->maxs[2];
1811 p->ctrl(i, 1).xyz[0] = (p->ctrl(i, 0).xyz[0] + p->ctrl(i, 2).xyz[0]) * 0.5;
1812 p->ctrl(i, 1).xyz[1] = (p->ctrl(i, 0).xyz[1] + p->ctrl(i, 2).xyz[1]) * 0.5;
1813 p->ctrl(i, 1).xyz[2] = (p->ctrl(i, 0).xyz[2] + p->ctrl(i, 2).xyz[2]) * 0.5;
1815 InterpolateInteriorPoints(p);
1818 if ( bBevel || bEndcap ) {
1820 for ( i = 0; i < p->height; i++ ) {
1821 VectorCopy(p->ctrl(1, i).xyz, p->ctrl(2, i).xyz);
1822 VectorCopy(p->ctrl(7, i).xyz, p->ctrl(6, i).xyz);
1825 for ( i = 0; i < p->height; i++ ) {
1826 VectorCopy(p->ctrl(5, i).xyz, p->ctrl(4, i).xyz);
1827 VectorCopy(p->ctrl(1, i).xyz, p->ctrl(2, i).xyz);
1828 VectorCopy(p->ctrl(7, i).xyz, p->ctrl(6, i).xyz);
1829 VectorCopy(p->ctrl(8, i).xyz, p->ctrl(7, i).xyz);
1833 for ( i = 0; i < p->width - 1; i ++ ) {
1834 for ( j = 0; j < p->height; j++ ) {
1835 VectorCopy(p->ctrl(i + 1, j).xyz, p->ctrl(i, j).xyz);
1838 for ( j = 0; j < p->height; j++ ) {
1839 VectorCopy(p->ctrl(0, j).xyz, p->ctrl(8, j).xyz);
1846 Patch_Naturalize(p);
1849 p->type = PATCH_CONE;
1850 float xc = (b->maxs[0] + b->mins[0]) * 0.5;
1851 float yc = (b->maxs[1] + b->mins[1]) * 0.5;
1853 for ( i = 0 ; i < p->width ; i ++ ) {
1854 p->ctrl(i, 2).xyz[0] = xc;
1855 p->ctrl(i, 2).xyz[1] = yc;
1858 b = AddBrushForPatch(p);
1864 patchMesh_t * Patch_GenerateGeneric( int width,int height,int orientation,const idVec3 &mins,const idVec3 &maxs ) {
1865 patchMesh_t *p = MakeNewPatch(width, height);
1866 p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
1868 p->type = PATCH_GENERIC;
1872 if ( orientation == 0 ) {
1875 } else if ( orientation == 1 ) {
1880 int xStep = mins[nFirst];
1881 float xAdj = abs((maxs[nFirst] - mins[nFirst]) / (width - 1));
1882 float yAdj = abs((maxs[nSecond] - mins[nSecond]) / (height - 1));
1884 for ( int i = 0; i < width; i++ ) {
1885 int yStep = mins[nSecond];
1886 for ( int j = 0; j < height; j++ ) {
1887 p->ctrl(i, j).xyz[nFirst] = xStep;
1888 p->ctrl(i, j).xyz[nSecond] = yStep;
1889 p->ctrl(i, j).xyz[orientation] = g_qeglobals.d_new_brush_bottom[orientation];
1903 brush_t * Patch_GenericMesh( int width,int height,int orientation,bool bDeleteSource,bool bOverride,patchMesh_t *parent ) {
1904 if ( height < 3 || height> 15 || width < 3 || width> 15 ) {
1905 Sys_Status("Invalid patch width or height.\n");
1909 if ( !bOverride && !QE_SingleBrush() ) {
1910 Sys_Status("Cannot generate a patch from multiple selections.\n");
1914 brush_t *b = selected_brushes.next;
1916 patchMesh_t *p = Patch_GenerateGeneric(width, height, orientation, b->mins, b->maxs);
1919 p->explicitSubdivisions = parent->explicitSubdivisions;
1920 p->horzSubdivisions = parent->horzSubdivisions;
1921 p->vertSubdivisions = parent->vertSubdivisions;
1924 Patch_Naturalize(p);
1926 b = AddBrushForPatch(p);
1928 if ( bDeleteSource ) {
1941 int PointInMoveList( idVec3 *pf ) {
1942 for ( int i = 0; i < g_qeglobals.d_num_move_points; i++ ) {
1943 if ( pf == g_qeglobals.d_move_points[i] ) {
1952 PointValueInMoveList
1955 static int PointValueInMoveList( idVec3 v ) {
1956 for ( int i = 0; i < g_qeglobals.d_num_move_points; i++ ) {
1957 if ( v.Compare(*g_qeglobals.d_move_points[i]) ) {
1966 RemovePointFromMoveList
1969 void RemovePointFromMoveList( idVec3 v ) {
1971 while ( (n = PointValueInMoveList(v)) >= 0 ) {
1972 for ( int i = n; i < g_qeglobals.d_num_move_points - 1; i++ ) {
1973 g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i + 1];
1975 g_qeglobals.d_num_move_points--;
1984 bool ColumnSelected( patchMesh_t *p,int nCol ) {
1985 for ( int i = 0; i < p->height; i++ ) {
1986 if ( PointInMoveList(&p->ctrl(nCol, i).xyz) == -1 ) {
1999 static void AddPoint( patchMesh_t *p,idVec3 *v,bool bWeldOrDrill = true ) {
2000 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
2001 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
2002 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v;
2003 if ( (g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill ) {
2004 for ( int i = 0 ; i < p->width ; i++ ) {
2005 for ( int j = 0 ; j < p->height ; j++ ) {
2006 if ( g_bPatchWeld ) {
2007 if ( (*v).Compare(p->ctrl(i, j).xyz) && PointInMoveList(&p->ctrl(i, j).xyz) == -1 ) {
2008 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = &p->ctrl(i, j).xyz;
2012 if ( g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA ) {
2013 if ( (idMath::Fabs((*v)[nDim1] - p->ctrl(i, j).xyz[nDim1]) <= VECTOR_EPSILON) && (idMath::Fabs((*v)[nDim2] - p->ctrl(i, j).xyz[nDim2]) <= VECTOR_EPSILON) ) {
2014 if ( PointInMoveList(&p->ctrl(i, j).xyz) == -1 ) {
2015 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = &p->ctrl(i, j).xyz;
2021 for ( int k = 0; k < 2; k++ ) {
2022 if (idMath::Fabs(v[k] - p->ctrl(i,j).xyz[k]) > VECTOR_EPSILON)
2026 if (l >= 2 && PointInMoveList(&p->ctrl(i,j).xyz) == -1) {
2027 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl(i,j).xyz;
2036 if (g_qeglobals.d_num_move_points == 1) {
2037 // single point selected
2038 // FIXME: the two loops can probably be reduced to one
2039 for ( int i = 0 ; i < p->width ; i++ ) {
2040 for ( int j = 0 ; j < p->height ; j++ ) {
2041 int n = PointInMoveList(v);
2043 if (((i & 0x01) && (j & 0x01)) == 0) {
2044 // put any sibling fixed points
2045 // into the inverse list
2051 if (p1 < p->width) {
2056 if (p3 < p->height) {
2073 void SelectRow( patchMesh_t *p,int nRow,bool bMulti ) {
2075 g_qeglobals.d_num_move_points = 0;
2077 for ( int i = 0; i < p->width; i++ ) {
2078 AddPoint(p, &p->ctrl(i, nRow).xyz, false);
2080 //common->Printf("Selected Row %d\n", nRow);
2088 void SelectColumn( patchMesh_t *p,int nCol,bool bMulti ) {
2090 g_qeglobals.d_num_move_points = 0;
2092 for ( int i = 0; i < p->height; i++ ) {
2093 AddPoint(p, &p->ctrl(nCol, i).xyz, false);
2095 //common->Printf("Selected Col %d\n", nCol);
2104 void AddPatchMovePoint( idVec3 v,bool bMulti,bool bFull ) {
2105 if ( !g_bSameView && !bMulti && !bFull ) {
2110 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
2112 patchMesh_t *p = pb->pPatch;
2113 for ( int i = 0 ; i < p->width ; i++ ) {
2114 for ( int j = 0 ; j < p->height ; j++ ) {
2115 if ( v.Compare(p->ctrl(i, j).xyz) ) {
2116 if ( PointInMoveList(&p->ctrl(i, j).xyz) == -1 ) {
2117 if ( bFull ) // if we want the full row/col this is on
2119 SelectColumn(p, i, bMulti);
2122 g_qeglobals.d_num_move_points = 0;
2123 AddPoint(p, &p->ctrl(i, j).xyz);
2124 //common->Printf("Selected col:row %d:%d\n", i, j);
2130 if ( ColumnSelected(p, i) ) {
2131 SelectRow(p, j, bMulti);
2133 SelectColumn(p, i, bMulti);
2137 if ( g_bSameView ) {
2138 RemovePointFromMoveList(v);
2150 Patch_UpdateSelected
2153 void Patch_UpdateSelected( idVec3 vMove ) {
2155 for ( i = 0 ; i < g_qeglobals.d_num_move_points ; i++ ) {
2156 VectorAdd(*g_qeglobals.d_move_points[i], vMove, *g_qeglobals.d_move_points[i]);
2157 if ( g_qeglobals.d_num_move_points == 1 ) {
2161 //--patchMesh_t* p = &patchMeshes[g_nSelectedPatch];
2162 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
2164 patchMesh_t *p = pb->pPatch;
2167 g_qeglobals.d_numpoints = 0;
2168 for ( i = 0 ; i < p->width ; i++ ) {
2169 for ( j = 0 ; j < p->height ; j++ ) {
2170 VectorCopy(p->ctrl(i, j).xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
2171 if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
2172 g_qeglobals.d_numpoints++;
2178 Patch_CalcBounds(p, vMin, vMax);
2179 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
2182 //Brush_Free(p->pSymbiot);
2183 //Select_Brush(AddBrushForPatch(g_nSelectedPatch));
2187 void Patch_AdjustSubdivisions( float hadj,float vadj ) {
2189 for ( pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
2191 patchMesh_t *p = pb->pPatch;
2192 p->horzSubdivisions += hadj;
2193 p->vertSubdivisions += vadj;
2197 Sys_UpdateWindows(W_ALL);
2200 extern float ShadeForNormal( idVec3 normal );
2207 //FIXME: this routine needs to be reorganized.. should be about 1/4 the size and complexity
2208 void DrawPatchMesh( patchMesh_t *pm,bool bPoints,int *list,bool bShade = false ) {
2211 bool bOverlay = pm->bOverlay;
2212 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
2214 // patches use two display lists, one for camera one for xy
2217 *list = qglGenLists(1);
2221 qglNewList(*list, GL_COMPILE_AND_EXECUTE);
2224 //FIXME: finish consolidating all the patch crap
2225 idSurface_Patch *cp = new idSurface_Patch(pm->width * 6, pm->height * 6);
2226 cp->SetSize(pm->width, pm->height);
2227 for ( i = 0; i < pm->width; i++ ) {
2228 for ( j = 0; j < pm->height; j++ ) {
2229 (*cp)[j * cp->GetWidth() + i].xyz = pm->ctrl(i, j).xyz;
2230 (*cp)[j * cp->GetWidth() + i].st = pm->ctrl(i, j).st;
2234 if ( pm->explicitSubdivisions ) {
2235 cp->SubdivideExplicit(pm->horzSubdivisions, pm->vertSubdivisions, true);
2237 cp->Subdivide(DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_ERROR, DEFAULT_CURVE_MAX_LENGTH, true);
2241 int width = cp->GetWidth();
2242 int height = cp->GetHeight();
2244 for (i = 0; i < width; i++) {
2245 for (j = 0; j < height; j++) {
2246 qglBegin(GL_POINTS);
2247 int index = j * width + i;
2248 qglVertex3fv((*cp)[index].xyz);
2251 sprintf(msg, "(%0.3f, %0.3f, %0.3f)(%0.3f, %0.3f)", (*cp)[index].xyz.x, (*cp)[index].xyz.y, (*cp)[index].xyz.z, (*cp)[index].st.x, (*cp)[index].st.y);
2252 qglRasterPos3f((*cp)[index].xyz.x + 1, (*cp)[index].xyz.y + 1, (*cp)[index].xyz.z + 1);
2253 qglCallLists (strlen(msg), GL_UNSIGNED_BYTE, msg);
2257 #ifdef TEST_SURFACE_CLIPPING
2259 idSurface *surf = cp;
2260 idSurface *front, *back;
2262 surf->Split(idPlane(1, 0, 0, 0), 0.1f, &front, &back);
2263 if ( front && back ) {
2264 front->TranslateSelf(idVec3(10, 10, 10));
2265 (*front) += (*back);
2270 // surf->ClipInPlace( idPlane( 1, 0, 0, 0 ), 0.1f, true );
2272 qglBegin(GL_TRIANGLES);
2273 for ( i = 0; i < surf->GetNumIndexes(); i += 3 ) {
2274 n = surf->GetIndexes()[i + 0];
2275 qglTexCoord2fv((*surf)[n].st.ToFloatPtr());
2276 qglVertex3fv((*surf)[n].xyz.ToFloatPtr());
2277 n = surf->GetIndexes()[i + 1];
2278 qglTexCoord2fv((*surf)[n].st.ToFloatPtr());
2279 qglVertex3fv((*surf)[n].xyz.ToFloatPtr());
2280 n = surf->GetIndexes()[i + 2];
2281 qglTexCoord2fv((*surf)[n].st.ToFloatPtr());
2282 qglVertex3fv((*surf)[n].xyz.ToFloatPtr());
2293 for ( i = 0 ; i < width - 1; i++ ) {
2294 qglBegin(GL_QUAD_STRIP);
2295 for ( j = 0 ; j < height; j++ ) {
2296 // v1-v2-v3-v4 makes a quad
2302 f = ShadeForNormal((*cp)[v2].normal);
2303 qglColor3f(f, f, f);
2305 qglTexCoord2fv((*cp)[v2].st.ToFloatPtr());
2306 qglVertex3fv((*cp)[v2].xyz.ToFloatPtr());
2308 f = ShadeForNormal((*cp)[v1].normal);
2309 qglColor3f(f, f, f);
2311 qglTexCoord2fv((*cp)[v1].st.ToFloatPtr());
2312 qglVertex3fv((*cp)[v1].xyz.ToFloatPtr());
2318 if ( list == &pm->nListSelected ) {
2319 globalImages->BindNull();
2320 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2321 qglColor3f(1.0f, 1.0f, 1.0f);
2322 for ( i = 0 ; i < width - 1; i++ ) {
2323 qglBegin(GL_QUAD_STRIP);
2324 for ( j = 0 ; j < height; j++ ) {
2328 qglVertex3fv((*cp)[v2].xyz.ToFloatPtr());
2329 qglVertex3fv((*cp)[v1].xyz.ToFloatPtr());
2344 idVec3 *pSelectedPoints[256];
2347 // FIXME: this bend painting code needs to be rolled up significantly as it is a mess right now
2348 if ( bPoints && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area || g_bPatchBendMode || g_bPatchInsertMode) ) {
2351 // bending or inserting
2352 if ( g_bPatchBendMode || g_bPatchInsertMode ) {
2354 if ( g_bPatchAxisOnRow ) {
2355 qglColor3f(1, 0, 1);
2356 qglBegin(GL_POINTS);
2357 for ( i = 0; i < pm->width; i++ ) {
2358 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(i, g_nPatchAxisIndex).xyz));
2362 // could do all of this in one loop but it was pretty messy
2363 if ( g_bPatchInsertMode ) {
2364 qglColor3f(0, 0, 1);
2365 qglBegin(GL_POINTS);
2366 for ( i = 0; i < pm->width; i++ ) {
2367 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(i, g_nPatchAxisIndex).xyz));
2368 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(i, g_nPatchAxisIndex + 1).xyz));
2372 if ( g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN ) {
2373 qglColor3f(0, 0, 1);
2374 qglBegin(GL_POINTS);
2375 if ( g_nPatchBendState == BEND_SELECT_ORIGIN ) {
2376 qglVertex3fv(g_vBendOrigin.ToFloatPtr());
2378 for ( i = 0; i < pm->width; i++ ) {
2379 if ( g_bPatchLowerEdge ) {
2380 for ( j = 0; j < g_nPatchAxisIndex; j++ ) {
2381 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(i, j).xyz));
2384 for ( j = pm->height - 1; j > g_nPatchAxisIndex; j-- ) {
2385 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(i, j).xyz));
2394 qglColor3f(1, 0, 1);
2395 qglBegin(GL_POINTS);
2396 for ( i = 0; i < pm->height; i++ ) {
2397 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(g_nPatchAxisIndex, i).xyz));
2401 // could do all of this in one loop but it was pretty messy
2402 if ( g_bPatchInsertMode ) {
2403 qglColor3f(0, 0, 1);
2404 qglBegin(GL_POINTS);
2405 for ( i = 0; i < pm->height; i++ ) {
2406 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(g_nPatchAxisIndex, i).xyz));
2407 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(g_nPatchAxisIndex + 1, i).xyz));
2411 if ( g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN ) {
2412 qglColor3f(0, 0, 1);
2413 qglBegin(GL_POINTS);
2414 for ( i = 0; i < pm->height; i++ ) {
2415 if ( g_nPatchBendState == BEND_SELECT_ORIGIN ) {
2416 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(g_nBendOriginIndex, i).xyz));
2418 if ( g_bPatchLowerEdge ) {
2419 for ( j = 0; j < g_nPatchAxisIndex; j++ ) {
2420 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(j, i).xyz));
2423 for ( j = pm->width - 1; j > g_nPatchAxisIndex; j-- ) {
2424 qglVertex3fv(reinterpret_cast< float(*)>(&pm->ctrl(j, i).xyz));
2435 for ( i = 0 ; i < pm->width ; i++ ) {
2436 for ( j = 0 ; j < pm->height ; j++ ) {
2437 qglBegin(GL_POINTS);
2438 // FIXME: need to not do loop lookups inside here
2439 int n = PointValueInMoveList(pm->ctrl(i, j).xyz);
2441 pSelectedPoints[nIndex++] = &pm->ctrl(i, j).xyz;
2444 if ( i & 0x01 || j & 0x01 ) {
2445 qglColor3f(1, 0, 1);
2447 qglColor3f(0, 1, 0);
2449 qglVertex3fv(pm->ctrl(i, j).xyz.ToFloatPtr());
2456 qglBegin(GL_POINTS);
2457 qglColor3f(0, 0, 1);
2458 while ( nIndex-- > 0 ) {
2459 qglVertex3fv((*pSelectedPoints[nIndex]).ToFloatPtr());
2466 qglColor3f(0.5, 0.5, 0.5);
2467 for ( i = 0 ; i < pm->width ; i++ ) {
2468 qglBegin(GL_POINTS);
2469 for ( j = 0 ; j < pm->height ; j++ ) {
2470 if ( i & 0x01 || j & 0x01 ) {
2471 qglColor3f(0.5, 0, 0.5);
2473 qglColor3f(0, 0.5, 0);
2475 qglVertex3fv(pm->ctrl(i, j).xyz.ToFloatPtr());
2487 void Patch_DrawXY( patchMesh_t *pm ) {
2488 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2489 if ( pm->bSelected ) {
2490 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
2491 //qglDisable (GL_LINE_STIPPLE);
2494 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES].ToFloatPtr());
2497 DrawPatchMesh(pm, pm->bSelected, &pm->nListID);
2498 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2499 if ( pm->bSelected ) {
2501 //qglEnable (GL_LINE_STIPPLE);
2510 void Patch_DrawCam( patchMesh_t *pm,bool selected ) {
2512 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
2515 qglColor3f(1, 1, 1);
2518 if ( g_bPatchWireFrame || nDrawMode == cd_wire ) {
2519 qglDisable(GL_CULL_FACE);
2520 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2521 globalImages->BindNull();
2522 DrawPatchMesh(pm, pm->bSelected, &pm->nListIDCam, true);
2523 qglEnable(GL_CULL_FACE);
2525 qglEnable(GL_CULL_FACE);
2526 qglCullFace(GL_FRONT);
2527 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
2529 if ( nDrawMode == cd_texture || nDrawMode == cd_light ) {
2530 pm->d_texture->GetEditorImage()->Bind();
2533 if ( !selected && pm->d_texture->GetEditorAlpha() != 1.0f ) {
2534 qglEnable(GL_BLEND);
2535 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2538 DrawPatchMesh(pm, pm->bSelected, &pm->nListIDCam, true);
2540 if ( !selected && pm->d_texture->GetEditorAlpha() != 1.0f ) {
2541 qglDisable(GL_BLEND);
2544 globalImages->BindNull();
2547 qglCullFace(GL_BACK);
2548 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
2549 qglDisable(GL_BLEND);
2551 qglEnable(GL_BLEND);
2552 qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][0], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][1], g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES][2], 0.25);
2553 qglDisable(GL_CULL_FACE);
2555 DrawPatchMesh(pm, pm->bSelected, (selected) ? &pm->nListSelected : &pm->nListIDCam, !selected);
2556 qglEnable(GL_CULL_FACE);
2559 #if 0 // this paints normal indicators on the ctrl points
2560 //--qglDisable (GL_DEPTH_TEST);
2562 for (int i = 0; i < pm->width; i++) {
2563 for (int j = 0; j < pm->height; j++) {
2565 qglBegin (GL_LINES);
2566 qglVertex3fv (pm->ctrl(i,j).xyz);
2567 VectorMA (pm->ctrl(i,j).xyz, 8, pm->ctrl(i,j].normal, temp);
2568 qglVertex3fv (temp);
2572 //--qglEnable (GL_DEPTH_TEST);
2580 void ConvexHullForSection( float section[2][4][7] ) {
2583 void BrushesForSection( float section[2][4][7] ) {
2592 void Patch_Move( patchMesh_t *pm,const idVec3 vMove,bool bRebuild ) {
2593 Patch_MakeDirty(pm);
2594 for ( int w = 0; w < pm->width; w++ ) {
2595 for ( int h = 0; h < pm->height; h++ ) {
2596 VectorAdd(pm->ctrl(w, h).xyz, vMove, pm->ctrl(w, h).xyz);
2601 Patch_CalcBounds(pm, vMin, vMax);
2602 //Brush_RebuildBrush(patchMeshes[n].pSymbiot, vMin, vMax);
2604 UpdatePatchInspector();
2612 void Patch_ApplyMatrix( patchMesh_t *p,const idVec3 vOrigin,const idMat3 matrix,bool bSnap ) {
2615 for ( int w = 0; w < p->width; w++ ) {
2616 for ( int h = 0; h < p->height; h++ ) {
2617 if ( (g_qeglobals.d_select_mode == sel_curvepoint || g_bPatchBendMode) && PointInMoveList(&p->ctrl(w, h).xyz) == -1 ) {
2620 vTemp = p->ctrl(w, h).xyz - vOrigin;
2622 p->ctrl(w, h).xyz = vTemp + vOrigin;
2626 Patch_CalcBounds(p, vMin, vMax);
2627 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
2635 void Patch_EditPatch() {
2636 //--patchMesh_t* p = &patchMeshes[n];
2637 g_qeglobals.d_numpoints = 0;
2638 g_qeglobals.d_num_move_points = 0;
2640 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
2642 patchMesh_t *p = pb->pPatch;
2643 for ( int i = 0 ; i < p->width ; i++ ) {
2644 for ( int j = 0 ; j < p->height ; j++ ) {
2645 VectorCopy(p->ctrl(i, j).xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
2646 if ( g_qeglobals.d_numpoints < MAX_POINTS - 1 ) {
2647 g_qeglobals.d_numpoints++;
2653 g_qeglobals.d_select_mode = sel_curvepoint;
2654 //--g_nSelectedPatch = n;
2664 //FIXME: need all sorts of asserts throughout a lot of this crap
2665 void Patch_Deselect() {
2666 //--g_nSelectedPatch = -1;
2667 g_qeglobals.d_select_mode = sel_brush;
2669 for ( brush_t*b = selected_brushes.next ; b != &selected_brushes ; b = b->next ) {
2671 b->pPatch->bSelected = false;
2675 if ( g_bPatchBendMode ) {
2679 if ( g_bPatchInsertMode ) {
2680 Patch_InsDelToggle();
2690 void Patch_Select( patchMesh_t *p ) {
2691 // maintained for point manip.. which i need to fix as this
2692 // is pf error prone
2693 //--g_nSelectedPatch = n;
2694 p->bSelected = true;
2703 void Patch_Deselect( patchMesh_t *p ) {
2704 p->bSelected = false;
2713 void Patch_Delete( patchMesh_t *p ) {
2714 if ( p->pSymbiot ) {
2715 p->pSymbiot->pPatch = NULL;
2726 UpdatePatchInspector();
2735 void Patch_Scale( patchMesh_t *p,const idVec3 vOrigin,const idVec3 vAmt,bool bRebuild ) {
2736 for ( int w = 0; w < p->width; w++ ) {
2737 for ( int h = 0; h < p->height; h++ ) {
2738 if ( g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(&p->ctrl(w, h).xyz) == -1 )
2740 for ( int i = 0 ; i < 3 ; i++ ) {
2741 p->ctrl(w, h).xyz[i] -= vOrigin[i];
2742 p->ctrl(w, h).xyz[i] *= vAmt[i];
2743 p->ctrl(w, h).xyz[i] += vOrigin[i];
2749 Patch_CalcBounds(p, vMin, vMax);
2750 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
2752 UpdatePatchInspector();
2761 void Patch_Cleanup() {
2762 //--g_nSelectedPatch = -1;
2763 //numPatchMeshes = 0;
2773 void Patch_SetView( int n ) {
2774 g_bSameView = (n == g_nPatchClickedView);
2775 g_nPatchClickedView = n;
2784 // FIXME: need array validation throughout
2785 void Patch_SetTexture( patchMesh_t *p,texdef_t *tex_def ) {
2786 p->d_texture = Texture_ForName(tex_def->name);
2787 UpdatePatchInspector();
2795 // FIXME: need array validation throughout
2796 void Patch_SetTextureName( patchMesh_t *p,const char *name ) {
2797 p->d_texture = Texture_ForName(name);
2798 UpdatePatchInspector();
2807 bool Patch_DragScale( patchMesh_t *p,idVec3 vAmt,idVec3 vMove ) {
2808 idVec3 vMin, vMax, vScale, vTemp, vMid;
2811 Patch_CalcBounds(p, vMin, vMax);
2813 VectorSubtract(vMax, vMin, vTemp);
2815 // if we are scaling in the same dimension the patch has no depth
2816 for ( i = 0; i < 3; i ++ ) {
2817 if ( vTemp[i] == 0 && vMove[i] != 0 ) {
2818 //Patch_Move(n, vMove, true);
2823 for ( i = 0 ; i < 3 ; i++ )
2824 vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2));
2826 for ( i = 0; i < 3; i++ ) {
2827 if ( vAmt[i] != 0 ) {
2828 vScale[i] = 1.0f + vAmt[i] / vTemp[i];
2834 Patch_Scale(p, vMid, vScale, false);
2836 VectorSubtract(vMax, vMin, vTemp);
2838 Patch_CalcBounds(p, vMin, vMax);
2840 VectorSubtract(vMax, vMin, vMid);
2842 VectorSubtract(vMid, vTemp, vTemp);
2844 VectorScale(vTemp, 0.5, vTemp);
2846 // abs of both should always be equal
2847 if ( !vMove.Compare(vAmt) ) {
2848 for ( i = 0; i < 3; i++ ) {
2849 if ( vMove[i] != vAmt[i] ) {
2850 vTemp[i] = -(vTemp[i]);
2855 Patch_Move(p, vTemp);
2865 void Patch_InsertColumn( patchMesh_t *p,bool bAdd ) {
2869 if ( p->width + 2 >= MAX_PATCH_WIDTH ) {
2873 Patch_AdjustSize(p, 2, 0);
2875 // re-adjust til after routine
2880 for ( h = 0; h < p->height; h++ ) {
2883 VectorSubtract(p->ctrl(j, h).xyz, p->ctrl(j - 1, h).xyz, vTemp);
2885 for ( i = 0; i < 3; i++ ) {
2889 memcpy(&p->ctrl(j + 2, h), &p->ctrl(j, h), sizeof(idDrawVert));
2890 memcpy(&p->ctrl(j, h), &p->ctrl(j - 1, h), sizeof(idDrawVert));
2892 VectorAdd(p->ctrl(j, h).xyz, vTemp, p->ctrl(j, h).xyz);
2893 memcpy(&p->ctrl(j + 1, h), &p->ctrl(j, h), sizeof(idDrawVert));
2894 VectorAdd(p->ctrl(j + 1, h).xyz, vTemp, p->ctrl(j + 1, h).xyz);
2897 for ( h = 0; h < p->height; h++ ) {
2900 memcpy(&p->ctrl(w + 2, h), &p->ctrl(w, h), sizeof(idDrawVert));
2903 VectorSubtract(p->ctrl(1, h).xyz, p->ctrl(0, h).xyz, vTemp);
2904 for ( i = 0; i < 3; i++ ) {
2907 VectorCopy(p->ctrl(0, h).xyz, p->ctrl(1, h).xyz);
2908 VectorAdd(p->ctrl(1, h).xyz, vTemp, p->ctrl(1, h).xyz);
2909 VectorCopy(p->ctrl(1, h).xyz, p->ctrl(2, h).xyz);
2910 VectorAdd(p->ctrl(2, h).xyz, vTemp, p->ctrl(2, h).xyz);
2914 UpdatePatchInspector();
2923 void Patch_InsertRow( patchMesh_t *p,bool bAdd ) {
2927 if ( p->height + 2 >= MAX_PATCH_HEIGHT ) {
2931 Patch_AdjustSize(p, 0, 2);
2935 for ( w = 0; w < p->width; w++ ) {
2937 VectorSubtract(p->ctrl(w, j).xyz, p->ctrl(w, j - 1).xyz, vTemp);
2938 for ( i = 0; i < 3; i++ ) {
2942 memcpy(&p->ctrl(w, j + 2), &p->ctrl(w, j), sizeof(idDrawVert));
2943 memcpy(&p->ctrl(w, j), &p->ctrl(w, j - 1), sizeof(idDrawVert));
2945 VectorAdd(p->ctrl(w, j).xyz, vTemp, p->ctrl(w, j).xyz);
2946 memcpy(&p->ctrl(w, j + 1), &p->ctrl(w, j), sizeof(idDrawVert));
2947 VectorAdd(p->ctrl(w, j + 1).xyz, vTemp, p->ctrl(w, j + 1).xyz);
2950 for ( w = 0; w < p->width; w++ ) {
2953 memcpy(&p->ctrl(w, h + 2), &p->ctrl(w, h), sizeof(idDrawVert));
2956 VectorSubtract(p->ctrl(w, 1).xyz, p->ctrl(w, 0).xyz, vTemp);
2957 for ( i = 0; i < 3; i++ ) {
2961 VectorCopy(p->ctrl(w, 0).xyz, p->ctrl(w, 1).xyz);
2962 VectorAdd(p->ctrl(w, 1).xyz, vTemp, p->ctrl(w, 1).xyz);
2963 VectorCopy(p->ctrl(w, 1).xyz, p->ctrl(w, 2).xyz);
2964 VectorAdd(p->ctrl(w, 2).xyz, vTemp, p->ctrl(w, 2).xyz);
2968 UpdatePatchInspector();
2977 void Patch_RemoveRow( patchMesh_t *p,bool bFirst ) {
2978 if ( p->height <= MIN_PATCH_HEIGHT ) {
2983 for ( int w = 0; w < p->width; w++ ) {
2984 for ( int h = 0; h < p->height - 2; h++ ) {
2985 memcpy(&p->ctrl(w, h), &p->ctrl(w, h + 2), sizeof(idDrawVert));
2990 Patch_AdjustSize(p, 0, -2);
2992 UpdatePatchInspector();
3001 void Patch_RemoveColumn( patchMesh_t *p,bool bFirst ) {
3002 if ( p->width <= MIN_PATCH_WIDTH ) {
3007 for ( int h = 0; h < p->height; h++ ) {
3008 for ( int w = 0; w < p->width - 2; w++ ) {
3009 memcpy(&p->ctrl(w, h), &p->ctrl(w + 2, h), sizeof(idDrawVert));
3014 Patch_AdjustSize(p, -2, 0);
3016 UpdatePatchInspector();
3020 void Patch_DisperseRows() {
3021 idVec3 vTemp, vTemp2;
3025 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3027 patchMesh_t *p = pb->pPatch;
3029 for ( w = 0; w < p->width; w++ ) {
3030 // for each row, we need to evenly disperse p->height number
3031 // of points across the old bounds
3033 // calc total distance to interpolate
3034 VectorSubtract(p->ctrl(w, p->height - 1).xyz, p->ctrl(w, 0).xyz, vTemp);
3036 //vTemp[0] = vTemp[1] = vTemp[2] = 0;
3037 //for (h = 0; h < p->height - nRows; h ++)
3039 // VectorAdd(vTemp, p->ctrl(w,h], vTemp);
3043 for ( i = 0; i < 3; i ++ ) {
3044 vTemp2[i] = vTemp[i] / (p->height - 1);
3048 for ( h = 0; h < p->height - 1; h++ ) {
3049 VectorAdd(p->ctrl(w, h).xyz, vTemp2, p->ctrl(w, h + 1).xyz);
3051 Patch_Naturalize(p);
3055 UpdatePatchInspector();
3063 void Patch_DisperseColumns() {
3064 idVec3 vTemp, vTemp2;
3067 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3069 patchMesh_t *p = pb->pPatch;
3072 for ( h = 0; h < p->height; h++ ) {
3073 // for each column, we need to evenly disperse p->width number
3074 // of points across the old bounds
3076 // calc total distance to interpolate
3077 VectorSubtract(p->ctrl(p->width - 1, h).xyz, p->ctrl(0, h).xyz, vTemp);
3080 for ( i = 0; i < 3; i ++ ) {
3081 vTemp2[i] = vTemp[i] / (p->width - 1);
3085 for ( w = 0; w < p->width - 1; w++ ) {
3086 VectorAdd(p->ctrl(w, h).xyz, vTemp2, p->ctrl(w + 1, h).xyz);
3089 Patch_Naturalize(p);
3092 UpdatePatchInspector();
3099 Patch_AdjustSelected
3102 void Patch_AdjustSelected( bool bInsert,bool bColumn,bool bFlag ) {
3103 bool bUpdate = false;
3104 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3108 Patch_InsertColumn(pb->pPatch, bFlag);
3110 Patch_InsertRow(pb->pPatch, bFlag);
3114 Patch_RemoveColumn(pb->pPatch, bFlag);
3116 Patch_RemoveRow(pb->pPatch, bFlag);
3121 patchMesh_t *p = pb->pPatch;
3122 Patch_CalcBounds(p, vMin, vMax);
3123 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
3127 Sys_UpdateWindows(W_ALL);
3131 void Parse1DMatrix( int x,float *p ) {
3132 GetToken(true); // (
3133 for ( int i = 0; i < x; i++ ) {
3137 GetToken(true); // )
3140 void Parse2DMatrix( int y,int x,float *p ) {
3141 GetToken(true); // (
3142 for ( int i = 0; i < y; i++ ) {
3143 Parse1DMatrix(x, p + i * x);
3145 GetToken(true); // )
3148 void Parse3DMatrix( int z,int y,int x,float *p ) {
3149 GetToken(true); // (
3150 for ( int i = 0; i < z; i++ ) {
3151 Parse2DMatrix(y, x, p + i * (x * MAX_PATCH_HEIGHT));
3153 GetToken(true); // )
3157 brush_t * Patch_Parse( bool bOld ) {
3158 const idMaterial *tex = declManager->FindMaterial(NULL);
3161 if ( strcmp(token, "{") ) {
3165 patchMesh_t *pm = NULL;
3167 if ( g_qeglobals.bSurfacePropertiesPlugin ) {
3169 //GETPLUGINTEXDEF(pm)->ParsePatchTexdef();
3175 if ( strcmp(token, "(") ) {
3176 if ( g_qeglobals.mapVersion < 2.0f ) {
3177 tex = Texture_ForName(va("textures/%s", token));
3179 tex = Texture_ForName(token);
3183 common->Printf("Warning: Patch read with no texture, using notexture... \n");
3186 if ( strcmp(token, "(") ) {
3190 // width, height, flags (currently only negative)
3192 int width = atoi(token);
3195 int height = atoi(token);
3197 pm = MakeNewPatch(width, height);
3198 pm->d_texture = tex;
3202 pm->horzSubdivisions = atoi(token);
3204 pm->vertSubdivisions = atoi(token);
3205 pm->explicitSubdivisions = true;
3209 pm->contents = atoi(token);
3212 pm->flags = atoi(token);
3215 pm->value = atoi(token);
3220 // pm->type = atoi(token);
3224 if ( strcmp(token, ")") )
3230 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
3231 Parse3DMatrix(pm->width, pm->height, 5, reinterpret_cast< float*>(&ctrl));
3235 for ( w = 0; w < pm->width; w++ ) {
3236 for ( h = 0; h < pm->height; h++ ) {
3237 pm->ctrl(w, h).xyz[0] = ctrl[w][h][0];
3238 pm->ctrl(w, h).xyz[1] = ctrl[w][h][1];
3239 pm->ctrl(w, h).xyz[2] = ctrl[w][h][2];
3240 pm->ctrl(w, h).st[0] = ctrl[w][h][3];
3241 pm->ctrl(w, h).st[1] = ctrl[w][h][4];
3247 if ( g_qeglobals.m_bBrushPrimitMode ) {
3248 // we are in brush primit mode, but maybe it's a classic patch that needs converting, test "}"
3249 if ( strcmp(token, "}") && strcmp(token, "(") ) {
3250 ParseEpair(pm->epairs);
3255 if ( strcmp(token, "}") ) {
3259 brush_t *b = AddBrushForPatch(pm, false);
3270 void Patch_Write( patchMesh_t *p,CMemFile *file ) {
3271 if ( g_qeglobals.bSurfacePropertiesPlugin ) {
3272 common->Printf("WARNING: Patch_Write to a CMemFile and Surface Properties plugin not done\n");
3275 if ( p->explicitSubdivisions ) {
3276 MemFile_fprintf(file, " {\n patchDef3\n {\n");
3277 MemFile_fprintf(file, " \"%s\"\n", p->d_texture->GetName());
3278 MemFile_fprintf(file, " ( %i %i %i %i %i %i %i ) \n", p->width, p->height, p->horzSubdivisions, p->vertSubdivisions, p->contents, p->flags, p->value);
3280 MemFile_fprintf(file, " {\n patchDef2\n {\n");
3281 MemFile_fprintf(file, " \"%s\"\n", p->d_texture->GetName());
3282 MemFile_fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
3286 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
3289 for ( w = 0; w < p->width; w++ ) {
3290 for ( h = 0; h < p->height; h++ ) {
3291 ctrl[w][h][0] = p->ctrl(w, h).xyz[0];
3292 ctrl[w][h][1] = p->ctrl(w, h).xyz[1];
3293 ctrl[w][h][2] = p->ctrl(w, h).xyz[2];
3294 ctrl[w][h][3] = p->ctrl(w, h).st[0];
3295 ctrl[w][h][4] = p->ctrl(w, h).st[1];
3299 _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast< float*>(&ctrl));
3301 if ( g_qeglobals.m_bBrushPrimitMode ) {
3303 int count = p->epairs->GetNumKeyVals();
3304 for ( int i = 0; i < count; i++ ) {
3305 MemFile_fprintf(file, "\"%s\" \"%s\"\n", p->epairs->GetKeyVal(i)->GetKey().c_str(), p->epairs->GetKeyVal(i)->GetValue().c_str());
3310 MemFile_fprintf(file, " }\n }\n");
3313 void Patch_Write( patchMesh_t *p,FILE *file ) {
3314 if ( p->explicitSubdivisions ) {
3315 fprintf(file, " {\n patchDef3\n {\n");
3316 fprintf(file, " \"%s\"\n", p->d_texture->GetName());
3317 fprintf(file, " ( %i %i %i %i %i %i %i ) \n", p->width, p->height, p->horzSubdivisions, p->vertSubdivisions, p->contents, p->flags, p->value);
3319 fprintf(file, " {\n patchDef2\n {\n");
3320 fprintf(file, " \"%s\"\n", p->d_texture->GetName());
3321 fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
3324 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
3327 for ( w = 0; w < p->width; w++ ) {
3328 for ( h = 0; h < p->height; h++ ) {
3329 ctrl[w][h][0] = p->ctrl(w, h).xyz[0];
3330 ctrl[w][h][1] = p->ctrl(w, h).xyz[1];
3331 ctrl[w][h][2] = p->ctrl(w, h).xyz[2];
3332 ctrl[w][h][3] = p->ctrl(w, h).st[0];
3333 ctrl[w][h][4] = p->ctrl(w, h).st[1];
3337 _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast< float*>(&ctrl));
3339 if ( g_qeglobals.m_bBrushPrimitMode ) {
3341 int count = p->epairs->GetNumKeyVals();
3342 for ( int i = 0; i < count; i++ ) {
3343 fprintf(file, "\"%s\" \"%s\"\n", p->epairs->GetKeyVal(i)->GetKey().c_str(), p->epairs->GetKeyVal(i)->GetValue().c_str());
3348 fprintf(file, " }\n }\n");
3357 void Patch_RotateTexture( patchMesh_t *p,float fAngle ) {
3359 Patch_CalcBounds(p, vMin, vMax);
3361 for ( int w = 0; w < p->width; w++ ) {
3362 for ( int h = 0; h < p->height; h++ ) {
3363 if ( g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(&p->ctrl(w, h).xyz) == -1 ) {
3367 float x = p->ctrl(w, h).st[0];
3368 float y = p->ctrl(w, h).st[1];
3369 p->ctrl(w, h).st[0] = x * cos(DEG2RAD(fAngle)) - y * sin(DEG2RAD(fAngle));
3370 p->ctrl(w, h).st[1] = y * cos(DEG2RAD(fAngle)) + x * sin(DEG2RAD(fAngle));
3381 void Patch_ScaleTexture( patchMesh_t *p,float fx,float fy,bool absolute ) {
3390 Patch_ResetTexturing(1, 1);
3393 for ( int w = 0; w < p->width; w++ ) {
3394 for ( int h = 0; h < p->height; h++ ) {
3395 if ( g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(&p->ctrl(w, h).xyz) == -1 ) {
3398 p->ctrl(w, h).st[0] *= fx;
3399 p->ctrl(w, h).st[1] *= fy;
3410 void Patch_ShiftTexture( patchMesh_t *p,float fx,float fy,bool autoAdjust ) {
3412 // fx = (fx > 0) ? 0.1 : -0.1;
3414 // fy = (fy > 0) ? 0.1 : -0.1;
3417 fx /= p->d_texture->GetEditorImage()->uploadWidth;
3418 fy /= p->d_texture->GetEditorImage()->uploadHeight;
3421 for ( int w = 0; w < p->width; w++ ) {
3422 for ( int h = 0; h < p->height; h++ ) {
3423 if ( g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(&p->ctrl(w, h).xyz) == -1 )
3426 p->ctrl(w, h).st[0] += fx;
3427 p->ctrl(w, h).st[1] += fy;
3433 void patchInvert( patchMesh_t *p ) {
3434 idDrawVert vertTemp;
3436 for ( int i = 0 ; i < p->width ; i++ ) {
3437 for ( int j = 0; j < p->height / 2; j++ ) {
3438 memcpy(&vertTemp, &p->ctrl(i, p->height - 1 - j), sizeof(idDrawVert));
3439 memcpy(&p->ctrl(i, p->height - 1 - j), &p->ctrl(i, j), sizeof(idDrawVert));
3440 memcpy(&p->ctrl(i, j), &vertTemp, sizeof(idDrawVert));
3447 Patch_ToggleInverted
3450 void Patch_ToggleInverted() {
3451 bool bUpdate = false;
3453 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3456 patchInvert(pb->pPatch);
3461 Sys_UpdateWindows(W_ALL);
3463 UpdatePatchInspector();
3466 void Patch_FlipTexture( patchMesh_t *p,bool y ) {
3470 for ( int i = 0 ; i < p->height ; i++ ) {
3471 for ( int j = 0; j < p->width / 2; j++ ) {
3472 temp = p->ctrl(p->width - 1 - j, i).st;
3473 p->ctrl(p->width - 1 - j, i).st = p->ctrl(j, i).st;
3474 p->ctrl(j, i).st = temp;
3478 for ( int i = 0 ; i < p->width ; i++ ) {
3479 for ( int j = 0; j < p->height / 2; j++ ) {
3480 temp = p->ctrl(i, p->height - 1 - j).st;
3481 p->ctrl(i, p->height - 1 - j).st = p->ctrl(i, j).st;
3482 p->ctrl(i, j).st = temp;
3491 Patch_ToggleInverted
3494 void Patch_InvertTexture( bool bY ) {
3495 bool bUpdate = false;
3496 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3499 Patch_FlipTexture(pb->pPatch, bY);
3504 Sys_UpdateWindows(W_ALL);
3507 UpdatePatchInspector();
3517 Saves patch ctrl info (originally to deal with a
3518 cancel in the surface dialog
3520 void Patch_Save( patchMesh_t *p ) {
3522 Mem_Free(patchSave->verts);
3523 Mem_Free(patchSave);
3526 patchSave = MakeNewPatch(p->width, p->height);
3527 memcpy(patchSave->verts, p->verts, sizeof(p->verts[0]) * p->width * p->height);
3536 void Patch_Restore( patchMesh_t *p ) {
3538 p->width = patchSave->width;
3539 p->height = patchSave->height;
3540 memcpy(p->verts, patchSave->verts, sizeof(p->verts[0]) * p->width * p->height);
3541 Mem_Free(patchSave->verts);
3542 Mem_Free(patchSave);
3547 void Patch_FitTexture( patchMesh_t *p,float fx,float fy ) {
3549 for ( int i = 0 ; i < p->width ; i++ ) {
3550 for ( int j = 0 ; j < p->height ; j++ ) {
3551 p->ctrl(i, j).st[0] = fx * (float) i / (p->width - 1);
3552 p->ctrl(i, j).st[1] = fy * (float) j / (p->height - 1);
3557 void Patch_ResetTexturing( float fx,float fy ) {
3558 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3560 patchMesh_t *p = pb->pPatch;
3562 for ( int i = 0 ; i < p->width ; i++ ) {
3563 for ( int j = 0 ; j < p->height ; j++ ) {
3564 p->ctrl(i, j).st[0] = fx * (float) i / (p->width - 1);
3565 p->ctrl(i, j).st[1] = fy * (float) j / (p->height - 1);
3573 void Patch_FitTexturing() {
3574 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3576 patchMesh_t *p = pb->pPatch;
3578 for ( int i = 0 ; i < p->width ; i++ ) {
3579 for ( int j = 0 ; j < p->height ; j++ ) {
3580 p->ctrl(i, j).st[0] = 1 * (float) i / (p->width - 1);
3581 p->ctrl(i, j).st[1] = 1 * (float) j / (p->height - 1);
3588 void Patch_SetTextureInfo( texdef_t *pt ) {
3589 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3592 Patch_RotateTexture(pb->pPatch, pt->rotate);
3594 if ( pt->shift[0] || pt->shift[1] )
3595 Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1], false);
3597 if ( pt->scale[0] || pt->scale[1] )
3598 Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false);
3600 patchMesh_t *p = pb->pPatch;
3601 p->value = pt->value;
3606 bool WINAPI OnlyPatchesSelected() {
3607 if ( g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes ) {
3610 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3611 if ( !pb->pPatch ) {
3618 bool WINAPI AnyPatchesSelected() {
3619 if ( g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes ) {
3622 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3630 patchMesh_t * SinglePatchSelected() {
3631 if ( selected_brushes.next->pPatch ) {
3632 return selected_brushes.next->pPatch;
3637 void Patch_BendToggle() {
3638 if ( g_bPatchBendMode ) {
3639 g_bPatchBendMode = false;
3641 g_pParentWnd->UpdatePatchToolbarButtons() ;
3645 brush_t *b = selected_brushes.next;
3647 if ( !QE_SingleBrush() || !b->pPatch ) {
3648 Sys_Status("Must bend a single patch");
3652 Patch_Save(b->pPatch);
3653 g_bPatchBendMode = true;
3654 g_nPatchBendState = BEND_SELECT_ROTATION;
3655 g_bPatchAxisOnRow = true;
3656 g_nPatchAxisIndex = 1;
3657 ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]);
3660 void Patch_BendHandleTAB() {
3661 if ( !g_bPatchBendMode ) {
3665 brush_t *b = selected_brushes.next;
3666 if ( !QE_SingleBrush() || !b->pPatch ) {
3668 Sys_Status("No patch to bend!");
3672 patchMesh_t *p = b->pPatch;
3674 bool bShift = ((GetAsyncKeyState(VK_SHIFT) & 0x8000) != 0);
3676 if ( g_nPatchBendState == BEND_SELECT_ROTATION ) {
3677 // only able to deal with odd numbered rows/cols
3678 g_nPatchAxisIndex += (bShift) ? -2 : 2;
3679 if ( g_bPatchAxisOnRow ) {
3680 if ( (bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height ) {
3681 g_bPatchAxisOnRow = false;
3682 g_nPatchAxisIndex = (bShift) ? p->width - 1 : 1;
3685 if ( (bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width ) {
3686 g_bPatchAxisOnRow = true;
3687 g_nPatchAxisIndex = (bShift) ? p->height - 1 : 1;
3690 } else if ( g_nPatchBendState == BEND_SELECT_ORIGIN ) {
3691 g_nBendOriginIndex += (bShift) ? -1 : 1;
3692 if ( g_bPatchAxisOnRow ) {
3694 if ( g_nBendOriginIndex < 0 )
3695 g_nBendOriginIndex = p->width - 1;
3697 if ( g_nBendOriginIndex > p->width - 1 )
3698 g_nBendOriginIndex = 0;
3700 VectorCopy(p->ctrl(g_nBendOriginIndex, g_nPatchAxisIndex).xyz, g_vBendOrigin);
3703 if ( g_nBendOriginIndex < 0 )
3704 g_nBendOriginIndex = p->height - 1;
3706 if ( g_nBendOriginIndex > p->height - 1 )
3707 g_nBendOriginIndex = 0;
3709 VectorCopy(p->ctrl(g_nPatchAxisIndex, g_nBendOriginIndex).xyz, g_vBendOrigin);
3711 } else if ( g_nPatchBendState == BEND_SELECT_EDGE ) {
3712 g_bPatchLowerEdge ^= 1;
3714 Sys_UpdateWindows(W_ALL);
3717 void Patch_BendHandleENTER() {
3718 if ( !g_bPatchBendMode ) {
3722 if ( g_nPatchBendState < BEND_BENDIT ) {
3723 g_nPatchBendState++;
3724 ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]);
3725 if ( g_nPatchBendState == BEND_SELECT_ORIGIN ) {
3726 g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0;
3727 g_nBendOriginIndex = 0;
3728 Patch_BendHandleTAB();
3729 } else if ( g_nPatchBendState == BEND_SELECT_EDGE ) {
3730 g_bPatchLowerEdge = true;
3731 } else if ( g_nPatchBendState == BEND_BENDIT ) {
3732 // basically we go into rotation mode, set the axis to the center of the
3738 Sys_UpdateWindows(W_ALL);
3742 void Patch_BendHandleESC() {
3743 if ( !g_bPatchBendMode ) {
3747 brush_t *b = selected_brushes.next;
3748 if ( QE_SingleBrush() && b->pPatch ) {
3749 Patch_Restore(b->pPatch);
3751 Sys_UpdateWindows(W_ALL);
3754 void Patch_SetBendRotateOrigin( patchMesh_t *p ) {
3755 int nType = g_pParentWnd->ActiveXY()->GetViewType();
3756 int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1;
3757 g_vBendOrigin[nDim3] = 0;
3758 VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin());
3762 // also sets the rotational origin
3763 void Patch_SelectBendAxis() {
3764 brush_t *b = selected_brushes.next;
3765 if ( !QE_SingleBrush() || !b->pPatch ) {
3766 // should not ever happen
3771 patchMesh_t *p = b->pPatch;
3772 if ( g_bPatchAxisOnRow ) {
3773 SelectRow(p, g_nPatchAxisIndex, false);
3775 SelectColumn(p, g_nPatchAxisIndex, false);
3778 Patch_SetBendRotateOrigin(p);
3781 void Patch_SelectBendNormal() {
3782 brush_t *b = selected_brushes.next;
3783 if ( !QE_SingleBrush() || !b->pPatch ) {
3784 // should not ever happen
3789 patchMesh_t *p = b->pPatch;
3791 g_qeglobals.d_num_move_points = 0;
3792 if ( g_bPatchAxisOnRow ) {
3793 if ( g_bPatchLowerEdge ) {
3794 for ( int j = 0; j < g_nPatchAxisIndex; j++ )
3795 SelectRow(p, j, true);
3797 for ( int j = p->height - 1; j > g_nPatchAxisIndex; j-- )
3798 SelectRow(p, j, true);
3801 if ( g_bPatchLowerEdge ) {
3802 for ( int j = 0; j < g_nPatchAxisIndex; j++ )
3803 SelectColumn(p, j, true);
3805 for ( int j = p->width - 1; j > g_nPatchAxisIndex; j-- )
3806 SelectColumn(p, j, true);
3809 Patch_SetBendRotateOrigin(p);
3814 void Patch_InsDelToggle() {
3815 if ( g_bPatchInsertMode ) {
3816 g_bPatchInsertMode = false;
3818 g_pParentWnd->UpdatePatchToolbarButtons() ;
3822 brush_t *b = selected_brushes.next;
3824 if ( !QE_SingleBrush() || !b->pPatch ) {
3825 Sys_Status("Must work with a single patch");
3829 Patch_Save(b->pPatch);
3830 g_bPatchInsertMode = true;
3831 g_nPatchInsertState = INSERT_SELECT_EDGE;
3832 g_bPatchAxisOnRow = true;
3833 g_nPatchAxisIndex = 0;
3834 ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]);
3837 void Patch_InsDelESC() {
3838 if ( !g_bPatchInsertMode ) {
3841 Patch_InsDelToggle();
3842 Sys_UpdateWindows(W_ALL);
3846 void Patch_InsDelHandleENTER() {
3849 void Patch_InsDelHandleTAB() {
3850 if ( !g_bPatchInsertMode ) {
3851 Patch_InsDelToggle();
3855 brush_t *b = selected_brushes.next;
3856 if ( !QE_SingleBrush() || !b->pPatch ) {
3858 common->Printf("No patch to bend!");
3862 patchMesh_t *p = b->pPatch;
3864 // only able to deal with odd numbered rows/cols
3865 g_nPatchAxisIndex += 2;
3866 if ( g_bPatchAxisOnRow ) {
3867 if ( g_nPatchAxisIndex >= p->height - 1 ) {
3868 g_bPatchAxisOnRow = false;
3869 g_nPatchAxisIndex = 0;
3872 if ( g_nPatchAxisIndex >= p->width - 1 ) {
3873 g_bPatchAxisOnRow = true;
3874 g_nPatchAxisIndex = 0;
3877 Sys_UpdateWindows(W_ALL);
3881 void _Write1DMatrix( FILE *f,int x,float *m ) {
3885 for ( i = 0 ; i < x ; i++ ) {
3886 if ( m[i] == (int) m[i] ) {
3887 fprintf(f, "%i ", (int) m[i]);
3889 fprintf(f, "%f ", m[i]);
3895 void _Write2DMatrix( FILE *f,int y,int x,float *m ) {
3899 for ( i = 0 ; i < y ; i++ ) {
3900 _Write1DMatrix(f, x, m + i * x);
3907 void _Write3DMatrix( FILE *f,int z,int y,int x,float *m ) {
3911 for ( i = 0 ; i < z ; i++ ) {
3912 _Write2DMatrix(f, y, x, m + i * (x * MAX_PATCH_HEIGHT));
3917 void _Write1DMatrix( CMemFile *f,int x,float *m ) {
3920 MemFile_fprintf(f, "( ");
3921 for ( i = 0 ; i < x ; i++ ) {
3922 if ( m[i] == (int) m[i] ) {
3923 MemFile_fprintf(f, "%i ", (int) m[i]);
3925 MemFile_fprintf(f, "%f ", m[i]);
3928 MemFile_fprintf(f, ")");
3931 void _Write2DMatrix( CMemFile *f,int y,int x,float *m ) {
3934 MemFile_fprintf(f, "( ");
3935 for ( i = 0 ; i < y ; i++ ) {
3936 _Write1DMatrix(f, x, m + i * x);
3937 MemFile_fprintf(f, " ");
3939 MemFile_fprintf(f, ")\n");
3943 void _Write3DMatrix( CMemFile *f,int z,int y,int x,float *m ) {
3946 MemFile_fprintf(f, "(\n");
3947 for ( i = 0 ; i < z ; i++ ) {
3948 _Write2DMatrix(f, y, x, m + i * (x * MAX_PATCH_HEIGHT));
3950 MemFile_fprintf(f, ")\n");
3954 void Patch_NaturalizeSelected( bool bCap,bool bCycleCap,bool alt ) {
3955 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3958 Patch_CapTexture(pb->pPatch, bCycleCap, alt);
3960 Patch_Naturalize(pb->pPatch, true, true, alt);
3966 void Patch_SubdivideSelected( bool subdivide,int horz,int vert ) {
3967 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
3969 pb->pPatch->explicitSubdivisions = subdivide;
3976 pb->pPatch->horzSubdivisions = horz;
3977 pb->pPatch->vertSubdivisions = vert;
3978 Patch_MakeDirty(pb->pPatch);
3985 bool within( idVec3 vTest,idVec3 vTL,idVec3 vBR ) {
3986 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
3987 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
3988 if ( (vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) || (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1]) ) {
3989 if ( (vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) || (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2]) ) {
3997 void Patch_SelectAreaPoints() {
3998 //jhefty - make patch selection additive ALWAYS
3999 //g_qeglobals.d_num_move_points = 0;
4000 g_nPatchClickedView = -1;
4002 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4004 patchMesh_t *p = pb->pPatch;
4005 for ( int i = 0; i < p->width; i++ ) {
4006 for ( int j = 0; j < p->height; j++ ) {
4007 if ( within(p->ctrl(i, j).xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR) ) {
4008 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = &p->ctrl(i, j).xyz;
4016 const char * Patch_GetTextureName() {
4017 brush_t *b = selected_brushes.next;
4019 patchMesh_t *p = b->pPatch;
4020 if ( p->d_texture->GetName() )
4021 return p->d_texture->GetName();
4026 patchMesh_t * Patch_Duplicate( patchMesh_t *pFrom ) {
4027 patchMesh_t *p = MakeNewPatch(pFrom->width, pFrom->height);
4028 p->contents = pFrom->contents;
4029 p->value = pFrom->value;
4030 p->horzSubdivisions = pFrom->horzSubdivisions;
4031 p->vertSubdivisions = pFrom->vertSubdivisions;
4032 p->explicitSubdivisions = pFrom->explicitSubdivisions;
4033 p->d_texture = pFrom->d_texture;
4034 p->bSelected = false;
4035 p->bOverlay = false;
4038 memcpy(p->verts, pFrom->verts, p->width * p->height * sizeof(idDrawVert));
4040 AddBrushForPatch(p);
4045 void Patch_Thicken( int nAmount,bool bSeam ) {
4055 if ( !QE_SingleBrush() ) {
4056 Sys_Status("Cannot thicken multiple patches. Please select a single patch.\n");
4060 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4061 if ( !pb->pPatch ) {
4065 patchMesh_t *p = pb->pPatch;
4066 Patch_MeshNormals(p);
4067 patchMesh_t *pNew = Patch_Duplicate(p);
4068 for ( i = 0; i < p->width; i++ ) {
4069 for ( j = 0; j < p->height; j++ ) {
4070 VectorMA(p->ctrl(i, j).xyz, nAmount, p->ctrl(i, j).normal, pNew->ctrl(i, j).xyz);
4074 Patch_Rebuild(pNew);
4075 pNew->type |= PATCH_THICK;
4076 brushes.Add(pNew->pSymbiot);
4079 // FIXME: this should detect if any edges of the patch are closed and act appropriately
4081 if ( !(p->type & PATCH_CYLINDER) ) {
4082 b = Patch_GenericMesh(3, p->height, 2, false, true, p);
4084 pSeam->type |= PATCH_SEAM;
4085 for ( i = 0; i < p->height; i++ ) {
4086 VectorCopy(p->ctrl(0, i).xyz, pSeam->ctrl(0, i).xyz);
4087 VectorCopy(pNew->ctrl(0, i).xyz, pSeam->ctrl(2, i).xyz);
4088 VectorAdd(pSeam->ctrl(0, i).xyz, pSeam->ctrl(2, i).xyz, pSeam->ctrl(1, i).xyz);
4089 VectorScale(pSeam->ctrl(1, i).xyz, 0.5, pSeam->ctrl(1, i).xyz);
4093 Patch_CalcBounds(pSeam, vMin, vMax);
4094 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
4095 //--Patch_CapTexture(pSeam);
4096 Patch_Naturalize(pSeam);
4101 b = Patch_GenericMesh(3, p->height, 2, false, true, p);
4103 pSeam->type |= PATCH_SEAM;
4104 for ( i = 0; i < p->height; i++ ) {
4105 VectorCopy(p->ctrl(w, i).xyz, pSeam->ctrl(0, i).xyz);
4106 VectorCopy(pNew->ctrl(w, i).xyz, pSeam->ctrl(2, i).xyz);
4107 VectorAdd(pSeam->ctrl(0, i).xyz, pSeam->ctrl(2, i).xyz, pSeam->ctrl(1, i).xyz);
4108 VectorScale(pSeam->ctrl(1, i).xyz, 0.5, pSeam->ctrl(1, i).xyz);
4110 Patch_CalcBounds(pSeam, vMin, vMax);
4111 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
4112 //--Patch_CapTexture(pSeam);
4113 Patch_Naturalize(pSeam);
4118 // otherwise we will add one per end
4119 b = Patch_GenericMesh(p->width, 3, 2, false, true, p);
4121 pSeam->type |= PATCH_SEAM;
4122 for ( i = 0; i < p->width; i++ ) {
4123 VectorCopy(p->ctrl(i, 0).xyz, pSeam->ctrl(i, 0).xyz);
4124 VectorCopy(pNew->ctrl(i, 0).xyz, pSeam->ctrl(i, 2).xyz);
4125 VectorAdd(pSeam->ctrl(i, 0).xyz, pSeam->ctrl(i, 2).xyz, pSeam->ctrl(i, 1).xyz);
4126 VectorScale(pSeam->ctrl(i, 1).xyz, 0.5, pSeam->ctrl(i, 1).xyz);
4130 Patch_CalcBounds(pSeam, vMin, vMax);
4131 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
4132 //--Patch_CapTexture(pSeam);
4133 Patch_Naturalize(pSeam);
4138 b = Patch_GenericMesh(p->width, 3, 2, false, true, p);
4140 pSeam->type |= PATCH_SEAM;
4141 for ( i = 0; i < p->width; i++ ) {
4142 VectorCopy(p->ctrl(i, h).xyz, pSeam->ctrl(i, 0).xyz);
4143 VectorCopy(pNew->ctrl(i, h).xyz, pSeam->ctrl(i, 2).xyz);
4144 VectorAdd(pSeam->ctrl(i, 0).xyz, pSeam->ctrl(i, 2).xyz, pSeam->ctrl(i, 1).xyz);
4145 VectorScale(pSeam->ctrl(i, 1).xyz, 0.5, pSeam->ctrl(i, 1).xyz);
4147 Patch_CalcBounds(pSeam, vMin, vMax);
4148 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
4149 //--Patch_CapTexture(pSeam);
4150 Patch_Naturalize(pSeam);
4157 for ( i = 0; i < brushes.GetSize(); i++ ) {
4158 Select_Brush(reinterpret_cast< brush_t*>(brushes.GetAt(i)));
4161 if ( brushes.GetSize() > 0 ) {
4162 eclass_t*pecNew = Eclass_ForName("func_static", false);
4164 entity_t*e = Entity_Create(pecNew);
4165 SetKeyValue(e, "type", "patchThick");
4169 UpdatePatchInspector();
4174 lets get another list together as far as necessities..
4176 *snapping stuff to the grid (i will only snap movements by the mouse to the grid.. snapping the rotational bend stuff will fubar everything)
4178 capping bevels/endcaps
4182 texture fix for caps
4192 void Patch_SetOverlays() {
4193 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4195 pb->pPatch->bOverlay = true;
4202 void Patch_ClearOverlays() {
4204 for ( pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4206 pb->pPatch->bOverlay = false;
4210 for ( pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next ) {
4212 pb->pPatch->bOverlay = false;
4217 // freezes selected vertices
4218 void Patch_Freeze() {
4220 for ( pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4222 pb->pPatch->bOverlay = false;
4226 for ( pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next ) {
4228 pb->pPatch->bOverlay = false;
4233 void Patch_UnFreeze( bool bAll ) {
4237 void Patch_Transpose() {
4240 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4242 patchMesh_t *p = pb->pPatch;
4244 if ( p->width > p->height ) {
4245 for ( i = 0 ; i < p->height ; i++ ) {
4246 for ( j = i + 1 ; j < p->width ; j++ ) {
4247 if ( j < p->height ) {
4249 memcpy(&dv, &p->ctrl(j, i), sizeof(idDrawVert));
4250 memcpy(&p->ctrl(j, i), &p->ctrl(i, j), sizeof(idDrawVert));
4251 memcpy(&p->ctrl(i, j), &dv, sizeof(idDrawVert));
4254 memcpy(&p->ctrl(j, i), &p->ctrl(i, j), sizeof(idDrawVert));
4259 for ( i = 0 ; i < p->width ; i++ ) {
4260 for ( j = i + 1 ; j < p->height ; j++ ) {
4261 if ( j < p->width ) {
4263 memcpy(&dv, &p->ctrl(i, j), sizeof(idDrawVert));
4264 memcpy(&p->ctrl(i, j), &p->ctrl(j, i), sizeof(idDrawVert));
4265 memcpy(&p->ctrl(j, i), &dv, sizeof(idDrawVert));
4268 memcpy(&p->ctrl(i, j), &p->ctrl(j, i), sizeof(idDrawVert));
4275 p->width = p->height;
4285 void Select_SnapToGrid() {
4287 for ( brush_t*pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next ) {
4289 patchMesh_t *p = pb->pPatch;
4290 for ( i = 0; i < p->width; i++ ) {
4291 for ( j = 0; j < p->height; j++ ) {
4292 for ( k = 0; k < 3; k++ ) {
4293 p->ctrl(i, j).xyz[k] = floor(p->ctrl(i, j).xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
4298 Patch_CalcBounds(p, vMin, vMax);
4299 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
4301 Brush_SnapToGrid(pb);
4307 void Patch_FindReplaceTexture( brush_t *pb,const char *pFind,const char *pReplace,bool bForce ) {
4309 patchMesh_t *p = pb->pPatch;
4310 if ( bForce || idStr::Icmp(p->d_texture->GetName(), pFind) == 0 ) {
4311 p->d_texture = Texture_ForName(pReplace);
4312 //strcpy(p->d_texture->name, pReplace);
4317 void Patch_ReplaceQTexture( brush_t *pb,idMaterial *pOld,idMaterial *pNew ) {
4319 patchMesh_t *p = pb->pPatch;
4320 if ( p->d_texture == pOld ) {
4321 p->d_texture = pNew;
4326 void Patch_Clone( patchMesh_t *p,brush_t *pNewOwner ) {
4329 void Patch_FromTriangle( idVec5 vx,idVec5 vy,idVec5 vz ) {
4330 patchMesh_t *p = MakeNewPatch(3, 3);
4331 p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
4332 p->type = PATCH_TRIANGLE;
4338 // 1 0 goes to mid of x and z
4339 // 1 1 goes to mid of x y and z
4340 // 1 2 goes to mid of x and y
4343 // 2 1 goes to mid of y and z
4351 vMidXZ.Lerp(vx, vz, 0.5);
4352 vMidXY.Lerp(vx, vy, 0.5);
4353 vMidYZ.Lerp(vy, vz, 0.5);
4355 p->ctrl(0, 0).xyz = vx.ToVec3();
4356 p->ctrl(0, 1).xyz = vx.ToVec3();
4357 p->ctrl(0, 2).xyz = vx.ToVec3();
4358 p->ctrl(0, 0).st[0] = vx[3];
4359 p->ctrl(0, 0).st[1] = vx[4];
4360 p->ctrl(0, 1).st[0] = vx[3];
4361 p->ctrl(0, 1).st[1] = vx[4];
4362 p->ctrl(0, 2).st[0] = vx[3];
4363 p->ctrl(0, 2).st[1] = vx[4];
4365 p->ctrl(1, 0).xyz = vMidXY.ToVec3();
4366 p->ctrl(1, 1).xyz = vx.ToVec3();
4367 p->ctrl(1, 2).xyz = vMidXZ.ToVec3();
4368 p->ctrl(1, 0).st[0] = vMidXY[3];
4369 p->ctrl(1, 0).st[1] = vMidXY[4];
4370 p->ctrl(1, 1).st[0] = vx[3];
4371 p->ctrl(1, 1).st[1] = vx[4];
4372 p->ctrl(1, 2).st[0] = vMidXZ[3];
4373 p->ctrl(1, 2).st[1] = vMidXZ[4];
4375 p->ctrl(2, 0).xyz = vy.ToVec3();
4376 p->ctrl(2, 1).xyz = vMidYZ.ToVec3();
4377 p->ctrl(2, 2).xyz = vz.ToVec3();
4378 p->ctrl(2, 0).st[0] = vy[3];
4379 p->ctrl(2, 0).st[1] = vy[4];
4380 p->ctrl(2, 1).st[0] = vMidYZ[3];
4381 p->ctrl(2, 1).st[1] = vMidYZ[4];
4382 p->ctrl(2, 2).st[0] = vz[3];
4383 p->ctrl(2, 2).st[1] = vz[4];
4386 //Patch_Naturalize(p);
4388 brush_t *b = AddBrushForPatch(p);
4395 sets an epair for the given patch
4398 void Patch_SetEpair( patchMesh_t *p,const char *pKey,const char *pValue ) {
4399 if ( g_qeglobals.m_bBrushPrimitMode ) {
4400 if ( p->epairs == NULL ) {
4401 p->epairs = new idDict;
4403 p->epairs->Set(pKey, pValue);
4412 const char * Patch_GetKeyValue( patchMesh_t *p,const char *pKey ) {
4413 if ( g_qeglobals.m_bBrushPrimitMode ) {
4415 return p->epairs->GetString(pKey);
4422 //Real nitpicky, but could you make CTRL-S save the current map with the current name? (ie: File/Save)
4425 When reading in textures, please check for the presence of a file called "textures.link" or something, which contains one line such as;
4427 g:\quake3\baseq3\textures\common
4429 So that, when I'm reading in, lets say, my \eerie directory, it goes through and adds my textures to the palette, along with everything in common.
4431 Don't forget to add "Finer texture alignment" to the list. I'd like to be able to move in 0.1 increments using the Shift-Arrow Keys.
4433 No. Sometimes textures are drawn the wrong way on patches. We'd like the ability to flip a texture. Like the way X/Y scale -1 used to worked.
4435 1) Easier way of deleting rows, columns
4436 2) Fine tuning of textures on patches (X/Y shifts other than with the surface dialog)
4437 2) Patch matrix transposition
4439 1) Actually, bump texture flipping on patches to the top of the list of things to do.
4440 2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S
4441 3) Brandon has a wierd anomoly. He fine-tunes a patch with caps. It looks fine when the patch is selected, but as soon as he escapes out, it reverts to it's pre-tuned state. When he selects the patch again, it looks tuned
4444 *1) Flipping textures on patches
4445 *2) When you select a patch, and hit S, it should read in the selected patch texture. Should not work if you multiselect patches and hit S
4446 3) Easier way of deleting rows columns
4448 5) Patch matrix transposition
4449 6) Inverted cylinder capping
4453 Have a new feature request. "Compute Bounding Box" for mapobjects (md3 files). This would be used for misc_mapobject (essentially, drop in 3DS Max models into our maps)
4455 Ok, Feature Request. Load and draw MD3's in the Camera view with proper bounding boxes. This should be off misc_model
4457 Feature Addition: View/Hide Hint Brushes -- This should be a specific case.