-/*\r
-GenSurf plugin for GtkRadiant\r
-Copyright (C) 2001 David Hyde, Loki software and qeradiant.com\r
-\r
-This library is free software; you can redistribute it and/or\r
-modify it under the terms of the GNU Lesser General Public\r
-License as published by the Free Software Foundation; either\r
-version 2.1 of the License, or (at your option) any later version.\r
-\r
-This library is distributed in the hope that it will be useful,\r
-but WITHOUT ANY WARRANTY; without even the implied warranty of\r
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
-Lesser General Public License for more details.\r
-\r
-You should have received a copy of the GNU Lesser General Public\r
-License along with this library; if not, write to the Free Software\r
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA\r
-*/\r
-\r
-#include <math.h>\r
-#include <stdio.h>\r
-#include <stdlib.h>\r
-#include "gensurf.h"\r
-\r
-#undef ISOMETRIC\r
-\r
-extern double backface;\r
-extern double dh, dv;\r
-extern double xmin,xmax,ymin,ymax,zmin,zmax;\r
-\r
-double SF, SFG; // Graphics scale factors\r
-double XLo, XHi, YLo, YHi, ZLo, ZHi;\r
-double yaw,roll;\r
-double elevation,azimuth;\r
-int cxChar = 10, cyChar = 16;\r
-int X0, Y0;\r
-int X0G, Y0G;\r
-\r
-static RECT rcCoord; // where X= Y= is drawn\r
-static RECT rcGrid; // rectangle within rcLower that forms the border of the grid, plus\r
- // a 3 pixel slop.\r
-static RECT rcLower; // lower half of window, where plan view is drawn\r
-static RECT rcUpper; // upper half or entire window, where isometric projection is drawn\r
-\r
-void vertex_selected ();\r
-void texfont_init ();\r
-void texfont_write (const char *text, float l, float t);\r
-\r
-#define PEN_GRID { \\r
- g_GLTable.m_pfn_qglLineWidth (1); \\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0); \\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); }\r
-\r
-#define PEN_RED { \\r
- g_GLTable.m_pfn_qglLineWidth (2); \\r
- g_GLTable.m_pfn_qglColor3f (1, 0, 0); \\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); }\r
-\r
-#define PEN_DASH { \\r
- g_GLTable.m_pfn_qglLineWidth (1); \\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0); \\r
- g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \\r
- g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); }\r
-\r
-#define DRAW_QUAD(rc,r,g,b) { \\r
- g_GLTable.m_pfn_qglBegin (GL_QUADS); \\r
- g_GLTable.m_pfn_qglColor3f (0,1,0); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.bottom); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.right, rc.bottom); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.right, rc.top+1); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.top+1); \\r
- g_GLTable.m_pfn_qglColor3f (r,g,b); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.left, rc.bottom+1); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.bottom+1); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.top); \\r
- g_GLTable.m_pfn_qglVertex2f (rc.left, rc.top); \\r
- g_GLTable.m_pfn_qglEnd (); }\r
-\r
-\r
-#ifndef ISOMETRIC\r
-double D=65536.;\r
-double ct[3],st[3];\r
-double Hhi, Hlo, Vhi, Vlo;\r
-#endif\r
-\r
-#define SUBDIVS 6\r
-\r
-\r
-void ShowPreview ()\r
-{\r
- if (Preview)\r
- {\r
- if (g_pWndPreview == NULL)\r
- CreateViewWindow ();\r
- gtk_widget_show (g_pWndPreview);\r
-\r
- UpdatePreview (true);\r
- }\r
- else\r
- gtk_widget_hide (g_pWndPreview);\r
-}\r
-\r
-static void draw_preview ()\r
-{\r
- int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height;\r
-\r
- g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1);\r
- g_GLTable.m_pfn_qglViewport (0, 0, width, height);\r
- g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION);\r
- g_GLTable.m_pfn_qglLoadIdentity ();\r
- g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1);\r
- g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);\r
- \r
- // ^Fishman - Antializing for the preview window.\r
- if (Antialiasing)\r
- {\r
- g_GLTable.m_pfn_qglEnable(GL_BLEND);\r
- g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);\r
- g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH);\r
- }\r
- else\r
- {\r
- g_GLTable.m_pfn_qglDisable(GL_BLEND);\r
- g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH);\r
- }\r
-\r
- texfont_init ();\r
-\r
- if (!ValidSurface ())\r
- return;\r
-\r
- rcUpper.left = 0;\r
- rcUpper.right = width;\r
- rcUpper.bottom = 0;\r
- rcUpper.top = height;\r
- rcLower.left = 0;\r
- rcLower.right = width;\r
- rcLower.bottom = 0;\r
- rcLower.top = height;\r
-\r
- if (VertexMode)\r
- {\r
- rcUpper.bottom = rcUpper.top/2;\r
- DrawPreview (rcUpper);\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- g_GLTable.m_pfn_qglVertex2f (rcUpper.left, rcUpper.bottom);\r
- g_GLTable.m_pfn_qglVertex2f (rcUpper.right, rcUpper.bottom);\r
- g_GLTable.m_pfn_qglEnd ();\r
- rcLower.top = rcUpper.bottom-1;\r
- DrawGrid (rcLower);\r
- rcCoord.left = rcLower.left;\r
- rcCoord.right = rcLower.right;\r
- rcCoord.bottom = rcLower.bottom;\r
- rcCoord.top = rcLower.top;\r
- rcCoord.top = rcCoord.bottom+cyChar;\r
- rcCoord.right = rcCoord.left + 15*cxChar;\r
- rcGrid.left = X0G - 3;\r
- rcGrid.bottom = Y0G - 3;\r
- rcGrid.right = X0G + (int)(SFG*(Hur-Hll)) + 3;\r
- rcGrid.top = Y0G + (int)(SFG*(Vur-Vll)) + 3;\r
- }\r
- else\r
- DrawPreview (rcUpper);\r
-}\r
-\r
-static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data)\r
-{\r
- if (event->count > 0)\r
- return TRUE;\r
-\r
- if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget))\r
- {\r
- g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n");\r
- return TRUE;\r
- }\r
-\r
- draw_preview ();\r
-\r
- g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget);\r
- g_GLTable.m_pfn_QE_CheckOpenGLForErrors ();\r
-\r
- return TRUE;\r
-}\r
-\r
-static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data)\r
-{\r
- POINT pt = { (long)event->x, widget->allocation.height - (long)event->y };\r
- bool Selected;\r
- double x,y;\r
- int i, j, k, ks;\r
- int i0, i1, j0, j1;\r
-\r
- if ((!VertexMode) || (event->button != 1))\r
- return;\r
-\r
- if (!PtInRect (&rcGrid,pt))\r
- {\r
- gdk_beep ();\r
- return;\r
- }\r
-\r
- x = Hll + (pt.x-X0G)/SFG;\r
- y = Vur - (pt.y-Y0G)/SFG;\r
- i = (int)(floor( (x-Hll)/dh - 0.5) + 1);\r
- j = (int)(floor( (y-Vll)/dv - 0.5) + 1);\r
- if (i < 0 || i > NH || j < 0 || j > NV)\r
- {\r
- gdk_beep ();\r
- return;\r
- }\r
-\r
- if(!CanEdit(i,j))\r
- {\r
- gdk_beep ();\r
- return;\r
- }\r
-\r
- // Control key pressed - add this point, or remove it if already selected\r
- if ((event->state & GDK_CONTROL_MASK) != 0)\r
- {\r
- Selected = FALSE;\r
- if (NumVerticesSelected)\r
- {\r
- for (k=0; k<NumVerticesSelected && !Selected; k++)\r
- {\r
- if(Vertex[k].i == i && Vertex[k].j == j)\r
- {\r
- Selected = TRUE;\r
- ks = k;\r
- }\r
- }\r
- }\r
-\r
- // Already selected - unselect it.\r
- if (Selected)\r
- {\r
- if (ks < NumVerticesSelected)\r
- {\r
- for (k=ks;k<NumVerticesSelected-1;k++)\r
- {\r
- Vertex[k].i = Vertex[k+1].i;\r
- Vertex[k].j = Vertex[k+1].j;\r
- }\r
- NumVerticesSelected--;\r
- }\r
- }\r
- else\r
- {\r
- Vertex[NumVerticesSelected].i = i;\r
- Vertex[NumVerticesSelected].j = j;\r
- NumVerticesSelected++;\r
- }\r
- }\r
- else if ((event->state & GDK_SHIFT_MASK) != 0)\r
- {\r
- if (NumVerticesSelected)\r
- {\r
- NumVerticesSelected = 1;\r
- i0 = min(Vertex[0].i, i);\r
- i1 = max(Vertex[0].i, i);\r
- j0 = min(Vertex[0].j, j);\r
- j1 = max(Vertex[0].j, j);\r
- for(i=i0; i<=i1; i++)\r
- {\r
- for(j=j0; j<=j1; j++)\r
- {\r
- if(i==0 && j==0 ) continue;\r
- if(i==NH && j==0 ) continue;\r
- if(i==0 && j==NV) continue;\r
- if(i==NH && j==NV) continue;\r
- if(i != Vertex[0].i || j != Vertex[0].j)\r
- {\r
- Vertex[NumVerticesSelected].i = i;\r
- Vertex[NumVerticesSelected].j = j;\r
- NumVerticesSelected++;\r
- }\r
- }\r
- }\r
- }\r
- else\r
- {\r
- Vertex[0].i = i;\r
- Vertex[0].j = j;\r
- NumVerticesSelected = 1;\r
- }\r
- }\r
- else\r
- {\r
- Vertex[0].i = i;\r
- Vertex[0].j = j;\r
- NumVerticesSelected = 1;\r
- }\r
-\r
- vertex_selected ();\r
-}\r
-\r
-static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data)\r
-{\r
- POINT pt = { (long)event->x, widget->allocation.height - (long)event->y };\r
-\r
- if (!VertexMode)\r
- return;\r
-\r
- if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget))\r
- {\r
- g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n");\r
- return;\r
- }\r
-\r
- g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST);\r
- g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left,\r
- rcCoord.top-rcCoord.bottom);\r
- g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT);\r
-\r
- if (PtInRect(&rcGrid,pt))\r
- {\r
- GdkCursor *cursor = gdk_cursor_new (GDK_CROSS);\r
- gdk_window_set_cursor (g_pWndPreview->window, cursor);\r
- gdk_cursor_unref (cursor);\r
-\r
- char Text[32];\r
- int x, y;\r
-\r
- x = (int)(Hll + (pt.x-X0G)/SFG);\r
- y = (int)(Vur - (pt.y-Y0G)/SFG);\r
- switch(Plane)\r
- {\r
- case PLANE_XZ0:\r
- case PLANE_XZ1:\r
- sprintf(Text," x=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );\r
- break;\r
- case PLANE_YZ0:\r
- case PLANE_YZ1:\r
- sprintf(Text," y=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );\r
- break;\r
- default:\r
- sprintf(Text," x=%d, y=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) );\r
- }\r
-\r
- texfont_write (Text, rcCoord.left, rcCoord.top);\r
- }\r
- else\r
- {\r
- gdk_window_set_cursor (g_pWndPreview->window, NULL);\r
- }\r
-\r
- g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget);\r
- g_GLTable.m_pfn_QE_CheckOpenGLForErrors ();\r
- g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST);\r
-}\r
-\r
-static gint preview_close (GtkWidget *widget, gpointer data)\r
-{\r
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE);\r
- return TRUE;\r
-}\r
-\r
-static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data)\r
-{\r
- *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360));\r
- UpdatePreview (false);\r
-}\r
-\r
-static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data)\r
-{\r
- preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast<double*>(data));\r
- return FALSE;\r
-}\r
-\r
-static void preview_spin (GtkAdjustment *adj, double *data)\r
-{\r
- *data = DegreesToRadians (adj->value);\r
- UpdatePreview (false);\r
-}\r
-\r
-void CreateViewWindow ()\r
-{\r
- GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame;\r
- GtkObject *adj;\r
-\r
-#ifndef ISOMETRIC\r
- elevation = PI/6.;\r
- azimuth = PI/6.;\r
-#endif\r
-\r
- g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);\r
- gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview");\r
- gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL);\r
- gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL);\r
- gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd));\r
- gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400);\r
-\r
- vbox = gtk_vbox_new (FALSE, 5);\r
- gtk_widget_show (vbox);\r
- gtk_container_add (GTK_CONTAINER (dlg), vbox);\r
-\r
-#ifndef ISOMETRIC\r
- hbox = gtk_hbox_new (TRUE, 5);\r
- gtk_widget_show (hbox);\r
- gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0);\r
- gtk_container_set_border_width (GTK_CONTAINER (hbox), 3);\r
-\r
- label = gtk_label_new ("Elevation");\r
- gtk_widget_show (label);\r
- gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);\r
- gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0);\r
-\r
- adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10);\r
- gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation);\r
- spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);\r
- gtk_widget_show (spin);\r
- gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);\r
- g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation);\r
-\r
- adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10);\r
- gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth);\r
- spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);\r
- gtk_widget_show (spin);\r
- gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE);\r
- gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0);\r
-\r
- label = gtk_label_new ("Azimuth");\r
- gtk_widget_show (label);\r
- gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5);\r
- gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0);\r
- g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth);\r
-#endif\r
-\r
- frame = gtk_frame_new (NULL);\r
- gtk_widget_show (frame);\r
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);\r
- gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0);\r
-\r
- g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL);\r
-\r
- gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK);\r
- gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);\r
- gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL);\r
- gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event",\r
- GTK_SIGNAL_FUNC (button_press), NULL);\r
-\r
- gtk_widget_show (g_pPreviewWidget);\r
- gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget);\r
-\r
- if (Preview)\r
- gtk_widget_show (g_pWndPreview);\r
-\r
- UpdatePreview (true);\r
-}\r
-\r
-//=============================================================\r
-/* DrawPreview */\r
-void DrawPreview (RECT rc)\r
-{\r
-#define COSXA 0.8660254037844\r
-#define SINXA 0.5\r
-#define COSYA 0.8660254037844\r
-#define SINYA 0.5\r
-\r
- double L;\r
- double x,y;\r
- int i, j;\r
- POINT pt[8];\r
- XYZ v[8];\r
- char axis[3][2] = {"X","Y","Z"};\r
-\r
-#ifndef ISOMETRIC\r
- evaluate();\r
-#endif\r
-\r
- XLo = xmin;\r
- XHi = xmax;\r
- YLo = ymin;\r
- YHi = ymax;\r
- ZLo = zmin;\r
- ZHi = zmax;\r
- switch (Plane)\r
- {\r
- case PLANE_XY1:\r
- ZHi = backface;\r
- break;\r
- case PLANE_XZ0:\r
- YLo = backface;\r
- break;\r
- case PLANE_XZ1:\r
- YHi = backface;\r
- break;\r
- case PLANE_YZ0:\r
- XLo = backface;\r
- break;\r
- case PLANE_YZ1:\r
- XHi = backface;\r
- break;\r
- default:\r
- ZLo = backface;\r
- }\r
-\r
-\r
-\r
- GetScaleFactor(rc);\r
- //PEN_GRID\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
-\r
- if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) )\r
- {\r
- XYZ *vv;\r
-\r
- vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ));\r
- for(i=0; i<gNumNodes; i++)\r
- {\r
- for(j=0; j<3; j++)\r
- vv[i].p[j] = (double)(gNode[i].p[j]);\r
- project(&vv[i]);\r
- }\r
-\r
- for(i=0; i<gNumTris; i++)\r
- {\r
- for(j=0; j<3; j++)\r
- Scale(rc,vv[gTri[i].v[j]],&pt[j]);\r
-\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[1].x, pt[1].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[2].x, pt[2].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
- free(vv);\r
- }\r
- else if (Game==QUAKE3 && UsePatches!=0)\r
- {\r
- int axis, ii, jj, k;\r
- float u, v;\r
- XYZ uv[3][3];\r
- XYZ Ctrl[3],out;\r
-\r
- switch (Plane)\r
- {\r
- case PLANE_XY0:\r
- case PLANE_XY1:\r
- k = 2;\r
- break;\r
- case PLANE_XZ0:\r
- case PLANE_XZ1:\r
- k = 1;\r
- break;\r
- default:\r
- k = 0;\r
- }\r
- for(i=0; i<NH; i+=2)\r
- {\r
- for(j=0; j<NV; j+=2)\r
- {\r
- VectorCopy(xyz[i ][j ].p,uv[0][0].p);\r
- VectorCopy(xyz[i+1][j ].p,uv[1][0].p);\r
- VectorCopy(xyz[i+2][j ].p,uv[2][0].p);\r
- VectorCopy(xyz[i ][j+1].p,uv[0][1].p);\r
- VectorCopy(xyz[i+1][j+1].p,uv[1][1].p);\r
- VectorCopy(xyz[i+2][j+1].p,uv[2][1].p);\r
- VectorCopy(xyz[i ][j+2].p,uv[0][2].p);\r
- VectorCopy(xyz[i+1][j+2].p,uv[1][2].p);\r
- VectorCopy(xyz[i+2][j+2].p,uv[2][2].p);\r
- 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
- 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
- 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
- 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
- uv[1][1].p[k] = (16*xyz[i+1][j+1].p[k] -\r
- xyz[i ][j ].p[k] - 2*xyz[i+1][j ].p[k] - xyz[i+2][j ].p[k] -\r
- 2*xyz[i ][j+1].p[k] -2*xyz[i+2][j+1].p[k] -\r
- xyz[i ][j+2].p[k] - 2*xyz[i+1][j+2].p[k] - xyz[i+2][j+2].p[k] )/4;\r
-\r
- for(ii=0; ii<=SUBDIVS; ii++)\r
- {\r
- if(ii==0 || ii==SUBDIVS/2 || ii==SUBDIVS)\r
- {\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
- // PEN_GRID\r
- }\r
- else\r
- {\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0);\r
- g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE);\r
- // PEN_DASH\r
- }\r
-\r
- u = (float)(ii)/(float)(SUBDIVS);\r
- for(jj=0; jj<3; jj++)\r
- {\r
- for(axis=0; axis<3; axis++)\r
- {\r
- float a, b, c;\r
- float qA, qB, qC;\r
- a = (float)uv[0][jj].p[axis];\r
- b = (float)uv[1][jj].p[axis];\r
- c = (float)uv[2][jj].p[axis];\r
- qA = a - 2 * b + c;\r
- qB = 2 * b - 2 * a;\r
- qC = a;\r
- Ctrl[jj].p[axis] = qA * u * u + qB * u + qC;\r
- }\r
- }\r
- VectorCopy(Ctrl[0].p,out.p);\r
- project(&out);\r
- Scale(rc,out,&pt[0]);\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- for(jj=1; jj<=SUBDIVS; jj++)\r
- {\r
- v = (float)(jj)/(float)(SUBDIVS);\r
- for (axis = 0 ; axis < 3 ; axis++) \r
- {\r
- float a, b, c;\r
- float qA, qB, qC;\r
- a = (float)Ctrl[0].p[axis];\r
- b = (float)Ctrl[1].p[axis];\r
- c = (float)Ctrl[2].p[axis];\r
- qA = a - 2 * b + c;\r
- qB = 2 * b - 2 * a;\r
- qC = a;\r
- out.p[axis] = qA * v * v + qB * v + qC;\r
- }\r
- project(&out);\r
- Scale(rc,out,&pt[0]);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
- for(jj=0; jj<=SUBDIVS; jj++)\r
- {\r
- if(jj==0 || jj==SUBDIVS/2 || jj==SUBDIVS)\r
- {\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
- // PEN_GRID\r
- }\r
- else\r
- {\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0);\r
- g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE);\r
- // PEN_DASH\r
- }\r
-\r
- v = (float)(jj)/(float)(SUBDIVS);\r
- for(ii=0; ii<3; ii++)\r
- {\r
- for(axis=0; axis<3; axis++)\r
- {\r
- float a, b, c;\r
- float qA, qB, qC;\r
- a = (float)uv[ii][0].p[axis];\r
- b = (float)uv[ii][1].p[axis];\r
- c = (float)uv[ii][2].p[axis];\r
- qA = a - 2 * b + c;\r
- qB = 2 * b - 2 * a;\r
- qC = a;\r
- Ctrl[ii].p[axis] = qA * v * v + qB * v + qC;\r
- }\r
- }\r
- VectorCopy(Ctrl[0].p,out.p);\r
- project(&out);\r
- Scale(rc,out,&pt[0]);\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- for(ii=1; ii<=SUBDIVS; ii++)\r
- {\r
- u = (float)(ii)/(float)(SUBDIVS);\r
- for (axis = 0 ; axis < 3 ; axis++) \r
- {\r
- float a, b, c;\r
- float qA, qB, qC;\r
- a = (float)Ctrl[0].p[axis];\r
- b = (float)Ctrl[1].p[axis];\r
- c = (float)Ctrl[2].p[axis];\r
- qA = a - 2 * b + c;\r
- qB = 2 * b - 2 * a;\r
- qC = a;\r
- out.p[axis] = qA * u * u + qB * u + qC;\r
- }\r
- project(&out);\r
- Scale(rc,out,&pt[0]);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
- }\r
- }\r
- }\r
- else\r
- {\r
- for(i=0; i<=NH; i++)\r
- {\r
- Scale(rc,xyz[i][0],&pt[0]);\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- for(j=1; j<=NV; j++)\r
- {\r
- Scale(rc,xyz[i][j],&pt[0]);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
- for(j=0; j<=NV; j++)\r
- {\r
- Scale(rc,xyz[0][j],&pt[0]);\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- for(i=1; i<=NH; i++)\r
- {\r
- Scale(rc,xyz[i][j],&pt[0]);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
- }\r
-\r
- if(Game!=QUAKE3 || UsePatches==0)\r
- {\r
- // Draw lines from corners to base, and lines around base\r
- for(i=0; i<=NH; i+=NH)\r
- {\r
- for(j=0; j<=NV; j+=NV)\r
- {\r
- VectorCopy(xyz[i][j].p, v[0].p);\r
- switch(Plane)\r
- {\r
- case PLANE_XZ0:\r
- case PLANE_XZ1:\r
- v[0].p[1] = backface;\r
- break;\r
- case PLANE_YZ0:\r
- case PLANE_YZ1:\r
- v[0].p[0] = backface;\r
- break;\r
- default:\r
- v[0].p[2] = backface;\r
- }\r
- Scale(rc,xyz[i][j],&pt[0]);\r
-#ifndef ISOMETRIC\r
- project(&v[0]);\r
-#endif\r
- Scale(rc,v[0],&pt[1]);\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[1].x, pt[1].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
- }\r
- VectorCopy(xyz[ 0][ 0].p, v[0].p);\r
- VectorCopy(xyz[NH][ 0].p, v[1].p);\r
- VectorCopy(xyz[NH][NV].p, v[2].p);\r
- VectorCopy(xyz[ 0][NV].p, v[3].p);\r
- switch(Plane)\r
- {\r
- case PLANE_XZ0:\r
- case PLANE_XZ1:\r
- v[0].p[1] = backface;;\r
- v[1].p[1] = v[0].p[1];\r
- v[2].p[1] = v[0].p[1];\r
- v[3].p[1] = v[0].p[1];\r
- break;\r
- case PLANE_YZ0:\r
- case PLANE_YZ1:\r
- v[0].p[0] = backface;\r
- v[1].p[0] = v[0].p[0];\r
- v[2].p[0] = v[0].p[0];\r
- v[3].p[0] = v[0].p[0];\r
- break;\r
- default:\r
- v[0].p[2] = backface;\r
- v[1].p[2] = v[0].p[2];\r
- v[2].p[2] = v[0].p[2];\r
- v[3].p[2] = v[0].p[2];\r
- }\r
-#ifndef ISOMETRIC\r
- project(&v[3]);\r
-#endif\r
- Scale(rc,v[3],&pt[0]);\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- for(i=0; i<3; i++)\r
- {\r
-#ifndef ISOMETRIC\r
- project(&v[i]);\r
-#endif\r
- Scale(rc,v[i],&pt[1]);\r
- g_GLTable.m_pfn_qglVertex2f (pt[1].x, pt[1].y);\r
- }\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- }\r
-\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
-\r
-#ifdef ISOMETRIC\r
- // Draw small depiction of coordinate axes\r
- pt[0].x = rc.right - cxChar - cxChar/2 - cyChar;\r
- pt[0].y = rc.bottom - cyChar/2 - cxChar/2;\r
- pt[1].x = pt[0].x + (int)(cyChar*COSXA);\r
- pt[1].y = pt[0].y - (int)(cyChar*SINXA);\r
- MoveToEx(hdc,pt[0].x,pt[0].y,NULL);\r
- LineTo(hdc,pt[1].x,pt[1].y);\r
- SetTextAlign(hdc,TA_LEFT | TA_TOP);\r
- TextOut(hdc,pt[1].x,pt[1].y-cyChar/2,"X",1);\r
- pt[1].x = pt[0].x - (int)(cyChar*COSYA);\r
- pt[1].y = pt[0].y - (int)(cyChar*SINYA);\r
- MoveToEx(hdc,pt[0].x,pt[0].y,NULL);\r
- LineTo(hdc,pt[1].x,pt[1].y);\r
- SetTextAlign(hdc,TA_RIGHT | TA_TOP);\r
- TextOut(hdc,pt[1].x,pt[1].y-cyChar/2,"Y",1);\r
- pt[1].x = pt[0].x;\r
- pt[1].y = pt[0].y - cyChar;\r
- MoveToEx(hdc,pt[0].x,pt[0].y,NULL);\r
- LineTo(hdc,pt[1].x,pt[1].y);\r
- SetTextAlign(hdc,TA_CENTER | TA_BOTTOM);\r
- TextOut(hdc,pt[1].x,pt[1].y,"Z",1);\r
-#else\r
- L = 2*(double)cyChar/SF;\r
- v[0].p[0] = 0.;\r
- v[0].p[1] = 0.;\r
- v[0].p[2] = 0.;\r
- v[1].p[0] = L;\r
- v[1].p[1] = 0.;\r
- v[1].p[2] = 0.;\r
- v[2].p[0] = 0.;\r
- v[2].p[1] = L;\r
- v[2].p[2] = 0.;\r
- v[3].p[0] = 0.;\r
- v[3].p[1] = 0.;\r
- v[3].p[2] = L;\r
- for(i=0; i<=3; i++)\r
- {\r
- project(&v[i]);\r
- Scale(rc,v[i],&pt[i]);\r
- }\r
- for(i=1; i<=3; i++)\r
- {\r
- pt[i].x += -pt[0].x + rc.right - 2*cyChar;\r
- pt[i].y += -pt[0].y + rc.bottom + 2*cyChar;\r
- }\r
- pt[0].x = rc.right - 2*cyChar;\r
- pt[0].y = rc.bottom + 2*cyChar;\r
-\r
- for(i=1; i<=3; i++)\r
- {\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x, pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- texfont_write (axis[i-1], pt[i].x-cxChar/2,pt[i].y+cyChar/2);\r
- }\r
-#endif\r
-\r
- // Draw player model's bounding box in red to give a sense of scale\r
- // PEN_RED\r
- g_GLTable.m_pfn_qglLineWidth (2);\r
- g_GLTable.m_pfn_qglColor3f (1, 0, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
-\r
- switch(Plane)\r
- {\r
- case PLANE_XY1:\r
- v[0].p[0] = xyz[NH/2][NV/2].p[0] + PlayerBox[Game].x[0];\r
- v[0].p[1] = xyz[NH/2][NV/2].p[1] + PlayerBox[Game].y[0];\r
- v[0].p[2] = zmin - PlayerBox[Game].z[0] - 32;\r
- break;\r
- case PLANE_XZ0:\r
- v[0].p[0] = (xmax+xmin)/2 + PlayerBox[Game].x[0];\r
- v[0].p[1] = ymax+64;\r
- v[0].p[2] = zmin;\r
- break;\r
- case PLANE_XZ1:\r
- v[0].p[0] = (xmax+xmin)/2 + PlayerBox[Game].x[0];\r
- v[0].p[1] = ymin-64;\r
- v[0].p[2] = zmin;\r
- break;\r
- case PLANE_YZ0:\r
- v[0].p[0] = xmax+64;\r
- v[0].p[1] = (ymax+ymin)/2 + PlayerBox[Game].y[0];\r
- v[0].p[2] = zmin;\r
- break;\r
- case PLANE_YZ1:\r
- v[0].p[0] = xmin-64;\r
- v[0].p[1] = (ymax+ymin)/2 + PlayerBox[Game].y[0];\r
- v[0].p[2] = zmin;\r
- break;\r
- default:\r
- // Put player on a node. For patches, put on an even numbered node.\r
- if(Game==QUAKE3 && UsePatches!=0)\r
- {\r
- if(NH > 2)\r
- x = Hll + dh * (int)(NH/2 + 1);\r
- else\r
- x = Hll + dh * (int)(NH/2);\r
- if(NV > 2)\r
- y = Vll + dv * (int)(NV/2 + 1);\r
- else\r
- y = Vll + dv * (int)(NV/2);\r
- }\r
- else\r
- {\r
- if(NH > 1)\r
- x = Hll + dh * (int)(NH/2);\r
- else\r
- x = Hll + dh/2;\r
- if(NV > 1)\r
- y = Vll + dv * (int)(NV/2);\r
- else\r
- y = Vll + dv/2;\r
- }\r
-// x = (Hll+Hur)/2.;\r
-// y = (Vll+Vur)/2.;\r
- v[0].p[0] = x + PlayerBox[Game].x[0];\r
- v[0].p[1] = y + PlayerBox[Game].y[0];\r
- v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist\r
- }\r
- v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0];\r
- v[1].p[1] = v[0].p[1];\r
- v[1].p[2] = v[0].p[2];\r
- v[2].p[0] = v[1].p[0];\r
- v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0];\r
- v[2].p[2] = v[0].p[2];\r
- v[3].p[0] = v[0].p[0];\r
- v[3].p[1] = v[2].p[1];\r
- v[3].p[2] = v[0].p[2];\r
- VectorCopy(v[0].p,v[4].p);\r
- VectorCopy(v[1].p,v[5].p);\r
- VectorCopy(v[2].p,v[6].p);\r
- VectorCopy(v[3].p,v[7].p);\r
- v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
- v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
- v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
- v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];\r
- for(i=0; i<=7; i++)\r
- {\r
-#ifndef ISOMETRIC\r
- project(&v[i]);\r
-#endif\r
- Scale(rc,v[i],&pt[i]);\r
- }\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[3].x, pt[3].y);\r
- for(i=0; i<=3; i++)\r
- g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP);\r
- g_GLTable.m_pfn_qglVertex2f (pt[7].x, pt[7].y);\r
- for(i=4; i<=7; i++)\r
- g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- for(i=0; i<=3; i++)\r
- {\r
- g_GLTable.m_pfn_qglVertex2f (pt[i].x,pt[i].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[i+4].x,pt[i+4].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
-\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
-}\r
-//=============================================================\r
-void DrawGrid(RECT rc)\r
-{\r
- int i, j, k;\r
- double h,w,x,y;\r
- POINT pt[2];\r
- RECT rcBox;\r
-\r
- w = (double)(rc.right-rc.left+1) - cxChar;\r
- h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar;\r
-\r
- SFG = w/(Hur-Hll);\r
- SFG = min(SFG, h/(Vur-Vll));\r
-\r
- // Center drawing\r
- X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2;\r
- Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2;\r
-\r
- g_GLTable.m_pfn_qglLineWidth (2);\r
- g_GLTable.m_pfn_qglColor3f (0, 1, 0);\r
- g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE);\r
-\r
- pt[0].y = Y0G;\r
- pt[1].y = Y0G + (int)(SFG*(Vur-Vll));\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- for(i=0; i<=NH; i++)\r
- {\r
- x = Hll + i * dh;\r
- pt[0].x = X0G + (int)(SFG*(x-Hll));\r
- g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[1].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
- pt[0].x = X0G;\r
- pt[1].x = X0G + (int)(SFG*(Hur-Hll));\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- for(i=0; i<=NV; i++)\r
- {\r
- y = Vll + i * dv;\r
- pt[0].y = Y0G + (int)(SFG*(Vur-y));\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[0].y);\r
- }\r
- g_GLTable.m_pfn_qglEnd ();\r
-\r
- g_GLTable.m_pfn_qglLineWidth (1);\r
-\r
- // Draw axes\r
- pt[0].x = rc.right - cyChar - cxChar - cyChar/2;\r
- pt[0].y = rc.bottom + cyChar/2;\r
- pt[1].x = pt[0].x + cyChar;\r
- pt[1].y = pt[0].y;\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- switch(Plane)\r
- {\r
- case PLANE_YZ0:\r
- case PLANE_YZ1:\r
- texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2);\r
- break;\r
- default:\r
- texfont_write ("X", pt[1].x, pt[1].y+cyChar/2);\r
- }\r
- pt[1].x = pt[0].x;\r
- pt[1].y = pt[0].y + cyChar;\r
- g_GLTable.m_pfn_qglBegin (GL_LINES);\r
- g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y);\r
- g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y);\r
- g_GLTable.m_pfn_qglEnd ();\r
- switch(Plane)\r
- {\r
- case PLANE_XY0:\r
- case PLANE_XY1:\r
- texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar);\r
- break;\r
- default:\r
- texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar);\r
- }\r
-\r
- // Denote fixed points with a 5x5 red rectangle\r
- for(i=0; i<=NH; i++)\r
- {\r
- for(j=0; j<=NV; j++)\r
- {\r
- if(xyz[i][j].fixed)\r
- {\r
- x = Hll + i*dh;\r
- y = Vll + j*dv;\r
- rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2;\r
- rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2;\r
- rcBox.right = rcBox.left + 5;\r
- rcBox.bottom = rcBox.top - 5;\r
-\r
- DRAW_QUAD (rcBox, 1,0,0);\r
- }\r
- }\r
- }\r
-\r
- // Denote currently selected point with a 5x5 green rectangle\r
- if (NumVerticesSelected)\r
- {\r
- for(k=0; k<NumVerticesSelected; k++)\r
- {\r
- x = Hll + Vertex[k].i*dh;\r
- y = Vll + Vertex[k].j*dv;\r
- rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2;\r
- rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2;\r
- rcBox.right = rcBox.left + 5;\r
- rcBox.bottom = rcBox.top - 5;\r
-\r
- DRAW_QUAD (rcBox, 0,1,0);\r
- }\r
- }\r
-\r
- // Unmovable vertices\r
- for(i=0; i<=NH; i++)\r
- {\r
- for(j=0; j<=NV; j++)\r
- {\r
- if(!CanEdit(i,j))\r
- {\r
- x = Hll + i*dh;\r
- y = Vll + j*dv;\r
- rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2;\r
- rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2;\r
- rcBox.right = rcBox.left + 5;\r
- rcBox.bottom = rcBox.top - 5;\r
-\r
- DRAW_QUAD (rcBox, 1,1,0);\r
- }\r
- }\r
- }\r
-\r
- // Legend\r
- rcBox.left = rc.left + cxChar/2 - 2;\r
- rcBox.top = rc.top - cyChar/2 - 2;\r
- rcBox.right = rcBox.left + 5;\r
- rcBox.bottom = rcBox.top - 5;\r
- DRAW_QUAD (rcBox, 1,0,0);\r
- texfont_write ("Fixed points", rcBox.right+cxChar,rcBox.top-4+cyChar/2);\r
-\r
- rcBox.top -= cyChar;\r
- rcBox.bottom -= cyChar;\r
- DRAW_QUAD (rcBox, 1,1,0);\r
- texfont_write ("Not movable", rcBox.right+cxChar, rcBox.top-4+cyChar/2);\r
-\r
- rcBox.top -= cyChar;\r
- rcBox.bottom -= cyChar;\r
- DRAW_QUAD (rcBox, 0,1,0);\r
- texfont_write ("Selected", rcBox.right+cxChar, rcBox.top-4+cyChar/2);\r
-}\r
-\r
-//=============================================================\r
-void GetScaleFactor(RECT rc)\r
-{\r
-#ifdef ISOMETRIC\r
- double h, w;\r
-\r
- w = (double)(rc.right-rc.left+1) - cxChar;\r
- h = (double)(rc.top-rc.bottom+1) - cxChar;\r
-\r
- SF = w/( (XHi-XLo)*COSXA + (YHi-YLo)*COSYA );\r
- SF = min(SF, h/( (XHi-XLo)*SINXA + (YHi-YLo)*SINYA + ZHi-ZLo ) );\r
- // Center drawing\r
- X0 = (int)(rc.left + rc.right - (int)(SF*( (XHi-XLo)*COSXA + (YHi-YLo)*COSYA )) )/2;\r
- Y0 = (int)(rc.top + rc.bottom - (int)(SF*( (XHi-XLo)*SINXA + (YHi-YLo)*SINYA + ZHi-ZLo) ))/2;\r
-\r
-#else\r
- double h, w;\r
-\r
- w = (double)(rc.right-rc.left+1) - cxChar;\r
- h = (double)(rc.top-rc.bottom+1) - cxChar;\r
-\r
- SF = w/(Hhi-Hlo);\r
- SF = min(SF, h/(Vhi-Vlo) );\r
- X0 = (int)(rc.left + rc.right - (int)(SF*(Hhi-Hlo)))/2;\r
- Y0 = (int)(rc.top + rc.bottom + (int)(SF*(Vhi-Vlo)))/2;\r
-#endif\r
-}\r
-\r
-//=============================================================\r
-void Scale(RECT rc,XYZ xyz,POINT *pt)\r
-{\r
-\r
-#ifdef ISOMETRIC\r
-\r
- pt[0].x = X0 + (int)(SF*( (xyz.p[0]-XLo)*COSXA +\r
- (YHi-xyz.p[1])*COSYA ));\r
- pt[0].y = Y0 + (int)(SF*( ZHi-xyz.p[2] +\r
- (YHi-xyz.p[1])*SINYA +\r
- (XHi-xyz.p[0])*SINXA ));\r
-#else\r
- pt[0].x = X0 + (int)(SF*( xyz.pp[0] - Hlo ) );\r
- pt[0].y = Y0 - (int)(SF*( Vhi - xyz.pp[1] ) );\r
-#endif\r
-\r
-}\r
-\r
-#ifndef ISOMETRIC\r
-/* ======================================================================= */\r
-void project(XYZ *v)\r
-{\r
- // project a 3D point (x,y,z) onto view plane\r
- double x, y, z, xa, ya, za;\r
-\r
- x = v->p[0];\r
- y = v->p[1];\r
- z = v->p[2];\r
-\r
- // yaw\r
- xa = ct[0]*x - st[0]*z;\r
- za = st[0]*x + ct[0]*z;\r
-\r
- // roll\r
- x = ct[1]*xa + st[1]*y;\r
- ya = ct[1]*y - st[1]*xa;\r
-\r
- // azimuth\r
- z = ct[2]*za - st[2]*ya;\r
- y = ct[2]*ya + st[2]*za;\r
-\r
- // horizontal and vertical projections:\r
-// v->pp[0] = D*x/z;\r
-// v->pp[1] = D*y/z;\r
- v->pp[0] = -y;\r
- v->pp[1] = x;\r
- v->pp[2] = z;\r
-\r
- // NOTE: if perspective transformation is desired,\r
- // set "persp" to the range from the surface,\r
- // then:\r
- // v->projected_h = -v->projected_h * persp/(v->projected_z-persp);\r
- // v->projected_v = -v->projected_v * persp/(v->projected_z-persp);\r
-}\r
-/*=======================================================================*/\r
-void evaluate()\r
-{\r
- int i, j;\r
- XYZ v[4];\r
- \r
- if(elevation > PI) elevation -= 2.*PI;\r
- roll = elevation * sin(azimuth);\r
- yaw = 1.5*PI + elevation*cos(azimuth);\r
-\r
- // Find angles from midpoint to viewpoint:\r
- st[0] = sin(yaw);\r
- st[1] = sin(roll);\r
- st[2] = sin(azimuth);\r
- ct[0] = cos(yaw);\r
- ct[1] = cos(roll);\r
- ct[2] = cos(azimuth);\r
-\r
- for(i=0; i<=NH; i++)\r
- {\r
- for(j=0; j<=NV; j++)\r
- {\r
- project(&xyz[i][j]);\r
- }\r
- }\r
-\r
- Hhi = xyz[0][0].pp[0];\r
- Hlo = Hhi;\r
- Vhi = xyz[0][0].pp[1];\r
- Vlo = Vhi;\r
- for(i=0; i<=NH; i++)\r
- {\r
- for(j=0; j<=NV; j++)\r
- {\r
- Hlo = min(Hlo,xyz[i][j].pp[0]);\r
- Hhi = max(Hhi,xyz[i][j].pp[0]);\r
- Vlo = min(Vlo,xyz[i][j].pp[1]);\r
- Vhi = max(Vhi,xyz[i][j].pp[1]);\r
- }\r
- }\r
-\r
- // Include backface in min-max\r
- VectorCopy(xyz[ 0][ 0].p,v[0].p);\r
- VectorCopy(xyz[NH][ 0].p,v[1].p);\r
- VectorCopy(xyz[NH][NV].p,v[2].p);\r
- VectorCopy(xyz[ 0][NV].p,v[3].p);\r
- switch(Plane)\r
- {\r
- case PLANE_XZ0:\r
- case PLANE_XZ1:\r
- v[0].p[1] = backface;\r
- v[1].p[1] = v[0].p[1];\r
- v[2].p[1] = v[0].p[1];\r
- v[3].p[1] = v[0].p[1];\r
- break;\r
- case PLANE_YZ0:\r
- case PLANE_YZ1:\r
- v[0].p[0] = backface;\r
- v[1].p[0] = v[0].p[0];\r
- v[2].p[0] = v[0].p[0];\r
- v[3].p[0] = v[0].p[0];\r
- break;\r
- default:\r
- v[0].p[2] = backface;\r
- v[1].p[2] = v[0].p[2];\r
- v[2].p[2] = v[0].p[2];\r
- v[3].p[2] = v[0].p[2];\r
- }\r
- for(i=0; i<=3; i++)\r
- {\r
- project(&v[i]);\r
- Hlo = min(Hlo,v[i].pp[0]);\r
- Hhi = max(Hhi,v[i].pp[0]);\r
- Vlo = min(Vlo,v[i].pp[1]);\r
- Vhi = max(Vhi,v[i].pp[1]);\r
- }\r
-\r
-}\r
-#endif\r
+/*
+ GenSurf plugin for GtkRadiant
+ Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include "gensurf.h"
+
+#undef ISOMETRIC
+
+extern double backface;
+extern double dh, dv;
+extern double xmin,xmax,ymin,ymax,zmin,zmax;
+
+double SF, SFG; // Graphics scale factors
+double XLo, XHi, YLo, YHi, ZLo, ZHi;
+double yaw,roll;
+double elevation,azimuth;
+int cxChar = 10, cyChar = 16;
+int X0, Y0;
+int X0G, Y0G;
+
+static Rect rcCoord; // where X= Y= is drawn
+static Rect rcGrid; // rectangle within rcLower that forms the border of the grid, plus
+ // a 3 pixel slop.
+static Rect rcLower; // lower half of window, where plan view is drawn
+static Rect rcUpper; // upper half or entire window, where isometric projection is drawn
+
+void vertex_selected();
+void texfont_init();
+void texfont_write( const char *text, int l, int t );
+
+#define PEN_GRID { \
+ g_GLTable.m_pfn_qglLineWidth( 1 ); \
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 ); \
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE ); }
+
+#define PEN_RED { \
+ g_GLTable.m_pfn_qglLineWidth( 2 ); \
+ g_GLTable.m_pfn_qglColor3f( 1, 0, 0 ); \
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE ); }
+
+#define PEN_DASH { \
+ g_GLTable.m_pfn_qglLineWidth( 1 ); \
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 ); \
+ g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 ); \
+ g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE ); }
+
+#define DRAW_QUAD( rc,r,g,b ) { \
+ g_GLTable.m_pfn_qglBegin( GL_QUADS ); \
+ g_GLTable.m_pfn_qglColor3f( 0,1,0 ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.left - 1, rc.bottom ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.right, rc.bottom ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.right, rc.top + 1 ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.left - 1, rc.top + 1 ); \
+ g_GLTable.m_pfn_qglColor3f( r,g,b ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.left, rc.bottom + 1 ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.right - 1, rc.bottom + 1 ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.right - 1, rc.top ); \
+ g_GLTable.m_pfn_qglVertex2i( rc.left, rc.top ); \
+ g_GLTable.m_pfn_qglEnd(); }
+
+
+#ifndef ISOMETRIC
+double D = 65536.;
+double ct[3],st[3];
+double Hhi, Hlo, Vhi, Vlo;
+#endif
+
+#define SUBDIVS 6
+
+
+void ShowPreview(){
+ if ( Preview ) {
+ if ( g_pWndPreview == NULL ) {
+ CreateViewWindow();
+ }
+ gtk_widget_show( g_pWndPreview );
+
+ UpdatePreview( true );
+ }
+ else{
+ gtk_widget_hide( g_pWndPreview );
+ }
+}
+
+static void draw_preview(){
+ int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height;
+
+ g_GLTable.m_pfn_qglClearColor( 0, 0, 0, 1 );
+ g_GLTable.m_pfn_qglViewport( 0, 0, width, height );
+ g_GLTable.m_pfn_qglMatrixMode( GL_PROJECTION );
+ g_GLTable.m_pfn_qglLoadIdentity();
+ g_GLTable.m_pfn_qglOrtho( 0, width, 0, height, -1, 1 );
+ g_GLTable.m_pfn_qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ // ^Fishman - Antializing for the preview window.
+ if ( Antialiasing ) {
+ g_GLTable.m_pfn_qglEnable( GL_BLEND );
+ g_GLTable.m_pfn_qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
+ g_GLTable.m_pfn_qglEnable( GL_LINE_SMOOTH );
+ }
+ else
+ {
+ g_GLTable.m_pfn_qglDisable( GL_BLEND );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_SMOOTH );
+ }
+
+ texfont_init();
+
+ if ( !ValidSurface() ) {
+ return;
+ }
+
+ rcUpper.left = 0;
+ rcUpper.right = width;
+ rcUpper.bottom = 0;
+ rcUpper.top = height;
+ rcLower.left = 0;
+ rcLower.right = width;
+ rcLower.bottom = 0;
+ rcLower.top = height;
+
+ if ( VertexMode ) {
+ rcUpper.bottom = rcUpper.top / 2;
+ DrawPreview( rcUpper );
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ g_GLTable.m_pfn_qglVertex2i( rcUpper.left, rcUpper.bottom );
+ g_GLTable.m_pfn_qglVertex2i( rcUpper.right, rcUpper.bottom );
+ g_GLTable.m_pfn_qglEnd();
+ rcLower.top = rcUpper.bottom - 1;
+ DrawGrid( rcLower );
+ rcCoord.left = rcLower.left;
+ rcCoord.right = rcLower.right;
+ rcCoord.bottom = rcLower.bottom;
+ rcCoord.top = rcLower.top;
+ rcCoord.top = rcCoord.bottom + cyChar;
+ rcCoord.right = rcCoord.left + 15 * cxChar;
+ rcGrid.left = X0G - 3;
+ rcGrid.bottom = Y0G - 3;
+ rcGrid.right = X0G + (int)( SFG * ( Hur - Hll ) ) + 3;
+ rcGrid.top = Y0G + (int)( SFG * ( Vur - Vll ) ) + 3;
+ }
+ else{
+ DrawPreview( rcUpper );
+ }
+}
+
+static gint expose( GtkWidget *widget, GdkEventExpose *event, gpointer data ){
+ if ( event->count > 0 ) {
+ return TRUE;
+ }
+
+ if ( !g_UIGtkTable.m_pfn_glwidget_make_current( g_pPreviewWidget ) ) {
+ g_FuncTable.m_pfnSysPrintf( "GtkGenSurf: glMakeCurrent failed\n" );
+ return TRUE;
+ }
+
+ draw_preview();
+
+ g_UIGtkTable.m_pfn_glwidget_swap_buffers( g_pPreviewWidget );
+ g_GLTable.m_pfn_QE_CheckOpenGLForErrors();
+
+ return TRUE;
+}
+
+static void button_press( GtkWidget *widget, GdkEventButton *event, gpointer data ){
+ Point pt = { (long)event->x, widget->allocation.height - (long)event->y };
+ bool Selected;
+ double x,y;
+ int i, j, k, ks;
+ int i0, i1, j0, j1;
+
+ if ( ( !VertexMode ) || ( event->button != 1 ) ) {
+ return;
+ }
+
+ if ( !PtInRect( &rcGrid,pt ) ) {
+ gdk_beep();
+ return;
+ }
+
+ x = Hll + ( pt.x - X0G ) / SFG;
+ y = Vur - ( pt.y - Y0G ) / SFG;
+ i = (int)( floor( ( x - Hll ) / dh - 0.5 ) + 1 );
+ j = (int)( floor( ( y - Vll ) / dv - 0.5 ) + 1 );
+ if ( i < 0 || i > NH || j < 0 || j > NV ) {
+ gdk_beep();
+ return;
+ }
+
+ if ( !CanEdit( i,j ) ) {
+ gdk_beep();
+ return;
+ }
+
+ // Control key pressed - add this point, or remove it if already selected
+ if ( ( event->state & GDK_CONTROL_MASK ) != 0 ) {
+ Selected = FALSE;
+ if ( NumVerticesSelected ) {
+ for ( k = 0; k < NumVerticesSelected && !Selected; k++ )
+ {
+ if ( Vertex[k].i == i && Vertex[k].j == j ) {
+ Selected = TRUE;
+ ks = k;
+ }
+ }
+ }
+
+ // Already selected - unselect it.
+ if ( Selected ) {
+ if ( ks < NumVerticesSelected ) {
+ for ( k = ks; k < NumVerticesSelected - 1; k++ )
+ {
+ Vertex[k].i = Vertex[k + 1].i;
+ Vertex[k].j = Vertex[k + 1].j;
+ }
+ NumVerticesSelected--;
+ }
+ }
+ else
+ {
+ Vertex[NumVerticesSelected].i = i;
+ Vertex[NumVerticesSelected].j = j;
+ NumVerticesSelected++;
+ }
+ }
+ else if ( ( event->state & GDK_SHIFT_MASK ) != 0 ) {
+ if ( NumVerticesSelected ) {
+ NumVerticesSelected = 1;
+ i0 = min( Vertex[0].i, i );
+ i1 = max( Vertex[0].i, i );
+ j0 = min( Vertex[0].j, j );
+ j1 = max( Vertex[0].j, j );
+ for ( i = i0; i <= i1; i++ )
+ {
+ for ( j = j0; j <= j1; j++ )
+ {
+ if ( i == 0 && j == 0 ) {
+ continue;
+ }
+ if ( i == NH && j == 0 ) {
+ continue;
+ }
+ if ( i == 0 && j == NV ) {
+ continue;
+ }
+ if ( i == NH && j == NV ) {
+ continue;
+ }
+ if ( i != Vertex[0].i || j != Vertex[0].j ) {
+ Vertex[NumVerticesSelected].i = i;
+ Vertex[NumVerticesSelected].j = j;
+ NumVerticesSelected++;
+ }
+ }
+ }
+ }
+ else
+ {
+ Vertex[0].i = i;
+ Vertex[0].j = j;
+ NumVerticesSelected = 1;
+ }
+ }
+ else
+ {
+ Vertex[0].i = i;
+ Vertex[0].j = j;
+ NumVerticesSelected = 1;
+ }
+
+ vertex_selected();
+}
+
+static void motion( GtkWidget *widget, GdkEventMotion *event, gpointer data ){
+ Point pt = { (long)event->x, widget->allocation.height - (long)event->y };
+
+ if ( !VertexMode ) {
+ return;
+ }
+
+ if ( !g_UIGtkTable.m_pfn_glwidget_make_current( g_pPreviewWidget ) ) {
+ g_FuncTable.m_pfnSysPrintf( "GtkGenSurf: glMakeCurrent failed\n" );
+ return;
+ }
+
+ g_GLTable.m_pfn_qglEnable( GL_SCISSOR_TEST );
+ g_GLTable.m_pfn_qglScissor( rcCoord.left, rcCoord.bottom, rcCoord.right - rcCoord.left,
+ rcCoord.top - rcCoord.bottom );
+ g_GLTable.m_pfn_qglClear( GL_COLOR_BUFFER_BIT );
+
+ if ( PtInRect( &rcGrid,pt ) ) {
+ GdkCursor *cursor = gdk_cursor_new( GDK_CROSS );
+ gdk_window_set_cursor( g_pWndPreview->window, cursor );
+ gdk_cursor_unref( cursor );
+
+ char Text[32];
+ int x, y;
+
+ x = (int)( Hll + ( pt.x - X0G ) / SFG );
+ y = (int)( Vur - ( pt.y - Y0G ) / SFG );
+ switch ( Plane )
+ {
+ case PLANE_XZ0:
+ case PLANE_XZ1:
+ sprintf( Text," x=%d, z=%d ",(int)( floor( x - 0.5 ) + 1. ),(int)( floor( y - 0.5 ) + 1. ) );
+ break;
+ case PLANE_YZ0:
+ case PLANE_YZ1:
+ sprintf( Text," y=%d, z=%d ",(int)( floor( x - 0.5 ) + 1. ),(int)( floor( y - 0.5 ) + 1. ) );
+ break;
+ default:
+ sprintf( Text," x=%d, y=%d ",(int)( floor( x - 0.5 ) + 1. ),(int)( floor( y - 0.5 ) + 1. ) );
+ }
+
+ texfont_write( Text, rcCoord.left, rcCoord.top );
+ }
+ else
+ {
+ gdk_window_set_cursor( g_pWndPreview->window, NULL );
+ }
+
+ g_UIGtkTable.m_pfn_glwidget_swap_buffers( g_pPreviewWidget );
+ g_GLTable.m_pfn_QE_CheckOpenGLForErrors();
+ g_GLTable.m_pfn_qglDisable( GL_SCISSOR_TEST );
+}
+
+static gint preview_close( GtkWidget *widget, gpointer data ){
+ gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( g_pWnd ), "main_preview" ) ), FALSE );
+ return TRUE;
+}
+
+static void preview_focusout( GtkSpinButton *spin, GdkEventFocus *event, double *data ){
+ *data = DegreesToRadians( (double)( gtk_spin_button_get_value_as_int( spin ) % 360 ) );
+ UpdatePreview( false );
+}
+
+static gint doublevariable_spinfocusout( GtkWidget* widget, GdkEventFocus* event, gpointer data ){
+ preview_focusout( GTK_SPIN_BUTTON( widget ), event, reinterpret_cast<double*>( data ) );
+ return FALSE;
+}
+
+static void preview_spin( GtkAdjustment *adj, double *data ){
+ *data = DegreesToRadians( adj->value );
+ UpdatePreview( false );
+}
+
+void CreateViewWindow(){
+ GtkWidget *hbox, *label, *spin;
+
+#ifndef ISOMETRIC
+ elevation = PI / 6.;
+ azimuth = PI / 6.;
+#endif
+
+ auto dlg = g_pWndPreview = ui::Window( ui::window_type::TOP );
+ gtk_window_set_title( GTK_WINDOW( dlg ), "GtkGenSurf Preview" );
+ dlg.connect( "delete_event", G_CALLBACK( preview_close ), NULL );
+ dlg.connect( "destroy", G_CALLBACK( gtk_widget_destroy ), NULL );
+ gtk_window_set_transient_for( GTK_WINDOW( dlg ), GTK_WINDOW( g_pWnd ) );
+ gtk_window_set_default_size( GTK_WINDOW( dlg ), 300, 400 );
+
+ auto vbox = ui::VBox( FALSE, 5 );
+ vbox.show();
+ dlg.add(vbox);
+
+#ifndef ISOMETRIC
+ hbox = ui::HBox( TRUE, 5 );
+ gtk_widget_show( hbox );
+ gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, TRUE, 0 );
+ gtk_container_set_border_width( GTK_CONTAINER( hbox ), 3 );
+
+ label = ui::Label( "Elevation" );
+ gtk_widget_show( label );
+ gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
+ gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, TRUE, 0 );
+
+ auto adj = ui::Adjustment( 30, -90, 90, 1, 10, 0 );
+ adj.connect( "value_changed", G_CALLBACK( preview_spin ), &elevation );
+ spin = ui::SpinButton( adj, 1, 0 );
+ gtk_widget_show( spin );
+ gtk_box_pack_start( GTK_BOX( hbox ), spin, FALSE, TRUE, 0 );
+ spin.connect( "focus_out_event", G_CALLBACK( doublevariable_spinfocusout ), &elevation );
+
+ adj = ui::Adjustment( 30, 0, 359, 1, 10, 0 );
+ adj.connect( "value_changed", G_CALLBACK( preview_spin ), &azimuth );
+ spin = ui::SpinButton( adj, 1, 0 );
+ gtk_widget_show( spin );
+ gtk_spin_button_set_wrap( GTK_SPIN_BUTTON( spin ), TRUE );
+ gtk_box_pack_end( GTK_BOX( hbox ), spin, FALSE, TRUE, 0 );
+
+ label = ui::Label( "Azimuth" );
+ gtk_widget_show( label );
+ gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
+ gtk_box_pack_end( GTK_BOX( hbox ), label, FALSE, TRUE, 0 );
+ spin.connect( "focus_out_event", G_CALLBACK( doublevariable_spinfocusout ), &azimuth );
+#endif
+
+ auto frame = ui::Frame(ui::null);
+ frame.show();
+ gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );
+ gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 0 );
+
+ g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new( FALSE, NULL );
+
+ gtk_widget_set_events( g_pPreviewWidget, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK );
+ g_pPreviewWidget.connect( "expose_event", G_CALLBACK( expose ), NULL );
+ g_pPreviewWidget.connect( "motion_notify_event", G_CALLBACK( motion ), NULL );
+ g_pPreviewWidget.connect( "button_press_event",
+ G_CALLBACK( button_press ), NULL );
+
+ gtk_widget_show( g_pPreviewWidget );
+ frame.add(ui::Widget(g_pPreviewWidget));
+
+ if ( Preview ) {
+ gtk_widget_show( g_pWndPreview );
+ }
+
+ UpdatePreview( true );
+}
+
+//=============================================================
+/* DrawPreview */
+void DrawPreview( Rect rc ){
+#define COSXA 0.8660254037844
+#define SINXA 0.5
+#define COSYA 0.8660254037844
+#define SINYA 0.5
+
+ double L;
+ double x,y;
+ int i, j;
+ Point pt[8];
+ XYZ v[8];
+ char axis[3][2] = {"X","Y","Z"};
+
+#ifndef ISOMETRIC
+ evaluate();
+#endif
+
+ XLo = xmin;
+ XHi = xmax;
+ YLo = ymin;
+ YHi = ymax;
+ ZLo = zmin;
+ ZHi = zmax;
+ switch ( Plane )
+ {
+ case PLANE_XY1:
+ ZHi = backface;
+ break;
+ case PLANE_XZ0:
+ YLo = backface;
+ break;
+ case PLANE_XZ1:
+ YHi = backface;
+ break;
+ case PLANE_YZ0:
+ XLo = backface;
+ break;
+ case PLANE_YZ1:
+ XHi = backface;
+ break;
+ default:
+ ZLo = backface;
+ }
+
+
+
+ GetScaleFactor( rc );
+ //PEN_GRID
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+
+ if ( Decimate > 0 && ( Game != QUAKE3 || UsePatches == 0 ) ) {
+ XYZ *vv;
+
+ vv = (XYZ *) malloc( gNumNodes * sizeof( XYZ ) );
+ for ( i = 0; i < gNumNodes; i++ )
+ {
+ for ( j = 0; j < 3; j++ )
+ vv[i].p[j] = (double)( gNode[i].p[j] );
+ project( &vv[i] );
+ }
+
+ for ( i = 0; i < gNumTris; i++ )
+ {
+ for ( j = 0; j < 3; j++ )
+ Scale( rc,vv[gTri[i].v[j]],&pt[j] );
+
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[1].x, pt[1].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[2].x, pt[2].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ g_GLTable.m_pfn_qglEnd();
+ }
+ free( vv );
+ }
+ else if ( Game == QUAKE3 && UsePatches != 0 ) {
+ int axis, ii, jj, k;
+ float u, v;
+ XYZ uv[3][3];
+ XYZ Ctrl[3],out;
+
+ switch ( Plane )
+ {
+ case PLANE_XY0:
+ case PLANE_XY1:
+ k = 2;
+ break;
+ case PLANE_XZ0:
+ case PLANE_XZ1:
+ k = 1;
+ break;
+ default:
+ k = 0;
+ }
+ for ( i = 0; i < NH; i += 2 )
+ {
+ for ( j = 0; j < NV; j += 2 )
+ {
+ VectorCopy( xyz[i ][j ].p,uv[0][0].p );
+ VectorCopy( xyz[i + 1][j ].p,uv[1][0].p );
+ VectorCopy( xyz[i + 2][j ].p,uv[2][0].p );
+ VectorCopy( xyz[i ][j + 1].p,uv[0][1].p );
+ VectorCopy( xyz[i + 1][j + 1].p,uv[1][1].p );
+ VectorCopy( xyz[i + 2][j + 1].p,uv[2][1].p );
+ VectorCopy( xyz[i ][j + 2].p,uv[0][2].p );
+ VectorCopy( xyz[i + 1][j + 2].p,uv[1][2].p );
+ VectorCopy( xyz[i + 2][j + 2].p,uv[2][2].p );
+ uv[1][0].p[k] = ( 4 * xyz[i + 1][j ].p[k] - xyz[i ][j ].p[k] - xyz[i + 2][j ].p[k] ) / 2;
+ uv[0][1].p[k] = ( 4 * xyz[i ][j + 1].p[k] - xyz[i ][j ].p[k] - xyz[i ][j + 2].p[k] ) / 2;
+ 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;
+ 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;
+ uv[1][1].p[k] = ( 16 * xyz[i + 1][j + 1].p[k] -
+ xyz[i ][j ].p[k] - 2 * xyz[i + 1][j ].p[k] - xyz[i + 2][j ].p[k] -
+ 2 * xyz[i ][j + 1].p[k] - 2 * xyz[i + 2][j + 1].p[k] -
+ xyz[i ][j + 2].p[k] - 2 * xyz[i + 1][j + 2].p[k] - xyz[i + 2][j + 2].p[k] ) / 4;
+
+ for ( ii = 0; ii <= SUBDIVS; ii++ )
+ {
+ if ( ii == 0 || ii == SUBDIVS / 2 || ii == SUBDIVS ) {
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+ // PEN_GRID
+ }
+ else
+ {
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 );
+ g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE );
+ // PEN_DASH
+ }
+
+ u = (float)( ii ) / (float)( SUBDIVS );
+ for ( jj = 0; jj < 3; jj++ )
+ {
+ for ( axis = 0; axis < 3; axis++ )
+ {
+ float a, b, c;
+ float qA, qB, qC;
+ a = (float)uv[0][jj].p[axis];
+ b = (float)uv[1][jj].p[axis];
+ c = (float)uv[2][jj].p[axis];
+ qA = a - 2 * b + c;
+ qB = 2 * b - 2 * a;
+ qC = a;
+ Ctrl[jj].p[axis] = qA * u * u + qB * u + qC;
+ }
+ }
+ VectorCopy( Ctrl[0].p,out.p );
+ project( &out );
+ Scale( rc,out,&pt[0] );
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ for ( jj = 1; jj <= SUBDIVS; jj++ )
+ {
+ v = (float)( jj ) / (float)( SUBDIVS );
+ for ( axis = 0 ; axis < 3 ; axis++ )
+ {
+ float a, b, c;
+ float qA, qB, qC;
+ a = (float)Ctrl[0].p[axis];
+ b = (float)Ctrl[1].p[axis];
+ c = (float)Ctrl[2].p[axis];
+ qA = a - 2 * b + c;
+ qB = 2 * b - 2 * a;
+ qC = a;
+ out.p[axis] = qA * v * v + qB * v + qC;
+ }
+ project( &out );
+ Scale( rc,out,&pt[0] );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+ }
+ for ( jj = 0; jj <= SUBDIVS; jj++ )
+ {
+ if ( jj == 0 || jj == SUBDIVS / 2 || jj == SUBDIVS ) {
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+ // PEN_GRID
+ }
+ else
+ {
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 );
+ g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE );
+ // PEN_DASH
+ }
+
+ v = (float)( jj ) / (float)( SUBDIVS );
+ for ( ii = 0; ii < 3; ii++ )
+ {
+ for ( axis = 0; axis < 3; axis++ )
+ {
+ float a, b, c;
+ float qA, qB, qC;
+ a = (float)uv[ii][0].p[axis];
+ b = (float)uv[ii][1].p[axis];
+ c = (float)uv[ii][2].p[axis];
+ qA = a - 2 * b + c;
+ qB = 2 * b - 2 * a;
+ qC = a;
+ Ctrl[ii].p[axis] = qA * v * v + qB * v + qC;
+ }
+ }
+ VectorCopy( Ctrl[0].p,out.p );
+ project( &out );
+ Scale( rc,out,&pt[0] );
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ for ( ii = 1; ii <= SUBDIVS; ii++ )
+ {
+ u = (float)( ii ) / (float)( SUBDIVS );
+ for ( axis = 0 ; axis < 3 ; axis++ )
+ {
+ float a, b, c;
+ float qA, qB, qC;
+ a = (float)Ctrl[0].p[axis];
+ b = (float)Ctrl[1].p[axis];
+ c = (float)Ctrl[2].p[axis];
+ qA = a - 2 * b + c;
+ qB = 2 * b - 2 * a;
+ qC = a;
+ out.p[axis] = qA * u * u + qB * u + qC;
+ }
+ project( &out );
+ Scale( rc,out,&pt[0] );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+ }
+ }
+ }
+ }
+ else
+ {
+ for ( i = 0; i <= NH; i++ )
+ {
+ Scale( rc,xyz[i][0],&pt[0] );
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ for ( j = 1; j <= NV; j++ )
+ {
+ Scale( rc,xyz[i][j],&pt[0] );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+ }
+ for ( j = 0; j <= NV; j++ )
+ {
+ Scale( rc,xyz[0][j],&pt[0] );
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ for ( i = 1; i <= NH; i++ )
+ {
+ Scale( rc,xyz[i][j],&pt[0] );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+ }
+ }
+
+ if ( Game != QUAKE3 || UsePatches == 0 ) {
+ // Draw lines from corners to base, and lines around base
+ for ( i = 0; i <= NH; i += NH )
+ {
+ for ( j = 0; j <= NV; j += NV )
+ {
+ VectorCopy( xyz[i][j].p, v[0].p );
+ switch ( Plane )
+ {
+ case PLANE_XZ0:
+ case PLANE_XZ1:
+ v[0].p[1] = backface;
+ break;
+ case PLANE_YZ0:
+ case PLANE_YZ1:
+ v[0].p[0] = backface;
+ break;
+ default:
+ v[0].p[2] = backface;
+ }
+ Scale( rc,xyz[i][j],&pt[0] );
+#ifndef ISOMETRIC
+ project( &v[0] );
+#endif
+ Scale( rc,v[0],&pt[1] );
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[1].x, pt[1].y );
+ g_GLTable.m_pfn_qglEnd();
+ }
+ }
+ VectorCopy( xyz[ 0][ 0].p, v[0].p );
+ VectorCopy( xyz[NH][ 0].p, v[1].p );
+ VectorCopy( xyz[NH][NV].p, v[2].p );
+ VectorCopy( xyz[ 0][NV].p, v[3].p );
+ switch ( Plane )
+ {
+ case PLANE_XZ0:
+ case PLANE_XZ1:
+ v[0].p[1] = backface;;
+ v[1].p[1] = v[0].p[1];
+ v[2].p[1] = v[0].p[1];
+ v[3].p[1] = v[0].p[1];
+ break;
+ case PLANE_YZ0:
+ case PLANE_YZ1:
+ v[0].p[0] = backface;
+ v[1].p[0] = v[0].p[0];
+ v[2].p[0] = v[0].p[0];
+ v[3].p[0] = v[0].p[0];
+ break;
+ default:
+ v[0].p[2] = backface;
+ v[1].p[2] = v[0].p[2];
+ v[2].p[2] = v[0].p[2];
+ v[3].p[2] = v[0].p[2];
+ }
+#ifndef ISOMETRIC
+ project( &v[3] );
+#endif
+ Scale( rc,v[3],&pt[0] );
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ for ( i = 0; i < 3; i++ )
+ {
+#ifndef ISOMETRIC
+ project( &v[i] );
+#endif
+ Scale( rc,v[i],&pt[1] );
+ g_GLTable.m_pfn_qglVertex2i( pt[1].x, pt[1].y );
+ }
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ g_GLTable.m_pfn_qglEnd();
+ }
+
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+
+#ifdef ISOMETRIC
+ // Draw small depiction of coordinate axes
+ pt[0].x = rc.right - cxChar - cxChar / 2 - cyChar;
+ pt[0].y = rc.bottom - cyChar / 2 - cxChar / 2;
+ pt[1].x = pt[0].x + (int)( cyChar * COSXA );
+ pt[1].y = pt[0].y - (int)( cyChar * SINXA );
+ MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
+ LineTo( hdc,pt[1].x,pt[1].y );
+ SetTextAlign( hdc,TA_LEFT | TA_TOP );
+ TextOut( hdc,pt[1].x,pt[1].y - cyChar / 2,"X",1 );
+ pt[1].x = pt[0].x - (int)( cyChar * COSYA );
+ pt[1].y = pt[0].y - (int)( cyChar * SINYA );
+ MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
+ LineTo( hdc,pt[1].x,pt[1].y );
+ SetTextAlign( hdc,TA_RIGHT | TA_TOP );
+ TextOut( hdc,pt[1].x,pt[1].y - cyChar / 2,"Y",1 );
+ pt[1].x = pt[0].x;
+ pt[1].y = pt[0].y - cyChar;
+ MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
+ LineTo( hdc,pt[1].x,pt[1].y );
+ SetTextAlign( hdc,TA_CENTER | TA_BOTTOM );
+ TextOut( hdc,pt[1].x,pt[1].y,"Z",1 );
+#else
+ L = 2 * (double)cyChar / SF;
+ v[0].p[0] = 0.;
+ v[0].p[1] = 0.;
+ v[0].p[2] = 0.;
+ v[1].p[0] = L;
+ v[1].p[1] = 0.;
+ v[1].p[2] = 0.;
+ v[2].p[0] = 0.;
+ v[2].p[1] = L;
+ v[2].p[2] = 0.;
+ v[3].p[0] = 0.;
+ v[3].p[1] = 0.;
+ v[3].p[2] = L;
+ for ( i = 0; i <= 3; i++ )
+ {
+ project( &v[i] );
+ Scale( rc,v[i],&pt[i] );
+ }
+ for ( i = 1; i <= 3; i++ )
+ {
+ pt[i].x += -pt[0].x + rc.right - 2 * cyChar;
+ pt[i].y += -pt[0].y + rc.bottom + 2 * cyChar;
+ }
+ pt[0].x = rc.right - 2 * cyChar;
+ pt[0].y = rc.bottom + 2 * cyChar;
+
+ for ( i = 1; i <= 3; i++ )
+ {
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[i].x, pt[i].y );
+ g_GLTable.m_pfn_qglEnd();
+ texfont_write( axis[i - 1], pt[i].x - cxChar / 2,pt[i].y + cyChar / 2 );
+ }
+#endif
+
+ // Draw player model's bounding box in red to give a sense of scale
+ // PEN_RED
+ g_GLTable.m_pfn_qglLineWidth( 2 );
+ g_GLTable.m_pfn_qglColor3f( 1, 0, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+
+ switch ( Plane )
+ {
+ case PLANE_XY1:
+ v[0].p[0] = xyz[NH / 2][NV / 2].p[0] + PlayerBox[Game].x[0];
+ v[0].p[1] = xyz[NH / 2][NV / 2].p[1] + PlayerBox[Game].y[0];
+ v[0].p[2] = zmin - PlayerBox[Game].z[0] - 32;
+ break;
+ case PLANE_XZ0:
+ v[0].p[0] = ( xmax + xmin ) / 2 + PlayerBox[Game].x[0];
+ v[0].p[1] = ymax + 64;
+ v[0].p[2] = zmin;
+ break;
+ case PLANE_XZ1:
+ v[0].p[0] = ( xmax + xmin ) / 2 + PlayerBox[Game].x[0];
+ v[0].p[1] = ymin - 64;
+ v[0].p[2] = zmin;
+ break;
+ case PLANE_YZ0:
+ v[0].p[0] = xmax + 64;
+ v[0].p[1] = ( ymax + ymin ) / 2 + PlayerBox[Game].y[0];
+ v[0].p[2] = zmin;
+ break;
+ case PLANE_YZ1:
+ v[0].p[0] = xmin - 64;
+ v[0].p[1] = ( ymax + ymin ) / 2 + PlayerBox[Game].y[0];
+ v[0].p[2] = zmin;
+ break;
+ default:
+ // Put player on a node. For patches, put on an even numbered node.
+ if ( Game == QUAKE3 && UsePatches != 0 ) {
+ if ( NH > 2 ) {
+ x = Hll + dh * (int)( NH / 2 + 1 );
+ }
+ else{
+ x = Hll + dh * (int)( NH / 2 );
+ }
+ if ( NV > 2 ) {
+ y = Vll + dv * (int)( NV / 2 + 1 );
+ }
+ else{
+ y = Vll + dv * (int)( NV / 2 );
+ }
+ }
+ else
+ {
+ if ( NH > 1 ) {
+ x = Hll + dh * (int)( NH / 2 );
+ }
+ else{
+ x = Hll + dh / 2;
+ }
+ if ( NV > 1 ) {
+ y = Vll + dv * (int)( NV / 2 );
+ }
+ else{
+ y = Vll + dv / 2;
+ }
+ }
+// x = (Hll+Hur)/2.;
+// y = (Vll+Vur)/2.;
+ v[0].p[0] = x + PlayerBox[Game].x[0];
+ v[0].p[1] = y + PlayerBox[Game].y[0];
+ v[0].p[2] = PlayerStartZ( x,y ) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist
+ }
+ v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0];
+ v[1].p[1] = v[0].p[1];
+ v[1].p[2] = v[0].p[2];
+ v[2].p[0] = v[1].p[0];
+ v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0];
+ v[2].p[2] = v[0].p[2];
+ v[3].p[0] = v[0].p[0];
+ v[3].p[1] = v[2].p[1];
+ v[3].p[2] = v[0].p[2];
+ VectorCopy( v[0].p,v[4].p );
+ VectorCopy( v[1].p,v[5].p );
+ VectorCopy( v[2].p,v[6].p );
+ VectorCopy( v[3].p,v[7].p );
+ v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
+ v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
+ v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
+ v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
+ for ( i = 0; i <= 7; i++ )
+ {
+#ifndef ISOMETRIC
+ project( &v[i] );
+#endif
+ Scale( rc,v[i],&pt[i] );
+ }
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[3].x, pt[3].y );
+ for ( i = 0; i <= 3; i++ )
+ g_GLTable.m_pfn_qglVertex2i( pt[i].x, pt[i].y );
+ g_GLTable.m_pfn_qglEnd();
+ g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
+ g_GLTable.m_pfn_qglVertex2i( pt[7].x, pt[7].y );
+ for ( i = 4; i <= 7; i++ )
+ g_GLTable.m_pfn_qglVertex2i( pt[i].x, pt[i].y );
+ g_GLTable.m_pfn_qglEnd();
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ for ( i = 0; i <= 3; i++ )
+ {
+ g_GLTable.m_pfn_qglVertex2i( pt[i].x,pt[i].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[i + 4].x,pt[i + 4].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+}
+//=============================================================
+void DrawGrid( Rect rc ){
+ int i, j, k;
+ double h,w,x,y;
+ Point pt[2];
+ Rect rcBox;
+
+ w = (double)( rc.right - rc.left + 1 ) - cxChar;
+ h = (double)( rc.top - rc.bottom + 1 ) - cxChar - cyChar;
+
+ SFG = w / ( Hur - Hll );
+ SFG = min( SFG, h / ( Vur - Vll ) );
+
+ // Center drawing
+ X0G = (int)( rc.left + rc.right - (int)( SFG * ( Hur - Hll ) ) ) / 2;
+ Y0G = (int)( rc.top + rc.bottom + cyChar - (int)( SFG * ( Vur - Vll ) ) ) / 2;
+
+ g_GLTable.m_pfn_qglLineWidth( 2 );
+ g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
+ g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
+
+ pt[0].y = Y0G;
+ pt[1].y = Y0G + (int)( SFG * ( Vur - Vll ) );
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ for ( i = 0; i <= NH; i++ )
+ {
+ x = Hll + i * dh;
+ pt[0].x = X0G + (int)( SFG * ( x - Hll ) );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[1].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+ pt[0].x = X0G;
+ pt[1].x = X0G + (int)( SFG * ( Hur - Hll ) );
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ for ( i = 0; i <= NV; i++ )
+ {
+ y = Vll + i * dv;
+ pt[0].y = Y0G + (int)( SFG * ( Vur - y ) );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x,pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[1].x,pt[0].y );
+ }
+ g_GLTable.m_pfn_qglEnd();
+
+ g_GLTable.m_pfn_qglLineWidth( 1 );
+
+ // Draw axes
+ pt[0].x = rc.right - cyChar - cxChar - cyChar / 2;
+ pt[0].y = rc.bottom + cyChar / 2;
+ pt[1].x = pt[0].x + cyChar;
+ pt[1].y = pt[0].y;
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x,pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[1].x,pt[1].y );
+ g_GLTable.m_pfn_qglEnd();
+ switch ( Plane )
+ {
+ case PLANE_YZ0:
+ case PLANE_YZ1:
+ texfont_write( "Y", pt[1].x, pt[1].y + cyChar / 2 );
+ break;
+ default:
+ texfont_write( "X", pt[1].x, pt[1].y + cyChar / 2 );
+ }
+ pt[1].x = pt[0].x;
+ pt[1].y = pt[0].y + cyChar;
+ g_GLTable.m_pfn_qglBegin( GL_LINES );
+ g_GLTable.m_pfn_qglVertex2i( pt[0].x,pt[0].y );
+ g_GLTable.m_pfn_qglVertex2i( pt[1].x,pt[1].y );
+ g_GLTable.m_pfn_qglEnd();
+ switch ( Plane )
+ {
+ case PLANE_XY0:
+ case PLANE_XY1:
+ texfont_write( "Y", pt[1].x - cyChar / 2, pt[1].y + cyChar );
+ break;
+ default:
+ texfont_write( "Z", pt[1].x - cyChar / 2, pt[1].y + cyChar );
+ }
+
+ // Denote fixed points with a 5x5 red rectangle
+ for ( i = 0; i <= NH; i++ )
+ {
+ for ( j = 0; j <= NV; j++ )
+ {
+ if ( xyz[i][j].fixed ) {
+ x = Hll + i * dh;
+ y = Vll + j * dv;
+ rcBox.left = X0G + (int)( SFG * ( x - Hll ) ) - 2;
+ rcBox.top = Y0G + (int)( SFG * ( Vur - y ) ) + 2;
+ rcBox.right = rcBox.left + 5;
+ rcBox.bottom = rcBox.top - 5;
+
+ DRAW_QUAD( rcBox, 1,0,0 );
+ }
+ }
+ }
+
+ // Denote currently selected point with a 5x5 green rectangle
+ if ( NumVerticesSelected ) {
+ for ( k = 0; k < NumVerticesSelected; k++ )
+ {
+ x = Hll + Vertex[k].i * dh;
+ y = Vll + Vertex[k].j * dv;
+ rcBox.left = X0G + (int)( SFG * ( x - Hll ) ) - 2;
+ rcBox.top = Y0G + (int)( SFG * ( Vur - y ) ) + 2;
+ rcBox.right = rcBox.left + 5;
+ rcBox.bottom = rcBox.top - 5;
+
+ DRAW_QUAD( rcBox, 0,1,0 );
+ }
+ }
+
+ // Unmovable vertices
+ for ( i = 0; i <= NH; i++ )
+ {
+ for ( j = 0; j <= NV; j++ )
+ {
+ if ( !CanEdit( i,j ) ) {
+ x = Hll + i * dh;
+ y = Vll + j * dv;
+ rcBox.left = X0G + (int)( SFG * ( x - Hll ) ) - 2;
+ rcBox.top = Y0G + (int)( SFG * ( Vur - y ) ) + 2;
+ rcBox.right = rcBox.left + 5;
+ rcBox.bottom = rcBox.top - 5;
+
+ DRAW_QUAD( rcBox, 1,1,0 );
+ }
+ }
+ }
+
+ // Legend
+ rcBox.left = rc.left + cxChar / 2 - 2;
+ rcBox.top = rc.top - cyChar / 2 - 2;
+ rcBox.right = rcBox.left + 5;
+ rcBox.bottom = rcBox.top - 5;
+ DRAW_QUAD( rcBox, 1,0,0 );
+ texfont_write( "Fixed points", rcBox.right + cxChar,rcBox.top - 4 + cyChar / 2 );
+
+ rcBox.top -= cyChar;
+ rcBox.bottom -= cyChar;
+ DRAW_QUAD( rcBox, 1,1,0 );
+ texfont_write( "Not movable", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2 );
+
+ rcBox.top -= cyChar;
+ rcBox.bottom -= cyChar;
+ DRAW_QUAD( rcBox, 0,1,0 );
+ texfont_write( "Selected", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2 );
+}
+
+//=============================================================
+void GetScaleFactor( Rect rc ){
+#ifdef ISOMETRIC
+ double h, w;
+
+ w = (double)( rc.right - rc.left + 1 ) - cxChar;
+ h = (double)( rc.top - rc.bottom + 1 ) - cxChar;
+
+ SF = w / ( ( XHi - XLo ) * COSXA + ( YHi - YLo ) * COSYA );
+ SF = min( SF, h / ( ( XHi - XLo ) * SINXA + ( YHi - YLo ) * SINYA + ZHi - ZLo ) );
+ // Center drawing
+ X0 = (int)( rc.left + rc.right - (int)( SF * ( ( XHi - XLo ) * COSXA + ( YHi - YLo ) * COSYA ) ) ) / 2;
+ Y0 = (int)( rc.top + rc.bottom - (int)( SF * ( ( XHi - XLo ) * SINXA + ( YHi - YLo ) * SINYA + ZHi - ZLo ) ) ) / 2;
+
+#else
+ double h, w;
+
+ w = (double)( rc.right - rc.left + 1 ) - cxChar;
+ h = (double)( rc.top - rc.bottom + 1 ) - cxChar;
+
+ SF = w / ( Hhi - Hlo );
+ SF = min( SF, h / ( Vhi - Vlo ) );
+ X0 = (int)( rc.left + rc.right - (int)( SF * ( Hhi - Hlo ) ) ) / 2;
+ Y0 = (int)( rc.top + rc.bottom + (int)( SF * ( Vhi - Vlo ) ) ) / 2;
+#endif
+}
+
+//=============================================================
+void Scale( Rect rc,XYZ xyz,Point *pt ){
+
+#ifdef ISOMETRIC
+
+ pt[0].x = X0 + (int)( SF * ( ( xyz.p[0] - XLo ) * COSXA +
+ ( YHi - xyz.p[1] ) * COSYA ) );
+ pt[0].y = Y0 + (int)( SF * ( ZHi - xyz.p[2] +
+ ( YHi - xyz.p[1] ) * SINYA +
+ ( XHi - xyz.p[0] ) * SINXA ) );
+#else
+ pt[0].x = X0 + (int)( SF * ( xyz.pp[0] - Hlo ) );
+ pt[0].y = Y0 - (int)( SF * ( Vhi - xyz.pp[1] ) );
+#endif
+
+}
+
+#ifndef ISOMETRIC
+/* ======================================================================= */
+void project( XYZ *v ){
+ // project a 3D point (x,y,z) onto view plane
+ double x, y, z, xa, ya, za;
+
+ x = v->p[0];
+ y = v->p[1];
+ z = v->p[2];
+
+ // yaw
+ xa = ct[0] * x - st[0] * z;
+ za = st[0] * x + ct[0] * z;
+
+ // roll
+ x = ct[1] * xa + st[1] * y;
+ ya = ct[1] * y - st[1] * xa;
+
+ // azimuth
+ z = ct[2] * za - st[2] * ya;
+ y = ct[2] * ya + st[2] * za;
+
+ // horizontal and vertical projections:
+// v->pp[0] = D*x/z;
+// v->pp[1] = D*y/z;
+ v->pp[0] = -y;
+ v->pp[1] = x;
+ v->pp[2] = z;
+
+ // NOTE: if perspective transformation is desired,
+ // set "persp" to the range from the surface,
+ // then:
+ // v->projected_h = -v->projected_h * persp/(v->projected_z-persp);
+ // v->projected_v = -v->projected_v * persp/(v->projected_z-persp);
+}
+/*=======================================================================*/
+void evaluate(){
+ int i, j;
+ XYZ v[4];
+
+ if ( elevation > PI ) {
+ elevation -= 2. * PI;
+ }
+ roll = elevation * sin( azimuth );
+ yaw = 1.5 * PI + elevation*cos( azimuth );
+
+ // Find angles from midpoint to viewpoint:
+ st[0] = sin( yaw );
+ st[1] = sin( roll );
+ st[2] = sin( azimuth );
+ ct[0] = cos( yaw );
+ ct[1] = cos( roll );
+ ct[2] = cos( azimuth );
+
+ for ( i = 0; i <= NH; i++ )
+ {
+ for ( j = 0; j <= NV; j++ )
+ {
+ project( &xyz[i][j] );
+ }
+ }
+
+ Hhi = xyz[0][0].pp[0];
+ Hlo = Hhi;
+ Vhi = xyz[0][0].pp[1];
+ Vlo = Vhi;
+ for ( i = 0; i <= NH; i++ )
+ {
+ for ( j = 0; j <= NV; j++ )
+ {
+ Hlo = min( Hlo,xyz[i][j].pp[0] );
+ Hhi = max( Hhi,xyz[i][j].pp[0] );
+ Vlo = min( Vlo,xyz[i][j].pp[1] );
+ Vhi = max( Vhi,xyz[i][j].pp[1] );
+ }
+ }
+
+ // Include backface in min-max
+ VectorCopy( xyz[ 0][ 0].p,v[0].p );
+ VectorCopy( xyz[NH][ 0].p,v[1].p );
+ VectorCopy( xyz[NH][NV].p,v[2].p );
+ VectorCopy( xyz[ 0][NV].p,v[3].p );
+ switch ( Plane )
+ {
+ case PLANE_XZ0:
+ case PLANE_XZ1:
+ v[0].p[1] = backface;
+ v[1].p[1] = v[0].p[1];
+ v[2].p[1] = v[0].p[1];
+ v[3].p[1] = v[0].p[1];
+ break;
+ case PLANE_YZ0:
+ case PLANE_YZ1:
+ v[0].p[0] = backface;
+ v[1].p[0] = v[0].p[0];
+ v[2].p[0] = v[0].p[0];
+ v[3].p[0] = v[0].p[0];
+ break;
+ default:
+ v[0].p[2] = backface;
+ v[1].p[2] = v[0].p[2];
+ v[2].p[2] = v[0].p[2];
+ v[3].p[2] = v[0].p[2];
+ }
+ for ( i = 0; i <= 3; i++ )
+ {
+ project( &v[i] );
+ Hlo = min( Hlo,v[i].pp[0] );
+ Hhi = max( Hhi,v[i].pp[0] );
+ Vlo = min( Vlo,v[i].pp[1] );
+ Vhi = max( Vhi,v[i].pp[1] );
+ }
+
+}
+#endif