/* 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 #include #include #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; kstate & 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(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 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; kp[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