2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
35 #include "../../renderer/tr_local.h"
36 #include "../../renderer/model_local.h" // for idRenderModelMD5
38 void Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset);
39 void Brush_DrawCurve( brush_t *b, bool bSelected, bool cam );
43 bool g_bShowLightVolumes = false;
44 bool g_bShowLightTextures = false;
46 void GLCircle(float x, float y, float z, float r);
48 const int POINTS_PER_KNOT = 50;
55 void DrawRenderModel( idRenderModel *model, idVec3 &origin, idMat3 &axis, bool cameraView ) {
56 for ( int i = 0; i < model->NumSurfaces(); i++ ) {
57 const modelSurface_t *surf = model->Surface( i );
58 const idMaterial *material = surf->shader;
60 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
62 if ( cameraView && (nDrawMode == cd_texture || nDrawMode == cd_light) ) {
63 material->GetEditorImage()->Bind();
66 qglBegin( GL_TRIANGLES );
68 const srfTriangles_t *tri = surf->geometry;
69 for ( int j = 0; j < tri->numIndexes; j += 3 ) {
70 for ( int k = 0; k < 3; k++ ) {
71 int index = tri->indexes[j + k];
74 v = tri->verts[index].xyz * axis + origin;
75 qglTexCoord2f( tri->verts[index].st.x, tri->verts[index].st.y );
76 qglVertex3fv( v.ToFloatPtr() );
89 void SnapVectorToGrid(idVec3 &v) {
90 v.x = floor(v.x / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
91 v.y = floor(v.y / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
92 v.z = floor(v.z / g_qeglobals.d_gridsize + 0.5f) * g_qeglobals.d_gridsize;
100 const char *Brush_Name( brush_t *b ) {
101 static char cBuff[1024];
103 b->numberId = g_nBrushId++;
104 if (g_qeglobals.m_bBrushPrimitMode) {
105 sprintf(cBuff, "Brush %i", b->numberId);
106 Brush_SetEpair(b, "Name", cBuff);
117 brush_t *Brush_Alloc( void ) {
118 brush_t *b = new brush_t;
119 b->prev = b->next = NULL;
120 b->oprev = b->onext = NULL;
125 b->lightCenter.Zero();
126 b->lightRight.Zero();
127 b->lightTarget.Zero();
129 b->lightRadius.Zero();
130 b->lightOffset.Zero();
131 b->lightColor.Zero();
132 b->lightStart.Zero();
134 b->pointLight = false;
137 b->trackLightOrigin = false;
139 b->entityModel = false;
140 b->brush_faces = NULL;
141 b->hiddenBrush = false;
143 b->pUndoOwner = NULL;
149 b->bModelFailed = false;
150 b->modelHandle = NULL;
151 b->forceVisibile = false;
152 b->forceWireFrame = false;
161 idVec3 baseaxis[18] = {
189 idVec3(0, 0, -1) // north wall
192 void TextureAxisFromPlane( const idPlane &pln, idVec3 &xv, idVec3 &yv) {
200 for (i = 0; i < 6; i++) {
201 dot = DotProduct(pln, baseaxis[i * 3]);
208 VectorCopy(baseaxis[bestaxis * 3 + 1], xv);
209 VectorCopy(baseaxis[bestaxis * 3 + 2], yv);
216 Light different planes differently to improve recognition
219 float lightaxis[3] = { 0.6f, 0.8f, 1.0f };
221 float ShadeForNormal(idVec3 normal) {
226 for (i = 0; i < 3; i++) {
227 if ( idMath::Fabs(normal[i]) > 0.9f ) {
233 // between two axial planes
234 for (i = 0; i < 3; i++) {
235 if ( idMath::Fabs(normal[i]) < 0.1f ) {
236 f = (lightaxis[(i + 1) % 3] + lightaxis[(i + 2) % 3]) / 2;
242 f = (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
251 face_t *Face_Alloc(void) {
252 brushprimit_texdef_t bp;
254 face_t *f = (face_t *) Mem_ClearedAlloc(sizeof(*f));
256 bp.coords[0][0] = 0.0f;
257 bp.coords[1][1] = 0.0f;
258 f->brushprimit_texdef = bp;
268 void Face_Free(face_t *f) {
271 if (f->face_winding) {
272 delete f->face_winding;
275 f->texdef.~texdef_t();
285 face_t *Face_Clone(face_t *f) {
289 n->texdef = f->texdef;
290 n->brushprimit_texdef = f->brushprimit_texdef;
292 memcpy(n->planepts, f->planepts, sizeof(n->planepts));
294 n->originalPlane = f->originalPlane;
297 // all other fields are derived, and will be set by Brush_Build
306 Makes an exact copy of the face.
309 face_t *Face_FullClone(face_t *f) {
313 n->texdef = f->texdef;
314 n->brushprimit_texdef = f->brushprimit_texdef;
315 memcpy(n->planepts, f->planepts, sizeof(n->planepts));
317 n->originalPlane = f->originalPlane;
319 if (f->face_winding) {
320 n->face_winding = f->face_winding->Copy();
323 n->face_winding = NULL;
326 n->d_texture = Texture_ForName(n->texdef.name);
335 void Clamp(float &f, int nClamp) {
336 float fFrac = f - static_cast<int>(f);
337 f = static_cast<int>(f) % nClamp;
346 void Face_MoveTexture(face_t *f, idVec3 delta) {
350 * #ifdef _DEBUG if (g_PrefsDlg.m_bBrushPrimitMode) common->Printf("Warning :
351 * Face_MoveTexture not done in brush primitive mode\n"); #endif
353 if (g_qeglobals.m_bBrushPrimitMode) {
354 Face_MoveTexture_BrushPrimit(f, delta);
357 TextureAxisFromPlane( f->plane, vX, vY );
360 vDP[0] = DotProduct(delta, vX);
361 vDP[1] = DotProduct(delta, vY);
363 double fAngle = DEG2RAD( f->texdef.rotate );
364 double c = cos(fAngle);
365 double s = sin(fAngle);
367 vShift[0] = vDP[0] * c - vDP[1] * s;
368 vShift[1] = vDP[0] * s + vDP[1] * c;
370 if (!f->texdef.scale[0]) {
371 f->texdef.scale[0] = 1;
374 if (!f->texdef.scale[1]) {
375 f->texdef.scale[1] = 1;
378 f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
379 f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
382 Clamp(f->texdef.shift[0], f->d_texture->GetEditorImage()->uploadWidth);
383 Clamp(f->texdef.shift[1], f->d_texture->GetEditorImage()->uploadHeight);
392 void Face_SetColor(brush_t *b, face_t *f, float fCurveColor) {
398 // set shading for face
399 shade = ShadeForNormal( f->plane.Normal() );
400 if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture && (b->owner && !b->owner->eclass->fixedsize)) {
401 // if (b->curveBrush) shade = fCurveColor;
402 f->d_color[0] = f->d_color[1] = f->d_color[2] = shade;
404 else if ( f && b && b->owner ) {
405 f->d_color[0] = shade * b->owner->eclass->color.x;
406 f->d_color[1] = shade * b->owner->eclass->color.y;
407 f->d_color[2] = shade * b->owner->eclass->color.z;
415 NOTE: this is never to get called while in brush primitives mode
418 void Face_TextureVectors(face_t *f, float STfromXYZ[2][4]) {
421 float ang, sinv, cosv;
430 // ++timo when playing with patches, this sometimes get called and the Warning is
431 // displayed find some way out ..
433 if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert) {
434 common->Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
440 memset(STfromXYZ, 0, 8 * sizeof (float));
443 td->scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 2 : 1;
447 td->scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 2 : 1;
450 // get natural texture axis
451 TextureAxisFromPlane( f->plane, pvecs[0], pvecs[1]);
454 if (td->rotate == 0) {
458 else if (td->rotate == 90) {
462 else if (td->rotate == 180) {
466 else if (td->rotate == 270) {
471 ang = DEG2RAD( td->rotate );
479 else if (pvecs[0][1]) {
489 else if (pvecs[1][1]) {
496 for (i = 0; i < 2; i++) {
497 ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
498 nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv];
499 STfromXYZ[i][sv] = ns;
500 STfromXYZ[i][tv] = nt;
504 for (i = 0; i < 2; i++) {
505 for (j = 0; j < 3; j++) {
506 STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
511 STfromXYZ[0][3] = td->shift[0];
512 STfromXYZ[1][3] = td->shift[1];
514 for (j = 0; j < 4; j++) {
515 STfromXYZ[0][j] /= q->GetEditorImage()->uploadWidth;
516 STfromXYZ[1][j] /= q->GetEditorImage()->uploadHeight;
525 void Face_MakePlane(face_t *f) {
529 idPlane oldPlane = f->plane;
531 // convert to a vector / dist plane
532 for (j = 0; j < 3; j++) {
533 t1[j] = f->planepts[0][j] - f->planepts[1][j];
534 t2[j] = f->planepts[2][j] - f->planepts[1][j];
535 t3[j] = f->planepts[1][j];
538 f->plane = t1.Cross( t2 );
539 //if ( f->plane.Compare( vec3_origin ) ) {
540 // printf("WARNING: brush plane with no normal\n");
543 f->plane.Normalize(false);
544 f->plane[3] = - (t3 * f->plane.Normal());
546 if ( !f->dirty && !f->plane.Compare( oldPlane, 0.01f ) ) {
553 EmitTextureCoordinates
556 void EmitTextureCoordinates(idVec5 &xyzst, const idMaterial *q, face_t *f, bool force) {
557 float STfromXYZ[2][4];
559 if (g_qeglobals.m_bBrushPrimitMode && !force) {
560 EmitBrushPrimitTextureCoordinates(f, f->face_winding);
563 Face_TextureVectors(f, STfromXYZ);
564 xyzst[3] = DotProduct(xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
565 xyzst[4] = DotProduct(xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
574 void Brush_MakeFacePlanes(brush_t *b) {
577 for (f = b->brush_faces; f; f = f->next) {
587 void DrawBrushEntityName(brush_t *b) {
590 // float a, s, c; vec3_t mid; int i;
592 return; // during contruction
595 if (b->owner == world_entity) {
599 if (b != b->owner->brushes.onext) {
600 return; // not key brush
603 if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES)) {
604 // draw the angle pointer
605 float a = FloatForKey(b->owner, "angle");
607 float s = sin( DEG2RAD( a ) );
608 float c = cos( DEG2RAD( a ) );
610 idVec3 mid = (b->mins + b->maxs) / 2.0f;
612 qglBegin(GL_LINE_STRIP);
613 qglVertex3fv(mid.ToFloatPtr());
617 qglVertex3fv(mid.ToFloatPtr());
624 qglVertex3fv(mid.ToFloatPtr());
631 qglVertex3fv(mid.ToFloatPtr());
638 qglVertex3fv(mid.ToFloatPtr());
643 int viewType = g_pParentWnd->ActiveXY()->GetViewType();
644 float scale = g_pParentWnd->ActiveXY()->Scale();
646 if (g_qeglobals.d_savedinfo.show_names && scale >= 1.0f) {
647 name = ValueForKey(b->owner, "name");
648 int nameLen = strlen(name);
649 if ( nameLen == 0 ) {
650 name = ValueForKey(b->owner, "classname");
651 nameLen = strlen(name);
654 idVec3 origin = b->owner->origin;
656 float halfWidth = ( (nameLen / 2) * (7.0f / scale) );
657 float halfHeight = 4.0f / scale;
661 origin.x -= halfWidth;
662 origin.y += halfHeight;
665 origin.x -= halfWidth;
666 origin.z += halfHeight;
669 origin.y -= halfWidth;
670 origin.z += halfHeight;
673 qglRasterPos3fv( origin.ToFloatPtr() );
674 qglCallLists(nameLen, GL_UNSIGNED_BYTE, name);
681 Brush_MakeFaceWinding
683 returns the visible winding
686 idWinding *Brush_MakeFaceWinding(brush_t *b, face_t *face, bool keepOnPlaneWinding) {
692 // get a poly that covers an effectively infinite area
693 w = new idWinding( face->plane );
695 // chop the poly by all of the other faces
697 for (clip = b->brush_faces; clip && w; clip = clip->next) {
703 if ( DotProduct(face->plane, clip->plane) > 0.999f &&
704 idMath::Fabs(face->plane[3] - clip->plane[3]) < 0.01f ) { // identical plane, use the later one
707 common->Printf("Unable to create face winding on brush\n");
713 // flip the plane, because we want to keep the back side
714 VectorSubtract(vec3_origin, clip->plane, plane );
715 plane[3] = -clip->plane[3];
717 w = w->Clip( plane, ON_EPSILON, keepOnPlaneWinding );
723 if ( w->GetNumPoints() < 3) {
729 Sys_Status("Unable to create face winding on brush\n");
738 Builds a brush rendering data and also sets the min/max bounds
739 TTimo added a bConvert flag to convert between old and new brush texture formats
740 TTimo brush grouping: update the group treeview if necessary
743 void Brush_Build(brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool updateLights) {
744 bool bLocalConvert = false;
747 if (!g_qeglobals.m_bBrushPrimitMode && bConvert) {
748 common->Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
752 // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need
753 // convert for this brush only
755 if (bConvert && !g_qeglobals.bNeedConvert) {
756 bLocalConvert = true;
757 g_qeglobals.bNeedConvert = true;
760 /* build the windings and generate the bounding box */
761 Brush_BuildWindings(b, bSnap, EntityHasModel(b->owner) || b->pPatch, updateLights);
763 /* move the points and edges if in select mode */
764 if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) {
765 SetupVertexSelection();
769 Sys_MarkMapModified();
770 g_pParentWnd->GetCamera()->MarkWorldDirty();
774 g_qeglobals.bNeedConvert = false;
780 Brush_SplitBrushByFace
782 The incoming brush is NOT freed. The incoming face is NOT left referenced.
785 void Brush_SplitBrushByFace(brush_t *in, face_t *f, brush_t **front, brush_t **back) {
793 nf->texdef = b->brush_faces->texdef;
794 nf->brushprimit_texdef = b->brush_faces->brushprimit_texdef;
795 nf->next = b->brush_faces;
799 Brush_RemoveEmptyFaces(b);
800 if (!b->brush_faces) { // completely clipped away
805 Entity_LinkBrush(in->owner, b);
812 // swap the plane winding
813 VectorCopy(nf->planepts[0], temp);
814 VectorCopy(nf->planepts[1], nf->planepts[0]);
815 VectorCopy(temp, nf->planepts[1]);
817 nf->texdef = b->brush_faces->texdef;
818 nf->brushprimit_texdef = b->brush_faces->brushprimit_texdef;
819 nf->next = b->brush_faces;
823 Brush_RemoveEmptyFaces(b);
824 if (!b->brush_faces) { // completely clipped away
829 Entity_LinkBrush(in->owner, b);
838 returns the best face to split the brush with. return NULL if the brush is convex
841 face_t *Brush_BestSplitFace(brush_t *b) {
842 face_t *face, *f, *bestface;
843 idWinding *front, *back;
844 int splits, tinywindings, value, bestvalue;
848 for ( face = b->brush_faces; face; face = face->next ) {
851 for ( f = b->brush_faces; f; f = f->next ) {
856 f->face_winding->Split( face->plane, 0.1f, &front, &back );
866 if ( front->IsTiny() ) {
870 if ( back->IsTiny() ) {
879 value = splits + 50 * tinywindings;
880 if ( value < bestvalue ) {
892 Brush_MakeConvexBrushes
894 MrE FIXME: this doesn't work because the old Brush_SplitBrushByFace is used
895 Turns the brush into a minimal number of convex brushes.
896 If the input brush is convex then it will be returned. Otherwise the input
898 NOTE: the input brush should have windings for the faces.
901 brush_t *Brush_MakeConvexBrushes(brush_t *b) {
902 brush_t *front, *back, *end;
906 face = Brush_BestSplitFace(b);
911 Brush_SplitBrushByFace(b, face, &front, &back);
913 // this should never happen
914 if (!front && !back) {
920 return Brush_MakeConvexBrushes(back);
923 b = Brush_MakeConvexBrushes(front);
925 for (end = b; end->next; end = end->next);
926 end->next = Brush_MakeConvexBrushes(back);
936 returns true if the brush is convex
939 int Brush_Convex(brush_t *b) {
940 face_t *face1, *face2;
942 for (face1 = b->brush_faces; face1; face1 = face1->next) {
943 if (!face1->face_winding) {
947 for (face2 = b->brush_faces; face2; face2 = face2->next) {
948 if (face1 == face2) {
952 if (!face2->face_winding) {
956 if ( face1->face_winding->PlanesConcave( *face2->face_winding,
957 face1->plane.Normal(), face2->plane.Normal(), -face1->plane[3], -face2->plane[3] ) ) {
970 The input brush must be convex.
971 The input brush must have face windings.
972 The output brush will be convex.
973 Returns true if the WHOLE vertex movement is performed.
976 #define MAX_MOVE_FACES 64
977 #define TINY_EPSILON 0.0325f
979 int Brush_MoveVertex(brush_t *b, const idVec3 &vertex, const idVec3 &delta, idVec3 &end, bool bSnap) {
980 face_t *f, *face, *newface, *lastface, *nextface;
981 face_t *movefaces[MAX_MOVE_FACES];
982 int movefacepoints[MAX_MOVE_FACES];
983 idWinding *w, tmpw(3);
986 int i, j, k, nummovefaces, result, done;
987 float dot, front, back, frac, smallestfrac;
990 tmpw.SetNumPoints( 3 );
991 VectorCopy(vertex, start);
992 VectorAdd(vertex, delta, end);
997 for (i = 0; i < 3; i++) {
998 end[i] = floor( end[i] / 0.125f + 0.5f ) * 0.125f;
1002 VectorCopy(end, mid);
1004 // if the start and end are the same
1005 if ( start.Compare( end, TINY_EPSILON ) ) {
1009 // the end point may not be the same as another vertex
1010 for ( face = b->brush_faces; face; face = face->next ) {
1011 w = face->face_winding;
1016 for (i = 0; i < w->GetNumPoints(); i++) {
1017 if ( end.Compare( (*w)[i].ToVec3(), TINY_EPSILON ) ) {
1018 VectorCopy(vertex, end);
1027 // chop off triangles from all brush faces that use the to be moved vertex store
1028 // pointers to these chopped off triangles in movefaces[]
1031 for (face = b->brush_faces; face; face = face->next) {
1032 w = face->face_winding;
1037 for (i = 0; i < w->GetNumPoints(); i++) {
1038 if ( start.Compare( (*w)[i].ToVec3(), TINY_EPSILON ) ) {
1039 if (face->face_winding->GetNumPoints() <= 3) {
1040 movefacepoints[nummovefaces] = i;
1041 movefaces[nummovefaces++] = face;
1045 dot = DotProduct(end, face->plane) + face->plane[3];
1047 // if the end point is in front of the face plane
1048 //if ( dot > 0.1f ) {
1049 if ( dot > TINY_EPSILON ) {
1050 // fanout triangle subdivision
1051 for (k = i; k < i + w->GetNumPoints() - 3; k++) {
1052 VectorCopy((*w)[i], tmpw[0]);
1053 VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[1]);
1054 VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[2]);
1055 newface = Face_Clone(face);
1058 for (f = face; f->original; f = f->original) {};
1060 newface->original = f;
1062 // store the new winding
1063 if (newface->face_winding) {
1064 delete newface->face_winding;
1067 newface->face_winding = tmpw.Copy();
1070 newface->d_texture = Texture_ForName(newface->texdef.name);
1072 // add the face to the brush
1073 newface->next = b->brush_faces;
1074 b->brush_faces = newface;
1076 // add this new triangle to the move faces
1077 movefacepoints[nummovefaces] = 0;
1078 movefaces[nummovefaces++] = newface;
1081 // give the original face a new winding
1082 VectorCopy((*w)[(i - 2 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[0]);
1083 VectorCopy((*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[1]);
1084 VectorCopy((*w)[i], tmpw[2]);
1085 delete face->face_winding;
1086 face->face_winding = tmpw.Copy();
1088 // add the original face to the move faces
1089 movefacepoints[nummovefaces] = 2;
1090 movefaces[nummovefaces++] = face;
1093 // chop a triangle off the face
1094 VectorCopy((*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()], tmpw[0]);
1095 VectorCopy((*w)[i], tmpw[1]);
1096 VectorCopy((*w)[(i + 1) % w->GetNumPoints()], tmpw[2]);
1098 // remove the point from the face winding
1099 w->RemovePoint( i );
1101 // get texture crap right
1102 Face_SetColor(b, face, 1.0);
1103 for (j = 0; j < w->GetNumPoints(); j++) {
1104 EmitTextureCoordinates( (*w)[j], face->d_texture, face );
1107 // make a triangle face
1108 newface = Face_Clone(face);
1111 for (f = face; f->original; f = f->original) {};
1113 newface->original = f;
1115 // store the new winding
1116 if (newface->face_winding) {
1117 delete newface->face_winding;
1120 newface->face_winding = tmpw.Copy();
1123 newface->d_texture = Texture_ForName(newface->texdef.name);
1125 // add the face to the brush
1126 newface->next = b->brush_faces;
1127 b->brush_faces = newface;
1128 movefacepoints[nummovefaces] = 1;
1129 movefaces[nummovefaces++] = newface;
1137 // now movefaces contains pointers to triangle faces that contain the to be moved
1141 VectorCopy(end, mid);
1143 for (face = b->brush_faces; face; face = face->next) {
1144 // check if there is a move face that has this face as the original
1145 for (i = 0; i < nummovefaces; i++) {
1146 if (movefaces[i]->original == face) {
1151 if (i >= nummovefaces) {
1155 // check if the original is not a move face itself
1156 for (j = 0; j < nummovefaces; j++) {
1157 if (face == movefaces[j]) {
1162 // if the original is not a move face itself
1163 if (j >= nummovefaces) {
1164 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane));
1167 k = movefacepoints[j];
1168 w = movefaces[j]->face_winding;
1169 VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[0]);
1170 VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[1]);
1172 k = movefacepoints[i];
1173 w = movefaces[i]->face_winding;
1174 VectorCopy((*w)[(k + 1) % w->GetNumPoints()], tmpw[2]);
1176 if ( !plane.FromPoints( tmpw[0].ToVec3(), tmpw[1].ToVec3(), tmpw[2].ToVec3(), false ) ) {
1177 VectorCopy((*w)[(k + 2) % w->GetNumPoints()], tmpw[2]);
1178 if ( !plane.FromPoints( tmpw[0].ToVec3(), tmpw[1].ToVec3(), tmpw[2].ToVec3() ), false ) {
1179 // this should never happen otherwise the face merge did
1180 // a crappy job a previous pass
1184 plane[0] = -plane[0];
1185 plane[1] = -plane[1];
1186 plane[2] = -plane[2];
1187 plane[3] = -plane[3];
1190 // now we've got the plane to check against
1191 front = DotProduct(start, plane) + plane[3];
1192 back = DotProduct(end, plane) + plane[3];
1194 // if the whole move is at one side of the plane
1195 if (front < TINY_EPSILON && back < TINY_EPSILON) {
1199 if (front > -TINY_EPSILON && back > -TINY_EPSILON) {
1203 // if there's no movement orthogonal to this plane at all
1204 if ( idMath::Fabs(front - back) < 0.001f ) {
1208 // ok first only move till the plane is hit
1209 frac = front / (front - back);
1210 if (frac < smallestfrac) {
1211 mid[0] = start[0] + (end[0] - start[0]) * frac;
1212 mid[1] = start[1] + (end[1] - start[1]) * frac;
1213 mid[2] = start[2] + (end[2] - start[2]) * frac;
1214 smallestfrac = frac;
1221 for (i = 0; i < nummovefaces; i++) {
1222 // move vertex to end position
1223 VectorCopy( mid, (*movefaces[i]->face_winding)[movefacepoints[i]] );
1225 // create new face plane
1226 for (j = 0; j < 3; j++) {
1227 VectorCopy( (*movefaces[i]->face_winding)[j], movefaces[i]->planepts[j] );
1230 Face_MakePlane( movefaces[i] );
1231 if ( movefaces[i]->plane.Normal().Length() < TINY_EPSILON ) {
1236 // if the brush is no longer convex
1237 if (!result || !Brush_Convex(b)) {
1238 for (i = 0; i < nummovefaces; i++) {
1239 // move the vertex back to the initial position
1240 VectorCopy( start, (*movefaces[i]->face_winding)[movefacepoints[i]] );
1242 // create new face plane
1243 for (j = 0; j < 3; j++) {
1244 VectorCopy( (*movefaces[i]->face_winding)[j], movefaces[i]->planepts[j] );
1247 Face_MakePlane(movefaces[i]);
1251 VectorCopy(start, end);
1255 VectorCopy(mid, start);
1258 // get texture crap right
1259 for (i = 0; i < nummovefaces; i++) {
1260 Face_SetColor( b, movefaces[i], 1.0f );
1261 for (j = 0; j < movefaces[i]->face_winding->GetNumPoints(); j++) {
1262 EmitTextureCoordinates( (*movefaces[i]->face_winding)[j], movefaces[i]->d_texture, movefaces[i] );
1266 // now try to merge faces with their original faces
1268 for (face = b->brush_faces; face; face = nextface) {
1269 nextface = face->next;
1270 if (!face->original) {
1275 if ( !face->plane.Compare( face->original->plane, 0.0001f ) ) {
1280 w = face->face_winding->TryMerge( *face->original->face_winding, face->plane.Normal(), true );
1286 delete face->original->face_winding;
1287 face->original->face_winding = w;
1289 // get texture crap right
1290 Face_SetColor( b, face->original, 1.0f );
1291 for (j = 0; j < face->original->face_winding->GetNumPoints(); j++) {
1292 EmitTextureCoordinates( (*face->original->face_winding)[j], face->original->d_texture, face->original);
1295 // remove the face that was merged with the original
1297 lastface->next = face->next;
1300 b->brush_faces = face->next;
1312 Brush_InsertVertexBetween
1314 Adds a vertex to the brush windings between the given two points.
1317 int Brush_InsertVertexBetween(brush_t *b, idVec3 p1, idVec3 p2) {
1319 idWinding *w, *neww;
1323 if ( p1.Compare( p2, TINY_EPSILON ) ) {
1327 VectorAdd( p1, p2, point );
1328 VectorScale( point, 0.5f, point );
1331 // the end point may not be the same as another vertex
1332 for (face = b->brush_faces; face; face = face->next) {
1333 w = face->face_winding;
1339 for (i = 0; i < w->GetNumPoints(); i++) {
1340 if (! p1.Compare((*w)[i].ToVec3(), TINY_EPSILON)) {
1344 if ( p2.Compare( (*w)[(i + 1) % w->GetNumPoints()].ToVec3(), TINY_EPSILON ) ) {
1345 neww = new idWinding( *w );
1346 neww->InsertPoint( point, (i + 1) % w->GetNumPoints() );
1349 else if ( p2.Compare( (*w)[(i - 1 + w->GetNumPoints()) % w->GetNumPoints()].ToVec3(), TINY_EPSILON ) ) {
1350 neww = new idWinding( *w );
1351 neww->InsertPoint( point, i );
1357 delete face->face_winding;
1358 face->face_winding = neww;
1368 Brush_ResetFaceOriginals
1370 reset points to original faces to NULL
1373 void Brush_ResetFaceOriginals(brush_t *b) {
1376 for (face = b->brush_faces; face; face = face->next) {
1377 face->original = NULL;
1385 The brush is NOT linked to any list
1386 FIXME: when using old brush primitives, the test loop for "Brush" and "patchDef2" "patchDef3"
1387 run before each face parsing. It works, but it's a performance hit
1390 brush_t *Brush_Parse(idVec3 origin) {
1394 idVec3 useOrigin = origin;
1396 g_qeglobals.d_parsed_brushes++;
1399 if (!GetToken(true)) {
1403 if (!strcmp(token, "}")) {
1407 // handle "Brush" primitive
1408 if ( idStr::Icmp(token, "brushDef") == 0 || idStr::Icmp(token, "brushDef2") == 0 || idStr::Icmp(token, "brushDef3") == 0 ) {
1409 // Timo parsing new brush format
1410 g_qeglobals.bPrimitBrushes = true;
1412 // check the map is not mixing the two kinds of brushes
1413 if (g_qeglobals.m_bBrushPrimitMode) {
1414 if (g_qeglobals.bOldBrushes) {
1415 common->Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
1419 // ++Timo write new brush primitive -> old conversion code for Q3->Q2 conversions ?
1420 common->Printf("Warning : conversion code from brush primitive not done ( Brush_Parse )\n");
1423 bool newFormat = false;
1424 if ( idStr::Icmp(token, "brushDef2") == 0 ) {
1427 // useOrigin.Zero();
1429 else if ( idStr::Icmp(token, "brushDef3") == 0 ) {
1434 BrushPrimit_Parse(b, newFormat, useOrigin);
1437 //Brush_BuildWindings(b, true, true, false, false);
1441 Warning("parsing brush primitive");
1449 if ( idStr::Icmp(token, "patchDef2") == 0 || idStr::Icmp(token, "patchDef3") == 0 ) {
1452 // double string compare but will go away soon
1453 b = Patch_Parse( idStr::Icmp(token, "patchDef2") == 0 );
1455 Warning("parsing patch/brush");
1462 // handle inline patch
1465 // Timo parsing old brush format
1466 g_qeglobals.bOldBrushes = true;
1467 if (g_qeglobals.m_bBrushPrimitMode) {
1468 // check the map is not mixing the two kinds of brushes
1469 if (g_qeglobals.bPrimitBrushes) {
1470 common->Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
1473 // set the "need" conversion flag
1474 g_qeglobals.bNeedConvert = true;
1480 // add the brush to the end of the chain, so loading and saving a map doesn't
1481 // reverse the order
1484 if (!b->brush_faces) {
1489 for (scan = b->brush_faces; scan->next; scan = scan->next)
1494 // read the three point plane definition
1495 for (i = 0; i < 3; i++) {
1500 if (strcmp(token, "(")) {
1501 Warning("parsing brush");
1505 for (j = 0; j < 3; j++) {
1507 f->planepts[i][j] = atof(token);
1511 if (strcmp(token, ")")) {
1512 Warning("parsing brush");
1518 // read the texturedef
1520 f->texdef.SetName(token);
1521 if (token[0] == '(') {
1526 f->texdef.shift[0] = atoi(token);
1528 f->texdef.shift[1] = atoi(token);
1530 f->texdef.rotate = atoi(token);
1532 f->texdef.scale[0] = atof(token);
1534 f->texdef.scale[1] = atof(token);
1536 // the flags and value field aren't necessarily present
1537 f->d_texture = Texture_ForName(f->texdef.name);
1540 // FIXME: idMaterial f->texdef.flags = f->d_texture->flags; f->texdef.value =
1541 // f->d_texture->value; f->texdef.contents = f->d_texture->contents;
1543 if (TokenAvailable()) {
1547 f->texdef.value = atoi(token);
1556 QERApp_MapPrintf_FILE
1558 callback for surface properties plugin must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
1559 carefully initialize !
1564 void WINAPI QERApp_MapPrintf_FILE(char *text, ...) {
1568 va_start(argptr, text);
1569 vsprintf(buf, text, argptr);
1572 fprintf(g_File, buf);
1579 sets an epair for the given brush
1582 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue) {
1583 if (g_qeglobals.m_bBrushPrimitMode) {
1585 Patch_SetEpair(b->pPatch, pKey, pValue);
1588 b->epairs.Set(pKey, pValue);
1592 Sys_Status("Can only set key/values in Brush primitive mode\n");
1601 const char *Brush_GetKeyValue(brush_t *b, const char *pKey) {
1602 if (g_qeglobals.m_bBrushPrimitMode) {
1604 return Patch_GetKeyValue(b->pPatch, pKey);
1607 return b->epairs.GetString(pKey);
1611 Sys_Status("Can only set brush/patch key/values in Brush primitive mode\n");
1621 save all brushes as Brush primitive format
1624 void Brush_Write(brush_t *b, FILE *f, const idVec3 &origin, bool newFormat) {
1630 Patch_Write(b->pPatch, f);
1634 if (g_qeglobals.m_bBrushPrimitMode) {
1635 // save brush primitive format
1637 WriteFileString(f, "{\nbrushDef3\n{\n");
1640 WriteFileString(f, "{\nbrushDef\n{\n");
1644 int count = b->epairs.GetNumKeyVals();
1645 for (int j = 0; j < count; j++) {
1646 WriteFileString(f, "\"%s\" \"%s\"\n", b->epairs.GetKeyVal(j)->GetKey().c_str(), b->epairs.GetKeyVal(j)->GetValue().c_str());
1649 for (fa = b->brush_faces; fa; fa = fa->next) {
1655 fa->planepts[0] -= origin;
1656 fa->planepts[1] -= origin;
1657 fa->planepts[2] -= origin;
1658 plane.FromPoints( fa->planepts[0], fa->planepts[1], fa->planepts[2], false );
1659 fa->planepts[0] += origin;
1660 fa->planepts[1] += origin;
1661 fa->planepts[2] += origin;
1663 plane = fa->originalPlane;
1666 WriteFileString(f, " ( ");
1667 for (i = 0; i < 4; i++) {
1668 if (plane[i] == (int)plane[i]) {
1669 WriteFileString(f, "%i ", (int)plane[i]);
1672 WriteFileString(f, "%f ", plane[i]);
1676 WriteFileString(f, ") ");
1679 for (i = 0; i < 3; i++) {
1680 WriteFileString(f, "( ");
1681 for (int j = 0; j < 3; j++) {
1682 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1683 WriteFileString(f, "%i ", static_cast<int>(fa->planepts[i][j]));
1686 WriteFileString(f, "%f ", fa->planepts[i][j]);
1690 WriteFileString(f, ") ");
1694 // save texture coordinates
1695 WriteFileString(f, "( ( ");
1696 for (i = 0; i < 3; i++) {
1697 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) {
1698 WriteFileString(f, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
1701 WriteFileString(f, "%f ", fa->brushprimit_texdef.coords[0][i]);
1705 WriteFileString(f, ") ( ");
1706 for (i = 0; i < 3; i++) {
1707 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) {
1708 WriteFileString(f, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
1711 WriteFileString(f, "%f ", fa->brushprimit_texdef.coords[1][i]);
1715 WriteFileString(f, ") ) ");
1717 char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "notexture";
1718 WriteFileString(f, "\"%s\" ", pName);
1719 WriteFileString(f, "%i %i %i\n", 0, 0, 0);
1722 WriteFileString(f, "}\n}\n");
1725 WriteFileString(f, "{\n");
1726 for (fa = b->brush_faces; fa; fa = fa->next) {
1727 for (i = 0; i < 3; i++) {
1728 WriteFileString(f, "( ");
1729 for (int j = 0; j < 3; j++) {
1730 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1731 WriteFileString(f, "%i ", static_cast<int>(fa->planepts[i][j]));
1734 WriteFileString(f, "%f ", fa->planepts[i][j]);
1738 WriteFileString(f, ") ");
1741 pname = fa->texdef.name;
1742 if (pname[0] == 0) {
1751 (int)fa->texdef.shift[0],
1752 (int)fa->texdef.shift[1],
1753 (int)fa->texdef.rotate
1756 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) {
1757 WriteFileString(f, "%i ", (int)fa->texdef.scale[0]);
1760 WriteFileString(f, "%f ", (float)fa->texdef.scale[0]);
1763 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) {
1764 WriteFileString(f, "%i", (int)fa->texdef.scale[1]);
1767 WriteFileString(f, "%f", (float)fa->texdef.scale[1]);
1770 WriteFileString(f, " %i %i %i",0, 0, 0);
1772 WriteFileString(f, "\n");
1775 WriteFileString(f, "}\n");
1781 QERApp_MapPrintf_MEMFILE
1783 callback for surface properties plugin must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
1784 carefully initialize !
1787 CMemFile *g_pMemFile;
1789 void WINAPI QERApp_MapPrintf_MEMFILE(char *text, ...) {
1793 va_start(argptr, text);
1794 vsprintf(buf, text, argptr);
1797 MemFile_fprintf(g_pMemFile, buf);
1804 save all brushes as Brush primitive format to a CMemFile*
1807 void Brush_Write(brush_t *b, CMemFile *pMemFile, const idVec3 &origin, bool newFormat) {
1813 Patch_Write(b->pPatch, pMemFile);
1817 if (g_qeglobals.m_bBrushPrimitMode) {
1818 // brush primitive format
1820 MemFile_fprintf(pMemFile, "{\nBrushDef2\n{\n");
1823 MemFile_fprintf(pMemFile, "{\nBrushDef\n{\n");
1828 int count = b->epairs.GetNumKeyVals();
1829 for (int j = 0; j < count; j++) {
1830 MemFile_fprintf(pMemFile, "\"%s\" \"%s\"\n", b->epairs.GetKeyVal(j)->GetKey().c_str(), b->epairs.GetKeyVal(j)->GetValue().c_str());
1833 for (fa = b->brush_faces; fa; fa = fa->next) {
1839 fa->planepts[0] -= origin;
1840 fa->planepts[1] -= origin;
1841 fa->planepts[2] -= origin;
1842 plane.FromPoints( fa->planepts[0], fa->planepts[1], fa->planepts[2], false );
1843 fa->planepts[0] += origin;
1844 fa->planepts[1] += origin;
1845 fa->planepts[2] += origin;
1847 plane = fa->originalPlane;
1850 MemFile_fprintf(pMemFile, " ( ");
1851 for (i = 0; i < 4; i++) {
1852 if (plane[i] == (int)plane[i]) {
1853 MemFile_fprintf(pMemFile, "%i ", (int)plane[i]);
1856 MemFile_fprintf(pMemFile, "%f ", plane[i]);
1860 MemFile_fprintf(pMemFile, ") ");
1863 for (i = 0; i < 3; i++) {
1864 MemFile_fprintf(pMemFile, "( ");
1865 for (int j = 0; j < 3; j++) {
1866 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1867 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
1870 MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
1874 MemFile_fprintf(pMemFile, ") ");
1878 // save texture coordinates
1879 MemFile_fprintf(pMemFile, "( ( ");
1880 for (i = 0; i < 3; i++) {
1881 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i])) {
1882 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
1885 MemFile_fprintf(pMemFile, "%f ", fa->brushprimit_texdef.coords[0][i]);
1889 MemFile_fprintf(pMemFile, ") ( ");
1890 for (i = 0; i < 3; i++) {
1891 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i])) {
1892 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
1895 MemFile_fprintf(pMemFile, "%f ", fa->brushprimit_texdef.coords[1][i]);
1899 MemFile_fprintf(pMemFile, ") ) ");
1901 // save texture attribs
1902 char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed";
1903 MemFile_fprintf(pMemFile, "\"%s\" ", pName);
1904 MemFile_fprintf(pMemFile, "%i %i %i\n", 0, 0, 0);
1907 MemFile_fprintf(pMemFile, "}\n}\n");
1910 // old brushes format also handle surface properties plugin
1911 MemFile_fprintf(pMemFile, "{\n");
1912 for (fa = b->brush_faces; fa; fa = fa->next) {
1913 for (i = 0; i < 3; i++) {
1914 MemFile_fprintf(pMemFile, "( ");
1915 for (int j = 0; j < 3; j++) {
1916 if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j])) {
1917 MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
1920 MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
1924 MemFile_fprintf(pMemFile, ") ");
1927 pname = fa->texdef.name;
1928 if (pname[0] == 0) {
1937 (int)fa->texdef.shift[0],
1938 (int)fa->texdef.shift[1],
1939 (int)fa->texdef.rotate
1942 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) {
1943 MemFile_fprintf(pMemFile, "%i ", (int)fa->texdef.scale[0]);
1946 MemFile_fprintf(pMemFile, "%f ", (float)fa->texdef.scale[0]);
1949 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) {
1950 MemFile_fprintf(pMemFile, "%i", (int)fa->texdef.scale[1]);
1953 MemFile_fprintf(pMemFile, "%f", (float)fa->texdef.scale[1]);
1956 MemFile_fprintf(pMemFile, " %i %i %i", 0, 0, 0);
1958 MemFile_fprintf(pMemFile, "\n");
1961 MemFile_fprintf(pMemFile, "}\n");
1969 Create non-textured blocks for entities The brush is NOT linked to any list
1972 brush_t *Brush_Create(idVec3 mins, idVec3 maxs, texdef_t *texdef) {
1979 // brush primitive mode : convert texdef to brushprimit_texdef ? most of the time
1982 for (i = 0; i < 3; i++) {
1983 if (maxs[i] < mins[i]) {
1984 Error("Brush_InitSolid: backwards");
1990 pts[0][0][0] = mins[0];
1991 pts[0][0][1] = mins[1];
1993 pts[1][0][0] = mins[0];
1994 pts[1][0][1] = maxs[1];
1996 pts[2][0][0] = maxs[0];
1997 pts[2][0][1] = maxs[1];
1999 pts[3][0][0] = maxs[0];
2000 pts[3][0][1] = mins[1];
2002 for (i = 0; i < 4; i++) {
2003 pts[i][0][2] = mins[2];
2004 pts[i][1][0] = pts[i][0][0];
2005 pts[i][1][1] = pts[i][0][1];
2006 pts[i][1][2] = maxs[2];
2009 for (i = 0; i < 4; i++) {
2011 f->texdef = *texdef;
2012 f->next = b->brush_faces;
2016 VectorCopy(pts[j][1], f->planepts[0]);
2017 VectorCopy(pts[i][1], f->planepts[1]);
2018 VectorCopy(pts[i][0], f->planepts[2]);
2022 f->texdef = *texdef;
2023 f->next = b->brush_faces;
2026 VectorCopy(pts[0][1], f->planepts[0]);
2027 VectorCopy(pts[1][1], f->planepts[1]);
2028 VectorCopy(pts[2][1], f->planepts[2]);
2031 f->texdef = *texdef;
2032 f->next = b->brush_faces;
2035 VectorCopy(pts[2][0], f->planepts[0]);
2036 VectorCopy(pts[1][0], f->planepts[1]);
2037 VectorCopy(pts[0][0], f->planepts[2]);
2047 void Brush_Scale(brush_t* b) {
2048 for ( face_t *f = b->brush_faces; f; f = f->next ) {
2049 for ( int i = 0; i < 3; i++ ) {
2050 VectorScale( f->planepts[i], g_qeglobals.d_gridsize, f->planepts[i] );
2059 Create non-textured pyramid for light entities The brush is NOT linked to any list
2062 brush_t *Brush_CreatePyramid(idVec3 mins, idVec3 maxs, texdef_t *texdef) {
2063 // ++timo handle new brush primitive ? return here ??
2064 return Brush_Create(mins, maxs, texdef);
2067 for (i = 0; i < 3; i++) {
2068 if (maxs[i] < mins[i]) {
2069 Error("Brush_InitSolid: backwards");
2073 brush_t *b = Brush_Alloc();
2077 float fMid = idMath::Rint(mins[2] + (idMath::Rint((maxs[2] - mins[2]) / 2)));
2079 corners[0][0] = mins[0];
2080 corners[0][1] = mins[1];
2081 corners[0][2] = fMid;
2083 corners[1][0] = mins[0];
2084 corners[1][1] = maxs[1];
2085 corners[1][2] = fMid;
2087 corners[2][0] = maxs[0];
2088 corners[2][1] = maxs[1];
2089 corners[2][2] = fMid;
2091 corners[3][0] = maxs[0];
2092 corners[3][1] = mins[1];
2093 corners[3][2] = fMid;
2097 top[0] = idMath::Rint(mins[0] + ((maxs[0] - mins[0]) / 2));
2098 top[1] = idMath::Rint(mins[1] + ((maxs[1] - mins[1]) / 2));
2099 top[2] = idMath::Rint(maxs[2]);
2101 VectorCopy(top, bottom);
2102 bottom[2] = mins[2];
2105 for (i = 0; i < 4; i++) {
2106 face_t *f = Face_Alloc();
2107 f->texdef = *texdef;
2108 f->next = b->brush_faces;
2111 int j = (i + 1) % 4;
2113 VectorCopy(top, f->planepts[0]);
2114 VectorCopy(corners[i], f->planepts[1]);
2115 VectorCopy(corners[j], f->planepts[2]);
2118 f->texdef = *texdef;
2119 f->next = b->brush_faces;
2122 VectorCopy(bottom, f->planepts[2]);
2123 VectorCopy(corners[i], f->planepts[1]);
2124 VectorCopy(corners[j], f->planepts[0]);
2134 Makes the current brush have the given number of 2d sides
2137 void Brush_MakeSided(int sides) {
2148 Sys_Status("Bad sides number", 0);
2152 if (sides >= MAX_POINTS_ON_WINDING - 4) {
2153 Sys_Status("too many sides.\n");
2157 if (!QE_SingleBrush()) {
2158 Sys_Status("Must have a single brush selected", 0);
2162 b = selected_brushes.next;
2163 VectorCopy(b->mins, mins);
2164 VectorCopy(b->maxs, maxs);
2165 texdef = &g_qeglobals.d_texturewin.texdef;
2169 if (g_pParentWnd->ActiveXY()) {
2170 switch (g_pParentWnd->ActiveXY()->GetViewType())
2187 // find center of brush
2189 for (i = 0; i < 3; i++) {
2190 mid[i] = (maxs[i] + mins[i]) * 0.5f;
2195 if ((maxs[i] - mins[i]) * 0.5f > width) {
2196 width = (maxs[i] - mins[i]) * 0.5f;
2204 f->texdef = *texdef;
2205 f->next = b->brush_faces;
2208 f->planepts[2][(axis + 1) % 3] = mins[(axis + 1) % 3];
2209 f->planepts[2][(axis + 2) % 3] = mins[(axis + 2) % 3];
2210 f->planepts[2][axis] = maxs[axis];
2211 f->planepts[1][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2212 f->planepts[1][(axis + 2) % 3] = mins[(axis + 2) % 3];
2213 f->planepts[1][axis] = maxs[axis];
2214 f->planepts[0][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2215 f->planepts[0][(axis + 2) % 3] = maxs[(axis + 2) % 3];
2216 f->planepts[0][axis] = maxs[axis];
2218 // create bottom face
2220 f->texdef = *texdef;
2221 f->next = b->brush_faces;
2224 f->planepts[0][(axis + 1) % 3] = mins[(axis + 1) % 3];
2225 f->planepts[0][(axis + 2) % 3] = mins[(axis + 2) % 3];
2226 f->planepts[0][axis] = mins[axis];
2227 f->planepts[1][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2228 f->planepts[1][(axis + 2) % 3] = mins[(axis + 2) % 3];
2229 f->planepts[1][axis] = mins[axis];
2230 f->planepts[2][(axis + 1) % 3] = maxs[(axis + 1) % 3];
2231 f->planepts[2][(axis + 2) % 3] = maxs[(axis + 2) % 3];
2232 f->planepts[2][axis] = mins[axis];
2234 for (i = 0; i < sides; i++) {
2236 f->texdef = *texdef;
2237 f->next = b->brush_faces;
2240 sv = sin(i * 3.14159265 * 2 / sides);
2241 cv = cos(i * 3.14159265 * 2 / sides);
2243 f->planepts[0][(axis + 1) % 3] = floor(mid[(axis + 1) % 3] + width * cv + 0.5f);
2244 f->planepts[0][(axis + 2) % 3] = floor(mid[(axis + 2) % 3] + width * sv + 0.5f);
2245 f->planepts[0][axis] = mins[axis];
2247 f->planepts[1][(axis + 1) % 3] = f->planepts[0][(axis + 1) % 3];
2248 f->planepts[1][(axis + 2) % 3] = f->planepts[0][(axis + 2) % 3];
2249 f->planepts[1][axis] = maxs[axis];
2251 f->planepts[2][(axis + 1) % 3] = floor(f->planepts[0][(axis + 1) % 3] - width * sv + 0.5f);
2252 f->planepts[2][(axis + 2) % 3] = floor(f->planepts[0][(axis + 2) % 3] + width * cv + 0.5f);
2253 f->planepts[2][axis] = maxs[axis];
2256 Brush_AddToList(b, &selected_brushes);
2258 Entity_LinkBrush(world_entity, b);
2262 Sys_UpdateWindows(W_ALL);
2269 Frees the brush with all of its faces and display list.
2270 Unlinks the brush from whichever chain it is in.
2271 Decrements the owner entity's brushcount.
2272 Removes owner entity if this was the last brush unless owner is the world.
2275 set bRemoveNode to false to avoid trying to delete the item in group view tree control
2278 void Brush_Free(brush_t *b, bool bRemoveNode) {
2281 // free the patch if it's there
2283 Patch_Delete(b->pPatch);
2287 for ( f = b->brush_faces; f; f = next ) {
2294 // unlink from active/selected list
2296 Brush_RemoveFromList(b);
2299 // unlink from entity list
2301 Entity_UnlinkBrush(b);
2311 returns the size in memory of the face
2314 int Face_MemorySize(face_t *f) {
2317 if ( f->face_winding ) {
2318 size += sizeof( idWinding ) + f->face_winding->GetNumPoints() * sizeof( (f->face_winding)[0] );
2320 size += sizeof( face_t );
2328 returns the size in memory of the brush
2331 int Brush_MemorySize( brush_t *b ) {
2335 size += Patch_MemorySize( b->pPatch );
2338 for ( f = b->brush_faces; f; f = f->next ) {
2339 size += Face_MemorySize(f);
2342 size += sizeof( brush_t ) + b->epairs.Size();
2350 does not add the brush to any lists
2353 brush_t *Brush_Clone(brush_t *b) {
2358 patchMesh_t *p = Patch_Duplicate(b->pPatch);
2359 Brush_RemoveFromList(p->pSymbiot);
2360 Entity_UnlinkBrush(p->pSymbiot);
2365 n->numberId = g_nBrushId++;
2366 n->owner = b->owner;
2367 n->lightColor = b->lightColor;
2368 n->lightEnd = b->lightEnd;
2369 n->lightOffset = b->lightOffset;
2370 n->lightRadius = b->lightRadius;
2371 n->lightRight = b->lightRight;
2372 n->lightStart = b->lightStart;
2373 n->lightTarget = b->lightTarget;
2374 n->lightCenter = b->lightCenter;
2375 n->lightTexture = b->lightTexture;
2376 n->lightUp = b->lightUp;
2377 n->modelHandle = b->modelHandle;
2378 n->pointLight = b->pointLight;
2379 for (f = b->brush_faces; f; f = f->next) {
2381 nf->next = n->brush_faces;
2382 n->brush_faces = nf;
2394 Makes an exact copy of the brush.
2395 Does NOT add the new brush to any lists.
2398 brush_t *Brush_FullClone(brush_t *b) {
2400 face_t *f, *nf, *f2, *nf2;
2404 patchMesh_t *p = Patch_Duplicate(b->pPatch);
2405 Brush_RemoveFromList(p->pSymbiot);
2406 Entity_UnlinkBrush(p->pSymbiot);
2408 n->owner = b->owner;
2413 n->numberId = g_nBrushId++;
2414 n->owner = b->owner;
2415 n->lightColor = b->lightColor;
2416 n->lightEnd = b->lightEnd;
2417 n->lightOffset = b->lightOffset;
2418 n->lightRadius = b->lightRadius;
2419 n->lightRight = b->lightRight;
2420 n->lightStart = b->lightStart;
2421 n->lightTarget = b->lightTarget;
2422 n->lightCenter = b->lightCenter;
2423 n->lightTexture = b->lightTexture;
2424 n->lightUp = b->lightUp;
2425 n->modelHandle = b->modelHandle;
2426 n->pointLight = b->pointLight;
2427 VectorCopy(b->mins, n->mins);
2428 VectorCopy(b->maxs, n->maxs);
2429 for (f = b->brush_faces; f; f = f->next) {
2434 nf = Face_FullClone(f);
2435 nf->next = n->brush_faces;
2436 n->brush_faces = nf;
2438 // copy all faces that have the original set to this face
2439 for (f2 = b->brush_faces; f2; f2 = f2->next) {
2440 if (f2->original == f) {
2441 nf2 = Face_FullClone(f2);
2442 nf2->next = n->brush_faces;
2443 n->brush_faces = nf2;
2451 for (nf = n->brush_faces; nf; nf = nf->next) {
2452 Face_SetColor( n, nf, 1.0f );
2453 if (nf->face_winding) {
2454 if (g_qeglobals.m_bBrushPrimitMode) {
2455 EmitBrushPrimitTextureCoordinates(nf, nf->face_winding);
2458 for (j = 0; j < nf->face_winding->GetNumPoints(); j++) {
2459 EmitTextureCoordinates( (*nf->face_winding)[j], nf->d_texture, nf );
2469 extern bool GetMatrixForKey(entity_t *ent, const char *key, idMat3 &mat);
2470 extern bool Patch_Intersect(patchMesh_t *pm, idVec3 origin, idVec3 direction , float &scale);
2471 extern bool RayIntersectsTri
2473 const idVec3 &origin,
2474 const idVec3 &direction,
2475 const idVec3 &vert0,
2476 const idVec3 &vert1,
2477 const idVec3 &vert2,
2487 void RotateVector(idVec3 &v, idVec3 origin, float a, float c, float s) {
2491 float x2 = (((x - origin[0]) * c) - ((y - origin[1]) * s)) + origin[0];
2492 float y2 = (((x - origin[0]) * s) + ((y - origin[1]) * c)) + origin[1];
2501 Brush_ModelIntersect
2505 bool Brush_ModelIntersect(brush_t *b, idVec3 origin, idVec3 dir,float &scale) {
2506 idRenderModel *model = b->modelHandle;
2510 model = b->owner->eclass->entityModel;
2514 if ( model->IsDynamicModel() != DM_STATIC ) {
2515 if ( dynamic_cast<idRenderModelMD5 *>( model ) ) {
2516 // take care of animated models
2517 md5 = b->owner->eclass->entityModel;
2519 const char *classname = ValueForKey( b->owner, "classname" );
2520 if (stricmp(classname, "func_static") == 0) {
2521 classname = ValueForKey(b->owner, "animclass");
2523 const char *anim = ValueForKey( b->owner, "anim" );
2524 int frame = IntForKey( b->owner, "frame" ) + 1;
2528 if ( !anim || !anim[ 0 ] ) {
2531 model = gameEdit->ANIM_CreateMeshForAnim( md5, classname, anim, frame, false );
2533 model = renderModelManager->DefaultModel();
2538 bool matrix = false;
2541 if (GetMatrixForKey(b->owner, "rotation", mat)) {
2544 a = FloatForKey(b->owner, "angle");
2546 s = sin( DEG2RAD( a ) );
2547 c = cos( DEG2RAD( a ) );
2554 for (int i = 0; i < model->NumSurfaces() ; i++) {
2555 const modelSurface_t *surf = model->Surface( i );
2556 srfTriangles_t *tri = surf->geometry;
2557 for (int j = 0; j < tri->numIndexes; j += 3) {
2559 v1 = tri->verts[tri->indexes[j]].xyz;
2560 v2 = tri->verts[tri->indexes[j + 1]].xyz;
2561 v3 = tri->verts[tri->indexes[j + 2]].xyz;
2564 v1 *= b->owner->rotation;
2565 v1 += b->owner->origin;
2566 v2 *= b->owner->rotation;
2567 v2 += b->owner->origin;
2568 v3 *= b->owner->rotation;
2569 v3 += b->owner->origin;
2571 v1 += b->owner->origin;
2572 v2 += b->owner->origin;
2573 v3 += b->owner->origin;
2574 RotateVector(v1, b->owner->origin, a, c, s);
2575 RotateVector(v2, b->owner->origin, a, c, s);
2576 RotateVector(v3, b->owner->origin, a, c, s);
2579 if (RayIntersectsTri(origin, dir, v1, v2, v3,scale)) {
2589 face_t *Brush_Ray(idVec3 origin, idVec3 dir, brush_t *b, float *dist, bool testPrimitive) {
2590 face_t *f, *firstface = NULL;
2594 float scale = HUGE_DISTANCE * 2;
2595 VectorCopy(origin, p1);
2596 for (i = 0; i < 3; i++) {
2597 p2[i] = p1[i] + dir[i] * HUGE_DISTANCE * 2;
2600 for (f = b->brush_faces; f; f = f->next) {
2601 d1 = DotProduct(p1, f->plane) + f->plane[3];
2602 d2 = DotProduct(p2, f->plane) + f->plane[3];
2603 if (d1 >= 0 && d2 >= 0) {
2605 return NULL; // ray is on front side of face
2608 if (d1 <= 0 && d2 <= 0) {
2612 // clip the ray to the plane
2613 frac = d1 / (d1 - d2);
2616 for (i = 0; i < 3; i++) {
2617 p1[i] = p1[i] + frac * (p2[i] - p1[i]);
2621 for (i = 0; i < 3; i++) {
2622 p2[i] = p1[i] + frac * (p2[i] - p1[i]);
2627 // find distance p1 is along dir
2628 VectorSubtract(p1, origin, p1);
2629 d1 = DotProduct(p1, dir);
2631 if (testPrimitive && !g_PrefsDlg.m_selectByBoundingBrush) {
2633 if (!Patch_Intersect(b->pPatch, origin, dir, scale)) {
2638 else if ( b->modelHandle != NULL && dynamic_cast<idRenderModelPrt*>( b->modelHandle ) == NULL && dynamic_cast< idRenderModelLiquid*> ( b->modelHandle ) == NULL ) {
2639 if (!Brush_ModelIntersect(b, origin, dir, scale)) {
2655 face_t *Brush_Point(idVec3 origin, brush_t *b) {
2659 for (f = b->brush_faces; f; f = f->next) {
2660 d1 = DotProduct(origin, f->plane) + f->plane[3];
2662 return NULL; // point is on front side of face
2666 return b->brush_faces;
2674 void Brush_AddToList(brush_t *b, brush_t *list) {
2675 if (b->next || b->prev) {
2676 Error("Brush_AddToList: allready linked");
2679 if (list == &selected_brushes || list == &active_brushes) {
2680 if (b->pPatch && list == &selected_brushes) {
2681 Patch_Select(b->pPatch);
2686 b->next = list->next;
2687 list->next->prev = b;
2695 Brush_RemoveFromList
2698 void Brush_RemoveFromList(brush_t *b) {
2699 if (!b->next || !b->prev) {
2700 Error("Brush_RemoveFromList: not linked");
2704 Patch_Deselect(b->pPatch);
2706 // Patch_Deselect(b->nPatchID);
2710 b->next->prev = b->prev;
2711 b->prev->next = b->next;
2712 b->next = b->prev = NULL;
2719 Doesn't set the curve flags.
2720 NOTE: never trust f->d_texture here, f->texdef and f->d_texture are out of sync when
2721 called by Brush_SetTexture use Texture_ForName() to find the right shader
2722 FIXME: send the right shader ( qtexture_t * ) in the parameters ?
2723 TTimo: surface plugin, added an IPluginTexdef* parameter if not NULL,
2724 get ->Copy() of it into the face ( and remember to hook ) if NULL, ask for a default
2727 void SetFaceTexdef( brush_t *b, face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale ) {
2729 if (g_qeglobals.m_bBrushPrimitMode) {
2730 f->texdef = *texdef;
2731 ConvertTexMatWithQTexture(brushprimit_texdef, NULL, &f->brushprimit_texdef, Texture_ForName(f->texdef.name));
2733 else if (bFitScale) {
2734 f->texdef = *texdef;
2736 // fit the scaling of the texture on the actual plane
2737 idVec3 p1, p2, p3; // absolute coordinates
2739 // compute absolute coordinates
2740 ComputeAbsolute(f, p1, p2, p3);
2742 // compute the scale
2744 VectorSubtract(p2, p1, vx);
2746 VectorSubtract(p3, p1, vy);
2750 VectorScale(vx, texdef->scale[0], vx);
2751 VectorScale(vy, texdef->scale[1], vy);
2752 VectorAdd(p1, vx, p2);
2753 VectorAdd(p1, vy, p3);
2755 // compute back shift scale rot
2756 AbsoluteToLocal(f->plane, f, p1, p2, p3);
2759 f->texdef = *texdef;
2769 void Brush_SetTexture(brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale) {
2771 Patch_SetTexture(b->pPatch, texdef);
2774 for (face_t * f = b->brush_faces; f; f = f->next) {
2775 SetFaceTexdef(b, f, texdef, brushprimit_texdef, bFitScale);
2783 ====================
2784 Brush_SetTextureName
2785 ====================
2787 void Brush_SetTextureName(brush_t *b, const char *name) {
2789 Patch_SetTextureName(b->pPatch, name);
2792 for (face_t * f = b->brush_faces; f; f = f->next) {
2793 f->texdef.SetName(name);
2804 bool ClipLineToFace(idVec3 &p1, idVec3 &p2, face_t *f) {
2809 d1 = DotProduct(p1, f->plane) + f->plane[3];
2810 d2 = DotProduct(p2, f->plane) + f->plane[3];
2812 if (d1 >= 0 && d2 >= 0) {
2813 return false; // totally outside
2816 if (d1 <= 0 && d2 <= 0) {
2817 return true; // totally inside
2820 fr = d1 / (d1 - d2);
2823 v = p1.ToFloatPtr();
2826 v = p2.ToFloatPtr();
2829 for (i = 0; i < 3; i++) {
2830 v[i] = p1[i] + fr * (p2[i] - p1[i]);
2841 int AddPlanept(idVec3 *f) {
2844 for (i = 0; i < g_qeglobals.d_num_move_points; i++) {
2845 if (g_qeglobals.d_move_points[i] == f) {
2850 if (g_qeglobals.d_num_move_points < MAX_MOVE_POINTS) {
2851 g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
2853 Sys_Status("Trying to move too many points\n");
2865 void AddMovePlane( idPlane *p ) {
2867 for (int i = 0; i < g_qeglobals.d_num_move_planes; i++) {
2868 if (g_qeglobals.d_move_planes[i] == p) {
2873 if (g_qeglobals.d_num_move_planes < MAX_MOVE_PLANES) {
2874 g_qeglobals.d_move_planes[g_qeglobals.d_num_move_planes++] = p;
2876 Sys_Status("Trying to move too many planes\n");
2883 Brush_SelectFaceForDragging
2885 Adds the faces planepts to move_points, and rotates and adds the planepts of adjacent face if shear is set
2888 void Brush_SelectFaceForDragging(brush_t *b, face_t *f, bool shear) {
2896 if (b->owner->eclass->fixedsize || EntityHasModel(b->owner)) {
2901 for (i = 0; i < 3; i++) {
2902 c += AddPlanept(&f->planepts[i]);
2905 //AddMovePlane(&f->plane);
2908 return; // allready completely added
2911 // select all points on this plane in all brushes the selection
2912 for (b2 = selected_brushes.next; b2 != &selected_brushes; b2 = b2->next) {
2917 for (f2 = b2->brush_faces; f2; f2 = f2->next) {
2918 for (i = 0; i < 3; i++) {
2919 if (idMath::Fabs(DotProduct(f2->planepts[i], f->plane) + f->plane[3]) > ON_EPSILON) {
2924 if (i == 3) { // move this face as well
2925 Brush_SelectFaceForDragging(b2, f2, shear);
2932 // if shearing, take all the planes adjacent to selected faces and rotate their
2933 // points so the edge clipped by a selcted face has two of the points
2939 for (f2 = b->brush_faces; f2; f2 = f2->next) {
2944 w = Brush_MakeFaceWinding(b, f2, false);
2949 // any points on f will become new control points
2950 for (i = 0; i < w->GetNumPoints(); i++) {
2951 d = DotProduct( (*w)[i], f->plane ) + f->plane[3];
2952 if (d > -ON_EPSILON && d < ON_EPSILON) {
2957 // if none of the points were on the plane, leave it alone
2958 if (i != w->GetNumPoints()) {
2959 if (i == 0) { // see if the first clockwise point was the
2961 /// last point on the winding
2962 d = DotProduct( (*w)[w->GetNumPoints() - 1], f->plane ) + f->plane[3];
2963 if (d > -ON_EPSILON && d < ON_EPSILON) {
2964 i = w->GetNumPoints() - 1;
2968 AddPlanept(&f2->planepts[0]);
2969 //AddMovePlane(&f2->plane);
2971 VectorCopy((*w)[i], f2->planepts[0]);
2972 if (++i == w->GetNumPoints()) {
2976 // see if the next point is also on the plane
2977 d = DotProduct( (*w)[i], f->plane ) + f->plane[3];
2978 if (d > -ON_EPSILON && d < ON_EPSILON) {
2979 AddPlanept(&f2->planepts[1]);
2982 VectorCopy( (*w)[i], f2->planepts[1] );
2983 if (++i == w->GetNumPoints()) {
2987 // the third point is never on the plane
2988 VectorCopy( (*w)[i], f2->planepts[2] );
2999 The mouse click did not hit the brush, so grab one or more side planes for dragging.
3002 void Brush_SideSelect(brush_t *b, idVec3 origin, idVec3 dir, bool shear) {
3010 // if (b->pPatch) return; Patch_SideSelect(b->nPatchID, origin, dir);
3011 for (f = b->brush_faces; f; f = f->next) {
3012 VectorCopy(origin, p1);
3013 VectorMA(origin, MAX_WORLD_SIZE, dir, p2);
3015 for (f2 = b->brush_faces; f2; f2 = f2->next) {
3020 ClipLineToFace(p1, p2, f2);
3027 if ( p1.Compare( origin ) ) {
3031 if (ClipLineToFace(p1, p2, f)) {
3035 Brush_SelectFaceForDragging(b, f, shear);
3039 extern void UpdateSelectablePoint(brush_t *b, idVec3 v, int type);
3040 extern void AddSelectablePoint(brush_t *b, idVec3 v, int type, bool priority);
3041 extern void ClearSelectablePoints(brush_t *b);
3045 Brush_TransformedPoint
3048 extern void VectorSnapGrid(idVec3 &v);
3050 idMat3 Brush_RotationMatrix(brush_t *b) {
3053 if (!GetMatrixForKey(b->owner, "light_rotation", mat)) {
3054 GetMatrixForKey(b->owner, "rotation", mat);
3059 idVec3 Brush_TransformedPoint(brush_t *b, const idVec3 &in) {
3061 out -= b->owner->origin;
3062 out *= Brush_RotationMatrix(b);
3063 out += b->owner->origin;
3068 Brush_UpdateLightPoints
3071 void Brush_UpdateLightPoints(brush_t *b, const idVec3 &offset) {
3073 if (!(b->owner->eclass->nShowFlags & ECLASS_LIGHT)) {
3074 if (b->modelHandle) {
3075 g_bScreenUpdates = false;
3076 g_pParentWnd->GetCamera()->BuildEntityRenderState(b->owner, true);
3077 g_bScreenUpdates = true;
3082 if (b->entityModel) {
3087 idVec3 *origin = (b->trackLightOrigin) ? &b->owner->lightOrigin : &b->owner->origin;
3089 if (!GetVectorForKey(b->owner, "_color", b->lightColor)) {
3090 b->lightColor[0] = b->lightColor[1] = b->lightColor[2] = 1;
3093 const char *str = ValueForKey(b->owner, "texture");
3094 b->lightTexture = -1;
3095 if (str && strlen(str) > 0) {
3096 const idMaterial *q = Texture_LoadLight(str);
3098 b->lightTexture = q->GetEditorImage()->texnum;
3102 str = ValueForKey(b->owner, "light_right");
3104 idVec3 vRight, vUp, vTarget, vTemp;
3106 if (GetVectorForKey(b->owner, "light_start", b->lightStart)) {
3108 if (!GetVectorForKey(b->owner, "light_end", b->lightEnd)) {
3109 GetVectorForKey(b->owner, "light_target", b->lightEnd);
3113 VectorAdd(b->lightEnd, *origin, b->lightEnd);
3114 VectorAdd(b->lightStart, *origin, b->lightStart);
3115 VectorAdd(b->lightStart, offset, b->lightStart);
3118 b->startEnd = false;
3121 GetVectorForKey(b->owner, "light_right", vRight);
3122 GetVectorForKey(b->owner, "light_up", vUp);
3123 GetVectorForKey(b->owner, "light_target", vTarget);
3124 if (offset.x || offset.y || offset.z) {
3126 VectorAdd(vTarget, offset, vTarget);
3127 SetKeyVec3(b->owner, "light_target", vTarget);
3130 VectorAdd(vTarget, *origin, b->lightTarget);
3131 VectorAdd(b->lightTarget, vRight, b->lightRight);
3132 VectorAdd(b->lightTarget, vUp, b->lightUp);
3134 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightUp), LIGHT_UP);
3135 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightRight), LIGHT_RIGHT);
3136 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightTarget), LIGHT_TARGET);
3137 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightStart), LIGHT_START);
3138 UpdateSelectablePoint(b, Brush_TransformedPoint(b, b->lightEnd), LIGHT_END);
3139 b->pointLight = false;
3142 b->pointLight = true;
3144 if (GetVectorForKey(b->owner, "light_center", vCenter)) {
3146 if (offset.x || offset.y || offset.z) {
3148 VectorAdd(vCenter, offset, vCenter);
3149 SetKeyVec3(b->owner, "light_center", vCenter);
3152 VectorAdd(vCenter, *origin, b->lightCenter);
3153 UpdateSelectablePoint(b, b->lightCenter, LIGHT_CENTER);
3156 if (!GetVectorForKey(b->owner, "light_radius", b->lightRadius)) {
3157 float f = FloatForKey(b->owner, "light");
3162 b->lightRadius[0] = b->lightRadius[1] = b->lightRadius[2] = f;
3168 g_bScreenUpdates = false;
3169 g_pParentWnd->GetCamera()->BuildEntityRenderState(b->owner, true);
3170 g_bScreenUpdates = true;
3179 void Brush_BuildWindings(brush_t *b, bool bSnap, bool keepOnPlaneWinding, bool updateLights, bool makeFacePlanes) {
3184 // clear the mins/maxs bounds
3185 b->mins[0] = b->mins[1] = b->mins[2] = 999999;
3186 b->maxs[0] = b->maxs[1] = b->maxs[2] = -999999;
3188 if (makeFacePlanes) {
3189 Brush_MakeFacePlanes(b);
3192 face = b->brush_faces;
3194 float fCurveColor = 1.0f;
3196 for (; face; face = face->next) {
3198 delete face->face_winding;
3199 w = face->face_winding = Brush_MakeFaceWinding(b, face, keepOnPlaneWinding);
3200 face->d_texture = Texture_ForName(face->texdef.name);
3206 for (i = 0; i < w->GetNumPoints(); i++) {
3207 // add to bounding box
3208 for (j = 0; j < 3; j++) {
3210 if (v > b->maxs[j]) {
3214 if (v < b->mins[j]) {
3220 // setup s and t vectors, and set color if (!g_PrefsDlg.m_bGLLighting) {
3221 if (makeFacePlanes) {
3222 Face_SetColor(b, face, fCurveColor);
3225 fCurveColor -= 0.1f;
3226 if ( fCurveColor <= 0.0f ) {
3230 // computing ST coordinates for the windings
3231 if (g_qeglobals.m_bBrushPrimitMode) {
3232 if (g_qeglobals.bNeedConvert) {
3234 // we have parsed old brushes format and need conversion convert old brush texture
3235 // representation to new format
3237 FaceToBrushPrimitFace(face);
3239 // use old texture coordinates code to check against
3240 for (i = 0; i < w->GetNumPoints(); i++) {
3241 EmitTextureCoordinates((*w)[i], face->d_texture, face);
3247 // use new texture representation to compute texture coordinates in debug mode we
3248 // will check against old code and warn if there are differences
3250 EmitBrushPrimitTextureCoordinates(face, w);
3253 for (i = 0; i < w->GetNumPoints(); i++) {
3254 EmitTextureCoordinates((*w)[i], face->d_texture, face);
3264 Brush_UpdateLightPoints(b, offset);
3270 Brush_RemoveEmptyFaces
3272 Frees any overconstraining faces
3275 void Brush_RemoveEmptyFaces(brush_t *b) {
3279 b->brush_faces = NULL;
3281 for (; f; f = next) {
3283 if (!f->face_winding) {
3287 f->next = b->brush_faces;
3298 void Brush_SnapToGrid(brush_t *pb) {
3300 for (face_t * f = pb->brush_faces; f; f = f->next) {
3301 idWinding *w = f->face_winding;
3304 continue; // freed face
3307 for (i = 0; i < w->GetNumPoints(); i++) {
3308 SnapVectorToGrid( (*w)[i].ToVec3() );
3311 for (i = 0; i < 3; i++) {
3312 f->planepts[i].x = (*w)[i].x;
3313 f->planepts[i].y = (*w)[i].y;
3314 f->planepts[i].z = (*w)[i].z;
3319 if (GetVectorForKey(pb->owner, "origin", v)) {
3320 SnapVectorToGrid(pb->owner->origin);
3321 sprintf(str, "%i %i %i", (int)pb->owner->origin.x, (int)pb->owner->origin.y, (int)pb->owner->origin.z);
3322 SetKeyValue(pb->owner, "origin", str);
3325 if (pb->owner->eclass->nShowFlags & ECLASS_LIGHT) {
3326 if (GetVectorForKey(pb->owner, "light_right", v)) {
3328 SnapVectorToGrid(v);
3330 SetKeyVec3(pb->owner, "light_right", v);
3331 GetVectorForKey(pb->owner, "light_up", v);
3332 SnapVectorToGrid(v);
3334 SetKeyVec3(pb->owner, "light_up", v);
3335 GetVectorForKey(pb->owner, "light_target", v);
3336 SnapVectorToGrid(v);
3337 pb->lightTarget = v;
3338 SetKeyVec3(pb->owner, "light_target", v);
3339 if (GetVectorForKey(pb->owner, "light_start", v)) {
3340 SnapVectorToGrid(v);
3342 SetKeyVec3(pb->owner, "light_start", v);
3343 GetVectorForKey(pb->owner, "light_end", v);
3344 SnapVectorToGrid(v);
3346 SetKeyVec3(pb->owner, "light_end", v);
3350 if (GetVectorForKey(pb->owner, "light_center", v)) {
3351 SnapVectorToGrid(v);
3352 SetKeyVec3(pb->owner, "light_center", v);
3357 if ( pb->owner->curve ) {
3358 int c = pb->owner->curve->GetNumValues();
3359 for ( i = 0; i < c; i++ ) {
3360 v = pb->owner->curve->GetValue( i );
3361 SnapVectorToGrid( v );
3362 pb->owner->curve->SetValue( i, v );
3374 void Brush_Rotate(brush_t *b, idMat3 matrix, idVec3 origin, bool bBuild) {
3375 for (face_t * f = b->brush_faces; f; f = f->next) {
3376 for (int i = 0; i < 3; i++) {
3377 f->planepts[i] -= origin;
3378 f->planepts[i] *= matrix;
3379 f->planepts[i] += origin;
3384 Brush_Build(b, false, false);
3388 extern void VectorRotate3Origin( const idVec3 &vIn, const idVec3 &vRotation, const idVec3 &vOrigin, idVec3 &out );
3395 void Brush_Rotate(brush_t *b, idVec3 vAngle, idVec3 vOrigin, bool bBuild) {
3396 for (face_t * f = b->brush_faces; f; f = f->next) {
3397 for (int i = 0; i < 3; i++) {
3398 VectorRotate3Origin(f->planepts[i], vAngle, vOrigin, f->planepts[i]);
3403 Brush_Build(b, false, false);
3412 void Brush_Center(brush_t *b, idVec3 vNewCenter) {
3415 // get center of the brush
3416 for (int j = 0; j < 3; j++) {
3417 vMid[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5f);
3420 // calc distance between centers
3421 VectorSubtract(vNewCenter, vMid, vMid);
3422 Brush_Move(b, vMid, true);
3429 the brush must be a true axial box
3432 void Brush_Resize( brush_t *b, idVec3 vMin, idVec3 vMax ) {
3436 assert( vMin[0] < vMax[0] && vMin[1] < vMax[1] && vMin[2] < vMax[2] );
3438 Brush_MakeFacePlanes( b );
3440 for( f = b->brush_faces; f; f = f->next ) {
3441 for ( i = 0; i < 3; i++ ) {
3442 if ( f->plane.Normal()[i] >= 0.999f ) {
3443 for ( j = 0; j < 3; j++ ) {
3444 f->planepts[j][i] = vMax[i];
3448 if ( f->plane.Normal()[i] <= -0.999f ) {
3449 for ( j = 0; j < 3; j++ ) {
3450 f->planepts[j][i] = vMin[i];
3458 Brush_Build( b, true );
3466 eclass_t *HasModel(brush_t *b) {
3468 vMin[0] = vMin[1] = vMin[2] = 999999;
3469 vMax[0] = vMax[1] = vMax[2] = -999999;
3471 if (b->owner->md3Class != NULL) {
3472 return b->owner->md3Class;
3475 if (b->owner->eclass->modelHandle > 0) {
3476 return b->owner->eclass;
3481 // FIXME: entity needs to track whether a cache hit failed and not ask again
3482 if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) {
3483 const char *pModel = ValueForKey(b->owner, "model");
3484 if (pModel != NULL && strlen(pModel) > 0) {
3485 e = GetCachedModel(b->owner, pModel, vMin, vMax);
3488 // we need to scale the brush to the proper size based on the model load recreate
3489 // brush just like in load/save
3491 VectorAdd(vMin, b->owner->origin, vMin);
3492 VectorAdd(vMax, b->owner->origin, vMax);
3493 Brush_Resize(b, vMin, vMax);
3494 b->bModelFailed = false;
3497 b->bModelFailed = true;
3507 Entity_GetRotationMatrixAngles
3510 bool Entity_GetRotationMatrixAngles( entity_t *e, idMat3 &mat, idAngles &angles ) {
3513 /* the angle keyword is a yaw value, except for two special markers */
3514 if ( GetMatrixForKey( e, "rotation", mat ) ) {
3515 angles = mat.ToAngles();
3518 else if ( e->epairs.GetInt( "angle", "0", angle ) ) {
3519 if ( angle == -1 ) { // up
3520 angles.Set( 270, 0, 0 );
3522 else if ( angle == -2 ) { // down
3523 angles.Set( 90, 0, 0 );
3526 angles.Set( 0, angle, 0 );
3528 mat = angles.ToMat3();
3543 static void FacingVectors(entity_t *e, idVec3 &forward, idVec3 &right, idVec3 &up) {
3547 Entity_GetRotationMatrixAngles(e, mat, angles);
3548 angles.ToVectors( &forward, &right, &up);
3553 Brush_DrawFacingAngle
3556 void Brush_DrawFacingAngle( brush_t *b, entity_t *e, bool particle ) {
3557 idVec3 forward, right, up;
3558 idVec3 endpoint, tip1, tip2;
3562 VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
3563 VectorScale(start, 0.5f, start);
3564 dist = (b->maxs[0] - start[0]) * 2.5f;
3566 FacingVectors(e, forward, right, up);
3567 VectorMA(start, dist, ( particle ) ? up : forward, endpoint);
3569 dist = (b->maxs[0] - start[0]) * 0.5f;
3570 VectorMA(endpoint, -dist, ( particle ) ? up : forward, tip1);
3571 VectorMA(tip1, -dist, ( particle ) ? forward : up, tip1);
3572 VectorMA(tip1, 2 * dist, ( particle ) ? forward : up, tip2);
3573 globalImages->BindNull();
3574 qglColor4f(1, 1, 1, 1);
3577 qglVertex3fv(start.ToFloatPtr());
3578 qglVertex3fv(endpoint.ToFloatPtr());
3579 qglVertex3fv(endpoint.ToFloatPtr());
3580 qglVertex3fv(tip1.ToFloatPtr());
3581 qglVertex3fv(endpoint.ToFloatPtr());
3582 qglVertex3fv(tip2.ToFloatPtr());
3592 void DrawProjectedLight(brush_t *b, bool bSelected, bool texture) {
3594 idVec3 v1, v2, cross, vieworg, edge[8][2], v[4];
3595 idVec3 target, start;
3597 if (!bSelected && !g_bShowLightVolumes) {
3601 // use the renderer to get the volume outline
3602 idPlane lightProject[4];
3604 srfTriangles_t *tri;
3606 // use the game's epair parsing code so
3607 // we can use the same renderLight generation
3608 entity_t *ent = b->owner;
3610 renderLight_t parms;
3612 spawnArgs = ent->epairs;
3613 gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &parms );
3614 R_RenderLightFrustum( parms, planes );
3616 tri = R_PolytopeSurface(6, planes, NULL);
3618 qglColor3f(1, 0, 1);
3619 for (i = 0; i < tri->numIndexes; i += 3) {
3620 qglBegin(GL_LINE_LOOP);
3621 glVertex3fv(tri->verts[tri->indexes[i]].xyz.ToFloatPtr());
3622 glVertex3fv(tri->verts[tri->indexes[i + 1]].xyz.ToFloatPtr());
3623 glVertex3fv(tri->verts[tri->indexes[i + 2]].xyz.ToFloatPtr());
3627 R_FreeStaticTriSurf(tri);
3629 // draw different selection points for point lights or projected
3630 // lights (FIXME: rotate these based on parms!)
3636 bool transform = GetMatrixForKey(b->owner, "light_rotation", mat);
3638 transform = GetMatrixForKey(b->owner, "rotation", mat);
3641 idVec3 *origin = (b->trackLightOrigin) ? &b->owner->lightOrigin : &b->owner->origin;
3642 if (b->pointLight) {
3643 if ( b->lightCenter[0] || b->lightCenter[1] || b->lightCenter[2] ) {
3645 qglColor3f( 1.0f, 0.4f, 0.8f );
3646 qglBegin(GL_POINTS);
3647 tv = b->lightCenter;
3653 qglVertex3fv(tv.ToFloatPtr());
3662 qglColor3f( 1.0f, 0.4f, 0.8f );
3663 qglBegin(GL_POINTS);
3670 qglVertex3fv(tv.ToFloatPtr());
3671 tv = b->lightTarget;
3677 qglVertex3fv(tv.ToFloatPtr());
3684 qglVertex3fv(tv.ToFloatPtr());
3688 qglColor3f( 0.4f, 1.0f, 0.8f );
3689 qglBegin(GL_POINTS);
3690 qglVertex3fv(b->lightStart.ToFloatPtr());
3691 qglVertex3fv(b->lightEnd.ToFloatPtr());
3703 void GLCircle(float x, float y, float z, float r)
3707 float ig = 3 - 2 * r;
3709 float idgd = 4 * r - 10;
3711 qglBegin(GL_POINTS);
3723 qglVertex3f(x + ix, y + iy, z);
3724 qglVertex3f(x - ix, y + iy, z);
3725 qglVertex3f(x + ix, y - iy, z);
3726 qglVertex3f(x - ix, y - iy, z);
3727 qglVertex3f(x + iy, y + ix, z);
3728 qglVertex3f(x - iy, y + ix, z);
3729 qglVertex3f(x + iy, y - ix, z);
3730 qglVertex3f(x - iy, y - ix, z);
3740 void DrawSpeaker(brush_t *b, bool bSelected, bool twoD) {
3742 if (!(g_qeglobals.d_savedinfo.showSoundAlways || (g_qeglobals.d_savedinfo.showSoundWhenSelected && bSelected))) {
3746 // convert to units ( inches )
3747 float min = FloatForKey(b->owner, "s_mindistance");
3748 float max = FloatForKey(b->owner, "s_maxdistance");
3750 const char *s = b->owner->epairs.GetString("s_shader");
3752 const idSoundShader *shader = declManager->FindSound( s, false );
3755 min = shader->GetMinDistance();
3758 max = shader->GetMaxDistance();
3763 if (min == 0 && max == 0) {
3768 // convert from meters to doom units
3769 min *= METERS_TO_DOOM;
3770 max *= METERS_TO_DOOM;
3774 qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, .5);
3776 qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, .5);
3778 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3779 GLCircle(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z, min);
3781 qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 1);
3783 qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 1);
3785 GLCircle(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z, max);
3788 qglTranslatef(b->owner->origin.x, b->owner->origin.y, b->owner->origin.z );
3789 qglColor3f( 0.4f, 0.4f, 0.4f );
3790 qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
3791 GLUquadricObj* qobj = gluNewQuadric();
3792 gluSphere(qobj, min, 8, 8);
3793 qglColor3f( 0.8f, 0.8f, 0.8f );
3794 gluSphere(qobj, max, 8, 8);
3795 qglEnable(GL_BLEND);
3796 qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
3797 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
3798 globalImages->BindNull();
3800 qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 0.35f );
3802 qglColor4f( b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 0.35f );
3804 gluSphere(qobj, min, 8, 8);
3806 qglColor4f( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, 0.1f );
3808 qglColor4f( b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, 0.1f );
3810 gluSphere(qobj, max, 8, 8);
3811 gluDeleteQuadric(qobj);
3823 void DrawLight(brush_t *b, bool bSelected) {
3825 bool bTriPaint = false;
3827 vTriColor[0] = vTriColor[2] = 1.0f;
3828 vTriColor[1] = 1.0f;
3831 CString strColor = ValueForKey(b->owner, "_color");
3832 if (strColor.GetLength() > 0) {
3834 int n = sscanf(strColor, "%f %f %f", &fR, &fG, &fB);
3842 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3845 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
3847 vCorners[0][0] = b->mins[0];
3848 vCorners[0][1] = b->mins[1];
3849 vCorners[0][2] = fMid;
3851 vCorners[1][0] = b->mins[0];
3852 vCorners[1][1] = b->maxs[1];
3853 vCorners[1][2] = fMid;
3855 vCorners[2][0] = b->maxs[0];
3856 vCorners[2][1] = b->maxs[1];
3857 vCorners[2][2] = fMid;
3859 vCorners[3][0] = b->maxs[0];
3860 vCorners[3][1] = b->mins[1];
3861 vCorners[3][2] = fMid;
3863 idVec3 vTop, vBottom;
3865 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
3866 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
3867 vTop[2] = b->maxs[2];
3869 VectorCopy(vTop, vBottom);
3870 vBottom[2] = b->mins[2];
3873 VectorCopy(vTriColor, vSave);
3875 globalImages->BindNull();
3876 qglBegin(GL_TRIANGLE_FAN);
3877 qglVertex3fv(vTop.ToFloatPtr());
3879 for (i = 0; i <= 3; i++) {
3880 vTriColor[0] *= 0.95f;
3881 vTriColor[1] *= 0.95f;
3882 vTriColor[2] *= 0.95f;
3883 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3884 qglVertex3fv(vCorners[i].ToFloatPtr());
3887 qglVertex3fv(vCorners[0].ToFloatPtr());
3890 VectorCopy(vSave, vTriColor);
3891 vTriColor[0] *= 0.95f;
3892 vTriColor[1] *= 0.95f;
3893 vTriColor[2] *= 0.95f;
3895 qglBegin(GL_TRIANGLE_FAN);
3896 qglVertex3fv(vBottom.ToFloatPtr());
3897 qglVertex3fv(vCorners[0].ToFloatPtr());
3898 for (i = 3; i >= 0; i--) {
3899 vTriColor[0] *= 0.95f;
3900 vTriColor[1] *= 0.95f;
3901 vTriColor[2] *= 0.95f;
3902 qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
3903 qglVertex3fv(vCorners[i].ToFloatPtr());
3908 DrawProjectedLight(b, bSelected, true);
3916 void Control_Draw(brush_t *b) {
3919 qtexture_t *prev = 0;
3922 // guarantee the texture will be set first
3924 for ( face = b->brush_faces, order = 0; face; face = face->next, order++ ) {
3925 w = face->face_winding;
3927 continue; // freed face
3930 qglColor4f(1, 1, .5, 1);
3931 qglBegin(GL_POLYGON);
3932 for (i = 0; i < w->GetNumPoints(); i++) {
3933 qglVertex3fv( (*w)[i].ToFloatPtr() );
3945 void Brush_DrawModel( brush_t *b, bool camera, bool bSelected ) {
3948 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
3950 if ( camera && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME && nDrawMode != cd_wire ) {
3951 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
3954 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
3957 idRenderModel *model = b->modelHandle;
3958 if ( model == NULL ) {
3959 model = b->owner->eclass->entityModel;
3962 idRenderModel *model2;
3965 bool fixedBounds = false;
3967 if ( model->IsDynamicModel() != DM_STATIC ) {
3968 if ( dynamic_cast<idRenderModelMD5 *>( model ) ) {
3969 const char *classname = ValueForKey( b->owner, "classname" );
3970 if (stricmp(classname, "func_static") == 0) {
3971 classname = ValueForKey(b->owner, "animclass");
3973 const char *anim = ValueForKey( b->owner, "anim" );
3974 int frame = IntForKey( b->owner, "frame" ) + 1;
3978 if ( !anim || !anim[ 0 ] ) {
3981 model2 = gameEdit->ANIM_CreateMeshForAnim( model, classname, anim, frame, false );
3982 } else if ( dynamic_cast<idRenderModelPrt*>( model ) || dynamic_cast<idRenderModelLiquid*>( model ) ) {
3990 bounds.ExpandSelf(12.0f);
3992 bounds = model->Bounds( NULL );
3997 color.x = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x;
3998 color.y = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y;
3999 color.z = g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z;
4001 color.x = b->owner->eclass->color.x;
4002 color.y = b->owner->eclass->color.y;
4003 color.z = b->owner->eclass->color.z;
4005 idVec3 center = bounds.GetCenter();
4006 glBox(color, b->owner->origin + center, bounds.GetRadius( center ) );
4007 model = renderModelManager->DefaultModel();
4013 Entity_GetRotationMatrixAngles( b->owner, axis, angles );
4016 qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4019 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
4022 DrawRenderModel( model, b->owner->origin, axis, camera );
4024 qglColor4fv( colorSave.ToFloatPtr() );
4026 if ( bSelected && camera )
4028 //draw selection tints
4030 if ( camera && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME ) {
4031 qglPolygonMode ( GL_FRONT_AND_BACK , GL_FILL );
4032 qglColor3fv ( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr () );
4033 qglEnable ( GL_BLEND );
4034 qglBlendFunc ( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
4035 DrawRenderModel( model, b->owner->origin, axis, camera );
4039 //draw white triangle outlines
4040 globalImages->BindNull();
4042 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
4043 qglDisable( GL_BLEND );
4044 qglDisable( GL_DEPTH_TEST );
4045 qglColor3f( 1.0f, 1.0f, 1.0f );
4046 qglPolygonOffset( 1.0f, 3.0f );
4047 DrawRenderModel( model, b->owner->origin, axis, false );
4048 qglEnable( GL_DEPTH_TEST );
4057 if ( bSelected && camera ) {
4058 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4060 else if ( camera ) {
4061 globalImages->BindNull();
4064 if ( g_bPatchShowBounds ) {
4065 for ( face_t *face = b->brush_faces; face; face = face->next ) {
4066 // only draw polygons facing in a direction we care about
4067 idWinding *w = face->face_winding;
4073 // if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) continue;
4076 qglBegin(GL_LINE_LOOP);
4077 for (int i = 0; i < w->GetNumPoints(); i++) {
4078 qglVertex3fv( (*w)[i].ToFloatPtr() );
4090 void GLTransformedVertex(float x, float y, float z, idMat3 mat, idVec3 origin, idVec3 color, float maxDist) {
4096 idVec3 n = v - g_pParentWnd->GetCamera()->Camera().origin;
4097 float max = n.Length() / maxDist;
4100 } else if (color.y) {
4105 qglColor3f(color.x, color.y, color.z);
4106 qglVertex3f(v.x, v.y, v.z);
4115 void GLTransformedCircle(int type, idVec3 origin, float r, idMat3 mat, float pointSize, idVec3 color, float maxDist) {
4116 qglPointSize(pointSize);
4117 qglBegin(GL_POINTS);
4118 for (int i = 0; i < 360; i++) {
4119 float cx = origin.x;
4120 float cy = origin.y;
4121 float cz = origin.z;
4124 cx += r * cos((float)i);
4125 cy += r * sin((float)i);
4128 cx += r * cos((float)i);
4129 cz += r * sin((float)i);
4132 cy += r * sin((float)i);
4133 cz += r * cos((float)i);
4138 GLTransformedVertex(cx, cy, cz, mat, origin, color, maxDist);
4148 void Brush_DrawAxis(brush_t *b) {
4149 if ( g_pParentWnd->ActiveXY()->RotateMode() && b->modelHandle ) {
4150 bool matrix = false;
4153 if (GetMatrixForKey(b->owner, "rotation", mat)) {
4156 a = FloatForKey(b->owner, "angle");
4158 s = sin( DEG2RAD( a ) );
4159 c = cos( DEG2RAD( a ) );
4167 bo.FromTransformedBounds(b->modelHandle->Bounds(), b->owner->origin, b->owner->rotation);
4169 float dist = (g_pParentWnd->GetCamera()->Camera().origin - bo[0]).Length();
4170 float dist2 = (g_pParentWnd->GetCamera()->Camera().origin - bo[1]).Length();
4176 xr = (b->modelHandle->Bounds()[1].x > b->modelHandle->Bounds()[0].x) ? b->modelHandle->Bounds()[1].x - b->modelHandle->Bounds()[0].x : b->modelHandle->Bounds()[0].x - b->modelHandle->Bounds()[1].x;
4177 yr = (b->modelHandle->Bounds()[1].y > b->modelHandle->Bounds()[0].y) ? b->modelHandle->Bounds()[1].y - b->modelHandle->Bounds()[0].y : b->modelHandle->Bounds()[0].y - b->modelHandle->Bounds()[1].y;
4178 zr = (b->modelHandle->Bounds()[1].z > b->modelHandle->Bounds()[0].z) ? b->modelHandle->Bounds()[1].z - b->modelHandle->Bounds()[0].z : b->modelHandle->Bounds()[0].z - b->modelHandle->Bounds()[1].z;
4180 globalImages->BindNull();
4182 GLTransformedCircle(0, b->owner->origin, xr, mat, 1.25, idVec3(0, 0, 1), dist);
4183 GLTransformedCircle(1, b->owner->origin, yr, mat, 1.25, idVec3(0, 1, 0), dist);
4184 GLTransformedCircle(2, b->owner->origin, zr, mat, 1.25, idVec3(1, 0, 0), dist);
4188 idVec3 org = b->owner->origin;
4189 if (g_qeglobals.rotateAxis == 0) {
4192 } else if (g_qeglobals.rotateAxis == 1) {
4197 if (g_qeglobals.flatRotation) {
4204 idVec3 vec = vec3_origin;
4205 vec[g_qeglobals.rotateAxis] = 1.0f;
4206 if (g_qeglobals.flatRotation == 1) {
4207 org = g_pParentWnd->ActiveXY()->RotateOrigin();
4208 float t = (org - bo.GetCenter()).Length();
4213 org = bo.GetCenter();
4215 idRotation rot(org, vec, 0);
4218 GLTransformedCircle(type, org, wr * 1.03f, mat, 1.45f, idVec3(1, 1, 1), dist);
4227 void Brush_DrawModelInfo(brush_t *b, bool selected) {
4228 if (b->modelHandle > 0) {
4230 qglGetFloatv(GL_CURRENT_COLOR, &color[0]);
4232 qglColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr());
4235 qglColor3fv(b->owner->eclass->color.ToFloatPtr());
4238 Brush_DrawModel(b, true, selected);
4253 void Brush_DrawEmitter(brush_t *b, bool bSelected, bool cam) {
4254 if ( !( b->owner->eclass->nShowFlags & ECLASS_PARTICLE ) ) {
4259 qglColor4f(g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].x, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].y, g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].z, .5);
4261 qglColor4f(b->owner->eclass->color.x, b->owner->eclass->color.y, b->owner->eclass->color.z, .5);
4265 Brush_DrawFacingAngle( b, b->owner, true );
4274 void Brush_DrawEnv( brush_t *b, bool cameraView, bool bSelected ) {
4275 idVec3 origin, newOrigin;
4276 idMat3 axis, newAxis;
4280 idRenderModel *model = gameEdit->AF_CreateMesh( b->owner->epairs, origin, axis, poseIsSet );
4283 if ( Entity_GetRotationMatrixAngles( b->owner, newAxis, newAngles ) ) {
4286 if ( b->owner->epairs.GetVector( "origin", "0 0 0", newOrigin ) ) {
4292 if ( cameraView && g_PrefsDlg.m_nEntityShowState != ENTITY_WIREFRAME ) {
4293 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4296 qglPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
4300 qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4303 qglColor3fv( g_qeglobals.d_savedinfo.colors[COLOR_SELBRUSHES].ToFloatPtr() );
4305 qglColor3f( 1.f, 1.f, 1.f );
4307 DrawRenderModel( model, origin, axis, true );
4308 globalImages->BindNull();
4312 qglColor4fv( colorSave.ToFloatPtr() );
4318 Brush_DrawCombatNode
4321 void Brush_DrawCombatNode( brush_t *b, bool cameraView, bool bSelected ) {
4322 float min_dist = b->owner->epairs.GetFloat( "min" );
4323 float max_dist = b->owner->epairs.GetFloat( "max" );
4324 float fov = b->owner->epairs.GetFloat( "fov", "60" );
4325 float yaw = b->owner->epairs.GetFloat("angle");
4326 idVec3 offset = b->owner->epairs.GetVector("offset");
4328 idAngles leftang( 0.0f, yaw + fov * 0.5f - 90.0f, 0.0f );
4329 idVec3 cone_left = leftang.ToForward();
4330 idAngles rightang( 0.0f, yaw - fov * 0.5f + 90.0f, 0.0f );
4331 idVec3 cone_right = rightang.ToForward();
4332 bool disabled = b->owner->epairs.GetBool( "start_off" );
4341 idVec3 leftDir( -cone_left.y, cone_left.x, 0.0f );
4342 idVec3 rightDir( cone_right.y, -cone_right.x, 0.0f );
4343 leftDir.NormalizeFast();
4344 rightDir.NormalizeFast();
4346 idMat3 axis = idAngles(0, yaw, 0).ToMat3();
4347 idVec3 org = b->owner->origin + offset;
4348 idVec3 entorg = b->owner->origin;
4349 float cone_dot = cone_right * axis[ 1 ];
4350 if ( idMath::Fabs( cone_dot ) > 0.1 ) {
4351 idVec3 pt, pt1, pt2, pt3, pt4;
4352 float cone_dist = max_dist / cone_dot;
4353 pt1 = org + leftDir * min_dist;
4354 pt2 = org + leftDir * cone_dist;
4355 pt3 = org + rightDir * cone_dist;
4356 pt4 = org + rightDir * min_dist;
4357 qglColor4fv(color.ToFloatPtr());
4358 qglBegin(GL_LINE_STRIP);
4359 qglVertex3fv( pt1.ToFloatPtr());
4360 qglVertex3fv( pt2.ToFloatPtr());
4361 qglVertex3fv( pt3.ToFloatPtr());
4362 qglVertex3fv( pt4.ToFloatPtr());
4363 qglVertex3fv( pt1.ToFloatPtr());
4366 qglColor4fv(colorGreen.ToFloatPtr());
4367 qglBegin(GL_LINE_STRIP);
4368 qglVertex3fv( entorg.ToFloatPtr());
4369 pt = (pt1 + pt4) * 0.5f;
4370 qglVertex3fv( pt.ToFloatPtr());
4371 pt = (pt2 + pt3) * 0.5f;
4372 qglVertex3fv( pt.ToFloatPtr());
4374 idVec3 dir = ((pt1 + pt2) * 0.5f) - tip;
4376 pt = tip + dir * 15.0f;
4377 qglVertex3fv( pt.ToFloatPtr());
4378 qglVertex3fv( tip.ToFloatPtr());
4379 dir = ((pt4 + pt3) * 0.5f) - tip;
4381 pt = tip + dir * 15.0f;
4382 qglVertex3fv( pt.ToFloatPtr());
4393 void Brush_Draw(brush_t *b, bool bSelected) {
4396 const idMaterial *prev = NULL;
4401 // (TTimo) NOTE: added by build 173, I check after pPlugEnt so it doesn't
4404 if ( b->hiddenBrush ) {
4408 Brush_DrawCurve( b, bSelected, true );
4411 Patch_DrawCam(b->pPatch, bSelected);
4415 int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
4417 if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES) && (b->owner->eclass->nShowFlags & ECLASS_ANGLE)) {
4418 Brush_DrawFacingAngle(b, b->owner, false);
4421 if ( b->owner->eclass->fixedsize ) {
4423 DrawSpeaker( b, bSelected, false );
4425 if ( g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT) && !(b->modelHandle || b->entityModel) ) {
4426 DrawLight( b, bSelected );
4430 if ( b->owner->eclass->nShowFlags & ECLASS_ENV ) {
4431 Brush_DrawEnv( b, true, bSelected );
4434 if ( b->owner->eclass->nShowFlags & ECLASS_COMBATNODE ) {
4435 Brush_DrawCombatNode( b, true, bSelected );
4441 if (!(b->owner && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) {
4442 qglColor4f( 1.0f, 0.0f, 0.0f, 0.8f );
4444 qglBegin(GL_POINTS);
4445 qglVertex3fv(b->owner->origin.ToFloatPtr());
4449 if ( b->owner->eclass->entityModel ) {
4450 qglColor3fv( b->owner->eclass->color.ToFloatPtr() );
4451 Brush_DrawModel( b, true, bSelected );
4455 Brush_DrawEmitter( b, bSelected, true );
4457 if ( b->modelHandle > 0 && !model ) {
4458 Brush_DrawModelInfo( b, bSelected );
4462 // guarantee the texture will be set first
4464 for (face = b->brush_faces, order = 0; face; face = face->next, order++) {
4465 w = face->face_winding;
4467 continue; // freed face
4470 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK) {
4471 if (strstr(face->texdef.name, "caulk")) {
4476 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_VISPORTALS) {
4477 if (strstr(face->texdef.name, "visportal")) {
4482 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_NODRAW) {
4483 if (strstr(face->texdef.name, "nodraw")) {
4488 if ( (nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev && !b->forceWireFrame ) {
4489 // set the texture for this face
4490 prev = face->d_texture;
4491 face->d_texture->GetEditorImage()->Bind();
4495 qglEnable(GL_BLEND);
4496 qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
4497 qglColor4f( face->d_color.x, face->d_color.y, face->d_color.z, 0.1f );
4499 qglColor4f( face->d_color.x, face->d_color.y, face->d_color.z, face->d_texture->GetEditorAlpha() );
4502 qglBegin(GL_POLYGON);
4504 for (i = 0; i < w->GetNumPoints(); i++) {
4505 if ( !b->forceWireFrame && ( nDrawMode == cd_texture || nDrawMode == cd_light ) ) {
4506 qglTexCoord2fv( &(*w)[i][3] );
4509 qglVertex3fv( (*w)[i].ToFloatPtr() );
4515 qglDisable(GL_BLEND);
4519 globalImages->BindNull();
4527 void Face_Draw(face_t *f) {
4530 if (f->face_winding == NULL) {
4534 qglBegin(GL_POLYGON);
4535 for (i = 0; i < f->face_winding->GetNumPoints(); i++) {
4536 qglVertex3fv( (*f->face_winding)[i].ToFloatPtr() );
4543 idSurface_SweptSpline *SplineToSweptSpline( idCurve<idVec3> *curve ) {
4544 // expects a vec3 curve and creates a vec4 based swept spline
4545 // must be either nurbs or catmull
4546 idCurve_Spline<idVec4> *newCurve = NULL;
4547 if ( dynamic_cast<idCurve_NURBS<idVec3>*>( curve ) ) {
4548 newCurve = new idCurve_NURBS<idVec4>;
4549 } else if ( dynamic_cast<idCurve_CatmullRomSpline<idVec3>*>( curve ) ) {
4550 newCurve = new idCurve_CatmullRomSpline<idVec4>;
4553 if ( curve == NULL || newCurve == NULL ) {
4557 int c = curve->GetNumValues();
4559 for ( int i = 0; i < c; i++ ) {
4560 idVec3 v = curve->GetValue( i );
4561 newCurve->AddValue( curve->GetTime( i ), idVec4( v.x, v.y, v.z, len ) );
4563 len += curve->GetLengthBetweenKnots( i, i + 1 ) * 0.1f;
4567 idSurface_SweptSpline *ss = new idSurface_SweptSpline;
4568 ss->SetSpline( newCurve );
4569 ss->SetSweptCircle( 10.0f );
4570 ss->Tessellate( newCurve->GetNumValues() * 6, 6 );
4580 void Brush_DrawCurve( brush_t *b, bool bSelected, bool cam ) {
4581 if ( b == NULL || b->owner->curve == NULL ) {
4585 int maxage = b->owner->curve->GetNumValues();
4587 qglColor3f( 0.0f, 0.0f, 1.0f );
4588 for ( i = 0; i < maxage; i++) {
4590 if ( bSelected && g_qeglobals.d_select_mode == sel_editpoint ) {
4591 idVec3 v = b->owner->curve->GetValue( i );
4593 glBox( colorBlue, v, 6.0f );
4594 if ( PointInMoveList( b->owner->curve->GetValueAddress( i ) ) >= 0 ) {
4595 glBox(colorBlue, v, 8.0f );
4598 qglPointSize( 4.0f );
4599 qglBegin( GL_POINTS );
4600 qglVertex3f( v.x, v.y, v.z );
4603 if ( PointInMoveList( b->owner->curve->GetValueAddress( i ) ) >= 0 ) {
4604 glBox(colorBlue, v, 4.0f );
4610 idSurface_SweptSpline *ss = SplineToSweptSpline( b->owner->curve );
4612 idMaterial *mat = declManager->FindMaterial( "_default" );
4613 mat->GetEditorImage()->Bind();
4614 qglPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
4615 qglBegin( GL_TRIANGLES );
4616 const int *indexes = ss->GetIndexes();
4617 const idDrawVert *verts = ss->GetVertices();
4618 for ( j = 0; j < ss->GetNumIndexes(); j += 3 ) {
4619 for ( k = 0; k < 3; k++ ) {
4620 int index = indexes[ j + 2 - k ];
4621 float f = ShadeForNormal( verts[index].normal );
4622 qglColor3f( f, f, f );
4623 qglTexCoord2fv( verts[index].st.ToFloatPtr() );
4624 qglVertex3fv( verts[index].xyz.ToFloatPtr() );
4632 /* qglPointSize( 1.0f );
4633 qglBegin( GL_POINTS );
4634 if ( i + 1 < maxage ) {
4635 int start = b->owner->curve->GetTime( i );
4636 int end = b->owner->curve->GetTime( i + 1 );
4637 int inc = (end - start) / POINTS_PER_KNOT;
4638 for ( int j = 0; j < POINTS_PER_KNOT; j++ ) {
4639 idVec3 v = b->owner->curve->GetCurrentValue( start );
4640 qglVertex3f( v.x, v.y, v.z );
4644 // DHM - _D3XP : Makes it easier to see curve
4645 qglBegin( GL_LINE_STRIP );
4646 if ( i + 1 < maxage ) {
4647 int start = b->owner->curve->GetTime( i );
4648 int end = b->owner->curve->GetTime( i + 1 );
4649 int inc = (end - start) / POINTS_PER_KNOT;
4650 for ( int j = 0; j <= POINTS_PER_KNOT; j++ ) {
4651 idVec3 v = b->owner->curve->GetCurrentValue( start );
4652 qglVertex3f( v.x, v.y, v.z );
4670 void Brush_DrawXY(brush_t *b, int nViewType, bool bSelected, bool ignoreViewType) {
4676 if ( b->hiddenBrush ) {
4681 qglGetFloatv(GL_CURRENT_COLOR, colorSave.ToFloatPtr());
4683 if (!(b->owner && (b->owner->eclass->nShowFlags & ECLASS_WORLDSPAWN))) {
4684 qglColor4f( 1.0f, 0.0f, 0.0f, 0.8f );
4686 qglBegin(GL_POINTS);
4687 qglVertex3fv(b->owner->origin.ToFloatPtr());
4691 Brush_DrawCurve( b, bSelected, false );
4693 qglColor4fv(colorSave.ToFloatPtr());
4697 Patch_DrawXY(b->pPatch);
4698 if (!g_bPatchShowBounds) {
4703 if (b->owner->eclass->fixedsize) {
4705 DrawSpeaker(b, bSelected, true);
4706 if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT) && !(b->modelHandle || b->entityModel)) {
4708 float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
4710 vCorners[0][0] = b->mins[0];
4711 vCorners[0][1] = b->mins[1];
4712 vCorners[0][2] = fMid;
4714 vCorners[1][0] = b->mins[0];
4715 vCorners[1][1] = b->maxs[1];
4716 vCorners[1][2] = fMid;
4718 vCorners[2][0] = b->maxs[0];
4719 vCorners[2][1] = b->maxs[1];
4720 vCorners[2][2] = fMid;
4722 vCorners[3][0] = b->maxs[0];
4723 vCorners[3][1] = b->mins[1];
4724 vCorners[3][2] = fMid;
4726 idVec3 vTop, vBottom;
4728 vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
4729 vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
4730 vTop[2] = b->maxs[2];
4732 VectorCopy(vTop, vBottom);
4733 vBottom[2] = b->mins[2];
4735 qglPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
4736 qglBegin(GL_TRIANGLE_FAN);
4737 qglVertex3fv(vTop.ToFloatPtr());
4738 qglVertex3fv(vCorners[0].ToFloatPtr());
4739 qglVertex3fv(vCorners[1].ToFloatPtr());
4740 qglVertex3fv(vCorners[2].ToFloatPtr());
4741 qglVertex3fv(vCorners[3].ToFloatPtr());
4742 qglVertex3fv(vCorners[0].ToFloatPtr());
4744 qglBegin(GL_TRIANGLE_FAN);
4745 qglVertex3fv(vBottom.ToFloatPtr());
4746 qglVertex3fv(vCorners[0].ToFloatPtr());
4747 qglVertex3fv(vCorners[3].ToFloatPtr());
4748 qglVertex3fv(vCorners[2].ToFloatPtr());
4749 qglVertex3fv(vCorners[1].ToFloatPtr());
4750 qglVertex3fv(vCorners[0].ToFloatPtr());
4752 DrawBrushEntityName(b);
4753 DrawProjectedLight(b, bSelected, false);
4755 } else if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL) {
4756 // if (PaintedModel(b, false)) return;
4757 } else if (b->owner->eclass->nShowFlags & ECLASS_ENV) {
4758 Brush_DrawEnv( b, false, bSelected );
4759 } else if (b->owner->eclass->nShowFlags & ECLASS_COMBATNODE) {
4760 Brush_DrawCombatNode(b, false, bSelected);
4763 if (b->owner->eclass->entityModel) {
4764 Brush_DrawModel( b, false, bSelected );
4765 DrawBrushEntityName(b);
4766 qglColor4fv(colorSave.ToFloatPtr());
4772 qglColor4fv(colorSave.ToFloatPtr());
4774 if (b->modelHandle > 0) {
4775 Brush_DrawEmitter( b, bSelected, false );
4776 Brush_DrawModel(b, false, bSelected);
4777 qglColor4fv(colorSave.ToFloatPtr());
4781 for (face = b->brush_faces, order = 0; face; face = face->next, order++) {
4782 // only draw polygons facing in a direction we care about
4783 if (!ignoreViewType) {
4784 if (nViewType == XY) {
4785 if (face->plane[2] <= 0) {
4789 if (nViewType == XZ) {
4790 if (face->plane[1] <= 0) {
4794 if (face->plane[0] <= 0) {
4801 w = face->face_winding;
4807 // if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA)) continue;
4810 qglBegin(GL_LINE_LOOP);
4811 for (i = 0; i < w->GetNumPoints(); i++) {
4812 qglVertex3fv( (*w)[i].ToFloatPtr() );
4816 for (i = 0; i < 3; i++) {
4817 glLabeledPoint(idVec4(1, 0, 0, 1), face->planepts[i], 3, va("%i", i));
4822 DrawBrushEntityName(b);
4827 PointValueInPointList
4830 static int PointValueInPointList( idVec3 v ) {
4831 for ( int i = 0; i < g_qeglobals.d_numpoints; i++ ) {
4832 if ( v == g_qeglobals.d_points[i] ) {
4840 extern bool Sys_KeyDown(int key);
4846 void Brush_Move(brush_t *b, const idVec3 move, bool bSnap, bool updateOrigin) {
4851 for (f = b->brush_faces; f; f = f->next) {
4853 VectorCopy(move, vTemp);
4855 if (g_PrefsDlg.m_bTextureLock) {
4856 Face_MoveTexture(f, vTemp);
4859 for (i = 0; i < 3; i++) {
4860 VectorAdd(f->planepts[i], move, f->planepts[i]);
4864 bool controlDown = Sys_KeyDown(VK_CONTROL);
4865 Brush_Build(b, bSnap, true, false, !controlDown);
4868 Patch_Move(b->pPatch, move);
4871 if ( b->owner->curve ) {
4872 b->owner->curve->Translate( move );
4873 Entity_UpdateCurveData( b->owner );
4878 // PGM - keep the origin vector up to date on fixed size entities.
4879 if (b->owner->eclass->fixedsize || EntityHasModel(b->owner) || (updateOrigin && GetVectorForKey(b->owner, "origin", temp))) {
4880 // if (!b->entityModel) {
4881 bool adjustOrigin = true;
4882 if(b->trackLightOrigin) {
4883 b->owner->lightOrigin += move;
4884 sprintf(text, "%i %i %i", (int)b->owner->lightOrigin[0], (int)b->owner->lightOrigin[1], (int)b->owner->lightOrigin[2]);
4885 SetKeyValue(b->owner, "light_origin", text);
4886 if (QE_SingleBrush(true, true)) {
4887 adjustOrigin = false;
4891 if (adjustOrigin && updateOrigin) {
4892 b->owner->origin += move;
4894 sprintf(text, "%g %g %g", b->owner->origin[0], b->owner->origin[1], b->owner->origin[2]);
4896 sprintf(text, "%i %i %i", (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2]);
4898 SetKeyValue(b->owner, "origin", text);
4901 // rebuild the light dragging points now that the origin has changed
4908 Brush_UpdateLightPoints(b, offset);
4911 Brush_UpdateLightPoints(b, offset);
4915 if (b->owner->eclass->nShowFlags & ECLASS_ENV) {
4916 const idKeyValue *arg = b->owner->epairs.MatchPrefix( "body ", NULL );
4921 sscanf( arg->GetValue(), "%f %f %f %f %f %f", &org.x, &org.y, &org.z, &ang.pitch, &ang.yaw, &ang.roll );
4923 val = org.ToString(8);
4925 val += ang.ToString(8);
4926 b->owner->epairs.Set(arg->GetKey(), val);
4927 arg = b->owner->epairs.MatchPrefix( "body ", arg );
4935 Select_AddProjectedLight
4938 void Select_AddProjectedLight() {
4942 // if (!QE_SingleBrush ()) return;
4943 brush_t *b = selected_brushes.next;
4945 if (b->owner->eclass->nShowFlags & ECLASS_LIGHT) {
4946 vTemp[0] = vTemp[1] = 0;
4948 str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4949 SetKeyValue(b->owner, "light_target", str);
4953 str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4954 SetKeyValue(b->owner, "light_up", str);
4958 str.Format("%f %f %f", vTemp[0], vTemp[1], vTemp[2]);
4959 SetKeyValue(b->owner, "light_right", str);
4969 void Brush_Print(brush_t *b) {
4971 for (face_t * f = b->brush_faces; f; f = f->next) {
4972 common->Printf("Face %i\n", nFace++);
4973 common->Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
4974 common->Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
4975 common->Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
4983 Makes the current brush have the given number of 2d sides and turns it into a cone
4986 void Brush_MakeSidedCone(int sides) {
4997 Sys_Status("Bad sides number", 0);
5001 if (!QE_SingleBrush()) {
5002 Sys_Status("Must have a single brush selected", 0);
5006 b = selected_brushes.next;
5007 VectorCopy(b->mins, mins);
5008 VectorCopy(b->maxs, maxs);
5009 texdef = &g_qeglobals.d_texturewin.texdef;
5013 // find center of brush
5015 for (i = 0; i < 2; i++) {
5016 mid[i] = (maxs[i] + mins[i]) * 0.5f;
5017 if (maxs[i] - mins[i] > width) {
5018 width = maxs[i] - mins[i];
5026 // create bottom face
5028 f->texdef = *texdef;
5029 f->next = b->brush_faces;
5032 f->planepts[0][0] = mins[0];
5033 f->planepts[0][1] = mins[1];
5034 f->planepts[0][2] = mins[2];
5035 f->planepts[1][0] = maxs[0];
5036 f->planepts[1][1] = mins[1];
5037 f->planepts[1][2] = mins[2];
5038 f->planepts[2][0] = maxs[0];
5039 f->planepts[2][1] = maxs[1];
5040 f->planepts[2][2] = mins[2];
5042 for (i = 0; i < sides; i++) {
5044 f->texdef = *texdef;
5045 f->next = b->brush_faces;
5048 sv = sin(i * idMath::TWO_PI / sides);
5049 cv = cos(i * idMath::TWO_PI / sides);
5051 f->planepts[0][0] = floor( mid[0] + width * cv + 0.5f );
5052 f->planepts[0][1] = floor( mid[1] + width * sv + 0.5f );
5053 f->planepts[0][2] = mins[2];
5055 f->planepts[1][0] = mid[0];
5056 f->planepts[1][1] = mid[1];
5057 f->planepts[1][2] = maxs[2];
5059 f->planepts[2][0] = floor( f->planepts[0][0] - width * sv + 0.5f );
5060 f->planepts[2][1] = floor( f->planepts[0][1] + width * cv + 0.5f );
5061 f->planepts[2][2] = maxs[2];
5064 Brush_AddToList(b, &selected_brushes);
5066 Entity_LinkBrush(world_entity, b);
5070 Sys_UpdateWindows(W_ALL);
5075 Brush_MakeSidedSphere
5077 Makes the current brushhave the given number of 2d sides and turns it into a sphere
5080 void Brush_MakeSidedSphere(int sides) {
5090 Sys_Status("Bad sides number", 0);
5094 if (!QE_SingleBrush()) {
5095 Sys_Status("Must have a single brush selected", 0);
5099 b = selected_brushes.next;
5102 texdef = &g_qeglobals.d_texturewin.texdef;
5106 // find center of brush
5108 for ( i = 0; i < 3; i++ ) {
5109 mid[i] = (maxs[i] + mins[i]) * 0.5f;
5110 if (maxs[i] - mins[i] > radius) {
5111 radius = maxs[i] - mins[i];
5119 for (i = 0; i < sides; i++) {
5120 for (j = 0; j < sides - 1; j++) {
5122 f->texdef = *texdef;
5123 f->next = b->brush_faces;
5126 f->planepts[0] = idPolar3(radius, idMath::TWO_PI * i / sides, idMath::PI * ((float)(j) / sides - 0.5f) ).ToVec3() + mid;
5127 f->planepts[1] = idPolar3(radius, idMath::TWO_PI * i / sides, idMath::PI * ((float)(j+1) / sides - 0.5f) ).ToVec3() + mid;
5128 f->planepts[2] = idPolar3(radius, idMath::TWO_PI * (i+1) / sides, idMath::PI * ((float)(j+1) / sides - 0.5f) ).ToVec3() + mid;
5132 Brush_AddToList(b, &selected_brushes);
5134 Entity_LinkBrush(world_entity, b);
5138 Sys_UpdateWindows(W_ALL);
5141 extern void Face_FitTexture_BrushPrimit(face_t *f, idVec3 mins, idVec3 maxs, float nHeight, float nWidth);
5148 void Face_FitTexture(face_t *face, float nHeight, float nWidth) {
5149 if (g_qeglobals.m_bBrushPrimitMode) {
5151 mins[0] = maxs[0] = 0;
5152 Face_FitTexture_BrushPrimit(face, mins, maxs, nHeight, nWidth);
5156 * winding_t *w; idBounds bounds; int i; float width, height, temp; float rot_width,
5157 * rot_height; float cosv,sinv,ang; float min_t, min_s, max_t, max_s; float s,t;
5158 * idVec3 vecs[2]; idVec3 coords[4]; texdef_t *td; if (nHeight < 1) { nHeight = 1;
5159 * } if (nWidth < 1) { nWidth = 1; } bounds.Clear(); td = &face->texdef; w =
5160 * face->face_winding; if (!w) { return; } for (i=0 ; i<w->numpoints ; i++) {
5161 * bounds.AddPoint( w->p[i] ); } // // get the current angle // ang = td->rotate /
5162 * 180 * Q_PI; sinv = sin(ang); cosv = cos(ang); // get natural texture axis
5163 * TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]); min_s = DotProduct(
5164 * bounds.b[0], vecs[0] ); min_t = DotProduct( bounds.b[0], vecs[1] ); max_s =
5165 * DotProduct( bounds.b[1], vecs[0] ); max_t = DotProduct( bounds.b[1], vecs[1] );
5166 * width = max_s - min_s; height = max_t - min_t; coords[0][0] = min_s;
5167 * coords[0][1] = min_t; coords[1][0] = max_s; coords[1][1] = min_t; coords[2][0]
5168 * = min_s; coords[2][1] = max_t; coords[3][0] = max_s; coords[3][1] = max_t;
5169 * min_s = min_t = 999999; max_s = max_t = -999999; for (i=0; i<4; i++) { s = cosv
5170 * * coords[i][0] - sinv * coords[i][1]; t = sinv * coords[i][0] + cosv *
5171 * coords[i][1]; if (i&1) { if (s > max_s) { max_s = s; } } else { if (s < min_s)
5172 * { min_s = s; } if (i<2) { if (t < min_t) { min_t = t; } } else { if (t > max_t)
5173 * { max_t = t; } } } } rot_width = (max_s - min_s); rot_height = (max_t - min_t);
5175 * -(rot_width/((float)(face->d_texture->GetEditorImage()->uploadWidth*nWidth)));
5177 * -(rot_height/((float)(face->d_texture->GetEditorImage()->uploadHeight*nHeight)));
5178 * td->shift[0] = min_s/td->scale[0]; temp = (int)(td->shift[0] /
5179 * (face->d_texture->GetEditorImage()->uploadWidth*nWidth)); temp =
5180 * (temp+1)*face->d_texture->GetEditorImage()->uploadWidth*nWidth; td->shift[0] =
5182 * td->shift[0])%(face->d_texture->GetEditorImage()->uploadWidth*nWidth);
5183 * td->shift[1] = min_t/td->scale[1]; temp = (int)(td->shift[1] /
5184 * (face->d_texture->GetEditorImage()->uploadHeight*nHeight)); temp =
5185 * (temp+1)*(face->d_texture->GetEditorImage()->uploadHeight*nHeight);
5186 * td->shift[1] = (int)(temp -
5187 * td->shift[1])%(face->d_texture->GetEditorImage()->uploadHeight*nHeight);
5197 void Brush_FitTexture(brush_t *b, float nHeight, float nWidth) {
5199 for (face = b->brush_faces; face; face = face->next) {
5200 Face_FitTexture(face, nHeight, nWidth);
5204 void Brush_GetBounds( brush_t *b, idBounds &bo ) {
5210 bo.AddPoint( b->mins );
5211 bo.AddPoint( b->maxs );
5213 if ( b->owner->curve ) {
5214 int c = b->owner->curve->GetNumValues();
5215 for ( int i = 0; i < c; i++ ) {
5216 bo.AddPoint ( b->owner->curve->GetValue( i ) );