]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - tools/quake2/extra/qe4/select.c
Q2Tools source - didn't import this in initially
[xonotic/netradiant.git] / tools / quake2 / extra / qe4 / select.c
1 /*
2 ===========================================================================
3 Copyright (C) 1997-2006 Id Software, Inc.
4
5 This file is part of Quake 2 Tools source code.
6
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.
11
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.
16
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 ===========================================================================
21 */
22
23 // select.c
24
25 #include "qe3.h"
26
27 /*
28 ===========
29 Test_Ray
30 ===========
31 */
32 #define DIST_START      999999
33 trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags)
34 {
35         brush_t *brush;
36         face_t  *face;
37         float   dist;
38         trace_t t;
39
40         memset (&t, 0, sizeof(t));
41         t.dist = DIST_START;
42
43         if (! (flags & SF_SELECTED_ONLY) )
44                 for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
45                 {
46                         if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
47                                 continue;
48                         if (FilterBrush (brush))
49                                 continue;
50                         face = Brush_Ray (origin, dir, brush, &dist);
51                         if (dist > 0 && dist < t.dist)
52                         {
53                                 t.dist = dist;
54                                 t.brush = brush;
55                                 t.face = face;
56                                 t.selected = false;
57                         }
58                 }
59         for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
60         {
61                 if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity)
62                         continue;
63                 if (FilterBrush (brush))
64                         continue;
65                 face = Brush_Ray (origin, dir, brush, &dist);
66                 if (dist > 0 && dist < t.dist)
67                 {
68                         t.dist = dist;
69                         t.brush = brush;
70                         t.face = face;
71                         t.selected = true;
72                 }
73         }
74
75         // if entites first, but didn't find any, check regular
76
77         if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL)
78                 return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST);
79
80         return t;
81 }
82
83
84 /*
85 ============
86 Select_Brush
87
88 ============
89 */
90 void Select_Brush (brush_t *brush)
91 {
92         brush_t *b;
93         entity_t        *e;
94
95         selected_face = NULL;
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++;
99
100         e = brush->owner;
101         if (e)
102         {
103                 // select complete entity on first click
104                 if (e != world_entity)
105                 {
106                         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
107                                 if (b->owner == e)
108                                         goto singleselect;
109                         for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext)
110                         {
111                                 Brush_RemoveFromList (b);
112                                 Brush_AddToList (b, &selected_brushes);
113                         }
114                 }
115                 else
116                 {
117 singleselect:
118                         Brush_RemoveFromList (brush);
119                         Brush_AddToList (brush, &selected_brushes);
120                 }
121
122                 if (e->eclass)
123                 {
124                         UpdateEntitySel(brush->owner->eclass);
125                 }
126         }
127 }
128
129 /*
130 ============
131 Select_Ray
132
133 If the origin is inside a brush, that brush will be ignored.
134 ============
135 */
136 void Select_Ray (vec3_t origin, vec3_t dir, int flags)
137 {
138         trace_t t;
139
140         t = Test_Ray (origin, dir, flags);
141         if (!t.brush)
142                 return;
143
144         if (flags == SF_SINGLEFACE)
145         {
146                 selected_face = t.face;
147                 selected_face_brush = t.brush;
148                 Sys_UpdateWindows (W_ALL);
149                 g_qeglobals.d_select_mode = sel_brush;
150                 return;
151         }
152
153         // move the brush to the other list
154
155         g_qeglobals.d_select_mode = sel_brush;
156
157         if (t.selected)
158         {
159                 Brush_RemoveFromList (t.brush);
160                 Brush_AddToList (t.brush, &active_brushes);
161         } else
162         {
163                 Select_Brush (t.brush);
164         }
165
166         Sys_UpdateWindows (W_ALL);
167 }
168
169
170 void Select_Delete (void)
171 {
172         brush_t *brush;
173
174         selected_face = NULL;
175         g_qeglobals.d_select_mode = sel_brush;
176
177         g_qeglobals.d_select_count = 0;
178         g_qeglobals.d_num_move_points = 0;
179         while (selected_brushes.next != &selected_brushes)
180         {
181                 brush = selected_brushes.next;
182                 Brush_Free (brush);
183         }
184
185         // FIXME: remove any entities with no brushes
186
187         Sys_UpdateWindows (W_ALL);
188 }
189
190 void Select_Deselect (void)
191 {
192         brush_t *b;
193
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;
198
199         if (b == &selected_brushes)
200         {
201                 if (selected_face)
202                 {
203                         selected_face = NULL;
204                         Sys_UpdateWindows (W_ALL);
205                 }
206                 return;
207         }
208
209         selected_face = NULL;
210         g_qeglobals.d_select_mode = sel_brush;
211
212         // grab top / bottom height for new brushes
213         if (b->mins[2] < b->maxs[2])
214         {
215                 g_qeglobals.d_new_brush_bottom_z = b->mins[2];
216                 g_qeglobals.d_new_brush_top_z = b->maxs[2];
217         }
218
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;
224
225         Sys_UpdateWindows (W_ALL);
226 }
227
228 /*
229 ============
230 Select_Move
231 ============
232 */
233 void Select_Move (vec3_t delta)
234 {
235         brush_t *b;
236
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);
241 }
242
243 /*
244 ============
245 Select_Clone
246
247 Creates an exact duplicate of the selection in place, then moves
248 the selected brushes off of their old positions
249 ============
250 */
251 void Select_Clone (void)
252 {
253         brush_t         *b, *b2, *n, *next, *next2;
254         vec3_t          delta;
255         entity_t        *e;
256
257         g_qeglobals.d_workcount++;
258         g_qeglobals.d_select_mode = sel_brush;
259
260         delta[0] = g_qeglobals.d_gridsize;
261         delta[1] = g_qeglobals.d_gridsize;
262         delta[2] = 0;
263
264         for (b=selected_brushes.next ; b != &selected_brushes ; b=next)
265         {
266                 next = b->next;
267                 // if the brush is a world brush, handle simply
268                 if (b->owner == world_entity)
269                 {
270                         n = Brush_Clone (b);
271                         Brush_AddToList (n, &active_brushes);
272                         Entity_LinkBrush (world_entity, n);
273                         Brush_Build( n );
274                         Brush_Move (b, delta);
275                         continue;
276                 }
277
278                 e = Entity_Clone (b->owner);
279                 // clear the target / targetname
280                 DeleteKey (e, "target");
281                 DeleteKey (e, "targetname");
282
283                 // if the brush is a fixed size entity, create a new entity
284                 if (b->owner->eclass->fixedsize)
285                 {
286                         n = Brush_Clone (b);
287                         Brush_AddToList (n, &active_brushes);
288                         Entity_LinkBrush (e, n);
289                         Brush_Build( n );
290                         Brush_Move (b, delta);
291                         continue;
292                 }
293
294                 // brush is a complex entity, grab all the other ones now
295
296                 next = &selected_brushes;
297
298                 for ( b2 = b ; b2 != &selected_brushes ; b2=next2)
299                 {
300                         next2 = b2->next;
301                         if (b2->owner != b->owner)
302                         {
303                                 if (next == &selected_brushes)
304                                         next = b2;
305                                 continue;
306                         }
307
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);
312
313                         n = Brush_Clone (b2);
314                         Brush_AddToList (n, &active_brushes);
315                         Entity_LinkBrush (e, n);
316                         Brush_Build( n );
317                         Brush_Move (b2, delta);
318                 }
319
320         }
321         Sys_UpdateWindows (W_ALL);
322 }
323
324
325
326 /*
327 ============
328 Select_SetTexture
329 ============
330 */
331 void Select_SetTexture (texdef_t *texdef)
332 {
333         brush_t *b;
334
335         if (selected_face)
336         {
337                 selected_face->texdef = *texdef;
338                 Brush_Build(selected_face_brush);
339         }
340         else
341         {
342                 for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
343                         if (!b->owner->eclass->fixedsize)
344                                 Brush_SetTexture (b, texdef);
345         }
346         Sys_UpdateWindows (W_ALL);
347 }
348
349
350 /*
351 ================================================================
352
353   TRANSFORMATIONS
354
355 ================================================================
356 */
357
358 void Select_GetBounds (vec3_t mins, vec3_t maxs)
359 {
360         brush_t *b;
361         int             i;
362
363         for (i=0 ; i<3 ; i++)
364         {
365                 mins[i] = 99999;
366                 maxs[i] = -99999;
367         }
368
369         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
370                 for (i=0 ; i<3 ; i++)
371                 {
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];
376                 }
377 }
378
379 void Select_GetMid (vec3_t mid)
380 {
381         vec3_t  mins, maxs;
382         int             i;
383
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 );
387 }
388
389 vec3_t  select_origin;
390 vec3_t  select_matrix[3];
391 qboolean        select_fliporder;
392
393 void Select_AplyMatrix (void)
394 {
395         brush_t *b;
396         face_t  *f;
397         int             i, j;
398         vec3_t  temp;
399
400         for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next)
401         {
402                 for (f=b->brush_faces ; f ; f=f->next)
403                 {
404                         for (i=0 ; i<3 ; i++)
405                         {
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])
409                                                 + select_origin[j];
410                         }
411                         if (select_fliporder)
412                         {
413                                 VectorCopy (f->planepts[0], temp);
414                                 VectorCopy (f->planepts[2], f->planepts[0]);
415                                 VectorCopy (temp, f->planepts[2]);
416                         }
417                 }
418                 Brush_Build( b );
419         }
420         Sys_UpdateWindows (W_ALL);
421 }
422
423
424 void Select_FlipAxis (int axis)
425 {
426         int             i;
427
428         Select_GetMid (select_origin);
429         for (i=0 ; i<3 ; i++)
430         {
431                 VectorCopy (vec3_origin, select_matrix[i]);
432                 select_matrix[i][i] = 1;
433         }
434         select_matrix[axis][axis] = -1;
435
436         select_fliporder = true;
437         Select_AplyMatrix ();
438 }
439
440 void Select_RotateAxis (int axis, float deg)
441 {
442         vec3_t  temp;
443         int             i, j;
444         vec_t   c, s;
445
446         if (deg == 0)
447                 return;
448
449         Select_GetMid (select_origin);
450         select_fliporder = false;
451
452         if (deg == 90)
453         {
454                 for (i=0 ; i<3 ; i++)
455                 {
456                         VectorCopy (vec3_origin, select_matrix[i]);
457                         select_matrix[i][i] = 1;
458                 }
459                 i = (axis+1)%3;
460                 j = (axis+2)%3;
461                 VectorCopy (select_matrix[i], temp);
462                 VectorCopy (select_matrix[j], select_matrix[i]);
463                 VectorSubtract (vec3_origin, temp, select_matrix[j]);
464         }
465         else
466         {
467                 deg = -deg;
468                 if (deg == -180)
469                 {
470                         c = -1;
471                         s = 0;
472                 }
473                 else if (deg == -270)
474                 {
475                         c = 0;
476                         s = -1;
477                 }
478                 else
479                 {
480                         c = cos(deg/180*3.14159);
481                         s = sin (deg/180*3.14159);
482                 }
483
484                 for (i=0 ; i<3 ; i++)
485                 {
486                         VectorCopy (vec3_origin, select_matrix[i]);
487                         select_matrix[i][i] = 1;
488                 }
489
490                 switch (axis)
491                 {
492                 case 0:
493                         select_matrix[1][1] = c;
494                         select_matrix[1][2] = -s;
495                         select_matrix[2][1] = s;
496                         select_matrix[2][2] = c;
497                         break;
498                 case 1:
499                         select_matrix[0][0] = c;
500                         select_matrix[0][2] = s;
501                         select_matrix[2][0] = -s;
502                         select_matrix[2][2] = c;
503                         break;
504                 case 2:
505                         select_matrix[0][0] = c;
506                         select_matrix[0][1] = -s;
507                         select_matrix[1][0] = s;
508                         select_matrix[1][1] = c;
509                         break;
510                 }
511         }
512
513         Select_AplyMatrix ();
514 }
515
516 /*
517 ================================================================
518
519 GROUP SELECTIONS
520
521 ================================================================
522 */
523
524 void Select_CompleteTall (void)
525 {
526         brush_t *b, *next;
527         int             i;
528         vec3_t  mins, maxs;
529
530         if (!QE_SingleBrush ())
531                 return;
532
533         g_qeglobals.d_select_mode = sel_brush;
534
535         VectorCopy (selected_brushes.next->mins, mins);
536         VectorCopy (selected_brushes.next->maxs, maxs);
537         Select_Delete ();
538
539         for (b=active_brushes.next ; b != &active_brushes ; b=next)
540         {
541                 next = b->next;
542                 for (i=0 ; i<2 ; i++)
543                         if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
544                                 break;
545                 if (i == 2)
546                 {
547                         Brush_RemoveFromList (b);
548                         Brush_AddToList (b, &selected_brushes);
549                 }
550         }
551         Sys_UpdateWindows (W_ALL);
552 }
553
554 void Select_PartialTall (void)
555 {
556         brush_t *b, *next;
557         int             i;
558         vec3_t  mins, maxs;
559
560         if (!QE_SingleBrush ())
561                 return;
562
563         g_qeglobals.d_select_mode = sel_brush;
564
565         VectorCopy (selected_brushes.next->mins, mins);
566         VectorCopy (selected_brushes.next->maxs, maxs);
567         Select_Delete ();
568
569         for (b=active_brushes.next ; b != &active_brushes ; b=next)
570         {
571                 next = b->next;
572                 for (i=0 ; i<2 ; i++)
573                         if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i])
574                                 break;
575                 if (i == 2)
576                 {
577                         Brush_RemoveFromList (b);
578                         Brush_AddToList (b, &selected_brushes);
579                 }
580         }
581         Sys_UpdateWindows (W_ALL);
582 }
583
584 void Select_Touching (void)
585 {
586         brush_t *b, *next;
587         int             i;
588         vec3_t  mins, maxs;
589
590         if (!QE_SingleBrush ())
591                 return;
592
593         g_qeglobals.d_select_mode = sel_brush;
594
595         VectorCopy (selected_brushes.next->mins, mins);
596         VectorCopy (selected_brushes.next->maxs, maxs);
597
598         for (b=active_brushes.next ; b != &active_brushes ; b=next)
599         {
600                 next = b->next;
601                 for (i=0 ; i<3 ; i++)
602                         if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1)
603                                 break;
604                 if (i == 3)
605                 {
606                         Brush_RemoveFromList (b);
607                         Brush_AddToList (b, &selected_brushes);
608                 }
609         }
610         Sys_UpdateWindows (W_ALL);
611 }
612
613 void Select_Inside (void)
614 {
615         brush_t *b, *next;
616         int             i;
617         vec3_t  mins, maxs;
618
619         if (!QE_SingleBrush ())
620                 return;
621
622         g_qeglobals.d_select_mode = sel_brush;
623
624         VectorCopy (selected_brushes.next->mins, mins);
625         VectorCopy (selected_brushes.next->maxs, maxs);
626         Select_Delete ();
627
628         for (b=active_brushes.next ; b != &active_brushes ; b=next)
629         {
630                 next = b->next;
631                 for (i=0 ; i<3 ; i++)
632                         if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i])
633                                 break;
634                 if (i == 3)
635                 {
636                         Brush_RemoveFromList (b);
637                         Brush_AddToList (b, &selected_brushes);
638                 }
639         }
640         Sys_UpdateWindows (W_ALL);
641 }
642
643 /*
644 =============
645 Select_Ungroup
646
647 Turn the currently selected entity back into normal brushes
648 =============
649 */
650 void  Select_Ungroup (void)
651 {
652         entity_t        *e;
653         brush_t         *b;
654
655         e = selected_brushes.next->owner;
656
657         if (!e || e == world_entity || e->eclass->fixedsize)
658         {
659                 Sys_Status ("Not a grouped entity.", 0);
660                 return;
661         }
662
663         for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext)
664         {
665                 Brush_RemoveFromList (b);
666                 Brush_AddToList (b, &active_brushes);
667                 Entity_UnlinkBrush (b);
668                 Entity_LinkBrush (world_entity, b);
669                 Brush_Build( b );
670                 b->owner = world_entity;
671         }
672
673         Entity_Free (e);
674         Sys_UpdateWindows (W_ALL);
675 }
676
677 /*
678 ====================
679 Select_MakeStructural
680 ====================
681 */
682 void Select_MakeStructural (void)
683 {
684         brush_t *b;
685         face_t  *f;
686
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;
690         Select_Deselect ();
691         Sys_UpdateWindows (W_ALL);
692 }
693
694 void Select_MakeDetail (void)
695 {
696         brush_t *b;
697         face_t  *f;
698
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;
702         Select_Deselect ();
703         Sys_UpdateWindows (W_ALL);
704 }
705
706