Quake-III-Arena

Quake III Arena GPL Source Release
Log | Files | Refs

SELECT.CPP (40721B)


      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 // select.c
     23 #include "stdafx.h"
     24 #include "qe3.h"
     25 
     26 
     27 // externs
     28 CPtrArray g_SelectedFaces;
     29 CPtrArray g_SelectedFaceBrushes;
     30 CPtrArray& g_ptrSelectedFaces = g_SelectedFaces;
     31 CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes;
     32 
     33 
     34 void clearSelection() {
     35 	g_qeglobals.d_select_mode = sel_brush;
     36 	g_qeglobals.selectObject = NULL;
     37 }
     38 
     39 /*
     40 ===========
     41 Test_Ray
     42 ===========
     43 */
     44 #define	DIST_START	999999
     45 trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags)
     46 {
     47 	brush_t	*brush;
     48 	face_t	*face;
     49 	float	dist;
     50 	trace_t	t;
     51 
     52 	memset (&t, 0, sizeof(t));
     53 	t.dist = DIST_START;
     54 
     55 	if (flags & SF_CYCLE)
     56 	{
     57 		CPtrArray array;
     58 		brush_t *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL;
     59 		Select_Deselect();
     60 
     61 		// go through active brushes and accumulate all "hit" brushes
     62 		for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
     63 		{
     64 			//if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
     65 			//  continue;
     66 		 
     67 			if (FilterBrush (brush))
     68 				continue;
     69 
     70 			if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
     71 				continue;
     72 
     73 			if( !g_PrefsDlg.m_bSelectTerrain && brush->terrainBrush )
     74 				continue;
     75 
     76 			//if (!g_bShowPatchBounds && brush->patchBrush)
     77 			//  continue;
     78 
     79 			face = Brush_Ray (origin, dir, brush, &dist);
     80 
     81 			if (face)
     82 			{
     83 				if ( brush->terrainBrush )
     84 				{
     85 					Terrain_Ray( origin, dir, brush, &dist );
     86 					if( dist == 0 )
     87 					{
     88 						// didn't actually hit the terrain
     89 						continue;
     90 					}
     91 				}
     92 				array.Add(brush);
     93 			}
     94 		}
     95 
     96 		int nSize = array.GetSize();
     97 		if (nSize > 0)
     98 		{
     99 			bool bFound = false;
    100 			for (int i = 0; i < nSize; i++)
    101 			{
    102 				brush_t *b = reinterpret_cast<brush_t*>(array.GetAt(i));
    103 				// did we hit the last one selected yet ?
    104 				if (b == pToSelect)
    105 				{
    106 					// yes we want to select the next one in the list 
    107 					int n = (i > 0) ? i-1 : nSize-1;
    108 					pToSelect = reinterpret_cast<brush_t*>(array.GetAt(n));
    109 					bFound = true;
    110 					break;
    111 				}
    112 			}
    113 			if (!bFound)
    114 				pToSelect = reinterpret_cast<brush_t*>(array.GetAt(0));
    115 		}
    116 		if (pToSelect)
    117 		{
    118 			face = Brush_Ray (origin, dir, pToSelect, &dist);
    119 			if ( pToSelect->terrainBrush )
    120 			{
    121 				t.terraface = Terrain_Ray( origin, dir, pToSelect, &dist );
    122 			}
    123 
    124 			t.dist = dist;
    125 			t.brush = pToSelect;
    126 			t.face = face;
    127 			t.selected = false;
    128 			return t;
    129 		}
    130 	}
    131 
    132 	if (! (flags & SF_SELECTED_ONLY) )
    133 	{
    134 		for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
    135 		{
    136 			if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
    137 				continue;
    138 			
    139 			if (FilterBrush (brush))
    140 				continue;
    141 
    142 			if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
    143 				continue;
    144 
    145 			if( !g_PrefsDlg.m_bSelectTerrain && brush->terrainBrush )
    146 				continue;
    147 
    148 			//if (!g_bShowPatchBounds && brush->patchBrush)
    149 			//  continue;
    150 
    151 			face = Brush_Ray (origin, dir, brush, &dist);
    152 			if ( face ) {
    153 				if ( brush->terrainBrush )
    154 				{
    155 					t.terraface = Terrain_Ray( origin, dir, brush, &dist );
    156 				}
    157 			}
    158 			if (dist > 0 && dist < t.dist)
    159 			{
    160 				t.dist = dist;
    161 				t.brush = brush;
    162 				t.face = face;
    163 				t.selected = false;
    164 			}
    165 		}
    166 	}
    167 
    168 
    169 	for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
    170 	{
    171 		if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
    172 			continue;
    173 
    174 		if (FilterBrush (brush))
    175 			continue;
    176 
    177 		if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
    178 			continue;
    179 
    180 		if( !g_PrefsDlg.m_bSelectTerrain && brush->terrainBrush )
    181 			continue;
    182 
    183 		face = Brush_Ray (origin, dir, brush, &dist);
    184 		if ( face ) {
    185 			if ( brush->terrainBrush )
    186 			{
    187 				t.terraface = Terrain_Ray( origin, dir, brush, &dist );
    188 			}
    189 		}
    190 		if (dist > 0 && dist < t.dist)
    191 		{
    192 			t.dist = dist;
    193 			t.brush = brush;
    194 			t.face = face;
    195 			t.selected = true;
    196 		}
    197 	}
    198 
    199 	// if entites first, but didn't find any, check regular
    200 
    201 	if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL)
    202 		return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST);
    203 
    204 	return t;
    205 
    206 }
    207 
    208 
    209 /*
    210 ============
    211 Select_Brush
    212 
    213 ============
    214 */
    215 void Select_Brush (brush_t *brush, bool bComplete, bool bStatus)
    216 {
    217 	brush_t	*b;
    218 	entity_t	*e;
    219 
    220   g_ptrSelectedFaces.RemoveAll();
    221   g_ptrSelectedFaceBrushes.RemoveAll();
    222 	//selected_face = NULL;
    223 	if (g_qeglobals.d_select_count < 2)
    224 		g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
    225 	g_qeglobals.d_select_count++;
    226 
    227   //if (brush->patchBrush)
    228   //  Patch_Select(brush->nPatchID);
    229 
    230 	e = brush->owner;
    231 	if (e)
    232 	{
    233 		// select complete entity on first click
    234 		if (e != world_entity && bComplete == true)
    235 		{
    236 			for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
    237 				if (b->owner == e)
    238 					goto singleselect;
    239 			for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
    240 			{
    241         Brush_RemoveFromList (b);
    242 				Brush_AddToList (b, &selected_brushes);
    243 			}
    244 		}
    245 		else
    246 		{
    247 singleselect:
    248 			Brush_RemoveFromList (brush);
    249 			Brush_AddToList (brush, &selected_brushes);
    250       UpdateSurfaceDialog();
    251       UpdatePatchInspector();
    252 		}
    253 
    254 		if (e->eclass)
    255 		{
    256 			UpdateEntitySel(brush->owner->eclass);
    257 		}
    258 	}
    259   if (bStatus)
    260   {
    261     vec3_t vMin, vMax, vSize;
    262 	  Select_GetBounds (vMin, vMax);
    263     VectorSubtract(vMax, vMin, vSize);
    264     CString strStatus;
    265     strStatus.Format("Selection X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
    266     g_pParentWnd->SetStatusText(2, strStatus);
    267   }
    268 }
    269 
    270 
    271 /*
    272 ============
    273 Select_Ray
    274 
    275 If the origin is inside a brush, that brush will be ignored.
    276 ============
    277 */
    278 void Select_Ray (vec3_t origin, vec3_t dir, int flags)
    279 {
    280 	trace_t	t;
    281 
    282 	t = Test_Ray (origin, dir, flags);
    283 	if (!t.brush)
    284 		return;
    285 
    286 	if (flags == SF_SINGLEFACE)
    287 	{
    288 		int nCount = g_SelectedFaces.GetSize();
    289 		bool bOk = true;
    290 		for (int i = 0; i < nCount; i++)
    291 		{
    292 			if (t.face == reinterpret_cast<face_t*>(g_SelectedFaces.GetAt(i)))
    293 			{
    294 				bOk = false;
    295 				// need to move remove i'th entry
    296 				g_SelectedFaces.RemoveAt(i, 1);
    297 				g_SelectedFaceBrushes.RemoveAt(i, 1);
    298 			}
    299 		}
    300 		if (bOk)
    301 		{
    302 			g_SelectedFaces.Add(t.face);
    303 			g_SelectedFaceBrushes.Add(t.brush);
    304 		}
    305 		//selected_face = t.face;
    306 		//selected_face_brush = t.brush;
    307 		Sys_UpdateWindows (W_ALL);
    308 		clearSelection();
    309 		// Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture
    310 		brushprimit_texdef_t brushprimit_texdef;
    311 		ConvertTexMatWithQTexture ( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL );
    312 		Texture_SetTexture ( &t.face->texdef, &brushprimit_texdef, false, GETPLUGINTEXDEF(t.face), false );
    313 		UpdateSurfaceDialog();
    314 		return;
    315 	}
    316 
    317 	// move the brush to the other list
    318 
    319 	clearSelection();
    320 
    321 	if (t.selected)
    322 	{		
    323 		Brush_RemoveFromList (t.brush);
    324 		Brush_AddToList (t.brush, &active_brushes);
    325 		UpdatePatchInspector();
    326 	} 
    327 	else
    328 	{
    329 		Select_Brush (t.brush, !(GetKeyState(VK_MENU) & 0x8000));
    330 	}
    331 
    332 	Sys_UpdateWindows (W_ALL);
    333 }
    334 
    335 
    336 void Select_Delete (void)
    337 {
    338 	brush_t	*brush;
    339 
    340   g_ptrSelectedFaces.RemoveAll();
    341   g_ptrSelectedFaceBrushes.RemoveAll();
    342 	//selected_face = NULL;
    343 	
    344 	clearSelection();
    345 
    346 	g_qeglobals.d_select_count = 0;
    347 	g_qeglobals.d_num_move_points = 0;
    348 	while (selected_brushes.next != &selected_brushes)
    349 	{
    350 		brush = selected_brushes.next;
    351     if (brush->patchBrush)
    352     {
    353       //Patch_Delete(brush->nPatchID);
    354       Patch_Delete(brush->pPatch);
    355     }
    356 	if (brush->terrainBrush)
    357 	{
    358 		Terrain_Delete(brush->pTerrain );
    359 	}
    360 
    361 		Brush_Free (brush);
    362 	}
    363 
    364 	// FIXME: remove any entities with no brushes
    365 
    366 	Sys_UpdateWindows (W_ALL);
    367 }
    368 
    369 void Select_Deselect (bool bDeselectFaces)
    370 {
    371 	brush_t	*b;
    372 
    373   Patch_Deselect();
    374 
    375   g_pParentWnd->ActiveXY()->UndoClear();
    376 
    377   g_qeglobals.d_workcount++;
    378 	g_qeglobals.d_select_count = 0;
    379 	g_qeglobals.d_num_move_points = 0;
    380 	b = selected_brushes.next;
    381 
    382 	if (b == &selected_brushes)
    383 	{
    384 		if (bDeselectFaces)
    385 		{
    386 			g_ptrSelectedFaces.RemoveAll();
    387       g_ptrSelectedFaceBrushes.RemoveAll();
    388       //selected_face = NULL;
    389 		}
    390  		Sys_UpdateWindows (W_ALL);
    391 		return;
    392 	}
    393 
    394   if (bDeselectFaces)
    395   {
    396   	g_ptrSelectedFaces.RemoveAll();
    397     g_ptrSelectedFaceBrushes.RemoveAll();
    398 	  //selected_face = NULL;
    399   }
    400 
    401 	clearSelection();
    402 
    403 	// grab top / bottom height for new brushes
    404 	if (b->mins[2] < b->maxs[2])
    405 	{
    406 		g_qeglobals.d_new_brush_bottom_z = b->mins[2];
    407 		g_qeglobals.d_new_brush_top_z = b->maxs[2];
    408 	}
    409 
    410 	selected_brushes.next->prev = &active_brushes;
    411 	selected_brushes.prev->next = active_brushes.next;
    412 	active_brushes.next->prev = selected_brushes.prev;
    413 	active_brushes.next = selected_brushes.next;
    414 	selected_brushes.prev = selected_brushes.next = &selected_brushes;	
    415 
    416 	Sys_UpdateWindows (W_ALL);
    417 }
    418 
    419 /*
    420 ============
    421 Select_Move
    422 ============
    423 */
    424 void Select_Move (vec3_t delta, bool bSnap)
    425 {
    426 	brush_t	*b;
    427   
    428  
    429 // actually move the selected brushes
    430 	for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
    431 		Brush_Move (b, delta, bSnap);
    432 
    433   vec3_t vMin, vMax;
    434 	Select_GetBounds (vMin, vMax);
    435   CString strStatus;
    436   strStatus.Format("Origin X:: %.1f  Y:: %.1f  Z:: %.1f", vMin[0], vMax[1], vMax[2]);
    437   g_pParentWnd->SetStatusText(2, strStatus);
    438 
    439 //	Sys_UpdateWindows (W_ALL);
    440 }
    441 
    442 /*
    443 ============
    444 Select_Clone
    445 
    446 Creates an exact duplicate of the selection in place, then moves
    447 the selected brushes off of their old positions
    448 ============
    449 */
    450 void Select_Clone (void)
    451 {
    452 #if 1
    453   ASSERT(g_pParentWnd->ActiveXY());
    454   g_bScreenUpdates = false;  
    455   g_pParentWnd->ActiveXY()->Copy();
    456   g_pParentWnd->ActiveXY()->Paste();
    457   g_pParentWnd->NudgeSelection(2, g_qeglobals.d_gridsize);
    458   g_pParentWnd->NudgeSelection(3, g_qeglobals.d_gridsize);
    459   g_bScreenUpdates = true;  
    460   Sys_UpdateWindows(W_ALL);
    461 #else
    462 
    463 	brush_t		*b, *b2, *n, *next, *next2;
    464 	vec3_t		delta;
    465 	entity_t	*e;
    466 
    467 	g_qeglobals.d_workcount++;
    468 	clearSelection();
    469 
    470 	delta[0] = g_qeglobals.d_gridsize;
    471 	delta[1] = g_qeglobals.d_gridsize;
    472 	delta[2] = 0;
    473 
    474 	for (b=selected_brushes.next ; b != &selected_brushes ; b=next)
    475 	{
    476 		next = b->next;
    477 		// if the brush is a world brush, handle simply
    478 		if (b->owner == world_entity)
    479 		{
    480 			n = Brush_Clone (b);
    481 			Brush_AddToList (n, &active_brushes);
    482 			Entity_LinkBrush (world_entity, n);
    483 			Brush_Build( n );
    484 			Brush_Move (b, delta);
    485 			continue;
    486 		}
    487 
    488 		e = Entity_Clone (b->owner);
    489 		// clear the target / targetname
    490 		DeleteKey (e, "target");
    491 		DeleteKey (e, "targetname");
    492 
    493 		// if the brush is a fixed size entity, create a new entity
    494 		if (b->owner->eclass->fixedsize)
    495 		{
    496 			n = Brush_Clone (b);
    497 			Brush_AddToList (n, &active_brushes);
    498 			Entity_LinkBrush (e, n);
    499 			Brush_Build( n );
    500 			Brush_Move (b, delta);
    501 			continue;
    502 		}
    503         
    504 		// brush is a complex entity, grab all the other ones now
    505 
    506 		next = &selected_brushes;
    507 
    508 		for ( b2 = b ; b2 != &selected_brushes ; b2=next2)
    509 		{
    510 			next2 = b2->next;
    511 			if (b2->owner != b->owner)
    512 			{
    513 				if (next == &selected_brushes)
    514 					next = b2;
    515 				continue;
    516 			}
    517 
    518 			// move b2 to the start of selected_brushes,
    519 			// so it won't be hit again
    520 			Brush_RemoveFromList (b2);
    521 			Brush_AddToList (b2, &selected_brushes);
    522 			
    523 			n = Brush_Clone (b2);
    524 			Brush_AddToList (n, &active_brushes);
    525 			Entity_LinkBrush (e, n);
    526 			Brush_Build( n );
    527 			Brush_Move (b2, delta, true);
    528 		}
    529 
    530 	}
    531 	Sys_UpdateWindows (W_ALL);
    532 #endif
    533 }
    534 
    535 
    536 
    537 /*
    538 ============
    539 Select_SetTexture
    540 Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping
    541 Timo :	brush primitive texturing
    542 		the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes )
    543 Timo :  texture plugin, added an IPluginTexdef* parameter
    544 		must be casted to an IPluginTexdef!
    545 		if not NULL, get ->Copy() of it into each face or brush ( and remember to hook )
    546 		if NULL, means we have no information, ask for a default
    547 ============
    548 */
    549 void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef )
    550 {
    551 	brush_t	*b;
    552 	int nCount = g_ptrSelectedFaces.GetSize();
    553 	if (nCount > 0)
    554 	{
    555 		Undo_Start("set face textures");
    556 		ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize());
    557 		for (int i = 0; i < nCount; i++)
    558 		{
    559 			face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
    560 			brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
    561 			Undo_AddBrush(selBrush);
    562 			SetFaceTexdef (selBrush, selFace, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>(pPlugTexdef) );
    563 			Brush_Build(selBrush, bFitScale);
    564 			Undo_EndBrush(selBrush);
    565 		}
    566 		Undo_End();
    567 	}
    568 	else if (selected_brushes.next != &selected_brushes)
    569 	{
    570 		Undo_Start("set brush textures");
    571 		for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
    572 			if (!b->owner->eclass->fixedsize)
    573 			{
    574 				Undo_AddBrush(b);
    575 				Brush_SetTexture (b, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>(pPlugTexdef) );
    576 				Undo_EndBrush(b);
    577 			}
    578 		Undo_End();
    579 	}
    580 	Sys_UpdateWindows (W_ALL);
    581 }
    582 
    583 
    584 /*
    585 ================================================================
    586 
    587   TRANSFORMATIONS
    588 
    589 ================================================================
    590 */
    591 
    592 void Select_GetBounds (vec3_t mins, vec3_t maxs)
    593 {
    594 	brush_t	*b;
    595 	int		i;
    596 
    597 	for (i=0 ; i<3 ; i++)
    598 	{
    599 		mins[i] = 99999;
    600 		maxs[i] = -99999;
    601 	}
    602 
    603 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
    604 		for (i=0 ; i<3 ; i++)
    605 		{
    606 			if (b->mins[i] < mins[i])
    607 				mins[i] = b->mins[i];
    608 			if (b->maxs[i] > maxs[i])
    609 				maxs[i] = b->maxs[i];
    610 		}
    611 }
    612 
    613 
    614 void Select_GetTrueMid (vec3_t mid)
    615 {
    616 	vec3_t	mins, maxs;
    617 	Select_GetBounds (mins, maxs);
    618 
    619   for (int i=0 ; i<3 ; i++)
    620     mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
    621 }
    622 
    623 
    624 void Select_GetMid (vec3_t mid)
    625 {
    626 	vec3_t	mins, maxs;
    627 	int		i;
    628 
    629   if (g_PrefsDlg.m_bNoClamp)
    630   {
    631     Select_GetTrueMid(mid);
    632     return;
    633   }
    634 
    635   Select_GetBounds (mins, maxs);
    636 
    637   for (i=0 ; i<3 ; i++)
    638 		mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize );
    639 
    640 }
    641 
    642 vec3_t	select_origin;
    643 vec3_t	select_matrix[3];
    644 qboolean	select_fliporder;
    645 
    646 void Select_ApplyMatrix (bool bSnap, bool bRotation, int nAxis, float fDeg)
    647 {
    648 	brush_t	*b;
    649 	face_t	*f;
    650 	int		i, j;
    651 	vec3_t	temp;
    652 
    653 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
    654 	{
    655 		for (f=b->brush_faces ; f ; f=f->next)
    656 		{
    657 			for (i=0 ; i<3 ; i++)
    658 			{
    659 				VectorSubtract (f->planepts[i], select_origin, temp);
    660 				for (j=0 ; j<3 ; j++)
    661 					f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + select_origin[j];
    662 			}
    663 			if (select_fliporder)
    664 			{
    665 				VectorCopy (f->planepts[0], temp);
    666 				VectorCopy (f->planepts[2], f->planepts[0]);
    667 				VectorCopy (temp, f->planepts[2]);
    668 			}
    669 		}
    670 
    671 		if(b->owner->eclass->fixedsize)
    672 		{
    673 			if (bRotation && b->owner->md3Class)
    674 			{
    675 				b->owner->vRotation[nAxis] += fDeg;
    676 			}
    677 		}
    678 
    679 		Brush_Build(b, bSnap);
    680     
    681 		if (b->patchBrush)
    682 		{
    683 			//Patch_ApplyMatrix(b->nPatchID, select_origin, select_matrix);
    684 			Patch_ApplyMatrix(b->pPatch, select_origin, select_matrix, bSnap);
    685 		}
    686 
    687 		if (b->terrainBrush)
    688 		{
    689 		  Terrain_ApplyMatrix(b->pTerrain, select_origin, select_matrix, bSnap);
    690 		}
    691 
    692 	}
    693 }
    694 
    695 void ProjectOnPlane(vec3_t& normal,float dist,vec3_t& ez, vec3_t& p)
    696 {
    697 	if (fabs(ez[0]) == 1)
    698 		p[0] = (dist - normal[1] * p[1] - normal[2] * p[2]) / normal[0];
    699 	else if (fabs(ez[1]) == 1)
    700 		p[1] = (dist - normal[0] * p[0] - normal[2] * p[2]) / normal[1];
    701 	else
    702 		p[2] = (dist - normal[0] * p[0] - normal[1] * p[1]) / normal[2];
    703 }
    704 
    705 void Back(vec3_t& dir, vec3_t& p)
    706 {
    707 	if (fabs(dir[0]) == 1)
    708 		p[0] = 0;
    709 	else if (fabs(dir[1]) == 1)
    710 		p[1] = 0;
    711 	else p[2] = 0;
    712 }
    713 
    714 
    715 
    716 // using scale[0] and scale[1]
    717 void ComputeScale(vec3_t& rex, vec3_t& rey, vec3_t& p, face_t* f)
    718 {
    719 	float px = DotProduct(rex, p);
    720 	float py = DotProduct(rey, p);
    721 	px *= f->texdef.scale[0];
    722 	py *= f->texdef.scale[1];
    723   vec3_t aux;
    724   VectorCopy(rex, aux);
    725   VectorScale(aux, px, aux);
    726   VectorCopy(aux, p);
    727   VectorCopy(rey, aux);
    728   VectorScale(aux, py, aux);
    729   VectorAdd(p, aux, p);
    730 }
    731 
    732 void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3)
    733 {
    734 	vec3_t ex,ey,ez;	        // local axis base
    735 
    736 #ifdef _DEBUG
    737 	if (g_qeglobals.m_bBrushPrimitMode)
    738 		Sys_Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n");
    739 #endif
    740 
    741   // compute first local axis base
    742   TextureAxisFromPlane(&f->plane, ex, ey);
    743   CrossProduct(ex, ey, ez);
    744 	    
    745 	vec3_t aux;
    746   VectorCopy(ex, aux);
    747   VectorScale(aux, -f->texdef.shift[0], aux);
    748   VectorCopy(aux, p1);
    749   VectorCopy(ey, aux);
    750   VectorScale(aux, -f->texdef.shift[1], aux);
    751   VectorAdd(p1, aux, p1);
    752   VectorCopy(p1, p2);
    753   VectorAdd(p2, ex, p2);
    754   VectorCopy(p1, p3);
    755   VectorAdd(p3, ey, p3);
    756   VectorCopy(ez, aux);
    757   VectorScale(aux, -f->texdef.rotate, aux);
    758   VectorRotate(p1, aux, p1);
    759   VectorRotate(p2, aux, p2);
    760   VectorRotate(p3, aux, p3);
    761 	// computing rotated local axis base
    762 	vec3_t rex,rey;
    763   VectorCopy(ex, rex);
    764   VectorRotate(rex, aux, rex);
    765   VectorCopy(ey, rey);
    766   VectorRotate(rey, aux, rey);
    767 
    768   ComputeScale(rex,rey,p1,f);
    769 	ComputeScale(rex,rey,p2,f);
    770 	ComputeScale(rex,rey,p3,f);
    771 
    772 	// project on normal plane
    773 	// along ez 
    774 	// assumes plane normal is normalized
    775 	ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1);
    776 	ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2);
    777 	ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3);
    778 };
    779 
    780 
    781 void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3)
    782 {
    783 	vec3_t ex,ey,ez;
    784 
    785 #ifdef _DEBUG
    786 	if (g_qeglobals.m_bBrushPrimitMode)
    787 		Sys_Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n");
    788 #endif
    789 
    790 	// computing new local axis base
    791   TextureAxisFromPlane(&normal2, ex, ey);
    792   CrossProduct(ex, ey, ez);
    793 
    794   // projecting back on (ex,ey)
    795 	Back(ez,p1);
    796 	Back(ez,p2);
    797 	Back(ez,p3);
    798 
    799 	vec3_t aux;
    800 	// rotation
    801   VectorCopy(p2, aux);
    802   VectorSubtract(aux, p1,aux);
    803 	
    804 	float x = DotProduct(aux,ex);
    805 	float y = DotProduct(aux,ey);
    806   f->texdef.rotate = 180 * atan2(y,x) / Q_PI;
    807 
    808 	vec3_t rex,rey;
    809 	// computing rotated local axis base
    810   VectorCopy(ez, aux);
    811   VectorScale(aux, f->texdef.rotate, aux);
    812   VectorCopy(ex, rex);
    813   VectorRotate(rex, aux, rex);
    814   VectorCopy(ey, rey);
    815   VectorRotate(rey, aux, rey);
    816 
    817 	// scale
    818   VectorCopy(p2, aux);
    819   VectorSubtract(aux, p1, aux);
    820   f->texdef.scale[0] = DotProduct(aux, rex);
    821   VectorCopy(p3, aux);
    822   VectorSubtract(aux, p1, aux);
    823   f->texdef.scale[1] = DotProduct(aux, rey);
    824 
    825 	// shift
    826 	// only using p1
    827 	x = DotProduct(rex,p1);
    828 	y = DotProduct(rey,p1);                 
    829 	x /= f->texdef.scale[0];
    830 	y /= f->texdef.scale[1];
    831 
    832   VectorCopy(rex, p1);
    833   VectorScale(p1, x, p1);
    834   VectorCopy(rey, aux);
    835   VectorScale(aux, y, aux);
    836   VectorAdd(p1, aux, p1);
    837   VectorCopy(ez, aux);
    838   VectorScale(aux, -f->texdef.rotate, aux);
    839   VectorRotate(p1, aux, p1);
    840 	f->texdef.shift[0] = -DotProduct(p1, ex);
    841 	f->texdef.shift[1] = -DotProduct(p1, ey);
    842 
    843 	// stored rot is good considering local axis base
    844 	// change it if necessary
    845 	f->texdef.rotate = -f->texdef.rotate;
    846 
    847   Clamp(f->texdef.shift[0], f->d_texture->width);
    848   Clamp(f->texdef.shift[1], f->d_texture->height);
    849   Clamp(f->texdef.rotate, 360);
    850 
    851 }
    852 
    853 void RotateFaceTexture(face_t* f, int nAxis, float fDeg)
    854 {
    855 	vec3_t p1,p2,p3, rota;   
    856 	p1[0] = p1[1] = p1[2] = 0;
    857 	VectorCopy(p1, p2);
    858 	VectorCopy(p1, p3);
    859 	VectorCopy(p1, rota);
    860 	ComputeAbsolute(f, p1, p2, p3);
    861   
    862 	rota[nAxis] = fDeg;
    863 	VectorRotate(p1, rota, select_origin, p1);
    864 	VectorRotate(p2, rota, select_origin, p2);
    865 	VectorRotate(p3, rota, select_origin, p3);
    866 
    867 	plane_t normal2;
    868 	vec3_t vNormal;
    869 	vNormal[0] = f->plane.normal[0];
    870 	vNormal[1] = f->plane.normal[1];
    871 	vNormal[2] = f->plane.normal[2];
    872 	VectorRotate(vNormal, rota, vNormal);
    873 	normal2.normal[0] = vNormal[0];
    874 	normal2.normal[1] = vNormal[1];
    875 	normal2.normal[2] = vNormal[2];
    876 	AbsoluteToLocal(normal2, f, p1, p2 ,p3);
    877 
    878 }
    879 
    880 void RotateTextures(int nAxis, float fDeg, vec3_t vOrigin)
    881 {
    882 	for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
    883 	{
    884 		for (face_t* f=b->brush_faces ; f ; f=f->next)
    885 		{
    886 			if (g_qeglobals.m_bBrushPrimitMode)
    887 				RotateFaceTexture_BrushPrimit( f, nAxis, fDeg, vOrigin );
    888 			else
    889 				RotateFaceTexture(f, nAxis, fDeg);
    890 			//++timo removed that call .. works fine .. ???????
    891 //			Brush_Build(b, false);
    892 		}
    893 		Brush_Build(b, false);
    894 	}
    895 }
    896 
    897 
    898 void Select_FlipAxis (int axis)
    899 {
    900 	int		i;
    901 
    902 	Select_GetMid (select_origin);
    903 	for (i=0 ; i<3 ; i++)
    904 	{
    905 		VectorCopy (vec3_origin, select_matrix[i]);
    906 		select_matrix[i][i] = 1;
    907 	}
    908 	select_matrix[axis][axis] = -1;
    909 
    910 	select_fliporder = true;
    911 	Select_ApplyMatrix (true, false, 0, 0);
    912 	Sys_UpdateWindows (W_ALL);
    913 }
    914 
    915 
    916 void Select_Scale(float x, float y, float z)
    917 {
    918 	Select_GetMid (select_origin);
    919 	for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
    920 	{
    921 		for (face_t* f=b->brush_faces ; f ; f=f->next)
    922 		{
    923 			for (int i=0 ; i<3 ; i++)
    924 			{
    925 				f->planepts[i][0] -= select_origin[0];
    926 				f->planepts[i][1] -= select_origin[1];
    927 				f->planepts[i][2] -= select_origin[2];
    928 				f->planepts[i][0] *= x;
    929 				//f->planepts[i][0] = floor(f->planepts[i][0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
    930 
    931 				f->planepts[i][1] *= y;
    932 				//f->planepts[i][1] = floor(f->planepts[i][1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
    933 
    934 				f->planepts[i][2] *= z;
    935 		        //f->planepts[i][2] = floor(f->planepts[i][2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
    936 		
    937 				f->planepts[i][0] += select_origin[0];
    938 				f->planepts[i][1] += select_origin[1];
    939 				f->planepts[i][2] += select_origin[2];
    940 			}
    941 		}
    942 		Brush_Build(b, false);
    943 		if (b->patchBrush)
    944 		{
    945 			vec3_t v;
    946 			v[0] = x;
    947 			v[1] = y;
    948 			v[2] = z;
    949 			//Patch_Scale(b->nPatchID, select_origin, v);
    950 			Patch_Scale(b->pPatch, select_origin, v);
    951 		}
    952 		if (b->terrainBrush)
    953 		{
    954 			vec3_t v;
    955 			v[0] = x;
    956 			v[1] = y;
    957 			v[2] = z;
    958 			Terrain_Scale(b->pTerrain, select_origin, v);
    959 		}
    960 	}
    961 }
    962 
    963 void Select_RotateAxis (int axis, float deg, bool bPaint, bool bMouse)
    964 {
    965 	vec3_t	temp;
    966 	int		i, j;
    967 	vec_t	c, s;
    968 
    969 	if (deg == 0)
    970   {
    971     //Sys_Printf("0 deg\n");
    972 		return;
    973   }
    974 
    975   if (bMouse)
    976   {
    977     VectorCopy(g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin);
    978   }
    979   else
    980   {
    981 	  Select_GetMid (select_origin);
    982   }
    983 
    984 	select_fliporder = false;
    985 
    986 	if (deg == 90)
    987 	{
    988 		for (i=0 ; i<3 ; i++)
    989 		{
    990 			VectorCopy (vec3_origin, select_matrix[i]);
    991 			select_matrix[i][i] = 1;
    992 		}
    993 		i = (axis+1)%3;
    994 		j = (axis+2)%3;
    995 		VectorCopy (select_matrix[i], temp);
    996 		VectorCopy (select_matrix[j], select_matrix[i]);
    997 		VectorSubtract (vec3_origin, temp, select_matrix[j]);
    998 	}
    999 	else
   1000 	{
   1001 		deg = -deg;
   1002 		if (deg == -180.0)
   1003 		{
   1004 			c = -1;
   1005 			s = 0;
   1006 		}
   1007 		else if (deg == -270.0)
   1008 		{
   1009 			c = 0;
   1010 			s = -1;
   1011 		}
   1012 		else
   1013 		{
   1014 			c = cos(deg * Q_PI / 180.0);
   1015 			s = sin(deg * Q_PI / 180.0);
   1016 		}
   1017 
   1018 		for (i=0 ; i<3 ; i++)
   1019 		{
   1020 			VectorCopy (vec3_origin, select_matrix[i]);
   1021 			select_matrix[i][i] = 1;
   1022 		}
   1023 
   1024 		switch (axis)
   1025 		{
   1026 		case 0:
   1027 			select_matrix[1][1] = c;
   1028 			select_matrix[1][2] = -s;
   1029 			select_matrix[2][1] = s;
   1030 			select_matrix[2][2] = c;
   1031 			break;
   1032 		case 1:
   1033 			select_matrix[0][0] = c;
   1034 			select_matrix[0][2] = s;
   1035 			select_matrix[2][0] = -s;
   1036 			select_matrix[2][2] = c;
   1037 			break;
   1038 		case 2:
   1039 			select_matrix[0][0] = c;
   1040 			select_matrix[0][1] = -s;
   1041 			select_matrix[1][0] = s;
   1042 			select_matrix[1][1] = c;
   1043 			break;
   1044 		}
   1045 	}
   1046 
   1047 	if (g_PrefsDlg.m_bRotateLock)
   1048 		RotateTextures(axis, deg, select_origin);
   1049 	Select_ApplyMatrix(!bMouse, true, axis, deg);
   1050 
   1051 	if (bPaint)
   1052 		Sys_UpdateWindows (W_ALL);
   1053 }
   1054 
   1055 /*
   1056 ================================================================
   1057 
   1058 GROUP SELECTIONS
   1059 
   1060 ================================================================
   1061 */
   1062 
   1063 void Select_CompleteTall (void)
   1064 {
   1065 	brush_t	*b, *next;
   1066 	//int		i;
   1067 	vec3_t	mins, maxs;
   1068 
   1069 	if (!QE_SingleBrush ())
   1070 		return;
   1071 
   1072 	clearSelection();
   1073 
   1074 	VectorCopy (selected_brushes.next->mins, mins);
   1075 	VectorCopy (selected_brushes.next->maxs, maxs);
   1076 	Select_Delete ();
   1077 
   1078   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
   1079   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
   1080 
   1081 	for (b=active_brushes.next ; b != &active_brushes ; b=next)
   1082 	{
   1083 		next = b->next;
   1084 
   1085     if ( (b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) 
   1086       || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2]) )
   1087       continue;
   1088 
   1089 	 	if (FilterBrush (b))
   1090 	 		continue;
   1091 
   1092 		Brush_RemoveFromList (b);
   1093 		Brush_AddToList (b, &selected_brushes);
   1094 #if 0
   1095     // old stuff
   1096     for (i=0 ; i<2 ; i++)
   1097 			if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
   1098 				break;
   1099 		if (i == 2)
   1100 		{
   1101 			Brush_RemoveFromList (b);
   1102 			Brush_AddToList (b, &selected_brushes);
   1103 		}
   1104 #endif
   1105 	}
   1106 	Sys_UpdateWindows (W_ALL);
   1107 }
   1108 
   1109 void Select_PartialTall (void)
   1110 {
   1111 	brush_t	*b, *next;
   1112 	//int		i;
   1113 	vec3_t	mins, maxs;
   1114 
   1115 	if (!QE_SingleBrush ())
   1116 		return;
   1117 
   1118 	clearSelection();
   1119 
   1120 	VectorCopy (selected_brushes.next->mins, mins);
   1121 	VectorCopy (selected_brushes.next->maxs, maxs);
   1122 	Select_Delete ();
   1123 
   1124   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
   1125   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
   1126 
   1127 	for (b=active_brushes.next ; b != &active_brushes ; b=next)
   1128 	{
   1129 		next = b->next;
   1130 
   1131     if ( (b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1]) 
   1132       || (b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2]) )
   1133       continue;
   1134 
   1135 	 	if (FilterBrush (b))
   1136 	 		continue;
   1137 
   1138   	Brush_RemoveFromList (b);
   1139 		Brush_AddToList (b, &selected_brushes);
   1140 
   1141 
   1142 #if 0
   1143 // old stuff
   1144 		for (i=0 ; i<2 ; i++)
   1145 			if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i])
   1146 				break;
   1147 		if (i == 2)
   1148 		{
   1149 			Brush_RemoveFromList (b);
   1150 			Brush_AddToList (b, &selected_brushes);
   1151 		}
   1152 #endif
   1153 	}
   1154 	Sys_UpdateWindows (W_ALL);
   1155 }
   1156 
   1157 void Select_Touching (void)
   1158 {
   1159 	brush_t	*b, *next;
   1160 	int		i;
   1161 	vec3_t	mins, maxs;
   1162 
   1163 	if (!QE_SingleBrush ())
   1164 		return;
   1165 
   1166 	clearSelection();
   1167 
   1168 	VectorCopy (selected_brushes.next->mins, mins);
   1169 	VectorCopy (selected_brushes.next->maxs, maxs);
   1170 
   1171 	for (b=active_brushes.next ; b != &active_brushes ; b=next)
   1172 	{
   1173 		next = b->next;
   1174 
   1175 	 	if (FilterBrush (b))
   1176 	 		continue;
   1177 
   1178 		for (i=0 ; i<3 ; i++)
   1179 			if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1)
   1180 				break;
   1181 
   1182 		if (i == 3)
   1183 		{
   1184 			Brush_RemoveFromList (b);
   1185 			Brush_AddToList (b, &selected_brushes);
   1186 		}
   1187 	}
   1188 	Sys_UpdateWindows (W_ALL);
   1189 }
   1190 
   1191 void Select_Inside (void)
   1192 {
   1193 	brush_t	*b, *next;
   1194 	int		i;
   1195 	vec3_t	mins, maxs;
   1196 
   1197 	if (!QE_SingleBrush ())
   1198 		return;
   1199 
   1200 	clearSelection();
   1201 
   1202 	VectorCopy (selected_brushes.next->mins, mins);
   1203 	VectorCopy (selected_brushes.next->maxs, maxs);
   1204 	Select_Delete ();
   1205 
   1206 	for (b=active_brushes.next ; b != &active_brushes ; b=next)
   1207 	{
   1208 		next = b->next;
   1209 
   1210 	 	if (FilterBrush (b))
   1211 	 		continue;
   1212 
   1213 		for (i=0 ; i<3 ; i++)
   1214 			if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
   1215 				break;
   1216 		if (i == 3)
   1217 		{
   1218 			Brush_RemoveFromList (b);
   1219 			Brush_AddToList (b, &selected_brushes);
   1220 		}
   1221 	}
   1222 	Sys_UpdateWindows (W_ALL);
   1223 }
   1224 
   1225 /*
   1226 =============
   1227 Select_Ungroup
   1228 
   1229 Turn the currently selected entity back into normal brushes
   1230 =============
   1231 */
   1232 void Select_Ungroup(void)
   1233 {
   1234 	int numselectedgroups;
   1235 	entity_t	*e;
   1236 	brush_t		*b, *sb;
   1237 
   1238 	numselectedgroups = 0;
   1239 	for (sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next)
   1240 	{
   1241 		e = sb->owner;
   1242 
   1243 		if (!e || e == world_entity || e->eclass->fixedsize)
   1244 		{
   1245 			continue;
   1246 		}
   1247 
   1248 		for (b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext)
   1249 		{
   1250 			//Brush_RemoveFromList (b);
   1251 			//Brush_AddToList (b, &active_brushes);
   1252 			Entity_UnlinkBrush (b);
   1253 			Entity_LinkBrush (world_entity, b);
   1254 			Brush_Build( b );
   1255 			b->owner = world_entity;
   1256 		}
   1257 		Entity_Free (e);
   1258 		numselectedgroups++;
   1259 	}
   1260 
   1261 	if (numselectedgroups <= 0)
   1262 	{
   1263 		Sys_Printf("No grouped entities selected.\n");
   1264 		return;
   1265 	}
   1266 	Sys_Printf("Ungrouped %d entit%s.\n", numselectedgroups, (numselectedgroups == 1)?"y":"ies");
   1267 	Sys_UpdateWindows (W_ALL);
   1268 }
   1269 
   1270 
   1271 /*
   1272 ====================
   1273 Select_MakeStructural
   1274 ====================
   1275 */
   1276 void Select_MakeStructural (void)
   1277 {
   1278 	brush_t	*b;
   1279 	face_t	*f;
   1280 
   1281 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
   1282 		for (f=b->brush_faces ; f ; f=f->next)
   1283 			f->texdef.contents &= ~CONTENTS_DETAIL;
   1284 	Select_Deselect ();
   1285 	Sys_UpdateWindows (W_ALL);
   1286 }
   1287 
   1288 void Select_MakeDetail (void)
   1289 {
   1290 	brush_t	*b;
   1291 	face_t	*f;
   1292 
   1293 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
   1294 		for (f=b->brush_faces ; f ; f=f->next)
   1295 			f->texdef.contents |= CONTENTS_DETAIL;
   1296 	Select_Deselect ();
   1297 	Sys_UpdateWindows (W_ALL);
   1298 }
   1299 
   1300 void Select_ShiftTexture(int x, int y)
   1301 {
   1302 	brush_t		*b;
   1303 	face_t		*f;
   1304 
   1305   int nFaceCount = g_ptrSelectedFaces.GetSize();
   1306 
   1307 	if(selected_brushes.next == &selected_brushes && nFaceCount == 0)
   1308 		return;
   1309 
   1310 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
   1311 	{
   1312 		for (f=b->brush_faces ; f ; f=f->next)
   1313 		{
   1314 			if (g_qeglobals.m_bBrushPrimitMode)
   1315 			{
   1316 				// use face normal to compute a true translation
   1317 				Select_ShiftTexture_BrushPrimit( f, x, y );
   1318 			}
   1319 			else
   1320 			{
   1321 				f->texdef.shift[0] += x;
   1322 				f->texdef.shift[1] += y;
   1323 			}
   1324 		}
   1325 		Brush_Build(b);
   1326 		if (b->patchBrush)
   1327 		{
   1328 			//Patch_ShiftTexture(b->nPatchID, x, y);
   1329 			Patch_ShiftTexture(b->pPatch, x, y);
   1330 		}
   1331 	}
   1332 
   1333 	if (nFaceCount > 0)
   1334 	{
   1335     for (int i = 0; i < nFaceCount; i++)
   1336     {
   1337       face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
   1338       brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
   1339   		if (g_qeglobals.m_bBrushPrimitMode)
   1340 	  	{
   1341 
   1342 			  // use face normal to compute a true translation
   1343         // Select_ShiftTexture_BrushPrimit( selected_face, x, y );
   1344 			  // use camera view to compute texture shift
   1345 			  g_pParentWnd->GetCamera()->ShiftTexture_BrushPrimit( selFace, x, y );
   1346       }
   1347   		else
   1348 	  	{
   1349 		  	selFace->texdef.shift[0] += x;
   1350 			  selFace->texdef.shift[1] += y;
   1351   		}
   1352 	  	Brush_Build(selBrush);
   1353     }
   1354 	}
   1355 
   1356 	Sys_UpdateWindows (W_CAMERA);
   1357 }
   1358 
   1359 void Select_ScaleTexture(int x, int y)
   1360 {
   1361 	brush_t		*b;
   1362 	face_t		*f;
   1363 
   1364   int nFaceCount = g_ptrSelectedFaces.GetSize();
   1365 
   1366   if(selected_brushes.next == &selected_brushes && nFaceCount == 0)
   1367 	{
   1368 		return;
   1369 	}
   1370 
   1371 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
   1372 	{
   1373 		for (f=b->brush_faces ; f ; f=f->next)
   1374 		{
   1375 			if (g_qeglobals.m_bBrushPrimitMode)
   1376 			{
   1377 				// apply same scale as the spinner button of the surface inspector
   1378 				float	shift[2];
   1379 				float	rotate;
   1380 				float	scale[2];
   1381 				brushprimit_texdef_t bp; 
   1382 				// compute normalized texture matrix
   1383 				ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL );
   1384 				// compute fake shift scale rot
   1385 				TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
   1386 				// update
   1387 				scale[0]+=static_cast<float>(x)*0.1;
   1388 				scale[1]+=static_cast<float>(y)*0.1;
   1389 				// compute new normalized texture matrix
   1390 				FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
   1391 				// apply to face texture matrix
   1392 				ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture );
   1393 			}
   1394 			else
   1395 			{
   1396 				f->texdef.scale[0] += x;
   1397 				f->texdef.scale[1] += y;
   1398 			}
   1399 		}
   1400 		Brush_Build(b);
   1401 		if (b->patchBrush)
   1402 		{
   1403 			Patch_ScaleTexture(b->pPatch, x, y);
   1404 		}
   1405 	}
   1406 
   1407 	if (nFaceCount > 0)
   1408 	{
   1409     for (int i = 0; i < nFaceCount; i++)
   1410     {
   1411       face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
   1412       brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
   1413 		  if (g_qeglobals.m_bBrushPrimitMode)
   1414 		  {
   1415 			  float	shift[2];
   1416 			  float	rotate;
   1417 			  float	scale[2];
   1418 			  brushprimit_texdef_t bp; 
   1419 			  ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL );
   1420 			  TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
   1421 			  scale[0]+=static_cast<float>(x)*0.1;
   1422 			  scale[1]+=static_cast<float>(y)*0.1;
   1423 			  FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
   1424 			  ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture );
   1425 		  }
   1426 		  else
   1427 		  {
   1428 			  selFace->texdef.scale[0] += x;
   1429 			  selFace->texdef.scale[1] += y;
   1430 		  }
   1431 		  Brush_Build(selBrush);
   1432     }
   1433 	}
   1434 
   1435 	Sys_UpdateWindows (W_CAMERA);
   1436 }
   1437 
   1438 void Select_RotateTexture(int amt)
   1439 {
   1440 	brush_t		*b;
   1441 	face_t		*f;
   1442 
   1443   int nFaceCount = g_ptrSelectedFaces.GetSize();
   1444 
   1445   if(selected_brushes.next == &selected_brushes && nFaceCount == 0)
   1446 	{
   1447 		return;
   1448 	}
   1449 
   1450 	for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
   1451 	{
   1452 		for (f=b->brush_faces ; f ; f=f->next)
   1453 		{
   1454 			if (g_qeglobals.m_bBrushPrimitMode)
   1455 			{
   1456 				// apply same scale as the spinner button of the surface inspector
   1457 				float	shift[2];
   1458 				float	rotate;
   1459 				float	scale[2];
   1460 				brushprimit_texdef_t bp; 
   1461 				// compute normalized texture matrix
   1462 				ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL );
   1463 				// compute fake shift scale rot
   1464 				TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
   1465 				// update
   1466 				rotate += amt;
   1467 				// compute new normalized texture matrix
   1468 				FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
   1469 				// apply to face texture matrix
   1470 				ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture );
   1471 			}
   1472 			else
   1473 			{
   1474 				f->texdef.rotate += amt;
   1475 				f->texdef.rotate = static_cast<int>(f->texdef.rotate) % 360;
   1476 			}
   1477 		}
   1478 		Brush_Build(b);
   1479 		if (b->patchBrush)
   1480 		{
   1481 			//Patch_RotateTexture(b->nPatchID, amt);
   1482 			Patch_RotateTexture(b->pPatch, amt);
   1483 		}
   1484 	}
   1485 	
   1486 	if (nFaceCount > 0)
   1487 	{
   1488     for (int i = 0; i < nFaceCount; i++)
   1489     {
   1490       face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
   1491       brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
   1492 		  if (g_qeglobals.m_bBrushPrimitMode)
   1493 		  {
   1494 			  float	shift[2];
   1495 			  float	rotate;
   1496 			  float	scale[2];
   1497 			  brushprimit_texdef_t bp; 
   1498 			  ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL );
   1499 			  TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
   1500 			  rotate += amt;
   1501 			  FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
   1502 			  ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture );
   1503 		  }
   1504 		  else
   1505 		  {
   1506 			  selFace->texdef.rotate += amt;
   1507 			  selFace->texdef.rotate = static_cast<int>(selFace->texdef.rotate) % 360;
   1508 		  }
   1509 		  Brush_Build(selBrush);
   1510     }
   1511 	}
   1512 
   1513 	Sys_UpdateWindows (W_CAMERA);
   1514 }
   1515 
   1516 
   1517 void FindReplaceTextures(const char* pFind, const char* pReplace, bool bSelected, bool bForce)
   1518 {
   1519 	brush_t* pList = (bSelected) ? &selected_brushes : &active_brushes;
   1520 	if (!bSelected)
   1521 	{
   1522 		Select_Deselect();
   1523 	}
   1524  
   1525 	for (brush_t* pBrush = pList->next ; pBrush != pList; pBrush = pBrush->next)
   1526 	{
   1527 		if (pBrush->patchBrush)
   1528 		{
   1529 			Patch_FindReplaceTexture(pBrush, pFind, pReplace, bForce);
   1530 		}
   1531 
   1532 		if (pBrush->terrainBrush)
   1533 		{
   1534 			Terrain_FindReplaceTexture(pBrush->pTerrain, pFind, pReplace, bForce);
   1535 		}
   1536 		for (face_t* pFace = pBrush->brush_faces; pFace; pFace = pFace->next)
   1537 		{
   1538 			if(bForce || strcmpi(pFace->texdef.name, pFind) == 0)
   1539 			{
   1540 				pFace->d_texture = Texture_ForName(pReplace);
   1541 				//strcpy(pFace->texdef.name, pReplace);
   1542 				pFace->texdef.SetName(pReplace);
   1543 			}
   1544 		}
   1545 		Brush_Build(pBrush);
   1546 	}
   1547 	Sys_UpdateWindows (W_CAMERA);
   1548 }
   1549 
   1550 
   1551 void Select_AllOfType()
   1552 {
   1553 	brush_t	*b, *next;
   1554 	entity_t	*e;
   1555 	if ( (selected_brushes.next == &selected_brushes)
   1556 		|| (selected_brushes.next->next != &selected_brushes) )
   1557 	{
   1558 
   1559     CString strName;
   1560     if (g_ptrSelectedFaces.GetSize() == 0)
   1561     {
   1562       strName = g_qeglobals.d_texturewin.texdef.name;
   1563     }
   1564     else
   1565     {
   1566       face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(0));
   1567       strName = selFace->texdef.name;
   1568     }
   1569 
   1570     Select_Deselect();
   1571 	  for (b=active_brushes.next ; b != &active_brushes ; b=next)
   1572     {
   1573 		  next = b->next;
   1574     	
   1575       if (FilterBrush (b))
   1576 	 	    continue;
   1577 
   1578       if (b->patchBrush)
   1579       {
   1580         if (strcmpi(strName, b->pPatch->d_texture->name) == 0)
   1581         {
   1582 			    Brush_RemoveFromList (b);
   1583 			    Brush_AddToList (b, &selected_brushes);
   1584         }
   1585       }
   1586       else
   1587       {
   1588         for (face_t* pFace = b->brush_faces; pFace; pFace = pFace->next)
   1589         {
   1590           if (strcmpi(strName, pFace->texdef.name) == 0)
   1591           {
   1592 			      Brush_RemoveFromList (b);
   1593 			      Brush_AddToList (b, &selected_brushes);
   1594           }
   1595         }
   1596       }
   1597     }
   1598     Sys_UpdateWindows(W_ALL);
   1599     return;
   1600   }
   1601 
   1602   
   1603   b = selected_brushes.next;
   1604 	e = b->owner;
   1605 
   1606   if (e != NULL)
   1607   {
   1608     if (e != world_entity)
   1609     {
   1610       CString strName = e->eclass->name;
   1611       CString strKey, strVal;
   1612       bool bCriteria = GetSelectAllCriteria(strKey, strVal);
   1613       Sys_Printf("Selecting all %s(s)\n", strName);
   1614       Select_Deselect();
   1615 
   1616 	    for (b=active_brushes.next ; b != &active_brushes ; b=next)
   1617     	{
   1618 		    next = b->next;
   1619     	 	
   1620         if (FilterBrush (b))
   1621 	 	    	continue;
   1622 
   1623         e = b->owner;
   1624         if (e != NULL)
   1625         {
   1626           if (strcmpi(e->eclass->name, strName) == 0)
   1627           {
   1628             bool doIt = true;
   1629             if (bCriteria) {
   1630               CString str = ValueForKey (e, strKey);
   1631               if (str.CompareNoCase(strVal) != 0) {
   1632                 doIt = false;
   1633               }
   1634             }
   1635             if (doIt) {
   1636   		        Brush_RemoveFromList (b);
   1637 	  	        Brush_AddToList (b, &selected_brushes);
   1638             }
   1639           }
   1640         }
   1641       }
   1642     }
   1643   }
   1644 	Sys_UpdateWindows (W_ALL);
   1645 
   1646 }
   1647 
   1648 void Select_Reselect()
   1649 {
   1650   CPtrArray holdArray;
   1651 	for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next)
   1652 	{
   1653     holdArray.Add(reinterpret_cast<void*>(b));
   1654 	}
   1655 
   1656   int n = holdArray.GetSize();
   1657   while (n-- > 0)
   1658   {
   1659     b = reinterpret_cast<brush_t*>(holdArray.GetAt(n));
   1660     Select_Brush(b);
   1661   }
   1662 	Sys_UpdateWindows (W_ALL);
   1663 }
   1664 
   1665 
   1666 void Select_FitTexture(int nHeight, int nWidth)
   1667 {
   1668 	brush_t		*b;
   1669 
   1670   int nFaceCount = g_ptrSelectedFaces.GetSize();
   1671 
   1672   if(selected_brushes.next == &selected_brushes && nFaceCount == 0)
   1673 		return;
   1674 
   1675   for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
   1676 	{
   1677     Brush_FitTexture(b, nHeight, nWidth);
   1678 		Brush_Build(b);
   1679 	}
   1680 
   1681 	if (nFaceCount > 0)
   1682 	{
   1683     for (int i = 0; i < nFaceCount; i++)
   1684     {
   1685       face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
   1686       brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
   1687       Face_FitTexture(selFace, nHeight, nWidth);
   1688 	  	Brush_Build(selBrush);
   1689     }
   1690 	}
   1691 
   1692 	Sys_UpdateWindows (W_CAMERA);
   1693 }
   1694 
   1695 void Select_AxialTexture()
   1696 {
   1697 
   1698 }
   1699 
   1700 void Select_Hide()
   1701 {
   1702 	for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next)
   1703 	{
   1704     b->hiddenBrush = true;
   1705 	}
   1706 	Sys_UpdateWindows (W_ALL);
   1707 }
   1708 
   1709 void Select_ShowAllHidden()
   1710 {
   1711   brush_t* b;
   1712 	for (b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next)
   1713 	{
   1714     b->hiddenBrush = false;
   1715 	}
   1716 	for (b=active_brushes.next ; b && b != &active_brushes ; b=b->next)
   1717 	{
   1718     b->hiddenBrush = false;
   1719 	}
   1720 	Sys_UpdateWindows (W_ALL);
   1721 }
   1722 
   1723 
   1724 /*
   1725 ============
   1726 Select_Invert
   1727 ============
   1728 */
   1729 void Select_Invert(void)
   1730 {
   1731 	brush_t *next, *prev;
   1732 
   1733 	Sys_Printf("inverting selection...\n");
   1734 
   1735 	next = active_brushes.next;
   1736 	prev = active_brushes.prev;
   1737 	if (selected_brushes.next != &selected_brushes)
   1738 	{
   1739 		active_brushes.next = selected_brushes.next;
   1740 		active_brushes.prev = selected_brushes.prev;
   1741 		active_brushes.next->prev = &active_brushes;
   1742 		active_brushes.prev->next = &active_brushes;
   1743 	}
   1744 	else
   1745 	{
   1746 		active_brushes.next = &active_brushes;
   1747 		active_brushes.prev = &active_brushes;
   1748 	}
   1749 	if (next != &active_brushes)
   1750 	{
   1751 		selected_brushes.next = next;
   1752 		selected_brushes.prev = prev;
   1753 		selected_brushes.next->prev = &selected_brushes;
   1754 		selected_brushes.prev->next = &selected_brushes;
   1755 	}
   1756 	else
   1757 	{
   1758 		selected_brushes.next = &selected_brushes;
   1759 		selected_brushes.prev = &selected_brushes;
   1760 	}
   1761 
   1762 	Sys_UpdateWindows(W_ALL);
   1763 
   1764 	Sys_Printf("done.\n");
   1765 }
   1766 
   1767 
   1768 /* 
   1769 ===========
   1770 Select_Name
   1771 ===========
   1772 */
   1773 void Select_Name(const char *pName)
   1774 {
   1775 	if (g_qeglobals.m_bBrushPrimitMode)
   1776   {
   1777 	  for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next)
   1778 	  {
   1779       Brush_SetEpair(b, "Name", pName);
   1780 	  }
   1781   }
   1782 }
   1783 
   1784 /* 
   1785 =================
   1786 Select_AddToGroup
   1787 add selected brushes to a group, update the tree
   1788 =================
   1789 */
   1790 void Select_AddToGroup(const char *pName)
   1791 {
   1792 	if (g_qeglobals.m_bBrushPrimitMode)
   1793   {
   1794 	  for (brush_t* b=selected_brushes.next ; b && b != &selected_brushes ; b=b->next)
   1795 	  {
   1796       Brush_SetEpair(b, "group", pName);
   1797 			Group_AddToProperGroup(b);
   1798 	  }
   1799   }
   1800 }