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();
47 void texfont_write( const char *text, int l, int t );
50 g_GLTable.m_pfn_qglLineWidth( 1 ); \
51 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 ); \
52 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE ); }
55 g_GLTable.m_pfn_qglLineWidth( 2 ); \
56 g_GLTable.m_pfn_qglColor3f( 1, 0, 0 ); \
57 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE ); }
60 g_GLTable.m_pfn_qglLineWidth( 1 ); \
61 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 ); \
62 g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 ); \
63 g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE ); }
65 #define DRAW_QUAD( rc,r,g,b ) { \
66 g_GLTable.m_pfn_qglBegin( GL_QUADS ); \
67 g_GLTable.m_pfn_qglColor3f( 0,1,0 ); \
68 g_GLTable.m_pfn_qglVertex2i( rc.left - 1, rc.bottom ); \
69 g_GLTable.m_pfn_qglVertex2i( rc.right, rc.bottom ); \
70 g_GLTable.m_pfn_qglVertex2i( rc.right, rc.top + 1 ); \
71 g_GLTable.m_pfn_qglVertex2i( rc.left - 1, rc.top + 1 ); \
72 g_GLTable.m_pfn_qglColor3f( r,g,b ); \
73 g_GLTable.m_pfn_qglVertex2i( rc.left, rc.bottom + 1 ); \
74 g_GLTable.m_pfn_qglVertex2i( rc.right - 1, rc.bottom + 1 ); \
75 g_GLTable.m_pfn_qglVertex2i( rc.right - 1, rc.top ); \
76 g_GLTable.m_pfn_qglVertex2i( rc.left, rc.top ); \
77 g_GLTable.m_pfn_qglEnd(); }
83 double Hhi, Hlo, Vhi, Vlo;
91 if ( g_pWndPreview == NULL ) {
94 gtk_widget_show( g_pWndPreview );
96 UpdatePreview( true );
99 gtk_widget_hide( g_pWndPreview );
103 static void draw_preview(){
104 int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height;
106 g_GLTable.m_pfn_qglClearColor( 0, 0, 0, 1 );
107 g_GLTable.m_pfn_qglViewport( 0, 0, width, height );
108 g_GLTable.m_pfn_qglMatrixMode( GL_PROJECTION );
109 g_GLTable.m_pfn_qglLoadIdentity();
110 g_GLTable.m_pfn_qglOrtho( 0, width, 0, height, -1, 1 );
111 g_GLTable.m_pfn_qglClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
113 // ^Fishman - Antializing for the preview window.
114 if ( Antialiasing ) {
115 g_GLTable.m_pfn_qglEnable( GL_BLEND );
116 g_GLTable.m_pfn_qglBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
117 g_GLTable.m_pfn_qglEnable( GL_LINE_SMOOTH );
121 g_GLTable.m_pfn_qglDisable( GL_BLEND );
122 g_GLTable.m_pfn_qglDisable( GL_LINE_SMOOTH );
127 if ( !ValidSurface() ) {
132 rcUpper.right = width;
134 rcUpper.top = height;
136 rcLower.right = width;
138 rcLower.top = height;
141 rcUpper.bottom = rcUpper.top / 2;
142 DrawPreview( rcUpper );
143 g_GLTable.m_pfn_qglBegin( GL_LINES );
144 g_GLTable.m_pfn_qglVertex2i( rcUpper.left, rcUpper.bottom );
145 g_GLTable.m_pfn_qglVertex2i( rcUpper.right, rcUpper.bottom );
146 g_GLTable.m_pfn_qglEnd();
147 rcLower.top = rcUpper.bottom - 1;
149 rcCoord.left = rcLower.left;
150 rcCoord.right = rcLower.right;
151 rcCoord.bottom = rcLower.bottom;
152 rcCoord.top = rcLower.top;
153 rcCoord.top = rcCoord.bottom + cyChar;
154 rcCoord.right = rcCoord.left + 15 * cxChar;
155 rcGrid.left = X0G - 3;
156 rcGrid.bottom = Y0G - 3;
157 rcGrid.right = X0G + (int)( SFG * ( Hur - Hll ) ) + 3;
158 rcGrid.top = Y0G + (int)( SFG * ( Vur - Vll ) ) + 3;
161 DrawPreview( rcUpper );
165 static gint expose( GtkWidget *widget, GdkEventExpose *event, gpointer data ){
166 if ( event->count > 0 ) {
170 if ( !g_UIGtkTable.m_pfn_glwidget_make_current( g_pPreviewWidget ) ) {
171 g_FuncTable.m_pfnSysPrintf( "GtkGenSurf: glMakeCurrent failed\n" );
177 g_UIGtkTable.m_pfn_glwidget_swap_buffers( g_pPreviewWidget );
178 g_GLTable.m_pfn_QE_CheckOpenGLForErrors();
183 static void button_press( GtkWidget *widget, GdkEventButton *event, gpointer data ){
184 Point pt = { (long)event->x, widget->allocation.height - (long)event->y };
190 if ( ( !VertexMode ) || ( event->button != 1 ) ) {
194 if ( !PtInRect( &rcGrid,pt ) ) {
199 x = Hll + ( pt.x - X0G ) / SFG;
200 y = Vur - ( pt.y - Y0G ) / SFG;
201 i = (int)( floor( ( x - Hll ) / dh - 0.5 ) + 1 );
202 j = (int)( floor( ( y - Vll ) / dv - 0.5 ) + 1 );
203 if ( i < 0 || i > NH || j < 0 || j > NV ) {
208 if ( !CanEdit( i,j ) ) {
213 // Control key pressed - add this point, or remove it if already selected
214 if ( ( event->state & GDK_CONTROL_MASK ) != 0 ) {
216 if ( NumVerticesSelected ) {
217 for ( k = 0; k < NumVerticesSelected && !Selected; k++ )
219 if ( Vertex[k].i == i && Vertex[k].j == j ) {
226 // Already selected - unselect it.
228 if ( ks < NumVerticesSelected ) {
229 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--;
239 Vertex[NumVerticesSelected].i = i;
240 Vertex[NumVerticesSelected].j = j;
241 NumVerticesSelected++;
244 else if ( ( event->state & GDK_SHIFT_MASK ) != 0 ) {
245 if ( NumVerticesSelected ) {
246 NumVerticesSelected = 1;
247 i0 = min( Vertex[0].i, i );
248 i1 = max( Vertex[0].i, i );
249 j0 = min( Vertex[0].j, j );
250 j1 = max( Vertex[0].j, j );
251 for ( i = i0; i <= i1; i++ )
253 for ( j = j0; j <= j1; j++ )
255 if ( i == 0 && j == 0 ) {
258 if ( i == NH && j == 0 ) {
261 if ( i == 0 && j == NV ) {
264 if ( i == NH && j == NV ) {
267 if ( i != Vertex[0].i || j != Vertex[0].j ) {
268 Vertex[NumVerticesSelected].i = i;
269 Vertex[NumVerticesSelected].j = j;
270 NumVerticesSelected++;
279 NumVerticesSelected = 1;
286 NumVerticesSelected = 1;
292 static void motion( GtkWidget *widget, GdkEventMotion *event, gpointer data ){
293 Point pt = { (long)event->x, widget->allocation.height - (long)event->y };
299 if ( !g_UIGtkTable.m_pfn_glwidget_make_current( g_pPreviewWidget ) ) {
300 g_FuncTable.m_pfnSysPrintf( "GtkGenSurf: glMakeCurrent failed\n" );
304 g_GLTable.m_pfn_qglEnable( GL_SCISSOR_TEST );
305 g_GLTable.m_pfn_qglScissor( rcCoord.left, rcCoord.bottom, rcCoord.right - rcCoord.left,
306 rcCoord.top - rcCoord.bottom );
307 g_GLTable.m_pfn_qglClear( GL_COLOR_BUFFER_BIT );
309 if ( PtInRect( &rcGrid,pt ) ) {
310 GdkCursor *cursor = gdk_cursor_new( GDK_CROSS );
311 gdk_window_set_cursor( g_pWndPreview->window, cursor );
312 gdk_cursor_unref( cursor );
317 x = (int)( Hll + ( pt.x - X0G ) / SFG );
318 y = (int)( Vur - ( pt.y - Y0G ) / SFG );
323 sprintf( Text," x=%d, z=%d ",(int)( floor( x - 0.5 ) + 1. ),(int)( floor( y - 0.5 ) + 1. ) );
327 sprintf( Text," y=%d, z=%d ",(int)( floor( x - 0.5 ) + 1. ),(int)( floor( y - 0.5 ) + 1. ) );
330 sprintf( Text," x=%d, y=%d ",(int)( floor( x - 0.5 ) + 1. ),(int)( floor( y - 0.5 ) + 1. ) );
333 texfont_write( Text, rcCoord.left, rcCoord.top );
337 gdk_window_set_cursor( g_pWndPreview->window, NULL );
340 g_UIGtkTable.m_pfn_glwidget_swap_buffers( g_pPreviewWidget );
341 g_GLTable.m_pfn_QE_CheckOpenGLForErrors();
342 g_GLTable.m_pfn_qglDisable( GL_SCISSOR_TEST );
345 static gint preview_close( GtkWidget *widget, gpointer data ){
346 gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON( g_object_get_data( G_OBJECT( g_pWnd ), "main_preview" ) ), FALSE );
350 static void preview_focusout( GtkSpinButton *spin, GdkEventFocus *event, double *data ){
351 *data = DegreesToRadians( (double)( gtk_spin_button_get_value_as_int( spin ) % 360 ) );
352 UpdatePreview( false );
355 static gint doublevariable_spinfocusout( GtkWidget* widget, GdkEventFocus* event, gpointer data ){
356 preview_focusout( GTK_SPIN_BUTTON( widget ), event, reinterpret_cast<double*>( data ) );
360 static void preview_spin( GtkAdjustment *adj, double *data ){
361 *data = DegreesToRadians( adj->value );
362 UpdatePreview( false );
365 void CreateViewWindow(){
366 GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame;
374 g_pWndPreview = dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL );
375 gtk_window_set_title( GTK_WINDOW( dlg ), "GtkGenSurf Preview" );
376 gtk_signal_connect( GTK_OBJECT( dlg ), "delete_event", GTK_SIGNAL_FUNC( preview_close ), NULL );
377 gtk_signal_connect( GTK_OBJECT( dlg ), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL );
378 gtk_window_set_transient_for( GTK_WINDOW( dlg ), GTK_WINDOW( g_pWnd ) );
379 gtk_window_set_default_size( GTK_WINDOW( dlg ), 300, 400 );
381 vbox = gtk_vbox_new( FALSE, 5 );
382 gtk_widget_show( vbox );
383 gtk_container_add( GTK_CONTAINER( dlg ), vbox );
386 hbox = gtk_hbox_new( TRUE, 5 );
387 gtk_widget_show( hbox );
388 gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, TRUE, 0 );
389 gtk_container_set_border_width( GTK_CONTAINER( hbox ), 3 );
391 label = gtk_label_new( "Elevation" );
392 gtk_widget_show( label );
393 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
394 gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, TRUE, 0 );
396 adj = gtk_adjustment_new( 30, -90, 90, 1, 10, 0 );
397 gtk_signal_connect( adj, "value_changed", GTK_SIGNAL_FUNC( preview_spin ), &elevation );
398 spin = gtk_spin_button_new( GTK_ADJUSTMENT( adj ), 1, 0 );
399 gtk_widget_show( spin );
400 gtk_box_pack_start( GTK_BOX( hbox ), spin, FALSE, TRUE, 0 );
401 g_signal_connect( G_OBJECT( spin ), "focus_out_event", G_CALLBACK( doublevariable_spinfocusout ), &elevation );
403 adj = gtk_adjustment_new( 30, 0, 359, 1, 10, 0 );
404 gtk_signal_connect( adj, "value_changed", GTK_SIGNAL_FUNC( preview_spin ), &azimuth );
405 spin = gtk_spin_button_new( GTK_ADJUSTMENT( adj ), 1, 0 );
406 gtk_widget_show( spin );
407 gtk_spin_button_set_wrap( GTK_SPIN_BUTTON( spin ), TRUE );
408 gtk_box_pack_end( GTK_BOX( hbox ), spin, FALSE, TRUE, 0 );
410 label = gtk_label_new( "Azimuth" );
411 gtk_widget_show( label );
412 gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 );
413 gtk_box_pack_end( GTK_BOX( hbox ), label, FALSE, TRUE, 0 );
414 g_signal_connect( G_OBJECT( spin ), "focus_out_event", G_CALLBACK( doublevariable_spinfocusout ), &azimuth );
417 frame = gtk_frame_new( NULL );
418 gtk_widget_show( frame );
419 gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN );
420 gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 0 );
422 g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new( FALSE, NULL );
424 gtk_widget_set_events( g_pPreviewWidget, GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | GDK_POINTER_MOTION_MASK );
425 gtk_signal_connect( GTK_OBJECT( g_pPreviewWidget ), "expose_event", GTK_SIGNAL_FUNC( expose ), NULL );
426 gtk_signal_connect( GTK_OBJECT( g_pPreviewWidget ), "motion_notify_event", GTK_SIGNAL_FUNC( motion ), NULL );
427 gtk_signal_connect( GTK_OBJECT( g_pPreviewWidget ), "button_press_event",
428 GTK_SIGNAL_FUNC( button_press ), NULL );
430 gtk_widget_show( g_pPreviewWidget );
431 gtk_container_add( GTK_CONTAINER( frame ), g_pPreviewWidget );
434 gtk_widget_show( g_pWndPreview );
437 UpdatePreview( true );
440 //=============================================================
442 void DrawPreview( Rect rc ){
443 #define COSXA 0.8660254037844
445 #define COSYA 0.8660254037844
453 char axis[3][2] = {"X","Y","Z"};
488 GetScaleFactor( rc );
490 g_GLTable.m_pfn_qglLineWidth( 1 );
491 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
492 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
494 if ( Decimate > 0 && ( Game != QUAKE3 || UsePatches == 0 ) ) {
497 vv = (XYZ *) malloc( gNumNodes * sizeof( XYZ ) );
498 for ( i = 0; i < gNumNodes; i++ )
500 for ( j = 0; j < 3; j++ )
501 vv[i].p[j] = (double)( gNode[i].p[j] );
505 for ( i = 0; i < gNumTris; i++ )
507 for ( j = 0; j < 3; j++ )
508 Scale( rc,vv[gTri[i].v[j]],&pt[j] );
510 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
511 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
512 g_GLTable.m_pfn_qglVertex2i( pt[1].x, pt[1].y );
513 g_GLTable.m_pfn_qglVertex2i( pt[2].x, pt[2].y );
514 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
515 g_GLTable.m_pfn_qglEnd();
519 else if ( Game == QUAKE3 && UsePatches != 0 ) {
538 for ( i = 0; i < NH; i += 2 )
540 for ( j = 0; j < NV; j += 2 )
542 VectorCopy( xyz[i ][j ].p,uv[0][0].p );
543 VectorCopy( xyz[i + 1][j ].p,uv[1][0].p );
544 VectorCopy( xyz[i + 2][j ].p,uv[2][0].p );
545 VectorCopy( xyz[i ][j + 1].p,uv[0][1].p );
546 VectorCopy( xyz[i + 1][j + 1].p,uv[1][1].p );
547 VectorCopy( xyz[i + 2][j + 1].p,uv[2][1].p );
548 VectorCopy( xyz[i ][j + 2].p,uv[0][2].p );
549 VectorCopy( xyz[i + 1][j + 2].p,uv[1][2].p );
550 VectorCopy( xyz[i + 2][j + 2].p,uv[2][2].p );
551 uv[1][0].p[k] = ( 4 * xyz[i + 1][j ].p[k] - xyz[i ][j ].p[k] - xyz[i + 2][j ].p[k] ) / 2;
552 uv[0][1].p[k] = ( 4 * xyz[i ][j + 1].p[k] - xyz[i ][j ].p[k] - xyz[i ][j + 2].p[k] ) / 2;
553 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;
554 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;
555 uv[1][1].p[k] = ( 16 * xyz[i + 1][j + 1].p[k] -
556 xyz[i ][j ].p[k] - 2 * xyz[i + 1][j ].p[k] - xyz[i + 2][j ].p[k] -
557 2 * xyz[i ][j + 1].p[k] - 2 * xyz[i + 2][j + 1].p[k] -
558 xyz[i ][j + 2].p[k] - 2 * xyz[i + 1][j + 2].p[k] - xyz[i + 2][j + 2].p[k] ) / 4;
560 for ( ii = 0; ii <= SUBDIVS; ii++ )
562 if ( ii == 0 || ii == SUBDIVS / 2 || ii == SUBDIVS ) {
563 g_GLTable.m_pfn_qglLineWidth( 1 );
564 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
565 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
570 g_GLTable.m_pfn_qglLineWidth( 1 );
571 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
572 g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 );
573 g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE );
577 u = (float)( ii ) / (float)( SUBDIVS );
578 for ( jj = 0; jj < 3; jj++ )
580 for ( axis = 0; axis < 3; axis++ )
584 a = (float)uv[0][jj].p[axis];
585 b = (float)uv[1][jj].p[axis];
586 c = (float)uv[2][jj].p[axis];
590 Ctrl[jj].p[axis] = qA * u * u + qB * u + qC;
593 VectorCopy( Ctrl[0].p,out.p );
595 Scale( rc,out,&pt[0] );
596 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
597 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
598 for ( jj = 1; jj <= SUBDIVS; jj++ )
600 v = (float)( jj ) / (float)( SUBDIVS );
601 for ( axis = 0 ; axis < 3 ; axis++ )
605 a = (float)Ctrl[0].p[axis];
606 b = (float)Ctrl[1].p[axis];
607 c = (float)Ctrl[2].p[axis];
611 out.p[axis] = qA * v * v + qB * v + qC;
614 Scale( rc,out,&pt[0] );
615 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
617 g_GLTable.m_pfn_qglEnd();
619 for ( jj = 0; jj <= SUBDIVS; jj++ )
621 if ( jj == 0 || jj == SUBDIVS / 2 || jj == SUBDIVS ) {
622 g_GLTable.m_pfn_qglLineWidth( 1 );
623 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
624 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
629 g_GLTable.m_pfn_qglLineWidth( 1 );
630 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
631 g_GLTable.m_pfn_qglLineStipple( 1, 0xF0F0 );
632 g_GLTable.m_pfn_qglEnable( GL_LINE_STIPPLE );
636 v = (float)( jj ) / (float)( SUBDIVS );
637 for ( ii = 0; ii < 3; ii++ )
639 for ( axis = 0; axis < 3; axis++ )
643 a = (float)uv[ii][0].p[axis];
644 b = (float)uv[ii][1].p[axis];
645 c = (float)uv[ii][2].p[axis];
649 Ctrl[ii].p[axis] = qA * v * v + qB * v + qC;
652 VectorCopy( Ctrl[0].p,out.p );
654 Scale( rc,out,&pt[0] );
655 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
656 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
657 for ( ii = 1; ii <= SUBDIVS; ii++ )
659 u = (float)( ii ) / (float)( SUBDIVS );
660 for ( axis = 0 ; axis < 3 ; axis++ )
664 a = (float)Ctrl[0].p[axis];
665 b = (float)Ctrl[1].p[axis];
666 c = (float)Ctrl[2].p[axis];
670 out.p[axis] = qA * u * u + qB * u + qC;
673 Scale( rc,out,&pt[0] );
674 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
676 g_GLTable.m_pfn_qglEnd();
683 for ( i = 0; i <= NH; i++ )
685 Scale( rc,xyz[i][0],&pt[0] );
686 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
687 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
688 for ( j = 1; j <= NV; j++ )
690 Scale( rc,xyz[i][j],&pt[0] );
691 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
693 g_GLTable.m_pfn_qglEnd();
695 for ( j = 0; j <= NV; j++ )
697 Scale( rc,xyz[0][j],&pt[0] );
698 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
699 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
700 for ( i = 1; i <= NH; i++ )
702 Scale( rc,xyz[i][j],&pt[0] );
703 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
705 g_GLTable.m_pfn_qglEnd();
709 if ( Game != QUAKE3 || UsePatches == 0 ) {
710 // Draw lines from corners to base, and lines around base
711 for ( i = 0; i <= NH; i += NH )
713 for ( j = 0; j <= NV; j += NV )
715 VectorCopy( xyz[i][j].p, v[0].p );
720 v[0].p[1] = backface;
724 v[0].p[0] = backface;
727 v[0].p[2] = backface;
729 Scale( rc,xyz[i][j],&pt[0] );
733 Scale( rc,v[0],&pt[1] );
734 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
735 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
736 g_GLTable.m_pfn_qglVertex2i( pt[1].x, pt[1].y );
737 g_GLTable.m_pfn_qglEnd();
740 VectorCopy( xyz[ 0][ 0].p, v[0].p );
741 VectorCopy( xyz[NH][ 0].p, v[1].p );
742 VectorCopy( xyz[NH][NV].p, v[2].p );
743 VectorCopy( xyz[ 0][NV].p, v[3].p );
748 v[0].p[1] = backface;;
749 v[1].p[1] = v[0].p[1];
750 v[2].p[1] = v[0].p[1];
751 v[3].p[1] = v[0].p[1];
755 v[0].p[0] = backface;
756 v[1].p[0] = v[0].p[0];
757 v[2].p[0] = v[0].p[0];
758 v[3].p[0] = v[0].p[0];
761 v[0].p[2] = backface;
762 v[1].p[2] = v[0].p[2];
763 v[2].p[2] = v[0].p[2];
764 v[3].p[2] = v[0].p[2];
769 Scale( rc,v[3],&pt[0] );
770 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
771 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
772 for ( i = 0; i < 3; i++ )
777 Scale( rc,v[i],&pt[1] );
778 g_GLTable.m_pfn_qglVertex2i( pt[1].x, pt[1].y );
780 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
781 g_GLTable.m_pfn_qglEnd();
784 g_GLTable.m_pfn_qglLineWidth( 1 );
785 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
786 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
789 // Draw small depiction of coordinate axes
790 pt[0].x = rc.right - cxChar - cxChar / 2 - cyChar;
791 pt[0].y = rc.bottom - cyChar / 2 - cxChar / 2;
792 pt[1].x = pt[0].x + (int)( cyChar * COSXA );
793 pt[1].y = pt[0].y - (int)( cyChar * SINXA );
794 MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
795 LineTo( hdc,pt[1].x,pt[1].y );
796 SetTextAlign( hdc,TA_LEFT | TA_TOP );
797 TextOut( hdc,pt[1].x,pt[1].y - cyChar / 2,"X",1 );
798 pt[1].x = pt[0].x - (int)( cyChar * COSYA );
799 pt[1].y = pt[0].y - (int)( cyChar * SINYA );
800 MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
801 LineTo( hdc,pt[1].x,pt[1].y );
802 SetTextAlign( hdc,TA_RIGHT | TA_TOP );
803 TextOut( hdc,pt[1].x,pt[1].y - cyChar / 2,"Y",1 );
805 pt[1].y = pt[0].y - cyChar;
806 MoveToEx( hdc,pt[0].x,pt[0].y,NULL );
807 LineTo( hdc,pt[1].x,pt[1].y );
808 SetTextAlign( hdc,TA_CENTER | TA_BOTTOM );
809 TextOut( hdc,pt[1].x,pt[1].y,"Z",1 );
811 L = 2 * (double)cyChar / SF;
824 for ( i = 0; i <= 3; i++ )
827 Scale( rc,v[i],&pt[i] );
829 for ( i = 1; i <= 3; i++ )
831 pt[i].x += -pt[0].x + rc.right - 2 * cyChar;
832 pt[i].y += -pt[0].y + rc.bottom + 2 * cyChar;
834 pt[0].x = rc.right - 2 * cyChar;
835 pt[0].y = rc.bottom + 2 * cyChar;
837 for ( i = 1; i <= 3; i++ )
839 g_GLTable.m_pfn_qglBegin( GL_LINES );
840 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
841 g_GLTable.m_pfn_qglVertex2i( pt[i].x, pt[i].y );
842 g_GLTable.m_pfn_qglEnd();
843 texfont_write( axis[i - 1], pt[i].x - cxChar / 2,pt[i].y + cyChar / 2 );
847 // Draw player model's bounding box in red to give a sense of scale
849 g_GLTable.m_pfn_qglLineWidth( 2 );
850 g_GLTable.m_pfn_qglColor3f( 1, 0, 0 );
851 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
856 v[0].p[0] = xyz[NH / 2][NV / 2].p[0] + PlayerBox[Game].x[0];
857 v[0].p[1] = xyz[NH / 2][NV / 2].p[1] + PlayerBox[Game].y[0];
858 v[0].p[2] = zmin - PlayerBox[Game].z[0] - 32;
861 v[0].p[0] = ( xmax + xmin ) / 2 + PlayerBox[Game].x[0];
862 v[0].p[1] = ymax + 64;
866 v[0].p[0] = ( xmax + xmin ) / 2 + PlayerBox[Game].x[0];
867 v[0].p[1] = ymin - 64;
871 v[0].p[0] = xmax + 64;
872 v[0].p[1] = ( ymax + ymin ) / 2 + PlayerBox[Game].y[0];
876 v[0].p[0] = xmin - 64;
877 v[0].p[1] = ( ymax + ymin ) / 2 + PlayerBox[Game].y[0];
881 // Put player on a node. For patches, put on an even numbered node.
882 if ( Game == QUAKE3 && UsePatches != 0 ) {
884 x = Hll + dh * (int)( NH / 2 + 1 );
887 x = Hll + dh * (int)( NH / 2 );
890 y = Vll + dv * (int)( NV / 2 + 1 );
893 y = Vll + dv * (int)( NV / 2 );
899 x = Hll + dh * (int)( NH / 2 );
905 y = Vll + dv * (int)( NV / 2 );
913 v[0].p[0] = x + PlayerBox[Game].x[0];
914 v[0].p[1] = y + PlayerBox[Game].y[0];
915 v[0].p[2] = PlayerStartZ( x,y ) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist
917 v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0];
918 v[1].p[1] = v[0].p[1];
919 v[1].p[2] = v[0].p[2];
920 v[2].p[0] = v[1].p[0];
921 v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0];
922 v[2].p[2] = v[0].p[2];
923 v[3].p[0] = v[0].p[0];
924 v[3].p[1] = v[2].p[1];
925 v[3].p[2] = v[0].p[2];
926 VectorCopy( v[0].p,v[4].p );
927 VectorCopy( v[1].p,v[5].p );
928 VectorCopy( v[2].p,v[6].p );
929 VectorCopy( v[3].p,v[7].p );
930 v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
931 v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
932 v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
933 v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0];
934 for ( i = 0; i <= 7; i++ )
939 Scale( rc,v[i],&pt[i] );
941 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
942 g_GLTable.m_pfn_qglVertex2i( pt[3].x, pt[3].y );
943 for ( i = 0; i <= 3; i++ )
944 g_GLTable.m_pfn_qglVertex2i( pt[i].x, pt[i].y );
945 g_GLTable.m_pfn_qglEnd();
946 g_GLTable.m_pfn_qglBegin( GL_LINE_STRIP );
947 g_GLTable.m_pfn_qglVertex2i( pt[7].x, pt[7].y );
948 for ( i = 4; i <= 7; i++ )
949 g_GLTable.m_pfn_qglVertex2i( pt[i].x, pt[i].y );
950 g_GLTable.m_pfn_qglEnd();
951 g_GLTable.m_pfn_qglBegin( GL_LINES );
952 for ( i = 0; i <= 3; i++ )
954 g_GLTable.m_pfn_qglVertex2i( pt[i].x,pt[i].y );
955 g_GLTable.m_pfn_qglVertex2i( pt[i + 4].x,pt[i + 4].y );
957 g_GLTable.m_pfn_qglEnd();
959 g_GLTable.m_pfn_qglLineWidth( 1 );
960 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
961 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
963 //=============================================================
964 void DrawGrid( Rect rc ){
970 w = (double)( rc.right - rc.left + 1 ) - cxChar;
971 h = (double)( rc.top - rc.bottom + 1 ) - cxChar - cyChar;
973 SFG = w / ( Hur - Hll );
974 SFG = min( SFG, h / ( Vur - Vll ) );
977 X0G = (int)( rc.left + rc.right - (int)( SFG * ( Hur - Hll ) ) ) / 2;
978 Y0G = (int)( rc.top + rc.bottom + cyChar - (int)( SFG * ( Vur - Vll ) ) ) / 2;
980 g_GLTable.m_pfn_qglLineWidth( 2 );
981 g_GLTable.m_pfn_qglColor3f( 0, 1, 0 );
982 g_GLTable.m_pfn_qglDisable( GL_LINE_STIPPLE );
985 pt[1].y = Y0G + (int)( SFG * ( Vur - Vll ) );
986 g_GLTable.m_pfn_qglBegin( GL_LINES );
987 for ( i = 0; i <= NH; i++ )
990 pt[0].x = X0G + (int)( SFG * ( x - Hll ) );
991 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[0].y );
992 g_GLTable.m_pfn_qglVertex2i( pt[0].x, pt[1].y );
994 g_GLTable.m_pfn_qglEnd();
996 pt[1].x = X0G + (int)( SFG * ( Hur - Hll ) );
997 g_GLTable.m_pfn_qglBegin( GL_LINES );
998 for ( i = 0; i <= NV; i++ )
1001 pt[0].y = Y0G + (int)( SFG * ( Vur - y ) );
1002 g_GLTable.m_pfn_qglVertex2i( pt[0].x,pt[0].y );
1003 g_GLTable.m_pfn_qglVertex2i( pt[1].x,pt[0].y );
1005 g_GLTable.m_pfn_qglEnd();
1007 g_GLTable.m_pfn_qglLineWidth( 1 );
1010 pt[0].x = rc.right - cyChar - cxChar - cyChar / 2;
1011 pt[0].y = rc.bottom + cyChar / 2;
1012 pt[1].x = pt[0].x + cyChar;
1014 g_GLTable.m_pfn_qglBegin( GL_LINES );
1015 g_GLTable.m_pfn_qglVertex2i( pt[0].x,pt[0].y );
1016 g_GLTable.m_pfn_qglVertex2i( pt[1].x,pt[1].y );
1017 g_GLTable.m_pfn_qglEnd();
1022 texfont_write( "Y", pt[1].x, pt[1].y + cyChar / 2 );
1025 texfont_write( "X", pt[1].x, pt[1].y + cyChar / 2 );
1028 pt[1].y = pt[0].y + cyChar;
1029 g_GLTable.m_pfn_qglBegin( GL_LINES );
1030 g_GLTable.m_pfn_qglVertex2i( pt[0].x,pt[0].y );
1031 g_GLTable.m_pfn_qglVertex2i( pt[1].x,pt[1].y );
1032 g_GLTable.m_pfn_qglEnd();
1037 texfont_write( "Y", pt[1].x - cyChar / 2, pt[1].y + cyChar );
1040 texfont_write( "Z", pt[1].x - cyChar / 2, pt[1].y + cyChar );
1043 // Denote fixed points with a 5x5 red rectangle
1044 for ( i = 0; i <= NH; i++ )
1046 for ( j = 0; j <= NV; j++ )
1048 if ( xyz[i][j].fixed ) {
1051 rcBox.left = X0G + (int)( SFG * ( x - Hll ) ) - 2;
1052 rcBox.top = Y0G + (int)( SFG * ( Vur - y ) ) + 2;
1053 rcBox.right = rcBox.left + 5;
1054 rcBox.bottom = rcBox.top - 5;
1056 DRAW_QUAD( rcBox, 1,0,0 );
1061 // Denote currently selected point with a 5x5 green rectangle
1062 if ( NumVerticesSelected ) {
1063 for ( k = 0; k < NumVerticesSelected; k++ )
1065 x = Hll + Vertex[k].i * dh;
1066 y = Vll + Vertex[k].j * dv;
1067 rcBox.left = X0G + (int)( SFG * ( x - Hll ) ) - 2;
1068 rcBox.top = Y0G + (int)( SFG * ( Vur - y ) ) + 2;
1069 rcBox.right = rcBox.left + 5;
1070 rcBox.bottom = rcBox.top - 5;
1072 DRAW_QUAD( rcBox, 0,1,0 );
1076 // Unmovable vertices
1077 for ( i = 0; i <= NH; i++ )
1079 for ( j = 0; j <= NV; j++ )
1081 if ( !CanEdit( i,j ) ) {
1084 rcBox.left = X0G + (int)( SFG * ( x - Hll ) ) - 2;
1085 rcBox.top = Y0G + (int)( SFG * ( Vur - y ) ) + 2;
1086 rcBox.right = rcBox.left + 5;
1087 rcBox.bottom = rcBox.top - 5;
1089 DRAW_QUAD( rcBox, 1,1,0 );
1095 rcBox.left = rc.left + cxChar / 2 - 2;
1096 rcBox.top = rc.top - cyChar / 2 - 2;
1097 rcBox.right = rcBox.left + 5;
1098 rcBox.bottom = rcBox.top - 5;
1099 DRAW_QUAD( rcBox, 1,0,0 );
1100 texfont_write( "Fixed points", rcBox.right + cxChar,rcBox.top - 4 + cyChar / 2 );
1102 rcBox.top -= cyChar;
1103 rcBox.bottom -= cyChar;
1104 DRAW_QUAD( rcBox, 1,1,0 );
1105 texfont_write( "Not movable", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2 );
1107 rcBox.top -= cyChar;
1108 rcBox.bottom -= cyChar;
1109 DRAW_QUAD( rcBox, 0,1,0 );
1110 texfont_write( "Selected", rcBox.right + cxChar, rcBox.top - 4 + cyChar / 2 );
1113 //=============================================================
1114 void GetScaleFactor( Rect rc ){
1118 w = (double)( rc.right - rc.left + 1 ) - cxChar;
1119 h = (double)( rc.top - rc.bottom + 1 ) - cxChar;
1121 SF = w / ( ( XHi - XLo ) * COSXA + ( YHi - YLo ) * COSYA );
1122 SF = min( SF, h / ( ( XHi - XLo ) * SINXA + ( YHi - YLo ) * SINYA + ZHi - ZLo ) );
1124 X0 = (int)( rc.left + rc.right - (int)( SF * ( ( XHi - XLo ) * COSXA + ( YHi - YLo ) * COSYA ) ) ) / 2;
1125 Y0 = (int)( rc.top + rc.bottom - (int)( SF * ( ( XHi - XLo ) * SINXA + ( YHi - YLo ) * SINYA + ZHi - ZLo ) ) ) / 2;
1130 w = (double)( rc.right - rc.left + 1 ) - cxChar;
1131 h = (double)( rc.top - rc.bottom + 1 ) - cxChar;
1133 SF = w / ( Hhi - Hlo );
1134 SF = min( SF, h / ( Vhi - Vlo ) );
1135 X0 = (int)( rc.left + rc.right - (int)( SF * ( Hhi - Hlo ) ) ) / 2;
1136 Y0 = (int)( rc.top + rc.bottom + (int)( SF * ( Vhi - Vlo ) ) ) / 2;
1140 //=============================================================
1141 void Scale( Rect rc,XYZ xyz,Point *pt ){
1145 pt[0].x = X0 + (int)( SF * ( ( xyz.p[0] - XLo ) * COSXA +
1146 ( YHi - xyz.p[1] ) * COSYA ) );
1147 pt[0].y = Y0 + (int)( SF * ( ZHi - xyz.p[2] +
1148 ( YHi - xyz.p[1] ) * SINYA +
1149 ( XHi - xyz.p[0] ) * SINXA ) );
1151 pt[0].x = X0 + (int)( SF * ( xyz.pp[0] - Hlo ) );
1152 pt[0].y = Y0 - (int)( SF * ( Vhi - xyz.pp[1] ) );
1158 /* ======================================================================= */
1159 void project( XYZ *v ){
1160 // project a 3D point (x,y,z) onto view plane
1161 double x, y, z, xa, ya, za;
1168 xa = ct[0] * x - st[0] * z;
1169 za = st[0] * x + ct[0] * z;
1172 x = ct[1] * xa + st[1] * y;
1173 ya = ct[1] * y - st[1] * xa;
1176 z = ct[2] * za - st[2] * ya;
1177 y = ct[2] * ya + st[2] * za;
1179 // horizontal and vertical projections:
1180 // v->pp[0] = D*x/z;
1181 // v->pp[1] = D*y/z;
1186 // NOTE: if perspective transformation is desired,
1187 // set "persp" to the range from the surface,
1189 // v->projected_h = -v->projected_h * persp/(v->projected_z-persp);
1190 // v->projected_v = -v->projected_v * persp/(v->projected_z-persp);
1192 /*=======================================================================*/
1197 if ( elevation > PI ) {
1198 elevation -= 2. * PI;
1200 roll = elevation * sin( azimuth );
1201 yaw = 1.5 * PI + elevation*cos( azimuth );
1203 // Find angles from midpoint to viewpoint:
1205 st[1] = sin( roll );
1206 st[2] = sin( azimuth );
1208 ct[1] = cos( roll );
1209 ct[2] = cos( azimuth );
1211 for ( i = 0; i <= NH; i++ )
1213 for ( j = 0; j <= NV; j++ )
1215 project( &xyz[i][j] );
1219 Hhi = xyz[0][0].pp[0];
1221 Vhi = xyz[0][0].pp[1];
1223 for ( i = 0; i <= NH; i++ )
1225 for ( j = 0; j <= NV; j++ )
1227 Hlo = min( Hlo,xyz[i][j].pp[0] );
1228 Hhi = max( Hhi,xyz[i][j].pp[0] );
1229 Vlo = min( Vlo,xyz[i][j].pp[1] );
1230 Vhi = max( Vhi,xyz[i][j].pp[1] );
1234 // Include backface in min-max
1235 VectorCopy( xyz[ 0][ 0].p,v[0].p );
1236 VectorCopy( xyz[NH][ 0].p,v[1].p );
1237 VectorCopy( xyz[NH][NV].p,v[2].p );
1238 VectorCopy( xyz[ 0][NV].p,v[3].p );
1243 v[0].p[1] = backface;
1244 v[1].p[1] = v[0].p[1];
1245 v[2].p[1] = v[0].p[1];
1246 v[3].p[1] = v[0].p[1];
1250 v[0].p[0] = backface;
1251 v[1].p[0] = v[0].p[0];
1252 v[2].p[0] = v[0].p[0];
1253 v[3].p[0] = v[0].p[0];
1256 v[0].p[2] = backface;
1257 v[1].p[2] = v[0].p[2];
1258 v[2].p[2] = v[0].p[2];
1259 v[3].p[2] = v[0].p[2];
1261 for ( i = 0; i <= 3; i++ )
1264 Hlo = min( Hlo,v[i].pp[0] );
1265 Hhi = max( Hhi,v[i].pp[0] );
1266 Vlo = min( Vlo,v[i].pp[1] );
1267 Vhi = max( Vhi,v[i].pp[1] );