Main Page | Class Hierarchy | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

Brush.cpp

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 
00023 
00024 #include "stdafx.h"
00025 #include <assert.h>
00026 #include "qe3.h"
00027 #include "winding.h"
00028 
00029 
00030 // globals
00031 
00032 int g_nBrushId = 0;
00033 
00034 const char* Brush_Name(brush_t *b)
00035 {
00036   static char cBuff[1024];
00037     b->numberId = g_nBrushId++;
00038     if (g_qeglobals.m_bBrushPrimitMode)
00039   {
00040     sprintf(cBuff, "Brush %i", b->numberId);
00041     Brush_SetEpair(b, "Name", cBuff);
00042   }
00043   return cBuff;
00044 }
00045 
00046 brush_t *Brush_Alloc()
00047 {
00048   brush_t *b = (brush_t*)qmalloc(sizeof(brush_t));
00049   return b;
00050 }
00051 
00052 
00053 
00054 
00055 void PrintWinding (winding_t *w)
00056 {
00057     int     i;
00058     
00059     printf ("-------------\n");
00060     for (i=0 ; i<w->numpoints ; i++)
00061         printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0]
00062         , w->points[i][1], w->points[i][2]);
00063 }
00064 
00065 void PrintPlane (plane_t *p)
00066 {
00067   printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n",  p->normal[0],  p->normal[1], 
00068   p->normal[2],  p->dist);
00069 }
00070 
00071 void PrintVector (vec3_t v)
00072 {
00073   printf ("(%5.2f, %5.2f, %5.2f)\n",  v[0],  v[1], v[2]);
00074 }
00075 
00076 
00077 /*
00078 =============================================================================
00079 
00080             TEXTURE COORDINATES
00081 
00082 =============================================================================
00083 */
00084 
00085 
00086 /*
00087 ==================
00088 textureAxisFromPlane
00089 ==================
00090 */
00091 vec3_t  baseaxis[18] =
00092 {
00093 {0,0,1}, {1,0,0}, {0,-1,0},         // floor
00094 {0,0,-1}, {1,0,0}, {0,-1,0},        // ceiling
00095 {1,0,0}, {0,1,0}, {0,0,-1},         // west wall
00096 {-1,0,0}, {0,1,0}, {0,0,-1},        // east wall
00097 {0,1,0}, {1,0,0}, {0,0,-1},         // south wall
00098 {0,-1,0}, {1,0,0}, {0,0,-1}         // north wall
00099 };
00100 
00101 void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv)
00102 {
00103     int     bestaxis;
00104     float   dot,best;
00105     int     i;
00106     
00107     best = 0;
00108     bestaxis = 0;
00109     
00110     for (i=0 ; i<6 ; i++)
00111     {
00112         dot = DotProduct (pln->normal, baseaxis[i*3]);
00113         if (dot > best)
00114         {
00115             best = dot;
00116             bestaxis = i;
00117         }
00118     }
00119     
00120     VectorCopy (baseaxis[bestaxis*3+1], xv);
00121     VectorCopy (baseaxis[bestaxis*3+2], yv);
00122 }
00123 
00124 
00125 
00126 float   lightaxis[3] = {0.6, 0.8, 1.0};
00127 /*
00128 ================
00129 SetShadeForPlane
00130 
00131 Light different planes differently to
00132 improve recognition
00133 ================
00134 */
00135 float SetShadeForPlane (plane_t *p)
00136 {
00137     int     i;
00138     float   f;
00139 
00140     // axial plane
00141     for (i=0 ; i<3 ; i++)
00142         if (fabs(p->normal[i]) > 0.9)
00143         {
00144             f = lightaxis[i];
00145             return f;
00146         }
00147 
00148     // between two axial planes
00149     for (i=0 ; i<3 ; i++)
00150         if (fabs(p->normal[i]) < 0.1)
00151         {
00152             f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2;
00153             return f;
00154         }
00155 
00156     // other
00157     f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3;
00158     return f;
00159 }
00160 
00161 vec3_t  vecs[2];
00162 float   shift[2];
00163 
00164 /*
00165 ================
00166 Face_Alloc
00167 ================
00168 */
00169 face_t *Face_Alloc( void )
00170 {
00171     face_t *f = (face_t*)qmalloc( sizeof( *f ) );
00172     
00173     if (g_qeglobals.bSurfacePropertiesPlugin)
00174         f->pData = static_cast<void *>( g_SurfaceTable.m_pfnTexdefAlloc( f ) );
00175 
00176     return f;
00177 }
00178 
00179 /*
00180 ================
00181 Face_Free
00182 ================
00183 */
00184 void Face_Free( face_t *f )
00185 {
00186     assert( f != 0 );
00187 
00188     if ( f->face_winding )
00189     {
00190         free( f->face_winding );
00191         f->face_winding = 0;
00192     }
00193 
00194     if (g_qeglobals.bSurfacePropertiesPlugin)
00195     {
00196 #ifdef _DEBUG
00197         if ( !f->pData )
00198         {
00199             Sys_Printf("WARNING: unexpected IPluginTexdef is NULL in Face_Free\n");
00200         }
00201         else
00202 #endif
00203         GETPLUGINTEXDEF(f)->DecRef();
00204     }
00205 
00206     f->texdef.~texdef_t();;
00207 
00208     free( f );
00209 }
00210 
00211 /*
00212 ================
00213 Face_Clone
00214 ================
00215 */
00216 face_t  *Face_Clone (face_t *f)
00217 {
00218     face_t  *n;
00219 
00220     n = Face_Alloc();
00221     n->texdef = f->texdef;
00222 
00223     memcpy (n->planepts, f->planepts, sizeof(n->planepts));
00224 
00225     // all other fields are derived, and will be set by Brush_Build
00226     return n;
00227 }
00228 
00229 /*
00230 ================
00231 Face_FullClone
00232 
00233 makes an exact copy of the face
00234 ================
00235 */
00236 face_t  *Face_FullClone (face_t *f)
00237 {
00238     face_t  *n;
00239 
00240     n = Face_Alloc();
00241     n->texdef = f->texdef;
00242     memcpy(n->planepts, f->planepts, sizeof(n->planepts));
00243     memcpy(&n->plane, &f->plane, sizeof(plane_t));
00244     if (f->face_winding)
00245         n->face_winding = Winding_Clone(f->face_winding);
00246     else
00247         n->face_winding = NULL;
00248     n->d_texture = Texture_ForName( n->texdef.name );
00249     return n;
00250 }
00251 
00252 /*
00253 ================
00254 Clamp
00255 ================
00256 */
00257 void Clamp(float& f, int nClamp)
00258 {
00259   float fFrac = f - static_cast<int>(f);
00260   f = static_cast<int>(f) % nClamp;
00261   f += fFrac;
00262 }
00263 
00264 /*
00265 ================
00266 Face_MoveTexture
00267 ================
00268 */
00269 void Face_MoveTexture(face_t *f, vec3_t delta)
00270 {
00271     vec3_t vX, vY;
00272 /*
00273 #ifdef _DEBUG
00274     if (g_PrefsDlg.m_bBrushPrimitMode)
00275         Sys_Printf("Warning : Face_MoveTexture not done in brush primitive mode\n");
00276 #endif
00277 */
00278     if (g_qeglobals.m_bBrushPrimitMode)
00279         Face_MoveTexture_BrushPrimit( f, delta );
00280     else
00281     {
00282         TextureAxisFromPlane(&f->plane, vX, vY);
00283 
00284         vec3_t vDP, vShift;
00285         vDP[0] = DotProduct(delta, vX);
00286         vDP[1] = DotProduct(delta, vY);
00287 
00288         double fAngle = f->texdef.rotate  / 180 * Q_PI;
00289         double c = cos(fAngle);
00290         double s = sin(fAngle);
00291 
00292         vShift[0] = vDP[0] * c - vDP[1] * s;
00293         vShift[1] = vDP[0] * s + vDP[1] * c;
00294 
00295         if (!f->texdef.scale[0])
00296             f->texdef.scale[0] = 1;
00297         if (!f->texdef.scale[1])
00298             f->texdef.scale[1] = 1;
00299 
00300         f->texdef.shift[0] -= vShift[0] / f->texdef.scale[0];
00301         f->texdef.shift[1] -= vShift[1] / f->texdef.scale[1];
00302   
00303         // clamp the shifts
00304         Clamp(f->texdef.shift[0], f->d_texture->width);
00305         Clamp(f->texdef.shift[1], f->d_texture->height);
00306     }
00307 }
00308 
00309 /*
00310 ================
00311 Face_SetColor
00312 ================
00313 */
00314 void Face_SetColor (brush_t *b, face_t *f, float fCurveColor) 
00315 {
00316     float   shade;
00317     qtexture_t *q;
00318 
00319     q = f->d_texture;
00320 
00321     // set shading for face
00322     shade = SetShadeForPlane (&f->plane);
00323     if (g_pParentWnd->GetCamera()->Camera().draw_mode == cd_texture && !b->owner->eclass->fixedsize)
00324     {
00325         //if (b->curveBrush)
00326         //  shade = fCurveColor;
00327         f->d_color[0] = 
00328         f->d_color[1] = 
00329         f->d_color[2] = shade;
00330     }
00331     else
00332     {
00333         f->d_color[0] = shade*q->color[0];
00334         f->d_color[1] = shade*q->color[1];
00335         f->d_color[2] = shade*q->color[2];
00336     }
00337 }
00338 
00339 /*
00340 ================
00341 Face_TextureVectors
00342 TTimo: NOTE: this is never to get called while in brush primitives mode
00343 ================
00344 */
00345 void Face_TextureVectors (face_t *f, float STfromXYZ[2][4])
00346 {
00347     vec3_t      pvecs[2];
00348     int         sv, tv;
00349     float       ang, sinv, cosv;
00350     float       ns, nt;
00351     int         i,j;
00352     qtexture_t *q;
00353     texdef_t    *td;
00354 
00355 #ifdef _DEBUG
00356     //++timo when playing with patches, this sometimes get called and the Warning is displayed
00357     // find some way out ..
00358     if (g_qeglobals.m_bBrushPrimitMode && !g_qeglobals.bNeedConvert)
00359         Sys_Printf("Warning : illegal call of Face_TextureVectors in brush primitive mode\n");
00360 #endif
00361 
00362     td = &f->texdef;
00363     q = f->d_texture;
00364 
00365     memset (STfromXYZ, 0, 8*sizeof(float));
00366 
00367     if (!td->scale[0])
00368         td->scale[0] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1;
00369     if (!td->scale[1])
00370         td->scale[1] = (g_PrefsDlg.m_bHiColorTextures) ? 0.5 : 1;
00371 
00372     // get natural texture axis
00373     TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]);
00374 
00375     // rotate axis
00376     if (td->rotate == 0)
00377         { sinv = 0 ; cosv = 1; }
00378     else if (td->rotate == 90)
00379         { sinv = 1 ; cosv = 0; }
00380     else if (td->rotate == 180)
00381         { sinv = 0 ; cosv = -1; }
00382     else if (td->rotate == 270)
00383         { sinv = -1 ; cosv = 0; }
00384     else
00385     {   
00386         ang = td->rotate / 180 * Q_PI;
00387         sinv = sin(ang);
00388         cosv = cos(ang);
00389     }
00390 
00391     if (pvecs[0][0])
00392         sv = 0;
00393     else if (pvecs[0][1])
00394         sv = 1;
00395     else
00396         sv = 2;
00397                 
00398     if (pvecs[1][0])
00399         tv = 0;
00400     else if (pvecs[1][1])
00401         tv = 1;
00402     else
00403         tv = 2;
00404                     
00405     for (i=0 ; i<2 ; i++) {
00406         ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv];
00407         nt = sinv * pvecs[i][sv] +  cosv * pvecs[i][tv];
00408         STfromXYZ[i][sv] = ns;
00409         STfromXYZ[i][tv] = nt;
00410     }
00411 
00412     // scale
00413     for (i=0 ; i<2 ; i++)
00414         for (j=0 ; j<3 ; j++)
00415             STfromXYZ[i][j] = STfromXYZ[i][j] / td->scale[i];
00416 
00417     // shift
00418     STfromXYZ[0][3] = td->shift[0];
00419     STfromXYZ[1][3] = td->shift[1];
00420 
00421     for (j=0 ; j<4 ; j++) {
00422         STfromXYZ[0][j] /= q->width;
00423         STfromXYZ[1][j] /= q->height;
00424     }
00425 }
00426 
00427 /*
00428 ================
00429 Face_MakePlane
00430 ================
00431 */
00432 void Face_MakePlane (face_t *f)
00433 {
00434     int     j;
00435     vec3_t  t1, t2, t3;
00436 
00437     // convert to a vector / dist plane
00438     for (j=0 ; j<3 ; j++)
00439     {
00440         t1[j] = f->planepts[0][j] - f->planepts[1][j];
00441         t2[j] = f->planepts[2][j] - f->planepts[1][j];
00442         t3[j] = f->planepts[1][j];
00443     }
00444     
00445     CrossProduct(t1,t2, f->plane.normal);
00446     if (VectorCompare (f->plane.normal, vec3_origin))
00447         printf ("WARNING: brush plane with no normal\n");
00448     VectorNormalize (f->plane.normal);
00449     f->plane.dist = DotProduct (t3, f->plane.normal);
00450 }
00451 
00452 /*
00453 ================
00454 EmitTextureCoordinates
00455 ================
00456 */
00457 void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f)
00458 {
00459     float   STfromXYZ[2][4];
00460 
00461     Face_TextureVectors (f,  STfromXYZ);
00462     xyzst[3] = DotProduct (xyzst, STfromXYZ[0]) + STfromXYZ[0][3];
00463     xyzst[4] = DotProduct (xyzst, STfromXYZ[1]) + STfromXYZ[1][3];
00464 }
00465 
00466 //==========================================================================
00467 
00468 /*
00469 ================
00470 Brush_MakeFacePlanes
00471 ================
00472 */
00473 void Brush_MakeFacePlanes (brush_t *b)
00474 {
00475     face_t  *f;
00476 
00477     for (f=b->brush_faces ; f ; f=f->next)
00478     {
00479         Face_MakePlane (f);
00480     }
00481 }
00482 
00483 /*
00484 ================
00485 DrawBrushEntityName
00486 ================
00487 */
00488 void DrawBrushEntityName (brush_t *b)
00489 {
00490     char    *name;
00491     //float a, s, c;
00492     //vec3_t    mid;
00493     //int       i;
00494 
00495     if (!b->owner)
00496         return;     // during contruction
00497 
00498     if (b->owner == world_entity)
00499         return;
00500 
00501     if (b != b->owner->brushes.onext)
00502         return; // not key brush
00503 
00504 // MERGEME
00505 #if 0
00506     if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES))
00507     {
00508         // draw the angle pointer
00509         a = FloatForKey (b->owner, "angle");
00510         if (a)
00511         {
00512             s = sin (a/180*Q_PI);
00513             c = cos (a/180*Q_PI);
00514             for (i=0 ; i<3 ; i++)
00515                 mid[i] = (b->mins[i] + b->maxs[i])*0.5; 
00516 
00517             qglBegin (GL_LINE_STRIP);
00518             qglVertex3fv (mid);
00519             mid[0] += c*8;
00520             mid[1] += s*8;
00521             mid[2] += s*8;
00522             qglVertex3fv (mid);
00523             mid[0] -= c*4;
00524             mid[1] -= s*4;
00525             mid[2] -= s*4;
00526             mid[0] -= s*4;
00527             mid[1] += c*4;
00528             mid[2] += c*4;
00529             qglVertex3fv (mid);
00530             mid[0] += c*4;
00531             mid[1] += s*4;
00532             mid[2] += s*4;
00533             mid[0] += s*4;
00534             mid[1] -= c*4;
00535             mid[2] -= c*4;
00536             qglVertex3fv (mid);
00537             mid[0] -= c*4;
00538             mid[1] -= s*4;
00539             mid[2] -= s*4;
00540             mid[0] += s*4;
00541             mid[1] -= c*4;
00542             mid[2] -= c*4;
00543             qglVertex3fv (mid);
00544             qglEnd ();
00545         }
00546     }
00547 #endif
00548 
00549     if (g_qeglobals.d_savedinfo.show_names)
00550     {
00551         name = ValueForKey (b->owner, "classname");
00552         qglRasterPos3f (b->mins[0]+4, b->mins[1]+4, b->mins[2]+4);
00553         qglCallLists (strlen(name), GL_UNSIGNED_BYTE, name);
00554     }
00555 }
00556 
00557 /*
00558 =================
00559 Brush_MakeFaceWinding
00560 
00561 returns the visible polygon on a face
00562 =================
00563 */
00564 winding_t *Brush_MakeFaceWinding (brush_t *b, face_t *face)
00565 {
00566     winding_t   *w;
00567     face_t      *clip;
00568     plane_t         plane;
00569     qboolean        past;
00570 
00571     // get a poly that covers an effectively infinite area
00572     w = Winding_BaseForPlane (&face->plane);
00573 
00574     // chop the poly by all of the other faces
00575     past = false;
00576     for (clip = b->brush_faces ; clip && w ; clip=clip->next)
00577     {
00578         if (clip == face)
00579         {
00580             past = true;
00581             continue;
00582         }
00583         if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999
00584             && fabs(face->plane.dist - clip->plane.dist) < 0.01 )
00585         {   // identical plane, use the later one
00586             if (past)
00587             {
00588                 free (w);
00589                 return NULL;
00590             }
00591             continue;
00592         }
00593 
00594         // flip the plane, because we want to keep the back side
00595         VectorSubtract (vec3_origin,clip->plane.normal, plane.normal);
00596         plane.dist = -clip->plane.dist;
00597         
00598         w = Winding_Clip (w, &plane, false);
00599         if (!w)
00600             return w;
00601     }
00602     
00603     if (w->numpoints < 3)
00604     {
00605         free(w);
00606         w = NULL;
00607     }
00608 
00609     if (!w)
00610         printf ("unused plane\n");
00611 
00612     return w;
00613 }
00614 
00615 /*
00616 =================
00617 Brush_SnapPlanepts
00618 =================
00619 */
00620 void Brush_SnapPlanepts (brush_t *b)
00621 {
00622     int     i, j;
00623     face_t  *f;
00624 
00625   if (g_PrefsDlg.m_bNoClamp)
00626     return;
00627 
00628     for (f=b->brush_faces ; f; f=f->next)
00629         for (i=0 ; i<3 ; i++)
00630             for (j=0 ; j<3 ; j++)
00631                 f->planepts[i][j] = floor (f->planepts[i][j] + 0.5);
00632 }
00633     
00634 /*
00635 ** Brush_Build
00636 **
00637 ** Builds a brush rendering data and also sets the min/max bounds
00638 */
00639 // TTimo
00640 // added a bConvert flag to convert between old and new brush texture formats
00641 // TTimo
00642 // brush grouping: update the group treeview if necessary
00643 void Brush_Build( brush_t *b, bool bSnap, bool bMarkMap, bool bConvert )
00644 {
00645     bool        bLocalConvert;
00646 
00647 #ifdef _DEBUG
00648     if (!g_qeglobals.m_bBrushPrimitMode && bConvert)
00649         Sys_Printf("Warning : conversion from brush primitive to old brush format not implemented\n");
00650 #endif
00651 
00652     // if bConvert is set and g_qeglobals.bNeedConvert is not, that just means we need convert for this brush only
00653     if (bConvert && !g_qeglobals.bNeedConvert)
00654     {
00655         bLocalConvert = true;
00656         g_qeglobals.bNeedConvert = true;
00657     }
00658 
00659     /*
00660     ** build the windings and generate the bounding box
00661     */
00662     Brush_BuildWindings(b, bSnap);
00663 
00664     Patch_BuildPoints (b);
00665 
00666     /*
00667     ** move the points and edges if in select mode
00668     */
00669     if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge)
00670         SetupVertexSelection ();
00671 
00672     if (b->itemOwner == NULL)
00673       Group_AddToProperGroup(b);
00674 
00675     if (bMarkMap)
00676     {
00677         Sys_MarkMapModified();
00678     }
00679 
00680     if (bLocalConvert)
00681         g_qeglobals.bNeedConvert = false;
00682 }
00683 
00684 /*
00685 ==============
00686 Brush_SplitBrushByFace
00687 
00688 The incoming brush is NOT freed.
00689 The incoming face is NOT left referenced.
00690 ==============
00691 */
00692 void Brush_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back)
00693 {
00694     brush_t *b;
00695     face_t  *nf;
00696     vec3_t  temp;
00697 
00698     b = Brush_Clone (in);
00699     nf = Face_Clone (f);
00700 
00701     nf->texdef = b->brush_faces->texdef;
00702     nf->next = b->brush_faces;
00703     b->brush_faces = nf;
00704 
00705     Brush_Build( b );
00706     Brush_RemoveEmptyFaces ( b );
00707     if ( !b->brush_faces )
00708     {   // completely clipped away
00709         Brush_Free (b);
00710         *back = NULL;
00711     }
00712     else
00713     {
00714         Entity_LinkBrush (in->owner, b);
00715         *back = b;
00716     }
00717 
00718     b = Brush_Clone (in);
00719     nf = Face_Clone (f);
00720     // swap the plane winding
00721     VectorCopy (nf->planepts[0], temp);
00722     VectorCopy (nf->planepts[1], nf->planepts[0]);
00723     VectorCopy (temp, nf->planepts[1]);
00724 
00725     nf->texdef = b->brush_faces->texdef;
00726     nf->next = b->brush_faces;
00727     b->brush_faces = nf;
00728 
00729     Brush_Build( b );
00730     Brush_RemoveEmptyFaces ( b );
00731     if ( !b->brush_faces )
00732     {   // completely clipped away
00733         Brush_Free (b);
00734         *front = NULL;
00735     }
00736     else
00737     {
00738         Entity_LinkBrush (in->owner, b);
00739         *front = b;
00740     }
00741 }
00742 
00743 /*
00744 =================
00745 Brush_BestSplitFace
00746 
00747 returns the best face to split the brush with.
00748 return NULL if the brush is convex
00749 =================
00750 */
00751 face_t *Brush_BestSplitFace(brush_t *b)
00752 {
00753     face_t *face, *f, *bestface;
00754     winding_t *front, *back;
00755     int splits, tinywindings, value, bestvalue;
00756 
00757     bestvalue = 999999;
00758     bestface = NULL;
00759     for (face = b->brush_faces; face; face = face->next)
00760     {
00761         splits = 0;
00762         tinywindings = 0;
00763         for (f = b->brush_faces; f; f = f->next)
00764         {
00765             if (f == face) continue;
00766             //
00767             Winding_SplitEpsilon(f->face_winding, face->plane.normal, face->plane.dist, 0.1, &front, &back);
00768 
00769             if (!front)
00770             {
00771                 Winding_Free(back);
00772             }
00773             else if (!back)
00774             {
00775                 Winding_Free(front);
00776             }
00777             else
00778             {
00779                 splits++;
00780                 if (Winding_IsTiny(front)) tinywindings++;
00781                 if (Winding_IsTiny(back)) tinywindings++;
00782             }
00783         }
00784         if (splits)
00785         {
00786             value = splits + 50 * tinywindings;
00787             if (value < bestvalue)
00788             {
00789                 bestvalue = value;
00790                 bestface = face;
00791             }
00792         }
00793     }
00794     return bestface;
00795 }
00796 
00797 /*
00798 =================
00799 Brush_MakeConvexBrushes
00800 
00801 MrE FIXME: this doesn't work because the old
00802            Brush_SplitBrushByFace is used
00803 Turns the brush into a minimal number of convex brushes.
00804 If the input brush is convex then it will be returned.
00805 Otherwise the input brush will be freed.
00806 NOTE: the input brush should have windings for the faces.
00807 =================
00808 */
00809 brush_t *Brush_MakeConvexBrushes(brush_t *b)
00810 {
00811     brush_t *front, *back, *end;
00812     face_t *face;
00813 
00814     b->next = NULL;
00815     face = Brush_BestSplitFace(b);
00816     if (!face) return b;
00817     Brush_SplitBrushByFace(b, face, &front, &back);
00818     //this should never happen
00819     if (!front && !back) return b;
00820     Brush_Free(b);
00821     if (!front)
00822         return Brush_MakeConvexBrushes(back);
00823     b = Brush_MakeConvexBrushes(front);
00824     if (back)
00825     {
00826         for (end = b; end->next; end = end->next);
00827         end->next = Brush_MakeConvexBrushes(back);
00828     }
00829     return b;
00830 }
00831 
00832 /*
00833 =================
00834 Brush_Convex
00835 =================
00836 */
00837 int Brush_Convex(brush_t *b)
00838 {
00839     face_t *face1, *face2;
00840 
00841     for (face1 = b->brush_faces; face1; face1 = face1->next)
00842     {
00843         if (!face1->face_winding) continue;
00844         for (face2 = b->brush_faces; face2; face2 = face2->next)
00845         {
00846             if (face1 == face2) continue;
00847             if (!face2->face_winding) continue;
00848             if (Winding_PlanesConcave(face1->face_winding, face2->face_winding,
00849                                         face1->plane.normal, face2->plane.normal,
00850                                         face1->plane.dist, face2->plane.dist))
00851             {
00852                 return false;
00853             }
00854         }
00855     }
00856     return true;
00857 }
00858 
00859 /*
00860 =================
00861 Brush_MoveVertexes_old1
00862 
00863 - The input brush must have face windings.
00864 - The input brush must be a brush with faces that do not intersect.
00865 - The input brush does not have to be convex.
00866 - The vertex will not be moved if the movement either causes the
00867   brush to have faces that intersect or causes the brush to be
00868   flipped inside out.
00869   (For instance a tetrahedron can easily be flipped inside out
00870   without having faces that intersect.)
00871 - The created brush does not have to be convex.
00872 - Returns true if the vertex movement is performed.
00873 =================
00874 */
00875 
00876 #define MAX_MOVE_FACES      64
00877 #define INTERSECT_EPSILON   0.1
00878 #define POINT_EPSILON       0.3
00879 
00880 int Brush_MoveVertex_old1(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
00881 {
00882     face_t *f, *face, *newface, *lastface, *nextface;
00883     face_t *movefaces[MAX_MOVE_FACES];
00884     int movefacepoints[MAX_MOVE_FACES];
00885     winding_t *w, tmpw;
00886     int i, j, k, nummovefaces, result;
00887     float dot;
00888 
00889     result = false;
00890     //
00891     tmpw.numpoints = 3;
00892     tmpw.maxpoints = 3;
00893     VectorAdd(vertex, delta, end);
00894     //snap or not?
00895     if (bSnap)
00896         for (i = 0; i < 3; i++)
00897             end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
00898     //chop off triangles from all brush faces that use the to be moved vertex
00899     //store pointers to these chopped off triangles in movefaces[]
00900     nummovefaces = 0;
00901     for (face = b->brush_faces; face; face = face->next)
00902     {
00903         w = face->face_winding;
00904         if (!w) continue;
00905         for (i = 0; i < w->numpoints; i++)
00906         {
00907             if (Point_Equal(w->points[i], vertex, POINT_EPSILON))
00908             {
00909                 if (face->face_winding->numpoints <= 3)
00910                 {
00911                     movefacepoints[nummovefaces] = i;
00912                     movefaces[nummovefaces++] = face;
00913                     break;
00914                 }
00915                 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
00916                 //if the end point is in front of the face plane
00917                 if (dot > 0.1)
00918                 {
00919                     //fanout triangle subdivision
00920                     for (k = i; k < i + w->numpoints-3; k++)
00921                     {
00922                         VectorCopy(w->points[i], tmpw.points[0]);
00923                         VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
00924                         VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
00925                         //
00926                         newface = Face_Clone(face);
00927                         //get the original
00928                         for (f = face; f->original; f = f->original) ;
00929                         newface->original = f;
00930                         //store the new winding
00931                         if (newface->face_winding) Winding_Free(newface->face_winding);
00932                         newface->face_winding = Winding_Clone(&tmpw);
00933                         //get the texture
00934                         newface->d_texture = Texture_ForName( newface->texdef.name );
00935                         //add the face to the brush
00936                         newface->next = b->brush_faces;
00937                         b->brush_faces = newface;
00938                         //add this new triangle to the move faces
00939                         movefacepoints[nummovefaces] = 0;
00940                         movefaces[nummovefaces++] = newface;
00941                     }
00942                     //give the original face a new winding
00943                     VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
00944                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
00945                     VectorCopy(w->points[i], tmpw.points[2]);
00946                     Winding_Free(face->face_winding);
00947                     face->face_winding = Winding_Clone(&tmpw);
00948                     //add the original face to the move faces
00949                     movefacepoints[nummovefaces] = 2;
00950                     movefaces[nummovefaces++] = face;
00951                 }
00952                 else
00953                 {
00954                     //chop a triangle off the face
00955                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
00956                     VectorCopy(w->points[i], tmpw.points[1]);
00957                     VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
00958                     //remove the point from the face winding
00959                     Winding_RemovePoint(w, i);
00960                     //get texture crap right
00961                     Face_SetColor(b, face, 1.0);
00962                     for (j = 0; j < w->numpoints; j++)
00963                         EmitTextureCoordinates(w->points[j], face->d_texture, face);
00964                     //make a triangle face
00965                     newface = Face_Clone(face);
00966                     //get the original
00967                     for (f = face; f->original; f = f->original) ;
00968                     newface->original = f;
00969                     //store the new winding
00970                     if (newface->face_winding) Winding_Free(newface->face_winding);
00971                     newface->face_winding = Winding_Clone(&tmpw);
00972                     //get the texture
00973                     newface->d_texture = Texture_ForName( newface->texdef.name );
00974                     //add the face to the brush
00975                     newface->next = b->brush_faces;
00976                     b->brush_faces = newface;
00977                     //
00978                     movefacepoints[nummovefaces] = 1;
00979                     movefaces[nummovefaces++] = newface;
00980                 }
00981                 break;
00982             }
00983         }
00984     }
00985     //now movefaces contains pointers to triangle faces that
00986     //contain the to be moved vertex
00987 
00988     //check if the move is valid
00989     int l;
00990     vec3_t p1, p2;
00991     winding_t *w2;
00992     plane_t plane;
00993 
00994     face = NULL;
00995     VectorCopy(vertex, tmpw.points[1]);
00996     VectorCopy(end, tmpw.points[2]);
00997     for (face = b->brush_faces; face; face = face->next)
00998     {
00999         for (i = 0; i < nummovefaces; i++)
01000         {
01001             if (face == movefaces[i])
01002                 break;
01003         }
01004         if (i < nummovefaces)
01005             continue;
01006         //the delta vector may not intersect with any of the not move faces
01007         if (Winding_VectorIntersect(face->face_winding, &face->plane, vertex, end, INTERSECT_EPSILON))
01008             break;
01009         //if the end point of the to be moved vertex is near this not move face
01010         if (abs(DotProduct(face->plane.normal, end) - face->plane.dist) < 0.5)
01011         {
01012             //the end point may not be inside or very close to the not move face winding
01013             if (Winding_PointInside(face->face_winding, &face->plane, end, 0.5))
01014                 break;
01015         }
01016         for (i = 0; i < nummovefaces; i++)
01017         {
01018             w = movefaces[i]->face_winding;
01019             j = movefacepoints[i];
01020             for (k = -1; k <= 1; k += 2)
01021             {
01022                 //check if the new edge will not intersect with the not move face
01023                 VectorCopy(w->points[(j + k + w->numpoints) % w->numpoints], tmpw.points[0]);
01024                 if (Winding_VectorIntersect(face->face_winding, &face->plane, tmpw.points[0], end, INTERSECT_EPSILON))
01025                 {
01026                     //ok the new edge instersects with the not move face
01027                     //we can't perform the vertex movement
01028                     //break;
01029                 }
01030                 //check if the not move face intersects the "movement winding"
01031                 Winding_Plane(&tmpw, plane.normal, &plane.dist);
01032                 w2 = face->face_winding;
01033                 for (l = 0; l < w2->numpoints; l++)
01034                 {
01035                     VectorCopy(w2->points[l], p1);
01036                     if (Point_Equal(p1, tmpw.points[0], POINT_EPSILON)) continue;
01037                     VectorCopy(w2->points[(l+1) % w2->numpoints], p2);
01038                     if (Point_Equal(p2, tmpw.points[0], POINT_EPSILON)) continue;
01039                     if (Winding_VectorIntersect(&tmpw, &plane, p1, p2, INTERSECT_EPSILON))
01040                         break;
01041                 }
01042                 if (l < w2->numpoints)
01043                 {
01044                     //ok this not move face intersects the "movement winding"
01045                     //we can't perform the vertex movement
01046                     break;
01047                 }
01048             }
01049             if (k <= 1) break;
01050         }
01051         if (i < nummovefaces)
01052             break;
01053     }
01054     if (!face)
01055     {
01056         //ok the move was valid
01057         //now move all the vertexes of the movefaces
01058         for (i = 0; i < nummovefaces; i++)
01059         {
01060             VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]);
01061             //create new face plane
01062             for (j = 0; j < 3; j++)
01063             {
01064                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01065             }
01066             Face_MakePlane(movefaces[i]);
01067         }
01068         result = true;
01069     }
01070     //get texture crap right
01071     for (i = 0; i < nummovefaces; i++)
01072     {
01073         Face_SetColor(b, movefaces[i], 1.0);
01074         for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
01075             EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
01076     }
01077 
01078     //now try to merge faces with their original faces
01079     lastface = NULL;
01080     for (face = b->brush_faces; face; face = nextface)
01081     {
01082         nextface = face->next;
01083         if (!face->original)
01084         {
01085             lastface = face;
01086             continue;
01087         }
01088         if (!Plane_Equal(&face->plane, &face->original->plane, false))
01089         {
01090             lastface = face;
01091             continue;
01092         }
01093         w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
01094         if (!w)
01095         {
01096             lastface = face;
01097             continue;
01098         }
01099         Winding_Free(face->original->face_winding);
01100         face->original->face_winding = w;
01101         //get texture crap right
01102         Face_SetColor(b, face->original, 1.0);
01103         for (j = 0; j < face->original->face_winding->numpoints; j++)
01104             EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
01105         //remove the face that was merged with the original
01106         if (lastface) lastface->next = face->next;
01107         else b->brush_faces = face->next;
01108         Face_Free(face);
01109     }
01110     return result;
01111 }
01112 
01113 /*
01114 =================
01115 Brush_MoveVertexes_old2
01116 
01117 - The input brush must be convex
01118 - The input brush must have face windings.
01119 - The output brush will be convex.
01120 - Returns true if the vertex movement is performed.
01121 =================
01122 */
01123 
01124 #define MAX_MOVE_FACES      64
01125 #define INTERSECT_EPSILON   0.1
01126 #define POINT_EPSILON       0.3
01127 
01128 int Brush_MoveVertex_old2(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
01129 {
01130     face_t *f, *face, *newface, *lastface, *nextface;
01131     face_t *movefaces[MAX_MOVE_FACES];
01132     int movefacepoints[MAX_MOVE_FACES];
01133     winding_t *w, tmpw;
01134     int i, j, k, nummovefaces, result;
01135     float dot;
01136 
01137     result = true;
01138     //
01139     tmpw.numpoints = 3;
01140     tmpw.maxpoints = 3;
01141     VectorAdd(vertex, delta, end);
01142     //snap or not?
01143     if (bSnap)
01144         for (i = 0; i < 3; i++)
01145             end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
01146     //chop off triangles from all brush faces that use the to be moved vertex
01147     //store pointers to these chopped off triangles in movefaces[]
01148     nummovefaces = 0;
01149     for (face = b->brush_faces; face; face = face->next)
01150     {
01151         w = face->face_winding;
01152         if (!w) continue;
01153         for (i = 0; i < w->numpoints; i++)
01154         {
01155             if (Point_Equal(w->points[i], vertex, POINT_EPSILON))
01156             {
01157                 if (face->face_winding->numpoints <= 3)
01158                 {
01159                     movefacepoints[nummovefaces] = i;
01160                     movefaces[nummovefaces++] = face;
01161                     break;
01162                 }
01163                 dot = DotProduct(end, face->plane.normal) - face->plane.dist;
01164                 //if the end point is in front of the face plane
01165                 if (dot > 0.1)
01166                 {
01167                     //fanout triangle subdivision
01168                     for (k = i; k < i + w->numpoints-3; k++)
01169                     {
01170                         VectorCopy(w->points[i], tmpw.points[0]);
01171                         VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
01172                         VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
01173                         //
01174                         newface = Face_Clone(face);
01175                         //get the original
01176                         for (f = face; f->original; f = f->original) ;
01177                         newface->original = f;
01178                         //store the new winding
01179                         if (newface->face_winding) Winding_Free(newface->face_winding);
01180                         newface->face_winding = Winding_Clone(&tmpw);
01181                         //get the texture
01182                         newface->d_texture = Texture_ForName( newface->texdef.name );
01183                         //add the face to the brush
01184                         newface->next = b->brush_faces;
01185                         b->brush_faces = newface;
01186                         //add this new triangle to the move faces
01187                         movefacepoints[nummovefaces] = 0;
01188                         movefaces[nummovefaces++] = newface;
01189                     }
01190                     //give the original face a new winding
01191                     VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
01192                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
01193                     VectorCopy(w->points[i], tmpw.points[2]);
01194                     Winding_Free(face->face_winding);
01195                     face->face_winding = Winding_Clone(&tmpw);
01196                     //add the original face to the move faces
01197                     movefacepoints[nummovefaces] = 2;
01198                     movefaces[nummovefaces++] = face;
01199                 }
01200                 else
01201                 {
01202                     //chop a triangle off the face
01203                     VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
01204                     VectorCopy(w->points[i], tmpw.points[1]);
01205                     VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
01206                     //remove the point from the face winding
01207                     Winding_RemovePoint(w, i);
01208                     //get texture crap right
01209                     Face_SetColor(b, face, 1.0);
01210                     for (j = 0; j < w->numpoints; j++)
01211                         EmitTextureCoordinates(w->points[j], face->d_texture, face);
01212                     //make a triangle face
01213                     newface = Face_Clone(face);
01214                     //get the original
01215                     for (f = face; f->original; f = f->original) ;
01216                     newface->original = f;
01217                     //store the new winding
01218                     if (newface->face_winding) Winding_Free(newface->face_winding);
01219                     newface->face_winding = Winding_Clone(&tmpw);
01220                     //get the texture
01221                     newface->d_texture = Texture_ForName( newface->texdef.name );
01222                     //add the face to the brush
01223                     newface->next = b->brush_faces;
01224                     b->brush_faces = newface;
01225                     //
01226                     movefacepoints[nummovefaces] = 1;
01227                     movefaces[nummovefaces++] = newface;
01228                 }
01229                 break;
01230             }
01231         }
01232     }
01233     //now movefaces contains pointers to triangle faces that
01234     //contain the to be moved vertex
01235 
01236     //move the vertex
01237     for (i = 0; i < nummovefaces; i++)
01238     {
01239         //move vertex to end position
01240         VectorCopy(end, movefaces[i]->face_winding->points[movefacepoints[i]]);
01241         //create new face plane
01242         for (j = 0; j < 3; j++)
01243         {
01244             VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01245         }
01246         Face_MakePlane(movefaces[i]);
01247     }
01248     //if the brush is no longer convex
01249     if (!Brush_Convex(b))
01250     {
01251         for (i = 0; i < nummovefaces; i++)
01252         {
01253             //move the vertex back to the initial position
01254             VectorCopy(vertex, movefaces[i]->face_winding->points[movefacepoints[i]]);
01255             //create new face plane
01256             for (j = 0; j < 3; j++)
01257             {
01258                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01259             }
01260             Face_MakePlane(movefaces[i]);
01261         }
01262         result = false;
01263     }
01264     //get texture crap right
01265     for (i = 0; i < nummovefaces; i++)
01266     {
01267         Face_SetColor(b, movefaces[i], 1.0);
01268         for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
01269             EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
01270     }
01271 
01272     //now try to merge faces with their original faces
01273     lastface = NULL;
01274     for (face = b->brush_faces; face; face = nextface)
01275     {
01276         nextface = face->next;
01277         if (!face->original)
01278         {
01279             lastface = face;
01280             continue;
01281         }
01282         if (!Plane_Equal(&face->plane, &face->original->plane, false))
01283         {
01284             lastface = face;
01285             continue;
01286         }
01287         w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
01288         if (!w)
01289         {
01290             lastface = face;
01291             continue;
01292         }
01293         Winding_Free(face->original->face_winding);
01294         face->original->face_winding = w;
01295         //get texture crap right
01296         Face_SetColor(b, face->original, 1.0);
01297         for (j = 0; j < face->original->face_winding->numpoints; j++)
01298             EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
01299         //remove the face that was merged with the original
01300         if (lastface) lastface->next = face->next;
01301         else b->brush_faces = face->next;
01302         Face_Free(face);
01303     }
01304     return result;
01305 }
01306 
01307 /*
01308 =================
01309 Brush_MoveVertexes
01310 
01311 - The input brush must be convex
01312 - The input brush must have face windings.
01313 - The output brush will be convex.
01314 - Returns true if the WHOLE vertex movement is performed.
01315 =================
01316 */
01317 
01318 #define MAX_MOVE_FACES      64
01319 
01320 int Brush_MoveVertex(brush_t *b, vec3_t vertex, vec3_t delta, vec3_t end, bool bSnap)
01321 {
01322     face_t *f, *face, *newface, *lastface, *nextface;
01323     face_t *movefaces[MAX_MOVE_FACES];
01324     int movefacepoints[MAX_MOVE_FACES];
01325     winding_t *w, tmpw;
01326     vec3_t start, mid;
01327     plane_t plane;
01328     int i, j, k, nummovefaces, result, done;
01329     float dot, front, back, frac, smallestfrac;
01330 
01331     result = true;
01332     //
01333     tmpw.numpoints = 3;
01334     tmpw.maxpoints = 3;
01335     VectorCopy(vertex, start);
01336     VectorAdd(vertex, delta, end);
01337     //snap or not?
01338     if (bSnap)
01339         for (i = 0; i < 3; i++)
01340             end[i] = floor(end[i] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
01341     //
01342     VectorCopy(end, mid);
01343     //if the start and end are the same
01344     if (Point_Equal(start, end, 0.3)) return false;
01345     //the end point may not be the same as another vertex
01346     for (face = b->brush_faces; face; face = face->next)
01347     {
01348         w = face->face_winding;
01349         if (!w) continue;
01350         for (i = 0; i < w->numpoints; i++)
01351         {
01352             if (Point_Equal(w->points[i], end, 0.3))
01353             {
01354                 VectorCopy(vertex, end);
01355                 return false;
01356             }
01357         }
01358     }
01359     //
01360     done = false;
01361     while(!done)
01362     {
01363         //chop off triangles from all brush faces that use the to be moved vertex
01364         //store pointers to these chopped off triangles in movefaces[]
01365         nummovefaces = 0;
01366         for (face = b->brush_faces; face; face = face->next)
01367         {
01368             w = face->face_winding;
01369             if (!w) continue;
01370             for (i = 0; i < w->numpoints; i++)
01371             {
01372                 if (Point_Equal(w->points[i], start, 0.2))
01373                 {
01374                     if (face->face_winding->numpoints <= 3)
01375                     {
01376                         movefacepoints[nummovefaces] = i;
01377                         movefaces[nummovefaces++] = face;
01378                         break;
01379                     }
01380                     dot = DotProduct(end, face->plane.normal) - face->plane.dist;
01381                     //if the end point is in front of the face plane
01382                     if (dot > 0.1)
01383                     {
01384                         //fanout triangle subdivision
01385                         for (k = i; k < i + w->numpoints-3; k++)
01386                         {
01387                             VectorCopy(w->points[i], tmpw.points[0]);
01388                             VectorCopy(w->points[(k+1) % w->numpoints], tmpw.points[1]);
01389                             VectorCopy(w->points[(k+2) % w->numpoints], tmpw.points[2]);
01390                             //
01391                             newface = Face_Clone(face);
01392                             //get the original
01393                             for (f = face; f->original; f = f->original) ;
01394                             newface->original = f;
01395                             //store the new winding
01396                             if (newface->face_winding) Winding_Free(newface->face_winding);
01397                             newface->face_winding = Winding_Clone(&tmpw);
01398                             //get the texture
01399                             newface->d_texture = Texture_ForName( newface->texdef.name );
01400                             //add the face to the brush
01401                             newface->next = b->brush_faces;
01402                             b->brush_faces = newface;
01403                             //add this new triangle to the move faces
01404                             movefacepoints[nummovefaces] = 0;
01405                             movefaces[nummovefaces++] = newface;
01406                         }
01407                         //give the original face a new winding
01408                         VectorCopy(w->points[(i-2+w->numpoints) % w->numpoints], tmpw.points[0]);
01409                         VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[1]);
01410                         VectorCopy(w->points[i], tmpw.points[2]);
01411                         Winding_Free(face->face_winding);
01412                         face->face_winding = Winding_Clone(&tmpw);
01413                         //add the original face to the move faces
01414                         movefacepoints[nummovefaces] = 2;
01415                         movefaces[nummovefaces++] = face;
01416                     }
01417                     else
01418                     {
01419                         //chop a triangle off the face
01420                         VectorCopy(w->points[(i-1+w->numpoints) % w->numpoints], tmpw.points[0]);
01421                         VectorCopy(w->points[i], tmpw.points[1]);
01422                         VectorCopy(w->points[(i+1) % w->numpoints], tmpw.points[2]);
01423                         //remove the point from the face winding
01424                         Winding_RemovePoint(w, i);
01425                         //get texture crap right
01426                         Face_SetColor(b, face, 1.0);
01427                         for (j = 0; j < w->numpoints; j++)
01428                             EmitTextureCoordinates(w->points[j], face->d_texture, face);
01429                         //make a triangle face
01430                         newface = Face_Clone(face);
01431                         //get the original
01432                         for (f = face; f->original; f = f->original) ;
01433                         newface->original = f;
01434                         //store the new winding
01435                         if (newface->face_winding) Winding_Free(newface->face_winding);
01436                         newface->face_winding = Winding_Clone(&tmpw);
01437                         //get the texture
01438                         newface->d_texture = Texture_ForName( newface->texdef.name );
01439                         //add the face to the brush
01440                         newface->next = b->brush_faces;
01441                         b->brush_faces = newface;
01442                         //
01443                         movefacepoints[nummovefaces] = 1;
01444                         movefaces[nummovefaces++] = newface;
01445                     }
01446                     break;
01447                 }
01448             }
01449         }
01450         //now movefaces contains pointers to triangle faces that
01451         //contain the to be moved vertex
01452         //
01453         done = true;
01454         VectorCopy(end, mid);
01455         smallestfrac = 1;
01456         for (face = b->brush_faces; face; face = face->next)
01457         {
01458             //check if there is a move face that has this face as the original
01459             for (i = 0; i < nummovefaces; i++)
01460             {
01461                 if (movefaces[i]->original == face) break;
01462             }
01463             if (i >= nummovefaces) continue;
01464             //check if the original is not a move face itself
01465             for (j = 0; j < nummovefaces; j++)
01466             {
01467                 if (face == movefaces[j]) break;
01468             }
01469             //if the original is not a move face itself
01470             if (j >= nummovefaces)
01471             {
01472                 memcpy(&plane, &movefaces[i]->original->plane, sizeof(plane_t));
01473             }
01474             else
01475             {
01476                 k = movefacepoints[j];
01477                 w = movefaces[j]->face_winding;
01478                 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[0]);
01479                 VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[1]);
01480                 //
01481                 k = movefacepoints[i];
01482                 w = movefaces[i]->face_winding;
01483                 VectorCopy(w->points[(k+1)%w->numpoints], tmpw.points[2]);
01484                 if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
01485                 {
01486                     VectorCopy(w->points[(k+2)%w->numpoints], tmpw.points[2]);
01487                     if (!Plane_FromPoints(tmpw.points[0], tmpw.points[1], tmpw.points[2], &plane))
01488                         //this should never happen otherwise the face merge did a crappy job a previous pass
01489                         continue;
01490                 }
01491             }
01492             //now we've got the plane to check agains
01493             front = DotProduct(start, plane.normal) - plane.dist;
01494             back = DotProduct(end, plane.normal) - plane.dist;
01495             //if the whole move is at one side of the plane
01496             if (front < 0.01 && back < 0.01) continue;
01497             if (front > -0.01 && back > -0.01) continue;
01498             //if there's no movement orthogonal to this plane at all
01499             if (fabs(front-back) < 0.001) continue;
01500             //ok first only move till the plane is hit
01501             frac = front/(front-back);
01502             if (frac < smallestfrac)
01503             {
01504                 mid[0] = start[0] + (end[0] - start[0]) * frac;
01505                 mid[1] = start[1] + (end[1] - start[1]) * frac;
01506                 mid[2] = start[2] + (end[2] - start[2]) * frac;
01507                 smallestfrac = frac;
01508             }
01509             //
01510             done = false;
01511         }
01512 
01513         //move the vertex
01514         for (i = 0; i < nummovefaces; i++)
01515         {
01516             //move vertex to end position
01517             VectorCopy(mid, movefaces[i]->face_winding->points[movefacepoints[i]]);
01518             //create new face plane
01519             for (j = 0; j < 3; j++)
01520             {
01521                 VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01522             }
01523             Face_MakePlane(movefaces[i]);
01524             if (VectorLength(movefaces[i]->plane.normal) < 0.1)
01525                 result = false;
01526         }
01527         //if the brush is no longer convex
01528         if (!result || !Brush_Convex(b))
01529         {
01530             for (i = 0; i < nummovefaces; i++)
01531             {
01532                 //move the vertex back to the initial position
01533                 VectorCopy(start, movefaces[i]->face_winding->points[movefacepoints[i]]);
01534                 //create new face plane
01535                 for (j = 0; j < 3; j++)
01536                 {
01537                     VectorCopy(movefaces[i]->face_winding->points[j], movefaces[i]->planepts[j]);
01538                 }
01539                 Face_MakePlane(movefaces[i]);
01540             }
01541             result = false;
01542             VectorCopy(start, end);
01543             done = true;
01544         }
01545         else
01546         {
01547             VectorCopy(mid, start);
01548         }
01549         //get texture crap right
01550         for (i = 0; i < nummovefaces; i++)
01551         {
01552             Face_SetColor(b, movefaces[i], 1.0);
01553             for (j = 0; j < movefaces[i]->face_winding->numpoints; j++)
01554                 EmitTextureCoordinates(movefaces[i]->face_winding->points[j], movefaces[i]->d_texture, movefaces[i]);
01555         }
01556 
01557         //now try to merge faces with their original faces
01558         lastface = NULL;
01559         for (face = b->brush_faces; face; face = nextface)
01560         {
01561             nextface = face->next;
01562             if (!face->original)
01563             {
01564                 lastface = face;
01565                 continue;
01566             }
01567             if (!Plane_Equal(&face->plane, &face->original->plane, false))
01568             {
01569                 lastface = face;
01570                 continue;
01571             }
01572             w = Winding_TryMerge(face->face_winding, face->original->face_winding, face->plane.normal, true);
01573             if (!w)
01574             {
01575                 lastface = face;
01576                 continue;
01577             }
01578             Winding_Free(face->original->face_winding);
01579             face->original->face_winding = w;
01580             //get texture crap right
01581             Face_SetColor(b, face->original, 1.0);
01582             for (j = 0; j < face->original->face_winding->numpoints; j++)
01583                 EmitTextureCoordinates(face->original->face_winding->points[j], face->original->d_texture, face->original);
01584             //remove the face that was merged with the original
01585             if (lastface) lastface->next = face->next;
01586             else b->brush_faces = face->next;
01587             Face_Free(face);
01588         }
01589     }
01590     return result;
01591 }
01592 
01593 /*
01594 =================
01595 Brush_InsertVertexBetween
01596 =================
01597 */
01598 int Brush_InsertVertexBetween(brush_t *b, vec3_t p1, vec3_t p2)
01599 {
01600     face_t *face;
01601     winding_t *w, *neww;
01602     vec3_t point;
01603     int i, insert;
01604 
01605     if (Point_Equal(p1, p2, 0.4))
01606         return false;
01607     VectorAdd(p1, p2, point);
01608     VectorScale(point, 0.5, point);
01609     insert = false;
01610     //the end point may not be the same as another vertex
01611     for (face = b->brush_faces; face; face = face->next)
01612     {
01613         w = face->face_winding;
01614         if (!w) continue;
01615         neww = NULL;
01616         for (i = 0; i < w->numpoints; i++)
01617         {
01618             if (!Point_Equal(w->points[i], p1, 0.1))
01619                 continue;
01620             if (Point_Equal(w->points[(i+1) % w->numpoints], p2, 0.1))
01621             {
01622                 neww = Winding_InsertPoint(w, point, (i+1) % w->numpoints);
01623                 break;
01624             }
01625             else if (Point_Equal(w->points[(i-1+w->numpoints) % w->numpoints], p2, 0.3))
01626             {
01627                 neww = Winding_InsertPoint(w, point, i);
01628                 break;
01629             }
01630         }
01631         if (neww)
01632         {
01633             Winding_Free(face->face_winding);
01634             face->face_winding = neww;
01635             insert = true;
01636         }
01637     }
01638     return insert;
01639 }
01640 
01641 
01642 /*
01643 =================
01644 Brush_ResetFaceOriginals
01645 =================
01646 */
01647 void Brush_ResetFaceOriginals(brush_t *b)
01648 {
01649     face_t *face;
01650 
01651     for (face = b->brush_faces; face; face = face->next)
01652     {
01653         face->original = NULL;
01654     }
01655 }
01656 
01657 /*
01658 =================
01659 Brush_Parse
01660 
01661 The brush is NOT linked to any list
01662 =================
01663 */
01664 //++timo FIXME: when using old brush primitives, the test loop for "Brush" and "patchDef2" "patchDef3" is ran
01665 // before each face parsing. It works, but it's a performance hit
01666 brush_t *Brush_Parse (void)
01667 {
01668     brush_t     *b;
01669     face_t      *f;
01670     int         i,j;
01671     
01672     g_qeglobals.d_parsed_brushes++;
01673     b = Brush_Alloc();
01674 
01675     do
01676     {
01677         if (!GetToken (true))
01678             break;
01679         if (!strcmp (token, "}") )
01680             break;
01681         
01682         // handle "Brush" primitive
01683         if (strcmpi(token, "brushDef") == 0)
01684         {
01685             // Timo parsing new brush format
01686             g_qeglobals.bPrimitBrushes=true;
01687             // check the map is not mixing the two kinds of brushes
01688             if (g_qeglobals.m_bBrushPrimitMode)
01689             {
01690                 if (g_qeglobals.bOldBrushes)
01691                     Sys_Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
01692             }
01693             //++Timo write new brush primitive -> old conversion code for Q3->Q2 conversions ?
01694             else
01695                 Sys_Printf("Warning : conversion code from brush primitive not done ( Brush_Parse )\n");
01696             
01697             BrushPrimit_Parse(b);
01698             if (b == NULL)
01699             {
01700                 Warning ("parsing brush primitive");
01701                 return NULL;
01702             }
01703             else
01704             {
01705                 continue;
01706             }
01707         }
01708         if ( strcmpi( token, "terrainDef" ) == 0 )
01709         {
01710             free (b);
01711 
01712             b = Terrain_Parse();
01713             if (b == NULL)
01714             {
01715                 Warning ("parsing terrain/brush");
01716                 return NULL;
01717             }
01718             else
01719             {
01720                 continue;
01721             }
01722         }
01723         if (strcmpi(token, "patchDef2") == 0 || strcmpi(token, "patchDef3") == 0)
01724         {
01725             free (b);
01726             
01727             // double string compare but will go away soon
01728             b = Patch_Parse(strcmpi(token, "patchDef2") == 0);
01729             if (b == NULL)
01730             {
01731                 Warning ("parsing patch/brush");
01732                 return NULL;
01733             }
01734             else
01735             {
01736                 continue;
01737             }
01738             // handle inline patch
01739         }
01740         else
01741         {
01742             // Timo parsing old brush format
01743             g_qeglobals.bOldBrushes=true;
01744             if (g_qeglobals.m_bBrushPrimitMode)
01745             {
01746                 // check the map is not mixing the two kinds of brushes
01747                 if (g_qeglobals.bPrimitBrushes)
01748                     Sys_Printf("Warning : old brushes and brush primitive in the same file are not allowed ( Brush_Parse )\n");
01749                 // set the "need" conversion flag
01750                 g_qeglobals.bNeedConvert=true;
01751             }
01752             
01753             f = Face_Alloc();
01754             
01755             // add the brush to the end of the chain, so
01756             // loading and saving a map doesn't reverse the order
01757             
01758             f->next = NULL;
01759             if (!b->brush_faces)
01760             {
01761                 b->brush_faces = f;
01762             }
01763             else
01764             {
01765                 face_t *scan;
01766                 for (scan=b->brush_faces ; scan->next ; scan=scan->next)
01767                     ;
01768                 scan->next = f;
01769             }
01770             
01771             // read the three point plane definition
01772             for (i=0 ; i<3 ; i++)
01773             {
01774                 if (i != 0)
01775                     GetToken (true);
01776                 if (strcmp (token, "(") )
01777                 {
01778                     Warning ("parsing brush");
01779                     return NULL;
01780                 }
01781                 
01782                 for (j=0 ; j<3 ; j++)
01783                 {
01784                     GetToken (false);
01785                     f->planepts[i][j] = atof(token);
01786                 }
01787                 
01788                 GetToken (false);
01789                 if (strcmp (token, ")") )
01790                 {
01791                     Warning ("parsing brush");
01792                     return NULL;
01793                 }
01794             }
01795         }
01796 
01797         // Timo
01798         // if we have a surface plugin, we'll call the plugin parsing
01799         if (g_qeglobals.bSurfacePropertiesPlugin)
01800         {
01801             GETPLUGINTEXDEF(f)->ParseTexdef();
01802         }
01803         else
01804         {
01805             
01806             // read the texturedef
01807             GetToken (false);
01808             f->texdef.SetName(token);
01809             if (token[0] == '(')
01810             {
01811                 int i = 32;
01812             }
01813             GetToken (false);
01814             f->texdef.shift[0] = atoi(token);
01815             GetToken (false);
01816             f->texdef.shift[1] = atoi(token);
01817             GetToken (false);
01818             f->texdef.rotate = atoi(token); 
01819             GetToken (false);
01820             f->texdef.scale[0] = atof(token);
01821             GetToken (false);
01822             f->texdef.scale[1] = atof(token);
01823                         
01824             // the flags and value field aren't necessarily present
01825             f->d_texture = Texture_ForName( f->texdef.name );
01826             f->texdef.flags = f->d_texture->flags;
01827             f->texdef.value = f->d_texture->value;
01828             f->texdef.contents = f->d_texture->contents;
01829             
01830             if (TokenAvailable ())
01831             {
01832                 GetToken (false);
01833                 f->texdef.contents = atoi(token);
01834                 GetToken (false);
01835                 f->texdef.flags = atoi(token);
01836                 GetToken (false);
01837                 f->texdef.value = atoi(token);
01838             }
01839             
01840         }
01841     } while (1);
01842     
01843     return b;
01844 }
01845 
01846 /*
01847 =================
01848 QERApp_MapPrintf_FILE
01849 callback for surface properties plugin
01850 must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
01851 =================
01852 */
01853 // carefully initialize !
01854 FILE * g_File;
01855 void WINAPI QERApp_MapPrintf_FILE( char *text, ... )
01856 {
01857     va_list argptr;
01858     char    buf[32768];
01859 
01860     va_start (argptr,text);
01861     vsprintf (buf, text,argptr);
01862     va_end (argptr);
01863 
01864     fprintf( g_File, buf );
01865 }
01866 
01867 
01868 /*
01869 ==============
01870 Brush_SetEpair
01871 sets an epair for the given brush
01872 ==============
01873 */
01874 void Brush_SetEpair(brush_t *b, const char *pKey, const char *pValue)
01875 {
01876     if (g_qeglobals.m_bBrushPrimitMode)
01877     {
01878     if (b->patchBrush)
01879     {
01880       Patch_SetEpair(b->pPatch, pKey, pValue);
01881     }
01882     else if (b->terrainBrush)
01883     {
01884       Terrain_SetEpair(b->pTerrain, pKey, pValue);
01885     }
01886     else
01887     {
01888           SetKeyValue(b->epairs, pKey, pValue);
01889     }
01890     }
01891     else
01892     {
01893         Sys_Printf("Can only set key/values in Brush primitive mode\n");
01894     }
01895 }
01896 
01897 /* 
01898 =================
01899 Brush_GetKeyValue
01900 =================
01901 */
01902 const char* Brush_GetKeyValue(brush_t *b, const char *pKey)
01903 {
01904     if (g_qeglobals.m_bBrushPrimitMode)
01905     {
01906     if (b->patchBrush)
01907     {
01908       return Patch_GetKeyValue(b->pPatch, pKey);
01909     }
01910     else if (b->terrainBrush)
01911     {
01912       return Terrain_GetKeyValue(b->pTerrain, pKey);
01913     }
01914     else
01915     {
01916           return ValueForKey(b->epairs, pKey);
01917     }
01918     }
01919     else
01920     {
01921         Sys_Printf("Can only set brush/patch key/values in Brush primitive mode\n");
01922     }
01923   return "";
01924 }
01925 
01926 /*
01927 =================
01928 Brush_Write
01929 save all brushes as Brush primitive format
01930 =================
01931 */
01932 void Brush_Write (brush_t *b, FILE *f)
01933 {
01934     epair_t *ep;
01935     face_t  *fa;
01936     char    *pname;
01937     int     i;
01938     
01939     if (b->patchBrush)
01940     {
01941         Patch_Write(b->pPatch, f);
01942         return;
01943     }
01944     if ( b->pTerrain )
01945     {
01946         Terrain_Write(b->pTerrain, f);
01947         return;
01948     }
01949     if (g_qeglobals.m_bBrushPrimitMode)
01950     {
01951         // save brush primitive format
01952         fprintf (f, "{\nbrushDef\n{\n");
01953         // brush epairs
01954         if (b->epairs)
01955             for (ep = b->epairs ; ep ; ep=ep->next)
01956                 fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value);
01957         for (fa=b->brush_faces ; fa ; fa=fa->next)
01958         {
01959             // save planepts
01960             for (i=0 ; i<3 ; i++)
01961             {
01962                 fprintf(f, "( ");
01963                 for (int j = 0; j < 3; j++)
01964                     if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j]))
01965                         fprintf(f, "%i ", static_cast<int>(fa->planepts[i][j]));
01966                     else
01967                         fprintf(f, "%f ", fa->planepts[i][j]);
01968                 fprintf(f, ") ");
01969             }
01970             // save texture coordinates
01971             fprintf(f,"( ( ");
01972             for (i=0 ; i<3 ; i++)
01973                 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i]))
01974                     fprintf(f,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
01975                 else
01976                     fprintf(f,"%f ",fa->brushprimit_texdef.coords[0][i]);
01977             fprintf(f,") ( ");
01978             for (i=0 ; i<3 ; i++)
01979                 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i]))
01980                     fprintf(f,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
01981                 else
01982                     fprintf(f,"%f ",fa->brushprimit_texdef.coords[1][i]);
01983             fprintf(f,") ) ");
01984             // save texture attribs
01985             //++timo surface properties plugin not implemented for brush primitives
01986             if (g_qeglobals.bSurfacePropertiesPlugin)
01987                 Sys_Printf("WARNING: surface properties plugin not supported with brush primitives (yet)\n");
01988 
01989       char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed";
01990             fprintf(f, "%s ", pName );
01991             fprintf(f, "%i %i %i\n", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
01992         }
01993         fprintf (f, "}\n}\n");
01994     }
01995     else
01996     {
01997         fprintf (f, "{\n");
01998         for (fa=b->brush_faces ; fa ; fa=fa->next)
01999         {
02000             for (i=0 ; i<3 ; i++)
02001             {
02002                 fprintf(f, "( ");
02003                 for (int j = 0; j < 3; j++)
02004                 {
02005                     if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j]))
02006                         fprintf(f, "%i ", static_cast<int>(fa->planepts[i][j]));
02007                     else
02008                         fprintf(f, "%f ", fa->planepts[i][j]);
02009                 }
02010                 fprintf(f, ") ");
02011             }
02012             
02013             if (g_qeglobals.bSurfacePropertiesPlugin)
02014             {
02015                 g_File = f;
02016 #ifdef _DEBUG
02017                 if (!fa->pData)
02018                     Sys_Printf("ERROR: unexpected IPluginTexdef* is NULL in Brush_Write\n");
02019                 else
02020 #endif
02021                 GETPLUGINTEXDEF(fa)->WriteTexdef( QERApp_MapPrintf_FILE );
02022             }
02023             else
02024             {
02025                 pname = fa->texdef.name;
02026                 if (pname[0] == 0)
02027                     pname = "unnamed";
02028                 
02029                 fprintf (f, "%s %i %i %i ", pname,
02030                     (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
02031                     (int)fa->texdef.rotate);
02032                 
02033                 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
02034                     fprintf (f, "%i ", (int)fa->texdef.scale[0]);
02035                 else
02036                     fprintf (f, "%f ", (float)fa->texdef.scale[0]);
02037                 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
02038                     fprintf (f, "%i", (int)fa->texdef.scale[1]);
02039                 else
02040                     fprintf (f, "%f", (float)fa->texdef.scale[1]);
02041                 
02042                 fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
02043             }
02044             fprintf (f, "\n");
02045         }
02046         fprintf (f, "}\n");
02047     }
02048 }
02049 
02050 /*
02051 =================
02052 QERApp_MapPrintf_MEMFILE
02053 callback for surface properties plugin
02054 must fit a PFN_QERAPP_MAPPRINTF ( see isurfaceplugin.h )
02055 =================
02056 */
02057 // carefully initialize !
02058 CMemFile * g_pMemFile;
02059 void WINAPI QERApp_MapPrintf_MEMFILE( char *text, ... )
02060 {
02061     va_list argptr;
02062     char    buf[32768];
02063 
02064     va_start (argptr,text);
02065     vsprintf (buf, text,argptr);
02066     va_end (argptr);
02067 
02068     MemFile_fprintf( g_pMemFile, buf );
02069 }
02070 
02071 /*
02072 =================
02073 Brush_Write to a CMemFile*
02074 save all brushes as Brush primitive format
02075 =================
02076 */
02077 void Brush_Write (brush_t *b, CMemFile *pMemFile)
02078 {
02079     epair_t *ep;
02080     face_t  *fa;
02081     char *pname;
02082     int     i;
02083     
02084     if (b->patchBrush)
02085     {
02086         Patch_Write(b->pPatch, pMemFile);
02087         return;
02088     }
02089     if (b->terrainBrush)
02090     {
02091         Terrain_Write(b->pTerrain, pMemFile);
02092         return;
02093     }
02094     //++timo NOTE: it's not very difficult to add since the surface properties plugin
02095     // writes throught a printf-style function prototype
02096     if (g_qeglobals.bSurfacePropertiesPlugin)
02097     {
02098         Sys_Printf("WARNING: Brush_Write to a CMemFile and Surface Properties plugin not done\n");
02099     }
02100     if (g_qeglobals.m_bBrushPrimitMode)
02101     {
02102         // brush primitive format
02103         MemFile_fprintf (pMemFile, "{\nBrushDef\n{\n");
02104         // brush epairs
02105         if (b->epairs)
02106             for( ep = b->epairs ; ep ; ep=ep->next )
02107                 MemFile_fprintf (pMemFile, "\"%s\" \"%s\"\n", ep->key, ep->value );
02108         for (fa=b->brush_faces ; fa ; fa=fa->next)
02109         {
02110             // save planepts
02111             for (i=0 ; i<3 ; i++)
02112             {
02113                 MemFile_fprintf(pMemFile, "( ");
02114                 for (int j = 0; j < 3; j++)
02115                     if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j]))
02116                         MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
02117                     else
02118                         MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
02119                 MemFile_fprintf(pMemFile, ") ");
02120             }
02121             // save texture coordinates
02122             MemFile_fprintf(pMemFile,"( ( ");
02123             for (i=0 ; i<3 ; i++)
02124                 if (fa->brushprimit_texdef.coords[0][i] == static_cast<int>(fa->brushprimit_texdef.coords[0][i]))
02125                     MemFile_fprintf(pMemFile,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[0][i]));
02126                 else
02127                     MemFile_fprintf(pMemFile,"%f ",fa->brushprimit_texdef.coords[0][i]);
02128             MemFile_fprintf(pMemFile,") ( ");
02129             for (i=0 ; i<3 ; i++)
02130                 if (fa->brushprimit_texdef.coords[1][i] == static_cast<int>(fa->brushprimit_texdef.coords[1][i]))
02131                     MemFile_fprintf(pMemFile,"%i ",static_cast<int>(fa->brushprimit_texdef.coords[1][i]));
02132                 else
02133                     MemFile_fprintf(pMemFile,"%f ",fa->brushprimit_texdef.coords[1][i]);
02134             MemFile_fprintf(pMemFile,") ) ");
02135             // save texture attribs
02136       char *pName = strlen(fa->texdef.name) > 0 ? fa->texdef.name : "unnamed";
02137             MemFile_fprintf(pMemFile, "%s ", pName);
02138             MemFile_fprintf(pMemFile, "%i %i %i\n", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
02139         }
02140         MemFile_fprintf (pMemFile, "}\n}\n");
02141     }
02142     else
02143     {
02144         // old brushes format
02145         // also handle surface properties plugin
02146         MemFile_fprintf (pMemFile, "{\n");
02147         for (fa=b->brush_faces ; fa ; fa=fa->next)
02148         {
02149             for (i=0 ; i<3 ; i++)
02150             {
02151                 MemFile_fprintf(pMemFile, "( ");
02152                 for (int j = 0; j < 3; j++)
02153                 {
02154                     if (fa->planepts[i][j] == static_cast<int>(fa->planepts[i][j]))
02155                         MemFile_fprintf(pMemFile, "%i ", static_cast<int>(fa->planepts[i][j]));
02156                     else
02157                         MemFile_fprintf(pMemFile, "%f ", fa->planepts[i][j]);
02158                 }
02159                 MemFile_fprintf(pMemFile, ") ");
02160             }
02161             
02162             if (g_qeglobals.bSurfacePropertiesPlugin)
02163             {
02164                 g_pMemFile = pMemFile;
02165 #ifdef _DEBUG
02166                 if (!fa->pData)
02167                     Sys_Printf("ERROR: unexpected IPluginTexdef* is NULL in Brush_Write\n");
02168                 else
02169 #endif
02170                 GETPLUGINTEXDEF(fa)->WriteTexdef( QERApp_MapPrintf_MEMFILE );
02171             }
02172             else
02173             {
02174                 pname = fa->texdef.name;
02175                 if (pname[0] == 0)
02176                     pname = "unnamed";
02177                 
02178                 MemFile_fprintf (pMemFile, "%s %i %i %i ", pname,
02179                     (int)fa->texdef.shift[0], (int)fa->texdef.shift[1],
02180                     (int)fa->texdef.rotate);
02181                 
02182                 if (fa->texdef.scale[0] == (int)fa->texdef.scale[0])
02183                     MemFile_fprintf (pMemFile, "%i ", (int)fa->texdef.scale[0]);
02184                 else
02185                     MemFile_fprintf (pMemFile, "%f ", (float)fa->texdef.scale[0]);
02186                 if (fa->texdef.scale[1] == (int)fa->texdef.scale[1])
02187                     MemFile_fprintf (pMemFile, "%i", (int)fa->texdef.scale[1]);
02188                 else
02189                     MemFile_fprintf (pMemFile, "%f", (float)fa->texdef.scale[1]);
02190                 
02191                 MemFile_fprintf (pMemFile, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value);
02192             }
02193             MemFile_fprintf (pMemFile, "\n");
02194         }
02195         MemFile_fprintf (pMemFile, "}\n");
02196     }
02197     
02198     
02199 }
02200 
02201 
02202 /*
02203 =============
02204 Brush_Create
02205 
02206 Create non-textured blocks for entities
02207 The brush is NOT linked to any list
02208 =============
02209 */
02210 brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef)
02211 {
02212     int     i, j;
02213     vec3_t  pts[4][2];
02214     face_t  *f;
02215     brush_t *b;
02216 
02217     // brush primitive mode : convert texdef to brushprimit_texdef ?
02218     // most of the time texdef is empty
02219     if (g_qeglobals.m_bBrushPrimitMode)
02220     {
02221         // check texdef is empty .. if there are cases it's not we need to write some conversion code
02222         if (texdef->shift[0]!=0 || texdef->shift[1]!=0 || texdef->scale[0]!=0 || texdef->scale[1]!=0 || texdef->rotate!=0)
02223             Sys_Printf("Warning : non-zero texdef detected in Brush_Create .. need brush primitive conversion\n");
02224     }
02225 
02226     for (i=0 ; i<3 ; i++)
02227     {
02228         if (maxs[i] < mins[i])
02229             Error ("Brush_InitSolid: backwards");
02230     }
02231 
02232     b = Brush_Alloc();
02233     
02234     pts[0][0][0] = mins[0];
02235     pts[0][0][1] = mins[1];
02236     
02237     pts[1][0][0] = mins[0];
02238     pts[1][0][1] = maxs[1];
02239     
02240     pts[2][0][0] = maxs[0];
02241     pts[2][0][1] = maxs[1];
02242     
02243     pts[3][0][0] = maxs[0];
02244     pts[3][0][1] = mins[1];
02245     
02246     for (i=0 ; i<4 ; i++)
02247     {
02248         pts[i][0][2] = mins[2];
02249         pts[i][1][0] = pts[i][0][0];
02250         pts[i][1][1] = pts[i][0][1];
02251         pts[i][1][2] = maxs[2];
02252     }
02253 
02254     for (i=0 ; i<4 ; i++)
02255     {
02256         f = Face_Alloc();
02257         f->texdef = *texdef;
02258         f->texdef.flags &= ~SURF_KEEP;
02259         f->texdef.contents &= ~CONTENTS_KEEP;
02260         f->next = b->brush_faces;
02261         b->brush_faces = f;
02262         j = (i+1)%4;
02263 
02264         VectorCopy (pts[j][1], f->planepts[0]);
02265         VectorCopy (pts[i][1], f->planepts[1]);
02266         VectorCopy (pts[i][0], f->planepts[2]);
02267     }
02268     
02269     f = Face_Alloc();
02270     f->texdef = *texdef;
02271     f->texdef.flags &= ~SURF_KEEP;
02272     f->texdef.contents &= ~CONTENTS_KEEP;
02273     f->next = b->brush_faces;
02274     b->brush_faces = f;
02275 
02276     VectorCopy (pts[0][1], f->planepts[0]);
02277     VectorCopy (pts[1][1], f->planepts[1]);
02278     VectorCopy (pts[2][1], f->planepts[2]);
02279 
02280     f = Face_Alloc();
02281     f->texdef = *texdef;
02282     f->texdef.flags &= ~SURF_KEEP;
02283     f->texdef.contents &= ~CONTENTS_KEEP;
02284     f->next = b->brush_faces;
02285     b->brush_faces = f;
02286 
02287     VectorCopy (pts[2][0], f->planepts[0]);
02288     VectorCopy (pts[1][0], f->planepts[1]);
02289     VectorCopy (pts[0][0], f->planepts[2]);
02290 
02291     return b;
02292 }
02293 
02294 /*
02295 =============
02296 Brush_CreatePyramid
02297 
02298 Create non-textured pyramid for light entities
02299 The brush is NOT linked to any list
02300 =============
02301 */
02302 brush_t *Brush_CreatePyramid (vec3_t mins, vec3_t maxs, texdef_t *texdef)
02303 {
02304     //++timo handle new brush primitive ? return here ??
02305     return Brush_Create(mins, maxs, texdef);
02306 
02307     for (int i=0 ; i<3 ; i++)
02308         if (maxs[i] < mins[i])
02309             Error ("Brush_InitSolid: backwards");
02310 
02311     brush_t* b = Brush_Alloc();
02312 
02313     vec3_t corners[4];
02314 
02315     float fMid = Q_rint(mins[2] + (Q_rint((maxs[2] - mins[2]) / 2)));
02316 
02317     corners[0][0] = mins[0];
02318     corners[0][1] = mins[1];
02319     corners[0][2] = fMid;
02320 
02321     corners[1][0] = mins[0];
02322     corners[1][1] = maxs[1];
02323     corners[1][2] = fMid;
02324 
02325     corners[2][0] = maxs[0];
02326     corners[2][1] = maxs[1];
02327     corners[2][2] = fMid;
02328 
02329     corners[3][0] = maxs[0];
02330     corners[3][1] = mins[1];
02331     corners[3][2] = fMid;
02332 
02333     vec3_t top, bottom;
02334 
02335     top[0] = Q_rint(mins[0] + ((maxs[0] - mins[0]) / 2));
02336     top[1] = Q_rint(mins[1] + ((maxs[1] - mins[1]) / 2));
02337     top[2] = Q_rint(maxs[2]);
02338 
02339     VectorCopy(top, bottom);
02340     bottom[2] = mins[2];
02341 
02342     // sides
02343     for (i = 0; i < 4; i++)
02344     {
02345         face_t* f = Face_Alloc();
02346         f->texdef = *texdef;
02347         f->texdef.flags &= ~SURF_KEEP;
02348         f->texdef.contents &= ~CONTENTS_KEEP;
02349         f->next = b->brush_faces;
02350         b->brush_faces = f;
02351         int j = (i+1)%4;
02352 
02353         VectorCopy (top, f->planepts[0]);
02354         VectorCopy (corners[i], f->planepts[1]);
02355         VectorCopy(corners[j], f->planepts[2]);
02356 
02357         f = Face_Alloc();
02358         f->texdef = *texdef;
02359         f->texdef.flags &= ~SURF_KEEP;
02360         f->texdef.contents &= ~CONTENTS_KEEP;
02361         f->next = b->brush_faces;
02362         b->brush_faces = f;
02363 
02364         VectorCopy (bottom, f->planepts[2]);
02365         VectorCopy (corners[i], f->planepts[1]);
02366         VectorCopy(corners[j], f->planepts[0]);
02367     }
02368 
02369     return b;
02370 }
02371 
02372 
02373 
02374 
02375 /*
02376 =============
02377 Brush_MakeSided
02378 
02379 Makes the current brush have the given number of 2d sides
02380 =============
02381 */
02382 void Brush_MakeSided (int sides)
02383 {
02384     int     i, axis;
02385     vec3_t  mins, maxs;
02386     brush_t *b;
02387     texdef_t    *texdef;
02388     face_t  *f;
02389     vec3_t  mid;
02390     float   width;
02391     float   sv, cv;
02392 
02393     if (sides < 3)
02394     {
02395         Sys_Status ("Bad sides number", 0);
02396         return;
02397     }
02398 
02399     if (sides >= MAX_POINTS_ON_WINDING-4)
02400     {
02401         Sys_Printf("too many sides.\n");
02402         return;
02403     }
02404 
02405     if (!QE_SingleBrush ())
02406     {
02407         Sys_Status ("Must have a single brush selected", 0 );
02408         return;
02409     }
02410 
02411     b = selected_brushes.next;
02412     VectorCopy (b->mins, mins);
02413     VectorCopy (b->maxs, maxs);
02414     texdef = &g_qeglobals.d_texturewin.texdef;
02415 
02416     Brush_Free (b);
02417 
02418     if (g_pParentWnd->ActiveXY())
02419     {
02420         switch(g_pParentWnd->ActiveXY()->GetViewType())
02421         {
02422             case XY: axis = 2; break;
02423             case XZ: axis = 1; break;
02424             case YZ: axis = 0; break;
02425         }
02426     }
02427     else
02428     {
02429         axis = 2;
02430     }
02431 
02432     // find center of brush
02433     width = 8;
02434     for (i = 0; i < 3; i++)
02435     {
02436         mid[i] = (maxs[i] + mins[i]) * 0.5;
02437         if (i == axis) continue;
02438         if ((maxs[i] - mins[i]) * 0.5 > width)
02439             width = (maxs[i] - mins[i]) * 0.5;
02440     }
02441 
02442     b = Brush_Alloc();
02443         
02444     // create top face
02445     f = Face_Alloc();
02446     f->texdef = *texdef;
02447     f->next = b->brush_faces;
02448     b->brush_faces = f;
02449 
02450     f->planepts[2][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[2][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[2][axis] = maxs[axis];
02451     f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = maxs[axis];
02452     f->planepts[0][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[0][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[0][axis] = maxs[axis];
02453 
02454     // create bottom face
02455     f = Face_Alloc();
02456     f->texdef = *texdef;
02457     f->next = b->brush_faces;
02458     b->brush_faces = f;
02459 
02460     f->planepts[0][(axis+1)%3] = mins[(axis+1)%3]; f->planepts[0][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[0][axis] = mins[axis];
02461     f->planepts[1][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[1][(axis+2)%3] = mins[(axis+2)%3]; f->planepts[1][axis] = mins[axis];
02462     f->planepts[2][(axis+1)%3] = maxs[(axis+1)%3]; f->planepts[2][(axis+2)%3] = maxs[(axis+2)%3]; f->planepts[2][axis] = mins[axis];
02463 
02464     for (i=0 ; i<sides ; i++)
02465     {
02466         f = Face_Alloc();
02467         f->texdef = *texdef;
02468         f->next = b->brush_faces;
02469         b->brush_faces = f;
02470 
02471         sv = sin (i*3.14159265*2/sides);
02472         cv = cos (i*3.14159265*2/sides);
02473 
02474         f->planepts[0][(axis+1)%3] = floor(mid[(axis+1)%3]+width*cv+0.5);
02475         f->planepts[0][(axis+2)%3] = floor(mid[(axis+2)%3]+width*sv+0.5);
02476         f->planepts[0][axis] = mins[axis];
02477 
02478         f->planepts[1][(axis+1)%3] = f->planepts[0][(axis+1)%3];
02479         f->planepts[1][(axis+2)%3] = f->planepts[0][(axis+2)%3];
02480         f->planepts[1][axis] = maxs[axis];
02481 
02482         f->planepts[2][(axis+1)%3] = floor(f->planepts[0][(axis+1)%3] - width*sv + 0.5);
02483         f->planepts[2][(axis+2)%3] = floor(f->planepts[0][(axis+2)%3] + width*cv + 0.5);
02484         f->planepts[2][axis] = maxs[axis];
02485     }
02486 
02487     Brush_AddToList (b, &selected_brushes);
02488 
02489     Entity_LinkBrush (world_entity, b);
02490 
02491     Brush_Build( b );
02492 
02493     Sys_UpdateWindows (W_ALL);
02494 }
02495 
02496 
02497 
02498 /*
02499 =============
02500 Brush_Free
02501 
02502 Frees the brush with all of its faces and display list.
02503 Unlinks the brush from whichever chain it is in.
02504 Decrements the owner entity's brushcount.
02505 Removes owner entity if this was the last brush
02506 unless owner is the world.
02507 Removes from groups
02508 =============
02509 */
02510 void Brush_Free (brush_t *b, bool bRemoveNode)
02511 {
02512     face_t  *f, *next;
02513     epair_t *ep, *enext;
02514 
02515     // remove from group
02516     if (bRemoveNode)
02517         Group_RemoveBrush(b);
02518 
02519     // free the patch if it's there
02520     if (b->patchBrush)
02521     {
02522         Patch_Delete(b->pPatch);
02523     }
02524 
02525     if( b->terrainBrush )
02526     {
02527         Terrain_Delete( b->pTerrain );
02528     }
02529 
02530     // free faces
02531     for (f=b->brush_faces ; f ; f=next)
02532     {
02533         next = f->next;
02534         Face_Free( f );
02535     }
02536 
02537     //Timo : free brush epairs
02538     for (ep = b->epairs ; ep ; ep=enext )
02539     {
02540         enext = ep->next;
02541         free (ep->key);
02542         free (ep->value);
02543         free (ep);
02544     }
02545 
02546     // unlink from active/selected list
02547     if (b->next)
02548         Brush_RemoveFromList (b);
02549 
02550     // unlink from entity list
02551     if (b->onext)
02552         Entity_UnlinkBrush (b);
02553 
02554     free (b);
02555 }
02556 
02557 /*
02558 =============
02559 Face_MemorySize
02560 =============
02561 */
02562 int Face_MemorySize(face_t *f )
02563 {
02564     int size = 0;
02565 
02566     if (f->face_winding)
02567     {
02568         size += _msize(f->face_winding);
02569     }
02570     //f->texdef.~texdef_t();;
02571     size += _msize(f);
02572     return size;
02573 }
02574 
02575 /*
02576 =============
02577 Brush_MemorySize
02578 =============
02579 */
02580 int Brush_MemorySize(brush_t *b)
02581 {
02582     face_t  *f;
02583     epair_t *ep;
02584     int size = 0;
02585 
02586     //
02587     if (b->patchBrush)
02588     {
02589         size += Patch_MemorySize(b->pPatch);
02590     }
02591     if (b->terrainBrush)
02592     {
02593         size += Terrain_MemorySize(b->pTerrain);
02594     }
02595     //
02596     for (f = b->brush_faces; f; f = f->next)
02597     {
02598         size += Face_MemorySize(f);
02599     }
02600     //
02601     for (ep = b->epairs; ep; ep = ep->next )
02602     {
02603         size += _msize(ep->key);
02604         size += _msize(ep->value);
02605         size += _msize(ep);
02606     }
02607     size += _msize(b);
02608     return size;
02609 }
02610 
02611 
02612 /*
02613 ============
02614 Brush_Clone
02615 
02616 Does NOT add the new brush to any lists
02617 ============
02618 */
02619 brush_t *Brush_Clone (brush_t *b)
02620 {
02621     brush_t *n = NULL;
02622     face_t  *f, *nf;
02623 
02624     if (b->patchBrush)
02625     {
02626         patchMesh_t *p = Patch_Duplicate(b->pPatch);
02627         Brush_RemoveFromList(p->pSymbiot);
02628         Entity_UnlinkBrush(p->pSymbiot);
02629         n = p->pSymbiot;
02630     }
02631     else if (b->terrainBrush)
02632     {
02633         terrainMesh_t *p = Terrain_Duplicate(b->pTerrain);
02634         Brush_RemoveFromList(p->pSymbiot);
02635         Entity_UnlinkBrush(p->pSymbiot);
02636         n = p->pSymbiot;
02637     }
02638     else
02639     {
02640     n = Brush_Alloc();
02641       n->numberId = g_nBrushId++;
02642         n->owner = b->owner;
02643         for (f=b->brush_faces ; f ; f=f->next)
02644         {
02645             nf = Face_Clone( f );
02646             nf->next = n->brush_faces;
02647             n->brush_faces = nf;
02648         }
02649     }
02650 
02651     return n;
02652 }
02653 
02654 
02655 
02656 /*
02657 ============
02658 Brush_Clone
02659 
02660 Does NOT add the new brush to any lists
02661 ============
02662 */
02663 brush_t *Brush_FullClone(brush_t *b)
02664 {
02665     brush_t *n = NULL;
02666     face_t *f, *nf, *f2, *nf2;
02667     int j;
02668 
02669     if (b->patchBrush)
02670     {
02671         patchMesh_t *p = Patch_Duplicate(b->pPatch);
02672         Brush_RemoveFromList(p->pSymbiot);
02673         Entity_UnlinkBrush(p->pSymbiot);
02674         n = p->pSymbiot;
02675         n->owner = b->owner;
02676         Brush_Build(n);
02677     }
02678     else if (b->terrainBrush)
02679     {
02680         terrainMesh_t *p = Terrain_Duplicate(b->pTerrain);
02681         Brush_RemoveFromList(p->pSymbiot);
02682         Entity_UnlinkBrush(p->pSymbiot);
02683         n = p->pSymbiot;
02684         n->owner = b->owner;
02685         Brush_Build(n);
02686     }
02687     else
02688     {
02689     n = Brush_Alloc();
02690     n->numberId = g_nBrushId++;
02691         n->owner = b->owner;
02692         VectorCopy(b->mins, n->mins);
02693         VectorCopy(b->maxs, n->maxs);
02694         //
02695         for (f = b->brush_faces; f; f = f->next)
02696         {
02697             if (f->original) continue;
02698             nf = Face_FullClone(f);
02699             nf->next = n->brush_faces;
02700             n->brush_faces = nf;
02701             //copy all faces that have the original set to this face
02702             for (f2 = b->brush_faces; f2; f2 = f2->next)
02703             {
02704                 if (f2->original == f)
02705                 {
02706                     nf2 = Face_FullClone(f2);
02707                     nf2->next = n->brush_faces;
02708                     n->brush_faces = nf2;
02709                     //set original
02710                     nf2->original = nf;
02711                 }
02712             }
02713         }
02714         for (nf = n->brush_faces; nf; nf = nf->next)
02715         {
02716             Face_SetColor(n, nf, 1.0);
02717             if (nf->face_winding)
02718       {
02719         if (g_qeglobals.m_bBrushPrimitMode)
02720                 EmitBrushPrimitTextureCoordinates(nf,nf->face_winding);
02721         else
02722         {
02723                   for (j = 0; j < nf->face_winding->numpoints; j++)
02724                     EmitTextureCoordinates(nf->face_winding->points[j], nf->d_texture, nf);
02725         }
02726       }
02727         }
02728   }
02729     return n;
02730 }
02731 
02732 /*
02733 ==============
02734 Brush_Ray
02735 
02736 Itersects a ray with a brush
02737 Returns the face hit and the distance along the ray the intersection occured at
02738 Returns NULL and 0 if not hit at all
02739 ==============
02740 */
02741 face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist)
02742 {
02743     face_t  *f, *firstface;
02744     vec3_t  p1, p2;
02745     float   frac, d1, d2;
02746     int     i;
02747 
02748     VectorCopy (origin, p1);
02749     for (i=0 ; i<3 ; i++)
02750         p2[i] = p1[i] + dir[i]*16384;
02751 
02752     for (f=b->brush_faces ; f ; f=f->next)
02753     {
02754         d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
02755         d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
02756         if (d1 >= 0 && d2 >= 0)
02757         {
02758             *dist = 0;
02759             return NULL;    // ray is on front side of face
02760         }
02761         if (d1 <=0 && d2 <= 0)
02762             continue;
02763     // clip the ray to the plane
02764         frac = d1 / (d1 - d2);
02765         if (d1 > 0)
02766         {
02767             firstface = f;
02768             for (i=0 ; i<3 ; i++)
02769                 p1[i] = p1[i] + frac *(p2[i] - p1[i]);
02770         }
02771         else
02772         {
02773             for (i=0 ; i<3 ; i++)
02774                 p2[i] = p1[i] + frac *(p2[i] - p1[i]);
02775         }
02776     }
02777 
02778     // find distance p1 is along dir
02779     VectorSubtract (p1, origin, p1);
02780     d1 = DotProduct (p1, dir);
02781 
02782     *dist = d1;
02783 
02784     return firstface;
02785 }
02786 
02787 //PGM
02788 face_t *Brush_Point (vec3_t origin, brush_t *b)
02789 {
02790     face_t  *f;
02791     float   d1;
02792 
02793     for (f=b->brush_faces ; f ; f=f->next)
02794     {
02795         d1 = DotProduct (origin, f->plane.normal) - f->plane.dist;
02796         if (d1 > 0)
02797         {
02798             return NULL;    // point is on front side of face
02799         }
02800     }
02801 
02802     return b->brush_faces;
02803 }
02804 //PGM
02805 
02806 
02807 void    Brush_AddToList (brush_t *b, brush_t *list)
02808 {
02809     if (b->next || b->prev)
02810         Error ("Brush_AddToList: allready linked");
02811     
02812     if (list == &selected_brushes || list == &active_brushes)
02813     {
02814         if (b->patchBrush && list == &selected_brushes)
02815         {
02816             Patch_Select(b->pPatch);
02817         }
02818         if (b->terrainBrush && list == &selected_brushes) {
02819             Terrain_Select(b->pTerrain);
02820         }
02821     }
02822     b->next = list->next;
02823     list->next->prev = b;
02824     list->next = b;
02825     b->prev = list;
02826     
02827     // TTimo messaging
02828     DispatchRadiantMsg( RADIANT_SELECTION );    
02829 }
02830 
02831 void    Brush_RemoveFromList (brush_t *b)
02832 {
02833     if (!b->next || !b->prev)
02834         Error ("Brush_RemoveFromList: not linked");
02835     
02836     if (b->patchBrush)
02837     {
02838         Patch_Deselect(b->pPatch);
02839         //Patch_Deselect(b->nPatchID);
02840     }
02841     if (b->terrainBrush)
02842     {
02843         Terrain_Deselect(b->pTerrain);
02844     }
02845 
02846     b->next->prev = b->prev;
02847     b->prev->next = b->next;
02848     b->next = b->prev = NULL;
02849 }
02850 
02851 /*
02852 ===============
02853 SetFaceTexdef
02854 
02855 Doesn't set the curve flags
02856 
02857 NOTE : ( TTimo )
02858     never trust f->d_texture here, f->texdef and f->d_texture are out of sync when called by Brush_SetTexture
02859     use Texture_ForName() to find the right shader
02860     FIXME : send the right shader ( qtexture_t * ) in the parameters ?
02861 
02862 TTimo: surface plugin, added an IPluginTexdef* parameter
02863         if not NULL, get ->Copy() of it into the face ( and remember to hook )
02864         if NULL, ask for a default
02865 ===============
02866 */
02867 void SetFaceTexdef (brush_t *b, face_t *f, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pPlugTexdef) {
02868     int     oldFlags;
02869     int     oldContents;
02870     face_t  *tf;
02871 
02872     oldFlags = f->texdef.flags;
02873     oldContents = f->texdef.contents;
02874     if (g_qeglobals.m_bBrushPrimitMode)
02875     {
02876         f->texdef = *texdef;
02877         ConvertTexMatWithQTexture( brushprimit_texdef, NULL, &f->brushprimit_texdef, Texture_ForName( f->texdef.name ) );
02878     }
02879     else
02880         if (bFitScale)
02881         {
02882             f->texdef = *texdef;
02883             // fit the scaling of the texture on the actual plane
02884             vec3_t p1,p2,p3; // absolute coordinates
02885             // compute absolute coordinates
02886             ComputeAbsolute(f,p1,p2,p3);
02887             // compute the scale
02888             vec3_t vx,vy;
02889             VectorSubtract(p2,p1,vx);
02890             VectorNormalize(vx);
02891             VectorSubtract(p3,p1,vy);
02892             VectorNormalize(vy);
02893             // assign scale
02894             VectorScale(vx,texdef->scale[0],vx);
02895             VectorScale(vy,texdef->scale[1],vy);
02896             VectorAdd(p1,vx,p2);
02897             VectorAdd(p1,vy,p3);
02898             // compute back shift scale rot
02899             AbsoluteToLocal(f->plane,f,p1,p2,p3);
02900         }
02901         else
02902             f->texdef = *texdef;
02903     f->texdef.flags = (f->texdef.flags & ~SURF_KEEP) | (oldFlags & SURF_KEEP);
02904     f->texdef.contents = (f->texdef.contents & ~CONTENTS_KEEP) | (oldContents & CONTENTS_KEEP);
02905 
02906     // surface plugin
02907     if (g_qeglobals.bSurfacePropertiesPlugin)
02908     {
02909 #ifdef _DEBUG
02910         if (!f->pData)
02911             Sys_Printf("ERROR: unexpected IPluginTexdef* is NULL in SetFaceTexdef\n");
02912         else
02913 #endif
02914             GETPLUGINTEXDEF(f)->DecRef();
02915         IPluginTexdef *pTexdef = NULL;
02916         if ( pPlugTexdef )
02917         {
02918             pTexdef = pPlugTexdef->Copy();
02919             pTexdef->Hook( f );
02920         }
02921         else
02922             pTexdef = g_SurfaceTable.m_pfnTexdefAlloc( f );
02923         f->pData = pTexdef;
02924     }
02925 
02926     // if this is a curve face, set all other curve faces to the same texdef
02927     if (f->texdef.flags & SURF_CURVE) 
02928     {
02929         for (tf = b->brush_faces ; tf ; tf = tf->next) 
02930         {
02931             if (tf->texdef.flags & SURF_CURVE) 
02932                 tf->texdef = f->texdef;
02933         }
02934     }
02935 }
02936 
02937 
02938 void Brush_SetTexture (brush_t *b, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, IPluginTexdef* pTexdef)
02939 {
02940     for (face_t* f = b->brush_faces ; f ; f = f->next) 
02941     {
02942         SetFaceTexdef (b, f, texdef, brushprimit_texdef, bFitScale, pTexdef);
02943     }
02944     Brush_Build( b );
02945     if (b->patchBrush)
02946     {
02947         //++timo clean
02948 //      Sys_Printf("WARNING: Brush_SetTexture needs surface plugin code for patches\n");
02949         Patch_SetTexture(b->pPatch, texdef, pTexdef );
02950     }
02951     if (b->terrainBrush)
02952     {
02953         Terrain_SetTexture(b->pTerrain, texdef);
02954     }
02955 
02956 }
02957 
02958 
02959 qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f)
02960 {
02961     float   d1, d2, fr;
02962     int     i;
02963     float   *v;
02964 
02965     d1 = DotProduct (p1, f->plane.normal) - f->plane.dist;
02966     d2 = DotProduct (p2, f->plane.normal) - f->plane.dist;
02967 
02968     if (d1 >= 0 && d2 >= 0)
02969         return false;       // totally outside
02970     if (d1 <= 0 && d2 <= 0)
02971         return true;        // totally inside
02972 
02973     fr = d1 / (d1 - d2);
02974 
02975     if (d1 > 0)
02976         v = p1;
02977     else
02978         v = p2;
02979 
02980     for (i=0 ; i<3 ; i++)
02981         v[i] = p1[i] + fr*(p2[i] - p1[i]);
02982 
02983     return true;
02984 }
02985 
02986 
02987 int AddPlanept (float *f)
02988 {
02989     int     i;
02990 
02991     for (i=0 ; i<g_qeglobals.d_num_move_points ; i++)
02992         if (g_qeglobals.d_move_points[i] == f)
02993             return 0;
02994     g_qeglobals.d_move_points[g_qeglobals.d_num_move_points++] = f;
02995     return 1;
02996 }
02997 
02998 /*
02999 ==============
03000 Brush_SelectFaceForDragging
03001 
03002 Adds the faces planepts to move_points, and
03003 rotates and adds the planepts of adjacent face if shear is set
03004 ==============
03005 */
03006 void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear)
03007 {
03008     int     i;
03009     face_t  *f2;
03010     winding_t   *w;
03011     float   d;
03012     brush_t *b2;
03013     int     c;
03014 
03015     if (b->owner->eclass->fixedsize)
03016         return;
03017 
03018     c = 0;
03019     for (i=0 ; i<3 ; i++)
03020         c += AddPlanept (f->planepts[i]);
03021     if (c == 0)
03022         return;     // allready completely added
03023 
03024     // select all points on this plane in all brushes the selection
03025     for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next)
03026     {
03027         if (b2 == b)
03028             continue;
03029         for (f2=b2->brush_faces ; f2 ; f2=f2->next)
03030         {
03031             for (i=0 ; i<3 ; i++)
03032                 if (fabs(DotProduct(f2->planepts[i], f->plane.normal)
03033                 -f->plane.dist) > ON_EPSILON)
03034                     break;
03035             if (i==3)
03036             {   // move this face as well
03037                 Brush_SelectFaceForDragging (b2, f2, shear);
03038                 break;
03039             }
03040         }
03041     }
03042 
03043 
03044     // if shearing, take all the planes adjacent to 
03045     // selected faces and rotate their points so the
03046     // edge clipped by a selcted face has two of the points
03047     if (!shear)
03048         return;
03049 
03050     for (f2=b->brush_faces ; f2 ; f2=f2->next)
03051     {
03052         if (f2 == f)
03053             continue;
03054         w = Brush_MakeFaceWinding (b, f2);
03055         if (!w)
03056             continue;
03057 
03058         // any points on f will become new control points
03059         for (i=0 ; i<w->numpoints ; i++)
03060         {
03061             d = DotProduct (w->points[i], f->plane.normal) 
03062                 - f->plane.dist;
03063             if (d > -ON_EPSILON && d < ON_EPSILON)
03064                 break;
03065         }
03066 
03067         //
03068         // if none of the points were on the plane,
03069         // leave it alone
03070         //
03071         if (i != w->numpoints)
03072         {
03073             if (i == 0)
03074             {   // see if the first clockwise point was the
03075                 // last point on the winding
03076                 d = DotProduct (w->points[w->numpoints-1]
03077                     , f->plane.normal) - f->plane.dist;
03078                 if (d > -ON_EPSILON && d < ON_EPSILON)
03079                     i = w->numpoints - 1;
03080             }
03081 
03082             AddPlanept (f2->planepts[0]);
03083 
03084             VectorCopy (w->points[i], f2->planepts[0]);
03085             if (++i == w->numpoints)
03086                 i = 0;
03087             
03088             // see if the next point is also on the plane
03089             d = DotProduct (w->points[i]
03090                 , f->plane.normal) - f->plane.dist;
03091             if (d > -ON_EPSILON && d < ON_EPSILON)
03092                 AddPlanept (f2->planepts[1]);
03093 
03094             VectorCopy (w->points[i], f2->planepts[1]);
03095             if (++i == w->numpoints)
03096                 i = 0;
03097 
03098             // the third point is never on the plane
03099 
03100             VectorCopy (w->points[i], f2->planepts[2]);
03101         }
03102 
03103         free(w);
03104     }
03105 }
03106 
03107 /*
03108 ==============
03109 Brush_SideSelect
03110 
03111 The mouse click did not hit the brush, so grab one or more side
03112 planes for dragging
03113 ==============
03114 */
03115 void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir
03116                        , qboolean shear)
03117 {
03118     face_t  *f, *f2;
03119     vec3_t  p1, p2;
03120 
03121   //if (b->patchBrush)
03122   //  return;
03123     //Patch_SideSelect(b->nPatchID, origin, dir);
03124     for (f=b->brush_faces ; f ; f=f->next)
03125     {
03126         VectorCopy (origin, p1);
03127         VectorMA (origin, 16384, dir, p2);
03128 
03129         for (f2=b->brush_faces ; f2 ; f2=f2->next)
03130         {
03131             if (f2 == f)
03132                 continue;
03133             ClipLineToFace (p1, p2, f2);
03134         }
03135 
03136         if (f2)
03137             continue;
03138 
03139         if (VectorCompare (p1, origin))
03140             continue;
03141         if (ClipLineToFace (p1, p2, f))
03142             continue;
03143 
03144         Brush_SelectFaceForDragging (b, f, shear);
03145     }
03146 
03147     
03148 }
03149 
03150 void Brush_BuildWindings( brush_t *b, bool bSnap )
03151 {
03152     winding_t *w;
03153     face_t    *face;
03154     vec_t      v;
03155 
03156     if (bSnap)
03157         Brush_SnapPlanepts( b );
03158 
03159     // clear the mins/maxs bounds
03160     b->mins[0] = b->mins[1] = b->mins[2] = 99999;
03161     b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999;
03162 
03163     Brush_MakeFacePlanes (b);
03164 
03165     face = b->brush_faces;
03166 
03167     float fCurveColor = 1.0;
03168 
03169     for ( ; face ; face=face->next)
03170     {
03171         int i, j;
03172         free(face->face_winding);
03173         w = face->face_winding = Brush_MakeFaceWinding (b, face);
03174         face->d_texture = Texture_ForName( face->texdef.name );
03175 
03176         if (!w)
03177             continue;
03178     
03179         for (i=0 ; i<w->numpoints ; i++)
03180         {
03181             // add to bounding box
03182             for (j=0 ; j<3 ; j++)
03183             {
03184                 v = w->points[i][j];
03185                 if (v > b->maxs[j])
03186                     b->maxs[j] = v;
03187                 if (v < b->mins[j])
03188                     b->mins[j] = v;
03189             }
03190         }
03191         // setup s and t vectors, and set color
03192         //if (!g_PrefsDlg.m_bGLLighting)
03193     //{
03194           Face_SetColor (b, face, fCurveColor);
03195     //}
03196 
03197         fCurveColor -= .10;
03198         if (fCurveColor <= 0)
03199             fCurveColor = 1.0;
03200 
03201         // computing ST coordinates for the windings
03202         if (g_qeglobals.m_bBrushPrimitMode)
03203         {
03204             if (g_qeglobals.bNeedConvert)
03205             {
03206                 // we have parsed old brushes format and need conversion
03207                 // convert old brush texture representation to new format
03208                 FaceToBrushPrimitFace(face);
03209 #ifdef _DEBUG
03210                 // use old texture coordinates code to check against
03211                 for (i=0 ; i<w->numpoints ; i++)
03212                     EmitTextureCoordinates( w->points[i], face->d_texture, face);
03213 #endif
03214             }
03215             // use new texture representation to compute texture coordinates
03216             // in debug mode we will check against old code and warn if there are differences
03217             EmitBrushPrimitTextureCoordinates(face,w);
03218         }
03219         else
03220         {
03221             for (i=0 ; i<w->numpoints ; i++)
03222                 EmitTextureCoordinates( w->points[i], face->d_texture, face);
03223         }
03224     }
03225 }
03226 
03227 /*
03228 ==================
03229 Brush_RemoveEmptyFaces
03230 
03231 Frees any overconstraining faces
03232 ==================
03233 */
03234 void Brush_RemoveEmptyFaces ( brush_t *b )
03235 {
03236     face_t  *f, *next;
03237 
03238     f = b->brush_faces;
03239     b->brush_faces = NULL;
03240 
03241     for ( ; f ; f=next)
03242     {
03243         next = f->next;
03244         if (!f->face_winding)
03245             Face_Free (f);
03246         else
03247         {
03248             f->next = b->brush_faces;
03249             b->brush_faces = f;
03250         }
03251 
03252     }
03253 }
03254 
03255 void Brush_SnapToGrid(brush_t *pb)
03256 {
03257     for (face_t *f = pb->brush_faces ; f; f = f->next)
03258     {
03259         for (int i = 0 ;i < 3 ;i++)
03260         {
03261             for (int j = 0 ;j < 3 ; j++)
03262             {
03263                 f->planepts[i][j] = floor (f->planepts[i][j] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
03264             }
03265         }
03266     }
03267     Brush_Build(pb);
03268 }
03269 
03270 void Brush_Rotate(brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild)
03271 {
03272     for (face_t* f=b->brush_faces ; f ; f=f->next)
03273     {
03274         for (int i=0 ; i<3 ; i++)
03275         {
03276             VectorRotate(f->planepts[i], vAngle, vOrigin, f->planepts[i]);
03277         }
03278     }
03279     if (bBuild)
03280     {
03281         Brush_Build(b, false, false);
03282     }
03283 }
03284 
03285 void Brush_Center(brush_t *b, vec3_t vNewCenter)
03286 {
03287   vec3_t vMid;
03288   // get center of the brush
03289   for (int j = 0; j < 3; j++)
03290   {
03291     vMid[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5);
03292   }
03293   // calc distance between centers
03294   VectorSubtract(vNewCenter, vMid, vMid);
03295   Brush_Move(b, vMid, true);
03296 
03297 }
03298 
03299 // only designed for fixed size entity brushes
03300 void Brush_Resize(brush_t *b, vec3_t vMin, vec3_t vMax)
03301 {
03302   brush_t *b2 = Brush_Create(vMin, vMax, &b->brush_faces->texdef);
03303 
03304   face_t *next;
03305     for (face_t *f=b->brush_faces ; f ; f=next)
03306     {
03307         next = f->next;
03308         Face_Free( f );
03309     }
03310 
03311   b->brush_faces = b2->brush_faces;
03312 
03313     // unlink from active/selected list
03314     if (b2->next)
03315   Brush_RemoveFromList (b2);
03316   free(b2);
03317   Brush_Build(b, true);
03318 }
03319 
03320 
03321 eclass_t* HasModel(brush_t *b)
03322 {
03323   vec3_t vMin, vMax;
03324   vMin[0] = vMin[1] = vMin[2] = 9999;
03325   vMax[0] = vMax[1] = vMax[2] = -9999;
03326 
03327   if (b->owner->md3Class != NULL)
03328   {
03329     return b->owner->md3Class;
03330   }
03331 
03332   if (Eclass_hasModel(b->owner->eclass, vMin, vMax))
03333   {
03334     return b->owner->eclass;
03335   }
03336 
03337   eclass_t *e = NULL;
03338   // FIXME: entity needs to track whether a cache hit failed and not ask again
03339   if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL)
03340   {
03341     char *pModel = ValueForKey(b->owner, "model");
03342     if (pModel != NULL && strlen(pModel) > 0)
03343     {
03344       e = GetCachedModel(b->owner, pModel, vMin, vMax);
03345       if (e != NULL)
03346       {
03347         // we need to scale the brush to the proper size based on the model load
03348         // recreate brush just like in load/save
03349 
03350             VectorAdd (vMin, b->owner->origin, vMin);
03351             VectorAdd (vMax, b->owner->origin, vMax);
03352 
03353         Brush_Resize(b, vMin, vMax);
03354 
03355 /*
03356         //
03357         vec3_t vTemp, vTemp2;
03358         VectorSubtract(b->maxs, b->mins, vTemp);
03359         VectorSubtract(vMax, vMin, vTemp2);
03360         for (int i = 0; i < 3; i++)
03361         {
03362           if (vTemp[i] != 0)
03363           {
03364             vTemp2[i] /= vTemp[i];
03365           }
03366         }
03367         vec3_t vMid, vMid2;
03368         vMid[0] = vMid[1] = vMid[2] = 0.0;
03369         vMid2[0] = vMid2[1] = vMid2[2] = 0.0;
03370 
03371         for (int j = 0; j < 3; j++)
03372         {
03373           vMid2[j] = b->mins[j] + abs((b->maxs[j] - b->mins[j]) * 0.5);
03374         }
03375 
03376         //VectorSubtract(vMid2, vMid, vMid2);
03377 
03378             for (face_t* f=b->brush_faces ; f ; f=f->next)
03379             {
03380                 for (int i=0 ; i<3 ; i++)
03381                 {
03382 
03383             // scale
03384             VectorSubtract(f->planepts[i], vMid2, f->planepts[i]);
03385             f->planepts[i][0] *= vTemp2[0];
03386             f->planepts[i][1] *= vTemp2[1];
03387             f->planepts[i][2] *= vTemp2[2];
03388             VectorAdd(f->planepts[i], vMid2, f->planepts[i]);
03389           }
03390         }
03391 
03392         //Brush_Center(b, b->owner->origin);
03393 
03394         //Brush_SnapToGrid(b);
03395 /*
03396         float a = FloatForKey (b->owner, "angle");
03397         if (a)
03398         {
03399           vec3_t vAngle;
03400           vAngle[0] = vAngle[1] = 0;
03401           vAngle[2] = a;
03402           Brush_Rotate(b, vAngle, b->owner->origin);
03403         }
03404         else
03405         {
03406           Brush_Build(b, true);
03407 */
03408 //        }
03409 
03410         b->bModelFailed = false;
03411       }
03412       else
03413       {
03414         b->bModelFailed = true;
03415       }
03416     } 
03417   }
03418   return e;
03419 }
03420 
03421 static bool g_bInPaintedModel = false;
03422 static bool g_bDoIt = false;
03423 bool PaintedModel(brush_t *b, bool bOkToTexture)
03424 {
03425     if (g_bInPaintedModel)
03426     { 
03427       return true;
03428     }
03429     
03430     if (g_PrefsDlg.m_nEntityShowState == ENTITY_BOX || b->bModelFailed)
03431     {
03432       return false;
03433     }
03434     else if (!IsBrushSelected(b) && (g_PrefsDlg.m_nEntityShowState & ENTITY_SELECTED_ONLY))
03435     {
03436         return false;
03437     }
03438 
03439     g_bInPaintedModel = true;
03440     bool bReturn = false;
03441 
03442     eclass_t *pEclass = HasModel(b);
03443 
03444     if (pEclass)
03445     {
03446       qglPushAttrib(GL_ALL_ATTRIB_BITS);
03447       entitymodel *model = pEclass->model;
03448 
03449 
03450       float a = FloatForKey (b->owner, "angle");
03451       while (model != NULL)
03452       {
03453         if (bOkToTexture == false || g_PrefsDlg.m_nEntityShowState & ENTITY_WIREFRAME || model->nTextureBind == -1) // skinned
03454         {
03455             qglDisable( GL_CULL_FACE );
03456             qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
03457             qglDisable(GL_TEXTURE_2D);
03458           qglColor3fv(pEclass->color);
03459         }
03460         else
03461         {
03462           qglColor3f(1, 1, 1);
03463           qglEnable(GL_TEXTURE_2D);
03464             qglBindTexture( GL_TEXTURE_2D, model->nTextureBind );
03465         }
03466         vec3_t v;
03467         
03468         int i,j;
03469         VectorAdd(b->maxs, b->mins, v);
03470         VectorScale(v, 0.5, v);
03471         VectorCopy(b->owner->origin, v);
03472 
03473           
03474         //for (i = 0; i < 3; i++)
03475         //{
03476         //  v[i] -= (pEclass->mins[i] - b->mins[i]);
03477         //}
03478 
03479         //if (model->nModelPosition)
03480         //{
03481               //v[2] = b->mins[2] - (pEclass->mins[2]);
03482         //}
03483 
03484         float s, c;
03485           if (a)
03486         {
03487               s = sin (a/180*Q_PI);
03488               c = cos (a/180*Q_PI);
03489         }
03490 
03491         vec3_t vSin;
03492         vec3_t vCos;
03493         VectorClear(vSin);
03494         VectorClear(vCos);
03495         for ( j = 0; j < 3; j++)
03496         {
03497           if (b->owner->vRotation[j])
03498           {
03499             vSin[j] = sin(b->owner->vRotation[j]/180*Q_PI);
03500             vCos[j] = cos(b->owner->vRotation[j]/180*Q_PI);
03501           }
03502         }
03503 
03504 
03505           qglBegin (GL_TRIANGLES);
03506 
03507         vec5_t vTest[3];
03508         for (i = 0; i < model->nTriCount; i++)
03509         {
03510           for (j = 0; j < 3; j++)
03511           {
03512 #if 1
03513             float x = model->pTriList[i].v[j][0] + v[0];
03514             float y = model->pTriList[i].v[j][1] + v[1];
03515             if (a)
03516             {
03517               float x2 = (((x - v[0]) * c) - ((y - v[1]) * s)) + v[0];
03518               float y2 = (((x - v[0]) * s) + ((y - v[1]) * c)) + v[1];
03519               x = x2;
03520               y = y2;
03521             }
03522             //qglTexCoord2f (pEclass->pTriList[i].st[j][0] / pEclass->nSkinWidth, pEclass->pTriList[i].st[j][1] / pEclass->nSkinHeight);
03523             qglTexCoord2f (model->pTriList[i].st[j][0], model->pTriList[i].st[j][1]);
03524             qglVertex3f(x, y, model->pTriList[i].v[j][2] + v[2]);
03525 #else
03526             float x = model->pTriList[i].v[j][0] + v[0];
03527             float y = model->pTriList[i].v[j][1] + v[1];
03528             float z = model->pTriList[i].v[j][2] + v[2];
03529 
03530             if (b->owner->vRotation[0])
03531             {
03532               float y2 = (((y - v[1]) * vCos[0]) - ((z - v[2]) * vSin[0])) + v[1];
03533               float z2 = (((y - v[1]) * vSin[0]) + ((z - v[2]) * vCos[0])) + v[2];
03534               y = y2;
03535               z = z2;
03536             }
03537             if (b->owner->vRotation[1])
03538             {
03539               float z2 = (((z - v[2]) * vCos[1]) - ((x - v[0]) * vSin[1])) + v[2];
03540               float x2 = (((z - v[2]) * vSin[1]) + ((x - v[0]) * vCos[1])) + v[0];
03541               x = x2;
03542               z = z2;
03543             }
03544             if (b->owner->vRotation[2])
03545             {
03546               float x2 = (((x - v[0]) * vCos[2]) - ((y - v[1]) * vSin[2])) + v[0];
03547               float y2 = (((x - v[0]) * vSin[2]) + ((y - v[1]) * vCos[2])) + v[1];
03548               x = x2;
03549               y = y2;
03550             }
03551             qglTexCoord2f (model->pTriList[i].st[j][0], model->pTriList[i].st[j][1]);
03552             qglVertex3f(x, y, z);
03553 #endif
03554             if (g_bDoIt)
03555             {
03556               vTest[j][0] = x;
03557               vTest[j][1] = y;
03558               vTest[j][2] = model->pTriList[i].v[j][2] + v[2];
03559               vTest[j][3] = model->pTriList[i].st[j][0];
03560               vTest[j][4] = model->pTriList[i].st[j][1];
03561             }
03562 
03563           }
03564           if (g_bDoIt)
03565           {
03566             Patch_FromTriangle(vTest[0], vTest[1], vTest[2]);
03567           }
03568         }
03569         qglEnd();
03570         if (g_PrefsDlg.m_nEntityShowState & ENTITY_WIREFRAME)   // skinned
03571         {
03572           qglEnable(GL_CULL_FACE );
03573           qglEnable(GL_TEXTURE_2D);
03574             qglPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
03575         }
03576         else
03577         {
03578             qglDisable(GL_TEXTURE_2D);
03579         }
03580         model = model->pNext;
03581       }
03582 
03583       if (g_bDoIt)
03584       {
03585         g_bDoIt = false;
03586       }
03587 
03588       vec3_t vColor;
03589       VectorScale(pEclass->color, 0.50, vColor);
03590 
03591       vec3_t vCenter, vMin, vMax;
03592       VectorCopy(b->owner->origin, vCenter);
03593 
03594           qglColor3fv(vColor);
03595       qglPointSize(4);
03596 
03597       qglBegin(GL_POINTS);
03598       qglVertex3fv(b->owner->origin);
03599       qglEnd();
03600 
03601       qglBegin(GL_LINES);
03602       vCenter[0] -= 8;
03603       qglVertex3fv(vCenter);
03604       vCenter[0] += 16;
03605       qglVertex3fv(vCenter);
03606       vCenter[0] -= 8;
03607       vCenter[1] -= 8;
03608       qglVertex3fv(vCenter);
03609       vCenter[1] += 16;
03610       qglVertex3fv(vCenter);
03611       vCenter[1] -= 8;
03612       vCenter[2] -= 8;
03613       qglVertex3fv(vCenter);
03614       vCenter[2] += 16;
03615       qglVertex3fv(vCenter);
03616       vCenter[2] -= 8;
03617       qglEnd();
03618 
03619       VectorCopy(vCenter, vMin);
03620       VectorCopy(vCenter, vMax);
03621       vMin[0] -= 4;
03622       vMin[1] -= 4;
03623       vMin[2] -= 4;
03624       vMax[0] += 4;
03625       vMax[1] += 4;
03626       vMax[2] += 4;
03627 
03628             qglBegin(GL_LINE_LOOP);
03629           qglVertex3f(vMin[0],vMin[1],vMin[2]);
03630           qglVertex3f(vMax[0],vMin[1],vMin[2]);
03631           qglVertex3f(vMax[0],vMax[1],vMin[2]);
03632           qglVertex3f(vMin[0],vMax[1],vMin[2]);
03633             qglEnd();
03634             
03635             qglBegin(GL_LINE_LOOP);
03636             qglVertex3f(vMin[0],vMin[1],vMax[2]);
03637               qglVertex3f(vMax[0],vMin[1],vMax[2]);
03638               qglVertex3f(vMax[0],vMax[1],vMax[2]);
03639               qglVertex3f(vMin[0],vMax[1],vMax[2]);
03640             qglEnd();
03641 
03642             qglBegin(GL_LINES);
03643             qglVertex3f(vMin[0],vMin[1],vMin[2]);
03644               qglVertex3f(vMin[0],vMin[1],vMax[2]);
03645               qglVertex3f(vMin[0],vMax[1],vMax[2]);
03646               qglVertex3f(vMin[0],vMax[1],vMin[2]);
03647               qglVertex3f(vMax[0],vMin[1],vMin[2]);
03648               qglVertex3f(vMax[0],vMin[1],vMax[2]);
03649               qglVertex3f(vMax[0],vMax[1],vMax[2]);
03650               qglVertex3f(vMax[0],vMax[1],vMin[2]);
03651             qglEnd();
03652 
03653 
03654         if (g_PrefsDlg.m_nEntityShowState & ENTITY_BOXED)
03655         {
03656             qglColor3fv(pEclass->color);
03657 
03658         vec3_t mins, maxs;
03659         VectorCopy(b->mins, mins);
03660         VectorCopy(b->maxs, maxs);
03661 /*
03662         if (a)
03663         {
03664           vec3_t vAngle;
03665           vAngle[0] = vAngle[1] = 0;
03666           vAngle[2] = a;
03667           VectorRotate(mins, vAngle, b->owner->origin, mins);
03668           VectorRotate(maxs, vAngle, b->owner->origin, maxs);
03669         }
03670 */
03671             qglBegin(GL_LINE_LOOP);
03672           qglVertex3f(mins[0],mins[1],mins[2]);
03673           qglVertex3f(maxs[0],mins[1],mins[2]);
03674           qglVertex3f(maxs[0],maxs[1],mins[2]);
03675           qglVertex3f(mins[0],maxs[1],mins[2]);
03676             qglEnd();
03677             
03678             qglBegin(GL_LINE_LOOP);
03679             qglVertex3f(mins[0],mins[1],maxs[2]);
03680               qglVertex3f(maxs[0],mins[1],maxs[2]);
03681               qglVertex3f(maxs[0],maxs[1],maxs[2]);
03682               qglVertex3f(mins[0],maxs[1],maxs[2]);
03683             qglEnd();
03684 
03685             qglBegin(GL_LINES);
03686             qglVertex3f(mins[0],mins[1],mins[2]);
03687               qglVertex3f(mins[0],mins[1],maxs[2]);
03688               qglVertex3f(mins[0],maxs[1],maxs[2]);
03689               qglVertex3f(mins[0],maxs[1],mins[2]);
03690               qglVertex3f(maxs[0],mins[1],mins[2]);
03691               qglVertex3f(maxs[0],mins[1],maxs[2]);
03692               qglVertex3f(maxs[0],maxs[1],maxs[2]);
03693               qglVertex3f(maxs[0],maxs[1],mins[2]);
03694             qglEnd();
03695       }
03696         qglPopAttrib();
03697       bReturn = true;
03698     }
03699     else
03700     {
03701       b->bModelFailed = true;
03702     }
03703 
03704   g_bInPaintedModel = false;
03705   return bReturn;
03706 }
03707 /*
03708 //++timo moved out to mahlib.h
03709 //++timo remove
03710 void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up)
03711 {
03712     float       angle;
03713     static float        sr, sp, sy, cr, cp, cy;
03714     // static to help MS compiler fp bugs
03715 
03716     angle = angles[YAW] * Q_PI / 180;
03717     sy = sin(angle);
03718     cy = cos(angle);
03719     angle = angles[PITCH] * Q_PI / 180;
03720     sp = sin(angle);
03721     cp = cos(angle);
03722     angle = angles[ROLL] * Q_PI / 180;
03723     sr = sin(angle);
03724     cr = cos(angle);
03725 
03726     if (forward)
03727     {
03728         forward[0] = cp*cy;
03729         forward[1] = cp*sy;
03730         forward[2] = -sp;
03731     }
03732     if (right)
03733     {
03734         right[0] = (-1*sr*sp*cy+-1*cr*-sy);
03735         right[1] = (-1*sr*sp*sy+-1*cr*cy);
03736         right[2] = -1*sr*cp;
03737     }
03738     if (up)
03739     {
03740         up[0] = (cr*sp*cy+-sr*-sy);
03741         up[1] = (cr*sp*sy+-sr*cy);
03742         up[2] = cr*cp;
03743     }
03744 }
03745 */
03746 void FacingVectors (entity_t *e, vec3_t forward, vec3_t right, vec3_t up)
03747 {
03748     int         angleVal;
03749     vec3_t      angles;
03750 
03751     angleVal = IntForKey(e, "angle");
03752     if (angleVal == -1)             // up
03753     {
03754         VectorSet(angles, 270, 0, 0);
03755     }
03756     else if(angleVal == -2)     // down
03757     {
03758         VectorSet(angles, 90, 0, 0);
03759     }
03760     else
03761     {
03762         VectorSet(angles, 0, angleVal, 0);
03763     }
03764 
03765     AngleVectors(angles, forward, right, up);
03766 }
03767 
03768 void Brush_DrawFacingAngle (brush_t *b, entity_t *e)
03769 {
03770     vec3_t  forward, right, up;
03771     vec3_t  endpoint, tip1, tip2;
03772     vec3_t  start;
03773     float   dist;
03774 
03775     VectorAdd(e->brushes.onext->mins, e->brushes.onext->maxs, start);
03776     VectorScale(start, 0.5, start);
03777     dist = (b->maxs[0] - start[0]) * 2.5;
03778 
03779     FacingVectors (e, forward, right, up);
03780     VectorMA (start, dist, forward, endpoint);
03781 
03782     dist = (b->maxs[0] - start[0]) * 0.5;
03783     VectorMA (endpoint, -dist, forward, tip1);
03784     VectorMA (tip1, -dist, up, tip1);
03785     VectorMA (tip1, 2*dist, up, tip2);
03786 
03787     qglColor4f (1, 1, 1, 1);
03788     qglLineWidth (4);
03789     qglBegin (GL_LINES);
03790     qglVertex3fv (start);
03791     qglVertex3fv (endpoint);
03792     qglVertex3fv (endpoint);
03793     qglVertex3fv (tip1);
03794     qglVertex3fv (endpoint);
03795     qglVertex3fv (tip2);
03796     qglEnd ();
03797     qglLineWidth (1);
03798 }
03799 
03800 void DrawLight(brush_t *b)
03801 {
03802     vec3_t vTriColor;
03803     bool bTriPaint = false;
03804 
03805   vTriColor[0] = vTriColor[2] = 1.0;
03806   vTriColor[1]  = 1.0;
03807   bTriPaint = true;
03808   CString strColor = ValueForKey(b->owner, "_color");
03809   if (strColor.GetLength() > 0)
03810   {
03811     float fR, fG, fB;
03812       int n = sscanf(strColor,"%f %f %f", &fR, &fG, &fB);
03813     if (n == 3)
03814     {
03815       vTriColor[0] = fR;
03816       vTriColor[1] = fG;
03817       vTriColor[2] = fB;
03818     }
03819   }
03820   qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
03821 
03822   vec3_t vCorners[4];
03823   float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
03824 
03825   vCorners[0][0] = b->mins[0];
03826   vCorners[0][1] = b->mins[1];
03827   vCorners[0][2] = fMid;
03828 
03829   vCorners[1][0] = b->mins[0];
03830   vCorners[1][1] = b->maxs[1];
03831   vCorners[1][2] = fMid;
03832 
03833   vCorners[2][0] = b->maxs[0];
03834   vCorners[2][1] = b->maxs[1];
03835   vCorners[2][2] = fMid;
03836 
03837   vCorners[3][0] = b->maxs[0];
03838   vCorners[3][1] = b->mins[1];
03839   vCorners[3][2] = fMid;
03840 
03841   vec3_t vTop, vBottom;
03842 
03843   vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
03844   vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
03845   vTop[2] = b->maxs[2];
03846 
03847   VectorCopy(vTop, vBottom);
03848   vBottom[2] = b->mins[2];
03849 
03850   vec3_t vSave;
03851   VectorCopy(vTriColor, vSave);
03852 
03853   qglBegin(GL_TRIANGLE_FAN);
03854   qglVertex3fv(vTop);
03855   for (int i = 0; i <= 3; i++)
03856   {
03857     vTriColor[0] *= 0.95;
03858     vTriColor[1] *= 0.95;
03859     vTriColor[2] *= 0.95;
03860     qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
03861     qglVertex3fv(vCorners[i]);
03862   }
03863   qglVertex3fv(vCorners[0]);
03864   qglEnd();
03865   
03866   VectorCopy(vSave, vTriColor);
03867   vTriColor[0] *= 0.95;
03868   vTriColor[1] *= 0.95;
03869   vTriColor[2] *= 0.95;
03870 
03871   qglBegin(GL_TRIANGLE_FAN);
03872   qglVertex3fv(vBottom);
03873   qglVertex3fv(vCorners[0]);
03874   for (i = 3; i >= 0; i--)
03875   {
03876     vTriColor[0] *= 0.95;
03877     vTriColor[1] *= 0.95;
03878     vTriColor[2] *= 0.95;
03879     qglColor3f(vTriColor[0], vTriColor[1], vTriColor[2]);
03880     qglVertex3fv(vCorners[i]);
03881   }
03882   qglEnd();
03883 
03884   // check for DOOM lights
03885   CString str = ValueForKey(b->owner, "light_right");
03886   if (str.GetLength() > 0) {
03887     vec3_t vRight, vUp, vTarget, vTemp;
03888     GetVectorForKey (b->owner, "light_right", vRight);
03889     GetVectorForKey (b->owner, "light_up", vUp);
03890     GetVectorForKey (b->owner, "light_target", vTarget);
03891 
03892     qglColor3f(0, 1, 0);
03893         qglBegin(GL_LINE_LOOP);
03894     VectorAdd(vTarget, b->owner->origin, vTemp);
03895     VectorAdd(vTemp, vRight, vTemp);
03896     VectorAdd(vTemp, vUp, vTemp);
03897     qglVertex3fv(b->owner->origin);
03898     qglVertex3fv(vTemp);
03899     VectorAdd(vTarget, b->owner->origin, vTemp);
03900     VectorAdd(vTemp, vUp, vTemp);
03901     VectorSubtract(vTemp, vRight, vTemp);
03902     qglVertex3fv(b->owner->origin);
03903     qglVertex3fv(vTemp);
03904     VectorAdd(vTarget, b->owner->origin, vTemp);
03905     VectorAdd(vTemp, vRight, vTemp);
03906     VectorSubtract(vTemp, vUp, vTemp);
03907     qglVertex3fv(b->owner->origin);
03908     qglVertex3fv(vTemp);
03909     VectorAdd(vTarget, b->owner->origin, vTemp);
03910     VectorSubtract(vTemp, vUp, vTemp);
03911     VectorSubtract(vTemp, vRight, vTemp);
03912     qglVertex3fv(b->owner->origin);
03913     qglVertex3fv(vTemp);
03914     qglEnd();
03915 
03916   }
03917 
03918 }
03919 
03920 void Brush_Draw( brush_t *b )
03921 {
03922     face_t          *face;
03923     int             i, order;
03924     qtexture_t      *prev = 0;
03925     winding_t *w;
03926 
03927     if ( b->owner && ( b->owner->eclass->nShowFlags & ECLASS_PLUGINENTITY ) )
03928     {
03929         b->owner->pPlugEnt->CamRender();
03930         return;
03931     }
03932     
03933     // (TTimo) NOTE: added by build 173, I check after pPlugEnt so it doesn't interfere ?
03934     if (b->hiddenBrush)
03935     {
03936         return;
03937     }
03938 
03939     if (b->patchBrush)
03940     {
03941         //Patch_DrawCam(b->nPatchID);
03942         Patch_DrawCam(b->pPatch);
03943         //if (!g_bPatchShowBounds)
03944         return;
03945     }
03946     
03947     if (b->terrainBrush)
03948     {
03949         Terrain_DrawCam(b->pTerrain);
03950         return;
03951     }
03952 
03953     int nDrawMode = g_pParentWnd->GetCamera()->Camera().draw_mode;
03954     
03955     if (b->owner->eclass->fixedsize)
03956     {
03957         
03958         if (!(g_qeglobals.d_savedinfo.exclude & EXCLUDE_ANGLES) && (b->owner->eclass->nShowFlags & ECLASS_ANGLE))
03959         {
03960             Brush_DrawFacingAngle(b, b->owner);
03961         }
03962         
03963         if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
03964         {
03965             DrawLight(b);
03966             return;
03967         }
03968         if (nDrawMode == cd_texture || nDrawMode == cd_light)
03969             qglDisable (GL_TEXTURE_2D);
03970         
03971         // if we are wireframing models
03972         bool bp = (b->bModelFailed) ? false : PaintedModel(b, true);
03973         
03974         if (nDrawMode == cd_texture || nDrawMode == cd_light)
03975             qglEnable (GL_TEXTURE_2D);
03976         
03977         if (bp)
03978             return;
03979     }
03980     
03981     // guarantee the texture will be set first
03982     prev = NULL;
03983     for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
03984     {
03985         w = face->face_winding;
03986         if (!w)
03987         {
03988             continue;       // freed face
03989         }
03990         
03991         if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CAULK)
03992         {
03993             if (strstr(face->texdef.name, "caulk"))
03994             {
03995                 continue;
03996             }
03997         }
03998         
03999 #if 0
04000         if (b->alphaBrush)
04001         {
04002             if (!(face->texdef.flags & SURF_ALPHA))
04003                 continue;
04004             //--qglPushAttrib(GL_ALL_ATTRIB_BITS);
04005             qglDisable(GL_CULL_FACE);
04006             //--qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
04007             //--qglBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
04008             //--qglDisable(GL_DEPTH_TEST);
04009             //--qglBlendFunc (GL_SRC_ALPHA, GL_DST_ALPHA);
04010             //--qglEnable (GL_BLEND);
04011         }
04012 #endif
04013         
04014         if ((nDrawMode == cd_texture || nDrawMode == cd_light) && face->d_texture != prev)
04015         {
04016             // set the texture for this face
04017             prev = face->d_texture;
04018             qglBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number );
04019         }
04020         
04021         
04022         
04023         if (!b->patchBrush)
04024         {
04025             if (face->texdef.flags & SURF_TRANS33) 
04026                 qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], 0.33 );
04027             else if ( face->texdef.flags & SURF_TRANS66) 
04028                 qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], 0.66 );
04029             else
04030                 qglColor3fv( face->d_color );
04031         }
04032         else
04033         {
04034             qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], 0.13 );
04035         }
04036         
04037         // shader drawing stuff
04038         if (face->d_texture->bFromShader)
04039         {
04040             // setup shader drawing
04041             qglColor4f ( face->d_color[0], face->d_color[1], face->d_color[2], face->d_texture->fTrans );
04042             
04043         }
04044         
04045         // draw the polygon
04046         
04047         //if (nDrawMode == cd_light)
04048         //{
04049         if (g_PrefsDlg.m_bGLLighting)
04050         {
04051             qglNormal3fv(face->plane.normal);
04052         }
04053         //}
04054         
04055         qglBegin(GL_POLYGON);
04056         //if (nDrawMode == cd_light)
04057         
04058         for (i=0 ; i<w->numpoints ; i++)
04059         {
04060             if (nDrawMode == cd_texture || nDrawMode == cd_light)
04061                 qglTexCoord2fv( &w->points[i][3] );
04062             qglVertex3fv(w->points[i]);
04063         }
04064         qglEnd();
04065     }
04066     
04067 #if 0
04068     if (b->alphaBrush)
04069     {
04070         //--qglPopAttrib();
04071         qglEnable(GL_CULL_FACE);
04072         //--qglDisable (GL_BLEND);
04073         //--qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
04074     }
04075 #endif
04076     
04077     if (b->owner->eclass->fixedsize && (nDrawMode == cd_texture || nDrawMode == cd_light))
04078         qglEnable (GL_TEXTURE_2D);
04079     
04080     qglBindTexture( GL_TEXTURE_2D, 0 );
04081 }
04082 
04083 
04084 
04085 void Face_Draw( face_t *f )
04086 {
04087     int i;
04088 
04089     if ( f->face_winding == 0 )
04090         return;
04091     qglBegin( GL_POLYGON );
04092     for ( i = 0 ; i < f->face_winding->numpoints; i++)
04093         qglVertex3fv( f->face_winding->points[i] );
04094     qglEnd();
04095 }
04096 
04097 void Brush_DrawXY(brush_t *b, int nViewType)
04098 {
04099     face_t *face;
04100     int     order;
04101     winding_t *w;
04102     int        i;
04103 
04104     if (b->hiddenBrush)
04105     {
04106         return;
04107     }
04108 
04109     if (b->patchBrush)
04110     {
04111         //Patch_DrawXY(b->nPatchID);
04112         Patch_DrawXY(b->pPatch);
04113         if (!g_bPatchShowBounds)
04114             return;
04115     }
04116 
04117     if (b->terrainBrush)
04118     {
04119         Terrain_DrawXY(b->pTerrain, b->owner);
04120     }
04121                      
04122 
04123     if (b->owner->eclass->fixedsize)
04124     {
04125         if (g_PrefsDlg.m_bNewLightDraw && (b->owner->eclass->nShowFlags & ECLASS_LIGHT))
04126         {
04127             vec3_t vCorners[4];
04128             float fMid = b->mins[2] + (b->maxs[2] - b->mins[2]) / 2;
04129 
04130             vCorners[0][0] = b->mins[0];
04131             vCorners[0][1] = b->mins[1];
04132             vCorners[0][2] = fMid;
04133 
04134             vCorners[1][0] = b->mins[0];
04135             vCorners[1][1] = b->maxs[1];
04136             vCorners[1][2] = fMid;
04137 
04138             vCorners[2][0] = b->maxs[0];
04139             vCorners[2][1] = b->maxs[1];
04140             vCorners[2][2] = fMid;
04141 
04142             vCorners[3][0] = b->maxs[0];
04143             vCorners[3][1] = b->mins[1];
04144             vCorners[3][2] = fMid;
04145 
04146             vec3_t vTop, vBottom;
04147 
04148             vTop[0] = b->mins[0] + ((b->maxs[0] - b->mins[0]) / 2);
04149             vTop[1] = b->mins[1] + ((b->maxs[1] - b->mins[1]) / 2);
04150             vTop[2] = b->maxs[2];
04151 
04152             VectorCopy(vTop, vBottom);
04153             vBottom[2] = b->mins[2];
04154 
04155             qglPolygonMode (GL_FRONT_AND_BACK, GL_LINE);
04156             qglBegin(GL_TRIANGLE_FAN);
04157             qglVertex3fv(vTop);
04158             qglVertex3fv(vCorners[0]);
04159             qglVertex3fv(vCorners[1]);
04160             qglVertex3fv(vCorners[2]);
04161             qglVertex3fv(vCorners[3]);
04162             qglVertex3fv(vCorners[0]);
04163             qglEnd();
04164             qglBegin(GL_TRIANGLE_FAN);
04165             qglVertex3fv(vBottom);
04166             qglVertex3fv(vCorners[0]);
04167             qglVertex3fv(vCorners[3]);
04168             qglVertex3fv(vCorners[2]);
04169             qglVertex3fv(vCorners[1]);
04170             qglVertex3fv(vCorners[0]);
04171             qglEnd();
04172             DrawBrushEntityName (b);
04173             return;
04174         }
04175         else if (b->owner->eclass->nShowFlags & ECLASS_MISCMODEL)
04176         {
04177             if (PaintedModel(b, false))
04178             return;
04179         }
04180     }
04181 
04182     for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++)
04183     {
04184         // only draw polygons facing in a direction we care about
04185     if (nViewType == XY)
04186     {
04187           if (face->plane.normal[2] <= 0)
04188               continue;
04189     }
04190     else
04191     {
04192       if (nViewType == XZ)
04193       {
04194         if (face->plane.normal[1] <= 0)
04195           continue;
04196       }
04197       else 
04198       {
04199         if (face->plane.normal[0] <= 0)
04200           continue;
04201       }
04202     }
04203 
04204         w = face->face_winding;
04205         if (!w)
04206             continue;
04207 
04208     //if (b->alphaBrush && !(face->texdef.flags & SURF_ALPHA))
04209     //  continue;
04210 
04211         // draw the polygon
04212         qglBegin(GL_LINE_LOOP);
04213     for (i=0 ; i<w->numpoints ; i++)
04214           qglVertex3fv(w->points[i]);
04215         qglEnd();
04216     }
04217 
04218     DrawBrushEntityName (b);
04219 
04220 }
04221 
04222 /*
04223 ============
04224 Brush_Move
04225 ============
04226 */
04227 void Brush_Move (brush_t *b, const vec3_t move, bool bSnap)
04228 {
04229   int i;
04230   face_t *f;
04231 
04232   for (f=b->brush_faces ; f ; f=f->next)
04233   {
04234     vec3_t vTemp;
04235     VectorCopy(move, vTemp);
04236 
04237     if (g_PrefsDlg.m_bTextureLock)
04238       Face_MoveTexture(f, vTemp);
04239     
04240     for (i=0 ; i<3 ; i++)
04241       VectorAdd (f->planepts[i], move, f->planepts[i]);
04242   }
04243   Brush_Build( b, bSnap );
04244 
04245 
04246   if (b->patchBrush)
04247   {
04248     //Patch_Move(b->nPatchID, move);
04249     Patch_Move(b->pPatch, move);
04250   }
04251 
04252   if (b->terrainBrush)
04253   {
04254     Terrain_Move(b->pTerrain, move);
04255   }
04256 
04257 
04258   // PGM - keep the origin vector up to date on fixed size entities.
04259   if(b->owner->eclass->fixedsize)
04260   {
04261     VectorAdd(b->owner->origin, move, b->owner->origin);
04262       //VectorAdd(b->maxs, b->mins, b->owner->origin);
04263       //VectorScale(b->owner->origin, 0.5, b->owner->origin);
04264   }
04265 }
04266 
04267 
04268 
04269 void Brush_Print(brush_t* b)
04270 {
04271   int nFace = 0;
04272   for (face_t* f = b->brush_faces ; f ; f=f->next)
04273   {
04274     Sys_Printf("Face %i\n", nFace++);
04275     Sys_Printf("%f %f %f\n", f->planepts[0][0], f->planepts[0][1], f->planepts[0][2]);
04276     Sys_Printf("%f %f %f\n", f->planepts[1][0], f->planepts[1][1], f->planepts[1][2]);
04277     Sys_Printf("%f %f %f\n", f->planepts[2][0], f->planepts[2][1], f->planepts[2][2]);
04278   }
04279  }
04280 
04281 
04282 
04283 /*
04284 =============
04285 Brush_MakeSided
04286 
04287 Makes the current brushhave the given number of 2d sides and turns it into a cone
04288 =============
04289 */
04290 void Brush_MakeSidedCone(int sides)
04291 {
04292     int     i;
04293     vec3_t  mins, maxs;
04294     brush_t *b;
04295     texdef_t    *texdef;
04296     face_t  *f;
04297     vec3_t  mid;
04298     float   width;
04299     float   sv, cv;
04300 
04301     if (sides < 3)
04302     {
04303         Sys_Status ("Bad sides number", 0);
04304         return;
04305     }
04306 
04307     if (!QE_SingleBrush ())
04308     {
04309         Sys_Status ("Must have a single brush selected", 0 );
04310         return;
04311     }
04312 
04313     b = selected_brushes.next;
04314     VectorCopy (b->mins, mins);
04315     VectorCopy (b->maxs, maxs);
04316     texdef = &g_qeglobals.d_texturewin.texdef;
04317 
04318     Brush_Free (b);
04319 
04320     // find center of brush
04321     width = 8;
04322     for (i=0 ; i<2 ; i++)
04323     {
04324         mid[i] = (maxs[i] + mins[i])*0.5;
04325         if (maxs[i] - mins[i] > width)
04326             width = maxs[i] - mins[i];
04327     }
04328     width /= 2;
04329 
04330     b = Brush_Alloc();
04331 
04332     // create bottom face
04333     f = Face_Alloc();
04334     f->texdef = *texdef;
04335     f->next = b->brush_faces;
04336     b->brush_faces = f;
04337 
04338     f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2];
04339     f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2];
04340     f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2];
04341 
04342     for (i=0 ; i<sides ; i++)
04343     {
04344         f = Face_Alloc();
04345         f->texdef = *texdef;
04346         f->next = b->brush_faces;
04347         b->brush_faces = f;
04348 
04349         sv = sin (i*3.14159265*2/sides);
04350         cv = cos (i*3.14159265*2/sides);
04351 
04352 
04353         f->planepts[0][0] = floor(mid[0]+width*cv+0.5);
04354         f->planepts[0][1] = floor(mid[1]+width*sv+0.5);
04355         f->planepts[0][2] = mins[2];
04356 
04357         f->planepts[1][0] = mid[0];
04358         f->planepts[1][1] = mid[1];
04359         f->planepts[1][2] = maxs[2];
04360 
04361         f->planepts[2][0] = floor(f->planepts[0][0] - width * sv + 0.5);
04362         f->planepts[2][1] = floor(f->planepts[0][1] + width * cv + 0.5);
04363         f->planepts[2][2] = maxs[2];
04364 
04365     }
04366 
04367     Brush_AddToList (b, &selected_brushes);
04368 
04369     Entity_LinkBrush (world_entity, b);
04370 
04371     Brush_Build( b );
04372 
04373     Sys_UpdateWindows (W_ALL);
04374 }
04375 
04376 /*
04377 =============
04378 Brush_MakeSided
04379 
04380 Makes the current brushhave the given number of 2d sides and turns it into a sphere
04381 =============
04382 
04383 */
04384 void Brush_MakeSidedSphere(int sides)
04385 {
04386     int     i,j;
04387     vec3_t  mins, maxs;
04388     brush_t *b;
04389     texdef_t    *texdef;
04390     face_t  *f;
04391     vec3_t  mid;
04392 
04393     if (sides < 4)
04394     {
04395         Sys_Status ("Bad sides number", 0);
04396         return;
04397     }
04398 
04399     if (!QE_SingleBrush ())
04400     {
04401         Sys_Status ("Must have a single brush selected", 0 );
04402         return;
04403     }
04404 
04405     b = selected_brushes.next;
04406     VectorCopy (b->mins, mins);
04407     VectorCopy (b->maxs, maxs);
04408     texdef = &g_qeglobals.d_texturewin.texdef;
04409 
04410     Brush_Free (b);
04411 
04412     // find center of brush
04413     float radius = 8;
04414     for (i=0 ; i<2 ; i++)
04415     {
04416         mid[i] = (maxs[i] + mins[i])*0.5;
04417         if (maxs[i] - mins[i] > radius)
04418             radius = maxs[i] - mins[i];
04419     }
04420     radius /= 2;
04421 
04422     b = Brush_Alloc();
04423 
04424     float dt = float(2 * Q_PI / sides);
04425     float dp = float(Q_PI / sides);
04426   float t,p;
04427     for(i=0; i <= sides-1; i++)
04428   {
04429         for(j=0;j <= sides-2; j++)
04430         {
04431             t = i * dt;
04432             p = float(j * dp - Q_PI / 2);
04433 
04434       f = Face_Alloc();
04435         f->texdef = *texdef;
04436         f->next = b->brush_faces;
04437         b->brush_faces = f;
04438 
04439       VectorPolar(f->planepts[0], radius, t, p);
04440       VectorPolar(f->planepts[1], radius, t, p + dp);
04441       VectorPolar(f->planepts[2], radius, t + dt, p + dp);
04442 
04443       for (int k = 0; k < 3; k++)
04444         VectorAdd(f->planepts[k], mid, f->planepts[k]);
04445         }
04446   }
04447 
04448   p = float((sides - 1) * dp - Q_PI / 2);
04449     for(i = 0; i <= sides-1; i++)
04450     {
04451         t = i * dt;
04452 
04453     f = Face_Alloc();
04454       f->texdef = *texdef;
04455       f->next = b->brush_faces;
04456       b->brush_faces = f;
04457 
04458     VectorPolar(f->planepts[0], radius, t, p);
04459     VectorPolar(f->planepts[1], radius, t + dt, p + dp);
04460     VectorPolar(f->planepts[2], radius, t + dt, p);
04461 
04462     for (int k = 0; k < 3; k++)
04463       VectorAdd(f->planepts[k], mid, f->planepts[k]);
04464     }
04465 
04466     Brush_AddToList (b, &selected_brushes);
04467 
04468     Entity_LinkBrush (world_entity, b);
04469 
04470     Brush_Build( b );
04471 
04472     Sys_UpdateWindows (W_ALL);
04473 }
04474 
04475 void Face_FitTexture( face_t * face, int nHeight, int nWidth )
04476 {
04477   winding_t *w;
04478   vec3_t   mins,maxs;
04479   int i;
04480   float width, height, temp;
04481   float rot_width, rot_height;
04482   float cosv,sinv,ang;
04483   float min_t, min_s, max_t, max_s;
04484   float s,t;
04485     vec3_t  vecs[2];
04486   vec3_t   coords[4];
04487     texdef_t    *td;
04488 
04489   if (nHeight < 1)
04490   {
04491     nHeight = 1;
04492   }
04493   if (nWidth < 1)
04494   {
04495     nWidth = 1;
04496   }
04497 
04498   ClearBounds (mins, maxs);
04499 
04500     td = &face->texdef;
04501     w = face->face_winding;
04502     if (!w)
04503     {
04504     return;
04505     }
04506   for (i=0 ; i<w->numpoints ; i++)
04507   {
04508     AddPointToBounds( w->points[i], mins, maxs );
04509   }
04510    // 
04511    // get the current angle
04512    //
04513     ang = td->rotate / 180 * Q_PI;
04514     sinv = sin(ang);
04515     cosv = cos(ang);
04516 
04517     // get natural texture axis
04518     TextureAxisFromPlane(&face->plane, vecs[0], vecs[1]);
04519 
04520   min_s = DotProduct( mins, vecs[0] );
04521   min_t = DotProduct( mins, vecs[1] );
04522   max_s = DotProduct( maxs, vecs[0] );
04523   max_t = DotProduct( maxs, vecs[1] );
04524   width = max_s - min_s;
04525   height = max_t - min_t;
04526   coords[0][0] = min_s;
04527   coords[0][1] = min_t;
04528   coords[1][0] = max_s;
04529   coords[1][1] = min_t;
04530   coords[2][0] = min_s;
04531   coords[2][1] = max_t;
04532   coords[3][0] = max_s;
04533   coords[3][1] = max_t;
04534   min_s = min_t = 99999;
04535   max_s = max_t = -99999;
04536   for (i=0; i<4; i++)
04537   {
04538     s = cosv * coords[i][0] - sinv * coords[i][1];
04539       t = sinv * coords[i][0] + cosv * coords[i][1];
04540     if (i&1)
04541     {
04542       if (s > max_s) 
04543       {
04544         max_s = s;
04545       }
04546     }
04547     else
04548     {
04549       if (s < min_s) 
04550       {
04551         min_s = s;
04552       }
04553       if (i<2)
04554       {
04555         if (t < min_t) 
04556         {
04557           min_t = t;
04558         }
04559       }
04560       else
04561       {
04562         if (t > max_t) 
04563         {
04564           max_t = t;
04565         }
04566       }
04567     }
04568   }
04569   rot_width =  (max_s - min_s);
04570   rot_height = (max_t - min_t);
04571   td->scale[0] = -(rot_width/((float)(face->d_texture->width*nWidth)));
04572   td->scale[1] = -(rot_height/((float)(face->d_texture->height*nHeight)));
04573 
04574   td->shift[0] = min_s/td->scale[0];
04575   temp = (int)(td->shift[0] / (face->d_texture->width*nWidth));
04576   temp = (temp+1)*face->d_texture->width*nWidth;
04577   td->shift[0] = (int)(temp - td->shift[0])%(face->d_texture->width*nWidth);
04578 
04579   td->shift[1] = min_t/td->scale[1];
04580   temp = (int)(td->shift[1] / (face->d_texture->height*nHeight));
04581   temp = (temp+1)*(face->d_texture->height*nHeight);
04582   td->shift[1] = (int)(temp - td->shift[1])%(face->d_texture->height*nHeight);
04583 }
04584 
04585 void Brush_FitTexture( brush_t *b, int nHeight, int nWidth )
04586 {
04587     face_t *face;
04588 
04589     for (face = b->brush_faces ; face ; face=face->next)
04590   {
04591     Face_FitTexture( face, nHeight, nWidth );
04592   }
04593 }
04594 
04595 

Generated on Thu Aug 25 12:38:26 2005 for Quake III Arena by  doxygen 1.3.9.1