2 GenSurf plugin for GtkRadiant
3 Copyright (C) 2001 David Hyde, Loki software and qeradiant.com
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 extern double backface;
29 extern double xmin, xmax, ymin, ymax, zmin, zmax;
31 double SF, SFG; // Graphics scale factors
32 double XLo, XHi, YLo, YHi, ZLo, ZHi;
34 double elevation, azimuth;
35 int cxChar = 10, cyChar = 16;
39 static Rect rcCoord; // where X= Y= is drawn
40 static Rect rcGrid; // rectangle within rcLower that forms the border of the grid, plus
42 static Rect rcLower; // lower half of window, where plan view is drawn
43 static Rect rcUpper; // upper half or entire window, where isometric projection is drawn
45 void vertex_selected();
49 void texfont_write(const char *text, int l, int t);
52 g_GLTable.m_pfn_qglLineWidth( 1 ); \
53 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 ); \
54 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE ); }
57 g_GLTable.m_pfn_qglLineWidth( 2 ); \
58 g_GLTable.m_pfn_qglColor3f( 1, 0, 0 ); \
59 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE ); }
62 g_GLTable.m_pfn_qglLineWidth( 1 ); \
63 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 ); \
64 g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 ); \
65 g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE ); }
67 #define DRAW_QUAD(rc, r, g, b) { \
68 g_GLTable.m_pfn_qglBegin( GL_QUADS ); \
69 g_GLTable.m_pfn_qglColor3f( 0,1,0 ); \
70 g_GLTable.m_pfn_qglVertex2i( rc.left - 1, rc.bottom ); \
71 g_GLTable.m_pfn_qglVertex2i( rc.right, rc.bottom ); \
72 g_GLTable.m_pfn_qglVertex2i( rc.right, rc.top + 1 ); \
73 g_GLTable.m_pfn_qglVertex2i( rc.left - 1, rc.top + 1 ); \
74 g_GLTable.m_pfn_qglColor3f( r,g,b ); \
75 g_GLTable.m_pfn_qglVertex2i( rc.left, rc.bottom + 1 ); \
76 g_GLTable.m_pfn_qglVertex2i( rc.right - 1, rc.bottom + 1 ); \
77 g_GLTable.m_pfn_qglVertex2i( rc.right - 1, rc.top ); \
78 g_GLTable.m_pfn_qglVertex2i( rc.left, rc.top ); \
79 g_GLTable.m_pfn_qglEnd(); }
85 double Hhi, Hlo, Vhi, Vlo;
94 if (g_pWndPreview == NULL) {
101 gtk_widget_hide(g_pWndPreview);
105 static void draw_preview()
107 int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height;
109 g_GLTable.m_pfn_qglClearColor(0, 0, 0, 1);
110 g_GLTable.m_pfn_qglViewport(0, 0, width, height);
111 g_GLTable.m_pfn_qglMatrixMode(GL_PROJECTION);
112 g_GLTable.m_pfn_qglLoadIdentity();
113 g_GLTable.m_pfn_qglOrtho(0, width, 0, height, -1, 1);
114 g_GLTable.m_pfn_qglClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
116 // ^Fishman - Antializing for the preview window.
118 g_GLTable.m_pfn_qglEnable(GL_BLEND);
119 g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
120 g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH);
122 g_GLTable.m_pfn_qglDisable(GL_BLEND);
123 g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH);
128 if (!ValidSurface()) {
133 rcUpper.right = width;
135 rcUpper.top = height;
137 rcLower.right = width;
139 rcLower.top = height;
142 rcUpper.bottom = rcUpper.top / 2;
143 DrawPreview(rcUpper);
144 g_GLTable.m_pfn_qglBegin(GL_LINES);
145 g_GLTable.m_pfn_qglVertex2i(rcUpper.left, rcUpper.bottom);
146 g_GLTable.m_pfn_qglVertex2i(rcUpper.right, rcUpper.bottom);
147 g_GLTable.m_pfn_qglEnd();
148 rcLower.top = rcUpper.bottom - 1;
150 rcCoord.left = rcLower.left;
151 rcCoord.right = rcLower.right;
152 rcCoord.bottom = rcLower.bottom;
153 rcCoord.top = rcLower.top;
154 rcCoord.top = rcCoord.bottom + cyChar;
155 rcCoord.right = rcCoord.left + 15 * cxChar;
156 rcGrid.left = X0G - 3;
157 rcGrid.bottom = Y0G - 3;
158 rcGrid.right = X0G + (int) (SFG * (Hur - Hll)) + 3;
159 rcGrid.top = Y0G + (int) (SFG * (Vur - Vll)) + 3;
161 DrawPreview(rcUpper);
165 static gint expose(GtkWidget *widget, GdkEventExpose *event, gpointer data)
167 if (event->count > 0) {
171 if (!g_UIGtkTable.m_pfn_glwidget_make_current(g_pPreviewWidget)) {
172 g_FuncTable.m_pfnSysPrintf("GtkGenSurf: glMakeCurrent failed\n");
178 g_UIGtkTable.m_pfn_glwidget_swap_buffers(g_pPreviewWidget);
179 g_GLTable.m_pfn_QE_CheckOpenGLForErrors();
184 static void button_press(GtkWidget *widget, GdkEventButton *event, gpointer data)
186 Point pt = {(long) event->x, widget->allocation.height - (long) event->y};
192 if ((!VertexMode) || (event->button != 1)) {
196 if (!PtInRect(&rcGrid, pt)) {
201 x = Hll + (pt.x - X0G) / SFG;
202 y = Vur - (pt.y - Y0G) / SFG;
203 i = (int) (floor((x - Hll) / dh - 0.5) + 1);
204 j = (int) (floor((y - Vll) / dv - 0.5) + 1);
205 if (i < 0 || i > NH || j < 0 || j > NV) {
210 if (!CanEdit(i, j)) {
215 // Control key pressed - add this point, or remove it if already selected
216 if ((event->state & GDK_CONTROL_MASK) != 0) {
218 if (NumVerticesSelected) {
219 for (k = 0; k < NumVerticesSelected && !Selected; k++) {
220 if (Vertex[k].i == i && Vertex[k].j == j) {
227 // Already selected - unselect it.
229 if (ks < NumVerticesSelected) {
230 for (k = ks; k < NumVerticesSelected - 1; k++) {
231 Vertex[k].i = Vertex[k + 1].i;
232 Vertex[k].j = Vertex[k + 1].j;
234 NumVerticesSelected--;
237 Vertex[NumVerticesSelected].i = i;
238 Vertex[NumVerticesSelected].j = j;
239 NumVerticesSelected++;
241 } else if ((event->state & GDK_SHIFT_MASK) != 0) {
242 if (NumVerticesSelected) {
243 NumVerticesSelected = 1;
244 i0 = min(Vertex[0].i, i);
245 i1 = max(Vertex[0].i, i);
246 j0 = min(Vertex[0].j, j);
247 j1 = max(Vertex[0].j, j);
248 for (i = i0; i <= i1; i++) {
249 for (j = j0; j <= j1; j++) {
250 if (i == 0 && j == 0) {
253 if (i == NH && j == 0) {
256 if (i == 0 && j == NV) {
259 if (i == NH && j == NV) {
262 if (i != Vertex[0].i || j != Vertex[0].j) {
263 Vertex[NumVerticesSelected].i = i;
264 Vertex[NumVerticesSelected].j = j;
265 NumVerticesSelected++;
272 NumVerticesSelected = 1;
277 NumVerticesSelected = 1;
283 static void motion(GtkWidget *widget, GdkEventMotion *event, gpointer data)
285 Point pt = {(long) event->x, widget->allocation.height - (long) event->y};
291 if (!g_UIGtkTable.m_pfn_glwidget_make_current(g_pPreviewWidget)) {
292 g_FuncTable.m_pfnSysPrintf("GtkGenSurf: glMakeCurrent failed\n");
296 g_GLTable.m_pfn_qglEnable(GL_SCISSOR_TEST);
297 g_GLTable.m_pfn_qglScissor(rcCoord.left, rcCoord.bottom, rcCoord.right - rcCoord.left,
298 rcCoord.top - rcCoord.bottom);
299 g_GLTable.m_pfn_qglClear(GL_COLOR_BUFFER_BIT);
301 if (PtInRect(&rcGrid, pt)) {
302 GdkCursor *cursor = gdk_cursor_new(GDK_CROSS);
303 gdk_window_set_cursor(g_pWndPreview->window, cursor);
304 gdk_cursor_unref(cursor);
309 x = (int) (Hll + (pt.x - X0G) / SFG);
310 y = (int) (Vur - (pt.y - Y0G) / SFG);
314 sprintf(Text, " x=%d, z=%d ", (int) (floor(x - 0.5) + 1.), (int) (floor(y - 0.5) + 1.));
318 sprintf(Text, " y=%d, z=%d ", (int) (floor(x - 0.5) + 1.), (int) (floor(y - 0.5) + 1.));
321 sprintf(Text, " x=%d, y=%d ", (int) (floor(x - 0.5) + 1.), (int) (floor(y - 0.5) + 1.));
324 texfont_write(Text, rcCoord.left, rcCoord.top);
326 gdk_window_set_cursor(g_pWndPreview->window, NULL);
329 g_UIGtkTable.m_pfn_glwidget_swap_buffers(g_pPreviewWidget);
330 g_GLTable.m_pfn_QE_CheckOpenGLForErrors();
331 g_GLTable.m_pfn_qglDisable(GL_SCISSOR_TEST);
334 static gint preview_close(GtkWidget *widget, gpointer data)
336 gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g_object_get_data(G_OBJECT(g_pWnd), "main_preview")), FALSE);
340 static void preview_focusout(GtkSpinButton *spin, GdkEventFocus *event, double *data)
342 *data = DegreesToRadians((double) (gtk_spin_button_get_value_as_int(spin) % 360));
343 UpdatePreview(false);
346 static gint doublevariable_spinfocusout(GtkWidget *widget, GdkEventFocus *event, gpointer data)
348 preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast<double *>( data ));
352 static void preview_spin(GtkAdjustment *adj, double *data)
354 *data = DegreesToRadians(adj->value);
355 UpdatePreview(false);
358 void CreateViewWindow()
360 GtkWidget *label, *spin;
367 auto dlg = g_pWndPreview = ui::Window(ui::window_type::TOP);
368 gtk_window_set_title(dlg, "GtkGenSurf Preview");
369 dlg.connect("delete_event", G_CALLBACK(preview_close), NULL);
370 dlg.connect("destroy", G_CALLBACK(gtk_widget_destroy), NULL);
371 gtk_window_set_transient_for(dlg, g_pWnd);
372 gtk_window_set_default_size(dlg, 300, 400);
374 auto vbox = ui::VBox(FALSE, 5);
379 auto hbox = ui::HBox(TRUE, 5);
381 vbox.pack_start(hbox, FALSE, TRUE, 0);
382 gtk_container_set_border_width(GTK_CONTAINER(hbox), 3);
384 label = ui::Label("Elevation");
386 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
387 hbox.pack_start(label, FALSE, TRUE, 0);
389 auto adj = ui::Adjustment(30, -90, 90, 1, 10, 0);
390 adj.connect("value_changed", G_CALLBACK(preview_spin), &elevation);
391 spin = ui::SpinButton(adj, 1, 0);
393 hbox.pack_start(spin, FALSE, TRUE, 0);
394 spin.connect("focus_out_event", G_CALLBACK(doublevariable_spinfocusout), &elevation);
396 adj = ui::Adjustment(30, 0, 359, 1, 10, 0);
397 adj.connect("value_changed", G_CALLBACK(preview_spin), &azimuth);
398 spin = ui::SpinButton(adj, 1, 0);
400 gtk_spin_button_set_wrap(GTK_SPIN_BUTTON(spin), TRUE);
401 hbox.pack_end(spin, FALSE, TRUE, 0);
403 label = ui::Label("Azimuth");
405 gtk_misc_set_alignment(GTK_MISC(label), 1, 0.5);
406 hbox.pack_end(label, FALSE, TRUE, 0);
407 spin.connect("focus_out_event", G_CALLBACK(doublevariable_spinfocusout), &azimuth);
410 auto frame = ui::Frame(ui::null);
412 gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_IN);
413 vbox.pack_start(frame, TRUE, TRUE, 0);
415 g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new(FALSE, NULL);
417 gtk_widget_set_events(g_pPreviewWidget, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK);
418 g_pPreviewWidget.connect("expose_event", G_CALLBACK(expose), NULL);
419 g_pPreviewWidget.connect("motion_notify_event", G_CALLBACK(motion), NULL);
420 g_pPreviewWidget.connect("button_press_event",
421 G_CALLBACK(button_press), NULL);
423 g_pPreviewWidget.show();
424 frame.add(ui::Widget(g_pPreviewWidget));
427 g_pWndPreview.show();
433 //=============================================================
435 void DrawPreview(Rect rc)
437 #define COSXA 0.8660254037844
439 #define COSYA 0.8660254037844
447 char axis[3][2] = {"X", "Y", "Z"};
482 g_GLTable.m_pfn_qglLineWidth(1);
483 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
484 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
486 if (Decimate > 0 && (Game != QUAKE3 || UsePatches == 0)) {
489 vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ));
490 for (i = 0; i < gNumNodes; i++) {
491 for (j = 0; j < 3; j++) {
492 vv[i].p[j] = (double) (gNode[i].p[j]);
497 for (i = 0; i < gNumTris; i++) {
498 for (j = 0; j < 3; j++) {
499 Scale(rc, vv[gTri[i].v[j]], &pt[j]);
502 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
503 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
504 g_GLTable.m_pfn_qglVertex2i(pt[1].x, pt[1].y);
505 g_GLTable.m_pfn_qglVertex2i(pt[2].x, pt[2].y);
506 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
507 g_GLTable.m_pfn_qglEnd();
510 } else if (Game == QUAKE3 && UsePatches != 0) {
528 for (i = 0; i < NH; i += 2) {
529 for (j = 0; j < NV; j += 2) {
530 VectorCopy(xyz[i][j].p, uv[0][0].p);
531 VectorCopy(xyz[i + 1][j].p, uv[1][0].p);
532 VectorCopy(xyz[i + 2][j].p, uv[2][0].p);
533 VectorCopy(xyz[i][j + 1].p, uv[0][1].p);
534 VectorCopy(xyz[i + 1][j + 1].p, uv[1][1].p);
535 VectorCopy(xyz[i + 2][j + 1].p, uv[2][1].p);
536 VectorCopy(xyz[i][j + 2].p, uv[0][2].p);
537 VectorCopy(xyz[i + 1][j + 2].p, uv[1][2].p);
538 VectorCopy(xyz[i + 2][j + 2].p, uv[2][2].p);
539 uv[1][0].p[k] = (4 * xyz[i + 1][j].p[k] - xyz[i][j].p[k] - xyz[i + 2][j].p[k]) / 2;
540 uv[0][1].p[k] = (4 * xyz[i][j + 1].p[k] - xyz[i][j].p[k] - xyz[i][j + 2].p[k]) / 2;
541 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;
542 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;
543 uv[1][1].p[k] = (16 * xyz[i + 1][j + 1].p[k] -
544 xyz[i][j].p[k] - 2 * xyz[i + 1][j].p[k] - xyz[i + 2][j].p[k] -
545 2 * xyz[i][j + 1].p[k] - 2 * xyz[i + 2][j + 1].p[k] -
546 xyz[i][j + 2].p[k] - 2 * xyz[i + 1][j + 2].p[k] - xyz[i + 2][j + 2].p[k]) / 4;
548 for (ii = 0; ii <= SUBDIVS; ii++) {
549 if (ii == 0 || ii == SUBDIVS / 2 || ii == SUBDIVS) {
550 g_GLTable.m_pfn_qglLineWidth(1);
551 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
552 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
555 g_GLTable.m_pfn_qglLineWidth(1);
556 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
557 g_GLTable.m_pfn_qglLineStipple(1, 0xF0F0);
558 g_GLTable.m_pfn_qglEnable(GL_LINE_STIPPLE);
562 u = (float) (ii) / (float) (SUBDIVS);
563 for (jj = 0; jj < 3; jj++) {
564 for (axis = 0; axis < 3; axis++) {
567 a = (float) uv[0][jj].p[axis];
568 b = (float) uv[1][jj].p[axis];
569 c = (float) uv[2][jj].p[axis];
573 Ctrl[jj].p[axis] = qA * u * u + qB * u + qC;
576 VectorCopy(Ctrl[0].p, out.p);
578 Scale(rc, out, &pt[0]);
579 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
580 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
581 for (jj = 1; jj <= SUBDIVS; jj++) {
582 v = (float) (jj) / (float) (SUBDIVS);
583 for (axis = 0; axis < 3; axis++) {
586 a = (float) Ctrl[0].p[axis];
587 b = (float) Ctrl[1].p[axis];
588 c = (float) Ctrl[2].p[axis];
592 out.p[axis] = qA * v * v + qB * v + qC;
595 Scale(rc, out, &pt[0]);
596 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
598 g_GLTable.m_pfn_qglEnd();
600 for (jj = 0; jj <= SUBDIVS; jj++) {
601 if (jj == 0 || jj == SUBDIVS / 2 || jj == SUBDIVS) {
602 g_GLTable.m_pfn_qglLineWidth(1);
603 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
604 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
607 g_GLTable.m_pfn_qglLineWidth(1);
608 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
609 g_GLTable.m_pfn_qglLineStipple(1, 0xF0F0);
610 g_GLTable.m_pfn_qglEnable(GL_LINE_STIPPLE);
614 v = (float) (jj) / (float) (SUBDIVS);
615 for (ii = 0; ii < 3; ii++) {
616 for (axis = 0; axis < 3; axis++) {
619 a = (float) uv[ii][0].p[axis];
620 b = (float) uv[ii][1].p[axis];
621 c = (float) uv[ii][2].p[axis];
625 Ctrl[ii].p[axis] = qA * v * v + qB * v + qC;
628 VectorCopy(Ctrl[0].p, out.p);
630 Scale(rc, out, &pt[0]);
631 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
632 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
633 for (ii = 1; ii <= SUBDIVS; ii++) {
634 u = (float) (ii) / (float) (SUBDIVS);
635 for (axis = 0; axis < 3; axis++) {
638 a = (float) Ctrl[0].p[axis];
639 b = (float) Ctrl[1].p[axis];
640 c = (float) Ctrl[2].p[axis];
644 out.p[axis] = qA * u * u + qB * u + qC;
647 Scale(rc, out, &pt[0]);
648 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
650 g_GLTable.m_pfn_qglEnd();
655 for (i = 0; i <= NH; i++) {
656 Scale(rc, xyz[i][0], &pt[0]);
657 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
658 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
659 for (j = 1; j <= NV; j++) {
660 Scale(rc, xyz[i][j], &pt[0]);
661 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
663 g_GLTable.m_pfn_qglEnd();
665 for (j = 0; j <= NV; j++) {
666 Scale(rc, xyz[0][j], &pt[0]);
667 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
668 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
669 for (i = 1; i <= NH; i++) {
670 Scale(rc, xyz[i][j], &pt[0]);
671 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
673 g_GLTable.m_pfn_qglEnd();
677 if (Game != QUAKE3 || UsePatches == 0) {
678 // Draw lines from corners to base, and lines around base
679 for (i = 0; i <= NH; i += NH) {
680 for (j = 0; j <= NV; j += NV) {
681 VectorCopy(xyz[i][j].p, v[0].p);
685 v[0].p[1] = backface;
689 v[0].p[0] = backface;
692 v[0].p[2] = backface;
694 Scale(rc, xyz[i][j], &pt[0]);
698 Scale(rc, v[0], &pt[1]);
699 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
700 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
701 g_GLTable.m_pfn_qglVertex2i(pt[1].x, pt[1].y);
702 g_GLTable.m_pfn_qglEnd();
705 VectorCopy(xyz[0][0].p, v[0].p);
706 VectorCopy(xyz[NH][0].p, v[1].p);
707 VectorCopy(xyz[NH][NV].p, v[2].p);
708 VectorCopy(xyz[0][NV].p, v[3].p);
712 v[0].p[1] = backface;;
713 v[1].p[1] = v[0].p[1];
714 v[2].p[1] = v[0].p[1];
715 v[3].p[1] = v[0].p[1];
719 v[0].p[0] = backface;
720 v[1].p[0] = v[0].p[0];
721 v[2].p[0] = v[0].p[0];
722 v[3].p[0] = v[0].p[0];
725 v[0].p[2] = backface;
726 v[1].p[2] = v[0].p[2];
727 v[2].p[2] = v[0].p[2];
728 v[3].p[2] = v[0].p[2];
733 Scale(rc, v[3], &pt[0]);
734 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
735 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
736 for (i = 0; i < 3; i++) {
740 Scale(rc, v[i], &pt[1]);
741 g_GLTable.m_pfn_qglVertex2i(pt[1].x, pt[1].y);
743 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
744 g_GLTable.m_pfn_qglEnd();
747 g_GLTable.m_pfn_qglLineWidth(1);
748 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
749 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
752 // Draw small depiction of coordinate axes
753 pt[0].x = rc.right - cxChar - cxChar / 2 - cyChar;
754 pt[0].y = rc.bottom - cyChar / 2 - cxChar / 2;
755 pt[1].x = pt[0].x + (int)( cyChar * COSXA );
756 pt[1].y = pt[0].y - (int)( cyChar * SINXA );
757 MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
758 LineTo( hdc,pt[1].x,pt[1].y );
759 SetTextAlign( hdc,TA_LEFT | TA_TOP );
760 TextOut( hdc,pt[1].x,pt[1].y - cyChar / 2,"X",1 );
761 pt[1].x = pt[0].x - (int)( cyChar * COSYA );
762 pt[1].y = pt[0].y - (int)( cyChar * SINYA );
763 MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
764 LineTo( hdc,pt[1].x,pt[1].y );
765 SetTextAlign( hdc,TA_RIGHT | TA_TOP );
766 TextOut( hdc,pt[1].x,pt[1].y - cyChar / 2,"Y",1 );
768 pt[1].y = pt[0].y - cyChar;
769 MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
770 LineTo( hdc,pt[1].x,pt[1].y );
771 SetTextAlign( hdc,TA_CENTER | TA_BOTTOM );
772 TextOut( hdc,pt[1].x,pt[1].y,"Z",1 );
774 L = 2 * (double) cyChar / SF;
787 for (i = 0; i <= 3; i++) {
789 Scale(rc, v[i], &pt[i]);
791 for (i = 1; i <= 3; i++) {
792 pt[i].x += -pt[0].x + rc.right - 2 * cyChar;
793 pt[i].y += -pt[0].y + rc.bottom + 2 * cyChar;
795 pt[0].x = rc.right - 2 * cyChar;
796 pt[0].y = rc.bottom + 2 * cyChar;
798 for (i = 1; i <= 3; i++) {
799 g_GLTable.m_pfn_qglBegin(GL_LINES);
800 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
801 g_GLTable.m_pfn_qglVertex2i(pt[i].x, pt[i].y);
802 g_GLTable.m_pfn_qglEnd();
803 texfont_write(axis[i - 1], pt[i].x - cxChar / 2, pt[i].y + cyChar / 2);
807 // Draw player model's bounding box in red to give a sense of scale
809 g_GLTable.m_pfn_qglLineWidth(2);
810 g_GLTable.m_pfn_qglColor3f(1, 0, 0);
811 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
815 v[0].p[0] = xyz[NH / 2][NV / 2].p[0] + PlayerBox[Game].x[0];
816 v[0].p[1] = xyz[NH / 2][NV / 2].p[1] + PlayerBox[Game].y[0];
817 v[0].p[2] = zmin - PlayerBox[Game].z[0] - 32;
820 v[0].p[0] = (xmax + xmin) / 2 + PlayerBox[Game].x[0];
821 v[0].p[1] = ymax + 64;
825 v[0].p[0] = (xmax + xmin) / 2 + PlayerBox[Game].x[0];
826 v[0].p[1] = ymin - 64;
830 v[0].p[0] = xmax + 64;
831 v[0].p[1] = (ymax + ymin) / 2 + PlayerBox[Game].y[0];
835 v[0].p[0] = xmin - 64;
836 v[0].p[1] = (ymax + ymin) / 2 + PlayerBox[Game].y[0];
840 // Put player on a node. For patches, put on an even numbered node.
841 if (Game == QUAKE3 && UsePatches != 0) {
843 x = Hll + dh * (int) (NH / 2 + 1);
845 x = Hll + dh * (int) (NH / 2);
848 y = Vll + dv * (int) (NV / 2 + 1);
850 y = Vll + dv * (int) (NV / 2);
854 x = Hll + dh * (int) (NH / 2);
859 y = Vll + dv * (int) (NV / 2);
866 v[0].p[0] = x + PlayerBox[Game].x[0];
867 v[0].p[1] = y + PlayerBox[Game].y[0];
868 v[0].p[2] = PlayerStartZ(x, y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist
870 v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0];
871 v[1].p[1] = v[0].p[1];
872 v[1].p[2] = v[0].p[2];
873 v[2].p[0] = v[1].p[0];
874 v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0];
875 v[2].p[2] = v[0].p[2];
876 v[3].p[0] = v[0].p[0];
877 v[3].p[1] = v[2].p[1];
878 v[3].p[2] = v[0].p[2];
879 VectorCopy(v[0].p, v[4].p);
880 VectorCopy(v[1].p, v[5].p);
881 VectorCopy(v[2].p, v[6].p);
882 VectorCopy(v[3].p, v[7].p);
883 v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
884 v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
885 v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
886 v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
887 for (i = 0; i <= 7; i++) {
891 Scale(rc, v[i], &pt[i]);
893 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
894 g_GLTable.m_pfn_qglVertex2i(pt[3].x, pt[3].y);
895 for (i = 0; i <= 3; i++) {
896 g_GLTable.m_pfn_qglVertex2i(pt[i].x, pt[i].y);
898 g_GLTable.m_pfn_qglEnd();
899 g_GLTable.m_pfn_qglBegin(GL_LINE_STRIP);
900 g_GLTable.m_pfn_qglVertex2i(pt[7].x, pt[7].y);
901 for (i = 4; i <= 7; i++) {
902 g_GLTable.m_pfn_qglVertex2i(pt[i].x, pt[i].y);
904 g_GLTable.m_pfn_qglEnd();
905 g_GLTable.m_pfn_qglBegin(GL_LINES);
906 for (i = 0; i <= 3; i++) {
907 g_GLTable.m_pfn_qglVertex2i(pt[i].x, pt[i].y);
908 g_GLTable.m_pfn_qglVertex2i(pt[i + 4].x, pt[i + 4].y);
910 g_GLTable.m_pfn_qglEnd();
912 g_GLTable.m_pfn_qglLineWidth(1);
913 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
914 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
917 //=============================================================
918 void DrawGrid(Rect rc)
925 w = (double) (rc.right - rc.left + 1) - cxChar;
926 h = (double) (rc.top - rc.bottom + 1) - cxChar - cyChar;
928 SFG = w / (Hur - Hll);
929 SFG = min(SFG, h / (Vur - Vll));
932 X0G = (int) (rc.left + rc.right - (int) (SFG * (Hur - Hll))) / 2;
933 Y0G = (int) (rc.top + rc.bottom + cyChar - (int) (SFG * (Vur - Vll))) / 2;
935 g_GLTable.m_pfn_qglLineWidth(2);
936 g_GLTable.m_pfn_qglColor3f(0, 1, 0);
937 g_GLTable.m_pfn_qglDisable(GL_LINE_STIPPLE);
940 pt[1].y = Y0G + (int) (SFG * (Vur - Vll));
941 g_GLTable.m_pfn_qglBegin(GL_LINES);
942 for (i = 0; i <= NH; i++) {
944 pt[0].x = X0G + (int) (SFG * (x - Hll));
945 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
946 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[1].y);
948 g_GLTable.m_pfn_qglEnd();
950 pt[1].x = X0G + (int) (SFG * (Hur - Hll));
951 g_GLTable.m_pfn_qglBegin(GL_LINES);
952 for (i = 0; i <= NV; i++) {
954 pt[0].y = Y0G + (int) (SFG * (Vur - y));
955 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
956 g_GLTable.m_pfn_qglVertex2i(pt[1].x, pt[0].y);
958 g_GLTable.m_pfn_qglEnd();
960 g_GLTable.m_pfn_qglLineWidth(1);
963 pt[0].x = rc.right - cyChar - cxChar - cyChar / 2;
964 pt[0].y = rc.bottom + cyChar / 2;
965 pt[1].x = pt[0].x + cyChar;
967 g_GLTable.m_pfn_qglBegin(GL_LINES);
968 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
969 g_GLTable.m_pfn_qglVertex2i(pt[1].x, pt[1].y);
970 g_GLTable.m_pfn_qglEnd();
974 texfont_write("Y", pt[1].x, pt[1].y + cyChar / 2);
977 texfont_write("X", pt[1].x, pt[1].y + cyChar / 2);
980 pt[1].y = pt[0].y + cyChar;
981 g_GLTable.m_pfn_qglBegin(GL_LINES);
982 g_GLTable.m_pfn_qglVertex2i(pt[0].x, pt[0].y);
983 g_GLTable.m_pfn_qglVertex2i(pt[1].x, pt[1].y);
984 g_GLTable.m_pfn_qglEnd();
988 texfont_write("Y", pt[1].x - cyChar / 2, pt[1].y + cyChar);
991 texfont_write("Z", pt[1].x - cyChar / 2, pt[1].y + cyChar);
994 // Denote fixed points with a 5x5 red rectangle
995 for (i = 0; i <= NH; i++) {
996 for (j = 0; j <= NV; j++) {
997 if (xyz[i][j].fixed) {
1000 rcBox.left = X0G + (int) (SFG * (x - Hll)) - 2;
1001 rcBox.top = Y0G + (int) (SFG * (Vur - y)) + 2;
1002 rcBox.right = rcBox.left + 5;
1003 rcBox.bottom = rcBox.top - 5;
1005 DRAW_QUAD(rcBox, 1, 0, 0);
1010 // Denote currently selected point with a 5x5 green rectangle
1011 if (NumVerticesSelected) {
1012 for (k = 0; k < NumVerticesSelected; k++) {
1013 x = Hll + Vertex[k].i * dh;
1014 y = Vll + Vertex[k].j * dv;
1015 rcBox.left = X0G + (int) (SFG * (x - Hll)) - 2;
1016 rcBox.top = Y0G + (int) (SFG * (Vur - y)) + 2;
1017 rcBox.right = rcBox.left + 5;
1018 rcBox.bottom = rcBox.top - 5;
1020 DRAW_QUAD(rcBox, 0, 1, 0);
1024 // Unmovable vertices
1025 for (i = 0; i <= NH; i++) {
1026 for (j = 0; j <= NV; j++) {
1027 if (!CanEdit(i, j)) {
1030 rcBox.left = X0G + (int) (SFG * (x - Hll)) - 2;
1031 rcBox.top = Y0G + (int) (SFG * (Vur - y)) + 2;
1032 rcBox.right = rcBox.left + 5;
1033 rcBox.bottom = rcBox.top - 5;
1035 DRAW_QUAD(rcBox, 1, 1, 0);
1041 rcBox.left = rc.left + cxChar / 2 - 2;
1042 rcBox.top = rc.top - cyChar / 2 - 2;
1043 rcBox.right = rcBox.left + 5;
1044 rcBox.bottom = rcBox.top - 5;
1045 DRAW_QUAD(rcBox, 1, 0, 0);
1046 texfont_write("Fixed points", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2);
1048 rcBox.top -= cyChar;
1049 rcBox.bottom -= cyChar;
1050 DRAW_QUAD(rcBox, 1, 1, 0);
1051 texfont_write("Not movable", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2);
1053 rcBox.top -= cyChar;
1054 rcBox.bottom -= cyChar;
1055 DRAW_QUAD(rcBox, 0, 1, 0);
1056 texfont_write("Selected", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2);
1059 //=============================================================
1060 void GetScaleFactor(Rect rc)
1065 w = (double)( rc.right - rc.left + 1 ) - cxChar;
1066 h = (double)( rc.top - rc.bottom + 1 ) - cxChar;
1068 SF = w / ( ( XHi - XLo ) * COSXA + ( YHi - YLo ) * COSYA );
1069 SF = min( SF, h / ( ( XHi - XLo ) * SINXA + ( YHi - YLo ) * SINYA + ZHi - ZLo ) );
1071 X0 = (int)( rc.left + rc.right - (int)( SF * ( ( XHi - XLo ) * COSXA + ( YHi - YLo ) * COSYA ) ) ) / 2;
1072 Y0 = (int)( rc.top + rc.bottom - (int)( SF * ( ( XHi - XLo ) * SINXA + ( YHi - YLo ) * SINYA + ZHi - ZLo ) ) ) / 2;
1077 w = (double) (rc.right - rc.left + 1) - cxChar;
1078 h = (double) (rc.top - rc.bottom + 1) - cxChar;
1080 SF = w / (Hhi - Hlo);
1081 SF = min(SF, h / (Vhi - Vlo));
1082 X0 = (int) (rc.left + rc.right - (int) (SF * (Hhi - Hlo))) / 2;
1083 Y0 = (int) (rc.top + rc.bottom + (int) (SF * (Vhi - Vlo))) / 2;
1087 //=============================================================
1088 void Scale(Rect rc, XYZ xyz, Point *pt)
1093 pt[0].x = X0 + (int)( SF * ( ( xyz.p[0] - XLo ) * COSXA +
1094 ( YHi - xyz.p[1] ) * COSYA ) );
1095 pt[0].y = Y0 + (int)( SF * ( ZHi - xyz.p[2] +
1096 ( YHi - xyz.p[1] ) * SINYA +
1097 ( XHi - xyz.p[0] ) * SINXA ) );
1099 pt[0].x = X0 + (int) (SF * (xyz.pp[0] - Hlo));
1100 pt[0].y = Y0 - (int) (SF * (Vhi - xyz.pp[1]));
1107 /* ======================================================================= */
1108 void project(XYZ *v)
1110 // project a 3D point (x,y,z) onto view plane
1111 double x, y, z, xa, ya, za;
1118 xa = ct[0] * x - st[0] * z;
1119 za = st[0] * x + ct[0] * z;
1122 x = ct[1] * xa + st[1] * y;
1123 ya = ct[1] * y - st[1] * xa;
1126 z = ct[2] * za - st[2] * ya;
1127 y = ct[2] * ya + st[2] * za;
1129 // horizontal and vertical projections:
1130 // v->pp[0] = D*x/z;
1131 // v->pp[1] = D*y/z;
1136 // NOTE: if perspective transformation is desired,
1137 // set "persp" to the range from the surface,
1139 // v->projected_h = -v->projected_h * persp/(v->projected_z-persp);
1140 // v->projected_v = -v->projected_v * persp/(v->projected_z-persp);
1143 /*=======================================================================*/
1149 if (elevation > PI) {
1150 elevation -= 2. * PI;
1152 roll = elevation * sin(azimuth);
1153 yaw = 1.5 * PI + elevation * cos(azimuth);
1155 // Find angles from midpoint to viewpoint:
1158 st[2] = sin(azimuth);
1161 ct[2] = cos(azimuth);
1163 for (i = 0; i <= NH; i++) {
1164 for (j = 0; j <= NV; j++) {
1165 project(&xyz[i][j]);
1169 Hhi = xyz[0][0].pp[0];
1171 Vhi = xyz[0][0].pp[1];
1173 for (i = 0; i <= NH; i++) {
1174 for (j = 0; j <= NV; j++) {
1175 Hlo = min(Hlo, xyz[i][j].pp[0]);
1176 Hhi = max(Hhi, xyz[i][j].pp[0]);
1177 Vlo = min(Vlo, xyz[i][j].pp[1]);
1178 Vhi = max(Vhi, xyz[i][j].pp[1]);
1182 // Include backface in min-max
1183 VectorCopy(xyz[0][0].p, v[0].p);
1184 VectorCopy(xyz[NH][0].p, v[1].p);
1185 VectorCopy(xyz[NH][NV].p, v[2].p);
1186 VectorCopy(xyz[0][NV].p, v[3].p);
1190 v[0].p[1] = backface;
1191 v[1].p[1] = v[0].p[1];
1192 v[2].p[1] = v[0].p[1];
1193 v[3].p[1] = v[0].p[1];
1197 v[0].p[0] = backface;
1198 v[1].p[0] = v[0].p[0];
1199 v[2].p[0] = v[0].p[0];
1200 v[3].p[0] = v[0].p[0];
1203 v[0].p[2] = backface;
1204 v[1].p[2] = v[0].p[2];
1205 v[2].p[2] = v[0].p[2];
1206 v[3].p[2] = v[0].p[2];
1208 for (i = 0; i <= 3; i++) {
1210 Hlo = min(Hlo, v[i].pp[0]);
1211 Hhi = max(Hhi, v[i].pp[0]);
1212 Vlo = min(Vlo, v[i].pp[1]);
1213 Vhi = max(Vhi, v[i].pp[1]);