00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "stdafx.h"
00028 #include "qe3.h"
00029 #include "DialogInfo.h"
00030 #include "CapDialog.h"
00031
00032
00033 extern void MemFile_fprintf(CMemFile* pMemFile, const char* pText, ...);
00034 extern face_t *Face_Alloc( void );
00035 void _Write3DMatrix (FILE *f, int y, int x, int z, float *m);
00036 void _Write3DMatrix (CMemFile *f, int y, int x, int z, float *m);
00037
00038
00039
00040 #define CBLOCK_SUBDIVISIONS 6
00041
00042
00043 patchMesh_t* MakeNewPatch()
00044 {
00045 patchMesh_t *pm = reinterpret_cast<patchMesh_t*>(qmalloc(sizeof(patchMesh_t)));
00046 if (g_qeglobals.bSurfacePropertiesPlugin)
00047 {
00048 pm->pData = static_cast<void *>( g_SurfaceTable.m_pfnPatchAlloc( pm ) );
00049 }
00050 return pm;
00051 }
00052
00053
00054
00055
00056
00057
00058
00059 patchMesh_t patchSave;
00060
00061
00062
00063
00064
00065
00066
00067
00068 int g_nPatchClickedView = -1;
00069 bool g_bSameView = false;
00070
00071
00072
00073 bool g_bPatchShowBounds = true;
00074 bool g_bPatchWireFrame = false;
00075 bool g_bPatchWeld = true;
00076 bool g_bPatchDrillDown = true;
00077 bool g_bPatchInsertMode = false;
00078 bool g_bPatchBendMode = false;
00079 int g_nPatchBendState = -1;
00080 int g_nPatchInsertState = -1;
00081 int g_nBendOriginIndex = 0;
00082 vec3_t g_vBendOrigin;
00083
00084 bool g_bPatchAxisOnRow = true;
00085 int g_nPatchAxisIndex = 0;
00086 bool g_bPatchLowerEdge = true;
00087
00088
00089 enum
00090 {
00091 BEND_SELECT_ROTATION = 0,
00092 BEND_SELECT_ORIGIN,
00093 BEND_SELECT_EDGE,
00094 BEND_BENDIT,
00095 BEND_STATE_COUNT
00096 };
00097
00098 const char *g_pBendStateMsg[] =
00099 {
00100 "Use TAB to cycle through available bend axis. Press ENTER when the desired one is highlighted.",
00101 "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",
00102 "Use TAB to choose which side to bend. Press ENTER when the desired one is highlighted.",
00103 "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",
00104 ""
00105 };
00106
00107
00108 enum
00109 {
00110 INSERT_SELECT_EDGE = 0,
00111 INSERT_STATE_COUNT
00112 };
00113
00114 const char* g_pInsertStateMsg[] =
00115 {
00116 "Use TAB to cycle through available rows/columns for insertion/deletion. Press INS to insert at the highlight, DEL to remove the pair"
00117 };
00118
00119
00120 float *g_InversePoints[1024];
00121
00122 const float fFullBright = 1.0;
00123 const float fLowerLimit = .50;
00124 const float fDec = .05;
00125 void _SetColor(face_t* f, float fColor[3])
00126 {
00127 return;
00128 fColor[0] = f->d_color[0];
00129 fColor[1] = f->d_color[1];
00130 fColor[2] = f->d_color[2];
00131 qglColor3fv(fColor);
00132 }
00133
00134
00135 void _DecColor(float fColor[3])
00136 {
00137 return;
00138 fColor[0] -= fDec;
00139 fColor[1] -= fDec ;
00140 fColor[2] -= fDec;
00141 for (int i = 0; i < 3; i++)
00142 {
00143 if (fColor[i] <= fLowerLimit)
00144 {
00145 fColor[0] = fFullBright;
00146 fColor[1] = fFullBright;
00147 fColor[2] = fFullBright;
00148 break;
00149 }
00150 }
00151 qglColor3fv(fColor);
00152 }
00153
00154 vec_t __VectorNormalize (vec3_t in, vec3_t out)
00155 {
00156 vec_t length, ilength;
00157
00158 length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]);
00159 if (length == 0)
00160 {
00161 VectorClear (out);
00162 return 0;
00163 }
00164
00165 ilength = 1.0/length;
00166 out[0] = in[0]*ilength;
00167 out[1] = in[1]*ilength;
00168 out[2] = in[2]*ilength;
00169
00170 return length;
00171 }
00172
00173
00174 void Patch_SetType(patchMesh_t *p, int nType)
00175 {
00176 p->type = (p->type & PATCH_STYLEMASK) | nType;
00177 }
00178
00179 void Patch_SetStyle(patchMesh_t *p, int nStyle)
00180 {
00181 p->type = (p->type & PATCH_TYPEMASK) | nStyle;
00182 }
00183
00184
00185
00186
00187
00188
00189 int Patch_MemorySize(patchMesh_t *p)
00190 {
00191 return _msize(p);
00192 }
00193
00194
00195
00196
00197
00198
00199
00200
00201 void InterpolateInteriorPoints( patchMesh_t *p )
00202 {
00203 int i, j, k;
00204 int next, prev;
00205
00206 for ( i = 0 ; i < p->width ; i += 2 )
00207 {
00208
00209 next = ( i == p->width - 1 ) ? 1 : ( i + 1 ) % p->width;
00210 prev = ( i == 0 ) ? p->width - 2 : i - 1;
00211
00212 #if 0
00213 if ( i == 0 )
00214 {
00215 next = ( i + 1 ) % p->width;
00216 prev = p->width - 2;
00217 }
00218 else if ( i == p->width - 1 )
00219 {
00220 next = 1;
00221 prev = i - 1;
00222 }
00223 else
00224 {
00225 next = ( i + 1 ) % p->width;
00226 prev = i - 1;
00227 }
00228 #endif
00229
00230 for ( j = 0 ; j < p->height ; j++ )
00231 {
00232 for ( k = 0 ; k < 3 ; k++ )
00233 {
00234 p->ctrl[i][j].xyz[k] = ( p->ctrl[next][j].xyz[k] + p->ctrl[prev][j].xyz[k] ) * 0.5;
00235 }
00236 }
00237 }
00238 }
00239
00240
00241
00242
00243
00244
00245
00246 int neighbors[8][2] = {
00247 {0,1}, {1,1}, {1,0}, {1,-1}, {0,-1}, {-1,-1}, {-1,0}, {-1,1}
00248 };
00249
00250 void Patch_MeshNormals(patchMesh_t *in )
00251 {
00252 int i, j, k, dist;
00253 vec3_t normal;
00254 vec3_t sum;
00255 int count;
00256 vec3_t base;
00257 vec3_t delta;
00258 int x, y;
00259 drawVert_t *dv;
00260 vec3_t around[8], temp;
00261 qboolean good[8];
00262 qboolean wrapWidth, wrapHeight;
00263 float len;
00264
00265 wrapWidth = false;
00266 for ( i = 0 ; i < in->height ; i++ )
00267 {
00268
00269 VectorSubtract( in->ctrl[0][i].xyz,
00270 in->ctrl[in->width-1][i].xyz, delta );
00271 len = VectorLength( delta );
00272 if ( len > 1.0 )
00273 {
00274 break;
00275 }
00276 }
00277 if ( i == in->height )
00278 {
00279 wrapWidth = true;
00280 }
00281
00282 wrapHeight = false;
00283 for ( i = 0 ; i < in->width ; i++ )
00284 {
00285 VectorSubtract( in->ctrl[i][0].xyz,
00286 in->ctrl[i][in->height-1].xyz, delta );
00287 len = VectorLength( delta );
00288 if ( len > 1.0 )
00289 {
00290 break;
00291 }
00292 }
00293 if ( i == in->width)
00294 {
00295 wrapHeight = true;
00296 }
00297
00298
00299 for ( i = 0 ; i < in->width ; i++ )
00300 {
00301 for ( j = 0 ; j < in->height ; j++ )
00302 {
00303 count = 0;
00304
00305 dv = &in->ctrl[i][j];
00306 VectorCopy( dv->xyz, base );
00307 for ( k = 0 ; k < 8 ; k++ )
00308 {
00309 VectorClear( around[k] );
00310 good[k] = false;
00311
00312 for ( dist = 1 ; dist <= 3 ; dist++ )
00313 {
00314 x = i + neighbors[k][0] * dist;
00315 y = j + neighbors[k][1] * dist;
00316 if ( wrapWidth )
00317 {
00318 if ( x < 0 )
00319 {
00320 x = in->width - 1 + x;
00321 }
00322 else if ( x >= in->width )
00323 {
00324 x = 1 + x - in->width;
00325 }
00326 }
00327 if ( wrapHeight )
00328 {
00329 if ( y < 0 )
00330 {
00331 y = in->height - 1 + y;
00332 }
00333 else if ( y >= in->height )
00334 {
00335 y = 1 + y - in->height;
00336 }
00337 }
00338
00339 if ( x < 0 || x >= in->width || y < 0 || y >= in->height )
00340 {
00341 break;
00342 }
00343
00344 VectorSubtract( in->ctrl[x][y].xyz, base, temp );
00345 if ( __VectorNormalize( temp, temp ) == 0 )
00346 {
00347 continue;
00348 }
00349 else
00350 {
00351 good[k] = true;
00352 VectorCopy( temp, around[k] );
00353 break;
00354 }
00355 }
00356 }
00357
00358 VectorClear( sum );
00359 for ( k = 0 ; k < 8 ; k++ )
00360 {
00361 if ( !good[k] || !good[(k+1)&7] )
00362 {
00363 continue;
00364 }
00365 CrossProduct( around[(k+1)&7], around[k], normal );
00366 if ( __VectorNormalize( normal, normal ) == 0 )
00367 {
00368 continue;
00369 }
00370 VectorAdd( normal, sum, sum );
00371 count++;
00372 }
00373 if ( count == 0 )
00374 {
00375
00376 count = 1;
00377
00378 }
00379 __VectorNormalize( sum, dv->normal );
00380 }
00381 }
00382 }
00383
00384
00385
00386
00387
00388
00389
00390
00391
00392 void Patch_CalcBounds(patchMesh_t *p, vec3_t& vMin, vec3_t& vMax)
00393 {
00394 vMin[0] = vMin[1] = vMin[2] = 99999;
00395 vMax[0] = vMax[1] = vMax[2] = -99999;
00396
00397 p->bDirty = true;
00398 for (int w = 0; w < p->width; w++)
00399 {
00400 for (int h = 0; h < p->height; h++)
00401 {
00402 for (int j = 0; j < 3; j++)
00403 {
00404 float f = p->ctrl[w][h].xyz[j];
00405 if (f < vMin[j])
00406 vMin[j] = f;
00407 if (f > vMax[j])
00408 vMax[j] = f;
00409 }
00410 }
00411 }
00412 }
00413
00414
00415
00416
00417
00418
00419 void Brush_RebuildBrush(brush_t *b, vec3_t vMins, vec3_t vMaxs)
00420 {
00421
00422
00423
00424 int i, j;
00425 face_t *f, *next;
00426 vec3_t pts[4][2];
00427 texdef_t texdef;
00428
00429
00430 for (j = 0; j < 3; j++)
00431 {
00432 if ((int)vMins[j] == (int)vMaxs[j])
00433 {
00434 vMins[j] -= 4;
00435 vMaxs[j] += 4;
00436 }
00437 }
00438
00439
00440 for (f=b->brush_faces ; f ; f=next)
00441 {
00442 next = f->next;
00443 if (f)
00444 texdef = f->texdef;
00445 Face_Free( f );
00446 }
00447
00448 b->brush_faces = NULL;
00449
00450
00451
00452 for (i=0 ; i<3 ; i++)
00453 if (vMaxs[i] < vMins[i])
00454 Error ("Brush_RebuildBrush: backwards");
00455
00456 pts[0][0][0] = vMins[0];
00457 pts[0][0][1] = vMins[1];
00458
00459 pts[1][0][0] = vMins[0];
00460 pts[1][0][1] = vMaxs[1];
00461
00462 pts[2][0][0] = vMaxs[0];
00463 pts[2][0][1] = vMaxs[1];
00464
00465 pts[3][0][0] = vMaxs[0];
00466 pts[3][0][1] = vMins[1];
00467
00468 for (i=0 ; i<4 ; i++)
00469 {
00470 pts[i][0][2] = vMins[2];
00471 pts[i][1][0] = pts[i][0][0];
00472 pts[i][1][1] = pts[i][0][1];
00473 pts[i][1][2] = vMaxs[2];
00474 }
00475
00476 for (i=0 ; i<4 ; i++)
00477 {
00478 f = Face_Alloc();
00479 f->texdef = texdef;
00480 f->texdef.flags &= ~SURF_KEEP;
00481 f->texdef.contents &= ~CONTENTS_KEEP;
00482 if ( b->patchBrush )
00483 {
00484 f->texdef.flags |= SURF_PATCH;
00485 }
00486 f->next = b->brush_faces;
00487 b->brush_faces = f;
00488 j = (i+1)%4;
00489
00490 VectorCopy (pts[j][1], f->planepts[0]);
00491 VectorCopy (pts[i][1], f->planepts[1]);
00492 VectorCopy (pts[i][0], f->planepts[2]);
00493 }
00494
00495 f = Face_Alloc();
00496 f->texdef = texdef;
00497 f->texdef.flags &= ~SURF_KEEP;
00498 f->texdef.contents &= ~CONTENTS_KEEP;
00499 if ( b->patchBrush )
00500 {
00501 f->texdef.flags |= SURF_PATCH;
00502 }
00503 f->next = b->brush_faces;
00504 b->brush_faces = f;
00505
00506 VectorCopy (pts[0][1], f->planepts[0]);
00507 VectorCopy (pts[1][1], f->planepts[1]);
00508 VectorCopy (pts[2][1], f->planepts[2]);
00509
00510 f = Face_Alloc();
00511 f->texdef = texdef;
00512 f->texdef.flags &= ~SURF_KEEP;
00513 f->texdef.contents &= ~CONTENTS_KEEP;
00514 if ( b->patchBrush )
00515 {
00516 f->texdef.flags |= SURF_PATCH;
00517 }
00518 f->next = b->brush_faces;
00519 b->brush_faces = f;
00520
00521 VectorCopy (pts[2][0], f->planepts[0]);
00522 VectorCopy (pts[1][0], f->planepts[1]);
00523 VectorCopy (pts[0][0], f->planepts[2]);
00524
00525 Brush_Build(b);
00526 }
00527
00528 void WINAPI Patch_Rebuild(patchMesh_t *p)
00529 {
00530 vec3_t vMin, vMax;
00531 Patch_CalcBounds(p, vMin, vMax);
00532 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
00533 p->bDirty = true;
00534 }
00535
00536
00537
00538
00539
00540
00541
00542 brush_t* AddBrushForPatch(patchMesh_t *pm, bool bLinkToWorld )
00543 {
00544
00545 vec3_t vMin, vMax;
00546 Patch_CalcBounds(pm, vMin, vMax);
00547
00548 for (int j = 0; j < 3; j++)
00549 {
00550 if (vMin[j] == vMax[j])
00551 {
00552 vMin[j] -= 4;
00553 vMax[j] += 4;
00554 }
00555 }
00556
00557 brush_t *b = Brush_Create(vMin, vMax, &g_qeglobals.d_texturewin.texdef);
00558 face_t *f;
00559 for (f=b->brush_faces ; f ; f=f->next)
00560 {
00561 f->texdef.flags |= SURF_PATCH;
00562 }
00563
00564
00565 b->pPatch = pm;
00566 pm->pSymbiot = b;
00567 pm->bSelected = false;
00568 pm->bOverlay = false;
00569 pm->bDirty = true;
00570 pm->nListID = -1;
00571
00572 if (bLinkToWorld)
00573 {
00574 Brush_AddToList (b, &active_brushes);
00575 Entity_LinkBrush (world_entity, b);
00576 Brush_Build(b);
00577 }
00578
00579 return b;
00580 }
00581
00582 void Patch_SetPointIntensities(int n)
00583 {
00584 #if 0
00585 patchMesh_t *p = patchMeshes[n];
00586 for (int i = 0; i < p->width; i++)
00587 {
00588 for (int j = 0; j < p->height; j++)
00589 {
00590
00591 }
00592 }
00593 #endif
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603 float Patch_Width(patchMesh_t *p)
00604 {
00605 float f = 0;
00606 for (int i = 0; i < p->width-1; i++)
00607 {
00608 vec3_t vTemp;
00609 VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
00610 f += VectorLength(vTemp);
00611 }
00612 return f;
00613 }
00614
00615 float Patch_WidthDistanceTo(patchMesh_t *p, int j)
00616 {
00617 float f = 0;
00618 for (int i = 0; i < j; i++)
00619 {
00620 vec3_t vTemp;
00621 VectorSubtract(p->ctrl[i][0].xyz, p->ctrl[i+1][0].xyz, vTemp);
00622 f += VectorLength(vTemp);
00623 }
00624 return f;
00625 }
00626
00627
00628
00629
00630
00631
00632
00633
00634 float Patch_Height(patchMesh_t *p)
00635 {
00636 float f = 0;
00637 for (int i = 0; i < p->height-1; i++)
00638 {
00639 vec3_t vTemp;
00640 VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
00641 f += VectorLength(vTemp);
00642 }
00643 return f;
00644 }
00645
00646 float Patch_HeightDistanceTo(patchMesh_t *p, int j)
00647 {
00648 float f = 0;
00649 for (int i = 0; i < j; i++)
00650 {
00651 vec3_t vTemp;
00652 VectorSubtract(p->ctrl[0][i].xyz, p->ctrl[0][i+1].xyz, vTemp);
00653 f += VectorLength(vTemp);
00654 }
00655 return f;
00656 }
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668 void Patch_Naturalize(patchMesh_t *p)
00669 {
00670 int nWidth = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? p->d_texture->width * 0.5 : p->d_texture->width;
00671 int nHeight = (g_PrefsDlg.m_bHiColorTextures == TRUE) ? p->d_texture->height * 0.5 : p->d_texture->height;
00672 float fPWidth = Patch_Width(p);
00673 float fPHeight = Patch_Height(p);
00674 float xAccum = 0;
00675 for ( int i = 0 ; i < p->width ; i++ )
00676 {
00677 float yAccum = 0;
00678 for ( int j = 0 ; j < p->height ; j++ )
00679 {
00680 p->ctrl[i][j].st[0] = (fPWidth / nWidth) * xAccum / fPWidth;
00681 p->ctrl[i][j].st[1] = (fPHeight / nHeight) * yAccum / fPHeight;
00682 yAccum = Patch_HeightDistanceTo(p,j+1);
00683
00684
00685 }
00686 xAccum = Patch_WidthDistanceTo(p,i+1);
00687 }
00688 p->bDirty = true;
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712 int Index3By[][2] =
00713 {
00714 {0,0},
00715 {1,0},
00716 {2,0},
00717 {2,1},
00718 {2,2},
00719 {1,2},
00720 {0,2},
00721 {0,1},
00722 {0,0},
00723 {0,0},
00724 {0,0},
00725 {0,0},
00726 {0,0},
00727 {0,0},
00728 {0,0}
00729 };
00730
00731 int Index5By[][2] =
00732 {
00733 {0,0},
00734 {1,0},
00735 {2,0},
00736 {3,0},
00737 {4,0},
00738 {4,1},
00739 {4,2},
00740 {4,3},
00741 {4,4},
00742 {3,4},
00743 {2,4},
00744 {1,4},
00745 {0,4},
00746 {0,3},
00747 {0,2},
00748 {0,1}
00749 };
00750
00751
00752
00753 int Interior3By[][2] =
00754 {
00755 {1,1}
00756 };
00757
00758 int Interior5By[][2] =
00759 {
00760 {1,1},
00761 {2,1},
00762 {3,1},
00763 {1,2},
00764 {2,2},
00765 {3,2},
00766 {1,3},
00767 {2,3},
00768 {3,3}
00769 };
00770
00771 int Interior3ByCount = sizeof(Interior3By) / sizeof(int[2]);
00772 int Interior5ByCount = sizeof(Interior5By) / sizeof(int[2]);
00773
00774 face_t* Patch_GetAxisFace(patchMesh_t *p)
00775 {
00776 face_t *f = NULL;
00777 vec3_t vTemp;
00778 brush_t *b = p->pSymbiot;
00779
00780 for (f = b->brush_faces ; f ; f = f->next)
00781 {
00782 VectorSubtract(f->face_winding->points[1], f->face_winding->points[0], vTemp);
00783 int nScore = 0;
00784
00785
00786
00787 for (int j = 0; j < 3; j++)
00788 {
00789 if (vTemp[j] > 8)
00790 nScore++;
00791 }
00792
00793 if (nScore > 0)
00794 break;
00795 }
00796
00797 if (f == NULL)
00798 f = b->brush_faces;
00799 return f;
00800 }
00801
00802 int g_nFaceCycle = 0;
00803
00804 face_t* nextFace(patchMesh_t *p)
00805 {
00806 brush_t *b = p->pSymbiot;
00807 face_t *f = NULL;
00808 int n = 0;
00809 for (f = b->brush_faces ; f && n <= g_nFaceCycle; f = f->next)
00810 {
00811 n++;
00812 }
00813 g_nFaceCycle++;
00814 if (g_nFaceCycle > 5)
00815 {
00816 g_nFaceCycle =0;
00817 f = b->brush_faces;
00818 }
00819
00820 return f;
00821 }
00822
00823
00824 extern void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f);
00825 void Patch_CapTexture(patchMesh_t *p, bool bFaceCycle = false)
00826 {
00827 Patch_MeshNormals(p);
00828 face_t *f = (bFaceCycle) ? nextFace(p) : Patch_GetAxisFace(p);
00829 vec3_t vSave;
00830 VectorCopy(f->plane.normal, vSave);
00831
00832 float fRotate = f->texdef.rotate;
00833 f->texdef.rotate = 0;
00834 float fScale[2];
00835 fScale[0] = f->texdef.scale[0];
00836 fScale[1] = f->texdef.scale[1];
00837 f->texdef.scale[0] = 0.5;
00838 f->texdef.scale[1] = 0.5;
00839 float fShift[2];
00840 fShift[0] = f->texdef.shift[0];
00841 fShift[1] = f->texdef.shift[1];
00842 f->texdef.shift[0] = 0;
00843 f->texdef.shift[1] = 0;
00844
00845 for (int i = 0; i < p->width; i++)
00846 {
00847 for (int j = 0; j < p->height; j++)
00848 {
00849 if (!bFaceCycle)
00850 {
00851 VectorCopy(p->ctrl[i][j].normal, f->plane.normal);
00852 }
00853 EmitTextureCoordinates( p->ctrl[i][j].xyz, f->d_texture, f);
00854 }
00855 }
00856 VectorCopy(vSave, f->plane.normal);
00857 f->texdef.rotate = fRotate;
00858 f->texdef.scale[0] = fScale[0];
00859 f->texdef.scale[1] = fScale[1];
00860 f->texdef.shift[0] = fShift[0];
00861 f->texdef.shift[1] = fShift[1];
00862 p->bDirty = true;
00863 }
00864
00865 void FillPatch(patchMesh_t *p, vec3_t v)
00866 {
00867 for (int i = 0; i < p->width; i++)
00868 {
00869 for (int j = 0; j < p->height; j++)
00870 {
00871 VectorCopy(v, p->ctrl[i][j].xyz);
00872 }
00873 }
00874 }
00875
00876 brush_t* Cap(patchMesh_t *pParent, bool bByColumn, bool bFirst)
00877 {
00878 brush_t *b;
00879 patchMesh_t *p;
00880 vec3_t vMin, vMax;
00881 int i, j;
00882
00883 bool bSmall = true;
00884
00885 if (pParent->width <= 9)
00886 {
00887 b = Patch_GenericMesh(3, 3, 2, false);
00888 }
00889 else
00890 {
00891 b = Patch_GenericMesh(5, 5, 2, false);
00892 bSmall = false;
00893 }
00894
00895 if (!b)
00896 {
00897 Sys_Printf("Unable to cap. You may need to ungroup the patch.\n");
00898 return NULL;
00899 }
00900
00901 p = b->pPatch;
00902 p->type |= PATCH_CAP;
00903
00904 vMin[0] = vMin[1] = vMin[2] = 9999;
00905 vMax[0] = vMax[1] = vMax[2] = -9999;
00906
00907
00908
00909 int nSize = (bByColumn) ? pParent->width : pParent->height;
00910 int nIndex = (bFirst) ? 0 : (bByColumn) ? pParent->height-1 : pParent->width-1;
00911
00912 FillPatch(p, pParent->ctrl[0][nIndex].xyz);
00913
00914 for (i = 0; i < nSize; i++)
00915 {
00916 if (bByColumn)
00917 {
00918 if (bSmall)
00919 {
00920 VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
00921 }
00922 else
00923 {
00924 VectorCopy(pParent->ctrl[i][nIndex].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
00925 }
00926 }
00927 else
00928 {
00929 if (bSmall)
00930 {
00931 VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
00932 }
00933 else
00934 {
00935 VectorCopy(pParent->ctrl[nIndex][i].xyz, p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz);
00936 }
00937 }
00938
00939 for (j = 0; j < 3; j++)
00940 {
00941 float f = (bSmall) ? p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz[j] : p->ctrl[Index5By[i][0]][Index5By[i][1]].xyz[j];
00942 if (f < vMin[j])
00943 vMin[j] = f;
00944 if (f > vMax[j])
00945 vMax[j] = f;
00946 }
00947 }
00948
00949 vec3_t vTemp;
00950 for (j = 0; j < 3; j++)
00951 {
00952 vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
00953 }
00954
00955 int nCount = (bSmall) ? Interior3ByCount : Interior5ByCount;
00956 for (j = 0; j < nCount; j++)
00957 {
00958 if (bSmall)
00959 {
00960 VectorCopy(vTemp, p->ctrl[Interior3By[j][0]][Interior3By[j][1]].xyz);
00961 }
00962 else
00963 {
00964 VectorCopy(vTemp, p->ctrl[Interior5By[j][0]][Interior5By[j][1]].xyz);
00965 }
00966 }
00967
00968 if (bFirst)
00969 {
00970 drawVert_t vertTemp;
00971 for (i = 0; i < p->width; i++)
00972 {
00973 for (j = 0; j < p->height / 2; j++)
00974 {
00975 memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
00976 memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
00977 memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
00978 }
00979 }
00980 }
00981
00982 Patch_Rebuild(p);
00983 Patch_CapTexture(p);
00984 return p->pSymbiot;
00985 }
00986
00987 brush_t* CapSpecial(patchMesh_t *pParent, int nType, bool bFirst)
00988 {
00989 brush_t *b;
00990 patchMesh_t *p;
00991 vec3_t vMin, vMax, vTemp;
00992 int i, j;
00993
00994 if (nType == CCapDialog::IENDCAP)
00995 b = Patch_GenericMesh(5, 3, 2, false);
00996 else
00997 b = Patch_GenericMesh(3, 3, 2, false);
00998
00999 if (!b)
01000 {
01001 Sys_Printf("Unable to cap. Make sure you ungroup before re-capping.");
01002 return NULL;
01003 }
01004
01005 p = b->pPatch;
01006 p->type |= PATCH_CAP;
01007
01008 vMin[0] = vMin[1] = vMin[2] = 9999;
01009 vMax[0] = vMax[1] = vMax[2] = -9999;
01010
01011 int nSize = pParent->width;
01012 int nIndex = (bFirst) ? 0 : pParent->height-1;
01013
01014
01015 Patch_CalcBounds(pParent, vMin, vMax);
01016
01017 for (j = 0; j < 3; j++)
01018 {
01019 vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
01020 }
01021
01022 if (nType == CCapDialog::IBEVEL)
01023 {
01024 VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
01025 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
01026 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
01027 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][2].xyz);
01028 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
01029 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
01030 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
01031 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][0].xyz);
01032 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[2][1].xyz);
01033 }
01034 else if (nType == CCapDialog::BEVEL)
01035 {
01036 vec3_t p1, p2, p3, p4, temp, dir;
01037
01038 VectorCopy(pParent->ctrl[0][nIndex].xyz, p3);
01039 VectorCopy(pParent->ctrl[1][nIndex].xyz, p1);
01040 VectorCopy(pParent->ctrl[2][nIndex].xyz, p2);
01041
01042 VectorSubtract(p3, p2, dir);
01043 VectorNormalize(dir);
01044 VectorSubtract(p1, p2, temp);
01045 vec_t dist = _DotProduct(temp, dir);
01046
01047 VectorScale(dir, dist, temp);
01048
01049 VectorAdd(p2, temp, temp);
01050
01051 VectorSubtract(temp, p1, temp);
01052 VectorScale(temp, 2, temp);
01053 VectorAdd(p1, temp, p4);
01054
01055 VectorCopy(p4, p->ctrl[0][0].xyz);
01056 VectorCopy(p4, p->ctrl[1][0].xyz);
01057 VectorCopy(p4, p->ctrl[0][1].xyz);
01058 VectorCopy(p4, p->ctrl[1][1].xyz);
01059 VectorCopy(p4, p->ctrl[0][2].xyz);
01060 VectorCopy(p4, p->ctrl[1][2].xyz);
01061 VectorCopy(p3, p->ctrl[2][0].xyz);
01062 VectorCopy(p1, p->ctrl[2][1].xyz);
01063 VectorCopy(p2, p->ctrl[2][2].xyz);
01064
01065 }
01066 else if (nType == CCapDialog::ENDCAP)
01067 {
01068 VectorAdd(pParent->ctrl[4][nIndex].xyz, pParent->ctrl[0][nIndex].xyz, vTemp);
01069 VectorScale(vTemp, 0.5, vTemp);
01070 VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
01071 VectorCopy(vTemp, p->ctrl[1][0].xyz);
01072 VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[2][0].xyz);
01073
01074 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[0][2].xyz);
01075 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][2].xyz);
01076 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
01077 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[1][1].xyz);
01078
01079 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
01080 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[2][1].xyz);
01081 }
01082 else
01083 {
01084 VectorCopy(pParent->ctrl[0][nIndex].xyz, p->ctrl[0][0].xyz);
01085 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][0].xyz);
01086 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][0].xyz);
01087 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][0].xyz);
01088 VectorCopy(pParent->ctrl[4][nIndex].xyz, p->ctrl[4][0].xyz);
01089
01090 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][1].xyz);
01091 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][1].xyz);
01092 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][1].xyz);
01093 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][1].xyz);
01094 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[4][1].xyz);
01095
01096 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[0][2].xyz);
01097 VectorCopy(pParent->ctrl[1][nIndex].xyz, p->ctrl[1][2].xyz);
01098 VectorCopy(pParent->ctrl[2][nIndex].xyz, p->ctrl[2][2].xyz);
01099 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[3][2].xyz);
01100 VectorCopy(pParent->ctrl[3][nIndex].xyz, p->ctrl[4][2].xyz);
01101 }
01102
01103
01104 bool bEndCap = (nType == CCapDialog::ENDCAP || nType == CCapDialog::IENDCAP);
01105 if ((!bFirst && !bEndCap) || (bFirst && bEndCap))
01106 {
01107 drawVert_t vertTemp;
01108 for (i = 0; i < p->width; i++)
01109 {
01110 for (j = 0; j < p->height / 2; j++)
01111 {
01112 memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
01113 memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
01114 memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
01115 }
01116 }
01117 }
01118
01119
01120
01121 Patch_Rebuild(p);
01122 Patch_CapTexture(p);
01123 return p->pSymbiot;
01124 }
01125
01126
01127 void Patch_CapCurrent(bool bInvertedBevel, bool bInvertedEndcap)
01128 {
01129 patchMesh_t *pParent = NULL;
01130 brush_t *b[4];
01131 brush_t *pCap = NULL;
01132 b[0] = b[1] = b[2] = b[3] = NULL;
01133 int nIndex = 0;
01134
01135 if (!QE_SingleBrush())
01136 {
01137 Sys_Printf("Cannot cap multiple selection. Please select a single patch.\n");
01138 return;
01139 }
01140
01141
01142 for (brush_t *pb = selected_brushes.next ; pb != NULL && pb != &selected_brushes ; pb = pb->next)
01143 {
01144 if (pb->patchBrush)
01145 {
01146 pParent = pb->pPatch;
01147
01148
01149
01150
01151 if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[pParent->width-1][0].xyz))
01152 {
01153 pCap = Cap(pParent, true, false);
01154 if (pCap != NULL)
01155 {
01156 b[nIndex++] = pCap;
01157 }
01158 }
01159 if (VectorCompare(pParent->ctrl[0][pParent->height-1].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
01160 {
01161 pCap = Cap(pParent, true, true);
01162 if (pCap != NULL)
01163 {
01164 b[nIndex++] = pCap;
01165 }
01166 }
01167 if (VectorCompare(pParent->ctrl[0][0].xyz, pParent->ctrl[0][pParent->height-1].xyz))
01168 {
01169 pCap = Cap(pParent, false, false);
01170 if (pCap != NULL)
01171 {
01172 b[nIndex++] = pCap;
01173 }
01174 }
01175 if (VectorCompare(pParent->ctrl[pParent->width-1][0].xyz, pParent->ctrl[pParent->width-1][pParent->height-1].xyz))
01176 {
01177 pCap = Cap(pParent, false, true);
01178 if (pCap != NULL)
01179 {
01180 b[nIndex++] = pCap;
01181 }
01182 }
01183 }
01184 }
01185
01186 if (pParent)
01187 {
01188
01189 if (nIndex == 0)
01190 {
01191 CCapDialog dlg;
01192 if (dlg.DoModal() == IDOK)
01193 {
01194 b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), false);
01195 b[nIndex++] = CapSpecial(pParent, dlg.getCapType(), true);
01196 }
01197 }
01198
01199 if (nIndex > 0)
01200 {
01201 while (nIndex > 0)
01202 {
01203 nIndex--;
01204 if (b[nIndex])
01205 {
01206 Select_Brush(b[nIndex]);
01207 }
01208 }
01209 eclass_t *pecNew = Eclass_ForName("func_group", false);
01210 if (pecNew)
01211 {
01212 entity_t *e = Entity_Create(pecNew);
01213 SetKeyValue(e, "type", "patchCapped");
01214 }
01215 }
01216 }
01217 }
01218
01219
01220
01221
01222 void GenerateEndCaps(brush_t *brushParent, bool bBevel, bool bEndcap, bool bInverted)
01223 {
01224 brush_t *b, *b2;
01225 patchMesh_t *p, *p2, *pParent;
01226 vec3_t vTemp, vMin, vMax;
01227 int i, j;
01228
01229 pParent = brushParent->pPatch;
01230
01231 Patch_CalcBounds(pParent, vMin, vMax);
01232
01233
01234 if (pParent->width > 9)
01235 b = Patch_GenericMesh(5, 3, 2, false);
01236 else
01237 b = Patch_GenericMesh(3, 3, 2, false);
01238 p = b->pPatch;
01239
01240 vMin[0] = vMin[1] = vMin[2] = 9999;
01241 vMax[0] = vMax[1] = vMax[2] = -9999;
01242
01243 for (i = 0; i < pParent->width; i++)
01244 {
01245 VectorCopy(pParent->ctrl[i][0].xyz, p->ctrl[Index3By[i][0]][Index3By[i][1]].xyz);
01246 for (j = 0; j < 3; j++)
01247 {
01248 if (pParent->ctrl[i][0].xyz[j] < vMin[j])
01249 vMin[j] = pParent->ctrl[i][0].xyz[j];
01250 if (pParent->ctrl[i][0].xyz[j] > vMax[j])
01251 vMax[j] = pParent->ctrl[i][0].xyz[j];
01252 }
01253 }
01254
01255 for (j = 0; j < 3; j++)
01256 {
01257 vTemp[j] = vMin[j] + abs((vMax[j] - vMin[j]) * 0.5);
01258 }
01259
01260 for (i = 0; i < Interior3ByCount; i++)
01261 {
01262 VectorCopy(vTemp, p->ctrl[Interior3By[i][0]][Interior3By[i][1]].xyz);
01263 }
01264
01265 Patch_CalcBounds(p, vMin, vMax);
01266 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
01267 Select_Brush(p->pSymbiot);
01268 return;
01269
01270 bool bCreated = false;
01271
01272 if (bInverted)
01273 {
01274 if (bBevel)
01275 {
01276 b = Patch_GenericMesh(3, 3, 2, false);
01277 p = b->pPatch;
01278 VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][2].xyz);
01279 VectorCopy(p->ctrl[2][2].xyz, p->ctrl[2][1].xyz);
01280 VectorCopy(p->ctrl[2][2].xyz, p->ctrl[0][1].xyz);
01281 VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][0].xyz);
01282 VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][1].xyz);
01283 VectorCopy(p->ctrl[2][0].xyz, p->ctrl[0][0].xyz);
01284
01285 b2 = Patch_GenericMesh(3, 3, 2, false);
01286 p2 = b2->pPatch;
01287 VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][2].xyz);
01288 VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[2][1].xyz);
01289 VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[0][1].xyz);
01290 VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][0].xyz);
01291 VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][1].xyz);
01292 VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[0][0].xyz);
01293
01294
01295 bCreated = true;
01296
01297 }
01298 else if (bEndcap)
01299 {
01300 b = Patch_GenericMesh(5, 5, 2, false);
01301 p = b->pPatch;
01302 VectorCopy(p->ctrl[4][4].xyz, p->ctrl[4][3].xyz);
01303 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[1][4].xyz);
01304 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[2][4].xyz);
01305 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[3][4].xyz);
01306
01307 VectorCopy(p->ctrl[4][0].xyz, p->ctrl[4][1].xyz);
01308 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
01309 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
01310 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[3][0].xyz);
01311
01312 for (i = 1; i < 4; i++)
01313 {
01314 for (j = 0; j < 4; j++)
01315 {
01316 VectorCopy(p->ctrl[4][i].xyz, p->ctrl[j][i].xyz);
01317 }
01318 }
01319
01320
01321 b2 = Patch_GenericMesh(5, 5, 2, false);
01322 p2 = b2->pPatch;
01323 VectorCopy(p2->ctrl[4][4].xyz, p2->ctrl[4][3].xyz);
01324 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[1][4].xyz);
01325 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[2][4].xyz);
01326 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[3][4].xyz);
01327
01328 VectorCopy(p2->ctrl[4][0].xyz, p2->ctrl[4][1].xyz);
01329 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
01330 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
01331 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[3][0].xyz);
01332
01333 for (i = 1; i < 4; i++)
01334 {
01335 for (j = 0; j < 4; j++)
01336 {
01337 VectorCopy(p2->ctrl[4][i].xyz, p2->ctrl[j][i].xyz);
01338 }
01339 }
01340
01341
01342 bCreated = true;
01343 }
01344 }
01345 else
01346 {
01347 if (bBevel)
01348 {
01349 b = Patch_GenericMesh(3, 3, 2, false);
01350 p = b->pPatch;
01351 VectorCopy(p->ctrl[2][0].xyz, p->ctrl[2][1].xyz);
01352 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
01353 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
01354
01355 b2 = Patch_GenericMesh(3, 3, 2, false);
01356 p2 = b2->pPatch;
01357 VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[2][1].xyz);
01358 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
01359 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
01360 bCreated = true;
01361 }
01362 else if (bEndcap)
01363 {
01364 b = Patch_GenericMesh(5, 5, 2, false);
01365 p = b->pPatch;
01366 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz);
01367 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[2][0].xyz);
01368 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[3][0].xyz);
01369 VectorCopy(p->ctrl[4][0].xyz, p->ctrl[4][1].xyz);
01370 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[4][0].xyz);
01371
01372 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[1][4].xyz);
01373 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[2][4].xyz);
01374 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[3][4].xyz);
01375 VectorCopy(p->ctrl[4][4].xyz, p->ctrl[4][3].xyz);
01376 VectorCopy(p->ctrl[0][4].xyz, p->ctrl[4][4].xyz);
01377
01378 b2 = Patch_GenericMesh(5, 5, 2, false);
01379 p2 = b2->pPatch;
01380 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz);
01381 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[2][0].xyz);
01382 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[3][0].xyz);
01383 VectorCopy(p2->ctrl[4][0].xyz, p2->ctrl[4][1].xyz);
01384 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[4][0].xyz);
01385
01386 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[1][4].xyz);
01387 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[2][4].xyz);
01388 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[3][4].xyz);
01389 VectorCopy(p2->ctrl[4][4].xyz, p2->ctrl[4][3].xyz);
01390 VectorCopy(p2->ctrl[0][4].xyz, p2->ctrl[4][4].xyz);
01391 bCreated = true;
01392 }
01393 else
01394 {
01395 b = Patch_GenericMesh(3, 3, 2, false);
01396 p = b->pPatch;
01397
01398 VectorCopy(p->ctrl[0][1].xyz, vTemp);
01399 VectorCopy(p->ctrl[0][2].xyz, p->ctrl[0][1].xyz)
01400 VectorCopy(p->ctrl[1][2].xyz, p->ctrl[0][2].xyz)
01401 VectorCopy(p->ctrl[2][2].xyz, p->ctrl[1][2].xyz)
01402 VectorCopy(p->ctrl[2][1].xyz, p->ctrl[2][2].xyz)
01403 VectorCopy(p->ctrl[2][0].xyz, p->ctrl[2][1].xyz)
01404 VectorCopy(p->ctrl[1][0].xyz, p->ctrl[2][0].xyz)
01405 VectorCopy(p->ctrl[0][0].xyz, p->ctrl[1][0].xyz)
01406 VectorCopy(vTemp, p->ctrl[0][0].xyz)
01407
01408 b2 = Patch_GenericMesh(3, 3, 2, false);
01409 p2 = b2->pPatch;
01410 VectorCopy(p2->ctrl[0][1].xyz, vTemp);
01411 VectorCopy(p2->ctrl[0][2].xyz, p2->ctrl[0][1].xyz)
01412 VectorCopy(p2->ctrl[1][2].xyz, p2->ctrl[0][2].xyz)
01413 VectorCopy(p2->ctrl[2][2].xyz, p2->ctrl[1][2].xyz)
01414 VectorCopy(p2->ctrl[2][1].xyz, p2->ctrl[2][2].xyz)
01415 VectorCopy(p2->ctrl[2][0].xyz, p2->ctrl[2][1].xyz)
01416 VectorCopy(p2->ctrl[1][0].xyz, p2->ctrl[2][0].xyz)
01417 VectorCopy(p2->ctrl[0][0].xyz, p2->ctrl[1][0].xyz)
01418 VectorCopy(vTemp, p2->ctrl[0][0].xyz)
01419 bCreated = true;
01420 }
01421 }
01422
01423 if (bCreated)
01424 {
01425 drawVert_t vertTemp;
01426 for (i = 0; i < p->width; i++)
01427 {
01428 for (j = 0; j < p->height; j++)
01429 {
01430 p->ctrl[i][j].xyz[2] = vMin[2];
01431 p2->ctrl[i][j].xyz[2] = vMax[2];
01432 }
01433
01434 for (j = 0; j < p->height / 2; j++)
01435 {
01436 memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
01437 memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
01438 memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
01439 }
01440
01441 }
01442
01443
01444 Patch_CalcBounds(p, vMin, vMax);
01445 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
01446 Patch_CalcBounds(p2, vMin, vMax);
01447 Brush_RebuildBrush(p2->pSymbiot, vMin, vMax);
01448 Select_Brush(p->pSymbiot);
01449 Select_Brush(p2->pSymbiot);
01450 }
01451 else
01452 {
01453 Select_Delete();
01454 }
01455
01456
01457 }
01458
01459
01460
01461
01462
01463
01464
01465 void Patch_BrushToMesh(bool bCone, bool bBevel, bool bEndcap, bool bSquare, int nHeight)
01466 {
01467 brush_t *b;
01468 patchMesh_t *p;
01469 int i,j;
01470
01471 if (!QE_SingleBrush())
01472 return;
01473
01474 b = selected_brushes.next;
01475
01476 p = MakeNewPatch();
01477
01478 p->d_texture = b->brush_faces->d_texture;
01479
01480 p->height = nHeight;
01481
01482 p->type = PATCH_CYLINDER;
01483 if (bBevel & !bSquare)
01484 {
01485 p->type = PATCH_BEVEL;
01486 p->width = 3;
01487 int nStep = (b->maxs[2] - b->mins[2]) / (p->height-1);
01488 int nStart = b->mins[2];
01489 for (i = 0; i < p->height; i++)
01490 {
01491 p->ctrl[0][i].xyz[0] = b->mins[0];
01492 p->ctrl[0][i].xyz[1] = b->mins[1];
01493 p->ctrl[0][i].xyz[2] = nStart;
01494
01495 p->ctrl[1][i].xyz[0] = b->maxs[0];
01496 p->ctrl[1][i].xyz[1] = b->mins[1];
01497 p->ctrl[1][i].xyz[2] = nStart;
01498
01499 p->ctrl[2][i].xyz[0] = b->maxs[0];
01500 p->ctrl[2][i].xyz[1] = b->maxs[1];
01501 p->ctrl[2][i].xyz[2] = nStart;
01502 nStart += nStep;
01503 }
01504 }
01505 else if (bEndcap & !bSquare)
01506 {
01507 p->type = PATCH_ENDCAP;
01508 p->width = 5;
01509 int nStep = (b->maxs[2] - b->mins[2]) / (p->height-1);
01510 int nStart = b->mins[2];
01511 for (i = 0; i < p->height; i++)
01512 {
01513 p->ctrl[0][i].xyz[0] = b->mins[0];
01514 p->ctrl[0][i].xyz[1] = b->mins[1];
01515 p->ctrl[0][i].xyz[2] = nStart;
01516
01517 p->ctrl[1][i].xyz[0] = b->mins[0];
01518 p->ctrl[1][i].xyz[1] = b->maxs[1];
01519 p->ctrl[1][i].xyz[2] = nStart;
01520
01521 p->ctrl[2][i].xyz[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) * 0.5);
01522 p->ctrl[2][i].xyz[1] = b->maxs[1];
01523 p->ctrl[2][i].xyz[2] = nStart;
01524
01525 p->ctrl[3][i].xyz[0] = b->maxs[0];
01526 p->ctrl[3][i].xyz[1] = b->maxs[1];
01527 p->ctrl[3][i].xyz[2] = nStart;
01528
01529 p->ctrl[4][i].xyz[0] = b->maxs[0];
01530 p->ctrl[4][i].xyz[1] = b->mins[1];
01531 p->ctrl[4][i].xyz[2] = nStart;
01532 nStart += nStep;
01533 }
01534 }
01535 else
01536 {
01537 p->width = 9;
01538 p->ctrl[1][0].xyz[0] = b->mins[0];
01539 p->ctrl[1][0].xyz[1] = b->mins[1];
01540
01541 p->ctrl[3][0].xyz[0] = b->maxs[0];
01542 p->ctrl[3][0].xyz[1] = b->mins[1];
01543
01544 p->ctrl[5][0].xyz[0] = b->maxs[0];
01545 p->ctrl[5][0].xyz[1] = b->maxs[1];
01546
01547 p->ctrl[7][0].xyz[0] = b->mins[0];
01548 p->ctrl[7][0].xyz[1] = b->maxs[1];
01549
01550 for ( i = 1 ; i < p->width - 1 ; i += 2 )
01551 {
01552
01553 p->ctrl[i][0].xyz[2] = b->mins[2];
01554
01555 VectorCopy( p->ctrl[i][0].xyz, p->ctrl[i][2].xyz );
01556
01557 p->ctrl[i][2].xyz[2] = b->maxs[2];
01558
01559 p->ctrl[i][1].xyz[0] = ( p->ctrl[i][0].xyz[0] + p->ctrl[i][2].xyz[0] ) * 0.5;
01560 p->ctrl[i][1].xyz[1] = ( p->ctrl[i][0].xyz[1] + p->ctrl[i][2].xyz[1] ) * 0.5;
01561 p->ctrl[i][1].xyz[2] = ( p->ctrl[i][0].xyz[2] + p->ctrl[i][2].xyz[2] ) * 0.5;
01562 }
01563 InterpolateInteriorPoints( p );
01564
01565 if (bSquare)
01566 {
01567 if (bBevel || bEndcap)
01568 {
01569 if (bBevel)
01570 {
01571 for (i = 0; i < p->height; i++)
01572 {
01573 VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
01574 VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
01575 }
01576 }
01577 else
01578 {
01579 for (i = 0; i < p->height; i++)
01580 {
01581 VectorCopy(p->ctrl[5][i].xyz, p->ctrl[4][i].xyz);
01582 VectorCopy(p->ctrl[1][i].xyz, p->ctrl[2][i].xyz);
01583 VectorCopy(p->ctrl[7][i].xyz, p->ctrl[6][i].xyz);
01584 VectorCopy(p->ctrl[8][i].xyz, p->ctrl[7][i].xyz);
01585 }
01586 }
01587 }
01588 else
01589 {
01590 for (i = 0; i < p->width-1; i ++)
01591 {
01592 for (j = 0; j < p->height; j++)
01593 {
01594 VectorCopy(p->ctrl[i+1][j].xyz, p->ctrl[i][j].xyz);
01595 }
01596 }
01597 for (j = 0; j < p->height; j++)
01598 {
01599 VectorCopy(p->ctrl[0][j].xyz, p->ctrl[8][j].xyz);
01600 }
01601 }
01602 }
01603 }
01604
01605
01606 Patch_Naturalize(p);
01607
01608 if (bCone)
01609 {
01610 p->type = PATCH_CONE;
01611 float xc = (b->maxs[0] + b->mins[0]) * 0.5;
01612 float yc = (b->maxs[1] + b->mins[1]) * 0.5;
01613
01614 for ( i = 0 ; i < p->width ; i ++)
01615 {
01616 p->ctrl[i][2].xyz[0] = xc;
01617 p->ctrl[i][2].xyz[1] = yc;
01618 }
01619 }
01620
01621
01622
01623
01624
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634
01635
01636
01637
01638
01639
01640
01641
01642
01643
01644
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661
01662
01663
01664 b = AddBrushForPatch(p);
01665
01666
01667 #if 1
01668 Select_Delete();
01669 Select_Brush(b);
01670 #else
01671 if (!bCone)
01672 {
01673 Select_Delete();
01674 Select_Brush(b);
01675 GenerateEndCaps(b, bBevel, bEndcap, bInverted);
01676 eclass_t *pecNew = Eclass_ForName("func_group", false);
01677 if (pecNew)
01678 {
01679 Entity_Create(pecNew);
01680 }
01681 }
01682 else
01683 {
01684 Select_Delete();
01685 Select_Brush(b);
01686 }
01687 #endif
01688
01689 }
01690
01691
01692
01693
01694
01695
01696 brush_t* Patch_GenericMesh(int nWidth, int nHeight, int nOrientation, bool bDeleteSource, bool bOverride)
01697 {
01698 int i,j;
01699
01700 if (nHeight < 3 || nHeight > 15 || nWidth < 3 || nWidth > 15)
01701 {
01702 Sys_Printf("Invalid patch width or height.\n");
01703 return NULL;
01704 }
01705
01706 if (! bOverride && !QE_SingleBrush())
01707 {
01708 Sys_Printf("Cannot generate a patch from multiple selections.\n");
01709 return NULL;
01710 }
01711
01712
01713
01714 patchMesh_t* p = MakeNewPatch();
01715 p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
01716
01717 p->width = nWidth;
01718 p->height = nHeight;
01719 p->type = PATCH_GENERIC;
01720
01721 int nFirst = 0;
01722 int nSecond = 1;
01723 if (nOrientation == 0)
01724 {
01725 nFirst = 1;
01726 nSecond = 2;
01727 }
01728 else if (nOrientation == 1)
01729 {
01730 nSecond = 2;
01731 }
01732
01733 brush_t *b = selected_brushes.next;
01734
01735 int xStep = b->mins[nFirst];
01736 float xAdj = abs((b->maxs[nFirst] - b->mins[nFirst]) / (nWidth - 1));
01737 float yAdj = abs((b->maxs[nSecond] - b->mins[nSecond]) / (nHeight - 1));
01738
01739 for (i = 0; i < nWidth; i++)
01740 {
01741 int yStep = b->mins[nSecond];
01742 for (j = 0; j < nHeight; j++)
01743 {
01744 p->ctrl[i][j].xyz[nFirst] = xStep;
01745 p->ctrl[i][j].xyz[nSecond] = yStep;
01746 p->ctrl[i][j].xyz[nOrientation] = 0;
01747 yStep += yAdj;
01748 }
01749 xStep += xAdj;
01750 }
01751
01752 Patch_Naturalize(p);
01753
01754 b = AddBrushForPatch(p);
01755 if (bDeleteSource)
01756 {
01757 Select_Delete();
01758 Select_Brush(b);
01759 }
01760
01761 return b;
01762
01763 }
01764
01765
01766
01767
01768
01769
01770 int PointInMoveList(float *pf)
01771 {
01772 for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
01773 {
01774 if (pf == &g_qeglobals.d_move_points[i][0])
01775 return i;
01776 }
01777 return -1;
01778 }
01779
01780
01781
01782
01783
01784
01785 int PointValueInMoveList(vec3_t v)
01786 {
01787 for (int i = 0; i < g_qeglobals.d_num_move_points; i++)
01788 {
01789 if (VectorCompare(v, g_qeglobals.d_move_points[i]))
01790 return i;
01791 }
01792 return -1;
01793 }
01794
01795
01796
01797
01798
01799
01800
01801 void RemovePointFromMoveList(vec3_t v)
01802 {
01803 int n;
01804 while ( (n = PointValueInMoveList(v)) >= 0)
01805 {
01806 for (int i = n; i < g_qeglobals.d_num_move_points-1; i++)
01807 {
01808 g_qeglobals.d_move_points[i] = g_qeglobals.d_move_points[i+1];
01809 }
01810 g_qeglobals.d_num_move_points--;
01811 }
01812 }
01813
01814
01815
01816
01817
01818
01819 bool ColumnSelected(patchMesh_t* p, int nCol)
01820 {
01821 for (int i = 0; i < p->height; i++)
01822 {
01823 if (PointInMoveList(p->ctrl[nCol][i].xyz) == -1)
01824 return false;
01825 }
01826 return true;
01827 }
01828
01829
01830
01831
01832
01833
01834 void AddPoint(patchMesh_t* p, vec3_t v, bool bWeldOrDrill = true)
01835 {
01836 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
01837 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
01838 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = v;
01839 if ((g_bPatchWeld || g_bPatchDrillDown) && bWeldOrDrill)
01840 {
01841 for ( int i = 0 ; i < p->width ; i++ )
01842 {
01843 for ( int j = 0 ; j < p->height ; j++ )
01844 {
01845 if (g_bPatchWeld)
01846 {
01847 if ( VectorCompare(v, p->ctrl[i][j].xyz)
01848 && PointInMoveList(p->ctrl[i][j].xyz) == -1)
01849 {
01850 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
01851 continue;
01852 }
01853 }
01854 if (g_bPatchDrillDown && g_nPatchClickedView != W_CAMERA)
01855 {
01856 if ( (fabs(v[nDim1] - p->ctrl[i][j].xyz[nDim1]) <= EQUAL_EPSILON)
01857 &&(fabs(v[nDim2] - p->ctrl[i][j].xyz[nDim2]) <= EQUAL_EPSILON))
01858 {
01859 if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
01860 {
01861 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
01862 continue;
01863 }
01864 }
01865 #if 0
01866 int l = 0;
01867 for ( int k = 0; k < 2; k++ )
01868 {
01869 if (fabs(v[k] - p->ctrl[i][j].xyz[k]) > EQUAL_EPSILON)
01870 continue;
01871 l++;
01872 }
01873 if (l >= 2 && PointInMoveList(p->ctrl[i][j].xyz) == -1)
01874 {
01875 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
01876 continue;
01877 }
01878 #endif
01879 }
01880 }
01881 }
01882 }
01883 #if 0
01884 if (g_qeglobals.d_num_move_points == 1)
01885 {
01886
01887
01888 for ( int i = 0 ; i < p->width ; i++ )
01889 {
01890 for ( int j = 0 ; j < p->height ; j++ )
01891 {
01892 int n = PointInMoveList(v);
01893 if (n >= 0)
01894 {
01895 if (((i & 0x01) && (j & 0x01)) == 0)
01896 {
01897
01898
01899 int p1, p2, p3, p4;
01900 p1 = i + 2;
01901 p2 = i - 2;
01902 p3 = j + 2;
01903 p4 = j - 2;
01904 if (p1 < p->width)
01905 {
01906
01907 }
01908 if (p2 >= 0)
01909 {
01910 }
01911 if (p3 < p->height)
01912 {
01913 }
01914 if (p4 >= 0)
01915 {
01916 }
01917 }
01918 }
01919 }
01920 }
01921 }
01922 #endif
01923 }
01924
01925
01926
01927
01928
01929
01930 void SelectRow(patchMesh_t* p, int nRow, bool bMulti)
01931 {
01932 if (!bMulti)
01933 g_qeglobals.d_num_move_points = 0;
01934 for (int i = 0; i < p->width; i++)
01935 {
01936 AddPoint(p, p->ctrl[i][nRow].xyz, false);
01937 }
01938
01939 }
01940
01941
01942
01943
01944
01945
01946 void SelectColumn(patchMesh_t* p, int nCol, bool bMulti)
01947 {
01948 if (!bMulti)
01949 g_qeglobals.d_num_move_points = 0;
01950 for (int i = 0; i < p->height; i++)
01951 {
01952 AddPoint(p, p->ctrl[nCol][i].xyz, false);
01953 }
01954
01955 }
01956
01957
01958
01959
01960
01961
01962
01963 void AddPatchMovePoint(vec3_t v, bool bMulti, bool bFull)
01964 {
01965 if (!g_bSameView && !bMulti && !bFull)
01966 {
01967 g_bSameView = true;
01968 return;
01969 }
01970
01971 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
01972 {
01973 if (pb->patchBrush)
01974 {
01975 patchMesh_t* p = pb->pPatch;
01976 for ( int i = 0 ; i < p->width ; i++ )
01977 {
01978 for ( int j = 0 ; j < p->height ; j++ )
01979 {
01980 if (VectorCompare(v, p->ctrl[i][j].xyz))
01981 {
01982 if (PointInMoveList(p->ctrl[i][j].xyz) == -1)
01983 {
01984 if (bFull)
01985 {
01986 SelectColumn(p, i, bMulti);
01987 }
01988 else
01989 {
01990 if (!bMulti)
01991 g_qeglobals.d_num_move_points = 0;
01992 AddPoint(p, p->ctrl[i][j].xyz);
01993
01994 }
01995
01996 return;
01997 }
01998 else
01999 {
02000 if (bFull)
02001 {
02002 if (ColumnSelected(p, i))
02003 {
02004 SelectRow(p, j, bMulti);
02005 }
02006 else
02007 {
02008 SelectColumn(p, i, bMulti);
02009 }
02010 return;
02011 }
02012 if (g_bSameView)
02013 {
02014 RemovePointFromMoveList(v);
02015 return;
02016 }
02017 }
02018 }
02019 }
02020 }
02021 }
02022 }
02023 }
02024
02025
02026
02027
02028
02029
02030 void Patch_UpdateSelected(vec3_t vMove)
02031 {
02032 int i, j;
02033 for (i=0 ; i < g_qeglobals.d_num_move_points ; i++)
02034 {
02035 VectorAdd (g_qeglobals.d_move_points[i], vMove, g_qeglobals.d_move_points[i]);
02036 if (g_qeglobals.d_num_move_points == 1)
02037 {
02038 }
02039 }
02040
02041
02042 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
02043 {
02044 if (pb->patchBrush)
02045 {
02046 patchMesh_t* p = pb->pPatch;
02047
02048
02049 g_qeglobals.d_numpoints = 0;
02050 for (i = 0 ; i < p->width ; i++ )
02051 {
02052 for ( j = 0 ; j < p->height ; j++ )
02053 {
02054 VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
02055 if (g_qeglobals.d_numpoints < MAX_POINTS-1)
02056 {
02057 g_qeglobals.d_numpoints++;
02058 }
02059 }
02060 }
02061
02062 vec3_t vMin, vMax;
02063 Patch_CalcBounds(p, vMin, vMax);
02064 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
02065 }
02066 }
02067
02068
02069 }
02070
02071
02072
02073
02074
02075
02076
02077
02078 void SampleSinglePatch (float ctrl[3][3][5], float u, float v, float out[5]) {
02079 float vCtrl[3][5];
02080 int vPoint;
02081 int axis;
02082
02083
02084 for (vPoint = 0 ; vPoint < 3 ; vPoint++)
02085 {
02086 for (axis = 0 ; axis < 5 ; axis++)
02087 {
02088 float a, b, c;
02089 float qA, qB, qC;
02090
02091 a = ctrl[0][vPoint][axis];
02092 b = ctrl[1][vPoint][axis];
02093 c = ctrl[2][vPoint][axis];
02094 qA = a - 2 * b + c;
02095 qB = 2 * b - 2 * a;
02096 qC = a;
02097
02098 vCtrl[vPoint][axis] = qA * u * u + qB * u + qC;
02099 }
02100 }
02101
02102
02103 for (axis = 0 ; axis < 5 ; axis++)
02104 {
02105 float a, b, c;
02106 float qA, qB, qC;
02107
02108 a = vCtrl[0][axis];
02109 b = vCtrl[1][axis];
02110 c = vCtrl[2][axis];
02111 qA = a - 2 * b + c;
02112 qB = 2 * b - 2 * a;
02113 qC = a;
02114
02115 out[axis] = qA * v * v + qB * v + qC;
02116 }
02117 }
02118
02119
02120
02121
02122
02123
02124 void DrawSinglePatch (float ctrl[3][3][5], bool bPoints)
02125 {
02126 int i, j;
02127 float u, v;
02128 float verts[CBLOCK_SUBDIVISIONS+1][CBLOCK_SUBDIVISIONS+1][5];
02129
02130 for (i = 0 ; i <= CBLOCK_SUBDIVISIONS ; i++)
02131 {
02132 for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++)
02133 {
02134 u = (float)i / CBLOCK_SUBDIVISIONS;
02135 v = (float)j / CBLOCK_SUBDIVISIONS;
02136 SampleSinglePatch (ctrl, u, v, verts[i][j]);
02137 }
02138 }
02139
02140
02141 int nCount = -1;
02142 for (i = 0 ; i < CBLOCK_SUBDIVISIONS ; i++)
02143 {
02144 qglBegin (GL_QUAD_STRIP);
02145
02146 for (j = 0 ; j <= CBLOCK_SUBDIVISIONS ; j++)
02147 {
02148 qglTexCoord2fv( verts[i+1][j] + 3 );
02149 qglVertex3fv( verts[i+1][j] );
02150
02151
02152
02153
02154
02155
02156
02157
02158
02159
02160
02161
02162
02163
02164
02165
02166 qglTexCoord2fv( verts[i][j] + 3 );
02167 qglVertex3fv( verts[i][j] );
02168
02169
02170
02171
02172
02173
02174
02175
02176
02177
02178
02179
02180
02181 }
02182 qglEnd ();
02183 }
02184
02185 }
02186
02187
02188
02189
02190
02191
02192
02193 void DrawPatchMesh( patchMesh_t *pm, bool bPoints, bool bShade = false ) {
02194 int i, j, k, l;
02195 float ctrl[3][3][5];
02196
02197 bool bOverlay = pm->bOverlay;
02198 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
02199
02200
02201
02202
02203
02204
02205
02206 if (g_PrefsDlg.m_bDisplayLists)
02207 {
02208 if (pm->bDirty || pm->nListID <= 0)
02209 {
02210 if (pm->nListID <= 0)
02211 pm->nListID = qglGenLists(1);
02212 if (pm->nListID > 0)
02213 {
02214 qglNewList(pm->nListID, GL_COMPILE_AND_EXECUTE);
02215 }
02216
02217
02218
02219 if (pm->type != PATCH_TRIANGLE)
02220 {
02221
02222
02223
02224 if (g_PrefsDlg.m_bGLLighting)
02225 {
02226 Patch_MeshNormals(pm);
02227 for (i = 0; i < pm->width; i++)
02228 {
02229 for (j = 0; j < pm->height; j++)
02230 {
02231
02232 qglNormal3fv(pm->ctrl[i][j].normal);
02233 }
02234 }
02235 }
02236
02237 for ( i = 0 ; i + 2 < pm->width ; i += 2 )
02238 {
02239 for ( j = 0 ; j + 2 < pm->height ; j += 2 )
02240 {
02241
02242 for ( k = 0 ; k < 3 ; k++ )
02243 {
02244 vec3_t vAvg;
02245 vAvg[0] = vAvg[1] = vAvg[2] = 0;
02246 for ( l = 0 ; l < 3 ; l++ )
02247 {
02248 ctrl[k][l][0] = pm->ctrl[ i + k ][ j + l ].xyz[ 0 ];
02249 ctrl[k][l][1] = pm->ctrl[ i + k ][ j + l ].xyz[ 1 ];
02250 ctrl[k][l][2] = pm->ctrl[ i + k ][ j + l ].xyz[ 2 ];
02251 ctrl[k][l][3] = pm->ctrl[ i + k ][ j + l ].xyz[ 3 ];
02252 ctrl[k][l][4] = pm->ctrl[ i + k ][ j + l ].xyz[ 4 ];
02253
02254 if (g_PrefsDlg.m_bGLLighting)
02255 {
02256 qglNormal3fv(pm->ctrl[i+k][j+l].normal);
02257 }
02258 }
02259
02260 }
02261
02262
02263
02264
02265
02266
02267
02268
02269
02270
02271
02272
02273
02274
02275
02276
02277
02278
02279
02280 DrawSinglePatch( ctrl, bPoints );
02281 }
02282 }
02283
02284
02285
02286
02287
02288
02289
02290
02291
02292
02293
02294
02295
02296
02297
02298 }
02299 else
02300 {
02301 qglBegin (GL_TRIANGLES);
02302 qglTexCoord2fv( pm->ctrl[0][0].st);
02303 qglVertex3fv( pm->ctrl[0][0].xyz);
02304 qglTexCoord2fv( pm->ctrl[2][0].st);
02305 qglVertex3fv( pm->ctrl[2][0].xyz);
02306 qglTexCoord2fv( pm->ctrl[2][2].st);
02307 qglVertex3fv( pm->ctrl[2][2].xyz);
02308 qglEnd();
02309 }
02310
02311 if (pm->nListID > 0)
02312 {
02313 qglEndList();
02314 pm->bDirty = false;
02315 }
02316 }
02317 else
02318 {
02319 qglCallList(pm->nListID);
02320 }
02321 }
02322 else
02323 {
02324 for ( i = 0 ; i + 2 < pm->width ; i += 2 )
02325 {
02326 for ( j = 0 ; j + 2 < pm->height ; j += 2 )
02327 {
02328 for ( k = 0 ; k < 3 ; k++ )
02329 {
02330 for ( l = 0 ; l < 3 ; l++ )
02331 {
02332 ctrl[k][l][0] = pm->ctrl[ i + k ][ j + l ].xyz[ 0 ];
02333 ctrl[k][l][1] = pm->ctrl[ i + k ][ j + l ].xyz[ 1 ];
02334 ctrl[k][l][2] = pm->ctrl[ i + k ][ j + l ].xyz[ 2 ];
02335 ctrl[k][l][3] = pm->ctrl[ i + k ][ j + l ].xyz[ 3 ];
02336 ctrl[k][l][4] = pm->ctrl[ i + k ][ j + l ].xyz[ 4 ];
02337 }
02338 }
02339
02340
02341
02342
02343 DrawSinglePatch( ctrl, bPoints );
02344 }
02345 }
02346 }
02347
02348 vec3_t* pSelectedPoints[256];
02349 int nIndex = 0;
02350
02351 qglPushAttrib(GL_CURRENT_BIT);
02352
02353
02354
02355
02356 bool bDisabledLighting = qglIsEnabled(GL_LIGHTING);
02357 if (bDisabledLighting)
02358 {
02359 qglDisable(GL_LIGHTING);
02360 }
02361
02362
02363
02364 if (bPoints && (g_qeglobals.d_select_mode == sel_curvepoint || g_qeglobals.d_select_mode == sel_area || g_bPatchBendMode || g_bPatchInsertMode))
02365 {
02366 bOverlay = false;
02367
02368
02369 if (g_bPatchBendMode || g_bPatchInsertMode)
02370 {
02371 qglPointSize(6);
02372 if (g_bPatchAxisOnRow)
02373 {
02374 qglColor3f(1, 0, 1);
02375 qglBegin(GL_POINTS);
02376 for (i = 0; i < pm->width; i++)
02377 {
02378 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex].xyz));
02379 }
02380 qglEnd();
02381
02382
02383 if (g_bPatchInsertMode)
02384 {
02385 qglColor3f(0, 0, 1);
02386 qglBegin(GL_POINTS);
02387 for (i = 0; i < pm->width; i++)
02388 {
02389 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex].xyz));
02390 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][g_nPatchAxisIndex+1].xyz));
02391 }
02392 qglEnd();
02393 }
02394 else
02395 {
02396 if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
02397 {
02398 qglColor3f(0, 0, 1);
02399 qglBegin(GL_POINTS);
02400 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
02401 {
02402 qglVertex3fv(g_vBendOrigin);
02403 }
02404 else
02405 {
02406 for (i = 0; i < pm->width; i++)
02407 {
02408 if (g_bPatchLowerEdge)
02409 {
02410 for (j = 0; j < g_nPatchAxisIndex; j++)
02411 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][j].xyz));
02412 }
02413 else
02414 {
02415 for (j = pm->height-1; j > g_nPatchAxisIndex; j--)
02416 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[i][j].xyz));
02417 }
02418 }
02419 }
02420 qglEnd();
02421 }
02422 }
02423 }
02424 else
02425 {
02426 qglColor3f(1, 0, 1);
02427 qglBegin(GL_POINTS);
02428 for (i = 0; i < pm->height; i++)
02429 {
02430 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex][i].xyz));
02431 }
02432 qglEnd();
02433
02434
02435 if (g_bPatchInsertMode)
02436 {
02437 qglColor3f(0, 0, 1);
02438 qglBegin(GL_POINTS);
02439 for (i = 0; i < pm->height; i++)
02440 {
02441 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex][i].xyz));
02442 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nPatchAxisIndex+1][i].xyz));
02443 }
02444 qglEnd();
02445 }
02446 else
02447 {
02448 if (g_nPatchBendState == BEND_SELECT_EDGE || g_nPatchBendState == BEND_BENDIT || g_nPatchBendState == BEND_SELECT_ORIGIN)
02449 {
02450 qglColor3f(0, 0, 1);
02451 qglBegin(GL_POINTS);
02452 for (i = 0; i < pm->height; i++)
02453 {
02454 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
02455 {
02456 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[g_nBendOriginIndex][i].xyz));
02457 }
02458 else
02459 {
02460 if (g_bPatchLowerEdge)
02461 {
02462 for (j = 0; j < g_nPatchAxisIndex; j++)
02463 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[j][i].xyz));
02464 }
02465 else
02466 {
02467 for (j = pm->width-1; j > g_nPatchAxisIndex; j--)
02468 qglVertex3fv(reinterpret_cast<float(*)>(&pm->ctrl[j][i].xyz));
02469 }
02470 }
02471 }
02472 qglEnd();
02473 }
02474 }
02475 }
02476 }
02477 else
02478 {
02479 qglPointSize(6);
02480 for ( i = 0 ; i < pm->width ; i++ )
02481 {
02482 for ( j = 0 ; j < pm->height ; j++ )
02483 {
02484 qglBegin(GL_POINTS);
02485
02486 int n = PointValueInMoveList(pm->ctrl[i][j].xyz);
02487 if (n >= 0)
02488 {
02489 pSelectedPoints[nIndex++] = reinterpret_cast<float(*)[3]>(&pm->ctrl[i][j].xyz);
02490 }
02491
02492 if (i & 0x01 || j & 0x01)
02493 qglColor3f(1, 0, 1);
02494 else
02495 qglColor3f(0, 1, 0);
02496 qglVertex3fv(pm->ctrl[i][j].xyz);
02497 qglEnd();
02498 }
02499 }
02500 }
02501 if (nIndex > 0)
02502 {
02503 qglBegin(GL_POINTS);
02504 qglColor3f(0, 0, 1);
02505 while (nIndex-- > 0)
02506 {
02507 qglVertex3fv(*pSelectedPoints[nIndex]);
02508 }
02509 qglEnd();
02510 }
02511 }
02512
02513 if (bOverlay)
02514 {
02515 qglPointSize(6);
02516 qglColor3f(0.5, 0.5, 0.5);
02517 for ( i = 0 ; i < pm->width ; i++ )
02518 {
02519 qglBegin(GL_POINTS);
02520 for ( j = 0 ; j < pm->height ; j++ )
02521 {
02522 if (i & 0x01 || j & 0x01)
02523 qglColor3f(0.5, 0, 0.5);
02524 else
02525 qglColor3f(0, 0.5, 0);
02526 qglVertex3fv(pm->ctrl[i][j].xyz);
02527 }
02528 qglEnd();
02529 }
02530 }
02531
02532
02533
02534 if (bDisabledLighting)
02535 {
02536 qglEnable(GL_LIGHTING);
02537 }
02538
02539 qglPopAttrib();
02540
02541 }
02542
02543
02544
02545
02546
02547
02548 void Patch_DrawXY(patchMesh_t *pm)
02549 {
02550 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02551 if (pm->bSelected)
02552 {
02553 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES]);
02554
02555
02556 }
02557 else
02558 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_BRUSHES]);
02559
02560 DrawPatchMesh( pm , pm->bSelected );
02561 qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
02562 if (pm->bSelected)
02563 {
02564
02565
02566 }
02567 }
02568
02569
02570
02571
02572
02573
02574 void Patch_DrawCam(patchMesh_t *pm)
02575 {
02576 qglColor3f (1,1,1);
02577 qglPushAttrib(GL_ALL_ATTRIB_BITS);
02578
02579 if (g_bPatchWireFrame)
02580 {
02581 qglDisable( GL_CULL_FACE );
02582 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02583 qglDisable(GL_TEXTURE_2D);
02584 if (g_PrefsDlg.m_bGLLighting)
02585 {
02586 qglDisable(GL_LIGHTING);
02587 }
02588 DrawPatchMesh( pm , pm->bSelected, true );
02589 if (g_PrefsDlg.m_bGLLighting)
02590 {
02591 qglEnable(GL_LIGHTING);
02592 }
02593 qglEnable( GL_CULL_FACE );
02594 }
02595 else
02596 {
02597 if (g_PrefsDlg.m_bGLLighting)
02598 {
02599
02600 }
02601 qglEnable( GL_CULL_FACE );
02602 qglCullFace(GL_FRONT);
02603 qglBindTexture (GL_TEXTURE_2D, pm->d_texture->texture_number);
02604
02605 if (pm->d_texture->bFromShader && pm->d_texture->fTrans < 1.0)
02606 {
02607
02608
02609 qglColor4f(pm->d_texture->color[0], pm->d_texture->color[1], pm->d_texture->color[2], pm->d_texture->fTrans);
02610 }
02611 DrawPatchMesh( pm , pm->bSelected, true );
02612
02613 qglCullFace(GL_BACK);
02614
02615 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
02616
02617 qglDisable ( GL_BLEND );
02618 DrawPatchMesh( pm , pm->bSelected, true );
02619 }
02620
02621 #if 0 // this paints normal indicators on the ctrl points
02622
02623 qglDisable (GL_TEXTURE_2D);
02624 qglColor3f (1,1,1);
02625
02626 for (int i = 0; i < pm->width; i++)
02627 {
02628 for (int j = 0; j < pm->height; j++)
02629 {
02630 vec3_t temp;
02631 qglBegin (GL_LINES);
02632 qglVertex3fv (pm->ctrl[i][j].xyz);
02633 VectorMA (pm->ctrl[i][j].xyz, 8, pm->ctrl[i][j].normal, temp);
02634 qglVertex3fv (temp);
02635 qglEnd ();
02636 }
02637 }
02638 qglEnable (GL_TEXTURE_2D);
02639
02640 #endif
02641
02642
02643 qglPopAttrib();
02644 }
02645
02646
02647
02648
02649 void ConvexHullForSection( float section[2][4][7] ) {
02650 }
02651
02652 void BrushesForSection( float section[2][4][7] ) {
02653 }
02654
02655
02656
02657
02658
02659 void Patch_BuildPoints (brush_t *b)
02660 {
02661 face_t *f;
02662 b->patchBrush = false;
02663 for (f=b->brush_faces ; f ; f=f->next)
02664 {
02665 if (f->texdef.flags & SURF_PATCH)
02666 {
02667 b->patchBrush = true;
02668
02669
02670
02671
02672 break;
02673 }
02674 }
02675 }
02676
02677
02678
02679
02680
02681
02682
02683
02684 #if 0
02685 void Patch_WriteFile (char *name)
02686 {
02687 char patchName[1024];
02688 time_t ltime;
02689 strcpy(patchName, name);
02690 StripExtension (patchName);
02691 strcat (patchName, ".patch");
02692
02693 FILE *file = fopen(patchName, "w");
02694 if (file)
02695 {
02696 time(<ime);
02697 fprintf (file, "// %s saved on %s\n", name, ctime(<ime) );
02698
02699 for (int i = 0; i < numPatchMeshes; i++)
02700 {
02701 fprintf(file, "{\n");
02702 fprintf(file, " %s\n", patchMeshes[i].d_texture->name);
02703 fprintf(file, " ( %i %i %i ) \n", patchMeshes[i].width, patchMeshes[i].height, patchMeshes[i].negative);
02704 for (int w = 0; w < patchMeshes[i].width; w++)
02705 {
02706 for (int h = 0; h < patchMeshes[i].height; h++)
02707 {
02708 fprintf(file, " ( ");
02709 for (int k = 0; k < 5; k++)
02710 {
02711 float f = patchMeshes[i].ctrl[w][h][k];
02712 if (f == int(f))
02713 fprintf(file, "%i ", (int)f);
02714 else
02715 fprintf(file, "%f ", f);
02716 }
02717 fprintf(file, ")\n");
02718 }
02719 }
02720 fprintf(file, "}\n");
02721 }
02722 fclose(file);
02723 }
02724 }
02725 #endif
02726
02727
02728
02729
02730
02731
02732 void Patch_Move(patchMesh_t *pm, const vec3_t vMove, bool bRebuild)
02733 {
02734 pm->bDirty = true;
02735 for (int w = 0; w < pm->width; w++)
02736 {
02737 for (int h = 0; h < pm->height; h++)
02738 {
02739 VectorAdd(pm->ctrl[w][h].xyz, vMove, pm->ctrl[w][h].xyz);
02740 }
02741 }
02742 if (bRebuild)
02743 {
02744 vec3_t vMin, vMax;
02745 Patch_CalcBounds(pm, vMin, vMax);
02746
02747 }
02748 UpdatePatchInspector();
02749
02750 }
02751
02752
02753
02754
02755
02756
02757 void Patch_ApplyMatrix(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vMatrix[3], bool bSnap)
02758 {
02759 vec3_t vTemp;
02760
02761 for (int w = 0; w < p->width; w++)
02762 {
02763 for (int h = 0; h < p->height; h++)
02764 {
02765 if ( (g_qeglobals.d_select_mode == sel_curvepoint || g_bPatchBendMode)
02766 && PointInMoveList(p->ctrl[w][h].xyz) == -1)
02767 continue;
02768 VectorSubtract (p->ctrl[w][h].xyz, vOrigin, vTemp);
02769 for (int j = 0; j < 3; j++)
02770 {
02771 p->ctrl[w][h].xyz[j] = DotProduct(vTemp, vMatrix[j]) + vOrigin[j];
02772 if (bSnap)
02773 {
02774 p->ctrl[w][h].xyz[j] = floor(p->ctrl[w][h].xyz[j] + 0.5);
02775 }
02776 }
02777 }
02778 }
02779 vec3_t vMin, vMax;
02780 Patch_CalcBounds(p, vMin, vMax);
02781 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
02782 }
02783
02784
02785
02786
02787
02788
02789 void Patch_EditPatch()
02790 {
02791
02792 g_qeglobals.d_numpoints = 0;
02793 g_qeglobals.d_num_move_points = 0;
02794
02795 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
02796 {
02797 if (pb->patchBrush)
02798 {
02799 patchMesh_t* p = pb->pPatch;
02800 for ( int i = 0 ; i < p->width ; i++ )
02801 {
02802 for ( int j = 0 ; j < p->height ; j++ )
02803 {
02804 VectorCopy (p->ctrl[i][j].xyz, g_qeglobals.d_points[g_qeglobals.d_numpoints]);
02805 if (g_qeglobals.d_numpoints < MAX_POINTS-1)
02806 {
02807 g_qeglobals.d_numpoints++;
02808 }
02809 }
02810 }
02811 }
02812 }
02813 g_qeglobals.d_select_mode = sel_curvepoint;
02814
02815 }
02816
02817
02818
02819
02820
02821
02822
02823
02824
02825 void Patch_Deselect()
02826 {
02827
02828 clearSelection();
02829
02830 for (brush_t *b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
02831 {
02832 if (b->patchBrush)
02833 {
02834 b->pPatch->bSelected = false;
02835 }
02836 }
02837
02838
02839
02840
02841 if (g_bPatchBendMode)
02842 Patch_BendToggle();
02843 if (g_bPatchInsertMode)
02844 Patch_InsDelToggle();
02845 }
02846
02847
02848
02849
02850
02851
02852
02853 void Patch_Select(patchMesh_t *p)
02854 {
02855
02856
02857
02858 p->bSelected = true;
02859 }
02860
02861
02862
02863
02864
02865
02866
02867 void Patch_Deselect(patchMesh_t *p)
02868 {
02869 p->bSelected = false;
02870 }
02871
02872
02873
02874
02875
02876
02877
02878 void Patch_Delete(patchMesh_t *p)
02879 {
02880 p->pSymbiot->pPatch = NULL;
02881 p->pSymbiot->patchBrush = false;
02882 if (g_qeglobals.bSurfacePropertiesPlugin)
02883 {
02884 #ifdef _DEBUG
02885 if (!p->pData)
02886 Sys_Printf("WARNING: unexpected IPluginTexdef* is NULL in Patch_Delete\n");
02887 else
02888 #endif
02889 {
02890 GETPLUGINTEXDEF(p)->DecRef();
02891 p->pData = NULL;
02892 }
02893 }
02894 free(p);
02895 p = NULL;
02896
02897
02898
02899
02900
02901
02902
02903
02904 UpdatePatchInspector();
02905 }
02906
02907
02908
02909
02910
02911
02912
02913 void Patch_Scale(patchMesh_t *p, const vec3_t vOrigin, const vec3_t vAmt, bool bRebuild)
02914 {
02915
02916 for (int w = 0; w < p->width; w++)
02917 {
02918 for (int h = 0; h < p->height; h++)
02919 {
02920 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
02921 continue;
02922 for (int i=0 ; i<3 ; i++)
02923 {
02924 p->ctrl[w][h].xyz[i] -= vOrigin[i];
02925 p->ctrl[w][h].xyz[i] *= vAmt[i];
02926 p->ctrl[w][h].xyz[i] += vOrigin[i];
02927 }
02928 }
02929 }
02930 if (bRebuild)
02931 {
02932 vec3_t vMin, vMax;
02933 Patch_CalcBounds(p, vMin, vMax);
02934 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
02935 }
02936 UpdatePatchInspector();
02937 }
02938
02939
02940
02941
02942
02943
02944
02945 void Patch_Cleanup()
02946 {
02947
02948
02949 }
02950
02951
02952
02953
02954
02955
02956
02957
02958 void Patch_SetView(int n)
02959 {
02960 g_bSameView = (n == g_nPatchClickedView);
02961 g_nPatchClickedView = n;
02962 }
02963
02964
02965
02966
02967
02968
02969
02970
02971 void Patch_SetTexture(patchMesh_t *p, texdef_t *tex_def, IPluginTexdef* pPlugTexdef)
02972 {
02973 p->d_texture = Texture_ForName(tex_def->name);
02974 if (g_qeglobals.bSurfacePropertiesPlugin)
02975 {
02976 #ifdef _DEBUG
02977 if (!p->pData)
02978 Sys_Printf("WARNING: unexpected p->pData is NULL in Patch_SetTexture\n");
02979 else
02980 #endif
02981 GETPLUGINTEXDEF(p)->DecRef();
02982 if (pPlugTexdef)
02983 {
02984 p->pData = pPlugTexdef->Copy();
02985 GETPLUGINTEXDEF(p)->Hook(p);
02986 }
02987 else
02988 {
02989 g_SurfaceTable.m_pfnPatchAlloc( p );
02990 GETPLUGINTEXDEF(p)->SetDefaultTexdef();
02991 }
02992 }
02993 UpdatePatchInspector();
02994 }
02995
02996
02997
02998
02999
03000
03001
03002 bool Patch_DragScale(patchMesh_t *p, vec3_t vAmt, vec3_t vMove)
03003 {
03004 vec3_t vMin, vMax, vScale, vTemp, vMid;
03005 int i;
03006
03007 Patch_CalcBounds(p, vMin, vMax);
03008
03009 VectorSubtract(vMax, vMin, vTemp);
03010
03011
03012 for (i = 0; i < 3; i ++)
03013 {
03014 if (vTemp[i] == 0 && vMove[i] != 0)
03015 {
03016
03017 return false;
03018 }
03019 }
03020
03021 for (i=0 ; i<3 ; i++)
03022 vMid[i] = (vMin[i] + ((vMax[i] - vMin[i]) / 2));
03023
03024 for (i = 0; i < 3; i++)
03025 {
03026 if (vAmt[i] != 0)
03027 {
03028 vScale[i] = 1.0 + vAmt[i] / vTemp[i];
03029 }
03030 else
03031 {
03032 vScale[i] = 1.0;
03033 }
03034 }
03035
03036 Patch_Scale(p, vMid, vScale, false);
03037
03038 VectorSubtract(vMax, vMin, vTemp);
03039
03040 Patch_CalcBounds(p, vMin, vMax);
03041
03042 VectorSubtract(vMax, vMin, vMid);
03043
03044 VectorSubtract(vMid, vTemp, vTemp);
03045
03046 VectorScale(vTemp, 0.5, vTemp);
03047
03048
03049 if (!VectorCompare(vMove, vAmt))
03050 {
03051 for (i = 0; i < 3; i++)
03052 {
03053 if (vMove[i] != vAmt[i])
03054 vTemp[i] = -(vTemp[i]);
03055 }
03056 }
03057
03058 Patch_Move(p, vTemp);
03059 return true;
03060 }
03061
03062
03063
03064
03065
03066
03067
03068 void Patch_AddRow(patchMesh_t *p)
03069 {
03070 vec3_t vMin, vMax, vTemp;
03071 int i, j;
03072
03073
03074 if (p->height+2 < MAX_PATCH_HEIGHT)
03075 {
03076 Patch_CalcBounds(p, vMin, vMax);
03077 VectorSubtract(vMax, vMin, vTemp);
03078 for (i = 0; i < 3; i++)
03079 {
03080 vTemp[i] /= p->height + 2;
03081 }
03082
03083 for (j = 0; j < p->width; j++)
03084 {
03085 VectorCopy(p->ctrl[j][p->height].xyz, p->ctrl[j][p->height+1].xyz);
03086 VectorCopy(p->ctrl[j][p->height].xyz, p->ctrl[j][p->height+2].xyz);
03087 p->height += 2;
03088 i = 1;
03089 while (i < p->height)
03090 {
03091 VectorAdd(p->ctrl[j][i].xyz, vTemp, p->ctrl[j][i].xyz);
03092 i++;
03093 }
03094 }
03095
03096 Patch_CalcBounds(p, vMin, vMax);
03097 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
03098 }
03099 UpdatePatchInspector();
03100 }
03101
03102
03103
03104
03105
03106
03107 void Patch_InsertColumn(patchMesh_t *p, bool bAdd)
03108 {
03109 int h, w, i, j;
03110 vec3_t vTemp;
03111
03112 if (p->width + 2 >= MAX_PATCH_WIDTH)
03113 return;
03114
03115 if (bAdd)
03116 {
03117 for (h = 0; h < p->height; h++)
03118 {
03119 j = p->width-1;
03120 VectorSubtract(p->ctrl[j][h].xyz, p->ctrl[j-1][h].xyz, vTemp);
03121 for (i = 0; i < 3; i++)
03122 vTemp[i] /= 3;
03123
03124 memcpy(&p->ctrl[j+2][h],&p->ctrl[j][h], sizeof(drawVert_t));
03125 memcpy(&p->ctrl[j][h],&p->ctrl[j-1][h], sizeof(drawVert_t));
03126
03127 VectorAdd(p->ctrl[j][h].xyz, vTemp, p->ctrl[j][h].xyz);
03128 memcpy(&p->ctrl[j+1][h], &p->ctrl[j][h], sizeof(drawVert_t));
03129 VectorAdd(p->ctrl[j+1][h].xyz, vTemp, p->ctrl[j+1][h].xyz);
03130 }
03131 }
03132 else
03133 {
03134 for (h = 0; h < p->height; h++)
03135 {
03136 w = p->width-1;
03137 while (w >= 0)
03138 {
03139 memcpy(&p->ctrl[w+2][h],&p->ctrl[w][h], sizeof(drawVert_t));
03140 w--;
03141 }
03142 VectorSubtract(p->ctrl[1][h].xyz, p->ctrl[0][h].xyz, vTemp);
03143 for (i = 0; i < 3; i++)
03144 vTemp[i] /= 3;
03145 VectorCopy(p->ctrl[0][h].xyz, p->ctrl[1][h].xyz);
03146 VectorAdd(p->ctrl[1][h].xyz, vTemp, p->ctrl[1][h].xyz);
03147 VectorCopy(p->ctrl[1][h].xyz, p->ctrl[2][h].xyz);
03148 VectorAdd(p->ctrl[2][h].xyz, vTemp, p->ctrl[2][h].xyz);
03149 }
03150 }
03151 p->width += 2;
03152 UpdatePatchInspector();
03153 }
03154
03155
03156
03157
03158
03159
03160
03161 void Patch_InsertRow(patchMesh_t *p, bool bAdd)
03162 {
03163 int h, w, i, j;
03164 vec3_t vTemp;
03165
03166 if (p->height + 2 >= MAX_PATCH_HEIGHT)
03167 return;
03168
03169 if (bAdd)
03170 {
03171 for (w = 0; w < p->width; w++)
03172 {
03173 j = p->height-1;
03174 VectorSubtract(p->ctrl[w][j].xyz, p->ctrl[w][j-1].xyz, vTemp);
03175 for (i = 0; i < 3; i++)
03176 vTemp[i] /= 3;
03177
03178 memcpy(&p->ctrl[w][j+2],&p->ctrl[w][j], sizeof(drawVert_t));
03179 memcpy(&p->ctrl[w][j],&p->ctrl[w][j-1], sizeof(drawVert_t));
03180
03181 VectorAdd(p->ctrl[w][j].xyz, vTemp, p->ctrl[w][j].xyz);
03182 memcpy(&p->ctrl[w][j+1], &p->ctrl[w][j], sizeof(drawVert_t));
03183 VectorAdd(p->ctrl[w][j+1].xyz, vTemp, p->ctrl[w][j+1].xyz);
03184 }
03185 }
03186 else
03187 {
03188 for (w = 0; w < p->width; w++)
03189 {
03190 h = p->height-1;
03191 while (h >= 0)
03192 {
03193 memcpy(&p->ctrl[w][h+2],&p->ctrl[w][h], sizeof(drawVert_t));
03194 h--;
03195 }
03196 VectorSubtract(p->ctrl[w][1].xyz, p->ctrl[w][0].xyz, vTemp);
03197 for (i = 0; i < 3; i++)
03198 vTemp[i] /= 3;
03199 VectorCopy(p->ctrl[w][0].xyz, p->ctrl[w][1].xyz);
03200 VectorAdd(p->ctrl[w][1].xyz, vTemp, p->ctrl[w][1].xyz);
03201 VectorCopy(p->ctrl[w][1].xyz, p->ctrl[w][2].xyz);
03202 VectorAdd(p->ctrl[w][2].xyz, vTemp, p->ctrl[w][2].xyz);
03203 }
03204 }
03205 p->height += 2;
03206 UpdatePatchInspector();
03207 }
03208
03209
03210
03211
03212
03213
03214
03215 void Patch_RemoveRow(patchMesh_t *p, bool bFirst)
03216 {
03217
03218 if (p->height <= MIN_PATCH_HEIGHT)
03219 return;
03220
03221 p->height -= 2;
03222
03223 if (bFirst)
03224 {
03225 for (int w = 0; w < p->width; w++)
03226 {
03227 for (int h = 0; h < p->height; h++)
03228 {
03229 memcpy(&p->ctrl[w][h], &p->ctrl[w][h+2], sizeof(drawVert_t));
03230 }
03231 }
03232 }
03233 UpdatePatchInspector();
03234 }
03235
03236
03237
03238
03239
03240
03241
03242 void Patch_RemoveColumn(patchMesh_t *p, bool bFirst)
03243 {
03244
03245 if (p->width <= MIN_PATCH_WIDTH)
03246 return;
03247
03248 p->width -= 2;
03249
03250 if (bFirst)
03251 {
03252 for (int h = 0; h < p->height; h++)
03253 {
03254 for (int w = 0; w < p->width; w++)
03255 {
03256 memcpy(&p->ctrl[w][h], &p->ctrl[w+2][h], sizeof(drawVert_t));
03257 }
03258 }
03259 }
03260 UpdatePatchInspector();
03261 }
03262
03263
03264
03265
03266
03267
03268
03269 void Patch_AdjustColumns(patchMesh_t *p, int nCols)
03270 {
03271 vec3_t vTemp, vTemp2;
03272 int i, w, h;
03273
03274 if (nCols & 0x01 || p->width + nCols < 3 || p->width + nCols > MAX_PATCH_WIDTH)
03275 return;
03276
03277
03278 p->width += nCols;
03279
03280 for (h = 0; h < p->height; h++)
03281 {
03282
03283
03284
03285
03286 VectorSubtract(p->ctrl[p->width - 1 - nCols][h].xyz, p->ctrl[0][h].xyz, vTemp);
03287
03288
03289 for (i = 0; i < 3; i ++)
03290 {
03291 vTemp2[i] = vTemp[i] / (p->width - 1);
03292 }
03293
03294
03295 for (w = 0; w < p->width-1; w++)
03296 {
03297 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
03298 }
03299
03300 }
03301 for ( w = 0 ; w < p->width ; w++ )
03302 {
03303 for ( h = 0 ; h < p->height ; h++ )
03304 {
03305 p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
03306 p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
03307 }
03308 }
03309 UpdatePatchInspector();
03310 }
03311
03312
03313
03314
03315
03316
03317
03318 void Patch_AdjustRows(patchMesh_t *p, int nRows)
03319 {
03320 vec3_t vTemp, vTemp2;
03321 int i, w, h;
03322
03323 if (nRows & 0x01 || p->height + nRows < 3 || p->height + nRows > MAX_PATCH_HEIGHT)
03324 return;
03325
03326
03327 p->height += nRows;
03328
03329 for (w = 0; w < p->width; w++)
03330 {
03331
03332
03333
03334
03335 VectorSubtract(p->ctrl[w][p->height - 1 - nRows].xyz, p->ctrl[w][0].xyz, vTemp);
03336
03337
03338
03339
03340
03341
03342
03343
03344 for (i = 0; i < 3; i ++)
03345 {
03346 vTemp2[i] = vTemp[i] / (p->height - 1);
03347 }
03348
03349
03350 for (h = 0; h < p->height-1; h++)
03351 {
03352 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
03353 }
03354
03355 }
03356 for ( w = 0 ; w < p->width ; w++ )
03357 {
03358 for ( h = 0 ; h < p->height ; h++ )
03359 {
03360 p->ctrl[w][h].st[0] = 4 * (float)w / (p->width - 1);
03361 p->ctrl[w][h].st[1] = 4 * (float)h / (p->height - 1);
03362 }
03363 }
03364 UpdatePatchInspector();
03365 }
03366
03367
03368 void Patch_DisperseRows()
03369 {
03370 vec3_t vTemp, vTemp2;
03371 int i, w, h;
03372
03373
03374 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03375 {
03376 if (pb->patchBrush)
03377 {
03378 patchMesh_t *p = pb->pPatch;
03379 Patch_Rebuild(p);
03380 for (w = 0; w < p->width; w++)
03381 {
03382
03383
03384
03385
03386 VectorSubtract(p->ctrl[w][p->height - 1].xyz, p->ctrl[w][0].xyz, vTemp);
03387
03388
03389
03390
03391
03392
03393
03394
03395 for (i = 0; i < 3; i ++)
03396 {
03397 vTemp2[i] = vTemp[i] / (p->height - 1);
03398 }
03399
03400
03401 for (h = 0; h < p->height-1; h++)
03402 {
03403 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w][h+1].xyz);
03404 }
03405 Patch_Naturalize(p);
03406
03407 }
03408 }
03409 }
03410 UpdatePatchInspector();
03411
03412 }
03413
03414
03415
03416
03417
03418
03419 void Patch_DisperseColumns()
03420 {
03421 vec3_t vTemp, vTemp2;
03422 int i, w, h;
03423
03424 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03425 {
03426 if (pb->patchBrush)
03427 {
03428 patchMesh_t *p = pb->pPatch;
03429 Patch_Rebuild(p);
03430
03431 for (h = 0; h < p->height; h++)
03432 {
03433
03434
03435
03436
03437 VectorSubtract(p->ctrl[p->width - 1][h].xyz, p->ctrl[0][h].xyz, vTemp);
03438
03439
03440 for (i = 0; i < 3; i ++)
03441 {
03442 vTemp2[i] = vTemp[i] / (p->width - 1);
03443 }
03444
03445
03446 for (w = 0; w < p->width-1; w++)
03447 {
03448 VectorAdd(p->ctrl[w][h].xyz, vTemp2, p->ctrl[w+1][h].xyz);
03449 }
03450
03451 }
03452 Patch_Naturalize(p);
03453 }
03454 }
03455 UpdatePatchInspector();
03456 }
03457
03458
03459
03460
03461
03462
03463
03464
03465 void Patch_AdjustSelected(bool bInsert, bool bColumn, bool bFlag)
03466 {
03467 bool bUpdate = false;
03468 for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03469 {
03470 if (pb->patchBrush)
03471 {
03472 if (bInsert)
03473 {
03474 if (bColumn)
03475 {
03476 Patch_InsertColumn(pb->pPatch, bFlag);
03477 }
03478 else
03479 {
03480 Patch_InsertRow(pb->pPatch, bFlag);
03481 }
03482 }
03483 else
03484 {
03485 if (bColumn)
03486 {
03487 Patch_RemoveColumn(pb->pPatch, bFlag);
03488 }
03489 else
03490 {
03491 Patch_RemoveRow(pb->pPatch, bFlag);
03492 }
03493 }
03494 bUpdate = true;
03495 vec3_t vMin, vMax;
03496 patchMesh_t *p = pb->pPatch;
03497 Patch_CalcBounds(p, vMin, vMax);
03498 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
03499 }
03500 }
03501 if (bUpdate)
03502 {
03503 Sys_UpdateWindows(W_ALL);
03504 }
03505 }
03506
03507
03508
03509
03510
03511
03512
03513 void Patch_AdjustSelectedRowCols(int nRows, int nCols)
03514 {
03515 for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03516 {
03517 if (pb->patchBrush)
03518 {
03519 Patch_InsertColumn(pb->pPatch, false);
03520 if (nRows != 0)
03521 {
03522 Patch_AdjustRows(pb->pPatch, nRows);
03523 }
03524
03525 if (nCols != 0)
03526 {
03527 Patch_AdjustColumns(pb->pPatch, nCols);
03528 }
03529 }
03530 }
03531 UpdatePatchInspector();
03532 }
03533
03534
03535
03536 void Parse1DMatrix(int x, float* p)
03537 {
03538 GetToken(true);
03539 for (int i = 0; i < x; i++)
03540 {
03541 GetToken(false);
03542 p[i] = atof(token);
03543 }
03544 GetToken(true);
03545 }
03546
03547 void Parse2DMatrix(int y, int x, float* p)
03548 {
03549 GetToken(true);
03550 for (int i = 0; i < y; i++)
03551 {
03552 Parse1DMatrix(x, p + i*x);
03553 }
03554 GetToken(true);
03555 }
03556
03557 void Parse3DMatrix(int z, int y, int x, float* p)
03558 {
03559 GetToken(true);
03560 for (int i = 0; i < z; i++)
03561 {
03562 Parse2DMatrix(y, x, p + i*(x*MAX_PATCH_HEIGHT));
03563 }
03564 GetToken(true);
03565 }
03566
03567
03568 brush_t* Patch_Parse(bool bOld)
03569 {
03570
03571
03572
03573
03574
03575 GetToken(true);
03576
03577 if (strcmp(token, "{"))
03578 return NULL;
03579
03580 patchMesh_t *pm = MakeNewPatch();
03581
03582 if (g_qeglobals.bSurfacePropertiesPlugin)
03583 {
03584 GETPLUGINTEXDEF(pm)->ParsePatchTexdef();
03585 }
03586 else
03587 {
03588
03589 GetToken(true);
03590
03591
03592 if (strcmp(token, "("))
03593 {
03594 pm->d_texture = Texture_ForName(token);
03595 GetToken(true);
03596 }
03597 else
03598 {
03599 pm->d_texture = notexture;
03600 Sys_Printf("Warning: Patch read with no texture, using notexture... \n");
03601 }
03602
03603 if (strcmp(token, "("))
03604 return NULL;
03605
03606
03607 GetToken(false);
03608 pm->width = atoi(token);
03609
03610 GetToken(false);
03611 pm->height = atoi(token);
03612
03613 GetToken(false);
03614 pm->contents = atoi(token);
03615
03616 GetToken(false);
03617 pm->flags = atoi(token);
03618
03619 GetToken(false);
03620 pm->value = atoi(token);
03621
03622 if (!bOld)
03623 {
03624 GetToken(false);
03625 pm->type = atoi(token);
03626 }
03627
03628 GetToken(false);
03629 if (strcmp(token, ")"))
03630 return NULL;
03631
03632 }
03633
03634
03635
03636 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
03637 Parse3DMatrix(pm->width, pm->height, 5, reinterpret_cast<float*>(&ctrl));
03638
03639 int w, h;
03640
03641 for (w = 0; w < pm->width; w++)
03642 {
03643 for (h = 0; h < pm->height; h++)
03644 {
03645 pm->ctrl[w][h].xyz[0] = ctrl[w][h][0];
03646 pm->ctrl[w][h].xyz[1] = ctrl[w][h][1];
03647 pm->ctrl[w][h].xyz[2] = ctrl[w][h][2];
03648 pm->ctrl[w][h].st[0] = ctrl[w][h][3];
03649 pm->ctrl[w][h].st[1] = ctrl[w][h][4];
03650 }
03651 }
03652
03653 GetToken(true);
03654
03655 if (g_qeglobals.m_bBrushPrimitMode)
03656 {
03657
03658 if (strcmp(token, "}") && strcmp (token, "(") )
03659 {
03660 epair_t *ep = ParseEpair();
03661 ep->next = pm->epairs;
03662 pm->epairs = ep;
03663 GetToken(true);
03664 }
03665 }
03666
03667 if (strcmp(token, "}"))
03668 return NULL;
03669
03670 brush_t *b = AddBrushForPatch(pm, false);
03671
03672 return b;
03673 }
03674
03675
03676
03677
03678
03679
03680
03681 void Patch_Write (patchMesh_t *p, CMemFile *file)
03682 {
03683 if (g_qeglobals.bSurfacePropertiesPlugin)
03684 {
03685 Sys_Printf("WARNING: Patch_Write to a CMemFile and Surface Properties plugin not done\n");
03686 }
03687
03688 MemFile_fprintf(file, " {\n patchDef2\n {\n");
03689
03690 MemFile_fprintf(file, " %s\n",p->d_texture->name);
03691
03692 MemFile_fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
03693
03694
03695 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
03696
03697 int w, h;
03698 for (w = 0; w < p->width; w++)
03699 {
03700 for (h = 0; h < p->height; h++)
03701 {
03702 ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
03703 ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
03704 ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
03705 ctrl[w][h][3] = p->ctrl[w][h].st[0];
03706 ctrl[w][h][4] = p->ctrl[w][h].st[1];
03707 }
03708 }
03709
03710 _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
03711
03712 if (g_qeglobals.m_bBrushPrimitMode)
03713 {
03714 if (p->epairs)
03715 {
03716 for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
03717 {
03718 MemFile_fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
03719 }
03720 }
03721 }
03722
03723 MemFile_fprintf(file, " }\n }\n");
03724 }
03725
03726 void Patch_Write (patchMesh_t *p, FILE *file)
03727 {
03728 fprintf(file, " {\n patchDef2\n {\n");
03729 if (g_qeglobals.bSurfacePropertiesPlugin)
03730 {
03731 #ifdef _DEBUG
03732 if ( !p->pData )
03733 Sys_Printf("ERROR: no IPluginTexdef in patch\n");
03734 #endif
03735 g_File = file;
03736 GETPLUGINTEXDEF(p)->WritePatchTexdef( QERApp_MapPrintf_FILE );
03737 }
03738 else
03739 {
03740 fprintf(file, " %s\n",p->d_texture->name);
03741 fprintf(file, " ( %i %i %i %i %i ) \n", p->width, p->height, p->contents, p->flags, p->value);
03742 }
03743
03744 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
03745
03746 int w, h;
03747 for (w = 0; w < p->width; w++)
03748 {
03749 for (h = 0; h < p->height; h++)
03750 {
03751 ctrl[w][h][0] = p->ctrl[w][h].xyz[0];
03752 ctrl[w][h][1] = p->ctrl[w][h].xyz[1];
03753 ctrl[w][h][2] = p->ctrl[w][h].xyz[2];
03754 ctrl[w][h][3] = p->ctrl[w][h].st[0];
03755 ctrl[w][h][4] = p->ctrl[w][h].st[1];
03756 }
03757 }
03758
03759 _Write3DMatrix(file, p->width, p->height, 5, reinterpret_cast<float*>(&ctrl));
03760
03761 if (g_qeglobals.m_bBrushPrimitMode)
03762 {
03763 if (p->epairs)
03764 {
03765 for (epair_t *ep = p->epairs ; ep ; ep=ep->next)
03766 {
03767 fprintf (file, "\"%s\" \"%s\"\n", ep->key, ep->value);
03768 }
03769 }
03770 }
03771
03772 fprintf(file, " }\n }\n");
03773 }
03774
03775
03776
03777
03778
03779
03780
03781 void Patch_RotateTexture(patchMesh_t *p, float fAngle)
03782 {
03783 vec3_t vMin, vMax;
03784 Patch_CalcBounds(p, vMin, vMax);
03785 p->bDirty = true;
03786 for (int w = 0; w < p->width; w++)
03787 {
03788 for (int h = 0; h < p->height; h++)
03789 {
03790 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
03791 continue;
03792
03793 float x = p->ctrl[w][h].st[0];
03794 float y = p->ctrl[w][h].st[1];
03795 p->ctrl[w][h].st[0] = x * cos(fAngle * Q_PI / 180) - y * sin(fAngle * Q_PI / 180);
03796 p->ctrl[w][h].st[1] = y * cos(fAngle * Q_PI / 180) + x * sin(fAngle * Q_PI / 180);
03797 }
03798 }
03799 }
03800
03801
03802
03803
03804
03805
03806
03807 void Patch_ScaleTexture(patchMesh_t *p, float fx, float fy, bool bFixup)
03808 {
03809
03810
03811 if (bFixup)
03812 {
03813 fx = (fx == 0) ? 1.0 : (fx > 0) ? 0.9 : 1.10;
03814 fy = (fy == 0) ? 1.0 : (fy > 0) ? 0.9 : 1.10;
03815 }
03816 else
03817 {
03818 if (fx == 0)
03819 fx = 1.0;
03820 if (fy == 0)
03821 fy = 1.0;
03822 }
03823
03824 for (int w = 0; w < p->width; w++)
03825 {
03826 for (int h = 0; h < p->height; h++)
03827 {
03828 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
03829 continue;
03830
03831 p->ctrl[w][h].st[0] *= fx;
03832 p->ctrl[w][h].st[1] *= fy;
03833 }
03834 }
03835 p->bDirty = true;
03836 }
03837
03838
03839
03840
03841
03842
03843
03844 void Patch_ShiftTexture(patchMesh_t *p, float fx, float fy)
03845 {
03846
03847
03848
03849
03850
03851 fx = (abs(fx) >= 1) ? fx / 10 : fx;
03852 fy = (abs(fy) >= 1) ? fy / 10 : fy;
03853
03854 for (int w = 0; w < p->width; w++)
03855 {
03856 for (int h = 0; h < p->height; h++)
03857 {
03858 if (g_qeglobals.d_select_mode == sel_curvepoint && PointInMoveList(p->ctrl[w][h].xyz) == -1)
03859 continue;
03860
03861 p->ctrl[w][h].st[0] += fx;
03862 p->ctrl[w][h].st[1] += fy;
03863 }
03864 }
03865 p->bDirty = true;
03866 }
03867
03868 void patchInvert(patchMesh_t *p)
03869 {
03870 drawVert_t vertTemp;
03871 p->bDirty = true;
03872 for ( int i = 0 ; i < p->width ; i++ )
03873 {
03874 for (int j = 0; j < p->height / 2; j++)
03875 {
03876 memcpy(&vertTemp, &p->ctrl[i][p->height - 1- j], sizeof (drawVert_t));
03877 memcpy(&p->ctrl[i][p->height - 1 - j], &p->ctrl[i][j], sizeof(drawVert_t));
03878 memcpy(&p->ctrl[i][j], &vertTemp, sizeof(drawVert_t));
03879 }
03880 }
03881 }
03882
03883
03884
03885
03886
03887
03888 void Patch_ToggleInverted()
03889 {
03890 bool bUpdate = false;
03891
03892 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03893 {
03894 if (pb->patchBrush)
03895 {
03896 bUpdate = true;
03897 patchInvert(pb->pPatch);
03898 }
03899 }
03900
03901 if (bUpdate)
03902 {
03903 Sys_UpdateWindows(W_ALL);
03904 }
03905 UpdatePatchInspector();
03906 }
03907
03908
03909
03910
03911
03912
03913 void Patch_InvertTexture(bool bY)
03914 {
03915 bool bUpdate = false;
03916
03917 float fTemp[2];
03918 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03919 {
03920 if (pb->patchBrush)
03921 {
03922 bUpdate = true;
03923 patchMesh_t *p = pb->pPatch;
03924 p->bDirty = true;
03925 if (bY)
03926 {
03927 for ( int i = 0 ; i < p->height ; i++ )
03928 {
03929 for (int j = 0; j < p->width / 2; j++)
03930 {
03931 memcpy(fTemp, &p->ctrl[p->width - 1- j][i].st[0], sizeof (float[2]));
03932 memcpy(&p->ctrl[p->width - 1- j][i].st[0], &p->ctrl[j][i].st[0], sizeof(float[2]));
03933 memcpy(&p->ctrl[j][i].st[0], fTemp, sizeof(float[2]));
03934 }
03935 }
03936 }
03937 else
03938 {
03939 for ( int i = 0 ; i < p->width ; i++ )
03940 {
03941 for (int j = 0; j < p->height / 2; j++)
03942 {
03943 memcpy(fTemp, &p->ctrl[i][p->height - 1- j].st[0], sizeof (float[2]));
03944 memcpy(&p->ctrl[i][p->height - 1 - j].st[0], &p->ctrl[i][j].st[0], sizeof(float[2]));
03945 memcpy(&p->ctrl[i][j].st[0], fTemp, sizeof(float[2]));
03946 }
03947 }
03948 }
03949 }
03950 }
03951
03952 if (bUpdate)
03953 {
03954 Sys_UpdateWindows(W_ALL);
03955 }
03956 UpdatePatchInspector();
03957 }
03958
03959
03960
03961
03962
03963
03964
03965
03966
03967
03968
03969 void Patch_Save(patchMesh_t *p)
03970 {
03971 patchSave.width = p->width;
03972 patchSave.height = p->height;
03973 memcpy(patchSave.ctrl, p->ctrl, sizeof(p->ctrl));
03974 }
03975
03976
03977
03978
03979
03980
03981
03982 void Patch_Restore(patchMesh_t *p)
03983 {
03984 p->width = patchSave.width;
03985 p->height = patchSave.height;
03986 memcpy(p->ctrl, patchSave.ctrl, sizeof(p->ctrl));
03987 }
03988
03989 void Patch_ResetTexturing(float fx, float fy)
03990 {
03991 for (brush_t* pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
03992 {
03993 if (pb->patchBrush)
03994 {
03995 patchMesh_t *p = pb->pPatch;
03996 p->bDirty = true;
03997 for ( int i = 0 ; i < p->width ; i++ )
03998 {
03999 for ( int j = 0 ; j < p->height ; j++ )
04000 {
04001 p->ctrl[i][j].st[0] = fx * (float)i / (p->width - 1);
04002 p->ctrl[i][j].st[1] = fy * (float)j / (p->height - 1);
04003 }
04004 }
04005 }
04006 }
04007 }
04008
04009
04010 void Patch_FitTexturing()
04011 {
04012 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04013 {
04014 if (pb->patchBrush)
04015 {
04016 patchMesh_t *p = pb->pPatch;
04017 p->bDirty = true;
04018 for ( int i = 0 ; i < p->width ; i++ )
04019 {
04020 for ( int j = 0 ; j < p->height ; j++ )
04021 {
04022 p->ctrl[i][j].st[0] = 1 * (float)i / (p->width - 1);
04023 p->ctrl[i][j].st[1] = 1 * (float)j / (p->height - 1);
04024 }
04025 }
04026 }
04027 }
04028 }
04029
04030
04031 void Patch_SetTextureInfo(texdef_t *pt)
04032 {
04033 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04034 {
04035 if (pb->patchBrush)
04036 {
04037 if (pt->rotate)
04038 Patch_RotateTexture(pb->pPatch, pt->rotate);
04039
04040 if (pt->shift[0] || pt->shift[1])
04041 Patch_ShiftTexture(pb->pPatch, pt->shift[0], pt->shift[1]);
04042
04043 if (pt->scale[0] || pt->scale[1])
04044 Patch_ScaleTexture(pb->pPatch, pt->scale[0], pt->scale[1], false);
04045
04046 patchMesh_t *p = pb->pPatch;
04047 p->contents = pt->contents;
04048 p->flags = pt->flags;
04049 p->value = pt->value;
04050 }
04051 }
04052 }
04053
04054 bool WINAPI OnlyPatchesSelected()
04055 {
04056 if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
04057 return false;
04058 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04059 {
04060 if (!pb->patchBrush)
04061 {
04062 return false;
04063 }
04064 }
04065 return true;
04066 }
04067
04068 bool WINAPI AnyPatchesSelected()
04069 {
04070 if (g_ptrSelectedFaces.GetSize() > 0 || selected_brushes.next == &selected_brushes)
04071 return false;
04072 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04073 {
04074 if (pb->patchBrush)
04075 {
04076 return true;
04077 }
04078 }
04079 return false;
04080 }
04081
04082 patchMesh_t* SinglePatchSelected()
04083 {
04084 if (selected_brushes.next->patchBrush)
04085 {
04086 return selected_brushes.next->pPatch;
04087 }
04088 return NULL;
04089 }
04090
04091 void Patch_BendToggle()
04092 {
04093 if (g_bPatchBendMode)
04094 {
04095 g_bPatchBendMode = false;
04096 HideInfoDialog();
04097 g_pParentWnd->UpdatePatchToolbarButtons() ;
04098 return;
04099 }
04100
04101 brush_t* b = selected_brushes.next;
04102
04103 if (!QE_SingleBrush() || !b->patchBrush)
04104 {
04105 Sys_Printf("Must bend a single patch");
04106 return;
04107 }
04108
04109 Patch_Save(b->pPatch);
04110 g_bPatchBendMode = true;
04111 g_nPatchBendState = BEND_SELECT_ROTATION;
04112 g_bPatchAxisOnRow = true;
04113 g_nPatchAxisIndex = 1;
04114 ShowInfoDialog(g_pBendStateMsg[BEND_SELECT_ROTATION]);
04115 }
04116
04117 void Patch_BendHandleTAB()
04118 {
04119 if (!g_bPatchBendMode)
04120 {
04121 return;
04122 }
04123
04124 brush_t* b = selected_brushes.next;
04125 if (!QE_SingleBrush() || !b->patchBrush)
04126 {
04127 Patch_BendToggle();
04128 Sys_Printf("No patch to bend!");
04129 return;
04130 }
04131
04132 patchMesh_t *p = b->pPatch;
04133
04134 bool bShift = (GetKeyState(VK_SHIFT) & 0x8000);
04135
04136 if (g_nPatchBendState == BEND_SELECT_ROTATION)
04137 {
04138
04139 g_nPatchAxisIndex += (bShift) ? -2 : 2;
04140 if (g_bPatchAxisOnRow)
04141 {
04142 if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->height)
04143 {
04144 g_bPatchAxisOnRow = false;
04145 g_nPatchAxisIndex = (bShift) ? p->width-1 : 1;
04146 }
04147 }
04148 else
04149 {
04150 if ((bShift) ? g_nPatchAxisIndex <= 0 : g_nPatchAxisIndex >= p->width)
04151 {
04152 g_bPatchAxisOnRow = true;
04153 g_nPatchAxisIndex = (bShift) ? p->height-1 : 1;
04154 }
04155 }
04156 }
04157 else
04158 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
04159 {
04160 g_nBendOriginIndex += (bShift) ? -1 : 1;
04161 if (g_bPatchAxisOnRow)
04162 {
04163 if (bShift)
04164 {
04165 if (g_nBendOriginIndex < 0)
04166 g_nBendOriginIndex = p->width-1;
04167 }
04168 else
04169 {
04170 if (g_nBendOriginIndex > p->width-1)
04171 g_nBendOriginIndex = 0;
04172 }
04173 VectorCopy(p->ctrl[g_nBendOriginIndex][g_nPatchAxisIndex].xyz, g_vBendOrigin);
04174 }
04175 else
04176 {
04177 if (bShift)
04178 {
04179 if (g_nBendOriginIndex < 0)
04180 g_nBendOriginIndex = p->height-1;
04181 }
04182 else
04183 {
04184 if (g_nBendOriginIndex > p->height-1)
04185 g_nBendOriginIndex = 0;
04186 }
04187 VectorCopy(p->ctrl[g_nPatchAxisIndex][g_nBendOriginIndex].xyz, g_vBendOrigin);
04188 }
04189 }
04190 else
04191 if (g_nPatchBendState == BEND_SELECT_EDGE)
04192 {
04193 g_bPatchLowerEdge ^= 1;
04194 }
04195 Sys_UpdateWindows(W_ALL);
04196 }
04197
04198 void Patch_BendHandleENTER()
04199 {
04200 if (!g_bPatchBendMode)
04201 {
04202 return;
04203 }
04204
04205 if (g_nPatchBendState < BEND_BENDIT)
04206 {
04207 g_nPatchBendState++;
04208 ShowInfoDialog(g_pBendStateMsg[g_nPatchBendState]);
04209 if (g_nPatchBendState == BEND_SELECT_ORIGIN)
04210 {
04211 g_vBendOrigin[0] = g_vBendOrigin[1] = g_vBendOrigin[2] = 0;
04212 g_nBendOriginIndex = 0;
04213 Patch_BendHandleTAB();
04214 }
04215 else
04216 if (g_nPatchBendState == BEND_SELECT_EDGE)
04217 {
04218 g_bPatchLowerEdge = true;
04219 }
04220 else
04221 if (g_nPatchBendState == BEND_BENDIT)
04222 {
04223
04224 }
04225 }
04226 else
04227 {
04228
04229 Patch_BendToggle();
04230 }
04231 Sys_UpdateWindows(W_ALL);
04232
04233 }
04234
04235
04236 void Patch_BendHandleESC()
04237 {
04238 if (!g_bPatchBendMode)
04239 {
04240 return;
04241 }
04242 Patch_BendToggle();
04243 brush_t* b = selected_brushes.next;
04244 if (QE_SingleBrush() && b->patchBrush)
04245 {
04246 Patch_Restore(b->pPatch);
04247 }
04248 Sys_UpdateWindows(W_ALL);
04249 }
04250
04251 void Patch_SetBendRotateOrigin(patchMesh_t *p)
04252 {
04253 #if 1
04254 int nType = g_pParentWnd->ActiveXY()->GetViewType();
04255 int nDim3 = (nType == XY) ? 2 : (nType == YZ) ? 0 : 1;
04256
04257 g_vBendOrigin[nDim3] = 0;
04258 VectorCopy(g_vBendOrigin, g_pParentWnd->ActiveXY()->RotateOrigin());
04259 return;
04260 #else
04261 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
04262 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
04263
04264 float fxLo, fyLo, fxHi, fyHi;
04265 fxLo = fyLo = 9999;
04266 fxHi = fyHi = -9999;
04267
04268 if (g_bPatchAxisOnRow)
04269 {
04270 for (int i = 0; i < p->width; i++)
04271 {
04272 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] < fxLo)
04273 fxLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
04274
04275 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1] > fxHi)
04276 fxHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim1];
04277
04278 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] < fyLo)
04279 fyLo = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
04280
04281 if (p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2] > fyHi)
04282 fyHi = p->ctrl[i][g_nPatchAxisIndex].xyz[nDim2];
04283 }
04284 }
04285 else
04286 {
04287 for (int i = 0; i < p->height; i++)
04288 {
04289 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] < fxLo)
04290 fxLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
04291
04292 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1] > fxHi)
04293 fxHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim1];
04294
04295 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] < fyLo)
04296 fyLo = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
04297
04298 if (p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2] > fyHi)
04299 fyHi = p->ctrl[g_nPatchAxisIndex][i].xyz[nDim2];
04300 }
04301 }
04302
04303 g_pParentWnd->ActiveXY()->RotateOrigin()[0] = g_pParentWnd->ActiveXY()->RotateOrigin()[1] = g_pParentWnd->ActiveXY()->RotateOrigin()[2] = 0.0;
04304 g_pParentWnd->ActiveXY()->RotateOrigin()[nDim1] = (fxLo + fxHi) * 0.5;
04305 g_pParentWnd->ActiveXY()->RotateOrigin()[nDim2] = (fyLo + fyHi) * 0.5;
04306 #endif
04307 }
04308
04309
04310 void Patch_SelectBendAxis()
04311 {
04312 brush_t* b = selected_brushes.next;
04313 if (!QE_SingleBrush() || !b->patchBrush)
04314 {
04315
04316 Patch_BendToggle();
04317 return;
04318 }
04319
04320 patchMesh_t *p = b->pPatch;
04321 if (g_bPatchAxisOnRow)
04322 {
04323 SelectRow(p, g_nPatchAxisIndex, false);
04324 }
04325 else
04326 {
04327 SelectColumn(p, g_nPatchAxisIndex, false);
04328 }
04329
04330
04331 Patch_SetBendRotateOrigin(p);
04332
04333 }
04334
04335 void Patch_SelectBendNormal()
04336 {
04337 brush_t* b = selected_brushes.next;
04338 if (!QE_SingleBrush() || !b->patchBrush)
04339 {
04340
04341 Patch_BendToggle();
04342 return;
04343 }
04344
04345 patchMesh_t *p = b->pPatch;
04346
04347 g_qeglobals.d_num_move_points = 0;
04348 if (g_bPatchAxisOnRow)
04349 {
04350 if (g_bPatchLowerEdge)
04351 {
04352 for (int j = 0; j < g_nPatchAxisIndex; j++)
04353 SelectRow(p, j, true);
04354 }
04355 else
04356 {
04357 for (int j = p->height-1; j > g_nPatchAxisIndex; j--)
04358 SelectRow(p, j, true);
04359 }
04360 }
04361 else
04362 {
04363 if (g_bPatchLowerEdge)
04364 {
04365 for (int j = 0; j < g_nPatchAxisIndex; j++)
04366 SelectColumn(p, j, true);
04367 }
04368 else
04369 {
04370 for (int j = p->width-1; j > g_nPatchAxisIndex; j--)
04371 SelectColumn(p, j, true);
04372 }
04373 }
04374 Patch_SetBendRotateOrigin(p);
04375 }
04376
04377
04378
04379 void Patch_InsDelToggle()
04380 {
04381 if (g_bPatchInsertMode)
04382 {
04383 g_bPatchInsertMode = false;
04384 HideInfoDialog();
04385 g_pParentWnd->UpdatePatchToolbarButtons() ;
04386 return;
04387 }
04388
04389 brush_t* b = selected_brushes.next;
04390
04391 if (!QE_SingleBrush() || !b->patchBrush)
04392 {
04393 Sys_Printf("Must work with a single patch");
04394 return;
04395 }
04396
04397 Patch_Save(b->pPatch);
04398 g_bPatchInsertMode = true;
04399 g_nPatchInsertState = INSERT_SELECT_EDGE;
04400 g_bPatchAxisOnRow = true;
04401 g_nPatchAxisIndex = 0;
04402 ShowInfoDialog(g_pInsertStateMsg[INSERT_SELECT_EDGE]);
04403
04404 }
04405
04406 void Patch_InsDelESC()
04407 {
04408 if (!g_bPatchInsertMode)
04409 {
04410 return;
04411 }
04412 Patch_InsDelToggle();
04413 Sys_UpdateWindows(W_ALL);
04414 }
04415
04416
04417 void Patch_InsDelHandleENTER()
04418 {
04419 }
04420
04421 void Patch_InsDelHandleTAB()
04422 {
04423 if (!g_bPatchInsertMode)
04424 {
04425 Patch_InsDelToggle();
04426 return;
04427 }
04428
04429 brush_t* b = selected_brushes.next;
04430 if (!QE_SingleBrush() || !b->patchBrush)
04431 {
04432 Patch_BendToggle();
04433 Sys_Printf("No patch to bend!");
04434 return;
04435 }
04436
04437 patchMesh_t *p = b->pPatch;
04438
04439
04440 g_nPatchAxisIndex += 2;
04441 if (g_bPatchAxisOnRow)
04442 {
04443 if (g_nPatchAxisIndex >= p->height-1)
04444 {
04445 g_bPatchAxisOnRow = false;
04446 g_nPatchAxisIndex = 0;
04447 }
04448 }
04449 else
04450 {
04451 if (g_nPatchAxisIndex >= p->width-1)
04452 {
04453 g_bPatchAxisOnRow = true;
04454 g_nPatchAxisIndex = 0;
04455 }
04456 }
04457 Sys_UpdateWindows(W_ALL);
04458 }
04459
04460
04461 void _Write1DMatrix (FILE *f, int x, float *m) {
04462 int i;
04463
04464 fprintf (f, "( ");
04465 for (i = 0 ; i < x ; i++) {
04466 if (m[i] == (int)m[i] ) {
04467 fprintf (f, "%i ", (int)m[i]);
04468 } else {
04469 fprintf (f, "%f ", m[i]);
04470 }
04471 }
04472 fprintf (f, ")");
04473 }
04474
04475 void _Write2DMatrix (FILE *f, int y, int x, float *m) {
04476 int i;
04477
04478 fprintf (f, "( ");
04479 for (i = 0 ; i < y ; i++) {
04480 _Write1DMatrix (f, x, m + i*x);
04481 fprintf (f, " ");
04482 }
04483 fprintf (f, ")\n");
04484 }
04485
04486
04487 void _Write3DMatrix (FILE *f, int z, int y, int x, float *m) {
04488 int i;
04489
04490 fprintf (f, "(\n");
04491 for (i = 0 ; i < z ; i++) {
04492 _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
04493 }
04494 fprintf (f, ")\n");
04495 }
04496
04497 void _Write1DMatrix (CMemFile *f, int x, float *m) {
04498 int i;
04499
04500 MemFile_fprintf (f, "( ");
04501 for (i = 0 ; i < x ; i++) {
04502 if (m[i] == (int)m[i] ) {
04503 MemFile_fprintf (f, "%i ", (int)m[i]);
04504 } else {
04505 MemFile_fprintf (f, "%f ", m[i]);
04506 }
04507 }
04508 MemFile_fprintf (f, ")");
04509 }
04510
04511 void _Write2DMatrix (CMemFile *f, int y, int x, float *m) {
04512 int i;
04513
04514 MemFile_fprintf (f, "( ");
04515 for (i = 0 ; i < y ; i++) {
04516 _Write1DMatrix (f, x, m + i*x);
04517 MemFile_fprintf (f, " ");
04518 }
04519 MemFile_fprintf (f, ")\n");
04520 }
04521
04522
04523 void _Write3DMatrix (CMemFile *f, int z, int y, int x, float *m) {
04524 int i;
04525
04526 MemFile_fprintf (f, "(\n");
04527 for (i = 0 ; i < z ; i++) {
04528 _Write2DMatrix (f, y, x, m + i*(x*MAX_PATCH_HEIGHT) );
04529 }
04530 MemFile_fprintf (f, ")\n");
04531 }
04532
04533
04534 void Patch_NaturalizeSelected(bool bCap, bool bCycleCap)
04535 {
04536 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04537 {
04538 if (pb->patchBrush)
04539 {
04540 if (bCap)
04541 Patch_CapTexture(pb->pPatch, bCycleCap);
04542 else
04543 Patch_Naturalize(pb->pPatch);
04544 }
04545 }
04546 }
04547
04548 bool within(vec3_t vTest, vec3_t vTL, vec3_t vBR)
04549 {
04550 int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
04551 int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
04552 if ((vTest[nDim1] > vTL[nDim1] && vTest[nDim1] < vBR[nDim1]) ||
04553 (vTest[nDim1] < vTL[nDim1] && vTest[nDim1] > vBR[nDim1]))
04554 {
04555 if ((vTest[nDim2] > vTL[nDim2] && vTest[nDim2] < vBR[nDim2]) ||
04556 (vTest[nDim2] < vTL[nDim2] && vTest[nDim2] > vBR[nDim2]))
04557 return true;
04558 }
04559 return false;
04560 }
04561
04562
04563 void Patch_SelectAreaPoints()
04564 {
04565 g_qeglobals.d_num_move_points = 0;
04566 g_nPatchClickedView = -1;
04567
04568 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04569 {
04570 if (pb->patchBrush)
04571 {
04572 patchMesh_t *p = pb->pPatch;
04573 for (int i = 0; i < p->width; i++)
04574 {
04575 for (int j = 0; j < p->height; j++)
04576 {
04577 if (within(p->ctrl[i][j].xyz, g_qeglobals.d_vAreaTL, g_qeglobals.d_vAreaBR))
04578 {
04579 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = p->ctrl[i][j].xyz;
04580 }
04581 }
04582 }
04583 }
04584 }
04585 }
04586
04587 const char* Patch_GetTextureName()
04588 {
04589 brush_t* b = selected_brushes.next;
04590 if (b->patchBrush)
04591 {
04592 patchMesh_t *p = b->pPatch;
04593 if (p->d_texture->name)
04594 return p->d_texture->name;
04595 }
04596 return "";
04597 }
04598
04599 patchMesh_t* Patch_Duplicate(patchMesh_t *pFrom)
04600 {
04601 patchMesh_t* p = MakeNewPatch();
04602 memcpy(p, pFrom , sizeof(patchMesh_t));
04603 p->bSelected = false;
04604 p->bDirty = true;
04605 p->bOverlay = false;
04606 p->nListID = -1;
04607
04608 if (g_qeglobals.bSurfacePropertiesPlugin)
04609 {
04610 #ifdef _DEBUG
04611 if (!pFrom->pData)
04612 Sys_Printf("WARNING: unexpected pFrom->pData is NULL in Patch_Duplicate\n");
04613 else
04614 #endif
04615 p->pData = GETPLUGINTEXDEF(pFrom)->Copy();
04616 }
04617 AddBrushForPatch(p);
04618 return p;
04619 }
04620
04621
04622 void Patch_Thicken(int nAmount, bool bSeam)
04623 {
04624 int i, j, h, w;
04625 brush_t *b;
04626 patchMesh_t *pSeam;
04627 vec3_t vMin, vMax;
04628 CPtrArray brushes;
04629
04630 nAmount = -nAmount;
04631
04632
04633 if (!QE_SingleBrush())
04634 {
04635 Sys_Printf("Cannot thicken multiple patches. Please select a single patch.\n");
04636 return;
04637 }
04638
04639 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04640 {
04641 if (pb->patchBrush)
04642 {
04643 patchMesh_t *p = pb->pPatch;
04644 Patch_MeshNormals(p);
04645 patchMesh_t *pNew = Patch_Duplicate(p);
04646 for (i = 0; i < p->width; i++)
04647 {
04648 for (j = 0; j < p->height; j++)
04649 {
04650 VectorMA (p->ctrl[i][j].xyz, nAmount, p->ctrl[i][j].normal, pNew->ctrl[i][j].xyz);
04651 }
04652 }
04653
04654 Patch_Rebuild(pNew);
04655 pNew->type |= PATCH_THICK;
04656 brushes.Add(pNew->pSymbiot);
04657
04658 if (bSeam)
04659 {
04660
04661
04662
04663 if (!(p->type & PATCH_CYLINDER))
04664 {
04665 b = Patch_GenericMesh(3, p->height, 2, false, true);
04666 pSeam = b->pPatch;
04667 pSeam->type |= PATCH_SEAM;
04668 for (i = 0; i < p->height; i++)
04669 {
04670 VectorCopy(p->ctrl[0][i].xyz, pSeam->ctrl[0][i].xyz);
04671 VectorCopy(pNew->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz);
04672 VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
04673 VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
04674 }
04675
04676
04677 Patch_CalcBounds(pSeam, vMin, vMax);
04678 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04679
04680 Patch_Naturalize(pSeam);
04681 patchInvert(pSeam);
04682 brushes.Add(b);
04683
04684 w = p->width - 1;
04685 b = Patch_GenericMesh(3, p->height, 2, false, true);
04686 pSeam = b->pPatch;
04687 pSeam->type |= PATCH_SEAM;
04688 for (i = 0; i < p->height; i++)
04689 {
04690 VectorCopy(p->ctrl[w][i].xyz, pSeam->ctrl[0][i].xyz);
04691 VectorCopy(pNew->ctrl[w][i].xyz, pSeam->ctrl[2][i].xyz);
04692 VectorAdd(pSeam->ctrl[0][i].xyz, pSeam->ctrl[2][i].xyz, pSeam->ctrl[1][i].xyz);
04693 VectorScale(pSeam->ctrl[1][i].xyz, 0.5, pSeam->ctrl[1][i].xyz);
04694 }
04695 Patch_CalcBounds(pSeam, vMin, vMax);
04696 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04697
04698 Patch_Naturalize(pSeam);
04699 brushes.Add(b);
04700 }
04701
04702
04703
04704 b = Patch_GenericMesh(p->width, 3, 2, false, true);
04705 pSeam = b->pPatch;
04706 pSeam->type |= PATCH_SEAM;
04707 for (i = 0; i < p->width; i++)
04708 {
04709 VectorCopy(p->ctrl[i][0].xyz, pSeam->ctrl[i][0].xyz);
04710 VectorCopy(pNew->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz);
04711 VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
04712 VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
04713 }
04714
04715
04716 Patch_CalcBounds(pSeam, vMin, vMax);
04717 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04718
04719 Patch_Naturalize(pSeam);
04720 patchInvert(pSeam);
04721 brushes.Add(b);
04722
04723 h = p->height - 1;
04724 b = Patch_GenericMesh(p->width, 3, 2, false, true);
04725 pSeam = b->pPatch;
04726 pSeam->type |= PATCH_SEAM;
04727 for (i = 0; i < p->width; i++)
04728 {
04729 VectorCopy(p->ctrl[i][h].xyz, pSeam->ctrl[i][0].xyz);
04730 VectorCopy(pNew->ctrl[i][h].xyz, pSeam->ctrl[i][2].xyz);
04731 VectorAdd(pSeam->ctrl[i][0].xyz, pSeam->ctrl[i][2].xyz, pSeam->ctrl[i][1].xyz);
04732 VectorScale(pSeam->ctrl[i][1].xyz, 0.5, pSeam->ctrl[i][1].xyz);
04733 }
04734 Patch_CalcBounds(pSeam, vMin, vMax);
04735 Brush_RebuildBrush(pSeam->pSymbiot, vMin, vMax);
04736
04737 Patch_Naturalize(pSeam);
04738 brushes.Add(b);
04739
04740 eclass_t *pecNew = Eclass_ForName("func_group", false);
04741 if (pecNew)
04742 {
04743 entity_t *e = Entity_Create(pecNew);
04744 SetKeyValue(e, "type", "patchThick");
04745 }
04746
04747
04748
04749 }
04750 patchInvert(pNew);
04751 }
04752 }
04753
04754 for (i = 0; i < brushes.GetSize(); i++)
04755 {
04756 Select_Brush(reinterpret_cast<brush_t*>(brushes.GetAt(i)));
04757 }
04758
04759 UpdatePatchInspector();
04760 }
04761
04762
04763
04764
04765
04766
04767
04768
04769
04770
04771
04772
04773
04774
04775
04776
04777
04778
04779
04780
04781
04782 void Patch_SetOverlays()
04783 {
04784 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04785 {
04786 if (pb->patchBrush)
04787 {
04788 pb->pPatch->bOverlay = true;
04789 }
04790 }
04791 }
04792
04793
04794
04795 void Patch_ClearOverlays()
04796 {
04797 brush_t *pb;
04798 for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04799 {
04800 if (pb->patchBrush)
04801 {
04802 pb->pPatch->bOverlay = false;
04803 }
04804 }
04805
04806 for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
04807 {
04808 if (pb->patchBrush)
04809 {
04810 pb->pPatch->bOverlay = false;
04811 }
04812 }
04813
04814 }
04815
04816
04817 void Patch_Freeze()
04818 {
04819 brush_t *pb;
04820 for (pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04821 {
04822 if (pb->patchBrush)
04823 {
04824 pb->pPatch->bOverlay = false;
04825 }
04826 }
04827
04828 for (pb = active_brushes.next ; pb != &active_brushes ; pb = pb->next)
04829 {
04830 if (pb->patchBrush)
04831 {
04832 pb->pPatch->bOverlay = false;
04833 }
04834 }
04835
04836 }
04837
04838 void Patch_UnFreeze(bool bAll)
04839 {
04840 }
04841
04842
04843
04844 void Patch_Transpose()
04845 {
04846 int i, j, w;
04847 drawVert_t dv;
04848 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04849 {
04850 if (pb->patchBrush)
04851 {
04852 patchMesh_t *p = pb->pPatch;
04853
04854 if ( p->width > p->height )
04855 {
04856 for ( i = 0 ; i < p->height ; i++ )
04857 {
04858 for ( j = i + 1 ; j < p->width ; j++ )
04859 {
04860 if ( j < p->height )
04861 {
04862
04863 memcpy(&dv,&p->ctrl[j][i],sizeof(drawVert_t));
04864 memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
04865 memcpy(&p->ctrl[i][j],&dv, sizeof(drawVert_t));
04866 }
04867 else
04868 {
04869
04870 memcpy(&p->ctrl[j][i],&p->ctrl[i][j], sizeof(drawVert_t));
04871 }
04872 }
04873 }
04874 }
04875 else
04876 {
04877 for ( i = 0 ; i < p->width ; i++ )
04878 {
04879 for ( j = i + 1 ; j < p->height ; j++ )
04880 {
04881 if ( j < p->width )
04882 {
04883
04884 memcpy(&dv,&p->ctrl[i][j], sizeof(drawVert_t));
04885 memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
04886 memcpy(&p->ctrl[j][i],&dv, sizeof(drawVert_t));
04887 }
04888 else
04889 {
04890
04891 memcpy(&p->ctrl[i][j],&p->ctrl[j][i], sizeof(drawVert_t));
04892 }
04893 }
04894 }
04895 }
04896
04897 w = p->width;
04898 p->width = p->height;
04899 p->height = w;
04900 patchInvert(p);
04901 Patch_Rebuild(p);
04902 }
04903 }
04904 }
04905
04906
04907
04908 void Select_SnapToGrid()
04909 {
04910 int i,j, k;
04911 for (brush_t *pb = selected_brushes.next ; pb != &selected_brushes ; pb = pb->next)
04912 {
04913 if (pb->patchBrush)
04914 {
04915 patchMesh_t *p = pb->pPatch;
04916 #if 0
04917 float ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT][5];
04918 memcpy(ctrl, p->ctrl, sizeof(p->ctrl));
04919 i = p->width;
04920 p->width = p->height;
04921 p->height = i;
04922 for (i = 0; i < p->width; i++)
04923 {
04924 int l = p->height-1;
04925 for (j = 0; j < p->height; j++)
04926 {
04927 for (k = 0; k < 5; k++)
04928 {
04929 p->ctrl[i][l][k] = ctrl[j][i][k];
04930 }
04931 l--;
04932 }
04933 }
04934 #else
04935 for (i = 0; i < p->width; i++)
04936 {
04937 for (j = 0; j < p->height; j++)
04938 {
04939 for (k = 0; k < 3; k++)
04940 {
04941 p->ctrl[i][j].xyz[k] = floor(p->ctrl[i][j].xyz[k] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
04942 }
04943 }
04944 }
04945 #endif
04946 vec3_t vMin, vMax;
04947 Patch_CalcBounds(p, vMin, vMax);
04948 Brush_RebuildBrush(p->pSymbiot, vMin, vMax);
04949 }
04950 else
04951 {
04952 Brush_SnapToGrid(pb);
04953 }
04954 }
04955 }
04956
04957
04958 void Patch_FindReplaceTexture(brush_t *pb, const char *pFind, const char *pReplace, bool bForce)
04959 {
04960 if (pb->patchBrush)
04961 {
04962 patchMesh_t *p = pb->pPatch;
04963 if (bForce || strcmpi(p->d_texture->name, pFind) == 0)
04964 {
04965 p->d_texture = Texture_ForName(pReplace);
04966
04967 }
04968 }
04969 }
04970
04971 void Patch_ReplaceQTexture(brush_t *pb, qtexture_t *pOld, qtexture_t *pNew)
04972 {
04973 if (pb->patchBrush)
04974 {
04975 patchMesh_t *p = pb->pPatch;
04976 if (p->d_texture == pOld)
04977 {
04978 p->d_texture = pNew;
04979 }
04980 }
04981 }
04982
04983 void Patch_Clone(patchMesh_t *p, brush_t *pNewOwner)
04984 {
04985 }
04986
04987 void Patch_FromTriangle(vec5_t vx, vec5_t vy, vec5_t vz)
04988 {
04989 patchMesh_t* p = MakeNewPatch();
04990 p->d_texture = Texture_ForName(g_qeglobals.d_texturewin.texdef.name);
04991 p->width = 3;
04992 p->height = 3;
04993 p->type = PATCH_TRIANGLE;
04994
04995
04996
04997
04998
04999
05000
05001
05002
05003
05004
05005
05006
05007 vec5_t vMidXZ;
05008 vec5_t vMidXY;
05009 vec5_t vMidYZ;
05010
05011
05012 for (int j = 0; j < 3; j++)
05013 {
05014 _Vector5Add(vx, vz, vMidXZ);
05015 _Vector5Scale(vMidXZ, 0.5, vMidXZ);
05016
05017 }
05018
05019 for (j = 0; j < 3; j++)
05020 {
05021 _Vector5Add(vx, vy, vMidXY);
05022 _Vector5Scale(vMidXY, 0.5, vMidXY);
05023
05024 }
05025
05026 for (j = 0; j < 3; j++)
05027 {
05028 _Vector5Add(vy, vz, vMidYZ);
05029 _Vector5Scale(vMidYZ, 0.5, vMidYZ);
05030
05031 }
05032
05033 _Vector53Copy(vx, p->ctrl[0][0].xyz);
05034 _Vector53Copy(vx, p->ctrl[0][1].xyz);
05035 _Vector53Copy(vx, p->ctrl[0][2].xyz);
05036 p->ctrl[0][0].st[0] = vx[3];
05037 p->ctrl[0][0].st[1] = vx[4];
05038 p->ctrl[0][1].st[0] = vx[3];
05039 p->ctrl[0][1].st[1] = vx[4];
05040 p->ctrl[0][2].st[0] = vx[3];
05041 p->ctrl[0][2].st[1] = vx[4];
05042
05043 _Vector53Copy(vMidXY, p->ctrl[1][0].xyz);
05044 _Vector53Copy(vx, p->ctrl[1][1].xyz);
05045 _Vector53Copy(vMidXZ, p->ctrl[1][2].xyz);
05046 p->ctrl[1][0].st[0] = vMidXY[3];
05047 p->ctrl[1][0].st[1] = vMidXY[4];
05048 p->ctrl[1][1].st[0] = vx[3];
05049 p->ctrl[1][1].st[1] = vx[4];
05050 p->ctrl[1][2].st[0] = vMidXZ[3];
05051 p->ctrl[1][2].st[1] = vMidXZ[4];
05052
05053 _Vector53Copy(vy, p->ctrl[2][0].xyz);
05054 _Vector53Copy(vMidYZ, p->ctrl[2][1].xyz);
05055 _Vector53Copy(vz, p->ctrl[2][2].xyz);
05056 p->ctrl[2][0].st[0] = vy[3];
05057 p->ctrl[2][0].st[1] = vy[4];
05058 p->ctrl[2][1].st[0] = vMidYZ[3];
05059 p->ctrl[2][1].st[1] = vMidYZ[4];
05060 p->ctrl[2][2].st[0] = vz[3];
05061 p->ctrl[2][2].st[1] = vz[4];
05062
05063
05064
05065
05066 brush_t *b = AddBrushForPatch(p);
05067
05068 }
05069
05070
05071
05072
05073
05074
05075
05076
05077 void Patch_SetEpair(patchMesh_t *p, const char *pKey, const char *pValue)
05078 {
05079 if (g_qeglobals.m_bBrushPrimitMode)
05080 {
05081 SetKeyValue(p->epairs, pKey, pValue);
05082 }
05083 }
05084
05085
05086
05087
05088
05089
05090 const char* Patch_GetKeyValue(patchMesh_t *p, const char *pKey)
05091 {
05092 if (g_qeglobals.m_bBrushPrimitMode)
05093 {
05094 return ValueForKey(p->epairs, pKey);
05095 }
05096 return "";
05097 }
05098
05099
05100
05101
05102
05103
05104
05105
05106
05107
05108
05109
05110
05111
05112
05113
05114
05115
05116
05117
05118
05119
05120
05121
05122
05123
05124
05125
05126
05127
05128
05129
05130
05131
05132
05133
05134
05135
05136