2 GenSurf plugin for GtkRadiant
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 extern double backface;
29 extern double xmin,xmax,ymin,ymax,zmin,zmax;
31 double SF, SFG; // Graphics scale factors
32 double XLo, XHi, YLo, YHi, ZLo, ZHi;
34 double elevation,azimuth;
35 int cxChar = 10, cyChar = 16;
39 static Rect rcCoord; // where X= Y= is drawn
40 static Rect rcGrid; // rectangle within rcLower that forms the border of the grid, plus
42 static Rect rcLower; // lower half of window, where plan view is drawn
43 static Rect rcUpper; // upper half or entire window, where isometric projection is drawn
45 void vertex_selected ();
47 void texfont_write (const char *text, int l, int t);
50 g_GLTable.m_pfn_qglLineWidth (1); \
51 g_GLTable.m_pfn_qglColor3f (0, 1, 0); \
52 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); }
55 g_GLTable.m_pfn_qglLineWidth (2); \
56 g_GLTable.m_pfn_qglColor3f (1, 0, 0); \
57 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); }
60 g_GLTable.m_pfn_qglLineWidth (1); \
61 g_GLTable.m_pfn_qglColor3f (0, 1, 0); \
62 g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \
63 g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); }
65 #define DRAW_QUAD(rc,r,g,b) { \
66 g_GLTable.m_pfn_qglBegin (GL_QUADS); \
67 g_GLTable.m_pfn_qglColor3f (0,1,0); \
68 g_GLTable.m_pfn_qglVertex2i (rc.left-1, rc.bottom); \
69 g_GLTable.m_pfn_qglVertex2i (rc.right, rc.bottom); \
70 g_GLTable.m_pfn_qglVertex2i (rc.right, rc.top+1); \
71 g_GLTable.m_pfn_qglVertex2i (rc.left-1, rc.top+1); \
72 g_GLTable.m_pfn_qglColor3f (r,g,b); \
73 g_GLTable.m_pfn_qglVertex2i (rc.left, rc.bottom+1); \
74 g_GLTable.m_pfn_qglVertex2i (rc.right-1, rc.bottom+1); \
75 g_GLTable.m_pfn_qglVertex2i (rc.right-1, rc.top); \
76 g_GLTable.m_pfn_qglVertex2i (rc.left, rc.top); \
77 g_GLTable.m_pfn_qglEnd (); }
83 double Hhi, Hlo, Vhi, Vlo;
93 if (g_pWndPreview == NULL)
95 gtk_widget_show (g_pWndPreview);
100 gtk_widget_hide (g_pWndPreview);
103 static void draw_preview ()
105 int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height;
107 g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1);
108 g_GLTable.m_pfn_qglViewport (0, 0, width, height);
109 g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION);
110 g_GLTable.m_pfn_qglLoadIdentity ();
111 g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1);
112 g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
114 // ^Fishman - Antializing for the preview window.
117 g_GLTable.m_pfn_qglEnable(GL_BLEND);
118 g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
119 g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH);
123 g_GLTable.m_pfn_qglDisable(GL_BLEND);
124 g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH);
129 if (!ValidSurface ())
133 rcUpper.right = width;
135 rcUpper.top = height;
137 rcLower.right = width;
139 rcLower.top = height;
143 rcUpper.bottom = rcUpper.top/2;
144 DrawPreview (rcUpper);
145 g_GLTable.m_pfn_qglBegin (GL_LINES);
146 g_GLTable.m_pfn_qglVertex2i (rcUpper.left, rcUpper.bottom);
147 g_GLTable.m_pfn_qglVertex2i (rcUpper.right, rcUpper.bottom);
148 g_GLTable.m_pfn_qglEnd ();
149 rcLower.top = rcUpper.bottom-1;
151 rcCoord.left = rcLower.left;
152 rcCoord.right = rcLower.right;
153 rcCoord.bottom = rcLower.bottom;
154 rcCoord.top = rcLower.top;
155 rcCoord.top = rcCoord.bottom+cyChar;
156 rcCoord.right = rcCoord.left + 15*cxChar;
157 rcGrid.left = X0G - 3;
158 rcGrid.bottom = Y0G - 3;
159 rcGrid.right = X0G + (int)(SFG*(Hur-Hll)) + 3;
160 rcGrid.top = Y0G + (int)(SFG*(Vur-Vll)) + 3;
163 DrawPreview (rcUpper);
166 static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)
168 if (event->count > 0)
171 if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget))
173 g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n");
179 g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget);
180 g_GLTable.m_pfn_QE_CheckOpenGLForErrors ();
185 static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)
187 Point pt = { (long)event->x, widget->allocation.height - (long)event->y };
193 if ((!VertexMode) || (event->button != 1))
196 if (!PtInRect (&rcGrid,pt))
202 x = Hll + (pt.x-X0G)/SFG;
203 y = Vur - (pt.y-Y0G)/SFG;
204 i = (int)(floor( (x-Hll)/dh - 0.5) + 1);
205 j = (int)(floor( (y-Vll)/dv - 0.5) + 1);
206 if (i < 0 || i > NH || j < 0 || j > NV)
218 // Control key pressed - add this point, or remove it if already selected
219 if ((event->state & GDK_CONTROL_MASK) != 0)
222 if (NumVerticesSelected)
224 for (k=0; k<NumVerticesSelected && !Selected; k++)
226 if(Vertex[k].i == i && Vertex[k].j == j)
234 // Already selected - unselect it.
237 if (ks < NumVerticesSelected)
239 for (k=ks;k<NumVerticesSelected-1;k++)
241 Vertex[k].i = Vertex[k+1].i;
242 Vertex[k].j = Vertex[k+1].j;
244 NumVerticesSelected--;
249 Vertex[NumVerticesSelected].i = i;
250 Vertex[NumVerticesSelected].j = j;
251 NumVerticesSelected++;
254 else if ((event->state & GDK_SHIFT_MASK) != 0)
256 if (NumVerticesSelected)
258 NumVerticesSelected = 1;
259 i0 = min(Vertex[0].i, i);
260 i1 = max(Vertex[0].i, i);
261 j0 = min(Vertex[0].j, j);
262 j1 = max(Vertex[0].j, j);
263 for(i=i0; i<=i1; i++)
265 for(j=j0; j<=j1; j++)
267 if(i==0 && j==0 ) continue;
268 if(i==NH && j==0 ) continue;
269 if(i==0 && j==NV) continue;
270 if(i==NH && j==NV) continue;
271 if(i != Vertex[0].i || j != Vertex[0].j)
273 Vertex[NumVerticesSelected].i = i;
274 Vertex[NumVerticesSelected].j = j;
275 NumVerticesSelected++;
284 NumVerticesSelected = 1;
291 NumVerticesSelected = 1;
297 static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)
299 Point pt = { (long)event->x, widget->allocation.height - (long)event->y };
304 if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget))
306 g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n");
310 g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST);
311 g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left,
312 rcCoord.top-rcCoord.bottom);
313 g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT);
315 if (PtInRect(&rcGrid,pt))
317 GdkCursor *cursor = gdk_cursor_new (GDK_CROSS);
318 gdk_window_set_cursor (g_pWndPreview->window, cursor);
319 gdk_cursor_unref (cursor);
324 x = (int)(Hll + (pt.x-X0G)/SFG);
325 y = (int)(Vur - (pt.y-Y0G)/SFG);
330 sprintf(Text," x=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );
334 sprintf(Text," y=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );
337 sprintf(Text," x=%d, y=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );
340 texfont_write (Text, rcCoord.left, rcCoord.top);
344 gdk_window_set_cursor (g_pWndPreview->window, NULL);
347 g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget);
348 g_GLTable.m_pfn_QE_CheckOpenGLForErrors ();
349 g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST);
352 static gint preview_close (GtkWidget *widget, gpointer data)
354 gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE);
358 static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data)
360 *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360));
361 UpdatePreview (false);
364 static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data)
366 preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast<double*>(data));
370 static void preview_spin (GtkAdjustment *adj, double *data)
372 *data = DegreesToRadians (adj->value);
373 UpdatePreview (false);
376 void CreateViewWindow ()
378 GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame;
386 g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
387 gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview");
388 gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL);
389 gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);
390 gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd));
391 gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400);
393 vbox = gtk_vbox_new (FALSE, 5);
394 gtk_widget_show (vbox);
395 gtk_container_add (GTK_CONTAINER (dlg), vbox);
398 hbox = gtk_hbox_new (TRUE, 5);
399 gtk_widget_show (hbox);
400 gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);
401 gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);
403 label = gtk_label_new ("Elevation");
404 gtk_widget_show (label);
405 gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
406 gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);
408 adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10);
409 gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation);
410 spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
411 gtk_widget_show (spin);
412 gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);
413 g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation);
415 adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10);
416 gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth);
417 spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
418 gtk_widget_show (spin);
419 gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE);
420 gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0);
422 label = gtk_label_new ("Azimuth");
423 gtk_widget_show (label);
424 gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);
425 gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0);
426 g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth);
429 frame = gtk_frame_new (NULL);
430 gtk_widget_show (frame);
431 gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
432 gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);
434 g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL);
436 gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK);
437 gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);
438 gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL);
439 gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event",
440 GTK_SIGNAL_FUNC (button_press), NULL);
442 gtk_widget_show (g_pPreviewWidget);
443 gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget);
446 gtk_widget_show (g_pWndPreview);
448 UpdatePreview (true);
451 //=============================================================
453 void DrawPreview (Rect rc)
455 #define COSXA 0.8660254037844
457 #define COSYA 0.8660254037844
465 char axis[3][2] = {"X","Y","Z"};
502 g_GLTable.m_pfn_qglLineWidth (1);
503 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
504 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
506 if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )
510 vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ));
511 for(i=0; i<gNumNodes; i++)
514 vv[i].p[j] = (double)(gNode[i].p[j]);
518 for(i=0; i<gNumTris; i++)
521 Scale(rc,vv[gTri[i].v[j]],&pt[j]);
523 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
524 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
525 g_GLTable.m_pfn_qglVertex2i (pt[1].x, pt[1].y);
526 g_GLTable.m_pfn_qglVertex2i (pt[2].x, pt[2].y);
527 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
528 g_GLTable.m_pfn_qglEnd ();
532 else if (Game==QUAKE3 && UsePatches!=0)
556 VectorCopy(xyz[i ][j ].p,uv[0][0].p);
557 VectorCopy(xyz[i+1][j ].p,uv[1][0].p);
558 VectorCopy(xyz[i+2][j ].p,uv[2][0].p);
559 VectorCopy(xyz[i ][j+1].p,uv[0][1].p);
560 VectorCopy(xyz[i+1][j+1].p,uv[1][1].p);
561 VectorCopy(xyz[i+2][j+1].p,uv[2][1].p);
562 VectorCopy(xyz[i ][j+2].p,uv[0][2].p);
563 VectorCopy(xyz[i+1][j+2].p,uv[1][2].p);
564 VectorCopy(xyz[i+2][j+2].p,uv[2][2].p);
565 uv[1][0].p[k] = (4*xyz[i+1][j ].p[k] - xyz[i ][j ].p[k] - xyz[i+2][j ].p[k])/2;
566 uv[0][1].p[k] = (4*xyz[i ][j+1].p[k] - xyz[i ][j ].p[k] - xyz[i ][j+2].p[k])/2;
567 uv[2][1].p[k] = (4*xyz[i+2][j+1].p[k] - xyz[i+2][j ].p[k] - xyz[i+2][j+2].p[k])/2;
568 uv[1][2].p[k] = (4*xyz[i+1][j+2].p[k] - xyz[i ][j+2].p[k] - xyz[i+2][j+2].p[k])/2;
569 uv[1][1].p[k] = (16*xyz[i+1][j+1].p[k] -
570 xyz[i ][j ].p[k] - 2*xyz[i+1][j ].p[k] - xyz[i+2][j ].p[k] -
571 2*xyz[i ][j+1].p[k] -2*xyz[i+2][j+1].p[k] -
572 xyz[i ][j+2].p[k] - 2*xyz[i+1][j+2].p[k] - xyz[i+2][j+2].p[k] )/4;
574 for(ii=0; ii<=SUBDIVS; ii++)
576 if(ii==0 || ii==SUBDIVS/2 || ii==SUBDIVS)
578 g_GLTable.m_pfn_qglLineWidth (1);
579 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
580 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
585 g_GLTable.m_pfn_qglLineWidth (1);
586 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
587 g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0);
588 g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE);
592 u = (float)(ii)/(float)(SUBDIVS);
593 for(jj=0; jj<3; jj++)
595 for(axis=0; axis<3; axis++)
599 a = (float)uv[0][jj].p[axis];
600 b = (float)uv[1][jj].p[axis];
601 c = (float)uv[2][jj].p[axis];
605 Ctrl[jj].p[axis] = qA * u * u + qB * u + qC;
608 VectorCopy(Ctrl[0].p,out.p);
610 Scale(rc,out,&pt[0]);
611 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
612 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
613 for(jj=1; jj<=SUBDIVS; jj++)
615 v = (float)(jj)/(float)(SUBDIVS);
616 for (axis = 0 ; axis < 3 ; axis++)
620 a = (float)Ctrl[0].p[axis];
621 b = (float)Ctrl[1].p[axis];
622 c = (float)Ctrl[2].p[axis];
626 out.p[axis] = qA * v * v + qB * v + qC;
629 Scale(rc,out,&pt[0]);
630 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
632 g_GLTable.m_pfn_qglEnd ();
634 for(jj=0; jj<=SUBDIVS; jj++)
636 if(jj==0 || jj==SUBDIVS/2 || jj==SUBDIVS)
638 g_GLTable.m_pfn_qglLineWidth (1);
639 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
640 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
645 g_GLTable.m_pfn_qglLineWidth (1);
646 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
647 g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0);
648 g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE);
652 v = (float)(jj)/(float)(SUBDIVS);
653 for(ii=0; ii<3; ii++)
655 for(axis=0; axis<3; axis++)
659 a = (float)uv[ii][0].p[axis];
660 b = (float)uv[ii][1].p[axis];
661 c = (float)uv[ii][2].p[axis];
665 Ctrl[ii].p[axis] = qA * v * v + qB * v + qC;
668 VectorCopy(Ctrl[0].p,out.p);
670 Scale(rc,out,&pt[0]);
671 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
672 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
673 for(ii=1; ii<=SUBDIVS; ii++)
675 u = (float)(ii)/(float)(SUBDIVS);
676 for (axis = 0 ; axis < 3 ; axis++)
680 a = (float)Ctrl[0].p[axis];
681 b = (float)Ctrl[1].p[axis];
682 c = (float)Ctrl[2].p[axis];
686 out.p[axis] = qA * u * u + qB * u + qC;
689 Scale(rc,out,&pt[0]);
690 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
692 g_GLTable.m_pfn_qglEnd ();
701 Scale(rc,xyz[i][0],&pt[0]);
702 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
703 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
706 Scale(rc,xyz[i][j],&pt[0]);
707 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
709 g_GLTable.m_pfn_qglEnd ();
713 Scale(rc,xyz[0][j],&pt[0]);
714 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
715 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
718 Scale(rc,xyz[i][j],&pt[0]);
719 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
721 g_GLTable.m_pfn_qglEnd ();
725 if(Game!=QUAKE3 || UsePatches==0)
727 // Draw lines from corners to base, and lines around base
728 for(i=0; i<=NH; i+=NH)
730 for(j=0; j<=NV; j+=NV)
732 VectorCopy(xyz[i][j].p, v[0].p);
737 v[0].p[1] = backface;
741 v[0].p[0] = backface;
744 v[0].p[2] = backface;
746 Scale(rc,xyz[i][j],&pt[0]);
750 Scale(rc,v[0],&pt[1]);
751 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
752 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
753 g_GLTable.m_pfn_qglVertex2i (pt[1].x, pt[1].y);
754 g_GLTable.m_pfn_qglEnd ();
757 VectorCopy(xyz[ 0][ 0].p, v[0].p);
758 VectorCopy(xyz[NH][ 0].p, v[1].p);
759 VectorCopy(xyz[NH][NV].p, v[2].p);
760 VectorCopy(xyz[ 0][NV].p, v[3].p);
765 v[0].p[1] = backface;;
766 v[1].p[1] = v[0].p[1];
767 v[2].p[1] = v[0].p[1];
768 v[3].p[1] = v[0].p[1];
772 v[0].p[0] = backface;
773 v[1].p[0] = v[0].p[0];
774 v[2].p[0] = v[0].p[0];
775 v[3].p[0] = v[0].p[0];
778 v[0].p[2] = backface;
779 v[1].p[2] = v[0].p[2];
780 v[2].p[2] = v[0].p[2];
781 v[3].p[2] = v[0].p[2];
786 Scale(rc,v[3],&pt[0]);
787 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
788 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
794 Scale(rc,v[i],&pt[1]);
795 g_GLTable.m_pfn_qglVertex2i (pt[1].x, pt[1].y);
797 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
798 g_GLTable.m_pfn_qglEnd ();
801 g_GLTable.m_pfn_qglLineWidth (1);
802 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
803 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
806 // Draw small depiction of coordinate axes
807 pt[0].x = rc.right - cxChar - cxChar/2 - cyChar;
808 pt[0].y = rc.bottom - cyChar/2 - cxChar/2;
809 pt[1].x = pt[0].x + (int)(cyChar*COSXA);
810 pt[1].y = pt[0].y - (int)(cyChar*SINXA);
811 MoveToEx(hdc,pt[0].x,pt[0].y,NULL);
812 LineTo(hdc,pt[1].x,pt[1].y);
813 SetTextAlign(hdc,TA_LEFT | TA_TOP);
814 TextOut(hdc,pt[1].x,pt[1].y-cyChar/2,"X",1);
815 pt[1].x = pt[0].x - (int)(cyChar*COSYA);
816 pt[1].y = pt[0].y - (int)(cyChar*SINYA);
817 MoveToEx(hdc,pt[0].x,pt[0].y,NULL);
818 LineTo(hdc,pt[1].x,pt[1].y);
819 SetTextAlign(hdc,TA_RIGHT | TA_TOP);
820 TextOut(hdc,pt[1].x,pt[1].y-cyChar/2,"Y",1);
822 pt[1].y = pt[0].y - cyChar;
823 MoveToEx(hdc,pt[0].x,pt[0].y,NULL);
824 LineTo(hdc,pt[1].x,pt[1].y);
825 SetTextAlign(hdc,TA_CENTER | TA_BOTTOM);
826 TextOut(hdc,pt[1].x,pt[1].y,"Z",1);
828 L = 2*(double)cyChar/SF;
844 Scale(rc,v[i],&pt[i]);
848 pt[i].x += -pt[0].x + rc.right - 2*cyChar;
849 pt[i].y += -pt[0].y + rc.bottom + 2*cyChar;
851 pt[0].x = rc.right - 2*cyChar;
852 pt[0].y = rc.bottom + 2*cyChar;
856 g_GLTable.m_pfn_qglBegin (GL_LINES);
857 g_GLTable.m_pfn_qglVertex2i (pt[0].x, pt[0].y);
858 g_GLTable.m_pfn_qglVertex2i (pt[i].x, pt[i].y);
859 g_GLTable.m_pfn_qglEnd ();
860 texfont_write (axis[i-1], pt[i].x-cxChar/2,pt[i].y+cyChar/2);
864 // Draw player model's bounding box in red to give a sense of scale
866 g_GLTable.m_pfn_qglLineWidth (2);
867 g_GLTable.m_pfn_qglColor3f (1, 0, 0);
868 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
873 v[0].p[0] = xyz[NH/2][NV/2].p[0] + PlayerBox[Game].x[0];
874 v[0].p[1] = xyz[NH/2][NV/2].p[1] + PlayerBox[Game].y[0];
875 v[0].p[2] = zmin - PlayerBox[Game].z[0] - 32;
878 v[0].p[0] = (xmax+xmin)/2 + PlayerBox[Game].x[0];
883 v[0].p[0] = (xmax+xmin)/2 + PlayerBox[Game].x[0];
889 v[0].p[1] = (ymax+ymin)/2 + PlayerBox[Game].y[0];
894 v[0].p[1] = (ymax+ymin)/2 + PlayerBox[Game].y[0];
898 // Put player on a node. For patches, put on an even numbered node.
899 if(Game==QUAKE3 && UsePatches!=0)
902 x = Hll + dh * (int)(NH/2 + 1);
904 x = Hll + dh * (int)(NH/2);
906 y = Vll + dv * (int)(NV/2 + 1);
908 y = Vll + dv * (int)(NV/2);
913 x = Hll + dh * (int)(NH/2);
917 y = Vll + dv * (int)(NV/2);
923 v[0].p[0] = x + PlayerBox[Game].x[0];
924 v[0].p[1] = y + PlayerBox[Game].y[0];
925 v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist
927 v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0];
928 v[1].p[1] = v[0].p[1];
929 v[1].p[2] = v[0].p[2];
930 v[2].p[0] = v[1].p[0];
931 v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0];
932 v[2].p[2] = v[0].p[2];
933 v[3].p[0] = v[0].p[0];
934 v[3].p[1] = v[2].p[1];
935 v[3].p[2] = v[0].p[2];
936 VectorCopy(v[0].p,v[4].p);
937 VectorCopy(v[1].p,v[5].p);
938 VectorCopy(v[2].p,v[6].p);
939 VectorCopy(v[3].p,v[7].p);
940 v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
941 v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
942 v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
943 v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
949 Scale(rc,v[i],&pt[i]);
951 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
952 g_GLTable.m_pfn_qglVertex2i (pt[3].x, pt[3].y);
954 g_GLTable.m_pfn_qglVertex2i (pt[i].x, pt[i].y);
955 g_GLTable.m_pfn_qglEnd ();
956 g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);
957 g_GLTable.m_pfn_qglVertex2i (pt[7].x, pt[7].y);
959 g_GLTable.m_pfn_qglVertex2i (pt[i].x, pt[i].y);
960 g_GLTable.m_pfn_qglEnd ();
961 g_GLTable.m_pfn_qglBegin (GL_LINES);
964 g_GLTable.m_pfn_qglVertex2i (pt[i].x,pt[i].y);
965 g_GLTable.m_pfn_qglVertex2i (pt[i+4].x,pt[i+4].y);
967 g_GLTable.m_pfn_qglEnd ();
969 g_GLTable.m_pfn_qglLineWidth (1);
970 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
971 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
973 //=============================================================
974 void DrawGrid(Rect rc)
981 w = (double)(rc.right-rc.left+1) - cxChar;
982 h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar;
985 SFG = min(SFG, h/(Vur-Vll));
988 X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2;
989 Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2;
991 g_GLTable.m_pfn_qglLineWidth (2);
992 g_GLTable.m_pfn_qglColor3f (0, 1, 0);
993 g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);
996 pt[1].y = Y0G + (int)(SFG*(Vur-Vll));
997 g_GLTable.m_pfn_qglBegin (GL_LINES);
1001 pt[0].x = X0G + (int)(SFG*(x-Hll));
1002 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
1003 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[1].y);
1005 g_GLTable.m_pfn_qglEnd ();
1007 pt[1].x = X0G + (int)(SFG*(Hur-Hll));
1008 g_GLTable.m_pfn_qglBegin (GL_LINES);
1009 for(i=0; i<=NV; i++)
1012 pt[0].y = Y0G + (int)(SFG*(Vur-y));
1013 g_GLTable.m_pfn_qglVertex2i (pt[0].x,pt[0].y);
1014 g_GLTable.m_pfn_qglVertex2i (pt[1].x,pt[0].y);
1016 g_GLTable.m_pfn_qglEnd ();
1018 g_GLTable.m_pfn_qglLineWidth (1);
1021 pt[0].x = rc.right - cyChar - cxChar - cyChar/2;
1022 pt[0].y = rc.bottom + cyChar/2;
1023 pt[1].x = pt[0].x + cyChar;
1025 g_GLTable.m_pfn_qglBegin (GL_LINES);
1026 g_GLTable.m_pfn_qglVertex2i (pt[0].x,pt[0].y);
1027 g_GLTable.m_pfn_qglVertex2i (pt[1].x,pt[1].y);
1028 g_GLTable.m_pfn_qglEnd ();
1033 texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2);
1036 texfont_write ("X", pt[1].x, pt[1].y+cyChar/2);
1039 pt[1].y = pt[0].y + cyChar;
1040 g_GLTable.m_pfn_qglBegin (GL_LINES);
1041 g_GLTable.m_pfn_qglVertex2i (pt[0].x,pt[0].y);
1042 g_GLTable.m_pfn_qglVertex2i (pt[1].x,pt[1].y);
1043 g_GLTable.m_pfn_qglEnd ();
1048 texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar);
1051 texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar);
1054 // Denote fixed points with a 5x5 red rectangle
1055 for(i=0; i<=NH; i++)
1057 for(j=0; j<=NV; j++)
1063 rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2;
1064 rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2;
1065 rcBox.right = rcBox.left + 5;
1066 rcBox.bottom = rcBox.top - 5;
1068 DRAW_QUAD (rcBox, 1,0,0);
1073 // Denote currently selected point with a 5x5 green rectangle
1074 if (NumVerticesSelected)
1076 for(k=0; k<NumVerticesSelected; k++)
1078 x = Hll + Vertex[k].i*dh;
1079 y = Vll + Vertex[k].j*dv;
1080 rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2;
1081 rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2;
1082 rcBox.right = rcBox.left + 5;
1083 rcBox.bottom = rcBox.top - 5;
1085 DRAW_QUAD (rcBox, 0,1,0);
1089 // Unmovable vertices
1090 for(i=0; i<=NH; i++)
1092 for(j=0; j<=NV; j++)
1098 rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2;
1099 rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2;
1100 rcBox.right = rcBox.left + 5;
1101 rcBox.bottom = rcBox.top - 5;
1103 DRAW_QUAD (rcBox, 1,1,0);
1109 rcBox.left = rc.left + cxChar/2 - 2;
1110 rcBox.top = rc.top - cyChar/2 - 2;
1111 rcBox.right = rcBox.left + 5;
1112 rcBox.bottom = rcBox.top - 5;
1113 DRAW_QUAD (rcBox, 1,0,0);
1114 texfont_write ("Fixed points", rcBox.right+cxChar,rcBox.top-4+cyChar/2);
1116 rcBox.top -= cyChar;
1117 rcBox.bottom -= cyChar;
1118 DRAW_QUAD (rcBox, 1,1,0);
1119 texfont_write ("Not movable", rcBox.right+cxChar, rcBox.top-4+cyChar/2);
1121 rcBox.top -= cyChar;
1122 rcBox.bottom -= cyChar;
1123 DRAW_QUAD (rcBox, 0,1,0);
1124 texfont_write ("Selected", rcBox.right+cxChar, rcBox.top-4+cyChar/2);
1127 //=============================================================
1128 void GetScaleFactor(Rect rc)
1133 w = (double)(rc.right-rc.left+1) - cxChar;
1134 h = (double)(rc.top-rc.bottom+1) - cxChar;
1136 SF = w/( (XHi-XLo)*COSXA + (YHi-YLo)*COSYA );
1137 SF = min(SF, h/( (XHi-XLo)*SINXA + (YHi-YLo)*SINYA + ZHi-ZLo ) );
1139 X0 = (int)(rc.left + rc.right - (int)(SF*( (XHi-XLo)*COSXA + (YHi-YLo)*COSYA )) )/2;
1140 Y0 = (int)(rc.top + rc.bottom - (int)(SF*( (XHi-XLo)*SINXA + (YHi-YLo)*SINYA + ZHi-ZLo) ))/2;
1145 w = (double)(rc.right-rc.left+1) - cxChar;
1146 h = (double)(rc.top-rc.bottom+1) - cxChar;
1149 SF = min(SF, h/(Vhi-Vlo) );
1150 X0 = (int)(rc.left + rc.right - (int)(SF*(Hhi-Hlo)))/2;
1151 Y0 = (int)(rc.top + rc.bottom + (int)(SF*(Vhi-Vlo)))/2;
1155 //=============================================================
1156 void Scale(Rect rc,XYZ xyz,Point *pt)
1161 pt[0].x = X0 + (int)(SF*( (xyz.p[0]-XLo)*COSXA +
1162 (YHi-xyz.p[1])*COSYA ));
1163 pt[0].y = Y0 + (int)(SF*( ZHi-xyz.p[2] +
1164 (YHi-xyz.p[1])*SINYA +
1165 (XHi-xyz.p[0])*SINXA ));
1167 pt[0].x = X0 + (int)(SF*( xyz.pp[0] - Hlo ) );
1168 pt[0].y = Y0 - (int)(SF*( Vhi - xyz.pp[1] ) );
1174 /* ======================================================================= */
1175 void project(XYZ *v)
1177 // project a 3D point (x,y,z) onto view plane
1178 double x, y, z, xa, ya, za;
1185 xa = ct[0]*x - st[0]*z;
1186 za = st[0]*x + ct[0]*z;
1189 x = ct[1]*xa + st[1]*y;
1190 ya = ct[1]*y - st[1]*xa;
1193 z = ct[2]*za - st[2]*ya;
1194 y = ct[2]*ya + st[2]*za;
1196 // horizontal and vertical projections:
1197 // v->pp[0] = D*x/z;
1198 // v->pp[1] = D*y/z;
1203 // NOTE: if perspective transformation is desired,
1204 // set "persp" to the range from the surface,
1206 // v->projected_h = -v->projected_h * persp/(v->projected_z-persp);
1207 // v->projected_v = -v->projected_v * persp/(v->projected_z-persp);
1209 /*=======================================================================*/
1215 if(elevation > PI) elevation -= 2.*PI;
1216 roll = elevation * sin(azimuth);
1217 yaw = 1.5*PI + elevation*cos(azimuth);
1219 // Find angles from midpoint to viewpoint:
1222 st[2] = sin(azimuth);
1225 ct[2] = cos(azimuth);
1227 for(i=0; i<=NH; i++)
1229 for(j=0; j<=NV; j++)
1231 project(&xyz[i][j]);
1235 Hhi = xyz[0][0].pp[0];
1237 Vhi = xyz[0][0].pp[1];
1239 for(i=0; i<=NH; i++)
1241 for(j=0; j<=NV; j++)
1243 Hlo = min(Hlo,xyz[i][j].pp[0]);
1244 Hhi = max(Hhi,xyz[i][j].pp[0]);
1245 Vlo = min(Vlo,xyz[i][j].pp[1]);
1246 Vhi = max(Vhi,xyz[i][j].pp[1]);
1250 // Include backface in min-max
1251 VectorCopy(xyz[ 0][ 0].p,v[0].p);
1252 VectorCopy(xyz[NH][ 0].p,v[1].p);
1253 VectorCopy(xyz[NH][NV].p,v[2].p);
1254 VectorCopy(xyz[ 0][NV].p,v[3].p);
1259 v[0].p[1] = backface;
1260 v[1].p[1] = v[0].p[1];
1261 v[2].p[1] = v[0].p[1];
1262 v[3].p[1] = v[0].p[1];
1266 v[0].p[0] = backface;
1267 v[1].p[0] = v[0].p[0];
1268 v[2].p[0] = v[0].p[0];
1269 v[3].p[0] = v[0].p[0];
1272 v[0].p[2] = backface;
1273 v[1].p[2] = v[0].p[2];
1274 v[2].p[2] = v[0].p[2];
1275 v[3].p[2] = v[0].p[2];
1280 Hlo = min(Hlo,v[i].pp[0]);
1281 Hhi = max(Hhi,v[i].pp[0]);
1282 Vlo = min(Vlo,v[i].pp[1]);
1283 Vhi = max(Vhi,v[i].pp[1]);