2 Copyright (C) 1999-2007 id Software, Inc. and contributors.
3 For a list of contributors, see the accompanying CONTRIBUTORS file.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 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.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 CPtrArray g_SelectedFaces;
29 CPtrArray g_SelectedFaceBrushes;
30 CPtrArray& g_ptrSelectedFaces = g_SelectedFaces;
31 CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes;
38 #define DIST_START 999999
39 trace_t Test_Ray( vec3_t origin, vec3_t dir, int flags ){
45 memset( &t, 0, sizeof( t ) );
48 if ( flags & SF_CYCLE ) {
50 brush_t *pToSelect = ( selected_brushes.next != &selected_brushes ) ? selected_brushes.next : NULL;
53 // go through active brushes and accumulate all "hit" brushes
54 for ( brush = active_brushes.next ; brush != &active_brushes ; brush = brush->next )
56 //if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
59 if ( brush->bFiltered ) {
63 if ( !g_PrefsDlg.m_bSelectCurves && brush->patchBrush ) {
67 if ( !g_PrefsDlg.m_bSelectModels && ( brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL ) ) {
71 //if (!g_bShowPatchBounds && brush->patchBrush)
74 face = Brush_Ray( origin, dir, brush, &dist, flags );
81 int nSize = array.GetSize();
84 for ( int i = 0; i < nSize; i++ )
86 brush_t *b = reinterpret_cast<brush_t*>( array.GetAt( i ) );
87 // did we hit the last one selected yet ?
88 if ( b == pToSelect ) {
89 // yes we want to select the next one in the list
90 int n = ( i > 0 ) ? i - 1 : nSize - 1;
91 pToSelect = reinterpret_cast<brush_t*>( array.GetAt( n ) );
97 pToSelect = reinterpret_cast<brush_t*>( array.GetAt( 0 ) );
101 face = Brush_Ray( origin, dir, pToSelect, &dist, flags );
110 if ( !( flags & SF_SELECTED_ONLY ) ) {
111 for ( brush = active_brushes.next ; brush != &active_brushes ; brush = brush->next )
113 if ( ( flags & SF_ENTITIES_FIRST ) && ( brush->owner == world_entity || !brush->owner->eclass->fixedsize ) ) {
117 if ( brush->bFiltered ) {
121 if ( !g_PrefsDlg.m_bSelectCurves && brush->patchBrush ) {
125 if ( !g_PrefsDlg.m_bSelectModels && ( brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL ) ) {
129 //if (!g_bShowPatchBounds && brush->patchBrush)
132 face = Brush_Ray( origin, dir, brush, &dist, flags );
133 if ( face && dist > 0 && dist < t.dist ) {
143 for ( brush = selected_brushes.next ; brush != &selected_brushes ; brush = brush->next )
145 if ( ( flags & SF_ENTITIES_FIRST ) && ( brush->owner == world_entity || !brush->owner->eclass->fixedsize ) ) {
149 if ( brush->bFiltered ) {
153 if ( !g_PrefsDlg.m_bSelectCurves && brush->patchBrush ) {
157 if ( !g_PrefsDlg.m_bSelectModels && ( brush->owner->eclass->nShowFlags & ECLASS_MISCMODEL ) ) {
161 face = Brush_Ray( origin, dir, brush, &dist, flags );
162 if ( dist > 0 && dist < t.dist ) {
170 // if entites first, but didn't find any, check regular
172 if ( ( flags & SF_ENTITIES_FIRST ) && t.brush == NULL ) {
173 return Test_Ray( origin, dir, flags & ~SF_ENTITIES_FIRST );
187 void Select_Brush( brush_t *brush, bool bComplete, bool bStatus ){
191 g_ptrSelectedFaces.RemoveAll();
192 g_ptrSelectedFaceBrushes.RemoveAll();
193 if ( g_qeglobals.d_select_count < 2 ) {
194 g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
196 g_qeglobals.d_select_count++;
200 // select complete entity on first click
201 if ( e != world_entity && bComplete == true ) {
202 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
203 if ( b->owner == e ) {
206 for ( b = e->brushes.onext ; b != &e->brushes ; b = b->onext )
208 if ( b == brush ) { // make sure we add the actual selected brush last, mainly for cycle select
211 Brush_RemoveFromList( b );
212 Brush_AddToList( b, &selected_brushes );
214 Brush_RemoveFromList( brush );
215 Brush_AddToList( brush, &selected_brushes );
220 Brush_RemoveFromList( brush );
221 Brush_AddToList( brush, &selected_brushes );
222 UpdatePatchInspector();
226 UpdateEntitySel( brush->owner->eclass );
229 UpdateSurfaceDialog();
233 vec3_t vMin, vMax, vSize;
234 Select_GetBounds( vMin, vMax );
235 VectorSubtract( vMax, vMin, vSize );
237 strStatus.Format( "Selection X:: %.1f Y:: %.1f Z:: %.1f", vSize[0], vSize[1], vSize[2] );
238 g_pParentWnd->SetStatusText( 2, strStatus );
244 Select_FaceInSelectedBrushes
247 bool Select_FaceInSelectedBrushes( face_t *face ){
251 for ( brush = selected_brushes.next; brush != &selected_brushes; brush = brush->next )
253 for ( tface = brush->brush_faces; tface; tface = tface->next )
255 if ( tface == face ) {
268 If the origin is inside a brush, that brush will be ignored.
271 void Select_Ray( vec3_t origin, vec3_t dir, int flags ){
275 static trace_t lastTrace = {
282 t = Test_Ray( origin, dir, flags );
287 if ( flags & SF_SINGLEFACE ) {
288 if ( flags & SF_DRAG ) {
289 if ( t.brush == lastTrace.brush && t.face == lastTrace.face ) {
295 if ( Select_FaceInSelectedBrushes( t.face ) ) {
296 // Deselect the brush
297 Brush_RemoveFromList( t.brush );
298 Brush_AddToList( t.brush, &active_brushes );
299 UpdatePatchInspector();
301 // Select all of the brush's faces except the one we are pointing at
302 for ( tface = t.brush->brush_faces; tface; tface = tface->next )
304 if ( tface == t.face ) {
309 // NOTE: keep the size check in the loop, we remove stuff inside
310 for ( int i = 0; i < g_SelectedFaces.GetSize(); i++ )
312 if ( tface == reinterpret_cast<face_t*>( g_SelectedFaces.GetAt( i ) ) ) {
318 g_SelectedFaces.Add( tface );
319 g_SelectedFaceBrushes.Add( t.brush );
322 g_qeglobals.d_select_mode = sel_facets_off;
327 // NOTE: keep the size check in the loop, we remove stuff inside
328 for ( int i = 0; i < g_SelectedFaces.GetSize(); i++ )
330 if ( t.face == reinterpret_cast<face_t*>( g_SelectedFaces.GetAt( i ) ) ) {
332 if ( flags & SF_DRAG_ON ) {
336 g_qeglobals.d_select_mode = sel_facets_off;
337 // need to remove i'th entry
338 g_SelectedFaces.RemoveAt( i, 1 );
339 g_SelectedFaceBrushes.RemoveAt( i, 1 );
343 if ( bOk && !( flags & SF_DRAG_OFF ) ) {
344 g_SelectedFaces.Add( t.face );
345 g_SelectedFaceBrushes.Add( t.brush );
346 g_qeglobals.d_select_mode = sel_facets_on;
349 UpdateSurfaceDialog();
350 Sys_UpdateWindows( W_ALL );
351 //g_qeglobals.d_select_mode = sel_brush;
352 // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture
353 brushprimit_texdef_t brushprimit_texdef;
354 ConvertTexMatWithQTexture( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL );
355 Texture_SetTexture( &t.face->texdef, &brushprimit_texdef, false, NULL, false );
359 // move the brush to the other list
361 if ( flags & SF_DRAG_ON ) {
365 g_qeglobals.d_select_mode = sel_brush_off;
366 Brush_RemoveFromList( t.brush );
367 Brush_AddToList( t.brush, &active_brushes );
369 UpdatePatchInspector();
373 if ( flags & SF_DRAG_OFF ) {
377 g_qeglobals.d_select_mode = sel_brush_on;
378 Select_Brush( t.brush, g_PrefsDlg.m_nCamDragMultiSelect == 1 ? Sys_AltDown() : !Sys_AltDown() );
380 UpdateSurfaceDialog();
381 Sys_UpdateWindows( W_ALL );
385 void Select_Delete( void ){
389 g_ptrSelectedFaces.RemoveAll();
390 g_ptrSelectedFaceBrushes.RemoveAll();
392 g_qeglobals.d_select_mode = sel_brush;
394 g_qeglobals.d_select_count = 0;
395 g_qeglobals.d_num_move_points = 0;
396 while ( selected_brushes.next != &selected_brushes )
398 brush = selected_brushes.next;
399 if ( brush->patchBrush ) {
400 Patch_Delete( brush->pPatch );
404 // remove if no brushes
405 if ( e != world_entity && e->brushes.onext == &e->brushes ) {
410 Sys_MarkMapModified();
411 UpdateSurfaceDialog();
412 Sys_UpdateWindows( W_ALL );
415 // update the workzone to a given brush
416 void UpdateWorkzone_ForBrush( brush_t* b ){
417 VectorCopy( b->mins, g_qeglobals.d_work_min );
418 VectorCopy( b->maxs, g_qeglobals.d_work_max );
421 // will update the workzone to the given brush
422 // g_pParentWnd->ActiveXY()->GetViewType()
423 // cf VIEWTYPE defintion: enum VIEWTYPE {YZ, XZ, XY};
424 // we fit our work zone to the last brush on the list (b)
425 int nViewType = g_pParentWnd->ActiveXY()->GetViewType();
426 int nDim1 = ( nViewType == YZ ) ? 1 : 0;
427 int nDim2 = ( nViewType == XY ) ? 1 : 2;
428 g_qeglobals.d_work_min[nDim1] = b->mins[nDim1];
429 g_qeglobals.d_work_max[nDim1] = b->maxs[nDim1];
430 g_qeglobals.d_work_min[nDim2] = b->mins[nDim2];
431 g_qeglobals.d_work_max[nDim2] = b->maxs[nDim2];
435 // here to filter new brushes once unselected
436 extern void PerformFiltering();
438 void Select_Deselect( bool bDeselectFaces ){
443 g_pParentWnd->ActiveXY()->UndoClear();
445 g_qeglobals.d_workcount++;
446 g_qeglobals.d_select_count = 0;
447 g_qeglobals.d_num_move_points = 0;
448 b = selected_brushes.next;
450 if ( b == &selected_brushes ) {
451 if ( bDeselectFaces ) {
452 g_ptrSelectedFaces.RemoveAll();
453 g_ptrSelectedFaceBrushes.RemoveAll();
456 UpdateSurfaceDialog();
457 Sys_UpdateWindows( W_ALL );
461 if ( bDeselectFaces ) {
462 g_ptrSelectedFaces.RemoveAll();
463 g_ptrSelectedFaceBrushes.RemoveAll();
466 g_qeglobals.d_select_mode = sel_brush;
468 UpdateWorkzone_ForBrush( b );
470 selected_brushes.next->prev = &active_brushes;
471 selected_brushes.prev->next = active_brushes.next;
472 active_brushes.next->prev = selected_brushes.prev;
473 active_brushes.next = selected_brushes.next;
474 selected_brushes.prev = selected_brushes.next = &selected_brushes;
476 // filter newly created stuff once it's unselected
478 UpdateSurfaceDialog();
479 Sys_UpdateWindows( W_ALL );
487 /*! Moves the currently selected brush/patch
488 \param delta How far to move the selection (x,y,z)
489 \param bSnap If the move should snap to grid points
491 void Select_Move( vec3_t delta, bool bSnap ){
494 // actually move the selected brushes
495 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
496 Brush_Move( b, delta, bSnap );
499 Select_GetBounds( vMin, vMax );
501 strStatus.Format( "Origin X:: %.1f Y:: %.1f Z:: %.1f", vMin[0], vMax[1], vMax[2] );
502 g_pParentWnd->SetStatusText( 2, strStatus );
504 //Sys_UpdateWindows (W_ALL);
512 /*! Moves the currently selected brush/patch vertices
513 \param delta How far to move the vertices (x,y,z)
514 \param bSnap If the move should snap to grid points
516 void Select_NudgePoint( vec3_t delta, qboolean bSnap ){
517 if ( g_qeglobals.d_select_mode == sel_vertex ) {
518 // move selected verts
521 qboolean success = true;
522 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
524 success &= (qboolean)Brush_MoveVertex( b, g_qeglobals.d_move_points[0], delta, end, bSnap );
527 VectorCopy( end, g_qeglobals.d_move_points[0] );
530 else if ( g_qeglobals.d_select_mode == sel_curvepoint ) {
531 // move selected patch control points
532 Patch_UpdateSelected( delta );
540 Creates an exact duplicate of the selection in place, then moves
541 the selected brushes off of their old positions
544 void Select_Clone( void ){
545 g_bScreenUpdates = false;
546 g_pParentWnd->Copy();
548 g_pParentWnd->Paste();
549 g_pParentWnd->NudgeSelection( 2, g_qeglobals.d_gridsize );
550 g_pParentWnd->NudgeSelection( 3, g_qeglobals.d_gridsize );
551 Undo_Start( "clone" );
552 Undo_EndBrushList( &selected_brushes );
554 g_bScreenUpdates = true;
555 Sys_UpdateWindows( W_ALL );
563 Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping
564 Timo : brush primitive texturing
565 the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes )
566 Timo : texture plugin, added an IPluginTexdef* parameter
567 must be casted to an IPluginTexdef!
568 if not NULL, get ->Copy() of it into each face or brush ( and remember to hook )
569 if NULL, means we have no information, ask for a default
570 TTimo - shader code cleanup
571 added IShader* parameter
574 void WINAPI Select_SetTexture2( IShader* pShader, texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ){
576 int nCount = g_ptrSelectedFaces.GetSize();
578 Undo_Start( "set face textures" );
579 ASSERT( g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize() );
580 for ( int i = 0; i < nCount; i++ )
582 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( i ) );
583 brush_t *selBrush = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( i ) );
584 Undo_AddBrush( selBrush );
585 //++timo TODO: propagate the IShader* ..
586 SetFaceTexdef( selFace, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>( pPlugTexdef ) );
587 Brush_Build( selBrush, bFitScale );
588 Undo_EndBrush( selBrush );
592 else if ( selected_brushes.next != &selected_brushes ) {
593 Undo_Start( "set brush textures" );
594 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
595 if ( !b->owner->eclass->fixedsize ) {
597 Brush_SetTexture2( b, pShader, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>( pPlugTexdef ) );
602 Sys_UpdateWindows( W_ALL );
609 Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping
610 Timo : brush primitive texturing
611 the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes )
612 Timo : texture plugin, added an IPluginTexdef* parameter
613 must be casted to an IPluginTexdef!
614 if not NULL, get ->Copy() of it into each face or brush ( and remember to hook )
615 if NULL, means we have no information, ask for a default
618 void WINAPI Select_SetTexture( texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef ){
621 static int count = 0;
628 Sys_Printf("count: %d\n", count);
630 Sys_Printf("break!\n");
633 int nCount = g_ptrSelectedFaces.GetSize();
635 Undo_Start( "set face textures" );
636 assert( g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize() );
637 for ( int i = 0; i < nCount; i++ )
639 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( i ) );
640 brush_t *selBrush = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( i ) );
641 Undo_AddBrush( selBrush );
642 SetFaceTexdef( selFace, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>( pPlugTexdef ) );
643 Brush_Build( selBrush, bFitScale );
644 Undo_EndBrush( selBrush );
648 else if ( selected_brushes.next != &selected_brushes ) {
649 Undo_Start( "set brush textures" );
650 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
651 if ( !b->owner->eclass->fixedsize ) {
653 Brush_SetTexture( b, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>( pPlugTexdef ) );
658 //++timo FIXME: not necessary in every cases, write a message defering / move one level up
659 Sys_UpdateWindows( W_ALL );
664 ================================================================
668 ================================================================
671 void Select_GetBounds( vec3_t mins, vec3_t maxs ){
675 for ( i = 0 ; i < 3 ; i++ )
681 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
683 if ( b->owner->eclass->fixedsize ) {
684 for ( i = 0 ; i < 3 ; i++ )
686 if ( b->owner->origin[i] < mins[i] ) {
687 mins[i] = b->owner->origin[i];
689 if ( b->owner->origin[i] > maxs[i] ) {
690 maxs[i] = b->owner->origin[i];
696 for ( i = 0 ; i < 3 ; i++ )
698 if ( b->mins[i] < mins[i] ) {
699 mins[i] = b->mins[i];
701 if ( b->maxs[i] > maxs[i] ) {
702 maxs[i] = b->maxs[i];
709 void Select_GetTrueMid( vec3_t mid ){
711 Select_GetBounds( mins, maxs );
713 for ( int i = 0 ; i < 3 ; i++ )
714 mid[i] = ( mins[i] + ( ( maxs[i] - mins[i] ) / 2 ) );
717 void Select_GetMid( vec3_t mid ){
721 if ( !g_PrefsDlg.m_bSnap ) {
722 Select_GetTrueMid( mid );
726 Select_GetBounds( mins, maxs );
728 for ( i = 0 ; i < 3 ; i++ )
729 mid[i] = g_qeglobals.d_gridsize * floor( ( ( mins[i] + maxs[i] ) * 0.5 ) / g_qeglobals.d_gridsize );
732 vec3_t select_origin;
733 vec3_t select_matrix[3];
734 qboolean select_fliporder;
736 // FIXME: bApplyBPrimit is supposed to be temporary
737 // TODO: manage Brush_Build calls, too many of them with the texture processing
738 // FIXME: the undo doesn't seem to work correctly on texturing and flip/rotate operations?? this is not supposed to be related to the texture locking code, so what is happening?
739 // FIXME: ApplyMatrix works on flipping operation, b0rks on Rotations (so does the "regular" rotation code??)
740 // FIXME: what is getting called in free rotation mode? that used to work right?
741 void Select_ApplyMatrix( bool bSnap, bool bRotation, int nAxis, float fDeg ){ //, qboolean bApplyBPrimit)
745 vec3_t temp, tmporigin;
747 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
749 if ( b->owner->eclass->fixedsize ) {
750 VectorCopy( b->owner->origin, tmporigin );
751 // transform the origin point
752 VectorSubtract( b->owner->origin, select_origin, temp );
753 for ( j = 0 ; j < 3 ; j++ )
754 b->owner->origin[j] = DotProduct( temp, select_matrix[j] ) + select_origin[j];
756 // update the origin key
758 sprintf( text, "%i %i %i",
759 (int)b->owner->origin[0], (int)b->owner->origin[1], (int)b->owner->origin[2] );
760 SetKeyValue( b->owner, "origin", text );
762 /*\todo remove brush-based bounding box for fixedsize entities */
763 VectorSubtract( b->owner->origin, tmporigin, temp );
764 for ( f = b->brush_faces ; f ; f = f->next )
766 // move fixedsize bbox to new origin
767 for ( i = 0 ; i < 3 ; i++ )
768 VectorAdd( f->planepts[i], temp, f->planepts[i] );
770 Brush_Build( b, bSnap,true,false,false ); // don't filter
773 else if ( b->patchBrush ) {
774 if ( !bRotation && !( ( g_qeglobals.d_select_mode == sel_curvepoint && g_qeglobals.d_num_move_points != 0 ) || g_bPatchBendMode ) ) {
775 // invert patch if this is a mirroring operation, unless points are selected or bendmode is active
776 patchInvert( b->pPatch );
778 // NOTE: does not clamp points to integers
779 Patch_ApplyMatrix( b->pPatch, select_origin, select_matrix, false );
783 for ( f = b->brush_faces ; f ; f = f->next )
785 // FIXME: only in BP mode!
786 // if we are using Brush Primitives texturing, we need to compute the texture matrix after the geometric transformation
787 // (with the default texturing you don't need to compute anything for flipping and mirroring operations)
788 // if (bApplyBPrimit) {
789 // ApplyMatrix_BrushPrimit (f, select_matrix, select_origin, select_fliporder);
791 for ( i = 0 ; i < 3 ; i++ )
793 VectorSubtract( f->planepts[i], select_origin, temp );
794 for ( j = 0 ; j < 3 ; j++ )
795 f->planepts[i][j] = DotProduct( temp, select_matrix[j] ) + select_origin[j];
797 if ( select_fliporder ) {
798 VectorCopy( f->planepts[0], temp );
799 VectorCopy( f->planepts[2], f->planepts[0] );
800 VectorCopy( temp, f->planepts[2] );
803 Brush_Build( b, bSnap,true,false,false ); // don't filter
808 void ProjectOnPlane( vec3_t& normal,float dist,vec3_t& ez, vec3_t& p ){
809 if ( fabs( ez[0] ) == 1 ) {
810 p[0] = ( dist - normal[1] * p[1] - normal[2] * p[2] ) / normal[0];
812 else if ( fabs( ez[1] ) == 1 ) {
813 p[1] = ( dist - normal[0] * p[0] - normal[2] * p[2] ) / normal[1];
816 p[2] = ( dist - normal[0] * p[0] - normal[1] * p[1] ) / normal[2];
820 void Back( vec3_t& dir, vec3_t& p ){
821 if ( fabs( dir[0] ) == 1 ) {
824 else if ( fabs( dir[1] ) == 1 ) {
832 // using scale[0] and scale[1]
833 void ComputeScale( vec3_t& rex, vec3_t& rey, vec3_t& p, face_t* f ){
834 float px = DotProduct( rex, p );
835 float py = DotProduct( rey, p );
836 px *= f->texdef.scale[0];
837 py *= f->texdef.scale[1];
839 VectorCopy( rex, aux );
840 VectorScale( aux, px, aux );
841 VectorCopy( aux, p );
842 VectorCopy( rey, aux );
843 VectorScale( aux, py, aux );
844 VectorAdd( p, aux, p );
847 void ComputeAbsolute( face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3 ){
848 vec3_t ex,ey,ez; // local axis base
851 if ( g_qeglobals.m_bBrushPrimitMode ) {
852 Sys_Printf( "Warning : illegal call of ComputeAbsolute in brush primitive mode\n" );
856 // compute first local axis base
857 TextureAxisFromPlane( &f->plane, ex, ey );
858 CrossProduct( ex, ey, ez );
861 VectorCopy( ex, aux );
862 VectorScale( aux, -f->texdef.shift[0], aux );
863 VectorCopy( aux, p1 );
864 VectorCopy( ey, aux );
865 VectorScale( aux, -f->texdef.shift[1], aux );
866 VectorAdd( p1, aux, p1 );
867 VectorCopy( p1, p2 );
868 VectorAdd( p2, ex, p2 );
869 VectorCopy( p1, p3 );
870 VectorAdd( p3, ey, p3 );
871 VectorCopy( ez, aux );
872 VectorScale( aux, -f->texdef.rotate, aux );
873 VectorRotate( p1, aux, p1 );
874 VectorRotate( p2, aux, p2 );
875 VectorRotate( p3, aux, p3 );
876 // computing rotated local axis base
878 VectorCopy( ex, rex );
879 VectorRotate( rex, aux, rex );
880 VectorCopy( ey, rey );
881 VectorRotate( rey, aux, rey );
883 ComputeScale( rex,rey,p1,f );
884 ComputeScale( rex,rey,p2,f );
885 ComputeScale( rex,rey,p3,f );
887 // project on normal plane
889 // assumes plane normal is normalized
890 ProjectOnPlane( f->plane.normal,f->plane.dist,ez,p1 );
891 ProjectOnPlane( f->plane.normal,f->plane.dist,ez,p2 );
892 ProjectOnPlane( f->plane.normal,f->plane.dist,ez,p3 );
896 void AbsoluteToLocal( plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3 ){
900 if ( g_qeglobals.m_bBrushPrimitMode ) {
901 Sys_Printf( "Warning : illegal call of AbsoluteToLocal in brush primitive mode\n" );
905 // computing new local axis base
906 TextureAxisFromPlane( &normal2, ex, ey );
907 CrossProduct( ex, ey, ez );
909 // projecting back on (ex,ey)
916 VectorCopy( p2, aux );
917 VectorSubtract( aux, p1,aux );
919 float x = DotProduct( aux,ex );
920 float y = DotProduct( aux,ey );
921 f->texdef.rotate = 180 * atan2( y,x ) / Q_PI;
924 // computing rotated local axis base
925 VectorCopy( ez, aux );
926 VectorScale( aux, f->texdef.rotate, aux );
927 VectorCopy( ex, rex );
928 VectorRotate( rex, aux, rex );
929 VectorCopy( ey, rey );
930 VectorRotate( rey, aux, rey );
933 VectorCopy( p2, aux );
934 VectorSubtract( aux, p1, aux );
935 f->texdef.scale[0] = DotProduct( aux, rex );
936 VectorCopy( p3, aux );
937 VectorSubtract( aux, p1, aux );
938 f->texdef.scale[1] = DotProduct( aux, rey );
942 x = DotProduct( rex,p1 );
943 y = DotProduct( rey,p1 );
944 x /= f->texdef.scale[0];
945 y /= f->texdef.scale[1];
947 VectorCopy( rex, p1 );
948 VectorScale( p1, x, p1 );
949 VectorCopy( rey, aux );
950 VectorScale( aux, y, aux );
951 VectorAdd( p1, aux, p1 );
952 VectorCopy( ez, aux );
953 VectorScale( aux, -f->texdef.rotate, aux );
954 VectorRotate( p1, aux, p1 );
955 f->texdef.shift[0] = -DotProduct( p1, ex );
956 f->texdef.shift[1] = -DotProduct( p1, ey );
958 // stored rot is good considering local axis base
959 // change it if necessary
960 f->texdef.rotate = -f->texdef.rotate;
962 Clamp( f->texdef.shift[0], f->d_texture->width );
963 Clamp( f->texdef.shift[1], f->d_texture->height );
964 Clamp( f->texdef.rotate, 360 );
968 void RotateFaceTexture( face_t* f, int nAxis, float fDeg ){
969 vec3_t p1,p2,p3, rota;
970 p1[0] = p1[1] = p1[2] = 0;
971 VectorCopy( p1, p2 );
972 VectorCopy( p1, p3 );
973 VectorCopy( p1, rota );
974 ComputeAbsolute( f, p1, p2, p3 );
977 VectorRotateOrigin( p1, rota, select_origin, p1 );
978 VectorRotateOrigin( p2, rota, select_origin, p2 );
979 VectorRotateOrigin( p3, rota, select_origin, p3 );
983 vNormal[0] = f->plane.normal[0];
984 vNormal[1] = f->plane.normal[1];
985 vNormal[2] = f->plane.normal[2];
986 VectorRotate( vNormal, rota, vNormal );
987 normal2.normal[0] = vNormal[0];
988 normal2.normal[1] = vNormal[1];
989 normal2.normal[2] = vNormal[2];
990 AbsoluteToLocal( normal2, f, p1, p2,p3 );
994 void RotateTextures( int nAxis, float fDeg, vec3_t vOrigin ){
995 for ( brush_t* b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
997 for ( face_t* f = b->brush_faces ; f ; f = f->next )
999 if ( g_qeglobals.m_bBrushPrimitMode ) {
1000 RotateFaceTexture_BrushPrimit( f, nAxis, fDeg, vOrigin );
1003 RotateFaceTexture( f, nAxis, fDeg );
1006 Brush_Build( b, false,true,false,false ); // don't filter
1010 void Select_ApplyMatrix_BrushPrimit(){
1012 if ( !g_qeglobals.m_bBrushPrimitMode ) {
1013 Sys_FPrintf( SYS_ERR,"ERROR: Select_ApplyMatrix_BrushPrimit called in non-BP mode\n" );
1016 for ( brush_t* b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1018 for ( face_t* f = b->brush_faces ; f ; f = f->next )
1020 ApplyMatrix_BrushPrimit( f, select_matrix, select_origin );
1025 void Select_FlipAxis( int axis ){
1028 Select_GetMid( select_origin );
1029 for ( i = 0 ; i < 3 ; i++ )
1031 VectorCopy( vec3_origin, select_matrix[i] );
1032 select_matrix[i][i] = 1;
1034 select_matrix[axis][axis] = -1;
1035 select_fliporder = true;
1038 if ( g_PrefsDlg.m_bRotateLock ) {
1039 // axis flipping inverts space orientation, we have to use a general texture locking algorithm instead of the RotateFaceTexture
1040 if ( g_qeglobals.m_bBrushPrimitMode ) {
1041 Select_ApplyMatrix_BrushPrimit();
1045 // there's never been flip locking for non BP mode, this would be tricky to write and there's not much interest for it with the coming of BP format
1046 // what could be done is converting regular to BP, locking, then back to regular :)
1047 Sys_FPrintf( SYS_WRN, "WARNING: regular texturing doesn't have texture lock on flipping operations\n" );
1050 // geometric transformation
1051 Select_ApplyMatrix( true, false, 0, 0 );
1052 Sys_UpdateWindows( W_ALL );
1056 void Select_Scale( float x, float y, float z ){
1057 Select_GetMid( select_origin );
1058 for ( brush_t* b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1060 // ignore fixedsize entities
1061 if ( b->owner->eclass->fixedsize ) {
1064 for ( face_t* f = b->brush_faces ; f ; f = f->next )
1066 for ( int i = 0 ; i < 3 ; i++ )
1068 f->planepts[i][0] -= select_origin[0];
1069 f->planepts[i][1] -= select_origin[1];
1070 f->planepts[i][2] -= select_origin[2];
1071 f->planepts[i][0] *= x;
1072 f->planepts[i][1] *= y;
1073 f->planepts[i][2] *= z;
1075 f->planepts[i][0] += select_origin[0];
1076 f->planepts[i][1] += select_origin[1];
1077 f->planepts[i][2] += select_origin[2];
1080 Brush_Build( b, false,true,false,false ); // don't filter
1081 if ( b->patchBrush ) {
1086 Patch_Scale( b->pPatch, select_origin, v );
1091 void Select_RotateAxis( int axis, float deg, bool bPaint, bool bMouse ){
1100 VectorCopy( g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin );
1104 Select_GetMid( select_origin );
1111 VectorSet(rotation, 0, 0, 360 - deg);
1112 for(brush_t *b = selected_brushes.next; b != &selected_brushes; b = b->next)
1113 if(b->owner->model.pEdit)
1114 b->owner->model.pEdit->Rotate(select_origin, rotation);
1118 select_fliporder = false;
1120 // the "90" degrees algorithm is mostly used on axis rotate as a speedup and possibly avoiding rounding errors as much as possible
1121 // previous implementation was doing an indirect-oriented rotation over the plane whereas the general algo below was doing a direct-oriented rotation
1122 // this was confusing the texture locking algorithms, fixed it to be direct-oriented (side consequence is that the axis rotate toolbar button rotates the other way now)
1123 // NOTE: previous algo was using vec3_origin in the matrix computation..
1124 // I don't see what an origin does in linear transformations (3x3 matrixes always relate to a (0,0,0) origin)
1125 // in Radiant it's initialized as (0,0,0) and never set to another value
1126 // so I got rid of it when it's not used for initialisation tasks (and even if it's not (0,0,0) it should not matter
1133 c = cos( deg * Q_PI / 180.0 );
1134 s = sin( deg * Q_PI / 180.0 );
1137 for ( i = 0 ; i < 3 ; i++ )
1139 VectorCopy( vec3_origin, select_matrix[i] );
1140 select_matrix[i][i] = 1;
1146 select_matrix[1][1] = c;
1147 select_matrix[1][2] = s;
1148 select_matrix[2][1] = -s;
1149 select_matrix[2][2] = c;
1152 select_matrix[0][0] = c;
1153 select_matrix[0][2] = s;
1154 select_matrix[2][0] = -s;
1155 select_matrix[2][2] = c;
1158 select_matrix[0][0] = c;
1159 select_matrix[0][1] = s;
1160 select_matrix[1][0] = -s;
1161 select_matrix[1][1] = c;
1167 if ( g_PrefsDlg.m_bRotateLock ) {
1168 // Terrible hack, reversing input rotation angle to correct
1169 // texture rotation direction for X and Z axes.
1170 // RotateTextures needs to be changed to fix this properly?
1172 RotateTextures( axis, deg, select_origin );
1175 RotateTextures( axis, deg * -1, select_origin );
1178 // geometric transformation
1179 Select_ApplyMatrix( !bMouse, true, axis, deg ); //, false);
1182 Sys_UpdateWindows( W_ALL );
1187 ================================================================
1191 ================================================================
1194 void Select_RealCompleteTall( vec3_t mins, vec3_t maxs ){
1197 int nDim1 = ( g_pParentWnd->ActiveXY()->GetViewType() == YZ ) ? 1 : 0;
1198 int nDim2 = ( g_pParentWnd->ActiveXY()->GetViewType() == XY ) ? 1 : 2;
1200 g_qeglobals.d_select_mode = sel_brush;
1202 for ( b = active_brushes.next ; b != &active_brushes ; b = next )
1206 if ( b->bFiltered ) {
1210 if ( ( b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1] )
1211 || ( b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2] ) ) {
1215 Brush_RemoveFromList( b );
1216 Brush_AddToList( b, &selected_brushes );
1220 void Select_CompleteTall( void ){
1223 if ( !QE_SingleBrush() ) {
1227 Undo_Start( "select complete tall" );
1228 Undo_AddBrushList( &selected_brushes );
1231 VectorCopy( selected_brushes.next->mins, mins );
1232 VectorCopy( selected_brushes.next->maxs, maxs );
1235 Select_RealCompleteTall( mins, maxs );
1236 Sys_UpdateWindows( W_ALL );
1239 void Select_PartialTall( void ){
1243 if ( !QE_SingleBrush() ) {
1247 Undo_Start( "select complete tall" );
1248 Undo_AddBrushList( &selected_brushes );
1251 g_qeglobals.d_select_mode = sel_brush;
1253 VectorCopy( selected_brushes.next->mins, mins );
1254 VectorCopy( selected_brushes.next->maxs, maxs );
1257 int nDim1 = ( g_pParentWnd->ActiveXY()->GetViewType() == YZ ) ? 1 : 0;
1258 int nDim2 = ( g_pParentWnd->ActiveXY()->GetViewType() == XY ) ? 1 : 2;
1260 for ( b = active_brushes.next ; b != &active_brushes ; b = next )
1264 if ( b->bFiltered ) {
1268 if ( ( b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1] )
1269 || ( b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2] ) ) {
1274 Brush_RemoveFromList( b );
1275 Brush_AddToList( b, &selected_brushes );
1278 Sys_UpdateWindows( W_ALL );
1281 void Select_Touching( void ){
1286 if ( !QE_SingleBrush() ) {
1290 g_qeglobals.d_select_mode = sel_brush;
1292 VectorCopy( selected_brushes.next->mins, mins );
1293 VectorCopy( selected_brushes.next->maxs, maxs );
1295 for ( b = active_brushes.next ; b != &active_brushes ; b = next )
1299 if ( b->bFiltered ) {
1303 for ( i = 0 ; i < 3 ; i++ )
1304 if ( b->mins[i] > maxs[i] + 1 || b->maxs[i] < mins[i] - 1 ) {
1309 Brush_RemoveFromList( b );
1310 Brush_AddToList( b, &selected_brushes );
1314 Sys_UpdateWindows( W_ALL );
1317 void Select_Inside( void ){
1322 if ( !QE_SingleBrush() ) {
1326 Undo_Start( "select inside" );
1327 Undo_AddBrushList( &selected_brushes );
1330 g_qeglobals.d_select_mode = sel_brush;
1332 VectorCopy( selected_brushes.next->mins, mins );
1333 VectorCopy( selected_brushes.next->maxs, maxs );
1336 for ( b = active_brushes.next ; b != &active_brushes ; b = next )
1340 if ( b->bFiltered ) {
1344 for ( i = 0 ; i < 3 ; i++ )
1345 if ( b->maxs[i] > maxs[i] || b->mins[i] < mins[i] ) {
1349 Brush_RemoveFromList( b );
1350 Brush_AddToList( b, &selected_brushes );
1354 Sys_UpdateWindows( W_ALL );
1357 void Select_SelectGroup( entity_t* group ){
1361 Undo_Start( "select func group" );
1362 Undo_AddBrushList( &selected_brushes );
1367 b = &group->brushes;
1372 Brush_RemoveFromList( b );
1373 Brush_AddToList( b, &selected_brushes );
1374 } while ( b->onext != &group->brushes );
1376 Sys_UpdateWindows( W_ALL );
1380 void Select_Ungroup( void ){
1381 int numselectedgroups;
1385 numselectedgroups = 0;
1386 for ( sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next )
1390 if ( e == world_entity || e->eclass->fixedsize ) {
1394 for ( b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext )
1396 Entity_UnlinkBrush( b );
1397 Entity_LinkBrush( world_entity, b );
1400 numselectedgroups++;
1403 if ( numselectedgroups <= 0 ) {
1404 Sys_Printf( "No grouped entities selected.\n" );
1407 Sys_Printf( "Ungrouped %d entit%s.\n", numselectedgroups, ( numselectedgroups == 1 ) ? "y" : "ies" );
1408 Sys_UpdateWindows( W_ALL );
1412 group selected brushes into specified entity
1413 if an entity is empty afterwards, destroy it
1415 void Select_GroupEntity( entity_t* group ){
1419 if ( group->eclass->fixedsize ) {
1420 Sys_FPrintf( SYS_ERR, "Select_GroupEntity: can't group anything to a fixedsize entity\n" );
1424 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
1426 if ( b->owner->eclass->fixedsize ) {
1430 Entity_UnlinkBrush( b );
1431 Entity_LinkBrush( group, b );
1432 if ( e != world_entity && e->brushes.onext == &e->brushes ) {
1433 Undo_AddEntity( e );
1440 merge all selected entities together into the first one selected
1441 NOTE: makes use of order of selected_brushes list
1442 can be used to move world brushes in an entity, or to merge several ents together
1443 NOTE: didn't devise a strategy on the epairs, we merge into the first entity and use those
1445 void Select_MergeEntity(){
1448 for ( b = selected_brushes.next; b != &selected_brushes; b = b->next )
1450 if ( !b->owner->eclass->fixedsize ) {
1457 Select_GroupEntity( e );
1460 for ( b = e->brushes.onext; b != &e->brushes; b = b->onext )
1462 //Brush_RemoveFromList (b);
1463 //Brush_AddToList(b, &active_brushes);
1466 Sys_Printf( "Merged %d brushes into %s entity\n", count, ValueForKey( e, "classname" ) );
1471 ====================
1473 ====================
1475 void Select_Seperate( void ) {
1476 Select_GroupEntity( world_entity );
1480 ====================
1481 Select_MakeStructural
1482 ====================
1484 void Select_MakeStructural( void ){
1488 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1490 for ( f = b->brush_faces ; f ; f = f->next )
1491 f->texdef.contents &= ~CONTENTS_DETAIL;
1492 b->bFiltered = FilterBrush( b );
1495 Sys_UpdateWindows( W_ALL );
1498 void Select_MakeDetail( void ){
1502 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1504 for ( f = b->brush_faces ; f ; f = f->next )
1505 f->texdef.contents |= CONTENTS_DETAIL;
1506 b->bFiltered = FilterBrush( b );
1509 Sys_UpdateWindows( W_ALL );
1512 // brush primitive texture adjustments, use the camera view to map adjustments
1513 // ShiftTextureRelative_BrushPrimit ( s , t ) will shift relative to the texture
1514 void ShiftTextureRelative_Camera( face_t *f, int x, int y ){
1516 vec_t XY[2]; // the values we are going to send for translation
1517 vec_t sgn[2]; // +1 or -1
1521 // get the two relative texture axes for the current texturing
1522 BrushPrimit_GetRelativeAxes( f, vecS, vecT );
1524 // center point of the face, project it on the camera space
1528 for ( i = 0; i < f->face_winding->numpoints; i++ )
1530 VectorAdd( C,f->face_winding->points[i],C );
1532 VectorScale( C,1.0 / f->face_winding->numpoints,C );
1534 pCam = g_pParentWnd->GetCamWnd();
1535 pCam->MatchViewAxes( C, vecS, axis[0], sgn[0] );
1536 pCam->MatchViewAxes( C, vecT, axis[1], sgn[1] );
1538 // this happens when the two directions can't be mapped on two different directions on the screen
1539 // then the move will occur against a single axis
1540 // (i.e. the user is not positioned well enough to send understandable shift commands)
1541 // NOTE: in most cases this warning is not very relevant because the user would use one of the two axes
1542 // for which the solution is easy (the other one being unknown)
1543 // so this warning could be removed
1544 if ( axis[0] == axis[1] ) {
1545 Sys_FPrintf( SYS_WRN, "Warning: degenerate in ShiftTextureRelative_Camera\n" );
1548 // compute the X Y geometric increments
1549 // those geometric increments will be applied along the texture axes (the ones we computed above)
1553 // moving right/left
1554 XY[axis[0]] += sgn[0] * x;
1557 XY[axis[1]] += sgn[1] * y;
1559 // we worked out a move along vecS vecT, and we now it's geometric amplitude
1561 ShiftTextureRelative_BrushPrimit( f, XY[0], XY[1] );
1564 void Select_ShiftTexture( int x, int y ){
1568 int nFaceCount = g_ptrSelectedFaces.GetSize();
1570 if ( selected_brushes.next == &selected_brushes && nFaceCount == 0 ) {
1574 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1576 for ( f = b->brush_faces ; f ; f = f->next )
1578 if ( g_qeglobals.m_bBrushPrimitMode ) {
1579 ShiftTextureRelative_Camera( f, x, y );
1583 f->texdef.shift[0] += x;
1584 f->texdef.shift[1] += y;
1587 Brush_Build( b,true,true,false,false ); // don't filter
1588 if ( b->patchBrush ) {
1589 Patch_ShiftTexture( b->pPatch, x, y );
1593 if ( nFaceCount > 0 ) {
1594 for ( int i = 0; i < nFaceCount; i++ )
1596 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( i ) );
1597 brush_t *selBrush = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( i ) );
1598 if ( g_qeglobals.m_bBrushPrimitMode ) {
1599 ShiftTextureRelative_Camera( selFace, x, y );
1603 selFace->texdef.shift[0] += x;
1604 selFace->texdef.shift[1] += y;
1606 Brush_Build( selBrush,true,true,false,false ); // don't filter
1610 Sys_UpdateWindows( W_CAMERA );
1613 // setting float as input
1614 void Select_ScaleTexture( float x, float y ){
1618 int nFaceCount = g_ptrSelectedFaces.GetSize();
1620 if ( selected_brushes.next == &selected_brushes && nFaceCount == 0 ) {
1624 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1626 for ( f = b->brush_faces ; f ; f = f->next )
1628 if ( g_qeglobals.m_bBrushPrimitMode ) {
1629 // apply same scale as the spinner button of the surface inspector
1633 brushprimit_texdef_t bp;
1634 // compute normalized texture matrix
1635 ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL );
1636 // compute fake shift scale rot
1637 TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
1639 scale[0] += static_cast<float>( x ) * 0.1;
1640 scale[1] += static_cast<float>( y ) * 0.1;
1641 // compute new normalized texture matrix
1642 FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
1643 // apply to face texture matrix
1644 ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture );
1648 f->texdef.scale[0] += x;
1649 f->texdef.scale[1] += y;
1652 Brush_Build( b,true,true,false,false ); // don't filter
1653 if ( b->patchBrush ) {
1654 Patch_ScaleTexture( b->pPatch, x, y );
1658 if ( nFaceCount > 0 ) {
1659 for ( int i = 0; i < nFaceCount; i++ )
1661 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( i ) );
1662 brush_t *selBrush = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( i ) );
1663 if ( g_qeglobals.m_bBrushPrimitMode ) {
1667 brushprimit_texdef_t bp;
1668 ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL );
1669 TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
1670 scale[0] += static_cast<float>( x ) * 0.1;
1671 scale[1] += static_cast<float>( y ) * 0.1;
1672 FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
1673 ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture );
1677 selFace->texdef.scale[0] += x;
1678 selFace->texdef.scale[1] += y;
1680 Brush_Build( selBrush,true,true,false,false ); // don't filter
1684 Sys_UpdateWindows( W_CAMERA );
1687 void Select_RotateTexture( int amt ){
1691 int nFaceCount = g_ptrSelectedFaces.GetSize();
1693 if ( selected_brushes.next == &selected_brushes && nFaceCount == 0 ) {
1697 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1699 for ( f = b->brush_faces ; f ; f = f->next )
1701 if ( g_qeglobals.m_bBrushPrimitMode ) {
1702 // apply same scale as the spinner button of the surface inspector
1706 brushprimit_texdef_t bp;
1707 // compute normalized texture matrix
1708 ConvertTexMatWithQTexture( &f->brushprimit_texdef, f->d_texture, &bp, NULL );
1709 // compute fake shift scale rot
1710 TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
1713 // compute new normalized texture matrix
1714 FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
1715 // apply to face texture matrix
1716 ConvertTexMatWithQTexture( &bp, NULL, &f->brushprimit_texdef, f->d_texture );
1720 f->texdef.rotate += amt;
1721 f->texdef.rotate = static_cast<int>( f->texdef.rotate ) % 360;
1724 Brush_Build( b,true,true,false,false ); // don't filter
1725 if ( b->patchBrush ) {
1726 //Patch_RotateTexture(b->nPatchID, amt);
1727 Patch_RotateTexture( b->pPatch, amt );
1731 if ( nFaceCount > 0 ) {
1732 for ( int i = 0; i < nFaceCount; i++ )
1734 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( i ) );
1735 brush_t *selBrush = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( i ) );
1736 if ( g_qeglobals.m_bBrushPrimitMode ) {
1740 brushprimit_texdef_t bp;
1741 ConvertTexMatWithQTexture( &selFace->brushprimit_texdef, selFace->d_texture, &bp, NULL );
1742 TexMatToFakeTexCoords( bp.coords, shift, &rotate, scale );
1744 FakeTexCoordsToTexMat( shift, rotate, scale, bp.coords );
1745 ConvertTexMatWithQTexture( &bp, NULL, &selFace->brushprimit_texdef, selFace->d_texture );
1749 selFace->texdef.rotate += amt;
1750 selFace->texdef.rotate = static_cast<int>( selFace->texdef.rotate ) % 360;
1752 Brush_Build( selBrush,true,true,false,false ); // don't filter
1756 Sys_UpdateWindows( W_CAMERA );
1759 // TTimo modified to handle shader architecture:
1760 // expects shader names at input, comparison relies on shader names .. texture names no longer relevant
1761 void FindReplaceTextures( const char* pFind, const char* pReplace, bool bSelected, bool bForce, bool bSelectMatchingFaces ){
1762 if ( strchr( pFind, ' ' ) || strchr( pReplace, ' ' ) ) {
1763 Sys_FPrintf( SYS_WRN, "FindReplaceTextures: '%s' or '%s' have spaces, aborted\n", pFind, pReplace );
1767 brush_t* pList = ( bSelected ) ? &selected_brushes : &active_brushes;
1772 //++timo BP mode: replacing a texture in BP mode is not that easy, you need to recompute the texture matrix
1773 // if the size of the replacing texture differs, otherwise you get wrong scaling
1774 if ( g_qeglobals.m_bBrushPrimitMode ) {
1775 Sys_Printf( "TODO: finalize find/replace code for brush primitives" );
1779 for ( brush_t* pBrush = pList->next ; pBrush != pList; pBrush = pBrush->next )
1781 if ( !bSelectMatchingFaces && pBrush->patchBrush ) {
1782 Patch_FindReplaceTexture( pBrush, pFind, pReplace, bForce );
1785 bool found = false; //spog
1786 for ( face_t* pFace = pBrush->brush_faces; pFace; pFace = pFace->next )
1788 if ( bForce || strcmpi( pFace->pShader->getName(), pFind ) == 0 ) {
1789 if ( !bSelectMatchingFaces ) {
1790 pFace->pShader->DecRef();
1791 pFace->pShader = QERApp_Shader_ForName( pReplace );
1792 pFace->pShader->IncRef();
1793 pFace->d_texture = pFace->pShader->getTexture();
1794 pFace->texdef.SetName( pReplace );
1797 else if ( bSelectMatchingFaces ) {
1798 mFaces.Add( pFace );
1803 if ( found ) { // spog - speed increase, only build brushes that changed
1804 Brush_Build( pBrush );
1809 if ( bSelectMatchingFaces ) {
1814 int nSize = mFaces.GetSize();
1815 for ( int i = 0; i < nSize; i++ ) {
1816 g_SelectedFaces.Add( reinterpret_cast<face_t *>( mFaces.GetAt( i ) ) );
1820 Sys_UpdateWindows( W_CAMERA );
1823 void Select_AllOfType(){
1826 // if no brush selected, we will select based on texture
1827 // the first selected face's texture if any, or the current texture
1828 // if a brush is selected, we will select entities (first non-worldspawn owner in selected brushes)
1829 if ( selected_brushes.next == &selected_brushes ) {
1832 if ( g_ptrSelectedFaces.GetSize() == 0 ) {
1833 strName = g_qeglobals.d_texturewin.texdef.GetName();
1837 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( 0 ) );
1838 strName = selFace->texdef.GetName();
1841 Sys_Printf( "Selecting all brushes with the texture %s\n", strName.GetBuffer() );
1844 for ( b = active_brushes.next ; b != &active_brushes ; b = next )
1848 if ( b->bFiltered ) {
1852 if ( b->patchBrush ) {
1853 if ( strcmpi( strName, b->pPatch->pShader->getName() ) == 0 ) {
1854 Brush_RemoveFromList( b );
1855 Brush_AddToList( b, &selected_brushes );
1860 for ( face_t* pFace = b->brush_faces; pFace; pFace = pFace->next )
1862 if ( strcmpi( strName, pFace->texdef.GetName() ) == 0 ) {
1863 Brush_RemoveFromList( b );
1864 Brush_AddToList( b, &selected_brushes );
1869 Sys_UpdateWindows( W_ALL );
1874 b = selected_brushes.next;
1878 if ( e != world_entity ) {
1879 CString strName = e->eclass->name;
1880 CString strKey, strVal;
1881 bool bCriteria = GetSelectAllCriteria( strKey, strVal );
1882 Sys_Printf( "Selecting all %s entities\n", strName.GetBuffer() );
1885 for ( b = active_brushes.next ; b != &active_brushes ; b = next )
1889 if ( b->bFiltered ) {
1895 if ( strcmpi( e->eclass->name, strName ) == 0 ) {
1898 CString str = ValueForKey( e, strKey );
1899 if ( str.CompareNoCase( strVal ) != 0 ) {
1904 Brush_RemoveFromList( b );
1905 Brush_AddToList( b, &selected_brushes );
1912 Sys_UpdateWindows( W_ALL );
1916 void Select_Reselect(){
1917 Select_Brush( selected_brushes.next );
1918 Sys_UpdateWindows( W_ALL );
1922 void Select_FitTexture( int nHeight, int nWidth ){
1925 int nFaceCount = g_ptrSelectedFaces.GetSize();
1927 if ( selected_brushes.next == &selected_brushes && nFaceCount == 0 ) {
1931 for ( b = selected_brushes.next ; b != &selected_brushes ; b = b->next )
1933 Brush_FitTexture( b, nHeight, nWidth );
1934 Brush_Build( b,true,true,false,false ); // don't filter
1937 if ( nFaceCount > 0 ) {
1938 for ( int i = 0; i < nFaceCount; i++ )
1940 face_t *selFace = reinterpret_cast<face_t*>( g_ptrSelectedFaces.GetAt( i ) );
1941 brush_t *selBrush = reinterpret_cast<brush_t*>( g_ptrSelectedFaceBrushes.GetAt( i ) );
1942 Face_FitTexture( selFace, nHeight, nWidth );
1943 Brush_Build( selBrush,true,true,false,false ); // don't filter
1947 Sys_UpdateWindows( W_CAMERA );
1951 for ( brush_t* b = selected_brushes.next ; b && b != &selected_brushes ; b = b->next )
1953 b->hiddenBrush = true;
1954 b->bFiltered = true;
1956 Sys_UpdateWindows( W_ALL );
1959 void Select_ShowAllHidden(){
1961 for ( b = selected_brushes.next ; b && b != &selected_brushes ; b = b->next )
1963 if ( b->hiddenBrush ) {
1964 b->hiddenBrush = false;
1965 b->bFiltered = FilterBrush( b );
1968 for ( b = active_brushes.next ; b && b != &active_brushes ; b = b->next )
1970 if ( b->hiddenBrush ) {
1971 b->hiddenBrush = false;
1972 b->bFiltered = FilterBrush( b );
1975 Sys_UpdateWindows( W_ALL );
1984 void Select_Invert( void ){
1985 brush_t *next, *prev, *b;
1987 Sys_Printf( "inverting selection...\n" );
1989 next = active_brushes.next;
1990 prev = active_brushes.prev;
1991 if ( selected_brushes.next != &selected_brushes ) {
1992 active_brushes.next = selected_brushes.next;
1993 active_brushes.prev = selected_brushes.prev;
1994 active_brushes.next->prev = &active_brushes;
1995 active_brushes.prev->next = &active_brushes;
1999 active_brushes.next = &active_brushes;
2000 active_brushes.prev = &active_brushes;
2002 if ( next != &active_brushes ) {
2003 selected_brushes.next = next;
2004 selected_brushes.prev = prev;
2005 selected_brushes.next->prev = &selected_brushes;
2006 selected_brushes.prev->next = &selected_brushes;
2010 selected_brushes.next = &selected_brushes;
2011 selected_brushes.prev = &selected_brushes;
2014 // now check if any hidden brush is selected
2015 for ( b = selected_brushes.next; b != &selected_brushes; )
2017 if ( b->patchBrush ) {
2018 b->pPatch->bSelected = true;
2021 if ( b->bFiltered ) {
2024 Brush_RemoveFromList( pb );
2025 Brush_AddToList( pb, &active_brushes );
2027 else{ b = b->next; }
2031 for ( b = active_brushes.next; b != &active_brushes; b = b->next )
2033 if ( b->patchBrush ) {
2034 b->pPatch->bSelected = false;
2038 // since invert selection only works at the brush level,
2039 // set g_qeglobals.d_select_mode accordingly
2040 g_qeglobals.d_select_mode = sel_brush;
2042 // since invert selection only works at the brush level,
2043 // set g_qeglobals.d_select_mode accordingly
2044 g_qeglobals.d_select_mode = sel_brush;
2046 Sys_UpdateWindows( W_ALL );
2048 Sys_Printf( "done.\n" );
2051 #ifdef ENABLE_GROUPS
2057 void Select_Name( const char *pName ){
2058 if ( g_qeglobals.m_bBrushPrimitMode ) {
2059 for ( brush_t* b = selected_brushes.next ; b && b != &selected_brushes ; b = b->next )
2061 Brush_SetEpair( b, "Name", pName );
2069 add selected brushes to a group, update the tree
2072 void Select_AddToGroup( const char *pName ){
2073 if ( g_qeglobals.m_bBrushPrimitMode ) {
2074 for ( brush_t* b = selected_brushes.next ; b && b != &selected_brushes ; b = b->next )
2076 Brush_SetEpair( b, "group", pName );
2077 Group_AddToProperGroup( b );