2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
5 This file is part of Quake 2 Tools source code.
7 Quake 2 Tools source code is free software; you can redistribute it
8 and/or modify it under the terms of the GNU General Public License as
9 published by the Free Software Foundation; either version 2 of the License,
10 or (at your option) any later version.
12 Quake 2 Tools source code is distributed in the hope that it will be
13 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with Quake 2 Tools source code; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 ===========================================================================
32 #define DIST_START 999999
33 trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags)
40 memset (&t, 0, sizeof(t));
43 if (! (flags & SF_SELECTED_ONLY) )
44 for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
46 if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
48 if (FilterBrush (brush))
50 face = Brush_Ray (origin, dir, brush, &dist);
51 if (dist > 0 && dist < t.dist)
59 for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
61 if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
63 if (FilterBrush (brush))
65 face = Brush_Ray (origin, dir, brush, &dist);
66 if (dist > 0 && dist < t.dist)
75 // if entites first, but didn't find any, check regular
77 if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL)
78 return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST);
90 void Select_Brush (brush_t *brush)
96 if (g_qeglobals.d_select_count < 2)
97 g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush;
98 g_qeglobals.d_select_count++;
103 // select complete entity on first click
104 if (e != world_entity)
106 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
109 for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
111 Brush_RemoveFromList (b);
112 Brush_AddToList (b, &selected_brushes);
118 Brush_RemoveFromList (brush);
119 Brush_AddToList (brush, &selected_brushes);
124 UpdateEntitySel(brush->owner->eclass);
133 If the origin is inside a brush, that brush will be ignored.
136 void Select_Ray (vec3_t origin, vec3_t dir, int flags)
140 t = Test_Ray (origin, dir, flags);
144 if (flags == SF_SINGLEFACE)
146 selected_face = t.face;
147 selected_face_brush = t.brush;
148 Sys_UpdateWindows (W_ALL);
149 g_qeglobals.d_select_mode = sel_brush;
153 // move the brush to the other list
155 g_qeglobals.d_select_mode = sel_brush;
159 Brush_RemoveFromList (t.brush);
160 Brush_AddToList (t.brush, &active_brushes);
163 Select_Brush (t.brush);
166 Sys_UpdateWindows (W_ALL);
170 void Select_Delete (void)
174 selected_face = NULL;
175 g_qeglobals.d_select_mode = sel_brush;
177 g_qeglobals.d_select_count = 0;
178 g_qeglobals.d_num_move_points = 0;
179 while (selected_brushes.next != &selected_brushes)
181 brush = selected_brushes.next;
185 // FIXME: remove any entities with no brushes
187 Sys_UpdateWindows (W_ALL);
190 void Select_Deselect (void)
194 g_qeglobals.d_workcount++;
195 g_qeglobals.d_select_count = 0;
196 g_qeglobals.d_num_move_points = 0;
197 b = selected_brushes.next;
199 if (b == &selected_brushes)
203 selected_face = NULL;
204 Sys_UpdateWindows (W_ALL);
209 selected_face = NULL;
210 g_qeglobals.d_select_mode = sel_brush;
212 // grab top / bottom height for new brushes
213 if (b->mins[2] < b->maxs[2])
215 g_qeglobals.d_new_brush_bottom_z = b->mins[2];
216 g_qeglobals.d_new_brush_top_z = b->maxs[2];
219 selected_brushes.next->prev = &active_brushes;
220 selected_brushes.prev->next = active_brushes.next;
221 active_brushes.next->prev = selected_brushes.prev;
222 active_brushes.next = selected_brushes.next;
223 selected_brushes.prev = selected_brushes.next = &selected_brushes;
225 Sys_UpdateWindows (W_ALL);
233 void Select_Move (vec3_t delta)
237 // actually move the selected brushes
238 for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next)
239 Brush_Move (b, delta);
240 // Sys_UpdateWindows (W_ALL);
247 Creates an exact duplicate of the selection in place, then moves
248 the selected brushes off of their old positions
251 void Select_Clone (void)
253 brush_t *b, *b2, *n, *next, *next2;
257 g_qeglobals.d_workcount++;
258 g_qeglobals.d_select_mode = sel_brush;
260 delta[0] = g_qeglobals.d_gridsize;
261 delta[1] = g_qeglobals.d_gridsize;
264 for (b=selected_brushes.next ; b != &selected_brushes ; b=next)
267 // if the brush is a world brush, handle simply
268 if (b->owner == world_entity)
271 Brush_AddToList (n, &active_brushes);
272 Entity_LinkBrush (world_entity, n);
274 Brush_Move (b, delta);
278 e = Entity_Clone (b->owner);
279 // clear the target / targetname
280 DeleteKey (e, "target");
281 DeleteKey (e, "targetname");
283 // if the brush is a fixed size entity, create a new entity
284 if (b->owner->eclass->fixedsize)
287 Brush_AddToList (n, &active_brushes);
288 Entity_LinkBrush (e, n);
290 Brush_Move (b, delta);
294 // brush is a complex entity, grab all the other ones now
296 next = &selected_brushes;
298 for ( b2 = b ; b2 != &selected_brushes ; b2=next2)
301 if (b2->owner != b->owner)
303 if (next == &selected_brushes)
308 // move b2 to the start of selected_brushes,
309 // so it won't be hit again
310 Brush_RemoveFromList (b2);
311 Brush_AddToList (b2, &selected_brushes);
313 n = Brush_Clone (b2);
314 Brush_AddToList (n, &active_brushes);
315 Entity_LinkBrush (e, n);
317 Brush_Move (b2, delta);
321 Sys_UpdateWindows (W_ALL);
331 void Select_SetTexture (texdef_t *texdef)
337 selected_face->texdef = *texdef;
338 Brush_Build(selected_face_brush);
342 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
343 if (!b->owner->eclass->fixedsize)
344 Brush_SetTexture (b, texdef);
346 Sys_UpdateWindows (W_ALL);
351 ================================================================
355 ================================================================
358 void Select_GetBounds (vec3_t mins, vec3_t maxs)
363 for (i=0 ; i<3 ; i++)
369 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
370 for (i=0 ; i<3 ; i++)
372 if (b->mins[i] < mins[i])
373 mins[i] = b->mins[i];
374 if (b->maxs[i] > maxs[i])
375 maxs[i] = b->maxs[i];
379 void Select_GetMid (vec3_t mid)
384 Select_GetBounds (mins, maxs);
385 for (i=0 ; i<3 ; i++)
386 mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize );
389 vec3_t select_origin;
390 vec3_t select_matrix[3];
391 qboolean select_fliporder;
393 void Select_AplyMatrix (void)
400 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
402 for (f=b->brush_faces ; f ; f=f->next)
404 for (i=0 ; i<3 ; i++)
406 VectorSubtract (f->planepts[i], select_origin, temp);
407 for (j=0 ; j<3 ; j++)
408 f->planepts[i][j] = DotProduct(temp, select_matrix[j])
411 if (select_fliporder)
413 VectorCopy (f->planepts[0], temp);
414 VectorCopy (f->planepts[2], f->planepts[0]);
415 VectorCopy (temp, f->planepts[2]);
420 Sys_UpdateWindows (W_ALL);
424 void Select_FlipAxis (int axis)
428 Select_GetMid (select_origin);
429 for (i=0 ; i<3 ; i++)
431 VectorCopy (vec3_origin, select_matrix[i]);
432 select_matrix[i][i] = 1;
434 select_matrix[axis][axis] = -1;
436 select_fliporder = true;
437 Select_AplyMatrix ();
440 void Select_RotateAxis (int axis, float deg)
449 Select_GetMid (select_origin);
450 select_fliporder = false;
454 for (i=0 ; i<3 ; i++)
456 VectorCopy (vec3_origin, select_matrix[i]);
457 select_matrix[i][i] = 1;
461 VectorCopy (select_matrix[i], temp);
462 VectorCopy (select_matrix[j], select_matrix[i]);
463 VectorSubtract (vec3_origin, temp, select_matrix[j]);
473 else if (deg == -270)
480 c = cos(deg/180*3.14159);
481 s = sin (deg/180*3.14159);
484 for (i=0 ; i<3 ; i++)
486 VectorCopy (vec3_origin, select_matrix[i]);
487 select_matrix[i][i] = 1;
493 select_matrix[1][1] = c;
494 select_matrix[1][2] = -s;
495 select_matrix[2][1] = s;
496 select_matrix[2][2] = c;
499 select_matrix[0][0] = c;
500 select_matrix[0][2] = s;
501 select_matrix[2][0] = -s;
502 select_matrix[2][2] = c;
505 select_matrix[0][0] = c;
506 select_matrix[0][1] = -s;
507 select_matrix[1][0] = s;
508 select_matrix[1][1] = c;
513 Select_AplyMatrix ();
517 ================================================================
521 ================================================================
524 void Select_CompleteTall (void)
530 if (!QE_SingleBrush ())
533 g_qeglobals.d_select_mode = sel_brush;
535 VectorCopy (selected_brushes.next->mins, mins);
536 VectorCopy (selected_brushes.next->maxs, maxs);
539 for (b=active_brushes.next ; b != &active_brushes ; b=next)
542 for (i=0 ; i<2 ; i++)
543 if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
547 Brush_RemoveFromList (b);
548 Brush_AddToList (b, &selected_brushes);
551 Sys_UpdateWindows (W_ALL);
554 void Select_PartialTall (void)
560 if (!QE_SingleBrush ())
563 g_qeglobals.d_select_mode = sel_brush;
565 VectorCopy (selected_brushes.next->mins, mins);
566 VectorCopy (selected_brushes.next->maxs, maxs);
569 for (b=active_brushes.next ; b != &active_brushes ; b=next)
572 for (i=0 ; i<2 ; i++)
573 if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i])
577 Brush_RemoveFromList (b);
578 Brush_AddToList (b, &selected_brushes);
581 Sys_UpdateWindows (W_ALL);
584 void Select_Touching (void)
590 if (!QE_SingleBrush ())
593 g_qeglobals.d_select_mode = sel_brush;
595 VectorCopy (selected_brushes.next->mins, mins);
596 VectorCopy (selected_brushes.next->maxs, maxs);
598 for (b=active_brushes.next ; b != &active_brushes ; b=next)
601 for (i=0 ; i<3 ; i++)
602 if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1)
606 Brush_RemoveFromList (b);
607 Brush_AddToList (b, &selected_brushes);
610 Sys_UpdateWindows (W_ALL);
613 void Select_Inside (void)
619 if (!QE_SingleBrush ())
622 g_qeglobals.d_select_mode = sel_brush;
624 VectorCopy (selected_brushes.next->mins, mins);
625 VectorCopy (selected_brushes.next->maxs, maxs);
628 for (b=active_brushes.next ; b != &active_brushes ; b=next)
631 for (i=0 ; i<3 ; i++)
632 if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
636 Brush_RemoveFromList (b);
637 Brush_AddToList (b, &selected_brushes);
640 Sys_UpdateWindows (W_ALL);
647 Turn the currently selected entity back into normal brushes
650 void Select_Ungroup (void)
655 e = selected_brushes.next->owner;
657 if (!e || e == world_entity || e->eclass->fixedsize)
659 Sys_Status ("Not a grouped entity.", 0);
663 for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext)
665 Brush_RemoveFromList (b);
666 Brush_AddToList (b, &active_brushes);
667 Entity_UnlinkBrush (b);
668 Entity_LinkBrush (world_entity, b);
670 b->owner = world_entity;
674 Sys_UpdateWindows (W_ALL);
679 Select_MakeStructural
682 void Select_MakeStructural (void)
687 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
688 for (f=b->brush_faces ; f ; f=f->next)
689 f->texdef.contents &= ~CONTENTS_DETAIL;
691 Sys_UpdateWindows (W_ALL);
694 void Select_MakeDetail (void)
699 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
700 for (f=b->brush_faces ; f ; f=f->next)
701 f->texdef.contents |= CONTENTS_DETAIL;
703 Sys_UpdateWindows (W_ALL);