Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

Brush.cpp (107620B)


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