]> de.git.xonotic.org Git - xonotic/netradiant.git/blobdiff - tools/quake2/extra/qe4/select.c
Merge remote-tracking branch 'ttimo/master'
[xonotic/netradiant.git] / tools / quake2 / extra / qe4 / select.c
diff --git a/tools/quake2/extra/qe4/select.c b/tools/quake2/extra/qe4/select.c
new file mode 100644 (file)
index 0000000..2761ecb
--- /dev/null
@@ -0,0 +1,706 @@
+/*
+===========================================================================
+Copyright (C) 1997-2006 Id Software, Inc.
+
+This file is part of Quake 2 Tools source code.
+
+Quake 2 Tools source code is free software; you can redistribute it
+and/or modify it under the terms of the GNU General Public License as
+published by the Free Software Foundation; either version 2 of the License,
+or (at your option) any later version.
+
+Quake 2 Tools source code is distributed in the hope that it will be
+useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with Quake 2 Tools source code; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+===========================================================================
+*/
+
+// select.c
+
+#include "qe3.h"
+
+/*
+===========
+Test_Ray
+===========
+*/
+#define        DIST_START      999999
+trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags)
+{
+       brush_t *brush;
+       face_t  *face;
+       float   dist;
+       trace_t t;
+
+       memset (&t, 0, sizeof(t));
+       t.dist = DIST_START;
+
+       if (! (flags & SF_SELECTED_ONLY) )
+               for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
+               {
+                       if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
+                               continue;
+                       if (FilterBrush (brush))
+                               continue;
+                       face = Brush_Ray (origin, dir, brush, &dist);
+                       if (dist > 0 && dist < t.dist)
+                       {
+                               t.dist = dist;
+                               t.brush = brush;
+                               t.face = face;
+                               t.selected = false;
+                       }
+               }
+       for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
+       {
+               if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
+                       continue;
+               if (FilterBrush (brush))
+                       continue;
+               face = Brush_Ray (origin, dir, brush, &dist);
+               if (dist > 0 && dist < t.dist)
+               {
+                       t.dist = dist;
+                       t.brush = brush;
+                       t.face = face;
+                       t.selected = true;
+               }
+       }
+
+       // if entites first, but didn't find any, check regular
+
+       if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL)
+               return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST);
+
+       return t;
+}
+
+
+/*
+============
+Select_Brush
+
+============
+*/
+void Select_Brush (brush_t *brush)
+{
+       brush_t *b;
+       entity_t        *e;
+
+       selected_face = NULL;
+       if (g_qeglobals.d_select_count < 2)
+               g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
+       g_qeglobals.d_select_count++;
+
+       e = brush->owner;
+       if (e)
+       {
+               // select complete entity on first click
+               if (e != world_entity)
+               {
+                       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
+                               if (b->owner == e)
+                                       goto singleselect;
+                       for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
+                       {
+                               Brush_RemoveFromList (b);
+                               Brush_AddToList (b, &selected_brushes);
+                       }
+               }
+               else
+               {
+singleselect:
+                       Brush_RemoveFromList (brush);
+                       Brush_AddToList (brush, &selected_brushes);
+               }
+
+               if (e->eclass)
+               {
+                       UpdateEntitySel(brush->owner->eclass);
+               }
+       }
+}
+
+/*
+============
+Select_Ray
+
+If the origin is inside a brush, that brush will be ignored.
+============
+*/
+void Select_Ray (vec3_t origin, vec3_t dir, int flags)
+{
+       trace_t t;
+
+       t = Test_Ray (origin, dir, flags);
+       if (!t.brush)
+               return;
+
+       if (flags == SF_SINGLEFACE)
+       {
+               selected_face = t.face;
+               selected_face_brush = t.brush;
+               Sys_UpdateWindows (W_ALL);
+               g_qeglobals.d_select_mode = sel_brush;
+               return;
+       }
+
+       // move the brush to the other list
+
+       g_qeglobals.d_select_mode = sel_brush;
+
+       if (t.selected)
+       {
+               Brush_RemoveFromList (t.brush);
+               Brush_AddToList (t.brush, &active_brushes);
+       } else
+       {
+               Select_Brush (t.brush);
+       }
+
+       Sys_UpdateWindows (W_ALL);
+}
+
+
+void Select_Delete (void)
+{
+       brush_t *brush;
+
+       selected_face = NULL;
+       g_qeglobals.d_select_mode = sel_brush;
+
+       g_qeglobals.d_select_count = 0;
+       g_qeglobals.d_num_move_points = 0;
+       while (selected_brushes.next != &selected_brushes)
+       {
+               brush = selected_brushes.next;
+               Brush_Free (brush);
+       }
+
+       // FIXME: remove any entities with no brushes
+
+       Sys_UpdateWindows (W_ALL);
+}
+
+void Select_Deselect (void)
+{
+       brush_t *b;
+
+       g_qeglobals.d_workcount++;
+       g_qeglobals.d_select_count = 0;
+       g_qeglobals.d_num_move_points = 0;
+       b = selected_brushes.next;
+
+       if (b == &selected_brushes)
+       {
+               if (selected_face)
+               {
+                       selected_face = NULL;
+                       Sys_UpdateWindows (W_ALL);
+               }
+               return;
+       }
+
+       selected_face = NULL;
+       g_qeglobals.d_select_mode = sel_brush;
+
+       // grab top / bottom height for new brushes
+       if (b->mins[2] < b->maxs[2])
+       {
+               g_qeglobals.d_new_brush_bottom_z = b->mins[2];
+               g_qeglobals.d_new_brush_top_z = b->maxs[2];
+       }
+
+       selected_brushes.next->prev = &active_brushes;
+       selected_brushes.prev->next = active_brushes.next;
+       active_brushes.next->prev = selected_brushes.prev;
+       active_brushes.next = selected_brushes.next;
+       selected_brushes.prev = selected_brushes.next = &selected_brushes;
+
+       Sys_UpdateWindows (W_ALL);
+}
+
+/*
+============
+Select_Move
+============
+*/
+void Select_Move (vec3_t delta)
+{
+       brush_t *b;
+
+// actually move the selected brushes
+       for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
+               Brush_Move (b, delta);
+//     Sys_UpdateWindows (W_ALL);
+}
+
+/*
+============
+Select_Clone
+
+Creates an exact duplicate of the selection in place, then moves
+the selected brushes off of their old positions
+============
+*/
+void Select_Clone (void)
+{
+       brush_t         *b, *b2, *n, *next, *next2;
+       vec3_t          delta;
+       entity_t        *e;
+
+       g_qeglobals.d_workcount++;
+       g_qeglobals.d_select_mode = sel_brush;
+
+       delta[0] = g_qeglobals.d_gridsize;
+       delta[1] = g_qeglobals.d_gridsize;
+       delta[2] = 0;
+
+       for (b=selected_brushes.next ; b != &selected_brushes ; b=next)
+       {
+               next = b->next;
+               // if the brush is a world brush, handle simply
+               if (b->owner == world_entity)
+               {
+                       n = Brush_Clone (b);
+                       Brush_AddToList (n, &active_brushes);
+                       Entity_LinkBrush (world_entity, n);
+                       Brush_Build( n );
+                       Brush_Move (b, delta);
+                       continue;
+               }
+
+               e = Entity_Clone (b->owner);
+               // clear the target / targetname
+               DeleteKey (e, "target");
+               DeleteKey (e, "targetname");
+
+               // if the brush is a fixed size entity, create a new entity
+               if (b->owner->eclass->fixedsize)
+               {
+                       n = Brush_Clone (b);
+                       Brush_AddToList (n, &active_brushes);
+                       Entity_LinkBrush (e, n);
+                       Brush_Build( n );
+                       Brush_Move (b, delta);
+                       continue;
+               }
+
+               // brush is a complex entity, grab all the other ones now
+
+               next = &selected_brushes;
+
+               for ( b2 = b ; b2 != &selected_brushes ; b2=next2)
+               {
+                       next2 = b2->next;
+                       if (b2->owner != b->owner)
+                       {
+                               if (next == &selected_brushes)
+                                       next = b2;
+                               continue;
+                       }
+
+                       // move b2 to the start of selected_brushes,
+                       // so it won't be hit again
+                       Brush_RemoveFromList (b2);
+                       Brush_AddToList (b2, &selected_brushes);
+
+                       n = Brush_Clone (b2);
+                       Brush_AddToList (n, &active_brushes);
+                       Entity_LinkBrush (e, n);
+                       Brush_Build( n );
+                       Brush_Move (b2, delta);
+               }
+
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+
+
+/*
+============
+Select_SetTexture
+============
+*/
+void Select_SetTexture (texdef_t *texdef)
+{
+       brush_t *b;
+
+       if (selected_face)
+       {
+               selected_face->texdef = *texdef;
+               Brush_Build(selected_face_brush);
+       }
+       else
+       {
+               for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
+                       if (!b->owner->eclass->fixedsize)
+                               Brush_SetTexture (b, texdef);
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+
+/*
+================================================================
+
+  TRANSFORMATIONS
+
+================================================================
+*/
+
+void Select_GetBounds (vec3_t mins, vec3_t maxs)
+{
+       brush_t *b;
+       int             i;
+
+       for (i=0 ; i<3 ; i++)
+       {
+               mins[i] = 99999;
+               maxs[i] = -99999;
+       }
+
+       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
+               for (i=0 ; i<3 ; i++)
+               {
+                       if (b->mins[i] < mins[i])
+                               mins[i] = b->mins[i];
+                       if (b->maxs[i] > maxs[i])
+                               maxs[i] = b->maxs[i];
+               }
+}
+
+void Select_GetMid (vec3_t mid)
+{
+       vec3_t  mins, maxs;
+       int             i;
+
+       Select_GetBounds (mins, maxs);
+       for (i=0 ; i<3 ; i++)
+               mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize );
+}
+
+vec3_t select_origin;
+vec3_t select_matrix[3];
+qboolean       select_fliporder;
+
+void Select_AplyMatrix (void)
+{
+       brush_t *b;
+       face_t  *f;
+       int             i, j;
+       vec3_t  temp;
+
+       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
+       {
+               for (f=b->brush_faces ; f ; f=f->next)
+               {
+                       for (i=0 ; i<3 ; i++)
+                       {
+                               VectorSubtract (f->planepts[i], select_origin, temp);
+                               for (j=0 ; j<3 ; j++)
+                                       f->planepts[i][j] = DotProduct(temp, select_matrix[j])
+                                               + select_origin[j];
+                       }
+                       if (select_fliporder)
+                       {
+                               VectorCopy (f->planepts[0], temp);
+                               VectorCopy (f->planepts[2], f->planepts[0]);
+                               VectorCopy (temp, f->planepts[2]);
+                       }
+               }
+               Brush_Build( b );
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+
+void Select_FlipAxis (int axis)
+{
+       int             i;
+
+       Select_GetMid (select_origin);
+       for (i=0 ; i<3 ; i++)
+       {
+               VectorCopy (vec3_origin, select_matrix[i]);
+               select_matrix[i][i] = 1;
+       }
+       select_matrix[axis][axis] = -1;
+
+       select_fliporder = true;
+       Select_AplyMatrix ();
+}
+
+void Select_RotateAxis (int axis, float deg)
+{
+       vec3_t  temp;
+       int             i, j;
+       vec_t   c, s;
+
+       if (deg == 0)
+               return;
+
+       Select_GetMid (select_origin);
+       select_fliporder = false;
+
+       if (deg == 90)
+       {
+               for (i=0 ; i<3 ; i++)
+               {
+                       VectorCopy (vec3_origin, select_matrix[i]);
+                       select_matrix[i][i] = 1;
+               }
+               i = (axis+1)%3;
+               j = (axis+2)%3;
+               VectorCopy (select_matrix[i], temp);
+               VectorCopy (select_matrix[j], select_matrix[i]);
+               VectorSubtract (vec3_origin, temp, select_matrix[j]);
+       }
+       else
+       {
+               deg = -deg;
+               if (deg == -180)
+               {
+                       c = -1;
+                       s = 0;
+               }
+               else if (deg == -270)
+               {
+                       c = 0;
+                       s = -1;
+               }
+               else
+               {
+                       c = cos(deg/180*3.14159);
+                       s = sin (deg/180*3.14159);
+               }
+
+               for (i=0 ; i<3 ; i++)
+               {
+                       VectorCopy (vec3_origin, select_matrix[i]);
+                       select_matrix[i][i] = 1;
+               }
+
+               switch (axis)
+               {
+               case 0:
+                       select_matrix[1][1] = c;
+                       select_matrix[1][2] = -s;
+                       select_matrix[2][1] = s;
+                       select_matrix[2][2] = c;
+                       break;
+               case 1:
+                       select_matrix[0][0] = c;
+                       select_matrix[0][2] = s;
+                       select_matrix[2][0] = -s;
+                       select_matrix[2][2] = c;
+                       break;
+               case 2:
+                       select_matrix[0][0] = c;
+                       select_matrix[0][1] = -s;
+                       select_matrix[1][0] = s;
+                       select_matrix[1][1] = c;
+                       break;
+               }
+       }
+
+       Select_AplyMatrix ();
+}
+
+/*
+================================================================
+
+GROUP SELECTIONS
+
+================================================================
+*/
+
+void Select_CompleteTall (void)
+{
+       brush_t *b, *next;
+       int             i;
+       vec3_t  mins, maxs;
+
+       if (!QE_SingleBrush ())
+               return;
+
+       g_qeglobals.d_select_mode = sel_brush;
+
+       VectorCopy (selected_brushes.next->mins, mins);
+       VectorCopy (selected_brushes.next->maxs, maxs);
+       Select_Delete ();
+
+       for (b=active_brushes.next ; b != &active_brushes ; b=next)
+       {
+               next = b->next;
+               for (i=0 ; i<2 ; i++)
+                       if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
+                               break;
+               if (i == 2)
+               {
+                       Brush_RemoveFromList (b);
+                       Brush_AddToList (b, &selected_brushes);
+               }
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+void Select_PartialTall (void)
+{
+       brush_t *b, *next;
+       int             i;
+       vec3_t  mins, maxs;
+
+       if (!QE_SingleBrush ())
+               return;
+
+       g_qeglobals.d_select_mode = sel_brush;
+
+       VectorCopy (selected_brushes.next->mins, mins);
+       VectorCopy (selected_brushes.next->maxs, maxs);
+       Select_Delete ();
+
+       for (b=active_brushes.next ; b != &active_brushes ; b=next)
+       {
+               next = b->next;
+               for (i=0 ; i<2 ; i++)
+                       if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i])
+                               break;
+               if (i == 2)
+               {
+                       Brush_RemoveFromList (b);
+                       Brush_AddToList (b, &selected_brushes);
+               }
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+void Select_Touching (void)
+{
+       brush_t *b, *next;
+       int             i;
+       vec3_t  mins, maxs;
+
+       if (!QE_SingleBrush ())
+               return;
+
+       g_qeglobals.d_select_mode = sel_brush;
+
+       VectorCopy (selected_brushes.next->mins, mins);
+       VectorCopy (selected_brushes.next->maxs, maxs);
+
+       for (b=active_brushes.next ; b != &active_brushes ; b=next)
+       {
+               next = b->next;
+               for (i=0 ; i<3 ; i++)
+                       if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1)
+                               break;
+               if (i == 3)
+               {
+                       Brush_RemoveFromList (b);
+                       Brush_AddToList (b, &selected_brushes);
+               }
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+void Select_Inside (void)
+{
+       brush_t *b, *next;
+       int             i;
+       vec3_t  mins, maxs;
+
+       if (!QE_SingleBrush ())
+               return;
+
+       g_qeglobals.d_select_mode = sel_brush;
+
+       VectorCopy (selected_brushes.next->mins, mins);
+       VectorCopy (selected_brushes.next->maxs, maxs);
+       Select_Delete ();
+
+       for (b=active_brushes.next ; b != &active_brushes ; b=next)
+       {
+               next = b->next;
+               for (i=0 ; i<3 ; i++)
+                       if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
+                               break;
+               if (i == 3)
+               {
+                       Brush_RemoveFromList (b);
+                       Brush_AddToList (b, &selected_brushes);
+               }
+       }
+       Sys_UpdateWindows (W_ALL);
+}
+
+/*
+=============
+Select_Ungroup
+
+Turn the currently selected entity back into normal brushes
+=============
+*/
+void  Select_Ungroup (void)
+{
+       entity_t        *e;
+       brush_t         *b;
+
+       e = selected_brushes.next->owner;
+
+       if (!e || e == world_entity || e->eclass->fixedsize)
+       {
+               Sys_Status ("Not a grouped entity.", 0);
+               return;
+       }
+
+       for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext)
+       {
+               Brush_RemoveFromList (b);
+               Brush_AddToList (b, &active_brushes);
+               Entity_UnlinkBrush (b);
+               Entity_LinkBrush (world_entity, b);
+               Brush_Build( b );
+               b->owner = world_entity;
+       }
+
+       Entity_Free (e);
+       Sys_UpdateWindows (W_ALL);
+}
+
+/*
+====================
+Select_MakeStructural
+====================
+*/
+void Select_MakeStructural (void)
+{
+       brush_t *b;
+       face_t  *f;
+
+       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
+               for (f=b->brush_faces ; f ; f=f->next)
+                       f->texdef.contents &= ~CONTENTS_DETAIL;
+       Select_Deselect ();
+       Sys_UpdateWindows (W_ALL);
+}
+
+void Select_MakeDetail (void)
+{
+       brush_t *b;
+       face_t  *f;
+
+       for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
+               for (f=b->brush_faces ; f ; f=f->next)
+                       f->texdef.contents |= CONTENTS_DETAIL;
+       Select_Deselect ();
+       Sys_UpdateWindows (W_ALL);
+}
+
+