mirror of
https://github.com/TTimo/GtkRadiant.git
synced 2024-11-10 07:11:54 +00:00
12b372f89c
git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant@1 8a3a26a2-13c4-0310-b231-cf6edde360e5
1287 lines
35 KiB
C++
1287 lines
35 KiB
C++
/*
|
|
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 *dlg, *vbox, *hbox, *label, *spin, *frame;
|
|
GtkObject *adj;
|
|
|
|
#ifndef ISOMETRIC
|
|
elevation = PI/6.;
|
|
azimuth = PI/6.;
|
|
#endif
|
|
|
|
g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL);
|
|
gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview");
|
|
gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL);
|
|
gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (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);
|
|
|
|
vbox = gtk_vbox_new (FALSE, 5);
|
|
gtk_widget_show (vbox);
|
|
gtk_container_add (GTK_CONTAINER (dlg), vbox);
|
|
|
|
#ifndef ISOMETRIC
|
|
hbox = gtk_hbox_new (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 = gtk_label_new ("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);
|
|
|
|
adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10);
|
|
gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation);
|
|
spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0);
|
|
gtk_widget_show (spin);
|
|
gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0);
|
|
g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation);
|
|
|
|
adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10);
|
|
gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth);
|
|
spin = gtk_spin_button_new (GTK_ADJUSTMENT (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 = gtk_label_new ("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);
|
|
g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth);
|
|
#endif
|
|
|
|
frame = gtk_frame_new (NULL);
|
|
gtk_widget_show (frame);
|
|
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);
|
|
gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL);
|
|
gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL);
|
|
gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event",
|
|
GTK_SIGNAL_FUNC (button_press), NULL);
|
|
|
|
gtk_widget_show (g_pPreviewWidget);
|
|
gtk_container_add (GTK_CONTAINER (frame), 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
|