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

SELECT.CPP

Go to the documentation of this file.
00001 /*
00002 ===========================================================================
00003 Copyright (C) 1999-2005 Id Software, Inc.
00004 
00005 This file is part of Quake III Arena source code.
00006 
00007 Quake III Arena source code is free software; you can redistribute it
00008 and/or modify it under the terms of the GNU General Public License as
00009 published by the Free Software Foundation; either version 2 of the License,
00010 or (at your option) any later version.
00011 
00012 Quake III Arena source code is distributed in the hope that it will be
00013 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 GNU General Public License for more details.
00016 
00017 You should have received a copy of the GNU General Public License
00018 along with Foobar; if not, write to the Free Software
00019 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00020 ===========================================================================
00021 */
00022 // select.c
00023 #include "stdafx.h"
00024 #include "qe3.h"
00025 
00026 
00027 // externs
00028 CPtrArray g_SelectedFaces;
00029 CPtrArray g_SelectedFaceBrushes;
00030 CPtrArray& g_ptrSelectedFaces = g_SelectedFaces;
00031 CPtrArray& g_ptrSelectedFaceBrushes = g_SelectedFaceBrushes;
00032 
00033 
00034 void clearSelection() {
00035     g_qeglobals.d_select_mode = sel_brush;
00036     g_qeglobals.selectObject = NULL;
00037 }
00038 
00039 /*
00040 ===========
00041 Test_Ray
00042 ===========
00043 */
00044 #define DIST_START  999999
00045 trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags)
00046 {
00047     brush_t *brush;
00048     face_t  *face;
00049     float   dist;
00050     trace_t t;
00051 
00052     memset (&t, 0, sizeof(t));
00053     t.dist = DIST_START;
00054 
00055     if (flags & SF_CYCLE)
00056     {
00057         CPtrArray array;
00058         brush_t *pToSelect = (selected_brushes.next != &selected_brushes) ? selected_brushes.next : NULL;
00059         Select_Deselect();
00060 
00061         // go through active brushes and accumulate all "hit" brushes
00062         for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
00063         {
00064             //if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
00065             //  continue;
00066          
00067             if (FilterBrush (brush))
00068                 continue;
00069 
00070             if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
00071                 continue;
00072 
00073             if( !g_PrefsDlg.m_bSelectTerrain && brush->terrainBrush )
00074                 continue;
00075 
00076             //if (!g_bShowPatchBounds && brush->patchBrush)
00077             //  continue;
00078 
00079             face = Brush_Ray (origin, dir, brush, &dist);
00080 
00081             if (face)
00082             {
00083                 if ( brush->terrainBrush )
00084                 {
00085                     Terrain_Ray( origin, dir, brush, &dist );
00086                     if( dist == 0 )
00087                     {
00088                         // didn't actually hit the terrain
00089                         continue;
00090                     }
00091                 }
00092                 array.Add(brush);
00093             }
00094         }
00095 
00096         int nSize = array.GetSize();
00097         if (nSize > 0)
00098         {
00099             bool bFound = false;
00100             for (int i = 0; i < nSize; i++)
00101             {
00102                 brush_t *b = reinterpret_cast<brush_t*>(array.GetAt(i));
00103                 // did we hit the last one selected yet ?
00104                 if (b == pToSelect)
00105                 {
00106                     // yes we want to select the next one in the list 
00107                     int n = (i > 0) ? i-1 : nSize-1;
00108                     pToSelect = reinterpret_cast<brush_t*>(array.GetAt(n));
00109                     bFound = true;
00110                     break;
00111                 }
00112             }
00113             if (!bFound)
00114                 pToSelect = reinterpret_cast<brush_t*>(array.GetAt(0));
00115         }
00116         if (pToSelect)
00117         {
00118             face = Brush_Ray (origin, dir, pToSelect, &dist);
00119             if ( pToSelect->terrainBrush )
00120             {
00121                 t.terraface = Terrain_Ray( origin, dir, pToSelect, &dist );
00122             }
00123 
00124             t.dist = dist;
00125             t.brush = pToSelect;
00126             t.face = face;
00127             t.selected = false;
00128             return t;
00129         }
00130     }
00131 
00132     if (! (flags & SF_SELECTED_ONLY) )
00133     {
00134         for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
00135         {
00136             if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
00137                 continue;
00138             
00139             if (FilterBrush (brush))
00140                 continue;
00141 
00142             if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
00143                 continue;
00144 
00145             if( !g_PrefsDlg.m_bSelectTerrain && brush->terrainBrush )
00146                 continue;
00147 
00148             //if (!g_bShowPatchBounds && brush->patchBrush)
00149             //  continue;
00150 
00151             face = Brush_Ray (origin, dir, brush, &dist);
00152             if ( face ) {
00153                 if ( brush->terrainBrush )
00154                 {
00155                     t.terraface = Terrain_Ray( origin, dir, brush, &dist );
00156                 }
00157             }
00158             if (dist > 0 && dist < t.dist)
00159             {
00160                 t.dist = dist;
00161                 t.brush = brush;
00162                 t.face = face;
00163                 t.selected = false;
00164             }
00165         }
00166     }
00167 
00168 
00169     for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
00170     {
00171         if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
00172             continue;
00173 
00174         if (FilterBrush (brush))
00175             continue;
00176 
00177         if (!g_PrefsDlg.m_bSelectCurves && brush->patchBrush)
00178             continue;
00179 
00180         if( !g_PrefsDlg.m_bSelectTerrain && brush->terrainBrush )
00181             continue;
00182 
00183         face = Brush_Ray (origin, dir, brush, &dist);
00184         if ( face ) {
00185             if ( brush->terrainBrush )
00186             {
00187                 t.terraface = Terrain_Ray( origin, dir, brush, &dist );
00188             }
00189         }
00190         if (dist > 0 && dist < t.dist)
00191         {
00192             t.dist = dist;
00193             t.brush = brush;
00194             t.face = face;
00195             t.selected = true;
00196         }
00197     }
00198 
00199     // if entites first, but didn't find any, check regular
00200 
00201     if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL)
00202         return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST);
00203 
00204     return t;
00205 
00206 }
00207 
00208 
00209 /*
00210 ============
00211 Select_Brush
00212 
00213 ============
00214 */
00215 void Select_Brush (brush_t *brush, bool bComplete, bool bStatus)
00216 {
00217     brush_t *b;
00218     entity_t    *e;
00219 
00220   g_ptrSelectedFaces.RemoveAll();
00221   g_ptrSelectedFaceBrushes.RemoveAll();
00222     //selected_face = NULL;
00223     if (g_qeglobals.d_select_count < 2)
00224         g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
00225     g_qeglobals.d_select_count++;
00226 
00227   //if (brush->patchBrush)
00228   //  Patch_Select(brush->nPatchID);
00229 
00230     e = brush->owner;
00231     if (e)
00232     {
00233         // select complete entity on first click
00234         if (e != world_entity && bComplete == true)
00235         {
00236             for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00237                 if (b->owner == e)
00238                     goto singleselect;
00239             for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
00240             {
00241         Brush_RemoveFromList (b);
00242                 Brush_AddToList (b, &selected_brushes);
00243             }
00244         }
00245         else
00246         {
00247 singleselect:
00248             Brush_RemoveFromList (brush);
00249             Brush_AddToList (brush, &selected_brushes);
00250       UpdateSurfaceDialog();
00251       UpdatePatchInspector();
00252         }
00253 
00254         if (e->eclass)
00255         {
00256             UpdateEntitySel(brush->owner->eclass);
00257         }
00258     }
00259   if (bStatus)
00260   {
00261     vec3_t vMin, vMax, vSize;
00262       Select_GetBounds (vMin, vMax);
00263     VectorSubtract(vMax, vMin, vSize);
00264     CString strStatus;
00265     strStatus.Format("Selection X:: %.1f  Y:: %.1f  Z:: %.1f", vSize[0], vSize[1], vSize[2]);
00266     g_pParentWnd->SetStatusText(2, strStatus);
00267   }
00268 }
00269 
00270 
00271 /*
00272 ============
00273 Select_Ray
00274 
00275 If the origin is inside a brush, that brush will be ignored.
00276 ============
00277 */
00278 void Select_Ray (vec3_t origin, vec3_t dir, int flags)
00279 {
00280     trace_t t;
00281 
00282     t = Test_Ray (origin, dir, flags);
00283     if (!t.brush)
00284         return;
00285 
00286     if (flags == SF_SINGLEFACE)
00287     {
00288         int nCount = g_SelectedFaces.GetSize();
00289         bool bOk = true;
00290         for (int i = 0; i < nCount; i++)
00291         {
00292             if (t.face == reinterpret_cast<face_t*>(g_SelectedFaces.GetAt(i)))
00293             {
00294                 bOk = false;
00295                 // need to move remove i'th entry
00296                 g_SelectedFaces.RemoveAt(i, 1);
00297                 g_SelectedFaceBrushes.RemoveAt(i, 1);
00298             }
00299         }
00300         if (bOk)
00301         {
00302             g_SelectedFaces.Add(t.face);
00303             g_SelectedFaceBrushes.Add(t.brush);
00304         }
00305         //selected_face = t.face;
00306         //selected_face_brush = t.brush;
00307         Sys_UpdateWindows (W_ALL);
00308         clearSelection();
00309         // Texture_SetTexture requires a brushprimit_texdef fitted to the default width=2 height=2 texture
00310         brushprimit_texdef_t brushprimit_texdef;
00311         ConvertTexMatWithQTexture ( &t.face->brushprimit_texdef, t.face->d_texture, &brushprimit_texdef, NULL );
00312         Texture_SetTexture ( &t.face->texdef, &brushprimit_texdef, false, GETPLUGINTEXDEF(t.face), false );
00313         UpdateSurfaceDialog();
00314         return;
00315     }
00316 
00317     // move the brush to the other list
00318 
00319     clearSelection();
00320 
00321     if (t.selected)
00322     {       
00323         Brush_RemoveFromList (t.brush);
00324         Brush_AddToList (t.brush, &active_brushes);
00325         UpdatePatchInspector();
00326     } 
00327     else
00328     {
00329         Select_Brush (t.brush, !(GetKeyState(VK_MENU) & 0x8000));
00330     }
00331 
00332     Sys_UpdateWindows (W_ALL);
00333 }
00334 
00335 
00336 void Select_Delete (void)
00337 {
00338     brush_t *brush;
00339 
00340   g_ptrSelectedFaces.RemoveAll();
00341   g_ptrSelectedFaceBrushes.RemoveAll();
00342     //selected_face = NULL;
00343     
00344     clearSelection();
00345 
00346     g_qeglobals.d_select_count = 0;
00347     g_qeglobals.d_num_move_points = 0;
00348     while (selected_brushes.next != &selected_brushes)
00349     {
00350         brush = selected_brushes.next;
00351     if (brush->patchBrush)
00352     {
00353       //Patch_Delete(brush->nPatchID);
00354       Patch_Delete(brush->pPatch);
00355     }
00356     if (brush->terrainBrush)
00357     {
00358         Terrain_Delete(brush->pTerrain );
00359     }
00360 
00361         Brush_Free (brush);
00362     }
00363 
00364     // FIXME: remove any entities with no brushes
00365 
00366     Sys_UpdateWindows (W_ALL);
00367 }
00368 
00369 void Select_Deselect (bool bDeselectFaces)
00370 {
00371     brush_t *b;
00372 
00373   Patch_Deselect();
00374 
00375   g_pParentWnd->ActiveXY()->UndoClear();
00376 
00377   g_qeglobals.d_workcount++;
00378     g_qeglobals.d_select_count = 0;
00379     g_qeglobals.d_num_move_points = 0;
00380     b = selected_brushes.next;
00381 
00382     if (b == &selected_brushes)
00383     {
00384         if (bDeselectFaces)
00385         {
00386             g_ptrSelectedFaces.RemoveAll();
00387       g_ptrSelectedFaceBrushes.RemoveAll();
00388       //selected_face = NULL;
00389         }
00390         Sys_UpdateWindows (W_ALL);
00391         return;
00392     }
00393 
00394   if (bDeselectFaces)
00395   {
00396     g_ptrSelectedFaces.RemoveAll();
00397     g_ptrSelectedFaceBrushes.RemoveAll();
00398       //selected_face = NULL;
00399   }
00400 
00401     clearSelection();
00402 
00403     // grab top / bottom height for new brushes
00404     if (b->mins[2] < b->maxs[2])
00405     {
00406         g_qeglobals.d_new_brush_bottom_z = b->mins[2];
00407         g_qeglobals.d_new_brush_top_z = b->maxs[2];
00408     }
00409 
00410     selected_brushes.next->prev = &active_brushes;
00411     selected_brushes.prev->next = active_brushes.next;
00412     active_brushes.next->prev = selected_brushes.prev;
00413     active_brushes.next = selected_brushes.next;
00414     selected_brushes.prev = selected_brushes.next = &selected_brushes;  
00415 
00416     Sys_UpdateWindows (W_ALL);
00417 }
00418 
00419 /*
00420 ============
00421 Select_Move
00422 ============
00423 */
00424 void Select_Move (vec3_t delta, bool bSnap)
00425 {
00426     brush_t *b;
00427   
00428  
00429 // actually move the selected brushes
00430     for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
00431         Brush_Move (b, delta, bSnap);
00432 
00433   vec3_t vMin, vMax;
00434     Select_GetBounds (vMin, vMax);
00435   CString strStatus;
00436   strStatus.Format("Origin X:: %.1f  Y:: %.1f  Z:: %.1f", vMin[0], vMax[1], vMax[2]);
00437   g_pParentWnd->SetStatusText(2, strStatus);
00438 
00439 //  Sys_UpdateWindows (W_ALL);
00440 }
00441 
00442 /*
00443 ============
00444 Select_Clone
00445 
00446 Creates an exact duplicate of the selection in place, then moves
00447 the selected brushes off of their old positions
00448 ============
00449 */
00450 void Select_Clone (void)
00451 {
00452 #if 1
00453   ASSERT(g_pParentWnd->ActiveXY());
00454   g_bScreenUpdates = false;  
00455   g_pParentWnd->ActiveXY()->Copy();
00456   g_pParentWnd->ActiveXY()->Paste();
00457   g_pParentWnd->NudgeSelection(2, g_qeglobals.d_gridsize);
00458   g_pParentWnd->NudgeSelection(3, g_qeglobals.d_gridsize);
00459   g_bScreenUpdates = true;  
00460   Sys_UpdateWindows(W_ALL);
00461 #else
00462 
00463     brush_t     *b, *b2, *n, *next, *next2;
00464     vec3_t      delta;
00465     entity_t    *e;
00466 
00467     g_qeglobals.d_workcount++;
00468     clearSelection();
00469 
00470     delta[0] = g_qeglobals.d_gridsize;
00471     delta[1] = g_qeglobals.d_gridsize;
00472     delta[2] = 0;
00473 
00474     for (b=selected_brushes.next ; b != &selected_brushes ; b=next)
00475     {
00476         next = b->next;
00477         // if the brush is a world brush, handle simply
00478         if (b->owner == world_entity)
00479         {
00480             n = Brush_Clone (b);
00481             Brush_AddToList (n, &active_brushes);
00482             Entity_LinkBrush (world_entity, n);
00483             Brush_Build( n );
00484             Brush_Move (b, delta);
00485             continue;
00486         }
00487 
00488         e = Entity_Clone (b->owner);
00489         // clear the target / targetname
00490         DeleteKey (e, "target");
00491         DeleteKey (e, "targetname");
00492 
00493         // if the brush is a fixed size entity, create a new entity
00494         if (b->owner->eclass->fixedsize)
00495         {
00496             n = Brush_Clone (b);
00497             Brush_AddToList (n, &active_brushes);
00498             Entity_LinkBrush (e, n);
00499             Brush_Build( n );
00500             Brush_Move (b, delta);
00501             continue;
00502         }
00503         
00504         // brush is a complex entity, grab all the other ones now
00505 
00506         next = &selected_brushes;
00507 
00508         for ( b2 = b ; b2 != &selected_brushes ; b2=next2)
00509         {
00510             next2 = b2->next;
00511             if (b2->owner != b->owner)
00512             {
00513                 if (next == &selected_brushes)
00514                     next = b2;
00515                 continue;
00516             }
00517 
00518             // move b2 to the start of selected_brushes,
00519             // so it won't be hit again
00520             Brush_RemoveFromList (b2);
00521             Brush_AddToList (b2, &selected_brushes);
00522             
00523             n = Brush_Clone (b2);
00524             Brush_AddToList (n, &active_brushes);
00525             Entity_LinkBrush (e, n);
00526             Brush_Build( n );
00527             Brush_Move (b2, delta, true);
00528         }
00529 
00530     }
00531     Sys_UpdateWindows (W_ALL);
00532 #endif
00533 }
00534 
00535 
00536 
00537 /*
00538 ============
00539 Select_SetTexture
00540 Timo : bFitScale to compute scale on the plane and counteract plane / axial plane snapping
00541 Timo :  brush primitive texturing
00542         the brushprimit_texdef given must be understood as a qtexture_t width=2 height=2 ( HiRes )
00543 Timo :  texture plugin, added an IPluginTexdef* parameter
00544         must be casted to an IPluginTexdef!
00545         if not NULL, get ->Copy() of it into each face or brush ( and remember to hook )
00546         if NULL, means we have no information, ask for a default
00547 ============
00548 */
00549 void WINAPI Select_SetTexture (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef )
00550 {
00551     brush_t *b;
00552     int nCount = g_ptrSelectedFaces.GetSize();
00553     if (nCount > 0)
00554     {
00555         Undo_Start("set face textures");
00556         ASSERT(g_ptrSelectedFaces.GetSize() == g_ptrSelectedFaceBrushes.GetSize());
00557         for (int i = 0; i < nCount; i++)
00558         {
00559             face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
00560             brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
00561             Undo_AddBrush(selBrush);
00562             SetFaceTexdef (selBrush, selFace, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>(pPlugTexdef) );
00563             Brush_Build(selBrush, bFitScale);
00564             Undo_EndBrush(selBrush);
00565         }
00566         Undo_End();
00567     }
00568     else if (selected_brushes.next != &selected_brushes)
00569     {
00570         Undo_Start("set brush textures");
00571         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00572             if (!b->owner->eclass->fixedsize)
00573             {
00574                 Undo_AddBrush(b);
00575                 Brush_SetTexture (b, texdef, brushprimit_texdef, bFitScale, static_cast<IPluginTexdef *>(pPlugTexdef) );
00576                 Undo_EndBrush(b);
00577             }
00578         Undo_End();
00579     }
00580     Sys_UpdateWindows (W_ALL);
00581 }
00582 
00583 
00584 /*
00585 ================================================================
00586 
00587   TRANSFORMATIONS
00588 
00589 ================================================================
00590 */
00591 
00592 void Select_GetBounds (vec3_t mins, vec3_t maxs)
00593 {
00594     brush_t *b;
00595     int     i;
00596 
00597     for (i=0 ; i<3 ; i++)
00598     {
00599         mins[i] = 99999;
00600         maxs[i] = -99999;
00601     }
00602 
00603     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00604         for (i=0 ; i<3 ; i++)
00605         {
00606             if (b->mins[i] < mins[i])
00607                 mins[i] = b->mins[i];
00608             if (b->maxs[i] > maxs[i])
00609                 maxs[i] = b->maxs[i];
00610         }
00611 }
00612 
00613 
00614 void Select_GetTrueMid (vec3_t mid)
00615 {
00616     vec3_t  mins, maxs;
00617     Select_GetBounds (mins, maxs);
00618 
00619   for (int i=0 ; i<3 ; i++)
00620     mid[i] = (mins[i] + ((maxs[i] - mins[i]) / 2));
00621 }
00622 
00623 
00624 void Select_GetMid (vec3_t mid)
00625 {
00626     vec3_t  mins, maxs;
00627     int     i;
00628 
00629   if (g_PrefsDlg.m_bNoClamp)
00630   {
00631     Select_GetTrueMid(mid);
00632     return;
00633   }
00634 
00635   Select_GetBounds (mins, maxs);
00636 
00637   for (i=0 ; i<3 ; i++)
00638         mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize );
00639 
00640 }
00641 
00642 vec3_t  select_origin;
00643 vec3_t  select_matrix[3];
00644 qboolean    select_fliporder;
00645 
00646 void Select_ApplyMatrix (bool bSnap, bool bRotation, int nAxis, float fDeg)
00647 {
00648     brush_t *b;
00649     face_t  *f;
00650     int     i, j;
00651     vec3_t  temp;
00652 
00653     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00654     {
00655         for (f=b->brush_faces ; f ; f=f->next)
00656         {
00657             for (i=0 ; i<3 ; i++)
00658             {
00659                 VectorSubtract (f->planepts[i], select_origin, temp);
00660                 for (j=0 ; j<3 ; j++)
00661                     f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + select_origin[j];
00662             }
00663             if (select_fliporder)
00664             {
00665                 VectorCopy (f->planepts[0], temp);
00666                 VectorCopy (f->planepts[2], f->planepts[0]);
00667                 VectorCopy (temp, f->planepts[2]);
00668             }
00669         }
00670 
00671         if(b->owner->eclass->fixedsize)
00672         {
00673             if (bRotation && b->owner->md3Class)
00674             {
00675                 b->owner->vRotation[nAxis] += fDeg;
00676             }
00677         }
00678 
00679         Brush_Build(b, bSnap);
00680     
00681         if (b->patchBrush)
00682         {
00683             //Patch_ApplyMatrix(b->nPatchID, select_origin, select_matrix);
00684             Patch_ApplyMatrix(b->pPatch, select_origin, select_matrix, bSnap);
00685         }
00686 
00687         if (b->terrainBrush)
00688         {
00689           Terrain_ApplyMatrix(b->pTerrain, select_origin, select_matrix, bSnap);
00690         }
00691 
00692     }
00693 }
00694 
00695 void ProjectOnPlane(vec3_t& normal,float dist,vec3_t& ez, vec3_t& p)
00696 {
00697     if (fabs(ez[0]) == 1)
00698         p[0] = (dist - normal[1] * p[1] - normal[2] * p[2]) / normal[0];
00699     else if (fabs(ez[1]) == 1)
00700         p[1] = (dist - normal[0] * p[0] - normal[2] * p[2]) / normal[1];
00701     else
00702         p[2] = (dist - normal[0] * p[0] - normal[1] * p[1]) / normal[2];
00703 }
00704 
00705 void Back(vec3_t& dir, vec3_t& p)
00706 {
00707     if (fabs(dir[0]) == 1)
00708         p[0] = 0;
00709     else if (fabs(dir[1]) == 1)
00710         p[1] = 0;
00711     else p[2] = 0;
00712 }
00713 
00714 
00715 
00716 // using scale[0] and scale[1]
00717 void ComputeScale(vec3_t& rex, vec3_t& rey, vec3_t& p, face_t* f)
00718 {
00719     float px = DotProduct(rex, p);
00720     float py = DotProduct(rey, p);
00721     px *= f->texdef.scale[0];
00722     py *= f->texdef.scale[1];
00723   vec3_t aux;
00724   VectorCopy(rex, aux);
00725   VectorScale(aux, px, aux);
00726   VectorCopy(aux, p);
00727   VectorCopy(rey, aux);
00728   VectorScale(aux, py, aux);
00729   VectorAdd(p, aux, p);
00730 }
00731 
00732 void ComputeAbsolute(face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3)
00733 {
00734     vec3_t ex,ey,ez;            // local axis base
00735 
00736 #ifdef _DEBUG
00737     if (g_qeglobals.m_bBrushPrimitMode)
00738         Sys_Printf("Warning : illegal call of ComputeAbsolute in brush primitive mode\n");
00739 #endif
00740 
00741   // compute first local axis base
00742   TextureAxisFromPlane(&f->plane, ex, ey);
00743   CrossProduct(ex, ey, ez);
00744         
00745     vec3_t aux;
00746   VectorCopy(ex, aux);
00747   VectorScale(aux, -f->texdef.shift[0], aux);
00748   VectorCopy(aux, p1);
00749   VectorCopy(ey, aux);
00750   VectorScale(aux, -f->texdef.shift[1], aux);
00751   VectorAdd(p1, aux, p1);
00752   VectorCopy(p1, p2);
00753   VectorAdd(p2, ex, p2);
00754   VectorCopy(p1, p3);
00755   VectorAdd(p3, ey, p3);
00756   VectorCopy(ez, aux);
00757   VectorScale(aux, -f->texdef.rotate, aux);
00758   VectorRotate(p1, aux, p1);
00759   VectorRotate(p2, aux, p2);
00760   VectorRotate(p3, aux, p3);
00761     // computing rotated local axis base
00762     vec3_t rex,rey;
00763   VectorCopy(ex, rex);
00764   VectorRotate(rex, aux, rex);
00765   VectorCopy(ey, rey);
00766   VectorRotate(rey, aux, rey);
00767 
00768   ComputeScale(rex,rey,p1,f);
00769     ComputeScale(rex,rey,p2,f);
00770     ComputeScale(rex,rey,p3,f);
00771 
00772     // project on normal plane
00773     // along ez 
00774     // assumes plane normal is normalized
00775     ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p1);
00776     ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p2);
00777     ProjectOnPlane(f->plane.normal,f->plane.dist,ez,p3);
00778 };
00779 
00780 
00781 void AbsoluteToLocal(plane_t normal2, face_t* f, vec3_t& p1, vec3_t& p2, vec3_t& p3)
00782 {
00783     vec3_t ex,ey,ez;
00784 
00785 #ifdef _DEBUG
00786     if (g_qeglobals.m_bBrushPrimitMode)
00787         Sys_Printf("Warning : illegal call of AbsoluteToLocal in brush primitive mode\n");
00788 #endif
00789 
00790     // computing new local axis base
00791   TextureAxisFromPlane(&normal2, ex, ey);
00792   CrossProduct(ex, ey, ez);
00793 
00794   // projecting back on (ex,ey)
00795     Back(ez,p1);
00796     Back(ez,p2);
00797     Back(ez,p3);
00798 
00799     vec3_t aux;
00800     // rotation
00801   VectorCopy(p2, aux);
00802   VectorSubtract(aux, p1,aux);
00803     
00804     float x = DotProduct(aux,ex);
00805     float y = DotProduct(aux,ey);
00806   f->texdef.rotate = 180 * atan2(y,x) / Q_PI;
00807 
00808     vec3_t rex,rey;
00809     // computing rotated local axis base
00810   VectorCopy(ez, aux);
00811   VectorScale(aux, f->texdef.rotate, aux);
00812   VectorCopy(ex, rex);
00813   VectorRotate(rex, aux, rex);
00814   VectorCopy(ey, rey);
00815   VectorRotate(rey, aux, rey);
00816 
00817     // scale
00818   VectorCopy(p2, aux);
00819   VectorSubtract(aux, p1, aux);
00820   f->texdef.scale[0] = DotProduct(aux, rex);
00821   VectorCopy(p3, aux);
00822   VectorSubtract(aux, p1, aux);
00823   f->texdef.scale[1] = DotProduct(aux, rey);
00824 
00825     // shift
00826     // only using p1
00827     x = DotProduct(rex,p1);
00828     y = DotProduct(rey,p1);                 
00829     x /= f->texdef.scale[0];
00830     y /= f->texdef.scale[1];
00831 
00832   VectorCopy(rex, p1);
00833   VectorScale(p1, x, p1);
00834   VectorCopy(rey, aux);
00835   VectorScale(aux, y, aux);
00836   VectorAdd(p1, aux, p1);
00837   VectorCopy(ez, aux);
00838   VectorScale(aux, -f->texdef.rotate, aux);
00839   VectorRotate(p1, aux, p1);
00840     f->texdef.shift[0] = -DotProduct(p1, ex);
00841     f->texdef.shift[1] = -DotProduct(p1, ey);
00842 
00843     // stored rot is good considering local axis base
00844     // change it if necessary
00845     f->texdef.rotate = -f->texdef.rotate;
00846 
00847   Clamp(f->texdef.shift[0], f->d_texture->width);
00848   Clamp(f->texdef.shift[1], f->d_texture->height);
00849   Clamp(f->texdef.rotate, 360);
00850 
00851 }
00852 
00853 void RotateFaceTexture(face_t* f, int nAxis, float fDeg)
00854 {
00855     vec3_t p1,p2,p3, rota;   
00856     p1[0] = p1[1] = p1[2] = 0;
00857     VectorCopy(p1, p2);
00858     VectorCopy(p1, p3);
00859     VectorCopy(p1, rota);
00860     ComputeAbsolute(f, p1, p2, p3);
00861   
00862     rota[nAxis] = fDeg;
00863     VectorRotate(p1, rota, select_origin, p1);
00864     VectorRotate(p2, rota, select_origin, p2);
00865     VectorRotate(p3, rota, select_origin, p3);
00866 
00867     plane_t normal2;
00868     vec3_t vNormal;
00869     vNormal[0] = f->plane.normal[0];
00870     vNormal[1] = f->plane.normal[1];
00871     vNormal[2] = f->plane.normal[2];
00872     VectorRotate(vNormal, rota, vNormal);
00873     normal2.normal[0] = vNormal[0];
00874     normal2.normal[1] = vNormal[1];
00875     normal2.normal[2] = vNormal[2];
00876     AbsoluteToLocal(normal2, f, p1, p2 ,p3);
00877 
00878 }
00879 
00880 void RotateTextures(int nAxis, float fDeg, vec3_t vOrigin)
00881 {
00882     for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00883     {
00884         for (face_t* f=b->brush_faces ; f ; f=f->next)
00885         {
00886             if (g_qeglobals.m_bBrushPrimitMode)
00887                 RotateFaceTexture_BrushPrimit( f, nAxis, fDeg, vOrigin );
00888             else
00889                 RotateFaceTexture(f, nAxis, fDeg);
00890             //++timo removed that call .. works fine .. ???????
00891 //          Brush_Build(b, false);
00892         }
00893         Brush_Build(b, false);
00894     }
00895 }
00896 
00897 
00898 void Select_FlipAxis (int axis)
00899 {
00900     int     i;
00901 
00902     Select_GetMid (select_origin);
00903     for (i=0 ; i<3 ; i++)
00904     {
00905         VectorCopy (vec3_origin, select_matrix[i]);
00906         select_matrix[i][i] = 1;
00907     }
00908     select_matrix[axis][axis] = -1;
00909 
00910     select_fliporder = true;
00911     Select_ApplyMatrix (true, false, 0, 0);
00912     Sys_UpdateWindows (W_ALL);
00913 }
00914 
00915 
00916 void Select_Scale(float x, float y, float z)
00917 {
00918     Select_GetMid (select_origin);
00919     for (brush_t* b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
00920     {
00921         for (face_t* f=b->brush_faces ; f ; f=f->next)
00922         {
00923             for (int i=0 ; i<3 ; i++)
00924             {
00925                 f->planepts[i][0] -= select_origin[0];
00926                 f->planepts[i][1] -= select_origin[1];
00927                 f->planepts[i][2] -= select_origin[2];
00928                 f->planepts[i][0] *= x;
00929                 //f->planepts[i][0] = floor(f->planepts[i][0] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
00930 
00931                 f->planepts[i][1] *= y;
00932                 //f->planepts[i][1] = floor(f->planepts[i][1] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
00933 
00934                 f->planepts[i][2] *= z;
00935                 //f->planepts[i][2] = floor(f->planepts[i][2] / g_qeglobals.d_gridsize + 0.5) * g_qeglobals.d_gridsize;
00936         
00937                 f->planepts[i][0] += select_origin[0];
00938                 f->planepts[i][1] += select_origin[1];
00939                 f->planepts[i][2] += select_origin[2];
00940             }
00941         }
00942         Brush_Build(b, false);
00943         if (b->patchBrush)
00944         {
00945             vec3_t v;
00946             v[0] = x;
00947             v[1] = y;
00948             v[2] = z;
00949             //Patch_Scale(b->nPatchID, select_origin, v);
00950             Patch_Scale(b->pPatch, select_origin, v);
00951         }
00952         if (b->terrainBrush)
00953         {
00954             vec3_t v;
00955             v[0] = x;
00956             v[1] = y;
00957             v[2] = z;
00958             Terrain_Scale(b->pTerrain, select_origin, v);
00959         }
00960     }
00961 }
00962 
00963 void Select_RotateAxis (int axis, float deg, bool bPaint, bool bMouse)
00964 {
00965     vec3_t  temp;
00966     int     i, j;
00967     vec_t   c, s;
00968 
00969     if (deg == 0)
00970   {
00971     //Sys_Printf("0 deg\n");
00972         return;
00973   }
00974 
00975   if (bMouse)
00976   {
00977     VectorCopy(g_pParentWnd->ActiveXY()->RotateOrigin(), select_origin);
00978   }
00979   else
00980   {
00981       Select_GetMid (select_origin);
00982   }
00983 
00984     select_fliporder = false;
00985 
00986     if (deg == 90)
00987     {
00988         for (i=0 ; i<3 ; i++)
00989         {
00990             VectorCopy (vec3_origin, select_matrix[i]);
00991             select_matrix[i][i] = 1;
00992         }
00993         i = (axis+1)%3;
00994         j = (axis+2)%3;
00995         VectorCopy (select_matrix[i], temp);
00996         VectorCopy (select_matrix[j], select_matrix[i]);
00997         VectorSubtract (vec3_origin, temp, select_matrix[j]);
00998     }
00999     else
01000     {
01001         deg = -deg;
01002         if (deg == -180.0)
01003         {
01004             c = -1;
01005             s = 0;
01006         }
01007         else if (deg == -270.0)
01008         {
01009             c = 0;
01010             s = -1;
01011         }
01012         else
01013         {
01014             c = cos(deg * Q_PI / 180.0);
01015             s = sin(deg * Q_PI / 180.0);
01016         }
01017 
01018         for (i=0 ; i<3 ; i++)
01019         {
01020             VectorCopy (vec3_origin, select_matrix[i]);
01021             select_matrix[i][i] = 1;
01022         }
01023 
01024         switch (axis)
01025         {
01026         case 0:
01027             select_matrix[1][1] = c;
01028             select_matrix[1][2] = -s;
01029             select_matrix[2][1] = s;
01030             select_matrix[2][2] = c;
01031             break;
01032         case 1:
01033             select_matrix[0][0] = c;
01034             select_matrix[0][2] = s;
01035             select_matrix[2][0] = -s;
01036             select_matrix[2][2] = c;
01037             break;
01038         case 2:
01039             select_matrix[0][0] = c;
01040             select_matrix[0][1] = -s;
01041             select_matrix[1][0] = s;
01042             select_matrix[1][1] = c;
01043             break;
01044         }
01045     }
01046 
01047     if (g_PrefsDlg.m_bRotateLock)
01048         RotateTextures(axis, deg, select_origin);
01049     Select_ApplyMatrix(!bMouse, true, axis, deg);
01050 
01051     if (bPaint)
01052         Sys_UpdateWindows (W_ALL);
01053 }
01054 
01055 /*
01056 ================================================================
01057 
01058 GROUP SELECTIONS
01059 
01060 ================================================================
01061 */
01062 
01063 void Select_CompleteTall (void)
01064 {
01065     brush_t *b, *next;
01066     //int       i;
01067     vec3_t  mins, maxs;
01068 
01069     if (!QE_SingleBrush ())
01070         return;
01071 
01072     clearSelection();
01073 
01074     VectorCopy (selected_brushes.next->mins, mins);
01075     VectorCopy (selected_brushes.next->maxs, maxs);
01076     Select_Delete ();
01077 
01078   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
01079   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
01080 
01081     for (b=active_brushes.next ; b != &active_brushes ; b=next)
01082     {
01083         next = b->next;
01084 
01085     if ( (b->maxs[nDim1] > maxs[nDim1] || b->mins[nDim1] < mins[nDim1]) 
01086       || (b->maxs[nDim2] > maxs[nDim2] || b->mins[nDim2] < mins[nDim2]) )
01087       continue;
01088 
01089         if (FilterBrush (b))
01090             continue;
01091 
01092         Brush_RemoveFromList (b);
01093         Brush_AddToList (b, &selected_brushes);
01094 #if 0
01095     // old stuff
01096     for (i=0 ; i<2 ; i++)
01097             if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
01098                 break;
01099         if (i == 2)
01100         {
01101             Brush_RemoveFromList (b);
01102             Brush_AddToList (b, &selected_brushes);
01103         }
01104 #endif
01105     }
01106     Sys_UpdateWindows (W_ALL);
01107 }
01108 
01109 void Select_PartialTall (void)
01110 {
01111     brush_t *b, *next;
01112     //int       i;
01113     vec3_t  mins, maxs;
01114 
01115     if (!QE_SingleBrush ())
01116         return;
01117 
01118     clearSelection();
01119 
01120     VectorCopy (selected_brushes.next->mins, mins);
01121     VectorCopy (selected_brushes.next->maxs, maxs);
01122     Select_Delete ();
01123 
01124   int nDim1 = (g_pParentWnd->ActiveXY()->GetViewType() == YZ) ? 1 : 0;
01125   int nDim2 = (g_pParentWnd->ActiveXY()->GetViewType() == XY) ? 1 : 2;
01126 
01127     for (b=active_brushes.next ; b != &active_brushes ; b=next)
01128     {
01129         next = b->next;
01130 
01131     if ( (b->mins[nDim1] > maxs[nDim1] || b->maxs[nDim1] < mins[nDim1]) 
01132       || (b->mins[nDim2] > maxs[nDim2] || b->maxs[nDim2] < mins[nDim2]) )
01133       continue;
01134 
01135         if (FilterBrush (b))
01136             continue;
01137 
01138     Brush_RemoveFromList (b);
01139         Brush_AddToList (b, &selected_brushes);
01140 
01141 
01142 #if 0
01143 // old stuff
01144         for (i=0 ; i<2 ; i++)
01145             if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i])
01146                 break;
01147         if (i == 2)
01148         {
01149             Brush_RemoveFromList (b);
01150             Brush_AddToList (b, &selected_brushes);
01151         }
01152 #endif
01153     }
01154     Sys_UpdateWindows (W_ALL);
01155 }
01156 
01157 void Select_Touching (void)
01158 {
01159     brush_t *b, *next;
01160     int     i;
01161     vec3_t  mins, maxs;
01162 
01163     if (!QE_SingleBrush ())
01164         return;
01165 
01166     clearSelection();
01167 
01168     VectorCopy (selected_brushes.next->mins, mins);
01169     VectorCopy (selected_brushes.next->maxs, maxs);
01170 
01171     for (b=active_brushes.next ; b != &active_brushes ; b=next)
01172     {
01173         next = b->next;
01174 
01175         if (FilterBrush (b))
01176             continue;
01177 
01178         for (i=0 ; i<3 ; i++)
01179             if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1)
01180                 break;
01181 
01182         if (i == 3)
01183         {
01184             Brush_RemoveFromList (b);
01185             Brush_AddToList (b, &selected_brushes);
01186         }
01187     }
01188     Sys_UpdateWindows (W_ALL);
01189 }
01190 
01191 void Select_Inside (void)
01192 {
01193     brush_t *b, *next;
01194     int     i;
01195     vec3_t  mins, maxs;
01196 
01197     if (!QE_SingleBrush ())
01198         return;
01199 
01200     clearSelection();
01201 
01202     VectorCopy (selected_brushes.next->mins, mins);
01203     VectorCopy (selected_brushes.next->maxs, maxs);
01204     Select_Delete ();
01205 
01206     for (b=active_brushes.next ; b != &active_brushes ; b=next)
01207     {
01208         next = b->next;
01209 
01210         if (FilterBrush (b))
01211             continue;
01212 
01213         for (i=0 ; i<3 ; i++)
01214             if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
01215                 break;
01216         if (i == 3)
01217         {
01218             Brush_RemoveFromList (b);
01219             Brush_AddToList (b, &selected_brushes);
01220         }
01221     }
01222     Sys_UpdateWindows (W_ALL);
01223 }
01224 
01225 /*
01226 =============
01227 Select_Ungroup
01228 
01229 Turn the currently selected entity back into normal brushes
01230 =============
01231 */
01232 void Select_Ungroup(void)
01233 {
01234     int numselectedgroups;
01235     entity_t    *e;
01236     brush_t     *b, *sb;
01237 
01238     numselectedgroups = 0;
01239     for (sb = selected_brushes.next; sb != &selected_brushes; sb = sb->next)
01240     {
01241         e = sb->owner;
01242 
01243         if (!e || e == world_entity || e->eclass->fixedsize)
01244         {
01245             continue;
01246         }
01247 
01248         for (b = e->brushes.onext; b != &e->brushes; b = e->brushes.onext)
01249         {
01250             //Brush_RemoveFromList (b);
01251             //Brush_AddToList (b, &active_brushes);
01252             Entity_UnlinkBrush (b);
01253             Entity_LinkBrush (world_entity, b);
01254             Brush_Build( b );
01255             b->owner = world_entity;
01256         }
01257         Entity_Free (e);
01258         numselectedgroups++;
01259     }
01260 
01261     if (numselectedgroups <= 0)
01262     {
01263         Sys_Printf("No grouped entities selected.\n");
01264         return;
01265     }
01266     Sys_Printf("Ungrouped %d entit%s.\n", numselectedgroups, (numselectedgroups == 1)?"y":"ies");
01267     Sys_UpdateWindows (W_ALL);
01268 }
01269 
01270 
01271 /*
01272 ====================
01273 Select_MakeStructural
01274 ====================
01275 */
01276 void Select_MakeStructural (void)
01277 {
01278     brush_t *b;
01279     face_t  *f;
01280 
01281     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
01282         for (f=b->brush_faces ; f ; f=f->next)
01283             f->texdef.contents &= ~CONTENTS_DETAIL;
01284     Select_Deselect ();
01285     Sys_UpdateWindows (W_ALL);
01286 }
01287 
01288 void Select_MakeDetail (void)
01289 {
01290     brush_t *b;
01291     face_t  *f;
01292 
01293     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
01294         for (f=b->brush_faces ; f ; f=f->next)
01295             f->texdef.contents |= CONTENTS_DETAIL;
01296     Select_Deselect ();
01297     Sys_UpdateWindows (W_ALL);
01298 }
01299 
01300 void Select_ShiftTexture(int x, int y)
01301 {
01302     brush_t     *b;
01303     face_t      *f;
01304 
01305   int nFaceCount = g_ptrSelectedFaces.GetSize();
01306 
01307     if(selected_brushes.next == &selected_brushes && nFaceCount == 0)
01308         return;
01309 
01310     for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
01311     {
01312         for (f=b->brush_faces ; f ; f=f->next)
01313         {
01314             if (g_qeglobals.m_bBrushPrimitMode)
01315             {
01316                 // use face normal to compute a true translation
01317                 Select_ShiftTexture_BrushPrimit( f, x, y );
01318             }
01319             else
01320             {
01321                 f->texdef.shift[0] += x;
01322                 f->texdef.shift[1] += y;
01323             }
01324         }
01325         Brush_Build(b);
01326         if (b->patchBrush)
01327         {
01328             //Patch_ShiftTexture(b->nPatchID, x, y);
01329             Patch_ShiftTexture(b->pPatch, x, y);
01330         }
01331     }
01332 
01333     if (nFaceCount > 0)
01334     {
01335     for (int i = 0; i < nFaceCount; i++)
01336     {
01337       face_t *selFace = reinterpret_cast<face_t*>(g_ptrSelectedFaces.GetAt(i));
01338       brush_t *selBrush = reinterpret_cast<brush_t*>(g_ptrSelectedFaceBrushes.GetAt(i));
01339         if (g_qeglobals.m_bBrushPrimitMode)
01340         {
01341 
01342               // use face normal to compute a true translation
01343         // Select_ShiftTexture_BrushPrimit( selected_face, x, y );
01344               // use camera view to compute texture shift
01345               g_pParentWnd->GetCamera()->ShiftTexture_BrushPrimit( selFace, x,