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