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 ===========================================================================
34 g_qeglobals.d_xy.origin[0] = 0;
35 g_qeglobals.d_xy.origin[1] = 20;
36 g_qeglobals.d_xy.origin[2] = 46;
38 g_qeglobals.d_xy.scale = 1;
43 ============================================================================
47 ============================================================================
50 static int cursorx, cursory;
51 static int buttonstate;
52 static int pressx, pressy;
53 static vec3_t pressdelta;
54 static qboolean press_selection;
56 void XY_ToPoint (int x, int y, vec3_t point)
58 point[0] = g_qeglobals.d_xy.origin[0] + (x - g_qeglobals.d_xy.width/2)/g_qeglobals.d_xy.scale;
59 point[1] = g_qeglobals.d_xy.origin[1] + (y - g_qeglobals.d_xy.height/2)/g_qeglobals.d_xy.scale;
63 void XY_ToGridPoint (int x, int y, vec3_t point)
65 point[0] = g_qeglobals.d_xy.origin[0] + (x - g_qeglobals.d_xy.width/2)/g_qeglobals.d_xy.scale;
66 point[1] = g_qeglobals.d_xy.origin[1] + (y - g_qeglobals.d_xy.height/2)/g_qeglobals.d_xy.scale;
68 point[0] = floor(point[0]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
69 point[1] = floor(point[1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
77 void XY_MouseDown (int x, int y, int buttons)
80 vec3_t origin, dir, right, up;
82 buttonstate = buttons;
85 VectorCopy (vec3_origin, pressdelta);
87 XY_ToPoint (x, y, point);
89 VectorCopy (point, origin);
92 dir[0] = 0; dir[1] = 0; dir[2] = -1;
93 right[0] = 1/g_qeglobals.d_xy.scale; right[1] = 0; right[2] = 0;
94 up[0] = 0; up[1] = 1/g_qeglobals.d_xy.scale; up[2] = 0;
96 press_selection = (selected_brushes.next != &selected_brushes);
98 Sys_GetCursorPos (&cursorx, &cursory);
100 // lbutton = manipulate selection
101 // shift-LBUTTON = select
102 if ( (buttons == MK_LBUTTON)
103 || (buttons == (MK_LBUTTON | MK_SHIFT))
104 || (buttons == (MK_LBUTTON | MK_CONTROL))
105 || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) )
107 Drag_Begin (x, y, buttons,
113 // control mbutton = move camera
114 if (buttonstate == (MK_CONTROL|MK_MBUTTON) )
116 camera.origin[0] = point[0];
117 camera.origin[1] = point[1];
118 Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY);
121 // mbutton = angle camera
122 if (buttonstate == MK_MBUTTON)
124 VectorSubtract (point, camera.origin, point);
125 if (point[1] || point[0])
127 camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]);
128 Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY);
132 // shift mbutton = move z checker
133 if (buttonstate == (MK_SHIFT|MK_MBUTTON) )
135 XY_ToPoint (x, y, point);
136 z.origin[0] = point[0];
137 z.origin[1] = point[1];
138 Sys_UpdateWindows (W_XY_OVERLAY|W_Z);
149 void XY_MouseUp (int x, int y, int buttons)
153 if (!press_selection)
154 Sys_UpdateWindows (W_ALL);
159 qboolean DragDelta (int x, int y, vec3_t move)
161 vec3_t xvec, yvec, delta;
164 xvec[0] = 1/g_qeglobals.d_xy.scale;
165 xvec[1] = xvec[2] = 0;
166 yvec[1] = 1/g_qeglobals.d_xy.scale;
167 yvec[0] = yvec[2] = 0;
169 for (i=0 ; i<3 ; i++)
171 delta[i] = xvec[i]*(x - pressx) + yvec[i]*(y - pressy);
172 delta[i] = floor(delta[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize;
174 VectorSubtract (delta, pressdelta, move);
175 VectorCopy (delta, pressdelta);
177 if (move[0] || move[1] || move[2])
187 void NewBrushDrag (int x, int y)
189 vec3_t mins, maxs, junk;
194 if (!DragDelta (x,y, junk))
196 // delete the current selection
197 if (selected_brushes.next != &selected_brushes)
198 Brush_Free (selected_brushes.next);
199 XY_ToGridPoint (pressx, pressy, mins);
200 mins[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z/g_qeglobals.d_gridsize));
201 XY_ToGridPoint (x, y, maxs);
202 maxs[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z/g_qeglobals.d_gridsize));
203 if (maxs[2] <= mins[2])
204 maxs[2] = mins[2] + g_qeglobals.d_gridsize;
206 for (i=0 ; i<3 ; i++)
208 if (mins[i] == maxs[i])
209 return; // don't create a degenerate brush
210 if (mins[i] > maxs[i])
218 n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef);
222 Brush_AddToList (n, &selected_brushes);
224 Entity_LinkBrush (world_entity, n);
228 // Sys_UpdateWindows (W_ALL);
229 Sys_UpdateWindows (W_XY| W_CAMERA);
237 void XY_MouseMoved (int x, int y, int buttons)
244 // lbutton without selection = drag new brush
245 if (buttonstate == MK_LBUTTON && !press_selection)
251 // lbutton (possibly with control and or shift)
252 // with selection = drag selection
253 if (buttonstate & MK_LBUTTON)
255 Drag_MouseMoved (x, y, buttons);
256 Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA);
260 // control mbutton = move camera
261 if (buttonstate == (MK_CONTROL|MK_MBUTTON) )
263 XY_ToPoint (x, y, point);
264 camera.origin[0] = point[0];
265 camera.origin[1] = point[1];
266 Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA);
270 // shift mbutton = move z checker
271 if (buttonstate == (MK_SHIFT|MK_MBUTTON) )
273 XY_ToPoint (x, y, point);
274 z.origin[0] = point[0];
275 z.origin[1] = point[1];
276 Sys_UpdateWindows (W_XY_OVERLAY|W_Z);
280 // mbutton = angle camera
281 if (buttonstate == MK_MBUTTON )
283 XY_ToPoint (x, y, point);
284 VectorSubtract (point, camera.origin, point);
285 if (point[1] || point[0])
287 camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]);
288 Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA);
293 // rbutton = drag xy origin
294 if (buttonstate == MK_RBUTTON)
296 Sys_GetCursorPos (&x, &y);
297 if (x != cursorx || y != cursory)
299 g_qeglobals.d_xy.origin[0] -= (x-cursorx)/g_qeglobals.d_xy.scale;
300 g_qeglobals.d_xy.origin[1] += (y-cursory)/g_qeglobals.d_xy.scale;
301 Sys_SetCursorPos (cursorx, cursory);
302 Sys_UpdateWindows (W_XY | W_XY_OVERLAY);
310 ============================================================================
314 ============================================================================
323 void XY_DrawGrid (void)
325 float x, y, xb, xe, yb, ye;
329 glDisable(GL_TEXTURE_2D);
330 glDisable(GL_TEXTURE_1D);
331 glDisable(GL_DEPTH_TEST);
334 w = g_qeglobals.d_xy.width/2 / g_qeglobals.d_xy.scale;
335 h = g_qeglobals.d_xy.height/2 / g_qeglobals.d_xy.scale;
337 xb = g_qeglobals.d_xy.origin[0] - w;
338 if (xb < region_mins[0])
340 xb = 64 * floor (xb/64);
342 xe = g_qeglobals.d_xy.origin[0] + w;
343 if (xe > region_maxs[0])
345 xe = 64 * ceil (xe/64);
347 yb = g_qeglobals.d_xy.origin[1] - h;
348 if (yb < region_mins[1])
350 yb = 64 * floor (yb/64);
352 ye = g_qeglobals.d_xy.origin[1] + h;
353 if (ye > region_maxs[1])
355 ye = 64 * ceil (ye/64);
359 glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]);
361 if ( g_qeglobals.d_showgrid )
366 for (x=xb ; x<=xe ; x+=64)
371 for (y=yb ; y<=ye ; y+=64)
382 if ( g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*g_qeglobals.d_xy.scale >= 4)
384 glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]);
387 for (x=xb ; x<xe ; x += g_qeglobals.d_gridsize)
389 if ( ! ((int)x & 63) )
394 for (y=yb ; y<ye ; y+=g_qeglobals.d_gridsize)
396 if ( ! ((int)y & 63) )
404 // draw coordinate text if needed
406 if ( g_qeglobals.d_savedinfo.show_coordinates)
408 glColor4f(0, 0, 0, 0);
410 for (x=xb ; x<xe ; x+=64)
412 glRasterPos2f (x, g_qeglobals.d_xy.origin[1] + h - 6/g_qeglobals.d_xy.scale);
413 sprintf (text, "%i",(int)x);
414 glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
416 for (y=yb ; y<ye ; y+=64)
418 glRasterPos2f (g_qeglobals.d_xy.origin[0] - w + 1, y);
419 sprintf (text, "%i",(int)y);
420 glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
430 void XY_DrawBlockGrid (void)
432 float x, y, xb, xe, yb, ye;
436 glDisable(GL_TEXTURE_2D);
437 glDisable(GL_TEXTURE_1D);
438 glDisable(GL_DEPTH_TEST);
441 w = g_qeglobals.d_xy.width/2 / g_qeglobals.d_xy.scale;
442 h = g_qeglobals.d_xy.height/2 / g_qeglobals.d_xy.scale;
444 xb = g_qeglobals.d_xy.origin[0] - w;
445 if (xb < region_mins[0])
447 xb = 1024 * floor (xb/1024);
449 xe = g_qeglobals.d_xy.origin[0] + w;
450 if (xe > region_maxs[0])
452 xe = 1024 * ceil (xe/1024);
454 yb = g_qeglobals.d_xy.origin[1] - h;
455 if (yb < region_mins[1])
457 yb = 1024 * floor (yb/1024);
459 ye = g_qeglobals.d_xy.origin[1] + h;
460 if (ye > region_maxs[1])
462 ye = 1024 * ceil (ye/1024);
471 for (x=xb ; x<=xe ; x+=1024)
476 for (y=yb ; y<=ye ; y+=1024)
485 // draw coordinate text if needed
487 for (x=xb ; x<xe ; x+=1024)
488 for (y=yb ; y<ye ; y+=1024)
490 glRasterPos2f (x+512, y+512);
491 sprintf (text, "%i,%i",(int)floor(x/1024), (int)floor(y/1024) );
492 glCallLists (strlen(text), GL_UNSIGNED_BYTE, text);
495 glColor4f(0, 0, 0, 0);
499 void DrawCameraIcon (void)
503 x = camera.origin[0];
504 y = camera.origin[1];
505 a = camera.angles[YAW]/180*Q_PI;
507 glColor3f (0.0, 0.0, 1.0);
508 glBegin(GL_LINE_STRIP);
509 glVertex3f (x-16,y,0);
510 glVertex3f (x,y+8,0);
511 glVertex3f (x+16,y,0);
512 glVertex3f (x,y-8,0);
513 glVertex3f (x-16,y,0);
514 glVertex3f (x+16,y,0);
517 glBegin(GL_LINE_STRIP);
518 glVertex3f (x+48*cos(a+Q_PI/4), y+48*sin(a+Q_PI/4), 0);
519 glVertex3f (x, y, 0);
520 glVertex3f (x+48*cos(a-Q_PI/4), y+48*sin(a-Q_PI/4), 0);
525 void DrawZIcon (void)
533 glDisable (GL_TEXTURE_2D);
534 glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
535 glDisable (GL_CULL_FACE);
536 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
537 glColor4f (0.0, 0.0, 1.0, 0.25);
539 glVertex3f (x-8,y-8,0);
540 glVertex3f (x+8,y-8,0);
541 glVertex3f (x+8,y+8,0);
542 glVertex3f (x-8,y+8,0);
544 glDisable (GL_BLEND);
546 glColor4f (0.0, 0.0, 1.0, 1);
548 glBegin(GL_LINE_LOOP);
549 glVertex3f (x-8,y-8,0);
550 glVertex3f (x+8,y-8,0);
551 glVertex3f (x+8,y+8,0);
552 glVertex3f (x-8,y+8,0);
555 glBegin(GL_LINE_STRIP);
556 glVertex3f (x-4,y+4,0);
557 glVertex3f (x+4,y+4,0);
558 glVertex3f (x-4,y-4,0);
559 glVertex3f (x+4,y-4,0);
569 BOOL FilterBrush(brush_t *pb)
572 return FALSE; // during construction
574 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP)
576 if (!strncmp(pb->brush_faces->texdef.name, "clip", 4))
580 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WATER)
582 if (pb->brush_faces->texdef.name[0] == '*')
586 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAIL)
588 if (pb->brush_faces->texdef.contents & CONTENTS_DETAIL)
592 if (pb->owner == world_entity)
594 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD)
598 else if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT)
601 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS)
603 if (!strncmp(pb->owner->eclass->name, "light", 5))
607 if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS)
609 if (!strncmp(pb->owner->eclass->name, "path", 4))
617 =============================================================
621 =============================================================
628 Draws connections between entities.
629 Needs to consider all entities, not just ones on screen,
630 because the lines can be visible when neither end is.
631 Called for both camera view and xy view.
634 void DrawPathLines (void)
645 char *ent_target[MAX_MAP_ENTITIES];
646 entity_t *ent_entity[MAX_MAP_ENTITIES];
650 for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next)
652 ent_target[num_entities] = ValueForKey (te, "target");
653 if (ent_target[num_entities][0])
655 ent_entity[num_entities] = te;
660 for (se = entities.next ; se != &entities ; se = se->next)
662 psz = ValueForKey(se, "targetname");
664 if (psz == NULL || psz[0] == '\0')
667 sb = se->brushes.onext;
668 if (sb == &se->brushes)
671 for (k=0 ; k<num_entities ; k++)
673 if (strcmp (ent_target[k], psz))
677 tb = te->brushes.onext;
678 if (tb == &te->brushes)
681 for (i=0 ; i<3 ; i++)
682 mid[i] = (sb->mins[i] + sb->maxs[i])*0.5;
684 for (i=0 ; i<3 ; i++)
685 mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5;
687 VectorSubtract (mid1, mid, dir);
688 len = VectorNormalize (dir);
689 s1[0] = -dir[1]*8 + dir[0]*8;
690 s2[0] = dir[1]*8 + dir[0]*8;
691 s1[1] = dir[0]*8 + dir[1]*8;
692 s2[1] = -dir[0]*8 + dir[1]*8;
694 glColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]);
700 arrows = (int)(len / 256) + 1;
702 for (i=0 ; i<arrows ; i++)
704 f = len * (i + 0.5) / arrows;
706 for (j=0 ; j<3 ; j++)
707 mid1[j] = mid[j] + f*dir[j];
709 glVertex3f (mid1[0] + s1[0], mid1[1] + s1[1], mid1[2]);
711 glVertex3f (mid1[0] + s2[0], mid1[1] + s2[1], mid1[2]);
721 //=============================================================
739 if (!active_brushes.next)
740 return; // not valid yet
742 if (g_qeglobals.d_xy.timing)
743 start = Sys_DoubleTime ();
748 g_qeglobals.d_xy.d_dirty = false;
750 glViewport(0, 0, g_qeglobals.d_xy.width, g_qeglobals.d_xy.height);
752 g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][0],
753 g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][1],
754 g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][2],
757 glClear(GL_COLOR_BUFFER_BIT);
762 glMatrixMode(GL_PROJECTION);
765 w = g_qeglobals.d_xy.width/2 / g_qeglobals.d_xy.scale;
766 h = g_qeglobals.d_xy.height/2 / g_qeglobals.d_xy.scale;
767 mins[0] = g_qeglobals.d_xy.origin[0] - w;
768 maxs[0] = g_qeglobals.d_xy.origin[0] + w;
769 mins[1] = g_qeglobals.d_xy.origin[1] - h;
770 maxs[1] = g_qeglobals.d_xy.origin[1] + h;
772 glOrtho (mins[0], maxs[0], mins[1], maxs[1], -8000, 8000);
782 glShadeModel (GL_FLAT);
783 glDisable(GL_TEXTURE_2D);
784 glDisable(GL_TEXTURE_1D);
785 glDisable(GL_DEPTH_TEST);
788 // glEnable (GL_LINE_SMOOTH);
793 for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next)
795 if (brush->mins[0] > maxs[0]
796 || brush->mins[1] > maxs[1]
797 || brush->maxs[0] < mins[0]
798 || brush->maxs[1] < mins[1] )
801 continue; // off screen
804 if (FilterBrush (brush))
807 if (brush->owner != e)
810 glColor3fv(e->eclass->color);
812 Brush_DrawXY( brush );
820 if ( g_qeglobals.d_pointfile_display_list)
821 glCallList (g_qeglobals.d_pointfile_display_list);
826 if ( g_qeglobals.show_blocks)
830 // now draw selected brushes
832 glTranslatef( g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]);
834 glColor3f(1.0, 0.0, 0.0);
835 glEnable (GL_LINE_STIPPLE);
836 glLineStipple (3, 0xaaaa);
839 for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next)
842 Brush_DrawXY( brush );
845 glDisable (GL_LINE_STIPPLE);
848 // edge / vertex flags
850 if (g_qeglobals.d_select_mode == sel_vertex)
855 for (i=0 ; i<g_qeglobals.d_numpoints ; i++)
856 glVertex3fv (g_qeglobals.d_points[i]);
860 else if (g_qeglobals.d_select_mode == sel_edge)
867 for (i=0 ; i<g_qeglobals.d_numedges ; i++)
869 v1 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p1];
870 v2 = g_qeglobals.d_points[g_qeglobals.d_edges[i].p2];
871 glVertex3f ( (v1[0]+v2[0])*0.5,(v1[1]+v2[1])*0.5,(v1[2]+v2[2])*0.5);
876 glTranslatef (-g_qeglobals.d_select_translate[0], -g_qeglobals.d_select_translate[1], -g_qeglobals.d_select_translate[2]);
879 // now draw camera point
885 QE_CheckOpenGLForErrors();
887 if (g_qeglobals.d_xy.timing)
889 end = Sys_DoubleTime ();
890 Sys_Printf ("xy: %i ms\n", (int)(1000*(end-start)));
899 void XY_Overlay (void)
904 static vec3_t lastcamera;
907 glViewport(0, 0, g_qeglobals.d_xy.width, g_qeglobals.d_xy.height);
912 glMatrixMode(GL_PROJECTION);
915 w = g_qeglobals.d_xy.width/2 / g_qeglobals.d_xy.scale;
916 h = g_qeglobals.d_xy.height/2 / g_qeglobals.d_xy.scale;
917 glOrtho (g_qeglobals.d_xy.origin[0] - w, g_qeglobals.d_xy.origin[0] + w
918 , g_qeglobals.d_xy.origin[1] - h, g_qeglobals.d_xy.origin[1] + h, -8000, 8000);
920 // erase the old camera and z checker positions
921 // if the entire xy hasn't been redrawn
923 if (g_qeglobals.d_xy.d_dirty)
925 glReadBuffer (GL_BACK);
926 glDrawBuffer (GL_FRONT);
928 glRasterPos2f (lastz[0]-9, lastz[1]-9);
929 glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
930 glCopyPixels(r[0], r[1], 18,18, GL_COLOR);
932 glRasterPos2f (lastcamera[0]-50, lastcamera[1]-50);
933 glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
934 glCopyPixels(r[0], r[1], 100,100, GL_COLOR);
936 g_qeglobals.d_xy.d_dirty = true;
939 // save off underneath where we are about to draw
941 VectorCopy (z.origin, lastz);
942 VectorCopy (camera.origin, lastcamera);
944 glReadBuffer (GL_FRONT);
945 glDrawBuffer (GL_BACK);
947 glRasterPos2f (lastz[0]-9, lastz[1]-9);
948 glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
949 glCopyPixels(r[0], r[1], 18,18, GL_COLOR);
951 glRasterPos2f (lastcamera[0]-50, lastcamera[1]-50);
952 glGetIntegerv (GL_CURRENT_RASTER_POSITION,r);
953 glCopyPixels(r[0], r[1], 100,100, GL_COLOR);
956 // draw the new icons
958 glDrawBuffer (GL_FRONT);
960 glShadeModel (GL_FLAT);
961 glDisable(GL_TEXTURE_2D);
962 glDisable(GL_TEXTURE_1D);
963 glDisable(GL_DEPTH_TEST);
970 glDrawBuffer (GL_BACK);