]> de.git.xonotic.org Git - xonotic/netradiant.git/blob - contrib/gtkgensurf/view.cpp
transfer from internal tree r5311 branches/1.4-gpl
[xonotic/netradiant.git] / contrib / gtkgensurf / view.cpp
1 /*\r
2 GenSurf plugin for GtkRadiant\r
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com\r
4 \r
5 This library is free software; you can redistribute it and/or\r
6 modify it under the terms of the GNU Lesser General Public\r
7 License as published by the Free Software Foundation; either\r
8 version 2.1 of the License, or (at your option) any later version.\r
9 \r
10 This library is distributed in the hope that it will be useful,\r
11 but WITHOUT ANY WARRANTY; without even the implied warranty of\r
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
13 Lesser General Public License for more details.\r
14 \r
15 You should have received a copy of the GNU Lesser General Public\r
16 License along with this library; if not, write to the Free Software\r
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA\r
18 */\r
19 \r
20 #include <math.h>\r
21 #include <stdio.h>\r
22 #include <stdlib.h>\r
23 #include "gensurf.h"\r
24 \r
25 #undef ISOMETRIC\r
26 \r
27 extern double backface;\r
28 extern double dh, dv;\r
29 extern double xmin,xmax,ymin,ymax,zmin,zmax;\r
30 \r
31 double    SF, SFG;         // Graphics scale factors\r
32 double    XLo, XHi, YLo, YHi, ZLo, ZHi;\r
33 double    yaw,roll;\r
34 double    elevation,azimuth;\r
35 int       cxChar = 10, cyChar = 16;\r
36 int       X0, Y0;\r
37 int       X0G, Y0G;\r
38 \r
39 static RECT rcCoord;   // where X= Y= is drawn\r
40 static RECT rcGrid;    // rectangle within rcLower that forms the border of the grid, plus\r
41                        //   a 3 pixel slop.\r
42 static RECT rcLower;   // lower half of window, where plan view is drawn\r
43 static RECT rcUpper;   // upper half or entire window, where isometric projection is drawn\r
44 \r
45 void vertex_selected ();\r
46 void texfont_init ();\r
47 void texfont_write (const char *text, float l, float t);\r
48 \r
49 #define PEN_GRID { \\r
50   g_GLTable.m_pfn_qglLineWidth (1); \\r
51   g_GLTable.m_pfn_qglColor3f (0, 1, 0); \\r
52   g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); }\r
53 \r
54 #define PEN_RED { \\r
55   g_GLTable.m_pfn_qglLineWidth (2); \\r
56   g_GLTable.m_pfn_qglColor3f (1, 0, 0); \\r
57   g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); }\r
58 \r
59 #define PEN_DASH { \\r
60   g_GLTable.m_pfn_qglLineWidth (1); \\r
61   g_GLTable.m_pfn_qglColor3f (0, 1, 0); \\r
62   g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \\r
63   g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); }\r
64 \r
65 #define DRAW_QUAD(rc,r,g,b) { \\r
66   g_GLTable.m_pfn_qglBegin (GL_QUADS); \\r
67   g_GLTable.m_pfn_qglColor3f (0,1,0); \\r
68   g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.bottom); \\r
69   g_GLTable.m_pfn_qglVertex2f (rc.right, rc.bottom); \\r
70   g_GLTable.m_pfn_qglVertex2f (rc.right, rc.top+1); \\r
71   g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.top+1); \\r
72   g_GLTable.m_pfn_qglColor3f (r,g,b); \\r
73   g_GLTable.m_pfn_qglVertex2f (rc.left, rc.bottom+1); \\r
74   g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.bottom+1); \\r
75   g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.top); \\r
76   g_GLTable.m_pfn_qglVertex2f (rc.left, rc.top); \\r
77   g_GLTable.m_pfn_qglEnd (); }\r
78 \r
79 \r
80 #ifndef ISOMETRIC\r
81 double    D=65536.;\r
82 double    ct[3],st[3];\r
83 double    Hhi, Hlo, Vhi, Vlo;\r
84 #endif\r
85 \r
86 #define SUBDIVS 6\r
87 \r
88 \r
89 void ShowPreview ()\r
90 {\r
91   if (Preview)\r
92   {\r
93     if (g_pWndPreview == NULL)\r
94       CreateViewWindow ();\r
95     gtk_widget_show (g_pWndPreview);\r
96 \r
97     UpdatePreview (true);\r
98   }\r
99   else\r
100     gtk_widget_hide (g_pWndPreview);\r
101 }\r
102 \r
103 static void draw_preview ()\r
104 {\r
105   int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height;\r
106 \r
107   g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1);\r
108   g_GLTable.m_pfn_qglViewport (0, 0, width, height);\r
109   g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION);\r
110   g_GLTable.m_pfn_qglLoadIdentity ();\r
111   g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1);\r
112   g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);\r
113         \r
114         // ^Fishman - Antializing for the preview window.\r
115         if (Antialiasing)\r
116         {\r
117                 g_GLTable.m_pfn_qglEnable(GL_BLEND);\r
118                 g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
119                 g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH);\r
120         }\r
121         else\r
122         {\r
123                 g_GLTable.m_pfn_qglDisable(GL_BLEND);\r
124                 g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH);\r
125         }\r
126 \r
127   texfont_init ();\r
128 \r
129   if (!ValidSurface ())\r
130     return;\r
131 \r
132   rcUpper.left = 0;\r
133   rcUpper.right = width;\r
134   rcUpper.bottom = 0;\r
135   rcUpper.top = height;\r
136   rcLower.left = 0;\r
137   rcLower.right = width;\r
138   rcLower.bottom = 0;\r
139   rcLower.top = height;\r
140 \r
141   if (VertexMode)\r
142   {\r
143     rcUpper.bottom = rcUpper.top/2;\r
144     DrawPreview (rcUpper);\r
145     g_GLTable.m_pfn_qglBegin (GL_LINES);\r
146     g_GLTable.m_pfn_qglVertex2f (rcUpper.left, rcUpper.bottom);\r
147     g_GLTable.m_pfn_qglVertex2f (rcUpper.right, rcUpper.bottom);\r
148     g_GLTable.m_pfn_qglEnd ();\r
149     rcLower.top = rcUpper.bottom-1;\r
150     DrawGrid (rcLower);\r
151     rcCoord.left = rcLower.left;\r
152     rcCoord.right = rcLower.right;\r
153     rcCoord.bottom = rcLower.bottom;\r
154     rcCoord.top = rcLower.top;\r
155     rcCoord.top = rcCoord.bottom+cyChar;\r
156     rcCoord.right = rcCoord.left + 15*cxChar;\r
157     rcGrid.left   = X0G - 3;\r
158     rcGrid.bottom = Y0G - 3;\r
159     rcGrid.right  = X0G + (int)(SFG*(Hur-Hll)) + 3;\r
160     rcGrid.top    = Y0G + (int)(SFG*(Vur-Vll)) + 3;\r
161   }\r
162   else\r
163     DrawPreview (rcUpper);\r
164 }\r
165 \r
166 static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)\r
167 {\r
168   if (event->count > 0)\r
169     return TRUE;\r
170 \r
171   if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget))\r
172   {\r
173     g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n");\r
174     return TRUE;\r
175   }\r
176 \r
177   draw_preview ();\r
178 \r
179   g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget);\r
180   g_GLTable.m_pfn_QE_CheckOpenGLForErrors ();\r
181 \r
182   return TRUE;\r
183 }\r
184 \r
185 static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)\r
186 {\r
187   POINT pt = { (long)event->x, widget->allocation.height - (long)event->y };\r
188   bool        Selected;\r
189   double      x,y;\r
190   int         i, j, k, ks;\r
191   int         i0, i1, j0, j1;\r
192 \r
193   if ((!VertexMode) || (event->button != 1))\r
194     return;\r
195 \r
196   if (!PtInRect (&rcGrid,pt))\r
197   {\r
198     gdk_beep ();\r
199     return;\r
200   }\r
201 \r
202   x = Hll + (pt.x-X0G)/SFG;\r
203   y = Vur - (pt.y-Y0G)/SFG;\r
204   i = (int)(floor( (x-Hll)/dh - 0.5) + 1);\r
205   j = (int)(floor( (y-Vll)/dv - 0.5) + 1);\r
206   if (i < 0 || i > NH || j < 0 || j > NV)\r
207   {\r
208     gdk_beep ();\r
209     return;\r
210   }\r
211 \r
212   if(!CanEdit(i,j))\r
213   {\r
214     gdk_beep ();\r
215     return;\r
216   }\r
217 \r
218   // Control key pressed - add this point, or remove it if already selected\r
219   if ((event->state & GDK_CONTROL_MASK) != 0)\r
220   {\r
221     Selected = FALSE;\r
222     if (NumVerticesSelected)\r
223     {\r
224       for (k=0; k<NumVerticesSelected && !Selected; k++)\r
225       {\r
226         if(Vertex[k].i == i && Vertex[k].j == j)\r
227         {\r
228           Selected = TRUE;\r
229           ks = k;\r
230         }\r
231       }\r
232     }\r
233 \r
234     // Already selected - unselect it.\r
235     if (Selected)\r
236     {\r
237       if (ks < NumVerticesSelected)\r
238       {\r
239         for (k=ks;k<NumVerticesSelected-1;k++)\r
240         {\r
241           Vertex[k].i = Vertex[k+1].i;\r
242           Vertex[k].j = Vertex[k+1].j;\r
243         }\r
244         NumVerticesSelected--;\r
245       }\r
246     }\r
247     else\r
248     {\r
249       Vertex[NumVerticesSelected].i = i;\r
250       Vertex[NumVerticesSelected].j = j;\r
251       NumVerticesSelected++;\r
252     }\r
253   }\r
254   else if ((event->state & GDK_SHIFT_MASK) != 0)\r
255   {\r
256     if (NumVerticesSelected)\r
257     {\r
258       NumVerticesSelected = 1;\r
259       i0 = min(Vertex[0].i, i);\r
260       i1 = max(Vertex[0].i, i);\r
261       j0 = min(Vertex[0].j, j);\r
262       j1 = max(Vertex[0].j, j);\r
263       for(i=i0; i<=i1; i++)\r
264       {\r
265         for(j=j0; j<=j1; j++)\r
266         {\r
267           if(i==0  && j==0 ) continue;\r
268           if(i==NH && j==0 ) continue;\r
269           if(i==0  && j==NV) continue;\r
270           if(i==NH && j==NV) continue;\r
271           if(i != Vertex[0].i || j != Vertex[0].j)\r
272           {\r
273             Vertex[NumVerticesSelected].i = i;\r
274             Vertex[NumVerticesSelected].j = j;\r
275             NumVerticesSelected++;\r
276           }\r
277         }\r
278       }\r
279     }\r
280     else\r
281     {\r
282       Vertex[0].i = i;\r
283       Vertex[0].j = j;\r
284       NumVerticesSelected = 1;\r
285     }\r
286   }\r
287   else\r
288   {\r
289     Vertex[0].i = i;\r
290     Vertex[0].j = j;\r
291     NumVerticesSelected = 1;\r
292   }\r
293 \r
294   vertex_selected ();\r
295 }\r
296 \r
297 static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)\r
298 {\r
299   POINT pt = { (long)event->x, widget->allocation.height - (long)event->y };\r
300 \r
301   if (!VertexMode)\r
302     return;\r
303 \r
304   if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget))\r
305   {\r
306     g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n");\r
307     return;\r
308   }\r
309 \r
310   g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST);\r
311   g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left,\r
312                               rcCoord.top-rcCoord.bottom);\r
313   g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT);\r
314 \r
315   if (PtInRect(&rcGrid,pt))\r
316   {\r
317     GdkCursor *cursor = gdk_cursor_new (GDK_CROSS);\r
318     gdk_window_set_cursor (g_pWndPreview->window, cursor);\r
319     gdk_cursor_unref (cursor);\r
320 \r
321     char Text[32];\r
322     int x, y;\r
323 \r
324     x = (int)(Hll + (pt.x-X0G)/SFG);\r
325     y = (int)(Vur - (pt.y-Y0G)/SFG);\r
326     switch(Plane)\r
327     {\r
328     case PLANE_XZ0:\r
329     case PLANE_XZ1:\r
330       sprintf(Text," x=%d, z=%d   ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );\r
331       break;\r
332     case PLANE_YZ0:\r
333     case PLANE_YZ1:\r
334       sprintf(Text," y=%d, z=%d   ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );\r
335       break;\r
336     default:\r
337       sprintf(Text," x=%d, y=%d   ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );\r
338     }\r
339 \r
340     texfont_write (Text, rcCoord.left, rcCoord.top);\r
341   }\r
342   else\r
343   {\r
344     gdk_window_set_cursor (g_pWndPreview->window, NULL);\r
345   }\r
346 \r
347   g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget);\r
348   g_GLTable.m_pfn_QE_CheckOpenGLForErrors ();\r
349   g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST);\r
350 }\r
351 \r
352 static gint preview_close (GtkWidget *widget, gpointer data)\r
353 {\r
354   gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE);\r
355   return TRUE;\r
356 }\r
357 \r
358 static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data)\r
359 {\r
360   *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360));\r
361   UpdatePreview (false);\r
362 }\r
363 \r
364 static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data)\r
365 {\r
366   preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast<double*>(data));\r
367   return FALSE;\r
368 }\r
369 \r
370 static void preview_spin (GtkAdjustment *adj, double *data)\r
371 {\r
372   *data = DegreesToRadians (adj->value);\r
373   UpdatePreview (false);\r
374 }\r
375 \r
376 void CreateViewWindow ()\r
377 {\r
378   GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame;\r
379   GtkObject *adj;\r
380 \r
381 #ifndef ISOMETRIC\r
382   elevation = PI/6.;\r
383   azimuth   = PI/6.;\r
384 #endif\r
385 \r
386   g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);\r
387   gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview");\r
388   gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL);\r
389   gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);\r
390   gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd));\r
391   gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400);\r
392 \r
393   vbox = gtk_vbox_new (FALSE, 5);\r
394   gtk_widget_show (vbox);\r
395   gtk_container_add (GTK_CONTAINER (dlg), vbox);\r
396 \r
397 #ifndef ISOMETRIC\r
398   hbox = gtk_hbox_new (TRUE, 5);\r
399   gtk_widget_show (hbox);\r
400   gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);\r
401   gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);\r
402 \r
403   label = gtk_label_new ("Elevation");\r
404   gtk_widget_show (label);\r
405   gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);\r
406   gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);\r
407 \r
408   adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10);\r
409   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation);\r
410   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);\r
411   gtk_widget_show (spin);\r
412   gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);\r
413   g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation);\r
414 \r
415   adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10);\r
416   gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth);\r
417   spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);\r
418   gtk_widget_show (spin);\r
419   gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE);\r
420   gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0);\r
421 \r
422   label = gtk_label_new ("Azimuth");\r
423   gtk_widget_show (label);\r
424   gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);\r
425   gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0);\r
426   g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth);\r
427 #endif\r
428 \r
429   frame = gtk_frame_new (NULL);\r
430   gtk_widget_show (frame);\r
431   gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);\r
432   gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);\r
433 \r
434   g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL);\r
435 \r
436   gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK);\r
437   gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);\r
438   gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL);\r
439   gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event",\r
440                       GTK_SIGNAL_FUNC (button_press), NULL);\r
441 \r
442   gtk_widget_show (g_pPreviewWidget);\r
443   gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget);\r
444 \r
445   if (Preview)\r
446     gtk_widget_show (g_pWndPreview);\r
447 \r
448   UpdatePreview (true);\r
449 }\r
450 \r
451 //=============================================================\r
452 /* DrawPreview */\r
453 void DrawPreview (RECT rc)\r
454 {\r
455 #define COSXA 0.8660254037844\r
456 #define SINXA 0.5\r
457 #define COSYA 0.8660254037844\r
458 #define SINYA 0.5\r
459 \r
460   double     L;\r
461   double     x,y;\r
462   int        i, j;\r
463   POINT      pt[8];\r
464   XYZ        v[8];\r
465   char axis[3][2] = {"X","Y","Z"};\r
466 \r
467 #ifndef ISOMETRIC\r
468   evaluate();\r
469 #endif\r
470 \r
471   XLo = xmin;\r
472   XHi = xmax;\r
473   YLo = ymin;\r
474   YHi = ymax;\r
475   ZLo = zmin;\r
476   ZHi = zmax;\r
477   switch (Plane)\r
478   {\r
479   case PLANE_XY1:\r
480     ZHi = backface;\r
481     break;\r
482   case PLANE_XZ0:\r
483     YLo = backface;\r
484     break;\r
485   case PLANE_XZ1:\r
486     YHi = backface;\r
487     break;\r
488   case PLANE_YZ0:\r
489     XLo = backface;\r
490     break;\r
491   case PLANE_YZ1:\r
492     XHi = backface;\r
493     break;\r
494   default:\r
495     ZLo = backface;\r
496   }\r
497 \r
498 \r
499 \r
500   GetScaleFactor(rc);\r
501         //PEN_GRID\r
502         g_GLTable.m_pfn_qglLineWidth (1);\r
503         g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
504         g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
505 \r
506     if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )\r
507     {\r
508       XYZ  *vv;\r
509 \r
510       vv   = (XYZ *) malloc(gNumNodes * sizeof(XYZ));\r
511       for(i=0; i<gNumNodes; i++)\r
512       {\r
513         for(j=0; j<3; j++)\r
514           vv[i].p[j] = (double)(gNode[i].p[j]);\r
515         project(&vv[i]);\r
516       }\r
517 \r
518       for(i=0; i<gNumTris; i++)\r
519       {\r
520         for(j=0; j<3; j++)\r
521           Scale(rc,vv[gTri[i].v[j]],&pt[j]);\r
522 \r
523         g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
524         g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
525         g_GLTable.m_pfn_qglVertex2f (pt[1].x, pt[1].y);\r
526         g_GLTable.m_pfn_qglVertex2f (pt[2].x, pt[2].y);\r
527         g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
528         g_GLTable.m_pfn_qglEnd ();\r
529       }\r
530       free(vv);\r
531     }\r
532     else if (Game==QUAKE3 && UsePatches!=0)\r
533     {\r
534       int               axis, ii, jj, k;\r
535       float     u, v;\r
536       XYZ               uv[3][3];\r
537       XYZ               Ctrl[3],out;\r
538 \r
539       switch (Plane)\r
540       {\r
541       case PLANE_XY0:\r
542       case PLANE_XY1:\r
543         k = 2;\r
544         break;\r
545       case PLANE_XZ0:\r
546       case PLANE_XZ1:\r
547         k = 1;\r
548         break;\r
549       default:\r
550         k = 0;\r
551       }\r
552       for(i=0; i<NH; i+=2)\r
553       {\r
554         for(j=0; j<NV; j+=2)\r
555         {\r
556           VectorCopy(xyz[i  ][j  ].p,uv[0][0].p);\r
557           VectorCopy(xyz[i+1][j  ].p,uv[1][0].p);\r
558           VectorCopy(xyz[i+2][j  ].p,uv[2][0].p);\r
559           VectorCopy(xyz[i  ][j+1].p,uv[0][1].p);\r
560           VectorCopy(xyz[i+1][j+1].p,uv[1][1].p);\r
561           VectorCopy(xyz[i+2][j+1].p,uv[2][1].p);\r
562           VectorCopy(xyz[i  ][j+2].p,uv[0][2].p);\r
563           VectorCopy(xyz[i+1][j+2].p,uv[1][2].p);\r
564           VectorCopy(xyz[i+2][j+2].p,uv[2][2].p);\r
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;\r
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;\r
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;\r
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;\r
569           uv[1][1].p[k] = (16*xyz[i+1][j+1].p[k] -\r
570                            xyz[i  ][j  ].p[k] - 2*xyz[i+1][j  ].p[k] -  xyz[i+2][j  ].p[k] -\r
571                            2*xyz[i  ][j+1].p[k]                        -2*xyz[i+2][j+1].p[k] -\r
572                            xyz[i  ][j+2].p[k] - 2*xyz[i+1][j+2].p[k] -  xyz[i+2][j+2].p[k]   )/4;\r
573 \r
574           for(ii=0; ii<=SUBDIVS; ii++)\r
575           {\r
576             if(ii==0 || ii==SUBDIVS/2 || ii==SUBDIVS)\r
577                                                 {\r
578                                                         g_GLTable.m_pfn_qglLineWidth (1);\r
579                                                         g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
580                                                         g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
581                                                         // PEN_GRID\r
582                                                 }\r
583             else\r
584                                                 {\r
585                                                         g_GLTable.m_pfn_qglLineWidth (1);\r
586                                                         g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
587                                                         g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0);\r
588                                                         g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE);\r
589               // PEN_DASH\r
590                                                 }\r
591 \r
592             u = (float)(ii)/(float)(SUBDIVS);\r
593             for(jj=0; jj<3; jj++)\r
594             {\r
595               for(axis=0; axis<3; axis++)\r
596               {\r
597                 float   a, b, c;\r
598                 float   qA, qB, qC;\r
599                 a = (float)uv[0][jj].p[axis];\r
600                 b = (float)uv[1][jj].p[axis];\r
601                 c = (float)uv[2][jj].p[axis];\r
602                 qA = a - 2 * b + c;\r
603                 qB = 2 * b - 2 * a;\r
604                 qC = a;\r
605                 Ctrl[jj].p[axis] = qA * u * u + qB * u + qC;\r
606               }\r
607             }\r
608             VectorCopy(Ctrl[0].p,out.p);\r
609             project(&out);\r
610             Scale(rc,out,&pt[0]);\r
611             g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
612             g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
613             for(jj=1; jj<=SUBDIVS; jj++)\r
614             {\r
615               v = (float)(jj)/(float)(SUBDIVS);\r
616               for (axis = 0 ; axis < 3 ; axis++) \r
617               {\r
618                 float   a, b, c;\r
619                 float   qA, qB, qC;\r
620                 a = (float)Ctrl[0].p[axis];\r
621                 b = (float)Ctrl[1].p[axis];\r
622                 c = (float)Ctrl[2].p[axis];\r
623                 qA = a - 2 * b + c;\r
624                 qB = 2 * b - 2 * a;\r
625                 qC = a;\r
626                 out.p[axis] = qA * v * v + qB * v + qC;\r
627               }\r
628               project(&out);\r
629               Scale(rc,out,&pt[0]);\r
630               g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
631             }\r
632             g_GLTable.m_pfn_qglEnd ();\r
633           }\r
634           for(jj=0; jj<=SUBDIVS; jj++)\r
635           {\r
636             if(jj==0 || jj==SUBDIVS/2 || jj==SUBDIVS)\r
637                                                 {\r
638                                                         g_GLTable.m_pfn_qglLineWidth (1);\r
639                                                         g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
640                                                         g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
641               // PEN_GRID\r
642                                                 }\r
643             else\r
644                                                 {\r
645                                                         g_GLTable.m_pfn_qglLineWidth (1);\r
646                                                         g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
647                                                         g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0);\r
648                                                         g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE);\r
649                                                         // PEN_DASH\r
650                                                 }\r
651 \r
652             v = (float)(jj)/(float)(SUBDIVS);\r
653             for(ii=0; ii<3; ii++)\r
654             {\r
655               for(axis=0; axis<3; axis++)\r
656               {\r
657                 float   a, b, c;\r
658                 float   qA, qB, qC;\r
659                 a = (float)uv[ii][0].p[axis];\r
660                 b = (float)uv[ii][1].p[axis];\r
661                 c = (float)uv[ii][2].p[axis];\r
662                 qA = a - 2 * b + c;\r
663                 qB = 2 * b - 2 * a;\r
664                 qC = a;\r
665                 Ctrl[ii].p[axis] = qA * v * v + qB * v + qC;\r
666               }\r
667             }\r
668             VectorCopy(Ctrl[0].p,out.p);\r
669             project(&out);\r
670             Scale(rc,out,&pt[0]);\r
671             g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
672             g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
673             for(ii=1; ii<=SUBDIVS; ii++)\r
674             {\r
675               u = (float)(ii)/(float)(SUBDIVS);\r
676               for (axis = 0 ; axis < 3 ; axis++) \r
677               {\r
678                 float   a, b, c;\r
679                 float   qA, qB, qC;\r
680                 a = (float)Ctrl[0].p[axis];\r
681                 b = (float)Ctrl[1].p[axis];\r
682                 c = (float)Ctrl[2].p[axis];\r
683                 qA = a - 2 * b + c;\r
684                 qB = 2 * b - 2 * a;\r
685                 qC = a;\r
686                 out.p[axis] = qA * u * u + qB * u + qC;\r
687               }\r
688               project(&out);\r
689               Scale(rc,out,&pt[0]);\r
690               g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
691             }\r
692             g_GLTable.m_pfn_qglEnd ();\r
693           }\r
694         }\r
695       }\r
696     }\r
697     else\r
698     {\r
699       for(i=0; i<=NH; i++)\r
700       {\r
701         Scale(rc,xyz[i][0],&pt[0]);\r
702         g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
703         g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
704         for(j=1; j<=NV; j++)\r
705         {\r
706           Scale(rc,xyz[i][j],&pt[0]);\r
707           g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
708         }\r
709         g_GLTable.m_pfn_qglEnd ();\r
710       }\r
711       for(j=0; j<=NV; j++)\r
712       {\r
713         Scale(rc,xyz[0][j],&pt[0]);\r
714         g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
715         g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
716         for(i=1; i<=NH; i++)\r
717         {\r
718           Scale(rc,xyz[i][j],&pt[0]);\r
719           g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
720         }\r
721         g_GLTable.m_pfn_qglEnd ();\r
722       }\r
723     }\r
724 \r
725   if(Game!=QUAKE3 || UsePatches==0)\r
726   {\r
727     // Draw lines from corners to base, and lines around base\r
728     for(i=0; i<=NH; i+=NH)\r
729     {\r
730       for(j=0; j<=NV; j+=NV)\r
731       {\r
732         VectorCopy(xyz[i][j].p, v[0].p);\r
733         switch(Plane)\r
734         {\r
735         case PLANE_XZ0:\r
736         case PLANE_XZ1:\r
737           v[0].p[1] = backface;\r
738           break;\r
739         case PLANE_YZ0:\r
740         case PLANE_YZ1:\r
741           v[0].p[0] = backface;\r
742           break;\r
743         default:\r
744           v[0].p[2] = backface;\r
745         }\r
746         Scale(rc,xyz[i][j],&pt[0]);\r
747 #ifndef ISOMETRIC\r
748         project(&v[0]);\r
749 #endif\r
750         Scale(rc,v[0],&pt[1]);\r
751         g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
752         g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
753         g_GLTable.m_pfn_qglVertex2f (pt[1].x, pt[1].y);\r
754         g_GLTable.m_pfn_qglEnd ();\r
755       }\r
756     }\r
757     VectorCopy(xyz[ 0][ 0].p, v[0].p);\r
758     VectorCopy(xyz[NH][ 0].p, v[1].p);\r
759     VectorCopy(xyz[NH][NV].p, v[2].p);\r
760     VectorCopy(xyz[ 0][NV].p, v[3].p);\r
761     switch(Plane)\r
762     {\r
763     case PLANE_XZ0:\r
764     case PLANE_XZ1:\r
765       v[0].p[1] = backface;;\r
766       v[1].p[1] = v[0].p[1];\r
767       v[2].p[1] = v[0].p[1];\r
768       v[3].p[1] = v[0].p[1];\r
769       break;\r
770     case PLANE_YZ0:\r
771     case PLANE_YZ1:\r
772       v[0].p[0] = backface;\r
773       v[1].p[0] = v[0].p[0];\r
774       v[2].p[0] = v[0].p[0];\r
775       v[3].p[0] = v[0].p[0];\r
776       break;\r
777     default:\r
778       v[0].p[2] = backface;\r
779       v[1].p[2] = v[0].p[2];\r
780       v[2].p[2] = v[0].p[2];\r
781       v[3].p[2] = v[0].p[2];\r
782     }\r
783 #ifndef ISOMETRIC\r
784     project(&v[3]);\r
785 #endif\r
786     Scale(rc,v[3],&pt[0]);\r
787     g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
788     g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
789     for(i=0; i<3; i++)\r
790     {\r
791 #ifndef ISOMETRIC\r
792       project(&v[i]);\r
793 #endif\r
794       Scale(rc,v[i],&pt[1]);\r
795       g_GLTable.m_pfn_qglVertex2f (pt[1].x, pt[1].y);\r
796     }\r
797     g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
798     g_GLTable.m_pfn_qglEnd ();\r
799   }\r
800 \r
801   g_GLTable.m_pfn_qglLineWidth (1);\r
802   g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
803   g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
804 \r
805 #ifdef ISOMETRIC\r
806   // Draw small depiction of coordinate axes\r
807   pt[0].x = rc.right  - cxChar   - cxChar/2 -  cyChar;\r
808   pt[0].y = rc.bottom - cyChar/2 - cxChar/2;\r
809   pt[1].x = pt[0].x + (int)(cyChar*COSXA);\r
810   pt[1].y = pt[0].y - (int)(cyChar*SINXA);\r
811   MoveToEx(hdc,pt[0].x,pt[0].y,NULL);\r
812   LineTo(hdc,pt[1].x,pt[1].y);\r
813   SetTextAlign(hdc,TA_LEFT | TA_TOP);\r
814   TextOut(hdc,pt[1].x,pt[1].y-cyChar/2,"X",1);\r
815   pt[1].x = pt[0].x - (int)(cyChar*COSYA);\r
816   pt[1].y = pt[0].y - (int)(cyChar*SINYA);\r
817   MoveToEx(hdc,pt[0].x,pt[0].y,NULL);\r
818   LineTo(hdc,pt[1].x,pt[1].y);\r
819   SetTextAlign(hdc,TA_RIGHT | TA_TOP);\r
820   TextOut(hdc,pt[1].x,pt[1].y-cyChar/2,"Y",1);\r
821   pt[1].x = pt[0].x;\r
822   pt[1].y = pt[0].y - cyChar;\r
823   MoveToEx(hdc,pt[0].x,pt[0].y,NULL);\r
824   LineTo(hdc,pt[1].x,pt[1].y);\r
825   SetTextAlign(hdc,TA_CENTER | TA_BOTTOM);\r
826   TextOut(hdc,pt[1].x,pt[1].y,"Z",1);\r
827 #else\r
828   L = 2*(double)cyChar/SF;\r
829   v[0].p[0] = 0.;\r
830   v[0].p[1] = 0.;\r
831   v[0].p[2] = 0.;\r
832   v[1].p[0] = L;\r
833   v[1].p[1] = 0.;\r
834   v[1].p[2] = 0.;\r
835   v[2].p[0] = 0.;\r
836   v[2].p[1] = L;\r
837   v[2].p[2] = 0.;\r
838   v[3].p[0] = 0.;\r
839   v[3].p[1] = 0.;\r
840   v[3].p[2] = L;\r
841   for(i=0; i<=3; i++)\r
842   {\r
843     project(&v[i]);\r
844     Scale(rc,v[i],&pt[i]);\r
845   }\r
846   for(i=1; i<=3; i++)\r
847   {\r
848     pt[i].x += -pt[0].x + rc.right  - 2*cyChar;\r
849     pt[i].y += -pt[0].y + rc.bottom + 2*cyChar;\r
850   }\r
851   pt[0].x = rc.right  - 2*cyChar;\r
852   pt[0].y = rc.bottom + 2*cyChar;\r
853 \r
854   for(i=1; i<=3; i++)\r
855   {\r
856     g_GLTable.m_pfn_qglBegin (GL_LINES);\r
857     g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
858     g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y);\r
859     g_GLTable.m_pfn_qglEnd ();\r
860     texfont_write (axis[i-1], pt[i].x-cxChar/2,pt[i].y+cyChar/2);\r
861   }\r
862 #endif\r
863 \r
864   // Draw player model's bounding box in red to give a sense of scale\r
865   // PEN_RED\r
866         g_GLTable.m_pfn_qglLineWidth (2);\r
867         g_GLTable.m_pfn_qglColor3f (1, 0, 0);\r
868         g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
869 \r
870   switch(Plane)\r
871   {\r
872   case PLANE_XY1:\r
873     v[0].p[0] = xyz[NH/2][NV/2].p[0] + PlayerBox[Game].x[0];\r
874     v[0].p[1] = xyz[NH/2][NV/2].p[1] + PlayerBox[Game].y[0];\r
875     v[0].p[2] = zmin - PlayerBox[Game].z[0] - 32;\r
876     break;\r
877   case PLANE_XZ0:\r
878     v[0].p[0] = (xmax+xmin)/2 + PlayerBox[Game].x[0];\r
879     v[0].p[1] = ymax+64;\r
880     v[0].p[2] = zmin;\r
881     break;\r
882   case PLANE_XZ1:\r
883     v[0].p[0] = (xmax+xmin)/2 + PlayerBox[Game].x[0];\r
884     v[0].p[1] = ymin-64;\r
885     v[0].p[2] = zmin;\r
886     break;\r
887   case PLANE_YZ0:\r
888     v[0].p[0] = xmax+64;\r
889     v[0].p[1] = (ymax+ymin)/2 + PlayerBox[Game].y[0];\r
890     v[0].p[2] = zmin;\r
891     break;\r
892   case PLANE_YZ1:\r
893     v[0].p[0] = xmin-64;\r
894     v[0].p[1] = (ymax+ymin)/2 + PlayerBox[Game].y[0];\r
895     v[0].p[2] = zmin;\r
896     break;\r
897   default:\r
898     // Put player on a node. For patches, put on an even numbered node.\r
899     if(Game==QUAKE3 && UsePatches!=0)\r
900     {\r
901       if(NH > 2)\r
902         x = Hll + dh * (int)(NH/2 + 1);\r
903       else\r
904         x = Hll + dh * (int)(NH/2);\r
905       if(NV > 2)\r
906         y = Vll + dv * (int)(NV/2 + 1);\r
907       else\r
908         y = Vll + dv * (int)(NV/2);\r
909     }\r
910     else\r
911     {\r
912       if(NH > 1)\r
913         x = Hll + dh * (int)(NH/2);\r
914       else\r
915         x = Hll + dh/2;\r
916       if(NV > 1)\r
917         y = Vll + dv * (int)(NV/2);\r
918       else\r
919         y = Vll + dv/2;\r
920     }\r
921 //              x = (Hll+Hur)/2.;\r
922 //              y = (Vll+Vur)/2.;\r
923     v[0].p[0] = x + PlayerBox[Game].x[0];\r
924     v[0].p[1] = y + PlayerBox[Game].y[0];\r
925     v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist\r
926   }\r
927   v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0];\r
928   v[1].p[1] = v[0].p[1];\r
929   v[1].p[2] = v[0].p[2];\r
930   v[2].p[0] = v[1].p[0];\r
931   v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0];\r
932   v[2].p[2] = v[0].p[2];\r
933   v[3].p[0] = v[0].p[0];\r
934   v[3].p[1] = v[2].p[1];\r
935   v[3].p[2] = v[0].p[2];\r
936   VectorCopy(v[0].p,v[4].p);\r
937   VectorCopy(v[1].p,v[5].p);\r
938   VectorCopy(v[2].p,v[6].p);\r
939   VectorCopy(v[3].p,v[7].p);\r
940   v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
941   v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
942   v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
943   v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
944   for(i=0; i<=7; i++)\r
945   {\r
946 #ifndef ISOMETRIC\r
947     project(&v[i]);\r
948 #endif\r
949     Scale(rc,v[i],&pt[i]);\r
950   }\r
951   g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
952   g_GLTable.m_pfn_qglVertex2f (pt[3].x, pt[3].y);\r
953   for(i=0; i<=3; i++)\r
954     g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y);\r
955   g_GLTable.m_pfn_qglEnd ();\r
956   g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
957   g_GLTable.m_pfn_qglVertex2f (pt[7].x, pt[7].y);\r
958   for(i=4; i<=7; i++)\r
959     g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y);\r
960   g_GLTable.m_pfn_qglEnd ();\r
961   g_GLTable.m_pfn_qglBegin (GL_LINES);\r
962   for(i=0; i<=3; i++)\r
963   {\r
964     g_GLTable.m_pfn_qglVertex2f (pt[i].x,pt[i].y);\r
965     g_GLTable.m_pfn_qglVertex2f (pt[i+4].x,pt[i+4].y);\r
966   }\r
967   g_GLTable.m_pfn_qglEnd ();\r
968 \r
969   g_GLTable.m_pfn_qglLineWidth (1);\r
970   g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
971   g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
972 }\r
973 //=============================================================\r
974 void DrawGrid(RECT rc)\r
975 {\r
976   int        i, j, k;\r
977   double     h,w,x,y;\r
978   POINT      pt[2];\r
979   RECT       rcBox;\r
980 \r
981   w = (double)(rc.right-rc.left+1) - cxChar;\r
982   h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar;\r
983 \r
984   SFG = w/(Hur-Hll);\r
985   SFG = min(SFG, h/(Vur-Vll));\r
986 \r
987   // Center drawing\r
988   X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2;\r
989   Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2;\r
990 \r
991   g_GLTable.m_pfn_qglLineWidth (2);\r
992   g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
993   g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
994 \r
995   pt[0].y = Y0G;\r
996   pt[1].y = Y0G + (int)(SFG*(Vur-Vll));\r
997   g_GLTable.m_pfn_qglBegin (GL_LINES);\r
998   for(i=0; i<=NH; i++)\r
999   {\r
1000     x = Hll + i * dh;\r
1001     pt[0].x = X0G + (int)(SFG*(x-Hll));\r
1002     g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[0].y);\r
1003     g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[1].y);\r
1004   }\r
1005   g_GLTable.m_pfn_qglEnd ();\r
1006   pt[0].x = X0G;\r
1007   pt[1].x = X0G + (int)(SFG*(Hur-Hll));\r
1008   g_GLTable.m_pfn_qglBegin (GL_LINES);\r
1009   for(i=0; i<=NV; i++)\r
1010   {\r
1011     y = Vll + i * dv;\r
1012     pt[0].y = Y0G + (int)(SFG*(Vur-y));\r
1013     g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y);\r
1014     g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[0].y);\r
1015   }\r
1016   g_GLTable.m_pfn_qglEnd ();\r
1017 \r
1018   g_GLTable.m_pfn_qglLineWidth (1);\r
1019 \r
1020   // Draw axes\r
1021   pt[0].x = rc.right  - cyChar - cxChar - cyChar/2;\r
1022   pt[0].y = rc.bottom + cyChar/2;\r
1023   pt[1].x = pt[0].x + cyChar;\r
1024   pt[1].y = pt[0].y;\r
1025   g_GLTable.m_pfn_qglBegin (GL_LINES);\r
1026   g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y);\r
1027   g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y);\r
1028   g_GLTable.m_pfn_qglEnd ();\r
1029   switch(Plane)\r
1030   {\r
1031   case PLANE_YZ0:\r
1032   case PLANE_YZ1:\r
1033     texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2);\r
1034     break;\r
1035   default:\r
1036     texfont_write ("X", pt[1].x, pt[1].y+cyChar/2);\r
1037   }\r
1038   pt[1].x = pt[0].x;\r
1039   pt[1].y = pt[0].y + cyChar;\r
1040   g_GLTable.m_pfn_qglBegin (GL_LINES);\r
1041   g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y);\r
1042   g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y);\r
1043   g_GLTable.m_pfn_qglEnd ();\r
1044   switch(Plane)\r
1045   {\r
1046   case PLANE_XY0:\r
1047   case PLANE_XY1:\r
1048     texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar);\r
1049     break;\r
1050   default:\r
1051     texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar);\r
1052   }\r
1053 \r
1054   // Denote fixed points with a 5x5 red rectangle\r
1055   for(i=0; i<=NH; i++)\r
1056   {\r
1057     for(j=0; j<=NV; j++)\r
1058     {\r
1059       if(xyz[i][j].fixed)\r
1060       {\r
1061         x = Hll + i*dh;\r
1062         y = Vll + j*dv;\r
1063         rcBox.left   = X0G + (int)(SFG*(x-Hll)) - 2;\r
1064         rcBox.top    = Y0G + (int)(SFG*(Vur-y)) + 2;\r
1065         rcBox.right  = rcBox.left + 5;\r
1066         rcBox.bottom = rcBox.top  - 5;\r
1067 \r
1068         DRAW_QUAD (rcBox, 1,0,0);\r
1069       }\r
1070     }\r
1071   }\r
1072 \r
1073   // Denote currently selected point with a 5x5 green rectangle\r
1074   if (NumVerticesSelected)\r
1075   {\r
1076     for(k=0; k<NumVerticesSelected; k++)\r
1077     {\r
1078       x = Hll + Vertex[k].i*dh;\r
1079       y = Vll + Vertex[k].j*dv;\r
1080       rcBox.left   = X0G + (int)(SFG*(x-Hll)) - 2;\r
1081       rcBox.top    = Y0G + (int)(SFG*(Vur-y)) + 2;\r
1082       rcBox.right  = rcBox.left + 5;\r
1083       rcBox.bottom = rcBox.top  - 5;\r
1084 \r
1085       DRAW_QUAD (rcBox, 0,1,0);\r
1086     }\r
1087   }\r
1088 \r
1089   // Unmovable vertices\r
1090   for(i=0; i<=NH; i++)\r
1091   {\r
1092     for(j=0; j<=NV; j++)\r
1093     {\r
1094       if(!CanEdit(i,j))\r
1095       {\r
1096         x = Hll + i*dh;\r
1097         y = Vll + j*dv;\r
1098         rcBox.left   = X0G + (int)(SFG*(x-Hll)) - 2;\r
1099         rcBox.top    = Y0G + (int)(SFG*(Vur-y)) + 2;\r
1100         rcBox.right  = rcBox.left + 5;\r
1101         rcBox.bottom = rcBox.top  - 5;\r
1102 \r
1103         DRAW_QUAD (rcBox, 1,1,0);\r
1104       }\r
1105     }\r
1106   }\r
1107 \r
1108   // Legend\r
1109   rcBox.left   = rc.left + cxChar/2 - 2;\r
1110   rcBox.top    = rc.top  - cyChar/2 - 2;\r
1111   rcBox.right  = rcBox.left + 5;\r
1112   rcBox.bottom = rcBox.top  - 5;\r
1113   DRAW_QUAD (rcBox, 1,0,0);\r
1114   texfont_write ("Fixed points", rcBox.right+cxChar,rcBox.top-4+cyChar/2);\r
1115 \r
1116   rcBox.top    -= cyChar;\r
1117   rcBox.bottom -= cyChar;\r
1118   DRAW_QUAD (rcBox, 1,1,0);\r
1119   texfont_write ("Not movable", rcBox.right+cxChar, rcBox.top-4+cyChar/2);\r
1120 \r
1121   rcBox.top    -= cyChar;\r
1122   rcBox.bottom -= cyChar;\r
1123   DRAW_QUAD (rcBox, 0,1,0);\r
1124   texfont_write ("Selected", rcBox.right+cxChar, rcBox.top-4+cyChar/2);\r
1125 }\r
1126 \r
1127 //=============================================================\r
1128 void GetScaleFactor(RECT rc)\r
1129 {\r
1130 #ifdef ISOMETRIC\r
1131         double      h, w;\r
1132 \r
1133         w = (double)(rc.right-rc.left+1) - cxChar;\r
1134         h = (double)(rc.top-rc.bottom+1) - cxChar;\r
1135 \r
1136         SF = w/( (XHi-XLo)*COSXA + (YHi-YLo)*COSYA );\r
1137         SF = min(SF, h/( (XHi-XLo)*SINXA + (YHi-YLo)*SINYA + ZHi-ZLo ) );\r
1138         // Center drawing\r
1139         X0 = (int)(rc.left + rc.right - (int)(SF*( (XHi-XLo)*COSXA + (YHi-YLo)*COSYA )) )/2;\r
1140         Y0 = (int)(rc.top + rc.bottom - (int)(SF*( (XHi-XLo)*SINXA + (YHi-YLo)*SINYA + ZHi-ZLo) ))/2;\r
1141 \r
1142 #else\r
1143         double      h, w;\r
1144 \r
1145         w = (double)(rc.right-rc.left+1) - cxChar;\r
1146         h = (double)(rc.top-rc.bottom+1) - cxChar;\r
1147 \r
1148         SF = w/(Hhi-Hlo);\r
1149         SF = min(SF, h/(Vhi-Vlo) );\r
1150         X0 = (int)(rc.left + rc.right - (int)(SF*(Hhi-Hlo)))/2;\r
1151         Y0 = (int)(rc.top + rc.bottom + (int)(SF*(Vhi-Vlo)))/2;\r
1152 #endif\r
1153 }\r
1154 \r
1155 //=============================================================\r
1156 void Scale(RECT rc,XYZ xyz,POINT *pt)\r
1157 {\r
1158 \r
1159 #ifdef ISOMETRIC\r
1160 \r
1161         pt[0].x = X0 + (int)(SF*( (xyz.p[0]-XLo)*COSXA +\r
1162                               (YHi-xyz.p[1])*COSYA   ));\r
1163         pt[0].y = Y0 + (int)(SF*(  ZHi-xyz.p[2] +\r
1164                                   (YHi-xyz.p[1])*SINYA +\r
1165                                                   (XHi-xyz.p[0])*SINXA   ));\r
1166 #else\r
1167         pt[0].x = X0 + (int)(SF*( xyz.pp[0] - Hlo ) );\r
1168         pt[0].y = Y0 - (int)(SF*( Vhi - xyz.pp[1] ) );\r
1169 #endif\r
1170 \r
1171 }\r
1172 \r
1173 #ifndef ISOMETRIC\r
1174 /* ======================================================================= */\r
1175 void project(XYZ *v)\r
1176 {\r
1177         // project a 3D point (x,y,z) onto view plane\r
1178         double x, y, z, xa, ya, za;\r
1179 \r
1180         x = v->p[0];\r
1181         y = v->p[1];\r
1182         z = v->p[2];\r
1183 \r
1184         // yaw\r
1185         xa = ct[0]*x - st[0]*z;\r
1186         za = st[0]*x + ct[0]*z;\r
1187 \r
1188         // roll\r
1189         x  = ct[1]*xa + st[1]*y;\r
1190         ya = ct[1]*y  - st[1]*xa;\r
1191 \r
1192         // azimuth\r
1193         z  = ct[2]*za - st[2]*ya;\r
1194         y  = ct[2]*ya + st[2]*za;\r
1195 \r
1196         // horizontal and vertical projections:\r
1197 //      v->pp[0] = D*x/z;\r
1198 //      v->pp[1] = D*y/z;\r
1199         v->pp[0] = -y;\r
1200         v->pp[1] =  x;\r
1201         v->pp[2] =  z;\r
1202 \r
1203         // NOTE: if perspective transformation is desired,\r
1204         // set "persp" to the range from the surface,\r
1205         // then:\r
1206         // v->projected_h = -v->projected_h * persp/(v->projected_z-persp);\r
1207         // v->projected_v = -v->projected_v * persp/(v->projected_z-persp);\r
1208 }\r
1209 /*=======================================================================*/\r
1210 void evaluate()\r
1211 {\r
1212         int i, j;\r
1213         XYZ v[4];\r
1214         \r
1215         if(elevation > PI) elevation -= 2.*PI;\r
1216         roll = elevation * sin(azimuth);\r
1217         yaw  = 1.5*PI + elevation*cos(azimuth);\r
1218 \r
1219         //      Find angles from midpoint to viewpoint:\r
1220         st[0] = sin(yaw);\r
1221         st[1] = sin(roll);\r
1222         st[2] = sin(azimuth);\r
1223         ct[0] = cos(yaw);\r
1224         ct[1] = cos(roll);\r
1225         ct[2] = cos(azimuth);\r
1226 \r
1227         for(i=0; i<=NH; i++)\r
1228         {\r
1229                 for(j=0; j<=NV; j++)\r
1230                 {\r
1231                         project(&xyz[i][j]);\r
1232                 }\r
1233         }\r
1234 \r
1235         Hhi = xyz[0][0].pp[0];\r
1236         Hlo = Hhi;\r
1237         Vhi = xyz[0][0].pp[1];\r
1238         Vlo = Vhi;\r
1239         for(i=0; i<=NH; i++)\r
1240         {\r
1241                 for(j=0; j<=NV; j++)\r
1242                 {\r
1243                         Hlo = min(Hlo,xyz[i][j].pp[0]);\r
1244                         Hhi = max(Hhi,xyz[i][j].pp[0]);\r
1245                         Vlo = min(Vlo,xyz[i][j].pp[1]);\r
1246                         Vhi = max(Vhi,xyz[i][j].pp[1]);\r
1247                 }\r
1248         }\r
1249 \r
1250         // Include backface in min-max\r
1251         VectorCopy(xyz[ 0][ 0].p,v[0].p);\r
1252         VectorCopy(xyz[NH][ 0].p,v[1].p);\r
1253         VectorCopy(xyz[NH][NV].p,v[2].p);\r
1254         VectorCopy(xyz[ 0][NV].p,v[3].p);\r
1255         switch(Plane)\r
1256         {\r
1257         case PLANE_XZ0:\r
1258         case PLANE_XZ1:\r
1259                 v[0].p[1] = backface;\r
1260                 v[1].p[1] = v[0].p[1];\r
1261                 v[2].p[1] = v[0].p[1];\r
1262                 v[3].p[1] = v[0].p[1];\r
1263                 break;\r
1264         case PLANE_YZ0:\r
1265         case PLANE_YZ1:\r
1266                 v[0].p[0] = backface;\r
1267                 v[1].p[0] = v[0].p[0];\r
1268                 v[2].p[0] = v[0].p[0];\r
1269                 v[3].p[0] = v[0].p[0];\r
1270                 break;\r
1271         default:\r
1272                 v[0].p[2] = backface;\r
1273                 v[1].p[2] = v[0].p[2];\r
1274                 v[2].p[2] = v[0].p[2];\r
1275                 v[3].p[2] = v[0].p[2];\r
1276         }\r
1277         for(i=0; i<=3; i++)\r
1278         {\r
1279                 project(&v[i]);\r
1280                 Hlo = min(Hlo,v[i].pp[0]);\r
1281                 Hhi = max(Hhi,v[i].pp[0]);\r
1282                 Vlo = min(Vlo,v[i].pp[1]);\r
1283                 Vhi = max(Vhi,v[i].pp[1]);\r
1284         }\r
1285 \r
1286 }\r
1287 #endif\r