Brush.cpp (107620B)
1 /* 2 =========================================================================== 3 Copyright (C) 1999-2005 Id Software, Inc. 4 5 This file is part of Quake III Arena source code. 6 7 Quake III Arena source code is free software; you can redistribute it 8 and/or modify it under the terms of the GNU General Public License as 9 published by the Free Software Foundation; either version 2 of the License, 10 or (at your option) any later version. 11 12 Quake III Arena source code is distributed in the hope that it will be 13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with Foobar; if not, write to the Free Software 19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 20 =========================================================================== 21 */ 22 23 24 #include "stdafx.h" 25 #include <assert.h> 26 #include "qe3.h" 27 #include "winding.h" 28 29 30 // globals 31 32 int g_nBrushId = 0; 33 34 const char* Brush_Name(brush_t *b) 35 { 36 static char cBuff[1024]; 37 b->numberId = g_nBrushId++; 38 if (g_qeglobals.m_bBrushPrimitMode) 39 { 40 sprintf(cBuff, "Brush %i", b->numberId); 41 Brush_SetEpair(b, "Name", cBuff); 42 } 43 return cBuff; 44 } 45 46 brush_t *Brush_Alloc() 47 { 48 brush_t *b = (brush_t*)qmalloc(sizeof(brush_t)); 49 return b; 50 } 51 52 53 54 55 void PrintWinding (winding_t *w) 56 { 57 int i; 58 59 printf ("-------------\n"); 60 for (i=0 ; i<w->numpoints ; i++) 61 printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] 62 , w->points[i][1], w->points[i][2]); 63 } 64 65 void PrintPlane (plane_t *p) 66 { 67 printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], 68 p->normal[2], p->dist); 69 } 70 71 void PrintVector (vec3_t v) 72 { 73 printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); 74 } 75 76 77 /* 78 ============================================================================= 79 80 TEXTURE COORDINATES 81 82 ============================================================================= 83 */ 84 85 86 /* 87 ================== 88 textureAxisFromPlane 89 ================== 90 */ 91 vec3_t baseaxis[18] = 92 { 93 {0,0,1}, {1,0,0}, {0,-1,0}, // floor 94 {0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling 95 {1,0,0}, {0,1,0}, {0,0,-1}, // west wall 96 {-1,0,0}, {0,1,0}, {0,0,-1}, // east wall 97 {0,1,0}, {1,0,0}, {0,0,-1}, // south wall 98 {0,-1,0}, {1,0,0}, {0,0,-1} // north wall 99 }; 100 101 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) 102 { 103 int bestaxis; 104 float dot,best; 105 int i; 106 107 best = 0; 108 bestaxis = 0; 109 110 for (i=0 ; i<6 ; i++) 111 { 112 dot = DotProduct (pln->normal, baseaxis[i*3]); 113 if (dot > best) 114 { 115 best = dot; 116 bestaxis = i; 117 } 118 } 119 120 VectorCopy (baseaxis[bestaxis*3+1], xv); 121 VectorCopy (baseaxis[bestaxis*3+2], yv); 122 } 123 124 125 126 float lightaxis[3] = {0.6, 0.8, 1.0}; 127 /* 128 ================ 129 SetShadeForPlane 130 131 Light different planes differently to 132 improve recognition 133 ================ 134 */ 135 float SetShadeForPlane (plane_t *p) 136 { 137 int i; 138 float f; 139 140 // axial plane 141 for (i=0 ; i<3 ; i++) 142 if (fabs(p->normal[i]) > 0.9) 143 { 144 f = lightaxis[i]; 145 return f; 146 } 147 148 // between two axial planes 149 for (i=0 ; i<3 ; i++) 150 if (fabs(p->normal[i]) < 0.1) 151 { 152 f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; 153 return f; 154 } 155 156 // other 157 f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; 158 return f; 159 } 160 161 vec3_t vecs[2]; 162 float shift[2]; 163 164 /* 165 ================ 166 Face_Alloc 167 ================ 168 */ 169 face_t *Face_Alloc( void ) 170 { 171 face_t *f = (face_t*)qmalloc( sizeof( *f ) ); 172 173 if (g_qeglobals.bSurfacePropertiesPlugin) 174 f->pData = static_cast<void *>( g_SurfaceTable.m_pfnTexdefAlloc( f ) ); 175 176 return f; 177 } 178 179 /* 180 ================ 181 Face_Free 182 ================ 183 */ 184 void Face_Free( face_t *f ) 185 { 186 assert( f != 0 ); 187 188 if ( f->face_winding ) 189 { 190 free( f->face_winding ); 191 f->face_winding = 0; 192 } 193 194 if (g_qeglobals.bSurfacePropertiesPlugin) 195 { 196 #ifdef _DEBUG 197 if ( !f->pData ) 198 { 199 Sys_Printf("WARNING: unexpected IPluginTexdef is NULL in Face_Free\n"); 200 } 201 else 202 #endif 203 GETPLUGINTEXDEF(f)->DecRef(); 204 } 205 206 f->texdef.~texdef_t();; 207 208 free( f ); 209 } 210 211 /* 212 ================ 213 Face_Clone 214 ================ 215 */ 216 face_t *Face_Clone (face_t *f) 217 { 218 face_t *n; 219 220 n = Face_Alloc(); 221 n->texdef = f->texdef; 222 223 memcpy (n->planepts, f->planepts, sizeof(n->planepts)); 224 225 // all other fields are derived, and will be set by Brush_Build 226 return n; 227 } 228 229 /* 230 ================ 231 Face_FullClone 232 233 makes an exact copy of the face 234 ================ 235 */ 236 face_t *Face_FullClone (face_t *f) 237 { 238 face_t *n; 239 240 n = Face_Alloc(); 241 n->texdef = f->texdef; 242 memcpy(n->planepts, f->planepts, sizeof(n->planepts)); 243 memcpy(&n->plane, &f->plane, sizeof(plane_t)); 244 if (f->face_winding) 245 n->face_winding = Winding_Clone(f->face_winding); 246 else 247 n->face_winding = NULL; 248 n->d_texture = Texture_ForName( n->texdef.name ); 249 return n; 250 } 251 252 /* 253 ================ 254 Clamp 255 ================ 256 */ 257 void Clamp(float& f, int nClamp) 258 { 259 float fFrac = f - static_cast<int>(f); 260 f = static_cast<int>(f) % nClamp; 261 f += fFrac; 262 } 263 264 /* 265 ================ 266 Face_MoveTexture 267 ================ 268 */ 269 void Face_MoveTexture(face_t *f, vec3_t delta) 270 { 271 vec3_t vX, vY; 272 /* 273 #ifdef _DEBUG 274 if (g_PrefsDlg.m_bBrushPrimitMode) 275 Sys_Printf("Warning : Face_MoveTexture not done in brush primitive mode\n"); 276 #endif 277 */ 278 if (g_qeglobals.m_bBrushPrimitMode) 279 Face_MoveTexture_BrushPrimit( f, delta ); 280 else 281 { 282 TextureAxisFromPlane(&f->plane, vX, vY); 283 284 vec3_t vDP, vShift; 285 vDP[0] = DotProduct(delta, vX); 286 vDP[1] = DotProduct(delta, vY); 287 288 double fAngle = f->texdef.rotate / 180 * Q_PI; 289 double c = cos(fAngle); 290 double s = sin(fAngle); 291 292 vShift[0] = vDP[0] * c - vDP[1] * s; 293 vShift[1] = vDP[0] * s + vDP[1] * c; 294 295 if (!f->texdef.scale[0]) 296 f->texdef.scale[0] = 1; 297 if (!f->texdef.scale[1]) 298 f->texdef.scale[1] = 1; 299 300 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0]; 301 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1]; 302 303 // clamp the shifts 304 Clamp(f->texdef.shift[0], f->d_texture->width); 305 Clamp(f->texdef.shift[1], f->d_texture->height); 306 } 307 } 308 309 /* 310 ================ 311 Face_SetColor 312 ================ 313 */ 314 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) 315 { 316 float shade; 317 qtexture_t *q; 318 319 q = f->d_texture; 320 321 // set shading for face 322 shade = SetShadeForPlane (&f->plane); 323 if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture && !b->owner->eclass->fixedsize) 324 { 325 //if (b->curveBrush) 326 // shade = fCurveColor; 327 f->d_color[0] = 328 f->d_color[1] = 329 f->d_color[2] = shade; 330 } 331 else 332 { 333 f->d_color[0] = shade*q->color[0]; 334 f->d_color[1] = shade*q->color[1]; 335 f->d_color[2] = shade*q->color[2]; 336 } 337 } 338 339 /* 340 ================ 341 Face_TextureVectors 342 TTimo: NOTE: this is never to get called while in brush primitives mode 343 ================ 344 */ 345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4]) 346 { 347 vec3_t pvecs[2]; 348 int sv, tv; 349 float ang, sinv, cosv; 350 float ns, nt; 351 int i,j; 352 qtexture_t *q; 353 texdef_t *td; 354 355 #ifdef _DEBUG 356 //++timo when playing with patches, this sometimes get called and the Warning is displayed 357 // find some way out .. 358 if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) 359 Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n"); 360 #endif 361 362 td = &f->texdef; 363 q = f->d_texture; 364 365 memset (STfromXYZ, 0, 8*sizeof(float)); 366 367 if (!td->scale[0]) 368 td->scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1; 369 if (!td->scale[1]) 370 td->scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1; 371 372 // get natural texture axis 373 TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); 374 375 // rotate axis 376 if (td->rotate == 0) 377 { sinv = 0 ; cosv = 1; } 378 else if (td->rotate == 90) 379 { sinv = 1 ; cosv = 0; } 380 else if (td->rotate == 180) 381 { sinv = 0 ; cosv = -1; } 382 else if (td->rotate == 270) 383 { sinv = -1 ; cosv = 0; } 384 else 385 { 386 ang = td->rotate / 180 * Q_PI; 387 sinv = sin(ang); 388 cosv = cos(ang); 389 } 390 391 if (pvecs[0][0]) 392 sv = 0; 393 else if (pvecs[0][1]) 394 sv = 1; 395 else 396 sv = 2; 397 398 if (pvecs[1][0]) 399 tv = 0; 400 else if (pvecs[1][1]) 401 tv = 1; 402 else 403 tv = 2; 404 405 for (i=0 ; i<2 ; i++) { 406 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; 407 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; 408 STfromXYZ[i][sv] = ns; 409 STfromXYZ[i][tv] = nt; 410 } 411 412 // scale 413 for (i=0 ; i<2 ; i++) 414 for (j=0 ; j<3 ; j++) 415 STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i]; 416 417 // shift 418 STfromXYZ[0][3] = td->shift[0]; 419 STfromXYZ[1][3] = td->shift[1]; 420 421 for (j=0 ; j<4 ; j++) { 422 STfromXYZ[0][j] /= q->width; 423 STfromXYZ[1][j] /= q->height; 424 } 425 } 426 427 /* 428 ================ 429 Face_MakePlane 430 ================ 431 */ 432 void Face_MakePlane (face_t *f) 433 { 434 int j; 435 vec3_t t1, t2, t3; 436 437 // convert to a vector / dist plane 438 for (j=0 ; j<3 ; j++) 439 { 440 t1[j] = f->planepts[0][j] - f->planepts[1][j]; 441 t2[j] = f->planepts[2][j] - f->planepts[1][j]; 442 t3[j] = f->planepts[1][j]; 443 } 444 445 CrossProduct(t1,t2, f->plane.normal); 446 if (VectorCompare (f->plane.normal, vec3_origin)) 447 printf ("WARNING: brush plane with no normal\n"); 448 VectorNormalize (f->plane.normal); 449 f->plane.dist = DotProduct (t3, f->plane.normal); 450 } 451 452 /* 453 ================ 454 EmitTextureCoordinates 455 ================ 456 */ 457 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) 458 { 459 float STfromXYZ[2][4]; 460 461 Face_TextureVectors (f, STfromXYZ); 462 xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3]; 463 xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3]; 464 } 465 466 //========================================================================== 467 468 /* 469 ================ 470 Brush_MakeFacePlanes 471 ================ 472 */ 473 void Brush_MakeFacePlanes (brush_t *b) 474 { 475 face_t *f; 476 477 for (f=b->brush_faces ; f ; f=f->next) 478 { 479 Face_MakePlane (f); 480 } 481 } 482 483 /* 484 ================ 485 DrawBrushEntityName 486 ================ 487 */ 488 void DrawBrushEntityName (brush_t *b) 489 { 490 char *name; 491 //float a, s, c; 492 //vec3_t mid; 493 //int i; 494 495 if (!b->owner) 496 return; // during contruction 497 498 if (b->owner == world_entity) 499 return; 500 501 if (b != b->owner->brushes.onext) 502 return; // not key brush 503 504 // MERGEME 505 #if 0 506 if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES)) 507 { 508 // draw the angle pointer 509 a = FloatForKey (b->owner, "angle"); 510 if (a) 511 { 512 s = sin (a/180*Q_PI); 513 c = cos (a/180*Q_PI); 514 for (i=0 ; i<3 ; i++) 515 mid[i] = (b->mins[i] + b->maxs[i])*0.5; 516 517 qglBegin (GL_LINE_STRIP); 518 qglVertex3fv (mid); 519 mid[0] += c*8; 520 mid[1] += s*8; 521 mid[2] += s*8; 522 qglVertex3fv (mid); 523 mid[0] -= c*4; 524 mid[1] -= s*4; 525 mid[2] -= s*4; 526 mid[0] -= s*4; 527 mid[1] += c*4; 528 mid[2] += c*4; 529 qglVertex3fv (mid); 530 mid[0] += c*4; 531 mid[1] += s*4; 532 mid[2] += s*4; 533 mid[0] += s*4; 534 mid[1] -= c*4; 535 mid[2] -= c*4; 536 qglVertex3fv (mid); 537 mid[0] -= c*4; 538 mid[1] -= s*4; 539 mid[2] -= s*4; 540 mid[0] += s*4; 541 mid[1] -= c*4; 542 mid[2] -= c*4; 543 qglVertex3fv (mid); 544 qglEnd (); 545 } 546 } 547 #endif 548 549 if (g_qeglobals.d_savedinfo.show_names) 550 { 551 name = ValueForKey (b->owner, "classname"); 552 qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4); 553 qglCallLists (strlen(name), GL_UNSIGNED_BYTE, name); 554 } 555 } 556 557 /* 558 ================= 559 Brush_MakeFaceWinding 560 561 returns the visible polygon on a face 562 ================= 563 */ 564 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face) 565 { 566 winding_t *w; 567 face_t *clip; 568 plane_t plane; 569 qboolean past; 570 571 // get a poly that covers an effectively infinite area 572 w = Winding_BaseForPlane (&face->plane); 573 574 // chop the poly by all of the other faces 575 past = false; 576 for (clip = b->brush_faces ; clip && w ; clip=clip->next) 577 { 578 if (clip == face) 579 { 580 past = true; 581 continue; 582 } 583 if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 584 && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) 585 { // identical plane, use the later one 586 if (past) 587 { 588 free (w); 589 return NULL; 590 } 591 continue; 592 } 593 594 // flip the plane, because we want to keep the back side 595 VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); 596 plane.dist = -clip->plane.dist; 597 598 w = Winding_Clip (w, &plane, false); 599 if (!w) 600 return w; 601 } 602 603 if (w->numpoints < 3) 604 { 605 free(w); 606 w = NULL; 607 } 608 609 if (!w) 610 printf ("unused plane\n"); 611 612 return w; 613 } 614 615 /* 616 ================= 617 Brush_SnapPlanepts 618 ================= 619 */ 620 void Brush_SnapPlanepts (brush_t *b) 621 { 622 int i, j; 623 face_t *f; 624 625 if (g_PrefsDlg.m_bNoClamp) 626 return; 627 628 for (f=b->brush_faces ; f; f=f->next) 629 for (i=0 ; i<3 ; i++) 630 for (j=0 ; j<3 ; j++) 631 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); 632 } 633 634 /* 635 ** Brush_Build 636 ** 637 ** Builds a brush rendering data and also sets the min/max bounds 638 */ 639 // TTimo 640 // added a bConvert flag to convert between old and new brush texture formats 641 // TTimo 642 // brush grouping: update the group treeview if necessary 643 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert ) 644 { 645 bool bLocalConvert; 646 647 #ifdef _DEBUG 648 if (!g_qeglobals.m_bBrushPrimitMode && bConvert) 649 Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n"); 650 #endif 651 652 // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only 653 if (bConvert && !g_qeglobals.bNeedConvert) 654 { 655 bLocalConvert = true; 656 g_qeglobals.bNeedConvert = true; 657 } 658 659 /* 660 ** build the windings and generate the bounding box 661 */ 662 Brush_BuildWindings(b, bSnap); 663 664 Patch_BuildPoints (b); 665 666 /* 667 ** move the points and edges if in select mode 668 */ 669 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) 670 SetupVertexSelection (); 671 672 if (b->itemOwner == NULL) 673 Group_AddToProperGroup(b); 674 675 if (bMarkMap) 676 { 677 Sys_MarkMapModified(); 678 } 679 680 if (bLocalConvert) 681 g_qeglobals.bNeedConvert = false; 682 } 683 684 /* 685 ============== 686 Brush_SplitBrushByFace 687 688 The incoming brush is NOT freed. 689 The incoming face is NOT left referenced. 690 ============== 691 */ 692 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back) 693 { 694 brush_t *b; 695 face_t *nf; 696 vec3_t temp; 697 698 b = Brush_Clone (in); 699 nf = Face_Clone (f); 700 701 nf->texdef = b->brush_faces->texdef; 702 nf->next = b->brush_faces; 703 b->brush_faces = nf; 704 705 Brush_Build( b ); 706 Brush_RemoveEmptyFaces ( b ); 707 if ( !b->brush_faces ) 708 { // completely clipped away 709 Brush_Free (b); 710 *back = NULL; 711 } 712 else 713 { 714 Entity_LinkBrush (in->owner, b); 715 *back = b; 716 } 717 718 b = Brush_Clone (in); 719 nf = Face_Clone (f); 720 // swap the plane winding 721 VectorCopy (nf->planepts[0], temp); 722 VectorCopy (nf->planepts[1], nf->planepts[0]); 723 VectorCopy (temp, nf->planepts[1]); 724 725 nf->texdef = b->brush_faces->texdef; 726 nf->next = b->brush_faces; 727 b->brush_faces = nf; 728 729 Brush_Build( b ); 730 Brush_RemoveEmptyFaces ( b ); 731 if ( !b->brush_faces ) 732 { // completely clipped away 733 Brush_Free (b); 734 *front = NULL; 735 } 736 else 737 { 738 Entity_LinkBrush (in->owner, b); 739 *front = b; 740 } 741 } 742 743 /* 744 ================= 745 Brush_BestSplitFace 746 747 returns the best face to split the brush with. 748 return NULL if the brush is convex 749 ================= 750 */ 751 face_t *Brush_BestSplitFace(brush_t *b) 752 { 753 face_t *face, *f, *bestface; 754 winding_t *front, *back; 755 int splits, tinywindings, value, bestvalue; 756 757 bestvalue = 999999; 758 bestface = NULL; 759 for (face = b->brush_faces; face; face = face->next) 760 { 761 splits = 0; 762 tinywindings = 0; 763 for (f = b->brush_faces; f; f = f->next) 764 { 765 if (f == face) continue; 766 // 767 Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1, &front, &back); 768 769 if (!front) 770 { 771 Winding_Free(back); 772 } 773 else if (!back) 774 { 775 Winding_Free(front); 776 } 777 else 778 { 779 splits++; 780 if (Winding_IsTiny(front)) tinywindings++; 781 if (Winding_IsTiny(back)) tinywindings++; 782 } 783 } 784 if (splits) 785 { 786 value = splits + 50 * tinywindings; 787 if (value < bestvalue) 788 { 789 bestvalue = value; 790 bestface = face; 791 } 792 } 793 } 794 return bestface; 795 } 796 797 /* 798 ================= 799 Brush_MakeConvexBrushes 800 801 MrE FIXME: this doesn't work because the old 802 Brush_SplitBrushByFace is used 803 Turns the brush into a minimal number of convex brushes. 804 If the input brush is convex then it will be returned. 805 Otherwise the input brush will be freed. 806 NOTE: the input brush should have windings for the faces. 807 ================= 808 */ 809 brush_t *Brush_MakeConvexBrushes(brush_t *b) 810 { 811 brush_t *front, *back, *end; 812 face_t *face; 813 814 b->next = NULL; 815 face = Brush_BestSplitFace(b); 816 if (!face) return b; 817 Brush_SplitBrushByFace(b, face, &front, &back); 818 //this should never happen 819 if (!front && !back) return b; 820 Brush_Free(b); 821 if (!front) 822 return Brush_MakeConvexBrushes(back); 823 b = Brush_MakeConvexBrushes(front); 824 if (back) 825 { 826 for (end = b; end->next; end = end->next); 827 end->next = Brush_MakeConvexBrushes(back); 828 } 829 return b; 830 } 831 832 /* 833 ================= 834 Brush_Convex 835 ================= 836 */ 837 int Brush_Convex(brush_t *b) 838 { 839 face_t *face1, *face2; 840 841 for (face1 = b->brush_faces; face1; face1 = face1->next) 842 { 843 if (!face1->face_winding) continue; 844 for (face2 = b->brush_faces; face2; face2 = face2->next) 845 { 846 if (face1 == face2) continue; 847 if (!face2->face_winding) continue; 848 if (Winding_PlanesConcave(face1->face_winding, face2->face_winding, 849 face1->plane.normal, face2->plane.normal, 850 face1->plane.dist, face2->plane.dist)) 851 { 852 return false; 853 } 854 } 855 } 856 return true; 857 } 858 859 /* 860 ================= 861 Brush_MoveVertexes_old1 862 863 - The input brush must have face windings. 864 - The input brush must be a brush with faces that do not intersect. 865 - The input brush does not have to be convex. 866 - The vertex will not be moved if the movement either causes the 867 brush to have faces that intersect or causes the brush to be 868 flipped inside out. 869 (For instance a tetrahedron can easily be flipped inside out 870 without having faces that intersect.) 871 - The created brush does not have to be convex. 872 - Returns true if the vertex movement is performed. 873 ================= 874 */ 875 876 #define MAX_MOVE_FACES 64 877 #define INTERSECT_EPSILON 0.1 878 #define POINT_EPSILON 0.3 879 880 int Brush_MoveVertex_old1(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) 881 { 882 face_t *f, *face, *newface, *lastface, *nextface; 883 face_t *movefaces[MAX_MOVE_FACES]; 884 int movefacepoints[MAX_MOVE_FACES]; 885 winding_t *w, tmpw; 886 int i, j, k, nummovefaces, result; 887 float dot; 888 889 result = false; 890 // 891 tmpw.numpoints = 3; 892 tmpw.maxpoints = 3; 893 VectorAdd(vertex, delta, end); 894 //snap or not? 895 if (bSnap) 896 for (i = 0; i < 3; i++) 897 end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; 898 //chop off triangles from all brush faces that use the to be moved vertex 899 //store pointers to these chopped off triangles in movefaces[] 900 nummovefaces = 0; 901 for (face = b->brush_faces; face; face = face->next) 902 { 903 w = face->face_winding; 904 if (!w) continue; 905 for (i = 0; i < w->numpoints; i++) 906 { 907 if (Point_Equal(w->points[i], vertex, POINT_EPSILON)) 908 { 909 if (face->face_winding->numpoints <= 3) 910 { 911 movefacepoints[nummovefaces] = i; 912 movefaces[nummovefaces++] = face; 913 break; 914 } 915 dot = DotProduct(end, face->plane.normal) - face->plane.dist; 916 //if the end point is in front of the face plane 917 if (dot > 0.1) 918 { 919 //fanout triangle subdivision 920 for (k = i; k < i + w->numpoints-3; k++) 921 { 922 VectorCopy(w->points[i], tmpw.points[0]); 923 VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); 924 VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); 925 // 926 newface = Face_Clone(face); 927 //get the original 928 for (f = face; f->original; f = f->original) ; 929 newface->original = f; 930 //store the new winding 931 if (newface->face_winding) Winding_Free(newface->face_winding); 932 newface->face_winding = Winding_Clone(&tmpw); 933 //get the texture 934 newface->d_texture = Texture_ForName( newface->texdef.name ); 935 //add the face to the brush 936 newface->next = b->brush_faces; 937 b->brush_faces = newface; 938 //add this new triangle to the move faces 939 movefacepoints[nummovefaces] = 0; 940 movefaces[nummovefaces++] = newface; 941 } 942 //give the original face a new winding 943 VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); 944 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); 945 VectorCopy(w->points[i], tmpw.points[2]); 946 Winding_Free(face->face_winding); 947 face->face_winding = Winding_Clone(&tmpw); 948 //add the original face to the move faces 949 movefacepoints[nummovefaces] = 2; 950 movefaces[nummovefaces++] = face; 951 } 952 else 953 { 954 //chop a triangle off the face 955 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); 956 VectorCopy(w->points[i], tmpw.points[1]); 957 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); 958 //remove the point from the face winding 959 Winding_RemovePoint(w, i); 960 //get texture crap right 961 Face_SetColor(b, face, 1.0); 962 for (j = 0; j < w->numpoints; j++) 963 EmitTextureCoordinates(w->points[j], face->d_texture, face); 964 //make a triangle face 965 newface = Face_Clone(face); 966 //get the original 967 for (f = face; f->original; f = f->original) ; 968 newface->original = f; 969 //store the new winding 970 if (newface->face_winding) Winding_Free(newface->face_winding); 971 newface->face_winding = Winding_Clone(&tmpw); 972 //get the texture 973 newface->d_texture = Texture_ForName( newface->texdef.name ); 974 //add the face to the brush 975 newface->next = b->brush_faces; 976 b->brush_faces = newface; 977 // 978 movefacepoints[nummovefaces] = 1; 979 movefaces[nummovefaces++] = newface; 980 } 981 break; 982 } 983 } 984 } 985 //now movefaces contains pointers to triangle faces that 986 //contain the to be moved vertex 987 988 //check if the move is valid 989 int l; 990 vec3_t p1, p2; 991 winding_t *w2; 992 plane_t plane; 993 994 face = NULL; 995 VectorCopy(vertex, tmpw.points[1]); 996 VectorCopy(end, tmpw.points[2]); 997 for (face = b->brush_faces; face; face = face->next) 998 { 999 for (i = 0; i < nummovefaces; i++) 1000 { 1001 if (face == movefaces[i]) 1002 break; 1003 } 1004 if (i < nummovefaces) 1005 continue; 1006 //the delta vector may not intersect with any of the not move faces 1007 if (Winding_VectorIntersect(face->face_winding, &face->plane, vertex, end, INTERSECT_EPSILON)) 1008 break; 1009 //if the end point of the to be moved vertex is near this not move face 1010 if (abs(DotProduct(face->plane.normal, end) - face->plane.dist) < 0.5) 1011 { 1012 //the end point may not be inside or very close to the not move face winding 1013 if (Winding_PointInside(face->face_winding, &face->plane, end, 0.5)) 1014 break; 1015 } 1016 for (i = 0; i < nummovefaces; i++) 1017 { 1018 w = movefaces[i]->face_winding; 1019 j = movefacepoints[i]; 1020 for (k = -1; k <= 1; k += 2) 1021 { 1022 //check if the new edge will not intersect with the not move face 1023 VectorCopy(w->points[(j + k + w->numpoints) % w->numpoints], tmpw.points[0]); 1024 if (Winding_VectorIntersect(face->face_winding, &face->plane, tmpw.points[0], end, INTERSECT_EPSILON)) 1025 { 1026 //ok the new edge instersects with the not move face 1027 //we can't perform the vertex movement 1028 //break; 1029 } 1030 //check if the not move face intersects the "movement winding" 1031 Winding_Plane(&tmpw, plane.normal, &plane.dist); 1032 w2 = face->face_winding; 1033 for (l = 0; l < w2->numpoints; l++) 1034 { 1035 VectorCopy(w2->points[l], p1); 1036 if (Point_Equal(p1, tmpw.points[0], POINT_EPSILON)) continue; 1037 VectorCopy(w2->points[(l+1) % w2->numpoints], p2); 1038 if (Point_Equal(p2, tmpw.points[0], POINT_EPSILON)) continue; 1039 if (Winding_VectorIntersect(&tmpw, &plane, p1, p2, INTERSECT_EPSILON)) 1040 break; 1041 } 1042 if (l < w2->numpoints) 1043 { 1044 //ok this not move face intersects the "movement winding" 1045 //we can't perform the vertex movement 1046 break; 1047 } 1048 } 1049 if (k <= 1) break; 1050 } 1051 if (i < nummovefaces) 1052 break; 1053 } 1054 if (!face) 1055 { 1056 //ok the move was valid 1057 //now move all the vertexes of the movefaces 1058 for (i = 0; i < nummovefaces; i++) 1059 { 1060 VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]); 1061 //create new face plane 1062 for (j = 0; j < 3; j++) 1063 { 1064 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); 1065 } 1066 Face_MakePlane(movefaces[i]); 1067 } 1068 result = true; 1069 } 1070 //get texture crap right 1071 for (i = 0; i < nummovefaces; i++) 1072 { 1073 Face_SetColor(b, movefaces[i], 1.0); 1074 for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) 1075 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); 1076 } 1077 1078 //now try to merge faces with their original faces 1079 lastface = NULL; 1080 for (face = b->brush_faces; face; face = nextface) 1081 { 1082 nextface = face->next; 1083 if (!face->original) 1084 { 1085 lastface = face; 1086 continue; 1087 } 1088 if (!Plane_Equal(&face->plane, &face->original->plane, false)) 1089 { 1090 lastface = face; 1091 continue; 1092 } 1093 w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); 1094 if (!w) 1095 { 1096 lastface = face; 1097 continue; 1098 } 1099 Winding_Free(face->original->face_winding); 1100 face->original->face_winding = w; 1101 //get texture crap right 1102 Face_SetColor(b, face->original, 1.0); 1103 for (j = 0; j < face->original->face_winding->numpoints; j++) 1104 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); 1105 //remove the face that was merged with the original 1106 if (lastface) lastface->next = face->next; 1107 else b->brush_faces = face->next; 1108 Face_Free(face); 1109 } 1110 return result; 1111 } 1112 1113 /* 1114 ================= 1115 Brush_MoveVertexes_old2 1116 1117 - The input brush must be convex 1118 - The input brush must have face windings. 1119 - The output brush will be convex. 1120 - Returns true if the vertex movement is performed. 1121 ================= 1122 */ 1123 1124 #define MAX_MOVE_FACES 64 1125 #define INTERSECT_EPSILON 0.1 1126 #define POINT_EPSILON 0.3 1127 1128 int Brush_MoveVertex_old2(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) 1129 { 1130 face_t *f, *face, *newface, *lastface, *nextface; 1131 face_t *movefaces[MAX_MOVE_FACES]; 1132 int movefacepoints[MAX_MOVE_FACES]; 1133 winding_t *w, tmpw; 1134 int i, j, k, nummovefaces, result; 1135 float dot; 1136 1137 result = true; 1138 // 1139 tmpw.numpoints = 3; 1140 tmpw.maxpoints = 3; 1141 VectorAdd(vertex, delta, end); 1142 //snap or not? 1143 if (bSnap) 1144 for (i = 0; i < 3; i++) 1145 end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; 1146 //chop off triangles from all brush faces that use the to be moved vertex 1147 //store pointers to these chopped off triangles in movefaces[] 1148 nummovefaces = 0; 1149 for (face = b->brush_faces; face; face = face->next) 1150 { 1151 w = face->face_winding; 1152 if (!w) continue; 1153 for (i = 0; i < w->numpoints; i++) 1154 { 1155 if (Point_Equal(w->points[i], vertex, POINT_EPSILON)) 1156 { 1157 if (face->face_winding->numpoints <= 3) 1158 { 1159 movefacepoints[nummovefaces] = i; 1160 movefaces[nummovefaces++] = face; 1161 break; 1162 } 1163 dot = DotProduct(end, face->plane.normal) - face->plane.dist; 1164 //if the end point is in front of the face plane 1165 if (dot > 0.1) 1166 { 1167 //fanout triangle subdivision 1168 for (k = i; k < i + w->numpoints-3; k++) 1169 { 1170 VectorCopy(w->points[i], tmpw.points[0]); 1171 VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); 1172 VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); 1173 // 1174 newface = Face_Clone(face); 1175 //get the original 1176 for (f = face; f->original; f = f->original) ; 1177 newface->original = f; 1178 //store the new winding 1179 if (newface->face_winding) Winding_Free(newface->face_winding); 1180 newface->face_winding = Winding_Clone(&tmpw); 1181 //get the texture 1182 newface->d_texture = Texture_ForName( newface->texdef.name ); 1183 //add the face to the brush 1184 newface->next = b->brush_faces; 1185 b->brush_faces = newface; 1186 //add this new triangle to the move faces 1187 movefacepoints[nummovefaces] = 0; 1188 movefaces[nummovefaces++] = newface; 1189 } 1190 //give the original face a new winding 1191 VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); 1192 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); 1193 VectorCopy(w->points[i], tmpw.points[2]); 1194 Winding_Free(face->face_winding); 1195 face->face_winding = Winding_Clone(&tmpw); 1196 //add the original face to the move faces 1197 movefacepoints[nummovefaces] = 2; 1198 movefaces[nummovefaces++] = face; 1199 } 1200 else 1201 { 1202 //chop a triangle off the face 1203 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); 1204 VectorCopy(w->points[i], tmpw.points[1]); 1205 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); 1206 //remove the point from the face winding 1207 Winding_RemovePoint(w, i); 1208 //get texture crap right 1209 Face_SetColor(b, face, 1.0); 1210 for (j = 0; j < w->numpoints; j++) 1211 EmitTextureCoordinates(w->points[j], face->d_texture, face); 1212 //make a triangle face 1213 newface = Face_Clone(face); 1214 //get the original 1215 for (f = face; f->original; f = f->original) ; 1216 newface->original = f; 1217 //store the new winding 1218 if (newface->face_winding) Winding_Free(newface->face_winding); 1219 newface->face_winding = Winding_Clone(&tmpw); 1220 //get the texture 1221 newface->d_texture = Texture_ForName( newface->texdef.name ); 1222 //add the face to the brush 1223 newface->next = b->brush_faces; 1224 b->brush_faces = newface; 1225 // 1226 movefacepoints[nummovefaces] = 1; 1227 movefaces[nummovefaces++] = newface; 1228 } 1229 break; 1230 } 1231 } 1232 } 1233 //now movefaces contains pointers to triangle faces that 1234 //contain the to be moved vertex 1235 1236 //move the vertex 1237 for (i = 0; i < nummovefaces; i++) 1238 { 1239 //move vertex to end position 1240 VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]); 1241 //create new face plane 1242 for (j = 0; j < 3; j++) 1243 { 1244 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); 1245 } 1246 Face_MakePlane(movefaces[i]); 1247 } 1248 //if the brush is no longer convex 1249 if (!Brush_Convex(b)) 1250 { 1251 for (i = 0; i < nummovefaces; i++) 1252 { 1253 //move the vertex back to the initial position 1254 VectorCopy(vertex, movefaces[i]->face_winding->points[movefacepoints[i]]); 1255 //create new face plane 1256 for (j = 0; j < 3; j++) 1257 { 1258 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); 1259 } 1260 Face_MakePlane(movefaces[i]); 1261 } 1262 result = false; 1263 } 1264 //get texture crap right 1265 for (i = 0; i < nummovefaces; i++) 1266 { 1267 Face_SetColor(b, movefaces[i], 1.0); 1268 for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) 1269 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); 1270 } 1271 1272 //now try to merge faces with their original faces 1273 lastface = NULL; 1274 for (face = b->brush_faces; face; face = nextface) 1275 { 1276 nextface = face->next; 1277 if (!face->original) 1278 { 1279 lastface = face; 1280 continue; 1281 } 1282 if (!Plane_Equal(&face->plane, &face->original->plane, false)) 1283 { 1284 lastface = face; 1285 continue; 1286 } 1287 w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); 1288 if (!w) 1289 { 1290 lastface = face; 1291 continue; 1292 } 1293 Winding_Free(face->original->face_winding); 1294 face->original->face_winding = w; 1295 //get texture crap right 1296 Face_SetColor(b, face->original, 1.0); 1297 for (j = 0; j < face->original->face_winding->numpoints; j++) 1298 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); 1299 //remove the face that was merged with the original 1300 if (lastface) lastface->next = face->next; 1301 else b->brush_faces = face->next; 1302 Face_Free(face); 1303 } 1304 return result; 1305 } 1306 1307 /* 1308 ================= 1309 Brush_MoveVertexes 1310 1311 - The input brush must be convex 1312 - The input brush must have face windings. 1313 - The output brush will be convex. 1314 - Returns true if the WHOLE vertex movement is performed. 1315 ================= 1316 */ 1317 1318 #define MAX_MOVE_FACES 64 1319 1320 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap) 1321 { 1322 face_t *f, *face, *newface, *lastface, *nextface; 1323 face_t *movefaces[MAX_MOVE_FACES]; 1324 int movefacepoints[MAX_MOVE_FACES]; 1325 winding_t *w, tmpw; 1326 vec3_t start, mid; 1327 plane_t plane; 1328 int i, j, k, nummovefaces, result, done; 1329 float dot, front, back, frac, smallestfrac; 1330 1331 result = true; 1332 // 1333 tmpw.numpoints = 3; 1334 tmpw.maxpoints = 3; 1335 VectorCopy(vertex, start); 1336 VectorAdd(vertex, delta, end); 1337 //snap or not? 1338 if (bSnap) 1339 for (i = 0; i < 3; i++) 1340 end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; 1341 // 1342 VectorCopy(end, mid); 1343 //if the start and end are the same 1344 if (Point_Equal(start, end, 0.3)) return false; 1345 //the end point may not be the same as another vertex 1346 for (face = b->brush_faces; face; face = face->next) 1347 { 1348 w = face->face_winding; 1349 if (!w) continue; 1350 for (i = 0; i < w->numpoints; i++) 1351 { 1352 if (Point_Equal(w->points[i], end, 0.3)) 1353 { 1354 VectorCopy(vertex, end); 1355 return false; 1356 } 1357 } 1358 } 1359 // 1360 done = false; 1361 while(!done) 1362 { 1363 //chop off triangles from all brush faces that use the to be moved vertex 1364 //store pointers to these chopped off triangles in movefaces[] 1365 nummovefaces = 0; 1366 for (face = b->brush_faces; face; face = face->next) 1367 { 1368 w = face->face_winding; 1369 if (!w) continue; 1370 for (i = 0; i < w->numpoints; i++) 1371 { 1372 if (Point_Equal(w->points[i], start, 0.2)) 1373 { 1374 if (face->face_winding->numpoints <= 3) 1375 { 1376 movefacepoints[nummovefaces] = i; 1377 movefaces[nummovefaces++] = face; 1378 break; 1379 } 1380 dot = DotProduct(end, face->plane.normal) - face->plane.dist; 1381 //if the end point is in front of the face plane 1382 if (dot > 0.1) 1383 { 1384 //fanout triangle subdivision 1385 for (k = i; k < i + w->numpoints-3; k++) 1386 { 1387 VectorCopy(w->points[i], tmpw.points[0]); 1388 VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]); 1389 VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]); 1390 // 1391 newface = Face_Clone(face); 1392 //get the original 1393 for (f = face; f->original; f = f->original) ; 1394 newface->original = f; 1395 //store the new winding 1396 if (newface->face_winding) Winding_Free(newface->face_winding); 1397 newface->face_winding = Winding_Clone(&tmpw); 1398 //get the texture 1399 newface->d_texture = Texture_ForName( newface->texdef.name ); 1400 //add the face to the brush 1401 newface->next = b->brush_faces; 1402 b->brush_faces = newface; 1403 //add this new triangle to the move faces 1404 movefacepoints[nummovefaces] = 0; 1405 movefaces[nummovefaces++] = newface; 1406 } 1407 //give the original face a new winding 1408 VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]); 1409 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]); 1410 VectorCopy(w->points[i], tmpw.points[2]); 1411 Winding_Free(face->face_winding); 1412 face->face_winding = Winding_Clone(&tmpw); 1413 //add the original face to the move faces 1414 movefacepoints[nummovefaces] = 2; 1415 movefaces[nummovefaces++] = face; 1416 } 1417 else 1418 { 1419 //chop a triangle off the face 1420 VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]); 1421 VectorCopy(w->points[i], tmpw.points[1]); 1422 VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]); 1423 //remove the point from the face winding 1424 Winding_RemovePoint(w, i); 1425 //get texture crap right 1426 Face_SetColor(b, face, 1.0); 1427 for (j = 0; j < w->numpoints; j++) 1428 EmitTextureCoordinates(w->points[j], face->d_texture, face); 1429 //make a triangle face 1430 newface = Face_Clone(face); 1431 //get the original 1432 for (f = face; f->original; f = f->original) ; 1433 newface->original = f; 1434 //store the new winding 1435 if (newface->face_winding) Winding_Free(newface->face_winding); 1436 newface->face_winding = Winding_Clone(&tmpw); 1437 //get the texture 1438 newface->d_texture = Texture_ForName( newface->texdef.name ); 1439 //add the face to the brush 1440 newface->next = b->brush_faces; 1441 b->brush_faces = newface; 1442 // 1443 movefacepoints[nummovefaces] = 1; 1444 movefaces[nummovefaces++] = newface; 1445 } 1446 break; 1447 } 1448 } 1449 } 1450 //now movefaces contains pointers to triangle faces that 1451 //contain the to be moved vertex 1452 // 1453 done = true; 1454 VectorCopy(end, mid); 1455 smallestfrac = 1; 1456 for (face = b->brush_faces; face; face = face->next) 1457 { 1458 //check if there is a move face that has this face as the original 1459 for (i = 0; i < nummovefaces; i++) 1460 { 1461 if (movefaces[i]->original == face) break; 1462 } 1463 if (i >= nummovefaces) continue; 1464 //check if the original is not a move face itself 1465 for (j = 0; j < nummovefaces; j++) 1466 { 1467 if (face == movefaces[j]) break; 1468 } 1469 //if the original is not a move face itself 1470 if (j >= nummovefaces) 1471 { 1472 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t)); 1473 } 1474 else 1475 { 1476 k = movefacepoints[j]; 1477 w = movefaces[j]->face_winding; 1478 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]); 1479 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]); 1480 // 1481 k = movefacepoints[i]; 1482 w = movefaces[i]->face_winding; 1483 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]); 1484 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) 1485 { 1486 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]); 1487 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane)) 1488 //this should never happen otherwise the face merge did a crappy job a previous pass 1489 continue; 1490 } 1491 } 1492 //now we've got the plane to check agains 1493 front = DotProduct(start, plane.normal) - plane.dist; 1494 back = DotProduct(end, plane.normal) - plane.dist; 1495 //if the whole move is at one side of the plane 1496 if (front < 0.01 && back < 0.01) continue; 1497 if (front > -0.01 && back > -0.01) continue; 1498 //if there's no movement orthogonal to this plane at all 1499 if (fabs(front-back) < 0.001) continue; 1500 //ok first only move till the plane is hit 1501 frac = front/(front-back); 1502 if (frac < smallestfrac) 1503 { 1504 mid[0] = start[0] + (end[0] - start[0]) * frac; 1505 mid[1] = start[1] + (end[1] - start[1]) * frac; 1506 mid[2] = start[2] + (end[2] - start[2]) * frac; 1507 smallestfrac = frac; 1508 } 1509 // 1510 done = false; 1511 } 1512 1513 //move the vertex 1514 for (i = 0; i < nummovefaces; i++) 1515 { 1516 //move vertex to end position 1517 VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]); 1518 //create new face plane 1519 for (j = 0; j < 3; j++) 1520 { 1521 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); 1522 } 1523 Face_MakePlane(movefaces[i]); 1524 if (VectorLength(movefaces[i]->plane.normal) < 0.1) 1525 result = false; 1526 } 1527 //if the brush is no longer convex 1528 if (!result || !Brush_Convex(b)) 1529 { 1530 for (i = 0; i < nummovefaces; i++) 1531 { 1532 //move the vertex back to the initial position 1533 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]); 1534 //create new face plane 1535 for (j = 0; j < 3; j++) 1536 { 1537 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]); 1538 } 1539 Face_MakePlane(movefaces[i]); 1540 } 1541 result = false; 1542 VectorCopy(start, end); 1543 done = true; 1544 } 1545 else 1546 { 1547 VectorCopy(mid, start); 1548 } 1549 //get texture crap right 1550 for (i = 0; i < nummovefaces; i++) 1551 { 1552 Face_SetColor(b, movefaces[i], 1.0); 1553 for (j = 0; j < movefaces[i]->face_winding->numpoints; j++) 1554 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]); 1555 } 1556 1557 //now try to merge faces with their original faces 1558 lastface = NULL; 1559 for (face = b->brush_faces; face; face = nextface) 1560 { 1561 nextface = face->next; 1562 if (!face->original) 1563 { 1564 lastface = face; 1565 continue; 1566 } 1567 if (!Plane_Equal(&face->plane, &face->original->plane, false)) 1568 { 1569 lastface = face; 1570 continue; 1571 } 1572 w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true); 1573 if (!w) 1574 { 1575 lastface = face; 1576 continue; 1577 } 1578 Winding_Free(face->original->face_winding); 1579 face->original->face_winding = w; 1580 //get texture crap right 1581 Face_SetColor(b, face->original, 1.0); 1582 for (j = 0; j < face->original->face_winding->numpoints; j++) 1583 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original); 1584 //remove the face that was merged with the original 1585 if (lastface) lastface->next = face->next; 1586 else b->brush_faces = face->next; 1587 Face_Free(face); 1588 } 1589 } 1590 return result; 1591 } 1592 1593 /* 1594 ================= 1595 Brush_InsertVertexBetween 1596 ================= 1597 */ 1598 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2) 1599 { 1600 face_t *face; 1601 winding_t *w, *neww; 1602 vec3_t point; 1603 int i, insert; 1604 1605 if (Point_Equal(p1, p2, 0.4)) 1606 return false; 1607 VectorAdd(p1, p2, point); 1608 VectorScale(point, 0.5, point); 1609 insert = false; 1610 //the end point may not be the same as another vertex 1611 for (face = b->brush_faces; face; face = face->next) 1612 { 1613 w = face->face_winding; 1614 if (!w) continue; 1615 neww = NULL; 1616 for (i = 0; i < w->numpoints; i++) 1617 { 1618 if (!Point_Equal(w->points[i], p1, 0.1)) 1619 continue; 1620 if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1)) 1621 { 1622 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints); 1623 break; 1624 } 1625 else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3)) 1626 { 1627 neww = Winding_InsertPoint(w, point, i); 1628 break; 1629 } 1630 } 1631 if (neww) 1632 { 1633 Winding_Free(face->face_winding); 1634 face->face_winding = neww; 1635 insert = true; 1636 } 1637 } 1638 return insert; 1639 } 1640 1641 1642 /* 1643 ================= 1644 Brush_ResetFaceOriginals 1645 ================= 1646 */ 1647 void Brush_ResetFaceOriginals(brush_t *b) 1648 { 1649 face_t *face; 1650 1651 for (face = b->brush_faces; face; face = face->next) 1652 { 1653 face->original = NULL; 1654 } 1655 } 1656 1657 /* 1658 ================= 1659 Brush_Parse 1660 1661 The brush is NOT linked to any list 1662 ================= 1663 */ 1664 //++timo FIXME: when using old brush primitives, the test loop for "Brush" and "patchDef2" "patchDef3" is ran 1665 // before each face parsing. It works, but it's a performance hit 1666 brush_t *Brush_Parse (void) 1667 { 1668 brush_t *b; 1669 face_t *f; 1670 int i,j; 1671 1672 g_qeglobals.d_parsed_brushes++; 1673 b = Brush_Alloc(); 1674 1675 do 1676 { 1677 if (!GetToken (true)) 1678 break; 1679 if (!strcmp (token, "}") ) 1680 break; 1681 1682 // handle "Brush" primitive 1683 if (strcmpi(token, "brushDef") == 0) 1684 { 1685 // Timo parsing new brush format 1686 g_qeglobals.bPrimitBrushes=true; 1687 // check the map is not mixing the two kinds of brushes 1688 if (g_qeglobals.m_bBrushPrimitMode) 1689 { 1690 if (g_qeglobals.bOldBrushes) 1691 Sys_Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n"); 1692 } 1693 //++Timo write new brush primitive -> old conversion code for Q3->Q2 conversions ? 1694 else 1695 Sys_Printf("Warning : conversion code from brush primitive not done ( Brush_Parse )\n"); 1696 1697 BrushPrimit_Parse(b); 1698 if (b == NULL) 1699 { 1700 Warning ("parsing brush primitive"); 1701 return NULL; 1702 } 1703 else 1704 { 1705 continue; 1706 } 1707 } 1708 if ( strcmpi( token, "terrainDef" ) == 0 ) 1709 { 1710 free (b); 1711 1712 b = Terrain_Parse(); 1713 if (b == NULL) 1714 { 1715 Warning ("parsing terrain/brush"); 1716 return NULL; 1717 } 1718 else 1719 { 1720 continue; 1721 } 1722 } 1723 if (strcmpi(token, "patchDef2") == 0 || strcmpi(token, "patchDef3") == 0) 1724 { 1725 free (b); 1726 1727 // double string compare but will go away soon 1728 b = Patch_Parse(strcmpi(token, "patchDef2") == 0); 1729 if (b == NULL) 1730 { 1731 Warning ("parsing patch/brush"); 1732 return NULL; 1733 } 1734 else 1735 { 1736 continue; 1737 } 1738 // handle inline patch 1739 } 1740 else 1741 { 1742 // Timo parsing old brush format 1743 g_qeglobals.bOldBrushes=true; 1744 if (g_qeglobals.m_bBrushPrimitMode) 1745 { 1746 // check the map is not mixing the two kinds of brushes 1747 if (g_qeglobals.bPrimitBrushes) 1748 Sys_Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n"); 1749 // set the "need" conversion flag 1750 g_qeglobals.bNeedConvert=true; 1751 } 1752 1753 f = Face_Alloc(); 1754 1755 // add the brush to the end of the chain, so 1756 // loading and saving a map doesn't reverse the order 1757 1758 f->next = NULL; 1759 if (!b->brush_faces) 1760 { 1761 b->brush_faces = f; 1762 } 1763 else 1764 { 1765 face_t *scan; 1766 for (scan=b->brush_faces ; scan->next ; scan=scan->next) 1767 ; 1768 scan->next = f; 1769 } 1770 1771 // read the three point plane definition 1772 for (i=0 ; i<3 ; i++) 1773 { 1774 if (i != 0) 1775 GetToken (true); 1776 if (strcmp (token, "(") ) 1777 { 1778 Warning ("parsing brush"); 1779 return NULL; 1780 } 1781 1782 for (j=0 ; j<3 ; j++) 1783 { 1784 GetToken (false); 1785 f->planepts[i][j] = atof(token); 1786 } 1787 1788 GetToken (false); 1789 if (strcmp (token, ")") ) 1790 { 1791 Warning ("parsing brush"); 1792 return NULL; 1793 } 1794 } 1795 } 1796 1797 // Timo 1798 // if we have a surface plugin, we'll call the plugin parsing 1799 if (g_qeglobals.bSurfacePropertiesPlugin) 1800 { 1801 GETPLUGINTEXDEF(f)->ParseTexdef(); 1802 } 1803 else 1804 { 1805 1806 // read the texturedef 1807 GetToken (false); 1808 f->texdef.SetName(token); 1809 if (token[0] == '(') 1810 { 1811 int i = 32; 1812 } 1813 GetToken (false); 1814 f->texdef.shift[0] = atoi(token); 1815 GetToken (false); 1816 f->texdef.shift[1] = atoi(token); 1817 GetToken (false); 1818 f->texdef.rotate = atoi(token); 1819 GetToken (false); 1820 f->texdef.scale[0] = atof(token); 1821 GetToken (false); 1822 f->texdef.scale[1] = atof(token); 1823 1824 // the flags and value field aren't necessarily present 1825 f->d_texture = Texture_ForName( f->texdef.name ); 1826 f->texdef.flags = f->d_texture->flags; 1827 f->texdef.value = f->d_texture->value; 1828 f->texdef.contents = f->d_texture->contents; 1829 1830 if (TokenAvailable ()) 1831 { 1832 GetToken (false); 1833 f->texdef.contents = atoi(token); 1834 GetToken (false); 1835 f->texdef.flags = atoi(token); 1836 GetToken (false); 1837 f->texdef.value = atoi(token); 1838 } 1839 1840 } 1841 } while (1); 1842 1843 return b; 1844 } 1845 1846 /* 1847 ================= 1848 QERApp_MapPrintf_FILE 1849 callback for surface properties plugin 1850 must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h ) 1851 ================= 1852 */ 1853 // carefully initialize ! 1854 FILE * g_File; 1855 void WINAPI QERApp_MapPrintf_FILE( char *text, ... ) 1856 { 1857 va_list argptr; 1858 char buf[32768]; 1859 1860 va_start (argptr,text); 1861 vsprintf (buf, text,argptr); 1862 va_end (argptr); 1863 1864 fprintf( g_File, buf ); 1865 } 1866 1867 1868 /* 1869 ============== 1870 Brush_SetEpair 1871 sets an epair for the given brush 1872 ============== 1873 */ 1874 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) 1875 { 1876 if (g_qeglobals.m_bBrushPrimitMode) 1877 { 1878 if (b->patchBrush) 1879 { 1880 Patch_SetEpair(b->pPatch, pKey, pValue); 1881 } 1882 else if (b->terrainBrush) 1883 { 1884 Terrain_SetEpair(b->pTerrain, pKey, pValue); 1885 } 1886 else 1887 { 1888 SetKeyValue(b->epairs, pKey, pValue); 1889 } 1890 } 1891 else 1892 { 1893 Sys_Printf("Can only set key/values in Brush primitive mode\n"); 1894 } 1895 } 1896 1897 /* 1898 ================= 1899 Brush_GetKeyValue 1900 ================= 1901 */ 1902 const char* Brush_GetKeyValue(brush_t *b, const char *pKey) 1903 { 1904 if (g_qeglobals.m_bBrushPrimitMode) 1905 { 1906 if (b->patchBrush) 1907 { 1908 return Patch_GetKeyValue(b->pPatch, pKey); 1909 } 1910 else if (b->terrainBrush) 1911 { 1912 return Terrain_GetKeyValue(b->pTerrain, pKey); 1913 } 1914 else 1915 { 1916 return ValueForKey(b->epairs, pKey); 1917 } 1918 } 1919 else 1920 { 1921 Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n"); 1922 } 1923 return ""; 1924 } 1925 1926 /* 1927 ================= 1928 Brush_Write 1929 save all brushes as Brush primitive format 1930 ================= 1931 */ 1932 void Brush_Write (brush_t *b, FILE *f) 1933 { 1934 epair_t *ep; 1935 face_t *fa; 1936 char *pname; 1937 int i; 1938 1939 if (b->patchBrush) 1940 { 1941 Patch_Write(b->pPatch, f); 1942 return; 1943 } 1944 if ( b->pTerrain ) 1945 { 1946 Terrain_Write(b->pTerrain, f); 1947 return; 1948 } 1949 if (g_qeglobals.m_bBrushPrimitMode) 1950 { 1951 // save brush primitive format 1952 fprintf (f, "{\nbrushDef\n{\n"); 1953 // brush epairs 1954 if (b->epairs) 1955 for (ep = b->epairs ; ep ; ep=ep->next) 1956 fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value); 1957 for (fa=b->brush_faces ; fa ; fa=fa->next) 1958 { 1959 // save planepts 1960 for (i=0 ; i<3 ; i++) 1961 { 1962 fprintf(f, "( "); 1963 for (int j = 0; j < 3; j++) 1964 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) 1965 fprintf(f, "%i ", static_cast<int>(fa->planepts[i][j])); 1966 else 1967 fprintf(f, "%f ", fa->planepts[i][j]); 1968 fprintf(f, ") "); 1969 } 1970 // save texture coordinates 1971 fprintf(f,"( ( "); 1972 for (i=0 ; i<3 ; i++) 1973 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) 1974 fprintf(f,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[0][i])); 1975 else 1976 fprintf(f,"%f ",fa->brushprimit_texdef.coords[0][i]); 1977 fprintf(f,") ( "); 1978 for (i=0 ; i<3 ; i++) 1979 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) 1980 fprintf(f,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[1][i])); 1981 else 1982 fprintf(f,"%f ",fa->brushprimit_texdef.coords[1][i]); 1983 fprintf(f,") ) "); 1984 // save texture attribs 1985 //++timo surface properties plugin not implemented for brush primitives 1986 if (g_qeglobals.bSurfacePropertiesPlugin) 1987 Sys_Printf("WARNING: surface properties plugin not supported with brush primitives (yet)\n"); 1988 1989 char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed"; 1990 fprintf(f, "%s ", pName ); 1991 fprintf(f, "%i %i %i\n", fa->texdef.contents, fa->texdef.flags, fa->texdef.value); 1992 } 1993 fprintf (f, "}\n}\n"); 1994 } 1995 else 1996 { 1997 fprintf (f, "{\n"); 1998 for (fa=b->brush_faces ; fa ; fa=fa->next) 1999 { 2000 for (i=0 ; i<3 ; i++) 2001 { 2002 fprintf(f, "( "); 2003 for (int j = 0; j < 3; j++) 2004 { 2005 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) 2006 fprintf(f, "%i ", static_cast<int>(fa->planepts[i][j])); 2007 else 2008 fprintf(f, "%f ", fa->planepts[i][j]); 2009 } 2010 fprintf(f, ") "); 2011 } 2012 2013 if (g_qeglobals.bSurfacePropertiesPlugin) 2014 { 2015 g_File = f; 2016 #ifdef _DEBUG 2017 if (!fa->pData) 2018 Sys_Printf("ERROR: unexpected IPluginTexdef* is NULL in Brush_Write\n"); 2019 else 2020 #endif 2021 GETPLUGINTEXDEF(fa)->WriteTexdef( QERApp_MapPrintf_FILE ); 2022 } 2023 else 2024 { 2025 pname = fa->texdef.name; 2026 if (pname[0] == 0) 2027 pname = "unnamed"; 2028 2029 fprintf (f, "%s %i %i %i ", pname, 2030 (int)fa->texdef.shift[0], (int)fa->texdef.shift[1], 2031 (int)fa->texdef.rotate); 2032 2033 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) 2034 fprintf (f, "%i ", (int)fa->texdef.scale[0]); 2035 else 2036 fprintf (f, "%f ", (float)fa->texdef.scale[0]); 2037 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) 2038 fprintf (f, "%i", (int)fa->texdef.scale[1]); 2039 else 2040 fprintf (f, "%f", (float)fa->texdef.scale[1]); 2041 2042 fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value); 2043 } 2044 fprintf (f, "\n"); 2045 } 2046 fprintf (f, "}\n"); 2047 } 2048 } 2049 2050 /* 2051 ================= 2052 QERApp_MapPrintf_MEMFILE 2053 callback for surface properties plugin 2054 must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h ) 2055 ================= 2056 */ 2057 // carefully initialize ! 2058 CMemFile * g_pMemFile; 2059 void WINAPI QERApp_MapPrintf_MEMFILE( char *text, ... ) 2060 { 2061 va_list argptr; 2062 char buf[32768]; 2063 2064 va_start (argptr,text); 2065 vsprintf (buf, text,argptr); 2066 va_end (argptr); 2067 2068 MemFile_fprintf( g_pMemFile, buf ); 2069 } 2070 2071 /* 2072 ================= 2073 Brush_Write to a CMemFile* 2074 save all brushes as Brush primitive format 2075 ================= 2076 */ 2077 void Brush_Write (brush_t *b, CMemFile *pMemFile) 2078 { 2079 epair_t *ep; 2080 face_t *fa; 2081 char *pname; 2082 int i; 2083 2084 if (b->patchBrush) 2085 { 2086 Patch_Write(b->pPatch, pMemFile); 2087 return; 2088 } 2089 if (b->terrainBrush) 2090 { 2091 Terrain_Write(b->pTerrain, pMemFile); 2092 return; 2093 } 2094 //++timo NOTE: it's not very difficult to add since the surface properties plugin 2095 // writes throught a printf-style function prototype 2096 if (g_qeglobals.bSurfacePropertiesPlugin) 2097 { 2098 Sys_Printf("WARNING: Brush_Write to a CMemFile and Surface Properties plugin not done\n"); 2099 } 2100 if (g_qeglobals.m_bBrushPrimitMode) 2101 { 2102 // brush primitive format 2103 MemFile_fprintf (pMemFile, "{\nBrushDef\n{\n"); 2104 // brush epairs 2105 if (b->epairs) 2106 for( ep = b->epairs ; ep ; ep=ep->next ) 2107 MemFile_fprintf (pMemFile, "\"%s\" \"%s\"\n", ep->key, ep->value ); 2108 for (fa=b->brush_faces ; fa ; fa=fa->next) 2109 { 2110 // save planepts 2111 for (i=0 ; i<3 ; i++) 2112 { 2113 MemFile_fprintf(pMemFile, "( "); 2114 for (int j = 0; j < 3; j++) 2115 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) 2116 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j])); 2117 else 2118 MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]); 2119 MemFile_fprintf(pMemFile, ") "); 2120 } 2121 // save texture coordinates 2122 MemFile_fprintf(pMemFile,"( ( "); 2123 for (i=0 ; i<3 ; i++) 2124 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) 2125 MemFile_fprintf(pMemFile,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[0][i])); 2126 else 2127 MemFile_fprintf(pMemFile,"%f ",fa->brushprimit_texdef.coords[0][i]); 2128 MemFile_fprintf(pMemFile,") ( "); 2129 for (i=0 ; i<3 ; i++) 2130 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) 2131 MemFile_fprintf(pMemFile,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[1][i])); 2132 else 2133 MemFile_fprintf(pMemFile,"%f ",fa->brushprimit_texdef.coords[1][i]); 2134 MemFile_fprintf(pMemFile,") ) "); 2135 // save texture attribs 2136 char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed"; 2137 MemFile_fprintf(pMemFile, "%s ", pName); 2138 MemFile_fprintf(pMemFile, "%i %i %i\n", fa->texdef.contents, fa->texdef.flags, fa->texdef.value); 2139 } 2140 MemFile_fprintf (pMemFile, "}\n}\n"); 2141 } 2142 else 2143 { 2144 // old brushes format 2145 // also handle surface properties plugin 2146 MemFile_fprintf (pMemFile, "{\n"); 2147 for (fa=b->brush_faces ; fa ; fa=fa->next) 2148 { 2149 for (i=0 ; i<3 ; i++) 2150 { 2151 MemFile_fprintf(pMemFile, "( "); 2152 for (int j = 0; j < 3; j++) 2153 { 2154 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) 2155 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j])); 2156 else 2157 MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]); 2158 } 2159 MemFile_fprintf(pMemFile, ") "); 2160 } 2161 2162 if (g_qeglobals.bSurfacePropertiesPlugin) 2163 { 2164 g_pMemFile = pMemFile; 2165 #ifdef _DEBUG 2166 if (!fa->pData) 2167 Sys_Printf("ERROR: unexpected IPluginTexdef* is NULL in Brush_Write\n"); 2168 else 2169 #endif 2170 GETPLUGINTEXDEF(fa)->WriteTexdef( QERApp_MapPrintf_MEMFILE ); 2171 } 2172 else 2173 { 2174 pname = fa->texdef.name; 2175 if (pname[0] == 0) 2176 pname = "unnamed"; 2177 2178 MemFile_fprintf (pMemFile, "%s %i %i %i ", pname, 2179 (int)fa->texdef.shift[0], (int)fa->texdef.shift[1], 2180 (int)fa->texdef.rotate); 2181 2182 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) 2183 MemFile_fprintf (pMemFile, "%i ", (int)fa->texdef.scale[0]); 2184 else 2185 MemFile_fprintf (pMemFile, "%f ", (float)fa->texdef.scale[0]); 2186 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) 2187 MemFile_fprintf (pMemFile, "%i", (int)fa->texdef.scale[1]); 2188 else 2189 MemFile_fprintf (pMemFile, "%f", (float)fa->texdef.scale[1]); 2190 2191 MemFile_fprintf (pMemFile, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value); 2192 } 2193 MemFile_fprintf (pMemFile, "\n"); 2194 } 2195 MemFile_fprintf (pMemFile, "}\n"); 2196 } 2197 2198 2199 } 2200 2201 2202 /* 2203 ============= 2204 Brush_Create 2205 2206 Create non-textured blocks for entities 2207 The brush is NOT linked to any list 2208 ============= 2209 */ 2210 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) 2211 { 2212 int i, j; 2213 vec3_t pts[4][2]; 2214 face_t *f; 2215 brush_t *b; 2216 2217 // brush primitive mode : convert texdef to brushprimit_texdef ? 2218 // most of the time texdef is empty 2219 if (g_qeglobals.m_bBrushPrimitMode) 2220 { 2221 // check texdef is empty .. if there are cases it's not we need to write some conversion code 2222 if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0) 2223 Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n"); 2224 } 2225 2226 for (i=0 ; i<3 ; i++) 2227 { 2228 if (maxs[i] < mins[i]) 2229 Error ("Brush_InitSolid: backwards"); 2230 } 2231 2232 b = Brush_Alloc(); 2233 2234 pts[0][0][0] = mins[0]; 2235 pts[0][0][1] = mins[1]; 2236 2237 pts[1][0][0] = mins[0]; 2238 pts[1][0][1] = maxs[1]; 2239 2240 pts[2][0][0] = maxs[0]; 2241 pts[2][0][1] = maxs[1]; 2242 2243 pts[3][0][0] = maxs[0]; 2244 pts[3][0][1] = mins[1]; 2245 2246 for (i=0 ; i<4 ; i++) 2247 { 2248 pts[i][0][2] = mins[2]; 2249 pts[i][1][0] = pts[i][0][0]; 2250 pts[i][1][1] = pts[i][0][1]; 2251 pts[i][1][2] = maxs[2]; 2252 } 2253 2254 for (i=0 ; i<4 ; i++) 2255 { 2256 f = Face_Alloc(); 2257 f->texdef = *texdef; 2258 f->texdef.flags &= ~SURF_KEEP; 2259 f->texdef.contents &= ~CONTENTS_KEEP; 2260 f->next = b->brush_faces; 2261 b->brush_faces = f; 2262 j = (i+1)%4; 2263 2264 VectorCopy (pts[j][1], f->planepts[0]); 2265 VectorCopy (pts[i][1], f->planepts[1]); 2266 VectorCopy (pts[i][0], f->planepts[2]); 2267 } 2268 2269 f = Face_Alloc(); 2270 f->texdef = *texdef; 2271 f->texdef.flags &= ~SURF_KEEP; 2272 f->texdef.contents &= ~CONTENTS_KEEP; 2273 f->next = b->brush_faces; 2274 b->brush_faces = f; 2275 2276 VectorCopy (pts[0][1], f->planepts[0]); 2277 VectorCopy (pts[1][1], f->planepts[1]); 2278 VectorCopy (pts[2][1], f->planepts[2]); 2279 2280 f = Face_Alloc(); 2281 f->texdef = *texdef; 2282 f->texdef.flags &= ~SURF_KEEP; 2283 f->texdef.contents &= ~CONTENTS_KEEP; 2284 f->next = b->brush_faces; 2285 b->brush_faces = f; 2286 2287 VectorCopy (pts[2][0], f->planepts[0]); 2288 VectorCopy (pts[1][0], f->planepts[1]); 2289 VectorCopy (pts[0][0], f->planepts[2]); 2290 2291 return b; 2292 } 2293 2294 /* 2295 ============= 2296 Brush_CreatePyramid 2297 2298 Create non-textured pyramid for light entities 2299 The brush is NOT linked to any list 2300 ============= 2301 */ 2302 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef) 2303 { 2304 //++timo handle new brush primitive ? return here ?? 2305 return Brush_Create(mins, maxs, texdef); 2306 2307 for (int i=0 ; i<3 ; i++) 2308 if (maxs[i] < mins[i]) 2309 Error ("Brush_InitSolid: backwards"); 2310 2311 brush_t* b = Brush_Alloc(); 2312 2313 vec3_t corners[4]; 2314 2315 float fMid = Q_rint(mins[2] + (Q_rint((maxs[2] - mins[2]) / 2))); 2316 2317 corners[0][0] = mins[0]; 2318 corners[0][1] = mins[1]; 2319 corners[0][2] = fMid; 2320 2321 corners[1][0] = mins[0]; 2322 corners[1][1] = maxs[1]; 2323 corners[1][2] = fMid; 2324 2325 corners[2][0] = maxs[0]; 2326 corners[2][1] = maxs[1]; 2327 corners[2][2] = fMid; 2328 2329 corners[3][0] = maxs[0]; 2330 corners[3][1] = mins[1]; 2331 corners[3][2] = fMid; 2332 2333 vec3_t top, bottom; 2334 2335 top[0] = Q_rint(mins[0] + ((maxs[0] - mins[0]) / 2)); 2336 top[1] = Q_rint(mins[1] + ((maxs[1] - mins[1]) / 2)); 2337 top[2] = Q_rint(maxs[2]); 2338 2339 VectorCopy(top, bottom); 2340 bottom[2] = mins[2]; 2341 2342 // sides 2343 for (i = 0; i < 4; i++) 2344 { 2345 face_t* f = Face_Alloc(); 2346 f->texdef = *texdef; 2347 f->texdef.flags &= ~SURF_KEEP; 2348 f->texdef.contents &= ~CONTENTS_KEEP; 2349 f->next = b->brush_faces; 2350 b->brush_faces = f; 2351 int j = (i+1)%4; 2352 2353 VectorCopy (top, f->planepts[0]); 2354 VectorCopy (corners[i], f->planepts[1]); 2355 VectorCopy(corners[j], f->planepts[2]); 2356 2357 f = Face_Alloc(); 2358 f->texdef = *texdef; 2359 f->texdef.flags &= ~SURF_KEEP; 2360 f->texdef.contents &= ~CONTENTS_KEEP; 2361 f->next = b->brush_faces; 2362 b->brush_faces = f; 2363 2364 VectorCopy (bottom, f->planepts[2]); 2365 VectorCopy (corners[i], f->planepts[1]); 2366 VectorCopy(corners[j], f->planepts[0]); 2367 } 2368 2369 return b; 2370 } 2371 2372 2373 2374 2375 /* 2376 ============= 2377 Brush_MakeSided 2378 2379 Makes the current brush have the given number of 2d sides 2380 ============= 2381 */ 2382 void Brush_MakeSided (int sides) 2383 { 2384 int i, axis; 2385 vec3_t mins, maxs; 2386 brush_t *b; 2387 texdef_t *texdef; 2388 face_t *f; 2389 vec3_t mid; 2390 float width; 2391 float sv, cv; 2392 2393 if (sides < 3) 2394 { 2395 Sys_Status ("Bad sides number", 0); 2396 return; 2397 } 2398 2399 if (sides >= MAX_POINTS_ON_WINDING-4) 2400 { 2401 Sys_Printf("too many sides.\n"); 2402 return; 2403 } 2404 2405 if (!QE_SingleBrush ()) 2406 { 2407 Sys_Status ("Must have a single brush selected", 0 ); 2408 return; 2409 } 2410 2411 b = selected_brushes.next; 2412 VectorCopy (b->mins, mins); 2413 VectorCopy (b->maxs, maxs); 2414 texdef = &g_qeglobals.d_texturewin.texdef; 2415 2416 Brush_Free (b); 2417 2418 if (g_pParentWnd->ActiveXY()) 2419 { 2420 switch(g_pParentWnd->ActiveXY()->GetViewType()) 2421 { 2422 case XY: axis = 2; break; 2423 case XZ: axis = 1; break; 2424 case YZ: axis = 0; break; 2425 } 2426 } 2427 else 2428 { 2429 axis = 2; 2430 } 2431 2432 // find center of brush 2433 width = 8; 2434 for (i = 0; i < 3; i++) 2435 { 2436 mid[i] = (maxs[i] + mins[i]) * 0.5; 2437 if (i == axis) continue; 2438 if ((maxs[i] - mins[i]) * 0.5 > width) 2439 width = (maxs[i] - mins[i]) * 0.5; 2440 } 2441 2442 b = Brush_Alloc(); 2443 2444 // create top face 2445 f = Face_Alloc(); 2446 f->texdef = *texdef; 2447 f->next = b->brush_faces; 2448 b->brush_faces = f; 2449 2450 f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis]; 2451 f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis]; 2452 f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis]; 2453 2454 // create bottom face 2455 f = Face_Alloc(); 2456 f->texdef = *texdef; 2457 f->next = b->brush_faces; 2458 b->brush_faces = f; 2459 2460 f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis]; 2461 f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis]; 2462 f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis]; 2463 2464 for (i=0 ; i<sides ; i++) 2465 { 2466 f = Face_Alloc(); 2467 f->texdef = *texdef; 2468 f->next = b->brush_faces; 2469 b->brush_faces = f; 2470 2471 sv = sin (i*3.14159265*2/sides); 2472 cv = cos (i*3.14159265*2/sides); 2473 2474 f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5); 2475 f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5); 2476 f->planepts[0][axis] = mins[axis]; 2477 2478 f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3]; 2479 f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3]; 2480 f->planepts[1][axis] = maxs[axis]; 2481 2482 f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5); 2483 f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5); 2484 f->planepts[2][axis] = maxs[axis]; 2485 } 2486 2487 Brush_AddToList (b, &selected_brushes); 2488 2489 Entity_LinkBrush (world_entity, b); 2490 2491 Brush_Build( b ); 2492 2493 Sys_UpdateWindows (W_ALL); 2494 } 2495 2496 2497 2498 /* 2499 ============= 2500 Brush_Free 2501 2502 Frees the brush with all of its faces and display list. 2503 Unlinks the brush from whichever chain it is in. 2504 Decrements the owner entity's brushcount. 2505 Removes owner entity if this was the last brush 2506 unless owner is the world. 2507 Removes from groups 2508 ============= 2509 */ 2510 void Brush_Free (brush_t *b, bool bRemoveNode) 2511 { 2512 face_t *f, *next; 2513 epair_t *ep, *enext; 2514 2515 // remove from group 2516 if (bRemoveNode) 2517 Group_RemoveBrush(b); 2518 2519 // free the patch if it's there 2520 if (b->patchBrush) 2521 { 2522 Patch_Delete(b->pPatch); 2523 } 2524 2525 if( b->terrainBrush ) 2526 { 2527 Terrain_Delete( b->pTerrain ); 2528 } 2529 2530 // free faces 2531 for (f=b->brush_faces ; f ; f=next) 2532 { 2533 next = f->next; 2534 Face_Free( f ); 2535 } 2536 2537 //Timo : free brush epairs 2538 for (ep = b->epairs ; ep ; ep=enext ) 2539 { 2540 enext = ep->next; 2541 free (ep->key); 2542 free (ep->value); 2543 free (ep); 2544 } 2545 2546 // unlink from active/selected list 2547 if (b->next) 2548 Brush_RemoveFromList (b); 2549 2550 // unlink from entity list 2551 if (b->onext) 2552 Entity_UnlinkBrush (b); 2553 2554 free (b); 2555 } 2556 2557 /* 2558 ============= 2559 Face_MemorySize 2560 ============= 2561 */ 2562 int Face_MemorySize(face_t *f ) 2563 { 2564 int size = 0; 2565 2566 if (f->face_winding) 2567 { 2568 size += _msize(f->face_winding); 2569 } 2570 //f->texdef.~texdef_t();; 2571 size += _msize(f); 2572 return size; 2573 } 2574 2575 /* 2576 ============= 2577 Brush_MemorySize 2578 ============= 2579 */ 2580 int Brush_MemorySize(brush_t *b) 2581 { 2582 face_t *f; 2583 epair_t *ep; 2584 int size = 0; 2585 2586 // 2587 if (b->patchBrush) 2588 { 2589 size += Patch_MemorySize(b->pPatch); 2590 } 2591 if (b->terrainBrush) 2592 { 2593 size += Terrain_MemorySize(b->pTerrain); 2594 } 2595 // 2596 for (f = b->brush_faces; f; f = f->next) 2597 { 2598 size += Face_MemorySize(f); 2599 } 2600 // 2601 for (ep = b->epairs; ep; ep = ep->next ) 2602 { 2603 size += _msize(ep->key); 2604 size += _msize(ep->value); 2605 size += _msize(ep); 2606 } 2607 size += _msize(b); 2608 return size; 2609 } 2610 2611 2612 /* 2613 ============ 2614 Brush_Clone 2615 2616 Does NOT add the new brush to any lists 2617 ============ 2618 */ 2619 brush_t *Brush_Clone (brush_t *b) 2620 { 2621 brush_t *n = NULL; 2622 face_t *f, *nf; 2623 2624 if (b->patchBrush) 2625 { 2626 patchMesh_t *p = Patch_Duplicate(b->pPatch); 2627 Brush_RemoveFromList(p->pSymbiot); 2628 Entity_UnlinkBrush(p->pSymbiot); 2629 n = p->pSymbiot; 2630 } 2631 else if (b->terrainBrush) 2632 { 2633 terrainMesh_t *p = Terrain_Duplicate(b->pTerrain); 2634 Brush_RemoveFromList(p->pSymbiot); 2635 Entity_UnlinkBrush(p->pSymbiot); 2636 n = p->pSymbiot; 2637 } 2638 else 2639 { 2640 n = Brush_Alloc(); 2641 n->numberId = g_nBrushId++; 2642 n->owner = b->owner; 2643 for (f=b->brush_faces ; f ; f=f->next) 2644 { 2645 nf = Face_Clone( f ); 2646 nf->next = n->brush_faces; 2647 n->brush_faces = nf; 2648 } 2649 } 2650 2651 return n; 2652 } 2653 2654 2655 2656 /* 2657 ============ 2658 Brush_Clone 2659 2660 Does NOT add the new brush to any lists 2661 ============ 2662 */ 2663 brush_t *Brush_FullClone(brush_t *b) 2664 { 2665 brush_t *n = NULL; 2666 face_t *f, *nf, *f2, *nf2; 2667 int j; 2668 2669 if (b->patchBrush) 2670 { 2671 patchMesh_t *p = Patch_Duplicate(b->pPatch); 2672 Brush_RemoveFromList(p->pSymbiot); 2673 Entity_UnlinkBrush(p->pSymbiot); 2674 n = p->pSymbiot; 2675 n->owner = b->owner; 2676 Brush_Build(n); 2677 } 2678 else if (b->terrainBrush) 2679 { 2680 terrainMesh_t *p = Terrain_Duplicate(b->pTerrain); 2681 Brush_RemoveFromList(p->pSymbiot); 2682 Entity_UnlinkBrush(p->pSymbiot); 2683 n = p->pSymbiot; 2684 n->owner = b->owner; 2685 Brush_Build(n); 2686 } 2687 else 2688 { 2689 n = Brush_Alloc(); 2690 n->numberId = g_nBrushId++; 2691 n->owner = b->owner; 2692 VectorCopy(b->mins, n->mins); 2693 VectorCopy(b->maxs, n->maxs); 2694 // 2695 for (f = b->brush_faces; f; f = f->next) 2696 { 2697 if (f->original) continue; 2698 nf = Face_FullClone(f); 2699 nf->next = n->brush_faces; 2700 n->brush_faces = nf; 2701 //copy all faces that have the original set to this face 2702 for (f2 = b->brush_faces; f2; f2 = f2->next) 2703 { 2704 if (f2->original == f) 2705 { 2706 nf2 = Face_FullClone(f2); 2707 nf2->next = n->brush_faces; 2708 n->brush_faces = nf2; 2709 //set original 2710 nf2->original = nf; 2711 } 2712 } 2713 } 2714 for (nf = n->brush_faces; nf; nf = nf->next) 2715 { 2716 Face_SetColor(n, nf, 1.0); 2717 if (nf->face_winding) 2718 { 2719 if (g_qeglobals.m_bBrushPrimitMode) 2720 EmitBrushPrimitTextureCoordinates(nf,nf->face_winding); 2721 else 2722 { 2723 for (j = 0; j < nf->face_winding->numpoints; j++) 2724 EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf); 2725 } 2726 } 2727 } 2728 } 2729 return n; 2730 } 2731 2732 /* 2733 ============== 2734 Brush_Ray 2735 2736 Itersects a ray with a brush 2737 Returns the face hit and the distance along the ray the intersection occured at 2738 Returns NULL and 0 if not hit at all 2739 ============== 2740 */ 2741 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist) 2742 { 2743 face_t *f, *firstface; 2744 vec3_t p1, p2; 2745 float frac, d1, d2; 2746 int i; 2747 2748 VectorCopy (origin, p1); 2749 for (i=0 ; i<3 ; i++) 2750 p2[i] = p1[i] + dir[i]*16384; 2751 2752 for (f=b->brush_faces ; f ; f=f->next) 2753 { 2754 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; 2755 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; 2756 if (d1 >= 0 && d2 >= 0) 2757 { 2758 *dist = 0; 2759 return NULL; // ray is on front side of face 2760 } 2761 if (d1 <=0 && d2 <= 0) 2762 continue; 2763 // clip the ray to the plane 2764 frac = d1 / (d1 - d2); 2765 if (d1 > 0) 2766 { 2767 firstface = f; 2768 for (i=0 ; i<3 ; i++) 2769 p1[i] = p1[i] + frac *(p2[i] - p1[i]); 2770 } 2771 else 2772 { 2773 for (i=0 ; i<3 ; i++) 2774 p2[i] = p1[i] + frac *(p2[i] - p1[i]); 2775 } 2776 } 2777 2778 // find distance p1 is along dir 2779 VectorSubtract (p1, origin, p1); 2780 d1 = DotProduct (p1, dir); 2781 2782 *dist = d1; 2783 2784 return firstface; 2785 } 2786 2787 //PGM 2788 face_t *Brush_Point (vec3_t origin, brush_t *b) 2789 { 2790 face_t *f; 2791 float d1; 2792 2793 for (f=b->brush_faces ; f ; f=f->next) 2794 { 2795 d1 = DotProduct (origin, f->plane.normal) - f->plane.dist; 2796 if (d1 > 0) 2797 { 2798 return NULL; // point is on front side of face 2799 } 2800 } 2801 2802 return b->brush_faces; 2803 } 2804 //PGM 2805 2806 2807 void Brush_AddToList (brush_t *b, brush_t *list) 2808 { 2809 if (b->next || b->prev) 2810 Error ("Brush_AddToList: allready linked"); 2811 2812 if (list == &selected_brushes || list == &active_brushes) 2813 { 2814 if (b->patchBrush && list == &selected_brushes) 2815 { 2816 Patch_Select(b->pPatch); 2817 } 2818 if (b->terrainBrush && list == &selected_brushes) { 2819 Terrain_Select(b->pTerrain); 2820 } 2821 } 2822 b->next = list->next; 2823 list->next->prev = b; 2824 list->next = b; 2825 b->prev = list; 2826 2827 // TTimo messaging 2828 DispatchRadiantMsg( RADIANT_SELECTION ); 2829 } 2830 2831 void Brush_RemoveFromList (brush_t *b) 2832 { 2833 if (!b->next || !b->prev) 2834 Error ("Brush_RemoveFromList: not linked"); 2835 2836 if (b->patchBrush) 2837 { 2838 Patch_Deselect(b->pPatch); 2839 //Patch_Deselect(b->nPatchID); 2840 } 2841 if (b->terrainBrush) 2842 { 2843 Terrain_Deselect(b->pTerrain); 2844 } 2845 2846 b->next->prev = b->prev; 2847 b->prev->next = b->next; 2848 b->next = b->prev = NULL; 2849 } 2850 2851 /* 2852 =============== 2853 SetFaceTexdef 2854 2855 Doesn't set the curve flags 2856 2857 NOTE : ( TTimo ) 2858 never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture 2859 use Texture_ForName() to find the right shader 2860 FIXME : send the right shader ( qtexture_t * ) in the parameters ? 2861 2862 TTimo: surface plugin, added an IPluginTexdef* parameter 2863 if not NULL, get ->Copy() of it into the face ( and remember to hook ) 2864 if NULL, ask for a default 2865 =============== 2866 */ 2867 void SetFaceTexdef (brush_t *b, face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) { 2868 int oldFlags; 2869 int oldContents; 2870 face_t *tf; 2871 2872 oldFlags = f->texdef.flags; 2873 oldContents = f->texdef.contents; 2874 if (g_qeglobals.m_bBrushPrimitMode) 2875 { 2876 f->texdef = *texdef; 2877 ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, Texture_ForName( f->texdef.name ) ); 2878 } 2879 else 2880 if (bFitScale) 2881 { 2882 f->texdef = *texdef; 2883 // fit the scaling of the texture on the actual plane 2884 vec3_t p1,p2,p3; // absolute coordinates 2885 // compute absolute coordinates 2886 ComputeAbsolute(f,p1,p2,p3); 2887 // compute the scale 2888 vec3_t vx,vy; 2889 VectorSubtract(p2,p1,vx); 2890 VectorNormalize(vx); 2891 VectorSubtract(p3,p1,vy); 2892 VectorNormalize(vy); 2893 // assign scale 2894 VectorScale(vx,texdef->scale[0],vx); 2895 VectorScale(vy,texdef->scale[1],vy); 2896 VectorAdd(p1,vx,p2); 2897 VectorAdd(p1,vy,p3); 2898 // compute back shift scale rot 2899 AbsoluteToLocal(f->plane,f,p1,p2,p3); 2900 } 2901 else 2902 f->texdef = *texdef; 2903 f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP); 2904 f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP); 2905 2906 // surface plugin 2907 if (g_qeglobals.bSurfacePropertiesPlugin) 2908 { 2909 #ifdef _DEBUG 2910 if (!f->pData) 2911 Sys_Printf("ERROR: unexpected IPluginTexdef* is NULL in SetFaceTexdef\n"); 2912 else 2913 #endif 2914 GETPLUGINTEXDEF(f)->DecRef(); 2915 IPluginTexdef *pTexdef = NULL; 2916 if ( pPlugTexdef ) 2917 { 2918 pTexdef = pPlugTexdef->Copy(); 2919 pTexdef->Hook( f ); 2920 } 2921 else 2922 pTexdef = g_SurfaceTable.m_pfnTexdefAlloc( f ); 2923 f->pData = pTexdef; 2924 } 2925 2926 // if this is a curve face, set all other curve faces to the same texdef 2927 if (f->texdef.flags & SURF_CURVE) 2928 { 2929 for (tf = b->brush_faces ; tf ; tf = tf->next) 2930 { 2931 if (tf->texdef.flags & SURF_CURVE) 2932 tf->texdef = f->texdef; 2933 } 2934 } 2935 } 2936 2937 2938 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef) 2939 { 2940 for (face_t* f = b->brush_faces ; f ; f = f->next) 2941 { 2942 SetFaceTexdef (b, f, texdef, brushprimit_texdef, bFitScale, pTexdef); 2943 } 2944 Brush_Build( b ); 2945 if (b->patchBrush) 2946 { 2947 //++timo clean 2948 // Sys_Printf("WARNING: Brush_SetTexture needs surface plugin code for patches\n"); 2949 Patch_SetTexture(b->pPatch, texdef, pTexdef ); 2950 } 2951 if (b->terrainBrush) 2952 { 2953 Terrain_SetTexture(b->pTerrain, texdef); 2954 } 2955 2956 } 2957 2958 2959 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) 2960 { 2961 float d1, d2, fr; 2962 int i; 2963 float *v; 2964 2965 d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; 2966 d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; 2967 2968 if (d1 >= 0 && d2 >= 0) 2969 return false; // totally outside 2970 if (d1 <= 0 && d2 <= 0) 2971 return true; // totally inside 2972 2973 fr = d1 / (d1 - d2); 2974 2975 if (d1 > 0) 2976 v = p1; 2977 else 2978 v = p2; 2979 2980 for (i=0 ; i<3 ; i++) 2981 v[i] = p1[i] + fr*(p2[i] - p1[i]); 2982 2983 return true; 2984 } 2985 2986 2987 int AddPlanept (float *f) 2988 { 2989 int i; 2990 2991 for (i=0 ; i<g_qeglobals.d_num_move_points ; i++) 2992 if (g_qeglobals.d_move_points[i] == f) 2993 return 0; 2994 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f; 2995 return 1; 2996 } 2997 2998 /* 2999 ============== 3000 Brush_SelectFaceForDragging 3001 3002 Adds the faces planepts to move_points, and 3003 rotates and adds the planepts of adjacent face if shear is set 3004 ============== 3005 */ 3006 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear) 3007 { 3008 int i; 3009 face_t *f2; 3010 winding_t *w; 3011 float d; 3012 brush_t *b2; 3013 int c; 3014 3015 if (b->owner->eclass->fixedsize) 3016 return; 3017 3018 c = 0; 3019 for (i=0 ; i<3 ; i++) 3020 c += AddPlanept (f->planepts[i]); 3021 if (c == 0) 3022 return; // allready completely added 3023 3024 // select all points on this plane in all brushes the selection 3025 for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) 3026 { 3027 if (b2 == b) 3028 continue; 3029 for (f2=b2->brush_faces ; f2 ; f2=f2->next) 3030 { 3031 for (i=0 ; i<3 ; i++) 3032 if (fabs(DotProduct(f2->planepts[i], f->plane.normal) 3033 -f->plane.dist) > ON_EPSILON) 3034 break; 3035 if (i==3) 3036 { // move this face as well 3037 Brush_SelectFaceForDragging (b2, f2, shear); 3038 break; 3039 } 3040 } 3041 } 3042 3043 3044 // if shearing, take all the planes adjacent to 3045 // selected faces and rotate their points so the 3046 // edge clipped by a selcted face has two of the points 3047 if (!shear) 3048 return; 3049 3050 for (f2=b->brush_faces ; f2 ; f2=f2->next) 3051 { 3052 if (f2 == f) 3053 continue; 3054 w = Brush_MakeFaceWinding (b, f2); 3055 if (!w) 3056 continue; 3057 3058 // any points on f will become new control points 3059 for (i=0 ; i<w->numpoints ; i++) 3060 { 3061 d = DotProduct (w->points[i], f->plane.normal) 3062 - f->plane.dist; 3063 if (d > -ON_EPSILON && d < ON_EPSILON) 3064 break; 3065 } 3066 3067 // 3068 // if none of the points were on the plane, 3069 // leave it alone 3070 // 3071 if (i != w->numpoints) 3072 { 3073 if (i == 0) 3074 { // see if the first clockwise point was the 3075 // last point on the winding 3076 d = DotProduct (w->points[w->numpoints-1] 3077 , f->plane.normal) - f->plane.dist; 3078 if (d > -ON_EPSILON && d < ON_EPSILON) 3079 i = w->numpoints - 1; 3080 } 3081 3082 AddPlanept (f2->planepts[0]); 3083 3084 VectorCopy (w->points[i], f2->planepts[0]); 3085 if (++i == w->numpoints) 3086 i = 0; 3087 3088 // see if the next point is also on the plane 3089 d = DotProduct (w->points[i] 3090 , f->plane.normal) - f->plane.dist; 3091 if (d > -ON_EPSILON && d < ON_EPSILON) 3092 AddPlanept (f2->planepts[1]); 3093 3094 VectorCopy (w->points[i], f2->planepts[1]); 3095 if (++i == w->numpoints) 3096 i = 0; 3097 3098 // the third point is never on the plane 3099 3100 VectorCopy (w->points[i], f2->planepts[2]); 3101 } 3102 3103 free(w); 3104 } 3105 } 3106 3107 /* 3108 ============== 3109 Brush_SideSelect 3110 3111 The mouse click did not hit the brush, so grab one or more side 3112 planes for dragging 3113 ============== 3114 */ 3115 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir 3116 , qboolean shear) 3117 { 3118 face_t *f, *f2; 3119 vec3_t p1, p2; 3120 3121 //if (b->patchBrush) 3122 // return; 3123 //Patch_SideSelect(b->nPatchID, origin, dir); 3124 for (f=b->brush_faces ; f ; f=f->next) 3125 { 3126 VectorCopy (origin, p1); 3127 VectorMA (origin, 16384, dir, p2); 3128 3129 for (f2=b->brush_faces ; f2 ; f2=f2->next) 3130 { 3131 if (f2 == f) 3132 continue; 3133 ClipLineToFace (p1, p2, f2); 3134 } 3135 3136 if (f2) 3137 continue; 3138 3139 if (VectorCompare (p1, origin)) 3140 continue; 3141 if (ClipLineToFace (p1, p2, f)) 3142 continue; 3143 3144 Brush_SelectFaceForDragging (b, f, shear); 3145 } 3146 3147 3148 } 3149 3150 void Brush_BuildWindings( brush_t *b, bool bSnap ) 3151 { 3152 winding_t *w; 3153 face_t *face; 3154 vec_t v; 3155 3156 if (bSnap) 3157 Brush_SnapPlanepts( b ); 3158 3159 // clear the mins/maxs bounds 3160 b->mins[0] = b->mins[1] = b->mins[2] = 99999; 3161 b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; 3162 3163 Brush_MakeFacePlanes (b); 3164 3165 face = b->brush_faces; 3166 3167 float fCurveColor = 1.0; 3168 3169 for ( ; face ; face=face->next) 3170 { 3171 int i, j; 3172 free(face->face_winding); 3173 w = face->face_winding = Brush_MakeFaceWinding (b, face); 3174 face->d_texture = Texture_ForName( face->texdef.name ); 3175 3176 if (!w) 3177 continue; 3178 3179 for (i=0 ; i<w->numpoints ; i++) 3180 { 3181 // add to bounding box 3182 for (j=0 ; j<3 ; j++) 3183 { 3184 v = w->points[i][j]; 3185 if (v > b->maxs[j]) 3186 b->maxs[j] = v; 3187 if (v < b->mins[j]) 3188 b->mins[j] = v; 3189 } 3190 } 3191 // setup s and t vectors, and set color 3192 //if (!g_PrefsDlg.m_bGLLighting) 3193 //{ 3194 Face_SetColor (b, face, fCurveColor); 3195 //} 3196 3197 fCurveColor -= .10; 3198 if (fCurveColor <= 0) 3199 fCurveColor = 1.0; 3200 3201 // computing ST coordinates for the windings 3202 if (g_qeglobals.m_bBrushPrimitMode) 3203 { 3204 if (g_qeglobals.bNeedConvert) 3205 { 3206 // we have parsed old brushes format and need conversion 3207 // convert old brush texture representation to new format 3208 FaceToBrushPrimitFace(face); 3209 #ifdef _DEBUG 3210 // use old texture coordinates code to check against 3211 for (i=0 ; i<w->numpoints ; i++) 3212 EmitTextureCoordinates( w->points[i], face->d_texture, face); 3213 #endif 3214 } 3215 // use new texture representation to compute texture coordinates 3216 // in debug mode we will check against old code and warn if there are differences 3217 EmitBrushPrimitTextureCoordinates(face,w); 3218 } 3219 else 3220 { 3221 for (i=0 ; i<w->numpoints ; i++) 3222 EmitTextureCoordinates( w->points[i], face->d_texture, face); 3223 } 3224 } 3225 } 3226 3227 /* 3228 ================== 3229 Brush_RemoveEmptyFaces 3230 3231 Frees any overconstraining faces 3232 ================== 3233 */ 3234 void Brush_RemoveEmptyFaces ( brush_t *b ) 3235 { 3236 face_t *f, *next; 3237 3238 f = b->brush_faces; 3239 b->brush_faces = NULL; 3240 3241 for ( ; f ; f=next) 3242 { 3243 next = f->next; 3244 if (!f->face_winding) 3245 Face_Free (f); 3246 else 3247 { 3248 f->next = b->brush_faces; 3249 b->brush_faces = f; 3250 } 3251 3252 } 3253 } 3254 3255 void Brush_SnapToGrid(brush_t *pb) 3256 { 3257 for (face_t *f = pb->brush_faces ; f; f = f->next) 3258 { 3259 for (int i = 0 ;i < 3 ;i++) 3260 { 3261 for (int j = 0 ;j < 3 ; j++) 3262 { 3263 f->planepts[i][j] = floor (f->planepts[i][j] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize; 3264 } 3265 } 3266 } 3267 Brush_Build(pb); 3268 } 3269 3270 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild) 3271 { 3272 for (face_t* f=b->brush_faces ; f ; f=f->next) 3273 { 3274 for (int i=0 ; i<3 ; i++) 3275 { 3276 VectorRotate(f->planepts[i], vAngle, vOrigin, f->planepts[i]); 3277 } 3278 } 3279 if (bBuild) 3280 { 3281 Brush_Build(b, false, false); 3282 } 3283 } 3284 3285 void Brush_Center(brush_t *b, vec3_t vNewCenter) 3286 { 3287 vec3_t vMid; 3288 // get center of the brush 3289 for (int j = 0; j < 3; j++) 3290 { 3291 vMid[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5); 3292 } 3293 // calc distance between centers 3294 VectorSubtract(vNewCenter, vMid, vMid); 3295 Brush_Move(b, vMid, true); 3296 3297 } 3298 3299 // only designed for fixed size entity brushes 3300 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax) 3301 { 3302 brush_t *b2 = Brush_Create(vMin, vMax, &b->brush_faces->texdef); 3303 3304 face_t *next; 3305 for (face_t *f=b->brush_faces ; f ; f=next) 3306 { 3307 next = f->next; 3308 Face_Free( f ); 3309 } 3310 3311 b->brush_faces = b2->brush_faces; 3312 3313 // unlink from active/selected list 3314 if (b2->next) 3315 Brush_RemoveFromList (b2); 3316 free(b2); 3317 Brush_Build(b, true); 3318 } 3319 3320 3321 eclass_t* HasModel(brush_t *b) 3322 { 3323 vec3_t vMin, vMax; 3324 vMin[0] = vMin[1] = vMin[2] = 9999; 3325 vMax[0] = vMax[1] = vMax[2] = -9999; 3326 3327 if (b->owner->md3Class != NULL) 3328 { 3329 return b->owner->md3Class; 3330 } 3331 3332 if (Eclass_hasModel(b->owner->eclass, vMin, vMax)) 3333 { 3334 return b->owner->eclass; 3335 } 3336 3337 eclass_t *e = NULL; 3338 // FIXME: entity needs to track whether a cache hit failed and not ask again 3339 if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) 3340 { 3341 char *pModel = ValueForKey(b->owner, "model"); 3342 if (pModel != NULL && strlen(pModel) > 0) 3343 { 3344 e = GetCachedModel(b->owner, pModel, vMin, vMax); 3345 if (e != NULL) 3346 { 3347 // we need to scale the brush to the proper size based on the model load 3348 // recreate brush just like in load/save 3349 3350 VectorAdd (vMin, b->owner->origin, vMin); 3351 VectorAdd (vMax, b->owner->origin, vMax); 3352 3353 Brush_Resize(b, vMin, vMax); 3354 3355 /* 3356 // 3357 vec3_t vTemp, vTemp2; 3358 VectorSubtract(b->maxs, b->mins, vTemp); 3359 VectorSubtract(vMax, vMin, vTemp2); 3360 for (int i = 0; i < 3; i++) 3361 { 3362 if (vTemp[i] != 0) 3363 { 3364 vTemp2[i] /= vTemp[i]; 3365 } 3366 } 3367 vec3_t vMid, vMid2; 3368 vMid[0] = vMid[1] = vMid[2] = 0.0; 3369 vMid2[0] = vMid2[1] = vMid2[2] = 0.0; 3370 3371 for (int j = 0; j < 3; j++) 3372 { 3373 vMid2[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5); 3374 } 3375 3376 //VectorSubtract(vMid2, vMid, vMid2); 3377 3378 for (face_t* f=b->brush_faces ; f ; f=f->next) 3379 { 3380 for (int i=0 ; i<3 ; i++) 3381 { 3382 3383 // scale 3384 VectorSubtract(f->planepts[i], vMid2, f->planepts[i]); 3385 f->planepts[i][0] *= vTemp2[0]; 3386 f->planepts[i][1] *= vTemp2[1]; 3387 f->planepts[i][2] *= vTemp2[2]; 3388 VectorAdd(f->planepts[i], vMid2, f->planepts[i]); 3389 } 3390 } 3391 3392 //Brush_Center(b, b->owner->origin); 3393 3394 //Brush_SnapToGrid(b); 3395 /* 3396 float a = FloatForKey (b->owner, "angle"); 3397 if (a) 3398 { 3399 vec3_t vAngle; 3400 vAngle[0] = vAngle[1] = 0; 3401 vAngle[2] = a; 3402 Brush_Rotate(b, vAngle, b->owner->origin); 3403 } 3404 else 3405 { 3406 Brush_Build(b, true); 3407 */ 3408 // } 3409 3410 b->bModelFailed = false; 3411 } 3412 else 3413 { 3414 b->bModelFailed = true; 3415 } 3416 } 3417 } 3418 return e; 3419 } 3420 3421 static bool g_bInPaintedModel = false; 3422 static bool g_bDoIt = false; 3423 bool PaintedModel(brush_t *b, bool bOkToTexture) 3424 { 3425 if (g_bInPaintedModel) 3426 { 3427 return true; 3428 } 3429 3430 if (g_PrefsDlg.m_nEntityShowState == ENTITY_BOX || b->bModelFailed) 3431 { 3432 return false; 3433 } 3434 else if (!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY)) 3435 { 3436 return false; 3437 } 3438 3439 g_bInPaintedModel = true; 3440 bool bReturn = false; 3441 3442 eclass_t *pEclass = HasModel(b); 3443 3444 if (pEclass) 3445 { 3446 qglPushAttrib(GL_ALL_ATTRIB_BITS); 3447 entitymodel *model = pEclass->model; 3448 3449 3450 float a = FloatForKey (b->owner, "angle"); 3451 while (model != NULL) 3452 { 3453 if (bOkToTexture == false || g_PrefsDlg.m_nEntityShowState & ENTITY_WIREFRAME || model->nTextureBind == -1) // skinned 3454 { 3455 qglDisable( GL_CULL_FACE ); 3456 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); 3457 qglDisable(GL_TEXTURE_2D); 3458 qglColor3fv(pEclass->color); 3459 } 3460 else 3461 { 3462 qglColor3f(1, 1, 1); 3463 qglEnable(GL_TEXTURE_2D); 3464 qglBindTexture( GL_TEXTURE_2D, model->nTextureBind ); 3465 } 3466 vec3_t v; 3467 3468 int i,j; 3469 VectorAdd(b->maxs, b->mins, v); 3470 VectorScale(v, 0.5, v); 3471 VectorCopy(b->owner->origin, v); 3472 3473 3474 //for (i = 0; i < 3; i++) 3475 //{ 3476 // v[i] -= (pEclass->mins[i] - b->mins[i]); 3477 //} 3478 3479 //if (model->nModelPosition) 3480 //{ 3481 //v[2] = b->mins[2] - (pEclass->mins[2]); 3482 //} 3483 3484 float s, c; 3485 if (a) 3486 { 3487 s = sin (a/180*Q_PI); 3488 c = cos (a/180*Q_PI); 3489 } 3490 3491 vec3_t vSin; 3492 vec3_t vCos; 3493 VectorClear(vSin); 3494 VectorClear(vCos); 3495 for ( j = 0; j < 3; j++) 3496 { 3497 if (b->owner->vRotation[j]) 3498 { 3499 vSin[j] = sin(b->owner->vRotation[j]/180*Q_PI); 3500 vCos[j] = cos(b->owner->vRotation[j]/180*Q_PI); 3501 } 3502 } 3503 3504 3505 qglBegin (GL_TRIANGLES); 3506 3507 vec5_t vTest[3]; 3508 for (i = 0; i < model->nTriCount; i++) 3509 { 3510 for (j = 0; j < 3; j++) 3511 { 3512 #if 1 3513 float x = model->pTriList[i].v[j][0] + v[0]; 3514 float y = model->pTriList[i].v[j][1] + v[1]; 3515 if (a) 3516 { 3517 float x2 = (((x - v[0]) * c) - ((y - v[1]) * s)) + v[0]; 3518 float y2 = (((x - v[0]) * s) + ((y - v[1]) * c)) + v[1]; 3519 x = x2; 3520 y = y2; 3521 } 3522 //qglTexCoord2f (pEclass->pTriList[i].st[j][0] / pEclass->nSkinWidth, pEclass->pTriList[i].st[j][1] / pEclass->nSkinHeight); 3523 qglTexCoord2f (model->pTriList[i].st[j][0], model->pTriList[i].st[j][1]); 3524 qglVertex3f(x, y, model->pTriList[i].v[j][2] + v[2]); 3525 #else 3526 float x = model->pTriList[i].v[j][0] + v[0]; 3527 float y = model->pTriList[i].v[j][1] + v[1]; 3528 float z = model->pTriList[i].v[j][2] + v[2]; 3529 3530 if (b->owner->vRotation[0]) 3531 { 3532 float y2 = (((y - v[1]) * vCos[0]) - ((z - v[2]) * vSin[0])) + v[1]; 3533 float z2 = (((y - v[1]) * vSin[0]) + ((z - v[2]) * vCos[0])) + v[2]; 3534 y = y2; 3535 z = z2; 3536 } 3537 if (b->owner->vRotation[1]) 3538 { 3539 float z2 = (((z - v[2]) * vCos[1]) - ((x - v[0]) * vSin[1])) + v[2]; 3540 float x2 = (((z - v[2]) * vSin[1]) + ((x - v[0]) * vCos[1])) + v[0]; 3541 x = x2; 3542 z = z2; 3543 } 3544 if (b->owner->vRotation[2]) 3545 { 3546 float x2 = (((x - v[0]) * vCos[2]) - ((y - v[1]) * vSin[2])) + v[0]; 3547 float y2 = (((x - v[0]) * vSin[2]) + ((y - v[1]) * vCos[2])) + v[1]; 3548 x = x2; 3549 y = y2; 3550 } 3551 qglTexCoord2f (model->pTriList[i].st[j][0], model->pTriList[i].st[j][1]); 3552 qglVertex3f(x, y, z); 3553 #endif 3554 if (g_bDoIt) 3555 { 3556 vTest[j][0] = x; 3557 vTest[j][1] = y; 3558 vTest[j][2] = model->pTriList[i].v[j][2] + v[2]; 3559 vTest[j][3] = model->pTriList[i].st[j][0]; 3560 vTest[j][4] = model->pTriList[i].st[j][1]; 3561 } 3562 3563 } 3564 if (g_bDoIt) 3565 { 3566 Patch_FromTriangle(vTest[0], vTest[1], vTest[2]); 3567 } 3568 } 3569 qglEnd(); 3570 if (g_PrefsDlg.m_nEntityShowState & ENTITY_WIREFRAME) // skinned 3571 { 3572 qglEnable(GL_CULL_FACE ); 3573 qglEnable(GL_TEXTURE_2D); 3574 qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL); 3575 } 3576 else 3577 { 3578 qglDisable(GL_TEXTURE_2D); 3579 } 3580 model = model->pNext; 3581 } 3582 3583 if (g_bDoIt) 3584 { 3585 g_bDoIt = false; 3586 } 3587 3588 vec3_t vColor; 3589 VectorScale(pEclass->color, 0.50, vColor); 3590 3591 vec3_t vCenter, vMin, vMax; 3592 VectorCopy(b->owner->origin, vCenter); 3593 3594 qglColor3fv(vColor); 3595 qglPointSize(4); 3596 3597 qglBegin(GL_POINTS); 3598 qglVertex3fv(b->owner->origin); 3599 qglEnd(); 3600 3601 qglBegin(GL_LINES); 3602 vCenter[0] -= 8; 3603 qglVertex3fv(vCenter); 3604 vCenter[0] += 16; 3605 qglVertex3fv(vCenter); 3606 vCenter[0] -= 8; 3607 vCenter[1] -= 8; 3608 qglVertex3fv(vCenter); 3609 vCenter[1] += 16; 3610 qglVertex3fv(vCenter); 3611 vCenter[1] -= 8; 3612 vCenter[2] -= 8; 3613 qglVertex3fv(vCenter); 3614 vCenter[2] += 16; 3615 qglVertex3fv(vCenter); 3616 vCenter[2] -= 8; 3617 qglEnd(); 3618 3619 VectorCopy(vCenter, vMin); 3620 VectorCopy(vCenter, vMax); 3621 vMin[0] -= 4; 3622 vMin[1] -= 4; 3623 vMin[2] -= 4; 3624 vMax[0] += 4; 3625 vMax[1] += 4; 3626 vMax[2] += 4; 3627 3628 qglBegin(GL_LINE_LOOP); 3629 qglVertex3f(vMin[0],vMin[1],vMin[2]); 3630 qglVertex3f(vMax[0],vMin[1],vMin[2]); 3631 qglVertex3f(vMax[0],vMax[1],vMin[2]); 3632 qglVertex3f(vMin[0],vMax[1],vMin[2]); 3633 qglEnd(); 3634 3635 qglBegin(GL_LINE_LOOP); 3636 qglVertex3f(vMin[0],vMin[1],vMax[2]); 3637 qglVertex3f(vMax[0],vMin[1],vMax[2]); 3638 qglVertex3f(vMax[0],vMax[1],vMax[2]); 3639 qglVertex3f(vMin[0],vMax[1],vMax[2]); 3640 qglEnd(); 3641 3642 qglBegin(GL_LINES); 3643 qglVertex3f(vMin[0],vMin[1],vMin[2]); 3644 qglVertex3f(vMin[0],vMin[1],vMax[2]); 3645 qglVertex3f(vMin[0],vMax[1],vMax[2]); 3646 qglVertex3f(vMin[0],vMax[1],vMin[2]); 3647 qglVertex3f(vMax[0],vMin[1],vMin[2]); 3648 qglVertex3f(vMax[0],vMin[1],vMax[2]); 3649 qglVertex3f(vMax[0],vMax[1],vMax[2]); 3650 qglVertex3f(vMax[0],vMax[1],vMin[2]); 3651 qglEnd(); 3652 3653 3654 if (g_PrefsDlg.m_nEntityShowState & ENTITY_BOXED) 3655 { 3656 qglColor3fv(pEclass->color); 3657 3658 vec3_t mins, maxs; 3659 VectorCopy(b->mins, mins); 3660 VectorCopy(b->maxs, maxs); 3661 /* 3662 if (a) 3663 { 3664 vec3_t vAngle; 3665 vAngle[0] = vAngle[1] = 0; 3666 vAngle[2] = a; 3667 VectorRotate(mins, vAngle, b->owner->origin, mins); 3668 VectorRotate(maxs, vAngle, b->owner->origin, maxs); 3669 } 3670 */ 3671 qglBegin(GL_LINE_LOOP); 3672 qglVertex3f(mins[0],mins[1],mins[2]); 3673 qglVertex3f(maxs[0],mins[1],mins[2]); 3674 qglVertex3f(maxs[0],maxs[1],mins[2]); 3675 qglVertex3f(mins[0],maxs[1],mins[2]); 3676 qglEnd(); 3677 3678 qglBegin(GL_LINE_LOOP); 3679 qglVertex3f(mins[0],mins[1],maxs[2]); 3680 qglVertex3f(maxs[0],mins[1],maxs[2]); 3681 qglVertex3f(maxs[0],maxs[1],maxs[2]); 3682 qglVertex3f(mins[0],maxs[1],maxs[2]); 3683 qglEnd(); 3684 3685 qglBegin(GL_LINES); 3686 qglVertex3f(mins[0],mins[1],mins[2]); 3687 qglVertex3f(mins[0],mins[1],maxs[2]); 3688 qglVertex3f(mins[0],maxs[1],maxs[2]); 3689 qglVertex3f(mins[0],maxs[1],mins[2]); 3690 qglVertex3f(maxs[0],mins[1],mins[2]); 3691 qglVertex3f(maxs[0],mins[1],maxs[2]); 3692 qglVertex3f(maxs[0],maxs[1],maxs[2]); 3693 qglVertex3f(maxs[0],maxs[1],mins[2]); 3694 qglEnd(); 3695 } 3696 qglPopAttrib(); 3697 bReturn = true; 3698 } 3699 else 3700 { 3701 b->bModelFailed = true; 3702 } 3703 3704 g_bInPaintedModel = false; 3705 return bReturn; 3706 } 3707 /* 3708 //++timo moved out to mahlib.h 3709 //++timo remove 3710 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) 3711 { 3712 float angle; 3713 static float sr, sp, sy, cr, cp, cy; 3714 // static to help MS compiler fp bugs 3715 3716 angle = angles[YAW] * Q_PI / 180; 3717 sy = sin(angle); 3718 cy = cos(angle); 3719 angle = angles[PITCH] * Q_PI / 180; 3720 sp = sin(angle); 3721 cp = cos(angle); 3722 angle = angles[ROLL] * Q_PI / 180; 3723 sr = sin(angle); 3724 cr = cos(angle); 3725 3726 if (forward) 3727 { 3728 forward[0] = cp*cy; 3729 forward[1] = cp*sy; 3730 forward[2] = -sp; 3731 } 3732 if (right) 3733 { 3734 right[0] = (-1*sr*sp*cy+-1*cr*-sy); 3735 right[1] = (-1*sr*sp*sy+-1*cr*cy); 3736 right[2] = -1*sr*cp; 3737 } 3738 if (up) 3739 { 3740 up[0] = (cr*sp*cy+-sr*-sy); 3741 up[1] = (cr*sp*sy+-sr*cy); 3742 up[2] = cr*cp; 3743 } 3744 } 3745 */ 3746 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up) 3747 { 3748 int angleVal; 3749 vec3_t angles; 3750 3751 angleVal = IntForKey(e, "angle"); 3752 if (angleVal == -1) // up 3753 { 3754 VectorSet(angles, 270, 0, 0); 3755 } 3756 else if(angleVal == -2) // down 3757 { 3758 VectorSet(angles, 90, 0, 0); 3759 } 3760 else 3761 { 3762 VectorSet(angles, 0, angleVal, 0); 3763 } 3764 3765 AngleVectors(angles, forward, right, up); 3766 } 3767 3768 void Brush_DrawFacingAngle (brush_t *b, entity_t *e) 3769 { 3770 vec3_t forward, right, up; 3771 vec3_t endpoint, tip1, tip2; 3772 vec3_t start; 3773 float dist; 3774 3775 VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start); 3776 VectorScale(start, 0.5, start); 3777 dist = (b->maxs[0] - start[0]) * 2.5; 3778 3779 FacingVectors (e, forward, right, up); 3780 VectorMA (start, dist, forward, endpoint); 3781 3782 dist = (b->maxs[0] - start[0]) * 0.5; 3783 VectorMA (endpoint, -dist, forward, tip1); 3784 VectorMA (tip1, -dist, up, tip1); 3785 VectorMA (tip1, 2*dist, up, tip2); 3786 3787 qglColor4f (1, 1, 1, 1); 3788 qglLineWidth (4); 3789 qglBegin (GL_LINES); 3790 qglVertex3fv (start); 3791 qglVertex3fv (endpoint); 3792 qglVertex3fv (endpoint); 3793 qglVertex3fv (tip1); 3794 qglVertex3fv (endpoint); 3795 qglVertex3fv (tip2); 3796 qglEnd (); 3797 qglLineWidth (1); 3798 } 3799 3800 void DrawLight(brush_t *b) 3801 { 3802 vec3_t vTriColor; 3803 bool bTriPaint = false; 3804 3805 vTriColor[0] = vTriColor[2] = 1.0; 3806 vTriColor[1] = 1.0; 3807 bTriPaint = true; 3808 CString strColor = ValueForKey(b->owner, "_color"); 3809 if (strColor.GetLength() > 0) 3810 { 3811 float fR, fG, fB; 3812 int n = sscanf(strColor,"%f %f %f", &fR, &fG, &fB); 3813 if (n == 3) 3814 { 3815 vTriColor[0] = fR; 3816 vTriColor[1] = fG; 3817 vTriColor[2] = fB; 3818 } 3819 } 3820 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]); 3821 3822 vec3_t vCorners[4]; 3823 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2; 3824 3825 vCorners[0][0] = b->mins[0]; 3826 vCorners[0][1] = b->mins[1]; 3827 vCorners[0][2] = fMid; 3828 3829 vCorners[1][0] = b->mins[0]; 3830 vCorners[1][1] = b->maxs[1]; 3831 vCorners[1][2] = fMid; 3832 3833 vCorners[2][0] = b->maxs[0]; 3834 vCorners[2][1] = b->maxs[1]; 3835 vCorners[2][2] = fMid; 3836 3837 vCorners[3][0] = b->maxs[0]; 3838 vCorners[3][1] = b->mins[1]; 3839 vCorners[3][2] = fMid; 3840 3841 vec3_t vTop, vBottom; 3842 3843 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2); 3844 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2); 3845 vTop[2] = b->maxs[2]; 3846 3847 VectorCopy(vTop, vBottom); 3848 vBottom[2] = b->mins[2]; 3849 3850 vec3_t vSave; 3851 VectorCopy(vTriColor, vSave); 3852 3853 qglBegin(GL_TRIANGLE_FAN); 3854 qglVertex3fv(vTop); 3855 for (int i = 0; i <= 3; i++) 3856 { 3857 vTriColor[0] *= 0.95; 3858 vTriColor[1] *= 0.95; 3859 vTriColor[2] *= 0.95; 3860 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]); 3861 qglVertex3fv(vCorners[i]); 3862 } 3863 qglVertex3fv(vCorners[0]); 3864 qglEnd(); 3865 3866 VectorCopy(vSave, vTriColor); 3867 vTriColor[0] *= 0.95; 3868 vTriColor[1] *= 0.95; 3869 vTriColor[2] *= 0.95; 3870 3871 qglBegin(GL_TRIANGLE_FAN); 3872 qglVertex3fv(vBottom); 3873 qglVertex3fv(vCorners[0]); 3874 for (i = 3; i >= 0; i--) 3875 { 3876 vTriColor[0] *= 0.95; 3877 vTriColor[1] *= 0.95; 3878 vTriColor[2] *= 0.95; 3879 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]); 3880 qglVertex3fv(vCorners[i]); 3881 } 3882 qglEnd(); 3883 3884 // check for DOOM lights 3885 CString str = ValueForKey(b->owner, "light_right"); 3886 if (str.GetLength() > 0) { 3887 vec3_t vRight, vUp, vTarget, vTemp; 3888 GetVectorForKey (b->owner, "light_right", vRight); 3889 GetVectorForKey (b->owner, "light_up", vUp); 3890 GetVectorForKey (b->owner, "light_target", vTarget); 3891 3892 qglColor3f(0, 1, 0); 3893 qglBegin(GL_LINE_LOOP); 3894 VectorAdd(vTarget, b->owner->origin, vTemp); 3895 VectorAdd(vTemp, vRight, vTemp); 3896 VectorAdd(vTemp, vUp, vTemp); 3897 qglVertex3fv(b->owner->origin); 3898 qglVertex3fv(vTemp); 3899 VectorAdd(vTarget, b->owner->origin, vTemp); 3900 VectorAdd(vTemp, vUp, vTemp); 3901 VectorSubtract(vTemp, vRight, vTemp); 3902 qglVertex3fv(b->owner->origin); 3903 qglVertex3fv(vTemp); 3904 VectorAdd(vTarget, b->owner->origin, vTemp); 3905 VectorAdd(vTemp, vRight, vTemp); 3906 VectorSubtract(vTemp, vUp, vTemp); 3907 qglVertex3fv(b->owner->origin); 3908 qglVertex3fv(vTemp); 3909 VectorAdd(vTarget, b->owner->origin, vTemp); 3910 VectorSubtract(vTemp, vUp, vTemp); 3911 VectorSubtract(vTemp, vRight, vTemp); 3912 qglVertex3fv(b->owner->origin); 3913 qglVertex3fv(vTemp); 3914 qglEnd(); 3915 3916 } 3917 3918 } 3919 3920 void Brush_Draw( brush_t *b ) 3921 { 3922 face_t *face; 3923 int i, order; 3924 qtexture_t *prev = 0; 3925 winding_t *w; 3926 3927 if ( b->owner && ( b->owner->eclass->nShowFlags & ECLASS_PLUGINENTITY ) ) 3928 { 3929 b->owner->pPlugEnt->CamRender(); 3930 return; 3931 } 3932 3933 // (TTimo) NOTE: added by build 173, I check after pPlugEnt so it doesn't interfere ? 3934 if (b->hiddenBrush) 3935 { 3936 return; 3937 } 3938 3939 if (b->patchBrush) 3940 { 3941 //Patch_DrawCam(b->nPatchID); 3942 Patch_DrawCam(b->pPatch); 3943 //if (!g_bPatchShowBounds) 3944 return; 3945 } 3946 3947 if (b->terrainBrush) 3948 { 3949 Terrain_DrawCam(b->pTerrain); 3950 return; 3951 } 3952 3953 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode; 3954 3955 if (b->owner->eclass->fixedsize) 3956 { 3957 3958 if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES) && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) 3959 { 3960 Brush_DrawFacingAngle(b, b->owner); 3961 } 3962 3963 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT)) 3964 { 3965 DrawLight(b); 3966 return; 3967 } 3968 if (nDrawMode == cd_texture || nDrawMode == cd_light) 3969 qglDisable (GL_TEXTURE_2D); 3970 3971 // if we are wireframing models 3972 bool bp = (b->bModelFailed) ? false : PaintedModel(b, true); 3973 3974 if (nDrawMode == cd_texture || nDrawMode == cd_light) 3975 qglEnable (GL_TEXTURE_2D); 3976 3977 if (bp) 3978 return; 3979 } 3980 3981 // guarantee the texture will be set first 3982 prev = NULL; 3983 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) 3984 { 3985 w = face->face_winding; 3986 if (!w) 3987 { 3988 continue; // freed face 3989 } 3990 3991 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) 3992 { 3993 if (strstr(face->texdef.name, "caulk")) 3994 { 3995 continue; 3996 } 3997 } 3998 3999 #if 0 4000 if (b->alphaBrush) 4001 { 4002 if (!(face->texdef.flags & SURF_ALPHA)) 4003 continue; 4004 //--qglPushAttrib(GL_ALL_ATTRIB_BITS); 4005 qglDisable(GL_CULL_FACE); 4006 //--qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 4007 //--qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 4008 //--qglDisable(GL_DEPTH_TEST); 4009 //--qglBlendFunc (GL_SRC_ALPHA, GL_DST_ALPHA); 4010 //--qglEnable (GL_BLEND); 4011 } 4012 #endif 4013 4014 if ((nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev) 4015 { 4016 // set the texture for this face 4017 prev = face->d_texture; 4018 qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); 4019 } 4020 4021 4022 4023 if (!b->patchBrush) 4024 { 4025 if (face->texdef.flags & SURF_TRANS33) 4026 qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], 0.33 ); 4027 else if ( face->texdef.flags & SURF_TRANS66) 4028 qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], 0.66 ); 4029 else 4030 qglColor3fv( face->d_color ); 4031 } 4032 else 4033 { 4034 qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], 0.13 ); 4035 } 4036 4037 // shader drawing stuff 4038 if (face->d_texture->bFromShader) 4039 { 4040 // setup shader drawing 4041 qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], face->d_texture->fTrans ); 4042 4043 } 4044 4045 // draw the polygon 4046 4047 //if (nDrawMode == cd_light) 4048 //{ 4049 if (g_PrefsDlg.m_bGLLighting) 4050 { 4051 qglNormal3fv(face->plane.normal); 4052 } 4053 //} 4054 4055 qglBegin(GL_POLYGON); 4056 //if (nDrawMode == cd_light) 4057 4058 for (i=0 ; i<w->numpoints ; i++) 4059 { 4060 if (nDrawMode == cd_texture || nDrawMode == cd_light) 4061 qglTexCoord2fv( &w->points[i][3] ); 4062 qglVertex3fv(w->points[i]); 4063 } 4064 qglEnd(); 4065 } 4066 4067 #if 0 4068 if (b->alphaBrush) 4069 { 4070 //--qglPopAttrib(); 4071 qglEnable(GL_CULL_FACE); 4072 //--qglDisable (GL_BLEND); 4073 //--qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); 4074 } 4075 #endif 4076 4077 if (b->owner->eclass->fixedsize && (nDrawMode == cd_texture || nDrawMode == cd_light)) 4078 qglEnable (GL_TEXTURE_2D); 4079 4080 qglBindTexture( GL_TEXTURE_2D, 0 ); 4081 } 4082 4083 4084 4085 void Face_Draw( face_t *f ) 4086 { 4087 int i; 4088 4089 if ( f->face_winding == 0 ) 4090 return; 4091 qglBegin( GL_POLYGON ); 4092 for ( i = 0 ; i < f->face_winding->numpoints; i++) 4093 qglVertex3fv( f->face_winding->points[i] ); 4094 qglEnd(); 4095 } 4096 4097 void Brush_DrawXY(brush_t *b, int nViewType) 4098 { 4099 face_t *face; 4100 int order; 4101 winding_t *w; 4102 int i; 4103 4104 if (b->hiddenBrush) 4105 { 4106 return; 4107 } 4108 4109 if (b->patchBrush) 4110 { 4111 //Patch_DrawXY(b->nPatchID); 4112 Patch_DrawXY(b->pPatch); 4113 if (!g_bPatchShowBounds) 4114 return; 4115 } 4116 4117 if (b->terrainBrush) 4118 { 4119 Terrain_DrawXY(b->pTerrain, b->owner); 4120 } 4121 4122 4123 if (b->owner->eclass->fixedsize) 4124 { 4125 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT)) 4126 { 4127 vec3_t vCorners[4]; 4128 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2; 4129 4130 vCorners[0][0] = b->mins[0]; 4131 vCorners[0][1] = b->mins[1]; 4132 vCorners[0][2] = fMid; 4133 4134 vCorners[1][0] = b->mins[0]; 4135 vCorners[1][1] = b->maxs[1]; 4136 vCorners[1][2] = fMid; 4137 4138 vCorners[2][0] = b->maxs[0]; 4139 vCorners[2][1] = b->maxs[1]; 4140 vCorners[2][2] = fMid; 4141 4142 vCorners[3][0] = b->maxs[0]; 4143 vCorners[3][1] = b->mins[1]; 4144 vCorners[3][2] = fMid; 4145 4146 vec3_t vTop, vBottom; 4147 4148 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2); 4149 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2); 4150 vTop[2] = b->maxs[2]; 4151 4152 VectorCopy(vTop, vBottom); 4153 vBottom[2] = b->mins[2]; 4154 4155 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE); 4156 qglBegin(GL_TRIANGLE_FAN); 4157 qglVertex3fv(vTop); 4158 qglVertex3fv(vCorners[0]); 4159 qglVertex3fv(vCorners[1]); 4160 qglVertex3fv(vCorners[2]); 4161 qglVertex3fv(vCorners[3]); 4162 qglVertex3fv(vCorners[0]); 4163 qglEnd(); 4164 qglBegin(GL_TRIANGLE_FAN); 4165 qglVertex3fv(vBottom); 4166 qglVertex3fv(vCorners[0]); 4167 qglVertex3fv(vCorners[3]); 4168 qglVertex3fv(vCorners[2]); 4169 qglVertex3fv(vCorners[1]); 4170 qglVertex3fv(vCorners[0]); 4171 qglEnd(); 4172 DrawBrushEntityName (b); 4173 return; 4174 } 4175 else if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) 4176 { 4177 if (PaintedModel(b, false)) 4178 return; 4179 } 4180 } 4181 4182 for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) 4183 { 4184 // only draw polygons facing in a direction we care about 4185 if (nViewType == XY) 4186 { 4187 if (face->plane.normal[2] <= 0) 4188 continue; 4189 } 4190 else 4191 { 4192 if (nViewType == XZ) 4193 { 4194 if (face->plane.normal[1] <= 0) 4195 continue; 4196 } 4197 else 4198 { 4199 if (face->plane.normal[0] <= 0) 4200 continue; 4201 } 4202 } 4203 4204 w = face->face_winding; 4205 if (!w) 4206 continue; 4207 4208 //if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) 4209 // continue; 4210 4211 // draw the polygon 4212 qglBegin(GL_LINE_LOOP); 4213 for (i=0 ; i<w->numpoints ; i++) 4214 qglVertex3fv(w->points[i]); 4215 qglEnd(); 4216 } 4217 4218 DrawBrushEntityName (b); 4219 4220 } 4221 4222 /* 4223 ============ 4224 Brush_Move 4225 ============ 4226 */ 4227 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap) 4228 { 4229 int i; 4230 face_t *f; 4231 4232 for (f=b->brush_faces ; f ; f=f->next) 4233 { 4234 vec3_t vTemp; 4235 VectorCopy(move, vTemp); 4236 4237 if (g_PrefsDlg.m_bTextureLock) 4238 Face_MoveTexture(f, vTemp); 4239 4240 for (i=0 ; i<3 ; i++) 4241 VectorAdd (f->planepts[i], move, f->planepts[i]); 4242 } 4243 Brush_Build( b, bSnap ); 4244 4245 4246 if (b->patchBrush) 4247 { 4248 //Patch_Move(b->nPatchID, move); 4249 Patch_Move(b->pPatch, move); 4250 } 4251 4252 if (b->terrainBrush) 4253 { 4254 Terrain_Move(b->pTerrain, move); 4255 } 4256 4257 4258 // PGM - keep the origin vector up to date on fixed size entities. 4259 if(b->owner->eclass->fixedsize) 4260 { 4261 VectorAdd(b->owner->origin, move, b->owner->origin); 4262 //VectorAdd(b->maxs, b->mins, b->owner->origin); 4263 //VectorScale(b->owner->origin, 0.5, b->owner->origin); 4264 } 4265 } 4266 4267 4268 4269 void Brush_Print(brush_t* b) 4270 { 4271 int nFace = 0; 4272 for (face_t* f = b->brush_faces ; f ; f=f->next) 4273 { 4274 Sys_Printf("Face %i\n", nFace++); 4275 Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]); 4276 Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]); 4277 Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]); 4278 } 4279 } 4280 4281 4282 4283 /* 4284 ============= 4285 Brush_MakeSided 4286 4287 Makes the current brushhave the given number of 2d sides and turns it into a cone 4288 ============= 4289 */ 4290 void Brush_MakeSidedCone(int sides) 4291 { 4292 int i; 4293 vec3_t mins, maxs; 4294 brush_t *b; 4295 texdef_t *texdef; 4296 face_t *f; 4297 vec3_t mid; 4298 float width; 4299 float sv, cv; 4300 4301 if (sides < 3) 4302 { 4303 Sys_Status ("Bad sides number", 0); 4304 return; 4305 } 4306 4307 if (!QE_SingleBrush ()) 4308 { 4309 Sys_Status ("Must have a single brush selected", 0 ); 4310 return; 4311 } 4312 4313 b = selected_brushes.next; 4314 VectorCopy (b->mins, mins); 4315 VectorCopy (b->maxs, maxs); 4316 texdef = &g_qeglobals.d_texturewin.texdef; 4317 4318 Brush_Free (b); 4319 4320 // find center of brush 4321 width = 8; 4322 for (i=0 ; i<2 ; i++) 4323 { 4324 mid[i] = (maxs[i] + mins[i])*0.5; 4325 if (maxs[i] - mins[i] > width) 4326 width = maxs[i] - mins[i]; 4327 } 4328 width /= 2; 4329 4330 b = Brush_Alloc(); 4331 4332 // create bottom face 4333 f = Face_Alloc(); 4334 f->texdef = *texdef; 4335 f->next = b->brush_faces; 4336 b->brush_faces = f; 4337 4338 f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; 4339 f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; 4340 f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; 4341 4342 for (i=0 ; i<sides ; i++) 4343 { 4344 f = Face_Alloc(); 4345 f->texdef = *texdef; 4346 f->next = b->brush_faces; 4347 b->brush_faces = f; 4348 4349 sv = sin (i*3.14159265*2/sides); 4350 cv = cos (i*3.14159265*2/sides); 4351 4352 4353 f->planepts[0][0] = floor(mid[0]+width*cv+0.5); 4354 f->planepts[0][1] = floor(mid[1]+width*sv+0.5); 4355 f->planepts[0][2] = mins[2]; 4356 4357 f->planepts[1][0] = mid[0]; 4358 f->planepts[1][1] = mid[1]; 4359 f->planepts[1][2] = maxs[2]; 4360 4361 f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5); 4362 f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5); 4363 f->planepts[2][2] = maxs[2]; 4364 4365 } 4366 4367 Brush_AddToList (b, &selected_brushes); 4368 4369 Entity_LinkBrush (world_entity, b); 4370 4371 Brush_Build( b ); 4372 4373 Sys_UpdateWindows (W_ALL); 4374 } 4375 4376 /* 4377 ============= 4378 Brush_MakeSided 4379 4380 Makes the current brushhave the given number of 2d sides and turns it into a sphere 4381 ============= 4382 4383 */ 4384 void Brush_MakeSidedSphere(int sides) 4385 { 4386 int i,j; 4387 vec3_t mins, maxs; 4388 brush_t *b; 4389 texdef_t *texdef; 4390 face_t *f; 4391 vec3_t mid; 4392 4393 if (sides < 4) 4394 { 4395 Sys_Status ("Bad sides number", 0); 4396 return; 4397 } 4398 4399 if (!QE_SingleBrush ()) 4400 { 4401 Sys_Status ("Must have a single brush selected", 0 ); 4402 return; 4403 } 4404 4405 b = selected_brushes.next; 4406 VectorCopy (b->mins, mins); 4407 VectorCopy (b->maxs, maxs); 4408 texdef = &g_qeglobals.d_texturewin.texdef; 4409 4410 Brush_Free (b); 4411 4412 // find center of brush 4413 float radius = 8; 4414 for (i=0 ; i<2 ; i++) 4415 { 4416 mid[i] = (maxs[i] + mins[i])*0.5; 4417 if (maxs[i] - mins[i] > radius) 4418 radius = maxs[i] - mins[i]; 4419 } 4420 radius /= 2; 4421 4422 b = Brush_Alloc(); 4423 4424 float dt = float(2 * Q_PI / sides); 4425 float dp = float(Q_PI / sides); 4426 float t,p; 4427 for(i=0; i <= sides-1; i++) 4428 { 4429 for(j=0;j <= sides-2; j++) 4430 { 4431 t = i * dt; 4432 p = float(j * dp - Q_PI / 2); 4433 4434 f = Face_Alloc(); 4435 f->texdef = *texdef; 4436 f->next = b->brush_faces; 4437 b->brush_faces = f; 4438 4439 VectorPolar(f->planepts[0], radius, t, p); 4440 VectorPolar(f->planepts[1], radius, t, p + dp); 4441 VectorPolar(f->planepts[2], radius, t + dt, p + dp); 4442 4443 for (int k = 0; k < 3; k++) 4444 VectorAdd(f->planepts[k], mid, f->planepts[k]); 4445 } 4446 } 4447 4448 p = float((sides - 1) * dp - Q_PI / 2); 4449 for(i = 0; i <= sides-1; i++) 4450 { 4451 t = i * dt; 4452 4453 f = Face_Alloc(); 4454 f->texdef = *texdef; 4455 f->next = b->brush_faces; 4456 b->brush_faces = f; 4457 4458 VectorPolar(f->planepts[0], radius, t, p); 4459 VectorPolar(f->planepts[1], radius, t + dt, p + dp); 4460 VectorPolar(f->planepts[2], radius, t + dt, p); 4461 4462 for (int k = 0; k < 3; k++) 4463 VectorAdd(f->planepts[k], mid, f->planepts[k]); 4464 } 4465 4466 Brush_AddToList (b, &selected_brushes); 4467 4468 Entity_LinkBrush (world_entity, b); 4469 4470 Brush_Build( b ); 4471 4472 Sys_UpdateWindows (W_ALL); 4473 } 4474 4475 void Face_FitTexture( face_t * face, int nHeight, int nWidth ) 4476 { 4477 winding_t *w; 4478 vec3_t mins,maxs; 4479 int i; 4480 float width, height, temp; 4481 float rot_width, rot_height; 4482 float cosv,sinv,ang; 4483 float min_t, min_s, max_t, max_s; 4484 float s,t; 4485 vec3_t vecs[2]; 4486 vec3_t coords[4]; 4487 texdef_t *td; 4488 4489 if (nHeight < 1) 4490 { 4491 nHeight = 1; 4492 } 4493 if (nWidth < 1) 4494 { 4495 nWidth = 1; 4496 } 4497 4498 ClearBounds (mins, maxs); 4499 4500 td = &face->texdef; 4501 w = face->face_winding; 4502 if (!w) 4503 { 4504 return; 4505 } 4506 for (i=0 ; i<w->numpoints ; i++) 4507 { 4508 AddPointToBounds( w->points[i], mins, maxs ); 4509 } 4510 // 4511 // get the current angle 4512 // 4513 ang = td->rotate / 180 * Q_PI; 4514 sinv = sin(ang); 4515 cosv = cos(ang); 4516 4517 // get natural texture axis 4518 TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); 4519 4520 min_s = DotProduct( mins, vecs[0] ); 4521 min_t = DotProduct( mins, vecs[1] ); 4522 max_s = DotProduct( maxs, vecs[0] ); 4523 max_t = DotProduct( maxs, vecs[1] ); 4524 width = max_s - min_s; 4525 height = max_t - min_t; 4526 coords[0][0] = min_s; 4527 coords[0][1] = min_t; 4528 coords[1][0] = max_s; 4529 coords[1][1] = min_t; 4530 coords[2][0] = min_s; 4531 coords[2][1] = max_t; 4532 coords[3][0] = max_s; 4533 coords[3][1] = max_t; 4534 min_s = min_t = 99999; 4535 max_s = max_t = -99999; 4536 for (i=0; i<4; i++) 4537 { 4538 s = cosv * coords[i][0] - sinv * coords[i][1]; 4539 t = sinv * coords[i][0] + cosv * coords[i][1]; 4540 if (i&1) 4541 { 4542 if (s > max_s) 4543 { 4544 max_s = s; 4545 } 4546 } 4547 else 4548 { 4549 if (s < min_s) 4550 { 4551 min_s = s; 4552 } 4553 if (i<2) 4554 { 4555 if (t < min_t) 4556 { 4557 min_t = t; 4558 } 4559 } 4560 else 4561 { 4562 if (t > max_t) 4563 { 4564 max_t = t; 4565 } 4566 } 4567 } 4568 } 4569 rot_width = (max_s - min_s); 4570 rot_height = (max_t - min_t); 4571 td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth))); 4572 td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight))); 4573 4574 td->shift[0] = min_s/td->scale[0]; 4575 temp = (int)(td->shift[0] / (face->d_texture->width*nWidth)); 4576 temp = (temp+1)*face->d_texture->width*nWidth; 4577 td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth); 4578 4579 td->shift[1] = min_t/td->scale[1]; 4580 temp = (int)(td->shift[1] / (face->d_texture->height*nHeight)); 4581 temp = (temp+1)*(face->d_texture->height*nHeight); 4582 td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight); 4583 } 4584 4585 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth ) 4586 { 4587 face_t *face; 4588 4589 for (face = b->brush_faces ; face ; face=face->next) 4590 { 4591 Face_FitTexture( face, nHeight, nWidth ); 4592 } 4593 } 4594 4595