From 67411cb18ec69b83c43ba8e6482c45baf83ec771 Mon Sep 17 00:00:00 2001 From: alex8664 Date: Sat, 31 Mar 2012 17:31:50 +0400 Subject: [PATCH 1/7] This is fix for failure of compilation on new libpng --- tools/quake3/q3map2/image.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/tools/quake3/q3map2/image.c b/tools/quake3/q3map2/image.c index b5a56e5c..d3b43633 100644 --- a/tools/quake3/q3map2/image.c +++ b/tools/quake3/q3map2/image.c @@ -123,12 +123,11 @@ void PNGReadData( png_struct *png, png_byte *buffer, png_size_t size ){ static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, int *height ){ png_struct *png; png_info *info, *end; - pngBuffer_t pb; + pngBuffer_t *pb = (pngBuffer_t*) png_get_io_ptr( png ); int i, bitDepth, colorType, channels; png_uint_32 w, h; byte **rowPointers; - /* dummy check */ if ( buffer == NULL || size <= 0 || pixels == NULL || width == NULL || height == NULL ) { return; @@ -167,14 +166,14 @@ static void LoadPNGBuffer( byte *buffer, int size, byte **pixels, int *width, in } /* set read callback */ - pb.buffer = buffer; - pb.size = size; - pb.offset = 0; + pb->buffer = buffer; + pb->size = size; + pb->offset = 0; png_set_read_fn( png, &pb, PNGReadData ); - png->io_ptr = &pb; /* hack! */ + //png->io_ptr = &pb; /* hack! */ /* set error longjmp */ - if ( setjmp( png->jmpbuf ) ) { + if ( setjmp( png_jmpbuf(png) ) ) { Sys_Printf( "WARNING: An error occurred reading PNG image\n" ); png_destroy_read_struct( &png, &info, &end ); return; From b6d70499bfbc5f99b6330c418bffb9f1797dc00b Mon Sep 17 00:00:00 2001 From: alex8664 Date: Sat, 31 Mar 2012 17:33:33 +0400 Subject: [PATCH 2/7] This is fix for failure of compilation on new libpng --- plugins/imagepng/plugin.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/plugins/imagepng/plugin.cpp b/plugins/imagepng/plugin.cpp index 9efdd2f5..784500f8 100644 --- a/plugins/imagepng/plugin.cpp +++ b/plugins/imagepng/plugin.cpp @@ -104,7 +104,7 @@ void user_warning_fn( png_structp png_ptr, png_const_charp warning_msg ){ void user_error_fn( png_structp png_ptr, png_const_charp error_msg ){ g_FuncTable.m_pfnSysPrintf( "libpng error: %s\n", error_msg ); - longjmp( png_ptr->jmpbuf, 0 ); + longjmp( png_jmpbuf(png_ptr), 0 ); } void user_read_data( png_structp png_ptr, png_bytep data, png_uint_32 length ){ @@ -153,9 +153,9 @@ void LoadImage( const char *filename, unsigned char **pic, int *width, int *heig } // configure the read function - png_set_read_fn( png_ptr, ( voidp ) & p_fbuffer, ( png_rw_ptr ) & user_read_data ); + png_set_read_fn( png_ptr, ( void * ) & p_fbuffer, ( png_rw_ptr ) & user_read_data ); - if ( setjmp( png_ptr->jmpbuf ) ) { + if ( setjmp( png_jmpbuf(png_ptr) ) ) { png_destroy_read_struct( &png_ptr, &info_ptr, &end_info ); if ( *pic ) { From adeab050ef4bf7e9fc01a0b67e385c72166399ef Mon Sep 17 00:00:00 2001 From: Clinton Freeman Date: Sun, 1 Apr 2012 16:54:44 -0400 Subject: [PATCH 3/7] reorganized about dialog and updated logo. fixed broken links --- install/bitmaps/logo.png | Bin 0 -> 24747 bytes radiant/gtkdlgs.cpp | 154 ++++++++++++++++++++------------------- 2 files changed, 80 insertions(+), 74 deletions(-) create mode 100644 install/bitmaps/logo.png diff --git a/install/bitmaps/logo.png b/install/bitmaps/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..cfa570bd3c46b510d941074bdbd388be9f9fda14 GIT binary patch literal 24747 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 literal 0 HcmV?d00001 diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp index 3c3ea0dd..7174c8d0 100644 --- a/radiant/gtkdlgs.cpp +++ b/radiant/gtkdlgs.cpp @@ -2497,6 +2497,8 @@ void DoThickenDlg(){ // ============================================================================= // About dialog (no program is complete without one) +static const int ABT_WIDGET_PADDING = 8; + void about_button_changelog( GtkWidget *widget, gpointer data ){ Str log; log = g_strAppPath; @@ -2512,11 +2514,15 @@ void about_button_credits( GtkWidget *widget, gpointer data ){ } void DoAbout(){ - GtkWidget *dlg, *vbox, *vbox2, *hbox, *frame, *table, *label, *pixmap, *button, *sc_extensions, *text_extensions; int loop = 1, ret = IDCANCEL; - dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + GtkWidget *main_vbox, *button_hbox, *gl_ext_hbox, *gl_ext_sc, *gl_ext_text; + GtkWidget *frame, *button, *table, *label, *image; + + // dialog + GtkWidget *dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_window_set_title( GTK_WINDOW( dlg ), _( "About GtkRadiant" ) ); + gtk_window_set_resizable( GTK_WINDOW( dlg ), FALSE ); gtk_signal_connect( GTK_OBJECT( dlg ), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); gtk_signal_connect( GTK_OBJECT( dlg ), "destroy", @@ -2524,77 +2530,53 @@ void DoAbout(){ g_object_set_data( G_OBJECT( dlg ), "loop", &loop ); g_object_set_data( G_OBJECT( dlg ), "ret", &ret ); - vbox = gtk_vbox_new( FALSE, 10 ); - gtk_widget_show( vbox ); - gtk_container_add( GTK_CONTAINER( dlg ), vbox ); - gtk_container_set_border_width( GTK_CONTAINER( vbox ), 5 ); + // layout top logo and everything else vertically without border padding + GtkWidget *outer_vbox = gtk_vbox_new( FALSE, 0 ); + gtk_widget_show( outer_vbox ); + gtk_container_add( GTK_CONTAINER( dlg ), outer_vbox ); + gtk_container_set_border_width( GTK_CONTAINER( outer_vbox ), 0 ); - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_widget_show( hbox ); - gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, TRUE, 0 ); + // radiant logo + CString s = g_strBitmapsPath; + s += "logo.png"; + image = gtk_image_new_from_file( s.GetBuffer() ); + gtk_widget_show( image ); + gtk_box_pack_start( GTK_BOX( outer_vbox ), image, FALSE, FALSE, 0 ); - vbox2 = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox2 ); - gtk_box_pack_start( GTK_BOX( hbox ), vbox2, TRUE, FALSE, 0 ); + // all other widgets layout + main_vbox = gtk_vbox_new( FALSE, ABT_WIDGET_PADDING ); + gtk_widget_show( main_vbox ); + gtk_box_pack_start( GTK_BOX( outer_vbox ), main_vbox, FALSE, FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER( main_vbox ), ABT_WIDGET_PADDING ); - frame = gtk_frame_new( NULL ); - gtk_widget_show( frame ); - gtk_box_pack_start( GTK_BOX( vbox2 ), frame, FALSE, FALSE, 0 ); - gtk_frame_set_shadow_type( GTK_FRAME( frame ), GTK_SHADOW_IN ); + // informative text + GtkWidget *info_hbox = gtk_hbox_new( FALSE, 0 ); + gtk_widget_show( info_hbox ); + gtk_box_pack_start( GTK_BOX( main_vbox ), info_hbox, FALSE, FALSE, 0 ); - pixmap = new_pixmap( g_pParentWnd->m_pWidget, "logo.bmp" ); - gtk_widget_show( pixmap ); - gtk_container_add( GTK_CONTAINER( frame ), pixmap ); - - label = gtk_label_new( "GtkRadiant " RADIANT_VERSION "\n" - __DATE__ "\n\n" + label = gtk_label_new( "GtkRadiant " RADIANT_VERSION " - " __DATE__ "\n" RADIANT_ABOUTMSG "\n\n" - "By qeradiant.com\n\n" - "This product contains software technology\n" - "from id Software, Inc. ('id Technology').\n" - "id Technology 2000 id Software,Inc.\n\n" - "GtkRadiant is unsupported, however\n" - "you may report your problems at\n" - "http://zerowing.idsoftware.com/bugzilla" - ); + "By http://icculus.org/gtkradiant/\n\n" + "This product contains software technology from id Software, Inc.\n" + "('id Technology'). id Technology 2000 id Software, Inc.\n\n" + "GtkRadiant is unsupported, however you may report your\n" + "problems at https://github.com/TTimo/GtkRadiant/issues" ); gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( hbox ), label, FALSE, FALSE, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 1, 0.5 ); + gtk_box_pack_start( GTK_BOX( info_hbox ), label, FALSE, FALSE, 0 ); gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); - vbox2 = gtk_vbox_new( FALSE, 5 ); - gtk_widget_show( vbox2 ); - gtk_box_pack_start( GTK_BOX( hbox ), vbox2, FALSE, TRUE, 0 ); - - button = gtk_button_new_with_label( _( "OK" ) ); - gtk_widget_show( button ); - gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", - GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); - - button = gtk_button_new_with_label( _( "Credits" ) ); - gtk_widget_show( button ); - gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", - GTK_SIGNAL_FUNC( about_button_credits ), NULL ); - - button = gtk_button_new_with_label( _( "Changelog" ) ); - gtk_widget_show( button ); - gtk_box_pack_start( GTK_BOX( vbox2 ), button, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", - GTK_SIGNAL_FUNC( about_button_changelog ), NULL ); - + // OpenGL properties frame = gtk_frame_new( _( "OpenGL Properties" ) ); gtk_widget_show( frame ); - gtk_box_pack_start( GTK_BOX( vbox ), frame, FALSE, FALSE, 0 ); + gtk_box_pack_start( GTK_BOX( main_vbox ), frame, FALSE, FALSE, 0 ); table = gtk_table_new( 3, 2, FALSE ); gtk_widget_show( table ); gtk_container_add( GTK_CONTAINER( frame ), table ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); - gtk_container_set_border_width( GTK_CONTAINER( table ), 5 ); + gtk_table_set_row_spacings( GTK_TABLE( table ), 4 ); + gtk_table_set_col_spacings( GTK_TABLE( table ), 4 ); + gtk_container_set_border_width( GTK_CONTAINER( table ), 4 ); label = gtk_label_new( _( "Vendor:" ) ); gtk_widget_show( label ); @@ -2638,28 +2620,52 @@ void DoAbout(){ (GtkAttachOptions) ( 0 ), 0, 0 ); gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + // OpenGL extensions frame = gtk_frame_new( _( "OpenGL Extensions" ) ); gtk_widget_show( frame ); - gtk_box_pack_start( GTK_BOX( vbox ), frame, TRUE, TRUE, 0 ); + gtk_box_pack_start( GTK_BOX( main_vbox ), frame, TRUE, TRUE, 0 ); - hbox = gtk_hbox_new( FALSE, 5 ); - gtk_widget_show( hbox ); - gtk_container_add( GTK_CONTAINER( frame ), hbox ); - gtk_container_set_border_width( GTK_CONTAINER( hbox ), 5 ); + gl_ext_hbox = gtk_hbox_new( FALSE, ABT_WIDGET_PADDING ); + gtk_widget_show( gl_ext_hbox ); + gtk_container_add( GTK_CONTAINER( frame ), gl_ext_hbox ); + gtk_container_set_border_width( GTK_CONTAINER( gl_ext_hbox ), 4 ); - sc_extensions = gtk_scrolled_window_new( NULL, NULL ); - gtk_box_pack_start( GTK_BOX( hbox ), sc_extensions, TRUE, TRUE, 0 ); - gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( sc_extensions ), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS ); - gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( sc_extensions ), GTK_SHADOW_IN ); - gtk_widget_show( sc_extensions ); + gl_ext_sc = gtk_scrolled_window_new( NULL, NULL ); + gtk_box_pack_start( GTK_BOX( gl_ext_hbox ), gl_ext_sc, TRUE, TRUE, 0 ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( gl_ext_sc ), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS ); + gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( gl_ext_sc ), GTK_SHADOW_IN ); + gtk_widget_show( gl_ext_sc ); - text_extensions = gtk_text_view_new(); - gtk_text_view_set_editable( GTK_TEXT_VIEW( text_extensions ), FALSE ); - gtk_container_add( GTK_CONTAINER( sc_extensions ), text_extensions ); - GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( text_extensions ) ); + gl_ext_text = gtk_text_view_new(); + gtk_text_view_set_editable( GTK_TEXT_VIEW( gl_ext_text ), FALSE ); + gtk_container_add( GTK_CONTAINER( gl_ext_sc ), gl_ext_text ); + GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( gl_ext_text ) ); gtk_text_buffer_set_text( buffer, (char *)qglGetString( GL_EXTENSIONS ), -1 ); - gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( text_extensions ), GTK_WRAP_WORD );; - gtk_widget_show( text_extensions ); + gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( gl_ext_text ), GTK_WRAP_WORD );; + gtk_widget_show( gl_ext_text ); + + // buttons + button_hbox = gtk_hbox_new( FALSE, 4 ); + gtk_widget_show( button_hbox ); + gtk_box_pack_start( GTK_BOX( main_vbox ), button_hbox, FALSE, TRUE, 0 ); + + button = gtk_button_new_with_label( _( "OK" ) ); + gtk_widget_show( button ); + gtk_box_pack_end( GTK_BOX( button_hbox ), button, FALSE, FALSE, 0 ); + gtk_signal_connect( GTK_OBJECT( button ), "clicked", + GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + + button = gtk_button_new_with_label( _( "Credits" ) ); + gtk_widget_show( button ); + gtk_box_pack_end( GTK_BOX( button_hbox ), button, FALSE, FALSE, 0 ); + gtk_signal_connect( GTK_OBJECT( button ), "clicked", + GTK_SIGNAL_FUNC( about_button_credits ), NULL ); + + button = gtk_button_new_with_label( _( "Changelog" ) ); + gtk_widget_show( button ); + gtk_box_pack_end( GTK_BOX( button_hbox ), button, FALSE, FALSE, 0 ); + gtk_signal_connect( GTK_OBJECT( button ), "clicked", + GTK_SIGNAL_FUNC( about_button_changelog ), NULL ); gtk_grab_add( dlg ); gtk_widget_show( dlg ); From 5a4c0cc6bcd809371f556be2d383a305c23d7881 Mon Sep 17 00:00:00 2001 From: Clinton Freeman Date: Sun, 1 Apr 2012 20:37:53 -0400 Subject: [PATCH 4/7] reorganized about dialog code, added updated 1.5.0 .ico --- radiant/gtkdlgs.cpp | 163 ++++++++++++++++++++++---------------------- radiant/radiant.ico | Bin 1078 -> 171238 bytes 2 files changed, 82 insertions(+), 81 deletions(-) diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp index 7174c8d0..21237640 100644 --- a/radiant/gtkdlgs.cpp +++ b/radiant/gtkdlgs.cpp @@ -2499,6 +2499,7 @@ void DoThickenDlg(){ static const int ABT_WIDGET_PADDING = 8; +//! @note kaz 04/01/2012 - not in use void about_button_changelog( GtkWidget *widget, gpointer data ){ Str log; log = g_strAppPath; @@ -2506,6 +2507,7 @@ void about_button_changelog( GtkWidget *widget, gpointer data ){ OpenURL( log.GetBuffer() ); } +//! @note kaz 04/01/2012 - not in use void about_button_credits( GtkWidget *widget, gpointer data ){ Str cred; cred = g_strAppPath; @@ -2514,12 +2516,9 @@ void about_button_credits( GtkWidget *widget, gpointer data ){ } void DoAbout(){ - int loop = 1, ret = IDCANCEL; + int loop = TRUE, ret = IDCANCEL; - GtkWidget *main_vbox, *button_hbox, *gl_ext_hbox, *gl_ext_sc, *gl_ext_text; - GtkWidget *frame, *button, *table, *label, *image; - - // dialog + // create dialog window GtkWidget *dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL ); gtk_window_set_title( GTK_WINDOW( dlg ), _( "About GtkRadiant" ) ); gtk_window_set_resizable( GTK_WINDOW( dlg ), FALSE ); @@ -2534,127 +2533,128 @@ void DoAbout(){ GtkWidget *outer_vbox = gtk_vbox_new( FALSE, 0 ); gtk_widget_show( outer_vbox ); gtk_container_add( GTK_CONTAINER( dlg ), outer_vbox ); - gtk_container_set_border_width( GTK_CONTAINER( outer_vbox ), 0 ); + gtk_container_set_border_width( GTK_CONTAINER( outer_vbox ), 0 ); // radiant logo CString s = g_strBitmapsPath; - s += "logo.png"; - image = gtk_image_new_from_file( s.GetBuffer() ); - gtk_widget_show( image ); - gtk_box_pack_start( GTK_BOX( outer_vbox ), image, FALSE, FALSE, 0 ); + s += "logo.png"; + GtkWidget *logo_image = gtk_image_new_from_file( s.GetBuffer() ); + gtk_widget_show( logo_image ); + gtk_box_pack_start( GTK_BOX( outer_vbox ), logo_image, FALSE, FALSE, 0 ); // all other widgets layout - main_vbox = gtk_vbox_new( FALSE, ABT_WIDGET_PADDING ); - gtk_widget_show( main_vbox ); - gtk_box_pack_start( GTK_BOX( outer_vbox ), main_vbox, FALSE, FALSE, 0 ); - gtk_container_set_border_width( GTK_CONTAINER( main_vbox ), ABT_WIDGET_PADDING ); + GtkWidget *inner_vbox = gtk_vbox_new( FALSE, ABT_WIDGET_PADDING ); + gtk_widget_show( inner_vbox ); + gtk_box_pack_start( GTK_BOX( outer_vbox ), inner_vbox, FALSE, FALSE, 0 ); + gtk_container_set_border_width( GTK_CONTAINER( inner_vbox ), ABT_WIDGET_PADDING ); // informative text GtkWidget *info_hbox = gtk_hbox_new( FALSE, 0 ); gtk_widget_show( info_hbox ); - gtk_box_pack_start( GTK_BOX( main_vbox ), info_hbox, FALSE, FALSE, 0 ); + gtk_box_pack_start( GTK_BOX( inner_vbox ), info_hbox, FALSE, FALSE, 0 ); - label = gtk_label_new( "GtkRadiant " RADIANT_VERSION " - " __DATE__ "\n" - RADIANT_ABOUTMSG "\n\n" - "By http://icculus.org/gtkradiant/\n\n" - "This product contains software technology from id Software, Inc.\n" - "('id Technology'). id Technology 2000 id Software, Inc.\n\n" - "GtkRadiant is unsupported, however you may report your\n" - "problems at https://github.com/TTimo/GtkRadiant/issues" ); + GtkWidget *info_label = gtk_label_new( + "GtkRadiant " RADIANT_VERSION " - " __DATE__ "\n" + RADIANT_ABOUTMSG "\n\n" + "This product contains software technology from id Software, Inc.\n" + "('id Technology'). id Technology 2000 id Software, Inc.\n\n" + "Visit http://icculus.org/gtkradiant/ to view a full list of credits,\n" + "changelogs, and to report problems with this software." ); - gtk_widget_show( label ); - gtk_box_pack_start( GTK_BOX( info_hbox ), label, FALSE, FALSE, 0 ); - gtk_label_set_justify( GTK_LABEL( label ), GTK_JUSTIFY_LEFT ); + gtk_widget_show( info_label ); + gtk_box_pack_start( GTK_BOX( info_hbox ), info_label, FALSE, FALSE, 0 ); + gtk_label_set_justify( GTK_LABEL( info_label ), GTK_JUSTIFY_LEFT ); // OpenGL properties - frame = gtk_frame_new( _( "OpenGL Properties" ) ); - gtk_widget_show( frame ); - gtk_box_pack_start( GTK_BOX( main_vbox ), frame, FALSE, FALSE, 0 ); + GtkWidget *gl_prop_frame = gtk_frame_new( _( "OpenGL Properties" ) ); + gtk_widget_show( gl_prop_frame ); + gtk_box_pack_start( GTK_BOX( inner_vbox ), gl_prop_frame, FALSE, FALSE, 0 ); - table = gtk_table_new( 3, 2, FALSE ); - gtk_widget_show( table ); - gtk_container_add( GTK_CONTAINER( frame ), table ); - gtk_table_set_row_spacings( GTK_TABLE( table ), 4 ); - gtk_table_set_col_spacings( GTK_TABLE( table ), 4 ); - gtk_container_set_border_width( GTK_CONTAINER( table ), 4 ); + GtkWidget *gl_prop_table = gtk_table_new( 3, 2, FALSE ); + gtk_widget_show( gl_prop_table ); + gtk_container_add( GTK_CONTAINER( gl_prop_frame ), gl_prop_table ); + gtk_table_set_row_spacings( GTK_TABLE( gl_prop_table ), 4 ); + gtk_table_set_col_spacings( GTK_TABLE( gl_prop_table ), 4 ); + gtk_container_set_border_width( GTK_CONTAINER( gl_prop_table ), 4 ); - label = gtk_label_new( _( "Vendor:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 0, 1, + GtkWidget *vendor_label = gtk_label_new( _( "Vendor:" ) ); + gtk_widget_show( vendor_label ); + gtk_table_attach( GTK_TABLE( gl_prop_table ), vendor_label, 0, 1, 0, 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + gtk_misc_set_alignment( GTK_MISC( vendor_label ), 0, 0.5 ); - label = gtk_label_new( _( "Version:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 1, 2, + GtkWidget *version_label = gtk_label_new( _( "Version:" ) ); + gtk_widget_show( version_label ); + gtk_table_attach( GTK_TABLE( gl_prop_table ), version_label, 0, 1, 1, 2, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + gtk_misc_set_alignment( GTK_MISC( version_label ), 0, 0.5 ); - label = gtk_label_new( _( "Renderer:" ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 0, 1, 2, 3, + GtkWidget *renderer_label = gtk_label_new( _( "Renderer:" ) ); + gtk_widget_show( renderer_label ); + gtk_table_attach( GTK_TABLE( gl_prop_table ), renderer_label, 0, 1, 2, 3, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + gtk_misc_set_alignment( GTK_MISC( renderer_label ), 0, 0.5 ); - label = gtk_label_new( (char*)qglGetString( GL_VENDOR ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 1, 2, 0, 1, + GtkWidget *gl_vendor_label = gtk_label_new( (char*)qglGetString( GL_VENDOR ) ); + gtk_widget_show( gl_vendor_label ); + gtk_table_attach( GTK_TABLE( gl_prop_table ), gl_vendor_label, 1, 2, 0, 1, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + gtk_misc_set_alignment( GTK_MISC( gl_vendor_label ), 0, 0.5 ); - label = gtk_label_new( (char*)qglGetString( GL_VERSION ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 1, 2, 1, 2, + GtkWidget *gl_version_label = gtk_label_new( (char*)qglGetString( GL_VERSION ) ); + gtk_widget_show( gl_version_label ); + gtk_table_attach( GTK_TABLE( gl_prop_table ), gl_version_label, 1, 2, 1, 2, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + gtk_misc_set_alignment( GTK_MISC( gl_version_label ), 0, 0.5 ); - label = gtk_label_new( (char*)qglGetString( GL_RENDERER ) ); - gtk_widget_show( label ); - gtk_table_attach( GTK_TABLE( table ), label, 1, 2, 2, 3, + GtkWidget *gl_renderer_label = gtk_label_new( (char*)qglGetString( GL_RENDERER ) ); + gtk_widget_show( gl_renderer_label ); + gtk_table_attach( GTK_TABLE( gl_prop_table ), gl_renderer_label, 1, 2, 2, 3, (GtkAttachOptions) ( GTK_FILL ), (GtkAttachOptions) ( 0 ), 0, 0 ); - gtk_misc_set_alignment( GTK_MISC( label ), 0, 0.5 ); + gtk_misc_set_alignment( GTK_MISC( gl_renderer_label ), 0, 0.5 ); // OpenGL extensions - frame = gtk_frame_new( _( "OpenGL Extensions" ) ); - gtk_widget_show( frame ); - gtk_box_pack_start( GTK_BOX( main_vbox ), frame, TRUE, TRUE, 0 ); + GtkWidget *gl_ext_frame = gtk_frame_new( _( "OpenGL Extensions" ) ); + gtk_widget_show( gl_ext_frame ); + gtk_box_pack_start( GTK_BOX( inner_vbox ), gl_ext_frame, TRUE, TRUE, 0 ); - gl_ext_hbox = gtk_hbox_new( FALSE, ABT_WIDGET_PADDING ); + GtkWidget *gl_ext_hbox = gtk_hbox_new( FALSE, ABT_WIDGET_PADDING ); gtk_widget_show( gl_ext_hbox ); - gtk_container_add( GTK_CONTAINER( frame ), gl_ext_hbox ); + gtk_container_add( GTK_CONTAINER( gl_ext_frame ), gl_ext_hbox ); gtk_container_set_border_width( GTK_CONTAINER( gl_ext_hbox ), 4 ); - gl_ext_sc = gtk_scrolled_window_new( NULL, NULL ); - gtk_box_pack_start( GTK_BOX( gl_ext_hbox ), gl_ext_sc, TRUE, TRUE, 0 ); - gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( gl_ext_sc ), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS ); - gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( gl_ext_sc ), GTK_SHADOW_IN ); - gtk_widget_show( gl_ext_sc ); + GtkWidget *gl_ext_scroll = gtk_scrolled_window_new( NULL, NULL ); + gtk_box_pack_start( GTK_BOX( gl_ext_hbox ), gl_ext_scroll, TRUE, TRUE, 0 ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( gl_ext_scroll ), GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS ); + gtk_scrolled_window_set_shadow_type( GTK_SCROLLED_WINDOW( gl_ext_scroll ), GTK_SHADOW_IN ); + gtk_widget_show( gl_ext_scroll ); - gl_ext_text = gtk_text_view_new(); - gtk_text_view_set_editable( GTK_TEXT_VIEW( gl_ext_text ), FALSE ); - gtk_container_add( GTK_CONTAINER( gl_ext_sc ), gl_ext_text ); - GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( gl_ext_text ) ); + GtkWidget *gl_ext_textview = gtk_text_view_new(); + gtk_text_view_set_editable( GTK_TEXT_VIEW( gl_ext_textview ), FALSE ); + gtk_container_add( GTK_CONTAINER( gl_ext_scroll ), gl_ext_textview ); + GtkTextBuffer* buffer = gtk_text_view_get_buffer( GTK_TEXT_VIEW( gl_ext_textview ) ); gtk_text_buffer_set_text( buffer, (char *)qglGetString( GL_EXTENSIONS ), -1 ); - gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( gl_ext_text ), GTK_WRAP_WORD );; - gtk_widget_show( gl_ext_text ); + gtk_text_view_set_wrap_mode( GTK_TEXT_VIEW( gl_ext_textview ), GTK_WRAP_WORD );; + gtk_widget_show( gl_ext_textview ); // buttons - button_hbox = gtk_hbox_new( FALSE, 4 ); + GtkWidget *button_hbox = gtk_hbox_new( FALSE, 4 ); gtk_widget_show( button_hbox ); - gtk_box_pack_start( GTK_BOX( main_vbox ), button_hbox, FALSE, TRUE, 0 ); + gtk_box_pack_start( GTK_BOX( inner_vbox ), button_hbox, FALSE, TRUE, 0 ); - button = gtk_button_new_with_label( _( "OK" ) ); - gtk_widget_show( button ); - gtk_box_pack_end( GTK_BOX( button_hbox ), button, FALSE, FALSE, 0 ); - gtk_signal_connect( GTK_OBJECT( button ), "clicked", + GtkWidget *ok_button = gtk_button_new_with_label( _( "OK" ) ); + gtk_widget_show( ok_button ); + gtk_box_pack_end( GTK_BOX( button_hbox ), ok_button, FALSE, FALSE, 0 ); + gtk_signal_connect( GTK_OBJECT( ok_button ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + /* button = gtk_button_new_with_label( _( "Credits" ) ); gtk_widget_show( button ); gtk_box_pack_end( GTK_BOX( button_hbox ), button, FALSE, FALSE, 0 ); @@ -2666,11 +2666,12 @@ void DoAbout(){ gtk_box_pack_end( GTK_BOX( button_hbox ), button, FALSE, FALSE, 0 ); gtk_signal_connect( GTK_OBJECT( button ), "clicked", GTK_SIGNAL_FUNC( about_button_changelog ), NULL ); + */ gtk_grab_add( dlg ); gtk_widget_show( dlg ); - while ( loop ) + while( loop ) gtk_main_iteration(); gtk_grab_remove( dlg ); diff --git a/radiant/radiant.ico b/radiant/radiant.ico index cca8503f29cc380b4e6cfb47603492ee03ea0198..89d4bbb5d44f5b1077a012eb0aff040522954737 100644 GIT binary patch literal 171238 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 From 6a2288bb90b4d5bd0fe594d376d516a621254ba1 Mon Sep 17 00:00:00 2001 From: Clinton Freeman Date: Sun, 1 Apr 2012 21:01:18 -0400 Subject: [PATCH 5/7] centered about on parent window --- radiant/gtkdlgs.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/radiant/gtkdlgs.cpp b/radiant/gtkdlgs.cpp index 21237640..eeeab109 100644 --- a/radiant/gtkdlgs.cpp +++ b/radiant/gtkdlgs.cpp @@ -2520,6 +2520,8 @@ void DoAbout(){ // create dialog window GtkWidget *dlg = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_transient_for( GTK_WINDOW( dlg ), GTK_WINDOW( g_pParentWnd->m_pWidget ) ); + gtk_window_set_position( GTK_WINDOW( dlg ), GTK_WIN_POS_CENTER_ON_PARENT ); gtk_window_set_title( GTK_WINDOW( dlg ), _( "About GtkRadiant" ) ); gtk_window_set_resizable( GTK_WINDOW( dlg ), FALSE ); gtk_signal_connect( GTK_OBJECT( dlg ), "delete_event", @@ -2668,6 +2670,7 @@ void DoAbout(){ GTK_SIGNAL_FUNC( about_button_changelog ), NULL ); */ + // show it gtk_grab_add( dlg ); gtk_widget_show( dlg ); From c64cd0cd05ef3d237097ff38d1da727a88bb7c7c Mon Sep 17 00:00:00 2001 From: Timothee TTimo Besset Date: Sat, 7 Apr 2012 18:53:01 -0500 Subject: [PATCH 6/7] Q2Tools source - didn't import this in initially --- tools/quake2/extra/COPYING.txt | 281 ++ tools/quake2/extra/Unpack/Unpack.dsp | 72 + tools/quake2/extra/Unpack/Unpack.dsw | 29 + tools/quake2/extra/Unpack/Unpack.java | 198 ++ tools/quake2/extra/bsp/bsp.mak | 1776 ++++++++++ tools/quake2/extra/bsp/bspinfo3/bspinfo3.c | 56 + tools/quake2/extra/bsp/bspinfo3/makefile | 53 + tools/quake2/extra/bsp/qbsp3/brushbsp.c | 1330 +++++++ tools/quake2/extra/bsp/qbsp3/csg.c | 635 ++++ tools/quake2/extra/bsp/qbsp3/faces.c | 1076 ++++++ tools/quake2/extra/bsp/qbsp3/gldraw.c | 232 ++ tools/quake2/extra/bsp/qbsp3/glfile.c | 149 + tools/quake2/extra/bsp/qbsp3/leakfile.c | 100 + tools/quake2/extra/bsp/qbsp3/makefile | 98 + tools/quake2/extra/bsp/qbsp3/map.c | 1017 ++++++ tools/quake2/extra/bsp/qbsp3/nodraw.c | 47 + tools/quake2/extra/bsp/qbsp3/portals.c | 1111 ++++++ tools/quake2/extra/bsp/qbsp3/prtfile.c | 287 ++ tools/quake2/extra/bsp/qbsp3/qbsp.h | 355 ++ tools/quake2/extra/bsp/qbsp3/qbsp3.c | 537 +++ tools/quake2/extra/bsp/qbsp3/textures.c | 221 ++ tools/quake2/extra/bsp/qbsp3/tree.c | 219 ++ tools/quake2/extra/bsp/qbsp3/writebsp.c | 590 ++++ tools/quake2/extra/bsp/qrad3/lightmap.c | 1316 +++++++ tools/quake2/extra/bsp/qrad3/makefile | 77 + tools/quake2/extra/bsp/qrad3/patches.c | 515 +++ tools/quake2/extra/bsp/qrad3/qrad.h | 158 + tools/quake2/extra/bsp/qrad3/qrad3.c | 717 ++++ tools/quake2/extra/bsp/qrad3/trace.c | 295 ++ tools/quake2/extra/bsp/qvis3/flow.c | 788 +++++ tools/quake2/extra/bsp/qvis3/makefile | 62 + tools/quake2/extra/bsp/qvis3/qvis3.c | 615 ++++ tools/quake2/extra/bsp/qvis3/vis.h | 149 + tools/quake2/extra/common/bspfile.c | 789 +++++ tools/quake2/extra/common/bspfile.h | 129 + tools/quake2/extra/common/cmdlib.c | 1055 ++++++ tools/quake2/extra/common/cmdlib.h | 145 + tools/quake2/extra/common/l3dslib.c | 301 ++ tools/quake2/extra/common/l3dslib.h | 27 + tools/quake2/extra/common/lbmlib.c | 824 +++++ tools/quake2/extra/common/lbmlib.h | 40 + tools/quake2/extra/common/mathlib.c | 174 + tools/quake2/extra/common/mathlib.h | 77 + tools/quake2/extra/common/mdfour.c | 224 ++ tools/quake2/extra/common/mdfour.h | 54 + tools/quake2/extra/common/polylib.c | 642 ++++ tools/quake2/extra/common/polylib.h | 55 + tools/quake2/extra/common/qfiles.h | 486 +++ tools/quake2/extra/common/scriplib.c | 297 ++ tools/quake2/extra/common/scriplib.h | 45 + tools/quake2/extra/common/threads.c | 448 +++ tools/quake2/extra/common/threads.h | 31 + tools/quake2/extra/common/trilib.c | 187 + tools/quake2/extra/common/trilib.h | 33 + tools/quake2/extra/qdata/anorms.h | 184 + tools/quake2/extra/qdata/images.c | 763 ++++ tools/quake2/extra/qdata/makefile | 81 + tools/quake2/extra/qdata/models.c | 1152 ++++++ tools/quake2/extra/qdata/qdata.c | 551 +++ tools/quake2/extra/qdata/qdata.dsp | 204 ++ tools/quake2/extra/qdata/qdata.dsw | 29 + tools/quake2/extra/qdata/qdata.h | 89 + tools/quake2/extra/qdata/qdata.mak | 549 +++ tools/quake2/extra/qdata/sprites.c | 228 ++ tools/quake2/extra/qdata/tables.c | 172 + tools/quake2/extra/qdata/video.c | 1259 +++++++ tools/quake2/extra/qe4/brush.c | 1568 +++++++++ tools/quake2/extra/qe4/brush.h | 87 + tools/quake2/extra/qe4/bspfile.h | 378 ++ tools/quake2/extra/qe4/camera.c | 594 ++++ tools/quake2/extra/qe4/camera.h | 63 + tools/quake2/extra/qe4/cmdlib.c | 686 ++++ tools/quake2/extra/qe4/cmdlib.h | 99 + tools/quake2/extra/qe4/csg.c | 168 + tools/quake2/extra/qe4/drag.c | 457 +++ tools/quake2/extra/qe4/eclass.c | 281 ++ tools/quake2/extra/qe4/entity.c | 538 +++ tools/quake2/extra/qe4/entity.h | 84 + tools/quake2/extra/qe4/entityw.h | 66 + tools/quake2/extra/qe4/glingr.h | 98 + tools/quake2/extra/qe4/icon1.ico | Bin 0 -> 766 bytes tools/quake2/extra/qe4/lbmlib.c | 835 +++++ tools/quake2/extra/qe4/lbmlib.h | 40 + tools/quake2/extra/qe4/makefile | 23 + tools/quake2/extra/qe4/map.c | 661 ++++ tools/quake2/extra/qe4/map.h | 53 + tools/quake2/extra/qe4/mathlib.c | 131 + tools/quake2/extra/qe4/mathlib.h | 66 + tools/quake2/extra/qe4/mru.c | 671 ++++ tools/quake2/extra/qe4/mru.h | 101 + tools/quake2/extra/qe4/parse.c | 141 + tools/quake2/extra/qe4/parse.h | 34 + tools/quake2/extra/qe4/points.c | 155 + tools/quake2/extra/qe4/q.bmp | Bin 0 -> 13878 bytes tools/quake2/extra/qe4/qe3.c | 451 +++ tools/quake2/extra/qe4/qe3.h | 306 ++ tools/quake2/extra/qe4/qe4.mak | 3716 ++++++++++++++++++++ tools/quake2/extra/qe4/qedefs.h | 117 + tools/quake2/extra/qe4/qfiles.h | 389 ++ tools/quake2/extra/qe4/resource.h | 308 ++ tools/quake2/extra/qe4/select.c | 706 ++++ tools/quake2/extra/qe4/select.h | 62 + tools/quake2/extra/qe4/textures.c | 1147 ++++++ tools/quake2/extra/qe4/textures.h | 70 + tools/quake2/extra/qe4/toolbar1.bmp | Bin 0 -> 1918 bytes tools/quake2/extra/qe4/vertsel.c | 245 ++ tools/quake2/extra/qe4/view.h | 52 + tools/quake2/extra/qe4/win_cam.c | 273 ++ tools/quake2/extra/qe4/win_dlg.c | 653 ++++ tools/quake2/extra/qe4/win_ent.c | 1137 ++++++ tools/quake2/extra/qe4/win_main.c | 1327 +++++++ tools/quake2/extra/qe4/win_qe3.aps | Bin 0 -> 78688 bytes tools/quake2/extra/qe4/win_qe3.c | 605 ++++ tools/quake2/extra/qe4/win_qe3.rc | 693 ++++ tools/quake2/extra/qe4/win_xy.c | 306 ++ tools/quake2/extra/qe4/win_z.c | 195 + tools/quake2/extra/qe4/xy.c | 973 +++++ tools/quake2/extra/qe4/xy.h | 48 + tools/quake2/extra/qe4/z.c | 426 +++ tools/quake2/extra/qe4/z.h | 42 + tools/quake2/extra/texpaint/docs.txt | 38 + tools/quake2/extra/texpaint/resource.h | 58 + tools/quake2/extra/texpaint/texmake.aps | Bin 0 -> 33472 bytes tools/quake2/extra/texpaint/texmake.rc | 156 + tools/quake2/extra/texpaint/texpaint.c | 311 ++ tools/quake2/extra/texpaint/texpaint.h | 88 + tools/quake2/extra/texpaint/texpaint.mak | 468 +++ tools/quake2/extra/texpaint/win_cam.c | 414 +++ tools/quake2/extra/texpaint/win_main.c | 496 +++ tools/quake2/extra/texpaint/win_pal.c | 257 ++ tools/quake2/extra/texpaint/win_skin.c | 946 +++++ 131 files changed, 52042 insertions(+) create mode 100644 tools/quake2/extra/COPYING.txt create mode 100644 tools/quake2/extra/Unpack/Unpack.dsp create mode 100644 tools/quake2/extra/Unpack/Unpack.dsw create mode 100644 tools/quake2/extra/Unpack/Unpack.java create mode 100644 tools/quake2/extra/bsp/bsp.mak create mode 100644 tools/quake2/extra/bsp/bspinfo3/bspinfo3.c create mode 100644 tools/quake2/extra/bsp/bspinfo3/makefile create mode 100644 tools/quake2/extra/bsp/qbsp3/brushbsp.c create mode 100644 tools/quake2/extra/bsp/qbsp3/csg.c create mode 100644 tools/quake2/extra/bsp/qbsp3/faces.c create mode 100644 tools/quake2/extra/bsp/qbsp3/gldraw.c create mode 100644 tools/quake2/extra/bsp/qbsp3/glfile.c create mode 100644 tools/quake2/extra/bsp/qbsp3/leakfile.c create mode 100644 tools/quake2/extra/bsp/qbsp3/makefile create mode 100644 tools/quake2/extra/bsp/qbsp3/map.c create mode 100644 tools/quake2/extra/bsp/qbsp3/nodraw.c create mode 100644 tools/quake2/extra/bsp/qbsp3/portals.c create mode 100644 tools/quake2/extra/bsp/qbsp3/prtfile.c create mode 100644 tools/quake2/extra/bsp/qbsp3/qbsp.h create mode 100644 tools/quake2/extra/bsp/qbsp3/qbsp3.c create mode 100644 tools/quake2/extra/bsp/qbsp3/textures.c create mode 100644 tools/quake2/extra/bsp/qbsp3/tree.c create mode 100644 tools/quake2/extra/bsp/qbsp3/writebsp.c create mode 100644 tools/quake2/extra/bsp/qrad3/lightmap.c create mode 100644 tools/quake2/extra/bsp/qrad3/makefile create mode 100644 tools/quake2/extra/bsp/qrad3/patches.c create mode 100644 tools/quake2/extra/bsp/qrad3/qrad.h create mode 100644 tools/quake2/extra/bsp/qrad3/qrad3.c create mode 100644 tools/quake2/extra/bsp/qrad3/trace.c create mode 100644 tools/quake2/extra/bsp/qvis3/flow.c create mode 100644 tools/quake2/extra/bsp/qvis3/makefile create mode 100644 tools/quake2/extra/bsp/qvis3/qvis3.c create mode 100644 tools/quake2/extra/bsp/qvis3/vis.h create mode 100644 tools/quake2/extra/common/bspfile.c create mode 100644 tools/quake2/extra/common/bspfile.h create mode 100644 tools/quake2/extra/common/cmdlib.c create mode 100644 tools/quake2/extra/common/cmdlib.h create mode 100644 tools/quake2/extra/common/l3dslib.c create mode 100644 tools/quake2/extra/common/l3dslib.h create mode 100644 tools/quake2/extra/common/lbmlib.c create mode 100644 tools/quake2/extra/common/lbmlib.h create mode 100644 tools/quake2/extra/common/mathlib.c create mode 100644 tools/quake2/extra/common/mathlib.h create mode 100644 tools/quake2/extra/common/mdfour.c create mode 100644 tools/quake2/extra/common/mdfour.h create mode 100644 tools/quake2/extra/common/polylib.c create mode 100644 tools/quake2/extra/common/polylib.h create mode 100644 tools/quake2/extra/common/qfiles.h create mode 100644 tools/quake2/extra/common/scriplib.c create mode 100644 tools/quake2/extra/common/scriplib.h create mode 100644 tools/quake2/extra/common/threads.c create mode 100644 tools/quake2/extra/common/threads.h create mode 100644 tools/quake2/extra/common/trilib.c create mode 100644 tools/quake2/extra/common/trilib.h create mode 100644 tools/quake2/extra/qdata/anorms.h create mode 100644 tools/quake2/extra/qdata/images.c create mode 100644 tools/quake2/extra/qdata/makefile create mode 100644 tools/quake2/extra/qdata/models.c create mode 100644 tools/quake2/extra/qdata/qdata.c create mode 100644 tools/quake2/extra/qdata/qdata.dsp create mode 100644 tools/quake2/extra/qdata/qdata.dsw create mode 100644 tools/quake2/extra/qdata/qdata.h create mode 100644 tools/quake2/extra/qdata/qdata.mak create mode 100644 tools/quake2/extra/qdata/sprites.c create mode 100644 tools/quake2/extra/qdata/tables.c create mode 100644 tools/quake2/extra/qdata/video.c create mode 100644 tools/quake2/extra/qe4/brush.c create mode 100644 tools/quake2/extra/qe4/brush.h create mode 100644 tools/quake2/extra/qe4/bspfile.h create mode 100644 tools/quake2/extra/qe4/camera.c create mode 100644 tools/quake2/extra/qe4/camera.h create mode 100644 tools/quake2/extra/qe4/cmdlib.c create mode 100644 tools/quake2/extra/qe4/cmdlib.h create mode 100644 tools/quake2/extra/qe4/csg.c create mode 100644 tools/quake2/extra/qe4/drag.c create mode 100644 tools/quake2/extra/qe4/eclass.c create mode 100644 tools/quake2/extra/qe4/entity.c create mode 100644 tools/quake2/extra/qe4/entity.h create mode 100644 tools/quake2/extra/qe4/entityw.h create mode 100644 tools/quake2/extra/qe4/glingr.h create mode 100644 tools/quake2/extra/qe4/icon1.ico create mode 100644 tools/quake2/extra/qe4/lbmlib.c create mode 100644 tools/quake2/extra/qe4/lbmlib.h create mode 100644 tools/quake2/extra/qe4/makefile create mode 100644 tools/quake2/extra/qe4/map.c create mode 100644 tools/quake2/extra/qe4/map.h create mode 100644 tools/quake2/extra/qe4/mathlib.c create mode 100644 tools/quake2/extra/qe4/mathlib.h create mode 100644 tools/quake2/extra/qe4/mru.c create mode 100644 tools/quake2/extra/qe4/mru.h create mode 100644 tools/quake2/extra/qe4/parse.c create mode 100644 tools/quake2/extra/qe4/parse.h create mode 100644 tools/quake2/extra/qe4/points.c create mode 100644 tools/quake2/extra/qe4/q.bmp create mode 100644 tools/quake2/extra/qe4/qe3.c create mode 100644 tools/quake2/extra/qe4/qe3.h create mode 100644 tools/quake2/extra/qe4/qe4.mak create mode 100644 tools/quake2/extra/qe4/qedefs.h create mode 100644 tools/quake2/extra/qe4/qfiles.h create mode 100644 tools/quake2/extra/qe4/resource.h create mode 100644 tools/quake2/extra/qe4/select.c create mode 100644 tools/quake2/extra/qe4/select.h create mode 100644 tools/quake2/extra/qe4/textures.c create mode 100644 tools/quake2/extra/qe4/textures.h create mode 100644 tools/quake2/extra/qe4/toolbar1.bmp create mode 100644 tools/quake2/extra/qe4/vertsel.c create mode 100644 tools/quake2/extra/qe4/view.h create mode 100644 tools/quake2/extra/qe4/win_cam.c create mode 100644 tools/quake2/extra/qe4/win_dlg.c create mode 100644 tools/quake2/extra/qe4/win_ent.c create mode 100644 tools/quake2/extra/qe4/win_main.c create mode 100644 tools/quake2/extra/qe4/win_qe3.aps create mode 100644 tools/quake2/extra/qe4/win_qe3.c create mode 100644 tools/quake2/extra/qe4/win_qe3.rc create mode 100644 tools/quake2/extra/qe4/win_xy.c create mode 100644 tools/quake2/extra/qe4/win_z.c create mode 100644 tools/quake2/extra/qe4/xy.c create mode 100644 tools/quake2/extra/qe4/xy.h create mode 100644 tools/quake2/extra/qe4/z.c create mode 100644 tools/quake2/extra/qe4/z.h create mode 100644 tools/quake2/extra/texpaint/docs.txt create mode 100644 tools/quake2/extra/texpaint/resource.h create mode 100644 tools/quake2/extra/texpaint/texmake.aps create mode 100644 tools/quake2/extra/texpaint/texmake.rc create mode 100644 tools/quake2/extra/texpaint/texpaint.c create mode 100644 tools/quake2/extra/texpaint/texpaint.h create mode 100644 tools/quake2/extra/texpaint/texpaint.mak create mode 100644 tools/quake2/extra/texpaint/win_cam.c create mode 100644 tools/quake2/extra/texpaint/win_main.c create mode 100644 tools/quake2/extra/texpaint/win_pal.c create mode 100644 tools/quake2/extra/texpaint/win_skin.c diff --git a/tools/quake2/extra/COPYING.txt b/tools/quake2/extra/COPYING.txt new file mode 100644 index 00000000..98443f35 --- /dev/null +++ b/tools/quake2/extra/COPYING.txt @@ -0,0 +1,281 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + diff --git a/tools/quake2/extra/Unpack/Unpack.dsp b/tools/quake2/extra/Unpack/Unpack.dsp new file mode 100644 index 00000000..89bea7ca --- /dev/null +++ b/tools/quake2/extra/Unpack/Unpack.dsp @@ -0,0 +1,72 @@ +# Microsoft Developer Studio Project File - Name="Unpack" - Package Owner=<4> +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Java Virtual Machine Java Project" 0x0809 + +CFG=Unpack - Java Virtual Machine Debug +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "Unpack.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "Unpack.mak" CFG="Unpack - Java Virtual Machine Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "Unpack - Java Virtual Machine Release" (based on\ + "Java Virtual Machine Java Project") +!MESSAGE "Unpack - Java Virtual Machine Debug" (based on\ + "Java Virtual Machine Java Project") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +JAVA=jvc.exe + +!IF "$(CFG)" == "Unpack - Java Virtual Machine Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Target_Dir "" +# ADD BASE JAVA /O +# ADD JAVA /O + +!ELSEIF "$(CFG)" == "Unpack - Java Virtual Machine Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "" +# PROP BASE Intermediate_Dir "" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "" +# PROP Intermediate_Dir "" +# PROP Target_Dir "" +# ADD BASE JAVA /g +# ADD JAVA /g + +!ENDIF + +# Begin Target + +# Name "Unpack - Java Virtual Machine Release" +# Name "Unpack - Java Virtual Machine Debug" +# Begin Source File + +SOURCE=.\Unpack.java +# End Source File +# End Target +# End Project diff --git a/tools/quake2/extra/Unpack/Unpack.dsw b/tools/quake2/extra/Unpack/Unpack.dsw new file mode 100644 index 00000000..29aef98e --- /dev/null +++ b/tools/quake2/extra/Unpack/Unpack.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "Unpack"=.\Unpack.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/quake2/extra/Unpack/Unpack.java b/tools/quake2/extra/Unpack/Unpack.java new file mode 100644 index 00000000..a18e72fa --- /dev/null +++ b/tools/quake2/extra/Unpack/Unpack.java @@ -0,0 +1,198 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +/* + * Unpack -- a completely non-object oriented utility... + * + */ + +import java.io.*; + +class Unpack { + static final int IDPAKHEADER = (('K'<<24)+('C'<<16)+('A'<<8)+'P'); + + static int intSwap(int i) { + int a, b, c, d; + + a = i & 255; + b = (i >> 8) & 255; + c = (i >> 16) & 255; + d = (i >> 24) & 255; + + return (a << 24) + (b << 16) + (c << 8) + d; + } + + static boolean patternMatch (String pattern, String s) { + int index; + int remaining; + + if (pattern.equals(s)) { + return true; + } + + // fairly lame single wildcard matching + index = pattern.indexOf('*'); + if (index == -1) { + return false; + } + if (!pattern.regionMatches(0, s, 0, index)) { + return false; + } + + index += 1; // skip the * + remaining = pattern.length() - index; + if (s.length() < remaining) { + return false; + } + + if (!pattern.regionMatches(index, s, s.length()-remaining, remaining)) { + return false; + } + + return true; + } + + static void usage() { + System.out.println ("Usage: unpack "); + System.out.println (" or: unpack -list "); + System.out.println (" may contain a single * wildcard"); + System.exit (1); + } + + public static void main (String[] args) { + int ident; + int dirofs; + int dirlen; + int i; + int numLumps; + byte[] name = new byte[56]; + String nameString; + int filepos; + int filelen; + RandomAccessFile readLump; + DataInputStream directory; + String pakName; + String pattern; + + if (args.length == 2) { + if (!args[0].equals("-list")) { + usage(); + } + pakName = args[1]; + pattern = null; + } else if (args.length == 3) { + pakName = args[0]; + pattern = args[1]; + } else { + pakName = null; + pattern = null; + usage (); + } + + try { + // one stream to read the directory + directory = new DataInputStream(new FileInputStream(pakName)); + + // another to read lumps + readLump = new RandomAccessFile(pakName, "r"); + + // read the header + ident = intSwap(directory.readInt()); + dirofs = intSwap(directory.readInt()); + dirlen = intSwap(directory.readInt()); + + if (ident != IDPAKHEADER) { + System.out.println ( pakName + " is not a pakfile."); + System.exit (1); + } + + // read the directory + directory.skipBytes (dirofs - 12); + numLumps = dirlen / 64; + + System.out.println (numLumps + " lumps in " + pakName); + + for (i = 0 ; i < numLumps ; i++) { + directory.readFully(name); + filepos = intSwap(directory.readInt()); + filelen = intSwap(directory.readInt()); + + nameString = new String (name, 0); + // chop to the first 0 byte + nameString = nameString.substring (0, nameString.indexOf(0)); + + if (pattern == null) { + // listing mode + System.out.println (nameString + " : " + filelen + "bytes"); + } else if (patternMatch (pattern, nameString) ) { + File writeFile; + DataOutputStream writeLump; + byte[] buffer = new byte[filelen]; + StringBuffer fixedString; + String finalName; + int index; + + System.out.println ("Unpaking " + nameString + " " + filelen + + " bytes"); + + // load the lump + readLump.seek(filepos); + readLump.readFully(buffer); + + // quake uses forward slashes, but java requires + // they only by the host's seperator, which + // varies from win to unix + fixedString = new StringBuffer (args[2] + File.separator + nameString); + for (index = 0 ; index < fixedString.length() ; index++) { + if (fixedString.charAt(index) == '/') { + fixedString.setCharAt(index, File.separatorChar); + } + } + finalName = fixedString.toString (); + + index = finalName.lastIndexOf(File.separatorChar); + if (index != -1) { + String finalPath; + File writePath; + + finalPath = finalName.substring(0, index); + writePath = new File (finalPath); + writePath.mkdirs(); + } + + writeFile = new File (finalName); + writeLump = new DataOutputStream ( new FileOutputStream(writeFile) ); + writeLump.write(buffer); + writeLump.close(); + + } + } + + readLump.close(); + directory.close(); + + } catch (IOException e) { + System.out.println ( e.toString() ); + } + } + +} diff --git a/tools/quake2/extra/bsp/bsp.mak b/tools/quake2/extra/bsp/bsp.mak new file mode 100644 index 00000000..17218de7 --- /dev/null +++ b/tools/quake2/extra/bsp/bsp.mak @@ -0,0 +1,1776 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=bspinfo3 - Win32 Debug +!MESSAGE No configuration specified. Defaulting to bspinfo3 - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "bsp - Win32 Release" && "$(CFG)" != "bsp - Win32 Debug" &&\ + "$(CFG)" != "qbsp3 - Win32 Release" && "$(CFG)" != "qbsp3 - Win32 Debug" &&\ + "$(CFG)" != "qvis3 - Win32 Release" && "$(CFG)" != "qvis3 - Win32 Debug" &&\ + "$(CFG)" != "qrad3 - Win32 Release" && "$(CFG)" != "qrad3 - Win32 Debug" &&\ + "$(CFG)" != "bspinfo3 - Win32 Release" && "$(CFG)" != "bspinfo3 - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "bsp.mak" CFG="bspinfo3 - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "bsp - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "bsp - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "qbsp3 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qbsp3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "qvis3 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qvis3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "qrad3 - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qrad3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE "bspinfo3 - Win32 Release" (based on\ + "Win32 (x86) Console Application") +!MESSAGE "bspinfo3 - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "bspinfo3 - Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "bsp - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : + +CLEAN : + -@erase + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/bsp.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/bsp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:no /pdb:"$(OUTDIR)/bsp.pdb" /machine:I386\ + /out:"$(OUTDIR)/bsp.exe" +LINK32_OBJS= \ + + +!ELSEIF "$(CFG)" == "bsp - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : + +CLEAN : + -@erase + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/bsp.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/bsp.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/bsp.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/bsp.exe" +LINK32_OBJS= \ + + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "qbsp3\Release" +# PROP BASE Intermediate_Dir "qbsp3\Release" +# PROP BASE Target_Dir "qbsp3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "qbsp3\Release" +# PROP Intermediate_Dir "qbsp3\Release" +# PROP Target_Dir "qbsp3" +OUTDIR=.\qbsp3\Release +INTDIR=.\qbsp3\Release + +ALL : "$(OUTDIR)\qbsp3.exe" + +CLEAN : + -@erase "$(INTDIR)\brushbsp.obj" + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\csg.obj" + -@erase "$(INTDIR)\faces.obj" + -@erase "$(INTDIR)\gldraw.obj" + -@erase "$(INTDIR)\glfile.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\leakfile.obj" + -@erase "$(INTDIR)\map.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\polylib.obj" + -@erase "$(INTDIR)\portals.obj" + -@erase "$(INTDIR)\prtfile.obj" + -@erase "$(INTDIR)\qbsp3.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\textures.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\tree.obj" + -@erase "$(INTDIR)\writebsp.obj" + -@erase "$(OUTDIR)\qbsp3.exe" + -@erase "$(OUTDIR)\qbsp3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qbsp3.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\qbsp3\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:no /pdb:"$(OUTDIR)/qbsp3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/qbsp3.exe" +LINK32_OBJS= \ + "$(INTDIR)\brushbsp.obj" \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\csg.obj" \ + "$(INTDIR)\faces.obj" \ + "$(INTDIR)\gldraw.obj" \ + "$(INTDIR)\glfile.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\leakfile.obj" \ + "$(INTDIR)\map.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\polylib.obj" \ + "$(INTDIR)\portals.obj" \ + "$(INTDIR)\prtfile.obj" \ + "$(INTDIR)\qbsp3.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\textures.obj" \ + "$(INTDIR)\threads.obj" \ + "$(INTDIR)\tree.obj" \ + "$(INTDIR)\writebsp.obj" + +"$(OUTDIR)\qbsp3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qbsp3\Debug" +# PROP BASE Intermediate_Dir "qbsp3\Debug" +# PROP BASE Target_Dir "qbsp3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "qbsp3\Debug" +# PROP Intermediate_Dir "qbsp3\Debug" +# PROP Target_Dir "qbsp3" +OUTDIR=.\qbsp3\Debug +INTDIR=.\qbsp3\Debug + +ALL : "$(OUTDIR)\qbsp3.exe" + +CLEAN : + -@erase "$(INTDIR)\brushbsp.obj" + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\csg.obj" + -@erase "$(INTDIR)\faces.obj" + -@erase "$(INTDIR)\gldraw.obj" + -@erase "$(INTDIR)\glfile.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\leakfile.obj" + -@erase "$(INTDIR)\map.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\polylib.obj" + -@erase "$(INTDIR)\portals.obj" + -@erase "$(INTDIR)\prtfile.obj" + -@erase "$(INTDIR)\qbsp3.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\textures.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\tree.obj" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\writebsp.obj" + -@erase "$(OUTDIR)\qbsp3.exe" + -@erase "$(OUTDIR)\qbsp3.ilk" + -@erase "$(OUTDIR)\qbsp3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/qbsp3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\qbsp3\Debug/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qbsp3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/qbsp3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/qbsp3.exe" +LINK32_OBJS= \ + "$(INTDIR)\brushbsp.obj" \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\csg.obj" \ + "$(INTDIR)\faces.obj" \ + "$(INTDIR)\gldraw.obj" \ + "$(INTDIR)\glfile.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\leakfile.obj" \ + "$(INTDIR)\map.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\polylib.obj" \ + "$(INTDIR)\portals.obj" \ + "$(INTDIR)\prtfile.obj" \ + "$(INTDIR)\qbsp3.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\textures.obj" \ + "$(INTDIR)\threads.obj" \ + "$(INTDIR)\tree.obj" \ + "$(INTDIR)\writebsp.obj" + +"$(OUTDIR)\qbsp3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qvis3 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "qvis3\Release" +# PROP BASE Intermediate_Dir "qvis3\Release" +# PROP BASE Target_Dir "qvis3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "qvis3\Release" +# PROP Intermediate_Dir "qvis3\Release" +# PROP Target_Dir "qvis3" +OUTDIR=.\qvis3\Release +INTDIR=.\qvis3\Release + +ALL : "$(OUTDIR)\qvis3.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\flow.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\qvis3.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(OUTDIR)\qvis3.exe" + -@erase "$(OUTDIR)\qvis3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qvis3.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\qvis3\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qvis3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:no /pdb:"$(OUTDIR)/qvis3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/qvis3.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\flow.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\qvis3.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\threads.obj" + +"$(OUTDIR)\qvis3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qvis3 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qvis3\Debug" +# PROP BASE Intermediate_Dir "qvis3\Debug" +# PROP BASE Target_Dir "qvis3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "qvis3\Debug" +# PROP Intermediate_Dir "qvis3\Debug" +# PROP Target_Dir "qvis3" +OUTDIR=.\qvis3\Debug +INTDIR=.\qvis3\Debug + +ALL : "$(OUTDIR)\qvis3.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\flow.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\qvis3.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\qvis3.exe" + -@erase "$(OUTDIR)\qvis3.ilk" + -@erase "$(OUTDIR)\qvis3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/qvis3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\qvis3\Debug/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qvis3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/qvis3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/qvis3.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\flow.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\qvis3.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\threads.obj" + +"$(OUTDIR)\qvis3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qrad3 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "qrad3\Release" +# PROP BASE Intermediate_Dir "qrad3\Release" +# PROP BASE Target_Dir "qrad3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "qrad3\Release" +# PROP Intermediate_Dir "qrad3\Release" +# PROP Target_Dir "qrad3" +OUTDIR=.\qrad3\Release +INTDIR=.\qrad3\Release + +ALL : "$(OUTDIR)\qrad3.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\lightmap.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\patches.obj" + -@erase "$(INTDIR)\polylib.obj" + -@erase "$(INTDIR)\qrad3.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\trace.obj" + -@erase "$(OUTDIR)\qrad3.exe" + -@erase "$(OUTDIR)\qrad3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qrad3.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\qrad3\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qrad3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:no /pdb:"$(OUTDIR)/qrad3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/qrad3.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\lightmap.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\patches.obj" \ + "$(INTDIR)\polylib.obj" \ + "$(INTDIR)\qrad3.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\threads.obj" \ + "$(INTDIR)\trace.obj" + +"$(OUTDIR)\qrad3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qrad3 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qrad3\Debug" +# PROP BASE Intermediate_Dir "qrad3\Debug" +# PROP BASE Target_Dir "qrad3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "qrad3\Debug" +# PROP Intermediate_Dir "qrad3\Debug" +# PROP Target_Dir "qrad3" +OUTDIR=.\qrad3\Debug +INTDIR=.\qrad3\Debug + +ALL : "$(OUTDIR)\qrad3.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\lightmap.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\patches.obj" + -@erase "$(INTDIR)\polylib.obj" + -@erase "$(INTDIR)\qrad3.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\trace.obj" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\qrad3.exe" + -@erase "$(OUTDIR)\qrad3.ilk" + -@erase "$(OUTDIR)\qrad3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/qrad3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\qrad3\Debug/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qrad3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/qrad3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/qrad3.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\lightmap.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\patches.obj" \ + "$(INTDIR)\polylib.obj" \ + "$(INTDIR)\qrad3.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\threads.obj" \ + "$(INTDIR)\trace.obj" + +"$(OUTDIR)\qrad3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "bspinfo3 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "bspinfo3\Release" +# PROP BASE Intermediate_Dir "bspinfo3\Release" +# PROP BASE Target_Dir "bspinfo3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "bspinfo3\Release" +# PROP Intermediate_Dir "bspinfo3\Release" +# PROP Target_Dir "bspinfo3" +OUTDIR=.\bspinfo3\Release +INTDIR=.\bspinfo3\Release + +ALL : "$(OUTDIR)\bspinfo3.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\bspinfo3.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(OUTDIR)\bspinfo3.exe" + -@erase "$(OUTDIR)\bspinfo3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /GX /Zd /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/bspinfo3.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\bspinfo3\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/bspinfo3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:no /pdb:"$(OUTDIR)/bspinfo3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/bspinfo3.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\bspinfo3.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\scriplib.obj" + +"$(OUTDIR)\bspinfo3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "bspinfo3 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "bspinfo3\Debug" +# PROP BASE Intermediate_Dir "bspinfo3\Debug" +# PROP BASE Target_Dir "bspinfo3" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "bspinfo3\Debug" +# PROP Intermediate_Dir "bspinfo3\Debug" +# PROP Target_Dir "bspinfo3" +OUTDIR=.\bspinfo3\Debug +INTDIR=.\bspinfo3\Debug + +ALL : "$(OUTDIR)\bspinfo3.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\bspinfo3.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\bspinfo3.exe" + -@erase "$(OUTDIR)\bspinfo3.ilk" + -@erase "$(OUTDIR)\bspinfo3.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MT /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/bspinfo3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/"\ + /c +CPP_OBJS=.\bspinfo3\Debug/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/bspinfo3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=wsock32.lib opengl32.lib glaux.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:console /incremental:yes /pdb:"$(OUTDIR)/bspinfo3.pdb" /debug\ + /machine:I386 /out:"$(OUTDIR)/bspinfo3.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\bspinfo3.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\scriplib.obj" + +"$(OUTDIR)\bspinfo3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "bsp - Win32 Release" +# Name "bsp - Win32 Debug" + +!IF "$(CFG)" == "bsp - Win32 Release" + +!ELSEIF "$(CFG)" == "bsp - Win32 Debug" + +!ENDIF + +# End Target +################################################################################ +# Begin Target + +# Name "qbsp3 - Win32 Release" +# Name "qbsp3 - Win32 Debug" + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\writebsp.c + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +DEP_CPP_WRITE=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\writebsp.obj" : $(SOURCE) $(DEP_CPP_WRITE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +DEP_CPP_WRITE=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\writebsp.obj" : $(SOURCE) $(DEP_CPP_WRITE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\brushbsp.c +DEP_CPP_BRUSH=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\brushbsp.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\csg.c +DEP_CPP_CSG_C=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\csg.obj" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\faces.c +DEP_CPP_FACES=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\faces.obj" : $(SOURCE) $(DEP_CPP_FACES) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\gldraw.c + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +DEP_CPP_GLDRA=\ + ".\qbsp3\qbsp.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\gldraw.obj" : $(SOURCE) $(DEP_CPP_GLDRA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +DEP_CPP_GLDRA=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\gldraw.obj" : $(SOURCE) $(DEP_CPP_GLDRA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\glfile.c + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +DEP_CPP_GLFIL=\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\glfile.obj" : $(SOURCE) $(DEP_CPP_GLFIL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +DEP_CPP_GLFIL=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\glfile.obj" : $(SOURCE) $(DEP_CPP_GLFIL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\leakfile.c + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +DEP_CPP_LEAKF=\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\leakfile.obj" : $(SOURCE) $(DEP_CPP_LEAKF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +DEP_CPP_LEAKF=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\leakfile.obj" : $(SOURCE) $(DEP_CPP_LEAKF) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\map.c +DEP_CPP_MAP_C=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\portals.c +DEP_CPP_PORTA=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\portals.obj" : $(SOURCE) $(DEP_CPP_PORTA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\prtfile.c +DEP_CPP_PRTFI=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\prtfile.obj" : $(SOURCE) $(DEP_CPP_PRTFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\qbsp.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\qbsp3.c +DEP_CPP_QBSP3=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\qbsp3.obj" : $(SOURCE) $(DEP_CPP_QBSP3) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\textures.c +DEP_CPP_TEXTU=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\textures.obj" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qbsp3\tree.c +DEP_CPP_TREE_=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + "..\common\threads.h"\ + ".\qbsp3\qbsp.h"\ + + +"$(INTDIR)\tree.obj" : $(SOURCE) $(DEP_CPP_TREE_) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\threads.c +DEP_CPP_THREA=\ + "..\common\cmdlib.h"\ + "..\common\threads.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.c +DEP_CPP_CMDLI=\ + "..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\stat.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\lbmlib.c +DEP_CPP_LBMLI=\ + "..\common\cmdlib.h"\ + "..\common\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.c +DEP_CPP_MATHL=\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\polylib.c +DEP_CPP_POLYL=\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + + +"$(INTDIR)\polylib.obj" : $(SOURCE) $(DEP_CPP_POLYL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\scriplib.c +DEP_CPP_SCRIP=\ + "..\common\cmdlib.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.c +DEP_CPP_BSPFI=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\threads.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\lbmlib.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\polylib.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\scriplib.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\qfiles.h + +!IF "$(CFG)" == "qbsp3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qbsp3 - Win32 Debug" + +!ENDIF + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "qvis3 - Win32 Release" +# Name "qvis3 - Win32 Debug" + +!IF "$(CFG)" == "qvis3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qvis3 - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\qvis3\vis.h + +!IF "$(CFG)" == "qvis3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qvis3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qvis3\qvis3.c +DEP_CPP_QVIS3=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + "..\common\threads.h"\ + ".\qvis3\vis.h"\ + + +"$(INTDIR)\qvis3.obj" : $(SOURCE) $(DEP_CPP_QVIS3) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qvis3\flow.c +DEP_CPP_FLOW_=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + ".\qvis3\vis.h"\ + + +"$(INTDIR)\flow.obj" : $(SOURCE) $(DEP_CPP_FLOW_) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.c +DEP_CPP_CMDLI=\ + "..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\stat.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.c +DEP_CPP_MATHL=\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\scriplib.c +DEP_CPP_SCRIP=\ + "..\common\cmdlib.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\threads.c +DEP_CPP_THREA=\ + "..\common\cmdlib.h"\ + "..\common\threads.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.c +DEP_CPP_BSPFI=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "qrad3 - Win32 Release" +# Name "qrad3 - Win32 Debug" + +!IF "$(CFG)" == "qrad3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qrad3 - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\qrad3\patches.c +DEP_CPP_PATCH=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\threads.h"\ + ".\qrad3\qrad.h"\ + + +"$(INTDIR)\patches.obj" : $(SOURCE) $(DEP_CPP_PATCH) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qrad3\lightmap.c +DEP_CPP_LIGHT=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\threads.h"\ + ".\qrad3\qrad.h"\ + + +"$(INTDIR)\lightmap.obj" : $(SOURCE) $(DEP_CPP_LIGHT) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qrad3\qrad.h + +!IF "$(CFG)" == "qrad3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qrad3 - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qrad3\qrad3.c +DEP_CPP_QRAD3=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + "..\common\qfiles.h"\ + "..\common\threads.h"\ + ".\qrad3\qrad.h"\ + + +"$(INTDIR)\qrad3.obj" : $(SOURCE) $(DEP_CPP_QRAD3) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qrad3\trace.c +DEP_CPP_TRACE=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + + +"$(INTDIR)\trace.obj" : $(SOURCE) $(DEP_CPP_TRACE) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\threads.c +DEP_CPP_THREA=\ + "..\common\cmdlib.h"\ + "..\common\threads.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.c +DEP_CPP_CMDLI=\ + "..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\stat.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.c +DEP_CPP_MATHL=\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\polylib.c +DEP_CPP_POLYL=\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\polylib.h"\ + + +"$(INTDIR)\polylib.obj" : $(SOURCE) $(DEP_CPP_POLYL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\scriplib.c +DEP_CPP_SCRIP=\ + "..\common\cmdlib.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.c +DEP_CPP_BSPFI=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\lbmlib.c +DEP_CPP_LBMLI=\ + "..\common\cmdlib.h"\ + "..\common\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +################################################################################ +# Begin Target + +# Name "bspinfo3 - Win32 Release" +# Name "bspinfo3 - Win32 Debug" + +!IF "$(CFG)" == "bspinfo3 - Win32 Release" + +!ELSEIF "$(CFG)" == "bspinfo3 - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\bspinfo3\bspinfo3.c +DEP_CPP_BSPIN=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + + +"$(INTDIR)\bspinfo3.obj" : $(SOURCE) $(DEP_CPP_BSPIN) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.c +DEP_CPP_MATHL=\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.c +DEP_CPP_CMDLI=\ + "..\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\stat.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.c +DEP_CPP_BSPFI=\ + "..\common\bspfile.h"\ + "..\common\cmdlib.h"\ + "..\common\mathlib.h"\ + "..\common\qfiles.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\scriplib.c +DEP_CPP_SCRIP=\ + "..\common\cmdlib.h"\ + "..\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/tools/quake2/extra/bsp/bspinfo3/bspinfo3.c b/tools/quake2/extra/bsp/bspinfo3/bspinfo3.c new file mode 100644 index 00000000..75a414f3 --- /dev/null +++ b/tools/quake2/extra/bsp/bspinfo3/bspinfo3.c @@ -0,0 +1,56 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +void main (int argc, char **argv) +{ + int i; + char source[1024]; + int size; + FILE *f; + + if (argc == 1) + Error ("usage: bspinfo bspfile [bspfiles]"); + + for (i=1 ; i /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i + +$(ODIR)/cmdlib.o : ../../common/cmdlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/scriplib.o : ../../common/scriplib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/bspfile.o : ../../common/bspfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i diff --git a/tools/quake2/extra/bsp/qbsp3/brushbsp.c b/tools/quake2/extra/bsp/qbsp3/brushbsp.c new file mode 100644 index 00000000..a111bd3b --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/brushbsp.c @@ -0,0 +1,1330 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + + +int c_nodes; +int c_nonvis; +int c_active_brushes; + +// if a brush just barely pokes onto the other side, +// let it slide by without chopping +#define PLANESIDE_EPSILON 0.001 +//0.1 + +#define PSIDE_FRONT 1 +#define PSIDE_BACK 2 +#define PSIDE_BOTH (PSIDE_FRONT|PSIDE_BACK) +#define PSIDE_FACING 4 + + +void FindBrushInTree (node_t *node, int brushnum) +{ + bspbrush_t *b; + + if (node->planenum == PLANENUM_LEAF) + { + for (b=node->brushlist ; b ; b=b->next) + if (b->original->brushnum == brushnum) + printf ("here\n"); + return; + } + FindBrushInTree (node->children[0], brushnum); + FindBrushInTree (node->children[1], brushnum); +} + +//================================================== + +/* +================ +DrawBrushList +================ +*/ +void DrawBrushList (bspbrush_t *brush, node_t *node) +{ + int i; + side_t *s; + + GLS_BeginScene (); + for ( ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + if (!s->winding) + continue; + if (s->texinfo == TEXINFO_NODE) + GLS_Winding (s->winding, 1); + else if (!s->visible) + GLS_Winding (s->winding, 2); + else + GLS_Winding (s->winding, 0); + } + } + GLS_EndScene (); +} + +/* +================ +WriteBrushList +================ +*/ +void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis) +{ + int i; + side_t *s; + FILE *f; + + qprintf ("writing %s\n", name); + f = SafeOpenWrite (name); + + for ( ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + if (!s->winding) + continue; + if (onlyvis && !s->visible) + continue; + OutputWinding (brush->sides[i].winding, f); + } + } + + fclose (f); +} + +void PrintBrush (bspbrush_t *brush) +{ + int i; + + printf ("brush: %p\n", brush); + for (i=0;inumsides ; i++) + { + pw(brush->sides[i].winding); + printf ("\n"); + } +} + +/* +================== +BoundBrush + +Sets the mins/maxs based on the windings +================== +*/ +void BoundBrush (bspbrush_t *brush) +{ + int i, j; + winding_t *w; + + ClearBounds (brush->mins, brush->maxs); + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + AddPointToBounds (w->p[j], brush->mins, brush->maxs); + } +} + +/* +================== +CreateBrushWindings + +================== +*/ +void CreateBrushWindings (bspbrush_t *brush) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + for (i=0 ; inumsides ; i++) + { + side = &brush->sides[i]; + plane = &mapplanes[side->planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; jnumsides && w; j++) + { + if (i == j) + continue; + if (brush->sides[j].bevel) + continue; + plane = &mapplanes[brush->sides[j].planenum^1]; + ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); + } + + side->winding = w; + } + + BoundBrush (brush); +} + +/* +================== +BrushFromBounds + +Creates a new axial brush +================== +*/ +bspbrush_t *BrushFromBounds (vec3_t mins, vec3_t maxs) +{ + bspbrush_t *b; + int i; + vec3_t normal; + vec_t dist; + + b = AllocBrush (6); + b->numsides = 6; + for (i=0 ; i<3 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = maxs[i]; + b->sides[i].planenum = FindFloatPlane (normal, dist); + + normal[i] = -1; + dist = -mins[i]; + b->sides[3+i].planenum = FindFloatPlane (normal, dist); + } + + CreateBrushWindings (b); + + return b; +} + +/* +================== +BrushVolume + +================== +*/ +vec_t BrushVolume (bspbrush_t *brush) +{ + int i; + winding_t *w; + vec3_t corner; + vec_t d, area, volume; + plane_t *plane; + + if (!brush) + return 0; + + // grab the first valid point as the corner + + w = NULL; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (w) + break; + } + if (!w) + return 0; + VectorCopy (w->p[0], corner); + + // make tetrahedrons to all other faces + + volume = 0; + for ( ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + plane = &mapplanes[brush->sides[i].planenum]; + d = -(DotProduct (corner, plane->normal) - plane->dist); + area = WindingArea (w); + volume += d*area; + } + + volume /= 3; + return volume; +} + +/* +================ +CountBrushList +================ +*/ +int CountBrushList (bspbrush_t *brushes) +{ + int c; + + c = 0; + for ( ; brushes ; brushes = brushes->next) + c++; + return c; +} + +/* +================ +AllocTree +================ +*/ +tree_t *AllocTree (void) +{ + tree_t *tree; + + tree = malloc(sizeof(*tree)); + memset (tree, 0, sizeof(*tree)); + ClearBounds (tree->mins, tree->maxs); + + return tree; +} + +/* +================ +AllocNode +================ +*/ +node_t *AllocNode (void) +{ + node_t *node; + + node = malloc(sizeof(*node)); + memset (node, 0, sizeof(*node)); + + return node; +} + + +/* +================ +AllocBrush +================ +*/ +bspbrush_t *AllocBrush (int numsides) +{ + bspbrush_t *bb; + int c; + + c = (int)&(((bspbrush_t *)0)->sides[numsides]); + bb = malloc(c); + memset (bb, 0, c); + if (numthreads == 1) + c_active_brushes++; + return bb; +} + +/* +================ +FreeBrush +================ +*/ +void FreeBrush (bspbrush_t *brushes) +{ + int i; + + for (i=0 ; inumsides ; i++) + if (brushes->sides[i].winding) + FreeWinding(brushes->sides[i].winding); + free (brushes); + if (numthreads == 1) + c_active_brushes--; +} + + +/* +================ +FreeBrushList +================ +*/ +void FreeBrushList (bspbrush_t *brushes) +{ + bspbrush_t *next; + + for ( ; brushes ; brushes = next) + { + next = brushes->next; + + FreeBrush (brushes); + } +} + +/* +================== +CopyBrush + +Duplicates the brush, the sides, and the windings +================== +*/ +bspbrush_t *CopyBrush (bspbrush_t *brush) +{ + bspbrush_t *newbrush; + int size; + int i; + + size = (int)&(((bspbrush_t *)0)->sides[brush->numsides]); + + newbrush = AllocBrush (brush->numsides); + memcpy (newbrush, brush, size); + + for (i=0 ; inumsides ; i++) + { + if (brush->sides[i].winding) + newbrush->sides[i].winding = CopyWinding (brush->sides[i].winding); + } + + return newbrush; +} + + +/* +================== +PointInLeaf + +================== +*/ +node_t *PointInLeaf (node_t *node, vec3_t point) +{ + vec_t d; + plane_t *plane; + + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (point, plane->normal) - plane->dist; + if (d > 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return node; +} + +//======================================================== + +/* +============== +BoxOnPlaneSide + +Returns PSIDE_FRONT, PSIDE_BACK, or PSIDE_BOTH +============== +*/ +int BoxOnPlaneSide (vec3_t mins, vec3_t maxs, plane_t *plane) +{ + int side; + int i; + vec3_t corners[2]; + vec_t dist1, dist2; + + // axial planes are easy + if (plane->type < 3) + { + side = 0; + if (maxs[plane->type] > plane->dist+PLANESIDE_EPSILON) + side |= PSIDE_FRONT; + if (mins[plane->type] < plane->dist-PLANESIDE_EPSILON) + side |= PSIDE_BACK; + return side; + } + + // create the proper leading and trailing verts for the box + + for (i=0 ; i<3 ; i++) + { + if (plane->normal[i] < 0) + { + corners[0][i] = mins[i]; + corners[1][i] = maxs[i]; + } + else + { + corners[1][i] = mins[i]; + corners[0][i] = maxs[i]; + } + } + + dist1 = DotProduct (plane->normal, corners[0]) - plane->dist; + dist2 = DotProduct (plane->normal, corners[1]) - plane->dist; + side = 0; + if (dist1 >= PLANESIDE_EPSILON) + side = PSIDE_FRONT; + if (dist2 < PLANESIDE_EPSILON) + side |= PSIDE_BACK; + + return side; +} + +/* +============ +QuickTestBrushToPlanenum + +============ +*/ +int QuickTestBrushToPlanenum (bspbrush_t *brush, int planenum, int *numsplits) +{ + int i, num; + plane_t *plane; + int s; + + *numsplits = 0; + + // if the brush actually uses the planenum, + // we can tell the side for sure + for (i=0 ; inumsides ; i++) + { + num = brush->sides[i].planenum; + if (num >= 0x10000) + Error ("bad planenum"); + if (num == planenum) + return PSIDE_BACK|PSIDE_FACING; + if (num == (planenum ^ 1) ) + return PSIDE_FRONT|PSIDE_FACING; + } + + // box on plane side + plane = &mapplanes[planenum]; + s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); + + // if both sides, count the visible faces split + if (s == PSIDE_BOTH) + { + *numsplits += 3; + } + + return s; +} + +/* +============ +TestBrushToPlanenum + +============ +*/ +int TestBrushToPlanenum (bspbrush_t *brush, int planenum, + int *numsplits, qboolean *hintsplit, int *epsilonbrush) +{ + int i, j, num; + plane_t *plane; + int s; + winding_t *w; + vec_t d, d_front, d_back; + int front, back; + + *numsplits = 0; + *hintsplit = false; + + // if the brush actually uses the planenum, + // we can tell the side for sure + for (i=0 ; inumsides ; i++) + { + num = brush->sides[i].planenum; + if (num >= 0x10000) + Error ("bad planenum"); + if (num == planenum) + return PSIDE_BACK|PSIDE_FACING; + if (num == (planenum ^ 1) ) + return PSIDE_FRONT|PSIDE_FACING; + } + + // box on plane side + plane = &mapplanes[planenum]; + s = BoxOnPlaneSide (brush->mins, brush->maxs, plane); + + if (s != PSIDE_BOTH) + return s; + +// if both sides, count the visible faces split + d_front = d_back = 0; + + for (i=0 ; inumsides ; i++) + { + if (brush->sides[i].texinfo == TEXINFO_NODE) + continue; // on node, don't worry about splits + if (!brush->sides[i].visible) + continue; // we don't care about non-visible + w = brush->sides[i].winding; + if (!w) + continue; + front = back = 0; + for (j=0 ; jnumpoints; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > d_front) + d_front = d; + if (d < d_back) + d_back = d; + + if (d > 0.1) // PLANESIDE_EPSILON) + front = 1; + if (d < -0.1) // PLANESIDE_EPSILON) + back = 1; + } + if (front && back) + { + if ( !(brush->sides[i].surf & SURF_SKIP) ) + { + (*numsplits)++; + if (brush->sides[i].surf & SURF_HINT) + *hintsplit = true; + } + } + } + + if ( (d_front > 0.0 && d_front < 1.0) + || (d_back < 0.0 && d_back > -1.0) ) + (*epsilonbrush)++; + +#if 0 + if (*numsplits == 0) + { // didn't really need to be split + if (front) + s = PSIDE_FRONT; + else if (back) + s = PSIDE_BACK; + else + s = 0; + } +#endif + + return s; +} + +//======================================================== + +/* +================ +WindingIsTiny + +Returns true if the winding would be crunched out of +existance by the vertex snapping. +================ +*/ +#define EDGE_LENGTH 0.2 +qboolean WindingIsTiny (winding_t *w) +{ +#if 0 + if (WindingArea (w) < 1) + return true; + return false; +#else + int i, j; + vec_t len; + vec3_t delta; + int edges; + + edges = 0; + for (i=0 ; inumpoints ; i++) + { + j = i == w->numpoints - 1 ? 0 : i+1; + VectorSubtract (w->p[j], w->p[i], delta); + len = VectorLength (delta); + if (len > EDGE_LENGTH) + { + if (++edges == 3) + return false; + } + } + return true; +#endif +} + +/* +================ +WindingIsHuge + +Returns true if the winding still has one of the points +from basewinding for plane +================ +*/ +qboolean WindingIsHuge (winding_t *w) +{ + int i, j; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + if (w->p[i][j] < -8000 || w->p[i][j] > 8000) + return true; + } + return false; +} + +//============================================================ + +/* +================ +Leafnode +================ +*/ +void LeafNode (node_t *node, bspbrush_t *brushes) +{ + bspbrush_t *b; + int i; + + node->planenum = PLANENUM_LEAF; + node->contents = 0; + + for (b=brushes ; b ; b=b->next) + { + // if the brush is solid and all of its sides are on nodes, + // it eats everything + if (b->original->contents & CONTENTS_SOLID) + { + for (i=0 ; inumsides ; i++) + if (b->sides[i].texinfo != TEXINFO_NODE) + break; + if (i == b->numsides) + { + node->contents = CONTENTS_SOLID; + break; + } + } + node->contents |= b->original->contents; + } + + node->brushlist = brushes; +} + + +//============================================================ + +void CheckPlaneAgainstParents (int pnum, node_t *node) +{ + node_t *p; + + for (p=node->parent ; p ; p=p->parent) + { + if (p->planenum == pnum) + Error ("Tried parent"); + } +} + +qboolean CheckPlaneAgainstVolume (int pnum, node_t *node) +{ + bspbrush_t *front, *back; + qboolean good; + + SplitBrush (node->volume, pnum, &front, &back); + + good = (front && back); + + if (front) + FreeBrush (front); + if (back) + FreeBrush (back); + + return good; +} + +/* +================ +SelectSplitSide + +Using a hueristic, choses one of the sides out of the brushlist +to partition the brushes with. +Returns NULL if there are no valid planes to split with.. +================ +*/ +side_t *SelectSplitSide (bspbrush_t *brushes, node_t *node) +{ + int value, bestvalue; + bspbrush_t *brush, *test; + side_t *side, *bestside; + int i, j, pass, numpasses; + int pnum; + int s; + int front, back, both, facing, splits; + int bsplits; + int bestsplits; + int epsilonbrush; + qboolean hintsplit; + + bestside = NULL; + bestvalue = -99999; + bestsplits = 0; + + // the search order goes: visible-structural, visible-detail, + // nonvisible-structural, nonvisible-detail. + // If any valid plane is available in a pass, no further + // passes will be tried. + numpasses = 4; + for (pass = 0 ; pass < numpasses ; pass++) + { + for (brush = brushes ; brush ; brush=brush->next) + { + if ( (pass & 1) && !(brush->original->contents & CONTENTS_DETAIL) ) + continue; + if ( !(pass & 1) && (brush->original->contents & CONTENTS_DETAIL) ) + continue; + for (i=0 ; inumsides ; i++) + { + side = brush->sides + i; + if (side->bevel) + continue; // never use a bevel as a spliter + if (!side->winding) + continue; // nothing visible, so it can't split + if (side->texinfo == TEXINFO_NODE) + continue; // allready a node splitter + if (side->tested) + continue; // we allready have metrics for this plane + if (side->surf & SURF_SKIP) + continue; // skip surfaces are never chosen + if ( side->visible ^ (pass<2) ) + continue; // only check visible faces on first pass + + pnum = side->planenum; + pnum &= ~1; // allways use positive facing plane + + CheckPlaneAgainstParents (pnum, node); + + if (!CheckPlaneAgainstVolume (pnum, node)) + continue; // would produce a tiny volume + + front = 0; + back = 0; + both = 0; + facing = 0; + splits = 0; + epsilonbrush = 0; + + for (test = brushes ; test ; test=test->next) + { + s = TestBrushToPlanenum (test, pnum, &bsplits, &hintsplit, &epsilonbrush); + + splits += bsplits; + if (bsplits && (s&PSIDE_FACING) ) + Error ("PSIDE_FACING with splits"); + + test->testside = s; + // if the brush shares this face, don't bother + // testing that facenum as a splitter again + if (s & PSIDE_FACING) + { + facing++; + for (j=0 ; jnumsides ; j++) + { + if ( (test->sides[j].planenum&~1) == pnum) + test->sides[j].tested = true; + } + } + if (s & PSIDE_FRONT) + front++; + if (s & PSIDE_BACK) + back++; + if (s == PSIDE_BOTH) + both++; + } + + // give a value estimate for using this plane + + value = 5*facing - 5*splits - abs(front-back); +// value = -5*splits; +// value = 5*facing - 5*splits; + if (mapplanes[pnum].type < 3) + value+=5; // axial is better + value -= epsilonbrush*1000; // avoid! + + // never split a hint side except with another hint + if (hintsplit && !(side->surf & SURF_HINT) ) + value = -9999999; + + // save off the side test so we don't need + // to recalculate it when we actually seperate + // the brushes + if (value > bestvalue) + { + bestvalue = value; + bestside = side; + bestsplits = splits; + for (test = brushes ; test ; test=test->next) + test->side = test->testside; + } + } + } + + // if we found a good plane, don't bother trying any + // other passes + if (bestside) + { + if (pass > 1) + { + if (numthreads == 1) + c_nonvis++; + } + if (pass > 0) + node->detail_seperator = true; // not needed for vis + break; + } + } + + // + // clear all the tested flags we set + // + for (brush = brushes ; brush ; brush=brush->next) + { + for (i=0 ; inumsides ; i++) + brush->sides[i].tested = false; + } + + return bestside; +} + + +/* +================== +BrushMostlyOnSide + +================== +*/ +int BrushMostlyOnSide (bspbrush_t *brush, plane_t *plane) +{ + int i, j; + winding_t *w; + vec_t d, max; + int side; + + max = 0; + side = PSIDE_FRONT; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > max) + { + max = d; + side = PSIDE_FRONT; + } + if (-d > max) + { + max = -d; + side = PSIDE_BACK; + } + } + } + return side; +} + +/* +================ +SplitBrush + +Generates two new brushes, leaving the original +unchanged +================ +*/ +void SplitBrush (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back) +{ + bspbrush_t *b[2]; + int i, j; + winding_t *w, *cw[2], *midwinding; + plane_t *plane, *plane2; + side_t *s, *cs; + float d, d_front, d_back; + + *front = *back = NULL; + plane = &mapplanes[planenum]; + + // check all points + d_front = d_back = 0; + for (i=0 ; inumsides ; i++) + { + w = brush->sides[i].winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + d = DotProduct (w->p[j], plane->normal) - plane->dist; + if (d > 0 && d > d_front) + d_front = d; + if (d < 0 && d < d_back) + d_back = d; + } + } + if (d_front < 0.1) // PLANESIDE_EPSILON) + { // only on back + *back = CopyBrush (brush); + return; + } + if (d_back > -0.1) // PLANESIDE_EPSILON) + { // only on front + *front = CopyBrush (brush); + return; + } + + // create a new winding from the split plane + + w = BaseWindingForPlane (plane->normal, plane->dist); + for (i=0 ; inumsides && w ; i++) + { + plane2 = &mapplanes[brush->sides[i].planenum ^ 1]; + ChopWindingInPlace (&w, plane2->normal, plane2->dist, 0); // PLANESIDE_EPSILON); + } + + if (!w || WindingIsTiny (w) ) + { // the brush isn't really split + int side; + + side = BrushMostlyOnSide (brush, plane); + if (side == PSIDE_FRONT) + *front = CopyBrush (brush); + if (side == PSIDE_BACK) + *back = CopyBrush (brush); + return; + } + + if (WindingIsHuge (w)) + { + qprintf ("WARNING: huge winding\n"); + } + + midwinding = w; + + // split it for real + + for (i=0 ; i<2 ; i++) + { + b[i] = AllocBrush (brush->numsides+1); + b[i]->original = brush->original; + } + + // split all the current windings + + for (i=0 ; inumsides ; i++) + { + s = &brush->sides[i]; + w = s->winding; + if (!w) + continue; + ClipWindingEpsilon (w, plane->normal, plane->dist, + 0 /*PLANESIDE_EPSILON*/, &cw[0], &cw[1]); + for (j=0 ; j<2 ; j++) + { + if (!cw[j]) + continue; +#if 0 + if (WindingIsTiny (cw[j])) + { + FreeWinding (cw[j]); + continue; + } +#endif + cs = &b[j]->sides[b[j]->numsides]; + b[j]->numsides++; + *cs = *s; +// cs->planenum = s->planenum; +// cs->texinfo = s->texinfo; +// cs->visible = s->visible; +// cs->original = s->original; + cs->winding = cw[j]; + cs->tested = false; + } + } + + + // see if we have valid polygons on both sides + + for (i=0 ; i<2 ; i++) + { + BoundBrush (b[i]); + for (j=0 ; j<3 ; j++) + { + if (b[i]->mins[j] < -4096 || b[i]->maxs[j] > 4096) + { + qprintf ("bogus brush after clip\n"); + break; + } + } + + if (b[i]->numsides < 3 || j < 3) + { + FreeBrush (b[i]); + b[i] = NULL; + } + } + + if ( !(b[0] && b[1]) ) + { + if (!b[0] && !b[1]) + qprintf ("split removed brush\n"); + else + qprintf ("split not on both sides\n"); + if (b[0]) + { + FreeBrush (b[0]); + *front = CopyBrush (brush); + } + if (b[1]) + { + FreeBrush (b[1]); + *back = CopyBrush (brush); + } + return; + } + + // add the midwinding to both sides + for (i=0 ; i<2 ; i++) + { + cs = &b[i]->sides[b[i]->numsides]; + b[i]->numsides++; + + cs->planenum = planenum^i^1; + cs->texinfo = TEXINFO_NODE; + cs->visible = false; + cs->tested = false; + if (i==0) + cs->winding = CopyWinding (midwinding); + else + cs->winding = midwinding; + } + +{ + vec_t v1; + int i; + + for (i=0 ; i<2 ; i++) + { + v1 = BrushVolume (b[i]); + if (v1 < 1.0) + { + FreeBrush (b[i]); + b[i] = NULL; +// qprintf ("tiny volume after clip\n"); + } + } +} + + *front = b[0]; + *back = b[1]; +} + +/* +================ +SplitBrushList +================ +*/ +void SplitBrushList (bspbrush_t *brushes, + node_t *node, bspbrush_t **front, bspbrush_t **back) +{ + bspbrush_t *brush, *newbrush, *newbrush2; + side_t *side; + int sides; + int i; + + *front = *back = NULL; + + for (brush = brushes ; brush ; brush=brush->next) + { + sides = brush->side; + + if (sides == PSIDE_BOTH) + { // split into two brushes + SplitBrush (brush, node->planenum, &newbrush, &newbrush2); + if (newbrush) + { + newbrush->next = *front; + *front = newbrush; + } + if (newbrush2) + { + newbrush2->next = *back; + *back = newbrush2; + } + continue; + } + + newbrush = CopyBrush (brush); + + // if the planenum is actualy a part of the brush + // find the plane and flag it as used so it won't be tried + // as a splitter again + if (sides & PSIDE_FACING) + { + for (i=0 ; inumsides ; i++) + { + side = newbrush->sides + i; + if ( (side->planenum& ~1) == node->planenum) + side->texinfo = TEXINFO_NODE; + } + } + + + if (sides & PSIDE_FRONT) + { + newbrush->next = *front; + *front = newbrush; + continue; + } + if (sides & PSIDE_BACK) + { + newbrush->next = *back; + *back = newbrush; + continue; + } + } +} + + +/* +================ +BuildTree_r +================ +*/ +node_t *BuildTree_r (node_t *node, bspbrush_t *brushes) +{ + node_t *newnode; + side_t *bestside; + int i; + bspbrush_t *children[2]; + + if (numthreads == 1) + c_nodes++; + + if (drawflag) + DrawBrushList (brushes, node); + + // find the best plane to use as a splitter + bestside = SelectSplitSide (brushes, node); + if (!bestside) + { + // leaf node + node->side = NULL; + node->planenum = -1; + LeafNode (node, brushes); + return node; + } + + // this is a splitplane node + node->side = bestside; + node->planenum = bestside->planenum & ~1; // always use front facing + + SplitBrushList (brushes, node, &children[0], &children[1]); + FreeBrushList (brushes); + + // allocate children before recursing + for (i=0 ; i<2 ; i++) + { + newnode = AllocNode (); + newnode->parent = node; + node->children[i] = newnode; + } + + SplitBrush (node->volume, node->planenum, &node->children[0]->volume, + &node->children[1]->volume); + + // recursively process children + for (i=0 ; i<2 ; i++) + { + node->children[i] = BuildTree_r (node->children[i], children[i]); + } + + return node; +} + +//=========================================================== + +/* +================= +BrushBSP + +The incoming list will be freed before exiting +================= +*/ +tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs) +{ + node_t *node; + bspbrush_t *b; + int c_faces, c_nonvisfaces; + int c_brushes; + tree_t *tree; + int i; + vec_t volume; + + qprintf ("--- BrushBSP ---\n"); + + tree = AllocTree (); + + c_faces = 0; + c_nonvisfaces = 0; + c_brushes = 0; + for (b=brushlist ; b ; b=b->next) + { + c_brushes++; + + volume = BrushVolume (b); + if (volume < microvolume) + { + printf ("WARNING: entity %i, brush %i: microbrush\n", + b->original->entitynum, b->original->brushnum); + } + + for (i=0 ; inumsides ; i++) + { + if (b->sides[i].bevel) + continue; + if (!b->sides[i].winding) + continue; + if (b->sides[i].texinfo == TEXINFO_NODE) + continue; + if (b->sides[i].visible) + c_faces++; + else + c_nonvisfaces++; + } + + AddPointToBounds (b->mins, tree->mins, tree->maxs); + AddPointToBounds (b->maxs, tree->mins, tree->maxs); + } + + qprintf ("%5i brushes\n", c_brushes); + qprintf ("%5i visible faces\n", c_faces); + qprintf ("%5i nonvisible faces\n", c_nonvisfaces); + + c_nodes = 0; + c_nonvis = 0; + node = AllocNode (); + + node->volume = BrushFromBounds (mins, maxs); + + tree->headnode = node; + + node = BuildTree_r (node, brushlist); + qprintf ("%5i visible nodes\n", c_nodes/2 - c_nonvis); + qprintf ("%5i nonvis nodes\n", c_nonvis); + qprintf ("%5i leafs\n", (c_nodes+1)/2); +#if 0 +{ // debug code +static node_t *tnode; +vec3_t p; + +p[0] = -1469; +p[1] = -118; +p[2] = 119; +tnode = PointInLeaf (tree->headnode, p); +printf ("contents: %i\n", tnode->contents); +p[0] = 0; +} +#endif + return tree; +} + diff --git a/tools/quake2/extra/bsp/qbsp3/csg.c b/tools/quake2/extra/bsp/qbsp3/csg.c new file mode 100644 index 00000000..2d69aa22 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/csg.c @@ -0,0 +1,635 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +/* + +tag all brushes with original contents +brushes may contain multiple contents +there will be no brush overlap after csg phase + + + + +each side has a count of the other sides it splits + +the best split will be the one that minimizes the total split counts +of all remaining sides + +precalc side on plane table + +evaluate split side +{ +cost = 0 +for all sides + for all sides + get + if side splits side and splitside is on same child + cost++; +} + + + */ + +void SplitBrush2 (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back) +{ + SplitBrush (brush, planenum, front, back); +#if 0 + if (*front && (*front)->sides[(*front)->numsides-1].texinfo == -1) + (*front)->sides[(*front)->numsides-1].texinfo = (*front)->sides[0].texinfo; // not -1 + if (*back && (*back)->sides[(*back)->numsides-1].texinfo == -1) + (*back)->sides[(*back)->numsides-1].texinfo = (*back)->sides[0].texinfo; // not -1 +#endif +} + +/* +=============== +SubtractBrush + +Returns a list of brushes that remain after B is subtracted from A. +May by empty if A is contained inside B. + +The originals are undisturbed. +=============== +*/ +bspbrush_t *SubtractBrush (bspbrush_t *a, bspbrush_t *b) +{ // a - b = out (list) + int i; + bspbrush_t *front, *back; + bspbrush_t *out, *in; + + in = a; + out = NULL; + for (i=0 ; inumsides && in ; i++) + { + SplitBrush2 (in, b->sides[i].planenum, &front, &back); + if (in != a) + FreeBrush (in); + if (front) + { // add to list + front->next = out; + out = front; + } + in = back; + } + if (in) + FreeBrush (in); + else + { // didn't really intersect + FreeBrushList (out); + return a; + } + return out; +} + +/* +=============== +IntersectBrush + +Returns a single brush made up by the intersection of the +two provided brushes, or NULL if they are disjoint. + +The originals are undisturbed. +=============== +*/ +bspbrush_t *IntersectBrush (bspbrush_t *a, bspbrush_t *b) +{ + int i; + bspbrush_t *front, *back; + bspbrush_t *in; + + in = a; + for (i=0 ; inumsides && in ; i++) + { + SplitBrush2 (in, b->sides[i].planenum, &front, &back); + if (in != a) + FreeBrush (in); + if (front) + FreeBrush (front); + in = back; + } + + if (in == a) + return NULL; + + in->next = NULL; + return in; +} + + +/* +=============== +BrushesDisjoint + +Returns true if the two brushes definately do not intersect. +There will be false negatives for some non-axial combinations. +=============== +*/ +qboolean BrushesDisjoint (bspbrush_t *a, bspbrush_t *b) +{ + int i, j; + + // check bounding boxes + for (i=0 ; i<3 ; i++) + if (a->mins[i] >= b->maxs[i] + || a->maxs[i] <= b->mins[i]) + return true; // bounding boxes don't overlap + + // check for opposing planes + for (i=0 ; inumsides ; i++) + { + for (j=0 ; jnumsides ; j++) + { + if (a->sides[i].planenum == + (b->sides[j].planenum^1) ) + return true; // opposite planes, so not touching + } + } + + return false; // might intersect +} + +/* +=============== +IntersectionContents + +Returns a content word for the intersection of two brushes. +Some combinations will generate a combination (water + clip), +but most will be the stronger of the two contents. +=============== +*/ +int IntersectionContents (int c1, int c2) +{ + int out; + + out = c1 | c2; + + if (out & CONTENTS_SOLID) + out = CONTENTS_SOLID; + + return out; +} + + +int minplanenums[3]; +int maxplanenums[3]; + +/* +=============== +ClipBrushToBox + +Any planes shared with the box edge will be set to no texinfo +=============== +*/ +bspbrush_t *ClipBrushToBox (bspbrush_t *brush, vec3_t clipmins, vec3_t clipmaxs) +{ + int i, j; + bspbrush_t *front, *back; + int p; + + for (j=0 ; j<2 ; j++) + { + if (brush->maxs[j] > clipmaxs[j]) + { + SplitBrush (brush, maxplanenums[j], &front, &back); + if (front) + FreeBrush (front); + brush = back; + if (!brush) + return NULL; + } + if (brush->mins[j] < clipmins[j]) + { + SplitBrush (brush, minplanenums[j], &front, &back); + if (back) + FreeBrush (back); + brush = front; + if (!brush) + return NULL; + } + } + + // remove any colinear faces + + for (i=0 ; inumsides ; i++) + { + p = brush->sides[i].planenum & ~1; + if (p == maxplanenums[0] || p == maxplanenums[1] + || p == minplanenums[0] || p == minplanenums[1]) + { + brush->sides[i].texinfo = TEXINFO_NODE; + brush->sides[i].visible = false; + } + } + return brush; +} + +/* +=============== +MakeBspBrushList +=============== +*/ +bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, + vec3_t clipmins, vec3_t clipmaxs) +{ + mapbrush_t *mb; + bspbrush_t *brushlist, *newbrush; + int i, j; + int c_faces; + int c_brushes; + int numsides; + int vis; + vec3_t normal; + float dist; + + for (i=0 ; i<2 ; i++) + { + VectorClear (normal); + normal[i] = 1; + dist = clipmaxs[i]; + maxplanenums[i] = FindFloatPlane (normal, dist); + dist = clipmins[i]; + minplanenums[i] = FindFloatPlane (normal, dist); + } + + brushlist = NULL; + c_faces = 0; + c_brushes = 0; + + for (i=startbrush ; inumsides; + if (!numsides) + continue; + // make sure the brush has at least one face showing + vis = 0; + for (j=0 ; joriginal_sides[j].visible && mb->original_sides[j].winding) + vis++; +#if 0 + if (!vis) + continue; // no faces at all +#endif + // if the brush is outside the clip area, skip it + for (j=0 ; j<3 ; j++) + if (mb->mins[j] >= clipmaxs[j] + || mb->maxs[j] <= clipmins[j]) + break; + if (j != 3) + continue; + + // + // make a copy of the brush + // + newbrush = AllocBrush (mb->numsides); + newbrush->original = mb; + newbrush->numsides = mb->numsides; + memcpy (newbrush->sides, mb->original_sides, numsides*sizeof(side_t)); + for (j=0 ; jsides[j].winding) + newbrush->sides[j].winding = CopyWinding (newbrush->sides[j].winding); + if (newbrush->sides[j].surf & SURF_HINT) + newbrush->sides[j].visible = true; // hints are always visible + } + VectorCopy (mb->mins, newbrush->mins); + VectorCopy (mb->maxs, newbrush->maxs); + + // + // carve off anything outside the clip box + // + newbrush = ClipBrushToBox (newbrush, clipmins, clipmaxs); + if (!newbrush) + continue; + + c_faces += vis; + c_brushes++; + + newbrush->next = brushlist; + brushlist = newbrush; + } + + return brushlist; +} + +/* +=============== +AddBspBrushListToTail +=============== +*/ +bspbrush_t *AddBrushListToTail (bspbrush_t *list, bspbrush_t *tail) +{ + bspbrush_t *walk, *next; + + for (walk=list ; walk ; walk=next) + { // add to end of list + next = walk->next; + walk->next = NULL; + tail->next = walk; + tail = walk; + } + + return tail; +} + +/* +=========== +CullList + +Builds a new list that doesn't hold the given brush +=========== +*/ +bspbrush_t *CullList (bspbrush_t *list, bspbrush_t *skip1) +{ + bspbrush_t *newlist; + bspbrush_t *next; + + newlist = NULL; + + for ( ; list ; list = next) + { + next = list->next; + if (list == skip1) + { + FreeBrush (list); + continue; + } + list->next = newlist; + newlist = list; + } + return newlist; +} + + +/* +================== +WriteBrushMap +================== +*/ +void WriteBrushMap (char *name, bspbrush_t *list) +{ + FILE *f; + side_t *s; + int i; + winding_t *w; + + printf ("writing %s\n", name); + f = fopen (name, "wb"); + if (!f) + Error ("Can't write %s\b", name); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for ( ; list ; list=list->next ) + { + fprintf (f, "{\n"); + for (i=0,s=list->sides ; inumsides ; i++,s++) + { + w = BaseWindingForPlane (mapplanes[s->planenum].normal, mapplanes[s->planenum].dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + +} + +/* +================== +BrushGE + +Returns true if b1 is allowed to bite b2 +================== +*/ +qboolean BrushGE (bspbrush_t *b1, bspbrush_t *b2) +{ + // detail brushes never bite structural brushes + if ( (b1->original->contents & CONTENTS_DETAIL) + && !(b2->original->contents & CONTENTS_DETAIL) ) + return false; + if (b1->original->contents & CONTENTS_SOLID) + return true; + return false; +} + +/* +================= +ChopBrushes + +Carves any intersecting solid brushes into the minimum number +of non-intersecting brushes. +================= +*/ +bspbrush_t *ChopBrushes (bspbrush_t *head) +{ + bspbrush_t *b1, *b2, *next; + bspbrush_t *tail; + bspbrush_t *keep; + bspbrush_t *sub, *sub2; + int c1, c2; + + qprintf ("---- ChopBrushes ----\n"); + qprintf ("original brushes: %i\n", CountBrushList (head)); + +#if 0 + if (startbrush == 0) + WriteBrushList ("before.gl", head, false); +#endif + keep = NULL; + +newlist: + // find tail + if (!head) + return NULL; + for (tail=head ; tail->next ; tail=tail->next) + ; + + for (b1=head ; b1 ; b1=next) + { + next = b1->next; + for (b2=b1->next ; b2 ; b2 = b2->next) + { + if (BrushesDisjoint (b1, b2)) + continue; + + sub = NULL; + sub2 = NULL; + c1 = 999999; + c2 = 999999; + + if ( BrushGE (b2, b1) ) + { + sub = SubtractBrush (b1, b2); + if (sub == b1) + continue; // didn't really intersect + if (!sub) + { // b1 is swallowed by b2 + head = CullList (b1, b1); + goto newlist; + } + c1 = CountBrushList (sub); + } + + if ( BrushGE (b1, b2) ) + { + sub2 = SubtractBrush (b2, b1); + if (sub2 == b2) + continue; // didn't really intersect + if (!sub2) + { // b2 is swallowed by b1 + FreeBrushList (sub); + head = CullList (b1, b2); + goto newlist; + } + c2 = CountBrushList (sub2); + } + + if (!sub && !sub2) + continue; // neither one can bite + + // only accept if it didn't fragment + // (commening this out allows full fragmentation) + if (c1 > 1 && c2 > 1) + { + if (sub2) + FreeBrushList (sub2); + if (sub) + FreeBrushList (sub); + continue; + } + + if (c1 < c2) + { + if (sub2) + FreeBrushList (sub2); + tail = AddBrushListToTail (sub, tail); + head = CullList (b1, b1); + goto newlist; + } + else + { + if (sub) + FreeBrushList (sub); + tail = AddBrushListToTail (sub2, tail); + head = CullList (b1, b2); + goto newlist; + } + } + + if (!b2) + { // b1 is no longer intersecting anything, so keep it + b1->next = keep; + keep = b1; + } + } + + qprintf ("output brushes: %i\n", CountBrushList (keep)); +#if 0 + { + WriteBrushList ("after.gl", keep, false); + WriteBrushMap ("after.map", keep); + } +#endif + return keep; +} + + +/* +================= +InitialBrushList +================= +*/ +bspbrush_t *InitialBrushList (bspbrush_t *list) +{ + bspbrush_t *b; + bspbrush_t *out, *newb; + int i; + + // only return brushes that have visible faces + out = NULL; + for (b=list ; b ; b=b->next) + { +#if 0 + for (i=0 ; inumsides ; i++) + if (b->sides[i].visible) + break; + if (i == b->numsides) + continue; +#endif + newb = CopyBrush (b); + newb->next = out; + out = newb; + + // clear visible, so it must be set by MarkVisibleFaces_r + // to be used in the optimized list + for (i=0 ; inumsides ; i++) + { + newb->sides[i].original = &b->sides[i]; +// newb->sides[i].visible = true; + b->sides[i].visible = false; + } + } + + return out; +} + +/* +================= +OptimizedBrushList +================= +*/ +bspbrush_t *OptimizedBrushList (bspbrush_t *list) +{ + bspbrush_t *b; + bspbrush_t *out, *newb; + int i; + + // only return brushes that have visible faces + out = NULL; + for (b=list ; b ; b=b->next) + { + for (i=0 ; inumsides ; i++) + if (b->sides[i].visible) + break; + if (i == b->numsides) + continue; + newb = CopyBrush (b); + newb->next = out; + out = newb; + } + +// WriteBrushList ("vis.gl", out, true); + + return out; +} diff --git a/tools/quake2/extra/bsp/qbsp3/faces.c b/tools/quake2/extra/bsp/qbsp3/faces.c new file mode 100644 index 00000000..1bbc922b --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/faces.c @@ -0,0 +1,1076 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +/* + + some faces will be removed before saving, but still form nodes: + + the insides of sky volumes + meeting planes of different water current volumes + +*/ + +// undefine for dumb linear searches +#define USE_HASHING + +#define INTEGRAL_EPSILON 0.01 +#define POINT_EPSILON 0.5 +#define OFF_EPSILON 0.5 + +int c_merge; +int c_subdivide; + +int c_totalverts; +int c_uniqueverts; +int c_degenerate; +int c_tjunctions; +int c_faceoverflows; +int c_facecollapse; +int c_badstartverts; + +#define MAX_SUPERVERTS 512 +int superverts[MAX_SUPERVERTS]; +int numsuperverts; + +face_t *edgefaces[MAX_MAP_EDGES][2]; +int firstmodeledge = 1; +int firstmodelface; + +int c_tryedges; + +vec3_t edge_dir; +vec3_t edge_start; +vec_t edge_len; + +int num_edge_verts; +int edge_verts[MAX_MAP_VERTS]; + + +float subdivide_size = 240; + + +face_t *NewFaceFromFace (face_t *f); + +//=========================================================================== + +typedef struct hashvert_s +{ + struct hashvert_s *next; + int num; +} hashvert_t; + + +#define HASH_SIZE 64 + + +int vertexchain[MAX_MAP_VERTS]; // the next vertex in a hash chain +int hashverts[HASH_SIZE*HASH_SIZE]; // a vertex number, or 0 for no verts + +face_t *edgefaces[MAX_MAP_EDGES][2]; + +//============================================================================ + + +unsigned HashVec (vec3_t vec) +{ + int x, y; + + x = (4096 + (int)(vec[0]+0.5)) >> 7; + y = (4096 + (int)(vec[1]+0.5)) >> 7; + + if ( x < 0 || x >= HASH_SIZE || y < 0 || y >= HASH_SIZE ) + Error ("HashVec: point outside valid range"); + + return y*HASH_SIZE + x; +} + +#ifdef USE_HASHING +/* +============= +GetVertex + +Uses hashing +============= +*/ +int GetVertexnum (vec3_t in) +{ + int h; + int i; + float *p; + vec3_t vert; + int vnum; + + c_totalverts++; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(in[i] - Q_rint(in[i])) < INTEGRAL_EPSILON) + vert[i] = Q_rint(in[i]); + else + vert[i] = in[i]; + } + + h = HashVec (vert); + + for (vnum=hashverts[h] ; vnum ; vnum=vertexchain[vnum]) + { + p = dvertexes[vnum].point; + if ( fabs(p[0]-vert[0]) 4096) + Error ("GetVertexnum: outside +/- 4096"); + } + + // search for an existing vertex match + for (i=0, dv=dvertexes ; ipoint[j]; + if ( d > POINT_EPSILON || d < -POINT_EPSILON) + break; + } + if (j == 3) + return i; // a match + } + + // new point + if (numvertexes == MAX_MAP_VERTS) + Error ("MAX_MAP_VERTS"); + VectorCopy (v, dv->point); + numvertexes++; + c_uniqueverts++; + + return numvertexes-1; +} +#endif + + +/* +================== +FaceFromSuperverts + +The faces vertexes have beeb added to the superverts[] array, +and there may be more there than can be held in a face (MAXEDGES). + +If less, the faces vertexnums[] will be filled in, otherwise +face will reference a tree of split[] faces until all of the +vertexnums can be added. + +superverts[base] will become face->vertexnums[0], and the others +will be circularly filled in. +================== +*/ +void FaceFromSuperverts (node_t *node, face_t *f, int base) +{ + face_t *newf; + int remaining; + int i; + + remaining = numsuperverts; + while (remaining > MAXEDGES) + { // must split into two faces, because of vertex overload + c_faceoverflows++; + + newf = f->split[0] = NewFaceFromFace (f); + newf = f->split[0]; + newf->next = node->faces; + node->faces = newf; + + newf->numpoints = MAXEDGES; + for (i=0 ; ivertexnums[i] = superverts[(i+base)%numsuperverts]; + + f->split[1] = NewFaceFromFace (f); + f = f->split[1]; + f->next = node->faces; + node->faces = f; + + remaining -= (MAXEDGES-2); + base = (base+MAXEDGES-1)%numsuperverts; + } + + // copy the vertexes back to the face + f->numpoints = remaining; + for (i=0 ; ivertexnums[i] = superverts[(i+base)%numsuperverts]; +} + + +/* +================== +EmitFaceVertexes +================== +*/ +void EmitFaceVertexes (node_t *node, face_t *f) +{ + winding_t *w; + int i; + + if (f->merged || f->split[0] || f->split[1]) + return; + + w = f->w; + for (i=0 ; inumpoints ; i++) + { + if (noweld) + { // make every point unique + if (numvertexes == MAX_MAP_VERTS) + Error ("MAX_MAP_VERTS"); + superverts[i] = numvertexes; + VectorCopy (w->p[i], dvertexes[numvertexes].point); + numvertexes++; + c_uniqueverts++; + c_totalverts++; + } + else + superverts[i] = GetVertexnum (w->p[i]); + } + numsuperverts = w->numpoints; + + // this may fragment the face if > MAXEDGES + FaceFromSuperverts (node, f, 0); +} + +/* +================== +EmitVertexes_r +================== +*/ +void EmitVertexes_r (node_t *node) +{ + int i; + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + { + EmitFaceVertexes (node, f); + } + + for (i=0 ; i<2 ; i++) + EmitVertexes_r (node->children[i]); +} + + +#ifdef USE_HASHING +/* +========== +FindEdgeVerts + +Uses the hash tables to cut down to a small number +========== +*/ +void FindEdgeVerts (vec3_t v1, vec3_t v2) +{ + int x1, x2, y1, y2, t; + int x, y; + int vnum; + +#if 0 +{ + int i; + num_edge_verts = numvertexes-1; + for (i=0 ; i> 7; + y1 = (4096 + (int)(v1[1]+0.5)) >> 7; + x2 = (4096 + (int)(v2[0]+0.5)) >> 7; + y2 = (4096 + (int)(v2[1]+0.5)) >> 7; + + if (x1 > x2) + { + t = x1; + x1 = x2; + x2 = t; + } + if (y1 > y2) + { + t = y1; + y1 = y2; + y2 = t; + } +#if 0 + x1--; + x2++; + y1--; + y2++; + if (x1 < 0) + x1 = 0; + if (x2 >= HASH_SIZE) + x2 = HASH_SIZE; + if (y1 < 0) + y1 = 0; + if (y2 >= HASH_SIZE) + y2 = HASH_SIZE; +#endif + num_edge_verts = 0; + for (x=x1 ; x <= x2 ; x++) + { + for (y=y1 ; y <= y2 ; y++) + { + for (vnum=hashverts[y*HASH_SIZE+x] ; vnum ; vnum=vertexchain[vnum]) + { + edge_verts[num_edge_verts++] = vnum; + } + } + } +} + +#else +/* +========== +FindEdgeVerts + +Forced a dumb check of everything +========== +*/ +void FindEdgeVerts (vec3_t v1, vec3_t v2) +{ + int i; + + num_edge_verts = numvertexes-1; + for (i=0 ; i= end) + continue; // off an end + VectorMA (edge_start, dist, edge_dir, exact); + VectorSubtract (p, exact, off); + error = VectorLength (off); + + if (fabs(error) > OFF_EPSILON) + continue; // not on the edge + + // break the edge + c_tjunctions++; + TestEdge (start, dist, p1, j, k+1); + TestEdge (dist, end, j, p2, k+1); + return; + } + + // the edge p1 to p2 is now free of tjunctions + if (numsuperverts >= MAX_SUPERVERTS) + Error ("MAX_SUPERVERTS"); + superverts[numsuperverts] = p1; + numsuperverts++; +} + +/* +================== +FixFaceEdges + +================== +*/ +void FixFaceEdges (node_t *node, face_t *f) +{ + int p1, p2; + int i; + vec3_t e2; + vec_t len; + int count[MAX_SUPERVERTS], start[MAX_SUPERVERTS]; + int base; + + if (f->merged || f->split[0] || f->split[1]) + return; + + numsuperverts = 0; + + for (i=0 ; inumpoints ; i++) + { + p1 = f->vertexnums[i]; + p2 = f->vertexnums[(i+1)%f->numpoints]; + + VectorCopy (dvertexes[p1].point, edge_start); + VectorCopy (dvertexes[p2].point, e2); + + FindEdgeVerts (edge_start, e2); + + VectorSubtract (e2, edge_start, edge_dir); + len = VectorNormalize (edge_dir, edge_dir); + + start[i] = numsuperverts; + TestEdge (0, len, p1, p2, 0); + + count[i] = numsuperverts - start[i]; + } + + if (numsuperverts < 3) + { // entire face collapsed + f->numpoints = 0; + c_facecollapse++; + return; + } + + // we want to pick a vertex that doesn't have tjunctions + // on either side, which can cause artifacts on trifans, + // especially underwater + for (i=0 ; inumpoints ; i++) + { + if (count[i] == 1 && count[(i+f->numpoints-1)%f->numpoints] == 1) + break; + } + if (i == f->numpoints) + { + f->badstartvert = true; + c_badstartverts++; + base = 0; + } + else + { // rotate the vertex order + base = start[i]; + } + + // this may fragment the face if > MAXEDGES + FaceFromSuperverts (node, f, base); +} + +/* +================== +FixEdges_r +================== +*/ +void FixEdges_r (node_t *node) +{ + int i; + face_t *f; + + if (node->planenum == PLANENUM_LEAF) + return; + + for (f=node->faces ; f ; f=f->next) + FixFaceEdges (node, f); + + for (i=0 ; i<2 ; i++) + FixEdges_r (node->children[i]); +} + +/* +=========== +FixTjuncs + +=========== +*/ +void FixTjuncs (node_t *headnode) +{ + // snap and merge all vertexes + qprintf ("---- snap verts ----\n"); + memset (hashverts, 0, sizeof(hashverts)); + c_totalverts = 0; + c_uniqueverts = 0; + c_faceoverflows = 0; + EmitVertexes_r (headnode); + qprintf ("%i unique from %i\n", c_uniqueverts, c_totalverts); + + // break edges on tjunctions + qprintf ("---- tjunc ----\n"); + c_tryedges = 0; + c_degenerate = 0; + c_facecollapse = 0; + c_tjunctions = 0; + if (!notjunc) + FixEdges_r (headnode); + qprintf ("%5i edges degenerated\n", c_degenerate); + qprintf ("%5i faces degenerated\n", c_facecollapse); + qprintf ("%5i edges added by tjunctions\n", c_tjunctions); + qprintf ("%5i faces added by tjunctions\n", c_faceoverflows); + qprintf ("%5i bad start verts\n", c_badstartverts); +} + + +//======================================================== + +int c_faces; + +face_t *AllocFace (void) +{ + face_t *f; + + f = malloc(sizeof(*f)); + memset (f, 0, sizeof(*f)); + c_faces++; + + return f; +} + +face_t *NewFaceFromFace (face_t *f) +{ + face_t *newf; + + newf = AllocFace (); + *newf = *f; + newf->merged = NULL; + newf->split[0] = newf->split[1] = NULL; + newf->w = NULL; + return newf; +} + +void FreeFace (face_t *f) +{ + if (f->w) + FreeWinding (f->w); + free (f); + c_faces--; +} + +//======================================================== + +/* +================== +GetEdge + +Called by writebsp. +Don't allow four way edges +================== +*/ +int GetEdge2 (int v1, int v2, face_t *f) +{ + dedge_t *edge; + int i; + + c_tryedges++; + + if (!noshare) + { + for (i=firstmodeledge ; i < numedges ; i++) + { + edge = &dedges[i]; + if (v1 == edge->v[1] && v2 == edge->v[0] + && edgefaces[i][0]->contents == f->contents) + { + if (edgefaces[i][1]) + // printf ("WARNING: multiple backward edge\n"); + continue; + edgefaces[i][1] = f; + return -i; + } + #if 0 + if (v1 == edge->v[0] && v2 == edge->v[1]) + { + printf ("WARNING: multiple forward edge\n"); + return i; + } + #endif + } + } + +// emit an edge + if (numedges >= MAX_MAP_EDGES) + Error ("numedges == MAX_MAP_EDGES"); + edge = &dedges[numedges]; + numedges++; + edge->v[0] = v1; + edge->v[1] = v2; + edgefaces[numedges-1][0] = f; + + return numedges-1; +} + +/* +=========================================================================== + +FACE MERGING + +=========================================================================== +*/ + +#define CONTINUOUS_EPSILON 0.001 + +/* +============= +TryMergeWinding + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +winding_t *TryMergeWinding (winding_t *f1, winding_t *f2, vec3_t planenormal) +{ + vec_t *p1, *p2, *p3, *p4, *back; + winding_t *newf; + int i, j, k, l; + vec3_t normal, delta; + vec_t dot; + qboolean keep1, keep2; + + + // + // find a common edge + // + p1 = p2 = NULL; // stop compiler warning + j = 0; // + + for (i=0 ; inumpoints ; i++) + { + p1 = f1->p[i]; + p2 = f1->p[(i+1)%f1->numpoints]; + for (j=0 ; jnumpoints ; j++) + { + p3 = f2->p[j]; + p4 = f2->p[(j+1)%f2->numpoints]; + for (k=0 ; k<3 ; k++) + { + if (fabs(p1[k] - p4[k]) > EQUAL_EPSILON) + break; + if (fabs(p2[k] - p3[k]) > EQUAL_EPSILON) + break; + } + if (k==3) + break; + } + if (j < f2->numpoints) + break; + } + + if (i == f1->numpoints) + return NULL; // no matching edges + + // + // check slope of connected lines + // if the slopes are colinear, the point can be removed + // + back = f1->p[(i+f1->numpoints-1)%f1->numpoints]; + VectorSubtract (p1, back, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->p[(j+2)%f2->numpoints]; + VectorSubtract (back, p1, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep1 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + back = f1->p[(i+2)%f1->numpoints]; + VectorSubtract (back, p2, delta); + CrossProduct (planenormal, delta, normal); + VectorNormalize (normal, normal); + + back = f2->p[(j+f2->numpoints-1)%f2->numpoints]; + VectorSubtract (back, p2, delta); + dot = DotProduct (delta, normal); + if (dot > CONTINUOUS_EPSILON) + return NULL; // not a convex polygon + keep2 = (qboolean)(dot < -CONTINUOUS_EPSILON); + + // + // build the new polygon + // + newf = AllocWinding (f1->numpoints + f2->numpoints); + + // copy first polygon + for (k=(i+1)%f1->numpoints ; k != i ; k=(k+1)%f1->numpoints) + { + if (k==(i+1)%f1->numpoints && !keep2) + continue; + + VectorCopy (f1->p[k], newf->p[newf->numpoints]); + newf->numpoints++; + } + + // copy second polygon + for (l= (j+1)%f2->numpoints ; l != j ; l=(l+1)%f2->numpoints) + { + if (l==(j+1)%f2->numpoints && !keep1) + continue; + VectorCopy (f2->p[l], newf->p[newf->numpoints]); + newf->numpoints++; + } + + return newf; +} + +/* +============= +TryMerge + +If two polygons share a common edge and the edges that meet at the +common points are both inside the other polygons, merge them + +Returns NULL if the faces couldn't be merged, or the new face. +The originals will NOT be freed. +============= +*/ +face_t *TryMerge (face_t *f1, face_t *f2, vec3_t planenormal) +{ + face_t *newf; + winding_t *nw; + + if (!f1->w || !f2->w) + return NULL; + if (f1->texinfo != f2->texinfo) + return NULL; + if (f1->planenum != f2->planenum) // on front and back sides + return NULL; + if (f1->contents != f2->contents) + return NULL; + + + nw = TryMergeWinding (f1->w, f2->w, planenormal); + if (!nw) + return NULL; + + c_merge++; + newf = NewFaceFromFace (f1); + newf->w = nw; + + f1->merged = newf; + f2->merged = newf; + + return newf; +} + +/* +=============== +MergeNodeFaces +=============== +*/ +void MergeNodeFaces (node_t *node) +{ + face_t *f1, *f2, *end; + face_t *merged; + plane_t *plane; + + plane = &mapplanes[node->planenum]; + merged = NULL; + + for (f1 = node->faces ; f1 ; f1 = f1->next) + { + if (f1->merged || f1->split[0] || f1->split[1]) + continue; + for (f2 = node->faces ; f2 != f1 ; f2=f2->next) + { + if (f2->merged || f2->split[0] || f2->split[1]) + continue; + merged = TryMerge (f1, f2, plane->normal); + if (!merged) + continue; + + // add merged to the end of the node face list + // so it will be checked against all the faces again + for (end = node->faces ; end->next ; end = end->next) + ; + merged->next = NULL; + end->next = merged; + break; + } + } +} + +//===================================================================== + +/* +=============== +SubdivideFace + +Chop up faces that are larger than we want in the surface cache +=============== +*/ +void SubdivideFace (node_t *node, face_t *f) +{ + float mins, maxs; + vec_t v; + int axis, i; + texinfo_t *tex; + vec3_t temp; + vec_t dist; + winding_t *w, *frontw, *backw; + + if (f->merged) + return; + +// special (non-surface cached) faces don't need subdivision + tex = &texinfo[f->texinfo]; + + if ( tex->flags & (SURF_WARP|SURF_SKY) ) + { + return; + } + + for (axis = 0 ; axis < 2 ; axis++) + { + while (1) + { + mins = 999999; + maxs = -999999; + + VectorCopy (tex->vecs[axis], temp); + w = f->w; + for (i=0 ; inumpoints ; i++) + { + v = DotProduct (w->p[i], temp); + if (v < mins) + mins = v; + if (v > maxs) + maxs = v; + } +#if 0 + if (maxs - mins <= 0) + Error ("zero extents"); +#endif + if (axis == 2) + { // allow double high walls + if (maxs - mins <= subdivide_size/* *2 */) + break; + } + else if (maxs - mins <= subdivide_size) + break; + + // split it + c_subdivide++; + + v = VectorNormalize (temp, temp); + + dist = (mins + subdivide_size - 16)/v; + + ClipWindingEpsilon (w, temp, dist, ON_EPSILON, &frontw, &backw); + if (!frontw || !backw) + Error ("SubdivideFace: didn't split the polygon"); + + f->split[0] = NewFaceFromFace (f); + f->split[0]->w = frontw; + f->split[0]->next = node->faces; + node->faces = f->split[0]; + + f->split[1] = NewFaceFromFace (f); + f->split[1]->w = backw; + f->split[1]->next = node->faces; + node->faces = f->split[1]; + + SubdivideFace (node, f->split[0]); + SubdivideFace (node, f->split[1]); + return; + } + } +} + +void SubdivideNodeFaces (node_t *node) +{ + face_t *f; + + for (f = node->faces ; f ; f=f->next) + { + SubdivideFace (node, f); + } +} + +//=========================================================================== + +int c_nodefaces; + + +/* +============ +FaceFromPortal + +============ +*/ +face_t *FaceFromPortal (portal_t *p, int pside) +{ + face_t *f; + side_t *side; + + side = p->side; + if (!side) + return NULL; // portal does not bridge different visible contents + + f = AllocFace (); + + f->texinfo = side->texinfo; + f->planenum = (side->planenum & ~1) | pside; + f->portal = p; + + if ( (p->nodes[pside]->contents & CONTENTS_WINDOW) + && VisibleContents(p->nodes[!pside]->contents^p->nodes[pside]->contents) == CONTENTS_WINDOW ) + return NULL; // don't show insides of windows + + if (pside) + { + f->w = ReverseWinding(p->winding); + f->contents = p->nodes[1]->contents; + } + else + { + f->w = CopyWinding(p->winding); + f->contents = p->nodes[0]->contents; + } + return f; +} + + +/* +=============== +MakeFaces_r + +If a portal will make a visible face, +mark the side that originally created it + + solid / empty : solid + solid / water : solid + water / empty : water + water / water : none +=============== +*/ +void MakeFaces_r (node_t *node) +{ + portal_t *p; + int s; + + // recurse down to leafs + if (node->planenum != PLANENUM_LEAF) + { + MakeFaces_r (node->children[0]); + MakeFaces_r (node->children[1]); + + // merge together all visible faces on the node + if (!nomerge) + MergeNodeFaces (node); + if (!nosubdiv) + SubdivideNodeFaces (node); + + return; + } + + // solid leafs never have visible faces + if (node->contents & CONTENTS_SOLID) + return; + + // see which portals are valid + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + + p->face[s] = FaceFromPortal (p, s); + if (p->face[s]) + { + c_nodefaces++; + p->face[s]->next = p->onnode->faces; + p->onnode->faces = p->face[s]; + } + } +} + +/* +============ +MakeFaces +============ +*/ +void MakeFaces (node_t *node) +{ + qprintf ("--- MakeFaces ---\n"); + c_merge = 0; + c_subdivide = 0; + c_nodefaces = 0; + + MakeFaces_r (node); + + qprintf ("%5i makefaces\n", c_nodefaces); + qprintf ("%5i merged\n", c_merge); + qprintf ("%5i subdivided\n", c_subdivide); +} diff --git a/tools/quake2/extra/bsp/qbsp3/gldraw.c b/tools/quake2/extra/bsp/qbsp3/gldraw.c new file mode 100644 index 00000000..08ab9c45 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/gldraw.c @@ -0,0 +1,232 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include +#include +#include +#include + +#include "qbsp.h" + +// can't use the glvertex3fv functions, because the vec3_t fields +// could be either floats or doubles, depending on DOUBLEVEC_T + +qboolean drawflag; +vec3_t draw_mins, draw_maxs; + + +#define WIN_SIZE 512 + +void InitWindow (void) +{ + auxInitDisplayMode (AUX_SINGLE | AUX_RGB); + auxInitPosition (0, 0, WIN_SIZE, WIN_SIZE); + auxInitWindow ("qcsg"); +} + +void Draw_ClearWindow (void) +{ + static int init; + int w, h, g; + vec_t mx, my; + + if (!drawflag) + return; + + if (!init) + { + init = true; + InitWindow (); + } + + glClearColor (1,0.8,0.8,0); + glClear (GL_COLOR_BUFFER_BIT); + + w = (draw_maxs[0] - draw_mins[0]); + h = (draw_maxs[1] - draw_mins[1]); + + mx = draw_mins[0] + w/2; + my = draw_mins[1] + h/2; + + g = w > h ? w : h; + + glLoadIdentity (); + gluPerspective (90, 1, 2, 16384); + gluLookAt (mx, my, draw_maxs[2] + g/2, mx , my, draw_maxs[2], 0, 1, 0); + + glColor3f (0,0,0); +// glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisable (GL_DEPTH_TEST); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +#if 0 + glColor4f (1,0,0,0.5); + glBegin (GL_POLYGON); + + glVertex3f (0, 500, 0); + glVertex3f (0, 900, 0); + glVertex3f (0, 900, 100); + glVertex3f (0, 500, 100); + + glEnd (); +#endif + + glFlush (); + +} + +void Draw_SetRed (void) +{ + if (!drawflag) + return; + + glColor3f (1,0,0); +} + +void Draw_SetGrey (void) +{ + if (!drawflag) + return; + + glColor3f (0.5,0.5,0.5); +} + +void Draw_SetBlack (void) +{ + if (!drawflag) + return; + + glColor3f (0,0,0); +} + +void DrawWinding (winding_t *w) +{ + int i; + + if (!drawflag) + return; + + glColor4f (0,0,0,0.5); + glBegin (GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glColor4f (0,1,0,0.3); + glBegin (GL_POLYGON); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glFlush (); +} + +void DrawAuxWinding (winding_t *w) +{ + int i; + + if (!drawflag) + return; + + glColor4f (0,0,0,0.5); + glBegin (GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glColor4f (1,0,0,0.3); + glBegin (GL_POLYGON); + for (i=0 ; inumpoints ; i++) + glVertex3f (w->p[i][0],w->p[i][1],w->p[i][2] ); + glEnd (); + + glFlush (); +} + +//============================================================ + +#define GLSERV_PORT 25001 + +qboolean wins_init; +int draw_socket; + +void GLS_BeginScene (void) +{ + WSADATA winsockdata; + WORD wVersionRequested; + struct sockaddr_in address; + int r; + + if (!wins_init) + { + wins_init = true; + + wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (MAKEWORD(1, 1), &winsockdata); + + if (r) + Error ("Winsock initialization failed."); + + } + + // connect a socket to the server + + draw_socket = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); + if (draw_socket == -1) + Error ("draw_socket failed"); + + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_LOOPBACK); + address.sin_port = GLSERV_PORT; + r = connect (draw_socket, (struct sockaddr *)&address, sizeof(address)); + if (r == -1) + { + closesocket (draw_socket); + draw_socket = 0; + } +} + +void GLS_Winding (winding_t *w, int code) +{ + byte buf[1024]; + int i, j; + + if (!draw_socket) + return; + + ((int *)buf)[0] = w->numpoints; + ((int *)buf)[1] = code; + for (i=0 ; inumpoints ; i++) + for (j=0 ; j<3 ; j++) + ((float *)buf)[2+i*3+j] = w->p[i][j]; + + send (draw_socket, buf, w->numpoints*12+8, 0); +} + +void GLS_EndScene (void) +{ + closesocket (draw_socket); + draw_socket = 0; +} diff --git a/tools/quake2/extra/bsp/qbsp3/glfile.c b/tools/quake2/extra/bsp/qbsp3/glfile.c new file mode 100644 index 00000000..6d767772 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/glfile.c @@ -0,0 +1,149 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +int c_glfaces; + +int PortalVisibleSides (portal_t *p) +{ + int fcon, bcon; + + if (!p->onnode) + return 0; // outside + + fcon = p->nodes[0]->contents; + bcon = p->nodes[1]->contents; + + // same contents never create a face + if (fcon == bcon) + return 0; + + // FIXME: is this correct now? + if (!fcon) + return 1; + if (!bcon) + return 2; + return 0; +} + +void OutputWinding (winding_t *w, FILE *glview) +{ + static int level = 128; + vec_t light; + int i; + + fprintf (glview, "%i\n", w->numpoints); + level+=28; + light = (level&255)/255.0; + for (i=0 ; inumpoints ; i++) + { + fprintf (glview, "%6.3f %6.3f %6.3f %6.3f %6.3f %6.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + light, + light, + light); + } + fprintf (glview, "\n"); +} + +/* +============= +OutputPortal +============= +*/ +void OutputPortal (portal_t *p, FILE *glview) +{ + winding_t *w; + int sides; + + sides = PortalVisibleSides (p); + if (!sides) + return; + + c_glfaces++; + + w = p->winding; + + if (sides == 2) // back side + w = ReverseWinding (w); + + OutputWinding (w, glview); + + if (sides == 2) + FreeWinding(w); +} + +/* +============= +WriteGLView_r +============= +*/ +void WriteGLView_r (node_t *node, FILE *glview) +{ + portal_t *p, *nextp; + + if (node->planenum != PLANENUM_LEAF) + { + WriteGLView_r (node->children[0], glview); + WriteGLView_r (node->children[1], glview); + return; + } + + // write all the portals + for (p=node->portals ; p ; p=nextp) + { + if (p->nodes[0] == node) + { + OutputPortal (p, glview); + nextp = p->next[0]; + } + else + nextp = p->next[1]; + } +} + +/* +============= +WriteGLView +============= +*/ +void WriteGLView (tree_t *tree, char *source) +{ + char name[1024]; + FILE *glview; + + c_glfaces = 0; + sprintf (name, "%s%s.gl",outbase, source); + printf ("Writing %s\n", name); + + glview = fopen (name, "w"); + if (!glview) + Error ("Couldn't open %s", name); + WriteGLView_r (tree->headnode, glview); + fclose (glview); + + printf ("%5i c_glfaces\n", c_glfaces); +} + diff --git a/tools/quake2/extra/bsp/qbsp3/leakfile.c b/tools/quake2/extra/bsp/qbsp3/leakfile.c new file mode 100644 index 00000000..53d48375 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/leakfile.c @@ -0,0 +1,100 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +/* +============================================================================== + +LEAF FILE GENERATION + +Save out name.line for qe3 to read +============================================================================== +*/ + + +/* +============= +LeakFile + +Finds the shortest possible chain of portals +that leads from the outside leaf to a specifically +occupied leaf +============= +*/ +void LeakFile (tree_t *tree) +{ + vec3_t mid; + FILE *linefile; + char filename[1024]; + node_t *node; + int count; + + if (!tree->outside_node.occupied) + return; + + qprintf ("--- LeakFile ---\n"); + + // + // write the points to the file + // + sprintf (filename, "%s.lin", source); + linefile = fopen (filename, "w"); + if (!linefile) + Error ("Couldn't open %s\n", filename); + + count = 0; + node = &tree->outside_node; + while (node->occupied > 1) + { + int next; + portal_t *p, *nextportal; + node_t *nextnode; + int s; + + // find the best portal exit + next = node->occupied; + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (p->nodes[s]->occupied + && p->nodes[s]->occupied < next) + { + nextportal = p; + nextnode = p->nodes[s]; + next = nextnode->occupied; + } + } + node = nextnode; + WindingCenter (nextportal->winding, mid); + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + count++; + } + // add the occupant center + GetVectorForKey (node->occupant, "origin", mid); + + fprintf (linefile, "%f %f %f\n", mid[0], mid[1], mid[2]); + qprintf ("%5i point linefile\n", count+1); + + fclose (linefile); +} + diff --git a/tools/quake2/extra/bsp/qbsp3/makefile b/tools/quake2/extra/bsp/qbsp3/makefile new file mode 100644 index 00000000..7368e5b1 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/makefile @@ -0,0 +1,98 @@ + +CFLAGS = -c +LDFLAGS = +ODIR = baddir + +EXEBASE = qbsp3 +EXE = $(ODIR)/qbsp3 +all: $(EXE) + +_next: + make "CFLAGS = -c -g -I../../common -DDOUBLEVEC_T" "ODIR = next" + +_irix: + make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix" + +_irixdebug: + make "CFLAGS = -c -O2 -g -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -g" "ODIR = irix" + +_irixinst: + make "CFLAGS = -c -Ofast=ip27 -OPT:IEEE_arithmetic=3 -I../../common -Xcpluscomm -DDOUBLEVEC_T" "LDFLAGS = -Ofast=ip27 -OPT:IEEE_arithmetic=3" "ODIR = irix" + cp irix/$(EXEBASE) /limbo/quake2/bin_irix + +_irixclean: + rm -f irix/*.o irix/$(EXEBASE) + +_osf: + make "CFLAGS = -c -O4 -I../../common -threads -DDOUBLEVEC_T" "LDFLAGS = -threads" "ODIR = osf" + +clean: + rm -f irix/*.o irix/$(EXEBASE) + +install: + cp irix/$(EXEBASE) /limbo/quake2/bin_irix + + +FILES = $(ODIR)/brushbsp.o $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/faces.o $(ODIR)/nodraw.o $(ODIR)/glfile.o $(ODIR)/leakfile.o $(ODIR)/map.o $(ODIR)/mathlib.o $(ODIR)/polylib.o $(ODIR)/portals.o $(ODIR)/prtfile.o $(ODIR)/qbsp3.o $(ODIR)/scriplib.o $(ODIR)/textures.o $(ODIR)/threads.o $(ODIR)/tree.o $(ODIR)/writebsp.o $(ODIR)/csg.o + +$(EXE) : $(FILES) + cc -o $(EXE) $(LDFLAGS) $(FILES) -lm + +$(ODIR)/brushbsp.o : brushbsp.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/faces.o : faces.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/nodraw.o : nodraw.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/glfile.o : glfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/leakfile.o : leakfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/map.o : map.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/portals.o : portals.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/prtfile.o : prtfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/qbsp3.o : qbsp3.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/tree.o : tree.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/textures.o : textures.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/writebsp.o : writebsp.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/csg.o : csg.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i + +$(ODIR)/cmdlib.o : ../../common/cmdlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/mathlib.o : ../../common/mathlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/polylib.o : ../../common/polylib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/scriplib.o : ../../common/scriplib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/threads.o : ../../common/threads.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/bspfile.o : ../../common/bspfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i diff --git a/tools/quake2/extra/bsp/qbsp3/map.c b/tools/quake2/extra/bsp/qbsp3/map.c new file mode 100644 index 00000000..232979c7 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/map.c @@ -0,0 +1,1017 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +extern qboolean onlyents; + +int nummapbrushes; +mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +int nummapbrushsides; +side_t brushsides[MAX_MAP_SIDES]; +brush_texture_t side_brushtextures[MAX_MAP_SIDES]; + +int nummapplanes; +plane_t mapplanes[MAX_MAP_PLANES]; + +#define PLANE_HASHES 1024 +plane_t *planehash[PLANE_HASHES]; + +vec3_t map_mins, map_maxs; + +// undefine to make plane finding use linear sort +#define USE_HASHING + +void TestExpandBrushes (void); + +int c_boxbevels; +int c_edgebevels; + +int c_areaportals; + +int c_clipbrushes; + +/* +============================================================================= + +PLANE FINDING + +============================================================================= +*/ + + +/* +================= +PlaneTypeForNormal +================= +*/ +int PlaneTypeForNormal (vec3_t normal) +{ + vec_t ax, ay, az; + +// NOTE: should these have an epsilon around 1.0? + if (normal[0] == 1.0 || normal[0] == -1.0) + return PLANE_X; + if (normal[1] == 1.0 || normal[1] == -1.0) + return PLANE_Y; + if (normal[2] == 1.0 || normal[2] == -1.0) + return PLANE_Z; + + ax = fabs(normal[0]); + ay = fabs(normal[1]); + az = fabs(normal[2]); + + if (ax >= ay && ax >= az) + return PLANE_ANYX; + if (ay >= ax && ay >= az) + return PLANE_ANYY; + return PLANE_ANYZ; +} + +/* +================ +PlaneEqual +================ +*/ +#define NORMAL_EPSILON 0.00001 +#define DIST_EPSILON 0.01 +qboolean PlaneEqual (plane_t *p, vec3_t normal, vec_t dist) +{ +#if 1 + if ( + fabs(p->normal[0] - normal[0]) < NORMAL_EPSILON + && fabs(p->normal[1] - normal[1]) < NORMAL_EPSILON + && fabs(p->normal[2] - normal[2]) < NORMAL_EPSILON + && fabs(p->dist - dist) < DIST_EPSILON ) + return true; +#else + if (p->normal[0] == normal[0] + && p->normal[1] == normal[1] + && p->normal[2] == normal[2] + && p->dist == dist) + return true; +#endif + return false; +} + +/* +================ +AddPlaneToHash +================ +*/ +void AddPlaneToHash (plane_t *p) +{ + int hash; + + hash = (int)fabs(p->dist) / 8; + hash &= (PLANE_HASHES-1); + + p->hash_chain = planehash[hash]; + planehash[hash] = p; +} + +/* +================ +CreateNewFloatPlane +================ +*/ +int CreateNewFloatPlane (vec3_t normal, vec_t dist) +{ + plane_t *p, temp; + + if (VectorLength(normal) < 0.5) + Error ("FloatPlane: bad normal"); + // create a new plane + if (nummapplanes+2 > MAX_MAP_PLANES) + Error ("MAX_MAP_PLANES"); + + p = &mapplanes[nummapplanes]; + VectorCopy (normal, p->normal); + p->dist = dist; + p->type = (p+1)->type = PlaneTypeForNormal (p->normal); + + VectorSubtract (vec3_origin, normal, (p+1)->normal); + (p+1)->dist = -dist; + + nummapplanes += 2; + + // allways put axial planes facing positive first + if (p->type < 3) + { + if (p->normal[0] < 0 || p->normal[1] < 0 || p->normal[2] < 0) + { + // flip order + temp = *p; + *p = *(p+1); + *(p+1) = temp; + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 1; + } + } + + AddPlaneToHash (p); + AddPlaneToHash (p+1); + return nummapplanes - 2; +} + +/* +============== +SnapVector +============== +*/ +void SnapVector (vec3_t normal) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if ( fabs(normal[i] - 1) < NORMAL_EPSILON ) + { + VectorClear (normal); + normal[i] = 1; + break; + } + if ( fabs(normal[i] - -1) < NORMAL_EPSILON ) + { + VectorClear (normal); + normal[i] = -1; + break; + } + } +} + +/* +============== +SnapPlane +============== +*/ +void SnapPlane (vec3_t normal, vec_t *dist) +{ + SnapVector (normal); + + if (fabs(*dist-Q_rint(*dist)) < DIST_EPSILON) + *dist = Q_rint(*dist); +} + +/* +============= +FindFloatPlane + +============= +*/ +#ifndef USE_HASHING +int FindFloatPlane (vec3_t normal, vec_t dist) +{ + int i; + plane_t *p; + + SnapPlane (normal, &dist); + for (i=0, p=mapplanes ; ihash_chain) + { + if (PlaneEqual (p, normal, dist)) + return p-mapplanes; + } + } + + return CreateNewFloatPlane (normal, dist); +} +#endif + +/* +================ +PlaneFromPoints +================ +*/ +int PlaneFromPoints (int *p0, int *p1, int *p2) +{ + vec3_t t1, t2, normal; + vec_t dist; + + VectorSubtract (p0, p1, t1); + VectorSubtract (p2, p1, t2); + CrossProduct (t1, t2, normal); + VectorNormalize (normal, normal); + + dist = DotProduct (p0, normal); + + return FindFloatPlane (normal, dist); +} + + +//==================================================================== + + +/* +=========== +BrushContents +=========== +*/ +int BrushContents (mapbrush_t *b) +{ + int contents; + side_t *s; + int i; + int trans; + + s = &b->original_sides[0]; + contents = s->contents; + trans = texinfo[s->texinfo].flags; + for (i=1 ; inumsides ; i++, s++) + { + s = &b->original_sides[i]; + trans |= texinfo[s->texinfo].flags; + if (s->contents != contents) + { + printf ("Entity %i, Brush %i: mixed face contents\n" + , b->entitynum, b->brushnum); + break; + } + } + + // if any side is translucent, mark the contents + // and change solid to window + if ( trans & (SURF_TRANS33|SURF_TRANS66) ) + { + contents |= CONTENTS_TRANSLUCENT; + if (contents & CONTENTS_SOLID) + { + contents &= ~CONTENTS_SOLID; + contents |= CONTENTS_WINDOW; + } + } + + return contents; +} + + +//============================================================================ + +/* +================= +AddBrushBevels + +Adds any additional planes necessary to allow the brush to be expanded +against axial bounding boxes +================= +*/ +void AddBrushBevels (mapbrush_t *b) +{ + int axis, dir; + int i, j, k, l, order; + side_t sidetemp; + brush_texture_t tdtemp; + side_t *s, *s2; + vec3_t normal; + float dist; + winding_t *w, *w2; + vec3_t vec, vec2; + float d; + + // + // add the axial planes + // + order = 0; + for (axis=0 ; axis <3 ; axis++) + { + for (dir=-1 ; dir <= 1 ; dir+=2, order++) + { + // see if the plane is allready present + for (i=0, s=b->original_sides ; inumsides ; i++,s++) + { + if (mapplanes[s->planenum].normal[axis] == dir) + break; + } + + if (i == b->numsides) + { // add a new side + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + nummapbrushsides++; + b->numsides++; + VectorClear (normal); + normal[axis] = dir; + if (dir == 1) + dist = b->maxs[axis]; + else + dist = -b->mins[axis]; + s->planenum = FindFloatPlane (normal, dist); + s->texinfo = b->original_sides[0].texinfo; + s->contents = b->original_sides[0].contents; + s->bevel = true; + c_boxbevels++; + } + + // if the plane is not in it canonical order, swap it + if (i != order) + { + sidetemp = b->original_sides[order]; + b->original_sides[order] = b->original_sides[i]; + b->original_sides[i] = sidetemp; + + j = b->original_sides - brushsides; + tdtemp = side_brushtextures[j+order]; + side_brushtextures[j+order] = side_brushtextures[j+i]; + side_brushtextures[j+i] = tdtemp; + } + } + } + + // + // add the edge bevels + // + if (b->numsides == 6) + return; // pure axial + + // test the non-axial plane edges + for (i=6 ; inumsides ; i++) + { + s = b->original_sides + i; + w = s->winding; + if (!w) + continue; + for (j=0 ; jnumpoints ; j++) + { + k = (j+1)%w->numpoints; + VectorSubtract (w->p[j], w->p[k], vec); + if (VectorNormalize (vec, vec) < 0.5) + continue; + SnapVector (vec); + for (k=0 ; k<3 ; k++) + if ( vec[k] == -1 || vec[k] == 1) + break; // axial + if (k != 3) + continue; // only test non-axial edges + + // try the six possible slanted axials from this edge + for (axis=0 ; axis <3 ; axis++) + { + for (dir=-1 ; dir <= 1 ; dir+=2) + { + // construct a plane + VectorClear (vec2); + vec2[axis] = dir; + CrossProduct (vec, vec2, normal); + if (VectorNormalize (normal, normal) < 0.5) + continue; + dist = DotProduct (w->p[j], normal); + + // if all the points on all the sides are + // behind this plane, it is a proper edge bevel + for (k=0 ; knumsides ; k++) + { + // if this plane has allready been used, skip it + if (PlaneEqual (&mapplanes[b->original_sides[k].planenum] + , normal, dist) ) + break; + + w2 = b->original_sides[k].winding; + if (!w2) + continue; + for (l=0 ; lnumpoints ; l++) + { + d = DotProduct (w2->p[l], normal) - dist; + if (d > 0.1) + break; // point in front + } + if (l != w2->numpoints) + break; + } + + if (k != b->numsides) + continue; // wasn't part of the outer hull + // add this plane + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + nummapbrushsides++; + s2 = &b->original_sides[b->numsides]; + s2->planenum = FindFloatPlane (normal, dist); + s2->texinfo = b->original_sides[0].texinfo; + s2->contents = b->original_sides[0].contents; + s2->bevel = true; + c_edgebevels++; + b->numsides++; + } + } + } + } +} + + +/* +================ +MakeBrushWindings + +makes basewindigs for sides and mins / maxs for the brush +================ +*/ +qboolean MakeBrushWindings (mapbrush_t *ob) +{ + int i, j; + winding_t *w; + side_t *side; + plane_t *plane; + + ClearBounds (ob->mins, ob->maxs); + + for (i=0 ; inumsides ; i++) + { + plane = &mapplanes[ob->original_sides[i].planenum]; + w = BaseWindingForPlane (plane->normal, plane->dist); + for (j=0 ; jnumsides && w; j++) + { + if (i == j) + continue; + if (ob->original_sides[j].bevel) + continue; + plane = &mapplanes[ob->original_sides[j].planenum^1]; + ChopWindingInPlace (&w, plane->normal, plane->dist, 0); //CLIP_EPSILON); + } + + side = &ob->original_sides[i]; + side->winding = w; + if (w) + { + side->visible = true; + for (j=0 ; jnumpoints ; j++) + AddPointToBounds (w->p[j], ob->mins, ob->maxs); + } + } + + for (i=0 ; i<3 ; i++) + { + if (ob->mins[0] < -4096 || ob->maxs[0] > 4096) + printf ("entity %i, brush %i: bounds out of range\n", ob->entitynum, ob->brushnum); + if (ob->mins[0] > 4096 || ob->maxs[0] < -4096) + printf ("entity %i, brush %i: no visible sides on brush\n", ob->entitynum, ob->brushnum); + } + + return true; +} + + +/* +================= +ParseBrush +================= +*/ +void ParseBrush (entity_t *mapent) +{ + mapbrush_t *b; + int i,j, k; + int mt; + side_t *side, *s2; + int planenum; + brush_texture_t td; + int planepts[3][3]; + + if (nummapbrushes == MAX_MAP_BRUSHES) + Error ("nummapbrushes == MAX_MAP_BRUSHES"); + + b = &mapbrushes[nummapbrushes]; + b->original_sides = &brushsides[nummapbrushsides]; + b->entitynum = num_entities-1; + b->brushnum = nummapbrushes - mapent->firstbrush; + + do + { + if (!GetToken (true)) + break; + if (!strcmp (token, "}") ) + break; + + if (nummapbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + side = &brushsides[nummapbrushsides]; + + // read the three point plane definition + for (i=0 ; i<3 ; i++) + { + if (i != 0) + GetToken (true); + if (strcmp (token, "(") ) + Error ("parsing brush"); + + for (j=0 ; j<3 ; j++) + { + GetToken (false); + planepts[i][j] = atoi(token); + } + + GetToken (false); + if (strcmp (token, ")") ) + Error ("parsing brush"); + + } + + + // + // read the texturedef + // + GetToken (false); + strcpy (td.name, token); + + GetToken (false); + td.shift[0] = atoi(token); + GetToken (false); + td.shift[1] = atoi(token); + GetToken (false); + td.rotate = atoi(token); + GetToken (false); + td.scale[0] = atof(token); + GetToken (false); + td.scale[1] = atof(token); + + // find default flags and values + mt = FindMiptex (td.name); + td.flags = textureref[mt].flags; + td.value = textureref[mt].value; + side->contents = textureref[mt].contents; + side->surf = td.flags = textureref[mt].flags; + + if (TokenAvailable()) + { + GetToken (false); + side->contents = atoi(token); + GetToken (false); + side->surf = td.flags = atoi(token); + GetToken (false); + td.value = atoi(token); + } + + // translucent objects are automatically classified as detail + if (side->surf & (SURF_TRANS33|SURF_TRANS66) ) + side->contents |= CONTENTS_DETAIL; + if (side->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) + side->contents |= CONTENTS_DETAIL; + if (fulldetail) + side->contents &= ~CONTENTS_DETAIL; + if (!(side->contents & ((LAST_VISIBLE_CONTENTS-1) + | CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP|CONTENTS_MIST) ) ) + side->contents |= CONTENTS_SOLID; + + // hints and skips are never detail, and have no content + if (side->surf & (SURF_HINT|SURF_SKIP) ) + { + side->contents = 0; + side->surf &= ~CONTENTS_DETAIL; + } + + + // + // find the plane number + // + planenum = PlaneFromPoints (planepts[0], planepts[1], planepts[2]); + if (planenum == -1) + { + printf ("Entity %i, Brush %i: plane with no normal\n" + , b->entitynum, b->brushnum); + continue; + } + + // + // see if the plane has been used already + // + for (k=0 ; knumsides ; k++) + { + s2 = b->original_sides + k; + if (s2->planenum == planenum) + { + printf ("Entity %i, Brush %i: duplicate plane\n" + , b->entitynum, b->brushnum); + break; + } + if ( s2->planenum == (planenum^1) ) + { + printf ("Entity %i, Brush %i: mirrored plane\n" + , b->entitynum, b->brushnum); + break; + } + } + if (k != b->numsides) + continue; // duplicated + + // + // keep this side + // + + side = b->original_sides + b->numsides; + side->planenum = planenum; + side->texinfo = TexinfoForBrushTexture (&mapplanes[planenum], + &td, vec3_origin); + + // save the td off in case there is an origin brush and we + // have to recalculate the texinfo + side_brushtextures[nummapbrushsides] = td; + + nummapbrushsides++; + b->numsides++; + } while (1); + + // get the content for the entire brush + b->contents = BrushContents (b); + + // allow detail brushes to be removed + if (nodetail && (b->contents & CONTENTS_DETAIL) ) + { + b->numsides = 0; + return; + } + + // allow water brushes to be removed + if (nowater && (b->contents & (CONTENTS_LAVA | CONTENTS_SLIME | CONTENTS_WATER)) ) + { + b->numsides = 0; + return; + } + + // create windings for sides and bounds for brush + MakeBrushWindings (b); + + // brushes that will not be visible at all will never be + // used as bsp splitters + if (b->contents & (CONTENTS_PLAYERCLIP|CONTENTS_MONSTERCLIP) ) + { + c_clipbrushes++; + for (i=0 ; inumsides ; i++) + b->original_sides[i].texinfo = TEXINFO_NODE; + } + + // + // origin brushes are removed, but they set + // the rotation origin for the rest of the brushes + // in the entity. After the entire entity is parsed, + // the planenums and texinfos will be adjusted for + // the origin brush + // + if (b->contents & CONTENTS_ORIGIN) + { + char string[32]; + vec3_t origin; + + if (num_entities == 1) + { + Error ("Entity %i, Brush %i: origin brushes not allowed in world" + , b->entitynum, b->brushnum); + return; + } + + VectorAdd (b->mins, b->maxs, origin); + VectorScale (origin, 0.5, origin); + + sprintf (string, "%i %i %i", (int)origin[0], (int)origin[1], (int)origin[2]); + SetKeyValue (&entities[b->entitynum], "origin", string); + + VectorCopy (origin, entities[b->entitynum].origin); + + // don't keep this brush + b->numsides = 0; + + return; + } + + AddBrushBevels (b); + + nummapbrushes++; + mapent->numbrushes++; +} + +/* +================ +MoveBrushesToWorld + +Takes all of the brushes from the current entity and +adds them to the world's brush list. + +Used by func_group and func_areaportal +================ +*/ +void MoveBrushesToWorld (entity_t *mapent) +{ + int newbrushes; + int worldbrushes; + mapbrush_t *temp; + int i; + + // this is pretty gross, because the brushes are expected to be + // in linear order for each entity + + newbrushes = mapent->numbrushes; + worldbrushes = entities[0].numbrushes; + + temp = malloc(newbrushes*sizeof(mapbrush_t)); + memcpy (temp, mapbrushes + mapent->firstbrush, newbrushes*sizeof(mapbrush_t)); + +#if 0 // let them keep their original brush numbers + for (i=0 ; inumbrushes = 0; +} + +/* +================ +ParseMapEntity +================ +*/ +qboolean ParseMapEntity (void) +{ + entity_t *mapent; + epair_t *e; + side_t *s; + int i, j; + int startbrush, startsides; + vec_t newdist; + mapbrush_t *b; + + if (!GetToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + startbrush = nummapbrushes; + startsides = nummapbrushsides; + + mapent = &entities[num_entities]; + num_entities++; + memset (mapent, 0, sizeof(*mapent)); + mapent->firstbrush = nummapbrushes; + mapent->numbrushes = 0; +// mapent->portalareas[0] = -1; +// mapent->portalareas[1] = -1; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + if (!strcmp (token, "{") ) + ParseBrush (mapent); + else + { + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } + } while (1); + + GetVectorForKey (mapent, "origin", mapent->origin); + + // + // if there was an origin brush, offset all of the planes and texinfo + // + if (mapent->origin[0] || mapent->origin[1] || mapent->origin[2]) + { + for (i=0 ; inumbrushes ; i++) + { + b = &mapbrushes[mapent->firstbrush + i]; + for (j=0 ; jnumsides ; j++) + { + s = &b->original_sides[j]; + newdist = mapplanes[s->planenum].dist - + DotProduct (mapplanes[s->planenum].normal, mapent->origin); + s->planenum = FindFloatPlane (mapplanes[s->planenum].normal, newdist); + s->texinfo = TexinfoForBrushTexture (&mapplanes[s->planenum], + &side_brushtextures[s-brushsides], mapent->origin); + } + MakeBrushWindings (b); + } + } + + // group entities are just for editor convenience + // toss all brushes into the world entity + if (!strcmp ("func_group", ValueForKey (mapent, "classname"))) + { + MoveBrushesToWorld (mapent); + mapent->numbrushes = 0; + return true; + } + + // areaportal entities move their brushes, but don't eliminate + // the entity + if (!strcmp ("func_areaportal", ValueForKey (mapent, "classname"))) + { + char str[128]; + + if (mapent->numbrushes != 1) + Error ("Entity %i: func_areaportal can only be a single brush", num_entities-1); + + b = &mapbrushes[nummapbrushes-1]; + b->contents = CONTENTS_AREAPORTAL; + c_areaportals++; + mapent->areaportalnum = c_areaportals; + // set the portal number as "style" + sprintf (str, "%i", c_areaportals); + SetKeyValue (mapent, "style", str); + MoveBrushesToWorld (mapent); + return true; + } + + return true; +} + +//=================================================================== + +/* +================ +LoadMapFile +================ +*/ +void LoadMapFile (char *filename) +{ + int i; + + qprintf ("--- LoadMapFile ---\n"); + + LoadScriptFile (filename); + + nummapbrushsides = 0; + num_entities = 0; + + while (ParseMapEntity ()) + { + } + + ClearBounds (map_mins, map_maxs); + for (i=0 ; i 4096) + continue; // no valid points + AddPointToBounds (mapbrushes[i].mins, map_mins, map_maxs); + AddPointToBounds (mapbrushes[i].maxs, map_mins, map_maxs); + } + + qprintf ("%5i brushes\n", nummapbrushes); + qprintf ("%5i clipbrushes\n", c_clipbrushes); + qprintf ("%5i total sides\n", nummapbrushsides); + qprintf ("%5i boxbevels\n", c_boxbevels); + qprintf ("%5i edgebevels\n", c_edgebevels); + qprintf ("%5i entities\n", num_entities); + qprintf ("%5i planes\n", nummapplanes); + qprintf ("%5i areaportals\n", c_areaportals); + qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], + map_maxs[0],map_maxs[1],map_maxs[2]); + +// TestExpandBrushes (); +} + + +//==================================================================== + + +/* +================ +TestExpandBrushes + +Expands all the brush planes and saves a new map out +================ +*/ +void TestExpandBrushes (void) +{ + FILE *f; + side_t *s; + int i, j, bn; + winding_t *w; + char *name = "expanded.map"; + mapbrush_t *brush; + vec_t dist; + + printf ("writing %s\n", name); + f = fopen (name, "wb"); + if (!f) + Error ("Can't write %s\b", name); + + fprintf (f, "{\n\"classname\" \"worldspawn\"\n"); + + for (bn=0 ; bnnumsides ; i++) + { + s = brush->original_sides + i; + dist = mapplanes[s->planenum].dist; + for (j=0 ; j<3 ; j++) + dist += fabs( 16 * mapplanes[s->planenum].normal[j] ); + + w = BaseWindingForPlane (mapplanes[s->planenum].normal, dist); + + fprintf (f,"( %i %i %i ) ", (int)w->p[0][0], (int)w->p[0][1], (int)w->p[0][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[1][0], (int)w->p[1][1], (int)w->p[1][2]); + fprintf (f,"( %i %i %i ) ", (int)w->p[2][0], (int)w->p[2][1], (int)w->p[2][2]); + + fprintf (f, "%s 0 0 0 1 1\n", texinfo[s->texinfo].texture); + FreeWinding (w); + } + fprintf (f, "}\n"); + } + fprintf (f, "}\n"); + + fclose (f); + + Error ("can't proceed after expanding brushes"); +} diff --git a/tools/quake2/extra/bsp/qbsp3/nodraw.c b/tools/quake2/extra/bsp/qbsp3/nodraw.c new file mode 100644 index 00000000..fd6959d8 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/nodraw.c @@ -0,0 +1,47 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +vec3_t draw_mins, draw_maxs; +qboolean drawflag; + +void Draw_ClearWindow (void) +{ +} + +//============================================================ + +#define GLSERV_PORT 25001 + + +void GLS_BeginScene (void) +{ +} + +void GLS_Winding (winding_t *w, int code) +{ +} + +void GLS_EndScene (void) +{ +} diff --git a/tools/quake2/extra/bsp/qbsp3/portals.c b/tools/quake2/extra/bsp/qbsp3/portals.c new file mode 100644 index 00000000..ef57caef --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/portals.c @@ -0,0 +1,1111 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + + +int c_active_portals; +int c_peak_portals; +int c_boundary; +int c_boundary_sides; + +/* +=========== +AllocPortal +=========== +*/ +portal_t *AllocPortal (void) +{ + portal_t *p; + + if (numthreads == 1) + c_active_portals++; + if (c_active_portals > c_peak_portals) + c_peak_portals = c_active_portals; + + p = malloc (sizeof(portal_t)); + memset (p, 0, sizeof(portal_t)); + + return p; +} + +void FreePortal (portal_t *p) +{ + if (p->winding) + FreeWinding (p->winding); + if (numthreads == 1) + c_active_portals--; + free (p); +} + +//============================================================== + +/* +============== +VisibleContents + +Returns the single content bit of the +strongest visible content present +============== +*/ +int VisibleContents (int contents) +{ + int i; + + for (i=1 ; i<=LAST_VISIBLE_CONTENTS ; i<<=1) + if (contents & i ) + return i; + + return 0; +} + + +/* +=============== +ClusterContents +=============== +*/ +int ClusterContents (node_t *node) +{ + int c1, c2, c; + + if (node->planenum == PLANENUM_LEAF) + return node->contents; + + c1 = ClusterContents(node->children[0]); + c2 = ClusterContents(node->children[1]); + c = c1|c2; + + // a cluster may include some solid detail areas, but + // still be seen into + if ( ! (c1&CONTENTS_SOLID) || ! (c2&CONTENTS_SOLID) ) + c &= ~CONTENTS_SOLID; + return c; +} + +/* +============= +Portal_VisFlood + +Returns true if the portal is empty or translucent, allowing +the PVS calculation to see through it. +The nodes on either side of the portal may actually be clusters, +not leafs, so all contents should be ored together +============= +*/ +qboolean Portal_VisFlood (portal_t *p) +{ + int c1, c2; + + if (!p->onnode) + return false; // to global outsideleaf + + c1 = ClusterContents(p->nodes[0]); + c2 = ClusterContents(p->nodes[1]); + + if (!VisibleContents (c1^c2)) + return true; + + if (c1 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL)) + c1 = 0; + if (c2 & (CONTENTS_TRANSLUCENT|CONTENTS_DETAIL)) + c2 = 0; + + if ( (c1|c2) & CONTENTS_SOLID ) + return false; // can't see through solid + + if (! (c1 ^ c2)) + return true; // identical on both sides + + if (!VisibleContents (c1^c2)) + return true; + return false; +} + + +/* +=============== +Portal_EntityFlood + +The entity flood determines which areas are +"outside" on the map, which are then filled in. +Flowing from side s to side !s +=============== +*/ +qboolean Portal_EntityFlood (portal_t *p, int s) +{ + if (p->nodes[0]->planenum != PLANENUM_LEAF + || p->nodes[1]->planenum != PLANENUM_LEAF) + Error ("Portal_EntityFlood: not a leaf"); + + // can never cross to a solid + if ( (p->nodes[0]->contents & CONTENTS_SOLID) + || (p->nodes[1]->contents & CONTENTS_SOLID) ) + return false; + + // can flood through everything else + return true; +} + + +//============================================================================= + +int c_tinyportals; + +/* +============= +AddPortalToNodes +============= +*/ +void AddPortalToNodes (portal_t *p, node_t *front, node_t *back) +{ + if (p->nodes[0] || p->nodes[1]) + Error ("AddPortalToNode: allready included"); + + p->nodes[0] = front; + p->next[0] = front->portals; + front->portals = p; + + p->nodes[1] = back; + p->next[1] = back->portals; + back->portals = p; +} + + +/* +============= +RemovePortalFromNode +============= +*/ +void RemovePortalFromNode (portal_t *portal, node_t *l) +{ + portal_t **pp, *t; + +// remove reference to the current portal + pp = &l->portals; + while (1) + { + t = *pp; + if (!t) + Error ("RemovePortalFromNode: portal not in leaf"); + + if ( t == portal ) + break; + + if (t->nodes[0] == l) + pp = &t->next[0]; + else if (t->nodes[1] == l) + pp = &t->next[1]; + else + Error ("RemovePortalFromNode: portal not bounding leaf"); + } + + if (portal->nodes[0] == l) + { + *pp = portal->next[0]; + portal->nodes[0] = NULL; + } + else if (portal->nodes[1] == l) + { + *pp = portal->next[1]; + portal->nodes[1] = NULL; + } +} + +//============================================================================ + +void PrintPortal (portal_t *p) +{ + int i; + winding_t *w; + + w = p->winding; + for (i=0 ; inumpoints ; i++) + printf ("(%5.0f,%5.0f,%5.0f)\n",w->p[i][0] + , w->p[i][1], w->p[i][2]); +} + +/* +================ +MakeHeadnodePortals + +The created portals will face the global outside_node +================ +*/ +#define SIDESPACE 8 +void MakeHeadnodePortals (tree_t *tree) +{ + vec3_t bounds[2]; + int i, j, n; + portal_t *p, *portals[6]; + plane_t bplanes[6], *pl; + node_t *node; + + node = tree->headnode; + +// pad with some space so there will never be null volume leafs + for (i=0 ; i<3 ; i++) + { + bounds[0][i] = tree->mins[i] - SIDESPACE; + bounds[1][i] = tree->maxs[i] + SIDESPACE; + } + + tree->outside_node.planenum = PLANENUM_LEAF; + tree->outside_node.brushlist = NULL; + tree->outside_node.portals = NULL; + tree->outside_node.contents = 0; + + for (i=0 ; i<3 ; i++) + for (j=0 ; j<2 ; j++) + { + n = j*3 + i; + + p = AllocPortal (); + portals[n] = p; + + pl = &bplanes[n]; + memset (pl, 0, sizeof(*pl)); + if (j) + { + pl->normal[i] = -1; + pl->dist = -bounds[j][i]; + } + else + { + pl->normal[i] = 1; + pl->dist = bounds[j][i]; + } + p->plane = *pl; + p->winding = BaseWindingForPlane (pl->normal, pl->dist); + AddPortalToNodes (p, node, &tree->outside_node); + } + +// clip the basewindings by all the other planes + for (i=0 ; i<6 ; i++) + { + for (j=0 ; j<6 ; j++) + { + if (j == i) + continue; + ChopWindingInPlace (&portals[i]->winding, bplanes[j].normal, bplanes[j].dist, ON_EPSILON); + } + } +} + +//=================================================== + + +/* +================ +BaseWindingForNode +================ +*/ +#define BASE_WINDING_EPSILON 0.001 +#define SPLIT_WINDING_EPSILON 0.001 + +winding_t *BaseWindingForNode (node_t *node) +{ + winding_t *w; + node_t *n; + plane_t *plane; + vec3_t normal; + vec_t dist; + + w = BaseWindingForPlane (mapplanes[node->planenum].normal + , mapplanes[node->planenum].dist); + + // clip by all the parents + for (n=node->parent ; n && w ; ) + { + plane = &mapplanes[n->planenum]; + + if (n->children[0] == node) + { // take front + ChopWindingInPlace (&w, plane->normal, plane->dist, BASE_WINDING_EPSILON); + } + else + { // take back + VectorSubtract (vec3_origin, plane->normal, normal); + dist = -plane->dist; + ChopWindingInPlace (&w, normal, dist, BASE_WINDING_EPSILON); + } + node = n; + n = n->parent; + } + + return w; +} + +//============================================================ + +qboolean WindingIsTiny (winding_t *w); + +/* +================== +MakeNodePortal + +create the new portal by taking the full plane winding for the cutting plane +and clipping it by all of parents of this node +================== +*/ +void MakeNodePortal (node_t *node) +{ + portal_t *new_portal, *p; + winding_t *w; + vec3_t normal; + float dist; + int side; + + w = BaseWindingForNode (node); + + // clip the portal by all the other portals in the node + for (p = node->portals ; p && w; p = p->next[side]) + { + if (p->nodes[0] == node) + { + side = 0; + VectorCopy (p->plane.normal, normal); + dist = p->plane.dist; + } + else if (p->nodes[1] == node) + { + side = 1; + VectorSubtract (vec3_origin, p->plane.normal, normal); + dist = -p->plane.dist; + } + else + Error ("CutNodePortals_r: mislinked portal"); + + ChopWindingInPlace (&w, normal, dist, 0.1); + } + + if (!w) + { + return; + } + + if (WindingIsTiny (w)) + { + c_tinyportals++; + FreeWinding (w); + return; + } + + + new_portal = AllocPortal (); + new_portal->plane = mapplanes[node->planenum]; + new_portal->onnode = node; + new_portal->winding = w; + AddPortalToNodes (new_portal, node->children[0], node->children[1]); +} + + +/* +============== +SplitNodePortals + +Move or split the portals that bound node so that the node's +children have portals instead of node. +============== +*/ +void SplitNodePortals (node_t *node) +{ + portal_t *p, *next_portal, *new_portal; + node_t *f, *b, *other_node; + int side; + plane_t *plane; + winding_t *frontwinding, *backwinding; + + plane = &mapplanes[node->planenum]; + f = node->children[0]; + b = node->children[1]; + + for (p = node->portals ; p ; p = next_portal) + { + if (p->nodes[0] == node) + side = 0; + else if (p->nodes[1] == node) + side = 1; + else + Error ("CutNodePortals_r: mislinked portal"); + next_portal = p->next[side]; + + other_node = p->nodes[!side]; + RemovePortalFromNode (p, p->nodes[0]); + RemovePortalFromNode (p, p->nodes[1]); + +// +// cut the portal into two portals, one on each side of the cut plane +// + ClipWindingEpsilon (p->winding, plane->normal, plane->dist, + SPLIT_WINDING_EPSILON, &frontwinding, &backwinding); + + if (frontwinding && WindingIsTiny(frontwinding)) + { + FreeWinding (frontwinding); + frontwinding = NULL; + c_tinyportals++; + } + + if (backwinding && WindingIsTiny(backwinding)) + { + FreeWinding (backwinding); + backwinding = NULL; + c_tinyportals++; + } + + if (!frontwinding && !backwinding) + { // tiny windings on both sides + continue; + } + + if (!frontwinding) + { + FreeWinding (backwinding); + if (side == 0) + AddPortalToNodes (p, b, other_node); + else + AddPortalToNodes (p, other_node, b); + continue; + } + if (!backwinding) + { + FreeWinding (frontwinding); + if (side == 0) + AddPortalToNodes (p, f, other_node); + else + AddPortalToNodes (p, other_node, f); + continue; + } + + // the winding is split + new_portal = AllocPortal (); + *new_portal = *p; + new_portal->winding = backwinding; + FreeWinding (p->winding); + p->winding = frontwinding; + + if (side == 0) + { + AddPortalToNodes (p, f, other_node); + AddPortalToNodes (new_portal, b, other_node); + } + else + { + AddPortalToNodes (p, other_node, f); + AddPortalToNodes (new_portal, other_node, b); + } + } + + node->portals = NULL; +} + + +/* +================ +CalcNodeBounds +================ +*/ +void CalcNodeBounds (node_t *node) +{ + portal_t *p; + int s; + int i; + + // calc mins/maxs for both leafs and nodes + ClearBounds (node->mins, node->maxs); + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + for (i=0 ; iwinding->numpoints ; i++) + AddPointToBounds (p->winding->p[i], node->mins, node->maxs); + } +} + + +/* +================== +MakeTreePortals_r +================== +*/ +void MakeTreePortals_r (node_t *node) +{ + int i; + + CalcNodeBounds (node); + if (node->mins[0] >= node->maxs[0]) + { + printf ("WARNING: node without a volume\n"); + } + + for (i=0 ; i<3 ; i++) + { + if (node->mins[i] < -8000 || node->maxs[i] > 8000) + { + printf ("WARNING: node with unbounded volume\n"); + break; + } + } + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + MakeTreePortals_r (node->children[0]); + MakeTreePortals_r (node->children[1]); +} + +/* +================== +MakeTreePortals +================== +*/ +void MakeTreePortals (tree_t *tree) +{ + MakeHeadnodePortals (tree); + MakeTreePortals_r (tree->headnode); +} + +/* +========================================================= + +FLOOD ENTITIES + +========================================================= +*/ + +/* +============= +FloodPortals_r +============= +*/ +void FloodPortals_r (node_t *node, int dist) +{ + portal_t *p; + int s; + + node->occupied = dist; + + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + + if (p->nodes[!s]->occupied) + continue; + + if (!Portal_EntityFlood (p, s)) + continue; + + FloodPortals_r (p->nodes[!s], dist+1); + } +} + +/* +============= +PlaceOccupant +============= +*/ +qboolean PlaceOccupant (node_t *headnode, vec3_t origin, entity_t *occupant) +{ + node_t *node; + vec_t d; + plane_t *plane; + + // find the leaf to start in + node = headnode; + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if (d >= 0) + node = node->children[0]; + else + node = node->children[1]; + } + + if (node->contents == CONTENTS_SOLID) + return false; + node->occupant = occupant; + + FloodPortals_r (node, 1); + + return true; +} + +/* +============= +FloodEntities + +Marks all nodes that can be reached by entites +============= +*/ +qboolean FloodEntities (tree_t *tree) +{ + int i; + vec3_t origin; + char *cl; + qboolean inside; + node_t *headnode; + + headnode = tree->headnode; + qprintf ("--- FloodEntities ---\n"); + inside = false; + tree->outside_node.occupied = 0; + + for (i=1 ; ioutside_node.occupied) + { + qprintf ("entity reached from outside -- no filling\n"); + } + + return (qboolean)(inside && !tree->outside_node.occupied); +} + +/* +========================================================= + +FLOOD AREAS + +========================================================= +*/ + +int c_areas; + +/* +============= +FloodAreas_r +============= +*/ +void FloodAreas_r (node_t *node) +{ + portal_t *p; + int s; + bspbrush_t *b; + entity_t *e; + + if (node->contents == CONTENTS_AREAPORTAL) + { + // this node is part of an area portal + b = node->brushlist; + e = &entities[b->original->entitynum]; + + // if the current area has allready touched this + // portal, we are done + if (e->portalareas[0] == c_areas || e->portalareas[1] == c_areas) + return; + + // note the current area as bounding the portal + if (e->portalareas[1]) + { + printf ("WARNING: areaportal entity %i touches > 2 areas\n", b->original->entitynum); + return; + } + if (e->portalareas[0]) + e->portalareas[1] = c_areas; + else + e->portalareas[0] = c_areas; + + return; + } + + if (node->area) + return; // allready got it + node->area = c_areas; + + for (p=node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); +#if 0 + if (p->nodes[!s]->occupied) + continue; +#endif + if (!Portal_EntityFlood (p, s)) + continue; + + FloodAreas_r (p->nodes[!s]); + } +} + +/* +============= +FindAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void FindAreas_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FindAreas_r (node->children[0]); + FindAreas_r (node->children[1]); + return; + } + + if (node->area) + return; // allready got it + + if (node->contents & CONTENTS_SOLID) + return; + + if (!node->occupied) + return; // not reachable by entities + + // area portals are allways only flooded into, never + // out of + if (node->contents == CONTENTS_AREAPORTAL) + return; + + c_areas++; + FloodAreas_r (node); +} + +/* +============= +SetAreaPortalAreas_r + +Just decend the tree, and for each node that hasn't had an +area set, flood fill out from there +============= +*/ +void SetAreaPortalAreas_r (node_t *node) +{ + bspbrush_t *b; + entity_t *e; + + if (node->planenum != PLANENUM_LEAF) + { + SetAreaPortalAreas_r (node->children[0]); + SetAreaPortalAreas_r (node->children[1]); + return; + } + + if (node->contents == CONTENTS_AREAPORTAL) + { + if (node->area) + return; // allready set + + b = node->brushlist; + e = &entities[b->original->entitynum]; + node->area = e->portalareas[0]; + if (!e->portalareas[1]) + { + printf ("WARNING: areaportal entity %i doesn't touch two areas\n", b->original->entitynum); + return; + } + } +} + +/* +============= +EmitAreaPortals + +============= +*/ +void EmitAreaPortals (node_t *headnode) +{ + int i, j; + entity_t *e; + dareaportal_t *dp; + + if (c_areas > MAX_MAP_AREAS) + Error ("MAX_MAP_AREAS"); + numareas = c_areas+1; + numareaportals = 1; // leave 0 as an error + + for (i=1 ; i<=c_areas ; i++) + { + dareas[i].firstareaportal = numareaportals; + for (j=0 ; jareaportalnum) + continue; + dp = &dareaportals[numareaportals]; + if (e->portalareas[0] == i) + { + dp->portalnum = e->areaportalnum; + dp->otherarea = e->portalareas[1]; + numareaportals++; + } + else if (e->portalareas[1] == i) + { + dp->portalnum = e->areaportalnum; + dp->otherarea = e->portalareas[0]; + numareaportals++; + } + } + dareas[i].numareaportals = numareaportals - dareas[i].firstareaportal; + } + + qprintf ("%5i numareas\n", numareas); + qprintf ("%5i numareaportals\n", numareaportals); +} + +/* +============= +FloodAreas + +Mark each leaf with an area, bounded by CONTENTS_AREAPORTAL +============= +*/ +void FloodAreas (tree_t *tree) +{ + qprintf ("--- FloodAreas ---\n"); + FindAreas_r (tree->headnode); + SetAreaPortalAreas_r (tree->headnode); + qprintf ("%5i areas\n", c_areas); +} + +//====================================================== + +int c_outside; +int c_inside; +int c_solid; + +void FillOutside_r (node_t *node) +{ + if (node->planenum != PLANENUM_LEAF) + { + FillOutside_r (node->children[0]); + FillOutside_r (node->children[1]); + return; + } + + // anything not reachable by an entity + // can be filled away + if (!node->occupied) + { + if (node->contents != CONTENTS_SOLID) + { + c_outside++; + node->contents = CONTENTS_SOLID; + } + else + c_solid++; + } + else + c_inside++; + +} + +/* +============= +FillOutside + +Fill all nodes that can't be reached by entities +============= +*/ +void FillOutside (node_t *headnode) +{ + c_outside = 0; + c_inside = 0; + c_solid = 0; + qprintf ("--- FillOutside ---\n"); + FillOutside_r (headnode); + qprintf ("%5i solid leafs\n", c_solid); + qprintf ("%5i leafs filled\n", c_outside); + qprintf ("%5i inside leafs\n", c_inside); +} + + +//============================================================== + +/* +============ +FindPortalSide + +Finds a brush side to use for texturing the given portal +============ +*/ +void FindPortalSide (portal_t *p) +{ + int viscontents; + bspbrush_t *bb; + mapbrush_t *brush; + node_t *n; + int i,j; + int planenum; + side_t *side, *bestside; + float dot, bestdot; + plane_t *p1, *p2; + + // decide which content change is strongest + // solid > lava > water, etc + viscontents = VisibleContents (p->nodes[0]->contents ^ p->nodes[1]->contents); + if (!viscontents) + return; + + planenum = p->onnode->planenum; + bestside = NULL; + bestdot = 0; + + for (j=0 ; j<2 ; j++) + { + n = p->nodes[j]; + p1 = &mapplanes[p->onnode->planenum]; + for (bb=n->brushlist ; bb ; bb=bb->next) + { + brush = bb->original; + if ( !(brush->contents & viscontents) ) + continue; + for (i=0 ; inumsides ; i++) + { + side = &brush->original_sides[i]; + if (side->bevel) + continue; + if (side->texinfo == TEXINFO_NODE) + continue; // non-visible + if ((side->planenum&~1) == planenum) + { // exact match + bestside = &brush->original_sides[i]; + goto gotit; + } + // see how close the match is + p2 = &mapplanes[side->planenum&~1]; + dot = DotProduct (p1->normal, p2->normal); + if (dot > bestdot) + { + bestdot = dot; + bestside = side; + } + } + } + } + +gotit: + if (!bestside) + qprintf ("WARNING: side not found for portal\n"); + + p->sidefound = true; + p->side = bestside; +} + + +/* +=============== +MarkVisibleSides_r + +=============== +*/ +void MarkVisibleSides_r (node_t *node) +{ + portal_t *p; + int s; + + if (node->planenum != PLANENUM_LEAF) + { + MarkVisibleSides_r (node->children[0]); + MarkVisibleSides_r (node->children[1]); + return; + } + + // empty leafs are never boundary leafs + if (!node->contents) + return; + + // see if there is a visible face + for (p=node->portals ; p ; p = p->next[!s]) + { + s = (p->nodes[0] == node); + if (!p->onnode) + continue; // edge of world + if (!p->sidefound) + FindPortalSide (p); + if (p->side) + p->side->visible = true; + } + +} + +/* +============= +MarkVisibleSides + +============= +*/ +void MarkVisibleSides (tree_t *tree, int startbrush, int endbrush) +{ + int i, j; + mapbrush_t *mb; + int numsides; + + qprintf ("--- MarkVisibleSides ---\n"); + + // clear all the visible flags + for (i=startbrush ; inumsides; + for (j=0 ; joriginal_sides[j].visible = false; + } + + // set visible flags on the sides that are used by portals + MarkVisibleSides_r (tree->headnode); +} + diff --git a/tools/quake2/extra/bsp/qbsp3/prtfile.c b/tools/quake2/extra/bsp/qbsp3/prtfile.c new file mode 100644 index 00000000..2a5b08f4 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/prtfile.c @@ -0,0 +1,287 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +/* +============================================================================== + +PORTAL FILE GENERATION + +Save out name.prt for qvis to read +============================================================================== +*/ + + +#define PORTALFILE "PRT1" + +FILE *pf; +int num_visclusters; // clusters the player can be in +int num_visportals; + +void WriteFloat (FILE *f, vec_t v) +{ + if ( fabs(v - Q_rint(v)) < 0.001 ) + fprintf (f,"%i ",(int)Q_rint(v)); + else + fprintf (f,"%f ",v); +} + +/* +================= +WritePortalFile_r +================= +*/ +void WritePortalFile_r (node_t *node) +{ + int i, s; + portal_t *p; + winding_t *w; + vec3_t normal; + vec_t dist; + + // decision node + if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) + { + WritePortalFile_r (node->children[0]); + WritePortalFile_r (node->children[1]); + return; + } + + if (node->contents & CONTENTS_SOLID) + return; + + for (p = node->portals ; p ; p=p->next[s]) + { + w = p->winding; + s = (p->nodes[1] == node); + if (w && p->nodes[0] == node) + { + if (!Portal_VisFlood (p)) + continue; + // write out to the file + + // sometimes planes get turned around when they are very near + // the changeover point between different axis. interpret the + // plane the same way vis will, and flip the side orders if needed + // FIXME: is this still relevent? + WindingPlane (w, normal, &dist); + if ( DotProduct (p->plane.normal, normal) < 0.99 ) + { // backwards... + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[1]->cluster, p->nodes[0]->cluster); + } + else + fprintf (pf,"%i %i %i ",w->numpoints, p->nodes[0]->cluster, p->nodes[1]->cluster); + for (i=0 ; inumpoints ; i++) + { + fprintf (pf,"("); + WriteFloat (pf, w->p[i][0]); + WriteFloat (pf, w->p[i][1]); + WriteFloat (pf, w->p[i][2]); + fprintf (pf,") "); + } + fprintf (pf,"\n"); + } + } + +} + +/* +================ +FillLeafNumbers_r + +All of the leafs under node will have the same cluster +================ +*/ +void FillLeafNumbers_r (node_t *node, int num) +{ + if (node->planenum == PLANENUM_LEAF) + { + if (node->contents & CONTENTS_SOLID) + node->cluster = -1; + else + node->cluster = num; + return; + } + node->cluster = num; + FillLeafNumbers_r (node->children[0], num); + FillLeafNumbers_r (node->children[1], num); +} + +/* +================ +NumberLeafs_r +================ +*/ +void NumberLeafs_r (node_t *node) +{ + portal_t *p; + + if (node->planenum != PLANENUM_LEAF && !node->detail_seperator) + { // decision node + node->cluster = -99; + NumberLeafs_r (node->children[0]); + NumberLeafs_r (node->children[1]); + return; + } + + // either a leaf or a detail cluster + + if ( node->contents & CONTENTS_SOLID ) + { // solid block, viewpoint never inside + node->cluster = -1; + return; + } + + FillLeafNumbers_r (node, num_visclusters); + num_visclusters++; + + // count the portals + for (p = node->portals ; p ; ) + { + if (p->nodes[0] == node) // only write out from first leaf + { + if (Portal_VisFlood (p)) + num_visportals++; + p = p->next[0]; + } + else + p = p->next[1]; + } + +} + + +/* +================ +CreateVisPortals_r +================ +*/ +void CreateVisPortals_r (node_t *node) +{ + // stop as soon as we get to a detail_seperator, which + // means that everything below is in a single cluster + if (node->planenum == PLANENUM_LEAF || node->detail_seperator ) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + CreateVisPortals_r (node->children[0]); + CreateVisPortals_r (node->children[1]); +} + +/* +================ +FinishVisPortals_r +================ +*/ +void FinishVisPortals2_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + return; + + MakeNodePortal (node); + SplitNodePortals (node); + + FinishVisPortals2_r (node->children[0]); + FinishVisPortals2_r (node->children[1]); +} + +void FinishVisPortals_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + return; + + if (node->detail_seperator) + { + FinishVisPortals2_r (node); + return; + } + + FinishVisPortals_r (node->children[0]); + FinishVisPortals_r (node->children[1]); +} + + +int clusterleaf; +void SaveClusters_r (node_t *node) +{ + if (node->planenum == PLANENUM_LEAF) + { + dleafs[clusterleaf++].cluster = node->cluster; + return; + } + SaveClusters_r (node->children[0]); + SaveClusters_r (node->children[1]); +} + +/* +================ +WritePortalFile +================ +*/ +void WritePortalFile (tree_t *tree) +{ + char filename[1024]; + node_t *headnode; + + qprintf ("--- WritePortalFile ---\n"); + + headnode = tree->headnode; + num_visclusters = 0; + num_visportals = 0; + + FreeTreePortals_r (headnode); + + MakeHeadnodePortals (tree); + + CreateVisPortals_r (headnode); + +// set the cluster field in every leaf and count the total number of portals + + NumberLeafs_r (headnode); + +// write the file + sprintf (filename, "%s.prt", source); + printf ("writing %s\n", filename); + pf = fopen (filename, "w"); + if (!pf) + Error ("Error opening %s", filename); + + fprintf (pf, "%s\n", PORTALFILE); + fprintf (pf, "%i\n", num_visclusters); + fprintf (pf, "%i\n", num_visportals); + + qprintf ("%5i visclusters\n", num_visclusters); + qprintf ("%5i visportals\n", num_visportals); + + WritePortalFile_r (headnode); + + fclose (pf); + + // we need to store the clusters out now because ordering + // issues made us do this after writebsp... + clusterleaf = 1; + SaveClusters_r (headnode); +} + diff --git a/tools/quake2/extra/bsp/qbsp3/qbsp.h b/tools/quake2/extra/bsp/qbsp3/qbsp.h new file mode 100644 index 00000000..af032e43 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/qbsp.h @@ -0,0 +1,355 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "scriplib.h" +#include "polylib.h" +#include "threads.h" +#include "bspfile.h" + +#define MAX_BRUSH_SIDES 128 +#define CLIP_EPSILON 0.1 + +#define BOGUS_RANGE 8192 + +#define TEXINFO_NODE -1 // side is allready on a node + +typedef struct plane_s +{ + vec3_t normal; + vec_t dist; + int type; + struct plane_s *hash_chain; +} plane_t; + +typedef struct +{ + vec_t shift[2]; + vec_t rotate; + vec_t scale[2]; + char name[32]; + int flags; + int value; +} brush_texture_t; + +typedef struct side_s +{ + int planenum; + int texinfo; + winding_t *winding; + struct side_s *original; // bspbrush_t sides will reference the mapbrush_t sides + int contents; // from miptex + int surf; // from miptex + qboolean visible; // choose visble planes first + qboolean tested; // this plane allready checked as a split + qboolean bevel; // don't ever use for bsp splitting +} side_t; + +typedef struct brush_s +{ + int entitynum; + int brushnum; + + int contents; + + vec3_t mins, maxs; + + int numsides; + side_t *original_sides; +} mapbrush_t; + +#define PLANENUM_LEAF -1 + +#define MAXEDGES 20 + +typedef struct face_s +{ + struct face_s *next; // on node + + // the chain of faces off of a node can be merged or split, + // but each face_t along the way will remain in the chain + // until the entire tree is freed + struct face_s *merged; // if set, this face isn't valid anymore + struct face_s *split[2]; // if set, this face isn't valid anymore + + struct portal_s *portal; + int texinfo; + int planenum; + int contents; // faces in different contents can't merge + int outputnumber; + winding_t *w; + int numpoints; + qboolean badstartvert; // tjunctions cannot be fixed without a midpoint vertex + int vertexnums[MAXEDGES]; +} face_t; + + + +typedef struct bspbrush_s +{ + struct bspbrush_s *next; + vec3_t mins, maxs; + int side, testside; // side of node during construction + mapbrush_t *original; + int numsides; + side_t sides[6]; // variably sized +} bspbrush_t; + + + +#define MAX_NODE_BRUSHES 8 +typedef struct node_s +{ + // both leafs and nodes + int planenum; // -1 = leaf node + struct node_s *parent; + vec3_t mins, maxs; // valid after portalization + bspbrush_t *volume; // one for each leaf/node + + // nodes only + qboolean detail_seperator; // a detail brush caused the split + side_t *side; // the side that created the node + struct node_s *children[2]; + face_t *faces; + + // leafs only + bspbrush_t *brushlist; // fragments of all brushes in this leaf + int contents; // OR of all brush contents + int occupied; // 1 or greater can reach entity + entity_t *occupant; // for leak file testing + int cluster; // for portalfile writing + int area; // for areaportals + struct portal_s *portals; // also on nodes during construction +} node_t; + +typedef struct portal_s +{ + plane_t plane; + node_t *onnode; // NULL = outside box + node_t *nodes[2]; // [0] = front side of plane + struct portal_s *next[2]; + winding_t *winding; + + qboolean sidefound; // false if ->side hasn't been checked + side_t *side; // NULL = non-visible + face_t *face[2]; // output face in bsp file +} portal_t; + +typedef struct +{ + node_t *headnode; + node_t outside_node; + vec3_t mins, maxs; +} tree_t; + +extern int entity_num; + +extern plane_t mapplanes[MAX_MAP_PLANES]; +extern int nummapplanes; + +extern int nummapbrushes; +extern mapbrush_t mapbrushes[MAX_MAP_BRUSHES]; + +extern vec3_t map_mins, map_maxs; + +#define MAX_MAP_SIDES (MAX_MAP_BRUSHES*6) + +extern int nummapbrushsides; +extern side_t brushsides[MAX_MAP_SIDES]; + +extern qboolean noprune; +extern qboolean nodetail; +extern qboolean fulldetail; +extern qboolean nomerge; +extern qboolean nosubdiv; +extern qboolean nowater; +extern qboolean noweld; +extern qboolean noshare; +extern qboolean notjunc; + +extern vec_t microvolume; + +extern char outbase[32]; + +extern char source[1024]; + +void LoadMapFile (char *filename); +int FindFloatPlane (vec3_t normal, vec_t dist); + +//============================================================================= + +// textures.c + +typedef struct +{ + char name[64]; + int flags; + int value; + int contents; + char animname[64]; +} textureref_t; + +#define MAX_MAP_TEXTURES 1024 + +extern textureref_t textureref[MAX_MAP_TEXTURES]; + +int FindMiptex (char *name); + +int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin); + +//============================================================================= + +void FindGCD (int *v); + +mapbrush_t *Brush_LoadEntity (entity_t *ent); +int PlaneTypeForNormal (vec3_t normal); +qboolean MakeBrushPlanes (mapbrush_t *b); +int FindIntPlane (int *inormal, int *iorigin); +void CreateBrush (int brushnum); + + +//============================================================================= + +// draw.c + +extern vec3_t draw_mins, draw_maxs; +extern qboolean drawflag; + +void Draw_ClearWindow (void); +void DrawWinding (winding_t *w); + +void GLS_BeginScene (void); +void GLS_Winding (winding_t *w, int code); +void GLS_EndScene (void); + +//============================================================================= + +// csg + +bspbrush_t *MakeBspBrushList (int startbrush, int endbrush, + vec3_t clipmins, vec3_t clipmaxs); +bspbrush_t *ChopBrushes (bspbrush_t *head); +bspbrush_t *InitialBrushList (bspbrush_t *list); +bspbrush_t *OptimizedBrushList (bspbrush_t *list); + +void WriteBrushMap (char *name, bspbrush_t *list); + +//============================================================================= + +// brushbsp + +void WriteBrushList (char *name, bspbrush_t *brush, qboolean onlyvis); + +bspbrush_t *CopyBrush (bspbrush_t *brush); + +void SplitBrush (bspbrush_t *brush, int planenum, + bspbrush_t **front, bspbrush_t **back); + +tree_t *AllocTree (void); +node_t *AllocNode (void); +bspbrush_t *AllocBrush (int numsides); +int CountBrushList (bspbrush_t *brushes); +void FreeBrush (bspbrush_t *brushes); +vec_t BrushVolume (bspbrush_t *brush); + +void BoundBrush (bspbrush_t *brush); +void FreeBrushList (bspbrush_t *brushes); + +tree_t *BrushBSP (bspbrush_t *brushlist, vec3_t mins, vec3_t maxs); + +//============================================================================= + +// portals.c + +int VisibleContents (int contents); + +void MakeHeadnodePortals (tree_t *tree); +void MakeNodePortal (node_t *node); +void SplitNodePortals (node_t *node); + +qboolean Portal_VisFlood (portal_t *p); + +qboolean FloodEntities (tree_t *tree); +void FillOutside (node_t *headnode); +void FloodAreas (tree_t *tree); +void MarkVisibleSides (tree_t *tree, int start, int end); +void FreePortal (portal_t *p); +void EmitAreaPortals (node_t *headnode); + +void MakeTreePortals (tree_t *tree); + +//============================================================================= + +// glfile.c + +void OutputWinding (winding_t *w, FILE *glview); +void WriteGLView (tree_t *tree, char *source); + +//============================================================================= + +// leakfile.c + +void LeakFile (tree_t *tree); + +//============================================================================= + +// prtfile.c + +void WritePortalFile (tree_t *tree); + +//============================================================================= + +// writebsp.c + +void SetModelNumbers (void); +void SetLightStyles (void); + +void BeginBSPFile (void); +void WriteBSP (node_t *headnode); +void EndBSPFile (void); +void BeginModel (void); +void EndModel (void); + +//============================================================================= + +// faces.c + +void MakeFaces (node_t *headnode); +void FixTjuncs (node_t *headnode); +int GetEdge2 (int v1, int v2, face_t *f); + +face_t *AllocFace (void); +void FreeFace (face_t *f); + +void MergeNodeFaces (node_t *node); + +//============================================================================= + +// tree.c + +void FreeTree (tree_t *tree); +void FreeTree_r (node_t *node); +void PrintTree_r (node_t *node, int depth); +void FreeTreePortals_r (node_t *node); +void PruneNodes_r (node_t *node); +void PruneNodes (node_t *node); diff --git a/tools/quake2/extra/bsp/qbsp3/qbsp3.c b/tools/quake2/extra/bsp/qbsp3/qbsp3.c new file mode 100644 index 00000000..1cc5b907 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/qbsp3.c @@ -0,0 +1,537 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qbsp.h" + +extern float subdivide_size; + +char source[1024]; +char name[1024]; + +vec_t microvolume = 1.0; +qboolean noprune; +qboolean glview; +qboolean nodetail; +qboolean fulldetail; +qboolean onlyents; +qboolean nomerge; +qboolean nowater; +qboolean nofill; +qboolean nocsg; +qboolean noweld; +qboolean noshare; +qboolean nosubdiv; +qboolean notjunc; +qboolean noopt; +qboolean leaktest; +qboolean verboseentities; + +char outbase[32]; + +int block_xl = -8, block_xh = 7, block_yl = -8, block_yh = 7; + +int entity_num; + + +node_t *block_nodes[10][10]; + +/* +============ +BlockTree + +============ +*/ +node_t *BlockTree (int xl, int yl, int xh, int yh) +{ + node_t *node; + vec3_t normal; + float dist; + int mid; + + if (xl == xh && yl == yh) + { + node = block_nodes[xl+5][yl+5]; + if (!node) + { // return an empty leaf + node = AllocNode (); + node->planenum = PLANENUM_LEAF; + node->contents = 0; //CONTENTS_SOLID; + return node; + } + return node; + } + + // create a seperator along the largest axis + node = AllocNode (); + + if (xh - xl > yh - yl) + { // split x axis + mid = xl + (xh-xl)/2 + 1; + normal[0] = 1; + normal[1] = 0; + normal[2] = 0; + dist = mid*1024; + node->planenum = FindFloatPlane (normal, dist); + node->children[0] = BlockTree ( mid, yl, xh, yh); + node->children[1] = BlockTree ( xl, yl, mid-1, yh); + } + else + { + mid = yl + (yh-yl)/2 + 1; + normal[0] = 0; + normal[1] = 1; + normal[2] = 0; + dist = mid*1024; + node->planenum = FindFloatPlane (normal, dist); + node->children[0] = BlockTree ( xl, mid, xh, yh); + node->children[1] = BlockTree ( xl, yl, xh, mid-1); + } + + return node; +} + +/* +============ +ProcessBlock_Thread + +============ +*/ +int brush_start, brush_end; +void ProcessBlock_Thread (int blocknum) +{ + int xblock, yblock; + vec3_t mins, maxs; + bspbrush_t *brushes; + tree_t *tree; + node_t *node; + + yblock = block_yl + blocknum / (block_xh-block_xl+1); + xblock = block_xl + blocknum % (block_xh-block_xl+1); + + qprintf ("############### block %2i,%2i ###############\n", xblock, yblock); + + mins[0] = xblock*1024; + mins[1] = yblock*1024; + mins[2] = -4096; + maxs[0] = (xblock+1)*1024; + maxs[1] = (yblock+1)*1024; + maxs[2] = 4096; + + // the makelist and chopbrushes could be cached between the passes... + brushes = MakeBspBrushList (brush_start, brush_end, mins, maxs); + if (!brushes) + { + node = AllocNode (); + node->planenum = PLANENUM_LEAF; + node->contents = CONTENTS_SOLID; + block_nodes[xblock+5][yblock+5] = node; + return; + } + + if (!nocsg) + brushes = ChopBrushes (brushes); + + tree = BrushBSP (brushes, mins, maxs); + + block_nodes[xblock+5][yblock+5] = tree->headnode; +} + +/* +============ +ProcessWorldModel + +============ +*/ +void ProcessWorldModel (void) +{ + entity_t *e; + tree_t *tree; + qboolean leaked; + qboolean optimize; + + e = &entities[entity_num]; + + brush_start = e->firstbrush; + brush_end = brush_start + e->numbrushes; + leaked = false; + + // + // perform per-block operations + // + if (block_xh * 1024 > map_maxs[0]) + block_xh = floor(map_maxs[0]/1024.0); + if ( (block_xl+1) * 1024 < map_mins[0]) + block_xl = floor(map_mins[0]/1024.0); + if (block_yh * 1024 > map_maxs[1]) + block_yh = floor(map_maxs[1]/1024.0); + if ( (block_yl+1) * 1024 < map_mins[1]) + block_yl = floor(map_mins[1]/1024.0); + + if (block_xl <-4) + block_xl = -4; + if (block_yl <-4) + block_yl = -4; + if (block_xh > 3) + block_xh = 3; + if (block_yh > 3) + block_yh = 3; + + for (optimize = false ; optimize <= true ; optimize++) + { + qprintf ("--------------------------------------------\n"); + + RunThreadsOnIndividual ((block_xh-block_xl+1)*(block_yh-block_yl+1), + !verbose, ProcessBlock_Thread); + + // + // build the division tree + // oversizing the blocks guarantees that all the boundaries + // will also get nodes. + // + + qprintf ("--------------------------------------------\n"); + + tree = AllocTree (); + tree->headnode = BlockTree (block_xl-1, block_yl-1, block_xh+1, block_yh+1); + + tree->mins[0] = (block_xl)*1024; + tree->mins[1] = (block_yl)*1024; + tree->mins[2] = map_mins[2] - 8; + + tree->maxs[0] = (block_xh+1)*1024; + tree->maxs[1] = (block_yh+1)*1024; + tree->maxs[2] = map_maxs[2] + 8; + + // + // perform the global operations + // + MakeTreePortals (tree); + + if (FloodEntities (tree)) + FillOutside (tree->headnode); + else + { + printf ("**** leaked ****\n"); + leaked = true; + LeakFile (tree); + if (leaktest) + { + printf ("--- MAP LEAKED ---\n"); + exit (0); + } + } + + MarkVisibleSides (tree, brush_start, brush_end); + if (noopt || leaked) + break; + if (!optimize) + { + FreeTree (tree); + } + } + + FloodAreas (tree); + if (glview) + WriteGLView (tree, source); + MakeFaces (tree->headnode); + FixTjuncs (tree->headnode); + + if (!noprune) + PruneNodes (tree->headnode); + + WriteBSP (tree->headnode); + + if (!leaked) + WritePortalFile (tree); + + FreeTree (tree); +} + +/* +============ +ProcessSubModel + +============ +*/ +void ProcessSubModel (void) +{ + entity_t *e; + int start, end; + tree_t *tree; + bspbrush_t *list; + vec3_t mins, maxs; + + e = &entities[entity_num]; + + start = e->firstbrush; + end = start + e->numbrushes; + + mins[0] = mins[1] = mins[2] = -4096; + maxs[0] = maxs[1] = maxs[2] = 4096; + list = MakeBspBrushList (start, end, mins, maxs); + if (!nocsg) + list = ChopBrushes (list); + tree = BrushBSP (list, mins, maxs); + MakeTreePortals (tree); + MarkVisibleSides (tree, start, end); + MakeFaces (tree->headnode); + FixTjuncs (tree->headnode); + WriteBSP (tree->headnode); + FreeTree (tree); +} + +/* +============ +ProcessModels +============ +*/ +void ProcessModels (void) +{ + BeginBSPFile (); + + for (entity_num=0 ; entity_num< num_entities ; entity_num++) + { + if (!entities[entity_num].numbrushes) + continue; + + qprintf ("############### model %i ###############\n", nummodels); + BeginModel (); + if (entity_num == 0) + ProcessWorldModel (); + else + ProcessSubModel (); + EndModel (); + + if (!verboseentities) + verbose = false; // don't bother printing submodels + } + + EndBSPFile (); +} + + +/* +============ +main +============ +*/ +int main (int argc, char **argv) +{ + int i; + double start, end; + char path[1024]; + + printf ("---- qbsp3 ----\n"); + + for (i=1 ; ivalue); + textureref[i].flags = LittleLong (mt->flags); + textureref[i].contents = LittleLong (mt->contents); + strcpy (textureref[i].animname, mt->animname); + free (mt); + } + nummiptex++; + + if (textureref[i].animname[0]) + FindMiptex (textureref[i].animname); + + return i; +} + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + vec_t dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + + + +int TexinfoForBrushTexture (plane_t *plane, brush_texture_t *bt, vec3_t origin) +{ + vec3_t vecs[2]; + int sv, tv; + vec_t ang, sinv, cosv; + vec_t ns, nt; + texinfo_t tx, *tc; + int i, j, k; + float shift[2]; + brush_texture_t anim; + int mt; + + if (!bt->name[0]) + return 0; + + memset (&tx, 0, sizeof(tx)); + strcpy (tx.texture, bt->name); + + TextureAxisFromPlane(plane, vecs[0], vecs[1]); + + shift[0] = DotProduct (origin, vecs[0]); + shift[1] = DotProduct (origin, vecs[1]); + + if (!bt->scale[0]) + bt->scale[0] = 1; + if (!bt->scale[1]) + bt->scale[1] = 1; + + +// rotate axis + if (bt->rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (bt->rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (bt->rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (bt->rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = bt->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (vecs[0][0]) + sv = 0; + else if (vecs[0][1]) + sv = 1; + else + sv = 2; + + if (vecs[1][0]) + tv = 0; + else if (vecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) + { + ns = cosv * vecs[i][sv] - sinv * vecs[i][tv]; + nt = sinv * vecs[i][sv] + cosv * vecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + tx.vecs[i][j] = vecs[i][j] / bt->scale[i]; + + tx.vecs[0][3] = bt->shift[0] + shift[0]; + tx.vecs[1][3] = bt->shift[1] + shift[1]; + tx.flags = bt->flags; + tx.value = bt->value; + + // + // find the texinfo + // + tc = texinfo; + for (i=0 ; iflags != tx.flags) + continue; + if (tc->value != tx.value) + continue; + for (j=0 ; j<2 ; j++) + { + if (strcmp (tc->texture, tx.texture)) + goto skip; + for (k=0 ; k<4 ; k++) + { + if (tc->vecs[j][k] != tx.vecs[j][k]) + goto skip; + } + } + return i; +skip:; + } + *tc = tx; + numtexinfo++; + + // load the next animation + mt = FindMiptex (bt->name); + if (textureref[mt].animname[0]) + { + anim = *bt; + strcpy (anim.name, textureref[mt].animname); + tc->nexttexinfo = TexinfoForBrushTexture (plane, &anim, origin); + } + else + tc->nexttexinfo = -1; + + + return i; +} diff --git a/tools/quake2/extra/bsp/qbsp3/tree.c b/tools/quake2/extra/bsp/qbsp3/tree.c new file mode 100644 index 00000000..a6c1f34c --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/tree.c @@ -0,0 +1,219 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "qbsp.h" + +extern int c_nodes; + +void RemovePortalFromNode (portal_t *portal, node_t *l); + +node_t *NodeForPoint (node_t *node, vec3_t origin) +{ + plane_t *plane; + vec_t d; + + while (node->planenum != PLANENUM_LEAF) + { + plane = &mapplanes[node->planenum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if (d >= 0) + node = node->children[0]; + else + node = node->children[1]; + } + + return node; +} + + + +/* +============= +FreeTreePortals_r +============= +*/ +void FreeTreePortals_r (node_t *node) +{ + portal_t *p, *nextp; + int s; + + // free children + if (node->planenum != PLANENUM_LEAF) + { + FreeTreePortals_r (node->children[0]); + FreeTreePortals_r (node->children[1]); + } + + // free portals + for (p=node->portals ; p ; p=nextp) + { + s = (p->nodes[1] == node); + nextp = p->next[s]; + + RemovePortalFromNode (p, p->nodes[!s]); + FreePortal (p); + } + node->portals = NULL; +} + +/* +============= +FreeTree_r +============= +*/ +void FreeTree_r (node_t *node) +{ + face_t *f, *nextf; + + // free children + if (node->planenum != PLANENUM_LEAF) + { + FreeTree_r (node->children[0]); + FreeTree_r (node->children[1]); + } + + // free bspbrushes + FreeBrushList (node->brushlist); + + // free faces + for (f=node->faces ; f ; f=nextf) + { + nextf = f->next; + FreeFace (f); + } + + // free the node + if (node->volume) + FreeBrush (node->volume); + + if (numthreads == 1) + c_nodes--; + free (node); +} + + +/* +============= +FreeTree +============= +*/ +void FreeTree (tree_t *tree) +{ + FreeTreePortals_r (tree->headnode); + FreeTree_r (tree->headnode); + free (tree); +} + +//=============================================================== + +void PrintTree_r (node_t *node, int depth) +{ + int i; + plane_t *plane; + bspbrush_t *bb; + + for (i=0 ; iplanenum == PLANENUM_LEAF) + { + if (!node->brushlist) + printf ("NULL\n"); + else + { + for (bb=node->brushlist ; bb ; bb=bb->next) + printf ("%i ", bb->original->brushnum); + printf ("\n"); + } + return; + } + + plane = &mapplanes[node->planenum]; + printf ("#%i (%5.2f %5.2f %5.2f):%5.2f\n", node->planenum, + plane->normal[0], plane->normal[1], plane->normal[2], + plane->dist); + PrintTree_r (node->children[0], depth+1); + PrintTree_r (node->children[1], depth+1); +} + +/* +========================================================= + +NODES THAT DON'T SEPERATE DIFFERENT CONTENTS CAN BE PRUNED + +========================================================= +*/ + +int c_pruned; + +/* +============ +PruneNodes_r +============ +*/ +void PruneNodes_r (node_t *node) +{ + bspbrush_t *b, *next; + + if (node->planenum == PLANENUM_LEAF) + return; + PruneNodes_r (node->children[0]); + PruneNodes_r (node->children[1]); + + if ( (node->children[0]->contents & CONTENTS_SOLID) + && (node->children[1]->contents & CONTENTS_SOLID) ) + { + if (node->faces) + Error ("node->faces seperating CONTENTS_SOLID"); + if (node->children[0]->faces || node->children[1]->faces) + Error ("!node->faces with children"); + + // FIXME: free stuff + node->planenum = PLANENUM_LEAF; + node->contents = CONTENTS_SOLID; + node->detail_seperator = false; + + if (node->brushlist) + Error ("PruneNodes: node->brushlist"); + + // combine brush lists + node->brushlist = node->children[1]->brushlist; + + for (b=node->children[0]->brushlist ; b ; b=next) + { + next = b->next; + b->next = node->brushlist; + node->brushlist = b; + } + + c_pruned++; + } +} + + +void PruneNodes (node_t *node) +{ + qprintf ("--- PruneNodes ---\n"); + c_pruned = 0; + PruneNodes_r (node); + qprintf ("%5i pruned nodes\n", c_pruned); +} + +//=========================================================== diff --git a/tools/quake2/extra/bsp/qbsp3/writebsp.c b/tools/quake2/extra/bsp/qbsp3/writebsp.c new file mode 100644 index 00000000..cc5c3266 --- /dev/null +++ b/tools/quake2/extra/bsp/qbsp3/writebsp.c @@ -0,0 +1,590 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "qbsp.h" + +int c_nofaces; +int c_facenodes; + + +/* +========================================================= + +ONLY SAVE OUT PLANES THAT ARE ACTUALLY USED AS NODES + +========================================================= +*/ + +int planeused[MAX_MAP_PLANES]; + +/* +============ +EmitPlanes + +There is no oportunity to discard planes, because all of the original +brushes will be saved in the map. +============ +*/ +void EmitPlanes (void) +{ + int i; + dplane_t *dp; + plane_t *mp; + int planetranslate[MAX_MAP_PLANES]; + + mp = mapplanes; + for (i=0 ; inormal, dp->normal); + dp->dist = mp->dist; + dp->type = mp->type; + numplanes++; + } +} + + +//======================================================== + +void EmitMarkFace (dleaf_t *leaf_p, face_t *f) +{ + int i; + int facenum; + + while (f->merged) + f = f->merged; + + if (f->split[0]) + { + EmitMarkFace (leaf_p, f->split[0]); + EmitMarkFace (leaf_p, f->split[1]); + return; + } + + facenum = f->outputnumber; + if (facenum == -1) + return; // degenerate face + + if (facenum < 0 || facenum >= numfaces) + Error ("Bad leafface"); + for (i=leaf_p->firstleafface ; i= MAX_MAP_LEAFFACES) + Error ("MAX_MAP_LEAFFACES"); + + dleaffaces[numleaffaces] = facenum; + numleaffaces++; + } + +} + + +/* +================== +EmitLeaf +================== +*/ +void EmitLeaf (node_t *node) +{ + dleaf_t *leaf_p; + portal_t *p; + int s; + face_t *f; + bspbrush_t *b; + int i; + int brushnum; + + // emit a leaf + if (numleafs >= MAX_MAP_LEAFS) + Error ("MAX_MAP_LEAFS"); + + leaf_p = &dleafs[numleafs]; + numleafs++; + + leaf_p->contents = node->contents; + leaf_p->cluster = node->cluster; + leaf_p->area = node->area; + + // + // write bounding box info + // + VectorCopy (node->mins, leaf_p->mins); + VectorCopy (node->maxs, leaf_p->maxs); + + // + // write the leafbrushes + // + leaf_p->firstleafbrush = numleafbrushes; + for (b=node->brushlist ; b ; b=b->next) + { + if (numleafbrushes >= MAX_MAP_LEAFBRUSHES) + Error ("MAX_MAP_LEAFBRUSHES"); + + brushnum = b->original - mapbrushes; + for (i=leaf_p->firstleafbrush ; inumleafbrushes = numleafbrushes - leaf_p->firstleafbrush; + + // + // write the leaffaces + // + if (leaf_p->contents & CONTENTS_SOLID) + return; // no leaffaces in solids + + leaf_p->firstleafface = numleaffaces; + + for (p = node->portals ; p ; p = p->next[s]) + { + s = (p->nodes[1] == node); + f = p->face[s]; + if (!f) + continue; // not a visible portal + + EmitMarkFace (leaf_p, f); + } + + leaf_p->numleaffaces = numleaffaces - leaf_p->firstleafface; +} + + +/* +================== +EmitFace +================== +*/ +void EmitFace (face_t *f) +{ + dface_t *df; + int i; + int e; + + f->outputnumber = -1; + + if (f->numpoints < 3) + { + return; // degenerated + } + if (f->merged || f->split[0] || f->split[1]) + { + return; // not a final face + } + + // save output number so leaffaces can use + f->outputnumber = numfaces; + + if (numfaces >= MAX_MAP_FACES) + Error ("numfaces == MAX_MAP_FACES"); + df = &dfaces[numfaces]; + numfaces++; + + // planenum is used by qlight, but not quake + df->planenum = f->planenum & (~1); + df->side = f->planenum & 1; + + df->firstedge = numsurfedges; + df->numedges = f->numpoints; + df->texinfo = f->texinfo; + for (i=0 ; inumpoints ; i++) + { +// e = GetEdge (f->pts[i], f->pts[(i+1)%f->numpoints], f); + e = GetEdge2 (f->vertexnums[i], f->vertexnums[(i+1)%f->numpoints], f); + if (numsurfedges >= MAX_MAP_SURFEDGES) + Error ("numsurfedges == MAX_MAP_SURFEDGES"); + dsurfedges[numsurfedges] = e; + numsurfedges++; + } +} + +/* +============ +EmitDrawingNode_r +============ +*/ +int EmitDrawNode_r (node_t *node) +{ + dnode_t *n; + face_t *f; + int i; + + if (node->planenum == PLANENUM_LEAF) + { + EmitLeaf (node); + return -numleafs; + } + + // emit a node + if (numnodes == MAX_MAP_NODES) + Error ("MAX_MAP_NODES"); + n = &dnodes[numnodes]; + numnodes++; + + VectorCopy (node->mins, n->mins); + VectorCopy (node->maxs, n->maxs); + + planeused[node->planenum]++; + planeused[node->planenum^1]++; + + if (node->planenum & 1) + Error ("WriteDrawNodes_r: odd planenum"); + n->planenum = node->planenum; + n->firstface = numfaces; + + if (!node->faces) + c_nofaces++; + else + c_facenodes++; + + for (f=node->faces ; f ; f=f->next) + EmitFace (f); + + n->numfaces = numfaces - n->firstface; + + + // + // recursively output the other nodes + // + for (i=0 ; i<2 ; i++) + { + if (node->children[i]->planenum == PLANENUM_LEAF) + { + n->children[i] = -(numleafs + 1); + EmitLeaf (node->children[i]); + } + else + { + n->children[i] = numnodes; + EmitDrawNode_r (node->children[i]); + } + } + + return n - dnodes; +} + +//========================================================= + + +/* +============ +WriteBSP +============ +*/ +void WriteBSP (node_t *headnode) +{ + int oldfaces; + + c_nofaces = 0; + c_facenodes = 0; + + qprintf ("--- WriteBSP ---\n"); + + oldfaces = numfaces; + dmodels[nummodels].headnode = EmitDrawNode_r (headnode); + EmitAreaPortals (headnode); + + qprintf ("%5i nodes with faces\n", c_facenodes); + qprintf ("%5i nodes without faces\n", c_nofaces); + qprintf ("%5i faces\n", numfaces-oldfaces); +} + +//=========================================================== + +/* +============ +SetModelNumbers +============ +*/ +void SetModelNumbers (void) +{ + int i; + int models; + char value[10]; + + models = 1; + for (i=1 ; icontents = b->contents; + db->firstside = numbrushsides; + db->numsides = b->numsides; + for (j=0 ; jnumsides ; j++) + { + if (numbrushsides == MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + cp = &dbrushsides[numbrushsides]; + numbrushsides++; + cp->planenum = b->original_sides[j].planenum; + cp->texinfo = b->original_sides[j].texinfo; + } + + // add any axis planes not contained in the brush to bevel off corners + for (x=0 ; x<3 ; x++) + for (s=-1 ; s<=1 ; s+=2) + { + // add the plane + VectorCopy (vec3_origin, normal); + normal[x] = s; + if (s == -1) + dist = -b->mins[x]; + else + dist = b->maxs[x]; + planenum = FindFloatPlane (normal, dist); + for (i=0 ; inumsides ; i++) + if (b->original_sides[i].planenum == planenum) + break; + if (i == b->numsides) + { + if (numbrushsides >= MAX_MAP_BRUSHSIDES) + Error ("MAX_MAP_BRUSHSIDES"); + + dbrushsides[numbrushsides].planenum = planenum; + dbrushsides[numbrushsides].texinfo = + dbrushsides[numbrushsides-1].texinfo; + numbrushsides++; + db->numsides++; + } + } + + } + +} + +//=========================================================== + +/* +================== +BeginBSPFile +================== +*/ +void BeginBSPFile (void) +{ + // these values may actually be initialized + // if the file existed when loaded, so clear them explicitly + nummodels = 0; + numfaces = 0; + numnodes = 0; + numbrushsides = 0; + numvertexes = 0; + numleaffaces = 0; + numleafbrushes = 0; + numsurfedges = 0; + + // edge 0 is not used, because 0 can't be negated + numedges = 1; + + // leave vertex 0 as an error + numvertexes = 1; + + // leave leaf 0 as an error + numleafs = 1; + dleafs[0].contents = CONTENTS_SOLID; +} + + +/* +============ +EndBSPFile +============ +*/ +void EndBSPFile (void) +{ + char path[1024]; + int len; + byte *buf; + + + EmitBrushes (); + EmitPlanes (); + UnparseEntities (); + + // load the pop +#if 0 + sprintf (path, "%s/pics/pop.lmp", gamedir); + len = LoadFile (path, &buf); + memcpy (dpop, buf, sizeof(dpop)); + free (buf); +#endif + + // write the map + sprintf (path, "%s.bsp", source); + printf ("Writing %s\n", path); + WriteBSPFile (path); +} + + +/* +================== +BeginModel +================== +*/ +int firstmodleaf; +extern int firstmodeledge; +extern int firstmodelface; +void BeginModel (void) +{ + dmodel_t *mod; + int start, end; + mapbrush_t *b; + int j; + entity_t *e; + vec3_t mins, maxs; + + if (nummodels == MAX_MAP_MODELS) + Error ("MAX_MAP_MODELS"); + mod = &dmodels[nummodels]; + + mod->firstface = numfaces; + + firstmodleaf = numleafs; + firstmodeledge = numedges; + firstmodelface = numfaces; + + // + // bound the brushes + // + e = &entities[entity_num]; + + start = e->firstbrush; + end = start + e->numbrushes; + ClearBounds (mins, maxs); + + for (j=start ; jnumsides) + continue; // not a real brush (origin brush) + AddPointToBounds (b->mins, mins, maxs); + AddPointToBounds (b->maxs, mins, maxs); + } + + VectorCopy (mins, mod->mins); + VectorCopy (maxs, mod->maxs); +} + + +/* +================== +EndModel +================== +*/ +void EndModel (void) +{ + dmodel_t *mod; + + mod = &dmodels[nummodels]; + + mod->numfaces = numfaces - mod->firstface; + + nummodels++; +} + diff --git a/tools/quake2/extra/bsp/qrad3/lightmap.c b/tools/quake2/extra/bsp/qrad3/lightmap.c new file mode 100644 index 00000000..e6a5aaaa --- /dev/null +++ b/tools/quake2/extra/bsp/qrad3/lightmap.c @@ -0,0 +1,1316 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "qrad.h" + +#define MAX_LSTYLES 256 + +typedef struct +{ + dface_t *faces[2]; + qboolean coplanar; +} edgeshare_t; + +edgeshare_t edgeshare[MAX_MAP_EDGES]; + +int facelinks[MAX_MAP_FACES]; +int planelinks[2][MAX_MAP_PLANES]; + +/* +============ +LinkPlaneFaces +============ +*/ +void LinkPlaneFaces (void) +{ + int i; + dface_t *f; + + f = dfaces; + for (i=0 ; iside][f->planenum]; + planelinks[f->side][f->planenum] = i; + } +} + +/* +============ +PairEdges +============ +*/ +void PairEdges (void) +{ + int i, j, k; + dface_t *f; + edgeshare_t *e; + + f = dfaces; + for (i=0 ; inumedges ; j++) + { + k = dsurfedges[f->firstedge + j]; + if (k < 0) + { + e = &edgeshare[-k]; + e->faces[1] = f; + } + else + { + e = &edgeshare[k]; + e->faces[0] = f; + } + + if (e->faces[0] && e->faces[1]) + { + // determine if coplanar + if (e->faces[0]->planenum == e->faces[1]->planenum) + e->coplanar = true; + } + } + } +} + +/* +================================================================= + + POINT TRIANGULATION + +================================================================= +*/ + +typedef struct triedge_s +{ + int p0, p1; + vec3_t normal; + vec_t dist; + struct triangle_s *tri; +} triedge_t; + +typedef struct triangle_s +{ + triedge_t *edges[3]; +} triangle_t; + +#define MAX_TRI_POINTS 1024 +#define MAX_TRI_EDGES (MAX_TRI_POINTS*6) +#define MAX_TRI_TRIS (MAX_TRI_POINTS*2) + +typedef struct +{ + int numpoints; + int numedges; + int numtris; + dplane_t *plane; + triedge_t *edgematrix[MAX_TRI_POINTS][MAX_TRI_POINTS]; + patch_t *points[MAX_TRI_POINTS]; + triedge_t edges[MAX_TRI_EDGES]; + triangle_t tris[MAX_TRI_TRIS]; +} triangulation_t; + +/* +=============== +AllocTriangulation +=============== +*/ +triangulation_t *AllocTriangulation (dplane_t *plane) +{ + triangulation_t *t; + + t = malloc(sizeof(triangulation_t)); + t->numpoints = 0; + t->numedges = 0; + t->numtris = 0; + + t->plane = plane; + +// memset (t->edgematrix, 0, sizeof(t->edgematrix)); + + return t; +} + +/* +=============== +FreeTriangulation +=============== +*/ +void FreeTriangulation (triangulation_t *tr) +{ + free (tr); +} + + +triedge_t *FindEdge (triangulation_t *trian, int p0, int p1) +{ + triedge_t *e, *be; + vec3_t v1; + vec3_t normal; + vec_t dist; + + if (trian->edgematrix[p0][p1]) + return trian->edgematrix[p0][p1]; + + if (trian->numedges > MAX_TRI_EDGES-2) + Error ("trian->numedges > MAX_TRI_EDGES-2"); + + VectorSubtract (trian->points[p1]->origin, trian->points[p0]->origin, v1); + VectorNormalize (v1, v1); + CrossProduct (v1, trian->plane->normal, normal); + dist = DotProduct (trian->points[p0]->origin, normal); + + e = &trian->edges[trian->numedges]; + e->p0 = p0; + e->p1 = p1; + e->tri = NULL; + VectorCopy (normal, e->normal); + e->dist = dist; + trian->numedges++; + trian->edgematrix[p0][p1] = e; + + be = &trian->edges[trian->numedges]; + be->p0 = p1; + be->p1 = p0; + be->tri = NULL; + VectorSubtract (vec3_origin, normal, be->normal); + be->dist = -dist; + trian->numedges++; + trian->edgematrix[p1][p0] = be; + + return e; +} + +triangle_t *AllocTriangle (triangulation_t *trian) +{ + triangle_t *t; + + if (trian->numtris >= MAX_TRI_TRIS) + Error ("trian->numtris >= MAX_TRI_TRIS"); + + t = &trian->tris[trian->numtris]; + trian->numtris++; + + return t; +} + +/* +============ +TriEdge_r +============ +*/ +void TriEdge_r (triangulation_t *trian, triedge_t *e) +{ + int i, bestp; + vec3_t v1, v2; + vec_t *p0, *p1, *p; + vec_t best, ang; + triangle_t *nt; + + if (e->tri) + return; // allready connected by someone + + // find the point with the best angle + p0 = trian->points[e->p0]->origin; + p1 = trian->points[e->p1]->origin; + best = 1.1; + for (i=0 ; i< trian->numpoints ; i++) + { + p = trian->points[i]->origin; + // a 0 dist will form a degenerate triangle + if (DotProduct(p, e->normal) - e->dist < 0) + continue; // behind edge + VectorSubtract (p0, p, v1); + VectorSubtract (p1, p, v2); + if (!VectorNormalize (v1,v1)) + continue; + if (!VectorNormalize (v2,v2)) + continue; + ang = DotProduct (v1, v2); + if (ang < best) + { + best = ang; + bestp = i; + } + } + if (best >= 1) + return; // edge doesn't match anything + + // make a new triangle + nt = AllocTriangle (trian); + nt->edges[0] = e; + nt->edges[1] = FindEdge (trian, e->p1, bestp); + nt->edges[2] = FindEdge (trian, bestp, e->p0); + for (i=0 ; i<3 ; i++) + nt->edges[i]->tri = nt; + TriEdge_r (trian, FindEdge (trian, bestp, e->p1)); + TriEdge_r (trian, FindEdge (trian, e->p0, bestp)); +} + +/* +============ +TriangulatePoints +============ +*/ +void TriangulatePoints (triangulation_t *trian) +{ + vec_t d, bestd; + vec3_t v1; + int bp1, bp2, i, j; + vec_t *p1, *p2; + triedge_t *e, *e2; + + if (trian->numpoints < 2) + return; + + // find the two closest points + bestd = 9999; + for (i=0 ; inumpoints ; i++) + { + p1 = trian->points[i]->origin; + for (j=i+1 ; jnumpoints ; j++) + { + p2 = trian->points[j]->origin; + VectorSubtract (p2, p1, v1); + d = VectorLength (v1); + if (d < bestd) + { + bestd = d; + bp1 = i; + bp2 = j; + } + } + } + + e = FindEdge (trian, bp1, bp2); + e2 = FindEdge (trian, bp2, bp1); + TriEdge_r (trian, e); + TriEdge_r (trian, e2); +} + +/* +=============== +AddPointToTriangulation +=============== +*/ +void AddPointToTriangulation (patch_t *patch, triangulation_t *trian) +{ + int pnum; + + pnum = trian->numpoints; + if (pnum == MAX_TRI_POINTS) + Error ("trian->numpoints == MAX_TRI_POINTS"); + trian->points[pnum] = patch; + trian->numpoints++; +} + +/* +=============== +LerpTriangle +=============== +*/ +void LerpTriangle (triangulation_t *trian, triangle_t *t, vec3_t point, vec3_t color) +{ + patch_t *p1, *p2, *p3; + vec3_t base, d1, d2; + float x, y, x1, y1, x2, y2; + + p1 = trian->points[t->edges[0]->p0]; + p2 = trian->points[t->edges[1]->p0]; + p3 = trian->points[t->edges[2]->p0]; + + VectorCopy (p1->totallight, base); + VectorSubtract (p2->totallight, base, d1); + VectorSubtract (p3->totallight, base, d2); + + x = DotProduct (point, t->edges[0]->normal) - t->edges[0]->dist; + y = DotProduct (point, t->edges[2]->normal) - t->edges[2]->dist; + + x1 = 0; + y1 = DotProduct (p2->origin, t->edges[2]->normal) - t->edges[2]->dist; + + x2 = DotProduct (p3->origin, t->edges[0]->normal) - t->edges[0]->dist; + y2 = 0; + + if (fabs(y1)edges[i]; + d = DotProduct (e->normal, point) - e->dist; + if (d < 0) + return false; // not inside + } + + return true; +} + +/* +=============== +SampleTriangulation +=============== +*/ +void SampleTriangulation (vec3_t point, triangulation_t *trian, vec3_t color) +{ + triangle_t *t; + triedge_t *e; + vec_t d, best; + patch_t *p0, *p1; + vec3_t v1, v2; + int i, j; + + if (trian->numpoints == 0) + { + VectorClear (color); + return; + } + if (trian->numpoints == 1) + { + VectorCopy (trian->points[0]->totallight, color); + return; + } + + // search for triangles + for (t = trian->tris, j=0 ; j < trian->numtris ; t++, j++) + { + if (!PointInTriangle (point, t)) + continue; + + // this is it + LerpTriangle (trian, t, point, color); + return; + } + + // search for exterior edge + for (e=trian->edges, j=0 ; j< trian->numedges ; e++, j++) + { + if (e->tri) + continue; // not an exterior edge + + d = DotProduct (point, e->normal) - e->dist; + if (d < 0) + continue; // not in front of edge + + p0 = trian->points[e->p0]; + p1 = trian->points[e->p1]; + + VectorSubtract (p1->origin, p0->origin, v1); + VectorNormalize (v1, v1); + VectorSubtract (point, p0->origin, v2); + d = DotProduct (v2, v1); + if (d < 0) + continue; + if (d > 1) + continue; + for (i=0 ; i<3 ; i++) + color[i] = p0->totallight[i] + d * (p1->totallight[i] - p0->totallight[i]); + return; + } + + // search for nearest point + best = 99999; + p1 = NULL; + for (j=0 ; jnumpoints ; j++) + { + p0 = trian->points[j]; + VectorSubtract (point, p0->origin, v1); + d = VectorLength (v1); + if (d < best) + { + best = d; + p1 = p0; + } + } + + if (!p1) + Error ("SampleTriangulation: no points"); + + VectorCopy (p1->totallight, color); +} + +/* +================================================================= + + LIGHTMAP SAMPLE GENERATION + +================================================================= +*/ + + +#define SINGLEMAP (64*64*4) + +typedef struct +{ + vec_t facedist; + vec3_t facenormal; + + int numsurfpt; + vec3_t surfpt[SINGLEMAP]; + + vec3_t modelorg; // for origined bmodels + + vec3_t texorg; + vec3_t worldtotex[2]; // s = (world - texorg) . worldtotex[0] + vec3_t textoworld[2]; // world = texorg + s * textoworld[0] + + vec_t exactmins[2], exactmaxs[2]; + + int texmins[2], texsize[2]; + int surfnum; + dface_t *face; +} lightinfo_t; + + +/* +================ +CalcFaceExtents + +Fills in s->texmins[] and s->texsize[] +also sets exactmins[] and exactmaxs[] +================ +*/ +void CalcFaceExtents (lightinfo_t *l) +{ + dface_t *s; + vec_t mins[2], maxs[2], val; + int i,j, e; + dvertex_t *v; + texinfo_t *tex; + vec3_t vt; + + s = l->face; + + mins[0] = mins[1] = 999999; + maxs[0] = maxs[1] = -99999; + + tex = &texinfo[s->texinfo]; + + for (i=0 ; inumedges ; i++) + { + e = dsurfedges[s->firstedge+i]; + if (e >= 0) + v = dvertexes + dedges[e].v[0]; + else + v = dvertexes + dedges[-e].v[1]; + +// VectorAdd (v->point, l->modelorg, vt); + VectorCopy (v->point, vt); + + for (j=0 ; j<2 ; j++) + { + val = DotProduct (vt, tex->vecs[j]) + tex->vecs[j][3]; + if (val < mins[j]) + mins[j] = val; + if (val > maxs[j]) + maxs[j] = val; + } + } + + for (i=0 ; i<2 ; i++) + { + l->exactmins[i] = mins[i]; + l->exactmaxs[i] = maxs[i]; + + mins[i] = floor(mins[i]/16); + maxs[i] = ceil(maxs[i]/16); + + l->texmins[i] = mins[i]; + l->texsize[i] = maxs[i] - mins[i]; + if (l->texsize[0] * l->texsize[1] > SINGLEMAP/4) // div 4 for extrasamples + Error ("Surface to large to map"); + } +} + +/* +================ +CalcFaceVectors + +Fills in texorg, worldtotex. and textoworld +================ +*/ +void CalcFaceVectors (lightinfo_t *l) +{ + texinfo_t *tex; + int i, j; + vec3_t texnormal; + vec_t distscale; + vec_t dist, len; + int w, h; + + tex = &texinfo[l->face->texinfo]; + +// convert from float to double + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + l->worldtotex[i][j] = tex->vecs[i][j]; + +// calculate a normal to the texture axis. points can be moved along this +// without changing their S/T + texnormal[0] = tex->vecs[1][1]*tex->vecs[0][2] + - tex->vecs[1][2]*tex->vecs[0][1]; + texnormal[1] = tex->vecs[1][2]*tex->vecs[0][0] + - tex->vecs[1][0]*tex->vecs[0][2]; + texnormal[2] = tex->vecs[1][0]*tex->vecs[0][1] + - tex->vecs[1][1]*tex->vecs[0][0]; + VectorNormalize (texnormal, texnormal); + +// flip it towards plane normal + distscale = DotProduct (texnormal, l->facenormal); + if (!distscale) + { + qprintf ("WARNING: Texture axis perpendicular to face\n"); + distscale = 1; + } + if (distscale < 0) + { + distscale = -distscale; + VectorSubtract (vec3_origin, texnormal, texnormal); + } + +// distscale is the ratio of the distance along the texture normal to +// the distance along the plane normal + distscale = 1/distscale; + + for (i=0 ; i<2 ; i++) + { + len = VectorLength (l->worldtotex[i]); + dist = DotProduct (l->worldtotex[i], l->facenormal); + dist *= distscale; + VectorMA (l->worldtotex[i], -dist, texnormal, l->textoworld[i]); + VectorScale (l->textoworld[i], (1/len)*(1/len), l->textoworld[i]); + } + + +// calculate texorg on the texture plane + for (i=0 ; i<3 ; i++) + l->texorg[i] = -tex->vecs[0][3]* l->textoworld[0][i] - tex->vecs[1][3] * l->textoworld[1][i]; + +// project back to the face plane + dist = DotProduct (l->texorg, l->facenormal) - l->facedist - 1; + dist *= distscale; + VectorMA (l->texorg, -dist, texnormal, l->texorg); + + // compensate for org'd bmodels + VectorAdd (l->texorg, l->modelorg, l->texorg); + + // total sample count + h = l->texsize[1]+1; + w = l->texsize[0]+1; + l->numsurfpt = w * h; +} + +/* +================= +CalcPoints + +For each texture aligned grid point, back project onto the plane +to get the world xyz value of the sample point +================= +*/ +void CalcPoints (lightinfo_t *l, float sofs, float tofs) +{ + int i; + int s, t, j; + int w, h, step; + vec_t starts, startt, us, ut; + vec_t *surf; + vec_t mids, midt; + vec3_t facemid; + dleaf_t *leaf; + + surf = l->surfpt[0]; + mids = (l->exactmaxs[0] + l->exactmins[0])/2; + midt = (l->exactmaxs[1] + l->exactmins[1])/2; + + for (j=0 ; j<3 ; j++) + facemid[j] = l->texorg[j] + l->textoworld[0][j]*mids + l->textoworld[1][j]*midt; + + h = l->texsize[1]+1; + w = l->texsize[0]+1; + l->numsurfpt = w * h; + + starts = l->texmins[0]*16; + startt = l->texmins[1]*16; + step = 16; + + + for (t=0 ; ttexorg[j] + l->textoworld[0][j]*us + + l->textoworld[1][j]*ut; + + leaf = PointInLeaf (surf); + if (leaf->contents != CONTENTS_SOLID) + { + if (!TestLine_r (0, facemid, surf)) + break; // got it + } + + // nudge it + if (i & 1) + { + if (us > mids) + { + us -= 8; + if (us < mids) + us = mids; + } + else + { + us += 8; + if (us > mids) + us = mids; + } + } + else + { + if (ut > midt) + { + ut -= 8; + if (ut < midt) + ut = midt; + } + else + { + ut += 8; + if (ut > midt) + ut = midt; + } + } + } + } + } + +} + + +//============================================================== + + + +#define MAX_STYLES 32 +typedef struct +{ + int numsamples; + float *origins; + int numstyles; + int stylenums[MAX_STYLES]; + float *samples[MAX_STYLES]; +} facelight_t; + +directlight_t *directlights[MAX_MAP_LEAFS]; +facelight_t facelight[MAX_MAP_FACES]; +int numdlights; + +/* +================== +FindTargetEntity +================== +*/ +entity_t *FindTargetEntity (char *target) +{ + int i; + char *n; + + for (i=0 ; itotallight[0] < DIRECT_LIGHT + && p->totallight[1] < DIRECT_LIGHT + && p->totallight[2] < DIRECT_LIGHT) + continue; + + numdlights++; + dl = malloc(sizeof(directlight_t)); + memset (dl, 0, sizeof(*dl)); + + VectorCopy (p->origin, dl->origin); + + leaf = PointInLeaf (dl->origin); + cluster = leaf->cluster; + dl->next = directlights[cluster]; + directlights[cluster] = dl; + + dl->type = emit_surface; + VectorCopy (p->plane->normal, dl->normal); + + dl->intensity = ColorNormalize (p->totallight, dl->color); + dl->intensity *= p->area * direct_scale; + VectorClear (p->totallight); // all sent now + } + + // + // entities + // + for (i=0 ; iorigin); + dl->style = FloatForKey (e, "_style"); + if (!dl->style) + dl->style = FloatForKey (e, "style"); + if (dl->style < 0 || dl->style >= MAX_LSTYLES) + dl->style = 0; + + leaf = PointInLeaf (dl->origin); + cluster = leaf->cluster; + + dl->next = directlights[cluster]; + directlights[cluster] = dl; + + intensity = FloatForKey (e, "light"); + if (!intensity) + intensity = FloatForKey (e, "_light"); + if (!intensity) + intensity = 300; + _color = ValueForKey (e, "_color"); + if (_color && _color[1]) + { + sscanf (_color, "%f %f %f", &dl->color[0],&dl->color[1],&dl->color[2]); + ColorNormalize (dl->color, dl->color); + } + else + dl->color[0] = dl->color[1] = dl->color[2] = 1.0; + dl->intensity = intensity*entity_scale; + dl->type = emit_point; + + target = ValueForKey (e, "target"); + + if (!strcmp (name, "light_spot") || target[0]) + { + dl->type = emit_spotlight; + dl->stopdot = FloatForKey (e, "_cone"); + if (!dl->stopdot) + dl->stopdot = 10; + dl->stopdot = cos(dl->stopdot/180*3.14159); + if (target[0]) + { // point towards target + e2 = FindTargetEntity (target); + if (!e2) + printf ("WARNING: light at (%i %i %i) has missing target\n", + (int)dl->origin[0], (int)dl->origin[1], (int)dl->origin[2]); + else + { + GetVectorForKey (e2, "origin", dest); + VectorSubtract (dest, dl->origin, dl->normal); + VectorNormalize (dl->normal, dl->normal); + } + } + else + { // point down angle + angle = FloatForKey (e, "angle"); + if (angle == ANGLE_UP) + { + dl->normal[0] = dl->normal[1] = 0; + dl->normal[2] = 1; + } + else if (angle == ANGLE_DOWN) + { + dl->normal[0] = dl->normal[1] = 0; + dl->normal[2] = -1; + } + else + { + dl->normal[2] = 0; + dl->normal[0] = cos (angle/180*3.14159); + dl->normal[1] = sin (angle/180*3.14159); + } + } + } + } + + qprintf ("%i direct lights\n", numdlights); +} + +/* +============= +GatherSampleLight + +Lightscale is the normalizer for multisampling +============= +*/ +void GatherSampleLight (vec3_t pos, vec3_t normal, + float **styletable, int offset, int mapsize, float lightscale) +{ + int i; + directlight_t *l; + byte pvs[(MAX_MAP_LEAFS+7)/8]; + vec3_t delta; + float dot, dot2; + float dist; + float scale; + float *dest; + + // get the PVS for the pos to limit the number of checks + if (!PvsForOrigin (pos, pvs)) + { + return; + } + + for (i = 0 ; inumclusters ; i++) + { + if ( ! (pvs[ i>>3] & (1<<(i&7))) ) + continue; + + for (l=directlights[i] ; l ; l=l->next) + { + VectorSubtract (l->origin, pos, delta); + dist = VectorNormalize (delta, delta); + dot = DotProduct (delta, normal); + if (dot <= 0.001) + continue; // behind sample surface + + switch (l->type) + { + case emit_point: + // linear falloff + scale = (l->intensity - dist) * dot; + break; + + case emit_surface: + dot2 = -DotProduct (delta, l->normal); + if (dot2 <= 0.001) + goto skipadd; // behind light surface + scale = (l->intensity / (dist*dist) ) * dot * dot2; + break; + + case emit_spotlight: + // linear falloff + dot2 = -DotProduct (delta, l->normal); + if (dot2 <= l->stopdot) + goto skipadd; // outside light cone + scale = (l->intensity - dist) * dot; + break; + default: + Error ("Bad l->type"); + } + + if (TestLine_r (0, pos, l->origin)) + continue; // occluded + + if (scale <= 0) + continue; + + // if this style doesn't have a table yet, allocate one + if (!styletable[l->style]) + { + styletable[l->style] = malloc (mapsize); + memset (styletable[l->style], 0, mapsize); + } + + dest = styletable[l->style] + offset; + // add some light to it + VectorMA (dest, scale*lightscale, l->color, dest); + +skipadd: ; + } + } + +} + +/* +============= +AddSampleToPatch + +Take the sample's collected light and +add it back into the apropriate patch +for the radiosity pass. + +The sample is added to all patches that might include +any part of it. They are counted and averaged, so it +doesn't generate extra light. +============= +*/ +void AddSampleToPatch (vec3_t pos, vec3_t color, int facenum) +{ + patch_t *patch; + vec3_t mins, maxs; + int i; + + if (numbounce == 0) + return; + if (color[0] + color[1] + color[2] < 3) + return; + + for (patch = face_patches[facenum] ; patch ; patch=patch->next) + { + // see if the point is in this patch (roughly) + WindingBounds (patch->winding, mins, maxs); + for (i=0 ; i<3 ; i++) + { + if (mins[i] > pos[i] + 16) + goto nextpatch; + if (maxs[i] < pos[i] - 16) + goto nextpatch; + } + + // add the sample to the patch + patch->samples++; + VectorAdd (patch->samplelight, color, patch->samplelight); +nextpatch:; + } + +} + + +/* +============= +BuildFacelights +============= +*/ +float sampleofs[5][2] = +{ {0,0}, {-0.25, -0.25}, {0.25, -0.25}, {0.25, 0.25}, {-0.25, 0.25} }; + + +void BuildFacelights (int facenum) +{ + dface_t *f; + lightinfo_t l[5]; + float *styletable[MAX_LSTYLES]; + int i, j; + float *spot; + patch_t *patch; + int numsamples; + int tablesize; + facelight_t *fl; + + f = &dfaces[facenum]; + + if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) ) + return; // non-lit texture + + memset (styletable,0, sizeof(styletable)); + + if (extrasamples) + numsamples = 5; + else + numsamples = 1; + for (i=0 ; iplanenum].normal, l[i].facenormal); + l[i].facedist = dplanes[f->planenum].dist; + if (f->side) + { + VectorSubtract (vec3_origin, l[i].facenormal, l[i].facenormal); + l[i].facedist = -l[i].facedist; + } + + // get the origin offset for rotating bmodels + VectorCopy (face_offset[facenum], l[i].modelorg); + + CalcFaceVectors (&l[i]); + CalcFaceExtents (&l[i]); + CalcPoints (&l[i], sampleofs[i][0], sampleofs[i][1]); + } + + tablesize = l[0].numsurfpt * sizeof(vec3_t); + styletable[0] = malloc(tablesize); + memset (styletable[0], 0, tablesize); + + fl = &facelight[facenum]; + fl->numsamples = l[0].numsurfpt; + fl->origins = malloc (tablesize); + memcpy (fl->origins, l[0].surfpt, tablesize); + + for (i=0 ; inext) + { + if (patch->samples) + { + VectorScale (patch->samplelight, 1.0/patch->samples, patch->samplelight); + } + else + { +// printf ("patch with no samples\n"); + } + } + + for (i=0 ; inumstyles == MAX_STYLES) + break; + fl->samples[fl->numstyles] = styletable[i]; + fl->stylenums[fl->numstyles] = i; + fl->numstyles++; + } + + // the light from DIRECT_LIGHTS is sent out, but the + // texture itself should still be full bright + + if (face_patches[facenum]->baselight[0] >= DIRECT_LIGHT || + face_patches[facenum]->baselight[1] >= DIRECT_LIGHT || + face_patches[facenum]->baselight[2] >= DIRECT_LIGHT + ) + { + spot = fl->samples[0]; + for (i=0 ; ibaselight, spot); + } + } +} + + +/* +============= +FinalLightFace + +Add the indirect lighting on top of the direct +lighting and save into final map format +============= +*/ +void FinalLightFace (int facenum) +{ + dface_t *f; + int i, j, k, st; + vec3_t lb; + patch_t *patch; + triangulation_t *trian; + facelight_t *fl; + float minlight; + float max, newmax; + byte *dest; + int pfacenum; + vec3_t facemins, facemaxs; + + f = &dfaces[facenum]; + fl = &facelight[facenum]; + + if ( texinfo[f->texinfo].flags & (SURF_WARP|SURF_SKY) ) + return; // non-lit texture + + ThreadLock (); + f->lightofs = lightdatasize; + lightdatasize += fl->numstyles*(fl->numsamples*3); + +// add green sentinals between lightmaps +#if 0 +lightdatasize += 64*3; +for (i=0 ; i<64 ; i++) +dlightdata[lightdatasize-(i+1)*3 + 1] = 255; +#endif + + if (lightdatasize > MAX_MAP_LIGHTING) + Error ("MAX_MAP_LIGHTING"); + ThreadUnlock (); + + f->styles[0] = 0; + f->styles[1] = f->styles[2] = f->styles[3] = 0xff; + + // + // set up the triangulation + // + if (numbounce > 0) + { + ClearBounds (facemins, facemaxs); + for (i=0 ; inumedges ; i++) + { + int ednum; + + ednum = dsurfedges[f->firstedge+i]; + if (ednum >= 0) + AddPointToBounds (dvertexes[dedges[ednum].v[0]].point, + facemins, facemaxs); + else + AddPointToBounds (dvertexes[dedges[-ednum].v[1]].point, + facemins, facemaxs); + } + + trian = AllocTriangulation (&dplanes[f->planenum]); + + // for all faces on the plane, add the nearby patches + // to the triangulation + for (pfacenum = planelinks[f->side][f->planenum] + ; pfacenum ; pfacenum = facelinks[pfacenum]) + { + for (patch = face_patches[pfacenum] ; patch ; patch=patch->next) + { + for (i=0 ; i < 3 ; i++) + { + if (facemins[i] - patch->origin[i] > subdiv*2) + break; + if (patch->origin[i] - facemaxs[i] > subdiv*2) + break; + } + if (i != 3) + continue; // not needed for this face + AddPointToTriangulation (patch, trian); + } + } + for (i=0 ; inumpoints ; i++) + memset (trian->edgematrix[i], 0, trian->numpoints*sizeof(trian->edgematrix[0][0]) ); + TriangulatePoints (trian); + } + + // + // sample the triangulation + // + + // _minlight allows models that have faces that would not be + // illuminated to receive a mottled light pattern instead of + // black + minlight = FloatForKey (face_entity[facenum], "_minlight") * 128; + + dest = &dlightdata[f->lightofs]; + + if (fl->numstyles > MAXLIGHTMAPS) + { + fl->numstyles = MAXLIGHTMAPS; + printf ("face with too many lightstyles: (%f %f %f)\n", + face_patches[facenum]->origin[0], + face_patches[facenum]->origin[1], + face_patches[facenum]->origin[2] + ); + } + + for (st=0 ; stnumstyles ; st++) + { + f->styles[st] = fl->stylenums[st]; + for (j=0 ; jnumsamples ; j++) + { + VectorCopy ( (fl->samples[st]+j*3), lb); + if (numbounce > 0 && st == 0) + { + vec3_t add; + + SampleTriangulation (fl->origins + j*3, trian, add); + VectorAdd (lb, add, lb); + } + // add an ambient term if desired + lb[0] += ambient; + lb[1] += ambient; + lb[2] += ambient; + + VectorScale (lb, lightscale, lb); + + // we need to clamp without allowing hue to change + for (k=0 ; k<3 ; k++) + if (lb[k] < 1) + lb[k] = 1; + max = lb[0]; + if (lb[1] > max) + max = lb[1]; + if (lb[2] > max) + max = lb[2]; + newmax = max; + if (newmax < 0) + newmax = 0; // roundoff problems + if (newmax < minlight) + { + newmax = minlight + (rand()%48); + } + if (newmax > maxlight) + newmax = maxlight; + + for (k=0 ; k<3 ; k++) + { + *dest++ = lb[k]*newmax/max; + } + } + } + + if (numbounce > 0) + FreeTriangulation (trian); +} diff --git a/tools/quake2/extra/bsp/qrad3/makefile b/tools/quake2/extra/bsp/qrad3/makefile new file mode 100644 index 00000000..4fb26c14 --- /dev/null +++ b/tools/quake2/extra/bsp/qrad3/makefile @@ -0,0 +1,77 @@ + +CFLAGS = -c +LDFLAGS = +ODIR = baddir + +EXEBASE = qrad3 +EXE = $(ODIR)/qrad3 +all: $(EXE) + +_next: + make "CFLAGS = -c -g -I../../common" "ODIR = next" + +_irix: + make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix" + +_irixdebug: + make "CFLAGS = -c -g -I../../common -Xcpluscomm" "LDFLAGS = " "ODIR = irix" + +_irixinst: + make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix" + cp irix/$(EXEBASE) /limbo/quake2/bin_irix + +_irixclean: + rm -f irix/*.o irix/$(EXEBASE) + +_osf: + make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads" "ODIR = osf" + +clean: + rm -f irix/*.o irix/$(EXEBASE) + +install: + cp irix/$(EXEBASE) /limbo/quake2/bin_irix + + +FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/lbmlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/polylib.o $(ODIR)/qrad3.o $(ODIR)/threads.o $(ODIR)/trace.o $(ODIR)/lightmap.o $(ODIR)/patches.o + +$(EXE) : $(FILES) + cc -o $(EXE) $(LDFLAGS) $(FILES) -lm + +$(ODIR)/qrad3.o : qrad3.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/patches.o : patches.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/trace.o : trace.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/vismat.o : vismat.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/lightmap.o : lightmap.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i + +$(ODIR)/cmdlib.o : ../../common/cmdlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/lbmlib.o : ../../common/lbmlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/mathlib.o : ../../common/mathlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/polylib.o : ../../common/polylib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/scriplib.o : ../../common/scriplib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/threads.o : ../../common/threads.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/bspfile.o : ../../common/bspfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i diff --git a/tools/quake2/extra/bsp/qrad3/patches.c b/tools/quake2/extra/bsp/qrad3/patches.c new file mode 100644 index 00000000..fbae0c32 --- /dev/null +++ b/tools/quake2/extra/bsp/qrad3/patches.c @@ -0,0 +1,515 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qrad.h" + +vec3_t texture_reflectivity[MAX_MAP_TEXINFO]; + +/* +=================================================================== + + TEXTURE LIGHT VALUES + +=================================================================== +*/ + +/* +====================== +CalcTextureReflectivity +====================== +*/ +void CalcTextureReflectivity (void) +{ + int i; + int j, k, texels; + int color[3]; + int texel; + byte *palette; + char path[1024]; + float r, scale; + miptex_t *mt; + + sprintf (path, "%spics/colormap.pcx", gamedir); + + // get the game palette + Load256Image (path, NULL, &palette, NULL, NULL); + + // allways set index 0 even if no textures + texture_reflectivity[0][0] = 0.5; + texture_reflectivity[0][1] = 0.5; + texture_reflectivity[0][2] = 0.5; + + for (i=0 ; iwidth)*LittleLong(mt->height); + color[0] = color[1] = color[2] = 0; + + for (j=0 ; joffsets[0]) + j]; + for (k=0 ; k<3 ; k++) + color[k] += palette[texel*3+k]; + } + + for (j=0 ; j<3 ; j++) + { + r = color[j]/texels/255.0; + texture_reflectivity[i][j] = r; + } + // scale the reflectivity up, because the textures are + // so dim + scale = ColorNormalize (texture_reflectivity[i], + texture_reflectivity[i]); + if (scale < 0.5) + { + scale *= 2; + VectorScale (texture_reflectivity[i], scale, texture_reflectivity[i]); + } +#if 0 +texture_reflectivity[i][0] = 0.5; +texture_reflectivity[i][1] = 0.5; +texture_reflectivity[i][2] = 0.5; +#endif + } +} + +/* +======================================================================= + +MAKE FACES + +======================================================================= +*/ + +/* +============= +WindingFromFace +============= +*/ +winding_t *WindingFromFace (dface_t *f) +{ + int i; + int se; + dvertex_t *dv; + int v; + winding_t *w; + + w = AllocWinding (f->numedges); + w->numpoints = f->numedges; + + for (i=0 ; inumedges ; i++) + { + se = dsurfedges[f->firstedge + i]; + if (se < 0) + v = dedges[-se].v[1]; + else + v = dedges[se].v[0]; + + dv = &dvertexes[v]; + VectorCopy (dv->point, w->p[i]); + } + + RemoveColinearPoints (w); + + return w; +} + +/* +============= +BaseLightForFace +============= +*/ +void BaseLightForFace (dface_t *f, vec3_t color) +{ + texinfo_t *tx; + + // + // check for light emited by texture + // + tx = &texinfo[f->texinfo]; + if (!(tx->flags & SURF_LIGHT) || tx->value == 0) + { + VectorClear (color); + return; + } + + VectorScale (texture_reflectivity[f->texinfo], tx->value, color); +} + +qboolean IsSky (dface_t *f) +{ + texinfo_t *tx; + + tx = &texinfo[f->texinfo]; + if (tx->flags & SURF_SKY) + return true; + return false; +} + +/* +============= +MakePatchForFace +============= +*/ +float totalarea; +void MakePatchForFace (int fn, winding_t *w) +{ + dface_t *f; + float area; + patch_t *patch; + dplane_t *pl; + int i; + vec3_t color; + dleaf_t *leaf; + + f = &dfaces[fn]; + + area = WindingArea (w); + totalarea += area; + + patch = &patches[num_patches]; + if (num_patches == MAX_PATCHES) + Error ("num_patches == MAX_PATCHES"); + patch->next = face_patches[fn]; + face_patches[fn] = patch; + + patch->winding = w; + + if (f->side) + patch->plane = &backplanes[f->planenum]; + else + patch->plane = &dplanes[f->planenum]; + if (face_offset[fn][0] || face_offset[fn][1] || face_offset[fn][2] ) + { // origin offset faces must create new planes + if (numplanes + fakeplanes >= MAX_MAP_PLANES) + Error ("numplanes + fakeplanes >= MAX_MAP_PLANES"); + pl = &dplanes[numplanes + fakeplanes]; + fakeplanes++; + + *pl = *(patch->plane); + pl->dist += DotProduct (face_offset[fn], pl->normal); + patch->plane = pl; + } + + WindingCenter (w, patch->origin); + VectorAdd (patch->origin, patch->plane->normal, patch->origin); + leaf = PointInLeaf(patch->origin); + patch->cluster = leaf->cluster; + if (patch->cluster == -1) + qprintf ("patch->cluster == -1\n"); + + patch->area = area; + if (patch->area <= 1) + patch->area = 1; + patch->sky = IsSky (f); + + VectorCopy (texture_reflectivity[f->texinfo], patch->reflectivity); + + // non-bmodel patches can emit light + if (fn < dmodels[0].numfaces) + { + BaseLightForFace (f, patch->baselight); + + ColorNormalize (patch->reflectivity, color); + + for (i=0 ; i<3 ; i++) + patch->baselight[i] *= color[i]; + + VectorCopy (patch->baselight, patch->totallight); + } + num_patches++; +} + + +entity_t *EntityForModel (int modnum) +{ + int i; + char *s; + char name[16]; + + sprintf (name, "*%i", modnum); + // search the entities for one using modnum + for (i=0 ; inumfaces ; j++) + { + fn = mod->firstface + j; + face_entity[fn] = ent; + VectorCopy (origin, face_offset[fn]); + f = &dfaces[fn]; + w = WindingFromFace (f); + for (k=0 ; knumpoints ; k++) + { + VectorAdd (w->p[k], origin, w->p[k]); + } + MakePatchForFace (fn, w); + } + } + + qprintf ("%i sqaure feet\n", (int)(totalarea/64)); +} + +/* +======================================================================= + +SUBDIVIDE + +======================================================================= +*/ + +void FinishSplit (patch_t *patch, patch_t *newp) +{ + dleaf_t *leaf; + + VectorCopy (patch->baselight, newp->baselight); + VectorCopy (patch->totallight, newp->totallight); + VectorCopy (patch->reflectivity, newp->reflectivity); + newp->plane = patch->plane; + newp->sky = patch->sky; + + patch->area = WindingArea (patch->winding); + newp->area = WindingArea (newp->winding); + + if (patch->area <= 1) + patch->area = 1; + if (newp->area <= 1) + newp->area = 1; + + WindingCenter (patch->winding, patch->origin); + VectorAdd (patch->origin, patch->plane->normal, patch->origin); + leaf = PointInLeaf(patch->origin); + patch->cluster = leaf->cluster; + if (patch->cluster == -1) + qprintf ("patch->cluster == -1\n"); + + WindingCenter (newp->winding, newp->origin); + VectorAdd (newp->origin, newp->plane->normal, newp->origin); + leaf = PointInLeaf(newp->origin); + newp->cluster = leaf->cluster; + if (newp->cluster == -1) + qprintf ("patch->cluster == -1\n"); +} + +/* +============= +SubdividePatch + +Chops the patch only if its local bounds exceed the max size +============= +*/ +void SubdividePatch (patch_t *patch) +{ + winding_t *w, *o1, *o2; + vec3_t mins, maxs, total; + vec3_t split; + vec_t dist; + int i, j; + vec_t v; + patch_t *newp; + + w = patch->winding; + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } + VectorSubtract (maxs, mins, total); + for (i=0 ; i<3 ; i++) + if (total[i] > (subdiv+1) ) + break; + if (i == 3) + { + // no splitting needed + return; + } + + // + // split the winding + // + VectorCopy (vec3_origin, split); + split[i] = 1; + dist = (mins[i] + maxs[i])*0.5; + ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); + + // + // create a new patch + // + if (num_patches == MAX_PATCHES) + Error ("MAX_PATCHES"); + newp = &patches[num_patches]; + num_patches++; + + newp->next = patch->next; + patch->next = newp; + + patch->winding = o1; + newp->winding = o2; + + FinishSplit (patch, newp); + + SubdividePatch (patch); + SubdividePatch (newp); +} + + +/* +============= +DicePatch + +Chops the patch by a global grid +============= +*/ +void DicePatch (patch_t *patch) +{ + winding_t *w, *o1, *o2; + vec3_t mins, maxs; + vec3_t split; + vec_t dist; + int i; + patch_t *newp; + + w = patch->winding; + WindingBounds (w, mins, maxs); + for (i=0 ; i<3 ; i++) + if (floor((mins[i]+1)/subdiv) < floor((maxs[i]-1)/subdiv)) + break; + if (i == 3) + { + // no splitting needed + return; + } + + // + // split the winding + // + VectorCopy (vec3_origin, split); + split[i] = 1; + dist = subdiv*(1+floor((mins[i]+1)/subdiv)); + ClipWindingEpsilon (w, split, dist, ON_EPSILON, &o1, &o2); + + // + // create a new patch + // + if (num_patches == MAX_PATCHES) + Error ("MAX_PATCHES"); + newp = &patches[num_patches]; + num_patches++; + + newp->next = patch->next; + patch->next = newp; + + patch->winding = o1; + newp->winding = o2; + + FinishSplit (patch, newp); + + DicePatch (patch); + DicePatch (newp); +} + + +/* +============= +SubdividePatches +============= +*/ +void SubdividePatches (void) +{ + int i, num; + + if (subdiv < 1) + return; + + num = num_patches; // because the list will grow + for (i=0 ; i +#endif + +typedef enum +{ + emit_surface, + emit_point, + emit_spotlight +} emittype_t; + + + +typedef struct directlight_s +{ + struct directlight_s *next; + emittype_t type; + + float intensity; + int style; + vec3_t origin; + vec3_t color; + vec3_t normal; // for surfaces and spotlights + float stopdot; // for spotlights +} directlight_t; + + +// the sum of all tranfer->transfer values for a given patch +// should equal exactly 0x10000, showing that all radiance +// reaches other patches +typedef struct +{ + unsigned short patch; + unsigned short transfer; +} transfer_t; + + +#define MAX_PATCHES 65000 // larger will cause 32 bit overflows + +typedef struct patch_s +{ + winding_t *winding; + struct patch_s *next; // next in face + int numtransfers; + transfer_t *transfers; + + int cluster; // for pvs checking + vec3_t origin; + dplane_t *plane; + + qboolean sky; + + vec3_t totallight; // accumulated by radiosity + // does NOT include light + // accounted for by direct lighting + float area; + + // illuminance * reflectivity = radiosity + vec3_t reflectivity; + vec3_t baselight; // emissivity only + + // each style 0 lightmap sample in the patch will be + // added up to get the average illuminance of the entire patch + vec3_t samplelight; + int samples; // for averaging direct light +} patch_t; + +extern patch_t *face_patches[MAX_MAP_FACES]; +extern entity_t *face_entity[MAX_MAP_FACES]; +extern vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels +extern patch_t patches[MAX_PATCHES]; +extern unsigned num_patches; + +extern int leafparents[MAX_MAP_LEAFS]; +extern int nodeparents[MAX_MAP_NODES]; + +extern float lightscale; + + +void MakeShadowSplits (void); + +//============================================== + + +void BuildVisMatrix (void); +qboolean CheckVisBit (unsigned p1, unsigned p2); + +//============================================== + +extern float ambient, maxlight; + +void LinkPlaneFaces (void); + +extern qboolean extrasamples; +extern int numbounce; + +extern directlight_t *directlights[MAX_MAP_LEAFS]; + +extern byte nodehit[MAX_MAP_NODES]; + +void BuildLightmaps (void); + +void BuildFacelights (int facenum); + +void FinalLightFace (int facenum); + +qboolean PvsForOrigin (vec3_t org, byte *pvs); + +int TestLine_r (int node, vec3_t start, vec3_t stop); + +void CreateDirectLights (void); + +dleaf_t *PointInLeaf (vec3_t point); + + +extern dplane_t backplanes[MAX_MAP_PLANES]; +extern int fakeplanes; // created planes for origin offset + +extern float subdiv; + +extern float direct_scale; +extern float entity_scale; + +int PointInLeafnum (vec3_t point); +void MakeTnodes (dmodel_t *bm); +void MakePatches (void); +void SubdividePatches (void); +void PairEdges (void); +void CalcTextureReflectivity (void); diff --git a/tools/quake2/extra/bsp/qrad3/qrad3.c b/tools/quake2/extra/bsp/qrad3/qrad3.c new file mode 100644 index 00000000..9c7caddc --- /dev/null +++ b/tools/quake2/extra/bsp/qrad3/qrad3.c @@ -0,0 +1,717 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qrad.h" + + + +/* + +NOTES +----- + +every surface must be divided into at least two patches each axis + +*/ + +patch_t *face_patches[MAX_MAP_FACES]; +entity_t *face_entity[MAX_MAP_FACES]; +patch_t patches[MAX_PATCHES]; +unsigned num_patches; + +vec3_t radiosity[MAX_PATCHES]; // light leaving a patch +vec3_t illumination[MAX_PATCHES]; // light arriving at a patch + +vec3_t face_offset[MAX_MAP_FACES]; // for rotating bmodels +dplane_t backplanes[MAX_MAP_PLANES]; + +char inbase[32], outbase[32]; + +int fakeplanes; // created planes for origin offset + +int numbounce = 8; +qboolean extrasamples; + +float subdiv = 64; +qboolean dumppatches; + +void BuildLightmaps (void); +int TestLine (vec3_t start, vec3_t stop); + +int junk; + +float ambient = 0; +float maxlight = 196; + +float lightscale = 1.0; + +qboolean glview; + +qboolean nopvs; + +char source[1024]; + +float direct_scale = 0.4; +float entity_scale = 1.0; + +/* +=================================================================== + +MISC + +=================================================================== +*/ + + +/* +============= +MakeBackplanes +============= +*/ +void MakeBackplanes (void) +{ + int i; + + for (i=0 ; ichildren[i]; + if (j < 0) + leafparents[-j - 1] = nodenum; + else + MakeParents (j, nodenum); + } +} + + +/* +=================================================================== + +TRANSFER SCALES + +=================================================================== +*/ + +int PointInLeafnum (vec3_t point) +{ + int nodenum; + vec_t dist; + dnode_t *node; + dplane_t *plane; + + nodenum = 0; + while (nodenum >= 0) + { + node = &dnodes[nodenum]; + plane = &dplanes[node->planenum]; + dist = DotProduct (point, plane->normal) - plane->dist; + if (dist > 0) + nodenum = node->children[0]; + else + nodenum = node->children[1]; + } + + return -nodenum - 1; +} + + +dleaf_t *PointInLeaf (vec3_t point) +{ + int num; + + num = PointInLeafnum (point); + return &dleafs[num]; +} + + +qboolean PvsForOrigin (vec3_t org, byte *pvs) +{ + dleaf_t *leaf; + + if (!visdatasize) + { + memset (pvs, 255, (numleafs+7)/8 ); + return true; + } + + leaf = PointInLeaf (org); + if (leaf->cluster == -1) + return false; // in solid leaf + + DecompressVis (dvisdata + dvis->bitofs[leaf->cluster][DVIS_PVS], pvs); + return true; +} + + +/* +============= +MakeTransfers + +============= +*/ +int total_transfer; + +void MakeTransfers (int i) +{ + int j; + vec3_t delta; + vec_t dist, scale; + float trans; + int itrans; + patch_t *patch, *patch2; + float total; + dplane_t plane; + vec3_t origin; + float transfers[MAX_PATCHES], *all_transfers; + int s; + int itotal; + byte pvs[(MAX_MAP_LEAFS+7)/8]; + int cluster; + + patch = patches + i; + total = 0; + + VectorCopy (patch->origin, origin); + plane = *patch->plane; + + if (!PvsForOrigin (patch->origin, pvs)) + return; + + // find out which patch2s will collect light + // from patch + + all_transfers = transfers; + patch->numtransfers = 0; + for (j=0, patch2 = patches ; jcluster; + if (cluster == -1) + continue; + if ( ! ( pvs[cluster>>3] & (1<<(cluster&7)) ) ) + continue; // not in pvs + } + + // calculate vector + VectorSubtract (patch2->origin, origin, delta); + dist = VectorNormalize (delta, delta); + if (!dist) + continue; // should never happen + + // reletive angles + scale = DotProduct (delta, plane.normal); + scale *= -DotProduct (delta, patch2->plane->normal); + if (scale <= 0) + continue; + + // check exact tramsfer + if (TestLine_r (0, patch->origin, patch2->origin) ) + continue; + + trans = scale * patch2->area / (dist*dist); + + if (trans < 0) + trans = 0; // rounding errors... + + transfers[j] = trans; + if (trans > 0) + { + total += trans; + patch->numtransfers++; + } + } + + // copy the transfers out and normalize + // total should be somewhere near PI if everything went right + // because partial occlusion isn't accounted for, and nearby + // patches have underestimated form factors, it will usually + // be higher than PI + if (patch->numtransfers) + { + transfer_t *t; + + if (patch->numtransfers < 0 || patch->numtransfers > MAX_PATCHES) + Error ("Weird numtransfers"); + s = patch->numtransfers * sizeof(transfer_t); + patch->transfers = malloc (s); + if (!patch->transfers) + Error ("Memory allocation failure"); + + // + // normalize all transfers so all of the light + // is transfered to the surroundings + // + t = patch->transfers; + itotal = 0; + for (j=0 ; jtransfer = itrans; + t->patch = j; + t++; + } + } + + // don't bother locking around this. not that important. + total_transfer += patch->numtransfers; +} + + +/* +============= +FreeTransfers +============= +*/ +void FreeTransfers (void) +{ + int i; + + for (i=0 ; iwinding; + fprintf (out, "%i\n", w->numpoints); + for (i=0 ; inumpoints ; i++) + { + fprintf (out, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + patch->totallight[0], + patch->totallight[1], + patch->totallight[2]); + } + fprintf (out, "\n"); + } + + fclose (out); +} + +/* +============= +WriteGlView +============= +*/ +void WriteGlView (void) +{ + char name[1024]; + FILE *f; + int i, j; + patch_t *p; + winding_t *w; + + strcpy (name, source); + StripExtension (name); + strcat (name, ".glr"); + + f = fopen (name, "w"); + if (!f) + Error ("Couldn't open %s", f); + + for (j=0 ; jwinding; + fprintf (f, "%i\n", w->numpoints); + for (i=0 ; inumpoints ; i++) + { + fprintf (f, "%5.2f %5.2f %5.2f %5.3f %5.3f %5.3f\n", + w->p[i][0], + w->p[i][1], + w->p[i][2], + p->totallight[0]/128, + p->totallight[1]/128, + p->totallight[2]/128); + } + fprintf (f, "\n"); + } + + fclose (f); +} + + +//============================================================== + +/* +============= +CollectLight +============= +*/ +float CollectLight (void) +{ + int i, j; + patch_t *patch; + vec_t total; + + total = 0; + + for (i=0, patch=patches ; isky) + { + VectorClear (radiosity[i]); + VectorClear (illumination[i]); + continue; + } + + for (j=0 ; j<3 ; j++) + { + patch->totallight[j] += illumination[i][j] / patch->area; + radiosity[i][j] = illumination[i][j] * patch->reflectivity[j]; + } + + total += radiosity[i][0] + radiosity[i][1] + radiosity[i][2]; + VectorClear (illumination[i]); + } + + return total; +} + + +/* +============= +ShootLight + +Send light out to other patches + Run multi-threaded +============= +*/ +void ShootLight (int patchnum) +{ + int k, l; + transfer_t *trans; + int num; + patch_t *patch; + vec3_t send; + + // this is the amount of light we are distributing + // prescale it so that multiplying by the 16 bit + // transfer values gives a proper output value + for (k=0 ; k<3 ; k++) + send[k] = radiosity[patchnum][k] / 0x10000; + patch = &patches[patchnum]; + + trans = patch->transfers; + num = patch->numtransfers; + + for (k=0 ; kpatch][l] += send[l]*trans->transfer; + } +} + +/* +============= +BounceLight +============= +*/ +void BounceLight (void) +{ + int i, j; + float added; + char name[64]; + patch_t *p; + + for (i=0 ; itotallight[j] = p->samplelight[j]; + radiosity[i][j] = p->samplelight[j] * p->reflectivity[j] * p->area; + } + } + + for (i=0 ; itotallight[0] < 0 || patch->totallight[1] < 0 || patch->totallight[2] < 0) + Error ("negative patch totallight\n"); + } +} + +/* +============= +RadWorld +============= +*/ +void RadWorld (void) +{ + if (numnodes == 0 || numfaces == 0) + Error ("Empty map"); + MakeBackplanes (); + MakeParents (0, -1); + MakeTnodes (&dmodels[0]); + + // turn each face into a single patch + MakePatches (); + + // subdivide patches to a maximum dimension + SubdividePatches (); + + // create directlights out of patches and lights + CreateDirectLights (); + + // build initial facelights + RunThreadsOnIndividual (numfaces, true, BuildFacelights); + + if (numbounce > 0) + { + // build transfer lists + RunThreadsOnIndividual (num_patches, true, MakeTransfers); + qprintf ("transfer lists: %5.1f megs\n" + , (float)total_transfer * sizeof(transfer_t) / (1024*1024)); + + // spread light around + BounceLight (); + + FreeTransfers (); + + CheckPatches (); + } + + if (glview) + WriteGlView (); + + // blend bounced light into direct light and save + PairEdges (); + LinkPlaneFaces (); + + lightdatasize = 0; + RunThreadsOnIndividual (numfaces, true, FinalLightFace); +} + + +/* +======== +main + +light modelfile +======== +*/ +int main (int argc, char **argv) +{ + int i; + double start, end; + char name[1024]; + + printf ("----- Radiosity ----\n"); + + verbose = false; + + for (i=1 ; i 255) + maxlight = 255; + + if (i != argc - 1) + Error ("usage: qrad [-v] [-chop num] [-scale num] [-ambient num] [-maxlight num] [-threads num] bspfile"); + + start = I_FloatTime (); + + SetQdirFromPath (argv[i]); + strcpy (source, ExpandArg(argv[i])); + StripExtension (source); + DefaultExtension (source, ".bsp"); + +// ReadLightFile (); + + sprintf (name, "%s%s", inbase, source); + printf ("reading %s\n", name); + LoadBSPFile (name); + ParseEntities (); + CalcTextureReflectivity (); + + if (!visdatasize) + { + printf ("No vis information, direct lighting only.\n"); + numbounce = 0; + ambient = 0.1; + } + + RadWorld (); + + sprintf (name, "%s%s", outbase, source); + printf ("writing %s\n", name); + WriteBSPFile (name); + + end = I_FloatTime (); + printf ("%5.0f seconds elapsed\n", end-start); + + return 0; +} + diff --git a/tools/quake2/extra/bsp/qrad3/trace.c b/tools/quake2/extra/bsp/qrad3/trace.c new file mode 100644 index 00000000..bb5f4949 --- /dev/null +++ b/tools/quake2/extra/bsp/qrad3/trace.c @@ -0,0 +1,295 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "bspfile.h" + +#define ON_EPSILON 0.1 + +typedef struct tnode_s +{ + int type; + vec3_t normal; + float dist; + int children[2]; + int pad; +} tnode_t; + +tnode_t *tnodes, *tnode_p; + +/* +============== +MakeTnode + +Converts the disk node structure into the efficient tracing structure +============== +*/ +void MakeTnode (int nodenum) +{ + tnode_t *t; + dplane_t *plane; + int i; + dnode_t *node; + + t = tnode_p++; + + node = dnodes + nodenum; + plane = dplanes + node->planenum; + + t->type = plane->type; + VectorCopy (plane->normal, t->normal); + t->dist = plane->dist; + + for (i=0 ; i<2 ; i++) + { + if (node->children[i] < 0) + t->children[i] = (dleafs[-node->children[i] - 1].contents & CONTENTS_SOLID) | (1<<31); + else + { + t->children[i] = tnode_p - tnodes; + MakeTnode (node->children[i]); + } + } + +} + + +/* +============= +MakeTnodes + +Loads the node structure out of a .bsp file to be used for light occlusion +============= +*/ +void MakeTnodes (dmodel_t *bm) +{ + // 32 byte align the structs + tnodes = malloc( (numnodes+1) * sizeof(tnode_t)); + tnodes = (tnode_t *)(((int)tnodes + 31)&~31); + tnode_p = tnodes; + + MakeTnode (0); +} + + +//========================================================== + + +int TestLine_r (int node, vec3_t start, vec3_t stop) +{ + tnode_t *tnode; + float front, back; + vec3_t mid; + float frac; + int side; + int r; + + if (node & (1<<31)) + return node & ~(1<<31); // leaf node + + tnode = &tnodes[node]; + switch (tnode->type) + { + case PLANE_X: + front = start[0] - tnode->dist; + back = stop[0] - tnode->dist; + break; + case PLANE_Y: + front = start[1] - tnode->dist; + back = stop[1] - tnode->dist; + break; + case PLANE_Z: + front = start[2] - tnode->dist; + back = stop[2] - tnode->dist; + break; + default: + front = (start[0]*tnode->normal[0] + start[1]*tnode->normal[1] + start[2]*tnode->normal[2]) - tnode->dist; + back = (stop[0]*tnode->normal[0] + stop[1]*tnode->normal[1] + stop[2]*tnode->normal[2]) - tnode->dist; + break; + } + + if (front >= -ON_EPSILON && back >= -ON_EPSILON) + return TestLine_r (tnode->children[0], start, stop); + + if (front < ON_EPSILON && back < ON_EPSILON) + return TestLine_r (tnode->children[1], start, stop); + + side = front < 0; + + frac = front / (front-back); + + mid[0] = start[0] + (stop[0] - start[0])*frac; + mid[1] = start[1] + (stop[1] - start[1])*frac; + mid[2] = start[2] + (stop[2] - start[2])*frac; + + r = TestLine_r (tnode->children[side], start, mid); + if (r) + return r; + return TestLine_r (tnode->children[!side], mid, stop); +} + +int TestLine (vec3_t start, vec3_t stop) +{ + return TestLine_r (0, start, stop); +} + +/* +============================================================================== + +LINE TRACING + +The major lighting operation is a point to point visibility test, performed +by recursive subdivision of the line by the BSP tree. + +============================================================================== +*/ + +typedef struct +{ + vec3_t backpt; + int side; + int node; +} tracestack_t; + + +/* +============== +TestLine +============== +*/ +qboolean _TestLine (vec3_t start, vec3_t stop) +{ + int node; + float front, back; + tracestack_t *tstack_p; + int side; + float frontx,fronty, frontz, backx, backy, backz; + tracestack_t tracestack[64]; + tnode_t *tnode; + + frontx = start[0]; + fronty = start[1]; + frontz = start[2]; + backx = stop[0]; + backy = stop[1]; + backz = stop[2]; + + tstack_p = tracestack; + node = 0; + + while (1) + { + if (node == CONTENTS_SOLID) + { +#if 0 + float d1, d2, d3; + + d1 = backx - frontx; + d2 = backy - fronty; + d3 = backz - frontz; + + if (d1*d1 + d2*d2 + d3*d3 > 1) +#endif + return false; // DONE! + } + + while (node < 0) + { + // pop up the stack for a back side + tstack_p--; + if (tstack_p < tracestack) + return true; + node = tstack_p->node; + + // set the hit point for this plane + + frontx = backx; + fronty = backy; + frontz = backz; + + // go down the back side + + backx = tstack_p->backpt[0]; + backy = tstack_p->backpt[1]; + backz = tstack_p->backpt[2]; + + node = tnodes[tstack_p->node].children[!tstack_p->side]; + } + + tnode = &tnodes[node]; + + switch (tnode->type) + { + case PLANE_X: + front = frontx - tnode->dist; + back = backx - tnode->dist; + break; + case PLANE_Y: + front = fronty - tnode->dist; + back = backy - tnode->dist; + break; + case PLANE_Z: + front = frontz - tnode->dist; + back = backz - tnode->dist; + break; + default: + front = (frontx*tnode->normal[0] + fronty*tnode->normal[1] + frontz*tnode->normal[2]) - tnode->dist; + back = (backx*tnode->normal[0] + backy*tnode->normal[1] + backz*tnode->normal[2]) - tnode->dist; + break; + } + + if (front > -ON_EPSILON && back > -ON_EPSILON) +// if (front > 0 && back > 0) + { + node = tnode->children[0]; + continue; + } + + if (front < ON_EPSILON && back < ON_EPSILON) +// if (front <= 0 && back <= 0) + { + node = tnode->children[1]; + continue; + } + + side = front < 0; + + front = front / (front-back); + + tstack_p->node = node; + tstack_p->side = side; + tstack_p->backpt[0] = backx; + tstack_p->backpt[1] = backy; + tstack_p->backpt[2] = backz; + + tstack_p++; + + backx = frontx + front*(backx-frontx); + backy = fronty + front*(backy-fronty); + backz = frontz + front*(backz-frontz); + + node = tnode->children[side]; + } +} + + diff --git a/tools/quake2/extra/bsp/qvis3/flow.c b/tools/quake2/extra/bsp/qvis3/flow.c new file mode 100644 index 00000000..66af998e --- /dev/null +++ b/tools/quake2/extra/bsp/qvis3/flow.c @@ -0,0 +1,788 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ +#include "vis.h" + +/* + + each portal will have a list of all possible to see from first portal + + if (!thread->portalmightsee[portalnum]) + + portal mightsee + + for p2 = all other portals in leaf + get sperating planes + for all portals that might be seen by p2 + mark as unseen if not present in seperating plane + flood fill a new mightsee + save as passagemightsee + + + void CalcMightSee (leaf_t *leaf, +*/ + +int CountBits (byte *bits, int numbits) +{ + int i; + int c; + + c = 0; + for (i=0 ; i>3] & (1<<(i&7)) ) + c++; + + return c; +} + +int c_fullskip; +int c_portalskip, c_leafskip; +int c_vistest, c_mighttest; + +int c_chop, c_nochop; + +int active; + +void CheckStack (leaf_t *leaf, threaddata_t *thread) +{ + pstack_t *p, *p2; + + for (p=thread->pstack_head.next ; p ; p=p->next) + { +// printf ("="); + if (p->leaf == leaf) + Error ("CheckStack: leaf recursion"); + for (p2=thread->pstack_head.next ; p2 != p ; p2=p2->next) + if (p2->leaf == p->leaf) + Error ("CheckStack: late leaf recursion"); + } +// printf ("\n"); +} + + +winding_t *AllocStackWinding (pstack_t *stack) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (stack->freewindings[i]) + { + stack->freewindings[i] = 0; + return &stack->windings[i]; + } + } + + Error ("AllocStackWinding: failed"); + + return NULL; +} + +void FreeStackWinding (winding_t *w, pstack_t *stack) +{ + int i; + + i = w - stack->windings; + + if (i<0 || i>2) + return; // not from local + + if (stack->freewindings[i]) + Error ("FreeStackWinding: allready free"); + stack->freewindings[i] = 1; +} + +/* +============== +ChopWinding + +============== +*/ +winding_t *ChopWinding (winding_t *in, pstack_t *stack, plane_t *split) +{ + vec_t dists[128]; + int sides[128]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + + if (!counts[1]) + return in; // completely on front side + + if (!counts[0]) + { + FreeStackWinding (in, stack); + return NULL; + } + + sides[i] = sides[0]; + dists[i] = dists[0]; + + neww = AllocStackWinding (stack); + + neww->numpoints = 0; + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + if (neww->numpoints == MAX_POINTS_ON_FIXED_WINDING) + { + FreeStackWinding (neww, stack); + return in; // can't chop -- fall back to original + } + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + +// free the original winding + FreeStackWinding (in, stack); + + return neww; +} + + +/* +============== +ClipToSeperators + +Source, pass, and target are an ordering of portals. + +Generates seperating planes canidates by taking two points from source and one +point from pass, and clips target by them. + +If target is totally clipped away, that portal can not be seen through. + +Normal clip keeps target on the same side as pass, which is correct if the +order goes source, pass, target. If the order goes pass, source, target then +flipclip should be set. +============== +*/ +winding_t *ClipToSeperators (winding_t *source, winding_t *pass, winding_t *target, qboolean flipclip, pstack_t *stack) +{ + int i, j, k, l; + plane_t plane; + vec3_t v1, v2; + float d; + vec_t length; + int counts[3]; + qboolean fliptest; + +// check all combinations + for (i=0 ; inumpoints ; i++) + { + l = (i+1)%source->numpoints; + VectorSubtract (source->points[l] , source->points[i], v1); + + // fing a vertex of pass that makes a plane that puts all of the + // vertexes of pass on the front side and all of the vertexes of + // source on the back side + for (j=0 ; jnumpoints ; j++) + { + VectorSubtract (pass->points[j], source->points[i], v2); + + plane.normal[0] = v1[1]*v2[2] - v1[2]*v2[1]; + plane.normal[1] = v1[2]*v2[0] - v1[0]*v2[2]; + plane.normal[2] = v1[0]*v2[1] - v1[1]*v2[0]; + + // if points don't make a valid plane, skip it + + length = plane.normal[0] * plane.normal[0] + + plane.normal[1] * plane.normal[1] + + plane.normal[2] * plane.normal[2]; + + if (length < ON_EPSILON) + continue; + + length = 1/sqrt(length); + + plane.normal[0] *= length; + plane.normal[1] *= length; + plane.normal[2] *= length; + + plane.dist = DotProduct (pass->points[j], plane.normal); + + // + // find out which side of the generated seperating plane has the + // source portal + // +#if 1 + fliptest = false; + for (k=0 ; knumpoints ; k++) + { + if (k == i || k == l) + continue; + d = DotProduct (source->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + { // source is on the negative side, so we want all + // pass and target on the positive side + fliptest = false; + break; + } + else if (d > ON_EPSILON) + { // source is on the positive side, so we want all + // pass and target on the negative side + fliptest = true; + break; + } + } + if (k == source->numpoints) + continue; // planar with source portal +#else + fliptest = flipclip; +#endif + // + // flip the normal if the source portal is backwards + // + if (fliptest) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } +#if 1 + // + // if all of the pass portal points are now on the positive side, + // this is the seperating plane + // + counts[0] = counts[1] = counts[2] = 0; + for (k=0 ; knumpoints ; k++) + { + if (k==j) + continue; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + break; + else if (d > ON_EPSILON) + counts[0]++; + else + counts[2]++; + } + if (k != pass->numpoints) + continue; // points on negative side, not a seperating plane + + if (!counts[0]) + continue; // planar with seperating plane +#else + k = (j+1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + continue; + k = (j+pass->numpoints-1)%pass->numpoints; + d = DotProduct (pass->points[k], plane.normal) - plane.dist; + if (d < -ON_EPSILON) + continue; +#endif + // + // flip the normal if we want the back side + // + if (flipclip) + { + VectorSubtract (vec3_origin, plane.normal, plane.normal); + plane.dist = -plane.dist; + } + + // + // clip target by the seperating plane + // + target = ChopWinding (target, stack, &plane); + if (!target) + return NULL; // target is not visible + } + } + + return target; +} + + + +/* +================== +RecursiveLeafFlow + +Flood fill through the leafs +If src_portal is NULL, this is the originating leaf +================== +*/ +void RecursiveLeafFlow (int leafnum, threaddata_t *thread, pstack_t *prevstack) +{ + pstack_t stack; + portal_t *p; + plane_t backplane; + leaf_t *leaf; + int i, j; + long *test, *might, *vis, more; + int pnum; + + thread->c_chains++; + + leaf = &leafs[leafnum]; +// CheckStack (leaf, thread); + + prevstack->next = &stack; + + stack.next = NULL; + stack.leaf = leaf; + stack.portal = NULL; + + might = (long *)stack.mightsee; + vis = (long *)thread->base->portalvis; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + if ( ! (prevstack->mightsee[pnum >> 3] & (1<<(pnum&7)) ) ) + { + continue; // can't possibly see it + } + + // if the portal can't see anything we haven't allready seen, skip it + if (p->status == stat_done) + { + test = (long *)p->portalvis; + } + else + { + test = (long *)p->portalflood; + } + + more = 0; + for (j=0 ; jmightsee)[j] & test[j]; + more |= (might[j] & ~vis[j]); + } + + if (!more && + (thread->base->portalvis[pnum>>3] & (1<<(pnum&7))) ) + { // can't see anything new + continue; + } + + // get plane of portal, point normal into the neighbor leaf + stack.portalplane = p->plane; + VectorSubtract (vec3_origin, p->plane.normal, backplane.normal); + backplane.dist = -p->plane.dist; + +// c_portalcheck++; + + stack.portal = p; + stack.next = NULL; + stack.freewindings[0] = 1; + stack.freewindings[1] = 1; + stack.freewindings[2] = 1; + +#if 1 +{ +float d; + + d = DotProduct (p->origin, thread->pstack_head.portalplane.normal); + d -= thread->pstack_head.portalplane.dist; + if (d < -p->radius) + { + continue; + } + else if (d > p->radius) + { + stack.pass = p->winding; + } + else + { + stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; + } +} +#else + stack.pass = ChopWinding (p->winding, &stack, &thread->pstack_head.portalplane); + if (!stack.pass) + continue; +#endif + + +#if 1 +{ +float d; + + d = DotProduct (thread->base->origin, p->plane.normal); + d -= p->plane.dist; + if (d > p->radius) + { + continue; + } + else if (d < -p->radius) + { + stack.source = prevstack->source; + } + else + { + stack.source = ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; + } +} +#else + stack.source = ChopWinding (prevstack->source, &stack, &backplane); + if (!stack.source) + continue; +#endif + + if (!prevstack->pass) + { // the second leaf can only be blocked if coplanar + + // mark the portal as visible + thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); + + RecursiveLeafFlow (p->leaf, thread, &stack); + continue; + } + + stack.pass = ClipToSeperators (stack.source, prevstack->pass, stack.pass, false, &stack); + if (!stack.pass) + continue; + + stack.pass = ClipToSeperators (prevstack->pass, stack.source, stack.pass, true, &stack); + if (!stack.pass) + continue; + + // mark the portal as visible + thread->base->portalvis[pnum>>3] |= (1<<(pnum&7)); + + // flow through it for real + RecursiveLeafFlow (p->leaf, thread, &stack); + } +} + + +/* +=============== +PortalFlow + +generates the portalvis bit vector +=============== +*/ +void PortalFlow (int portalnum) +{ + threaddata_t data; + int i; + portal_t *p; + int c_might, c_can; + + p = sorted_portals[portalnum]; + p->status = stat_working; + + c_might = CountBits (p->portalflood, numportals*2); + + memset (&data, 0, sizeof(data)); + data.base = p; + + data.pstack_head.portal = p; + data.pstack_head.source = p->winding; + data.pstack_head.portalplane = p->plane; + for (i=0 ; iportalflood)[i]; + RecursiveLeafFlow (p->leaf, &data, &data.pstack_head); + + p->status = stat_done; + + c_can = CountBits (p->portalvis, numportals*2); + + qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", + (int)(p - portals), c_might, c_can, data.c_chains); +} + + +/* +=============================================================================== + +This is a rough first-order aproximation that is used to trivially reject some +of the final calculations. + + +Calculates portalfront and portalflood bit vectors + +thinking about: + +typedef struct passage_s +{ + struct passage_s *next; + struct portal_s *to; + stryct sep_s *seperators; + byte *mightsee; +} passage_t; + +typedef struct portal_s +{ + struct passage_s *passages; + int leaf; // leaf portal faces into +} portal_s; + +leaf = portal->leaf +clear +for all portals + + +calc portal visibility + clear bit vector + for all passages + passage visibility + + +for a portal to be visible to a passage, it must be on the front of +all seperating planes, and both portals must be behind the mew portal + +=============================================================================== +*/ + +int c_flood, c_vis; + + +/* +================== +SimpleFlood + +================== +*/ +void SimpleFlood (portal_t *srcportal, int leafnum) +{ + int i; + leaf_t *leaf; + portal_t *p; + int pnum; + + leaf = &leafs[leafnum]; + + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + if ( ! (srcportal->portalfront[pnum>>3] & (1<<(pnum&7)) ) ) + continue; + + if (srcportal->portalflood[pnum>>3] & (1<<(pnum&7)) ) + continue; + + srcportal->portalflood[pnum>>3] |= (1<<(pnum&7)); + + SimpleFlood (srcportal, p->leaf); + } +} + +/* +============== +BasePortalVis +============== +*/ +void BasePortalVis (int portalnum) +{ + int j, k; + portal_t *tp, *p; + float d; + winding_t *w; + + p = portals+portalnum; + + p->portalfront = malloc (portalbytes); + memset (p->portalfront, 0, portalbytes); + + p->portalflood = malloc (portalbytes); + memset (p->portalflood, 0, portalbytes); + + p->portalvis = malloc (portalbytes); + memset (p->portalvis, 0, portalbytes); + + for (j=0, tp = portals ; jwinding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], p->plane.normal) + - p->plane.dist; + if (d > ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + w = p->winding; + for (k=0 ; knumpoints ; k++) + { + d = DotProduct (w->points[k], tp->plane.normal) + - tp->plane.dist; + if (d < -ON_EPSILON) + break; + } + if (k == w->numpoints) + continue; // no points on front + + p->portalfront[j>>3] |= (1<<(j&7)); + } + + SimpleFlood (p, p->leaf); + + p->nummightsee = CountBits (p->portalflood, numportals*2); +// printf ("portal %i: %i mightsee\n", portalnum, p->nummightsee); + c_flood += p->nummightsee; +} + + + + + +/* +=============================================================================== + +This is a second order aproximation + +Calculates portalvis bit vector + +WAAAAAAY too slow. + +=============================================================================== +*/ + +/* +================== +RecursiveLeafBitFlow + +================== +*/ +void RecursiveLeafBitFlow (int leafnum, byte *mightsee, byte *cansee) +{ + portal_t *p; + leaf_t *leaf; + int i, j; + long more; + int pnum; + byte newmight[MAX_PORTALS/8]; + + leaf = &leafs[leafnum]; + +// check all portals for flowing into other leafs + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + pnum = p - portals; + + // if some previous portal can't see it, skip + if (! (mightsee[pnum>>3] & (1<<(pnum&7)) ) ) + continue; + + // if this portal can see some portals we mightsee, recurse + more = 0; + for (j=0 ; jportalflood)[j]; + more |= ((long *)newmight)[j] & ~((long *)cansee)[j]; + } + + if (!more) + continue; // can't see anything new + + cansee[pnum>>3] |= (1<<(pnum&7)); + + RecursiveLeafBitFlow (p->leaf, newmight, cansee); + } +} + +/* +============== +BetterPortalVis +============== +*/ +void BetterPortalVis (int portalnum) +{ + portal_t *p; + + p = portals+portalnum; + + RecursiveLeafBitFlow (p->leaf, p->portalflood, p->portalvis); + + // build leaf vis information + p->nummightsee = CountBits (p->portalvis, numportals*2); + c_vis += p->nummightsee; +} + + diff --git a/tools/quake2/extra/bsp/qvis3/makefile b/tools/quake2/extra/bsp/qvis3/makefile new file mode 100644 index 00000000..57946de1 --- /dev/null +++ b/tools/quake2/extra/bsp/qvis3/makefile @@ -0,0 +1,62 @@ + +CFLAGS = -c +LDFLAGS = +ODIR = baddir + +EXEBASE = qvis3 +EXE = $(ODIR)/qvis3 +all: $(EXE) + +_next: + make "CFLAGS = -c -g -I../../common" "ODIR = next" + +_irix: + make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix" + +_irixinst: + make "CFLAGS = -c -Ofast=ip32_10k -I../../common -Xcpluscomm" "LDFLAGS = -Ofast=ip32_10k" "ODIR = irix" + cp irix/$(EXEBASE) /limbo/quake2/bin_irix + +_irixclean: + rm -f irix/*.o irix/$(EXEBASE) + +_osf: + make "CFLAGS = -c -O4 -I../../common -threads" "LDFLAGS = -threads -lm" "ODIR = osf" + +clean: + rm -f irix/*.o irix/$(EXEBASE) + +install: + cp irix/$(EXEBASE) /limbo/quake2/bin_irix + + +FILES = $(ODIR)/bspfile.o $(ODIR)/cmdlib.o $(ODIR)/mathlib.o $(ODIR)/scriplib.o $(ODIR)/threads.o $(ODIR)/qvis3.o $(ODIR)/flow.o + +$(EXE) : $(FILES) + cc -o $(EXE) $(LDFLAGS) $(FILES) + +$(ODIR)/qvis3.o : qvis3.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/flow.o : flow.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i + +$(ODIR)/cmdlib.o : ../../common/cmdlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/mathlib.o : ../../common/mathlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/polylib.o : ../../common/polylib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/scriplib.o : ../../common/scriplib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/threads.o : ../../common/threads.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/bspfile.o : ../../common/bspfile.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i diff --git a/tools/quake2/extra/bsp/qvis3/qvis3.c b/tools/quake2/extra/bsp/qvis3/qvis3.c new file mode 100644 index 00000000..7cc87510 --- /dev/null +++ b/tools/quake2/extra/bsp/qvis3/qvis3.c @@ -0,0 +1,615 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "vis.h" +#include "threads.h" +#include "stdlib.h" + +int numportals; +int portalclusters; + +char inbase[32]; +char outbase[32]; + +portal_t *portals; +leaf_t *leafs; + +int c_portaltest, c_portalpass, c_portalcheck; + +byte *uncompressedvis; + +byte *vismap, *vismap_p, *vismap_end; // past visfile +int originalvismapsize; + +int leafbytes; // (portalclusters+63)>>3 +int leaflongs; + +int portalbytes, portallongs; + +qboolean fastvis; +qboolean nosort; + +int testlevel = 2; + +int totalvis; + +portal_t *sorted_portals[MAX_MAP_PORTALS*2]; + + +//============================================================================= + +void PlaneFromWinding (winding_t *w, plane_t *plane) +{ + vec3_t v1, v2; + +// calc plane + VectorSubtract (w->points[2], w->points[1], v1); + VectorSubtract (w->points[0], w->points[1], v2); + CrossProduct (v2, v1, plane->normal); + VectorNormalize (plane->normal, plane->normal); + plane->dist = DotProduct (w->points[0], plane->normal); +} + + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + size = (int)((winding_t *)0)->points[points]; + w = malloc (size); + memset (w, 0, size); + + return w; +} + + + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + printf ("(%5.1f, %5.1f, %5.1f)\n",w->points[i][0], w->points[i][1],w->points[i][2]); +} + +void prl(leaf_t *l) +{ + int i; + portal_t *p; + plane_t pl; + + for (i=0 ; inumportals ; i++) + { + p = l->portals[i]; + pl = p->plane; + printf ("portal %4i to leaf %4i : %7.1f : (%4.1f, %4.1f, %4.1f)\n",(int)(p-portals),p->leaf,pl.dist, pl.normal[0], pl.normal[1], pl.normal[2]); + } +} + + +//============================================================================= + +/* +============= +SortPortals + +Sorts the portals from the least complex, so the later ones can reuse +the earlier information. +============= +*/ +int PComp (const void *a, const void *b) +{ + if ( (*(portal_t **)a)->nummightsee == (*(portal_t **)b)->nummightsee) + return 0; + if ( (*(portal_t **)a)->nummightsee < (*(portal_t **)b)->nummightsee) + return -1; + return 1; +} +void SortPortals (void) +{ + int i; + + for (i=0 ; i>3] & (1<<(i&7)) ) + { + p = portals+i; + leafbits[p->leaf>>3] |= (1<<(p->leaf&7)); + } + } + + c_leafs = CountBits (leafbits, portalclusters); + + return c_leafs; +} + + +/* +=============== +ClusterMerge + +Merges the portal visibility for a leaf +=============== +*/ +void ClusterMerge (int leafnum) +{ + leaf_t *leaf; + byte portalvector[MAX_PORTALS/8]; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + int i, j; + int numvis; + byte *dest; + portal_t *p; + int pnum; + + // OR together all the portalvis bits + + memset (portalvector, 0, portalbytes); + leaf = &leafs[leafnum]; + for (i=0 ; inumportals ; i++) + { + p = leaf->portals[i]; + if (p->status != stat_done) + Error ("portal not done"); + for (j=0 ; jportalvis)[j]; + pnum = p - portals; + portalvector[pnum>>3] |= 1<<(pnum&7); + } + + // convert portal bits to leaf bits + numvis = LeafVectorFromPortalVector (portalvector, uncompressed); + + if (uncompressed[leafnum>>3] & (1<<(leafnum&7))) + printf ("WARNING: Leaf portals saw into leaf\n"); + + uncompressed[leafnum>>3] |= (1<<(leafnum&7)); + numvis++; // count the leaf itself + + // save uncompressed for PHS calculation + memcpy (uncompressedvis + leafnum*leafbytes, uncompressed, leafbytes); + +// +// compress the bit string +// + qprintf ("cluster %4i : %4i visible\n", leafnum, numvis); + totalvis += numvis; + + i = CompressVis (uncompressed, compressed); + + dest = vismap_p; + vismap_p += i; + + if (vismap_p > vismap_end) + Error ("Vismap expansion overflow"); + + dvis->bitofs[leafnum][DVIS_PVS] = dest-vismap; + + memcpy (dest, compressed, i); +} + + +/* +================== +CalcPortalVis +================== +*/ +void CalcPortalVis (void) +{ + int i; + +// fastvis just uses mightsee for a very loose bound + if (fastvis) + { + for (i=0 ; iwinding; + VectorCopy (vec3_origin, total); + for (i=0 ; inumpoints ; i++) + { + VectorAdd (total, w->points[i], total); + } + + for (i=0 ; i<3 ; i++) + total[i] /= w->numpoints; + + bestr = 0; + for (i=0 ; inumpoints ; i++) + { + VectorSubtract (w->points[i], total, dist); + r = VectorLength (dist); + if (r > bestr) + bestr = r; + } + VectorCopy (total, p->origin); + p->radius = bestr; +} + +/* +============ +LoadPortals +============ +*/ +void LoadPortals (char *name) +{ + int i, j; + portal_t *p; + leaf_t *l; + char magic[80]; + FILE *f; + int numpoints; + winding_t *w; + int leafnums[2]; + plane_t plane; + + if (!strcmp(name,"-")) + f = stdin; + else + { + f = fopen(name, "r"); + if (!f) + Error ("LoadPortals: couldn't read %s\n",name); + } + + if (fscanf (f,"%79s\n%i\n%i\n",magic, &portalclusters, &numportals) != 3) + Error ("LoadPortals: failed to read header"); + if (strcmp(magic,PORTALFILE)) + Error ("LoadPortals: not a portal file"); + + printf ("%4i portalclusters\n", portalclusters); + printf ("%4i numportals\n", numportals); + + // these counts should take advantage of 64 bit systems automatically + leafbytes = ((portalclusters+63)&~63)>>3; + leaflongs = leafbytes/sizeof(long); + + portalbytes = ((numportals*2+63)&~63)>>3; + portallongs = portalbytes/sizeof(long); + +// each file portal is split into two memory portals + portals = malloc(2*numportals*sizeof(portal_t)); + memset (portals, 0, 2*numportals*sizeof(portal_t)); + + leafs = malloc(portalclusters*sizeof(leaf_t)); + memset (leafs, 0, portalclusters*sizeof(leaf_t)); + + originalvismapsize = portalclusters*leafbytes; + uncompressedvis = malloc(originalvismapsize); + + vismap = vismap_p = dvisdata; + dvis->numclusters = portalclusters; + vismap_p = (byte *)&dvis->bitofs[portalclusters]; + + vismap_end = vismap + MAX_MAP_VISIBILITY; + + for (i=0, p=portals ; i MAX_POINTS_ON_WINDING) + Error ("LoadPortals: portal %i has too many points", i); + if ( (unsigned)leafnums[0] > portalclusters + || (unsigned)leafnums[1] > portalclusters) + Error ("LoadPortals: reading portal %i", i); + + w = p->winding = NewWinding (numpoints); + w->original = true; + w->numpoints = numpoints; + + for (j=0 ; jpoints[j][k] = v[k]; + } + fscanf (f, "\n"); + + // calc plane + PlaneFromWinding (w, &plane); + + // create forward portal + l = &leafs[leafnums[0]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = w; + VectorSubtract (vec3_origin, plane.normal, p->plane.normal); + p->plane.dist = -plane.dist; + p->leaf = leafnums[1]; + SetPortalSphere (p); + p++; + + // create backwards portal + l = &leafs[leafnums[1]]; + if (l->numportals == MAX_PORTALS_ON_LEAF) + Error ("Leaf with too many portals"); + l->portals[l->numportals] = p; + l->numportals++; + + p->winding = NewWinding(w->numpoints); + p->winding->numpoints = w->numpoints; + for (j=0 ; jnumpoints ; j++) + { + VectorCopy (w->points[w->numpoints-1-j], p->winding->points[j]); + } + + p->plane = plane; + p->leaf = leafnums[0]; + SetPortalSphere (p); + p++; + + } + + fclose (f); +} + + +/* +================ +CalcPHS + +Calculate the PHS (Potentially Hearable Set) +by ORing together all the PVS visible from a leaf +================ +*/ +void CalcPHS (void) +{ + int i, j, k, l, index; + int bitbyte; + long *dest, *src; + byte *scan; + int count; + byte uncompressed[MAX_MAP_LEAFS/8]; + byte compressed[MAX_MAP_LEAFS/8]; + + printf ("Building PHS...\n"); + + count = 0; + for (i=0 ; i= portalclusters) + Error ("Bad bit in PVS"); // pad bits should be 0 + src = (long *)(uncompressedvis + index*leafbytes); + dest = (long *)uncompressed; + for (l=0 ; l>3] & (1<<(j&7)) ) + count++; + + // + // compress the bit string + // + j = CompressVis (uncompressed, compressed); + + dest = (long *)vismap_p; + vismap_p += j; + + if (vismap_p > vismap_end) + Error ("Vismap expansion overflow"); + + dvis->bitofs[i][DVIS_PHS] = (byte *)dest-vismap; + + memcpy (dest, compressed, j); + } + + printf ("Average clusters hearable: %i\n", count/portalclusters); +} + +/* +=========== +main +=========== +*/ +int main (int argc, char **argv) +{ + char portalfile[1024]; + char source[1024]; + char name[1024]; + int i; + double start, end; + + printf ("---- vis ----\n"); + + verbose = false; + for (i=1 ; i>3; + visrow = (dvis->numclusters + 7)>>3; + + for (j=0 ; j>3; + row = (dvis->numclusters+7)>>3; + out = decompressed; + + do + { + if (*in) + { + *out++ = *in++; + continue; + } + + c = in[1]; + if (!c) + Error ("DecompressVis: 0 repeat"); + in += 2; + while (c) + { + *out++ = 0; + c--; + } + } while (out - decompressed < row); +} + +//============================================================================= + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile (qboolean todisk) +{ + int i, j; + dmodel_t *d; + + +// models + for (i=0 ; ifirstface = LittleLong (d->firstface); + d->numfaces = LittleLong (d->numfaces); + d->headnode = LittleLong (d->headnode); + + for (j=0 ; j<3 ; j++) + { + d->mins[j] = LittleFloat(d->mins[j]); + d->maxs[j] = LittleFloat(d->maxs[j]); + d->origin[j] = LittleFloat(d->origin[j]); + } + } + +// +// vertexes +// + for (i=0 ; inumclusters; + else + j = LittleLong(dvis->numclusters); + dvis->numclusters = LittleLong (dvis->numclusters); + for (i=0 ; ibitofs[i][0] = LittleLong (dvis->bitofs[i][0]); + dvis->bitofs[i][1] = LittleLong (dvis->bitofs[i][1]); + } +} + + +dheader_t *header; + +int CopyLump (int lump, void *dest, int size) +{ + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if (length % size) + Error ("LoadBSPFile: odd lump size"); + + memcpy (dest, (byte *)header + ofs, length); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +void LoadBSPFile (char *filename) +{ + int i; + +// +// load the file header +// + LoadFile (filename, (void **)&header); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->ident != IDBSPHEADER) + Error ("%s is not a IBSP file", filename); + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, header->version, BSPVERSION); + + nummodels = CopyLump (LUMP_MODELS, dmodels, sizeof(dmodel_t)); + numvertexes = CopyLump (LUMP_VERTEXES, dvertexes, sizeof(dvertex_t)); + numplanes = CopyLump (LUMP_PLANES, dplanes, sizeof(dplane_t)); + numleafs = CopyLump (LUMP_LEAFS, dleafs, sizeof(dleaf_t)); + numnodes = CopyLump (LUMP_NODES, dnodes, sizeof(dnode_t)); + numtexinfo = CopyLump (LUMP_TEXINFO, texinfo, sizeof(texinfo_t)); + numfaces = CopyLump (LUMP_FACES, dfaces, sizeof(dface_t)); + numleaffaces = CopyLump (LUMP_LEAFFACES, dleaffaces, sizeof(dleaffaces[0])); + numleafbrushes = CopyLump (LUMP_LEAFBRUSHES, dleafbrushes, sizeof(dleafbrushes[0])); + numsurfedges = CopyLump (LUMP_SURFEDGES, dsurfedges, sizeof(dsurfedges[0])); + numedges = CopyLump (LUMP_EDGES, dedges, sizeof(dedge_t)); + numbrushes = CopyLump (LUMP_BRUSHES, dbrushes, sizeof(dbrush_t)); + numbrushsides = CopyLump (LUMP_BRUSHSIDES, dbrushsides, sizeof(dbrushside_t)); + numareas = CopyLump (LUMP_AREAS, dareas, sizeof(darea_t)); + numareaportals = CopyLump (LUMP_AREAPORTALS, dareaportals, sizeof(dareaportal_t)); + + visdatasize = CopyLump (LUMP_VISIBILITY, dvisdata, 1); + lightdatasize = CopyLump (LUMP_LIGHTING, dlightdata, 1); + entdatasize = CopyLump (LUMP_ENTITIES, dentdata, 1); + + CopyLump (LUMP_POP, dpop, 1); + + free (header); // everything has been copied out + +// +// swap everything +// + SwapBSPFile (false); +} + + +/* +============= +LoadBSPFileTexinfo + +Only loads the texinfo lump, so qdata can scan for textures +============= +*/ +void LoadBSPFileTexinfo (char *filename) +{ + int i; + FILE *f; + int length, ofs; + + header = malloc(sizeof(dheader_t)); + + f = fopen (filename, "rb"); + fread (header, sizeof(dheader_t), 1, f); + +// swap the header + for (i=0 ; i< sizeof(dheader_t)/4 ; i++) + ((int *)header)[i] = LittleLong ( ((int *)header)[i]); + + if (header->ident != IDBSPHEADER) + Error ("%s is not a IBSP file", filename); + if (header->version != BSPVERSION) + Error ("%s is version %i, not %i", filename, header->version, BSPVERSION); + + + length = header->lumps[LUMP_TEXINFO].filelen; + ofs = header->lumps[LUMP_TEXINFO].fileofs; + + fseek (f, ofs, SEEK_SET); + fread (texinfo, length, 1, f); + fclose (f); + + numtexinfo = length / sizeof(texinfo_t); + + free (header); // everything has been copied out + + SwapBSPFile (false); +} + + +//============================================================================ + +FILE *wadfile; +dheader_t outheader; + +void AddLump (int lumpnum, void *data, int len) +{ + lump_t *lump; + + lump = &header->lumps[lumpnum]; + + lump->fileofs = LittleLong( ftell(wadfile) ); + lump->filelen = LittleLong(len); + SafeWrite (wadfile, data, (len+3)&~3); +} + +/* +============= +WriteBSPFile + +Swaps the bsp file in place, so it should not be referenced again +============= +*/ +void WriteBSPFile (char *filename) +{ + header = &outheader; + memset (header, 0, sizeof(dheader_t)); + + SwapBSPFile (true); + + header->ident = LittleLong (IDBSPHEADER); + header->version = LittleLong (BSPVERSION); + + wadfile = SafeOpenWrite (filename); + SafeWrite (wadfile, header, sizeof(dheader_t)); // overwritten later + + AddLump (LUMP_PLANES, dplanes, numplanes*sizeof(dplane_t)); + AddLump (LUMP_LEAFS, dleafs, numleafs*sizeof(dleaf_t)); + AddLump (LUMP_VERTEXES, dvertexes, numvertexes*sizeof(dvertex_t)); + AddLump (LUMP_NODES, dnodes, numnodes*sizeof(dnode_t)); + AddLump (LUMP_TEXINFO, texinfo, numtexinfo*sizeof(texinfo_t)); + AddLump (LUMP_FACES, dfaces, numfaces*sizeof(dface_t)); + AddLump (LUMP_BRUSHES, dbrushes, numbrushes*sizeof(dbrush_t)); + AddLump (LUMP_BRUSHSIDES, dbrushsides, numbrushsides*sizeof(dbrushside_t)); + AddLump (LUMP_LEAFFACES, dleaffaces, numleaffaces*sizeof(dleaffaces[0])); + AddLump (LUMP_LEAFBRUSHES, dleafbrushes, numleafbrushes*sizeof(dleafbrushes[0])); + AddLump (LUMP_SURFEDGES, dsurfedges, numsurfedges*sizeof(dsurfedges[0])); + AddLump (LUMP_EDGES, dedges, numedges*sizeof(dedge_t)); + AddLump (LUMP_MODELS, dmodels, nummodels*sizeof(dmodel_t)); + AddLump (LUMP_AREAS, dareas, numareas*sizeof(darea_t)); + AddLump (LUMP_AREAPORTALS, dareaportals, numareaportals*sizeof(dareaportal_t)); + + AddLump (LUMP_LIGHTING, dlightdata, lightdatasize); + AddLump (LUMP_VISIBILITY, dvisdata, visdatasize); + AddLump (LUMP_ENTITIES, dentdata, entdatasize); + AddLump (LUMP_POP, dpop, sizeof(dpop)); + + fseek (wadfile, 0, SEEK_SET); + SafeWrite (wadfile, header, sizeof(dheader_t)); + fclose (wadfile); +} + +//============================================================================ + +/* +============= +PrintBSPFileSizes + +Dumps info about current file +============= +*/ +void PrintBSPFileSizes (void) +{ + if (!num_entities) + ParseEntities (); + + printf ("%5i models %7i\n" + ,nummodels, (int)(nummodels*sizeof(dmodel_t))); + printf ("%5i brushes %7i\n" + ,numbrushes, (int)(numbrushes*sizeof(dbrush_t))); + printf ("%5i brushsides %7i\n" + ,numbrushsides, (int)(numbrushsides*sizeof(dbrushside_t))); + printf ("%5i planes %7i\n" + ,numplanes, (int)(numplanes*sizeof(dplane_t))); + printf ("%5i texinfo %7i\n" + ,numtexinfo, (int)(numtexinfo*sizeof(texinfo_t))); + printf ("%5i entdata %7i\n", num_entities, entdatasize); + + printf ("\n"); + + printf ("%5i vertexes %7i\n" + ,numvertexes, (int)(numvertexes*sizeof(dvertex_t))); + printf ("%5i nodes %7i\n" + ,numnodes, (int)(numnodes*sizeof(dnode_t))); + printf ("%5i faces %7i\n" + ,numfaces, (int)(numfaces*sizeof(dface_t))); + printf ("%5i leafs %7i\n" + ,numleafs, (int)(numleafs*sizeof(dleaf_t))); + printf ("%5i leaffaces %7i\n" + ,numleaffaces, (int)(numleaffaces*sizeof(dleaffaces[0]))); + printf ("%5i leafbrushes %7i\n" + ,numleafbrushes, (int)(numleafbrushes*sizeof(dleafbrushes[0]))); + printf ("%5i surfedges %7i\n" + ,numsurfedges, (int)(numsurfedges*sizeof(dsurfedges[0]))); + printf ("%5i edges %7i\n" + ,numedges, (int)(numedges*sizeof(dedge_t))); + printf (" lightdata %7i\n", lightdatasize); + printf (" visdata %7i\n", visdatasize); +} + + +//============================================ + +int num_entities; +entity_t entities[MAX_MAP_ENTITIES]; + +void StripTrailing (char *e) +{ + char *s; + + s = e + strlen(e)-1; + while (s >= e && *s <= 32) + { + *s = 0; + s--; + } +} + +/* +================= +ParseEpair +================= +*/ +epair_t *ParseEpair (void) +{ + epair_t *e; + + e = malloc (sizeof(epair_t)); + memset (e, 0, sizeof(epair_t)); + + if (strlen(token) >= MAX_KEY-1) + Error ("ParseEpar: token too long"); + e->key = copystring(token); + GetToken (false); + if (strlen(token) >= MAX_VALUE-1) + Error ("ParseEpar: token too long"); + e->value = copystring(token); + + // strip trailing spaces + StripTrailing (e->key); + StripTrailing (e->value); + + return e; +} + + +/* +================ +ParseEntity +================ +*/ +qboolean ParseEntity (void) +{ + epair_t *e; + entity_t *mapent; + + if (!GetToken (true)) + return false; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + if (num_entities == MAX_MAP_ENTITIES) + Error ("num_entities == MAX_MAP_ENTITIES"); + + mapent = &entities[num_entities]; + num_entities++; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + e = ParseEpair (); + e->next = mapent->epairs; + mapent->epairs = e; + } while (1); + + return true; +} + +/* +================ +ParseEntities + +Parses the dentdata string into entities +================ +*/ +void ParseEntities (void) +{ + num_entities = 0; + ParseFromMemory (dentdata, entdatasize); + + while (ParseEntity ()) + { + } +} + + +/* +================ +UnparseEntities + +Generates the dentdata string from all the entities +================ +*/ +void UnparseEntities (void) +{ + char *buf, *end; + epair_t *ep; + char line[2048]; + int i; + char key[1024], value[1024]; + + buf = dentdata; + end = buf; + *end = 0; + + for (i=0 ; inext) + { + strcpy (key, ep->key); + StripTrailing (key); + strcpy (value, ep->value); + StripTrailing (value); + + sprintf (line, "\"%s\" \"%s\"\n", key, value); + strcat (end, line); + end += strlen(line); + } + strcat (end,"}\n"); + end += 2; + + if (end > buf + MAX_MAP_ENTSTRING) + Error ("Entity text too long"); + } + entdatasize = end - buf + 1; +} + +void PrintEntity (entity_t *ent) +{ + epair_t *ep; + + printf ("------- entity %p -------\n", ent); + for (ep=ent->epairs ; ep ; ep=ep->next) + { + printf ("%s = %s\n", ep->key, ep->value); + } + +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = copystring(value); + return; + } + ep = malloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = copystring(key); + ep->value = copystring(value); +} + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +vec_t FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + double v1, v2, v3; + + k = ValueForKey (ent, key); +// scanf into doubles, then assign, so it is vec_t size independent + v1 = v2 = v3 = 0; + sscanf (k, "%lf %lf %lf", &v1, &v2, &v3); + vec[0] = v1; + vec[1] = v2; + vec[2] = v3; +} + + diff --git a/tools/quake2/extra/common/bspfile.h b/tools/quake2/extra/common/bspfile.h new file mode 100644 index 00000000..11eeb031 --- /dev/null +++ b/tools/quake2/extra/common/bspfile.h @@ -0,0 +1,129 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qfiles.h" + + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; +extern dvis_t *dvis; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int numleaffaces; +extern unsigned short dleaffaces[MAX_MAP_LEAFFACES]; + +extern int numleafbrushes; +extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + +extern int numareas; +extern darea_t dareas[MAX_MAP_AREAS]; + +extern int numareaportals; +extern dareaportal_t dareaportals[MAX_MAP_AREAPORTALS]; + +extern int numbrushes; +extern dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +extern int numbrushsides; +extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + +extern byte dpop[256]; + +void DecompressVis (byte *in, byte *decompressed); +int CompressVis (byte *vis, byte *dest); + +void LoadBSPFile (char *filename); +void LoadBSPFileTexinfo (char *filename); // just for qdata +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +//=============== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + int firstbrush; + int numbrushes; + epair_t *epairs; + +// only valid for func_areaportals + int areaportalnum; + int portalareas[2]; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities (void); +void UnparseEntities (void); + +void SetKeyValue (entity_t *ent, char *key, char *value); +char *ValueForKey (entity_t *ent, char *key); +// will return "" if not present + +vec_t FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +epair_t *ParseEpair (void); + +void PrintEntity (entity_t *ent); + diff --git a/tools/quake2/extra/common/cmdlib.c b/tools/quake2/extra/common/cmdlib.c new file mode 100644 index 00000000..60f615a0 --- /dev/null +++ b/tools/quake2/extra/common/cmdlib.c @@ -0,0 +1,1055 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// cmdlib.c + +#include "cmdlib.h" +#include +#include + +#ifdef WIN32 +#include +#endif + +#ifdef NeXT +#include +#endif + +#define BASEDIRNAME "quake2" +#define PATHSEPERATOR '/' + +// set these before calling CheckParm +int myargc; +char **myargv; + +char com_token[1024]; +qboolean com_eof; + +qboolean archive; +char archivedir[1024]; + + +/* +=================== +ExpandWildcards + +Mimic unix command line expansion +=================== +*/ +#define MAX_EX_ARGC 1024 +int ex_argc; +char *ex_argv[MAX_EX_ARGC]; +#ifdef _WIN32 +#include "io.h" +void ExpandWildcards (int *argc, char ***argv) +{ + struct _finddata_t fileinfo; + int handle; + int i; + char filename[1024]; + char filebase[1024]; + char *path; + + ex_argc = 0; + for (i=0 ; i<*argc ; i++) + { + path = (*argv)[i]; + if ( path[0] == '-' + || ( !strstr(path, "*") && !strstr(path, "?") ) ) + { + ex_argv[ex_argc++] = path; + continue; + } + + handle = _findfirst (path, &fileinfo); + if (handle == -1) + return; + + ExtractFilePath (path, filebase); + + do + { + sprintf (filename, "%s%s", filebase, fileinfo.name); + ex_argv[ex_argc++] = copystring (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); + } + + *argc = ex_argc; + *argv = ex_argv; +} +#else +void ExpandWildcards (int *argc, char ***argv) +{ +} +#endif + +#ifdef WIN_ERROR +#include +/* +================= +Error + +For abnormal program terminations in windowed apps +================= +*/ +void Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + char text2[1024]; + int err; + + err = GetLastError (); + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + sprintf (text2, "%s\nGetLastError() = %i", text, err); + MessageBox(NULL, text2, "Error", 0 /* MB_OK */ ); + + exit (1); +} + +#else +/* +================= +Error + +For abnormal program terminations in console apps +================= +*/ +void Error (char *error, ...) +{ + va_list argptr; + + printf ("\n************ ERROR ************\n"); + + va_start (argptr,error); + vprintf (error,argptr); + va_end (argptr); + printf ("\n"); + + exit (1); +} +#endif + +// only printf if in verbose mode +qboolean verbose = false; +void qprintf (char *format, ...) +{ + va_list argptr; + + if (!verbose) + return; + + va_start (argptr,format); + vprintf (format,argptr); + va_end (argptr); +} + + +/* + +qdir will hold the path up to the quake directory, including the slash + + f:\quake\ + /raid/quake/ + +gamedir will hold qdir + the game directory (id1, id2, etc) + + */ + +char qdir[1024]; +char gamedir[1024]; + +void SetQdirFromPath (char *path) +{ + char temp[1024]; + char *c; + int len; + + if (!(path[0] == '/' || path[0] == '\\' || path[1] == ':')) + { // path is partial + Q_getwd (temp); + strcat (temp, path); + path = temp; + } + + // search for "quake2" in path + + len = strlen(BASEDIRNAME); + for (c=path+strlen(path)-1 ; c != path ; c--) + if (!Q_strncasecmp (c, BASEDIRNAME, len)) + { + strncpy (qdir, path, c+len+1-path); + qprintf ("qdir: %s\n", qdir); + c += len+1; + while (*c) + { + if (*c == '/' || *c == '\\') + { + strncpy (gamedir, path, c+1-path); + qprintf ("gamedir: %s\n", gamedir); + return; + } + c++; + } + Error ("No gamedir in %s", path); + return; + } + Error ("SetQdirFromPath: no '%s' in %s", BASEDIRNAME, path); +} + +char *ExpandArg (char *path) +{ + static char full[1024]; + + if (path[0] != '/' && path[0] != '\\' && path[1] != ':') + { + Q_getwd (full); + strcat (full, path); + } + else + strcpy (full, path); + return full; +} + +char *ExpandPath (char *path) +{ + static char full[1024]; + if (!qdir) + Error ("ExpandPath called without qdir set"); + if (path[0] == '/' || path[0] == '\\' || path[1] == ':') + return path; + sprintf (full, "%s%s", qdir, path); + return full; +} + +char *ExpandPathAndArchive (char *path) +{ + char *expanded; + char archivename[1024]; + + expanded = ExpandPath (path); + + if (archive) + { + sprintf (archivename, "%s/%s", archivedir, path); + QCopyFile (expanded, archivename); + } + return expanded; +} + + +char *copystring(char *s) +{ + char *b; + b = malloc(strlen(s)+1); + strcpy (b, s); + return b; +} + + + +/* +================ +I_FloatTime +================ +*/ +double I_FloatTime (void) +{ + time_t t; + + time (&t); + + return t; +#if 0 +// more precise, less portable + struct timeval tp; + struct timezone tzp; + static int secbase; + + gettimeofday(&tp, &tzp); + + if (!secbase) + { + secbase = tp.tv_sec; + return tp.tv_usec/1000000.0; + } + + return (tp.tv_sec - secbase) + tp.tv_usec/1000000.0; +#endif +} + +void Q_getwd (char *out) +{ +#ifdef WIN32 + _getcwd (out, 256); + strcat (out, "\\"); +#else + getwd (out); + strcat (out, "/"); +#endif +} + + +void Q_mkdir (char *path) +{ +#ifdef WIN32 + if (_mkdir (path) != -1) + return; +#else + if (mkdir (path, 0777) != -1) + return; +#endif + if (errno != EEXIST) + Error ("mkdir %s: %s",path, strerror(errno)); +} + +/* +============ +FileTime + +returns -1 if not present +============ +*/ +int FileTime (char *path) +{ + struct stat buf; + + if (stat (path,&buf) == -1) + return -1; + + return buf.st_mtime; +} + + + +/* +============== +COM_Parse + +Parse a token out of a string +============== +*/ +char *COM_Parse (char *data) +{ + int c; + int len; + + len = 0; + com_token[0] = 0; + + if (!data) + return NULL; + +// skip whitespace +skipwhite: + while ( (c = *data) <= ' ') + { + if (c == 0) + { + com_eof = true; + return NULL; // end of file; + } + data++; + } + +// skip // comments + if (c=='/' && data[1] == '/') + { + while (*data && *data != '\n') + data++; + goto skipwhite; + } + + +// handle quoted strings specially + if (c == '\"') + { + data++; + do + { + c = *data++; + if (c=='\"') + { + com_token[len] = 0; + return data; + } + com_token[len] = c; + len++; + } while (1); + } + +// parse single characters + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + { + com_token[len] = c; + len++; + com_token[len] = 0; + return data+1; + } + +// parse a regular word + do + { + com_token[len] = c; + data++; + len++; + c = *data; + if (c=='{' || c=='}'|| c==')'|| c=='(' || c=='\'' || c==':') + break; + } while (c>32); + + com_token[len] = 0; + return data; +} + + +int Q_strncasecmp (char *s1, char *s2, int n) +{ + int c1, c2; + + do + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + } while (c1); + + return 0; // strings are equal +} + +int Q_strcasecmp (char *s1, char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + + +char *strupr (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = toupper(*in); + in++; + } + return start; +} + +char *strlower (char *start) +{ + char *in; + in = start; + while (*in) + { + *in = tolower(*in); + in++; + } + return start; +} + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (char *check) +{ + int i; + + for (i = 1;i 0 && path[length] != PATHSEPERATOR) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/') + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +// FIXME: should include the slash, otherwise +// backing to an empty path will be wrong when appending a slash +void ExtractFilePath (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '\\' && *(src-1) != '/') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileBase (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != PATHSEPERATOR) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (char *hex) +{ + char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + +#endif + + +//======================================================= + + +// FIXME: byte swap? + +// this is a 16 bit, non-reflected CRC using the polynomial 0x1021 +// and the initial and final xor values shown below... in other words, the +// CCITT standard CRC used by XMODEM + +#define CRC_INIT_VALUE 0xffff +#define CRC_XOR_VALUE 0x0000 + +static unsigned short crctable[256] = +{ + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +void CRC_Init(unsigned short *crcvalue) +{ + *crcvalue = CRC_INIT_VALUE; +} + +void CRC_ProcessByte(unsigned short *crcvalue, byte data) +{ + *crcvalue = (*crcvalue << 8) ^ crctable[(*crcvalue >> 8) ^ data]; +} + +unsigned short CRC_Value(unsigned short crcvalue) +{ + return crcvalue ^ CRC_XOR_VALUE; +} +//============================================================================= + +/* +============ +CreatePath +============ +*/ +void CreatePath (char *path) +{ + char *ofs, c; + + if (path[1] == ':') + path += 2; + + for (ofs = path+1 ; *ofs ; ofs++) + { + c = *ofs; + if (c == '/' || c == '\\') + { // create the directory + *ofs = 0; + Q_mkdir (path); + *ofs = c; + } + } +} + + +/* +============ +QCopyFile + + Used to archive source files +============ +*/ +void QCopyFile (char *from, char *to) +{ + void *buffer; + int length; + + length = LoadFile (from, &buffer); + CreatePath (to); + SaveFile (to, buffer, length); + free (buffer); +} diff --git a/tools/quake2/extra/common/cmdlib.h b/tools/quake2/extra/common/cmdlib.h new file mode 100644 index 00000000..0045a09d --- /dev/null +++ b/tools/quake2/extra/common/cmdlib.h @@ -0,0 +1,145 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#ifdef _WIN32 +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#pragma warning(disable : 4018) // signed/unsigned mismatch +#pragma warning(disable : 4305) // truncate from double to float +#endif + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum {false, true} qboolean; +typedef unsigned char byte; +#endif + +// the dec offsetof macro doesnt work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +char *strupr (char *in); +char *strlower (char *in); +int Q_strncasecmp (char *s1, char *s2, int n); +int Q_strcasecmp (char *s1, char *s2); +void Q_getwd (char *out); + +int Q_filelength (FILE *f); +int FileTime (char *path); + +void Q_mkdir (char *path); + +extern char qdir[1024]; +extern char gamedir[1024]; +void SetQdirFromPath (char *path); +char *ExpandArg (char *path); // from cmd line +char *ExpandPath (char *path); // from scripts +char *ExpandPathAndArchive (char *path); + + +double I_FloatTime (void); + +void Error (char *error, ...); +int CheckParm (char *check); + +FILE *SafeOpenWrite (char *filename); +FILE *SafeOpenRead (char *filename); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, void *buffer, int count); + +int LoadFile (char *filename, void **bufferptr); +int TryLoadFile (char *filename, void **bufferptr); +void SaveFile (char *filename, void *buffer, int count); +qboolean FileExists (char *filename); + +void DefaultExtension (char *path, char *extension); +void DefaultPath (char *path, char *basepath); +void StripFilename (char *path); +void StripExtension (char *path); + +void ExtractFilePath (char *path, char *dest); +void ExtractFileBase (char *path, char *dest); +void ExtractFileExtension (char *path, char *dest); + +int ParseNum (char *str); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +char *copystring(char *s); + + +void CRC_Init(unsigned short *crcvalue); +void CRC_ProcessByte(unsigned short *crcvalue, byte data); +unsigned short CRC_Value(unsigned short crcvalue); + +void CreatePath (char *path); +void QCopyFile (char *from, char *to); + +extern qboolean archive; +extern char archivedir[1024]; + + +extern qboolean verbose; +void qprintf (char *format, ...); + +void ExpandWildcards (int *argc, char ***argv); + + +// for compression routines +typedef struct +{ + byte *data; + int count; +} cblock_t; + + +#endif diff --git a/tools/quake2/extra/common/l3dslib.c b/tools/quake2/extra/common/l3dslib.c new file mode 100644 index 00000000..8441f4af --- /dev/null +++ b/tools/quake2/extra/common/l3dslib.c @@ -0,0 +1,301 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// l3dslib.c: library for loading triangles from an Alias triangle file +// + +#include +#include "cmdlib.h" +#include "mathlib.h" +#include "trilib.h" +#include "l3dslib.h" + +#define MAIN3DS 0x4D4D +#define EDIT3DS 0x3D3D // this is the start of the editor config +#define EDIT_OBJECT 0x4000 +#define OBJ_TRIMESH 0x4100 +#define TRI_VERTEXL 0x4110 +#define TRI_FACEL1 0x4120 + +#define MAXVERTS 2000 + +typedef struct { + int v[4]; +} tri; + +float fverts[MAXVERTS][3]; +tri tris[MAXTRIANGLES]; + +int bytesread, level, numtris, totaltris; +int vertsfound, trisfound; + +triangle_t *ptri; + + +// Alias stores triangles as 3 explicit vertices in .tri files, so even though we +// start out with a vertex pool and vertex indices for triangles, we have to convert +// to raw, explicit triangles +void StoreAliasTriangles (void) +{ + int i, j, k; + + if ((totaltris + numtris) > MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0; i MAXVERTS) + Error ("Error: Too many vertices"); + + for (i=0 ; i MAXTRIANGLES) + Error ("Error: Too many triangles"); + + for (i=0 ; i 0) + { + w -= ParseChunk (input); + } + + retval = length; + goto Done; + + default: + // skip other chunks + while (w > 0) + { + t = w; + + if (t > BLOCK_SIZE) + t = BLOCK_SIZE; + + if (feof(input)) + Error ("Error: unexpected end of file"); + + fread (&temp, t, 1, input); + bytesread += t; + + w -= t; + } + + retval = length; + goto Done; + } + +Done: + level--; + return retval; +} + + +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles) +{ + FILE *input; + short int tshort; + + bytesread = 0; + level = 0; + numtris = 0; + totaltris = 0; + vertsfound = 0; + trisfound = 0; + + if ((input = fopen(filename, "rb")) == 0) { + fprintf(stderr,"reader: could not open file '%s'\n", filename); + exit(0); + } + + fread(&tshort, sizeof(tshort), 1, input); + +// should only be MAIN3DS, but some files seem to start with EDIT3DS, with +// no MAIN3DS + if ((tshort != MAIN3DS) && (tshort != EDIT3DS)) { + fprintf(stderr,"File is not a 3DS file.\n"); + exit(0); + } + +// back to top of file so we can parse the first chunk descriptor + fseek(input, 0, SEEK_SET); + + ptri = malloc (MAXTRIANGLES * sizeof(triangle_t)); + + *pptri = ptri; + +// parse through looking for the relevant chunk tree (MAIN3DS | EDIT3DS | EDIT_OBJECT | +// OBJ_TRIMESH | {TRI_VERTEXL, TRI_FACEL1}) and skipping other chunks + ParseChunk (input); + + if (vertsfound || trisfound) + Error ("Incomplete triangle set"); + + *numtriangles = totaltris; + + fclose (input); +} + diff --git a/tools/quake2/extra/common/l3dslib.h b/tools/quake2/extra/common/l3dslib.h new file mode 100644 index 00000000..d28871f1 --- /dev/null +++ b/tools/quake2/extra/common/l3dslib.h @@ -0,0 +1,27 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// l3dslib.h: header file for loading triangles from a 3DS triangle file +// +void Load3DSTriangleList (char *filename, triangle_t **pptri, int *numtriangles); + diff --git a/tools/quake2/extra/common/lbmlib.c b/tools/quake2/extra/common/lbmlib.c new file mode 100644 index 00000000..25793534 --- /dev/null +++ b/tools/quake2/extra/common/lbmlib.c @@ -0,0 +1,824 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// lbmlib.c + +#include "cmdlib.h" +#include "lbmlib.h" + + + +/* +============================================================================ + + LBM STUFF + +============================================================================ +*/ + + +typedef unsigned char UBYTE; +//conflicts with windows typedef short WORD; +typedef unsigned short UWORD; +typedef long LONG; + +typedef enum +{ + ms_none, + ms_mask, + ms_transcolor, + ms_lasso +} mask_t; + +typedef enum +{ + cm_none, + cm_rle1 +} compress_t; + +typedef struct +{ + UWORD w,h; + short x,y; + UBYTE nPlanes; + UBYTE masking; + UBYTE compression; + UBYTE pad1; + UWORD transparentColor; + UBYTE xAspect,yAspect; + short pageWidth,pageHeight; +} bmhd_t; + +extern bmhd_t bmhd; // will be in native byte order + + + +#define FORMID ('F'+('O'<<8)+((int)'R'<<16)+((int)'M'<<24)) +#define ILBMID ('I'+('L'<<8)+((int)'B'<<16)+((int)'M'<<24)) +#define PBMID ('P'+('B'<<8)+((int)'M'<<16)+((int)' '<<24)) +#define BMHDID ('B'+('M'<<8)+((int)'H'<<16)+((int)'D'<<24)) +#define BODYID ('B'+('O'<<8)+((int)'D'<<16)+((int)'Y'<<24)) +#define CMAPID ('C'+('M'<<8)+((int)'A'<<16)+((int)'P'<<24)) + + +bmhd_t bmhd; + +int Align (int l) +{ + if (l&1) + return l+1; + return l; +} + + + +/* +================ +LBMRLEdecompress + +Source must be evenly aligned! +================ +*/ +byte *LBMRLEDecompress (byte *source,byte *unpacked, int bpwidth) +{ + int count; + byte b,rept; + + count = 0; + + do + { + rept = *source++; + + if (rept > 0x80) + { + rept = (rept^0xff)+2; + b = *source++; + memset(unpacked,b,rept); + unpacked += rept; + } + else if (rept < 0x80) + { + rept++; + memcpy(unpacked,source,rept); + unpacked += rept; + source += rept; + } + else + rept = 0; // rept of 0x80 is NOP + + count += rept; + + } while (countbpwidth) + Error ("Decompression exceeded width!\n"); + + + return source; +} + + +/* +================= +LoadLBM +================= +*/ +void LoadLBM (char *filename, byte **picture, byte **palette) +{ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + + int formtype,formlength; + int chunktype,chunklength; + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + +// +// load the LBM +// + LoadFile (filename, (void **)&LBMbuffer); + +// +// parse the LBM header +// + LBM_P = LBMbuffer; + if ( *(int *)LBMbuffer != LittleLong(FORMID) ) + Error ("No FORM ID at start of file!\n"); + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align(formlength); + + formtype = LittleLong(*(int *)LBM_P); + + if (formtype != ILBMID && formtype != PBMID) + Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff + ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + + LBM_P += 4; + +// +// parse chunks +// + + while (LBM_P < LBMEND_P) + { + chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + LBM_P += 4; + chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + LBM_P += 4; + + switch ( chunktype ) + { + case BMHDID: + memcpy (&bmhd,LBM_P,sizeof(bmhd)); + bmhd.w = BigShort(bmhd.w); + bmhd.h = BigShort(bmhd.h); + bmhd.x = BigShort(bmhd.x); + bmhd.y = BigShort(bmhd.y); + bmhd.pageWidth = BigShort(bmhd.pageWidth); + bmhd.pageHeight = BigShort(bmhd.pageHeight); + break; + + case CMAPID: + cmapbuffer = malloc (768); + memset (cmapbuffer, 0, 768); + memcpy (cmapbuffer, LBM_P, chunklength); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = malloc (bmhd.w*bmhd.h); + if (formtype == PBMID) + { + // + // unpack PBM + // + for (y=0 ; ydata; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + Error ("Bad pcx file %s", filename); + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + if (!out) + Error ("Skin_Cache: couldn't allocate"); + + *pic = out; + + pix = out; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + Error ("PCX file %s was malformed", filename); + + free (pcx); +} + +/* +============== +WritePCXfile +============== +*/ +void WritePCXfile (char *filename, byte *data, + int width, int height, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = malloc (width*height*2+1000); + memset (pcx, 0, sizeof(*pcx)); + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(2); // not a grey scale + + // pack the image + pack = &pcx->data; + + for (i=0 ; i=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + fclose(fin); +} diff --git a/tools/quake2/extra/common/lbmlib.h b/tools/quake2/extra/common/lbmlib.h new file mode 100644 index 00000000..c90a6dd8 --- /dev/null +++ b/tools/quake2/extra/common/lbmlib.h @@ -0,0 +1,40 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// piclib.h + + +void LoadLBM (char *filename, byte **picture, byte **palette); +void WriteLBMfile (char *filename, byte *data, int width, int height + , byte *palette); +void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height); +void WritePCXfile (char *filename, byte *data, int width, int height + , byte *palette); + +// loads / saves either lbm or pcx, depending on extension +void Load256Image (char *name, byte **pixels, byte **palette, + int *width, int *height); +void Save256Image (char *name, byte *pixels, byte *palette, + int width, int height); + + +void LoadTGA (char *filename, byte **pixels, int *width, int *height); diff --git a/tools/quake2/extra/common/mathlib.c b/tools/quake2/extra/common/mathlib.c new file mode 100644 index 00000000..207027b3 --- /dev/null +++ b/tools/quake2/extra/common/mathlib.c @@ -0,0 +1,174 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// mathlib.c -- math primitives + +#include "cmdlib.h" +#include "mathlib.h" + +vec3_t vec3_origin = {0,0,0}; + + +double VectorLength(vec3_t v) +{ + int i; + double length; + + length = 0; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = sqrt (length); // FIXME + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return false; + + return true; +} + +vec_t Q_rint (vec_t in) +{ + return floor (in + 0.5); +} + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +void _VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} + +vec_t VectorNormalize (vec3_t in, vec3_t out) +{ + vec_t length, ilength; + + length = sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +vec_t ColorNormalize (vec3_t in, vec3_t out) +{ + float max, scale; + + max = in[0]; + if (in[1] > max) + max = in[1]; + if (in[2] > max) + max = in[2]; + + if (max == 0) + return 0; + + scale = 1.0 / max; + + VectorScale (in, scale, out); + + return max; +} + + + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void ClearBounds (vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} diff --git a/tools/quake2/extra/common/mathlib.h b/tools/quake2/extra/common/mathlib.h new file mode 100644 index 00000000..ee7fddee --- /dev/null +++ b/tools/quake2/extra/common/mathlib.h @@ -0,0 +1,77 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h + +#include + +#ifdef DOUBLEVEC_T +typedef double vec_t; +#else +typedef float vec_t; +#endif +typedef vec_t vec3_t[3]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +#define Q_PI 3.14159265358979323846 + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorNegate(x) {x[0]=-x[0];x[1]=-x[1];x[2]=-x[2];} + +vec_t Q_rint (vec_t in); +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); +void _VectorScale (vec3_t v, vec_t scale, vec3_t out); + +double VectorLength(vec3_t v); + +void VectorMA (vec3_t va, double scale, vec3_t vb, vec3_t vc); + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (vec3_t in, vec3_t out); +vec_t ColorNormalize (vec3_t in, vec3_t out); +void VectorInverse (vec3_t v); + +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +#endif diff --git a/tools/quake2/extra/common/mdfour.c b/tools/quake2/extra/common/mdfour.c new file mode 100644 index 00000000..f5b9a29d --- /dev/null +++ b/tools/quake2/extra/common/mdfour.c @@ -0,0 +1,224 @@ +/* + mdfour.c + + An implementation of MD4 designed for use in the samba SMB + authentication protocol + + Copyright (C) 1997-1998 Andrew Tridgell + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA + + $Id: mdfour.c,v 1.1 2002/08/23 22:03:27 abster Exp $ +*/ + +#include /* XoXus: needed for memset call */ +#include "mdfour.h" + +/* NOTE: This code makes no attempt to be fast! + + It assumes that a int is at least 32 bits long +*/ + +static struct mdfour *m; + +#define F(X,Y,Z) (((X)&(Y)) | ((~(X))&(Z))) +#define G(X,Y,Z) (((X)&(Y)) | ((X)&(Z)) | ((Y)&(Z))) +#define H(X,Y,Z) ((X)^(Y)^(Z)) +#ifdef LARGE_INT32 +#define lshift(x,s) ((((x)<<(s))&0xFFFFFFFF) | (((x)>>(32-(s)))&0xFFFFFFFF)) +#else +#define lshift(x,s) (((x)<<(s)) | ((x)>>(32-(s)))) +#endif + +#define ROUND1(a,b,c,d,k,s) a = lshift(a + F(b,c,d) + X[k], s) +#define ROUND2(a,b,c,d,k,s) a = lshift(a + G(b,c,d) + X[k] + 0x5A827999,s) +#define ROUND3(a,b,c,d,k,s) a = lshift(a + H(b,c,d) + X[k] + 0x6ED9EBA1,s) + +/* this applies md4 to 64 byte chunks */ +static void mdfour64(uint32 *M) +{ + int j; + uint32 AA, BB, CC, DD; + uint32 X[16]; + uint32 A,B,C,D; + + for (j=0;j<16;j++) + X[j] = M[j]; + + A = m->A; B = m->B; C = m->C; D = m->D; + AA = A; BB = B; CC = C; DD = D; + + ROUND1(A,B,C,D, 0, 3); ROUND1(D,A,B,C, 1, 7); + ROUND1(C,D,A,B, 2, 11); ROUND1(B,C,D,A, 3, 19); + ROUND1(A,B,C,D, 4, 3); ROUND1(D,A,B,C, 5, 7); + ROUND1(C,D,A,B, 6, 11); ROUND1(B,C,D,A, 7, 19); + ROUND1(A,B,C,D, 8, 3); ROUND1(D,A,B,C, 9, 7); + ROUND1(C,D,A,B, 10, 11); ROUND1(B,C,D,A, 11, 19); + ROUND1(A,B,C,D, 12, 3); ROUND1(D,A,B,C, 13, 7); + ROUND1(C,D,A,B, 14, 11); ROUND1(B,C,D,A, 15, 19); + + ROUND2(A,B,C,D, 0, 3); ROUND2(D,A,B,C, 4, 5); + ROUND2(C,D,A,B, 8, 9); ROUND2(B,C,D,A, 12, 13); + ROUND2(A,B,C,D, 1, 3); ROUND2(D,A,B,C, 5, 5); + ROUND2(C,D,A,B, 9, 9); ROUND2(B,C,D,A, 13, 13); + ROUND2(A,B,C,D, 2, 3); ROUND2(D,A,B,C, 6, 5); + ROUND2(C,D,A,B, 10, 9); ROUND2(B,C,D,A, 14, 13); + ROUND2(A,B,C,D, 3, 3); ROUND2(D,A,B,C, 7, 5); + ROUND2(C,D,A,B, 11, 9); ROUND2(B,C,D,A, 15, 13); + + ROUND3(A,B,C,D, 0, 3); ROUND3(D,A,B,C, 8, 9); + ROUND3(C,D,A,B, 4, 11); ROUND3(B,C,D,A, 12, 15); + ROUND3(A,B,C,D, 2, 3); ROUND3(D,A,B,C, 10, 9); + ROUND3(C,D,A,B, 6, 11); ROUND3(B,C,D,A, 14, 15); + ROUND3(A,B,C,D, 1, 3); ROUND3(D,A,B,C, 9, 9); + ROUND3(C,D,A,B, 5, 11); ROUND3(B,C,D,A, 13, 15); + ROUND3(A,B,C,D, 3, 3); ROUND3(D,A,B,C, 11, 9); + ROUND3(C,D,A,B, 7, 11); ROUND3(B,C,D,A, 15, 15); + + A += AA; B += BB; C += CC; D += DD; + +#ifdef LARGE_INT32 + A &= 0xFFFFFFFF; B &= 0xFFFFFFFF; + C &= 0xFFFFFFFF; D &= 0xFFFFFFFF; +#endif + + for (j=0;j<16;j++) + X[j] = 0; + + m->A = A; m->B = B; m->C = C; m->D = D; +} + +static void copy64(uint32 *M, unsigned char *in) +{ + int i; + + for (i=0;i<16;i++) + M[i] = (in[i*4+3]<<24) | (in[i*4+2]<<16) | + (in[i*4+1]<<8) | (in[i*4+0]<<0); +} + +static void copy4(unsigned char *out,uint32 x) +{ + out[0] = x&0xFF; + out[1] = (x>>8)&0xFF; + out[2] = (x>>16)&0xFF; + out[3] = (x>>24)&0xFF; +} + +void mdfour_begin(struct mdfour *md) +{ + md->A = 0x67452301; + md->B = 0xefcdab89; + md->C = 0x98badcfe; + md->D = 0x10325476; + md->totalN = 0; +} + + +static void mdfour_tail(unsigned char *in, int n) +{ + unsigned char buf[128]; + uint32 M[16]; + uint32 b; + + m->totalN += n; + + b = m->totalN * 8; + + memset(buf, 0, 128); + if (n) memcpy(buf, in, n); + buf[n] = 0x80; + + if (n <= 55) { + copy4(buf+56, b); + copy64(M, buf); + mdfour64(M); + } else { + copy4(buf+120, b); + copy64(M, buf); + mdfour64(M); + copy64(M, buf+64); + mdfour64(M); + } +} + +void mdfour_update(struct mdfour *md, unsigned char *in, int n) +{ + uint32 M[16]; + + if (n == 0) mdfour_tail(in, n); + + m = md; + + while (n >= 64) { + copy64(M, in); + mdfour64(M); + in += 64; + n -= 64; + m->totalN += 64; + } + + mdfour_tail(in, n); +} + + +void mdfour_result(struct mdfour *md, unsigned char *out) +{ + m = md; + + copy4(out, m->A); + copy4(out+4, m->B); + copy4(out+8, m->C); + copy4(out+12, m->D); +} + + +void mdfour(unsigned char *out, unsigned char *in, int n) +{ + struct mdfour md; + mdfour_begin(&md); + mdfour_update(&md, in, n); + mdfour_result(&md, out); +} + +/////////////////////////////////////////////////////////////// +// MD4-based checksum utility functions +// +// Copyright (C) 2000 Jeff Teunissen +// +// Author: Jeff Teunissen +// Date: 01 Jan 2000 + +unsigned Com_BlockChecksum (void *buffer, int length) +{ + int digest[4]; + unsigned val; + + mdfour ( (unsigned char *) digest, (unsigned char *) buffer, length ); + + val = digest[0] ^ digest[1] ^ digest[2] ^ digest[3]; + + return val; +} + +void Com_BlockFullChecksum (void *buffer, int len, unsigned char *outbuf) +{ + mdfour ( outbuf, (unsigned char *) buffer, len ); +} + diff --git a/tools/quake2/extra/common/mdfour.h b/tools/quake2/extra/common/mdfour.h new file mode 100644 index 00000000..69ca6f78 --- /dev/null +++ b/tools/quake2/extra/common/mdfour.h @@ -0,0 +1,54 @@ +/* + mdfour.h + + an implementation of MD4 designed for use in the SMB authentication + protocol + + Copyright (C) Andrew Tridgell 1997-1998 + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation; either version 2 + of the License, or (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to: + + Free Software Foundation, Inc. + 59 Temple Place - Suite 330 + Boston, MA 02111-1307, USA +*/ + +#ifndef _MDFOUR_H +#define _MDFOUR_H + +#ifndef int32 +#define int32 int +#endif + +#if SIZEOF_INT > 4 +#define LARGE_INT32 +#endif + +#ifndef uint32 +#define uint32 unsigned int32 +#endif + +struct mdfour { + uint32 A, B, C, D; + uint32 totalN; +}; + +void mdfour_begin(struct mdfour *md); // old: MD4Init +void mdfour_update(struct mdfour *md, unsigned char *in, int n); //old: MD4Update +void mdfour_result(struct mdfour *md, unsigned char *out); // old: MD4Final +void mdfour(unsigned char *out, unsigned char *in, int n); + +#endif // _MDFOUR_H + diff --git a/tools/quake2/extra/common/polylib.c b/tools/quake2/extra/common/polylib.c new file mode 100644 index 00000000..c190ebd6 --- /dev/null +++ b/tools/quake2/extra/common/polylib.c @@ -0,0 +1,642 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "polylib.h" + + +extern int numthreads; + +// counters are only bumped when running single threaded, +// because they are an awefull coherence problem +int c_active_windings; +int c_peak_windings; +int c_winding_allocs; +int c_winding_points; + +#define BOGUS_RANGE 8192 + +void pw(winding_t *w) +{ + int i; + for (i=0 ; inumpoints ; i++) + printf ("(%5.1f, %5.1f, %5.1f)\n",w->p[i][0], w->p[i][1],w->p[i][2]); +} + + +/* +============= +AllocWinding +============= +*/ +winding_t *AllocWinding (int points) +{ + winding_t *w; + int s; + + if (numthreads == 1) + { + c_winding_allocs++; + c_winding_points += points; + c_active_windings++; + if (c_active_windings > c_peak_windings) + c_peak_windings = c_active_windings; + } + s = sizeof(vec_t)*3*points + sizeof(int); + w = malloc (s); + memset (w, 0, s); + return w; +} + +void FreeWinding (winding_t *w) +{ + if (*(unsigned *)w == 0xdeaddead) + Error ("FreeWinding: freed a freed winding"); + *(unsigned *)w = 0xdeaddead; + + if (numthreads == 1) + c_active_windings--; + free (w); +} + +/* +============ +RemoveColinearPoints +============ +*/ +int c_removed; + +void RemoveColinearPoints (winding_t *w) +{ + int i, j, k; + vec3_t v1, v2; + int nump; + vec3_t p[MAX_POINTS_ON_WINDING]; + + nump = 0; + for (i=0 ; inumpoints ; i++) + { + j = (i+1)%w->numpoints; + k = (i+w->numpoints-1)%w->numpoints; + VectorSubtract (w->p[j], w->p[i], v1); + VectorSubtract (w->p[i], w->p[k], v2); + VectorNormalize(v1,v1); + VectorNormalize(v2,v2); + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (w->p[i], p[nump]); + nump++; + } + } + + if (nump == w->numpoints) + return; + + if (numthreads == 1) + c_removed += w->numpoints - nump; + w->numpoints = nump; + memcpy (w->p, p, nump*sizeof(p[0])); +} + +/* +============ +WindingPlane +============ +*/ +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist) +{ + vec3_t v1, v2; + + VectorSubtract (w->p[1], w->p[0], v1); + VectorSubtract (w->p[2], w->p[0], v2); + CrossProduct (v2, v1, normal); + VectorNormalize (normal, normal); + *dist = DotProduct (w->p[0], normal); + +} + +/* +============= +WindingArea +============= +*/ +vec_t WindingArea (winding_t *w) +{ + int i; + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (i=2 ; inumpoints ; i++) + { + VectorSubtract (w->p[i-1], w->p[0], d1); + VectorSubtract (w->p[i], w->p[0], d2); + CrossProduct (d1, d2, cross); + total += 0.5 * VectorLength ( cross ); + } + return total; +} + +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs) +{ + vec_t v; + int i,j; + + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; + + for (i=0 ; inumpoints ; i++) + { + for (j=0 ; j<3 ; j++) + { + v = w->p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +/* +============= +WindingCenter +============= +*/ +void WindingCenter (winding_t *w, vec3_t center) +{ + int i; + float scale; + + VectorCopy (vec3_origin, center); + for (i=0 ; inumpoints ; i++) + VectorAdd (w->p[i], center, center); + + scale = 1.0/w->numpoints; + VectorScale (center, scale, center); +} + +/* +================= +BaseWindingForPlane +================= +*/ +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +/* +================== +CopyWinding +================== +*/ +winding_t *CopyWinding (winding_t *w) +{ + int size; + winding_t *c; + + c = AllocWinding (w->numpoints); + size = (int)((winding_t *)0)->p[w->numpoints]; + memcpy (c, w, size); + return c; +} + +/* +================== +ReverseWinding +================== +*/ +winding_t *ReverseWinding (winding_t *w) +{ + int i; + winding_t *c; + + c = AllocWinding (w->numpoints); + for (i=0 ; inumpoints ; i++) + { + VectorCopy (w->p[w->numpoints-1-i], c->p[i]); + } + c->numpoints = w->numpoints; + return c; +} + + +/* +============= +ClipWindingEpsilon +============= +*/ +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f, *b; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding (in); + return; + } + if (!counts[1]) + { + *front = CopyWinding (in); + return; + } + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + *front = f = AllocWinding (maxpts); + *back = b = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (winding_t **inout, vec3_t normal, vec_t dist, vec_t epsilon) +{ + winding_t *in; + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec_t dot; // VC 4.2 optimizer bug if not static + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding (in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding (in); + *inout = f; +} + + +/* +================= +ChopWinding + +Returns the fragment of in that is on the front side +of the cliping plane. The original is freed. +================= +*/ +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist) +{ + winding_t *f, *b; + + ClipWindingEpsilon (in, normal, dist, ON_EPSILON, &f, &b); + FreeWinding (in); + if (b) + FreeWinding (b); + return f; +} + + +/* +================= +CheckWinding + +================= +*/ +void CheckWinding (winding_t *w) +{ + int i, j; + vec_t *p1, *p2; + vec_t d, edgedist; + vec3_t dir, edgenormal, facenormal; + vec_t area; + vec_t facedist; + + if (w->numpoints < 3) + Error ("CheckWinding: %i points",w->numpoints); + + area = WindingArea(w); + if (area < 1) + Error ("CheckWinding: %f area", area); + + WindingPlane (w, facenormal, &facedist); + + for (i=0 ; inumpoints ; i++) + { + p1 = w->p[i]; + + for (j=0 ; j<3 ; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Error ("CheckFace: BUGUS_RANGE: %f",p1[j]); + + j = i+1 == w->numpoints ? 0 : i+1; + + // check the point is on the face plane + d = DotProduct (p1, facenormal) - facedist; + if (d < -ON_EPSILON || d > ON_EPSILON) + Error ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = w->p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Error ("CheckWinding: degenerate edge"); + + CrossProduct (facenormal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + edgedist += ON_EPSILON; + + // all other points must be on front side + for (j=0 ; jnumpoints ; j++) + { + if (j == i) + continue; + d = DotProduct (w->p[j], edgenormal); + if (d > edgedist) + Error ("CheckWinding: non-convex"); + } + } +} + + +/* +============ +WindingOnPlaneSide +============ +*/ +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist) +{ + qboolean front, back; + int i; + vec_t d; + + front = false; + back = false; + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = true; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = true; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + diff --git a/tools/quake2/extra/common/polylib.h b/tools/quake2/extra/common/polylib.h new file mode 100644 index 00000000..2024a0dc --- /dev/null +++ b/tools/quake2/extra/common/polylib.h @@ -0,0 +1,55 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +typedef struct +{ + int numpoints; + vec3_t p[4]; // variable sized +} winding_t; + +#define MAX_POINTS_ON_WINDING 64 + +// you can define on_epsilon in the makefile as tighter +#ifndef ON_EPSILON +#define ON_EPSILON 0.1 +#endif + +winding_t *AllocWinding (int points); +vec_t WindingArea (winding_t *w); +void WindingCenter (winding_t *w, vec3_t center); +void ClipWindingEpsilon (winding_t *in, vec3_t normal, vec_t dist, + vec_t epsilon, winding_t **front, winding_t **back); +winding_t *ChopWinding (winding_t *in, vec3_t normal, vec_t dist); +winding_t *CopyWinding (winding_t *w); +winding_t *ReverseWinding (winding_t *w); +winding_t *BaseWindingForPlane (vec3_t normal, vec_t dist); +void CheckWinding (winding_t *w); +void WindingPlane (winding_t *w, vec3_t normal, vec_t *dist); +void RemoveColinearPoints (winding_t *w); +int WindingOnPlaneSide (winding_t *w, vec3_t normal, vec_t dist); +void FreeWinding (winding_t *w); +void WindingBounds (winding_t *w, vec3_t mins, vec3_t maxs); + +void ChopWindingInPlace (winding_t **w, vec3_t normal, vec_t dist, vec_t epsilon); +// frees the original if clipped + +void pw(winding_t *w); diff --git a/tools/quake2/extra/common/qfiles.h b/tools/quake2/extra/common/qfiles.h new file mode 100644 index 00000000..d7a85563 --- /dev/null +++ b/tools/quake2/extra/common/qfiles.h @@ -0,0 +1,486 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +The .pak files are just a linear collapse of a directory tree + +======================================================================== +*/ + +#define IDPAKHEADER (('K'<<24)+('C'<<16)+('A'<<8)+'P') + +typedef struct +{ + char name[56]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +#define MAX_FILES_IN_PACK 4096 + + +/* +======================================================================== + +PCX files are used for as many images as possible + +======================================================================== +*/ + +typedef struct +{ + char manufacturer; + char version; + char encoding; + char bits_per_pixel; + unsigned short xmin,ymin,xmax,ymax; + unsigned short hres,vres; + unsigned char palette[48]; + char reserved; + char color_planes; + unsigned short bytes_per_line; + unsigned short palette_type; + char filler[58]; + unsigned char data; // unbounded +} pcx_t; + + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 32 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} dtrivertx_t; + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .WAL texture file format + +============================================================================== +*/ + + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + int flags; + int contents; + int value; +} miptex_t; + + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 38 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x40000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_AREAS 256 +#define MAX_MAP_AREAPORTALS 1024 +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 +#define LUMP_AREAS 17 +#define LUMP_AREAPORTALS 18 +#define HEADER_LUMPS 19 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// these definitions also need to be in q_shared.h! + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 2 // translucent, but not watery +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes + +#define CONTENTS_AREAPORTAL 0x8000 + +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define CONTENTS_DEADMONSTER 0x4000000 +#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans +#define CONTENTS_LADDER 0x20000000 + + + +#define SURF_LIGHT 0x1 // value will hold the light strength + +#define SURF_SLICK 0x2 // effects game physics + +#define SURF_SKY 0x4 // don't draw, but add to skybox +#define SURF_WARP 0x8 // turbulent water warp +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 // scroll towards angle +#define SURF_NODRAW 0x80 // don't bother referencing the texture + +#define SURF_HINT 0x100 // make a primary bsp splitter +#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes + + + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + short cluster; + short area; + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the visibility lump consists of a header with a count, then +// byte offsets for the PVS and PHS of each cluster, then the raw +// compressed bit vectors +#define DVIS_PVS 0 +#define DVIS_PHS 1 +typedef struct +{ + int numclusters; + int bitofs[8][2]; // bitofs[numclusters][2] +} dvis_t; + +// each area has a list of portals that lead into other areas +// when portals are closed, other areas may not be visible or +// hearable even if the vis info says that it should be +typedef struct +{ + int portalnum; + int otherarea; +} dareaportal_t; + +typedef struct +{ + int numareaportals; + int firstareaportal; +} darea_t; diff --git a/tools/quake2/extra/common/scriplib.c b/tools/quake2/extra/common/scriplib.c new file mode 100644 index 00000000..a9e2f3b5 --- /dev/null +++ b/tools/quake2/extra/common/scriplib.c @@ -0,0 +1,297 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// scriplib.c + +#include "cmdlib.h" +#include "scriplib.h" + +/* +============================================================================= + + PARSING STUFF + +============================================================================= +*/ + +typedef struct +{ + char filename[1024]; + char *buffer,*script_p,*end_p; + int line; +} script_t; + +#define MAX_INCLUDES 8 +script_t scriptstack[MAX_INCLUDES]; +script_t *script; +int scriptline; + +char token[MAXTOKEN]; +qboolean endofscript; +qboolean tokenready; // only true if UnGetToken was just called + +/* +============== +AddScriptToStack +============== +*/ +void AddScriptToStack (char *filename) +{ + int size; + + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, ExpandPath (filename) ); + + size = LoadFile (script->filename, (void **)&script->buffer); + + printf ("entering %s\n", script->filename); + + script->line = 1; + + script->script_p = script->buffer; + script->end_p = script->buffer + size; +} + + +/* +============== +LoadScriptFile +============== +*/ +void LoadScriptFile (char *filename) +{ + script = scriptstack; + AddScriptToStack (filename); + + endofscript = false; + tokenready = false; +} + + +/* +============== +ParseFromMemory +============== +*/ +void ParseFromMemory (char *buffer, int size) +{ + script = scriptstack; + script++; + if (script == &scriptstack[MAX_INCLUDES]) + Error ("script file exceeded MAX_INCLUDES"); + strcpy (script->filename, "memory buffer" ); + + script->buffer = buffer; + script->line = 1; + script->script_p = script->buffer; + script->end_p = script->buffer + size; + + endofscript = false; + tokenready = false; +} + + +/* +============== +UnGetToken + +Signals that the current token was not used, and should be reported +for the next GetToken. Note that + +GetToken (true); +UnGetToken (); +GetToken (false); + +could cross a line boundary. +============== +*/ +void UnGetToken (void) +{ + tokenready = true; +} + + +qboolean EndOfScript (qboolean crossline) +{ + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + + if (!strcmp (script->filename, "memory buffer")) + { + endofscript = true; + return false; + } + + free (script->buffer); + if (script == scriptstack+1) + { + endofscript = true; + return false; + } + script--; + scriptline = script->line; + printf ("returning to %s\n", script->filename); + return GetToken (crossline); +} + +/* +============== +GetToken +============== +*/ +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (tokenready) // is a token allready waiting? + { + tokenready = false; + return true; + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + +// +// skip space +// +skipspace: + while (*script->script_p <= 32) + { + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + if (*script->script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + scriptline = script->line++; + } + } + + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + + // ; # // comments + if (*script->script_p == ';' || *script->script_p == '#' + || ( script->script_p[0] == '/' && script->script_p[1] == '/') ) + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script->script_p++ != '\n') + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + goto skipspace; + } + + // /* */ comments + if (script->script_p[0] == '/' && script->script_p[1] == '*') + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + script->script_p+=2; + while (script->script_p[0] != '*' && script->script_p[1] != '/') + { + script->script_p++; + if (script->script_p >= script->end_p) + return EndOfScript (crossline); + } + script->script_p += 2; + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script->script_p == '"') + { + // quoted token + script->script_p++; + while (*script->script_p != '"') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + script->script_p++; + } + else // regular token + while ( *script->script_p > 32 && *script->script_p != ';') + { + *token_p++ = *script->script_p++; + if (script->script_p == script->end_p) + break; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i\n",scriptline); + } + + *token_p = 0; + + if (!strcmp (token, "$include")) + { + GetToken (false); + AddScriptToStack (token); + return GetToken (crossline); + } + + return true; +} + + +/* +============== +TokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script->script_p; + + if (search_p >= script->end_p) + return false; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + search_p++; + if (search_p == script->end_p) + return false; + + } + + if (*search_p == ';') + return false; + + return true; +} + + diff --git a/tools/quake2/extra/common/scriplib.h b/tools/quake2/extra/common/scriplib.h new file mode 100644 index 00000000..25c1c059 --- /dev/null +++ b/tools/quake2/extra/common/scriplib.h @@ -0,0 +1,45 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// scriplib.h + +#ifndef __CMDLIB__ +#include "cmdlib.h" +#endif + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern char *scriptbuffer,*script_p,*scriptend_p; +extern int grabbed; +extern int scriptline; +extern qboolean endofscript; + + +void LoadScriptFile (char *filename); +void ParseFromMemory (char *buffer, int size); + +qboolean GetToken (qboolean crossline); +void UnGetToken (void); +qboolean TokenAvailable (void); + + diff --git a/tools/quake2/extra/common/threads.c b/tools/quake2/extra/common/threads.c new file mode 100644 index 00000000..25a87c78 --- /dev/null +++ b/tools/quake2/extra/common/threads.c @@ -0,0 +1,448 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "threads.h" + +#define MAX_THREADS 64 + +int dispatch; +int workcount; +int oldf; +qboolean pacifier; + +qboolean threaded; + +/* +============= +GetThreadWork + +============= +*/ +int GetThreadWork (void) +{ + int r; + int f; + + ThreadLock (); + + if (dispatch == workcount) + { + ThreadUnlock (); + return -1; + } + + f = 10*dispatch / workcount; + if (f != oldf) + { + oldf = f; + if (pacifier) + printf ("%i...", f); + } + + r = dispatch; + dispatch++; + ThreadUnlock (); + + return r; +} + + +void (*workfunction) (int); + +void ThreadWorkerFunction (int threadnum) +{ + int work; + + while (1) + { + work = GetThreadWork (); + if (work == -1) + break; +//printf ("thread %i, work %i\n", threadnum, work); + workfunction(work); + } +} + +void RunThreadsOnIndividual (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + if (numthreads == -1) + ThreadSetDefault (); + workfunction = func; + RunThreadsOn (workcnt, showpacifier, ThreadWorkerFunction); +} + + +/* +=================================================================== + +WIN32 + +=================================================================== +*/ +#ifdef WIN32 + +#define USED + +#include + +int numthreads = -1; +CRITICAL_SECTION crit; +static int enter; + +void ThreadSetDefault (void) +{ + SYSTEM_INFO info; + + if (numthreads == -1) // not set manually + { + GetSystemInfo (&info); + numthreads = info.dwNumberOfProcessors; + if (numthreads < 1 || numthreads > 32) + numthreads = 1; + } + + qprintf ("%i threads\n", numthreads); +} + + +void ThreadLock (void) +{ + if (!threaded) + return; + EnterCriticalSection (&crit); + if (enter) + Error ("Recursive ThreadLock\n"); + enter = 1; +} + +void ThreadUnlock (void) +{ + if (!threaded) + return; + if (!enter) + Error ("ThreadUnlock without lock\n"); + enter = 0; + LeaveCriticalSection (&crit); +} + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int threadid[MAX_THREADS]; + HANDLE threadhandle[MAX_THREADS]; + int i; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + // + // run threads in parallel + // + InitializeCriticalSection (&crit); + + if (numthreads == 1) + { // use same thread + func (0); + } + else + { + for (i=0 ; i + +pthread_mutex_t *my_mutex; + +void ThreadLock (void) +{ + if (my_mutex) + pthread_mutex_lock (my_mutex); +} + +void ThreadUnlock (void) +{ + if (my_mutex) + pthread_mutex_unlock (my_mutex); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + pthread_t work_threads[MAX_THREADS]; + pthread_addr_t status; + pthread_attr_t attrib; + pthread_mutexattr_t mattrib; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + if (pacifier) + setbuf (stdout, NULL); + + if (!my_mutex) + { + my_mutex = malloc (sizeof(*my_mutex)); + if (pthread_mutexattr_create (&mattrib) == -1) + Error ("pthread_mutex_attr_create failed"); + if (pthread_mutexattr_setkind_np (&mattrib, MUTEX_FAST_NP) == -1) + Error ("pthread_mutexattr_setkind_np failed"); + if (pthread_mutex_init (my_mutex, mattrib) == -1) + Error ("pthread_mutex_init failed"); + } + + if (pthread_attr_create (&attrib) == -1) + Error ("pthread_attr_create failed"); + if (pthread_attr_setstacksize (&attrib, 0x100000) == -1) + Error ("pthread_attr_setstacksize failed"); + + for (i=0 ; i +#include +#include +#include + + +int numthreads = -1; +abilock_t lck; + +void ThreadSetDefault (void) +{ + if (numthreads == -1) + numthreads = prctl(PR_MAXPPROCS); + printf ("%i threads\n", numthreads); +//@@ + usconfig (CONF_INITUSERS, numthreads); +} + + +void ThreadLock (void) +{ + spin_lock (&lck); +} + +void ThreadUnlock (void) +{ + release_lock (&lck); +} + + +/* +============= +RunThreadsOn +============= +*/ +void RunThreadsOn (int workcnt, qboolean showpacifier, void(*func)(int)) +{ + int i; + int pid[MAX_THREADS]; + int start, end; + + start = I_FloatTime (); + dispatch = 0; + workcount = workcnt; + oldf = -1; + pacifier = showpacifier; + threaded = true; + + if (pacifier) + setbuf (stdout, NULL); + + init_lock (&lck); + + for (i=0 ; i +#include "cmdlib.h" +#include "mathlib.h" +#include "trilib.h" + +// on disk representation of a face + + +#define FLOAT_START 99999.0 +#define FLOAT_END -FLOAT_START +#define MAGIC 123322 + +//#define NOISY 1 + +typedef struct { + float v[3]; +} vector; + +typedef struct +{ + vector n; /* normal */ + vector p; /* point */ + vector c; /* color */ + float u; /* u */ + float v; /* v */ +} aliaspoint_t; + +typedef struct { + aliaspoint_t pt[3]; +} tf_triangle; + + +void ByteSwapTri (tf_triangle *tri) +{ + int i; + + for (i=0 ; iverts[j][k] = tri.pt[j].p.v[k]; + } + } + + ptri++; + + if ((ptri - *pptri) >= MAXTRIANGLES) + Error ("Error: too many triangles; increase MAXTRIANGLES\n"); + } + } + + *numtriangles = ptri - *pptri; + + fclose (input); +} + diff --git a/tools/quake2/extra/common/trilib.h b/tools/quake2/extra/common/trilib.h new file mode 100644 index 00000000..11ece3de --- /dev/null +++ b/tools/quake2/extra/common/trilib.h @@ -0,0 +1,33 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// trilib.h: header file for loading triangles from an Alias triangle file +// +#define MAXTRIANGLES 2048 + +typedef struct { + vec3_t verts[3]; +} triangle_t; + +void LoadTriangleList (char *filename, triangle_t **pptri, int *numtriangles); + diff --git a/tools/quake2/extra/qdata/anorms.h b/tools/quake2/extra/qdata/anorms.h new file mode 100644 index 00000000..18da0abc --- /dev/null +++ b/tools/quake2/extra/qdata/anorms.h @@ -0,0 +1,184 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +{-0.525731, 0.000000, 0.850651}, +{-0.442863, 0.238856, 0.864188}, +{-0.295242, 0.000000, 0.955423}, +{-0.309017, 0.500000, 0.809017}, +{-0.162460, 0.262866, 0.951056}, +{0.000000, 0.000000, 1.000000}, +{0.000000, 0.850651, 0.525731}, +{-0.147621, 0.716567, 0.681718}, +{0.147621, 0.716567, 0.681718}, +{0.000000, 0.525731, 0.850651}, +{0.309017, 0.500000, 0.809017}, +{0.525731, 0.000000, 0.850651}, +{0.295242, 0.000000, 0.955423}, +{0.442863, 0.238856, 0.864188}, +{0.162460, 0.262866, 0.951056}, +{-0.681718, 0.147621, 0.716567}, +{-0.809017, 0.309017, 0.500000}, +{-0.587785, 0.425325, 0.688191}, +{-0.850651, 0.525731, 0.000000}, +{-0.864188, 0.442863, 0.238856}, +{-0.716567, 0.681718, 0.147621}, +{-0.688191, 0.587785, 0.425325}, +{-0.500000, 0.809017, 0.309017}, +{-0.238856, 0.864188, 0.442863}, +{-0.425325, 0.688191, 0.587785}, +{-0.716567, 0.681718, -0.147621}, +{-0.500000, 0.809017, -0.309017}, +{-0.525731, 0.850651, 0.000000}, +{0.000000, 0.850651, -0.525731}, +{-0.238856, 0.864188, -0.442863}, +{0.000000, 0.955423, -0.295242}, +{-0.262866, 0.951056, -0.162460}, +{0.000000, 1.000000, 0.000000}, +{0.000000, 0.955423, 0.295242}, +{-0.262866, 0.951056, 0.162460}, +{0.238856, 0.864188, 0.442863}, +{0.262866, 0.951056, 0.162460}, +{0.500000, 0.809017, 0.309017}, +{0.238856, 0.864188, -0.442863}, +{0.262866, 0.951056, -0.162460}, +{0.500000, 0.809017, -0.309017}, +{0.850651, 0.525731, 0.000000}, +{0.716567, 0.681718, 0.147621}, +{0.716567, 0.681718, -0.147621}, +{0.525731, 0.850651, 0.000000}, +{0.425325, 0.688191, 0.587785}, +{0.864188, 0.442863, 0.238856}, +{0.688191, 0.587785, 0.425325}, +{0.809017, 0.309017, 0.500000}, +{0.681718, 0.147621, 0.716567}, +{0.587785, 0.425325, 0.688191}, +{0.955423, 0.295242, 0.000000}, +{1.000000, 0.000000, 0.000000}, +{0.951056, 0.162460, 0.262866}, +{0.850651, -0.525731, 0.000000}, +{0.955423, -0.295242, 0.000000}, +{0.864188, -0.442863, 0.238856}, +{0.951056, -0.162460, 0.262866}, +{0.809017, -0.309017, 0.500000}, +{0.681718, -0.147621, 0.716567}, +{0.850651, 0.000000, 0.525731}, +{0.864188, 0.442863, -0.238856}, +{0.809017, 0.309017, -0.500000}, +{0.951056, 0.162460, -0.262866}, +{0.525731, 0.000000, -0.850651}, +{0.681718, 0.147621, -0.716567}, +{0.681718, -0.147621, -0.716567}, +{0.850651, 0.000000, -0.525731}, +{0.809017, -0.309017, -0.500000}, +{0.864188, -0.442863, -0.238856}, +{0.951056, -0.162460, -0.262866}, +{0.147621, 0.716567, -0.681718}, +{0.309017, 0.500000, -0.809017}, +{0.425325, 0.688191, -0.587785}, +{0.442863, 0.238856, -0.864188}, +{0.587785, 0.425325, -0.688191}, +{0.688191, 0.587785, -0.425325}, +{-0.147621, 0.716567, -0.681718}, +{-0.309017, 0.500000, -0.809017}, +{0.000000, 0.525731, -0.850651}, +{-0.525731, 0.000000, -0.850651}, +{-0.442863, 0.238856, -0.864188}, +{-0.295242, 0.000000, -0.955423}, +{-0.162460, 0.262866, -0.951056}, +{0.000000, 0.000000, -1.000000}, +{0.295242, 0.000000, -0.955423}, +{0.162460, 0.262866, -0.951056}, +{-0.442863, -0.238856, -0.864188}, +{-0.309017, -0.500000, -0.809017}, +{-0.162460, -0.262866, -0.951056}, +{0.000000, -0.850651, -0.525731}, +{-0.147621, -0.716567, -0.681718}, +{0.147621, -0.716567, -0.681718}, +{0.000000, -0.525731, -0.850651}, +{0.309017, -0.500000, -0.809017}, +{0.442863, -0.238856, -0.864188}, +{0.162460, -0.262866, -0.951056}, +{0.238856, -0.864188, -0.442863}, +{0.500000, -0.809017, -0.309017}, +{0.425325, -0.688191, -0.587785}, +{0.716567, -0.681718, -0.147621}, +{0.688191, -0.587785, -0.425325}, +{0.587785, -0.425325, -0.688191}, +{0.000000, -0.955423, -0.295242}, +{0.000000, -1.000000, 0.000000}, +{0.262866, -0.951056, -0.162460}, +{0.000000, -0.850651, 0.525731}, +{0.000000, -0.955423, 0.295242}, +{0.238856, -0.864188, 0.442863}, +{0.262866, -0.951056, 0.162460}, +{0.500000, -0.809017, 0.309017}, +{0.716567, -0.681718, 0.147621}, +{0.525731, -0.850651, 0.000000}, +{-0.238856, -0.864188, -0.442863}, +{-0.500000, -0.809017, -0.309017}, +{-0.262866, -0.951056, -0.162460}, +{-0.850651, -0.525731, 0.000000}, +{-0.716567, -0.681718, -0.147621}, +{-0.716567, -0.681718, 0.147621}, +{-0.525731, -0.850651, 0.000000}, +{-0.500000, -0.809017, 0.309017}, +{-0.238856, -0.864188, 0.442863}, +{-0.262866, -0.951056, 0.162460}, +{-0.864188, -0.442863, 0.238856}, +{-0.809017, -0.309017, 0.500000}, +{-0.688191, -0.587785, 0.425325}, +{-0.681718, -0.147621, 0.716567}, +{-0.442863, -0.238856, 0.864188}, +{-0.587785, -0.425325, 0.688191}, +{-0.309017, -0.500000, 0.809017}, +{-0.147621, -0.716567, 0.681718}, +{-0.425325, -0.688191, 0.587785}, +{-0.162460, -0.262866, 0.951056}, +{0.442863, -0.238856, 0.864188}, +{0.162460, -0.262866, 0.951056}, +{0.309017, -0.500000, 0.809017}, +{0.147621, -0.716567, 0.681718}, +{0.000000, -0.525731, 0.850651}, +{0.425325, -0.688191, 0.587785}, +{0.587785, -0.425325, 0.688191}, +{0.688191, -0.587785, 0.425325}, +{-0.955423, 0.295242, 0.000000}, +{-0.951056, 0.162460, 0.262866}, +{-1.000000, 0.000000, 0.000000}, +{-0.850651, 0.000000, 0.525731}, +{-0.955423, -0.295242, 0.000000}, +{-0.951056, -0.162460, 0.262866}, +{-0.864188, 0.442863, -0.238856}, +{-0.951056, 0.162460, -0.262866}, +{-0.809017, 0.309017, -0.500000}, +{-0.864188, -0.442863, -0.238856}, +{-0.951056, -0.162460, -0.262866}, +{-0.809017, -0.309017, -0.500000}, +{-0.681718, 0.147621, -0.716567}, +{-0.681718, -0.147621, -0.716567}, +{-0.850651, 0.000000, -0.525731}, +{-0.688191, 0.587785, -0.425325}, +{-0.587785, 0.425325, -0.688191}, +{-0.425325, 0.688191, -0.587785}, +{-0.425325, -0.688191, -0.587785}, +{-0.587785, -0.425325, -0.688191}, +{-0.688191, -0.587785, -0.425325}, diff --git a/tools/quake2/extra/qdata/images.c b/tools/quake2/extra/qdata/images.c new file mode 100644 index 00000000..90934f13 --- /dev/null +++ b/tools/quake2/extra/qdata/images.c @@ -0,0 +1,763 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qdata.h" + +char mip_prefix[1024]; // directory to dump the textures in + +qboolean colormap_issued; +byte colormap_palette[768]; + +/* +============== +RemapZero + +Replaces all 0 bytes in an image with the closest palette entry. +This is because NT won't let us change index 0, so any palette +animation leaves those pixels untouched. +============== +*/ +void RemapZero (byte *pixels, byte *palette, int width, int height) +{ + int i, c; + int alt_zero; + int value, best; + + alt_zero = 0; + best = 9999999; + for (i=1 ; i<255 ; i++) + { + value = palette[i*3+0]+palette[i*3+1]+palette[i*3+2]; + if (value < best) + { + best = value; + alt_zero = i; + } + } + + c = width*height; + for (i=0 ; ibyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; ybyteimagewidth || yl+h>byteimageheight) + Error ("GrabPic: Bad size: %i, %i, %i, %i",xl,yl,w,h); + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; y 255) + r = 255; + if (r < 0) + r = 0; + if (g > 255) + g = 255; + if (g < 0) + g = 0; + if (b > 255) + b = 255; + if (b < 0) + b = 0; +#ifndef TABLECOLORS + bestcolor = BestColor (r, g, b, 0, 254); +#else + bestcolor = palmap[r>>3][g>>3][b>>3]; +#endif + + return bestcolor; +} + + +void BuildPalmap (void) +{ +#ifdef TABLECOLORS + int r, g, b; + int bestcolor; + + if (palmap_built) + return; + palmap_built = true; + + for (r=4 ; r<256 ; r+=8) + { + for (g=4 ; g<256 ; g+=8) + { + for (b=4 ; b<256 ; b+=8) + { + bestcolor = BestColor (r, g, b, 1, 254); + palmap[r>>3][g>>3][b>>3] = bestcolor; + } + } + } +#endif + + if (!colormap_issued) + Error ("You must issue a $colormap command first"); + +} + +/* +============= +AveragePixels +============= +*/ +byte AveragePixels (int count) +{ + int r,g,b; + int i; + int vis; + int pix; + int bestcolor; + byte *pal; + int fullbright; + + vis = 0; + r = g = b = 0; + fullbright = 0; + for (i=0 ; i +must be multiples of sixteen +SURF_WINDOW +============== +*/ +void Cmd_Mip (void) +{ + int x,y,xl,yl,xh,yh,w,h; + byte *screen_p, *source; + int linedelta; + miptex_t *qtex; + int miplevel, mipstep; + int xx, yy, pix; + int count; + int flags, value, contents; + mipparm_t *mp; + char lumpname[64]; + byte *lump_p; + char filename[1024]; + char animname[64]; + + GetToken (false); + strcpy (lumpname, token); + + GetToken (false); + xl = atoi (token); + GetToken (false); + yl = atoi (token); + GetToken (false); + w = atoi (token); + GetToken (false); + h = atoi (token); + + if ( (w & 15) || (h & 15) ) + Error ("line %i: miptex sizes must be multiples of 16", scriptline); + + flags = 0; + contents = 0; + value = 0; + + animname[0] = 0; + + // get optional flags and values + while (TokenAvailable ()) + { + GetToken (false); + + for (mp=mipparms ; mp->name ; mp++) + { + if (!strcmp(mp->name, token)) + { + switch (mp->type) + { + case pt_animvalue: + GetToken (false); // specify the next animation frame + strcpy (animname, token); + break; + case pt_flags: + flags |= mp->flags; + break; + case pt_contents: + contents |= mp->flags; + break; + case pt_flagvalue: + flags |= mp->flags; + GetToken (false); // specify the light value + value = atoi(token); + break; + } + break; + } + } + if (!mp->name) + Error ("line %i: unknown parm %s", scriptline, token); + } + + sprintf (filename, "%stextures/%s/%s.wal", gamedir, mip_prefix, lumpname); + if (g_release) + return; // textures are only released by $maps + + xh = xl+w; + yh = yl+h; + + qtex = malloc (sizeof(miptex_t) + w*h*2); + memset (qtex, 0, sizeof(miptex_t)); + + qtex->width = LittleLong(w); + qtex->height = LittleLong(h); + qtex->flags = LittleLong(flags); + qtex->contents = LittleLong(contents); + qtex->value = LittleLong(value); + sprintf (qtex->name, "%s/%s", mip_prefix, lumpname); + if (animname[0]) + sprintf (qtex->animname, "%s/%s", mip_prefix, animname); + + lump_p = (byte *)(&qtex->value+1); + + screen_p = byteimage + yl*byteimagewidth + xl; + linedelta = byteimagewidth - w; + + source = lump_p; + qtex->offsets[0] = LittleLong(lump_p - (byte *)qtex); + + for (y=yl ; yoffsets[miplevel] = LittleLong(lump_p - (byte *)qtex); + + mipstep = 1< /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/models.o : models.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/sprites.o : sprites.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/images.o : images.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/tables.o : tables.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i + +$(ODIR)/cmdlib.o : ../common/cmdlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/scriplib.o : ../common/scriplib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/lbmlib.o : ../common/lbmlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/mathlib.o : ../common/mathlib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/trilib.o : ../common/trilib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/l3dslib.o : ../common/l3dslib.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i +$(ODIR)/threads.o : ../common/threads.c + cc $(CFLAGS) -E $? | tr -d '\015' > /tmp/temp.i + cc $(CFLAGS) -o $@ /tmp/temp.i diff --git a/tools/quake2/extra/qdata/models.c b/tools/quake2/extra/qdata/models.c new file mode 100644 index 00000000..d6922cb7 --- /dev/null +++ b/tools/quake2/extra/qdata/models.c @@ -0,0 +1,1152 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qdata.h" + +//================================================================= + +typedef struct +{ + int numnormals; + vec3_t normalsum; +} vertexnormals_t; + +typedef struct +{ + vec3_t v; + int lightnormalindex; +} trivert_t; + +typedef struct +{ + vec3_t mins, maxs; + char name[16]; + trivert_t v[MAX_VERTS]; +} frame_t; + +//================================================================ + +frame_t g_frames[MAX_FRAMES]; + +dmdl_t model; + + +float scale_up; // set by $scale +vec3_t adjust; // set by $origin +int g_fixedwidth, g_fixedheight; // set by $skinsize + + +// +// base frame info +// +vec3_t base_xyz[MAX_VERTS]; +dstvert_t base_st[MAX_VERTS]; +dtriangle_t triangles[MAX_TRIANGLES]; + +int triangle_st[MAX_TRIANGLES][3][2]; + +// the command list holds counts, s/t values, and xyz indexes +// that are valid for every frame +int commands[16384]; +int numcommands; +int numglverts; +int used[MAX_TRIANGLES]; + +char g_skins[MAX_MD2SKINS][64]; + +char cdarchive[1024]; +char cdpartial[1024]; +char cddir[1024]; + +char modelname[64]; // empty unless $modelname issued (players) + +#define NUMVERTEXNORMALS 162 + +float avertexnormals[NUMVERTEXNORMALS][3] = { +#include "anorms.h" +}; + +FILE *headerouthandle = NULL; + +//============================================================== + +/* +=============== +ClearModel +=============== +*/ +void ClearModel (void) +{ + memset (&model, 0, sizeof(model)); + + modelname[0] = 0; + scale_up = 1.0; + VectorCopy (vec3_origin, adjust); + g_fixedwidth = g_fixedheight = 0; + g_skipmodel = false; +} + + +void H_printf(char *fmt, ...) +{ + va_list argptr; + char name[1024]; + + if (!headerouthandle) + { + sprintf (name, "%s/tris.h", cddir); + headerouthandle = SafeOpenWrite (name); + fprintf(headerouthandle, "// %s\n\n", cddir); + fprintf(headerouthandle, "// This file generated by qdata - Do NOT Modify\n\n"); + } + + va_start (argptr, fmt); + vfprintf (headerouthandle, fmt, argptr); + va_end (argptr); +} + + +/* +============ +WriteModelFile +============ +*/ +void WriteModelFile (FILE *modelouthandle) +{ + int i; + dmdl_t modeltemp; + int j, k; + frame_t *in; + daliasframe_t *out; + byte buffer[MAX_VERTS*4+128]; + float v; + int c_on, c_off; + + model.ident = IDALIASHEADER; + model.version = ALIAS_VERSION; + model.framesize = (int)&((daliasframe_t *)0)->verts[model.num_xyz]; + model.num_glcmds = numcommands; + model.ofs_skins = sizeof(dmdl_t); + model.ofs_st = model.ofs_skins + model.num_skins * MAX_SKINNAME; + model.ofs_tris = model.ofs_st + model.num_st*sizeof(dstvert_t); + model.ofs_frames = model.ofs_tris + model.num_tris*sizeof(dtriangle_t); + model.ofs_glcmds = model.ofs_frames + model.num_frames*model.framesize; + model.ofs_end = model.ofs_glcmds + model.num_glcmds*4; + + // + // write out the model header + // + for (i=0 ; iname, in->name); + for (j=0 ; j<3 ; j++) + { + out->scale[j] = (in->maxs[j] - in->mins[j])/255; + out->translate[j] = in->mins[j]; + } + + for (j=0 ; jverts[j].lightnormalindex = in->v[j].lightnormalindex; + + for (k=0 ; k<3 ; k++) + { + // scale to byte values & min/max check + v = Q_rint ( (in->v[j].v[k] - out->translate[k]) / out->scale[k] ); + + // clamp, so rounding doesn't wrap from 255.6 to 0 + if (v > 255.0) + v = 255.0; + if (v < 0) + v = 0; + out->verts[j].v[k] = v; + } + } + + for (j=0 ; j<3 ; j++) + { + out->scale[j] = LittleFloat (out->scale[j]); + out->translate[j] = LittleFloat (out->translate[j]); + } + + SafeWrite (modelouthandle, out, model.framesize); + } + + // + // write out glcmds + // + SafeWrite (modelouthandle, commands, numcommands*4); +} + + +/* +=============== +FinishModel +=============== +*/ +void FinishModel (void) +{ + FILE *modelouthandle; + int i; + char name[1024]; + + if (!model.num_frames) + return; + +// +// copy to release directory tree if doing a release build +// + if (g_release) + { + if (modelname[0]) + sprintf (name, "%s", modelname); + else + sprintf (name, "%s/tris.md2", cdpartial); + ReleaseFile (name); + + for (i=0 ; iindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+2)%3]; + st1 = last->index_st[(startv+2)%3]; + m2 = last->index_xyz[(startv+1)%3]; + st2 = last->index_st[(startv+1)%3]; + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + if (stripcount & 1) + { + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + } + else + { + m1 = check->index_xyz[ (k+2)%3 ]; + st1 = check->index_st[ (k+2)%3 ]; + } + + strip_xyz[stripcount+2] = check->index_xyz[ (k+2)%3 ]; + strip_st[stripcount+2] = check->index_st[ (k+2)%3 ]; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; jindex_xyz[(startv)%3]; + strip_xyz[1] = last->index_xyz[(startv+1)%3]; + strip_xyz[2] = last->index_xyz[(startv+2)%3]; + strip_st[0] = last->index_st[(startv)%3]; + strip_st[1] = last->index_st[(startv+1)%3]; + strip_st[2] = last->index_st[(startv+2)%3]; + + strip_tris[0] = starttri; + stripcount = 1; + + m1 = last->index_xyz[(startv+0)%3]; + st1 = last->index_st[(startv+0)%3]; + m2 = last->index_xyz[(startv+2)%3]; + st2 = last->index_st[(startv+2)%3]; + + + // look for a matching triangle +nexttri: + for (j=starttri+1, check=&triangles[starttri+1] + ; jindex_xyz[k] != m1) + continue; + if (check->index_st[k] != st1) + continue; + if (check->index_xyz[ (k+1)%3 ] != m2) + continue; + if (check->index_st[ (k+1)%3 ] != st2) + continue; + + // this is the next part of the fan + + // if we can't use this triangle, this tristrip is done + if (used[j]) + goto done; + + // the new edge + m2 = check->index_xyz[ (k+2)%3 ]; + st2 = check->index_st[ (k+2)%3 ]; + + strip_xyz[stripcount+2] = m2; + strip_st[stripcount+2] = st2; + strip_tris[stripcount] = j; + stripcount++; + + used[j] = 2; + goto nexttri; + } + } +done: + + // clear the temp used flags + for (j=starttri+1 ; j bestlen) + { + besttype = type; + bestlen = len; + for (j=0 ; j= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + + s_scale = t_scale = scale; + + iwidth = ceil(width*s_scale); + iheight = ceil(height*t_scale); + + iwidth += 4; + iheight += 4; + } + else + { // new style + iwidth = g_fixedwidth / 2; + iheight = g_fixedheight; + + s_scale = (float)(iwidth-4) / width; + t_scale = (float)(iheight-4) / height; + } + +// +// determine which side of each triangle to map the texture to +// + for (i=0 ; i 0) + { + basex = iwidth + 2; + } + else + { + basex = 2; + } + basey = 2; + + for (j=0 ; j<3 ; j++) + { + pbasevert = ptri[i].verts[j]; + + triangle_st[i][j][0] = Q_rint((pbasevert[0] - mins[0]) * s_scale + basex); + triangle_st[i][j][1] = Q_rint((maxs[2] - pbasevert[2]) * t_scale + basey); + } + } + +// make the width a multiple of 4; some hardware requires this, and it ensures +// dword alignment for each scan + swidth = iwidth*2; + model.skinwidth = (swidth + 3) & ~3; + model.skinheight = iheight; +} + + +/* +================= +Cmd_Base +================= +*/ +void Cmd_Base (void) +{ + triangle_t *ptri; + int i, j, k; + int time1; + char file1[1024]; + + GetToken (false); + + if (g_skipmodel || g_release || g_archive) + return; + + printf ("---------------------\n"); + sprintf (file1, "%s/%s.%s", cdarchive, token, trifileext); + printf ("%s\n", file1); + + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s.%s", cddir, token, trifileext); + + time1 = FileTime (file1); + if (time1 == -1) + Error ("%s doesn't exist", file1); + +// +// load the base triangles +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &model.num_tris); + else + LoadTriangleList (file1, &ptri, &model.num_tris); + +// +// get the ST values +// + BuildST (ptri, model.num_tris); + +// +// run through all the base triangles, storing each unique vertex in the +// base vertex list and setting the indirect triangles to point to the base +// vertices +// + for (i=0 ; i= '0' && *s <= '9') + s--; + + strcpy (suffix, s+1); + strcpy (base, frame); + base[s-frame+1] = 0; + + // check for 'run1.tri' + sprintf (file1, "%s/%s%s.%s",cddir, base, suffix, trifileext); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s%s.%s", base, suffix, trifileext); + return retname; + } + + // check for 'run.1' + sprintf (file1, "%s/%s.%s",cddir, base, suffix); + time1 = FileTime (file1); + if (time1 != -1) + { + sprintf (retname, "%s.%s", base, suffix); + return retname; + } + + Error ("frame %s could not be found",frame); + return NULL; +} + +/* +=============== +GrabFrame +=============== +*/ +void GrabFrame (char *frame) +{ + triangle_t *ptri; + int i, j; + trivert_t *ptrivert; + int num_tris; + char file1[1024]; + frame_t *fr; + vertexnormals_t vnorms[MAX_VERTS]; + int index_xyz; + char *framefile; + + // the frame 'run1' will be looked for as either + // run.1 or run1.tri, so the new alias sequence save + // feature an be used + framefile = FindFrameFile (frame); + + sprintf (file1, "%s/%s", cdarchive, framefile); + ExpandPathAndArchive (file1); + + sprintf (file1, "%s/%s",cddir, framefile); + + printf ("grabbing %s\n", file1); + + if (model.num_frames >= MAX_FRAMES) + Error ("model.num_frames >= MAX_FRAMES"); + fr = &g_frames[model.num_frames]; + model.num_frames++; + + strcpy (fr->name, frame); + +// +// load the frame +// + if (do3ds) + Load3DSTriangleList (file1, &ptri, &num_tris); + else + LoadTriangleList (file1, &ptri, &num_tris); + + if (num_tris != model.num_tris) + Error ("%s: number of triangles doesn't match base frame\n", file1); + +// +// allocate storage for the frame's vertices +// + ptrivert = fr->v; + + for (i=0 ; imins, fr->maxs); + +// +// store the frame's vertices in the same order as the base. This assumes the +// triangles and vertices in this frame are in exactly the same order as in the +// base +// + for (i=0 ; imins, fr->maxs); + + VectorAdd (vnorms[index_xyz].normalsum, normal, vnorms[index_xyz].normalsum); + vnorms[index_xyz].numnormals++; + } + } + +// +// calculate the vertex normals, match them to the template list, and store the +// index of the best match +// + for (i=0 ; i maxdot) + { + maxdot = dot; + maxdotindex = j; + } + } + + ptrivert[i].lightnormalindex = maxdotindex; + } + + free (ptri); +} + +/* +=============== +Cmd_Frame +=============== +*/ +void Cmd_Frame (void) +{ + while (TokenAvailable()) + { + GetToken (false); + if (g_skipmodel) + continue; + if (g_release || g_archive) + { + model.num_frames = 1; // don't skip the writeout + continue; + } + + H_printf("#define FRAME_%-16s\t%i\n", token, model.num_frames); + + GrabFrame (token); + } +} + + +/* +=============== +Cmd_Skin + +Skins aren't actually stored in the file, only a reference +is saved out to the header file. +=============== +*/ +void Cmd_Skin (void) +{ + byte *palette; + byte *pixels; + int width, height; + byte *cropped; + int y; + char name[1024], savename[1024]; + + GetToken (false); + + if (model.num_skins == MAX_MD2SKINS) + Error ("model.num_skins == MAX_MD2SKINS"); + + if (g_skipmodel) + return; + + sprintf (name, "%s/%s.lbm", cdarchive, token); + strcpy (name, ExpandPathAndArchive( name ) ); +// sprintf (name, "%s/%s.lbm", cddir, token); + + if (TokenAvailable()) + { + GetToken (false); + sprintf (g_skins[model.num_skins], "%s.pcx", token); + sprintf (savename, "%s%s.pcx", gamedir, g_skins[model.num_skins]); + } + else + { + sprintf (savename, "%s/%s.pcx", cddir, token); + sprintf (g_skins[model.num_skins], "%s/%s.pcx", cdpartial, token); + } + + model.num_skins++; + + if (g_skipmodel || g_release || g_archive) + return; + + // load the image + printf ("loading %s\n", name); + Load256Image (name, &pixels, &palette, &width, &height); + RemapZero (pixels, palette, width, height); + + // crop it to the proper size + cropped = malloc (model.skinwidth*model.skinheight); + for (y=0 ; y= sizeof(pf->name)) + Error ("Filename too long for pak: %s", filename); + + len = LoadFile (source, (void **)&buf); + + if (g_compress_pak && len < 4096*1024 ) + { + cblock_t in, out; + cblock_t Huffman (cblock_t in); + + in.count = len; + in.data = buf; + + out = Huffman (in); + + if (out.count < in.count) + { + printf (" compressed from %i to %i\n", in.count, out.count); + free (in.data); + buf = out.data; + len = out.count; + } + else + free (out.data); + } + + strcpy (pf->name, filename); + pf->filepos = LittleLong(ftell(pakfile)); + pf->filelen = LittleLong(len); + pf++; + + SafeWrite (pakfile, buf, len); + + free (buf); +} + + +/* +============== +FinishPak +============== +*/ +void FinishPak (void) +{ + int dirlen; + int d; + int i; + unsigned checksum; + + if (!g_pak) + return; + + pakheader.id[0] = 'P'; + pakheader.id[1] = 'A'; + pakheader.id[2] = 'C'; + pakheader.id[3] = 'K'; + dirlen = (byte *)pf - (byte *)pfiles; + pakheader.dirofs = LittleLong(ftell(pakfile)); + pakheader.dirlen = LittleLong(dirlen); + + checksum = Com_BlockChecksum ( (void *)pfiles, dirlen ); + + SafeWrite (pakfile, pfiles, dirlen); + + i = ftell (pakfile); + + fseek (pakfile, 0, SEEK_SET); + SafeWrite (pakfile, &pakheader, sizeof(pakheader)); + fclose (pakfile); + + d = pf - pfiles; + printf ("%i files packed in %i bytes\n",d, i); + printf ("checksum: 0x%x\n", checksum); +} + + +/* +=============== +Cmd_File + +This is only used to cause a file to be copied during a release +build (default.cfg, maps, etc) +=============== +*/ +void Cmd_File (void) +{ + GetToken (false); + ReleaseFile (token); +} + +/* +=============== +PackDirectory_r + +=============== +*/ +#ifdef _WIN32 +#include "io.h" +void PackDirectory_r (char *dir) +{ + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char filename[1024]; + + sprintf (dirstring, "%s%s/*.*", gamedir, dir); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + do + { + sprintf (filename, "%s/%s", dir, fileinfo.name); + if (fileinfo.attrib & _A_SUBDIR) + { // directory + if (fileinfo.name[0] != '.') // don't pak . and .. + PackDirectory_r (filename); + continue; + } + // copy or pack the file + ReleaseFile (filename); + } while (_findnext( handle, &fileinfo ) != -1); + + _findclose (handle); +} +#else + +#include +#ifdef NeXT +#include +#else +#include +#endif + +void PackDirectory_r (char *dir) +{ +#ifdef NeXT + struct direct **namelist, *ent; +#else + struct dirent **namelist, *ent; +#endif + int count; + struct stat st; + int i; + int len; + char fullname[1024]; + char dirstring[1024]; + char *name; + + sprintf (dirstring, "%s%s", gamedir, dir); + count = scandir(dirstring, &namelist, NULL, NULL); + + for (i=0 ; id_name; + + if (name[0] == '.') + continue; + + sprintf (fullname, "%s/%s", dir, name); + sprintf (dirstring, "%s%s/%s", gamedir, dir, name); + + if (stat (dirstring, &st) == -1) + Error ("fstating %s", pf->name); + if (st.st_mode & S_IFDIR) + { // directory + PackDirectory_r (fullname); + continue; + } + + // copy or pack the file + ReleaseFile (fullname); + } +} +#endif + + +/* +=============== +Cmd_Dir + +This is only used to cause a directory to be copied during a +release build (sounds, etc) +=============== +*/ +void Cmd_Dir (void) +{ + GetToken (false); + PackDirectory_r (token); +} + +//======================================================================== + +#define MAX_RTEX 16384 +int numrtex; +char rtex[MAX_RTEX][64]; + +void ReleaseTexture (char *name) +{ + int i; + char path[1024]; + + for (i=0 ; i= argc) + Error ("usage: qgrab [-archive ] [-release ] [-only ] [-3ds] file.qgr"); + + if (do3ds) + trifileext = ext_3ds; + else + trifileext = ext_tri; + + for ( ; i +# Microsoft Developer Studio Generated Build File, Format Version 5.00 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +CFG=qdata - Win32 Release +!MESSAGE This is not a valid makefile. To build this project using NMAKE, +!MESSAGE use the Export Makefile command and run +!MESSAGE +!MESSAGE NMAKE /f "qdata.mak". +!MESSAGE +!MESSAGE You can specify a configuration when running NMAKE +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qdata.mak" CFG="qdata - Win32 Release" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qdata - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qdata - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE + +# Begin Project +# PROP Scc_ProjName "" +# PROP Scc_LocalPath "" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qdata - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir ".\Release" +# PROP BASE Intermediate_Dir ".\Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir ".\Release" +# PROP Intermediate_Dir ".\Release" +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir ".\Debug" +# PROP BASE Intermediate_Dir ".\Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir ".\Debug" +# PROP Intermediate_Dir ".\Debug" +# PROP Ignore_Export_Lib 0 +# PROP Target_Dir "" +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /FD /c +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 + +!ENDIF + +# Begin Target + +# Name "qdata - Win32 Release" +# Name "qdata - Win32 Debug" +# Begin Group "Source Files" + +# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;hpj;bat;for;f90" +# Begin Source File + +SOURCE=..\common\bspfile.c +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.c +# End Source File +# Begin Source File + +SOURCE=.\images.c +# End Source File +# Begin Source File + +SOURCE=..\common\l3dslib.c +# End Source File +# Begin Source File + +SOURCE=..\common\lbmlib.c +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.c +# End Source File +# Begin Source File + +SOURCE=..\common\mdfour.c +# End Source File +# Begin Source File + +SOURCE=.\models.c +# End Source File +# Begin Source File + +SOURCE=.\qdata.c +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.c +# End Source File +# Begin Source File + +SOURCE=.\sprites.c +# End Source File +# Begin Source File + +SOURCE=.\tables.c +# End Source File +# Begin Source File + +SOURCE=..\common\threads.c +# End Source File +# Begin Source File + +SOURCE=..\common\trilib.c +# End Source File +# Begin Source File + +SOURCE=.\video.c +# End Source File +# End Group +# Begin Group "Header Files" + +# PROP Default_Filter "h;hpp;hxx;hm;inl;fi;fd" +# Begin Source File + +SOURCE=.\anorms.h +# End Source File +# Begin Source File + +SOURCE=..\common\bspfile.h +# End Source File +# Begin Source File + +SOURCE=..\common\cmdlib.h +# End Source File +# Begin Source File + +SOURCE=..\common\l3dslib.h +# End Source File +# Begin Source File + +SOURCE=..\common\lbmlib.h +# End Source File +# Begin Source File + +SOURCE=..\common\mathlib.h +# End Source File +# Begin Source File + +SOURCE=.\modelgen.h +# End Source File +# Begin Source File + +SOURCE=.\qdata.h +# End Source File +# Begin Source File + +SOURCE=..\common\qfiles.h +# End Source File +# Begin Source File + +SOURCE=..\common\scriplib.h +# End Source File +# Begin Source File + +SOURCE=..\common\threads.h +# End Source File +# Begin Source File + +SOURCE=..\common\trilib.h +# End Source File +# End Group +# Begin Group "Resource Files" + +# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;cnt;rtf;gif;jpg;jpeg;jpe" +# End Group +# End Target +# End Project diff --git a/tools/quake2/extra/qdata/qdata.dsw b/tools/quake2/extra/qdata/qdata.dsw new file mode 100644 index 00000000..5a1c558b --- /dev/null +++ b/tools/quake2/extra/qdata/qdata.dsw @@ -0,0 +1,29 @@ +Microsoft Developer Studio Workspace File, Format Version 5.00 +# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE! + +############################################################################### + +Project: "qdata"=.\qdata.dsp - Package Owner=<4> + +Package=<5> +{{{ +}}} + +Package=<4> +{{{ +}}} + +############################################################################### + +Global: + +Package=<5> +{{{ +}}} + +Package=<3> +{{{ +}}} + +############################################################################### + diff --git a/tools/quake2/extra/qdata/qdata.h b/tools/quake2/extra/qdata/qdata.h new file mode 100644 index 00000000..bd8e63c3 --- /dev/null +++ b/tools/quake2/extra/qdata/qdata.h @@ -0,0 +1,89 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// qdata.h + + +#include +#include +#include +#include +#include + +#include "cmdlib.h" +#include "scriplib.h" +#include "mathlib.h" +#include "trilib.h" +#include "lbmlib.h" +#include "threads.h" +#include "l3dslib.h" +#include "bspfile.h" + +void Cmd_Modelname (void); +void Cmd_Base (void); +void Cmd_Cd (void); +void Cmd_Origin (void); +void Cmd_ScaleUp (void); +void Cmd_Frame (void); +void Cmd_Modelname (void); +void Cmd_Skin (void); +void Cmd_Skinsize (void); +void FinishModel (void); + +void Cmd_Inverse16Table( void ); + +void Cmd_SpriteName (void); +void Cmd_Load (void); +void Cmd_SpriteFrame (void); +void FinishSprite (void); + +void Cmd_Grab (void); +void Cmd_Raw (void); +void Cmd_Mip (void); +void Cmd_Environment (void); +void Cmd_Colormap (void); + +void Cmd_File (void); +void Cmd_Dir (void); +void Cmd_StartWad (void); +void Cmd_EndWad (void); +void Cmd_Mippal (void); +void Cmd_Mipdir (void); +void Cmd_Alphalight (void); + +void Cmd_Video (void); + +void RemapZero (byte *pixels, byte *palette, int width, int height); + +void ReleaseFile (char *filename); + +extern byte *byteimage, *lbmpalette; +extern int byteimagewidth, byteimageheight; + +extern qboolean g_release; // don't grab, copy output data to new tree +extern char g_releasedir[1024]; // c:\quake2\baseq2, etc +extern qboolean g_archive; // don't grab, copy source data to new tree +extern qboolean do3ds; +extern char g_only[256]; // if set, only grab this cd +extern qboolean g_skipmodel; // set true when a cd is not g_only + +extern char *trifileext; diff --git a/tools/quake2/extra/qdata/qdata.mak b/tools/quake2/extra/qdata/qdata.mak new file mode 100644 index 00000000..5639dab1 --- /dev/null +++ b/tools/quake2/extra/qdata/qdata.mak @@ -0,0 +1,549 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Console Application" 0x0103 + +!IF "$(CFG)" == "" +CFG=qdata - Win32 Debug +!MESSAGE No configuration specified. Defaulting to qdata - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "qdata - Win32 Release" && "$(CFG)" != "qdata - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qdata.mak" CFG="qdata - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qdata - Win32 Release" (based on "Win32 (x86) Console Application") +!MESSAGE "qdata - Win32 Debug" (based on "Win32 (x86) Console Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "qdata - Win32 Debug" +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "qdata - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\qdata.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\images.obj" + -@erase "$(INTDIR)\l3dslib.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\models.obj" + -@erase "$(INTDIR)\qdata.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\sprites.obj" + -@erase "$(INTDIR)\tables.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\trilib.obj" + -@erase "$(OUTDIR)\qdata.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /GX /O2 /I "../common" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /O2 /I "../common" /D "WIN32" /D "NDEBUG" /D\ + "_CONSOLE" /Fp"$(INTDIR)/qdata.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qdata.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /nologo /subsystem:console /incremental:no\ + /pdb:"$(OUTDIR)/qdata.pdb" /machine:I386 /out:"$(OUTDIR)/qdata.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\images.obj" \ + "$(INTDIR)\l3dslib.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\models.obj" \ + "$(INTDIR)\qdata.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\sprites.obj" \ + "$(INTDIR)\tables.obj" \ + "$(INTDIR)\threads.obj" \ + "$(INTDIR)\trilib.obj" + +"$(OUTDIR)\qdata.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\qdata.exe" + +CLEAN : + -@erase "$(INTDIR)\bspfile.obj" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\images.obj" + -@erase "$(INTDIR)\l3dslib.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\models.obj" + -@erase "$(INTDIR)\qdata.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\sprites.obj" + -@erase "$(INTDIR)\tables.obj" + -@erase "$(INTDIR)\threads.obj" + -@erase "$(INTDIR)\trilib.obj" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(OUTDIR)\qdata.exe" + -@erase "$(OUTDIR)\qdata.ilk" + -@erase "$(OUTDIR)\qdata.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /I "../common" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /YX /c +CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /I "../common" /D "WIN32" /D "_DEBUG"\ + /D "_CONSOLE" /Fp"$(INTDIR)/qdata.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\. +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qdata.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 +LINK32_FLAGS=kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib\ + advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib\ + odbccp32.lib /nologo /subsystem:console /incremental:yes\ + /pdb:"$(OUTDIR)/qdata.pdb" /debug /machine:I386 /out:"$(OUTDIR)/qdata.exe" +LINK32_OBJS= \ + "$(INTDIR)\bspfile.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\images.obj" \ + "$(INTDIR)\l3dslib.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\models.obj" \ + "$(INTDIR)\qdata.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\sprites.obj" \ + "$(INTDIR)\tables.obj" \ + "$(INTDIR)\threads.obj" \ + "$(INTDIR)\trilib.obj" + +"$(OUTDIR)\qdata.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "qdata - Win32 Release" +# Name "qdata - Win32 Debug" + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\images.c +DEP_CPP_IMAGE=\ + "..\common\qfiles.h"\ + ".\../common\bspfile.h"\ + ".\../common\cmdlib.h"\ + ".\../common\l3dslib.h"\ + ".\../common\lbmlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\scriplib.h"\ + ".\../common\threads.h"\ + ".\../common\trilib.h"\ + ".\qdata.h"\ + {$(INCLUDE)}"\sys\STAT.H"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\images.obj" : $(SOURCE) $(DEP_CPP_IMAGE) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\modelgen.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qdata.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\sprites.c +DEP_CPP_SPRIT=\ + "..\common\qfiles.h"\ + ".\../common\bspfile.h"\ + ".\../common\cmdlib.h"\ + ".\../common\l3dslib.h"\ + ".\../common\lbmlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\scriplib.h"\ + ".\../common\threads.h"\ + ".\../common\trilib.h"\ + ".\qdata.h"\ + {$(INCLUDE)}"\sys\STAT.H"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\sprites.obj" : $(SOURCE) $(DEP_CPP_SPRIT) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\l3dslib.c +DEP_CPP_L3DSL=\ + ".\../common\cmdlib.h"\ + ".\../common\l3dslib.h"\ + ".\../common\mathlib.h"\ + ".\../common\trilib.h"\ + + +"$(INTDIR)\l3dslib.obj" : $(SOURCE) $(DEP_CPP_L3DSL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\lbmlib.c +DEP_CPP_LBMLI=\ + ".\../common\cmdlib.h"\ + ".\../common\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.c +DEP_CPP_MATHL=\ + ".\../common\cmdlib.h"\ + ".\../common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\scriplib.c +DEP_CPP_SCRIP=\ + ".\../common\cmdlib.h"\ + ".\../common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\threads.c +DEP_CPP_THREA=\ + ".\../common\cmdlib.h"\ + ".\../common\threads.h"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\threads.obj" : $(SOURCE) $(DEP_CPP_THREA) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\trilib.c +DEP_CPP_TRILI=\ + ".\../common\cmdlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\trilib.h"\ + + +"$(INTDIR)\trilib.obj" : $(SOURCE) $(DEP_CPP_TRILI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.c +DEP_CPP_CMDLI=\ + ".\../common\cmdlib.h"\ + {$(INCLUDE)}"\sys\STAT.H"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\models.c +DEP_CPP_MODEL=\ + "..\common\qfiles.h"\ + ".\../common\bspfile.h"\ + ".\../common\cmdlib.h"\ + ".\../common\l3dslib.h"\ + ".\../common\lbmlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\scriplib.h"\ + ".\../common\threads.h"\ + ".\../common\trilib.h"\ + ".\anorms.h"\ + ".\qdata.h"\ + {$(INCLUDE)}"\sys\STAT.H"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\models.obj" : $(SOURCE) $(DEP_CPP_MODEL) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qdata.c +DEP_CPP_QDATA=\ + "..\common\qfiles.h"\ + ".\../common\bspfile.h"\ + ".\../common\cmdlib.h"\ + ".\../common\l3dslib.h"\ + ".\../common\lbmlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\scriplib.h"\ + ".\../common\threads.h"\ + ".\../common\trilib.h"\ + ".\qdata.h"\ + {$(INCLUDE)}"\sys\STAT.H"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\qdata.obj" : $(SOURCE) $(DEP_CPP_QDATA) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\mathlib.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\lbmlib.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\cmdlib.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\tables.c +DEP_CPP_TABLE=\ + "..\common\qfiles.h"\ + ".\../common\bspfile.h"\ + ".\../common\cmdlib.h"\ + ".\../common\l3dslib.h"\ + ".\../common\lbmlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\scriplib.h"\ + ".\../common\threads.h"\ + ".\../common\trilib.h"\ + ".\qdata.h"\ + {$(INCLUDE)}"\sys\STAT.H"\ + {$(INCLUDE)}"\sys\TYPES.H"\ + + +"$(INTDIR)\tables.obj" : $(SOURCE) $(DEP_CPP_TABLE) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\qfiles.h + +!IF "$(CFG)" == "qdata - Win32 Release" + +!ELSEIF "$(CFG)" == "qdata - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=..\common\bspfile.c +DEP_CPP_BSPFI=\ + "..\common\qfiles.h"\ + ".\../common\bspfile.h"\ + ".\../common\cmdlib.h"\ + ".\../common\mathlib.h"\ + ".\../common\scriplib.h"\ + + +"$(INTDIR)\bspfile.obj" : $(SOURCE) $(DEP_CPP_BSPFI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/tools/quake2/extra/qdata/sprites.c b/tools/quake2/extra/qdata/sprites.c new file mode 100644 index 00000000..7bc308a8 --- /dev/null +++ b/tools/quake2/extra/qdata/sprites.c @@ -0,0 +1,228 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qdata.h" + +#define MAX_SPRFRAMES MAX_MD2SKINS + +dsprite_t sprite; +dsprframe_t frames[MAX_SPRFRAMES]; + +byte *byteimage, *lbmpalette; +int byteimagewidth, byteimageheight; + +char spritename[1024]; + + +void FinishSprite (void); +void Cmd_Spritename (void); + + + +/* +============== +FinishSprite +============== +*/ +void FinishSprite (void) +{ + FILE *spriteouthandle; + int i, curframe; + dsprite_t spritetemp; + char savename[1024]; + + if (sprite.numframes == 0) + return; + + if (!strlen(spritename)) + Error ("Didn't name sprite file"); + + sprintf (savename, "%s%s.sp2", gamedir, spritename); + + if (g_release) + { + char name[1024]; + + sprintf (name, "%s.sp2", spritename); + ReleaseFile (name); + spritename[0] = 0; // clear for a new sprite + sprite.numframes = 0; + return; + } + + + printf ("saving in %s\n", savename); + CreatePath (savename); + spriteouthandle = SafeOpenWrite (savename); + + +// +// write out the sprite header +// + spritetemp.ident = LittleLong (IDSPRITEHEADER); + spritetemp.version = LittleLong (SPRITE_VERSION); + spritetemp.numframes = LittleLong (sprite.numframes); + + SafeWrite (spriteouthandle, &spritetemp, 12); + +// +// write out the frames +// + curframe = 0; + + for (i=0 ; i 256) || (h > 256)) + Error ("Sprite has a dimension longer than 256"); + + xh = xl+w; + yh = yl+h; + + if (sprite.numframes >= MAX_SPRFRAMES) + Error ("Too many frames; increase MAX_SPRFRAMES\n"); + + pframe = &frames[sprite.numframes]; + pframe->width = w; + pframe->height = h; + pframe->origin_x = ox; + pframe->origin_y = oy; + sprintf (pframe->name, "%s_%i.pcx", spritename, sprite.numframes); + sprintf (savename, "%s%s_%i.pcx", gamedir, spritename, sprite.numframes); + sprite.numframes++; + + if (g_release) + { + ReleaseFile (pframe->name); + return; + } + + // crop it to the proper size + cropped = malloc (w*h); + for (y=0 ; y> 5 ) & 63 ) << 2; + b[0] = ( ( color >> 11 ) & 31 ) << 3; + + for ( i = 0; i < 256; i++ ) + { + r[1] = ( d_8to24table[i] >> 0 ) & 0xFF; + g[1] = ( d_8to24table[i] >> 8 ) & 0xFF; + b[1] = ( d_8to24table[i] >> 16 ) & 0xFF; + + d = ( r[1] - r[0] ) * ( r[1] - r[0] ) + + ( g[1] - g[0] ) * ( g[1] - g[0] ) + + ( b[1] - b[0] ) * ( b[1] - b[0] ); + + if ( d < closest_distance_so_far ) + { + closest_distance_so_far = d; + closest_so_far = i; + } + } + + return closest_so_far; +} +*/ + +extern byte BestColor( int, int, int, int, int ); + +void Inverse16_BuildTable( void ) +{ + int i; + + /* + ** create the 16-to-8 table + */ + for ( i = 0; i < 65536; i++ ) + { + int r = i & 31; + int g = ( i >> 5 ) & 63; + int b = ( i >> 11 ) & 31; + + r <<= 3; + g <<= 2; + b <<= 3; + + inverse16to8table[i] = BestColor( r, g, b, 0, 255 ); + } +} + +void Alphalight_Thread (int i) +{ + int j; + float r, g, b; + float mr, mg, mb, ma; + float distortion, bestdistortion; + float v; + + r = (i>>10) * (1.0/16); + g = ((i>>5)&31) * (1.0/16); + b = (i&31) * (1.0/16); + + bestdistortion = 999999; + for (j=0 ; j<16*16*16*16 ; j++) + { + mr = (j>>12) * (1.0/16); + mg = ((j>>8)&15) * (1.0/16); + mb = ((j>>4)&15) * (1.0/16); + ma = (j&15) * (1.0/16); + + v = r * 0.5 - (mr*ma + 0.5*(1.0-ma)); + distortion = v*v; + v = g * 0.5 - (mg*ma + 0.5*(1.0-ma)); + distortion += v*v; + v = b * 0.5 - (mb*ma + 0.5*(1.0-ma)); + distortion += v*v; + + distortion *= 1.0 + ma*4; + + if (distortion < bestdistortion) + { + bestdistortion = distortion; + alphamap[i] = j; + } + } +} + +void Cmd_Alphalight (void) +{ + char savename[1024]; + + GetToken (false); + + if (g_release) + { + ReleaseFile (token); + return; + } + + sprintf (savename, "%s%s", gamedir, token); + printf ("Building alphalight table...\n"); + + RunThreadsOnIndividual (32*32*32, true, Alphalight_Thread); + + SaveFile (savename, (byte *)alphamap, sizeof(alphamap)); +} + + +void Cmd_Inverse16Table( void ) +{ + char savename[1024]; + + if ( g_release ) + { + sprintf (savename, "pics/16to8.dat"); + ReleaseFile( savename ); + return; + } + + sprintf (savename, "%spics/16to8.dat", gamedir); + printf ("Building inverse 16-to-8 table...\n"); + + Inverse16_BuildTable(); + + SaveFile( savename, (byte *) inverse16to8table, sizeof( inverse16to8table ) ); +} diff --git a/tools/quake2/extra/qdata/video.c b/tools/quake2/extra/qdata/video.c new file mode 100644 index 00000000..b2df1493 --- /dev/null +++ b/tools/quake2/extra/qdata/video.c @@ -0,0 +1,1259 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qdata.h" + +byte *soundtrack; +char base[32]; + +/* +=============================================================================== + +WAV loading + +=============================================================================== +*/ + +typedef struct +{ + int rate; + int width; + int channels; + int loopstart; + int samples; + int dataofs; // chunk starts this many bytes from file start +} wavinfo_t; + + +byte *data_p; +byte *iff_end; +byte *last_chunk; +byte *iff_data; +int iff_chunk_len; + + +int samplecounts[0x10000]; + +wavinfo_t wavinfo; + +short GetLittleShort(void) +{ + short val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + data_p += 2; + return val; +} + +int GetLittleLong(void) +{ + int val = 0; + val = *data_p; + val = val + (*(data_p+1)<<8); + val = val + (*(data_p+2)<<16); + val = val + (*(data_p+3)<<24); + data_p += 4; + return val; +} + +void FindNextChunk(char *name) +{ + while (1) + { + data_p=last_chunk; + + if (data_p >= iff_end) + { // didn't find the chunk + data_p = NULL; + return; + } + + data_p += 4; + iff_chunk_len = GetLittleLong(); + if (iff_chunk_len < 0) + { + data_p = NULL; + return; + } +// if (iff_chunk_len > 1024*1024) +// Sys_Error ("FindNextChunk: %i length is past the 1 meg sanity limit", iff_chunk_len); + data_p -= 8; + last_chunk = data_p + 8 + ( (iff_chunk_len + 1) & ~1 ); + if (!strncmp(data_p, name, 4)) + return; + } +} + +void FindChunk(char *name) +{ + last_chunk = iff_data; + FindNextChunk (name); +} + + +void DumpChunks(void) +{ + char str[5]; + + str[4] = 0; + data_p=iff_data; + do + { + memcpy (str, data_p, 4); + data_p += 4; + iff_chunk_len = GetLittleLong(); + printf ("0x%x : %s (%d)\n", (int)(data_p - 4), str, iff_chunk_len); + data_p += (iff_chunk_len + 1) & ~1; + } while (data_p < iff_end); +} + +/* +============ +GetWavinfo +============ +*/ +wavinfo_t GetWavinfo (char *name, byte *wav, int wavlength) +{ + wavinfo_t info; + int i; + int format; + int samples; + + memset (&info, 0, sizeof(info)); + + if (!wav) + return info; + + iff_data = wav; + iff_end = wav + wavlength; + +// find "RIFF" chunk + FindChunk("RIFF"); + if (!(data_p && !strncmp(data_p+8, "WAVE", 4))) + { + printf("Missing RIFF/WAVE chunks\n"); + return info; + } + +// get "fmt " chunk + iff_data = data_p + 12; +// DumpChunks (); + + FindChunk("fmt "); + if (!data_p) + { + printf("Missing fmt chunk\n"); + return info; + } + data_p += 8; + format = GetLittleShort(); + if (format != 1) + { + printf("Microsoft PCM format only\n"); + return info; + } + + info.channels = GetLittleShort(); + info.rate = GetLittleLong(); + data_p += 4+2; + info.width = GetLittleShort() / 8; + +// get cue chunk + FindChunk("cue "); + if (data_p) + { + data_p += 32; + info.loopstart = GetLittleLong(); +// Com_Printf("loopstart=%d\n", sfx->loopstart); + + // if the next chunk is a LIST chunk, look for a cue length marker + FindNextChunk ("LIST"); + if (data_p) + { + if (!strncmp (data_p + 28, "mark", 4)) + { // this is not a proper parse, but it works with cooledit... + data_p += 24; + i = GetLittleLong (); // samples in loop + info.samples = info.loopstart + i; + } + } + } + else + info.loopstart = -1; + +// find data chunk + FindChunk("data"); + if (!data_p) + { + printf("Missing data chunk\n"); + return info; + } + + data_p += 4; + samples = GetLittleLong (); + + if (info.samples) + { + if (samples < info.samples) + Error ("Sound %s has a bad loop length", name); + } + else + info.samples = samples; + + info.dataofs = data_p - wav; + + return info; +} + +//===================================================================== + +/* +============== +LoadSoundtrack +============== +*/ +void LoadSoundtrack (void) +{ + char name[1024]; + FILE *f; + int len; + int i, val, j; + + soundtrack = NULL; + sprintf (name, "%svideo/%s/%s.wav", gamedir, base, base); + printf ("%s\n", name); + f = fopen (name, "rb"); + if (!f) + { + printf ("no soundtrack for %s\n", base); + return; + } + len = Q_filelength(f); + soundtrack = malloc(len); + fread (soundtrack, 1, len, f); + fclose (f); + + wavinfo = GetWavinfo (name, soundtrack, len); + + // count samples for compression + memset (samplecounts, 0, sizeof(samplecounts)); + + j = wavinfo.samples/2; + for (i=0 ; i wavinfo.samples || !soundtrack) + fwrite (&empty, 1, width, output); + else + fwrite (soundtrack + wavinfo.dataofs + sample*width, 1, width,output); + } +} + +//========================================================================== + +/* +================== +MTF +================== +*/ +cblock_t MTF (cblock_t in) +{ + int i, j, b, code; + byte *out_p; + int index[256]; + cblock_t out; + + out_p = out.data = malloc(in.count + 4); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i<256 ; i++) + index[i] = i; + + for (i=0 ; i b2) + return 1; + if (++i1 == bwt_size) + i1 = 0; + if (++i2 == bwt_size) + i2 = 0; + } + + return 0; +} + +/* +================== +BWT +================== +*/ +cblock_t BWT (cblock_t in) +{ + int *sorted; + int i; + byte *out_p; + cblock_t out; + + bwt_size = in.count; + bwt_data = in.data; + + sorted = malloc(in.count*sizeof(*sorted)); + for (i=0 ; i>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write head index + for (i=0 ; i>8)&255; + *out_p++ = (i>>16)&255; + *out_p++ = (i>>24)&255; + + // write the L column + for (i=0 ; i 32) + Error ("bitcount > 32"); + charbits[nodenum] = bits; + charbitscount[nodenum] = bitcount; + return; + } + + node = &hnodes[nodenum]; + bits <<= 1; + BuildChars (node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars (node->children[1], bits, bitcount+1); +} + + +/* +================== +Huffman +================== +*/ +cblock_t Huffman (cblock_t in) +{ + int i; + hnode_t *node; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int max, maxchar; + + // count + memset (hnodes, 0, sizeof(hnodes)); + for (i=0 ; i max) + { + max = hnodes[i].count; + maxchar = i; + } + } + if (max == 0) + Error ("Huffman: max == 0"); + + for (i=0 ; i<256 ; i++) + { + hnodes[i].count = (hnodes[i].count*255+max-1) / max; + } + + // build the nodes + numhnodes = 256; + while (numhnodes != 511) + { + node = &hnodes[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode (); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode (); + if (node->children[1] == -1) + { + if (node->children[0] != numhnodes-1) + Error ("Bad smallestnode"); + break; + } + node->count = hnodes[node->children[0]].count + + hnodes[node->children[1]].count; + numhnodes++; + } + + BuildChars (numhnodes-1, 0, 0); + + out_p = out.data = malloc(in.count*2 + 1024); + memset (out_p, 0, in.count*2+1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // save out the 256 normalized counts so the tree can be recreated + for (i=0 ; i<256 ; i++) + *out_p++ = hnodes[i].count; + + // write bits + outbits = 0; + for (i=0 ; i>3] |= 1<<(outbits&7); + outbits++; + } + } + + out_p += (outbits+7)>>3; + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + +/* +================== +RLE +================== +*/ +#define RLE_CODE 0xe8 +#define RLE_TRIPPLE 0xe9 + +int rle_counts[256]; +int rle_bytes[256]; + +cblock_t RLE (cblock_t in) +{ + int i; + byte *out_p; + int val; + int repeat; + cblock_t out; + + out_p = out.data = malloc (in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + for (i=0 ; i 3 || val == RLE_CODE) + { + *out_p++ = RLE_CODE; + *out_p++ = val; + *out_p++ = repeat; + } + else + { + while (repeat--) + *out_p++ = val; + } + } + + out.count = out_p - out.data; + return out; +} + +//========================================================================== + +unsigned lzss_head[256]; +unsigned lzss_next[0x20000]; + +/* +================== +LZSS +================== +*/ +#define BACK_WINDOW 0x10000 +#define BACK_BITS 16 +#define FRONT_WINDOW 16 +#define FRONT_BITS 4 +cblock_t LZSS (cblock_t in) +{ + int i; + byte *out_p; + cblock_t out; + int val; + int j, start, max; + int bestlength, beststart; + int outbits; + +if (in.count >= sizeof(lzss_next)/4) +Error ("LZSS: too big"); + + memset (lzss_head, -1, sizeof(lzss_head)); + + out_p = out.data = malloc (in.count*2); + memset (out.data, 0, in.count*2); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + outbits = 0; + for (i=0 ; i in.count) + max = in.count - i; + + start = lzss_head[val]; + while (start != -1 && start >= i-BACK_WINDOW) + { + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + start = lzss_next[start]; + } + +#else +// slow simple search + // search for a match + max = FRONT_WINDOW; + if (i + max > in.count) + max = in.count - i; + + start = i - BACK_WINDOW; + if (start < 0) + start = 0; + bestlength = 0; + beststart = 0; + for ( ; start < i ; start++) + { + if (in.data[start] != val) + continue; + // count match length + for (j=0 ; j bestlength) + { + bestlength = j; + beststart = start; + } + } +#endif + beststart = BACK_WINDOW - (i-beststart); + + if (bestlength < 3) + { // output a single char + bestlength = 1; + + out_p[outbits>>3] |= 1<<(outbits&7); // set bit to mark char + outbits++; + for (j=0 ; j<8 ; j++, outbits++) + if (val & (1<>3] |= 1<<(outbits&7); + } + else + { // output a phrase + outbits++; // leave a 0 bit to mark phrase + for (j=0 ; j>3] |= 1<<(outbits&7); + for (j=0 ; j>3] |= 1<<(outbits&7); + } + + while (bestlength--) + { + val = in.data[i]; + lzss_next[i] = lzss_head[val]; + lzss_head[val] = i; + i++; + } + } + + out_p += (outbits+7)>>3; + out.count = out_p - out.data; + return out; +} + +//========================================================================== + +#define MIN_REPT 15 +#define MAX_REPT 0 +#define HUF_TOKENS (256+MAX_REPT) + +unsigned charbits1[256][HUF_TOKENS]; +int charbitscount1[256][HUF_TOKENS]; + +hnode_t hnodes1[256][HUF_TOKENS*2]; +int numhnodes1[256]; + +int order0counts[256]; + +/* +================== +SmallestNode1 +================== +*/ +int SmallestNode1 (hnode_t *hnodes, int numhnodes) +{ + int i; + int best, bestnode; + + best = 99999999; + bestnode = -1; + for (i=0 ; i 32) + Error ("bitcount > 32"); + charbits1[prev][nodenum] = bits; + charbitscount1[prev][nodenum] = bitcount; + return; + } + + node = &hnodes1[prev][nodenum]; + bits <<= 1; + BuildChars1 (prev, node->children[0], bits, bitcount+1); + bits |= 1; + BuildChars1 (prev, node->children[1], bits, bitcount+1); +} + + +/* +================== +BuildTree1 +================== +*/ +void BuildTree1 (int prev) +{ + hnode_t *node, *nodebase; + int numhnodes; + + // build the nodes + numhnodes = HUF_TOKENS; + nodebase = hnodes1[prev]; + while (1) + { + node = &nodebase[numhnodes]; + + // pick two lowest counts + node->children[0] = SmallestNode1 (nodebase, numhnodes); + if (node->children[0] == -1) + break; // no more + + node->children[1] = SmallestNode1 (nodebase, numhnodes); + if (node->children[1] == -1) + break; + + node->count = nodebase[node->children[0]].count + + nodebase[node->children[1]].count; + numhnodes++; + } + numhnodes1[prev] = numhnodes-1; + BuildChars1 (prev, numhnodes-1, 0, 0); +} + + +/* +================== +Huffman1_Count +================== +*/ +void Huffman1_Count (cblock_t in) +{ + int i; + int prev; + int v; + int rept; + + prev = 0; + for (i=0 ; i MIN_REPT) + { + hnodes1[prev][255+rept].count++; + i += rept-1; + } +#endif + } +} + + +/* +================== +Huffman1_Build +================== +*/ +byte scaled[256][HUF_TOKENS]; +void Huffman1_Build (FILE *f) +{ + int i, j, v; + int max; + int total; + + for (i=0 ; i<256 ; i++) + { + // normalize and save the counts + max = 0; + for (j=0 ; j max) + max = hnodes1[i][j].count; + } + if (max == 0) + max = 1; + total = 0; + for (j=0 ; j 255) + Error ("v > 255"); + scaled[i][j] = hnodes1[i][j].count = v; + if (v) + total++; + } + if (total == 1) + { // must have two tokens + if (!scaled[i][0]) + scaled[i][0] = hnodes1[i][0].count = 1; + else + scaled[i][1] = hnodes1[i][1].count = 1; + } + + BuildTree1 (i); + } + +#if 0 + // count up the total bits + total = 0; + for (i=0 ; i<256 ; i++) + for (j=0 ; j<256 ; j++) + total += charbitscount1[i][j] * hnodes1[i][j].count; + + total = (total+7)/8; + printf ("%i bytes huffman1 compressed\n", total); +#endif + + fwrite (scaled, 1, sizeof(scaled), f); +} + +/* +================== +Huffman1 + +Order 1 compression with pre-built table +================== +*/ +cblock_t Huffman1 (cblock_t in) +{ + int i; + int outbits, c; + unsigned bits; + byte *out_p; + cblock_t out; + int prev; + int v; + int rept; + + out_p = out.data = malloc(in.count*2 + 1024); + memset (out_p, 0, in.count*2+1024); + + // write count + *out_p++ = in.count&255; + *out_p++ = (in.count>>8)&255; + *out_p++ = (in.count>>16)&255; + *out_p++ = (in.count>>24)&255; + + // write bits + outbits = 0; + prev = 0; + for (i=0 ; i>3] |= 1<<(outbits&7); + outbits++; + } + + prev = v; +#if 1 + // check for repeat encodes + for (rept=1 ; i+rept < in.count && rept < MAX_REPT ; rept++) + if (in.data[i+rept] != v) + break; + if (rept > MIN_REPT) + { + c = charbitscount1[prev][255+rept]; + bits = charbits1[prev][255+rept]; + if (!c) + Error ("!bits"); + while (c) + { + c--; + if (bits & (1<>3] |= 1<<(outbits&7); + outbits++; + } + i += rept-1; + } +#endif + } + + out_p += (outbits+7)>>3; + + out.count = out_p - out.data; + + return out; +} + +//========================================================================== + + +/* +=================== +LoadFrame +=================== +*/ +cblock_t LoadFrame (char *base, int frame, int digits, byte **palette) +{ + int ten3, ten2, ten1, ten0; + cblock_t in; + int width, height; + char name[1024]; + FILE *f; + + in.data = NULL; + in.count = -1; + + ten3 = frame/1000; + ten2 = (frame-ten3*1000)/100; + ten1 = (frame-ten3*1000-ten2*100)/10; + ten0 = frame%10; + + if (digits == 4) + sprintf (name, "%svideo/%s/%s%i%i%i%i.pcx", gamedir, base, base, ten3, ten2, ten1, ten0); + else + sprintf (name, "%svideo/%s/%s%i%i%i.pcx", gamedir, base, base, ten2, ten1, ten0); + + f = fopen(name, "rb"); + if (!f) + { + in.data = NULL; + return in; + } + fclose (f); + + printf ("%s\n", name); + Load256Image (name, &in.data, palette, &width, &height); + in.count = width*height; +// FIXME: map 0 and 255! + +#if 0 + // rle compress + rle = RLE(in); + free (in.data); + + return rle; +#endif + + return in; +} + +/* +=============== +Cmd_Video + +video +=============== +*/ +void Cmd_Video (void) +{ + char savename[1024]; + char name[1024]; + FILE *output; + int startframe, frame; + byte *palette; + int width, height; + byte current_palette[768]; + int command; + int i; + int digits; + cblock_t in, huffman; + int swap; + + + GetToken (false); + strcpy (base, token); + if (g_release) + { +// sprintf (savename, "video/%s.cin", token); +// ReleaseFile (savename); + return; + } + + GetToken (false); + digits = atoi(token); + + // optionally skip frames + if (TokenAvailable ()) + { + GetToken (false); + startframe = atoi(token); + } + else + startframe=0; + + sprintf (savename, "%svideo/%s.cin", gamedir, base); + + + // clear stuff + memset (charbits1, 0, sizeof(charbits1)); + memset (charbitscount1, 0, sizeof(charbitscount1)); + memset (hnodes1, 0, sizeof(hnodes1)); + memset (numhnodes1, 0, sizeof(numhnodes1)); + memset (order0counts, 0, sizeof(order0counts)); + + + // load the entire sound wav file if present + LoadSoundtrack (); + + if (digits == 4) + sprintf (name, "%svideo/%s/%s0000.pcx", gamedir, base, base); + else + sprintf (name, "%svideo/%s/%s000.pcx", gamedir, base, base); + + printf ("%s\n", name); + Load256Image (name, NULL, &palette, &width, &height); + + output = fopen (savename, "wb"); + if (!output) + Error ("Can't open %s", savename); + + // write header info + i = LittleLong (width); + fwrite (&i, 4, 1, output); + i = LittleLong (height); + fwrite (&i, 4, 1, output); + i = LittleLong (wavinfo.rate); + fwrite (&i, 4, 1, output); + i = LittleLong (wavinfo.width); + fwrite (&i, 4, 1, output); + i = LittleLong (wavinfo.channels); + fwrite (&i, 4, 1, output); + + // build the dictionary + for ( frame=startframe ; ; frame++) + { + printf ("counting ", frame); + in = LoadFrame (base, frame, digits, &palette); + if (!in.data) + break; + Huffman1_Count (in); + free (in.data); + } + printf ("\n"); + + // build nodes and write counts + Huffman1_Build (output); + + + memset (current_palette, 0, sizeof(current_palette)); + + // compress it with the dictionary + for (frame=startframe ; ; frame++) + { + printf ("packing ", frame); + in = LoadFrame (base, frame, digits, &palette); + if (!in.data) + break; + + // see if the palette has changed + for (i=0 ; i<768 ; i++) + if (palette[i] != current_palette[i]) + { + // write a palette change + memcpy (current_palette, palette, sizeof(current_palette)); + command = LittleLong(1); + fwrite (&command, 1, 4, output); + fwrite (current_palette, 1, sizeof(current_palette), output); + break; + } + if (i == 768) + { + command = 0; // no palette change + fwrite (&command, 1, 4, output); + } + + // save the image + huffman = Huffman1 (in); + printf ("%5i bytes after huffman1\n", huffman.count); + + swap = LittleLong (huffman.count); + fwrite (&swap, 1, sizeof(swap), output); + + fwrite (huffman.data, 1, huffman.count, output); + + // save some sound samples + WriteSound (output, frame); + + free (palette); + free (in.data); + free (huffman.data); + } + printf ("\n"); + + // write end-of-file command + command = 2; + fwrite (&command, 1, 4, output); + + printf ("Total size: %i\n", ftell (output)); + + fclose (output); + + if (soundtrack) + free (soundtrack); +} diff --git a/tools/quake2/extra/qe4/brush.c b/tools/quake2/extra/qe4/brush.c new file mode 100644 index 00000000..e8a2b53a --- /dev/null +++ b/tools/quake2/extra/qe4/brush.c @@ -0,0 +1,1568 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include +#include "qe3.h" + +#define MAX_POINTS_ON_WINDING 64 + +face_t *Face_Alloc( void ); +void Face_Free( face_t *f ); + +winding_t *NewWinding (int points); +void FreeWinding (winding_t *w); +winding_t *Winding_Clone( winding_t *w ); +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon); + +void PrintWinding (winding_t *w) +{ + int i; + + printf ("-------------\n"); + for (i=0 ; inumpoints ; i++) + printf ("(%5.2f, %5.2f, %5.2f)\n", w->points[i][0] + , w->points[i][1], w->points[i][2]); +} + +void PrintPlane (plane_t *p) +{ + printf ("(%5.2f, %5.2f, %5.2f) : %5.2f\n", p->normal[0], p->normal[1], + p->normal[2], p->dist); +} + +void PrintVector (vec3_t v) +{ + printf ("(%5.2f, %5.2f, %5.2f)\n", v[0], v[1], v[2]); +} + + +face_t *Face_Clone (face_t *f) +{ + face_t *n; + + n = Face_Alloc(); + n->texdef = f->texdef; + memcpy (n->planepts, f->planepts, sizeof(n->planepts)); + + // all other fields are derived, and will be set by Brush_Build + return n; +} + +//============================================================================ + +#define BOGUS_RANGE 18000 + + +/* +================== +NewWinding +================== +*/ +winding_t *NewWinding (int points) +{ + winding_t *w; + int size; + + if (points > MAX_POINTS_ON_WINDING) + Error ("NewWinding: %i points", points); + + size = (int)((winding_t *)0)->points[points]; + w = malloc (size); + memset (w, 0, size); + w->maxpoints = points; + + return w; +} + + +void FreeWinding (winding_t *w) +{ + free (w); +} + + +/* +================== +Winding_Clone +================== +*/ +winding_t *Winding_Clone(winding_t *w) +{ + int size; + winding_t *c; + + size = (int)((winding_t *)0)->points[w->numpoints]; + c = qmalloc (size); + memcpy (c, w, size); + return c; +} + + +/* +================== +ClipWinding + +Clips the winding to the plane, returning the new winding on the positive side +Frees the input winding. +If keepon is true, an exactly on-plane winding will be saved, otherwise +it will be clipped away. +================== +*/ +winding_t *ClipWinding (winding_t *in, plane_t *split, qboolean keepon) +{ + vec_t dists[MAX_POINTS_ON_WINDING]; + int sides[MAX_POINTS_ON_WINDING]; + int counts[3]; + vec_t dot; + int i, j; + vec_t *p1, *p2; + vec3_t mid; + winding_t *neww; + int maxpts; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->points[i], split->normal); + dot -= split->dist; + dists[i] = dot; + if (dot > ON_EPSILON) + sides[i] = SIDE_FRONT; + else if (dot < -ON_EPSILON) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (keepon && !counts[0] && !counts[1]) + return in; + + if (!counts[0]) + { + FreeWinding (in); + return NULL; + } + if (!counts[1]) + return in; + + maxpts = in->numpoints+4; // can't use counts[0]+2 because + // of fp grouping errors + neww = NewWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->points[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->points[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (split->normal[j] == 1) + mid[j] = split->dist; + else if (split->normal[j] == -1) + mid[j] = -split->dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, neww->points[neww->numpoints]); + neww->numpoints++; + } + + if (neww->numpoints > maxpts) + Error ("ClipWinding: points exceeded estimate"); + +// free the original winding + FreeWinding (in); + + return neww; +} + + + +/* +============================================================================= + + TEXTURE COORDINATES + +============================================================================= +*/ + + +/* +================== +textureAxisFromPlane +================== +*/ +vec3_t baseaxis[18] = +{ +{0,0,1}, {1,0,0}, {0,-1,0}, // floor +{0,0,-1}, {1,0,0}, {0,-1,0}, // ceiling +{1,0,0}, {0,1,0}, {0,0,-1}, // west wall +{-1,0,0}, {0,1,0}, {0,0,-1}, // east wall +{0,1,0}, {1,0,0}, {0,0,-1}, // south wall +{0,-1,0}, {1,0,0}, {0,0,-1} // north wall +}; + +void TextureAxisFromPlane(plane_t *pln, vec3_t xv, vec3_t yv) +{ + int bestaxis; + float dot,best; + int i; + + best = 0; + bestaxis = 0; + + for (i=0 ; i<6 ; i++) + { + dot = DotProduct (pln->normal, baseaxis[i*3]); + if (dot > best) + { + best = dot; + bestaxis = i; + } + } + + VectorCopy (baseaxis[bestaxis*3+1], xv); + VectorCopy (baseaxis[bestaxis*3+2], yv); +} + + +float lightaxis[3] = {0.6, 0.8, 1.0}; +/* +================ +SetShadeForPlane + +Light different planes differently to +improve recognition +================ +*/ +float SetShadeForPlane (plane_t *p) +{ + int i; + float f; + + // axial plane + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) > 0.9) + { + f = lightaxis[i]; + return f; + } + + // between two axial planes + for (i=0 ; i<3 ; i++) + if (fabs(p->normal[i]) < 0.1) + { + f = (lightaxis[(i+1)%3] + lightaxis[(i+2)%3])/2; + return f; + } + + // other + f= (lightaxis[0] + lightaxis[1] + lightaxis[2]) / 3; + return f; +} + +vec3_t vecs[2]; +float shift[2]; + +/* +================ +BeginTexturingFace +================ +*/ +void BeginTexturingFace (brush_t *b, face_t *f, qtexture_t *q) +{ + vec3_t pvecs[2]; + int sv, tv; + float ang, sinv, cosv; + float ns, nt; + int i,j; + float shade; + + // get natural texture axis + TextureAxisFromPlane(&f->plane, pvecs[0], pvecs[1]); + + // set shading for face + shade = SetShadeForPlane (&f->plane); + if (camera.draw_mode == cd_texture && !b->owner->eclass->fixedsize) + { + f->d_color[0] = + f->d_color[1] = + f->d_color[2] = shade; + } + else + { + f->d_color[0] = shade*q->color[0]; + f->d_color[1] = shade*q->color[1]; + f->d_color[2] = shade*q->color[2]; + } + + if (camera.draw_mode != cd_texture) + return; + + if (!f->texdef.scale[0]) + f->texdef.scale[0] = 1; + if (!f->texdef.scale[1]) + f->texdef.scale[1] = 1; + + +// rotate axis + if (f->texdef.rotate == 0) + { sinv = 0 ; cosv = 1; } + else if (f->texdef.rotate == 90) + { sinv = 1 ; cosv = 0; } + else if (f->texdef.rotate == 180) + { sinv = 0 ; cosv = -1; } + else if (f->texdef.rotate == 270) + { sinv = -1 ; cosv = 0; } + else + { + ang = f->texdef.rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + } + + if (pvecs[0][0]) + sv = 0; + else if (pvecs[0][1]) + sv = 1; + else + sv = 2; + + if (pvecs[1][0]) + tv = 0; + else if (pvecs[1][1]) + tv = 1; + else + tv = 2; + + for (i=0 ; i<2 ; i++) + { + ns = cosv * pvecs[i][sv] - sinv * pvecs[i][tv]; + nt = sinv * pvecs[i][sv] + cosv * pvecs[i][tv]; + vecs[i][sv] = ns; + vecs[i][tv] = nt; + } + + for (i=0 ; i<2 ; i++) + for (j=0 ; j<3 ; j++) + vecs[i][j] = vecs[i][j] / f->texdef.scale[i]; +} + + +void _EmitTextureCoordinates (vec3_t v, qtexture_t *q) +{ + float s, t; + + s = DotProduct (v, vecs[0]); + t = DotProduct (v, vecs[1]); + + s += shift[0]; + t += shift[1]; + + s /= q->width; + t /= q->height; + + glTexCoord2f (s, t); +} + +void EmitTextureCoordinates ( float *xyzst, qtexture_t *q, face_t *f) +{ + float s, t, ns, nt; + float ang, sinv, cosv; + vec3_t vecs[2]; + texdef_t *td; + + // get natural texture axis + TextureAxisFromPlane(&f->plane, vecs[0], vecs[1]); + + td = &f->texdef; + + ang = td->rotate / 180 * Q_PI; + sinv = sin(ang); + cosv = cos(ang); + + if (!td->scale[0]) + td->scale[0] = 1; + if (!td->scale[1]) + td->scale[1] = 1; + + s = DotProduct(xyzst, vecs[0]); + t = DotProduct(xyzst, vecs[1]); + + ns = cosv * s - sinv * t; + nt = sinv * s + cosv * t; + + s = ns/td->scale[0] + td->shift[0]; + t = nt/td->scale[1] + td->shift[1]; + + // gl scales everything from 0 to 1 + s /= q->width; + t /= q->height; + + xyzst[3] = s; + xyzst[4] = t; +} + +//========================================================================== + + +/* +================= +BasePolyForPlane +================= +*/ +winding_t *BasePolyForPlane (plane_t *p) +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + winding_t *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = fabs(p->normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Error ("BasePolyForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + + v = DotProduct (vup, p->normal); + VectorMA (vup, -v, p->normal, vup); + VectorNormalize (vup); + + VectorScale (p->normal, p->dist, org); + + CrossProduct (vup, p->normal, vright); + + VectorScale (vup, 8192, vup); + VectorScale (vright, 8192, vright); + +// project a really big axis aligned box onto the plane + w = NewWinding (4); + + VectorSubtract (org, vright, w->points[0]); + VectorAdd (w->points[0], vup, w->points[0]); + + VectorAdd (org, vright, w->points[1]); + VectorAdd (w->points[1], vup, w->points[1]); + + VectorAdd (org, vright, w->points[2]); + VectorSubtract (w->points[2], vup, w->points[2]); + + VectorSubtract (org, vright, w->points[3]); + VectorSubtract (w->points[3], vup, w->points[3]); + + w->numpoints = 4; + + return w; +} + +void Brush_MakeFacePlanes (brush_t *b) +{ + face_t *f; + int j; + vec3_t t1, t2, t3; + + for (f=b->brush_faces ; f ; f=f->next) + { + // convert to a vector / dist plane + for (j=0 ; j<3 ; j++) + { + t1[j] = f->planepts[0][j] - f->planepts[1][j]; + t2[j] = f->planepts[2][j] - f->planepts[1][j]; + t3[j] = f->planepts[1][j]; + } + + CrossProduct(t1,t2, f->plane.normal); + if (VectorCompare (f->plane.normal, vec3_origin)) + printf ("WARNING: brush plane with no normal\n"); + VectorNormalize (f->plane.normal); + f->plane.dist = DotProduct (t3, f->plane.normal); + } +} + +void DrawBrushEntityName (brush_t *b) +{ + char *name; + float a, s, c; + vec3_t mid; + int i; + + if (!b->owner) + return; // during contruction + + if (b->owner == world_entity) + return; + + if (b != b->owner->brushes.onext) + return; // not key brush + + // draw the angle pointer + a = FloatForKey (b->owner, "angle"); + if (a) + { + s = sin (a/180*Q_PI); + c = cos (a/180*Q_PI); + for (i=0 ; i<3 ; i++) + mid[i] = (b->mins[i] + b->maxs[i])*0.5; + + glBegin (GL_LINE_STRIP); + glVertex3fv (mid); + mid[0] += c*8; + mid[1] += s*8; + glVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[0] -= s*4; + mid[1] += c*4; + glVertex3fv (mid); + mid[0] += c*4; + mid[1] += s*4; + mid[0] += s*4; + mid[1] -= c*4; + glVertex3fv (mid); + mid[0] -= c*4; + mid[1] -= s*4; + mid[0] += s*4; + mid[1] -= c*4; + glVertex3fv (mid); + glEnd (); + } + + if (!g_qeglobals.d_savedinfo.show_names) + return; + + name = ValueForKey (b->owner, "classname"); + glRasterPos2f (b->mins[0]+4, b->mins[1]+4); + glCallLists (strlen(name), GL_UNSIGNED_BYTE, name); +} + +/* +================= +MakeFaceWinding + +returns the visible polygon on a face +================= +*/ +winding_t *MakeFaceWinding (brush_t *b, face_t *face) +{ + winding_t *w; + face_t *clip; + plane_t plane; + qboolean past; + + // get a poly that covers an effectively infinite area + w = BasePolyForPlane (&face->plane); + + // chop the poly by all of the other faces + past = false; + for (clip = b->brush_faces ; clip && w ; clip=clip->next) + { + if (clip == face) + { + past = true; + continue; + } + if (DotProduct (face->plane.normal, clip->plane.normal) > 0.999 + && fabs(face->plane.dist - clip->plane.dist) < 0.01 ) + { // identical plane, use the later one + if (past) + { + free (w); + return NULL; + } + continue; + } + + // flip the plane, because we want to keep the back side + VectorSubtract (vec3_origin,clip->plane.normal, plane.normal); + plane.dist = -clip->plane.dist; + + w = ClipWinding (w, &plane, false); + if (!w) + return w; + } + + if (w->numpoints < 3) + { + free(w); + w = NULL; + } + + if (!w) + printf ("unused plane\n"); + + return w; +} + + +void Brush_SnapPlanepts (brush_t *b) +{ + int i, j; + face_t *f; + + for (f=b->brush_faces ; f; f=f->next) + for (i=0 ; i<3 ; i++) + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = floor (f->planepts[i][j] + 0.5); +} + +/* +** Brush_Build +** +** Builds a brush rendering data and also sets the min/max bounds +*/ +#define ZERO_EPSILON 0.001 +void Brush_Build( brush_t *b ) +{ +// int order; +// face_t *face; +// winding_t *w; + char title[1024]; + + if (modified != 1) + { + modified = true; // mark the map as changed + sprintf (title, "%s *", currentmap); + + QE_ConvertDOSToUnixName( title, title ); + Sys_SetTitle (title); + } + + /* + ** build the windings and generate the bounding box + */ + Brush_BuildWindings( b ); + + /* + ** move the points and edges if in select mode + */ + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + SetupVertexSelection (); +} + +/* +================= +Brush_Parse + +The brush is NOT linked to any list +================= +*/ +brush_t *Brush_Parse (void) +{ + brush_t *b; + face_t *f; + int i,j; + + g_qeglobals.d_parsed_brushes++; + b = qmalloc(sizeof(brush_t)); + + do + { + if (!GetToken (true)) + break; + if (!strcmp (token, "}") ) + break; + + f = Face_Alloc(); + + // add the brush to the end of the chain, so + // loading and saving a map doesn't reverse the order + + f->next = NULL; + if (!b->brush_faces) + { + b->brush_faces = f; + } + else + { + face_t *scan; + + for (scan=b->brush_faces ; scan->next ; scan=scan->next) + ; + scan->next = f; + } + + // read the three point plane definition + for (i=0 ; i<3 ; i++) + { + if (i != 0) + GetToken (true); + if (strcmp (token, "(") ) + Error ("parsing brush"); + + for (j=0 ; j<3 ; j++) + { + GetToken (false); + f->planepts[i][j] = atoi(token); + } + + GetToken (false); + if (strcmp (token, ")") ) + Error ("parsing brush"); + + } + + // read the texturedef + GetToken (false); + strcpy(f->texdef.name, token); + GetToken (false); + f->texdef.shift[0] = atoi(token); + GetToken (false); + f->texdef.shift[1] = atoi(token); + GetToken (false); + f->texdef.rotate = atoi(token); + GetToken (false); + f->texdef.scale[0] = atof(token); + GetToken (false); + f->texdef.scale[1] = atof(token); + + // the flags and value field aren't necessarily present + f->d_texture = Texture_ForName( f->texdef.name ); + f->texdef.flags = f->d_texture->flags; + f->texdef.value = f->d_texture->value; + f->texdef.contents = f->d_texture->contents; + + if (TokenAvailable ()) + { + GetToken (false); + f->texdef.contents = atoi(token); + GetToken (false); + f->texdef.flags = atoi(token); + GetToken (false); + f->texdef.value = atoi(token); + } + } while (1); + + return b; +} + +/* +================= +Brush_Write +================= +*/ +void Brush_Write (brush_t *b, FILE *f) +{ + face_t *fa; + char *pname; + int i; + + fprintf (f, "{\n"); + for (fa=b->brush_faces ; fa ; fa=fa->next) + { + for (i=0 ; i<3 ; i++) + fprintf (f, "( %i %i %i ) ", (int)fa->planepts[i][0] + , (int)fa->planepts[i][1], (int)fa->planepts[i][2]); + + pname = fa->texdef.name; + if (pname[0] == 0) + pname = "unnamed"; + + fprintf (f, "%s %i %i %i ", pname, + (int)fa->texdef.shift[0], (int)fa->texdef.shift[1], + (int)fa->texdef.rotate); + + if (fa->texdef.scale[0] == (int)fa->texdef.scale[0]) + fprintf (f, "%i ", (int)fa->texdef.scale[0]); + else + fprintf (f, "%f ", (float)fa->texdef.scale[0]); + if (fa->texdef.scale[1] == (int)fa->texdef.scale[1]) + fprintf (f, "%i", (int)fa->texdef.scale[1]); + else + fprintf (f, "%f", (float)fa->texdef.scale[1]); + + // only output flags and value if not default + if (fa->texdef.value != fa->d_texture->value + || fa->texdef.flags != fa->d_texture->flags + || fa->texdef.contents != fa->d_texture->contents) + { + fprintf (f, " %i %i %i", fa->texdef.contents, fa->texdef.flags, fa->texdef.value); + } + + fprintf (f, "\n"); + } + fprintf (f, "}\n"); +} + + +/* +============= +Brush_Create + +Create non-textured blocks for entities +The brush is NOT linked to any list +============= +*/ +brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef) +{ + int i, j; + vec3_t pts[4][2]; + face_t *f; + brush_t *b; + + for (i=0 ; i<3 ; i++) + if (maxs[i] < mins[i]) + Error ("Brush_InitSolid: backwards"); + + b = qmalloc (sizeof(brush_t)); + + pts[0][0][0] = mins[0]; + pts[0][0][1] = mins[1]; + + pts[1][0][0] = mins[0]; + pts[1][0][1] = maxs[1]; + + pts[2][0][0] = maxs[0]; + pts[2][0][1] = maxs[1]; + + pts[3][0][0] = maxs[0]; + pts[3][0][1] = mins[1]; + + for (i=0 ; i<4 ; i++) + { + pts[i][0][2] = mins[2]; + pts[i][1][0] = pts[i][0][0]; + pts[i][1][1] = pts[i][0][1]; + pts[i][1][2] = maxs[2]; + } + + for (i=0 ; i<4 ; i++) + { + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + j = (i+1)%4; + + VectorCopy (pts[j][1], f->planepts[0]); + VectorCopy (pts[i][1], f->planepts[1]); + VectorCopy (pts[i][0], f->planepts[2]); + } + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[0][1], f->planepts[0]); + VectorCopy (pts[1][1], f->planepts[1]); + VectorCopy (pts[2][1], f->planepts[2]); + + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + VectorCopy (pts[2][0], f->planepts[0]); + VectorCopy (pts[1][0], f->planepts[1]); + VectorCopy (pts[0][0], f->planepts[2]); + + return b; +} + + +/* +============= +Brush_MakeSided + +Makes the current brushhave the given number of 2d sides +============= +*/ +void Brush_MakeSided (int sides) +{ + int i; + vec3_t mins, maxs; + brush_t *b; + texdef_t *texdef; + face_t *f; + vec3_t mid; + float width; + float sv, cv; + + if (sides < 3) + { + Sys_Status ("Bad sides number", 0); + return; + } + + if (!QE_SingleBrush ()) + { + Sys_Status ("Must have a single brush selected", 0 ); + return; + } + + b = selected_brushes.next; + VectorCopy (b->mins, mins); + VectorCopy (b->maxs, maxs); + texdef = &g_qeglobals.d_texturewin.texdef; + + Brush_Free (b); + + // find center of brush + width = 8; + for (i=0 ; i<2 ; i++) + { + mid[i] = (maxs[i] + mins[i])*0.5; + if (maxs[i] - mins[i] > width) + width = maxs[i] - mins[i]; + } + width /= 2; + + b = qmalloc (sizeof(brush_t)); + + // create top face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + +f->planepts[2][0] = mins[0];f->planepts[2][1] = mins[1];f->planepts[2][2] = maxs[2]; +f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = maxs[2]; +f->planepts[0][0] = maxs[0];f->planepts[0][1] = maxs[1];f->planepts[0][2] = maxs[2]; + + // create bottom face + f = Face_Alloc(); + f->texdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + +f->planepts[0][0] = mins[0];f->planepts[0][1] = mins[1];f->planepts[0][2] = mins[2]; +f->planepts[1][0] = maxs[0];f->planepts[1][1] = mins[1];f->planepts[1][2] = mins[2]; +f->planepts[2][0] = maxs[0];f->planepts[2][1] = maxs[1];f->planepts[2][2] = mins[2]; + + for (i=0 ; itexdef = *texdef; + f->next = b->brush_faces; + b->brush_faces = f; + + sv = sin (i*3.14159265*2/sides); + cv = cos (i*3.14159265*2/sides); + + f->planepts[0][0] = floor(mid[0]+width*cv+0.5); + f->planepts[0][1] = floor(mid[1]+width*sv+0.5); + f->planepts[0][2] = mins[2]; + + f->planepts[1][0] = f->planepts[0][0]; + f->planepts[1][1] = f->planepts[0][1]; + f->planepts[1][2] = maxs[2]; + + f->planepts[2][0] = floor(f->planepts[0][0] - width*sv + 0.5); + f->planepts[2][1] = floor(f->planepts[0][1] + width*cv + 0.5); + f->planepts[2][2] = maxs[2]; + + } + + Brush_AddToList (b, &selected_brushes); + + Entity_LinkBrush (world_entity, b); + + Brush_Build( b ); + + Sys_UpdateWindows (W_ALL); +} + + +/* +============= +Brush_Free + +Frees the brush with all of its faces and display list. +Unlinks the brush from whichever chain it is in. +Decrements the owner entity's brushcount. +Removes owner entity if this was the last brush +unless owner is the world. +============= +*/ +void Brush_Free (brush_t *b) +{ + face_t *f, *next; + + // free faces + for (f=b->brush_faces ; f ; f=next) + { + next = f->next; + Face_Free( f ); + } + + /* + for ( i = 0; i < b->d_numwindings; i++ ) + { + if ( b->d_windings[i] ) + { + FreeWinding( b->d_windings[i] ); + b->d_windings[i] = 0; + } + } + */ + + // unlink from active/selected list + if (b->next) + Brush_RemoveFromList (b); + + // unlink from entity list + if (b->onext) + Entity_UnlinkBrush (b); + + free (b); +} + +/* +============ +Brush_Move +============ +*/ +void Brush_Move (brush_t *b, vec3_t move) +{ + int i; + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + for (i=0 ; i<3 ; i++) + VectorAdd (f->planepts[i], move, f->planepts[i]); + Brush_Build( b ); +} + +/* +============ +Brush_Clone + +Does NOT add the new brush to any lists +============ +*/ +brush_t *Brush_Clone (brush_t *b) +{ + brush_t *n; + face_t *f, *nf; + + n = qmalloc(sizeof(brush_t)); + n->owner = b->owner; + for (f=b->brush_faces ; f ; f=f->next) + { + nf = Face_Clone( f ); + nf->next = n->brush_faces; + n->brush_faces = nf; + } + return n; +} + +/* +============== +Brush_Ray + +Itersects a ray with a brush +Returns the face hit and the distance along the ray the intersection occured at +Returns NULL and 0 if not hit at all +============== +*/ +face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist) +{ + face_t *f, *firstface; + vec3_t p1, p2; + float frac, d1, d2; + int i; + + VectorCopy (origin, p1); + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + dir[i]*16384; + + for (f=b->brush_faces ; f ; f=f->next) + { + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + if (d1 >= 0 && d2 >= 0) + { + *dist = 0; + return NULL; // ray is on front side of face + } + if (d1 <=0 && d2 <= 0) + continue; + // clip the ray to the plane + frac = d1 / (d1 - d2); + if (d1 > 0) + { + firstface = f; + for (i=0 ; i<3 ; i++) + p1[i] = p1[i] + frac *(p2[i] - p1[i]); + } + else + { + for (i=0 ; i<3 ; i++) + p2[i] = p1[i] + frac *(p2[i] - p1[i]); + } + } + + // find distance p1 is along dir + VectorSubtract (p1, origin, p1); + d1 = DotProduct (p1, dir); + + *dist = d1; + + return firstface; +} + +void Brush_AddToList (brush_t *b, brush_t *list) +{ + if (b->next || b->prev) + Error ("Brush_RemoveFromList: allready linked"); + b->next = list->next; + list->next->prev = b; + list->next = b; + b->prev = list; +} + +void Brush_RemoveFromList (brush_t *b) +{ + if (!b->next || !b->prev) + Error ("Brush_RemoveFromList: not linked"); + b->next->prev = b->prev; + b->prev->next = b->next; + b->next = b->prev = NULL; +} + +void Brush_SetTexture (brush_t *b, texdef_t *texdef) +{ + face_t *f; + + for (f=b->brush_faces ; f ; f=f->next) + f->texdef = *texdef; + Brush_Build( b ); +} + + +qboolean ClipLineToFace (vec3_t p1, vec3_t p2, face_t *f) +{ + float d1, d2, fr; + int i; + float *v; + + d1 = DotProduct (p1, f->plane.normal) - f->plane.dist; + d2 = DotProduct (p2, f->plane.normal) - f->plane.dist; + + if (d1 >= 0 && d2 >= 0) + return false; // totally outside + if (d1 <= 0 && d2 <= 0) + return true; // totally inside + + fr = d1 / (d1 - d2); + + if (d1 > 0) + v = p1; + else + v = p2; + + for (i=0 ; i<3 ; i++) + v[i] = p1[i] + fr*(p2[i] - p1[i]); + + return true; +} + + +int AddPlanept (float *f) +{ + int i; + + for (i=0 ; iowner->eclass->fixedsize) + return; + + c = 0; + for (i=0 ; i<3 ; i++) + c += AddPlanept (f->planepts[i]); + if (c == 0) + return; // allready completely added + + // select all points on this plane in all brushes the selection + for (b2=selected_brushes.next ; b2 != &selected_brushes ; b2 = b2->next) + { + if (b2 == b) + continue; + for (f2=b2->brush_faces ; f2 ; f2=f2->next) + { + for (i=0 ; i<3 ; i++) + if (fabs(DotProduct(f2->planepts[i], f->plane.normal) + -f->plane.dist) > ON_EPSILON) + break; + if (i==3) + { // move this face as well + Brush_SelectFaceForDragging (b2, f2, shear); + break; + } + } + } + + + // if shearing, take all the planes adjacent to + // selected faces and rotate their points so the + // edge clipped by a selcted face has two of the points + if (!shear) + return; + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + w = MakeFaceWinding (b, f2); + if (!w) + continue; + + // any points on f will become new control points + for (i=0 ; inumpoints ; i++) + { + d = DotProduct (w->points[i], f->plane.normal) + - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + break; + } + + // + // if none of the points were on the plane, + // leave it alone + // + if (i != w->numpoints) + { + if (i == 0) + { // see if the first clockwise point was the + // last point on the winding + d = DotProduct (w->points[w->numpoints-1] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + i = w->numpoints - 1; + } + + AddPlanept (f2->planepts[0]); + + VectorCopy (w->points[i], f2->planepts[0]); + if (++i == w->numpoints) + i = 0; + + // see if the next point is also on the plane + d = DotProduct (w->points[i] + , f->plane.normal) - f->plane.dist; + if (d > -ON_EPSILON && d < ON_EPSILON) + AddPlanept (f2->planepts[1]); + + VectorCopy (w->points[i], f2->planepts[1]); + if (++i == w->numpoints) + i = 0; + + // the third point is never on the plane + + VectorCopy (w->points[i], f2->planepts[2]); + } + + free(w); + } +} + +/* +============== +Brush_SideSelect + +The mouse click did not hit the brush, so grab one or more side +planes for dragging +============== +*/ +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir + , qboolean shear) +{ + face_t *f, *f2; + vec3_t p1, p2; + + for (f=b->brush_faces ; f ; f=f->next) + { + VectorCopy (origin, p1); + VectorMA (origin, 16384, dir, p2); + + for (f2=b->brush_faces ; f2 ; f2=f2->next) + { + if (f2 == f) + continue; + ClipLineToFace (p1, p2, f2); + } + + if (f2) + continue; + + if (VectorCompare (p1, origin)) + continue; + if (ClipLineToFace (p1, p2, f)) + continue; + + Brush_SelectFaceForDragging (b, f, shear); + } + + +} + +void Brush_BuildWindings( brush_t *b ) +{ + winding_t *w; + face_t *face; + vec_t v; + + Brush_SnapPlanepts( b ); + + // clear the mins/maxs bounds + b->mins[0] = b->mins[1] = b->mins[2] = 99999; + b->maxs[0] = b->maxs[1] = b->maxs[2] = -99999; + + Brush_MakeFacePlanes (b); + + face = b->brush_faces; + + for ( ; face ; face=face->next) + { + int i, j; + + w = face->face_winding = MakeFaceWinding (b, face); + face->d_texture = Texture_ForName( face->texdef.name ); + + if (!w) + { + continue; + } + + for (i=0 ; inumpoints ; i++) + { + // add to bounding box + for (j=0 ; j<3 ; j++) + { + v = w->points[i][j]; + if (v > b->maxs[j]) + b->maxs[j] = v; + if (v < b->mins[j]) + b->mins[j] = v; + } + } + // setup s and t vectors, and set color + BeginTexturingFace( b, face, face->d_texture); + + + for (i=0 ; inumpoints ; i++) + { + EmitTextureCoordinates( w->points[i], face->d_texture, face); + } + } +} + +/* +================== +Brush_RemoveEmptyFaces + +Frees any overconstraining faces +================== +*/ +void Brush_RemoveEmptyFaces ( brush_t *b ) +{ + face_t *f, *next; + + f = b->brush_faces; + b->brush_faces = NULL; + + for ( ; f ; f=next) + { + next = f->next; + if (!f->face_winding) + Face_Free (f); + else + { + f->next = b->brush_faces; + b->brush_faces = f; + } + + } +} + +void Brush_Draw( brush_t *b ) +{ + face_t *face; + int i, order; + qtexture_t *prev = 0; + winding_t *w; + + if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture) + glDisable (GL_TEXTURE_2D); + + // guarantee the texture will be set first + prev = NULL; + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + w = face->face_winding; + if (!w) + continue; // freed face + + if ( face->d_texture != prev && camera.draw_mode == cd_texture) + { + // set the texture for this face + prev = face->d_texture; + glBindTexture( GL_TEXTURE_2D, face->d_texture->texture_number ); + } + + glColor3fv( face->d_color ); + + // draw the polygon + glBegin(GL_POLYGON); + for (i=0 ; inumpoints ; i++) + { + if (camera.draw_mode == cd_texture) + glTexCoord2fv( &w->points[i][3] ); + glVertex3fv(w->points[i]); + } + glEnd(); + } + + if (b->owner->eclass->fixedsize && camera.draw_mode == cd_texture) + glEnable (GL_TEXTURE_2D); + + glBindTexture( GL_TEXTURE_2D, 0 ); +} + +void Face_Draw( face_t *f ) +{ + int i; + + if ( f->face_winding == 0 ) + return; + glBegin( GL_POLYGON ); + for ( i = 0 ; i < f->face_winding->numpoints; i++) + glVertex3fv( f->face_winding->points[i] ); + glEnd(); +} + +void Brush_DrawXY( brush_t *b ) +{ + face_t *face; + int order; + winding_t *w; + int i; + + for (face = b->brush_faces,order = 0 ; face ; face=face->next, order++) + { + // only draw up facing polygons + if (face->plane.normal[2] <= 0) + continue; + + w = face->face_winding; + if (!w) + continue; + + // draw the polygon + glBegin(GL_LINE_LOOP); + for (i=0 ; inumpoints ; i++) + glVertex3fv(w->points[i]); + glEnd(); + } + + // optionally add a text label + if ( g_qeglobals.d_savedinfo.show_names ) + DrawBrushEntityName (b); +} + +face_t *Face_Alloc( void ) +{ + face_t *f = qmalloc( sizeof( *f ) ); + + return f; +} + +void Face_Free( face_t *f ) +{ + assert( f != 0 ); + + if ( f->face_winding ) + free( f->face_winding ), f->face_winding = 0; + free( f ); +} diff --git a/tools/quake2/extra/qe4/brush.h b/tools/quake2/extra/qe4/brush.h new file mode 100644 index 00000000..7a948e03 --- /dev/null +++ b/tools/quake2/extra/qe4/brush.h @@ -0,0 +1,87 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// brush.h + + +typedef struct +{ + int numpoints; + int maxpoints; + float points[8][5]; // variable sized +} winding_t; + + +// the normals on planes point OUT of the brush +#define MAXPOINTS 16 +typedef struct face_s +{ + struct face_s *next; + vec3_t planepts[3]; + texdef_t texdef; + + plane_t plane; + + winding_t *face_winding; + + vec3_t d_color; + qtexture_t *d_texture; + +// int d_numpoints; +// vec3_t *d_points; +} face_t; + +#define MAX_FACES 16 +typedef struct brush_s +{ + struct brush_s *prev, *next; // links in active/selected + struct brush_s *oprev, *onext; // links in entity + struct entity_s *owner; + vec3_t mins, maxs; + + face_t *brush_faces; +} brush_t; + + +void Brush_AddToList (brush_t *b, brush_t *list); +void Brush_Build(brush_t *b); +void Brush_BuildWindings( brush_t *b ); +brush_t *Brush_Clone (brush_t *b); +brush_t *Brush_Create (vec3_t mins, vec3_t maxs, texdef_t *texdef); +void Brush_Draw( brush_t *b ); +void Brush_DrawXY( brush_t *b ); +void Brush_Free (brush_t *b); +void Brush_MakeSided (int sides); +void Brush_Move (brush_t *b, vec3_t move); +brush_t *Brush_Parse (void); +face_t *Brush_Ray (vec3_t origin, vec3_t dir, brush_t *b, float *dist); +void Brush_RemoveFromList (brush_t *b); +void Brush_SelectFaceForDragging (brush_t *b, face_t *f, qboolean shear); +void Brush_SetTexture (brush_t *b, texdef_t *texdef); +void Brush_SideSelect (brush_t *b, vec3_t origin, vec3_t dir, qboolean shear); +void Brush_Write (brush_t *b, FILE *f); +void Brush_RemoveEmptyFaces ( brush_t *b ); + +int AddPlanept (float *f); +face_t *Face_Clone (face_t *f); +void Face_Draw( face_t *face ); +winding_t *MakeFaceWinding (brush_t *b, face_t *face); diff --git a/tools/quake2/extra/qe4/bspfile.h b/tools/quake2/extra/qe4/bspfile.h new file mode 100644 index 00000000..89c56a34 --- /dev/null +++ b/tools/quake2/extra/qe4/bspfile.h @@ -0,0 +1,378 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_PATHS 2048 +#define MAX_MAP_ENTSTRING 0x20000 +#define MAX_MAP_TEXTURES 1024 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_MIPTEX 0x200000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +#define BSPVERSION 34 + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_TEXTURES 2 +#define LUMP_VERTEXES 3 +#define LUMP_VISIBILITY 4 +#define LUMP_NODES 5 +#define LUMP_TEXINFO 6 +#define LUMP_FACES 7 +#define LUMP_LIGHTING 8 +#define LUMP_LEAFS 9 +#define LUMP_LEAFFACES 10 +#define LUMP_LEAFBRUSHES 11 +#define LUMP_EDGES 12 +#define LUMP_SURFEDGES 13 +#define LUMP_MODELS 14 +#define LUMP_PATHS 15 +#define LUMP_BRUSHES 16 +#define LUMP_BRUSHSIDES 17 +#define LUMP_POP 18 + +#define HEADER_LUMPS 18 + +typedef struct +{ + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int visleafs; // not including the solid leaf 0 + int firstface, numfaces; +} dmodel_t; + +typedef struct +{ + int nummiptex; + int dataofs[4]; // [nummiptex] +} dmiptexlump_t; + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[16]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + int flags; + int value; +} miptex_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 2 // translucent, but not watery +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_THINWATER 64 // translucent faces + +#define LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes +#define CONTENTS_MONSTER 128 +#define CONTENTS_PLAYERCLIP 256 +#define CONTENTS_MONSTERCLIP 512 + + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 1024 +#define CONTENTS_CURRENT_90 2048 +#define CONTENTS_CURRENT_180 4096 +#define CONTENTS_CURRENT_270 8192 +#define CONTENTS_CURRENT_UP 16384 +#define CONTENTS_CURRENT_DOWN 32768 + +#define CONTENTS_ORIGIN 65536 // removed before processing + + + +// !!! if this is changed, it must be changed in asm_i386.h too !!! +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int miptex; + int flags; // miptex flags + overrides + int value; // light emition, etc +} texinfo_t; + +#define TEX_SPECIAL 1 // sky or slime, no lightmap or 256 subdivision +#define SURF_LIGHT 2 + +#define SURF_WATER 4 +#define SURF_SLIME 8 +#define SURF_LAVA 16 +#define SURF_WINDOW 32 + +#define SURF_SKY 64 +#define SURF_MIRROR 128 + +#define SURF_SLIPPERY 256 + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes + int visofs; // -1 = no visibility info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +typedef struct +{ + float origin[3]; + float angles[3]; + int next, prev; + int flags; + float speed; +} dpath_t; + +//============================================================================ + +#ifndef QUAKE_GAME + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + + +// the utilities get to be lazy and just use large static arrays + +extern int nummodels; +extern dmodel_t dmodels[MAX_MAP_MODELS]; + +extern int visdatasize; +extern byte dvisdata[MAX_MAP_VISIBILITY]; + +extern int lightdatasize; +extern byte dlightdata[MAX_MAP_LIGHTING]; + +extern int texdatasize; +extern byte dtexdata[MAX_MAP_MIPTEX]; // (dmiptexlump_t) + +extern int entdatasize; +extern char dentdata[MAX_MAP_ENTSTRING]; + +extern int numleafs; +extern dleaf_t dleafs[MAX_MAP_LEAFS]; + +extern int numplanes; +extern dplane_t dplanes[MAX_MAP_PLANES]; + +extern int numvertexes; +extern dvertex_t dvertexes[MAX_MAP_VERTS]; + +extern int numnodes; +extern dnode_t dnodes[MAX_MAP_NODES]; + +extern int numtexinfo; +extern texinfo_t texinfo[MAX_MAP_TEXINFO]; + +extern int numfaces; +extern dface_t dfaces[MAX_MAP_FACES]; + +extern int numedges; +extern dedge_t dedges[MAX_MAP_EDGES]; + +extern int numleaffaces; +extern unsigned short dleaffaces[MAX_MAP_LEAFFACES]; + +extern int numleafbrushes; +extern unsigned short dleafbrushes[MAX_MAP_LEAFBRUSHES]; + +extern int numsurfedges; +extern int dsurfedges[MAX_MAP_SURFEDGES]; + +extern int numpaths; +extern dpath_t dpaths[MAX_MAP_PATHS]; + +extern int numbrushes; +extern dbrush_t dbrushes[MAX_MAP_BRUSHES]; + +extern int numbrushsides; +extern dbrushside_t dbrushsides[MAX_MAP_BRUSHSIDES]; + + +void DecompressVis (byte *in, byte *decompressed); +int CompressVis (byte *vis, byte *dest); + +void LoadBSPFile (char *filename); +void WriteBSPFile (char *filename); +void PrintBSPFileSizes (void); + +//=============== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct +{ + vec3_t origin; + int firstbrush; + int numbrushes; + epair_t *epairs; +} entity_t; + +extern int num_entities; +extern entity_t entities[MAX_MAP_ENTITIES]; + +void ParseEntities (void); +void UnparseEntities (void); + +void SetKeyValue (entity_t *ent, char *key, char *value); +char *ValueForKey (entity_t *ent, char *key); +// will return "" if not present + +vec_t FloatForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +epair_t *ParseEpair (void); + +void PrintEntity (entity_t *ent); + +extern int r_leaftovis[MAX_MAP_LEAFS]; +extern int r_vistoleaf[MAX_MAP_LEAFS]; +extern int r_numvisleafs; + +#endif diff --git a/tools/quake2/extra/qe4/camera.c b/tools/quake2/extra/qe4/camera.c new file mode 100644 index 00000000..8dd7d5f5 --- /dev/null +++ b/tools/quake2/extra/qe4/camera.c @@ -0,0 +1,594 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +#define PAGEFLIPS 2 + +void DrawPathLines (void); + +camera_t camera; + +/* +============ +Cam_Init +============ +*/ +void Cam_Init (void) +{ +// camera.draw_mode = cd_texture; +// camera.draw_mode = cd_solid; +// camera.draw_mode = cd_wire; + + camera.timing = false; + + camera.origin[0] = 0; + camera.origin[1] = 20; + camera.origin[2] = 46; + + camera.color[0] = 0.3; + camera.color[1] = 0.3; + camera.color[2] = 0.3; +} + + +//============================================================================ + +void Cam_BuildMatrix (void) +{ + float xa, ya; + float matrix[4][4]; + int i; + + xa = camera.angles[0]/180*Q_PI; + ya = camera.angles[1]/180*Q_PI; + + // the movement matrix is kept 2d + + camera.forward[0] = cos(ya); + camera.forward[1] = sin(ya); + camera.right[0] = camera.forward[1]; + camera.right[1] = -camera.forward[0]; + + glGetFloatv (GL_PROJECTION_MATRIX, &matrix[0][0]); + + for (i=0 ; i<3 ; i++) + { + camera.vright[i] = matrix[i][0]; + camera.vup[i] = matrix[i][1]; + camera.vpn[i] = matrix[i][2]; + } + + VectorNormalize (camera.vright); + VectorNormalize (camera.vup); + VectorNormalize (camera.vpn); +} + +//=============================================== + +/* +=============== +Cam_ChangeFloor +=============== +*/ +void Cam_ChangeFloor (qboolean up) +{ + brush_t *b; + float d, bestd, current; + vec3_t start, dir; + + start[0] = camera.origin[0]; + start[1] = camera.origin[1]; + start[2] = 8192; + dir[0] = dir[1] = 0; + dir[2] = -1; + + current = 8192 - (camera.origin[2] - 48); + if (up) + bestd = 0; + else + bestd = 16384; + + for (b=active_brushes.next ; b != &active_brushes ; b=b->next) + { + if (!Brush_Ray (start, dir, b, &d)) + continue; + if (up && d < current && d > bestd) + bestd = d; + if (!up && d > current && d < bestd) + bestd = d; + } + + if (bestd == 0 || bestd == 16384) + return; + + camera.origin[2] += current - bestd; + Sys_UpdateWindows (W_CAMERA|W_Z_OVERLAY); +} + + +//=============================================== + +int cambuttonstate; +static int buttonx, buttony; +static int cursorx, cursory; + +face_t *side_select; + +#define ANGLE_SPEED 300 +#define MOVE_SPEED 400 + +/* +================ +Cam_PositionDrag +================ +*/ +void Cam_PositionDrag (void) +{ + int x, y; + + Sys_GetCursorPos (&x, &y); + if (x != cursorx || y != cursory) + { + x -= cursorx; + VectorMA (camera.origin, x, camera.vright, camera.origin); + y -= cursory; + camera.origin[2] -= y; + + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_CAMERA | W_XY_OVERLAY); + } +} + +/* +=============== +Cam_MouseControl +=============== +*/ +void Cam_MouseControl (float dtime) +{ + int xl, xh; + int yl, yh; + float xf, yf; + + if (cambuttonstate != MK_RBUTTON) + return; + + xf = (float)(buttonx - camera.width/2) / (camera.width/2); + yf = (float)(buttony - camera.height/2) / (camera.height/2); + + xl = camera.width/3; + xh = xl*2; + yl = camera.height/3; + yh = yl*2; + +#if 0 + // strafe + if (buttony < yl && (buttonx < xl || buttonx > xh)) + VectorMA (camera.origin, xf*dtime*MOVE_SPEED, camera.right, camera.origin); + else +#endif + { + xf *= 1.0 - fabs(yf); + if (xf < 0) + { + xf += 0.1; + if (xf > 0) + xf = 0; + } + else + { + xf -= 0.1; + if (xf < 0) + xf = 0; + } + + VectorMA (camera.origin, yf*dtime*MOVE_SPEED, camera.forward, camera.origin); + camera.angles[YAW] += xf*-dtime*ANGLE_SPEED; + } + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); +} + + + + +/* +============== +Cam_MouseDown +============== +*/ +void Cam_MouseDown (int x, int y, int buttons) +{ + vec3_t dir; + float f, r, u; + int i; + + // + // calc ray direction + // + u = (float)(y - camera.height/2) / (camera.width/2); + r = (float)(x - camera.width/2) / (camera.width/2); + f = 1; + + for (i=0 ; i<3 ; i++) + dir[i] = camera.vpn[i] * f + camera.vright[i] * r + camera.vup[i] * u; + VectorNormalize (dir); + + Sys_GetCursorPos (&cursorx, &cursory); + + cambuttonstate = buttons; + buttonx = x; + buttony = y; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + || (buttons == MK_MBUTTON) + || (buttons == (MK_MBUTTON|MK_CONTROL)) + || (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL)) ) + { + Drag_Begin (x, y, buttons, + camera.vright, camera.vup, + camera.origin, dir); + return; + } + + if (buttons == MK_RBUTTON) + { + Cam_MouseControl (0.1); + return; + } +} + +/* +============== +Cam_MouseUp +============== +*/ +void Cam_MouseUp (int x, int y, int buttons) +{ + cambuttonstate = 0; + Drag_MouseUp (); +} + + +/* +============== +Cam_MouseMoved +============== +*/ +void Cam_MouseMoved (int x, int y, int buttons) +{ + cambuttonstate = buttons; + if (!buttons) + return; + buttonx = x; + buttony = y; + + if (buttons == (MK_RBUTTON|MK_CONTROL) ) + { + Cam_PositionDrag (); + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + return; + } + + Sys_GetCursorPos (&cursorx, &cursory); + + if (buttons & (MK_LBUTTON | MK_MBUTTON) ) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_XY|W_CAMERA|W_Z); + } +} + + +vec3_t cull1, cull2; +int cullv1[3], cullv2[3]; + +void InitCull (void) +{ + int i; + + VectorSubtract (camera.vpn, camera.vright, cull1); + VectorAdd (camera.vpn, camera.vright, cull2); + + for (i=0 ; i<3 ; i++) + { + if (cull1[i] > 0) + cullv1[i] = 3+i; + else + cullv1[i] = i; + if (cull2[i] > 0) + cullv2[i] = 3+i; + else + cullv2[i] = i; + } +} + +qboolean CullBrush (brush_t *b) +{ + int i; + vec3_t point; + float d; + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[cullv1[i]] - camera.origin[i]; + + d = DotProduct (point, cull1); + if (d < -1) + return true; + + for (i=0 ; i<3 ; i++) + point[i] = b->mins[cullv2[i]] - camera.origin[i]; + + d = DotProduct (point, cull2); + if (d < -1) + return true; + + return false; +} + + +/* +============== +Cam_Draw +============== +*/ +void Cam_Draw (void) +{ + brush_t *brush; + face_t *face; + float screenaspect; + float yfov; + double start, end; + int i; + + if (!active_brushes.next) + return; // not valid yet + + if (camera.timing) + start = Sys_DoubleTime (); + + // + // clear + // + QE_CheckOpenGLForErrors(); + + glViewport(0, 0, camera.width, camera.height); + glScissor(0, 0, camera.width, camera.height); + glClearColor ( + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][2], + 0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // + // set up viewpoint + // + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + + screenaspect = (float)camera.width/camera.height; + yfov = 2*atan((float)camera.height/camera.width)*180/Q_PI; + gluPerspective (yfov, screenaspect, 2, 8192); + + glRotatef (-90, 1, 0, 0); // put Z going up + glRotatef (90, 0, 0, 1); // put Z going up + glRotatef (camera.angles[0], 0, 1, 0); + glRotatef (-camera.angles[1], 0, 0, 1); + glTranslatef (-camera.origin[0], -camera.origin[1], -camera.origin[2]); + + Cam_BuildMatrix (); + + InitCull (); + + // + // draw stuff + // + + switch (camera.draw_mode) + { + case cd_wire: + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glDisable(GL_BLEND); + glDisable(GL_DEPTH_TEST); + glColor3f(1.0, 1.0, 1.0); +// glEnable (GL_LINE_SMOOTH); + break; + + case cd_solid: + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + glShadeModel (GL_FLAT); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glDisable(GL_TEXTURE_2D); + + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthFunc (GL_LEQUAL); + break; + + case cd_texture: + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + + glShadeModel (GL_FLAT); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_TEXTURE_2D); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glDepthFunc (GL_LEQUAL); + +#if 0 + + { + GLfloat fogColor[4] = {0.0, 1.0, 0.0, 0.25}; + + glFogi (GL_FOG_MODE, GL_LINEAR); + glHint (GL_FOG_HINT, GL_NICEST); /* per pixel */ + glFogf (GL_FOG_START, -8192); + glFogf (GL_FOG_END, 65536); + glFogfv (GL_FOG_COLOR, fogColor); + + } + +#endif + break; + + case cd_blend: + glCullFace(GL_FRONT); + glEnable(GL_CULL_FACE); + + glShadeModel (GL_FLAT); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glEnable(GL_TEXTURE_2D); + + glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + glDisable(GL_DEPTH_TEST); + glEnable (GL_BLEND); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + break; + } + + glMatrixMode(GL_TEXTURE); + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if (CullBrush (brush)) + continue; + if (FilterBrush (brush)) + continue; + + Brush_Draw( brush ); + } + glMatrixMode(GL_PROJECTION); + + // + // now draw selected brushes + // + + glTranslatef (g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]); + glMatrixMode(GL_TEXTURE); + + // draw normally + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + Brush_Draw( brush ); + } + + // blend on top + glMatrixMode(GL_PROJECTION); + + glColor4f(1.0, 0.0, 0.0, 0.3); + glEnable (GL_BLEND); + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glDisable (GL_TEXTURE_2D); + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + for (face=brush->brush_faces ; face ; face=face->next) + Face_Draw( face ); + if (selected_face) + Face_Draw(selected_face); + + // non-zbuffered outline + + glDisable (GL_BLEND); + glDisable (GL_DEPTH_TEST); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glColor3f (1, 1, 1); + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + for (face=brush->brush_faces ; face ; face=face->next) + Face_Draw( face ); + + // edge / vertex flags + + if (g_qeglobals.d_select_mode == sel_vertex) + { + glPointSize (4); + glColor3f (0,1,0); + glBegin (GL_POINTS); + for (i=0 ; i32); + + com_token[len] = 0; + return data; +} + + +int Q_strncasecmp (char *s1, char *s2, int n) +{ + int c1, c2; + + while (1) + { + c1 = *s1++; + c2 = *s2++; + + if (!n--) + return 0; // strings are equal until end point + + if (c1 != c2) + { + if (c1 >= 'a' && c1 <= 'z') + c1 -= ('a' - 'A'); + if (c2 >= 'a' && c2 <= 'z') + c2 -= ('a' - 'A'); + if (c1 != c2) + return -1; // strings not equal + } + if (!c1) + return 0; // strings are equal + } + + return -1; +} + +int Q_strcasecmp (char *s1, char *s2) +{ + return Q_strncasecmp (s1, s2, 99999); +} + + + +/* +============================================================================= + + MISC FUNCTIONS + +============================================================================= +*/ + + +int argc; +char *argv[MAX_NUM_ARGVS]; + +/* +============ +ParseCommandLine +============ +*/ +void ParseCommandLine (char *lpCmdLine) +{ + argc = 1; + argv[0] = "programname"; + + while (*lpCmdLine && (argc < MAX_NUM_ARGVS)) + { + while (*lpCmdLine && ((*lpCmdLine <= 32) || (*lpCmdLine > 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + argv[argc] = lpCmdLine; + argc++; + + while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + *lpCmdLine = 0; + lpCmdLine++; + } + + } + } +} + + + +/* +================= +CheckParm + +Checks for the given parameter in the program's command line arguments +Returns the argument number (1 to argc-1) or 0 if not present +================= +*/ +int CheckParm (char *check) +{ + int i; + + for (i = 1;i 0 && path[length] != PATHSEPERATOR) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/') + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != PATHSEPERATOR) + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileName (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileBase (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void ExtractFileExtension (char *path, char *dest) +{ + char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +/* +============== +ParseNum / ParseHex +============== +*/ +int ParseHex (char *hex) +{ + char *str; + int num; + + num = 0; + str = hex; + + while (*str) + { + num <<= 4; + if (*str >= '0' && *str <= '9') + num += *str-'0'; + else if (*str >= 'a' && *str <= 'f') + num += 10 + *str-'a'; + else if (*str >= 'A' && *str <= 'F') + num += 10 + *str-'A'; + else + Error ("Bad hex number: %s",hex); + str++; + } + + return num; +} + + +int ParseNum (char *str) +{ + if (str[0] == '$') + return ParseHex (str+1); + if (str[0] == '0' && str[1] == 'x') + return ParseHex (str+2); + return atol (str); +} + + + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + + +#else + + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + + + +#endif + diff --git a/tools/quake2/extra/qe4/cmdlib.h b/tools/quake2/extra/qe4/cmdlib.h new file mode 100644 index 00000000..b748950c --- /dev/null +++ b/tools/quake2/extra/qe4/cmdlib.h @@ -0,0 +1,99 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// cmdlib.h + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include +#include +#include +#include +#include +#include +#include + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum {false, true} qboolean; +typedef unsigned char byte; +#endif + +// the dec offsetof macro doesn't work very well... +#define myoffsetof(type,identifier) ((size_t)&((type *)0)->identifier) + + +// set these before calling CheckParm +extern int myargc; +extern char **myargv; + +int Q_strncasecmp (char *s1, char *s2, int n); +int Q_strcasecmp (char *s1, char *s2); + +int Q_filelength (FILE *f); + +double I_FloatTime (void); + +void Error (char *error, ...); +int CheckParm (char *check); +void ParseCommandLine (char *lpCmdLine); + +FILE *SafeOpenWrite (char *filename); +FILE *SafeOpenRead (char *filename); +void SafeRead (FILE *f, void *buffer, int count); +void SafeWrite (FILE *f, void *buffer, int count); + +int LoadFile (char *filename, void **bufferptr); +int LoadFileNoCrash (char *filename, void **bufferptr); +void SaveFile (char *filename, void *buffer, int count); + +void DefaultExtension (char *path, char *extension); +void DefaultPath (char *path, char *basepath); +void StripFilename (char *path); +void StripExtension (char *path); + +void ExtractFilePath (char *path, char *dest); +void ExtractFileName (char *path, char *dest); +void ExtractFileBase (char *path, char *dest); +void ExtractFileExtension (char *path, char *dest); + +int ParseNum (char *str); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); + + +char *COM_Parse (char *data); + +extern char com_token[1024]; +extern qboolean com_eof; + +#define MAX_NUM_ARGVS 32 +extern int argc; +extern char *argv[MAX_NUM_ARGVS]; + +#endif diff --git a/tools/quake2/extra/qe4/csg.c b/tools/quake2/extra/qe4/csg.c new file mode 100644 index 00000000..e36a2ade --- /dev/null +++ b/tools/quake2/extra/qe4/csg.c @@ -0,0 +1,168 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +/* +============== +CSG_SplitBrushByFace + +The incoming brush is NOT freed. +The incoming face is NOT left referenced. +============== +*/ +void CSG_SplitBrushByFace (brush_t *in, face_t *f, brush_t **front, brush_t **back) +{ + brush_t *b; + face_t *nf; + vec3_t temp; + + b = Brush_Clone (in); + nf = Face_Clone (f); + + nf->texdef = b->brush_faces->texdef; + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *back = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *back = b; + } + + b = Brush_Clone (in); + nf = Face_Clone (f); + // swap the plane winding + VectorCopy (nf->planepts[0], temp); + VectorCopy (nf->planepts[1], nf->planepts[0]); + VectorCopy (temp, nf->planepts[1]); + + nf->texdef = b->brush_faces->texdef; + nf->next = b->brush_faces; + b->brush_faces = nf; + + Brush_Build( b ); + Brush_RemoveEmptyFaces ( b ); + if ( !b->brush_faces ) + { // completely clipped away + Brush_Free (b); + *front = NULL; + } + else + { + Entity_LinkBrush (in->owner, b); + *front = b; + } +} + +/* +============= +CSG_MakeHollow +============= +*/ +void CSG_MakeHollow (void) +{ + brush_t *b, *front, *back, *next; + face_t *f; + face_t split; + vec3_t move; + int i; + + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + for (f = b->brush_faces ; f ; f=f->next) + { + split = *f; + VectorScale (f->plane.normal, g_qeglobals.d_gridsize, move); + for (i=0 ; i<3 ; i++) + VectorSubtract (split.planepts[i], move, split.planepts[i]); + + CSG_SplitBrushByFace (b, &split, &front, &back); + if (back) + Brush_Free (back); + if (front) + Brush_AddToList (front, &selected_brushes); + } + Brush_Free (b); + } + Sys_UpdateWindows (W_ALL); +} + + +/* +============= +CSG_Subtract +============= +*/ +void CSG_Subtract (void) +{ + brush_t *b, *s, *frag, *front, *back, *next, *snext; + face_t *f; + int i; + + Sys_Printf ("Subtracting...\n"); + + for (b = selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + + if (b->owner->eclass->fixedsize) + continue; // can't use texture from a fixed entity, so don't subtract + + for (s=active_brushes.next ; s != &active_brushes ; s=snext) + { + snext = s->next; + if (s->owner->eclass->fixedsize) + continue; + + for (i=0 ; i<3 ; i++) + if (b->mins[i] >= s->maxs[i] - ON_EPSILON + || b->maxs[i] <= s->mins[i] + ON_EPSILON) + break; + if (i != 3) + continue; // definately don't touch + + frag = s; + for (f = b->brush_faces ; f && frag ; f=f->next) + { + CSG_SplitBrushByFace (frag, f, &front, &back); + Brush_Free (frag); + frag = back; + if (front) + Brush_AddToList (front, &active_brushes); + } + if (frag) + Brush_Free (frag); + } + } + + Sys_Printf ("done.\n"); + Sys_UpdateWindows (W_ALL); +} diff --git a/tools/quake2/extra/qe4/drag.c b/tools/quake2/extra/qe4/drag.c new file mode 100644 index 00000000..2418325e --- /dev/null +++ b/tools/quake2/extra/qe4/drag.c @@ -0,0 +1,457 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +/* + + drag either multiple brushes, or select plane points from + a single brush. + +*/ + +qboolean drag_ok; +vec3_t drag_xvec; +vec3_t drag_yvec; + +static int buttonstate; +static int pressx, pressy; +static vec3_t pressdelta; +static int buttonx, buttony; + + +//int num_move_points; +//float *move_points[1024]; + +int lastx, lasty; + +qboolean drag_first; + + +void AxializeVector (vec3_t v) +{ + vec3_t a; + float o; + int i; + + if (!v[0] && !v[1]) + return; + if (!v[1] && !v[2]) + return; + if (!v[0] && !v[2]) + return; + + for (i=0 ; i<3 ; i++) + a[i] = fabs(v[i]); + if (a[0] > a[1] && a[0] > a[2]) + i = 0; + else if (a[1] > a[0] && a[1] > a[2]) + i = 1; + else + i = 2; + + o = v[i]; + VectorCopy (vec3_origin, v); + if (o<0) + v[i] = -1; + else + v[i] = 1; + +} + + +/* +=========== +Drag_Setup +=========== +*/ +void Drag_Setup (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir) +{ + trace_t t; + face_t *f; + + if (selected_brushes.next == &selected_brushes) + { + Sys_Status("No selection to drag\n", 0); + return; + } + + drag_first = true; + g_qeglobals.d_num_move_points = 0; + VectorCopy (vec3_origin, pressdelta); + pressx = x; + pressy = y; + + VectorCopy (xaxis, drag_xvec); + AxializeVector (drag_xvec); + VectorCopy (yaxis, drag_yvec); + AxializeVector (drag_yvec); + + if (g_qeglobals.d_select_mode == sel_vertex) + { + SelectVertexByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + return; + } + } + if (g_qeglobals.d_select_mode == sel_edge) + { + SelectEdgeByRay (origin, dir); + if (g_qeglobals.d_num_move_points) + { + drag_ok = true; + return; + } + } + + + // + // check for direct hit first + // + t = Test_Ray (origin, dir, true); + if (t.selected) + { + drag_ok = true; + + if (buttons == (MK_LBUTTON|MK_CONTROL) ) + { + Sys_Printf ("Shear dragging face\n"); + Brush_SelectFaceForDragging (t.brush, t.face, true); + } + else if (buttons == (MK_LBUTTON|MK_CONTROL|MK_SHIFT) ) + { + Sys_Printf ("Sticky dragging brush\n"); + for (f=t.brush->brush_faces ; f ; f=f->next) + Brush_SelectFaceForDragging (t.brush, f, false); + } + else + Sys_Printf ("Dragging entire selection\n"); + + return; + } + + if (g_qeglobals.d_select_mode == sel_vertex || g_qeglobals.d_select_mode == sel_edge) + return; + + // + // check for side hit + // + if (selected_brushes.next->next != &selected_brushes) + { + Sys_Printf ("Click isn't inside multiple selection\n"); + return; + } + + if (selected_brushes.next->owner->eclass->fixedsize) + { + Sys_Printf ("Can't stretch fixed size entities\n"); + return; + } + + + if (buttons & MK_CONTROL) + Brush_SideSelect (selected_brushes.next, origin, dir, true); + else + Brush_SideSelect (selected_brushes.next, origin, dir, false); + + + Sys_Printf ("Side stretch\n"); + drag_ok = true; +} + +entity_t *peLink; + +void UpdateTarget(vec3_t origin, vec3_t dir) +{ + trace_t t; + entity_t *pe; + int i; + char sz[128]; + + t = Test_Ray (origin, dir, 0); + + if (!t.brush) + return; + + pe = t.brush->owner; + + if (pe == NULL) + return; + + // is this the first? + if (peLink != NULL) + { + + // Get the target id from out current target + // if there is no id, make one + + i = IntForKey(pe, "target"); + if (i <= 0) + { + i = GetUniqueTargetId(1); + sprintf(sz, "%d", i); + + SetKeyValue(pe, "target", sz); + } + + // set the target # into our src + + sprintf(sz, "%d", i); + SetKeyValue(peLink, "targetname", sz); + + Sys_UpdateWindows(W_ENTITY); + + } + + // promote the target to the src + + peLink = pe; + +} + +/* +=========== +Drag_Begin +=========== +*/ +void Drag_Begin (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir) +{ + trace_t t; + + drag_ok = false; + VectorCopy (vec3_origin, pressdelta); + + drag_first = true; + peLink = NULL; + + // shift LBUTTON = select entire brush + if (buttons == (MK_LBUTTON | MK_SHIFT)) + { + if (!dir[0] && !dir[1]) + Select_Ray (origin, dir, SF_ENTITIES_FIRST); // hack for XY + else + Select_Ray (origin, dir, 0); + return; + } + + // ctrl-shift LBUTTON = select single face + if (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) + { + Select_Deselect (); + Select_Ray (origin, dir, SF_SINGLEFACE); + return; + } + + // LBUTTON + all other modifiers = manipulate selection + if (buttons & MK_LBUTTON) + { + Drag_Setup (x, y, buttons, xaxis, yaxis, origin, dir); + return; + } + + // middle button = grab texture + if (buttons == MK_MBUTTON) + { + t = Test_Ray (origin, dir, false); + if (t.face) + { + g_qeglobals.d_new_brush_bottom_z = t.brush->mins[2]; + g_qeglobals.d_new_brush_top_z = t.brush->maxs[2]; + Texture_SetTexture (&t.face->texdef); + } + else + Sys_Printf ("Did not select a texture\n"); + return; + } + + // ctrl-middle button = set entire brush to texture + if (buttons == (MK_MBUTTON|MK_CONTROL) ) + { + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.name[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + Brush_SetTexture (t.brush, &g_qeglobals.d_texturewin.texdef); + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a btrush\n"); + return; + } + + // ctrl-shift-middle button = set single face to texture + if (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL) ) + { + t = Test_Ray (origin, dir, false); + if (t.brush) + { + if (t.brush->brush_faces->texdef.name[0] == '(') + Sys_Printf ("Can't change an entity texture\n"); + else + { + t.face->texdef = g_qeglobals.d_texturewin.texdef; + Brush_Build( t.brush ); + Sys_UpdateWindows (W_ALL); + } + } + else + Sys_Printf ("Didn't hit a btrush\n"); + return; + } + +} + + +/* +=========== +MoveSelection +=========== +*/ +void MoveSelection (vec3_t move) +{ + int i; + brush_t *b; + + if (!move[0] && !move[1] && !move[2]) + return; + + Sys_UpdateWindows (W_XY|W_CAMERA); + + // + // dragging only a part of the selection + // + if (g_qeglobals.d_num_move_points) + { + for (i=0 ; inext) + { + Brush_Build( b ); + for (i=0 ; i<3 ; i++) + if (b->mins[i] > b->maxs[i] + || b->maxs[i] - b->mins[i] > 4096) + break; // dragged backwards or fucked up + if (i != 3) + break; + } + + // if any of the brushes were crushed out of existance + // calcel the entire move + if (b != &selected_brushes) + { + Sys_Printf ("Brush dragged backwards, move canceled\n"); + for (i=0 ; inext) + Brush_Build( b ); + } + + } + else + { + // + // if there are lots of brushes selected, just translate instead + // of rebuilding the brushes + // + if (drag_yvec[2] == 0 && selected_brushes.next->next != &selected_brushes) + { + VectorAdd (g_qeglobals.d_select_translate, move, g_qeglobals.d_select_translate); + } + else + { + Select_Move (move); + } + } +} + +/* +=========== +Drag_MouseMoved +=========== +*/ +void Drag_MouseMoved (int x, int y, int buttons) +{ + vec3_t move, delta; + int i; + char movestring[128]; + + if (!buttons) + { + drag_ok = false; + return; + } + if (!drag_ok) + return; + + // clear along one axis + if (buttons & MK_SHIFT) + { + drag_first = false; + if (abs(x-pressx) > abs(y-pressy)) + y = pressy; + else + x = pressx; + } + + + for (i=0 ; i<3 ; i++) + { + move[i] = drag_xvec[i]*(x - pressx) + + drag_yvec[i]*(y - pressy); + move[i] = floor(move[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + + sprintf (movestring, "drag (%i %i %i)", (int)move[0], (int)move[1], (int)move[2]); + Sys_Status (movestring, 0); + + VectorSubtract (move, pressdelta, delta); + MoveSelection (delta); + VectorCopy (move, pressdelta); +} + +/* +=========== +Drag_MouseUp +=========== +*/ +void Drag_MouseUp (void) +{ + Sys_Status ("drag completed.", 0); + if (g_qeglobals.d_select_translate[0] || g_qeglobals.d_select_translate[1] || g_qeglobals.d_select_translate[2]) + { + Select_Move (g_qeglobals.d_select_translate); + VectorCopy (vec3_origin, g_qeglobals.d_select_translate); + Sys_UpdateWindows (W_CAMERA); + } +} diff --git a/tools/quake2/extra/qe4/eclass.c b/tools/quake2/extra/qe4/eclass.c new file mode 100644 index 00000000..466d8a48 --- /dev/null +++ b/tools/quake2/extra/qe4/eclass.c @@ -0,0 +1,281 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" +#include "io.h" + +eclass_t *eclass; +eclass_t *eclass_bad; +char eclass_directory[1024]; + +/* + +the classname, color triple, and bounding box are parsed out of comments +A ? size means take the exact brush size. + +/*QUAKED (0 0 0) ? +/*QUAKED (0 0 0) (-8 -8 -8) (8 8 8) + +Flag names can follow the size description: + +/*QUAKED func_door (0 .5 .8) ? START_OPEN STONE_SOUND DOOR_DONT_LINK GOLD_KEY SILVER_KEY + +*/ +char *debugname; + +eclass_t *Eclass_InitFromText (char *text) +{ + char *t; + int len; + int r, i; + char parms[256], *p; + eclass_t *e; + char color[128]; + + e = qmalloc(sizeof(*e)); + memset (e, 0, sizeof(*e)); + + text += strlen("/*QUAKED "); + +// grab the name + text = COM_Parse (text); + e->name = qmalloc (strlen(com_token)+1); + strcpy (e->name, com_token); + debugname = e->name; + +// grab the color, reformat as texture name + r = sscanf (text," (%f %f %f)", &e->color[0], &e->color[1], &e->color[2]); + if (r != 3) + return e; + sprintf (color, "(%f %f %f)", e->color[0], e->color[1], e->color[2]); + strcpy (e->texdef.name, color); + + while (*text != ')') + { + if (!*text) + return e; + text++; + } + text++; + +// get the size + text = COM_Parse (text); + if (com_token[0] == '(') + { // parse the size as two vectors + e->fixedsize = true; + r = sscanf (text,"%f %f %f) (%f %f %f)", &e->mins[0], &e->mins[1], &e->mins[2], + &e->maxs[0], &e->maxs[1], &e->maxs[2]); + if (r != 6) + return e; + + for (i=0 ; i<2 ; i++) + { + while (*text != ')') + { + if (!*text) + return e; + text++; + } + text++; + } + } + else + { // use the brushes + } + +// get the flags + + +// copy to the first /n + p = parms; + while (*text && *text != '\n') + *p++ = *text++; + *p = 0; + text++; + +// any remaining words are parm flags + p = parms; + for (i=0 ; i<8 ; i++) + { + p = COM_Parse (p); + if (!p) + break; + strcpy (e->flagnames[i], com_token); + } + +// find the length until close comment + for (t=text ; t[0] && !(t[0]=='*' && t[1]=='/') ; t++) + ; + +// copy the comment block out + len = t-text; + e->comments = qmalloc (len+1); + memcpy (e->comments, text, len); +#if 0 + for (i=0 ; icomments[i] = '\r'; + else + e->comments[i] = text[i]; +#endif + e->comments[len] = 0; + + return e; +} + + +/* +================= +Eclass_InsertAlphabetized +================= +*/ +void Eclass_InsertAlphabetized (eclass_t *e) +{ + eclass_t *s; + + if (!eclass) + { + eclass = e; + return; + } + + + s = eclass; + if (stricmp (e->name, s->name) < 0) + { + e->next = s; + eclass = e; + return; + } + + do + { + if (!s->next || stricmp (e->name, s->next->name) < 0) + { + e->next = s->next; + s->next = e; + return; + } + s=s->next; + } while (1); +} + + +/* +================= +Eclass_ScanFile +================= +*/ +void Eclass_ScanFile (char *filename) +{ + int size; + char *data; + eclass_t *e; + int i; + char temp[1024]; + + QE_ConvertDOSToUnixName( temp, filename ); + + Sys_Printf ("ScanFile: %s\n", temp); + + size = LoadFile (filename, (void *)&data); + + for (i=0 ; inext) + if (!strcmp (name, e->name)) + return e; + + // create a new class for it + if (has_brushes) + { + sprintf (init, "/*QUAKED %s (0 0.5 0) ?\nNot found in source.\n", name); + e = Eclass_InitFromText (init); + } + else + { + sprintf (init, "/*QUAKED %s (0 0.5 0) (-8 -8 -8) (8 8 8)\nNot found in source.\n", name); + e = Eclass_InitFromText (init); + } + + Eclass_InsertAlphabetized (e); + + return e; +} + diff --git a/tools/quake2/extra/qe4/entity.c b/tools/quake2/extra/qe4/entity.c new file mode 100644 index 00000000..7cbe14ae --- /dev/null +++ b/tools/quake2/extra/qe4/entity.c @@ -0,0 +1,538 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +char *ValueForKey (entity_t *ent, char *key) +{ + epair_t *ep; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + return ep->value; + return ""; +} + +void SetKeyValue (entity_t *ent, char *key, char *value) +{ + epair_t *ep; + + if (ent == NULL) + return; + + if (!key || !key[0]) + return; + + for (ep=ent->epairs ; ep ; ep=ep->next) + if (!strcmp (ep->key, key) ) + { + free (ep->value); + ep->value = qmalloc(strlen(value)+1); + strcpy (ep->value, value); + return; + } + ep = qmalloc (sizeof(*ep)); + ep->next = ent->epairs; + ent->epairs = ep; + ep->key = qmalloc(strlen(key)+1); + strcpy (ep->key, key); + ep->value = qmalloc(strlen(value)+1); + strcpy (ep->value, value); +} + +void DeleteKey (entity_t *ent, char *key) +{ + epair_t **ep, *next; + + ep = &ent->epairs; + while (*ep) + { + next = *ep; + if ( !strcmp (next->key, key) ) + { + *ep = next->next; + free(next->key); + free(next->value); + free(next); + return; + } + ep = &next->next; + } +} + +float FloatForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atof(k); +} + +int IntForKey (entity_t *ent, char *key) +{ + char *k; + + k = ValueForKey (ent, key); + return atoi(k); +} + +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec) +{ + char *k; + + k = ValueForKey (ent, key); + sscanf (k, "%f %f %f", &vec[0], &vec[1], &vec[2]); +} + + +/* +=============== +Entity_Free + +Frees the entity and any brushes is has. +The entity is removed from the global entities list. +=============== +*/ +void Entity_Free (entity_t *e) +{ + epair_t *ep, *next; + + while (e->brushes.onext != &e->brushes) + Brush_Free (e->brushes.onext); + + if (e->next) + { + e->next->prev = e->prev; + e->prev->next = e->next; + } + + for (ep = e->epairs ; ep ; ep=next) + { + next = ep->next; + free (ep); + } + free (e); +} + +/* +================= +ParseEpair +================= +*/ +epair_t *ParseEpair (void) +{ + epair_t *e; + + e = qmalloc (sizeof(*e)); + + e->key = qmalloc(strlen(token)+1); + strcpy (e->key, token); + + GetToken (false); + e->value = qmalloc(strlen(token)+1); + strcpy (e->value, token); + + return e; +} + +/* +================ +Entity_Parse + +If onlypairs is set, the classname info will not +be looked up, and the entity will not be added +to the global list. Used for parsing the project. +================ +*/ +entity_t *Entity_Parse (qboolean onlypairs) +{ + entity_t *ent; + eclass_t *e; + brush_t *b; + vec3_t mins, maxs; + epair_t *ep; + qboolean has_brushes; + + if (!GetToken (true)) + return NULL; + + if (strcmp (token, "{") ) + Error ("ParseEntity: { not found"); + + ent = qmalloc (sizeof(*ent)); + ent->brushes.onext = ent->brushes.oprev = &ent->brushes; + + do + { + if (!GetToken (true)) + Error ("ParseEntity: EOF without closing brace"); + if (!strcmp (token, "}") ) + break; + if (!strcmp (token, "{") ) + { + b = Brush_Parse (); + b->owner = ent; + + // add to the end of the entity chain + b->onext = &ent->brushes; + b->oprev = ent->brushes.oprev; + ent->brushes.oprev->onext = b; + ent->brushes.oprev = b; + } + else + { + ep = ParseEpair (); + ep->next = ent->epairs; + ent->epairs = ep; + } + } while (1); + + if (onlypairs) + return ent; + + if (ent->brushes.onext == &ent->brushes) + has_brushes = false; + else + has_brushes = true; + + GetVectorForKey (ent, "origin", ent->origin); + + e = Eclass_ForName (ValueForKey (ent, "classname"), has_brushes); + ent->eclass = e; + if (e->fixedsize) + { // fixed size entity + if (ent->brushes.onext != &ent->brushes) + { + printf ("Warning: Fixed size entity with brushes\n"); +#if 0 + while (ent->brushes.onext != &ent->brushes) + { // FIXME: this will free the entity and crash! + Brush_Free (b); + } +#endif +ent->brushes.next = ent->brushes.prev = &ent->brushes; + } + // create a custom brush + VectorAdd (e->mins, ent->origin, mins); + VectorAdd (e->maxs, ent->origin, maxs); + b = Brush_Create (mins, maxs, &e->texdef); + b->owner = ent; + + b->onext = ent->brushes.onext; + b->oprev = &ent->brushes; + ent->brushes.onext->oprev = b; + ent->brushes.onext = b; + } + else + { // brush entity + if (ent->brushes.next == &ent->brushes) + printf ("Warning: Brush entity with no brushes\n"); + } + + // add all the brushes to the main list + for (b=ent->brushes.onext ; b != &ent->brushes ; b=b->onext) + { + b->next = active_brushes.next; + active_brushes.next->prev = b; + b->prev = &active_brushes; + active_brushes.next = b; + } + + return ent; +} + +/* +============ +Entity_Write +============ +*/ +void Entity_Write (entity_t *e, FILE *f, qboolean use_region) +{ + epair_t *ep; + brush_t *b; + vec3_t origin; + char text[128]; + int count; + + // if none of the entities brushes are in the region, + // don't write the entity at all + if (use_region) + { + // in region mode, save the camera position as playerstart + if ( !strcmp(ValueForKey (e, "classname"), "info_player_start") ) + { + fprintf (f, "{\n"); + fprintf (f, "\"classname\" \"info_player_start\"\n"); + fprintf (f, "\"origin\" \"%i %i %i\"\n", (int)camera.origin[0], + (int)camera.origin[1], (int)camera.origin[2]); + fprintf (f, "\"angle\" \"%i\"\n", (int)camera.angles[YAW]); + fprintf (f, "}\n"); + return; + } + + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + if (!Map_IsBrushFiltered(b)) + break; // got one + + if (b == &e->brushes) + return; // nothing visible + } + + // if fixedsize, calculate a new origin based on the current + // brush position + if (e->eclass->fixedsize) + { + VectorSubtract (e->brushes.onext->mins, e->eclass->mins, origin); + sprintf (text, "%i %i %i", (int)origin[0], + (int)origin[1], (int)origin[2]); + SetKeyValue (e, "origin", text); + } + + fprintf (f, "{\n"); + for (ep = e->epairs ; ep ; ep=ep->next) + fprintf (f, "\"%s\" \"%s\"\n", ep->key, ep->value); + + if (!e->eclass->fixedsize) + { + count = 0; + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + if (!use_region || !Map_IsBrushFiltered (b)) + { + fprintf (f, "// brush %i\n", count); + count++; + Brush_Write (b, f); + } + } + } + fprintf (f, "}\n"); +} + + + +/* +============ +Entity_Create + +Creates a new entity out of the selected_brushes list. +If the entity class is fixed size, the brushes are only +used to find a midpoint. Otherwise, the brushes have +their ownershi[ transfered to the new entity. +============ +*/ +entity_t *Entity_Create (eclass_t *c) +{ + entity_t *e; + brush_t *b; + vec3_t mins, maxs; + int i; + + // check to make sure the brushes are ok + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (b->owner != world_entity) + { + Sys_Printf ("Entity NOT created, brushes not all from world\n"); + Sys_Beep (); + return NULL; + } + + // create it + + e = qmalloc(sizeof(*e)); + e->brushes.onext = e->brushes.oprev = &e->brushes; + e->eclass = c; + SetKeyValue (e, "classname", c->name); + + // add the entity to the entity list + e->next = entities.next; + entities.next = e; + e->next->prev = e; + e->prev = &entities; + + if (c->fixedsize) + { + // + // just use the selection for positioning + // + b = selected_brushes.next; + for (i=0 ; i<3 ; i++) + e->origin[i] = b->mins[i] - c->mins[i]; + + // create a custom brush + VectorAdd (c->mins, e->origin, mins); + VectorAdd (c->maxs, e->origin, maxs); + b = Brush_Create (mins, maxs, &c->texdef); + + Entity_LinkBrush (e, b); + + // delete the current selection + Select_Delete (); + + // select the new brush + b->next = b->prev = &selected_brushes; + selected_brushes.next = selected_brushes.prev = b; + + Brush_Build( b ); + } + else + { + // + // change the selected brushes over to the new entity + // + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + Entity_UnlinkBrush (b); + Entity_LinkBrush (e, b); + Brush_Build( b ); // so the key brush gets a name + } + } + + Sys_UpdateWindows (W_ALL); + return e; +} + + +/* +=========== +Entity_LinkBrush +=========== +*/ +void Entity_LinkBrush (entity_t *e, brush_t *b) +{ + if (b->oprev || b->onext) + Error ("Entity_LinkBrush: Allready linked"); + b->owner = e; + + b->onext = e->brushes.onext; + b->oprev = &e->brushes; + e->brushes.onext->oprev = b; + e->brushes.onext = b; +} + +/* +=========== +Entity_UnlinkBrush +=========== +*/ +void Entity_UnlinkBrush (brush_t *b) +{ + if (!b->owner || !b->onext || !b->oprev) + Error ("Entity_UnlinkBrush: Not currently linked"); + b->onext->oprev = b->oprev; + b->oprev->onext = b->onext; + b->onext = b->oprev = NULL; + b->owner = NULL; +} + + + +/* +=========== +Entity_Clone +=========== +*/ +entity_t *Entity_Clone (entity_t *e) +{ + entity_t *n; + epair_t *ep, *np; + + n = qmalloc(sizeof(*n)); + n->brushes.onext = n->brushes.oprev = &n->brushes; + n->eclass = e->eclass; + + // add the entity to the entity list + n->next = entities.next; + entities.next = n; + n->next->prev = n; + n->prev = &entities; + + for (ep = e->epairs ; ep ; ep=ep->next) + { + np = qmalloc(sizeof(*np)); + np->key = copystring(ep->key); + np->value = copystring(ep->value); + np->next = n->epairs; + n->epairs = np; + } + return n; +} + +int GetUniqueTargetId(int iHint) +{ + int iMin, iMax, i; + BOOL fFound; + entity_t *pe; + + fFound = FALSE; + pe = entities.next; + iMin = 0; + iMax = 0; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + i = IntForKey(pe, "target"); + if (i) + { + iMin = min(i, iMin); + iMax = max(i, iMax); + if (i == iHint) + fFound = TRUE; + } + } + + if (fFound) + return iMax + 1; + else + return iHint; +} + +entity_t *FindEntity(char *pszKey, char *pszValue) +{ + entity_t *pe; + + pe = entities.next; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + if (!strcmp(ValueForKey(pe, pszKey), pszValue)) + return pe; + } + + return NULL; +} + +entity_t *FindEntityInt(char *pszKey, int iValue) +{ + entity_t *pe; + + pe = entities.next; + + for (; pe != NULL && pe != &entities ; pe = pe->next) + { + if (IntForKey(pe, pszKey) == iValue) + return pe; + } + + return NULL; +} + diff --git a/tools/quake2/extra/qe4/entity.h b/tools/quake2/extra/qe4/entity.h new file mode 100644 index 00000000..012f08dc --- /dev/null +++ b/tools/quake2/extra/qe4/entity.h @@ -0,0 +1,84 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// entity.h + + +#define MAX_FLAGS 8 + +typedef struct eclass_s +{ + struct eclass_s *next; + char *name; + qboolean fixedsize; + qboolean unknown; // wasn't found in source + vec3_t mins, maxs; + vec3_t color; + texdef_t texdef; + char *comments; + char flagnames[MAX_FLAGS][32]; +} eclass_t; + +extern eclass_t *eclass; + +void Eclass_InitForSourceDirectory (char *path); +eclass_t *Eclass_ForName (char *name, qboolean has_brushes); + +//=================================================== + + +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +typedef struct entity_s +{ + struct entity_s *prev, *next; + brush_t brushes; // head/tail of list + vec3_t origin; + eclass_t *eclass; + epair_t *epairs; +} entity_t; + +char *ValueForKey (entity_t *ent, char *key); +void SetKeyValue (entity_t *ent, char *key, char *value); +void DeleteKey (entity_t *ent, char *key); +float FloatForKey (entity_t *ent, char *key); +int IntForKey (entity_t *ent, char *key); +void GetVectorForKey (entity_t *ent, char *key, vec3_t vec); + +void Entity_Free (entity_t *e); +entity_t *Entity_Parse (qboolean onlypairs); +void Entity_Write (entity_t *e, FILE *f, qboolean use_region); +entity_t *Entity_Create (eclass_t *c); +entity_t *Entity_Clone (entity_t *e); + +void Entity_LinkBrush (entity_t *e, brush_t *b); +void Entity_UnlinkBrush (brush_t *b); +entity_t *FindEntity(char *pszKey, char *pszValue); +entity_t *FindEntityInt(char *pszKey, int iValue); + +int GetUniqueTargetId(int iHint); + diff --git a/tools/quake2/extra/qe4/entityw.h b/tools/quake2/extra/qe4/entityw.h new file mode 100644 index 00000000..d3f7bd05 --- /dev/null +++ b/tools/quake2/extra/qe4/entityw.h @@ -0,0 +1,66 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// entity.h + +#define DlgXBorder 5 +#define DlgYBorder 5 + + +#define EntList 0 +#define EntComment 1 +#define EntCheck1 2 +#define EntCheck2 3 +#define EntCheck3 4 +#define EntCheck4 5 +#define EntCheck5 6 +#define EntCheck6 7 +#define EntCheck7 8 +#define EntCheck8 9 +#define EntCheck9 10 +#define EntCheck10 11 +#define EntCheck11 12 +#define EntCheck12 13 +#define EntProps 14 +#define EntDir0 15 +#define EntDir45 16 +#define EntDir90 17 +#define EntDir135 18 +#define EntDir180 19 +#define EntDir225 20 +#define EntDir270 21 +#define EntDir315 22 +#define EntDirUp 23 +#define EntDirDown 24 +#define EntDelProp 25 +#define EntKeyLabel 26 +#define EntKeyField 27 +#define EntValueLabel 28 +#define EntValueField 29 +#define EntColor 30 + +#define EntLast 31 + +extern HWND hwndEnt[EntLast]; + +extern int rgIds[EntLast]; + diff --git a/tools/quake2/extra/qe4/glingr.h b/tools/quake2/extra/qe4/glingr.h new file mode 100644 index 00000000..19cb1c5e --- /dev/null +++ b/tools/quake2/extra/qe4/glingr.h @@ -0,0 +1,98 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// This .h file contains constants, typedefs, etc. for Intergraph +// extensions to OpenGL. These extensions are: +// +// Multiple Palette Extension +// Texture Object Extension + +#define GL_INGR_multiple_palette 1 +#define GL_EXT_texture_object 1 + + +// New constants and typedefs for the Multiple Palette Extension +#define GL_PALETTE_INGR 0x80c0 +#define GL_MAX_PALETTES_INGR 0x80c1 +#define GL_MAX_PALETTE_ENTRIES_INGR 0x80c2 +#define GL_CURRENT_PALETTE_INGR 0x80c3 +#define GL_PALETTE_WRITEMASK_INGR 0x80c4 +#define GL_CURRENT_RASTER_PALETTE_INGR 0x80c5 +#define GL_PALETTE_CLEAR_VALUE_INGR 0x80c6 + +// Function prototypes for the Multiple Palette Extension routines +typedef void (APIENTRY *PALETTEFUNCPTR)(GLuint); +typedef void (APIENTRY *PALETTEMASKFUNCPTR)(GLboolean); +typedef void (APIENTRY *WGLLOADPALETTEFUNCPTR)(GLuint, GLsizei, GLuint *); +typedef void (APIENTRY *CLEARPALETTEFUNCPTR)(GLuint); + + +// New Constants and typedefs for the Texture Object Extension +#define GL_TEXTURE_PRIORITY_EXT 0x8066 +#define GL_TEXTURE_RESIDENT_EXT 0x8067 +#define GL_TEXTURE_1D_BINDING_EXT 0x8068 +#define GL_TEXTURE_2D_BINDING_EXT 0x8069 + +// Function prototypes for the Texture Object Extension routines +typedef GLboolean (APIENTRY *ARETEXRESFUNCPTR)(GLsizei, const GLuint *, + const GLboolean *); +typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint); +typedef void (APIENTRY *DELTEXFUNCPTR)(GLsizei, const GLuint *); +typedef void (APIENTRY *GENTEXFUNCPTR)(GLsizei, GLuint *); +typedef GLboolean (APIENTRY *ISTEXFUNCPTR)(GLuint); +typedef void (APIENTRY *PRIORTEXFUNCPTR)(GLsizei, const GLuint *, + const GLclampf *); + + +/* OpenGL ExtEscape escape function constants */ +#ifndef OPENGL_GETINFO +#define OPENGL_GETINFO 4353 /* for OpenGL ExtEscape */ +#endif + +// OPENGL_GETINFO ExtEscape sub-escape numbers. They are defined by +// Microsoft. + +#ifndef OPENGL_GETINFO_DRVNAME + +#define OPENGL_GETINFO_DRVNAME 0 + + +// Input structure for OPENGL_GETINFO ExtEscape. + +typedef struct _OPENGLGETINFO +{ + ULONG ulSubEsc; +} OPENGLGETINFO, *POPENGLGETINFO; + + +// Output structure for OPENGL_GETINFO_DRVNAME ExtEscape. + +typedef struct _GLDRVNAMERET +{ + ULONG ulVersion; // must be 1 for this version + ULONG ulDriverVersion; // driver specific version number + WCHAR awch[MAX_PATH+1]; +} GLDRVNAMERET, *PGLDRVNAMERET; + +#endif + + diff --git a/tools/quake2/extra/qe4/icon1.ico b/tools/quake2/extra/qe4/icon1.ico new file mode 100644 index 0000000000000000000000000000000000000000..d24956b6fe8f7efa2e945a98d72380e6c10ed564 GIT binary patch literal 766 zcmeH_K@P$o6huGOq+3^RW$7*SNZz2_z#~E80XPC(nz%4cV;TbOILO8rZ=myef8bBp z5JVJ9>x~p$8<8!2Pc%6aC2MvO!|b~ZLng*lW9L?!bMzA6wFD?T!YZTE{`%<`;2)^U zD 0x80) + { + rept = (rept^0xff)+2; + b = *source++; + memset(unpacked,b,rept); + unpacked += rept; + } + else if (rept < 0x80) + { + rept++; + memcpy(unpacked,source,rept); + unpacked += rept; + source += rept; + } + else + rept = 0; // rept of 0x80 is NOP + + count += rept; + + } while (countbpwidth) + Error ("Decompression exceeded width!\n"); + + + return source; +} + + +/* +================= +LoadLBM +================= +*/ +void LoadLBM (char *filename, byte **picture, byte **palette) +{ + byte *LBMbuffer, *picbuffer, *cmapbuffer; + int y; + byte *LBM_P, *LBMEND_P; + byte *pic_p; + byte *body_p; + + int formtype,formlength; + int chunktype,chunklength; + +// qiet compiler warnings + picbuffer = NULL; + cmapbuffer = NULL; + +// +// load the LBM +// + LoadFile (filename, (void **)&LBMbuffer); + +// +// parse the LBM header +// + LBM_P = LBMbuffer; + if ( *(int *)LBMbuffer != LittleLong(FORMID) ) + Error ("No FORM ID at start of file!\n"); + + LBM_P += 4; + formlength = BigLong( *(int *)LBM_P ); + LBM_P += 4; + LBMEND_P = LBM_P + Align(formlength); + + formtype = LittleLong(*(int *)LBM_P); + + if (formtype != ILBMID && formtype != PBMID) + Error ("Unrecognized form type: %c%c%c%c\n", formtype&0xff + ,(formtype>>8)&0xff,(formtype>>16)&0xff,(formtype>>24)&0xff); + + LBM_P += 4; + +// +// parse chunks +// + + while (LBM_P < LBMEND_P) + { + chunktype = LBM_P[0] + (LBM_P[1]<<8) + (LBM_P[2]<<16) + (LBM_P[3]<<24); + LBM_P += 4; + chunklength = LBM_P[3] + (LBM_P[2]<<8) + (LBM_P[1]<<16) + (LBM_P[0]<<24); + LBM_P += 4; + + switch ( chunktype ) + { + case BMHDID: + memcpy (&bmhd,LBM_P,sizeof(bmhd)); + bmhd.w = BigShort(bmhd.w); + bmhd.h = BigShort(bmhd.h); + bmhd.x = BigShort(bmhd.x); + bmhd.y = BigShort(bmhd.y); + bmhd.pageWidth = BigShort(bmhd.pageWidth); + bmhd.pageHeight = BigShort(bmhd.pageHeight); + break; + + case CMAPID: + cmapbuffer = malloc (768); + memset (cmapbuffer, 0, 768); + memcpy (cmapbuffer, LBM_P, chunklength); + break; + + case BODYID: + body_p = LBM_P; + + pic_p = picbuffer = malloc (bmhd.w*bmhd.h); + if (formtype == PBMID) + { + // + // unpack PBM + // + for (y=0 ; ydata; + + pcx->xmin = LittleShort(pcx->xmin); + pcx->ymin = LittleShort(pcx->ymin); + pcx->xmax = LittleShort(pcx->xmax); + pcx->ymax = LittleShort(pcx->ymax); + pcx->hres = LittleShort(pcx->hres); + pcx->vres = LittleShort(pcx->vres); + pcx->bytes_per_line = LittleShort(pcx->bytes_per_line); + pcx->palette_type = LittleShort(pcx->palette_type); + + if (pcx->manufacturer != 0x0a + || pcx->version != 5 + || pcx->encoding != 1 + || pcx->bits_per_pixel != 8 + || pcx->xmax >= 640 + || pcx->ymax >= 480) + Error ("Bad pcx file %s", filename); + + if (palette) + { + *palette = malloc(768); + memcpy (*palette, (byte *)pcx + len - 768, 768); + } + + if (width) + *width = pcx->xmax+1; + if (height) + *height = pcx->ymax+1; + + if (!pic) + return; + + out = malloc ( (pcx->ymax+1) * (pcx->xmax+1) ); + if (!out) + Error ("Skin_Cache: couldn't allocate"); + + *pic = out; + + pix = out; + + for (y=0 ; y<=pcx->ymax ; y++, pix += pcx->xmax+1) + { + for (x=0 ; x<=pcx->xmax ; ) + { + dataByte = *raw++; + + if((dataByte & 0xC0) == 0xC0) + { + runLength = dataByte & 0x3F; + dataByte = *raw++; + } + else + runLength = 1; + + while(runLength-- > 0) + pix[x++] = dataByte; + } + + } + + if ( raw - (byte *)pcx > len) + Error ("PCX file %s was malformed", filename); + + free (pcx); +} + +/* +============== +WritePCXfile +============== +*/ +void WritePCXfile (char *filename, byte *data, + int width, int height, byte *palette) +{ + int i, j, length; + pcx_t *pcx; + byte *pack; + + pcx = malloc (width*height*2+1000); + memset (pcx, 0, sizeof(*pcx)); + + pcx->manufacturer = 0x0a; // PCX id + pcx->version = 5; // 256 color + pcx->encoding = 1; // uncompressed + pcx->bits_per_pixel = 8; // 256 color + pcx->xmin = 0; + pcx->ymin = 0; + pcx->xmax = LittleShort((short)(width-1)); + pcx->ymax = LittleShort((short)(height-1)); + pcx->hres = LittleShort((short)width); + pcx->vres = LittleShort((short)height); + pcx->color_planes = 1; // chunky image + pcx->bytes_per_line = LittleShort((short)width); + pcx->palette_type = LittleShort(2); // not a grey scale + + // pack the image + pack = &pcx->data; + + for (i=0 ; i=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column=0; row--) { + pixbuf = targa_rgba + row*columns*4; + for(column=0; column0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + else { // non run-length packet + for(j=0;j0) + row--; + else + goto breakOut; + pixbuf = targa_rgba + row*columns*4; + } + } + } + } + breakOut:; + } + } + + fclose(fin); +} diff --git a/tools/quake2/extra/qe4/lbmlib.h b/tools/quake2/extra/qe4/lbmlib.h new file mode 100644 index 00000000..c90a6dd8 --- /dev/null +++ b/tools/quake2/extra/qe4/lbmlib.h @@ -0,0 +1,40 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// piclib.h + + +void LoadLBM (char *filename, byte **picture, byte **palette); +void WriteLBMfile (char *filename, byte *data, int width, int height + , byte *palette); +void LoadPCX (char *filename, byte **picture, byte **palette, int *width, int *height); +void WritePCXfile (char *filename, byte *data, int width, int height + , byte *palette); + +// loads / saves either lbm or pcx, depending on extension +void Load256Image (char *name, byte **pixels, byte **palette, + int *width, int *height); +void Save256Image (char *name, byte *pixels, byte *palette, + int width, int height); + + +void LoadTGA (char *filename, byte **pixels, int *width, int *height); diff --git a/tools/quake2/extra/qe4/makefile b/tools/quake2/extra/qe4/makefile new file mode 100644 index 00000000..7797ac31 --- /dev/null +++ b/tools/quake2/extra/qe4/makefile @@ -0,0 +1,23 @@ + +TARGETOS=WINNT + +!include + +# This line allows NMAKE to work as well + +all: gengl.exe + +# Update the object file if necessary + +gengl.obj: gengl.c gengl.h + $(cc) $(cflags) $(cvars) $(cdebug) $(cf) gengl.c + +render.obj: render.c gengl.h + $(cc) $(cflags) $(cvars) $(cdebug) $(cf) render.c + +gengl.res: gengl.rc genglrc.h + rc -r gengl.rc + +gengl.exe: gengl.obj gengl.res render.obj + $(link) $(linkdebug) /NODEFAULTLIB $(guilflags) -out:gengl.exe \ + gengl.obj render.obj gengl.res $(guilibsdll) opengl32.lib glu32.lib diff --git a/tools/quake2/extra/qe4/map.c b/tools/quake2/extra/qe4/map.c new file mode 100644 index 00000000..9528e152 --- /dev/null +++ b/tools/quake2/extra/qe4/map.c @@ -0,0 +1,661 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// map.c + +#include "qe3.h" + +qboolean modified; // for quit confirmation (0 = clean, 1 = unsaved, + // 2 = autosaved, but not regular saved) + +char currentmap[1024]; + +brush_t active_brushes; // brushes currently being displayed +brush_t selected_brushes; // highlighted +face_t *selected_face; +brush_t *selected_face_brush; +brush_t filtered_brushes; // brushes that have been filtered or regioned + +entity_t entities; // head/tail of doubly linked list + +entity_t *world_entity; + +void AddRegionBrushes (void); +void RemoveRegionBrushes (void); + +/* +============================================================= + + Cross map selection saving + + this could fuck up if you have only part of a complex entity selected... +============================================================= +*/ + +brush_t between_brushes; +entity_t between_entities; + + +void Map_SaveBetween (void) +{ + brush_t *b; + entity_t *e, *e2; + + between_brushes.next = selected_brushes.next; + between_brushes.prev = selected_brushes.prev; + between_brushes.next->prev = &between_brushes; + between_brushes.prev->next = &between_brushes; + + between_entities.next = between_entities.prev = &between_entities; + selected_brushes.next = selected_brushes.prev = &selected_brushes; + + for (b=between_brushes.next ; b != &between_brushes ; b=b->next) + { + e = b->owner; + if (e == world_entity) + b->owner = NULL; + else + { + for (e2=between_entities.next ; e2 != &between_entities ; e2=e2->next) + if (e2 == e) + goto next; // allready got the entity + // move the entity over + e->prev->next = e->next; + e->next->prev = e->prev; + e->next = between_entities.next; + e->prev = &between_entities; + e->next->prev = e; + e->prev->next = e; + } +next: ; + } +} + +void Map_RestoreBetween (void) +{ + entity_t *head, *tail; + brush_t *b; + + if (!between_brushes.next) + return; + + for (b=between_brushes.next ; b != &between_brushes ; b=b->next) + { + if (!b->owner) + { + b->owner = world_entity; + b->onext = world_entity->brushes.onext; + b->oprev = &world_entity->brushes; + b->onext->oprev = b; + b->oprev->onext = b; + } + } + + selected_brushes.next = between_brushes.next; + selected_brushes.prev = between_brushes.prev; + selected_brushes.next->prev = &selected_brushes; + selected_brushes.prev->next = &selected_brushes; + + head = between_entities.next; + tail = between_entities.prev; + + if (head != tail) + { + entities.prev->next = head; + head->prev = entities.prev; + tail->next = &entities; + entities.prev = tail; + } + + between_brushes.next = NULL; + between_entities.next = NULL; +} + +//============================================================================ + +void Map_BuildBrushData(void) +{ + brush_t *b, *next; + + if (active_brushes.next == NULL) + return; + + Sys_BeginWait (); // this could take a while + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + Brush_Build( b ); + if (!b->brush_faces) + { + Brush_Free (b); + Sys_Printf ("Removed degenerate brush\n"); + } + } + + Sys_EndWait(); +} + +entity_t *Map_FindClass (char *cname) +{ + entity_t *ent; + + for (ent = entities.next ; ent != &entities ; ent=ent->next) + { + if (!strcmp(cname, ValueForKey (ent, "classname"))) + return ent; + } + return NULL; +} + +/* +================ +Map_Free +================ +*/ +void Map_Free (void) +{ + if (selected_brushes.next && + (selected_brushes.next != &selected_brushes) ) + { + if (MessageBox(g_qeglobals.d_hwndMain, "Copy selection?", "", MB_YESNO) == IDYES) + Map_SaveBetween (); + } + + Texture_ClearInuse (); + Pointfile_Clear (); + strcpy (currentmap, "unnamed.map"); + Sys_SetTitle (currentmap); + g_qeglobals.d_num_entities = 0; + + if (!active_brushes.next) + { // first map + active_brushes.prev = active_brushes.next = &active_brushes; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + filtered_brushes.prev = filtered_brushes.next = &filtered_brushes; + + entities.prev = entities.next = &entities; + } + else + { + while (active_brushes.next != &active_brushes) + Brush_Free (active_brushes.next); + while (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + while (filtered_brushes.next != &filtered_brushes) + Brush_Free (filtered_brushes.next); + + while (entities.next != &entities) + Entity_Free (entities.next); + } + + world_entity = NULL; +} + +/* +================ +Map_LoadFile +================ +*/ +void Map_LoadFile (char *filename) +{ + char *buf; + entity_t *ent; + char temp[1024]; + + Sys_BeginWait (); + + SetInspectorMode(W_CONSOLE); + + QE_ConvertDOSToUnixName( temp, filename ); + Sys_Printf ("Map_LoadFile: %s\n", temp ); + + Map_Free (); + + g_qeglobals.d_parsed_brushes = 0; + strcpy (currentmap, filename); + LoadFile (filename, (void **)&buf); + + StartTokenParsing (buf); + + g_qeglobals.d_num_entities = 0; + + while (1) + { + ent = Entity_Parse (false); + if (!ent) + break; + if (!strcmp(ValueForKey (ent, "classname"), "worldspawn")) + { + if (world_entity) + Sys_Printf ("WARNING: multiple worldspawn\n"); + world_entity = ent; + } + else + { + // add the entity to the end of the entity list + ent->next = &entities; + ent->prev = entities.prev; + entities.prev->next = ent; + entities.prev = ent; + g_qeglobals.d_num_entities++; + } + } + + free (buf); + + if (!world_entity) + { + Sys_Printf ("No worldspawn in map.\n"); + Map_New (); + return; + } + + Sys_Printf ("--- LoadMapFile ---\n"); + Sys_Printf ("%s\n", temp ); + + Sys_Printf ("%5i brushes\n", g_qeglobals.d_parsed_brushes ); + Sys_Printf ("%5i entities\n", g_qeglobals.d_num_entities); + + Map_RestoreBetween (); + + Sys_Printf ("Map_BuildAllDisplayLists\n"); + Map_BuildBrushData(); + + // + // move the view to a start position + // + ent = Map_FindClass ("info_player_start"); + if (!ent) + ent = Map_FindClass ("info_player_deathmatch"); + camera.angles[PITCH] = 0; + if (ent) + { + GetVectorForKey (ent, "origin", camera.origin); + GetVectorForKey (ent, "origin", g_qeglobals.d_xy.origin); + camera.angles[YAW] = FloatForKey (ent, "angle"); + } + else + { + camera.angles[YAW] = 0; + VectorCopy (vec3_origin, camera.origin); + VectorCopy (vec3_origin, g_qeglobals.d_xy.origin); + } + + Sys_UpdateWindows (W_ALL); + + Map_RegionOff (); + + modified = false; + Sys_SetTitle (temp); + + Texture_ShowInuse (); + + Sys_EndWait(); + +} + +/* +=========== +Map_SaveFile +=========== +*/ +void Map_SaveFile (char *filename, qboolean use_region ) +{ + entity_t *e, *next; + FILE *f; + char temp[1024]; + int count; + + QE_ConvertDOSToUnixName( temp, filename ); + + if (!use_region) + { + char backup[1024]; + + // rename current to .bak + strcpy (backup, filename); + StripExtension (backup); + strcat (backup, ".bak"); + _unlink (backup); + rename (filename, backup); + } + + Sys_Printf ("Map_SaveFile: %s\n", filename); + + f = fopen(filename, "w"); + if (!f) + { + Sys_Printf ("ERROR!!!! Couldn't open %s\n", filename); + return; + } + + if (use_region) + AddRegionBrushes (); + + // write world entity first + Entity_Write (world_entity, f, use_region); + + // then write all other ents + count = 1; + for (e=entities.next ; e != &entities ; e=next) + { + fprintf (f, "// entity %i\n", count); + count++; + next = e->next; + if (e->brushes.onext == &e->brushes) + Entity_Free (e); // no brushes left, so remove it + else + Entity_Write (e, f, use_region); + } + + fclose (f); + + if (use_region) + RemoveRegionBrushes (); + + Sys_Printf ("Saved.\n"); + modified = false; + + if ( !strstr( temp, "autosave" ) ) + Sys_SetTitle (temp); + + if (!use_region) + { + time_t timer; + FILE *f; + + time (&timer); + MessageBeep (MB_ICONEXCLAMATION); + f = fopen ("c:/tstamps.log", "a"); + if (f) + { + fprintf (f, "%4i : %35s : %s", g_qeglobals.d_workcount, filename, ctime(&timer)); + fclose (f); + g_qeglobals.d_workcount = 0; + } + fclose (f); + Sys_Status ("Saved.\n", 0); + } +} + +/* +=========== +Map_New +=========== +*/ +void Map_New (void) +{ + Sys_Printf ("Map_New\n"); + Map_Free (); + world_entity = qmalloc(sizeof(*world_entity)); + world_entity->brushes.onext = + world_entity->brushes.oprev = &world_entity->brushes; + SetKeyValue (world_entity, "classname", "worldspawn"); + world_entity->eclass = Eclass_ForName ("worldspawn", true); + + camera.angles[YAW] = 0; + VectorCopy (vec3_origin, camera.origin); + camera.origin[2] = 48; + VectorCopy (vec3_origin, g_qeglobals.d_xy.origin); + + Map_RestoreBetween (); + + Sys_UpdateWindows (W_ALL); + modified = false; +} + + +/* +=========================================================== + + REGION + +=========================================================== +*/ + +qboolean region_active; +vec3_t region_mins = {-4096, -4096, -4096}; +vec3_t region_maxs = {4096, 4096, 4096}; + +brush_t *region_sides[4]; + +/* +=========== +AddRegionBrushes + +a regioned map will have temp walls put up at the region boundary +=========== +*/ +void AddRegionBrushes (void) +{ + vec3_t mins, maxs; + int i; + texdef_t td; + + if (!region_active) + return; + + memset (&td, 0, sizeof(td)); + strcpy (td.name, "REGION"); + + mins[0] = region_mins[0] - 16; + maxs[0] = region_mins[0] + 1; + mins[1] = region_mins[1] - 16; + maxs[1] = region_maxs[1] + 16; + mins[2] = -2048; + maxs[2] = 2048; + region_sides[0] = Brush_Create (mins, maxs, &td); + + mins[0] = region_maxs[0] - 1; + maxs[0] = region_maxs[0] + 16; + region_sides[1] = Brush_Create (mins, maxs, &td); + + mins[0] = region_mins[0] - 16; + maxs[0] = region_maxs[0] + 16; + mins[1] = region_mins[1] - 16; + maxs[1] = region_mins[1] + 1; + region_sides[2] = Brush_Create (mins, maxs, &td); + + mins[1] = region_maxs[1] - 1; + maxs[1] = region_maxs[1] + 16; + region_sides[3] = Brush_Create (mins, maxs, &td); + + for (i=0 ; i<4 ; i++) + { + Brush_AddToList (region_sides[i], &selected_brushes); + Entity_LinkBrush (world_entity, region_sides[i]); + Brush_Build( region_sides[i] ); + } +} + +void RemoveRegionBrushes (void) +{ + int i; + + if (!region_active) + return; + for (i=0 ; i<4 ; i++) + Brush_Free (region_sides[i]); +} + + +qboolean Map_IsBrushFiltered (brush_t *b) +{ + int i; + + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] > region_maxs[i]) + return true; + if (b->maxs[i] < region_mins[i]) + return true; + } + return false; +} + +/* +=========== +Map_RegionOff + +Other filtering options may still be on +=========== +*/ +void Map_RegionOff (void) +{ + brush_t *b, *next; + int i; + + region_active = false; + for (i=0 ; i<3 ; i++) + { + region_maxs[i] = 4096; + region_mins[i] = -4096; + } + + for (b=filtered_brushes.next ; b != &filtered_brushes ; b=next) + { + next = b->next; + if (Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + Brush_AddToList (b, &active_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + +void Map_ApplyRegion (void) +{ + brush_t *b, *next; + + region_active = true; + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + if (!Map_IsBrushFiltered (b)) + continue; // still filtered + Brush_RemoveFromList (b); + Brush_AddToList (b, &filtered_brushes); + } + + Sys_UpdateWindows (W_ALL); +} + + +/* +======================== +Map_RegionSelectedBrushes +======================== +*/ +void Map_RegionSelectedBrushes (void) +{ + Map_RegionOff (); + + region_active = true; + Select_GetBounds (region_mins, region_maxs); + + // move the entire active_brushes list to filtered_brushes + filtered_brushes.next = active_brushes.next; + filtered_brushes.prev = active_brushes.prev; + filtered_brushes.next->prev = &filtered_brushes; + filtered_brushes.prev->next = &filtered_brushes; + + // move the entire selected_brushes list to active_brushes + active_brushes.next = selected_brushes.next; + active_brushes.prev = selected_brushes.prev; + active_brushes.next->prev = &active_brushes; + active_brushes.prev->next = &active_brushes; + + // clear selected_brushes + selected_brushes.next = selected_brushes.prev = &selected_brushes; + + Sys_UpdateWindows (W_ALL); +} + + +/* +=========== +Map_RegionXY +=========== +*/ +void Map_RegionXY (void) +{ + Map_RegionOff (); + + region_mins[0] = g_qeglobals.d_xy.origin[0] - 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale; + region_maxs[0] = g_qeglobals.d_xy.origin[0] + 0.5*g_qeglobals.d_xy.width/g_qeglobals.d_xy.scale; + region_mins[1] = g_qeglobals.d_xy.origin[1] - 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale; + region_maxs[1] = g_qeglobals.d_xy.origin[1] + 0.5*g_qeglobals.d_xy.height/g_qeglobals.d_xy.scale; + region_mins[2] = -4096; + region_maxs[2] = 4096; + + Map_ApplyRegion (); +} + +/* +=========== +Map_RegionTallBrush +=========== +*/ +void Map_RegionTallBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + region_mins[2] = -4096; + region_maxs[2] = 4096; + + Select_Delete (); + Map_ApplyRegion (); +} +/* +=========== +Map_RegionBrush +=========== +*/ +void Map_RegionBrush (void) +{ + brush_t *b; + + if (!QE_SingleBrush ()) + return; + + b = selected_brushes.next; + + Map_RegionOff (); + + VectorCopy (b->mins, region_mins); + VectorCopy (b->maxs, region_maxs); + + Select_Delete (); + Map_ApplyRegion (); +} + diff --git a/tools/quake2/extra/qe4/map.h b/tools/quake2/extra/qe4/map.h new file mode 100644 index 00000000..58d9ed75 --- /dev/null +++ b/tools/quake2/extra/qe4/map.h @@ -0,0 +1,53 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// map.h -- the state of the current world that all views are displaying + +extern char currentmap[1024]; + +// head/tail of doubly linked lists +extern brush_t active_brushes; // brushes currently being displayed +extern brush_t selected_brushes; // highlighted +extern face_t *selected_face; +extern brush_t *selected_face_brush; +extern brush_t filtered_brushes; // brushes that have been filtered or regioned + +extern entity_t entities; +extern entity_t *world_entity; // the world entity is NOT included in + // the entities chain + +extern qboolean modified; // for quit confirmations + +extern vec3_t region_mins, region_maxs; +extern qboolean region_active; + +void Map_LoadFile (char *filename); +void Map_SaveFile (char *filename, qboolean use_region); +void Map_New (void); +void Map_BuildBrushData(void); + +void Map_RegionOff (void); +void Map_RegionXY (void); +void Map_RegionTallBrush (void); +void Map_RegionBrush (void); +void Map_RegionSelectedBrushes (void); +qboolean Map_IsBrushFiltered (brush_t *b); diff --git a/tools/quake2/extra/qe4/mathlib.c b/tools/quake2/extra/qe4/mathlib.c new file mode 100644 index 00000000..d430ff70 --- /dev/null +++ b/tools/quake2/extra/qe4/mathlib.c @@ -0,0 +1,131 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// mathlib.c -- math primitives + +#include "cmdlib.h" +#include "mathlib.h" + +vec3_t vec3_origin = {0.0f,0.0f,0.0f}; + + +float VectorLength(vec3_t v) +{ + int i; + float length; + + length = 0.0f; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = (float)sqrt (length); + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return false; + + return true; +} + +vec_t Q_rint (vec_t in) +{ + return (float)floor (in + 0.5); +} + +void VectorMA (vec3_t va, float scale, vec3_t vb, vec3_t vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +vec_t VectorNormalize (vec3_t v) +{ + int i; + float length; + + length = 0.0f; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = (float)sqrt (length); + if (length == 0) + return (vec_t)0; + + for (i=0 ; i< 3 ; i++) + v[i] /= length; + + return length; +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +void VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} + diff --git a/tools/quake2/extra/qe4/mathlib.h b/tools/quake2/extra/qe4/mathlib.h new file mode 100644 index 00000000..2569bed5 --- /dev/null +++ b/tools/quake2/extra/qe4/mathlib.h @@ -0,0 +1,66 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h + +#include + +typedef float vec_t; +typedef vec_t vec3_t[3]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +#define Q_PI 3.14159265358979323846 + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} + +vec_t Q_rint (vec_t in); +vec_t _DotProduct (vec3_t v1, vec3_t v2); +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out); +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out); +void _VectorCopy (vec3_t in, vec3_t out); + +float VectorLength(vec3_t v); + +void VectorMA (vec3_t va, float scale, vec3_t vb, vec3_t vc); + +void CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (vec3_t v); +void VectorInverse (vec3_t v); +void VectorScale (vec3_t v, vec_t scale, vec3_t out); + +#endif diff --git a/tools/quake2/extra/qe4/mru.c b/tools/quake2/extra/qe4/mru.c new file mode 100644 index 00000000..84a5a3eb --- /dev/null +++ b/tools/quake2/extra/qe4/mru.c @@ -0,0 +1,671 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +//************************************************************* +// File name: mru.c +// +// Description: +// +// Routines for MRU support +// +// Development Team: +// +// Gilles Vollant (100144.2636@compuserve.com) +// +//************************************************************* + +#include +#include +#include + +#include "mru.h" +// CreateMruMenu : MRUMENU constructor +// wNbLruShowInit : nb of item showed in menu +// wNbLruMenuInit : nb of item stored in memory +// wMaxSizeLruItemInit : size max. of filename + + +//************************************************************* +// +// CreateMruMenu() +// +// Purpose: +// +// Allocate and Initialize an MRU and return a pointer on it +// +// +// Parameters: +// +// WORD wNbLruShowInit - Maximum number of item displayed on menu +// WORD wNbLruMenuInit - Maximum number of item stored in memory +// WORD wMaxSizeLruItemInit - Maximum size of an item (ie size of pathname) +// WORD wIdMruInit - ID of the first item in the menu (default:IDMRU) +// +// +// Return: (LPMRUMENU) +// +// Pointer on a MRUMENU structure, used by other function +// +// +// Comments: +// wNbLruShowInit <= wNbLruMenuInit +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* + +LPMRUMENU CreateMruMenu (WORD wNbLruShowInit, + WORD wNbLruMenuInit,WORD wMaxSizeLruItemInit,WORD wIdMruInit) +{ +LPMRUMENU lpMruMenu; + lpMruMenu = (LPMRUMENU)GlobalAllocPtr(GHND,sizeof(MRUMENU)); + + lpMruMenu->wNbItemFill = 0; + lpMruMenu->wNbLruMenu = wNbLruMenuInit; + lpMruMenu->wNbLruShow = wNbLruShowInit; + lpMruMenu->wIdMru = wIdMruInit; + lpMruMenu->wMaxSizeLruItem = wMaxSizeLruItemInit; + lpMruMenu->lpMRU = (LPSTR)GlobalAllocPtr(GHND, + lpMruMenu->wNbLruMenu*(UINT)lpMruMenu->wMaxSizeLruItem); + if (lpMruMenu->lpMRU == NULL) + { + GlobalFreePtr(lpMruMenu); + lpMruMenu = NULL; + } + return lpMruMenu; +} + +//************************************************************* +// +// CreateMruMenuDefault() +// +// Purpose: +// +// Allocate and Initialize an MRU and return a pointer on it +// Use default parameter +// +// +// Parameters: +// +// +// Return: (LPMRUMENU) +// +// Pointer on a MRUMENU structure, used by other function +// +// +// Comments: +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* + +LPMRUMENU CreateMruMenuDefault() +{ + return CreateMruMenu (NBMRUMENUSHOW,NBMRUMENU,MAXSIZEMRUITEM,IDMRU); +} + + +//************************************************************* +// +// DeleteMruMenu() +// +// Purpose: +// Destructor : +// Clean and free a MRUMENU structure +// +// Parameters: +// +// LPMRUMENU lpMruMenu - pointer on MRUMENU, allocated +// by CreateMruMenu() or CreateMruMenuDefault() +// +// +// Return: void +// +// +// Comments: +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void DeleteMruMenu(LPMRUMENU lpMruMenu) +{ + GlobalFreePtr(lpMruMenu->lpMRU); + GlobalFreePtr(lpMruMenu); +} + +//************************************************************* +// +// SetNbLruShow() +// +// Purpose: +// Change the maximum number of item displayed on menu +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wNbLruShowInit - Maximum number of item displayed on menu +// +// +// Return: void +// +// +// Comments: +// +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void SetNbLruShow (LPMRUMENU lpMruMenu,WORD wNbLruShowInit) +{ + lpMruMenu->wNbLruShow = min(wNbLruShowInit,lpMruMenu->wNbLruMenu); +} + +//************************************************************* +// +// SetMenuItem() +// +// Purpose: +// Set the filename of an item +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wItem - Number of Item to set, zero based +// LPSTR lpItem - String, contain the filename of the item +// +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// used when load .INI or reg database +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL SetMenuItem (LPMRUMENU lpMruMenu,WORD wItem,LPSTR lpItem) +{ + if (wItem >= NBMRUMENU) + return FALSE; + _fstrncpy((lpMruMenu->lpMRU) + + ((lpMruMenu->wMaxSizeLruItem) * (UINT)wItem), + lpItem,lpMruMenu->wMaxSizeLruItem-1); + lpMruMenu->wNbItemFill = max(lpMruMenu->wNbItemFill,wItem+1); + return TRUE; +} + +//************************************************************* +// +// GetMenuItem() +// +// Purpose: +// Get the filename of an item +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wItem - Number of Item to set, zero based +// BOOL fIDMBased - TRUE : wItem is based on ID menu item +// FALSE : wItem is zero-based +// LPSTR lpItem - String where the filename of the item will be +// stored by GetMenuItem() +// UINT uiSize - Size of the lpItem buffer +// +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Used for saving in .INI or reg database, or when user select +// an MRU in File menu +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL GetMenuItem (LPMRUMENU lpMruMenu,WORD wItem, + BOOL fIDMBased,LPSTR lpItem,UINT uiSize) +{ + if (fIDMBased) + wItem -= (lpMruMenu->wIdMru + 1); + if (wItem >= lpMruMenu->wNbItemFill) + return FALSE; + _fstrncpy(lpItem,(lpMruMenu->lpMRU) + + ((lpMruMenu->wMaxSizeLruItem) * (UINT)(wItem)),uiSize); + *(lpItem+uiSize-1) = '\0'; + return TRUE; +} + +//************************************************************* +// +// AddNewItem() +// +// Purpose: +// Add an item at the begin of the list +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpItem - String contain the filename to add +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Used when used open a file (using File Open common +// dialog, Drag and drop or MRU) +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void AddNewItem (LPMRUMENU lpMruMenu,LPSTR lpItem) +{ +WORD i,j; + for (i=0;iwNbItemFill;i++) + if (lstrcmpi(lpItem,(lpMruMenu->lpMRU) + + ((lpMruMenu->wMaxSizeLruItem) * (UINT)i)) == 0) + { + // Shift the other items + for (j=i;j>0;j--) + lstrcpy((lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)j), + (lpMruMenu->lpMRU) + (lpMruMenu->wMaxSizeLruItem * (UINT)(j-1))); + _fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1); + return ; + } + lpMruMenu->wNbItemFill = min(lpMruMenu->wNbItemFill+1,lpMruMenu->wNbLruMenu); + for (i=lpMruMenu->wNbItemFill-1;i>0;i--) + lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i), + lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i-1))); + _fstrncpy(lpMruMenu->lpMRU,lpItem,lpMruMenu->wMaxSizeLruItem-1); +} + +//************************************************************* +// +// DelMenuItem() +// +// Purpose: +// Delete an item +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// WORD wItem - Number of Item to set, zero based +// BOOL fIDMBased - TRUE : wItem is based on ID menu item +// FALSE : wItem is zero-based +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Used when used open a file, using MRU, and when an error +// occured (by example, when file was deleted) +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL DelMenuItem(LPMRUMENU lpMruMenu,WORD wItem,BOOL fIDMBased) +{ +WORD i; + if (fIDMBased) + wItem -= (lpMruMenu->wIdMru + 1); + if (lpMruMenu->wNbItemFill <= wItem) + return FALSE; + lpMruMenu->wNbItemFill--; + for (i=wItem;iwNbItemFill;i++) + lstrcpy(lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)i), + lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem * (UINT)(i+1))); + return TRUE; +} + +//************************************************************* +// +// PlaceMenuMRUItem() +// +// Purpose: +// Add MRU at the end of a menu +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// HMENU hMenu - Handle of menu where MRU must be added +// UINT uiItem - Item of menu entry where MRU must be added +// +// Return: void +// +// +// Comments: +// Used MRU is modified, for refresh the File menu +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +void PlaceMenuMRUItem(LPMRUMENU lpMruMenu,HMENU hMenu,UINT uiItem) +{ +int i; +WORD wNbShow; + if (hMenu == NULL) + return; + // remove old MRU in menu + for (i=0;i<=(int)(lpMruMenu->wNbLruMenu);i++) + RemoveMenu(hMenu,i+lpMruMenu->wIdMru,MF_BYCOMMAND); + + if (lpMruMenu->wNbItemFill == 0) + return; + + // If they are item, insert a separator before the files + InsertMenu(hMenu,uiItem,MF_SEPARATOR,lpMruMenu->wIdMru,NULL); + + wNbShow = min(lpMruMenu->wNbItemFill,lpMruMenu->wNbLruShow); + for (i=(int)wNbShow-1;i>=0;i--) + { + LPSTR lpTxt; + if (lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20)) + { + wsprintf(lpTxt,"&%lu %s", + (DWORD)(i+1),lpMruMenu->lpMRU + (lpMruMenu->wMaxSizeLruItem*(UINT)i)); + InsertMenu(hMenu,(((WORD)i)!=(wNbShow-1)) ? (lpMruMenu->wIdMru+i+2) : lpMruMenu->wIdMru, + MF_STRING,lpMruMenu->wIdMru+i+1,lpTxt); + GlobalFreePtr(lpTxt); + } + } + +} + +/////////////////////////////////////////// + + + +//************************************************************* +// +// SaveMruInIni() +// +// Purpose: +// Save MRU in a private .INI +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszSection - Points to a null-terminated string containing +// the name of the section +// LPSTR lpszFile - Points to a null-terminated string that names +// the initialization file. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// See WritePrivateProfileString API for more info on lpszSection and lpszFile +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL SaveMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile) +{ +LPSTR lpTxt; +WORD i; + + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + wsprintf(szEntry,"File%lu",(DWORD)i+1); + if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10)) + *lpTxt = '\0'; + WritePrivateProfileString(lpszSection,szEntry,lpTxt,lpszFile); + } + GlobalFreePtr(lpTxt); + WritePrivateProfileString(NULL,NULL,NULL,lpszFile); // flush cache + return TRUE; +} + + +//************************************************************* +// +// LoadMruInIni() +// +// Purpose: +// Load MRU from a private .INI +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszSection - Points to a null-terminated string containing +// the name of the section +// LPSTR lpszFile - Points to a null-terminated string that names +// the initialization file. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// See GetPrivateProfileString API for more info on lpszSection and lpszFile +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL LoadMruInIni(LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile) +{ +LPSTR lpTxt; +WORD i; + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + + wsprintf(szEntry,"File%lu",(DWORD)i+1); + GetPrivateProfileString(lpszSection,szEntry,"",lpTxt, + lpMruMenu->wMaxSizeLruItem + 10,lpszFile); + if (*lpTxt == '\0') + break; + SetMenuItem(lpMruMenu,i,lpTxt); + } + GlobalFreePtr(lpTxt); + return TRUE; +} + +#ifdef WIN32 + +BOOL IsWin395OrHigher(void) +{ + WORD wVer; + + wVer = LOWORD(GetVersion()); + wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer); + + return (wVer >= 0x035F); // 5F = 95 dec +} + + +//************************************************************* +// +// SaveMruInReg() +// +// Purpose: +// Save MRU in the registry +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszKey - Points to a null-terminated string +// specifying the name of a key that +// this function opens or creates. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Win32 function designed for Windows NT and Windows 95 +// See RegCreateKeyEx API for more info on lpszKey +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL SaveMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey) +{ +LPSTR lpTxt; +WORD i; +HKEY hCurKey; +DWORD dwDisp; + + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + RegCreateKeyEx(HKEY_CURRENT_USER,lpszKey,0,NULL, + REG_OPTION_NON_VOLATILE,KEY_ALL_ACCESS,NULL,&hCurKey,&dwDisp); + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + wsprintf(szEntry,"File%lu",(DWORD)i+1); + if (!GetMenuItem(lpMruMenu,i,FALSE,lpTxt,lpMruMenu->wMaxSizeLruItem + 10)) + *lpTxt = '\0'; + RegSetValueEx(hCurKey,szEntry,0,REG_SZ,lpTxt,lstrlen(lpTxt)); + } + RegCloseKey(hCurKey); + GlobalFreePtr(lpTxt); + return TRUE; +} + +//************************************************************* +// +// LoadMruInReg() +// +// Purpose: +// Load MRU from the registry +// +// Parameters: +// LPMRUMENU lpMruMenu - pointer on MRUMENU +// LPSTR lpszKey - Points to a null-terminated string +// specifying the name of a key that +// this function opens or creates. +// +// Return: (BOOL) +// TRUE - Function run successfully +// FALSE - Function don't run successfully +// +// +// Comments: +// Win32 function designed for Windows NT and Windows 95 +// See RegOpenKeyEx API for more info on lpszKey +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +BOOL LoadMruInReg(LPMRUMENU lpMruMenu,LPSTR lpszKey) +{ +LPSTR lpTxt; +WORD i; +HKEY hCurKey; +DWORD dwType; + lpTxt = (LPSTR)GlobalAllocPtr(GHND,lpMruMenu->wMaxSizeLruItem + 20); + if (lpTxt == NULL) + return FALSE; + + RegOpenKeyEx(HKEY_CURRENT_USER,lpszKey,0,KEY_READ,&hCurKey); + + + for (i=0;iwNbLruMenu;i++) + { + char szEntry[16]; + DWORD dwSizeBuf; + wsprintf(szEntry,"File%lu",(DWORD)i+1); + *lpTxt = '\0'; + dwSizeBuf = lpMruMenu->wMaxSizeLruItem + 10; + RegQueryValueEx(hCurKey,szEntry,NULL,&dwType,(LPBYTE)lpTxt,&dwSizeBuf); + *(lpTxt+dwSizeBuf)='\0'; + if (*lpTxt == '\0') + break; + SetMenuItem(lpMruMenu,i,lpTxt); + } + RegCloseKey(hCurKey); + GlobalFreePtr(lpTxt); + return TRUE; +} + + +//************************************************************* +// +// GetWin32Kind() +// +// Purpose: +// Get the Win32 platform +// +// Parameters: +// +// Return: (WIN32KIND) +// WINNT - Run under Windows NT +// WIN32S - Run under Windows 3.1x + Win32s +// WIN95ORGREATHER - Run under Windows 95 +// +// +// Comments: +// Win32 function designed for Windows NT and Windows 95 +// See RegOpenKeyEx API for more info on lpszKey +// +// History: Date Author Comment +// 09/24/94 G. Vollant Created +// +//************************************************************* +WIN32KIND GetWin32Kind() +{ +BOOL IsWin395OrHigher(void); + + WORD wVer; + + if ((GetVersion() & 0x80000000) == 0) + return WINNT; + wVer = LOWORD(GetVersion()); + wVer = (((WORD)LOBYTE(wVer)) << 8) | (WORD)HIBYTE(wVer); + + if (wVer >= 0x035F) + return WIN95ORGREATHER; + else + return WIN32S; +} +#endif diff --git a/tools/quake2/extra/qe4/mru.h b/tools/quake2/extra/qe4/mru.h new file mode 100644 index 00000000..b78b986c --- /dev/null +++ b/tools/quake2/extra/qe4/mru.h @@ -0,0 +1,101 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +//************************************************************* +// File name: mru.h +// +// Description: +// +// Header for MRU support +// +// Development Team: +// +// Gilles Vollant (100144.2636@compuserve.com) +// +//************************************************************* + +#ifndef __MRU_H__ +#define __MRU_H__ + +#define NBMRUMENUSHOW 6 // Default number of MRU showed in the menu File +#define NBMRUMENU 9 // Default number of MRU stored +#define IDMRU 8000 // Default First ID of MRU +#ifdef OFS_MAXPATHNAME +#define MAXSIZEMRUITEM OFS_MAXPATHNAME +#else +#define MAXSIZEMRUITEM 128 // Default max size of an entry +#endif + +typedef struct +{ +WORD wNbItemFill; +WORD wNbLruShow; +WORD wNbLruMenu; +WORD wMaxSizeLruItem; +WORD wIdMru; +LPSTR lpMRU; +} MRUMENU; + +typedef MRUMENU FAR * LPMRUMENU; + +#ifdef __cplusplus +LPMRUMENU CreateMruMenu (WORD wNbLruShowInit=NBMRUMENUSHOW, + WORD wNbLruMenuInit=NBMRUMENU, + WORD wMaxSizeLruItemInit=MAXSIZEMRUITEM, + WORD wIdMruInit=IDMRU); +#else +LPMRUMENU CreateMruMenu (WORD wNbLruShowInit, + WORD wNbLruMenuInit, + WORD wMaxSizeLruItemInit, + WORD wIdMruInit); +#endif + +LPMRUMENU CreateMruMenuDefault(); +void DeleteMruMenu (LPMRUMENU lpMruMenu); + +void SetNbLruShow (LPMRUMENU lpMruMenu,WORD wNbLruShowInit); +BOOL SetMenuItem (LPMRUMENU lpMruMenu,WORD wItem, + LPSTR lpItem); +BOOL GetMenuItem (LPMRUMENU lpMruMenu,WORD wItem, + BOOL fIDMBased,LPSTR lpItem,UINT uiSize); +BOOL DelMenuItem (LPMRUMENU lpMruMenu,WORD wItem,BOOL fIDMBased); +void AddNewItem (LPMRUMENU lpMruMenu,LPSTR lpItem); +void PlaceMenuMRUItem(LPMRUMENU lpMruMenu,HMENU hMenu,UINT uiItem); + +BOOL SaveMruInIni (LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile); +BOOL LoadMruInIni (LPMRUMENU lpMruMenu,LPSTR lpszSection,LPSTR lpszFile); +#ifdef WIN32 +BOOL SaveMruInReg (LPMRUMENU lpMruMenu,LPSTR lpszKey); +BOOL LoadMruInReg (LPMRUMENU lpMruMenu,LPSTR lpszKey); + +typedef enum +{ +WIN32S, +WINNT, +WIN95ORGREATHER +} WIN32KIND; +WIN32KIND GetWin32Kind(); +#endif + + +////////////////////////////////////////////////////////////// +#endif diff --git a/tools/quake2/extra/qe4/parse.c b/tools/quake2/extra/qe4/parse.c new file mode 100644 index 00000000..8258a4ad --- /dev/null +++ b/tools/quake2/extra/qe4/parse.c @@ -0,0 +1,141 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +char token[MAXTOKEN]; +qboolean unget; +char *script_p; +int scriptline; + +void StartTokenParsing (char *data) +{ + scriptline = 1; + script_p = data; + unget = false; +} + +qboolean GetToken (qboolean crossline) +{ + char *token_p; + + if (unget) // is a token allready waiting? + return true; + +// +// skip space +// +skipspace: + while (*script_p <= 32) + { + if (!*script_p) + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + return false; + } + if (*script_p++ == '\n') + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + scriptline++; + } + } + + if (script_p[0] == '/' && script_p[1] == '/') // comment field + { + if (!crossline) + Error ("Line %i is incomplete\n",scriptline); + while (*script_p++ != '\n') + if (!*script_p) + { + if (!crossline) + Error ("Line %i is incomplete",scriptline); + return false; + } + goto skipspace; + } + +// +// copy token +// + token_p = token; + + if (*script_p == '"') + { + script_p++; + while ( *script_p != '"' ) + { + if (!*script_p) + Error ("EOF inside quoted token"); + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + } + script_p++; + } + else while ( *script_p > 32 ) + { + *token_p++ = *script_p++; + if (token_p == &token[MAXTOKEN]) + Error ("Token too large on line %i",scriptline); + } + + *token_p = 0; + + return true; +} + +void UngetToken (void) +{ + unget = true; +} + + +/* +============== +TokenAvailable + +Returns true if there is another token on the line +============== +*/ +qboolean TokenAvailable (void) +{ + char *search_p; + + search_p = script_p; + + while ( *search_p <= 32) + { + if (*search_p == '\n') + return false; + if (*search_p == 0) + return false; + search_p++; + } + + if (*search_p == ';') + return false; + + return true; +} + diff --git a/tools/quake2/extra/qe4/parse.h b/tools/quake2/extra/qe4/parse.h new file mode 100644 index 00000000..0d5d3e1c --- /dev/null +++ b/tools/quake2/extra/qe4/parse.h @@ -0,0 +1,34 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// parse.h -- text file parsing routines + +#define MAXTOKEN 1024 + +extern char token[MAXTOKEN]; +extern int scriptline; + +void StartTokenParsing (char *data); +qboolean GetToken (qboolean crossline); +void UngetToken (void); +qboolean TokenAvailable (void); + diff --git a/tools/quake2/extra/qe4/points.c b/tools/quake2/extra/qe4/points.c new file mode 100644 index 00000000..deaae483 --- /dev/null +++ b/tools/quake2/extra/qe4/points.c @@ -0,0 +1,155 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + + +#define MAX_POINTFILE 8192 +static vec3_t s_pointvecs[MAX_POINTFILE]; +static int s_num_points, s_check_point; + +void Pointfile_Delete (void) +{ + char name[1024]; + + strcpy (name, currentmap); + StripExtension (name); + strcat (name, ".lin"); + + remove(name); +} + +// advance camera to next point +void Pointfile_Next (void) +{ + vec3_t dir; + + if (s_check_point >= s_num_points-2) + { + Sys_Status ("End of pointfile", 0); + return; + } + s_check_point++; + VectorCopy (s_pointvecs[s_check_point], camera.origin); + VectorCopy (s_pointvecs[s_check_point], g_qeglobals.d_xy.origin); + VectorSubtract (s_pointvecs[s_check_point+1], camera.origin, dir); + VectorNormalize (dir); + camera.angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + camera.angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +// advance camera to previous point +void Pointfile_Prev (void) +{ + vec3_t dir; + + if ( s_check_point == 0) + { + Sys_Status ("Start of pointfile", 0); + return; + } + s_check_point--; + VectorCopy (s_pointvecs[s_check_point], camera.origin); + VectorCopy (s_pointvecs[s_check_point], g_qeglobals.d_xy.origin); + VectorSubtract (s_pointvecs[s_check_point+1], camera.origin, dir); + VectorNormalize (dir); + camera.angles[1] = atan2 (dir[1], dir[0])*180/3.14159; + camera.angles[0] = asin (dir[2])*180/3.14159; + + Sys_UpdateWindows (W_ALL); +} + +void Pointfile_Check (void) +{ + char name[1024]; + FILE *f; + vec3_t v; + + strcpy (name, currentmap); + StripExtension (name); + strcat (name, ".lin"); + + f = fopen (name, "r"); + if (!f) + return; + + Sys_Printf ("Reading pointfile %s\n", name); + + if (!g_qeglobals.d_pointfile_display_list) + g_qeglobals.d_pointfile_display_list = glGenLists(1); + + s_num_points = 0; + glNewList (g_qeglobals.d_pointfile_display_list, GL_COMPILE); + glColor3f (1, 0, 0); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glLineWidth (4); + glBegin(GL_LINE_STRIP); + do + { + if (fscanf (f, "%f %f %f\n", &v[0], &v[1], &v[2]) != 3) + break; + if (s_num_points < MAX_POINTFILE) + { + VectorCopy (v, s_pointvecs[s_num_points]); + s_num_points++; + } + glVertex3fv (v); + } while (1); + glEnd(); + glLineWidth (1); + glEndList (); + + s_check_point = 0; + fclose (f); + Pointfile_Next (); +} + +void Pointfile_Draw( void ) +{ + int i; + + glColor3f( 1.0F, 0.0F, 0.0F ); + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glLineWidth (4); + glBegin(GL_LINE_STRIP); + for ( i = 0; i < s_num_points; i++ ) + { + glVertex3fv( s_pointvecs[i] ); + } + glEnd(); + glLineWidth( 1 ); +} + +void Pointfile_Clear (void) +{ + if (!g_qeglobals.d_pointfile_display_list) + return; + + glDeleteLists (g_qeglobals.d_pointfile_display_list, 1); + g_qeglobals.d_pointfile_display_list = 0; + Sys_UpdateWindows (W_ALL); +} + diff --git a/tools/quake2/extra/qe4/q.bmp b/tools/quake2/extra/qe4/q.bmp new file mode 100644 index 0000000000000000000000000000000000000000..598971a27f28da3e04d05e2847c615a612f9fac5 GIT binary patch literal 13878 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 literal 0 HcmV?d00001 diff --git a/tools/quake2/extra/qe4/qe3.c b/tools/quake2/extra/qe4/qe3.c new file mode 100644 index 00000000..153640d1 --- /dev/null +++ b/tools/quake2/extra/qe4/qe3.c @@ -0,0 +1,451 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +QEGlobals_t g_qeglobals; + +void QE_CheckOpenGLForErrors(void) +{ + int i; + + while ( ( i = glGetError() ) != GL_NO_ERROR ) + { + char buffer[100]; + + sprintf( buffer, "OpenGL Error: %s", gluErrorString( i ) ); + + MessageBox( g_qeglobals.d_hwndMain, buffer , "QuakeEd Error", MB_OK | MB_ICONEXCLAMATION ); + exit( 1 ); + } +} + + +char *ExpandReletivePath (char *p) +{ + static char temp[1024]; + char *base; + + if (!p || !p[0]) + return NULL; + if (p[0] == '/' || p[0] == '\\') + return p; + + base = ValueForKey(g_qeglobals.d_project_entity, "basepath"); + sprintf (temp, "%s/%s", base, p); + return temp; +} + + + +void *qmalloc (int size) +{ + void *b; + b = malloc(size); + memset (b, 0, size); + return b; +} + +char *copystring (char *s) +{ + char *b; + b = malloc(strlen(s)+1); + strcpy (b,s); + return b; +} + +/* +=============== +QE_CheckAutoSave + +If five minutes have passed since making a change +and the map hasn't been saved, save it out. +=============== +*/ +void QE_CheckAutoSave( void ) +{ + static clock_t s_start; + clock_t now; + + now = clock(); + + if ( modified != 1 || !s_start) + { + s_start = now; + return; + } + + if ( now - s_start > ( CLOCKS_PER_SEC * 60 * QE_AUTOSAVE_INTERVAL ) ) + { + Sys_Printf ("Autosaving...\n"); + Sys_Status ("Autosaving...", 0 ); + + Map_SaveFile (ValueForKey(g_qeglobals.d_project_entity, "autosave"), false); + + Sys_Status ("Autosaving...Saved.", 0 ); + modified = 2; + s_start = now; + } +} + + + +/* +=========== +QE_LoadProject +=========== +*/ +qboolean QE_LoadProject (char *projectfile) +{ + char *data; + + Sys_Printf ("QE_LoadProject (%s)\n", projectfile); + + if ( LoadFileNoCrash (projectfile, (void *)&data) == -1) + return false; + StartTokenParsing (data); + g_qeglobals.d_project_entity = Entity_Parse (true); + if (!g_qeglobals.d_project_entity) + Error ("Couldn't parse %s", projectfile); + free (data); + + Eclass_InitForSourceDirectory (ValueForKey (g_qeglobals.d_project_entity, "entitypath")); + + FillClassList (); // list in entity window + + Map_New (); + + FillTextureMenu (); + FillBSPMenu (); + + return true; +} + +/* +=========== +QE_KeyDown +=========== +*/ +#define SPEED_MOVE 32 +#define SPEED_TURN 22.5 + +qboolean QE_KeyDown (int key) +{ + switch (key) + { + case 'K': + PostMessage( g_qeglobals.d_hwndMain, WM_COMMAND, ID_MISC_SELECTENTITYCOLOR, 0 ); + break; + + case VK_UP: + VectorMA (camera.origin, SPEED_MOVE, camera.forward, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_DOWN: + VectorMA (camera.origin, -SPEED_MOVE, camera.forward, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_LEFT: + camera.angles[1] += SPEED_TURN; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_RIGHT: + camera.angles[1] -= SPEED_TURN; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case 'D': + camera.origin[2] += SPEED_MOVE; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z_OVERLAY); + break; + case 'C': + camera.origin[2] -= SPEED_MOVE; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z_OVERLAY); + break; + case 'A': + camera.angles[0] += SPEED_TURN; + if (camera.angles[0] > 85) + camera.angles[0] = 85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case 'Z': + camera.angles[0] -= SPEED_TURN; + if (camera.angles[0] < -85) + camera.angles[0] = -85; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_COMMA: + VectorMA (camera.origin, -SPEED_MOVE, camera.right, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + case VK_PERIOD: + VectorMA (camera.origin, SPEED_MOVE, camera.right, camera.origin); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + + case '0': + g_qeglobals.d_showgrid = !g_qeglobals.d_showgrid; + PostMessage( g_qeglobals.d_hwndXY, WM_PAINT, 0, 0 ); + break; + case '1': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_1, 0); + break; + case '2': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_2, 0); + break; + case '3': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_4, 0); + break; + case '4': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_8, 0); + break; + case '5': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_16, 0); + break; + case '6': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_32, 0); + break; + case '7': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_GRID_64, 0); + break; + + case 'E': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DRAGEDGES, 0); + break; + case 'V': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DRAGVERTECIES, 0); + break; + + case 'N': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_ENTITY, 0); + break; + case 'O': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_CONSOLE, 0); + break; + case 'T': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_TEXTURE, 0); + break; + case 'S': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_TEXTURES_INSPECTOR, 0); + break; + + case ' ': + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_CLONE, 0); + break; + + case VK_BACK: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DELETE, 0); + break; + case VK_ESCAPE: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_SELECTION_DESELECT, 0); + break; + case VK_END: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_CENTER, 0); + break; + + case VK_DELETE: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_ZOOMIN, 0); + break; + case VK_INSERT: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_ZOOMOUT, 0); + break; + + case VK_NEXT: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_DOWNFLOOR, 0); + break; + case VK_PRIOR: + PostMessage (g_qeglobals.d_hwndMain, WM_COMMAND, ID_VIEW_UPFLOOR, 0); + break; + + default: + return false; + + } + + return true; +} + +/* +=============== +ConnectEntities + +Sets target / targetname on the two entities selected +from the first selected to the secon +=============== +*/ +void ConnectEntities (void) +{ + entity_t *e1, *e2, *e; + char *target, *tn; + int maxtarg, targetnum; + char newtarg[32]; + + if (g_qeglobals.d_select_count != 2) + { + Sys_Status ("Must have two brushes selected.", 0); + Sys_Beep (); + return; + } + + e1 = g_qeglobals.d_select_order[0]->owner; + e2 = g_qeglobals.d_select_order[1]->owner; + + if (e1 == world_entity || e2 == world_entity) + { + Sys_Status ("Can't connect to the world.", 0); + Sys_Beep (); + return; + } + + if (e1 == e2) + { + Sys_Status ("Brushes are from same entity.", 0); + Sys_Beep (); + return; + } + + target = ValueForKey (e1, "target"); + if (target && target[0]) + strcpy (newtarg, target); + else + { + target = ValueForKey (e2, "targetname"); + if (target && target[0]) + strcpy (newtarg, target); + else + { + // make a unique target value + maxtarg = 0; + for (e=entities.next ; e != &entities ; e=e->next) + { + tn = ValueForKey (e, "targetname"); + if (tn && tn[0]) + { + targetnum = atoi(tn+1); + if (targetnum > maxtarg) + maxtarg = targetnum; + } + } + sprintf (newtarg, "t%i", maxtarg+1); + } + } + + SetKeyValue (e1, "target", newtarg); + SetKeyValue (e2, "targetname", newtarg); + Sys_UpdateWindows (W_XY | W_CAMERA); + + Select_Deselect(); + Select_Brush (g_qeglobals.d_select_order[1]); +} + +qboolean QE_SingleBrush (void) +{ + if ( (selected_brushes.next == &selected_brushes) + || (selected_brushes.next->next != &selected_brushes) ) + { + Sys_Printf ("Error: you must have a single brush selected\n"); + return false; + } + if (selected_brushes.next->owner->eclass->fixedsize) + { + Sys_Printf ("Error: you cannot manipulate fixed size entities\n"); + return false; + } + + return true; +} + +void QE_Init (void) +{ + /* + ** initialize variables + */ + g_qeglobals.d_gridsize = 8; + g_qeglobals.d_showgrid = true; + + /* + ** other stuff + */ + Texture_Init (); + Cam_Init (); + XY_Init (); + Z_Init (); +} + +void QE_ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +int g_numbrushes, g_numentities; + +void QE_CountBrushesAndUpdateStatusBar( void ) +{ + static int s_lastbrushcount, s_lastentitycount; + static qboolean s_didonce; + + entity_t *e; + brush_t *b, *next; + + g_numbrushes = 0; + g_numentities = 0; + + if ( active_brushes.next != NULL ) + { + for ( b = active_brushes.next ; b != NULL && b != &active_brushes ; b=next) + { + next = b->next; + if (b->brush_faces ) + { + if ( !b->owner->eclass->fixedsize) + g_numbrushes++; + else + g_numentities++; + } + } + } + + if ( entities.next != NULL ) + { + for ( e = entities.next ; e != &entities && g_numentities != MAX_MAP_ENTITIES ; e = e->next) + { + g_numentities++; + } + } + + if ( ( ( g_numbrushes != s_lastbrushcount ) || ( g_numentities != s_lastentitycount ) ) || ( !s_didonce ) ) + { + Sys_UpdateStatusBar(); + + s_lastbrushcount = g_numbrushes; + s_lastentitycount = g_numentities; + s_didonce = true; + } +} + diff --git a/tools/quake2/extra/qe4/qe3.h b/tools/quake2/extra/qe4/qe3.h new file mode 100644 index 00000000..67930599 --- /dev/null +++ b/tools/quake2/extra/qe4/qe3.h @@ -0,0 +1,306 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifndef __QE3_H__ +#define __QE3_H__ + +// disable data conversion warnings for gl +#pragma warning(disable : 4244) // MIPS +#pragma warning(disable : 4136) // X86 +#pragma warning(disable : 4051) // ALPHA + +#include + +#include +#include +#include +#include "glingr.h" +#include +#include + +#include "cmdlib.h" +#include "mathlib.h" +#include "parse.h" +#include "lbmlib.h" + +#include +#include "afxres.h" +#include "resource.h" + +#include "qedefs.h" + +typedef struct +{ + vec3_t normal; + double dist; + int type; +} plane_t; + +#include "qfiles.h" + +#include "textures.h" +#include "brush.h" +#include "entity.h" +#include "map.h" +#include "select.h" + +#include "camera.h" +#include "xy.h" +#include "z.h" +#include "mru.h" + +typedef struct +{ + int p1, p2; + face_t *f1, *f2; +} pedge_t; + +typedef struct +{ + int iSize; + int iTexMenu; // nearest, linear, etc + float fGamma; // gamma for textures + char szProject[256]; // last project loaded + vec3_t colors[COLOR_LAST]; + qboolean show_names, + show_coordinates; + int exclude; +} SavedInfo_t; + +// +// system functions +// +void Sys_UpdateStatusBar( void ); +void Sys_UpdateWindows (int bits); +void Sys_Beep (void); +void Sys_ClearPrintf (void); +void Sys_Printf (char *text, ...); +double Sys_DoubleTime (void); +void Sys_GetCursorPos (int *x, int *y); +void Sys_SetCursorPos (int x, int y); +void Sys_SetTitle (char *text); +void Sys_BeginWait (void); +void Sys_EndWait (void); +void Sys_Status(const char *psz, int part); + +/* +** most of the QE globals are stored in this structure +*/ +typedef struct +{ + qboolean d_showgrid; + int d_gridsize; + + int d_num_entities; + + entity_t *d_project_entity; + + float d_new_brush_bottom_z, + d_new_brush_top_z; + + HINSTANCE d_hInstance; + + HGLRC d_hglrcBase; + HDC d_hdcBase; + + HWND d_hwndMain; + HWND d_hwndCamera; + HWND d_hwndEdit; + HWND d_hwndEntity; + HWND d_hwndTexture; + HWND d_hwndXY; + HWND d_hwndZ; + HWND d_hwndStatus; + + vec3_t d_points[MAX_POINTS]; + int d_numpoints; + pedge_t d_edges[MAX_EDGES]; + int d_numedges; + + int d_num_move_points; + float *d_move_points[1024]; + + qtexture_t *d_qtextures; + + texturewin_t d_texturewin; + + int d_pointfile_display_list; + + xy_t d_xy; + + LPMRUMENU d_lpMruMenu; + + SavedInfo_t d_savedinfo; + + int d_workcount; + + // connect entities uses the last two brushes selected + int d_select_count; + brush_t *d_select_order[2]; + vec3_t d_select_translate; // for dragging w/o making new display lists + select_t d_select_mode; + + int d_font_list; + + int d_parsed_brushes; + + qboolean show_blocks; +} QEGlobals_t; + +void *qmalloc (int size); +char *copystring (char *s); +char *ExpandReletivePath (char *p); + +void Pointfile_Delete (void); +void Pointfile_Check (void); +void Pointfile_Next (void); +void Pointfile_Prev (void); +void Pointfile_Clear (void); +void Pointfile_Draw( void ); +void Pointfile_Load( void ); + +// +// drag.c +// +void Drag_Begin (int x, int y, int buttons, + vec3_t xaxis, vec3_t yaxis, + vec3_t origin, vec3_t dir); +void Drag_MouseMoved (int x, int y, int buttons); +void Drag_MouseUp (void); + +// +// csg.c +// +void CSG_MakeHollow (void); +void CSG_Subtract (void); + +// +// vertsel.c +// + +void SetupVertexSelection (void); +void SelectEdgeByRay (vec3_t org, vec3_t dir); +void SelectVertexByRay (vec3_t org, vec3_t dir); + +void ConnectEntities (void); + +extern int update_bits; + +extern int screen_width; +extern int screen_height; + +extern HANDLE bsp_process; + +char *TranslateString (char *buf); + +void ProjectDialog (void); + +void FillTextureMenu (void); +void FillBSPMenu (void); + +BOOL CALLBACK Win_Dialog ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter +); + + +// +// win_cam.c +// +void WCam_Create (HINSTANCE hInstance); + + +// +// win_xy.c +// +void WXY_Create (HINSTANCE hInstance); + +// +// win_z.c +// +void WZ_Create (HINSTANCE hInstance); + +// +// win_ent.c +// + + +// +// win_main.c +// +void Main_Create (HINSTANCE hInstance); +extern BOOL SaveWindowState(HWND hWnd, const char *pszName); +extern BOOL LoadWindowState(HWND hWnd, const char *pszName); + +extern BOOL SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize); +extern BOOL loadRegistryInfo(const char *pszName, void *pvBuf, long *plSize); + +// +// entityw.c +// +BOOL CreateEntityWindow(HINSTANCE hInstance); +void FillClassList (void); +BOOL UpdateEntitySel(eclass_t *pec); +void SetInspectorMode(int iType); +int DrawTexControls(HWND hWnd); +void SetSpawnFlags(void); +void GetSpawnFlags(void); +void SetKeyValuePairs(void); +extern void BuildGammaTable(float g); + + +// win_dlg.c + +void DoGamma(void); +void DoFind(void); +void DoRotate(void); +void DoSides(void); +void DoAbout(void); +void DoSurface(void); + +/* +** QE function declarations +*/ +void QE_CheckAutoSave( void ); +void QE_ConvertDOSToUnixName( char *dst, const char *src ); +void QE_CountBrushesAndUpdateStatusBar( void ); +void QE_CheckOpenGLForErrors(void); +void QE_ExpandBspString (char *bspaction, char *out, char *mapname); +void QE_Init (void); +qboolean QE_KeyDown (int key); +qboolean QE_LoadProject (char *projectfile); +qboolean QE_SingleBrush (void); + +/* +** QE Win32 function declarations +*/ +int QEW_SetupPixelFormat(HDC hDC, qboolean zbuffer ); +void QEW_StopGL( HWND hWnd, HGLRC hGLRC, HDC hDC ); + +/* +** extern declarations +*/ +extern QEGlobals_t g_qeglobals; + +#endif diff --git a/tools/quake2/extra/qe4/qe4.mak b/tools/quake2/extra/qe4/qe4.mak new file mode 100644 index 00000000..9032cfa4 --- /dev/null +++ b/tools/quake2/extra/qe4/qe4.mak @@ -0,0 +1,3716 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 +# TARGTYPE "Win32 (ALPHA) Application" 0x0601 + +!IF "$(CFG)" == "" +CFG=qe3 - Win32 (ALPHA) Debug +!MESSAGE No configuration specified. Defaulting to qe3 - Win32 (ALPHA) Debug. +!ENDIF + +!IF "$(CFG)" != "qe3 - Win32 Release" && "$(CFG)" != "qe3 - Win32 Debug" &&\ + "$(CFG)" != "qe3 - Win32 (ALPHA) Debug" && "$(CFG)" !=\ + "qe3 - Win32 (ALPHA) Release" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "qe4.mak" CFG="qe3 - Win32 (ALPHA) Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "qe3 - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "qe3 - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE "qe3 - Win32 (ALPHA) Debug" (based on "Win32 (ALPHA) Application") +!MESSAGE "qe3 - Win32 (ALPHA) Release" (based on "Win32 (ALPHA) Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "qe3 - Win32 Debug" + +!IF "$(CFG)" == "qe3 - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\qe4.exe" "$(OUTDIR)\qe4.bsc" + +CLEAN : + -@erase "$(INTDIR)\brush.obj" + -@erase "$(INTDIR)\brush.sbr" + -@erase "$(INTDIR)\camera.obj" + -@erase "$(INTDIR)\camera.sbr" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\cmdlib.sbr" + -@erase "$(INTDIR)\csg.obj" + -@erase "$(INTDIR)\csg.sbr" + -@erase "$(INTDIR)\drag.obj" + -@erase "$(INTDIR)\drag.sbr" + -@erase "$(INTDIR)\eclass.obj" + -@erase "$(INTDIR)\eclass.sbr" + -@erase "$(INTDIR)\entity.obj" + -@erase "$(INTDIR)\entity.sbr" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\lbmlib.sbr" + -@erase "$(INTDIR)\map.obj" + -@erase "$(INTDIR)\map.sbr" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\mathlib.sbr" + -@erase "$(INTDIR)\mru.obj" + -@erase "$(INTDIR)\mru.sbr" + -@erase "$(INTDIR)\parse.obj" + -@erase "$(INTDIR)\parse.sbr" + -@erase "$(INTDIR)\points.obj" + -@erase "$(INTDIR)\points.sbr" + -@erase "$(INTDIR)\qe3.obj" + -@erase "$(INTDIR)\qe3.sbr" + -@erase "$(INTDIR)\select.obj" + -@erase "$(INTDIR)\select.sbr" + -@erase "$(INTDIR)\textures.obj" + -@erase "$(INTDIR)\textures.sbr" + -@erase "$(INTDIR)\vertsel.obj" + -@erase "$(INTDIR)\vertsel.sbr" + -@erase "$(INTDIR)\win_cam.obj" + -@erase "$(INTDIR)\win_cam.sbr" + -@erase "$(INTDIR)\win_dlg.obj" + -@erase "$(INTDIR)\win_dlg.sbr" + -@erase "$(INTDIR)\win_ent.obj" + -@erase "$(INTDIR)\win_ent.sbr" + -@erase "$(INTDIR)\win_main.obj" + -@erase "$(INTDIR)\win_main.sbr" + -@erase "$(INTDIR)\win_qe3.obj" + -@erase "$(INTDIR)\win_qe3.res" + -@erase "$(INTDIR)\win_qe3.sbr" + -@erase "$(INTDIR)\win_xy.obj" + -@erase "$(INTDIR)\win_xy.sbr" + -@erase "$(INTDIR)\win_z.obj" + -@erase "$(INTDIR)\win_z.sbr" + -@erase "$(INTDIR)\xy.obj" + -@erase "$(INTDIR)\xy.sbr" + -@erase "$(INTDIR)\z.obj" + -@erase "$(INTDIR)\z.sbr" + -@erase "$(OUTDIR)\qe4.bsc" + -@erase "$(OUTDIR)\qe4.exe" + -@erase "$(OUTDIR)\qe4.pdb" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /GX /Zd /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /Fr /YX /c +CPP_PROJ=/nologo /ML /W3 /GX /Zd /O1 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\ + /Fr"$(INTDIR)/" /Fp"$(INTDIR)/qe4.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\Release/ + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +MTL=mktyplib.exe +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/win_qe3.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qe4.bsc" +BSC32_SBRS= \ + "$(INTDIR)\brush.sbr" \ + "$(INTDIR)\camera.sbr" \ + "$(INTDIR)\cmdlib.sbr" \ + "$(INTDIR)\csg.sbr" \ + "$(INTDIR)\drag.sbr" \ + "$(INTDIR)\eclass.sbr" \ + "$(INTDIR)\entity.sbr" \ + "$(INTDIR)\lbmlib.sbr" \ + "$(INTDIR)\map.sbr" \ + "$(INTDIR)\mathlib.sbr" \ + "$(INTDIR)\mru.sbr" \ + "$(INTDIR)\parse.sbr" \ + "$(INTDIR)\points.sbr" \ + "$(INTDIR)\qe3.sbr" \ + "$(INTDIR)\select.sbr" \ + "$(INTDIR)\textures.sbr" \ + "$(INTDIR)\vertsel.sbr" \ + "$(INTDIR)\win_cam.sbr" \ + "$(INTDIR)\win_dlg.sbr" \ + "$(INTDIR)\win_ent.sbr" \ + "$(INTDIR)\win_main.sbr" \ + "$(INTDIR)\win_qe3.sbr" \ + "$(INTDIR)\win_xy.sbr" \ + "$(INTDIR)\win_z.sbr" \ + "$(INTDIR)\xy.sbr" \ + "$(INTDIR)\z.sbr" + +"$(OUTDIR)\qe4.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 +LINK32_FLAGS=comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib\ + gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib\ + oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows\ + /incremental:no /pdb:"$(OUTDIR)/qe4.pdb" /debug /machine:I386\ + /out:"$(OUTDIR)/qe4.exe" +LINK32_OBJS= \ + "$(INTDIR)\brush.obj" \ + "$(INTDIR)\camera.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\csg.obj" \ + "$(INTDIR)\drag.obj" \ + "$(INTDIR)\eclass.obj" \ + "$(INTDIR)\entity.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\map.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\mru.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\points.obj" \ + "$(INTDIR)\qe3.obj" \ + "$(INTDIR)\select.obj" \ + "$(INTDIR)\textures.obj" \ + "$(INTDIR)\vertsel.obj" \ + "$(INTDIR)\win_cam.obj" \ + "$(INTDIR)\win_dlg.obj" \ + "$(INTDIR)\win_ent.obj" \ + "$(INTDIR)\win_main.obj" \ + "$(INTDIR)\win_qe3.obj" \ + "$(INTDIR)\win_qe3.res" \ + "$(INTDIR)\win_xy.obj" \ + "$(INTDIR)\win_z.obj" \ + "$(INTDIR)\xy.obj" \ + "$(INTDIR)\z.obj" + +"$(OUTDIR)\qe4.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "Debug" +# PROP BASE Intermediate_Dir "Debug" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\qe4.exe" "$(OUTDIR)\qe4.bsc" + +CLEAN : + -@erase "$(INTDIR)\brush.obj" + -@erase "$(INTDIR)\brush.sbr" + -@erase "$(INTDIR)\camera.obj" + -@erase "$(INTDIR)\camera.sbr" + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\cmdlib.sbr" + -@erase "$(INTDIR)\csg.obj" + -@erase "$(INTDIR)\csg.sbr" + -@erase "$(INTDIR)\drag.obj" + -@erase "$(INTDIR)\drag.sbr" + -@erase "$(INTDIR)\eclass.obj" + -@erase "$(INTDIR)\eclass.sbr" + -@erase "$(INTDIR)\entity.obj" + -@erase "$(INTDIR)\entity.sbr" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\lbmlib.sbr" + -@erase "$(INTDIR)\map.obj" + -@erase "$(INTDIR)\map.sbr" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\mathlib.sbr" + -@erase "$(INTDIR)\mru.obj" + -@erase "$(INTDIR)\mru.sbr" + -@erase "$(INTDIR)\parse.obj" + -@erase "$(INTDIR)\parse.sbr" + -@erase "$(INTDIR)\points.obj" + -@erase "$(INTDIR)\points.sbr" + -@erase "$(INTDIR)\qe3.obj" + -@erase "$(INTDIR)\qe3.sbr" + -@erase "$(INTDIR)\select.obj" + -@erase "$(INTDIR)\select.sbr" + -@erase "$(INTDIR)\textures.obj" + -@erase "$(INTDIR)\textures.sbr" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\vertsel.obj" + -@erase "$(INTDIR)\vertsel.sbr" + -@erase "$(INTDIR)\win_cam.obj" + -@erase "$(INTDIR)\win_cam.sbr" + -@erase "$(INTDIR)\win_dlg.obj" + -@erase "$(INTDIR)\win_dlg.sbr" + -@erase "$(INTDIR)\win_ent.obj" + -@erase "$(INTDIR)\win_ent.sbr" + -@erase "$(INTDIR)\win_main.obj" + -@erase "$(INTDIR)\win_main.sbr" + -@erase "$(INTDIR)\win_qe3.obj" + -@erase "$(INTDIR)\win_qe3.res" + -@erase "$(INTDIR)\win_qe3.sbr" + -@erase "$(INTDIR)\win_xy.obj" + -@erase "$(INTDIR)\win_xy.sbr" + -@erase "$(INTDIR)\win_z.obj" + -@erase "$(INTDIR)\win_z.sbr" + -@erase "$(INTDIR)\xy.obj" + -@erase "$(INTDIR)\xy.sbr" + -@erase "$(INTDIR)\z.obj" + -@erase "$(INTDIR)\z.sbr" + -@erase "$(OUTDIR)\qe4.bsc" + -@erase "$(OUTDIR)\qe4.exe" + -@erase "$(OUTDIR)\qe4.map" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FR /YX /c +CPP_PROJ=/nologo /MLd /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\ + /FR"$(INTDIR)/" /Fp"$(INTDIR)/qe4.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\Debug/ + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +MTL=mktyplib.exe +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /win32 +MTL_PROJ=/nologo /D "_DEBUG" /win32 +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/win_qe3.res" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qe4.bsc" +BSC32_SBRS= \ + "$(INTDIR)\brush.sbr" \ + "$(INTDIR)\camera.sbr" \ + "$(INTDIR)\cmdlib.sbr" \ + "$(INTDIR)\csg.sbr" \ + "$(INTDIR)\drag.sbr" \ + "$(INTDIR)\eclass.sbr" \ + "$(INTDIR)\entity.sbr" \ + "$(INTDIR)\lbmlib.sbr" \ + "$(INTDIR)\map.sbr" \ + "$(INTDIR)\mathlib.sbr" \ + "$(INTDIR)\mru.sbr" \ + "$(INTDIR)\parse.sbr" \ + "$(INTDIR)\points.sbr" \ + "$(INTDIR)\qe3.sbr" \ + "$(INTDIR)\select.sbr" \ + "$(INTDIR)\textures.sbr" \ + "$(INTDIR)\vertsel.sbr" \ + "$(INTDIR)\win_cam.sbr" \ + "$(INTDIR)\win_dlg.sbr" \ + "$(INTDIR)\win_ent.sbr" \ + "$(INTDIR)\win_main.sbr" \ + "$(INTDIR)\win_qe3.sbr" \ + "$(INTDIR)\win_xy.sbr" \ + "$(INTDIR)\win_z.sbr" \ + "$(INTDIR)\xy.sbr" \ + "$(INTDIR)\z.sbr" + +"$(OUTDIR)\qe4.bsc" : "$(OUTDIR)" $(BSC32_SBRS) + $(BSC32) @<< + $(BSC32_FLAGS) $(BSC32_SBRS) +<< + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /profile /map /debug /machine:I386 +LINK32_FLAGS=comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib\ + gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib\ + oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows\ + /profile /map:"$(INTDIR)/qe4.map" /debug /machine:I386 /out:"$(OUTDIR)/qe4.exe"\ + +LINK32_OBJS= \ + "$(INTDIR)\brush.obj" \ + "$(INTDIR)\camera.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\csg.obj" \ + "$(INTDIR)\drag.obj" \ + "$(INTDIR)\eclass.obj" \ + "$(INTDIR)\entity.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\map.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\mru.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\points.obj" \ + "$(INTDIR)\qe3.obj" \ + "$(INTDIR)\select.obj" \ + "$(INTDIR)\textures.obj" \ + "$(INTDIR)\vertsel.obj" \ + "$(INTDIR)\win_cam.obj" \ + "$(INTDIR)\win_dlg.obj" \ + "$(INTDIR)\win_ent.obj" \ + "$(INTDIR)\win_main.obj" \ + "$(INTDIR)\win_qe3.obj" \ + "$(INTDIR)\win_qe3.res" \ + "$(INTDIR)\win_xy.obj" \ + "$(INTDIR)\win_z.obj" \ + "$(INTDIR)\xy.obj" \ + "$(INTDIR)\z.obj" + +"$(OUTDIR)\qe4.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "qe3___Wi" +# PROP BASE Intermediate_Dir "qe3___Wi" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "debug_alpha" +# PROP Intermediate_Dir "debug_alpha" +# PROP Target_Dir "" +OUTDIR=.\debug_alpha +INTDIR=.\debug_alpha + +ALL : "$(OUTDIR)\qe3.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +CPP_PROJ=/nologo /MLd /Gt0 /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS"\ + /Fp"$(INTDIR)/qe3.pch" /YX /Fo"$(INTDIR)/" /Fd"$(INTDIR)/" /c +CPP_OBJS=.\debug_alpha/ +CPP_SBRS=.\. + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +MTL=mktyplib.exe +# ADD BASE MTL /nologo /D "_DEBUG" /alpha +# ADD MTL /nologo /D "_DEBUG" /alpha +MTL_PROJ=/nologo /D "_DEBUG" /alpha +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/win_qe3.res" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qe3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:ALPHA +# SUBTRACT BASE LINK32 /incremental:no +# ADD LINK32 comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:ALPHA +# SUBTRACT LINK32 /incremental:no +LINK32_FLAGS=comctl32.lib opengl32.lib glu32.lib kernel32.lib\ + user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib\ + ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo\ + /subsystem:windows /incremental:yes /pdb:"$(OUTDIR)/qe3.pdb" /debug\ + /machine:ALPHA /out:"$(OUTDIR)/qe3.exe" +LINK32_OBJS= \ + "$(INTDIR)\brush.obj" \ + "$(INTDIR)\camera.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\csg.obj" \ + "$(INTDIR)\drag.obj" \ + "$(INTDIR)\eclass.obj" \ + "$(INTDIR)\entity.obj" \ + "$(INTDIR)\map.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\mru.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\points.obj" \ + "$(INTDIR)\qe3.obj" \ + "$(INTDIR)\select.obj" \ + "$(INTDIR)\textures.obj" \ + "$(INTDIR)\vertsel.obj" \ + "$(INTDIR)\win_cam.obj" \ + "$(INTDIR)\win_dlg.obj" \ + "$(INTDIR)\win_ent.obj" \ + "$(INTDIR)\win_main.obj" \ + "$(INTDIR)\win_qe3.obj" \ + "$(INTDIR)\win_qe3.res" \ + "$(INTDIR)\win_xy.obj" \ + "$(INTDIR)\win_z.obj" \ + "$(INTDIR)\xy.obj" \ + "$(INTDIR)\z.obj" + +"$(OUTDIR)\qe3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "qe3___W0" +# PROP BASE Intermediate_Dir "qe3___W0" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "release_alpha" +# PROP Intermediate_Dir "release_alpha" +# PROP Target_Dir "" +OUTDIR=.\release_alpha +INTDIR=.\release_alpha + +ALL : "$(OUTDIR)\qe3.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +CPP=cl.exe +# ADD BASE CPP /nologo /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +CPP_PROJ=/nologo /ML /Gt0 /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS"\ + /Fp"$(INTDIR)/qe3.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\release_alpha/ +CPP_SBRS=.\. + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +MTL=mktyplib.exe +# ADD BASE MTL /nologo /D "NDEBUG" /alpha +# ADD MTL /nologo /D "NDEBUG" /alpha +MTL_PROJ=/nologo /D "NDEBUG" /alpha +RSC=rc.exe +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/win_qe3.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/qe3.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:ALPHA +# ADD LINK32 comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:ALPHA +LINK32_FLAGS=comctl32.lib opengl32.lib glu32.lib kernel32.lib user32.lib\ + gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib\ + oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows\ + /incremental:no /pdb:"$(OUTDIR)/qe3.pdb" /machine:ALPHA\ + /out:"$(OUTDIR)/qe3.exe" +LINK32_OBJS= \ + "$(INTDIR)\brush.obj" \ + "$(INTDIR)\camera.obj" \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\csg.obj" \ + "$(INTDIR)\drag.obj" \ + "$(INTDIR)\eclass.obj" \ + "$(INTDIR)\entity.obj" \ + "$(INTDIR)\map.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\mru.obj" \ + "$(INTDIR)\parse.obj" \ + "$(INTDIR)\points.obj" \ + "$(INTDIR)\qe3.obj" \ + "$(INTDIR)\select.obj" \ + "$(INTDIR)\textures.obj" \ + "$(INTDIR)\vertsel.obj" \ + "$(INTDIR)\win_cam.obj" \ + "$(INTDIR)\win_dlg.obj" \ + "$(INTDIR)\win_ent.obj" \ + "$(INTDIR)\win_main.obj" \ + "$(INTDIR)\win_qe3.obj" \ + "$(INTDIR)\win_qe3.res" \ + "$(INTDIR)\win_xy.obj" \ + "$(INTDIR)\win_z.obj" \ + "$(INTDIR)\xy.obj" \ + "$(INTDIR)\z.obj" + +"$(OUTDIR)\qe3.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +################################################################################ +# Begin Target + +# Name "qe3 - Win32 Release" +# Name "qe3 - Win32 Debug" +# Name "qe3 - Win32 (ALPHA) Debug" +# Name "qe3 - Win32 (ALPHA) Release" + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\textures.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\textures.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_TEXTU=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\textures.obj" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + +"$(INTDIR)\textures.sbr" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_TEXTU=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\textures.obj" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + +"$(INTDIR)\textures.sbr" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_TEXTU=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\textures.obj" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_TEXTU=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\textures.obj" : $(SOURCE) $(DEP_CPP_TEXTU) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\resource.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mathlib.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mathlib.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_MATHL=\ + ".\cmdlib.h"\ + ".\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + +"$(INTDIR)\mathlib.sbr" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_MATHL=\ + ".\cmdlib.h"\ + ".\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + +"$(INTDIR)\mathlib.sbr" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_MATHL=\ + ".\cmdlib.h"\ + ".\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_MATHL=\ + ".\cmdlib.h"\ + ".\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\map.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\map.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_MAP_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + +"$(INTDIR)\map.sbr" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_MAP_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + +"$(INTDIR)\map.sbr" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_MAP_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_MAP_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\map.obj" : $(SOURCE) $(DEP_CPP_MAP_C) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\cmdlib.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\cmdlib.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_CMDLI=\ + ".\cmdlib.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + +"$(INTDIR)\cmdlib.sbr" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_CMDLI=\ + ".\cmdlib.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + +"$(INTDIR)\cmdlib.sbr" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_CMDLI=\ + ".\cmdlib.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_CMDLI=\ + ".\cmdlib.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\brush.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\brush.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_BRUSH=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\brush.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + +"$(INTDIR)\brush.sbr" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_BRUSH=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\brush.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + +"$(INTDIR)\brush.sbr" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_BRUSH=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\brush.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_BRUSH=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\brush.obj" : $(SOURCE) $(DEP_CPP_BRUSH) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\notes.txt + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_cam.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_cam.obj" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + +"$(INTDIR)\win_cam.sbr" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_cam.obj" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + +"$(INTDIR)\win_cam.sbr" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_cam.obj" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_cam.obj" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qe3.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\parse.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\parse.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_PARSE=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\parse.obj" : $(SOURCE) $(DEP_CPP_PARSE) "$(INTDIR)" + +"$(INTDIR)\parse.sbr" : $(SOURCE) $(DEP_CPP_PARSE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_PARSE=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\parse.obj" : $(SOURCE) $(DEP_CPP_PARSE) "$(INTDIR)" + +"$(INTDIR)\parse.sbr" : $(SOURCE) $(DEP_CPP_PARSE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_PARSE=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\parse.obj" : $(SOURCE) $(DEP_CPP_PARSE) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_PARSE=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\parse.obj" : $(SOURCE) $(DEP_CPP_PARSE) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\camera.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\camera.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_CAMER=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\camera.obj" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)" + +"$(INTDIR)\camera.sbr" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_CAMER=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\camera.obj" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)" + +"$(INTDIR)\camera.sbr" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_CAMER=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\camera.obj" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_CAMER=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\camera.obj" : $(SOURCE) $(DEP_CPP_CAMER) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_qe3.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_xy.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_X=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_xy.obj" : $(SOURCE) $(DEP_CPP_WIN_X) "$(INTDIR)" + +"$(INTDIR)\win_xy.sbr" : $(SOURCE) $(DEP_CPP_WIN_X) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_X=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_xy.obj" : $(SOURCE) $(DEP_CPP_WIN_X) "$(INTDIR)" + +"$(INTDIR)\win_xy.sbr" : $(SOURCE) $(DEP_CPP_WIN_X) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_X=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_xy.obj" : $(SOURCE) $(DEP_CPP_WIN_X) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_X=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_xy.obj" : $(SOURCE) $(DEP_CPP_WIN_X) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_qe3.rc + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_RSC_WIN_Q=\ + ".\icon1.ico"\ + ".\q.bmp"\ + ".\toolbar1.bmp"\ + + +"$(INTDIR)\win_qe3.res" : $(SOURCE) $(DEP_RSC_WIN_Q) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_RSC_WIN_Q=\ + ".\icon1.ico"\ + ".\q.bmp"\ + ".\toolbar1.bmp"\ + + +"$(INTDIR)\win_qe3.res" : $(SOURCE) $(DEP_RSC_WIN_Q) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_RSC_WIN_Q=\ + ".\icon1.ico"\ + ".\toolbar1.bmp"\ + + +"$(INTDIR)\win_qe3.res" : $(SOURCE) $(DEP_RSC_WIN_Q) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)/win_qe3.res" /d "_DEBUG" $(SOURCE) + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_RSC_WIN_Q=\ + ".\icon1.ico"\ + ".\toolbar1.bmp"\ + + +"$(INTDIR)\win_qe3.res" : $(SOURCE) $(DEP_RSC_WIN_Q) "$(INTDIR)" + $(RSC) /l 0x409 /fo"$(INTDIR)/win_qe3.res" /d "NDEBUG" $(SOURCE) + + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\xy.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_XY_C14=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\xy.obj" : $(SOURCE) $(DEP_CPP_XY_C14) "$(INTDIR)" + +"$(INTDIR)\xy.sbr" : $(SOURCE) $(DEP_CPP_XY_C14) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_XY_C14=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\xy.obj" : $(SOURCE) $(DEP_CPP_XY_C14) "$(INTDIR)" + +"$(INTDIR)\xy.sbr" : $(SOURCE) $(DEP_CPP_XY_C14) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_XY_C14=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\xy.obj" : $(SOURCE) $(DEP_CPP_XY_C14) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_XY_C14=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\xy.obj" : $(SOURCE) $(DEP_CPP_XY_C14) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\xy.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\select.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_SELEC=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\select.obj" : $(SOURCE) $(DEP_CPP_SELEC) "$(INTDIR)" + +"$(INTDIR)\select.sbr" : $(SOURCE) $(DEP_CPP_SELEC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_SELEC=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\select.obj" : $(SOURCE) $(DEP_CPP_SELEC) "$(INTDIR)" + +"$(INTDIR)\select.sbr" : $(SOURCE) $(DEP_CPP_SELEC) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_SELEC=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\select.obj" : $(SOURCE) $(DEP_CPP_SELEC) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_SELEC=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\select.obj" : $(SOURCE) $(DEP_CPP_SELEC) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_qe3.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_QE=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_qe3.obj" : $(SOURCE) $(DEP_CPP_WIN_QE) "$(INTDIR)" + +"$(INTDIR)\win_qe3.sbr" : $(SOURCE) $(DEP_CPP_WIN_QE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_QE=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_qe3.obj" : $(SOURCE) $(DEP_CPP_WIN_QE) "$(INTDIR)" + +"$(INTDIR)\win_qe3.sbr" : $(SOURCE) $(DEP_CPP_WIN_QE) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_QE=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_qe3.obj" : $(SOURCE) $(DEP_CPP_WIN_QE) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_QE=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_qe3.obj" : $(SOURCE) $(DEP_CPP_WIN_QE) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\select.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qe3.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_QE3_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\qe3.obj" : $(SOURCE) $(DEP_CPP_QE3_C) "$(INTDIR)" + +"$(INTDIR)\qe3.sbr" : $(SOURCE) $(DEP_CPP_QE3_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_QE3_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\qe3.obj" : $(SOURCE) $(DEP_CPP_QE3_C) "$(INTDIR)" + +"$(INTDIR)\qe3.sbr" : $(SOURCE) $(DEP_CPP_QE3_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_QE3_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\qe3.obj" : $(SOURCE) $(DEP_CPP_QE3_C) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_QE3_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\qe3.obj" : $(SOURCE) $(DEP_CPP_QE3_C) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\eclass.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_ECLAS=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\eclass.obj" : $(SOURCE) $(DEP_CPP_ECLAS) "$(INTDIR)" + +"$(INTDIR)\eclass.sbr" : $(SOURCE) $(DEP_CPP_ECLAS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_ECLAS=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\eclass.obj" : $(SOURCE) $(DEP_CPP_ECLAS) "$(INTDIR)" + +"$(INTDIR)\eclass.sbr" : $(SOURCE) $(DEP_CPP_ECLAS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_ECLAS=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\eclass.obj" : $(SOURCE) $(DEP_CPP_ECLAS) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_ECLAS=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\eclass.obj" : $(SOURCE) $(DEP_CPP_ECLAS) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\eclass.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\entity.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_ENTIT=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\entity.obj" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)" + +"$(INTDIR)\entity.sbr" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_ENTIT=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\entity.obj" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)" + +"$(INTDIR)\entity.sbr" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_ENTIT=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\entity.obj" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_ENTIT=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\entity.obj" : $(SOURCE) $(DEP_CPP_ENTIT) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\entity.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_dlg.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_D=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_dlg.obj" : $(SOURCE) $(DEP_CPP_WIN_D) "$(INTDIR)" + +"$(INTDIR)\win_dlg.sbr" : $(SOURCE) $(DEP_CPP_WIN_D) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_D=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_dlg.obj" : $(SOURCE) $(DEP_CPP_WIN_D) "$(INTDIR)" + +"$(INTDIR)\win_dlg.sbr" : $(SOURCE) $(DEP_CPP_WIN_D) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_D=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_dlg.obj" : $(SOURCE) $(DEP_CPP_WIN_D) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_D=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_dlg.obj" : $(SOURCE) $(DEP_CPP_WIN_D) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\points.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_POINT=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\points.obj" : $(SOURCE) $(DEP_CPP_POINT) "$(INTDIR)" + +"$(INTDIR)\points.sbr" : $(SOURCE) $(DEP_CPP_POINT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_POINT=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\points.obj" : $(SOURCE) $(DEP_CPP_POINT) "$(INTDIR)" + +"$(INTDIR)\points.sbr" : $(SOURCE) $(DEP_CPP_POINT) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_POINT=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\points.obj" : $(SOURCE) $(DEP_CPP_POINT) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_POINT=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\points.obj" : $(SOURCE) $(DEP_CPP_POINT) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_z.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_Z=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_z.obj" : $(SOURCE) $(DEP_CPP_WIN_Z) "$(INTDIR)" + +"$(INTDIR)\win_z.sbr" : $(SOURCE) $(DEP_CPP_WIN_Z) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_Z=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_z.obj" : $(SOURCE) $(DEP_CPP_WIN_Z) "$(INTDIR)" + +"$(INTDIR)\win_z.sbr" : $(SOURCE) $(DEP_CPP_WIN_Z) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_Z=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_z.obj" : $(SOURCE) $(DEP_CPP_WIN_Z) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_Z=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_z.obj" : $(SOURCE) $(DEP_CPP_WIN_Z) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\z.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_Z_C26=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\z.obj" : $(SOURCE) $(DEP_CPP_Z_C26) "$(INTDIR)" + +"$(INTDIR)\z.sbr" : $(SOURCE) $(DEP_CPP_Z_C26) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_Z_C26=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\z.obj" : $(SOURCE) $(DEP_CPP_Z_C26) "$(INTDIR)" + +"$(INTDIR)\z.sbr" : $(SOURCE) $(DEP_CPP_Z_C26) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_Z_C26=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\z.obj" : $(SOURCE) $(DEP_CPP_Z_C26) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_Z_C26=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\z.obj" : $(SOURCE) $(DEP_CPP_Z_C26) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\z.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\drag.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_DRAG_=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\drag.obj" : $(SOURCE) $(DEP_CPP_DRAG_) "$(INTDIR)" + +"$(INTDIR)\drag.sbr" : $(SOURCE) $(DEP_CPP_DRAG_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_DRAG_=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\drag.obj" : $(SOURCE) $(DEP_CPP_DRAG_) "$(INTDIR)" + +"$(INTDIR)\drag.sbr" : $(SOURCE) $(DEP_CPP_DRAG_) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_DRAG_=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\drag.obj" : $(SOURCE) $(DEP_CPP_DRAG_) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_DRAG_=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\drag.obj" : $(SOURCE) $(DEP_CPP_DRAG_) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_main.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_M=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\entityw.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_main.obj" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + +"$(INTDIR)\win_main.sbr" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_M=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\entityw.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_main.obj" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + +"$(INTDIR)\win_main.sbr" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_M=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_main.obj" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_M=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_main.obj" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\csg.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_CSG_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\csg.obj" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + +"$(INTDIR)\csg.sbr" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_CSG_C=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\csg.obj" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + +"$(INTDIR)\csg.sbr" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_CSG_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\csg.obj" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_CSG_C=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\csg.obj" : $(SOURCE) $(DEP_CPP_CSG_C) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\vertsel.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_VERTS=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\vertsel.obj" : $(SOURCE) $(DEP_CPP_VERTS) "$(INTDIR)" + +"$(INTDIR)\vertsel.sbr" : $(SOURCE) $(DEP_CPP_VERTS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_VERTS=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\vertsel.obj" : $(SOURCE) $(DEP_CPP_VERTS) "$(INTDIR)" + +"$(INTDIR)\vertsel.sbr" : $(SOURCE) $(DEP_CPP_VERTS) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_VERTS=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\vertsel.obj" : $(SOURCE) $(DEP_CPP_VERTS) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_VERTS=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\vertsel.obj" : $(SOURCE) $(DEP_CPP_VERTS) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\mru.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_MRU_C=\ + ".\mru.h"\ + + +"$(INTDIR)\mru.obj" : $(SOURCE) $(DEP_CPP_MRU_C) "$(INTDIR)" + +"$(INTDIR)\mru.sbr" : $(SOURCE) $(DEP_CPP_MRU_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_MRU_C=\ + ".\mru.h"\ + + +"$(INTDIR)\mru.obj" : $(SOURCE) $(DEP_CPP_MRU_C) "$(INTDIR)" + +"$(INTDIR)\mru.sbr" : $(SOURCE) $(DEP_CPP_MRU_C) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_MRU_C=\ + ".\mru.h"\ + + +"$(INTDIR)\mru.obj" : $(SOURCE) $(DEP_CPP_MRU_C) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_MRU_C=\ + ".\mru.h"\ + + +"$(INTDIR)\mru.obj" : $(SOURCE) $(DEP_CPP_MRU_C) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_ent.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_WIN_E=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\entityw.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_ent.obj" : $(SOURCE) $(DEP_CPP_WIN_E) "$(INTDIR)" + +"$(INTDIR)\win_ent.sbr" : $(SOURCE) $(DEP_CPP_WIN_E) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_WIN_E=\ + ".\brush.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\entityw.h"\ + ".\glingr.h"\ + ".\lbmlib.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\mru.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\qedefs.h"\ + ".\qfiles.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_ent.obj" : $(SOURCE) $(DEP_CPP_WIN_E) "$(INTDIR)" + +"$(INTDIR)\win_ent.sbr" : $(SOURCE) $(DEP_CPP_WIN_E) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +DEP_CPP_WIN_E=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\entityw.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_ent.obj" : $(SOURCE) $(DEP_CPP_WIN_E) "$(INTDIR)" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +DEP_CPP_WIN_E=\ + ".\brush.h"\ + ".\bspfile.h"\ + ".\camera.h"\ + ".\cmdlib.h"\ + ".\entity.h"\ + ".\entityw.h"\ + ".\gl\GL.H"\ + ".\gl\GLAUX.H"\ + ".\gl\GLU.H"\ + ".\glingr.h"\ + ".\map.h"\ + ".\mathlib.h"\ + ".\parse.h"\ + ".\qe3.h"\ + ".\select.h"\ + ".\textures.h"\ + ".\xy.h"\ + ".\z.h"\ + + +"$(INTDIR)\win_ent.obj" : $(SOURCE) $(DEP_CPP_WIN_E) "$(INTDIR)" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\lbmlib.c + +!IF "$(CFG)" == "qe3 - Win32 Release" + +DEP_CPP_LBMLI=\ + ".\cmdlib.h"\ + ".\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + +"$(INTDIR)\lbmlib.sbr" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +DEP_CPP_LBMLI=\ + ".\cmdlib.h"\ + ".\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + +"$(INTDIR)\lbmlib.sbr" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\qfiles.h + +!IF "$(CFG)" == "qe3 - Win32 Release" + +!ELSEIF "$(CFG)" == "qe3 - Win32 Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Debug" + +!ELSEIF "$(CFG)" == "qe3 - Win32 (ALPHA) Release" + +!ENDIF + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/tools/quake2/extra/qe4/qedefs.h b/tools/quake2/extra/qe4/qedefs.h new file mode 100644 index 00000000..041aaab6 --- /dev/null +++ b/tools/quake2/extra/qe4/qedefs.h @@ -0,0 +1,117 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#ifndef __QEDEFS_H__ +#define __QEDEFS_H__ + +#define QE_VERSION 0x0401 + +#define QE3_STYLE (WS_OVERLAPPED| WS_CAPTION | WS_THICKFRAME | \ + /* WS_MINIMIZEBOX | */ WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | \ + WS_CLIPCHILDREN | WS_CHILD) + +#define QE_AUTOSAVE_INTERVAL 5 // number of minutes between autosaves + +#define CAMERA_WINDOW_CLASS "QCamera" +#define XY_WINDOW_CLASS "QXY" +#define Z_WINDOW_CLASS "QZ" +#define ENT_WINDOW_CLASS "QENT" + +#define ZWIN_WIDTH 40 +#define CWIN_SIZE (0.4) + +#define MAX_EDGES 256 +#define MAX_POINTS 512 + +#define CMD_TEXTUREWAD 60000 +#define CMD_BSPCOMMAND 61000 + +#define PITCH 0 +#define YAW 1 +#define ROLL 2 + +#define QE_TIMER0 1 + +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +#define ON_EPSILON 0.01 + +#define KEY_FORWARD 1 +#define KEY_BACK 2 +#define KEY_TURNLEFT 4 +#define KEY_TURNRIGHT 8 +#define KEY_LEFT 16 +#define KEY_RIGHT 32 +#define KEY_LOOKUP 64 +#define KEY_LOOKDOWN 128 +#define KEY_UP 256 +#define KEY_DOWN 512 + +// xy.c +#define EXCLUDE_LIGHTS 1 +#define EXCLUDE_ENT 2 +#define EXCLUDE_PATHS 4 +#define EXCLUDE_WATER 8 +#define EXCLUDE_WORLD 16 +#define EXCLUDE_CLIP 32 +#define EXCLUDE_DETAIL 64 + + +// +// menu indexes for modifying menus +// +#define MENU_VIEW 2 +#define MENU_BSP 4 +#define MENU_TEXTURE 6 + + +// odd things not in windows header... +#define VK_COMMA 188 +#define VK_PERIOD 190 + +/* +** window bits +*/ +#define W_CAMERA 0x0001 +#define W_XY 0x0002 +#define W_XY_OVERLAY 0x0004 +#define W_Z 0x0008 +#define W_TEXTURE 0x0010 +#define W_Z_OVERLAY 0x0020 +#define W_CONSOLE 0x0040 +#define W_ENTITY 0x0080 +#define W_ALL 0xFFFFFFFF + +#define COLOR_TEXTUREBACK 0 +#define COLOR_GRIDBACK 1 +#define COLOR_GRIDMINOR 2 +#define COLOR_GRIDMAJOR 3 +#define COLOR_CAMERABACK 4 +#define COLOR_ENTITY 5 +#define COLOR_LAST 6 + +#endif diff --git a/tools/quake2/extra/qe4/qfiles.h b/tools/quake2/extra/qe4/qfiles.h new file mode 100644 index 00000000..e7dbbdfe --- /dev/null +++ b/tools/quake2/extra/qe4/qfiles.h @@ -0,0 +1,389 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// +// qfiles.h: quake file formats +// This file must be identical in the quake and utils directories +// + +/* +======================================================================== + +.MD2 triangle model file format + +======================================================================== +*/ + +#define IDALIASHEADER (('2'<<24)+('P'<<16)+('D'<<8)+'I') +#define ALIAS_VERSION 8 + +#define MAX_TRIANGLES 4096 +#define MAX_VERTS 2048 +#define MAX_FRAMES 512 +#define MAX_MD2SKINS 32 +#define MAX_SKINNAME 64 + +typedef struct +{ + short s; + short t; +} dstvert_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} dtriangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} dtrivertx_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + dtrivertx_t verts[1]; // variable sized +} daliasframe_t; + + +// the glcmd format: +// a positive integer starts a tristrip command, followed by that many +// vertex structures. +// a negative integer starts a trifan command, followed by -x vertexes +// a zero indicates the end of the command list. +// a vertex consists of a floating point s, a floating point t, +// and an integer vertex index. + + +typedef struct +{ + int ident; + int version; + + int skinwidth; + int skinheight; + int framesize; // byte size of each frame + + int num_skins; + int num_xyz; + int num_st; // greater than num_xyz for seams + int num_tris; + int num_glcmds; // dwords in strip/fan command list + int num_frames; + + int ofs_skins; // each skin is a MAX_SKINNAME string + int ofs_st; // byte offset from start for stverts + int ofs_tris; // offset for dtriangles + int ofs_frames; // offset for first frame + int ofs_glcmds; + int ofs_end; // end of file + +} dmdl_t; + +/* +======================================================================== + +.SP2 sprite file format + +======================================================================== +*/ + +#define IDSPRITEHEADER (('2'<<24)+('S'<<16)+('D'<<8)+'I') + // little-endian "IDS2" +#define SPRITE_VERSION 2 + +typedef struct +{ + int width, height; + int origin_x, origin_y; // raster coordinates inside pic + char name[MAX_SKINNAME]; // name of pcx file +} dsprframe_t; + +typedef struct { + int ident; + int version; + int numframes; + dsprframe_t frames[1]; // variable sized +} dsprite_t; + +/* +============================================================================== + + .WAL texture file format + +============================================================================== +*/ + + +#define MIPLEVELS 4 +typedef struct miptex_s +{ + char name[32]; + unsigned width, height; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + int flags; + int contents; + int value; +} miptex_t; + + + +/* +============================================================================== + + .BSP file format + +============================================================================== +*/ + +#define IDBSPHEADER (('P'<<24)+('S'<<16)+('B'<<8)+'I') + // little-endian "IBSP" + +#define BSPVERSION 36 + + +// upper design bounds +// leaffaces, leafbrushes, planes, and verts are still bounded by +// 16 bit short limits +#define MAX_MAP_MODELS 1024 +#define MAX_MAP_BRUSHES 8192 +#define MAX_MAP_ENTITIES 2048 +#define MAX_MAP_ENTSTRING 0x20000 +#define MAX_MAP_TEXINFO 8192 + +#define MAX_MAP_PLANES 65536 +#define MAX_MAP_NODES 65536 +#define MAX_MAP_BRUSHSIDES 65536 +#define MAX_MAP_LEAFS 65536 +#define MAX_MAP_VERTS 65536 +#define MAX_MAP_FACES 65536 +#define MAX_MAP_LEAFFACES 65536 +#define MAX_MAP_LEAFBRUSHES 65536 +#define MAX_MAP_PORTALS 65536 +#define MAX_MAP_EDGES 128000 +#define MAX_MAP_SURFEDGES 256000 +#define MAX_MAP_LIGHTING 0x200000 +#define MAX_MAP_VISIBILITY 0x100000 + +// key / value pair sizes + +#define MAX_KEY 32 +#define MAX_VALUE 1024 + +//============================================================================= + +typedef struct +{ + int fileofs, filelen; +} lump_t; + +#define LUMP_ENTITIES 0 +#define LUMP_PLANES 1 +#define LUMP_VERTEXES 2 +#define LUMP_VISIBILITY 3 +#define LUMP_NODES 4 +#define LUMP_TEXINFO 5 +#define LUMP_FACES 6 +#define LUMP_LIGHTING 7 +#define LUMP_LEAFS 8 +#define LUMP_LEAFFACES 9 +#define LUMP_LEAFBRUSHES 10 +#define LUMP_EDGES 11 +#define LUMP_SURFEDGES 12 +#define LUMP_MODELS 13 +#define LUMP_BRUSHES 14 +#define LUMP_BRUSHSIDES 15 +#define LUMP_POP 16 + +#define HEADER_LUMPS 17 + +typedef struct +{ + int ident; + int version; + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct +{ + float mins[3], maxs[3]; + float origin[3]; // for sounds or lights + int headnode; + int firstface, numfaces; // submodels just draw faces + // without walking the bsp tree +} dmodel_t; + + +typedef struct +{ + float point[3]; +} dvertex_t; + + +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 + +// 3-5 are non-axial planes snapped to the nearest +#define PLANE_ANYX 3 +#define PLANE_ANYY 4 +#define PLANE_ANYZ 5 + +// planes (x&~1) and (x&~1)+1 are allways opposites + +typedef struct +{ + float normal[3]; + float dist; + int type; // PLANE_X - PLANE_ANYZ ?remove? trivial to regenerate +} dplane_t; + + +// contents flags are seperate bits +// a given brush can contribute multiple content bits +// multiple brushes can be in a single leaf + +// lower bits are stronger, and will eat weaker brushes completely +#define CONTENTS_SOLID 1 // an eye is never valid in a solid +#define CONTENTS_WINDOW 2 // translucent, but not watery +#define CONTENTS_AUX 4 +#define CONTENTS_LAVA 8 +#define CONTENTS_SLIME 16 +#define CONTENTS_WATER 32 +#define CONTENTS_MIST 64 +#define LAST_VISIBLE_CONTENTS 64 + +// remaining contents are non-visible, and don't eat brushes +#define CONTENTS_PLAYERCLIP 0x10000 +#define CONTENTS_MONSTERCLIP 0x20000 + +// currents can be added to any other contents, and may be mixed +#define CONTENTS_CURRENT_0 0x40000 +#define CONTENTS_CURRENT_90 0x80000 +#define CONTENTS_CURRENT_180 0x100000 +#define CONTENTS_CURRENT_270 0x200000 +#define CONTENTS_CURRENT_UP 0x400000 +#define CONTENTS_CURRENT_DOWN 0x800000 + +#define CONTENTS_ORIGIN 0x1000000 // removed before bsping an entity + +#define CONTENTS_MONSTER 0x2000000 // should never be on a brush, only in game +#define CONTENTS_DEADMONSTER 0x4000000 +#define CONTENTS_DETAIL 0x8000000 // brushes to be added after vis leafs +#define CONTENTS_TRANSLUCENT 0x10000000 // auto set if any surface has trans + + + +typedef struct +{ + int planenum; + int children[2]; // negative numbers are -(leafs+1), not nodes + short mins[3]; // for frustom culling + short maxs[3]; + unsigned short firstface; + unsigned short numfaces; // counting both sides +} dnode_t; + + +typedef struct texinfo_s +{ + float vecs[2][4]; // [s/t][xyz offset] + int flags; // miptex flags + overrides + int value; // light emission, etc + char texture[32]; // texture name (textures/*.wal) + int nexttexinfo; // for animations, -1 = end of chain +} texinfo_t; + + +#define SURF_LIGHT 0x1 // value will hold the light strength + +#define SURF_SLICK 0x2 // effects game physics + +#define SURF_SKY 0x4 // don't draw, but add to skybox +#define SURF_WARP 0x8 // turbulent water warp +#define SURF_TRANS33 0x10 +#define SURF_TRANS66 0x20 +#define SURF_FLOWING 0x40 // scroll towards angle +#define SURF_NODRAW 0x80 // don't bother referencing the texture + + +// note that edge 0 is never used, because negative edge nums are used for +// counterclockwise use of the edge in a face +typedef struct +{ + unsigned short v[2]; // vertex numbers +} dedge_t; + +#define MAXLIGHTMAPS 4 +typedef struct +{ + unsigned short planenum; + short side; + + int firstedge; // we must support > 64k edges + short numedges; + short texinfo; + +// lighting info + byte styles[MAXLIGHTMAPS]; + int lightofs; // start of [numstyles*surfsize] samples +} dface_t; + +typedef struct +{ + int contents; // OR of all brushes (not needed?) + + int pvsofs; // -1 = no info + int phsofs; // -1 = no info + + short mins[3]; // for frustum culling + short maxs[3]; + + unsigned short firstleafface; + unsigned short numleaffaces; + + unsigned short firstleafbrush; + unsigned short numleafbrushes; +} dleaf_t; + +typedef struct +{ + unsigned short planenum; // facing out of the leaf + short texinfo; +} dbrushside_t; + +typedef struct +{ + int firstside; + int numsides; + int contents; +} dbrush_t; + +#define ANGLE_UP -1 +#define ANGLE_DOWN -2 + diff --git a/tools/quake2/extra/qe4/resource.h b/tools/quake2/extra/qe4/resource.h new file mode 100644 index 00000000..0a65eca2 --- /dev/null +++ b/tools/quake2/extra/qe4/resource.h @@ -0,0 +1,308 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by win_qe3.rc +// +#define IDAPPLY 3 +#define IDR_MENU1 101 +#define IDR_ACCELERATOR1 104 +#define IDD_CREATE_ENTITY 107 +#define IDD_EDIT_ENTITY 108 +#define IDR_TOOLBAR1 109 +#define IDD_FINDTEXTURE 111 +#define IDD_ENTITY 115 +#define IDR_E_MENU 116 +#define IDD_EDITPROP 117 +#define IDD_GAMMA 118 +#define IDD_FINDBRUSH 119 +#define IDI_ICON1 120 +#define IDD_ROTATE 121 +#define IDD_SIDES 122 +#define IDD_ABOUT 123 +#define IDB_BITMAP1 127 +#define IDD_SURFACE 129 +#define IDC_ENTITY_COMMENT 1018 +#define IDC_VALUE 1021 +#define IDC_KEY 1022 +#define IDC_ENTITY_LIST 1023 +#define IDC_PAIRS 1024 +#define IDC_CHECK1 1026 +#define IDC_CHECK2 1027 +#define IDC_CHECK3 1028 +#define IDC_CHECK4 1029 +#define IDC_CHECK5 1030 +#define IDC_CHECK6 1031 +#define IDC_CHECK7 1032 +#define IDC_CHECK8 1033 +#define IDC_CHECK9 1034 +#define IDC_CHECK10 1035 +#define IDC_CHECK11 1036 +#define IDC_CHECK12 1037 +#define IDC_ANGLE90 1038 +#define IDC_CHECK13 1038 +#define IDC_ANGLE45 1039 +#define IDC_CHECK14 1039 +#define IDC_ANGLE135 1040 +#define IDC_CHECK15 1040 +#define IDC_ANGLE225 1041 +#define IDC_CHECK16 1041 +#define IDC_ANGLEUP 1042 +#define IDC_CHECK17 1042 +#define IDC_ANGLE180 1043 +#define IDC_CHECK18 1043 +#define IDC_ANGLE315 1044 +#define IDC_CHECK19 1044 +#define IDC_ANGLE0 1045 +#define IDC_CHECK20 1045 +#define IDC_ANGLE270 1046 +#define IDC_CHECK21 1046 +#define IDC_ANGLEDOWN 1047 +#define IDC_CHECK22 1047 +#define IDC_DELETEKEY 1048 +#define IDC_ADDPAIR 1048 +#define IDC_CHECK23 1048 +#define IDC_DELETEPAIR 1049 +#define IDC_CHECK24 1049 +#define IDC_CHECK25 1050 +#define IDC_SPAWN1 1051 +#define IDC_CHECK26 1051 +#define IDC_SPAWN2 1052 +#define IDC_CHECK27 1052 +#define IDC_SPAWN3 1053 +#define IDC_CHECK28 1053 +#define IDC_SPAWN4 1054 +#define IDC_CHECK29 1054 +#define IDC_SPAWN5 1055 +#define IDC_CHECK30 1055 +#define IDC_SPAWN6 1056 +#define IDC_CHECK31 1056 +#define IDC_SPAWN7 1057 +#define IDC_CHECK32 1057 +#define IDC_SPAWN8 1058 +#define IDC_CHECK33 1058 +#define IDC_EDIT1 1059 +#define IDC_CHECK34 1059 +#define IDC_ROTATE_BOX 1060 +#define IDC_ROTZ 1060 +#define IDC_CHECK35 1060 +#define IDC_SCALE_BOX 1061 +#define IDC_ROTY 1061 +#define IDC_CHECK36 1061 +#define IDC_E_VALUE_FIELD 1062 +#define IDC_CHECK37 1062 +#define IDC_CHECK38 1063 +#define IDC_E_LIST 1064 +#define IDC_CHECK39 1064 +#define IDC_E_COMMENT 1065 +#define IDC_CHECK40 1065 +#define IDC_CHECK41 1066 +#define IDC_E_PROPS 1067 +#define IDC_CHECK42 1067 +#define IDC_E_135 1068 +#define IDC_CHECK43 1068 +#define IDC_E_180 1069 +#define IDC_CHECK44 1069 +#define IDC_E_225 1070 +#define IDC_CHECK45 1070 +#define IDC_E_270 1071 +#define IDC_CHECK46 1071 +#define IDC_E_90 1072 +#define IDC_CHECK47 1072 +#define IDC_E_45 1073 +#define IDC_CHECK48 1073 +#define IDC_E_0 1074 +#define IDC_CHECK49 1074 +#define IDC_E_315 1075 +#define IDC_CHECK50 1075 +#define IDC_E_UP 1076 +#define IDC_CHECK51 1076 +#define IDC_E_DOWN 1077 +#define IDC_CHECK52 1077 +#define IDC_CHECK53 1078 +#define IDC_CHECK54 1079 +#define IDC_E_ADDPROP 1080 +#define IDC_CHECK55 1080 +#define IDC_E_DELPROP 1081 +#define IDC_CHECK56 1081 +#define IDC_E_CREATE 1082 +#define IDC_CHECK57 1082 +#define IDC_E_STATUS 1083 +#define IDC_CHECK58 1083 +#define IDC_CHECK59 1084 +#define IDC_CHECK60 1085 +#define IDC_CHECK61 1086 +#define IDC_CHECK62 1087 +#define IDC_CHECK63 1088 +#define IDC_CHECK64 1089 +#define IDC_SHIFT_BOX 1090 +#define IDC_HSHIFT 1090 +#define IDC_VSHIFT 1091 +#define IDC_ROTATEV 1092 +#define IDC_SCALEV 1093 +#define IDC_SCALEH 1094 +#define IDC_SHIFTV 1095 +#define IDC_HSHIFTA 1095 +#define IDC_SHIFTH 1096 +#define IDC_VSHIFTA 1097 +#define IDC_HSCALE 1098 +#define IDC_HSCALEA 1099 +#define IDC_VSCALE 1100 +#define IDC_VSCALEA 1101 +#define IDC_ROTATE 1102 +#define IDC_G_EDIT 1103 +#define IDC_ROTATEA 1103 +#define IDC_STATIC_KEY 1104 +#define IDC_FIND_BRUSH 1104 +#define IDC_STATIC_VALUE 1105 +#define IDC_E_KEY_FIELD 1106 +#define IDC_FIND_ENTITY 1107 +#define IDC_SIDES 1108 +#define IDC_ROTX 1109 +#define IDC_E_COLOR 1111 +#define IDC_ABOUT_GLVENDOR 1112 +#define IDC_ABOUT_GLVERSION 1113 +#define IDC_ABOUT_GLRENDERER 1114 +#define IDC_TEXTURE 1114 +#define IDC_ABOUT_GLEXTENSIONS 1115 +#define ID_FILE_EXIT 40002 +#define ID_FILE_SAVEAS 40004 +#define ID_VIEW_CENTER 40005 +#define ID_VIEW_UPFLOOR 40006 +#define ID_VIEW_DOWNFLOOR 40007 +#define ID_BRUSH_FLIPX 40008 +#define ID_BRUSH_FLIPY 40009 +#define ID_BRUSH_FLIPZ 40010 +#define ID_BRUSH_ROTATEX 40011 +#define ID_BRUSH_ROTATEY 40012 +#define ID_BRUSH_ROTATEZ 40013 +#define ID_BSP_FULLVIS 40016 +#define ID_BSP_FASTVIS 40017 +#define ID_BSP_NOVIS 40018 +#define ID_BSP_RELIGHT 40019 +#define ID_BSP_ENTITIES 40020 +#define ID_FILE_POINTFILE 40021 +#define ID_VIEW_100 40022 +#define ID_VIEW_75 40023 +#define ID_VIEW_50 40024 +#define ID_VIEW_25 40025 +#define ID_VIEW_12 40026 +#define ID_GRID_1 40028 +#define ID_GRID_2 40029 +#define ID_GRID_4 40030 +#define ID_GRID_8 40031 +#define ID_GRID_16 40032 +#define ID_TEXTURES_SHOWALL 40033 +#define ID_TEXTURES_SHOWINUSE 40034 +#define ID_TEXTURES_TOGGLEVIEW 40037 +#define ID_SELECTION_CREATEENTITY 40039 +#define ID_SELECTION_EDITENTITY 40040 +#define ID_MISC_BENCHMARK 40041 +#define ID_REGION_OFF 40043 +#define ID_REGION_SETXY 40044 +#define ID_REGION_SETBRUSH 40045 +#define ID_SELECTION_MAKEHOLLOW 40046 +#define ID_SELECTION_SELECTPARTIALTALL 40047 +#define ID_SELECTION_SELECTCOMPLETETALL 40048 +#define ID_SELECTION_CSGSUBTRACT 40049 +#define ID_SELECTION_SELECTTOUCHING 40050 +#define ID_VIEW_NEAREST 40052 +#define ID_VIEW_LINEAR 40053 +#define ID_VIEW_BILINEAR 40054 +#define ID_VIEW_TRILINEAR 40055 +#define ID_VIEW_NEARESTMIPMAP 40056 +#define ID_VIEW_BILINEARMIPMAP 40057 +#define ID_VIEW_SHOWNAMES 40058 +#define ID_VIEW_ZOOMIN 40059 +#define ID_VIEW_ZOOMOUT 40060 +#define ID_VIEW_SHOWCOORDINATES 40061 +#define ID_VIEW_Z100 40062 +#define ID_VIEW_ZZOOMIN 40063 +#define ID_VIEW_ZZOOMOUT 40064 +#define ID_SELECTION_CLONE 40065 +#define ID_SELECTION_DESELECT 40066 +#define ID_SELECTION_DELETE 40067 +#define ID_BUTTON40068 40068 +#define ID_TEXTURES_WIREFRAME 40072 +#define ID_TEXTURES_FLATSHADE 40073 +#define ID_SELECTION_DRAGVERTECIES 40074 +#define ID_SELECTION_DRAGEDGES 40075 +#define ID_REGION_SETTALLBRUSH 40076 +#define ID_SELECTION_SELECTINSIDE 40092 +#define ID_PROJECT_RELEAD 40094 +#define ID_PROJECT_CHANGE 40095 +#define ID_MISC_GAMMA 40097 +#define ID_VIEW_SHOWENT 40098 +#define ID_VIEW_SHOWPATH 40099 +#define ID_VIEW_SHOWLIGHTS 40100 +#define ID_VIEW_SHOWCLIP 40101 +#define ID_VIEW_SHOWWATER 40102 +#define ID_VIEW_SHOWWORLD 40103 +#define ID_MISC_TEXTUREBACKGROUN 40104 +#define ID_TEXTUREBK 40105 +#define ID_COLORS_XYBK 40106 +#define ID_FILE_ABOUT 40107 +#define ID_VIEW_CONSOLE 40108 +#define ID_VIEW_ENTITY 40109 +#define ID_VIEW_TEXTURE 40110 +#define ID_COLORS_MAJOR 40111 +#define ID_COLORS_MINOR 40113 +#define ID_SELECTION_CONNECT 40114 +#define ID_FILE_LOADPROJECT 40115 +#define ID_MISC_FINDBRUSH 40116 +#define ID_MISC_NEXTLEAKSPOT 40117 +#define ID_MISC_PREVIOUSLEAKSPOT 40118 +#define ID_BRUSH_3SIDED 40119 +#define ID_BRUSH_4SIDED 40120 +#define ID_BRUSH_5SIDED 40121 +#define ID_BRUSH_6SIDED 40122 +#define ID_BRUSH_7SIDED 40123 +#define ID_BRUSH_8SIDED 40124 +#define ID_BRUSH_9SIDED 40125 +#define ID_SELECTION_ARBITRARYROTATION 40126 +#define ID_BRUSH_ARBITRARYSIDED 40127 +#define ID_GRID_32 40128 +#define ID_GRID_64 40129 +#define ID_SELECTION_UNGROUPENTITY 40130 +#define ID_MISC_SELECTENTITYCOLOR 40131 +#define ID_MISC_PRINTXY 40132 +#define ID_HELP_ABOUT 40134 +#define ID_EDIT_COPYBRUSH 40135 +#define ID_EDIT_PASTEBRUSH 40136 +#define ID_TEXTURES_INSPECTOR 40137 +#define ID_VIEW_SHOWDETAIL 40138 +#define ID_SELECTION_MAKE_DETAIL 40139 +#define ID_SELECTION_MAKE_STRUCTURAL 40140 +#define ID_REGION_SETSELECTION 40142 +#define ID_VIEW_SHOWBLOCKS 40143 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 130 +#define _APS_NEXT_COMMAND_VALUE 40144 +#define _APS_NEXT_CONTROL_VALUE 1115 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/tools/quake2/extra/qe4/select.c b/tools/quake2/extra/qe4/select.c new file mode 100644 index 00000000..2761ecb3 --- /dev/null +++ b/tools/quake2/extra/qe4/select.c @@ -0,0 +1,706 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// select.c + +#include "qe3.h" + +/* +=========== +Test_Ray +=========== +*/ +#define DIST_START 999999 +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags) +{ + brush_t *brush; + face_t *face; + float dist; + trace_t t; + + memset (&t, 0, sizeof(t)); + t.dist = DIST_START; + + if (! (flags & SF_SELECTED_ONLY) ) + for (brush = active_brushes.next ; brush != &active_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) + continue; + if (FilterBrush (brush)) + continue; + face = Brush_Ray (origin, dir, brush, &dist); + if (dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = false; + } + } + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( (flags & SF_ENTITIES_FIRST) && brush->owner == world_entity) + continue; + if (FilterBrush (brush)) + continue; + face = Brush_Ray (origin, dir, brush, &dist); + if (dist > 0 && dist < t.dist) + { + t.dist = dist; + t.brush = brush; + t.face = face; + t.selected = true; + } + } + + // if entites first, but didn't find any, check regular + + if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) + return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST); + + return t; +} + + +/* +============ +Select_Brush + +============ +*/ +void Select_Brush (brush_t *brush) +{ + brush_t *b; + entity_t *e; + + selected_face = NULL; + if (g_qeglobals.d_select_count < 2) + g_qeglobals.d_select_order[g_qeglobals.d_select_count] = brush; + g_qeglobals.d_select_count++; + + e = brush->owner; + if (e) + { + // select complete entity on first click + if (e != world_entity) + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (b->owner == e) + goto singleselect; + for (b=e->brushes.onext ; b != &e->brushes ; b=b->onext) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + else + { +singleselect: + Brush_RemoveFromList (brush); + Brush_AddToList (brush, &selected_brushes); + } + + if (e->eclass) + { + UpdateEntitySel(brush->owner->eclass); + } + } +} + +/* +============ +Select_Ray + +If the origin is inside a brush, that brush will be ignored. +============ +*/ +void Select_Ray (vec3_t origin, vec3_t dir, int flags) +{ + trace_t t; + + t = Test_Ray (origin, dir, flags); + if (!t.brush) + return; + + if (flags == SF_SINGLEFACE) + { + selected_face = t.face; + selected_face_brush = t.brush; + Sys_UpdateWindows (W_ALL); + g_qeglobals.d_select_mode = sel_brush; + return; + } + + // move the brush to the other list + + g_qeglobals.d_select_mode = sel_brush; + + if (t.selected) + { + Brush_RemoveFromList (t.brush); + Brush_AddToList (t.brush, &active_brushes); + } else + { + Select_Brush (t.brush); + } + + Sys_UpdateWindows (W_ALL); +} + + +void Select_Delete (void) +{ + brush_t *brush; + + selected_face = NULL; + g_qeglobals.d_select_mode = sel_brush; + + g_qeglobals.d_select_count = 0; + g_qeglobals.d_num_move_points = 0; + while (selected_brushes.next != &selected_brushes) + { + brush = selected_brushes.next; + Brush_Free (brush); + } + + // FIXME: remove any entities with no brushes + + Sys_UpdateWindows (W_ALL); +} + +void Select_Deselect (void) +{ + brush_t *b; + + g_qeglobals.d_workcount++; + g_qeglobals.d_select_count = 0; + g_qeglobals.d_num_move_points = 0; + b = selected_brushes.next; + + if (b == &selected_brushes) + { + if (selected_face) + { + selected_face = NULL; + Sys_UpdateWindows (W_ALL); + } + return; + } + + selected_face = NULL; + g_qeglobals.d_select_mode = sel_brush; + + // grab top / bottom height for new brushes + if (b->mins[2] < b->maxs[2]) + { + g_qeglobals.d_new_brush_bottom_z = b->mins[2]; + g_qeglobals.d_new_brush_top_z = b->maxs[2]; + } + + selected_brushes.next->prev = &active_brushes; + selected_brushes.prev->next = active_brushes.next; + active_brushes.next->prev = selected_brushes.prev; + active_brushes.next = selected_brushes.next; + selected_brushes.prev = selected_brushes.next = &selected_brushes; + + Sys_UpdateWindows (W_ALL); +} + +/* +============ +Select_Move +============ +*/ +void Select_Move (vec3_t delta) +{ + brush_t *b; + +// actually move the selected brushes + for (b = selected_brushes.next ; b != &selected_brushes ; b=b->next) + Brush_Move (b, delta); +// Sys_UpdateWindows (W_ALL); +} + +/* +============ +Select_Clone + +Creates an exact duplicate of the selection in place, then moves +the selected brushes off of their old positions +============ +*/ +void Select_Clone (void) +{ + brush_t *b, *b2, *n, *next, *next2; + vec3_t delta; + entity_t *e; + + g_qeglobals.d_workcount++; + g_qeglobals.d_select_mode = sel_brush; + + delta[0] = g_qeglobals.d_gridsize; + delta[1] = g_qeglobals.d_gridsize; + delta[2] = 0; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=next) + { + next = b->next; + // if the brush is a world brush, handle simply + if (b->owner == world_entity) + { + n = Brush_Clone (b); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (world_entity, n); + Brush_Build( n ); + Brush_Move (b, delta); + continue; + } + + e = Entity_Clone (b->owner); + // clear the target / targetname + DeleteKey (e, "target"); + DeleteKey (e, "targetname"); + + // if the brush is a fixed size entity, create a new entity + if (b->owner->eclass->fixedsize) + { + n = Brush_Clone (b); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (e, n); + Brush_Build( n ); + Brush_Move (b, delta); + continue; + } + + // brush is a complex entity, grab all the other ones now + + next = &selected_brushes; + + for ( b2 = b ; b2 != &selected_brushes ; b2=next2) + { + next2 = b2->next; + if (b2->owner != b->owner) + { + if (next == &selected_brushes) + next = b2; + continue; + } + + // move b2 to the start of selected_brushes, + // so it won't be hit again + Brush_RemoveFromList (b2); + Brush_AddToList (b2, &selected_brushes); + + n = Brush_Clone (b2); + Brush_AddToList (n, &active_brushes); + Entity_LinkBrush (e, n); + Brush_Build( n ); + Brush_Move (b2, delta); + } + + } + Sys_UpdateWindows (W_ALL); +} + + + +/* +============ +Select_SetTexture +============ +*/ +void Select_SetTexture (texdef_t *texdef) +{ + brush_t *b; + + if (selected_face) + { + selected_face->texdef = *texdef; + Brush_Build(selected_face_brush); + } + else + { + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + if (!b->owner->eclass->fixedsize) + Brush_SetTexture (b, texdef); + } + Sys_UpdateWindows (W_ALL); +} + + +/* +================================================================ + + TRANSFORMATIONS + +================================================================ +*/ + +void Select_GetBounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + + for (i=0 ; i<3 ; i++) + { + mins[i] = 99999; + maxs[i] = -99999; + } + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] < mins[i]) + mins[i] = b->mins[i]; + if (b->maxs[i] > maxs[i]) + maxs[i] = b->maxs[i]; + } +} + +void Select_GetMid (vec3_t mid) +{ + vec3_t mins, maxs; + int i; + + Select_GetBounds (mins, maxs); + for (i=0 ; i<3 ; i++) + mid[i] = g_qeglobals.d_gridsize*floor ( ( (mins[i] + maxs[i])*0.5 )/g_qeglobals.d_gridsize ); +} + +vec3_t select_origin; +vec3_t select_matrix[3]; +qboolean select_fliporder; + +void Select_AplyMatrix (void) +{ + brush_t *b; + face_t *f; + int i, j; + vec3_t temp; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + { + for (f=b->brush_faces ; f ; f=f->next) + { + for (i=0 ; i<3 ; i++) + { + VectorSubtract (f->planepts[i], select_origin, temp); + for (j=0 ; j<3 ; j++) + f->planepts[i][j] = DotProduct(temp, select_matrix[j]) + + select_origin[j]; + } + if (select_fliporder) + { + VectorCopy (f->planepts[0], temp); + VectorCopy (f->planepts[2], f->planepts[0]); + VectorCopy (temp, f->planepts[2]); + } + } + Brush_Build( b ); + } + Sys_UpdateWindows (W_ALL); +} + + +void Select_FlipAxis (int axis) +{ + int i; + + Select_GetMid (select_origin); + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + select_matrix[axis][axis] = -1; + + select_fliporder = true; + Select_AplyMatrix (); +} + +void Select_RotateAxis (int axis, float deg) +{ + vec3_t temp; + int i, j; + vec_t c, s; + + if (deg == 0) + return; + + Select_GetMid (select_origin); + select_fliporder = false; + + if (deg == 90) + { + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + i = (axis+1)%3; + j = (axis+2)%3; + VectorCopy (select_matrix[i], temp); + VectorCopy (select_matrix[j], select_matrix[i]); + VectorSubtract (vec3_origin, temp, select_matrix[j]); + } + else + { + deg = -deg; + if (deg == -180) + { + c = -1; + s = 0; + } + else if (deg == -270) + { + c = 0; + s = -1; + } + else + { + c = cos(deg/180*3.14159); + s = sin (deg/180*3.14159); + } + + for (i=0 ; i<3 ; i++) + { + VectorCopy (vec3_origin, select_matrix[i]); + select_matrix[i][i] = 1; + } + + switch (axis) + { + case 0: + select_matrix[1][1] = c; + select_matrix[1][2] = -s; + select_matrix[2][1] = s; + select_matrix[2][2] = c; + break; + case 1: + select_matrix[0][0] = c; + select_matrix[0][2] = s; + select_matrix[2][0] = -s; + select_matrix[2][2] = c; + break; + case 2: + select_matrix[0][0] = c; + select_matrix[0][1] = -s; + select_matrix[1][0] = s; + select_matrix[1][1] = c; + break; + } + } + + Select_AplyMatrix (); +} + +/* +================================================================ + +GROUP SELECTIONS + +================================================================ +*/ + +void Select_CompleteTall (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<2 ; i++) + if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) + break; + if (i == 2) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + Sys_UpdateWindows (W_ALL); +} + +void Select_PartialTall (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<2 ; i++) + if (b->mins[i] > maxs[i] || b->maxs[i] < mins[i]) + break; + if (i == 2) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + Sys_UpdateWindows (W_ALL); +} + +void Select_Touching (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<3 ; i++) + if (b->mins[i] > maxs[i]+1 || b->maxs[i] < mins[i]-1) + break; + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + Sys_UpdateWindows (W_ALL); +} + +void Select_Inside (void) +{ + brush_t *b, *next; + int i; + vec3_t mins, maxs; + + if (!QE_SingleBrush ()) + return; + + g_qeglobals.d_select_mode = sel_brush; + + VectorCopy (selected_brushes.next->mins, mins); + VectorCopy (selected_brushes.next->maxs, maxs); + Select_Delete (); + + for (b=active_brushes.next ; b != &active_brushes ; b=next) + { + next = b->next; + for (i=0 ; i<3 ; i++) + if (b->maxs[i] > maxs[i] || b->mins[i] < mins[i]) + break; + if (i == 3) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + } + } + Sys_UpdateWindows (W_ALL); +} + +/* +============= +Select_Ungroup + +Turn the currently selected entity back into normal brushes +============= +*/ +void Select_Ungroup (void) +{ + entity_t *e; + brush_t *b; + + e = selected_brushes.next->owner; + + if (!e || e == world_entity || e->eclass->fixedsize) + { + Sys_Status ("Not a grouped entity.", 0); + return; + } + + for (b=e->brushes.onext ; b != &e->brushes ; b=e->brushes.onext) + { + Brush_RemoveFromList (b); + Brush_AddToList (b, &active_brushes); + Entity_UnlinkBrush (b); + Entity_LinkBrush (world_entity, b); + Brush_Build( b ); + b->owner = world_entity; + } + + Entity_Free (e); + Sys_UpdateWindows (W_ALL); +} + +/* +==================== +Select_MakeStructural +==================== +*/ +void Select_MakeStructural (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents &= ~CONTENTS_DETAIL; + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + +void Select_MakeDetail (void) +{ + brush_t *b; + face_t *f; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + f->texdef.contents |= CONTENTS_DETAIL; + Select_Deselect (); + Sys_UpdateWindows (W_ALL); +} + + diff --git a/tools/quake2/extra/qe4/select.h b/tools/quake2/extra/qe4/select.h new file mode 100644 index 00000000..003902a2 --- /dev/null +++ b/tools/quake2/extra/qe4/select.h @@ -0,0 +1,62 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +typedef enum +{ + sel_brush, + // sel_sticky_brush, + // sel_face, + sel_vertex, + sel_edge +} select_t; + +typedef struct +{ + brush_t *brush; + face_t *face; + float dist; + qboolean selected; +} trace_t; + +#define SF_SELECTED_ONLY 1 +#define SF_ENTITIES_FIRST 2 +#define SF_SINGLEFACE 4 + + +trace_t Test_Ray (vec3_t origin, vec3_t dir, int flags); + +void Select_GetBounds (vec3_t mins, vec3_t maxs); +void Select_Brush (brush_t *b); +void Select_Ray (vec3_t origin, vec3_t dir, int flags); +void Select_Delete (void); +void Select_Deselect (void); +void Select_Clone (void); +void Select_Move (vec3_t delta); +void Select_SetTexture (texdef_t *texdef); +void Select_FlipAxis (int axis); +void Select_RotateAxis (int axis, float deg); +void Select_CompleteTall (void); +void Select_PartialTall (void); +void Select_Touching (void); +void Select_Inside (void); +void Select_MakeStructural (void); +void Select_MakeDetail (void); diff --git a/tools/quake2/extra/qe4/textures.c b/tools/quake2/extra/qe4/textures.c new file mode 100644 index 00000000..21fa8ce0 --- /dev/null +++ b/tools/quake2/extra/qe4/textures.c @@ -0,0 +1,1147 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" +#include "io.h" + +#define TYP_MIPTEX 68 +static unsigned tex_palette[256]; + +static qtexture_t *notexture; + +static qboolean nomips; + +#define FONT_HEIGHT 10 + +static HGLRC s_hglrcTexture; +static HDC s_hdcTexture; + +//int texture_mode = GL_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_NEAREST; +//int texture_mode = GL_NEAREST_MIPMAP_LINEAR; +//int texture_mode = GL_LINEAR; +//int texture_mode = GL_LINEAR_MIPMAP_NEAREST; +int texture_mode = GL_LINEAR_MIPMAP_LINEAR; + +int texture_extension_number = 1; + +// current active texture directory. if empty, show textures in use +char texture_directory[32]; // use if texture_showinuse is false +qboolean texture_showinuse; + +// texture layout functions +qtexture_t *current_texture; +int current_x, current_y, current_row; + +int texture_nummenus; +#define MAX_TEXTUREDIRS 100 +char texture_menunames[MAX_TEXTUREDIRS][64]; + +qboolean g_dontuse; // set to true to load the texture but not flag as used + +void SelectTexture (int mx, int my); + +void Texture_MouseDown (int x, int y, int buttons); +void Texture_MouseUp (int x, int y, int buttons); +void Texture_MouseMoved (int x, int y, int buttons); + +//===================================================== + +void SortTextures(void) +{ + qtexture_t *q, *qtemp, *qhead, *qcur, *qprev; + + // standard insertion sort + // Take the first texture from the list and + // add it to our new list + if ( g_qeglobals.d_qtextures == NULL) + return; + + qhead = g_qeglobals.d_qtextures; + q = g_qeglobals.d_qtextures->next; + qhead->next = NULL; + + // while there are still things on the old + // list, keep adding them to the new list + while (q) + { + qtemp = q; + q = q->next; + + qprev = NULL; + qcur = qhead; + + while (qcur) + { + // Insert it here? + if (strcmp(qtemp->name, qcur->name) < 0) + { + qtemp->next = qcur; + if (qprev) + qprev->next = qtemp; + else + qhead = qtemp; + break; + } + + // Move on + + qprev = qcur; + qcur = qcur->next; + + + // is this one at the end? + + if (qcur == NULL) + { + qprev->next = qtemp; + qtemp->next = NULL; + } + } + + + } + + g_qeglobals.d_qtextures = qhead; +} + +//===================================================== + + +/* +============== +Texture_InitPalette +============== +*/ +void Texture_InitPalette (byte *pal) +{ + int r,g,b,v; + int i; + int inf; + byte gammatable[256]; + float gamma; + + gamma = g_qeglobals.d_savedinfo.fGamma; + + if (gamma == 1.0) + { + for (i=0 ; i<256 ; i++) + gammatable[i] = i; + } + else + { + for (i=0 ; i<256 ; i++) + { + inf = 255 * pow ( (i+0.5)/255.5 , gamma ) + 0.5; + if (inf < 0) + inf = 0; + if (inf > 255) + inf = 255; + gammatable[i] = inf; + } + } + + for (i=0 ; i<256 ; i++) + { + r = gammatable[pal[0]]; + g = gammatable[pal[1]]; + b = gammatable[pal[2]]; + pal += 3; + + v = (r<<24) + (g<<16) + (b<<8) + 255; + v = BigLong (v); + + tex_palette[i] = v; + } +} + +void SetTexParameters (void) +{ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, texture_mode ); + + switch ( texture_mode ) + { + case GL_NEAREST: + case GL_NEAREST_MIPMAP_NEAREST: + case GL_NEAREST_MIPMAP_LINEAR: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + break; + case GL_LINEAR: + case GL_LINEAR_MIPMAP_NEAREST: + case GL_LINEAR_MIPMAP_LINEAR: + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + break; + } +} + +/* +============ +Texture_SetMode +============ +*/ +void Texture_SetMode(int iMenu) +{ + int i, iMode; + HMENU hMenu; + qboolean texturing = true; + + hMenu = GetMenu(g_qeglobals.d_hwndMain); + + switch(iMenu) { + case ID_VIEW_NEAREST: + iMode = GL_NEAREST; + break; + case ID_VIEW_NEARESTMIPMAP: + iMode = GL_NEAREST_MIPMAP_NEAREST; + break; + case ID_VIEW_LINEAR: + iMode = GL_NEAREST_MIPMAP_LINEAR; + break; + case ID_VIEW_BILINEAR: + iMode = GL_LINEAR; + break; + case ID_VIEW_BILINEARMIPMAP: + iMode = GL_LINEAR_MIPMAP_NEAREST; + break; + case ID_VIEW_TRILINEAR: + iMode = GL_LINEAR_MIPMAP_LINEAR; + break; + + case ID_TEXTURES_WIREFRAME: + iMode = 0; + texturing = false; + break; + + case ID_TEXTURES_FLATSHADE: + iMode = 0; + texturing = false; + break; + + } + + CheckMenuItem(hMenu, ID_VIEW_NEAREST, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_NEARESTMIPMAP, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_LINEAR, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_BILINEARMIPMAP, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_BILINEAR, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_VIEW_TRILINEAR, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_TEXTURES_WIREFRAME, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_TEXTURES_FLATSHADE, MF_BYCOMMAND | MF_UNCHECKED); + + CheckMenuItem(hMenu, iMenu, MF_BYCOMMAND | MF_CHECKED); + + g_qeglobals.d_savedinfo.iTexMenu = iMenu; + texture_mode = iMode; + if ( texturing ) + SetTexParameters (); + + if ( !texturing && iMenu == ID_TEXTURES_WIREFRAME) + { + camera.draw_mode = cd_wire; + Map_BuildBrushData(); + Sys_UpdateWindows (W_ALL); + return; + + } else if ( !texturing && iMenu == ID_TEXTURES_FLATSHADE) { + + camera.draw_mode = cd_solid; + Map_BuildBrushData(); + Sys_UpdateWindows (W_ALL); + return; + } + + for (i=1 ; iwidth); + height = LittleLong(qtex->height); + + q->width = width; + q->height = height; + + q->flags = qtex->flags; + q->value = qtex->value; + q->contents = qtex->contents; + + dest = qmalloc (width*height*4); + + count = width*height; + source = (byte *)qtex + LittleLong(qtex->offsets[0]); + + // The dib is upside down so we want to copy it into + // the buffer bottom up. + + total[0] = total[1] = total[2] = 0; + for (i=0 ; icolor[0] = (float)total[0]/(count*255); + q->color[1] = (float)total[1]/(count*255); + q->color[2] = (float)total[2]/(count*255); + + q->texture_number = texture_extension_number++; + + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dest); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, width, height,GL_RGBA, GL_UNSIGNED_BYTE, dest); + + free (dest); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + return q; +} + +/* +=============== +Texture_CreateSolid + +Create a single pixel texture of the apropriate color +=============== +*/ +qtexture_t *Texture_CreateSolid (char *name) +{ + byte data[4]; + qtexture_t *q; + + q = qmalloc(sizeof(*q)); + + sscanf (name, "(%f %f %f)", &q->color[0], &q->color[1], &q->color[2]); + + data[0] = q->color[0]*255; + data[1] = q->color[1]*255; + data[2] = q->color[2]*255; + data[3] = 255; + + q->width = q->height = 1; + q->texture_number = texture_extension_number++; + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 1, 1,GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture( GL_TEXTURE_2D, 0 ); + + return q; +} + + +/* +================= +Texture_MakeNotexture +================= +*/ +void Texture_MakeNotexture (void) +{ + qtexture_t *q; + byte data[4][4]; + + notexture = q = qmalloc(sizeof(*q)); + strcpy (q->name, "notexture"); + q->width = q->height = 64; + + memset (data, 0, sizeof(data)); + data[0][2] = data[3][2] = 255; + + q->color[0] = 0; + q->color[1] = 0; + q->color[2] = 0.5; + + q->texture_number = texture_extension_number++; + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + SetTexParameters (); + + if (nomips) + glTexImage2D(GL_TEXTURE_2D, 0, 3, 2, 2, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + else + gluBuild2DMipmaps(GL_TEXTURE_2D, 3, 2, 2,GL_RGBA, GL_UNSIGNED_BYTE, data); + + glBindTexture( GL_TEXTURE_2D, 0 ); +} + + + +/* +=============== +Texture_ForName +=============== +*/ +qtexture_t *Texture_ForName (char *name) +{ + byte *lump; + qtexture_t *q; + char filename[1024]; + +//return notexture; + for (q=g_qeglobals.d_qtextures ; q ; q=q->next) + { + if (!strcmp(name, q->name)) + { + if (!g_dontuse) + q->inuse = true; + return q; + } + } + + if (name[0] == '(') + { + q = Texture_CreateSolid (name); + strncpy (q->name, name, sizeof(q->name)-1); + } + else + { + // load the file + sprintf (filename, "%s/%s.wal", + ValueForKey (g_qeglobals.d_project_entity, "texturepath"), + name); + Sys_Printf ("Loading %s\n", name); + if (LoadFile (filename, &lump) == -1) + { + Sys_Printf (" load failed!\n"); + return notexture; + } + q = Texture_LoadTexture ((miptex_t *)lump); + free (lump); + strncpy (q->name, name, sizeof(q->name)-1); + StripExtension (q->name); + } + + if (!g_dontuse) + q->inuse = true; + q->next = g_qeglobals.d_qtextures; + g_qeglobals.d_qtextures = q; + + return q; +} + +/* +================== +FillTextureMenu + +================== +*/ +void FillTextureMenu (void) +{ + HMENU hmenu; + int i; + struct _finddata_t fileinfo; + int handle; + char dirstring[1024]; + char *path; + + hmenu = GetSubMenu (GetMenu(g_qeglobals.d_hwndMain), MENU_TEXTURE); + + // delete everything + for (i=0 ; inext) + { + q->inuse = false; + } +} + + + +/* +============== +Texture_ShowDirectory +============== +*/ +void Texture_ShowDirectory (int menunum) +{ + struct _finddata_t fileinfo; + int handle; + char name[1024]; + char dirstring[1024]; + + texture_showinuse = false; + strcpy (texture_directory, texture_menunames[menunum-CMD_TEXTUREWAD]); + + g_qeglobals.d_texturewin.originy = 0; + Sys_Status("loading all textures\n", 0); + + // load all .wal files + sprintf (dirstring, "%s/textures/%s*.wal", + ValueForKey (g_qeglobals.d_project_entity, "basepath"), + texture_menunames[menunum-CMD_TEXTUREWAD]); + + Sys_Printf ("Scanning %s\n", dirstring); + + handle = _findfirst (dirstring, &fileinfo); + if (handle == -1) + return; + + g_dontuse = true; + do + { + sprintf (name, "%s%s", texture_directory, fileinfo.name); + StripExtension (name); + Texture_ForName (name); + } while (_findnext( handle, &fileinfo ) != -1); + g_dontuse = false; + + _findclose (handle); + + SortTextures(); + SetInspectorMode(W_TEXTURE); + Sys_UpdateWindows(W_TEXTURE); + + sprintf (name, "Textures: %s", texture_directory); + SetWindowText(g_qeglobals.d_hwndEntity, name); + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.name[0]) + SelectTexture (16, g_qeglobals.d_texturewin.height -16); +} + +/* +============== +Texture_ShowInuse +============== +*/ +void Texture_ShowInuse (void) +{ + char name[1024]; + face_t *f; + brush_t *b; + + texture_showinuse = true; + + g_qeglobals.d_texturewin.originy = 0; + Sys_Status("Selecting active textures\n", 0); + Texture_ClearInuse (); + + for (b=active_brushes.next ; b != NULL && b != &active_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + Texture_ForName (f->texdef.name); + + for (b=selected_brushes.next ; b != NULL && b != &selected_brushes ; b=b->next) + for (f=b->brush_faces ; f ; f=f->next) + Texture_ForName (f->texdef.name); + + SortTextures(); + SetInspectorMode(W_TEXTURE); + Sys_UpdateWindows (W_TEXTURE); + + sprintf (name, "Textures: in use"); + SetWindowText(g_qeglobals.d_hwndEntity, name); + + // select the first texture in the list + if (!g_qeglobals.d_texturewin.texdef.name[0]) + SelectTexture (16, g_qeglobals.d_texturewin.height -16); +} + +/* +============================================================================ + +TEXTURE LAYOUT + +============================================================================ +*/ + +void Texture_StartPos (void) +{ + current_texture = g_qeglobals.d_qtextures; + current_x = 8; + current_y = -8; + current_row = 0; +} + +qtexture_t *Texture_NextPos (int *x, int *y) +{ + qtexture_t *q; + + while (1) + { + q = current_texture; + if (!q) + return q; + current_texture = current_texture->next; + if (q->name[0] == '(') // fake color texture + continue; + if (q->inuse) + break; // allways show in use + if (!texture_showinuse && strncmp (q->name, texture_directory, strlen(texture_directory))) + continue; + break; + } + + if (current_x + q->width > g_qeglobals.d_texturewin.width-8 && current_row) + { // go to the next row unless the texture is the first on the row + current_x = 8; + current_y -= current_row + FONT_HEIGHT + 4; + current_row = 0; + } + + *x = current_x; + *y = current_y; + + // Is our texture larger than the row? If so, grow the + // row height to match it + + if (current_row < q->height) + current_row = q->height; + + // never go less than 64, or the names get all crunched up + current_x += q->width < 64 ? 64 : q->width; + current_x += 8; + + return q; +} + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int textures_cursorx, textures_cursory; + + +/* +============ +Texture_SetTexture + +============ +*/ +void Texture_SetTexture (texdef_t *texdef) +{ + qtexture_t *q; + int x,y; + char sz[256]; + + if (texdef->name[0] == '(') + { + Sys_Status("Can't select an entity texture\n", 0); + return; + } + g_qeglobals.d_texturewin.texdef = *texdef; + + Sys_UpdateWindows (W_TEXTURE); + sprintf(sz, "Selected texture: %s\n", texdef->name); + Sys_Status(sz, 0); + Select_SetTexture(texdef); + +// scroll origin so the texture is completely on screen + Texture_StartPos (); + while (1) + { + q = Texture_NextPos (&x, &y); + if (!q) + break; + if (!strcmpi(texdef->name, q->name)) + { + if (y > g_qeglobals.d_texturewin.originy) + { + g_qeglobals.d_texturewin.originy = y; + Sys_UpdateWindows (W_TEXTURE); + return; + } + + if (y-q->height-2*FONT_HEIGHT < g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height) + { + g_qeglobals.d_texturewin.originy = y-q->height-2*FONT_HEIGHT+g_qeglobals.d_texturewin.height; + Sys_UpdateWindows (W_TEXTURE); + return; + } + + return; + } + } +} + + +/* +============== +SelectTexture + + By mouse click +============== +*/ +void SelectTexture (int mx, int my) +{ + int x, y; + qtexture_t *q; + texdef_t tex; + + my += g_qeglobals.d_texturewin.originy-g_qeglobals.d_texturewin.height; + + Texture_StartPos (); + while (1) + { + q = Texture_NextPos (&x, &y); + if (!q) + break; + if (mx > x && mx - x < q->width + && my < y && y - my < q->height + FONT_HEIGHT) + { + memset (&tex, 0, sizeof(tex)); + tex.scale[0] = 1; + tex.scale[1] = 1; + tex.flags = q->flags; + tex.value = q->value; + tex.contents = q->contents; + strcpy (tex.name, q->name); + Texture_SetTexture (&tex); + return; + } + } + + Sys_Status("Did not select a texture\n", 0); +} + +/* +============== +Texture_MouseDown +============== +*/ +void Texture_MouseDown (int x, int y, int buttons) +{ + Sys_GetCursorPos (&textures_cursorx, &textures_cursory); + + // lbutton = select texture + if (buttons == MK_LBUTTON ) + { + SelectTexture (x, g_qeglobals.d_texturewin.height - 1 - y); + return; + } + +} + +/* +============== +Texture_MouseUp +============== +*/ +void Texture_MouseUp (int x, int y, int buttons) +{ +} + +/* +============== +Texture_MouseMoved +============== +*/ +void Texture_MouseMoved (int x, int y, int buttons) +{ + int scale = 1; + + if ( buttons & MK_SHIFT ) + scale = 4; + + // rbutton = drag texture origin + if (buttons & MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != textures_cursory) + { + g_qeglobals.d_texturewin.originy += ( y-textures_cursory) * scale; + if (g_qeglobals.d_texturewin.originy > 0) + g_qeglobals.d_texturewin.originy = 0; + Sys_SetCursorPos (textures_cursorx, textures_cursory); + Sys_UpdateWindows (W_TEXTURE); + } + return; + } +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + +int imax(int iFloor, int i) { if (i>iFloor) return iFloor; return i; } +HFONT ghFont = NULL; + +/* +============ +Texture_Draw2 +============ +*/ +void Texture_Draw2 (int width, int height) +{ + qtexture_t *q; + int x, y; + char *name; + + glClearColor ( + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][0], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][1], + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][2], + 0); + glViewport (0,0,width,height); + glClear (GL_COLOR_BUFFER_BIT); + glDisable (GL_DEPTH_TEST); + glMatrixMode(GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, width, g_qeglobals.d_texturewin.originy-height, g_qeglobals.d_texturewin.originy, -100, 100); + glEnable (GL_TEXTURE_2D); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + g_qeglobals.d_texturewin.width = width; + g_qeglobals.d_texturewin.height = height; + Texture_StartPos (); + + while (1) + { + q = Texture_NextPos (&x, &y); + if (!q) + break; + + // Is this texture visible? + if ( (y-q->height-FONT_HEIGHT < g_qeglobals.d_texturewin.originy) + && (y > g_qeglobals.d_texturewin.originy - height) ) + { + + // if in use, draw a background + if (q->inuse && !texture_showinuse) + { + glLineWidth (1); + glColor3f (0.5,1,0.5); + glDisable (GL_TEXTURE_2D); + + glBegin (GL_LINE_LOOP); + glVertex2f (x-1,y+1-FONT_HEIGHT); + glVertex2f (x-1,y-q->height-1-FONT_HEIGHT); + glVertex2f (x+1+q->width,y-q->height-1-FONT_HEIGHT); + glVertex2f (x+1+q->width,y+1-FONT_HEIGHT); + glEnd (); + + glEnable (GL_TEXTURE_2D); + } + + // Draw the texture + glColor3f (1,1,1); + glBindTexture( GL_TEXTURE_2D, q->texture_number ); + glBegin (GL_QUADS); + glTexCoord2f (0,0); + glVertex2f (x,y-FONT_HEIGHT); + glTexCoord2f (1,0); + glVertex2f (x+q->width,y-FONT_HEIGHT); + glTexCoord2f (1,1); + glVertex2f (x+q->width,y-FONT_HEIGHT-q->height); + glTexCoord2f (0,1); + glVertex2f (x,y-FONT_HEIGHT-q->height); + glEnd (); + + // draw the selection border + if (!strcmpi(g_qeglobals.d_texturewin.texdef.name, q->name)) + { + glLineWidth (3); + glColor3f (1,0,0); + glDisable (GL_TEXTURE_2D); + + glBegin (GL_LINE_LOOP); + glVertex2f (x-4,y-FONT_HEIGHT+4); + glVertex2f (x-4,y-FONT_HEIGHT-q->height-4); + glVertex2f (x+4+q->width,y-FONT_HEIGHT-q->height-4); + glVertex2f (x+4+q->width,y-FONT_HEIGHT+4); + glEnd (); + + glEnable (GL_TEXTURE_2D); + glLineWidth (1); + } + + // draw the texture name + glColor3f (0,0,0); + glRasterPos2f (x, y-FONT_HEIGHT+2); + + // don't draw the directory name + for (name = q->name ; *name && *name != '/' && *name != '\\' ; name++) + ; + if (!*name) + name = q->name; + else + name++; + glCallLists (strlen(name), GL_UNSIGNED_BYTE, name); + } + } + + // reset the current texture + glBindTexture( GL_TEXTURE_2D, 0 ); + glFinish(); +} + +/* +============ +WTexWndProc +============ +*/ +LONG WINAPI WTex_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int xPos, yPos; + RECT rect; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_CREATE: + s_hdcTexture = GetDC(hWnd); + QEW_SetupPixelFormat(s_hdcTexture, false); + + if ( ( s_hglrcTexture = wglCreateContext( s_hdcTexture ) ) == 0 ) + Error( "wglCreateContext in WTex_WndProc failed" ); + + if (!wglMakeCurrent( s_hdcTexture, s_hglrcTexture )) + Error ("wglMakeCurrent in WTex_WndProc failed"); + + if (!wglShareLists( g_qeglobals.d_hglrcBase, s_hglrcTexture ) ) + Error( "wglShareLists in WTex_WndProc failed" ); + + return 0; + + case WM_DESTROY: + wglMakeCurrent( NULL, NULL ); + wglDeleteContext( s_hglrcTexture ); + ReleaseDC( hWnd, s_hdcTexture ); + return 0; + + case WM_PAINT: + { + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + + if ( !wglMakeCurrent( s_hdcTexture, s_hglrcTexture ) ) + Error ("wglMakeCurrent failed"); + Texture_Draw2 (rect.right-rect.left, rect.bottom-rect.top); + SwapBuffers(s_hdcTexture); + + EndPaint(hWnd, &ps); + } + return 0; + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + SetCapture( g_qeglobals.d_hwndTexture ); + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + + Texture_MouseDown (xPos, yPos, wParam); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + + Texture_MouseUp (xPos, yPos, wParam); + if (! (wParam & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_MOUSEMOVE: + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + + Texture_MouseMoved (xPos, yPos, wParam); + return 0; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + + +/* +================== +CreateTextureWindow + +We need to create a seperate window for the textures +in the inspector window, because we can't share +gl and gdi drawing in a single window +================== +*/ +#define TEXTURE_WINDOW_CLASS "QTEX" +HWND CreateTextureWindow (void) +{ + WNDCLASS wc; + HWND hwnd; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WTex_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = g_qeglobals.d_hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = TEXTURE_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + hwnd = CreateWindow (TEXTURE_WINDOW_CLASS , + "Texture View", + WS_BORDER|WS_CHILD|WS_VISIBLE, + 20, + 20, + 64, + 64, // size + + g_qeglobals.d_hwndEntity, // parent window + 0, // no menu + g_qeglobals.d_hInstance, + 0); + if (!hwnd) + Error ("Couldn't create texturewindow"); + + return hwnd; +} + +/* +================== +Texture_Flush +================== +*/ +void Texture_Flush (void) +{ +} + + +/* +================== +Texture_Init +================== +*/ +void Texture_Init (void) +{ + char name[1024]; + byte *pal; + + // load the palette + sprintf (name, "%s/pics/colormap.pcx", + ValueForKey (g_qeglobals.d_project_entity, "basepath")); + Load256Image (name, NULL, &pal, NULL, NULL); + if (!pal) + Error ("Couldn't load %s", name); + Texture_InitPalette (pal); + free (pal); + + // create the fallback texture + Texture_MakeNotexture (); + + g_qeglobals.d_qtextures = NULL; +} + diff --git a/tools/quake2/extra/qe4/textures.h b/tools/quake2/extra/qe4/textures.h new file mode 100644 index 00000000..e85353fc --- /dev/null +++ b/tools/quake2/extra/qe4/textures.h @@ -0,0 +1,70 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +typedef struct +{ + char name[32]; + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +} texdef_t; + + +typedef struct +{ + int width, height; + int originy; + texdef_t texdef; +} texturewin_t; + +typedef struct qtexture_s +{ + struct qtexture_s *next; + char name[64]; // includes partial directory and extension + int width, height; + int contents; + int flags; + int value; + int texture_number; // gl bind number + vec3_t color; // for flat shade mode + qboolean inuse; // true = is present on the level +} qtexture_t; + + +// a texturename of the form (0 0 0) will +// create a solid color texture + +void Texture_Init (void); +void Texture_Flush (void); +void Texture_ClearInuse (void); +void Texture_ShowInuse (void); +void Texture_ShowDirectory (int menunum); + +qtexture_t *Texture_ForName (char *name); + +void Texture_Init (void); +void Texture_SetTexture (texdef_t *texdef); + +void Texture_SetMode(int iMenu); // GL_TEXTURE_NEAREST, etc.. diff --git a/tools/quake2/extra/qe4/toolbar1.bmp b/tools/quake2/extra/qe4/toolbar1.bmp new file mode 100644 index 0000000000000000000000000000000000000000..f942898ba036cc606153f137daa2503e2cc489d7 GIT binary patch literal 1918 zcmb7^L2lbX3`JQZfCz7L1tF`Rqx;@Pt17Evc9~;z?Nj(jy@C7wpONIKfebSq{^4-Q zPf}8T{QNzHo4n-^(|h|5!wAVKB*GHFG^{EX3HvZy=(r8%-UUgoUA1@N!^&J!b;Q+W^u zl1!3a4B>|39BO#?nmx2l&}PJ|l;nf)o>!Ig02sSy;bnyQYs`}yj>{i6EcY`4Tbl?K zuoG|47UV2ZTHW(P&Bd5!#sFR}@diFCye52UifS)vz++x=o6;(E+8op*s|+-p;F*Rw zBSx}dH+xH*YnJkN^u>i&4)seVE=TFx^L=0E>|Rxc8crb%gTYp^VA@)F_jP>Y4T9k1 zGQ6oz2KVwEC9j(bEJ@KMRl`cIhCv-k7ED_kFS#rmZgYmE{reEFo8EX^R03q?hiV@% z4a2+4cg3E+&57zX6J$YA^`bOi9Jm^#_BL#zgbMZhESD_sOxV-1@wU)z7t?&5P31`z HI`RJlI#}rz literal 0 HcmV?d00001 diff --git a/tools/quake2/extra/qe4/vertsel.c b/tools/quake2/extra/qe4/vertsel.c new file mode 100644 index 00000000..613824f7 --- /dev/null +++ b/tools/quake2/extra/qe4/vertsel.c @@ -0,0 +1,245 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +int FindPoint (vec3_t point) +{ + int i, j; + + for (i=0 ; i 0.1) + break; + if (j == 3) + return i; + } + + VectorCopy (point, g_qeglobals.d_points[g_qeglobals.d_numpoints]); + g_qeglobals.d_numpoints++; + + return g_qeglobals.d_numpoints-1; +} + +int FindEdge (int p1, int p2, face_t *f) +{ + int i; + + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + for (i=0 ; inumpoints ; i++) + FindEdge (pnum[i], pnum[(i+1)%w->numpoints], f); + + free (w); +} + +void SetupVertexSelection (void) +{ + face_t *f; + brush_t *b; + + g_qeglobals.d_numpoints = 0; + g_qeglobals.d_numedges = 0; + if (!QE_SingleBrush()) + return; + b = selected_brushes.next; + for (f=b->brush_faces ; f ; f=f->next) + MakeFace (f); + + Sys_UpdateWindows (W_ALL); +} + + +void SelectFaceEdge (face_t *f, int p1, int p2) +{ + winding_t *w; + int i, j, k; + int pnum[128]; + + w = MakeFaceWinding (selected_brushes.next, f); + if (!w) + return; + for (i=0 ; inumpoints ; i++) + pnum[i] = FindPoint (w->points[i]); + for (i=0 ; inumpoints ; i++) + if (pnum[i] == p1 && pnum[(i+1)%w->numpoints] == p2) + { + VectorCopy (g_qeglobals.d_points[pnum[i]], f->planepts[0]); + VectorCopy (g_qeglobals.d_points[pnum[(i+1)%w->numpoints]], f->planepts[1]); + VectorCopy (g_qeglobals.d_points[pnum[(i+2)%w->numpoints]], f->planepts[2]); + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + + AddPlanept (f->planepts[0]); + AddPlanept (f->planepts[1]); + break; + } + + if (i == w->numpoints) + Sys_Printf ("SelectFaceEdge: failed\n"); + free (w); +} + +void SelectVertex (int p1) +{ + brush_t *b; + winding_t *w; + int i, j, k; + face_t *f; + + b = selected_brushes.next; + for (f=b->brush_faces ; f ; f=f->next) + { + w = MakeFaceWinding (b, f); + if (!w) + continue; + for (i=0 ; inumpoints ; i++) + { + if (FindPoint (w->points[i]) == p1) + { + VectorCopy (w->points[(i+w->numpoints-1)%w->numpoints], f->planepts[0]); + VectorCopy (w->points[i], f->planepts[1]); + VectorCopy (w->points[(i+1)%w->numpoints], f->planepts[2]); + for (j=0 ; j<3 ; j++) + { + for (k=0 ; k<3 ; k++) + { + f->planepts[j][k] = floor(f->planepts[j][k]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + } + + AddPlanept (f->planepts[1]); + break; + } + } + free (w); + } +} + +void SelectEdgeByRay (vec3_t org, vec3_t dir) +{ + int i, j, besti; + float d, bestd; + vec3_t mid, temp; + pedge_t *e; + + // find the edge closest to the ray + besti = -1; + bestd = 8; + + for (i=0 ; if1, e->p1, e->p2); + SelectFaceEdge (e->f2, e->p2, e->p1); +} + +void SelectVertexByRay (vec3_t org, vec3_t dir) +{ + int i, besti; + float d, bestd; + vec3_t temp; + + // find the point closest to the ray + besti = -1; + bestd = 8; + + for (i=0 ; inext; + if (e == &entities) + { + Sys_Status ("No such entity.", 0); + return; + } + } + } + + b = e->brushes.onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush.", 0); + return; + } + while (brushnum--) + { + b=b->onext; + if (b == &e->brushes) + { + Sys_Status ("No such brush.", 0); + return; + } + } + + Brush_RemoveFromList (b); + Brush_AddToList (b, &selected_brushes); + + + Sys_UpdateWindows (W_ALL); + for (i=0 ; i<3 ; i++) + g_qeglobals.d_xy.origin[i] = (b->mins[i] + b->maxs[i])/2; + + Sys_Status ("Selected.", 0); +} + +/* +================= +GetSelectionIndex +================= +*/ +void GetSelectionIndex (int *ent, int *brush) +{ + brush_t *b, *b2; + entity_t *entity; + + *ent = *brush = 0; + + b = selected_brushes.next; + if (b == &selected_brushes) + return; + + // find entity + if (b->owner != world_entity) + { + (*ent)++; + for (entity = entities.next ; entity != &entities + ; entity=entity->next, (*ent)++) + ; + } + + // find brush + for (b2=b->owner->brushes.onext + ; b2 != b && b2 != &b->owner->brushes + ; b2=b2->onext, (*brush)++) + ; +} + +BOOL CALLBACK FindBrushDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char entstr[256]; + char brushstr[256]; + HWND h; + int ent, brush; + + switch (uMsg) + { + case WM_INITDIALOG: + // set entity and brush number + GetSelectionIndex (&ent, &brush); + sprintf (entstr, "%i", ent); + sprintf (brushstr, "%i", brush); + SetWindowText(GetDlgItem(hwndDlg, IDC_FIND_ENTITY), entstr); + SetWindowText(GetDlgItem(hwndDlg, IDC_FIND_BRUSH), brushstr); + + h = GetDlgItem(hwndDlg, IDC_FIND_ENTITY); + SetFocus (h); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_FIND_ENTITY), entstr, 255); + GetWindowText(GetDlgItem(hwndDlg, IDC_FIND_BRUSH), brushstr, 255); + SelectBrush (atoi(entstr), atoi(brushstr)); + EndDialog(hwndDlg, 1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + return FALSE; +} + + + +void DoFind(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_FINDBRUSH, g_qeglobals.d_hwndMain, FindBrushDlgProc); +} + +/* +=================================================== + + ARBITRARY ROTATE + +=================================================== +*/ + + +BOOL CALLBACK RotateDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char str[256]; + HWND h; + float v; + + switch (uMsg) + { + case WM_INITDIALOG: + h = GetDlgItem(hwndDlg, IDC_FIND_ENTITY); + SetFocus (h); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) + { + + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_ROTX), str, 255); + v = atof(str); + if (v) + Select_RotateAxis (0, v); + + GetWindowText(GetDlgItem(hwndDlg, IDC_ROTY), str, 255); + v = atof(str); + if (v) + Select_RotateAxis (1, v); + + GetWindowText(GetDlgItem(hwndDlg, IDC_ROTZ), str, 255); + v = atof(str); + if (v) + Select_RotateAxis (2, v); + + EndDialog(hwndDlg, 1); + return TRUE; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + return TRUE; + } + } + + return FALSE; +} + + + +void DoRotate(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_ROTATE, g_qeglobals.d_hwndMain, RotateDlgProc); +} + +/* +=================================================== + + ARBITRARY SIDES + +=================================================== +*/ + + +BOOL CALLBACK SidesDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + char str[256]; + HWND h; + + switch (uMsg) + { + case WM_INITDIALOG: + h = GetDlgItem(hwndDlg, IDC_FIND_ENTITY); + SetFocus (h); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: + GetWindowText(GetDlgItem(hwndDlg, IDC_SIDES), str, 255); + Brush_MakeSided (atoi(str)); + + EndDialog(hwndDlg, 1); + break; + + case IDCANCEL: + EndDialog(hwndDlg, 0); + break; + } + default: + return FALSE; + } +} + + + +void DoSides(void) +{ + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_SIDES, g_qeglobals.d_hwndMain, SidesDlgProc); +} + +//====================================================================== + +/* +=================== +DoAbout +=================== +*/ +BOOL CALLBACK AboutDlgProc( HWND hwndDlg, + UINT uMsg, + WPARAM wParam, + LPARAM lParam ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + char renderer[1024]; + char version[1024]; + char vendor[1024]; + char extensions[4096]; + + sprintf( renderer, "Renderer:\t%s", glGetString( GL_RENDERER ) ); + sprintf( version, "Version:\t\t%s", glGetString( GL_VERSION ) ); + sprintf( vendor, "Vendor:\t\t%s", glGetString( GL_VENDOR ) ); + sprintf( extensions, "\n%s", glGetString( GL_EXTENSIONS ) ); + + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLRENDERER ), renderer ); + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLVERSION ), version ); + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLVENDOR ), vendor ); + SetWindowText( GetDlgItem( hwndDlg, IDC_ABOUT_GLEXTENSIONS ), extensions ); + } + return TRUE; + + case WM_CLOSE: + EndDialog( hwndDlg, 1 ); + return TRUE; + + case WM_COMMAND: + if ( LOWORD( wParam ) == IDOK ) + EndDialog(hwndDlg, 1); + return TRUE; + } + return FALSE; +} + +void DoAbout(void) +{ + DialogBox( g_qeglobals.d_hInstance, ( char * ) IDD_ABOUT, g_qeglobals.d_hwndMain, AboutDlgProc ); +} + + +/* +=================================================== + + SURFACE INSPECTOR + +=================================================== +*/ + +texdef_t g_old_texdef; +HWND g_surfwin; +qboolean g_changed_surface; + +int g_checkboxes[64] = { + IDC_CHECK1, IDC_CHECK2, IDC_CHECK3, IDC_CHECK4, + IDC_CHECK5, IDC_CHECK6, IDC_CHECK7, IDC_CHECK8, + IDC_CHECK9, IDC_CHECK10, IDC_CHECK11, IDC_CHECK12, + IDC_CHECK13, IDC_CHECK14, IDC_CHECK15, IDC_CHECK16, + IDC_CHECK17, IDC_CHECK18, IDC_CHECK19, IDC_CHECK20, + IDC_CHECK21, IDC_CHECK22, IDC_CHECK23, IDC_CHECK24, + IDC_CHECK25, IDC_CHECK26, IDC_CHECK27, IDC_CHECK28, + IDC_CHECK29, IDC_CHECK30, IDC_CHECK31, IDC_CHECK32, + + IDC_CHECK33, IDC_CHECK34, IDC_CHECK35, IDC_CHECK36, + IDC_CHECK37, IDC_CHECK38, IDC_CHECK39, IDC_CHECK40, + IDC_CHECK41, IDC_CHECK42, IDC_CHECK43, IDC_CHECK44, + IDC_CHECK45, IDC_CHECK46, IDC_CHECK47, IDC_CHECK48, + IDC_CHECK49, IDC_CHECK50, IDC_CHECK51, IDC_CHECK52, + IDC_CHECK53, IDC_CHECK54, IDC_CHECK55, IDC_CHECK56, + IDC_CHECK57, IDC_CHECK58, IDC_CHECK59, IDC_CHECK60, + IDC_CHECK61, IDC_CHECK62, IDC_CHECK63, IDC_CHECK64 + }; + +/* +============== +SetTexMods + +Set the fields to the current texdef +=============== +*/ +void SetTexMods(void) +{ + char sz[128]; + texdef_t *pt; + int i; + + pt = &g_qeglobals.d_texturewin.texdef; + + SendMessage (g_surfwin, WM_SETREDRAW, 0, 0); + + SetWindowText(GetDlgItem(g_surfwin, IDC_TEXTURE), pt->name); + + sprintf(sz, "%d", (int)pt->shift[0]); + SetWindowText(GetDlgItem(g_surfwin, IDC_HSHIFT), sz); + + sprintf(sz, "%d", (int)pt->shift[1]); + SetWindowText(GetDlgItem(g_surfwin, IDC_VSHIFT), sz); + + sprintf(sz, "%4.2f", pt->scale[0]); + SetWindowText(GetDlgItem(g_surfwin, IDC_HSCALE), sz); + + sprintf(sz, "%4.2f", pt->scale[1]); + SetWindowText(GetDlgItem(g_surfwin, IDC_VSCALE), sz); + + sprintf(sz, "%d", (int)pt->rotate); + SetWindowText(GetDlgItem(g_surfwin, IDC_ROTATE), sz); + + sprintf(sz, "%d", (int)pt->value); + SetWindowText(GetDlgItem(g_surfwin, IDC_VALUE), sz); + + for (i=0 ; i<32 ; i++) + SendMessage(GetDlgItem(g_surfwin, g_checkboxes[i]), BM_SETCHECK, !!(pt->flags&(1<contents&(1<name, sz, sizeof(pt->name)-1); + if (pt->name[0] <= ' ') + { + strcpy (pt->name, "none"); + SetWindowText(GetDlgItem(g_surfwin, IDC_TEXTURE), pt->name); + } + + GetWindowText (GetDlgItem(g_surfwin, IDC_HSHIFT), sz, 127); + pt->shift[0] = atof(sz); + + GetWindowText (GetDlgItem(g_surfwin, IDC_VSHIFT), sz, 127); + pt->shift[1] = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_HSCALE), sz, 127); + pt->scale[0] = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_VSCALE), sz, 127); + pt->scale[1] = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_ROTATE), sz, 127); + pt->rotate = atof(sz); + + GetWindowText(GetDlgItem(g_surfwin, IDC_VALUE), sz, 127); + pt->value = atof(sz); + + pt->flags = 0; + for (i=0 ; i<32 ; i++) + { + b = SendMessage(GetDlgItem(g_surfwin, g_checkboxes[i]), BM_GETCHECK, 0, 0); + if (b != 1 && b != 0) + continue; + pt->flags |= b<contents = 0; + for (i=0 ; i<32 ; i++) + { + b = SendMessage(GetDlgItem(g_surfwin, g_checkboxes[32+i]), BM_GETCHECK, 0, 0); + if (b != 1 && b != 0) + continue; + pt->contents |= b<rotate += 45; + else + pt->rotate -= 45; + + if (pt->rotate < 0) + pt->rotate += 360; + + if (pt->rotate >= 360) + pt->rotate -= 360; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_HSCALEA)) + { + if (nScrollCode == SB_LINEDOWN) + pt->scale[0] -= 0.1; + else + pt->scale[0] += 0.1; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_VSCALEA)) + { + if (nScrollCode == SB_LINEUP) + pt->scale[1] += 0.1; + else + pt->scale[1] -= 0.1; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_HSHIFTA)) + { + if (nScrollCode == SB_LINEDOWN) + pt->shift[0] -= 8; + else + pt->shift[0] += 8; + } + + else if (hwnd == GetDlgItem(g_surfwin, IDC_VSHIFTA)) + { + if (nScrollCode == SB_LINEUP) + pt->shift[1] += 8; + else + pt->shift[1] -= 8; + } + + SetTexMods(); + g_changed_surface = true; + Select_SetTexture(pt); +} + + + +BOOL CALLBACK SurfaceDlgProc ( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter + ) +{ + switch (uMsg) + { + case WM_INITDIALOG: + g_surfwin = hwndDlg; + SetTexMods (); + return FALSE; + + case WM_COMMAND: + switch (LOWORD(wParam)) { + + case IDOK: + GetTexMods (); + EndDialog(hwndDlg, 1); + break; + + case IDAPPLY: + GetTexMods (); + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + break; + + case IDCANCEL: + g_qeglobals.d_texturewin.texdef = g_old_texdef; + if (g_changed_surface) + Select_SetTexture(&g_qeglobals.d_texturewin.texdef); + EndDialog(hwndDlg, 0); + break; + } + break; + + case WM_HSCROLL: + case WM_VSCROLL: + UpdateSpinners(uMsg, wParam, lParam); + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + return 0; + + default: + return FALSE; + } +} + + + +void DoSurface (void) +{ + // save current state for cancel + g_old_texdef = g_qeglobals.d_texturewin.texdef; + g_changed_surface = false; + + DialogBox(g_qeglobals.d_hInstance, (char *)IDD_SURFACE, g_qeglobals.d_hwndMain, SurfaceDlgProc); +} + diff --git a/tools/quake2/extra/qe4/win_ent.c b/tools/quake2/extra/qe4/win_ent.c new file mode 100644 index 00000000..74fa9589 --- /dev/null +++ b/tools/quake2/extra/qe4/win_ent.c @@ -0,0 +1,1137 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" +#include "entityw.h" + +int rgIds[EntLast] = { + IDC_E_LIST, + IDC_E_COMMENT, + IDC_CHECK1, + IDC_CHECK2, + IDC_CHECK3, + IDC_CHECK4, + IDC_CHECK5, + IDC_CHECK6, + IDC_CHECK7, + IDC_CHECK8, + IDC_CHECK9, + IDC_CHECK10, + IDC_CHECK11, + IDC_CHECK12, + IDC_E_PROPS, + IDC_E_0, + IDC_E_45, + IDC_E_90, + IDC_E_135, + IDC_E_180, + IDC_E_225, + IDC_E_270, + IDC_E_315, + IDC_E_UP, + IDC_E_DOWN, + IDC_E_DELPROP, + + IDC_STATIC_KEY, + IDC_E_KEY_FIELD, + IDC_STATIC_VALUE, + IDC_E_VALUE_FIELD, + + IDC_E_COLOR +}; + +HWND hwndEnt[EntLast]; + +int inspector_mode; // W_TEXTURE, W_ENTITY, or W_CONSOLE + +qboolean multiple_entities; + +entity_t *edit_entity; + +HWND CreateTextureWindow (void); + +BOOL CALLBACK EntityWndProc( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam); // second message parameter + +void SizeEntityDlg(int iWidth, int iHeight); +void AddProp(void); +void GetTexMods(void); + + +LRESULT (CALLBACK* OldFieldWindowProc) (HWND, UINT, WPARAM, LPARAM); +LRESULT (CALLBACK* OldEntityListWindowProc) (HWND, UINT, WPARAM, LPARAM); + +/* +========================= +FieldWndProc + +Just to handle tab and enter... +========================= +*/ +BOOL CALLBACK FieldWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_CHAR: + if (LOWORD(wParam) == VK_TAB) + return FALSE; + if (LOWORD(wParam) == VK_RETURN) + return FALSE; + if (LOWORD(wParam) == VK_ESCAPE) + { + SetFocus (g_qeglobals.d_hwndCamera); + return FALSE; + } + break; + + case WM_KEYDOWN: + if (LOWORD(wParam) == VK_TAB) + { + if (hwnd == hwndEnt[EntKeyField]) + { + SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)""); + SetFocus (hwndEnt[EntValueField]); + } + else + SetFocus (hwndEnt[EntKeyField]); + } + if (LOWORD(wParam) == VK_RETURN) + { + if (hwnd == hwndEnt[EntKeyField]) + { + SendMessage (hwndEnt[EntValueField], WM_SETTEXT, 0, (long)""); + SetFocus (hwndEnt[EntValueField]); + } + else + { + AddProp (); + SetFocus (g_qeglobals.d_hwndCamera); + } + } + break; +// case WM_NCHITTEST: + case WM_LBUTTONDOWN: + SetFocus (hwnd); + break; + } + return CallWindowProc (OldFieldWindowProc, hwnd, uMsg, wParam, lParam); +} + + +/* +========================= +EntityListWndProc + +Just to handle enter... +========================= +*/ +BOOL CALLBACK EntityListWndProc( + HWND hwnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_KEYDOWN: + if (LOWORD(wParam) == VK_RETURN) + { + SendMessage ( g_qeglobals.d_hwndEntity, + WM_COMMAND, + (LBN_DBLCLK<<16) + IDC_E_LIST, + 0 ); + return 0; + } + break; + } + return CallWindowProc (OldEntityListWindowProc, hwnd, uMsg, wParam, lParam); +} + + +/* +================ +GetEntityControls + +Finds the controls from the dialog and +moves them to the window +================ +*/ +void GetEntityControls(HWND ghwndEntity) +{ + int i; + + for (i = 0; i < EntLast; i++) + { + if (i == EntList || i == EntProps || i == EntComment) + continue; + if (i == EntKeyField || i == EntValueField) + continue; + hwndEnt[i] = GetDlgItem(ghwndEntity, rgIds[i]); + if (hwndEnt[i]) + SetParent (hwndEnt[i], g_qeglobals.d_hwndEntity ); + } + + + // SetParent apears to not modify some internal state + // on listboxes, so create it from scratch... + + hwndEnt[EntList] = CreateWindow ("listbox", NULL, + LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT + | WS_VSCROLL | WS_CHILD | WS_VISIBLE, + 5, 5, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_LIST, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntList]) + Error ("CreateWindow failed"); + + hwndEnt[EntProps] = CreateWindow ("listbox", NULL, + LBS_STANDARD | LBS_NOINTEGRALHEIGHT | LBS_USETABSTOPS + | WS_VSCROLL | WS_CHILD | WS_VISIBLE, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_PROPS, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntProps]) + Error ("CreateWindow failed"); + + hwndEnt[EntComment] = CreateWindow ("edit", NULL, + ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_COMMENT, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntComment]) + Error ("CreateWindow failed"); + + hwndEnt[EntKeyField] = CreateWindow ("edit", NULL, + WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_KEY_FIELD, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntKeyField]) + Error ("CreateWindow failed"); + + hwndEnt[EntValueField] = CreateWindow ("edit", NULL, + WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_VALUE_FIELD, + g_qeglobals.d_hInstance, + NULL); + if (!hwndEnt[EntValueField]) + Error ("CreateWindow failed"); + + g_qeglobals.d_hwndEdit = CreateWindow ("edit", NULL, + ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_CHILD | WS_VISIBLE | WS_BORDER, + 5, 100, 180, 99, + g_qeglobals.d_hwndEntity, + (void *)IDC_E_STATUS, + g_qeglobals.d_hInstance, + NULL); + if (!g_qeglobals.d_hwndEdit) + Error ("CreateWindow failed"); + + g_qeglobals.d_hwndTexture = CreateTextureWindow (); + +#if 0 + for (i=0 ; i<12 ; i++) + { + hwndEnt[EntCheck1 + i] = CreateWindow ("button", NULL, + BS_AUTOCHECKBOX | WS_CHILD | WS_VISIBLE, + 5, 100, 180, 99, + entwindow, + (void *)IDC_E_STATUS, + main_instance, + NULL); + if (!hwndEnt[EntCheck1 + i]) + Error ("CreateWindow failed"); + } +#endif +} + + + +/* +=============================================================== + +ENTITY WINDOW + +=============================================================== +*/ + + +void FillClassList (void) +{ + eclass_t *pec; + int iIndex; + + SendMessage(hwndEnt[EntList], LB_RESETCONTENT, 0 , 0); + + for (pec = eclass ; pec ; pec = pec->next) + { + iIndex = SendMessage(hwndEnt[EntList], LB_ADDSTRING, 0 , (LPARAM)pec->name); + SendMessage(hwndEnt[EntList], LB_SETITEMDATA, iIndex, (LPARAM)pec); + } + +} + + +/* +============== +WEnt_Create +============== +*/ +void WEnt_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)EntityWndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = GetStockObject (LTGRAY_BRUSH); + wc.lpszMenuName = NULL; + wc.lpszClassName = ENT_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("RegisterClass: failed"); + + g_qeglobals.d_hwndEntity = CreateWindow (ENT_WINDOW_CLASS , + "Entity", + QE3_STYLE , + 20, + 20, + 100, + 480, // size + + g_qeglobals.d_hwndMain, // parent + 0, // no menu + hInstance, + NULL); + + if (!g_qeglobals.d_hwndEntity ) + Error ("Couldn't create Entity window"); +} + +/* +============== +CreateEntityWindow +============== +*/ +BOOL CreateEntityWindow(HINSTANCE hInstance) +{ + HWND hwndEntityPalette; + + inspector_mode = W_ENTITY; + + WEnt_Create (hInstance); + + hwndEntityPalette = CreateDialog(hInstance, (char *)IDD_ENTITY, g_qeglobals.d_hwndMain, (DLGPROC)NULL); + if (!hwndEntityPalette) + Error ("CreateDialog failed"); + + GetEntityControls (hwndEntityPalette); + DestroyWindow (hwndEntityPalette); + + OldFieldWindowProc = (void *)GetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC); + SetWindowLong (hwndEnt[EntKeyField], GWL_WNDPROC, (long)FieldWndProc); + SetWindowLong (hwndEnt[EntValueField], GWL_WNDPROC, (long)FieldWndProc); + + OldEntityListWindowProc = (void *)GetWindowLong (hwndEnt[EntList], GWL_WNDPROC); + SetWindowLong (hwndEnt[EntList], GWL_WNDPROC, (long)EntityListWndProc); + + FillClassList (); + + LoadWindowState(g_qeglobals.d_hwndEntity, "EntityWindow"); + + ShowWindow (g_qeglobals.d_hwndEntity, SW_SHOW); + SetInspectorMode (W_CONSOLE); + + return TRUE; +} + +/* +============== +SetInspectorMode +============== +*/ +void SetInspectorMode(int iType) +{ + RECT rc; + HMENU hMenu = GetMenu( g_qeglobals.d_hwndMain ); + + // Is the caller asking us to cycle to the next window? + + if (iType == -1) + { + if (inspector_mode == W_ENTITY) + iType = W_TEXTURE; + else if (inspector_mode == W_TEXTURE) + iType = W_CONSOLE; + else + iType = W_ENTITY; + } + + inspector_mode = iType; + switch(iType) + { + + case W_ENTITY: + SetWindowText(g_qeglobals.d_hwndEntity, "Entity"); + EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_ENABLED | MF_BYCOMMAND ); + break; + + case W_TEXTURE: +// title is set by textures.c SetWindowText(g_qeglobals.d_hwndEntity, "Textures"); + EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); + break; + + case W_CONSOLE: + SetWindowText(g_qeglobals.d_hwndEntity, "Console"); + EnableMenuItem( hMenu, ID_MISC_SELECTENTITYCOLOR, MF_GRAYED | MF_DISABLED | MF_BYCOMMAND ); + break; + + default: + break; + } + + GetWindowRect (g_qeglobals.d_hwndEntity, &rc); + SizeEntityDlg( rc.right - rc.left - 8, rc.bottom - rc.top - 32); + + RedrawWindow (g_qeglobals.d_hwndEntity, NULL, NULL, RDW_ERASE | RDW_INVALIDATE + | RDW_ERASENOW | RDW_UPDATENOW | RDW_ALLCHILDREN); + +// InvalidateRect(entwindow, NULL, true); +// ShowWindow (entwindow, SW_SHOW); +// UpdateWindow (entwindow); + + SetWindowPos( g_qeglobals.d_hwndEntity, + HWND_TOP, + rc.left, rc.top, + rc.right - rc.left, rc.bottom - rc.top, + SWP_NOSIZE | SWP_NOMOVE ); +} + + + + + +// SetKeyValuePairs +// +// Reset the key/value (aka property) listbox and fill it with the +// k/v pairs from the entity being edited. +// + +void SetKeyValuePairs (void) +{ + epair_t *pep; + RECT rc; + char sz[4096]; + + if (edit_entity == NULL) + return; + + // set key/value pair list + + GetWindowRect(hwndEnt[EntProps], &rc); + SendMessage(hwndEnt[EntProps], LB_SETCOLUMNWIDTH, (rc.right - rc.left)/2, 0); + SendMessage(hwndEnt[EntProps], LB_RESETCONTENT, 0, 0); + + // Walk through list and add pairs + + for (pep = edit_entity->epairs ; pep ; pep = pep->next) + { + // if the key is less than 8 chars, add a tab for alignment + if (strlen(pep->key) > 8) + sprintf (sz, "%s\t%s", pep->key, pep->value); + else + sprintf (sz, "%s\t\t%s", pep->key, pep->value); + SendMessage(hwndEnt[EntProps], LB_ADDSTRING, 0, (LPARAM)sz); + } + +} + +// SetSpawnFlags +// +// Update the checkboxes to reflect the flag state of the entity +// +void SetSpawnFlags(void) +{ + int f; + int i; + int v; + + f = atoi(ValueForKey (edit_entity, "spawnflags")); + for (i=0 ; i<12 ; i++) + { + v = !!(f&(1<next) + SetKeyValue(b->owner, "spawnflags", sz); + } + else + SetKeyValue (edit_entity, "spawnflags", sz); + SetKeyValuePairs (); +} + +// UpdateSel +// +// Update the listbox, checkboxes and k/v pairs to reflect the new selection +// + +BOOL UpdateSel(int iIndex, eclass_t *pec) +{ + int i; + brush_t *b; + + if (selected_brushes.next == &selected_brushes) + { + edit_entity = world_entity; + multiple_entities = false; + } + else + { + edit_entity = selected_brushes.next->owner; + for (b=selected_brushes.next->next ; b != &selected_brushes ; b=b->next) + { + if (b->owner != edit_entity) + { + multiple_entities = true; + break; + } + } + } + + if (iIndex != LB_ERR) + SendMessage(hwndEnt[EntList], LB_SETCURSEL, iIndex, 0); + + if (pec == NULL) + return TRUE; + + // Set up the description + + SendMessage(hwndEnt[EntComment], WM_SETTEXT, 0, + (LPARAM)TranslateString(pec->comments)); + + for (i=0 ; i<8 ; i++) + { + HWND hwnd = hwndEnt[EntCheck1+i]; + if (pec->flagnames[i] && pec->flagnames[i][0] != 0) + { + EnableWindow(hwnd, TRUE); + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)pec->flagnames[i]); + } else { + + // disable check box + SendMessage(hwnd, WM_SETTEXT, 0, (LPARAM)" "); + EnableWindow(hwnd, FALSE); + } + } + + SetSpawnFlags(); + SetKeyValuePairs(); + return TRUE; +} + +BOOL UpdateEntitySel(eclass_t *pec) +{ + int iIndex; + + iIndex = (int)SendMessage(hwndEnt[EntList], LB_FINDSTRINGEXACT, + (WPARAM)-1, (LPARAM)pec->name); + + return UpdateSel(iIndex, pec); +} + +// CreateEntity +// +// Creates a new entity based on the currently selected brush and entity type. +// + +void CreateEntity(void) +{ + eclass_t *pecNew; + entity_t *petNew; + int i; + HWND hwnd; + char sz[1024]; + + // check to make sure we have a brush + + if (selected_brushes.next == &selected_brushes) + { + MessageBox(g_qeglobals.d_hwndMain, "You must have a selected brush to create an entity" + , "info", 0); + return; + } + + + // find out what type of entity we are trying to create + + hwnd = hwndEnt[EntList]; + + i = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); + + if (i < 0) + { + MessageBox(g_qeglobals.d_hwndMain, "You must have a selected class to create an entity" + , "info", 0); + return; + } + + SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); + + if (!stricmp(sz, "worldspawn")) + { + MessageBox(g_qeglobals.d_hwndMain, "Can't create an entity with worldspawn.", "info", 0); + return; + } + + pecNew = Eclass_ForName(sz, false); + + // create it + + petNew = Entity_Create(pecNew); + + if (petNew == NULL) + { + MessageBox(g_qeglobals.d_hwndMain, "Failed to create entity.", "info", 0); + return; + } + + if (selected_brushes.next == &selected_brushes) + edit_entity = world_entity; + else + edit_entity = selected_brushes.next->owner; + + SetKeyValuePairs(); + Select_Deselect (); + Select_Brush (edit_entity->brushes.onext); +} + + + +/* +=============== +AddProp + +=============== +*/ +void AddProp(void) +{ + char key[4096]; + char value[4096]; + + if (edit_entity == NULL) + return; + + // Get current selection text + + SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(key)-1, (LPARAM)key); + SendMessage(hwndEnt[EntValueField], WM_GETTEXT, sizeof(value)-1, (LPARAM)value); + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + SetKeyValue(b->owner, key, value); + } + else + SetKeyValue(edit_entity, key, value); + + // refresh the prop listbox + + SetKeyValuePairs(); +} + +/* +=============== +DelProp + +=============== +*/ +void DelProp(void) +{ + char sz[4096]; + + if (edit_entity == NULL) + return; + + // Get current selection text + + SendMessage(hwndEnt[EntKeyField], WM_GETTEXT, sizeof(sz)-1, (LPARAM)sz); + + if (multiple_entities) + { + brush_t *b; + + for (b=selected_brushes.next ; b != &selected_brushes ; b=b->next) + DeleteKey(b->owner, sz); + } + else + DeleteKey(edit_entity, sz); + + // refresh the prop listbox + + SetKeyValuePairs(); +} + +/* +=============== +EditProp + +=============== +*/ +void EditProp(void) +{ + int i; + HWND hwnd; + char sz[4096]; + char *val; + + if (edit_entity == NULL) + return; + + hwnd = hwndEnt[EntProps]; + + // Get current selection text + + i = SendMessage(hwnd, LB_GETCURSEL, 0, 0); + + if (i < 0) + return; + + SendMessage(hwnd, LB_GETTEXT, i, (LPARAM)sz); + + // strip it down to the key name + + for(i=0;sz[i] != '\t';i++) + ; + + sz[i] = '\0'; + + val = sz + i + 1; + if (*val == '\t') + val++; + + SendMessage(hwndEnt[EntKeyField], WM_SETTEXT, 0, (LPARAM)sz); + SendMessage(hwndEnt[EntValueField], WM_SETTEXT, 0, (LPARAM)val); +} + + +HDWP defer; +int col; +void MOVE(HWND e, int x, int y, int w, int h) +{ +// defer=DeferWindowPos(defer,e,HWND_TOP,col+(x),y,w,h,SWP_SHOWWINDOW); +// MoveWindow (e, col+x, y, w, h, FALSE); + SetWindowPos (e, HWND_TOP, col+x, y, w, h, + SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_NOZORDER); +} + + +/* +=============== +SizeEnitityDlg + +Positions all controls so that the active inspector +is displayed correctly and the inactive ones are +off the side +=============== +*/ +void SizeEntityDlg(int iWidth, int iHeight) +{ + int y, x, xCheck, yCheck; + int i, iRow; + int w, h; + + if (iWidth < 32 || iHeight < 32) + return; + + SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 0, 0); + + //========================================== + + // + // console + // + + if (inspector_mode == W_CONSOLE) + col = 0; + else + col = iWidth; + + MOVE(g_qeglobals.d_hwndEdit, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); + + //========================================== + + // + // texture controls + // + if (inspector_mode == W_TEXTURE) + col = 0; + else + col = iWidth; + + MOVE(g_qeglobals.d_hwndTexture, DlgXBorder, DlgYBorder, iWidth - (2 * DlgXBorder), iHeight - (2 * DlgYBorder) ); + + //========================================== + + // + // entity controls + // + if (inspector_mode == W_ENTITY) + col = 0; + else + col = iWidth; + + + // top half includes the entity list (2/3) and the + // comments (1/3) - 2 gaps, above and below. + + y = iHeight/2; + y -= 2 * DlgYBorder; + y = y / 3; + w = iWidth - (2 * DlgXBorder); + MOVE(hwndEnt[EntList], DlgXBorder, DlgYBorder, w, 2 * y); + + MOVE(hwndEnt[EntComment], + DlgXBorder, 2 * DlgYBorder + 2 * y, + w, y - (2 * DlgYBorder)); + + // bottom half includes flags (fixed), k/v pairs, + // and buttons (fixed). + + // xCheck = width of a single check box + // yCheck = distance from top of one check to the next + + xCheck = (iWidth - (2 * DlgXBorder)) / 3; + yCheck = 20; + + x = DlgXBorder; + + for (iRow = 0; iRow <= 12; iRow += 4) + { + y = iHeight/2; + + for (i = 0; i < 4; i++) + { + MOVE(hwndEnt[EntCheck1 + i + iRow], + x, y, xCheck, yCheck); + y += yCheck; + } + + x += xCheck; + } + + // + // properties scroll box + // + y = iHeight/2 + 4 * yCheck; + + w = iWidth - (2 * DlgXBorder); + h = (iHeight - (yCheck * 5 + 2 * DlgYBorder) ) - y; + + MOVE(hwndEnt[EntProps], DlgXBorder, y, w, h); + + y += h + DlgYBorder; + + // + // key / value fields + // + w = iWidth-(DlgXBorder+45); + MOVE(hwndEnt[EntKeyLabel], DlgXBorder, y, 40, yCheck); + MOVE(hwndEnt[EntKeyField], DlgXBorder+40, y, w, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntValueLabel], DlgXBorder, y, 40, yCheck); + MOVE(hwndEnt[EntValueField], DlgXBorder+40, y, w, yCheck); + y += yCheck; + + // + // angle check boxes + // + i = y; + x = DlgXBorder; + + xCheck = yCheck*2; + + MOVE(hwndEnt[EntDir135], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir180], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir225], x, y, xCheck, yCheck); + + y = i; + x += xCheck; + + + MOVE(hwndEnt[EntDir90], x, y, xCheck, yCheck); + y += yCheck; + y += yCheck; + + MOVE(hwndEnt[EntDir270], x, y, xCheck, yCheck); + + y = i; + x += xCheck; + + + MOVE(hwndEnt[EntDir45], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir0], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDir315], x, y, xCheck, yCheck); + + y = i + yCheck/2; + x += xCheck + xCheck/2; + + + MOVE(hwndEnt[EntDirUp], x, y, xCheck, yCheck); + y += yCheck; + + MOVE(hwndEnt[EntDirDown], x, y, xCheck, yCheck); + + y = i; + x += 1.5 * xCheck; + + MOVE(hwndEnt[EntDelProp], x, y, xCheck*2, yCheck); + y += yCheck; + + SendMessage( g_qeglobals.d_hwndEntity, WM_SETREDRAW, 1, 0); +// InvalidateRect(entwindow, NULL, TRUE); +} + + +/* +========================= +EntityWndProc +========================= +*/ +BOOL CALLBACK EntityWndProc( + HWND hwndDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam) // second message parameter +{ + RECT rc; + + GetClientRect(hwndDlg, &rc); + + switch (uMsg) + { + case WM_GETMINMAXINFO: + { + LPMINMAXINFO lpmmi; + + lpmmi = (LPMINMAXINFO) lParam; + lpmmi->ptMinTrackSize.x = 320; + lpmmi->ptMinTrackSize.y = 500; + } + return 0; + + case WM_WINDOWPOSCHANGING: + { + LPWINDOWPOS lpwp; + lpwp = (LPWINDOWPOS) lParam; + + DefWindowProc (hwndDlg, uMsg, wParam, lParam); + + lpwp->flags |= SWP_NOCOPYBITS; + SizeEntityDlg(lpwp->cx-8, lpwp->cy-32); + return 0; + + } + return 0; + + + case WM_COMMAND: + switch (LOWORD(wParam)) { + case IDC_E_DELPROP: + DelProp(); + SetFocus (g_qeglobals.d_hwndCamera); + break; + + case IDC_E_0: + SetKeyValue (edit_entity, "angle", "0"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_45: + SetKeyValue (edit_entity, "angle", "45"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_90: + SetKeyValue (edit_entity, "angle", "90"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_135: + SetKeyValue (edit_entity, "angle", "135"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_180: + SetKeyValue (edit_entity, "angle", "180"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_225: + SetKeyValue (edit_entity, "angle", "225"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_270: + SetKeyValue (edit_entity, "angle", "270"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_315: + SetKeyValue (edit_entity, "angle", "315"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_UP: + SetKeyValue (edit_entity, "angle", "-1"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + case IDC_E_DOWN: + SetKeyValue (edit_entity, "angle", "-2"); + SetFocus (g_qeglobals.d_hwndCamera); + SetKeyValuePairs (); + break; + + case IDC_CHECK1: + case IDC_CHECK2: + case IDC_CHECK3: + case IDC_CHECK4: + case IDC_CHECK5: + case IDC_CHECK6: + case IDC_CHECK7: + case IDC_CHECK8: + case IDC_CHECK9: + case IDC_CHECK10: + case IDC_CHECK11: + case IDC_CHECK12: + GetSpawnFlags(); + SetFocus (g_qeglobals.d_hwndCamera); + break; + + + case IDC_E_PROPS: + switch (HIWORD(wParam)) + { + case LBN_SELCHANGE: + + EditProp(); + return TRUE; + } + break; + + case IDC_E_LIST: + + switch (HIWORD(wParam)) { + + case LBN_SELCHANGE: + { + int iIndex; + eclass_t *pec; + + iIndex = SendMessage(hwndEnt[EntList], LB_GETCURSEL, 0, 0); + pec = (eclass_t *)SendMessage(hwndEnt[EntList], LB_GETITEMDATA, + iIndex, 0); + + UpdateSel(iIndex, pec); + + return TRUE; + break; + } + + case LBN_DBLCLK: + CreateEntity (); + SetFocus (g_qeglobals.d_hwndCamera); + break; + } + break; + + + default: + return DefWindowProc( hwndDlg, uMsg, wParam, lParam ); + } + + return 0; + } + + return DefWindowProc (hwndDlg, uMsg, wParam, lParam); +} diff --git a/tools/quake2/extra/qe4/win_main.c b/tools/quake2/extra/qe4/win_main.c new file mode 100644 index 00000000..cde20bca --- /dev/null +++ b/tools/quake2/extra/qe4/win_main.c @@ -0,0 +1,1327 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" +#include +#include "mru.h" +#include "entityw.h" + +static HWND s_hwndToolbar; + +BOOL SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize); +BOOL LoadRegistryInfo(const char *pszName, void *pvBuf, long *plSize); + +static HWND CreateMyStatusWindow(HINSTANCE hInst); +static HWND CreateToolBar(HINSTANCE hinst); + +extern int WXY_Print( void ); + +/* +============================================================================== + + MENU + +============================================================================== +*/ + +void OpenDialog (void); +void SaveAsDialog (void); +qboolean ConfirmModified (void); +void Select_Ungroup (void); + +void QE_ExpandBspString (char *bspaction, char *out, char *mapname) +{ + char *in; + char src[1024]; + char rsh[1024]; + char base[256]; + + ExtractFileName (mapname, base); + sprintf (src, "%s/maps/%s", ValueForKey(g_qeglobals.d_project_entity, "remotebasepath"), base); + strcpy (rsh, ValueForKey(g_qeglobals.d_project_entity, "rshcmd")); + + in = ValueForKey( g_qeglobals.d_project_entity, bspaction ); + while (*in) + { + if (in[0] == '!') + { + strcpy (out, rsh); + out += strlen(rsh); + in++; + continue; + } + if (in[0] == '$') + { + strcpy (out, src); + out += strlen(src); + in++; + continue; + } + if (in[0] == '@') + { + *out++ = '"'; + in++; + continue; + } + *out++ = *in++; + } + *out = 0; +} + + + +void RunBsp (char *command) +{ + char sys[1024]; + char batpath[1024]; + char outputpath[1024]; + char temppath[512]; + char name[1024]; + FILE *hFile; + BOOL ret; + PROCESS_INFORMATION ProcessInformation; + STARTUPINFO startupinfo; + + SetInspectorMode (W_CONSOLE); + + if (bsp_process) + { + Sys_Printf ("BSP is still going...\n"); + return; + } + + GetTempPath(512, temppath); + sprintf (outputpath, "%sjunk.txt", temppath); + + strcpy (name, currentmap); + if (region_active) + { + Map_SaveFile (name, false); + StripExtension (name); + strcat (name, ".reg"); + } + + Map_SaveFile (name, region_active); + + + QE_ExpandBspString (command, sys, name); + + Sys_ClearPrintf (); + Sys_Printf ("======================================\nRunning bsp command...\n"); + Sys_Printf ("\n%s\n", sys); + + // + // write qe3bsp.bat + // + sprintf (batpath, "%sqe3bsp.bat", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, sys); + fclose (hFile); + + // + // write qe3bsp2.bat + // + sprintf (batpath, "%sqe3bsp2.bat", temppath); + hFile = fopen(batpath, "w"); + if (!hFile) + Error ("Can't write to %s", batpath); + fprintf (hFile, "%sqe3bsp.bat > %s", temppath, outputpath); + fclose (hFile); + + Pointfile_Delete (); + + GetStartupInfo (&startupinfo); + + ret = CreateProcess( + batpath, // pointer to name of executable module + NULL, // pointer to command line string + NULL, // pointer to process security attributes + NULL, // pointer to thread security attributes + FALSE, // handle inheritance flag + 0 /*DETACHED_PROCESS*/, // creation flags + NULL, // pointer to new environment block + NULL, // pointer to current directory name + &startupinfo, // pointer to STARTUPINFO + &ProcessInformation // pointer to PROCESS_INFORMATION + ); + + if (!ret) + Error ("CreateProcess failed"); + + bsp_process = ProcessInformation.hProcess; + + Sleep (100); // give the new process a chance to open it's window + + BringWindowToTop( g_qeglobals.d_hwndMain ); // pop us back on top + SetFocus (g_qeglobals.d_hwndCamera); +} + +/* +============= +DoColor + +============= +*/ +qboolean DoColor(int iIndex) +{ + CHOOSECOLOR cc; + static COLORREF custom[16]; + + cc.lStructSize = sizeof(cc); + cc.hwndOwner = g_qeglobals.d_hwndMain; + cc.hInstance = g_qeglobals.d_hInstance; + cc.rgbResult = + (int)(g_qeglobals.d_savedinfo.colors[iIndex][0]*255) + + (((int)(g_qeglobals.d_savedinfo.colors[iIndex][1]*255))<<8) + + (((int)(g_qeglobals.d_savedinfo.colors[iIndex][2]*255))<<16); + cc.lpCustColors = custom; + cc.Flags = CC_FULLOPEN|CC_RGBINIT; + //cc.lCustData; + //cc.lpfnHook; + //cc.lpTemplateName + + if (!ChooseColor(&cc)) + return false; + + g_qeglobals.d_savedinfo.colors[iIndex][0] = (cc.rgbResult&255)/255.0; + g_qeglobals.d_savedinfo.colors[iIndex][1] = ((cc.rgbResult>>8)&255)/255.0; + g_qeglobals.d_savedinfo.colors[iIndex][2] = ((cc.rgbResult>>16)&255)/255.0; + + /* + ** scale colors so that at least one component is at 1.0F + ** if this is meant to select an entity color + */ + if ( iIndex == COLOR_ENTITY ) + { + float largest = 0.0F; + + if ( g_qeglobals.d_savedinfo.colors[iIndex][0] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][0]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][1] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][1]; + if ( g_qeglobals.d_savedinfo.colors[iIndex][2] > largest ) + largest = g_qeglobals.d_savedinfo.colors[iIndex][2]; + + if ( largest == 0.0F ) + { + g_qeglobals.d_savedinfo.colors[iIndex][0] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][1] = 1.0F; + g_qeglobals.d_savedinfo.colors[iIndex][2] = 1.0F; + } + else + { + float scaler = 1.0F / largest; + + g_qeglobals.d_savedinfo.colors[iIndex][0] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][1] *= scaler; + g_qeglobals.d_savedinfo.colors[iIndex][2] *= scaler; + } + } + + Sys_UpdateWindows (W_ALL); + + return true; +} + + +/* Copied from MSDN */ + +BOOL DoMru(HWND hWnd,WORD wId) +{ + char szFileName[128]; + OFSTRUCT of; + BOOL fExist; + + GetMenuItem(g_qeglobals.d_lpMruMenu, wId, TRUE, szFileName, sizeof(szFileName)); + + // Test if the file exists. + + fExist = OpenFile(szFileName ,&of,OF_EXIST) != HFILE_ERROR; + + if (fExist) { + + // Place the file on the top of MRU. + AddNewItem(g_qeglobals.d_lpMruMenu,(LPSTR)szFileName); + + // Now perform opening this file !!! + Map_LoadFile (szFileName); + } + else + // Remove the file on MRU. + DelMenuItem(g_qeglobals.d_lpMruMenu,wId,TRUE); + + // Refresh the File menu. + PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu,GetSubMenu(GetMenu(hWnd),0), + ID_FILE_EXIT); + + return fExist; +} + + +/* handle all WM_COMMAND messages here */ +LONG WINAPI CommandHandler ( + HWND hWnd, + WPARAM wParam, + LPARAM lParam) +{ + HMENU hMenu; + + switch (LOWORD(wParam)) + { +// +// file menu +// + case ID_FILE_EXIT: + /* exit application */ + if (!ConfirmModified()) + return TRUE; + + PostMessage (hWnd, WM_CLOSE, 0, 0L); + break; + + case ID_FILE_OPEN: + if (!ConfirmModified()) + return TRUE; + OpenDialog (); + break; + + case ID_FILE_NEW: + if (!ConfirmModified()) + return TRUE; + Map_New (); + break; + case ID_FILE_SAVE: + if (!strcmp(currentmap, "unnamed.map")) + SaveAsDialog (); + else + Map_SaveFile (currentmap, false); // ignore region + break; + case ID_FILE_SAVEAS: + SaveAsDialog (); + break; + + case ID_FILE_LOADPROJECT: + if (!ConfirmModified()) + return TRUE; + ProjectDialog (); + break; + + case ID_FILE_POINTFILE: + if (g_qeglobals.d_pointfile_display_list) + Pointfile_Clear (); + else + Pointfile_Check (); + break; + +// +// view menu +// + case ID_VIEW_ENTITY: + SetInspectorMode(W_ENTITY); + break; + case ID_VIEW_CONSOLE: + SetInspectorMode(W_CONSOLE); + break; + case ID_VIEW_TEXTURE: + SetInspectorMode(W_TEXTURE); + break; + + case ID_VIEW_100: + g_qeglobals.d_xy.scale = 1; + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + break; + case ID_VIEW_ZOOMIN: + g_qeglobals.d_xy.scale *= 5.0/4; + if (g_qeglobals.d_xy.scale > 16) + g_qeglobals.d_xy.scale = 16; + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + break; + case ID_VIEW_ZOOMOUT: + g_qeglobals.d_xy.scale *= 4.0/5; + if (g_qeglobals.d_xy.scale < 0.1) + g_qeglobals.d_xy.scale = 0.1; + Sys_UpdateWindows (W_XY|W_XY_OVERLAY); + break; + + case ID_VIEW_Z100: + z.scale = 1; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); + break; + case ID_VIEW_ZZOOMIN: + z.scale *= 5.0/4; + if (z.scale > 4) + z.scale = 4; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); + break; + case ID_VIEW_ZZOOMOUT: + z.scale *= 4.0/5; + if (z.scale < 0.125) + z.scale = 0.125; + Sys_UpdateWindows (W_Z|W_Z_OVERLAY); + break; + + case ID_VIEW_CENTER: + camera.angles[ROLL] = camera.angles[PITCH] = 0; + camera.angles[YAW] = 22.5 * + floor( (camera.angles[YAW]+11)/22.5 ); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + break; + + case ID_VIEW_UPFLOOR: + Cam_ChangeFloor (true); + break; + case ID_VIEW_DOWNFLOOR: + Cam_ChangeFloor (false); + break; + + case ID_VIEW_SHOWNAMES: + g_qeglobals.d_savedinfo.show_names = !g_qeglobals.d_savedinfo.show_names; + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWNAMES, MF_BYCOMMAND | (g_qeglobals.d_savedinfo.show_names ? MF_CHECKED : MF_UNCHECKED) ); + Map_BuildBrushData(); + Sys_UpdateWindows (W_XY); + break; + + case ID_VIEW_SHOWCOORDINATES: + g_qeglobals.d_savedinfo.show_coordinates ^= 1; + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWCOORDINATES, MF_BYCOMMAND | (g_qeglobals.d_savedinfo.show_coordinates ? MF_CHECKED : MF_UNCHECKED) ); + Sys_UpdateWindows (W_XY); + break; + + case ID_VIEW_SHOWBLOCKS: + g_qeglobals.show_blocks ^= 1; + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWBLOCKS, MF_BYCOMMAND | (g_qeglobals.show_blocks ? MF_CHECKED : MF_UNCHECKED) ); + Sys_UpdateWindows (W_XY); + break; + + case ID_VIEW_SHOWLIGHTS: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_LIGHTS ) & EXCLUDE_LIGHTS ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWPATH: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_PATHS ) & EXCLUDE_PATHS ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWENT: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_ENT ) & EXCLUDE_ENT ) + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_UNCHECKED); + else + CheckMenuItem( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWENT, MF_BYCOMMAND | MF_CHECKED); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWWATER: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WATER ) & EXCLUDE_WATER ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWCLIP: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_CLIP ) & EXCLUDE_CLIP ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWDETAIL: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_DETAIL ) & EXCLUDE_DETAIL ) + { + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWDETAIL, MF_BYCOMMAND | MF_UNCHECKED ); + SetWindowText (g_qeglobals.d_hwndCamera, "Camera View (DETAIL EXCLUDED)"); + } + else + { + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWDETAIL, MF_BYCOMMAND | MF_CHECKED ); + SetWindowText (g_qeglobals.d_hwndCamera, "Camera View"); + } + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + case ID_VIEW_SHOWWORLD: + if ( ( g_qeglobals.d_savedinfo.exclude ^= EXCLUDE_WORLD ) & EXCLUDE_WORLD ) + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_UNCHECKED ); + else + CheckMenuItem ( GetMenu(g_qeglobals.d_hwndMain), ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_CHECKED ); + Sys_UpdateWindows (W_XY|W_CAMERA); + break; + + +// +// grid menu +// + case ID_GRID_1: + case ID_GRID_2: + case ID_GRID_4: + case ID_GRID_8: + case ID_GRID_16: + case ID_GRID_32: + case ID_GRID_64: + { + hMenu = GetMenu(hWnd); + + CheckMenuItem(hMenu, ID_GRID_1, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_2, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_4, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_8, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_16, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_32, MF_BYCOMMAND | MF_UNCHECKED); + CheckMenuItem(hMenu, ID_GRID_64, MF_BYCOMMAND | MF_UNCHECKED); + + switch (LOWORD(wParam)) + { + case ID_GRID_1: g_qeglobals.d_gridsize = 0; break; + case ID_GRID_2: g_qeglobals.d_gridsize = 1; break; + case ID_GRID_4: g_qeglobals.d_gridsize = 2; break; + case ID_GRID_8: g_qeglobals.d_gridsize = 3; break; + case ID_GRID_16: g_qeglobals.d_gridsize = 4; break; + case ID_GRID_32: g_qeglobals.d_gridsize = 5; break; + case ID_GRID_64: g_qeglobals.d_gridsize = 6; break; + } + g_qeglobals.d_gridsize = 1 << g_qeglobals.d_gridsize; + + CheckMenuItem(hMenu, LOWORD(wParam), MF_BYCOMMAND | MF_CHECKED); + Sys_UpdateWindows (W_XY|W_Z); + break; + } + +// +// texture menu +// + case ID_VIEW_NEAREST: + case ID_VIEW_NEARESTMIPMAP: + case ID_VIEW_LINEAR: + case ID_VIEW_BILINEAR: + case ID_VIEW_BILINEARMIPMAP: + case ID_VIEW_TRILINEAR: + case ID_TEXTURES_WIREFRAME: + case ID_TEXTURES_FLATSHADE: + Texture_SetMode (LOWORD(wParam)); + break; + + case ID_TEXTURES_SHOWINUSE: + Sys_BeginWait (); + Texture_ShowInuse (); + SetInspectorMode(W_TEXTURE); + break; + + case ID_TEXTURES_INSPECTOR: + DoSurface (); + break; + + case CMD_TEXTUREWAD: + case CMD_TEXTUREWAD+1: + case CMD_TEXTUREWAD+2: + case CMD_TEXTUREWAD+3: + case CMD_TEXTUREWAD+4: + case CMD_TEXTUREWAD+5: + case CMD_TEXTUREWAD+6: + case CMD_TEXTUREWAD+7: + case CMD_TEXTUREWAD+8: + case CMD_TEXTUREWAD+9: + case CMD_TEXTUREWAD+10: + case CMD_TEXTUREWAD+11: + case CMD_TEXTUREWAD+12: + case CMD_TEXTUREWAD+13: + case CMD_TEXTUREWAD+14: + case CMD_TEXTUREWAD+15: + case CMD_TEXTUREWAD+16: + case CMD_TEXTUREWAD+17: + case CMD_TEXTUREWAD+18: + case CMD_TEXTUREWAD+19: + case CMD_TEXTUREWAD+20: + case CMD_TEXTUREWAD+21: + case CMD_TEXTUREWAD+22: + case CMD_TEXTUREWAD+23: + case CMD_TEXTUREWAD+24: + case CMD_TEXTUREWAD+25: + case CMD_TEXTUREWAD+26: + case CMD_TEXTUREWAD+27: + case CMD_TEXTUREWAD+28: + case CMD_TEXTUREWAD+29: + case CMD_TEXTUREWAD+30: + case CMD_TEXTUREWAD+31: + Sys_BeginWait (); + Texture_ShowDirectory (LOWORD(wParam)); + SetInspectorMode(W_TEXTURE); + break; + +// +// bsp menu +// + case CMD_BSPCOMMAND: + case CMD_BSPCOMMAND+1: + case CMD_BSPCOMMAND+2: + case CMD_BSPCOMMAND+3: + case CMD_BSPCOMMAND+4: + case CMD_BSPCOMMAND+5: + case CMD_BSPCOMMAND+6: + case CMD_BSPCOMMAND+7: + case CMD_BSPCOMMAND+8: + case CMD_BSPCOMMAND+9: + case CMD_BSPCOMMAND+10: + case CMD_BSPCOMMAND+11: + case CMD_BSPCOMMAND+12: + case CMD_BSPCOMMAND+13: + case CMD_BSPCOMMAND+14: + case CMD_BSPCOMMAND+15: + case CMD_BSPCOMMAND+16: + case CMD_BSPCOMMAND+17: + case CMD_BSPCOMMAND+18: + case CMD_BSPCOMMAND+19: + case CMD_BSPCOMMAND+20: + case CMD_BSPCOMMAND+21: + case CMD_BSPCOMMAND+22: + case CMD_BSPCOMMAND+23: + case CMD_BSPCOMMAND+24: + case CMD_BSPCOMMAND+25: + case CMD_BSPCOMMAND+26: + case CMD_BSPCOMMAND+27: + case CMD_BSPCOMMAND+28: + case CMD_BSPCOMMAND+29: + case CMD_BSPCOMMAND+30: + case CMD_BSPCOMMAND+31: + { + extern char *bsp_commands[256]; + + RunBsp (bsp_commands[LOWORD(wParam-CMD_BSPCOMMAND)]); + } + break; + +// +// misc menu +// + case ID_MISC_BENCHMARK: + SendMessage ( g_qeglobals.d_hwndCamera, + WM_USER+267, 0, 0); + break; + + case ID_TEXTUREBK: + DoColor(COLOR_TEXTUREBACK); + Sys_UpdateWindows (W_ALL); + break; + + case ID_MISC_SELECTENTITYCOLOR: + { + extern int inspector_mode; + + if ( ( inspector_mode == W_ENTITY ) && DoColor(COLOR_ENTITY) == true ) + { + extern void AddProp( void ); + + char buffer[100]; + + sprintf( buffer, "%f %f %f", g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][0], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][1], + g_qeglobals.d_savedinfo.colors[COLOR_ENTITY][2] ); + + SetWindowText( hwndEnt[EntValueField], buffer ); + SetWindowText( hwndEnt[EntKeyField], "_color" ); + AddProp(); + } + Sys_UpdateWindows( W_ALL ); + } + break; + + case ID_MISC_PRINTXY: + WXY_Print(); + break; + + case ID_COLORS_XYBK: + DoColor(COLOR_GRIDBACK); + Sys_UpdateWindows (W_ALL); + break; + + case ID_COLORS_MAJOR: + DoColor(COLOR_GRIDMAJOR); + Sys_UpdateWindows (W_ALL); + break; + + case ID_COLORS_MINOR: + DoColor(COLOR_GRIDMINOR); + Sys_UpdateWindows (W_ALL); + break; + + case ID_MISC_GAMMA: + DoGamma(); + break; + + case ID_MISC_FINDBRUSH: + DoFind(); + break; + + case ID_MISC_NEXTLEAKSPOT: + Pointfile_Next(); + break; + case ID_MISC_PREVIOUSLEAKSPOT: + Pointfile_Prev(); + break; + +// +// brush menu +// + case ID_BRUSH_3SIDED: + Brush_MakeSided (3); + break; + case ID_BRUSH_4SIDED: + Brush_MakeSided (4); + break; + case ID_BRUSH_5SIDED: + Brush_MakeSided (5); + break; + case ID_BRUSH_6SIDED: + Brush_MakeSided (6); + break; + case ID_BRUSH_7SIDED: + Brush_MakeSided (7); + break; + case ID_BRUSH_8SIDED: + Brush_MakeSided (8); + break; + case ID_BRUSH_9SIDED: + Brush_MakeSided (9); + break; + case ID_BRUSH_ARBITRARYSIDED: + DoSides (); + break; + +// +// select menu +// + case ID_BRUSH_FLIPX: + Select_FlipAxis (0); + break; + case ID_BRUSH_FLIPY: + Select_FlipAxis (1); + break; + case ID_BRUSH_FLIPZ: + Select_FlipAxis (2); + break; + case ID_BRUSH_ROTATEX: + Select_RotateAxis (0, 90); + break; + case ID_BRUSH_ROTATEY: + Select_RotateAxis (1, 90); + break; + case ID_BRUSH_ROTATEZ: + Select_RotateAxis (2, 90); + break; + + case ID_SELECTION_ARBITRARYROTATION: + DoRotate (); + break; + + case ID_SELECTION_UNGROUPENTITY: + Select_Ungroup (); + break; + + case ID_SELECTION_CONNECT: + ConnectEntities (); + break; + + case ID_SELECTION_DRAGVERTECIES: + if (g_qeglobals.d_select_mode == sel_vertex) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } + else + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_vertex; + } + break; + case ID_SELECTION_DRAGEDGES: + if (g_qeglobals.d_select_mode == sel_edge) + { + g_qeglobals.d_select_mode = sel_brush; + Sys_UpdateWindows (W_ALL); + } + else + { + SetupVertexSelection (); + if (g_qeglobals.d_numpoints) + g_qeglobals.d_select_mode = sel_edge; + } + break; + + case ID_SELECTION_SELECTPARTIALTALL: + Select_PartialTall (); + break; + case ID_SELECTION_SELECTCOMPLETETALL: + Select_CompleteTall (); + break; + case ID_SELECTION_SELECTTOUCHING: + Select_Touching (); + break; + case ID_SELECTION_SELECTINSIDE: + Select_Inside (); + break; + case ID_SELECTION_CSGSUBTRACT: + CSG_Subtract (); + break; + case ID_SELECTION_MAKEHOLLOW: + CSG_MakeHollow (); + break; + + case ID_SELECTION_CLONE: + Select_Clone (); + break; + case ID_SELECTION_DELETE: + Select_Delete (); + break; + case ID_SELECTION_DESELECT: + Select_Deselect (); + break; + + case ID_SELECTION_MAKE_DETAIL: + Select_MakeDetail (); + break; + case ID_SELECTION_MAKE_STRUCTURAL: + Select_MakeStructural (); + break; + + +// +// region menu +// + case ID_REGION_OFF: + Map_RegionOff (); + break; + case ID_REGION_SETXY: + Map_RegionXY (); + break; + case ID_REGION_SETTALLBRUSH: + Map_RegionTallBrush (); + break; + case ID_REGION_SETBRUSH: + Map_RegionBrush (); + break; + case ID_REGION_SETSELECTION: + Map_RegionSelectedBrushes (); + break; + + case IDMRU+1: + case IDMRU+2: + case IDMRU+3: + case IDMRU+4: + case IDMRU+5: + case IDMRU+6: + case IDMRU+7: + case IDMRU+8: + case IDMRU+9: + DoMru(hWnd,LOWORD(wParam)); + break; + +// +// help menu +// + + case ID_HELP_ABOUT: + DoAbout(); + break; + + default: + return FALSE; + } + + return TRUE; +} + +/* +============ +WMAIN_WndProc +============ +*/ +LONG WINAPI WMAIN_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 1; + RECT rect; + HDC maindc; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_TIMER: + QE_CountBrushesAndUpdateStatusBar(); + QE_CheckAutoSave(); + return 0; + + case WM_DESTROY: + SaveMruInReg(g_qeglobals.d_lpMruMenu,"Software\\id\\QuakeEd4\\MRU"); + DeleteMruMenu(g_qeglobals.d_lpMruMenu); + PostQuitMessage(0); + KillTimer( hWnd, QE_TIMER0 ); + return 0; + + case WM_CREATE: + maindc = GetDC(hWnd); +// QEW_SetupPixelFormat(maindc, false); + g_qeglobals.d_lpMruMenu = CreateMruMenuDefault(); + LoadMruInReg(g_qeglobals.d_lpMruMenu,"Software\\id\\QuakeEd4\\MRU"); + + // Refresh the File menu. + PlaceMenuMRUItem(g_qeglobals.d_lpMruMenu,GetSubMenu(GetMenu(hWnd),0), + ID_FILE_EXIT); + + return 0; + + case WM_SIZE: + // resize the status window + MoveWindow( g_qeglobals.d_hwndStatus, -100, 100, 10, 10, true); + return 0; + + case WM_KEYDOWN: + return QE_KeyDown (wParam); + + case WM_CLOSE: + /* call destroy window to cleanup and go away */ + SaveWindowState(g_qeglobals.d_hwndXY, "xywindow"); + SaveWindowState(g_qeglobals.d_hwndCamera, "camerawindow"); + SaveWindowState(g_qeglobals.d_hwndZ, "zwindow"); + SaveWindowState(g_qeglobals.d_hwndEntity, "EntityWindow"); + SaveWindowState(g_qeglobals.d_hwndMain, "mainwindow"); + + // FIXME: is this right? + SaveRegistryInfo("SavedInfo", &g_qeglobals.d_savedinfo, sizeof(g_qeglobals.d_savedinfo)); + DestroyWindow (hWnd); + return 0; + + case WM_COMMAND: + return CommandHandler (hWnd, wParam, lParam); + return 0; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + + + +/* +============== +Main_Create +============== +*/ +void Main_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + int i; + HMENU hMenu; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WMAIN_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU1); + wc.lpszClassName = "QUAKE_MAIN"; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + + g_qeglobals.d_hwndMain = CreateWindow ("QUAKE_MAIN" , + "QuakeEd 3", + WS_OVERLAPPEDWINDOW | + WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, + 0,0,screen_width,screen_height+GetSystemMetrics(SM_CYSIZE), // size + 0, + 0, // no menu + hInstance, + NULL); + if (!g_qeglobals.d_hwndMain) + Error ("Couldn't create main window"); + + /* create a timer so that we can count brushes */ + SetTimer( g_qeglobals.d_hwndMain, + QE_TIMER0, + 1000, + NULL ); + + LoadWindowState(g_qeglobals.d_hwndMain, "mainwindow"); + + s_hwndToolbar = CreateToolBar(hInstance); + + g_qeglobals.d_hwndStatus = CreateMyStatusWindow(hInstance); + + // + // load misc info from registry + // + i = sizeof(g_qeglobals.d_savedinfo); + LoadRegistryInfo("SavedInfo", &g_qeglobals.d_savedinfo, &i); + + if (g_qeglobals.d_savedinfo.iSize != sizeof(g_qeglobals.d_savedinfo)) + { + // fill in new defaults + + g_qeglobals.d_savedinfo.iSize = sizeof(g_qeglobals.d_savedinfo); + g_qeglobals.d_savedinfo.fGamma = 1.0; + g_qeglobals.d_savedinfo.iTexMenu = ID_VIEW_NEAREST; + + g_qeglobals.d_savedinfo.exclude = 0; + g_qeglobals.d_savedinfo.show_coordinates = true; + g_qeglobals.d_savedinfo.show_names = true; + + for (i=0 ; i<3 ; i++) + { + g_qeglobals.d_savedinfo.colors[COLOR_TEXTUREBACK][i] = 0.25; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDBACK][i] = 1.0; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR][i] = 0.75; + g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR][i] = 0.5; + g_qeglobals.d_savedinfo.colors[COLOR_CAMERABACK][i] = 0.25; + } + } + + if ( ( hMenu = GetMenu( g_qeglobals.d_hwndMain ) ) != 0 ) + { + /* + ** by default all of these are checked because that's how they're defined in the menu editor + */ + if ( !g_qeglobals.d_savedinfo.show_names ) + CheckMenuItem( hMenu, ID_VIEW_SHOWNAMES, MF_BYCOMMAND | MF_UNCHECKED ); + if ( !g_qeglobals.d_savedinfo.show_coordinates ) + CheckMenuItem( hMenu, ID_VIEW_SHOWCOORDINATES, MF_BYCOMMAND | MF_UNCHECKED ); + + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS ) + CheckMenuItem( hMenu, ID_VIEW_SHOWLIGHTS, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT ) + CheckMenuItem( hMenu, ID_VIEW_ENTITY, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS ) + CheckMenuItem( hMenu, ID_VIEW_SHOWPATH, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_WATER ) + CheckMenuItem( hMenu, ID_VIEW_SHOWWATER, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD ) + CheckMenuItem( hMenu, ID_VIEW_SHOWWORLD, MF_BYCOMMAND | MF_UNCHECKED ); + if ( g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP ) + CheckMenuItem( hMenu, ID_VIEW_SHOWCLIP, MF_BYCOMMAND | MF_UNCHECKED ); + } + + ShowWindow (g_qeglobals.d_hwndMain, SW_SHOWDEFAULT); +} + + +/* +============================================================= + +REGISTRY INFO + +============================================================= +*/ + +BOOL SaveRegistryInfo(const char *pszName, void *pvBuf, long lSize) +{ + LONG lres; + DWORD dwDisp; + HKEY hKeyId; + + lres = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\id\\QuakeEd4", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyId, &dwDisp); + + if (lres != ERROR_SUCCESS) + return FALSE; + + lres = RegSetValueEx(hKeyId, pszName, 0, REG_BINARY, pvBuf, lSize); + + RegCloseKey(hKeyId); + + if (lres != ERROR_SUCCESS) + return FALSE; + + return TRUE; +} + +BOOL LoadRegistryInfo(const char *pszName, void *pvBuf, long *plSize) +{ + HKEY hKey; + long lres, lType, lSize; + + if (plSize == NULL) + plSize = &lSize; + + lres = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\id\\QuakeEd4", 0, KEY_READ, &hKey); + + if (lres != ERROR_SUCCESS) + return FALSE; + + lres = RegQueryValueEx(hKey, pszName, NULL, &lType, pvBuf, plSize); + + RegCloseKey(hKey); + + if (lres != ERROR_SUCCESS) + return FALSE; + + return TRUE; +} + +BOOL SaveWindowState(HWND hWnd, const char *pszName) +{ + RECT rc; + + GetWindowRect(hWnd, &rc); + if (hWnd != g_qeglobals.d_hwndMain) + MapWindowPoints(NULL, g_qeglobals.d_hwndMain, (POINT *)&rc, 2); + return SaveRegistryInfo(pszName, &rc, sizeof(rc)); +} + + +BOOL LoadWindowState(HWND hWnd, const char *pszName) +{ + RECT rc; + LONG lSize = sizeof(rc); + + if (LoadRegistryInfo(pszName, &rc, &lSize)) + { + if (rc.left < 0) + rc.left = 0; + if (rc.top < 0) + rc.top = 0; + if (rc.right < rc.left + 16) + rc.right = rc.left + 16; + if (rc.bottom < rc.top + 16) + rc.bottom = rc.top + 16; + + MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top, FALSE); + return TRUE; + } + + return FALSE; +} + +/* +=============================================================== + + STATUS WINDOW + +=============================================================== +*/ + +void Sys_UpdateStatusBar( void ) +{ + extern int g_numbrushes, g_numentities; + + char numbrushbuffer[100]=""; + + sprintf( numbrushbuffer, "Brushes: %d Entities: %d", g_numbrushes, g_numentities ); + + Sys_Status( numbrushbuffer, 2 ); +} + +void Sys_Status(const char *psz, int part ) +{ + SendMessage(g_qeglobals.d_hwndStatus, SB_SETTEXT, part, (LPARAM)psz); +} + +static HWND CreateMyStatusWindow(HINSTANCE hInst) +{ + HWND hWnd; + int partsize[3] = { 300, 1100, -1 }; + + hWnd = CreateWindowEx( WS_EX_TOPMOST, // no extended styles + STATUSCLASSNAME, // status bar + "", // no text + WS_CHILD | WS_BORDER | WS_VISIBLE, // styles + -100, -100, 10, 10, // x, y, cx, cy + g_qeglobals.d_hwndMain, // parent window + (HMENU)100, // window ID + hInst, // instance + NULL); // window data + + SendMessage( hWnd, SB_SETPARTS, 3, ( long ) partsize ); + + return hWnd; +} + +//============================================================== + +#define NUMBUTTONS 15 +HWND CreateToolBar(HINSTANCE hinst) +{ + HWND hwndTB; + TBADDBITMAP tbab; + TBBUTTON tbb[NUMBUTTONS]; + + // Ensure that the common control DLL is loaded. + + InitCommonControls(); + + // Create a toolbar that the user can customize and that has a + // tooltip associated with it. + + hwndTB = CreateWindowEx(0, TOOLBARCLASSNAME, (LPSTR) NULL, + WS_CHILD | TBSTYLE_TOOLTIPS | CCS_ADJUSTABLE | WS_BORDER, + 0, 0, 0, 0, g_qeglobals.d_hwndMain, (HMENU) IDR_TOOLBAR1, hinst, NULL); + + // Send the TB_BUTTONSTRUCTSIZE message, which is required for + // backward compatibility. + + SendMessage(hwndTB, TB_BUTTONSTRUCTSIZE, (WPARAM) sizeof(TBBUTTON), 0); + + // Add the bitmap containing button images to the toolbar. + + tbab.hInst = hinst; + tbab.nID = IDR_TOOLBAR1; + SendMessage(hwndTB, TB_ADDBITMAP, (WPARAM)NUMBUTTONS, (WPARAM) &tbab); + + // Fill the TBBUTTON array with button information, and add the + // buttons to the toolbar. + + tbb[0].iBitmap = 0; + tbb[0].idCommand = ID_BRUSH_FLIPX; + tbb[0].fsState = TBSTATE_ENABLED; + tbb[0].fsStyle = TBSTYLE_BUTTON; + tbb[0].dwData = 0; + tbb[0].iString = 0; + + tbb[1].iBitmap = 2; + tbb[1].idCommand = ID_BRUSH_FLIPY; + tbb[1].fsState = TBSTATE_ENABLED; + tbb[1].fsStyle = TBSTYLE_BUTTON; + tbb[1].dwData = 0; + tbb[1].iString = 0; + + tbb[2].iBitmap = 4; + tbb[2].idCommand = ID_BRUSH_FLIPZ; + tbb[2].fsState = TBSTATE_ENABLED; + tbb[2].fsStyle = TBSTYLE_BUTTON; + tbb[2].dwData = 0; + tbb[2].iString = 0; + + tbb[3].iBitmap = 1; + tbb[3].idCommand = ID_BRUSH_ROTATEX; + tbb[3].fsState = TBSTATE_ENABLED; + tbb[3].fsStyle = TBSTYLE_BUTTON; + tbb[3].dwData = 0; + tbb[3].iString = 0; + + tbb[4].iBitmap = 3; + tbb[4].idCommand = ID_BRUSH_ROTATEY; + tbb[4].fsState = TBSTATE_ENABLED; + tbb[4].fsStyle = TBSTYLE_BUTTON; + tbb[4].dwData = 0; + tbb[4].iString = 0; + + tbb[5].iBitmap = 5; + tbb[5].idCommand = ID_BRUSH_ROTATEZ; + tbb[5].fsState = TBSTATE_ENABLED; + tbb[5].fsStyle = TBSTYLE_BUTTON; + tbb[5].dwData = 0; + tbb[5].iString = 0; + + tbb[6].iBitmap = 6; + tbb[6].idCommand = ID_SELECTION_SELECTCOMPLETETALL; + tbb[6].fsState = TBSTATE_ENABLED; + tbb[6].fsStyle = TBSTYLE_BUTTON; + tbb[6].dwData = 0; + tbb[6].iString = 0; + + tbb[7].iBitmap = 7; + tbb[7].idCommand = ID_SELECTION_SELECTTOUCHING; + tbb[7].fsState = TBSTATE_ENABLED; + tbb[7].fsStyle = TBSTYLE_BUTTON; + tbb[7].dwData = 0; + tbb[7].iString = 0; + + tbb[8].iBitmap = 8; + tbb[8].idCommand = ID_SELECTION_SELECTPARTIALTALL; + tbb[8].fsState = TBSTATE_ENABLED; + tbb[8].fsStyle = TBSTYLE_BUTTON; + tbb[8].dwData = 0; + tbb[8].iString = 0; + + + tbb[9].iBitmap = 9; + tbb[9].idCommand = ID_SELECTION_SELECTINSIDE; + tbb[9].fsState = TBSTATE_ENABLED; + tbb[9].fsStyle = TBSTYLE_BUTTON; + tbb[9].dwData = 0; + tbb[9].iString = 0; + + tbb[10].iBitmap = 10; + tbb[10].idCommand = ID_SELECTION_CSGSUBTRACT; + tbb[10].fsState = TBSTATE_ENABLED; + tbb[10].fsStyle = TBSTYLE_BUTTON; + tbb[10].dwData = 0; + tbb[10].iString = 0; + + + tbb[11].iBitmap = 11; + tbb[11].idCommand = ID_SELECTION_MAKEHOLLOW; + tbb[11].fsState = TBSTATE_ENABLED; + tbb[11].fsStyle = TBSTYLE_BUTTON; + tbb[11].dwData = 0; + tbb[11].iString = 0; + + tbb[12].iBitmap = 12; + tbb[12].idCommand = ID_TEXTURES_WIREFRAME; + tbb[12].fsState = TBSTATE_ENABLED; + tbb[12].fsStyle = TBSTYLE_BUTTON; + tbb[12].dwData = 0; + tbb[12].iString = 0; + + tbb[13].iBitmap = 13; + tbb[13].idCommand = ID_TEXTURES_FLATSHADE; + tbb[13].fsState = TBSTATE_ENABLED; + tbb[13].fsStyle = TBSTYLE_BUTTON; + tbb[13].dwData = 0; + tbb[13].iString = 0; + + tbb[14].iBitmap = 14; + tbb[14].idCommand = ID_VIEW_TRILINEAR; + tbb[14].fsState = TBSTATE_ENABLED; + tbb[14].fsStyle = TBSTYLE_BUTTON; + tbb[14].dwData = 0; + tbb[14].iString = 0; + + SendMessage(hwndTB, TB_ADDBUTTONS, (WPARAM)NUMBUTTONS, + (LPARAM) (LPTBBUTTON) &tbb); + + ShowWindow(hwndTB, SW_SHOW); + + return hwndTB; +} + diff --git a/tools/quake2/extra/qe4/win_qe3.aps b/tools/quake2/extra/qe4/win_qe3.aps new file mode 100644 index 0000000000000000000000000000000000000000..9be3e7d4015343730c7c75a7b43042f0422584cf GIT binary patch literal 78688 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 Qt#12RCoG_NY*#1zKl-IdC;$Ke literal 0 HcmV?d00001 diff --git a/tools/quake2/extra/qe4/win_qe3.c b/tools/quake2/extra/qe4/win_qe3.c new file mode 100644 index 00000000..297a58d9 --- /dev/null +++ b/tools/quake2/extra/qe4/win_qe3.c @@ -0,0 +1,605 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" +#include "mru.h" + +int screen_width; +int screen_height; +qboolean have_quit; + +int update_bits; + +HANDLE bsp_process; + +//=========================================== + +void Sys_SetTitle (char *text) +{ + SetWindowText (g_qeglobals.d_hwndMain, text); +} + +HCURSOR waitcursor; + +void Sys_BeginWait (void) +{ + waitcursor = SetCursor (LoadCursor (NULL, IDC_WAIT)); +} + +void Sys_EndWait (void) +{ + if (waitcursor) + { + SetCursor (waitcursor); + waitcursor = NULL; + } +} + + +void Sys_GetCursorPos (int *x, int *y) +{ + POINT lpPoint; + + GetCursorPos (&lpPoint); + *x = lpPoint.x; + *y = lpPoint.y; +} + +void Sys_SetCursorPos (int x, int y) +{ + SetCursorPos (x, y); +} + +void Sys_UpdateWindows (int bits) +{ +// Sys_Printf("updating 0x%X\n", bits); + update_bits |= bits; +//update_bits = -1; +} + + +void Sys_Beep (void) +{ + MessageBeep (MB_ICONASTERISK); +} + +char *TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; iepairs ; ep ; ep=ep->next) + { + if (ep->key[0] == 'b' && ep->key[1] == 's' && ep->key[2] == 'p') + { + bsp_commands[i] = ep->key; + AppendMenu (hmenu, MF_ENABLED|MF_STRING, + CMD_BSPCOMMAND+i, (LPCTSTR)ep->key); + i++; + } + } + count = i; +} + +//============================================== + +/* +=============== +CheckBspProcess + +See if the BSP is done yet +=============== +*/ +void CheckBspProcess (void) +{ + char outputpath[1024]; + char temppath[512]; + DWORD exitcode; + char *out; + BOOL ret; + + if (!bsp_process) + return; + + ret = GetExitCodeProcess (bsp_process, &exitcode); + if (!ret) + Error ("GetExitCodeProcess failed"); + if (exitcode == STILL_ACTIVE) + return; + + bsp_process = 0; + + GetTempPath(512, temppath); + sprintf (outputpath, "%sjunk.txt", temppath); + + LoadFile (outputpath, (void *)&out); + Sys_Printf ("%s", out); + Sys_Printf ("\ncompleted.\n"); + free (out); + Sys_Beep (); + + Pointfile_Check (); +} + +extern int cambuttonstate; + +/* +================== +WinMain + +================== +*/ +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance + ,LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + double time, oldtime, delta; + HACCEL accelerators; + + g_qeglobals.d_hInstance = hInstance; + + InitCommonControls (); + + screen_width = GetSystemMetrics (SM_CXFULLSCREEN); + screen_height = GetSystemMetrics (SM_CYFULLSCREEN); + + // hack for broken NT 4.0 dual screen + if (screen_width > 2*screen_height) + screen_width /= 2; + + accelerators = LoadAccelerators (hInstance + , MAKEINTRESOURCE(IDR_ACCELERATOR1)); + if (!accelerators) + Error ("LoadAccelerators failed"); + + Main_Create (hInstance); + + WCam_Create (hInstance); + WXY_Create (hInstance); + WZ_Create (hInstance); + CreateEntityWindow(hInstance); + + // the project file can be specified on the command line, + // or implicitly found in the scripts directory + if (lpCmdLine && strlen(lpCmdLine)) + { + ParseCommandLine (lpCmdLine); + if (!QE_LoadProject(argv[1])) + Error ("Couldn't load %s project file", argv[1]); + } + else if (!QE_LoadProject("scripts/quake.qe4")) + Error ("Couldn't load scripts/quake.qe4 project file"); + + QE_Init (); + + Sys_Printf ("Entering message loop\n"); + + oldtime = Sys_DoubleTime (); + + while (!have_quit) + { + Sys_EndWait (); // remove wait cursor if active + + while (PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) + { + if (!TranslateAccelerator(g_qeglobals.d_hwndMain, accelerators, &msg) ) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + if (msg.message == WM_QUIT) + have_quit = true; + } + + + CheckBspProcess (); + + time = Sys_DoubleTime (); + delta = time - oldtime; + oldtime = time; + if (delta > 0.2) + delta = 0.2; + + // run time dependant behavior + Cam_MouseControl (delta); + + // update any windows now + if (update_bits & W_CAMERA) + { + InvalidateRect(g_qeglobals.d_hwndCamera, NULL, false); + UpdateWindow (g_qeglobals.d_hwndCamera); + } + if (update_bits & (W_Z | W_Z_OVERLAY) ) + { + InvalidateRect(g_qeglobals.d_hwndZ, NULL, false); + UpdateWindow (g_qeglobals.d_hwndZ); + } + + if ( update_bits & W_TEXTURE ) + { + InvalidateRect(g_qeglobals.d_hwndTexture, NULL, false); + UpdateWindow (g_qeglobals.d_hwndEntity); + } + + if (update_bits & (W_XY | W_XY_OVERLAY)) + { + InvalidateRect(g_qeglobals.d_hwndXY, NULL, false); + UpdateWindow (g_qeglobals.d_hwndXY); + } + + update_bits = 0; + + if (!cambuttonstate && !have_quit) + { // if not driving in the camera view, block + WaitMessage (); + } + + } + + /* return success of application */ + return TRUE; + +} + diff --git a/tools/quake2/extra/qe4/win_qe3.rc b/tools/quake2/extra/qe4/win_qe3.rc new file mode 100644 index 00000000..06dab11e --- /dev/null +++ b/tools/quake2/extra/qe4/win_qe3.rc @@ -0,0 +1,693 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU1 MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New", ID_FILE_NEW + MENUITEM "&Open", ID_FILE_OPEN + MENUITEM "&Save", ID_FILE_SAVE + MENUITEM "Save &as...", ID_FILE_SAVEAS + MENUITEM "&Pointfile", ID_FILE_POINTFILE + MENUITEM "Load &project", ID_FILE_LOADPROJECT + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Copy brush", ID_EDIT_COPYBRUSH, GRAYED + MENUITEM "&Paste brush", ID_EDIT_PASTEBRUSH, GRAYED + END + POPUP "&View" + BEGIN + MENUITEM "Texture View\tT", ID_VIEW_TEXTURE + MENUITEM "Console View\tO", ID_VIEW_CONSOLE + MENUITEM "Entity View\tN", ID_VIEW_ENTITY + MENUITEM SEPARATOR + MENUITEM "&Center\tEnd", ID_VIEW_CENTER + MENUITEM "&Up Floor\tPage Up", ID_VIEW_UPFLOOR + MENUITEM "&Down Floor\tPage Down", ID_VIEW_DOWNFLOOR + MENUITEM SEPARATOR + MENUITEM "&XY 100%", ID_VIEW_100 + MENUITEM "XY Zoom &In\tDelete", ID_VIEW_ZOOMIN + MENUITEM "XY Zoom &Out\tInsert", ID_VIEW_ZOOMOUT + MENUITEM SEPARATOR + MENUITEM "Show &Names", ID_VIEW_SHOWNAMES, CHECKED + MENUITEM "Show Blocks", ID_VIEW_SHOWBLOCKS + MENUITEM "Show C&oordinates", ID_VIEW_SHOWCOORDINATES + , CHECKED + MENUITEM "Show &Entities", ID_VIEW_SHOWENT, CHECKED + MENUITEM "Show &Path", ID_VIEW_SHOWPATH, CHECKED + MENUITEM "Show &Lights", ID_VIEW_SHOWLIGHTS, CHECKED + MENUITEM "Show &Water", ID_VIEW_SHOWWATER, CHECKED + MENUITEM "Show Clip &Brush", ID_VIEW_SHOWCLIP, CHECKED + MENUITEM "Show Wor&ld", ID_VIEW_SHOWWORLD, CHECKED + MENUITEM "Show Detail\tctrl-D", ID_VIEW_SHOWDETAIL, CHECKED + MENUITEM SEPARATOR + MENUITEM "&Z 100%", ID_VIEW_Z100 + MENUITEM "Z Zoo&m In\tctrl-Delete", ID_VIEW_ZZOOMIN + MENUITEM "Z Zoom O&ut\tctrl-Insert", ID_VIEW_ZZOOMOUT + END + POPUP "&Selection" + BEGIN + MENUITEM "Drag &Edges\tE", ID_SELECTION_DRAGEDGES + MENUITEM "Drag &Vertecies\tV", ID_SELECTION_DRAGVERTECIES + MENUITEM "&Clone\tspace", ID_SELECTION_CLONE + MENUITEM "Deselect\tEsc", ID_SELECTION_DESELECT + MENUITEM "&Delete\tBackspace", ID_SELECTION_DELETE + MENUITEM "Flip &X", ID_BRUSH_FLIPX + MENUITEM "Flip &Y", ID_BRUSH_FLIPY + MENUITEM "Flip &Z", ID_BRUSH_FLIPZ + MENUITEM "Rotate X", ID_BRUSH_ROTATEX + MENUITEM "Rotate Y", ID_BRUSH_ROTATEY + MENUITEM "Rotate Z", ID_BRUSH_ROTATEZ + MENUITEM "Arbitrary rotation", ID_SELECTION_ARBITRARYROTATION + + MENUITEM "Make &Hollow", ID_SELECTION_MAKEHOLLOW + MENUITEM "CSG &Subtract", ID_SELECTION_CSGSUBTRACT + MENUITEM "Select Complete &Tall", ID_SELECTION_SELECTCOMPLETETALL + + MENUITEM "Select T&ouching", ID_SELECTION_SELECTTOUCHING + MENUITEM "Select &Partial Tall", ID_SELECTION_SELECTPARTIALTALL + + MENUITEM "Select &Inside", ID_SELECTION_SELECTINSIDE + MENUITEM "Connect entities\tCtrl-k", ID_SELECTION_CONNECT + MENUITEM "Ungroup entity", ID_SELECTION_UNGROUPENTITY + MENUITEM "Make detail\tCtrl-m", ID_SELECTION_MAKE_DETAIL + MENUITEM "Make structural", ID_SELECTION_MAKE_STRUCTURAL + END + POPUP "&Bsp" + BEGIN + MENUITEM SEPARATOR + END + POPUP "&Grid" + BEGIN + MENUITEM "Grid1\t&1", ID_GRID_1 + MENUITEM "Grid2\t&2", ID_GRID_2 + MENUITEM "Grid4\t&3", ID_GRID_4 + MENUITEM "Grid8\t&4", ID_GRID_8, CHECKED + MENUITEM "Grid16\t&5", ID_GRID_16 + MENUITEM "Grid32\t&6", ID_GRID_32 + MENUITEM "Grid64\t&7", ID_GRID_64 + END + POPUP "&Textures" + BEGIN + MENUITEM "Show In &Use\tU", ID_TEXTURES_SHOWINUSE + MENUITEM "&Surface inspector\tS", ID_TEXTURES_INSPECTOR + MENUITEM SEPARATOR + MENUITEM "&Wireframe", ID_TEXTURES_WIREFRAME + MENUITEM "&Flat shade", ID_TEXTURES_FLATSHADE + MENUITEM "&Nearest", ID_VIEW_NEAREST + MENUITEM "Nearest &Mipmap", ID_VIEW_NEARESTMIPMAP + MENUITEM "&Linear", ID_VIEW_LINEAR + MENUITEM "&Bilinear", ID_VIEW_BILINEAR + MENUITEM "B&ilinear Mipmap", ID_VIEW_BILINEARMIPMAP + MENUITEM "T&rilinear", ID_VIEW_TRILINEAR + MENUITEM SEPARATOR + END + POPUP "&Misc" + BEGIN + MENUITEM "&Benchmark", ID_MISC_BENCHMARK + POPUP "&Colors" + BEGIN + MENUITEM "&Texture Background", ID_TEXTUREBK + MENUITEM "Grid Background", ID_COLORS_XYBK + MENUITEM "Grid Major", ID_COLORS_MAJOR + MENUITEM "Grid Minor", ID_COLORS_MINOR + END + MENUITEM "&Gamma", ID_MISC_GAMMA + MENUITEM "Find brush", ID_MISC_FINDBRUSH + MENUITEM "Next leak spot\tctrl-l", ID_MISC_NEXTLEAKSPOT + MENUITEM "Previous leak spot\tctrl-p", ID_MISC_PREVIOUSLEAKSPOT + MENUITEM "&Print XY View", ID_MISC_PRINTXY + MENUITEM "&Select Entity Color\tK", ID_MISC_SELECTENTITYCOLOR + END + POPUP "&Region" + BEGIN + MENUITEM "&Off", ID_REGION_OFF + MENUITEM "&Set XY", ID_REGION_SETXY + MENUITEM "Set &Tall Brush", ID_REGION_SETTALLBRUSH + MENUITEM "Set &Brush", ID_REGION_SETBRUSH + MENUITEM "Set Se&lected Brushes", ID_REGION_SETSELECTION + END + POPUP "&Brush" + BEGIN + MENUITEM "3 sided\tctrl-3", ID_BRUSH_3SIDED + MENUITEM "4 sided\tctrl-4", ID_BRUSH_4SIDED + MENUITEM "5 sided\tctrl-5", ID_BRUSH_5SIDED + MENUITEM "6 sided\tctrl-6", ID_BRUSH_6SIDED + MENUITEM "7 sided\tctrl-7", ID_BRUSH_7SIDED + MENUITEM "8 sided\tctrl-8", ID_BRUSH_8SIDED + MENUITEM "9 sided\tctrl-9", ID_BRUSH_9SIDED + MENUITEM "Arbitrary sided", ID_BRUSH_ARBITRARYSIDED + END + POPUP "&Help" + BEGIN + MENUITEM "&About", ID_HELP_ABOUT + END +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_FINDTEXTURE DIALOG DISCARDABLE 0, 0, 129, 53 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Find Texture" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,10,30,50,14 + PUSHBUTTON "Cancel",IDCANCEL,70,30,50,14 + EDITTEXT IDC_EDIT1,10,10,110,14,ES_AUTOHSCROLL +END + +IDD_ENTITY DIALOGEX 0, 0, 234, 389 +STYLE DS_3DLOOK | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | + WS_CAPTION | WS_THICKFRAME +EXSTYLE WS_EX_TOOLWINDOW | WS_EX_CLIENTEDGE +CAPTION "Entity" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + LISTBOX IDC_E_LIST,5,5,180,99,LBS_SORT | LBS_NOINTEGRALHEIGHT | + LBS_WANTKEYBOARDINPUT | WS_VSCROLL | WS_TABSTOP, + WS_EX_CLIENTEDGE + EDITTEXT IDC_E_COMMENT,5,106,180,50,ES_MULTILINE | ES_READONLY | + WS_VSCROLL,WS_EX_CLIENTEDGE + PUSHBUTTON "135",IDC_E_135,5,290,15,15 + PUSHBUTTON "180",IDC_E_180,5,305,15,15 + PUSHBUTTON "225",IDC_E_225,5,320,15,15 + PUSHBUTTON "270",IDC_E_270,21,320,15,15 + PUSHBUTTON "90",IDC_E_90,21,290,15,15 + PUSHBUTTON "45",IDC_E_45,35,290,15,15 + PUSHBUTTON "0",IDC_E_0,35,305,15,15 + PUSHBUTTON "315",IDC_E_315,35,320,15,15 + PUSHBUTTON "Up",IDC_E_UP,60,295,15,15 + PUSHBUTTON "Dn",IDC_E_DOWN,60,310,15,15 + CONTROL "",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,160,50,8 + CONTROL "",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,170,50,8 + CONTROL "",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,180,50,8 + CONTROL "",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,5,190,50,8 + CONTROL "",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,160,50,8 + CONTROL "",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,170,50,8 + CONTROL "",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,180,50,8 + CONTROL "",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | WS_DISABLED | + WS_TABSTOP,65,190,50,8 + CONTROL "!Easy",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 125,160,50,8 + CONTROL "!Medium",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,170,50,8 + CONTROL "!Hard",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,180,50,10 + CONTROL "!DeathMatch",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,125,190,55,10 + LISTBOX IDC_E_PROPS,5,205,180,50,LBS_SORT | LBS_USETABSTOPS | + LBS_NOINTEGRALHEIGHT | LBS_WANTKEYBOARDINPUT | + WS_VSCROLL | WS_TABSTOP,WS_EX_CLIENTEDGE + PUSHBUTTON "Del Key/Pair",IDC_E_DELPROP,105,295,45,15 + EDITTEXT IDC_E_STATUS,83,312,95,30,ES_MULTILINE | ES_AUTOVSCROLL | + ES_AUTOHSCROLL | ES_READONLY | WS_VSCROLL | WS_HSCROLL + LTEXT "Key",IDC_STATIC_KEY,5,260,25,10 + LTEXT "Value",IDC_STATIC_VALUE,5,275,25,10 + EDITTEXT IDC_E_KEY_FIELD,40,260,135,14,ES_AUTOHSCROLL + EDITTEXT IDC_E_VALUE_FIELD,40,275,135,14,ES_AUTOHSCROLL +END + +IDD_GAMMA DIALOGEX 0, 0, 127, 76 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Gamma" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,10,40,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,40,50,14 + EDITTEXT IDC_G_EDIT,30,15,66,13,ES_AUTOHSCROLL,WS_EX_CLIENTEDGE +END + +IDD_FINDBRUSH DIALOGEX 0, 0, 127, 76 +STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU +CAPTION "Find brush" +FONT 8, "MS Sans Serif", 0, 0, 0x1 +BEGIN + DEFPUSHBUTTON "OK",IDOK,5,55,50,14 + PUSHBUTTON "Cancel",IDCANCEL,65,55,50,14 + EDITTEXT IDC_FIND_ENTITY,80,15,46,13,ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE + EDITTEXT IDC_FIND_BRUSH,80,30,46,13,ES_AUTOHSCROLL, + WS_EX_CLIENTEDGE + LTEXT "Entity number",IDC_STATIC,10,15,60,8 + LTEXT "Brush number",IDC_STATIC,10,30,65,8 +END + +IDD_ROTATE DIALOG DISCARDABLE 0, 0, 186, 71 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Arbitrary rotation" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + EDITTEXT IDC_ROTX,30,5,40,14,ES_AUTOHSCROLL + LTEXT "x",IDC_STATIC,5,10,8,8 + EDITTEXT IDC_ROTZ,30,45,40,14,ES_AUTOHSCROLL + LTEXT "y",IDC_STATIC,5,25,8,8 + EDITTEXT IDC_ROTY,30,25,40,14,ES_AUTOHSCROLL + LTEXT "z",IDC_STATIC,5,45,8,8 +END + +IDD_SIDES DIALOG DISCARDABLE 0, 0, 186, 55 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Arbitrrary sides" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + EDITTEXT IDC_SIDES,50,15,40,14,ES_AUTOHSCROLL + LTEXT "Sides",IDC_STATIC,15,15,18,8 +END + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 274, 212 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About QuakeEd" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,217,7,50,14 + CONTROL 127,IDC_STATIC,"Static",SS_BITMAP,7,7,83,58 + CONTROL "QuakeEd 4.0(beta)\nCopyright (C) 1997 id Software, Inc.", + IDC_STATIC,"Static",SS_LEFTNOWORDWRAP | WS_GROUP,100,10, + 110,23 + GROUPBOX "OpenGL Properties",IDC_STATIC,5,75,265,50 + LTEXT "Vendor:\t\tWHOEVER",IDC_ABOUT_GLVENDOR,10,90,125,10 + LTEXT "Version:\t\t1.1",IDC_ABOUT_GLVERSION,10,100,125,10 + LTEXT "Renderer:\tWHATEVER",IDC_ABOUT_GLRENDERER,10,110,125,10 + LTEXT "WHATEVER",IDC_ABOUT_GLEXTENSIONS,10,140,255,60 + GROUPBOX "OpenGL Extensions",IDC_STATIC,5,130,265,80 +END + +IDD_SURFACE DIALOG DISCARDABLE 400, 100, 392, 181 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Surface inspector" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,5,155,40,14 + PUSHBUTTON "Cancel",IDCANCEL,105,155,40,14 + EDITTEXT IDC_HSHIFT,85,45,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_HSHIFTA,120,45,10,15,SBS_VERT + LTEXT "Horizontal shift",IDC_STATIC,10,45,65,8 + LTEXT "Vertical shift",IDC_STATIC,10,60,65,8 + LTEXT "Horizontal stretch",IDC_STATIC,10,75,65,8 + LTEXT "Vertical stretch",IDC_STATIC,10,90,65,8 + LTEXT "Rotate",IDC_STATIC,10,105,65,8 + LTEXT "value",IDC_STATIC,10,120,65,8 + EDITTEXT IDC_VSHIFT,85,60,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_VSHIFTA,120,60,10,15,SBS_VERT + EDITTEXT IDC_HSCALE,85,75,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_HSCALEA,120,75,10,15,SBS_VERT + EDITTEXT IDC_VSCALE,85,90,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_VSCALEA,120,90,10,15,SBS_VERT + EDITTEXT IDC_ROTATE,85,105,35,15,ES_AUTOHSCROLL + SCROLLBAR IDC_ROTATEA,120,105,10,15,SBS_VERT + EDITTEXT IDC_VALUE,85,120,35,15,ES_AUTOHSCROLL + EDITTEXT IDC_TEXTURE,50,15,80,14,ES_AUTOHSCROLL + CONTROL "light",IDC_CHECK1,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,10,41,8 + CONTROL "slick",IDC_CHECK2,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,20,41,8 + CONTROL "sky",IDC_CHECK3,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,30,41,8 + CONTROL "warp",IDC_CHECK4,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,40,41,8 + CONTROL "trans33",IDC_CHECK5,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,50,41,8 + CONTROL "trans66",IDC_CHECK6,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,60,41,8 + CONTROL "flowing",IDC_CHECK7,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,70,41,8 + CONTROL "nodraw",IDC_CHECK8,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,160,80,41,8 + CONTROL "100",IDC_CHECK9,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,90,41,8 + CONTROL "200",IDC_CHECK10,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,100,41,8 + CONTROL "400",IDC_CHECK11,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,110,41,8 + CONTROL "800",IDC_CHECK12,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,120,41,8 + CONTROL "1000",IDC_CHECK13,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,130,41,8 + CONTROL "2000",IDC_CHECK14,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,140,41,8 + CONTROL "4000",IDC_CHECK15,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,150,41,8 + CONTROL "8000",IDC_CHECK16,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 160,160,41,8 + LTEXT "Texture",IDC_STATIC,10,18,30,8 + PUSHBUTTON "Apply",IDAPPLY,55,155,40,14 + CONTROL "10000",IDC_CHECK17,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,10,41,8 + CONTROL "20000",IDC_CHECK18,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,20,41,8 + CONTROL "40000",IDC_CHECK19,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,30,41,8 + CONTROL "80000",IDC_CHECK20,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,40,41,8 + CONTROL "100000",IDC_CHECK21,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,50,41,8 + CONTROL "200000",IDC_CHECK22,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,60,41,8 + CONTROL "400000",IDC_CHECK23,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,70,41,8 + CONTROL "800000",IDC_CHECK24,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,80,41,8 + CONTROL "1000000",IDC_CHECK25,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,90,41,8 + CONTROL "2000000",IDC_CHECK26,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,100,41,8 + CONTROL "4000000",IDC_CHECK27,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,110,41,8 + CONTROL "8000000",IDC_CHECK28,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,120,41,8 + CONTROL "10000000",IDC_CHECK29,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,130,40,8 + CONTROL "20000000",IDC_CHECK30,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,140,45,8 + CONTROL "40000000",IDC_CHECK31,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,150,45,8 + CONTROL "80000000",IDC_CHECK32,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,210,160,45,8 + CONTROL "solid",IDC_CHECK33,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,10,41,8 + CONTROL "window",IDC_CHECK34,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,20,41,8 + CONTROL "aux",IDC_CHECK35,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,31,41,8 + CONTROL "lava",IDC_CHECK36,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,41,41,8 + CONTROL "slime",IDC_CHECK37,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,50,41,8 + CONTROL "water",IDC_CHECK38,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,280,60,41,8 + CONTROL "mist",IDC_CHECK39,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,71,41,8 + CONTROL "80",IDC_CHECK40,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,81,41,8 + CONTROL "100",IDC_CHECK41,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,90,41,8 + CONTROL "200",IDC_CHECK42,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,100,41,8 + CONTROL "400",IDC_CHECK43,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,111,41,8 + CONTROL "800",IDC_CHECK44,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,121,41,8 + CONTROL "1000",IDC_CHECK45,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,130,41,8 + CONTROL "2000",IDC_CHECK46,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,140,41,8 + CONTROL "4000",IDC_CHECK47,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,151,41,8 + CONTROL "8000",IDC_CHECK48,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 280,161,41,8 + CONTROL "playerclip",IDC_CHECK49,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,10,41,8 + CONTROL "monsterclip",IDC_CHECK50,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,20,50,8 + CONTROL "current_0",IDC_CHECK51,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,31,50,8 + CONTROL "current_90",IDC_CHECK52,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,41,50,8 + CONTROL "current_180",IDC_CHECK53,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,50,50,8 + CONTROL "current_270",IDC_CHECK54,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,60,50,8 + CONTROL "current_up",IDC_CHECK55,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,71,50,8 + CONTROL "current_dn",IDC_CHECK56,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,81,50,8 + CONTROL "origin",IDC_CHECK57,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,90,41,8 + CONTROL "monster",IDC_CHECK58,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,100,41,8 + CONTROL "corpse",IDC_CHECK59,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,111,41,8 + CONTROL "detail",IDC_CHECK60,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,121,41,8 + CONTROL "translucent",IDC_CHECK61,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,130,50,8 + CONTROL "ladder",IDC_CHECK62,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,140,45,8 + CONTROL "40000000",IDC_CHECK63,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,151,45,8 + CONTROL "80000000",IDC_CHECK64,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,330,161,45,8 + GROUPBOX "Surf flags",IDC_STATIC,150,0,115,175 + GROUPBOX "Content flags",IDC_STATIC,270,0,115,175 +END + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,1 + PRODUCTVERSION 1,0,0,1 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "CompanyName", "Id Software\0" + VALUE "FileDescription", "qe3\0" + VALUE "FileVersion", "1, 0, 0, 1\0" + VALUE "InternalName", "qe3\0" + VALUE "LegalCopyright", "Copyright © 1996\0" + VALUE "OriginalFilename", "qe3.exe\0" + VALUE "ProductName", "Id Software qe3\0" + VALUE "ProductVersion", "1, 0, 0, 1\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE +BEGIN + "3", ID_BRUSH_3SIDED, VIRTKEY, CONTROL, NOINVERT + "4", ID_BRUSH_4SIDED, VIRTKEY, CONTROL, NOINVERT + "5", ID_BRUSH_5SIDED, VIRTKEY, CONTROL, NOINVERT + "6", ID_BRUSH_6SIDED, VIRTKEY, CONTROL, NOINVERT + "7", ID_BRUSH_7SIDED, VIRTKEY, CONTROL, NOINVERT + "8", ID_BRUSH_8SIDED, VIRTKEY, CONTROL, NOINVERT + "9", ID_BRUSH_9SIDED, VIRTKEY, CONTROL, NOINVERT + "D", ID_VIEW_SHOWDETAIL, VIRTKEY, CONTROL, NOINVERT + "K", ID_SELECTION_CONNECT, VIRTKEY, CONTROL, NOINVERT + "L", ID_MISC_NEXTLEAKSPOT, VIRTKEY, CONTROL, NOINVERT + "M", ID_SELECTION_MAKE_DETAIL, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPEN, VIRTKEY, CONTROL, NOINVERT + "P", ID_MISC_PREVIOUSLEAKSPOT, VIRTKEY, CONTROL, NOINVERT + "S", ID_FILE_SAVE, VIRTKEY, CONTROL, NOINVERT + VK_DELETE, ID_VIEW_ZZOOMIN, VIRTKEY, CONTROL, NOINVERT + VK_INSERT, ID_VIEW_ZZOOMOUT, VIRTKEY, CONTROL, NOINVERT + "X", ID_FILE_EXIT, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Toolbar +// + +IDR_TOOLBAR1 TOOLBAR DISCARDABLE 16, 15 +BEGIN + BUTTON ID_BRUSH_FLIPX + BUTTON ID_BRUSH_ROTATEX + BUTTON ID_BRUSH_FLIPY + BUTTON ID_BRUSH_ROTATEY + BUTTON ID_BRUSH_FLIPZ + BUTTON ID_BRUSH_ROTATEZ + BUTTON ID_SELECTION_SELECTCOMPLETETALL + BUTTON ID_SELECTION_SELECTTOUCHING + BUTTON ID_SELECTION_SELECTPARTIALTALL + BUTTON ID_SELECTION_SELECTINSIDE + BUTTON ID_SELECTION_CSGSUBTRACT + BUTTON ID_SELECTION_MAKEHOLLOW + BUTTON ID_TEXTURES_WIREFRAME + BUTTON ID_TEXTURES_FLATSHADE + BUTTON ID_VIEW_TRILINEAR +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Bitmap +// + +IDR_TOOLBAR1 BITMAP DISCARDABLE "toolbar1.bmp" +IDB_BITMAP1 BITMAP DISCARDABLE "q.bmp" + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ENTITY, DIALOG + BEGIN + RIGHTMARGIN, 227 + BOTTOMMARGIN, 387 + END + + IDD_GAMMA, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 120 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END + + IDD_FINDBRUSH, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 120 + TOPMARGIN, 7 + BOTTOMMARGIN, 68 + END + + IDD_ROTATE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 64 + END + + IDD_SIDES, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 48 + END + + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 267 + TOPMARGIN, 7 + BOTTOMMARGIN, 205 + END + + IDD_SURFACE, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 385 + TOPMARGIN, 7 + BOTTOMMARGIN, 174 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +IDI_ICON1 ICON DISCARDABLE "icon1.ico" +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/quake2/extra/qe4/win_xy.c b/tools/quake2/extra/qe4/win_xy.c new file mode 100644 index 00000000..75a03444 --- /dev/null +++ b/tools/quake2/extra/qe4/win_xy.c @@ -0,0 +1,306 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// win_xy.c -- windows specific xy view code + +#include "qe3.h" + +static HDC s_hdcXY; +static HGLRC s_hglrcXY; + +static unsigned s_stipple[32] = +{ + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, + 0xaaaaaaaa, 0x55555555,0xaaaaaaaa, 0x55555555, +}; + +/* +============ +WXY_WndProc +============ +*/ +LONG WINAPI WXY_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int fwKeys, xPos, yPos; + RECT rect; + + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_CREATE: + + s_hdcXY = GetDC(hWnd); + + QEW_SetupPixelFormat(s_hdcXY, false); + + if ( ( s_hglrcXY = wglCreateContext( s_hdcXY ) ) == 0 ) + Error( "wglCreateContext in WXY_WndProc failed" ); + + if (!wglMakeCurrent( s_hdcXY, s_hglrcXY )) + Error ("wglMakeCurrent failed"); + + if (!wglShareLists( g_qeglobals.d_hglrcBase, s_hglrcXY ) ) + Error( "wglShareLists in WXY_WndProc failed" ); + + glPolygonStipple ((char *)s_stipple); + glLineStipple (3, 0xaaaa); + + return 0; + + case WM_DESTROY: + QEW_StopGL( hWnd, s_hglrcXY, s_hdcXY ); + return 0; + + case WM_PAINT: + { + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + + if (!wglMakeCurrent( s_hdcXY, s_hglrcXY )) + Error ("wglMakeCurrent failed"); + + QE_CheckOpenGLForErrors(); + XY_Draw (); + QE_CheckOpenGLForErrors(); + + SwapBuffers(s_hdcXY); + + EndPaint(hWnd, &ps); + } + return 0; + + case WM_KEYDOWN: + return QE_KeyDown (wParam); + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + if ( GetTopWindow( g_qeglobals.d_hwndMain ) != hWnd) + BringWindowToTop(hWnd); + SetFocus( g_qeglobals.d_hwndXY ); + SetCapture( g_qeglobals.d_hwndXY ); + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + XY_MouseDown (xPos, yPos, fwKeys); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + XY_MouseUp (xPos, yPos, fwKeys); + if (! (fwKeys & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_MOUSEMOVE: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + XY_MouseMoved (xPos, yPos, fwKeys); + return 0; + + case WM_SIZE: + g_qeglobals.d_xy.width = rect.right; + g_qeglobals.d_xy.height = rect.bottom; + InvalidateRect( g_qeglobals.d_hwndXY, NULL, false); + return 0; + + case WM_NCCALCSIZE:// don't let windows copy pixels + DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + SendMessage( hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0 ); + return 0; + + case WM_CLOSE: + DestroyWindow (hWnd); + return 0; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + +/* +============== +WXY_Create +============== +*/ +void WXY_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WXY_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; //(HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = NULL; + wc.lpszClassName = XY_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("RegisterClass: failed"); + + g_qeglobals.d_hwndXY = CreateWindow (XY_WINDOW_CLASS , + "XY View", + QE3_STYLE , + ZWIN_WIDTH, + (int)(screen_height*CWIN_SIZE)-20, + screen_width-ZWIN_WIDTH, + (int)(screen_height*(1.0-CWIN_SIZE)-38), // size + + g_qeglobals.d_hwndMain, // parent + 0, // no menu + hInstance, + NULL); + + if (!g_qeglobals.d_hwndXY ) + Error ("Couldn't create XY View"); + + LoadWindowState(g_qeglobals.d_hwndXY, "xywindow"); + ShowWindow(g_qeglobals.d_hwndXY, SW_SHOWDEFAULT); +} + +static void WXY_InitPixelFormat( PIXELFORMATDESCRIPTOR *pPFD ) +{ + memset( pPFD, 0, sizeof( *pPFD ) ); + + pPFD->nSize = sizeof( PIXELFORMATDESCRIPTOR ); + pPFD->nVersion = 1; + pPFD->dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW; + pPFD->iPixelType = PFD_TYPE_RGBA; + pPFD->cColorBits = 24; + pPFD->cDepthBits = 32; + pPFD->iLayerType = PFD_MAIN_PLANE; + +} + +void WXY_Print( void ) +{ + DOCINFO di; + + PRINTDLG pd; + + /* + ** initialize the PRINTDLG struct and execute it + */ + memset( &pd, 0, sizeof( pd ) ); + pd.lStructSize = sizeof( pd ); + pd.hwndOwner = g_qeglobals.d_hwndXY; + pd.Flags = PD_RETURNDC; + pd.hInstance = 0; + if ( !PrintDlg( &pd ) || !pd.hDC ) + { + MessageBox( g_qeglobals.d_hwndMain, "Could not PrintDlg()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + /* + ** StartDoc + */ + memset( &di, 0, sizeof( di ) ); + di.cbSize = sizeof( di ); + di.lpszDocName = "QE4"; + if ( StartDoc( pd.hDC, &di ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "Could not StartDoc()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + /* + ** StartPage + */ + if ( StartPage( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "Could not StartPage()", "QE4 Print Error", MB_OK | MB_ICONERROR ); + return; + } + + /* + ** read pixels from the XY window + */ + { + int bmwidth = 320, bmheight = 320; + int pwidth, pheight; + + RECT r; + + GetWindowRect( g_qeglobals.d_hwndXY, &r ); + + bmwidth = r.right - r.left; + bmheight = r.bottom - r.top; + + pwidth = GetDeviceCaps( pd.hDC, PHYSICALWIDTH ) - GetDeviceCaps( pd.hDC, PHYSICALOFFSETX ); + pheight = GetDeviceCaps( pd.hDC, PHYSICALHEIGHT ) - GetDeviceCaps( pd.hDC, PHYSICALOFFSETY ); + + StretchBlt( pd.hDC, + 0, 0, + pwidth, pheight, + s_hdcXY, + 0, 0, + bmwidth, bmheight, + SRCCOPY ); + } + + /* + ** EndPage and EndDoc + */ + if ( EndPage( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndPage()", MB_OK | MB_ICONERROR ); + return; + } + + if ( EndDoc( pd.hDC ) <= 0 ) + { + MessageBox( g_qeglobals.d_hwndMain, "QE4 Print Error", "Could not EndDoc()", MB_OK | MB_ICONERROR ); + return; + } +} diff --git a/tools/quake2/extra/qe4/win_z.c b/tools/quake2/extra/qe4/win_z.c new file mode 100644 index 00000000..a7233c8c --- /dev/null +++ b/tools/quake2/extra/qe4/win_z.c @@ -0,0 +1,195 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// win_cam.c -- windows specific camera view code + +#include "qe3.h" + +static HDC s_hdcZ; +static HGLRC s_hglrcZ; + +/* +============ +WZ_WndProc +============ +*/ +LONG WINAPI WZ_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + int fwKeys, xPos, yPos; + RECT rect; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + + case WM_DESTROY: + QEW_StopGL( hWnd, s_hglrcZ, s_hdcZ ); + return 0; + + case WM_CREATE: + s_hdcZ = GetDC(hWnd); + QEW_SetupPixelFormat( s_hdcZ, false); + if ( ( s_hglrcZ = wglCreateContext( s_hdcZ ) ) == 0 ) + Error( "wglCreateContext in WZ_WndProc failed" ); + + if (!wglMakeCurrent( s_hdcZ, s_hglrcZ )) + Error ("wglMakeCurrent in WZ_WndProc failed"); + + if (!wglShareLists( g_qeglobals.d_hglrcBase, s_hglrcZ ) ) + Error( "wglShareLists in WZ_WndProc failed" ); + return 0; + + case WM_PAINT: + { + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + + if ( !wglMakeCurrent( s_hdcZ, s_hglrcZ ) ) + Error ("wglMakeCurrent failed"); + QE_CheckOpenGLForErrors(); + + Z_Draw (); + SwapBuffers(s_hdcZ); + + EndPaint(hWnd, &ps); + } + return 0; + + + case WM_KEYDOWN: + QE_KeyDown (wParam); + return 0; + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_LBUTTONDOWN: + if (GetTopWindow(g_qeglobals.d_hwndMain) != hWnd) + BringWindowToTop(hWnd); + + SetFocus( g_qeglobals.d_hwndZ ); + SetCapture( g_qeglobals.d_hwndZ ); + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Z_MouseDown (xPos, yPos, fwKeys); + return 0; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Z_MouseUp (xPos, yPos, fwKeys); + if (! (fwKeys & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + return 0; + + case WM_GETMINMAXINFO: + { + MINMAXINFO *pmmi = (LPMINMAXINFO) lParam; + + pmmi->ptMinTrackSize.x = ZWIN_WIDTH; + return 0; + } + + case WM_MOUSEMOVE: + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + Z_MouseMoved (xPos, yPos, fwKeys); + return 0; + + case WM_SIZE: + z.width = rect.right; + z.height = rect.bottom; + InvalidateRect( g_qeglobals.d_hwndZ, NULL, false); + return 0; + + case WM_NCCALCSIZE:// don't let windows copy pixels + DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + + case WM_KILLFOCUS: + case WM_SETFOCUS: + SendMessage( hWnd, WM_NCACTIVATE, uMsg == WM_SETFOCUS, 0 ); + return 0; + + case WM_CLOSE: + /* call destroy window to cleanup and go away */ + DestroyWindow (hWnd); + return 0; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + + +/* +============== +WZ_Create +============== +*/ +void WZ_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WZ_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = NULL; + wc.lpszClassName = Z_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + g_qeglobals.d_hwndZ = CreateWindow (Z_WINDOW_CLASS , + "Z", + QE3_STYLE, + 0,20,ZWIN_WIDTH,screen_height-38, // size + g_qeglobals.d_hwndMain, // parent + 0, // no menu + hInstance, + NULL); + if (!g_qeglobals.d_hwndZ) + Error ("Couldn't create zwindow"); + + LoadWindowState(g_qeglobals.d_hwndZ, "zwindow"); + ShowWindow (g_qeglobals.d_hwndZ, SW_SHOWDEFAULT); +} diff --git a/tools/quake2/extra/qe4/xy.c b/tools/quake2/extra/qe4/xy.c new file mode 100644 index 00000000..5c8303e6 --- /dev/null +++ b/tools/quake2/extra/qe4/xy.c @@ -0,0 +1,973 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "qe3.h" + +#define PAGEFLIPS 2 + +/* +============ +XY_Init +============ +*/ +void XY_Init (void) +{ + g_qeglobals.d_xy.origin[0] = 0; + g_qeglobals.d_xy.origin[1] = 20; + g_qeglobals.d_xy.origin[2] = 46; + + g_qeglobals.d_xy.scale = 1; +} + + +/* +============================================================================ + + MOUSE ACTIONS + +============================================================================ +*/ + +static int cursorx, cursory; +static int buttonstate; +static int pressx, pressy; +static vec3_t pressdelta; +static qboolean press_selection; + +void XY_ToPoint (int x, int y, vec3_t point) +{ + point[0] = g_qeglobals.d_xy.origin[0] + (x - g_qeglobals.d_xy.width/2)/g_qeglobals.d_xy.scale; + point[1] = g_qeglobals.d_xy.origin[1] + (y - g_qeglobals.d_xy.height/2)/g_qeglobals.d_xy.scale; + point[2] = 0; +} + +void XY_ToGridPoint (int x, int y, vec3_t point) +{ + point[0] = g_qeglobals.d_xy.origin[0] + (x - g_qeglobals.d_xy.width/2)/g_qeglobals.d_xy.scale; + point[1] = g_qeglobals.d_xy.origin[1] + (y - g_qeglobals.d_xy.height/2)/g_qeglobals.d_xy.scale; + point[2] = 0; + point[0] = floor(point[0]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + point[1] = floor(point[1]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; +} + +/* +============== +XY_MouseDown +============== +*/ +void XY_MouseDown (int x, int y, int buttons) +{ + vec3_t point; + vec3_t origin, dir, right, up; + + buttonstate = buttons; + pressx = x; + pressy = y; + VectorCopy (vec3_origin, pressdelta); + + XY_ToPoint (x, y, point); + + VectorCopy (point, origin); + origin[2] = 8192; + + dir[0] = 0; dir[1] = 0; dir[2] = -1; + right[0] = 1/g_qeglobals.d_xy.scale; right[1] = 0; right[2] = 0; + up[0] = 0; up[1] = 1/g_qeglobals.d_xy.scale; up[2] = 0; + + press_selection = (selected_brushes.next != &selected_brushes); + + Sys_GetCursorPos (&cursorx, &cursory); + + // lbutton = manipulate selection + // shift-LBUTTON = select + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == (MK_LBUTTON | MK_CONTROL)) + || (buttons == (MK_LBUTTON | MK_CONTROL | MK_SHIFT)) ) + { + Drag_Begin (x, y, buttons, + right, up, + origin, dir); + return; + } + + // control mbutton = move camera + if (buttonstate == (MK_CONTROL|MK_MBUTTON) ) + { + camera.origin[0] = point[0]; + camera.origin[1] = point[1]; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + } + + // mbutton = angle camera + if (buttonstate == MK_MBUTTON) + { + VectorSubtract (point, camera.origin, point); + if (point[1] || point[0]) + { + camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]); + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY); + } + } + + // shift mbutton = move z checker + if (buttonstate == (MK_SHIFT|MK_MBUTTON) ) + { + XY_ToPoint (x, y, point); + z.origin[0] = point[0]; + z.origin[1] = point[1]; + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + +} + +/* +============== +XY_MouseUp +============== +*/ +void XY_MouseUp (int x, int y, int buttons) +{ + Drag_MouseUp (); + + if (!press_selection) + Sys_UpdateWindows (W_ALL); + + buttonstate = 0; +} + +qboolean DragDelta (int x, int y, vec3_t move) +{ + vec3_t xvec, yvec, delta; + int i; + + xvec[0] = 1/g_qeglobals.d_xy.scale; + xvec[1] = xvec[2] = 0; + yvec[1] = 1/g_qeglobals.d_xy.scale; + yvec[0] = yvec[2] = 0; + + for (i=0 ; i<3 ; i++) + { + delta[i] = xvec[i]*(x - pressx) + yvec[i]*(y - pressy); + delta[i] = floor(delta[i]/g_qeglobals.d_gridsize+0.5)*g_qeglobals.d_gridsize; + } + VectorSubtract (delta, pressdelta, move); + VectorCopy (delta, pressdelta); + + if (move[0] || move[1] || move[2]) + return true; + return false; +} + +/* +============== +NewBrushDrag +============== +*/ +void NewBrushDrag (int x, int y) +{ + vec3_t mins, maxs, junk; + int i; + float temp; + brush_t *n; + + if (!DragDelta (x,y, junk)) + return; + // delete the current selection + if (selected_brushes.next != &selected_brushes) + Brush_Free (selected_brushes.next); + XY_ToGridPoint (pressx, pressy, mins); + mins[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_bottom_z/g_qeglobals.d_gridsize)); + XY_ToGridPoint (x, y, maxs); + maxs[2] = g_qeglobals.d_gridsize * ((int)(g_qeglobals.d_new_brush_top_z/g_qeglobals.d_gridsize)); + if (maxs[2] <= mins[2]) + maxs[2] = mins[2] + g_qeglobals.d_gridsize; + + for (i=0 ; i<3 ; i++) + { + if (mins[i] == maxs[i]) + return; // don't create a degenerate brush + if (mins[i] > maxs[i]) + { + temp = mins[i]; + mins[i] = maxs[i]; + maxs[i] = temp; + } + } + + n = Brush_Create (mins, maxs, &g_qeglobals.d_texturewin.texdef); + if (!n) + return; + + Brush_AddToList (n, &selected_brushes); + + Entity_LinkBrush (world_entity, n); + + Brush_Build( n ); + +// Sys_UpdateWindows (W_ALL); + Sys_UpdateWindows (W_XY| W_CAMERA); +} + +/* +============== +XY_MouseMoved +============== +*/ +void XY_MouseMoved (int x, int y, int buttons) +{ + vec3_t point; + + if (!buttonstate) + return; + + // lbutton without selection = drag new brush + if (buttonstate == MK_LBUTTON && !press_selection) + { + NewBrushDrag (x, y); + return; + } + + // lbutton (possibly with control and or shift) + // with selection = drag selection + if (buttonstate & MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + return; + } + + // control mbutton = move camera + if (buttonstate == (MK_CONTROL|MK_MBUTTON) ) + { + XY_ToPoint (x, y, point); + camera.origin[0] = point[0]; + camera.origin[1] = point[1]; + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + return; + } + + // shift mbutton = move z checker + if (buttonstate == (MK_SHIFT|MK_MBUTTON) ) + { + XY_ToPoint (x, y, point); + z.origin[0] = point[0]; + z.origin[1] = point[1]; + Sys_UpdateWindows (W_XY_OVERLAY|W_Z); + return; + } + + // mbutton = angle camera + if (buttonstate == MK_MBUTTON ) + { + XY_ToPoint (x, y, point); + VectorSubtract (point, camera.origin, point); + if (point[1] || point[0]) + { + camera.angles[YAW] = 180/Q_PI*atan2 (point[1], point[0]); + Sys_UpdateWindows (W_XY_OVERLAY | W_CAMERA); + } + return; + } + + // rbutton = drag xy origin + if (buttonstate == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if (x != cursorx || y != cursory) + { + g_qeglobals.d_xy.origin[0] -= (x-cursorx)/g_qeglobals.d_xy.scale; + g_qeglobals.d_xy.origin[1] += (y-cursory)/g_qeglobals.d_xy.scale; + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_XY | W_XY_OVERLAY); + } + return; + } +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + + +/* +============== +XY_DrawGrid +============== +*/ +void XY_DrawGrid (void) +{ + float x, y, xb, xe, yb, ye; + int w, h; + char text[32]; + + glDisable(GL_TEXTURE_2D); + glDisable(GL_TEXTURE_1D); + glDisable(GL_DEPTH_TEST); + glDisable(GL_BLEND); + + w = g_qeglobals.d_xy.width/2 / g_qeglobals.d_xy.scale; + h = g_qeglobals.d_xy.height/2 / g_qeglobals.d_xy.scale; + + xb = g_qeglobals.d_xy.origin[0] - w; + if (xb < region_mins[0]) + xb = region_mins[0]; + xb = 64 * floor (xb/64); + + xe = g_qeglobals.d_xy.origin[0] + w; + if (xe > region_maxs[0]) + xe = region_maxs[0]; + xe = 64 * ceil (xe/64); + + yb = g_qeglobals.d_xy.origin[1] - h; + if (yb < region_mins[1]) + yb = region_mins[1]; + yb = 64 * floor (yb/64); + + ye = g_qeglobals.d_xy.origin[1] + h; + if (ye > region_maxs[1]) + ye = region_maxs[1]; + ye = 64 * ceil (ye/64); + + // draw major blocks + + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); + + if ( g_qeglobals.d_showgrid ) + { + + glBegin (GL_LINES); + + for (x=xb ; x<=xe ; x+=64) + { + glVertex2f (x, yb); + glVertex2f (x, ye); + } + for (y=yb ; y<=ye ; y+=64) + { + glVertex2f (xb, y); + glVertex2f (xe, y); + } + + glEnd (); + + } + + // draw minor blocks + if ( g_qeglobals.d_showgrid && g_qeglobals.d_gridsize*g_qeglobals.d_xy.scale >= 4) + { + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); + + glBegin (GL_LINES); + for (x=xb ; x region_maxs[0]) + xe = region_maxs[0]; + xe = 1024 * ceil (xe/1024); + + yb = g_qeglobals.d_xy.origin[1] - h; + if (yb < region_mins[1]) + yb = region_mins[1]; + yb = 1024 * floor (yb/1024); + + ye = g_qeglobals.d_xy.origin[1] + h; + if (ye > region_maxs[1]) + ye = region_maxs[1]; + ye = 1024 * ceil (ye/1024); + + // draw major blocks + + glColor3f(0,0,1); + glLineWidth (2); + + glBegin (GL_LINES); + + for (x=xb ; x<=xe ; x+=1024) + { + glVertex2f (x, yb); + glVertex2f (x, ye); + } + for (y=yb ; y<=ye ; y+=1024) + { + glVertex2f (xb, y); + glVertex2f (xe, y); + } + + glEnd (); + glLineWidth (1); + + // draw coordinate text if needed + + for (x=xb ; xowner) + return FALSE; // during construction + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_CLIP) + { + if (!strncmp(pb->brush_faces->texdef.name, "clip", 4)) + return TRUE; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WATER) + { + if (pb->brush_faces->texdef.name[0] == '*') + return TRUE; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_DETAIL) + { + if (pb->brush_faces->texdef.contents & CONTENTS_DETAIL) + return TRUE; + } + + if (pb->owner == world_entity) + { + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_WORLD) + return TRUE; + return FALSE; + } + else if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_ENT) + return TRUE; + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_LIGHTS) + { + if (!strncmp(pb->owner->eclass->name, "light", 5)) + return TRUE; + } + + if (g_qeglobals.d_savedinfo.exclude & EXCLUDE_PATHS) + { + if (!strncmp(pb->owner->eclass->name, "path", 4)) + return TRUE; + } + + return FALSE; +} + +/* +============================================================= + + PATH LINES + +============================================================= +*/ + +/* +================== +DrawPathLines + +Draws connections between entities. +Needs to consider all entities, not just ones on screen, +because the lines can be visible when neither end is. +Called for both camera view and xy view. +================== +*/ +void DrawPathLines (void) +{ + int i, j, k; + vec3_t mid, mid1; + entity_t *se, *te; + brush_t *sb, *tb; + char *psz; + vec3_t dir, s1, s2; + vec_t len, f; + int arrows; + int num_entities; + char *ent_target[MAX_MAP_ENTITIES]; + entity_t *ent_entity[MAX_MAP_ENTITIES]; + + + num_entities = 0; + for (te = entities.next ; te != &entities && num_entities != MAX_MAP_ENTITIES ; te = te->next) + { + ent_target[num_entities] = ValueForKey (te, "target"); + if (ent_target[num_entities][0]) + { + ent_entity[num_entities] = te; + num_entities++; + } + } + + for (se = entities.next ; se != &entities ; se = se->next) + { + psz = ValueForKey(se, "targetname"); + + if (psz == NULL || psz[0] == '\0') + continue; + + sb = se->brushes.onext; + if (sb == &se->brushes) + continue; + + for (k=0 ; kbrushes.onext; + if (tb == &te->brushes) + continue; + + for (i=0 ; i<3 ; i++) + mid[i] = (sb->mins[i] + sb->maxs[i])*0.5; + + for (i=0 ; i<3 ; i++) + mid1[i] = (tb->mins[i] + tb->maxs[i])*0.5; + + VectorSubtract (mid1, mid, dir); + len = VectorNormalize (dir); + s1[0] = -dir[1]*8 + dir[0]*8; + s2[0] = dir[1]*8 + dir[0]*8; + s1[1] = dir[0]*8 + dir[1]*8; + s2[1] = -dir[0]*8 + dir[1]*8; + + glColor3f (se->eclass->color[0], se->eclass->color[1], se->eclass->color[2]); + + glBegin(GL_LINES); + glVertex3fv(mid); + glVertex3fv(mid1); + + arrows = (int)(len / 256) + 1; + + for (i=0 ; inext) + { + if (brush->mins[0] > maxs[0] + || brush->mins[1] > maxs[1] + || brush->maxs[0] < mins[0] + || brush->maxs[1] < mins[1] ) + { + culled++; + continue; // off screen + } + + if (FilterBrush (brush)) + continue; + drawn++; + if (brush->owner != e) + { + e = brush->owner; + glColor3fv(e->eclass->color); + } + Brush_DrawXY( brush ); + } + + DrawPathLines (); + + // + // draw pointfile + // + if ( g_qeglobals.d_pointfile_display_list) + glCallList (g_qeglobals.d_pointfile_display_list); + + // + // draw block grid + // + if ( g_qeglobals.show_blocks) + XY_DrawBlockGrid (); + + // + // now draw selected brushes + // + glTranslatef( g_qeglobals.d_select_translate[0], g_qeglobals.d_select_translate[1], g_qeglobals.d_select_translate[2]); + + glColor3f(1.0, 0.0, 0.0); + glEnable (GL_LINE_STIPPLE); + glLineStipple (3, 0xaaaa); + glLineWidth (2); + + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + drawn++; + Brush_DrawXY( brush ); + } + + glDisable (GL_LINE_STIPPLE); + glLineWidth (1); + + // edge / vertex flags + + if (g_qeglobals.d_select_mode == sel_vertex) + { + glPointSize (4); + glColor3f (0,1,0); + glBegin (GL_POINTS); + for (i=0 ; imins[0] + b->maxs[0])/2; + } + + dir[0] = 0; dir[1] = 1; dir[2] = 0; + + vright[0] = 0; vright[1] = 0; vright[2] = 0; + + // LBUTTON = manipulate selection + // shift-LBUTTON = select + // middle button = grab texture + // ctrl-middle button = set entire brush to texture + // ctrl-shift-middle button = set single face to texture + if ( (buttons == MK_LBUTTON) + || (buttons == (MK_LBUTTON | MK_SHIFT)) + || (buttons == MK_MBUTTON) +// || (buttons == (MK_MBUTTON|MK_CONTROL)) + || (buttons == (MK_MBUTTON|MK_SHIFT|MK_CONTROL)) ) + { + Drag_Begin (x, y, buttons, + vright, vup, + org, dir); + return; + } + + // control mbutton = move camera + if ((buttons == (MK_CONTROL|MK_MBUTTON) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + camera.origin[2] = org[2] ; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + + +} + +/* +============== +Z_MouseUp +============== +*/ +void Z_MouseUp (int x, int y, int buttons) +{ + Drag_MouseUp (); +} + +/* +============== +Z_MouseMoved +============== +*/ +void Z_MouseMoved (int x, int y, int buttons) +{ + if (!buttons) + return; + if (buttons == MK_LBUTTON) + { + Drag_MouseMoved (x, y, buttons); + Sys_UpdateWindows (W_Z|W_CAMERA); + return; + } + // rbutton = drag z origin + if (buttons == MK_RBUTTON) + { + Sys_GetCursorPos (&x, &y); + if ( y != cursory) + { + z.origin[2] += y-cursory; + Sys_SetCursorPos (cursorx, cursory); + Sys_UpdateWindows (W_Z); + } + return; + } + // control mbutton = move camera + if ((buttons == (MK_CONTROL|MK_MBUTTON) ) || (buttons == (MK_CONTROL|MK_LBUTTON))) + { + camera.origin[2] = (y - (z.height/2))/z.scale; + Sys_UpdateWindows (W_CAMERA|W_XY_OVERLAY|W_Z); + } + +} + + +/* +============================================================================ + +DRAWING + +============================================================================ +*/ + + +/* +============== +Z_DrawGrid +============== +*/ +void Z_DrawGrid (void) +{ + float zz, zb, ze; + int w, h; + char text[32]; + + w = z.width/2 / z.scale; + h = z.height/2 / z.scale; + + zb = z.origin[2] - h; + if (zb < region_mins[2]) + zb = region_mins[2]; + zb = 64 * floor (zb/64); + + ze = z.origin[2] + h; + if (ze > region_maxs[2]) + ze = region_maxs[2]; + ze = 64 * ceil (ze/64); + + // draw major blocks + + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMAJOR]); + + glBegin (GL_LINES); + + glVertex2f (0, zb); + glVertex2f (0, ze); + + for (zz=zb ; zz= 4) + { + glColor3fv(g_qeglobals.d_savedinfo.colors[COLOR_GRIDMINOR]); + + glBegin (GL_LINES); + for (zz=zb ; zznext) + { + if (brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) + continue; + + if (!Brush_Ray (org_top, dir_down, brush, &top)) + continue; + top = org_top[2] - top; + if (!Brush_Ray (org_bottom, dir_up, brush, &bottom)) + continue; + bottom = org_bottom[2] + bottom; + + q = Texture_ForName (brush->brush_faces->texdef.name); + glColor3f (q->color[0], q->color[1], q->color[2]); + glBegin (GL_QUADS); + glVertex2f (-xCam, bottom); + glVertex2f (xCam, bottom); + glVertex2f (xCam, top); + glVertex2f (-xCam, top); + glEnd (); + + glColor3f (1,1,1); + glBegin (GL_LINE_LOOP); + glVertex2f (-xCam, bottom); + glVertex2f (xCam, bottom); + glVertex2f (xCam, top); + glVertex2f (-xCam, top); + glEnd (); + } + + // + // now draw selected brushes + // + for (brush = selected_brushes.next ; brush != &selected_brushes ; brush=brush->next) + { + if ( !(brush->mins[0] >= z.origin[0] + || brush->maxs[0] <= z.origin[0] + || brush->mins[1] >= z.origin[1] + || brush->maxs[1] <= z.origin[1]) ) + { + if (Brush_Ray (org_top, dir_down, brush, &top)) + { + top = org_top[2] - top; + if (Brush_Ray (org_bottom, dir_up, brush, &bottom)) + { + bottom = org_bottom[2] + bottom; + + q = Texture_ForName (brush->brush_faces->texdef.name); + glColor3f (q->color[0], q->color[1], q->color[2]); + glBegin (GL_QUADS); + glVertex2f (-xCam, bottom); + glVertex2f (xCam, bottom); + glVertex2f (xCam, top); + glVertex2f (-xCam, top); + glEnd (); + } + } + } + + glColor3f (1,0,0); + glBegin (GL_LINE_LOOP); + glVertex2f (-xCam, brush->mins[2]); + glVertex2f (xCam, brush->mins[2]); + glVertex2f (xCam, brush->maxs[2]); + glVertex2f (-xCam, brush->maxs[2]); + glEnd (); + } + + + ZDrawCameraIcon (); + + glFinish(); + QE_CheckOpenGLForErrors(); + + if (z.timing) + { + end = Sys_DoubleTime (); + Sys_Printf ("z: %i ms\n", (int)(1000*(end-start))); + } +} + diff --git a/tools/quake2/extra/qe4/z.h b/tools/quake2/extra/qe4/z.h new file mode 100644 index 00000000..5e3545a6 --- /dev/null +++ b/tools/quake2/extra/qe4/z.h @@ -0,0 +1,42 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +// window system independent camera view code + +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; // at center of window + float scale; +} z_t; + +extern z_t z; + +void Z_Init (void); +void Z_MouseDown (int x, int y, int buttons); +void Z_MouseUp (int x, int y, int buttons); +void Z_MouseMoved (int x, int y, int buttons); +void Z_Draw (void); + diff --git a/tools/quake2/extra/texpaint/docs.txt b/tools/quake2/extra/texpaint/docs.txt new file mode 100644 index 00000000..f50759e9 --- /dev/null +++ b/tools/quake2/extra/texpaint/docs.txt @@ -0,0 +1,38 @@ + +Texpaint works with three data types: + +Skin textures +Model frames +S/T mappings + + +Skin textures can be either lbm or pcx files, and they will allways be +saved out the same size as loaded in, even if it is larger than the +active texture area. + +Model frames are alias .tri files. Adding support for 3ds would not +be difficult, but it is likely that there would be coordinate problems +unless the entire model was done completely in 3ds. + +S/T mappings allow a skin to be mapped onto any model frame. A mapping is +generated from a base frame and a texture size. If a coords.txt file is +not present, texpaint will generate a default mapping that is compatable +with the output of the old texmake. New skin or remap to skin will +generate a new coords.txt file. + + +Usage +----- +A three button mouse is required. + +The left button paints with the current color in either the skin window +or the camera window, or selects colors in the palette view. Ctrl-left +click picks up the color clicked on in any view, making it current. + +Right button dragging slides the object or skin around. Ctrl-right drag +to move in or out on the object. + +Middle button dragging rotates the object in the camera view. Ctrl-middle +drag to change the roll angle. + + diff --git a/tools/quake2/extra/texpaint/resource.h b/tools/quake2/extra/texpaint/resource.h new file mode 100644 index 00000000..7c26da1d --- /dev/null +++ b/tools/quake2/extra/texpaint/resource.h @@ -0,0 +1,58 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by texmake.rc +// +#define IDR_MENU1 101 +#define IDR_MENU2 102 +#define IDR_ACCELERATOR1 104 +#define IDD_NEWSKIN 105 +#define IDC_WIDTH 1000 +#define IDC_HEIGHT 1001 +#define ID_FILE_SAVEAS 4003 +#define ID_VIEW_MODELLINES 4006 +#define ID_VIEW_MODELLIGHTING 4008 +#define ID_FILE_OPENSKIN 4009 +#define ID_FILE_SAVESKIN 4010 +#define ID_FILE_SAVESKINAS 4011 +#define ID_FILE_EXIT 4012 +#define ID_FILE_OPENMODEL 4013 +#define ID_FILE_RELOADSKIN 4014 +#define ID_FILE_NEWSKIN 4016 +#define ID_FILE_OPENFRAME 4017 +#define ID_VIEW_SKINLINES 4018 +#define ID_VIEW_MODELINES 4019 +#define ID_VIEW_TEXTURELINES 4020 +#define ID_FILE_RESAMPLESKIN 4024 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 4025 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/tools/quake2/extra/texpaint/texmake.aps b/tools/quake2/extra/texpaint/texmake.aps new file mode 100644 index 0000000000000000000000000000000000000000..5a63f6cc81037601ec654473af83084e5fb92dea GIT binary patch literal 33472 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 Hn}h!crfN(| literal 0 HcmV?d00001 diff --git a/tools/quake2/extra/texpaint/texmake.rc b/tools/quake2/extra/texpaint/texmake.rc new file mode 100644 index 00000000..21a1eb10 --- /dev/null +++ b/tools/quake2/extra/texpaint/texmake.rc @@ -0,0 +1,156 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Menu +// + +IDR_MENU2 MENU DISCARDABLE +BEGIN + POPUP "&File" + BEGIN + MENUITEM "&New skin\tCtrl-n", ID_FILE_NEWSKIN + MENUITEM "&Open skin\tCtrl-o", ID_FILE_OPENSKIN + MENUITEM "&Reload skin\tCtrl-r", ID_FILE_RELOADSKIN + MENUITEM "&Save skin\tCtrl-s", ID_FILE_SAVESKIN + MENUITEM "Save skin &as\tCtrl-a", ID_FILE_SAVESKINAS + MENUITEM "Resample skin", ID_FILE_RESAMPLESKIN + MENUITEM SEPARATOR + MENUITEM "Open &frame\tCtrl-f", ID_FILE_OPENFRAME + MENUITEM SEPARATOR + MENUITEM "E&xit", ID_FILE_EXIT + END + POPUP "&Edit" + BEGIN + MENUITEM "&Undo\tCtrl-z", ID_EDIT_UNDO + MENUITEM "&Redo\tCtrl-y", ID_EDIT_REDO + END + POPUP "&View" + BEGIN + MENUITEM "&Model lines\tCtrl-m", ID_VIEW_MODELLINES + MENUITEM "&Texture lines\tCtrl-t", ID_VIEW_TEXTURELINES + MENUITEM "Model &lighting\tCtrl-l", ID_VIEW_MODELLIGHTING + END +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Accelerator +// + +IDR_ACCELERATOR1 ACCELERATORS DISCARDABLE +BEGIN + "A", ID_FILE_SAVESKINAS, VIRTKEY, CONTROL, NOINVERT + "F", ID_FILE_OPENFRAME, VIRTKEY, CONTROL, NOINVERT + "L", ID_VIEW_MODELLIGHTING, VIRTKEY, CONTROL, NOINVERT + "M", ID_VIEW_MODELLINES, VIRTKEY, CONTROL, NOINVERT + "N", ID_FILE_NEWSKIN, VIRTKEY, CONTROL, NOINVERT + "O", ID_FILE_OPENSKIN, VIRTKEY, CONTROL, NOINVERT + "R", ID_FILE_RELOADSKIN, VIRTKEY, CONTROL, NOINVERT + "S", ID_FILE_SAVESKIN, VIRTKEY, CONTROL, NOINVERT + "T", ID_VIEW_TEXTURELINES, VIRTKEY, CONTROL, NOINVERT + "Y", ID_EDIT_REDO, VIRTKEY, CONTROL, NOINVERT + "Z", ID_EDIT_UNDO, VIRTKEY, CONTROL, NOINVERT +END + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_NEWSKIN DIALOG DISCARDABLE 0, 0, 186, 95 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "New Skin" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,129,24,50,14 + EDITTEXT IDC_WIDTH,51,14,40,14,ES_AUTOHSCROLL + LTEXT "Width",IDC_STATIC,20,17,20,8 + EDITTEXT IDC_HEIGHT,51,37,40,14,ES_AUTOHSCROLL + LTEXT "height",IDC_STATIC,19,40,20,8 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_NEWSKIN, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 88 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/tools/quake2/extra/texpaint/texpaint.c b/tools/quake2/extra/texpaint/texpaint.c new file mode 100644 index 00000000..cad7028d --- /dev/null +++ b/tools/quake2/extra/texpaint/texpaint.c @@ -0,0 +1,311 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "texpaint.h" + +triangle_t *faces; +int numfaces; + +int skinwidth, skinheight; +int picwidth, picheight; +int width, height; +int iwidth, iheight; +int width2, height2; // padded to ^2 + +float tmcoords[10000][3][2]; + +byte pic[1024*512]; +unsigned rgb[1024*512]; + +float scale; +float s_scale, t_scale; + +char filename[1024]; +char picfilename[1024]; + + +/* +================ +BoundFaces +================ +*/ +vec3_t mins, maxs; + +void BoundFaces (void) +{ + int i,j,k; + triangle_t *pol; + float v; + + for (i=0 ; i<3 ; i++) + { + mins[i] = 9999; + maxs[i] = -9999; + } + + for (i=0 ; iverts[j][k]; + if (vmaxs[k]) + maxs[k] = v; + } + } + + for (i=0 ; i<3 ; i++) + { + mins[i] = floor(mins[i]); + maxs[i] = ceil(maxs[i]); + } + + width = maxs[0] - mins[0]; + height = maxs[2] - mins[2]; + + printf ("width: %i height: %i\n",width, height); + + if (!skinwidth) + { // old way + scale = 8; + if (width*scale >= 150) + scale = 150.0 / width; + if (height*scale >= 190) + scale = 190.0 / height; + s_scale = t_scale = scale; + iwidth = ceil(width*scale) + 4; + iheight = ceil(height*scale) + 4; + } + else + { // new way + s_scale = (skinwidth/2-4)/(float)width; + t_scale = (skinheight-4)/(float)height; + iwidth = skinwidth/2; + iheight = skinheight; + } + + printf ("scale: %f\n",scale); + printf ("iwidth: %i iheight: %i\n",iwidth, iheight); +} + + + +/* +============ +AddFace +============ +*/ +void AddFace (int facenum, triangle_t *f) +{ + vec3_t v1, v2, normal; + int basex, basey; + int i, j; + int coords[3][2]; + +// +// determine which side to map the teture to +// + VectorSubtract (f->verts[0], f->verts[1], v1); + VectorSubtract (f->verts[2], f->verts[1], v2); + CrossProduct (v1, v2, normal); + + if (normal[1] > 0) + basex = iwidth + 2; + else + basex = 2; + basey = 2; + + for (i=0 ; i<3 ; i++) + { + coords[i][0] = Q_rint((f->verts[i][0] - mins[0])*s_scale + basex); + coords[i][1] = Q_rint( (maxs[2] - f->verts[i][2])*t_scale + basey); +tmcoords[facenum][i][0] = coords[i][0]/(float)width2; +tmcoords[facenum][i][1] = coords[i][1]/(float)height2; + } + +} + + +void CalcTmCoords (void) +{ + int j; + + BoundFaces (); + + for (j=0 ; j 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + argv[argc] = lpCmdLine; + argc++; + + while (*lpCmdLine && ((*lpCmdLine > 32) && (*lpCmdLine <= 126))) + lpCmdLine++; + + if (*lpCmdLine) + { + *lpCmdLine = 0; + lpCmdLine++; + } + + } + } +} + +/* +================= +LoadTriFile +================= +*/ +void LoadTriFile (char *name) +{ + strcpy (tri_filename, name); + SetWindowText (camerawindow, tri_filename); + + LoadTriangleList (tri_filename, &faces, &numfaces); + InvalidateRect (camerawindow, NULL, false); +} + +/* +================== +TimerProc + +================== +*/ +int CALLBACK TimerProc( + HWND hwnd, // handle of window for timer messages + UINT uMsg, // WM_TIMER message + UINT idEvent, // timer identifier + DWORD dwTime // current system time + ) +{ + static int counter; + char name[1024]; + + if (!skin_filename[0]) + return 0; + + if (!modified_past_autosave) + { + counter = 0; + return 0; + } + + counter++; + + if (counter < 3*5) + return 0; // save every five minutes + + strcpy (name, skin_filename); + StripExtension (name); + strcat (name, "_autosave.lbm"); + Skin_SaveFile (name); + + modified_past_autosave = false; + counter = 0; + + return 0; +} + +/* +================== +WinMain + +================== +*/ +int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance + ,LPSTR lpCmdLine, int nCmdShow) +{ + MSG msg; + HACCEL accelerators; + + main_instance = hInstance; + + ParseCommandLine (lpCmdLine); + + screen_width = GetSystemMetrics (SM_CXFULLSCREEN); + screen_height = GetSystemMetrics (SM_CYFULLSCREEN); + + // hack for broken NT 4.0 dual screen + if (screen_width > 2*screen_height) + screen_width /= 2; + + accelerators = LoadAccelerators (hInstance + , MAKEINTRESOURCE(IDR_ACCELERATOR1)); + if (!accelerators) + Sys_Error ("LoadAccelerators failed"); + + Main_Create (hInstance); + WCam_Create (hInstance); + WPal_Create (hInstance); + WSkin_Create (hInstance); + + if (argc == 2) + Skin_LoadFile (argv[1]); + + SetTimer ( mainwindow, 1, 1000*20, TimerProc ); + + while (1) + { + if (!GetMessage (&msg, mainwindow, 0, 0)) + break; + if (!TranslateAccelerator(mainwindow, accelerators, &msg) ) + { + TranslateMessage (&msg); + DispatchMessage (&msg); + } + } + + /* return success of application */ + return TRUE; +} + diff --git a/tools/quake2/extra/texpaint/texpaint.h b/tools/quake2/extra/texpaint/texpaint.h new file mode 100644 index 00000000..15eaf9ed --- /dev/null +++ b/tools/quake2/extra/texpaint/texpaint.h @@ -0,0 +1,88 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "cmdlib.h" +#include "mathlib.h" +#include "lbmlib.h" +#include "trilib.h" +#include "l3dslib.h" + +#include +#include +#include +#include +#include "resource.h" +#include "afxres.h" + +extern HINSTANCE main_instance; + +extern HGLRC baseRC; + +extern HWND mainwindow; +extern HWND camerawindow; +extern HWND palettewindow; +extern HWND skinwindow; + +extern int screen_width, screen_height; + +#define QE3_STYLE (WS_OVERLAPPED| WS_CAPTION | WS_THICKFRAME | \ + /* WS_MINIMIZEBOX | */ WS_MAXIMIZEBOX | WS_CLIPSIBLINGS | \ + WS_CLIPCHILDREN | WS_CHILD) + +extern byte pic[1024*512]; +extern unsigned rgb[1024*512]; +extern unsigned index_texture[1024*512]; +extern byte palette[768]; + +extern triangle_t *faces; +extern int numfaces; +extern float tmcoords[10000][3][2]; + +extern int skinwidth, skinheight; +extern int picwidth, picheight; +extern int width, height; +extern int iwidth, iheight; +extern int width2, height2; // padded to ^2 + +extern char tri_filename[1024]; +extern char skin_filename[1024]; + +extern int selected_index; +extern unsigned selected_rgb; + +extern qboolean model_lines; +extern qboolean skin_lines; + +extern qboolean modified; +extern qboolean modified_past_autosave; + +#define TEXTURE_SKIN 1 +#define TEXTURE_INDEX 2 + +#define MENU_VIEW 2 + +#define MODEL_DISPLAYLIST 1 + +typedef void (APIENTRY *BINDTEXFUNCPTR)(GLenum, GLuint); + +extern BINDTEXFUNCPTR BindTextureEXT; + diff --git a/tools/quake2/extra/texpaint/texpaint.mak b/tools/quake2/extra/texpaint/texpaint.mak new file mode 100644 index 00000000..1a836604 --- /dev/null +++ b/tools/quake2/extra/texpaint/texpaint.mak @@ -0,0 +1,468 @@ +# Microsoft Developer Studio Generated NMAKE File, Format Version 4.20 +# ** DO NOT EDIT ** + +# TARGTYPE "Win32 (x86) Application" 0x0101 + +!IF "$(CFG)" == "" +CFG=texpaint - Win32 Debug +!MESSAGE No configuration specified. Defaulting to texpaint - Win32 Debug. +!ENDIF + +!IF "$(CFG)" != "texpaint - Win32 Release" && "$(CFG)" !=\ + "texpaint - Win32 Debug" +!MESSAGE Invalid configuration "$(CFG)" specified. +!MESSAGE You can specify a configuration when running NMAKE on this makefile +!MESSAGE by defining the macro CFG on the command line. For example: +!MESSAGE +!MESSAGE NMAKE /f "texpaint.mak" CFG="texpaint - Win32 Debug" +!MESSAGE +!MESSAGE Possible choices for configuration are: +!MESSAGE +!MESSAGE "texpaint - Win32 Release" (based on "Win32 (x86) Application") +!MESSAGE "texpaint - Win32 Debug" (based on "Win32 (x86) Application") +!MESSAGE +!ERROR An invalid configuration is specified. +!ENDIF + +!IF "$(OS)" == "Windows_NT" +NULL= +!ELSE +NULL=nul +!ENDIF +################################################################################ +# Begin Project +# PROP Target_Last_Scanned "texpaint - Win32 Debug" +MTL=mktyplib.exe +CPP=cl.exe +RSC=rc.exe + +!IF "$(CFG)" == "texpaint - Win32 Release" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 0 +# PROP BASE Output_Dir "Release" +# PROP BASE Intermediate_Dir "Release" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 0 +# PROP Output_Dir "Release" +# PROP Intermediate_Dir "Release" +# PROP Target_Dir "" +OUTDIR=.\Release +INTDIR=.\Release + +ALL : "$(OUTDIR)\texpaint.exe" + +CLEAN : + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\l3dslib.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\texmake.res" + -@erase "$(INTDIR)\texpaint.obj" + -@erase "$(INTDIR)\trilib.obj" + -@erase "$(INTDIR)\win_cam.obj" + -@erase "$(INTDIR)\win_main.obj" + -@erase "$(INTDIR)\win_pal.obj" + -@erase "$(INTDIR)\win_skin.obj" + -@erase "$(OUTDIR)\texpaint.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /YX /c +CPP_PROJ=/nologo /ML /GX /O2 /I "..\common" /D "WIN32" /D "NDEBUG" /D\ + "_WINDOWS" /Fp"$(INTDIR)/texpaint.pch" /YX /Fo"$(INTDIR)/" /c +CPP_OBJS=.\Release/ +CPP_SBRS=.\. +# ADD BASE MTL /nologo /D "NDEBUG" /win32 +# ADD MTL /nologo /D "NDEBUG" /win32 +MTL_PROJ=/nologo /D "NDEBUG" /win32 +# ADD BASE RSC /l 0x409 /d "NDEBUG" +# ADD RSC /l 0x409 /d "NDEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/texmake.res" /d "NDEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/texpaint.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +# ADD LINK32 opengl32.lib glu32.lib glaux.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 +LINK32_FLAGS=opengl32.lib glu32.lib glaux.lib kernel32.lib user32.lib gdi32.lib\ + winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\ + uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /incremental:no\ + /pdb:"$(OUTDIR)/texpaint.pdb" /machine:I386 /out:"$(OUTDIR)/texpaint.exe" +LINK32_OBJS= \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\l3dslib.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\texmake.res" \ + "$(INTDIR)\texpaint.obj" \ + "$(INTDIR)\trilib.obj" \ + "$(INTDIR)\win_cam.obj" \ + "$(INTDIR)\win_main.obj" \ + "$(INTDIR)\win_pal.obj" \ + "$(INTDIR)\win_skin.obj" + +"$(OUTDIR)\texpaint.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ELSEIF "$(CFG)" == "texpaint - Win32 Debug" + +# PROP BASE Use_MFC 0 +# PROP BASE Use_Debug_Libraries 1 +# PROP BASE Output_Dir "texpaint" +# PROP BASE Intermediate_Dir "texpaint" +# PROP BASE Target_Dir "" +# PROP Use_MFC 0 +# PROP Use_Debug_Libraries 1 +# PROP Output_Dir "Debug" +# PROP Intermediate_Dir "Debug" +# PROP Target_Dir "" +OUTDIR=.\Debug +INTDIR=.\Debug + +ALL : "$(OUTDIR)\texpaint.exe" + +CLEAN : + -@erase "$(INTDIR)\cmdlib.obj" + -@erase "$(INTDIR)\l3dslib.obj" + -@erase "$(INTDIR)\lbmlib.obj" + -@erase "$(INTDIR)\mathlib.obj" + -@erase "$(INTDIR)\scriplib.obj" + -@erase "$(INTDIR)\texmake.res" + -@erase "$(INTDIR)\texpaint.obj" + -@erase "$(INTDIR)\trilib.obj" + -@erase "$(INTDIR)\vc40.idb" + -@erase "$(INTDIR)\vc40.pdb" + -@erase "$(INTDIR)\win_cam.obj" + -@erase "$(INTDIR)\win_main.obj" + -@erase "$(INTDIR)\win_pal.obj" + -@erase "$(INTDIR)\win_skin.obj" + -@erase "$(OUTDIR)\texpaint.exe" + +"$(OUTDIR)" : + if not exist "$(OUTDIR)/$(NULL)" mkdir "$(OUTDIR)" + +# ADD BASE CPP /nologo /W3 /Gm /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /YX /c +# ADD CPP /nologo /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "WIN_ERROR" /YX /c +CPP_PROJ=/nologo /MLd /Gm /GX /Zi /Od /I "..\common" /D "WIN32" /D "_DEBUG" /D\ + "_WINDOWS" /D "WIN_ERROR" /Fp"$(INTDIR)/texpaint.pch" /YX /Fo"$(INTDIR)/"\ + /Fd"$(INTDIR)/" /c +CPP_OBJS=.\Debug/ +CPP_SBRS=.\. +# ADD BASE MTL /nologo /D "_DEBUG" /win32 +# ADD MTL /nologo /D "_DEBUG" /win32 +MTL_PROJ=/nologo /D "_DEBUG" /win32 +# ADD BASE RSC /l 0x409 /d "_DEBUG" +# ADD RSC /l 0x409 /d "_DEBUG" +RSC_PROJ=/l 0x409 /fo"$(INTDIR)/texmake.res" /d "_DEBUG" +BSC32=bscmake.exe +# ADD BASE BSC32 /nologo +# ADD BSC32 /nologo +BSC32_FLAGS=/nologo /o"$(OUTDIR)/texpaint.bsc" +BSC32_SBRS= \ + +LINK32=link.exe +# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 +# ADD LINK32 opengl32.lib glu32.lib glaux.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /pdb:none /debug /machine:I386 +LINK32_FLAGS=opengl32.lib glu32.lib glaux.lib kernel32.lib user32.lib gdi32.lib\ + winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib\ + uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /pdb:none /debug\ + /machine:I386 /out:"$(OUTDIR)/texpaint.exe" +LINK32_OBJS= \ + "$(INTDIR)\cmdlib.obj" \ + "$(INTDIR)\l3dslib.obj" \ + "$(INTDIR)\lbmlib.obj" \ + "$(INTDIR)\mathlib.obj" \ + "$(INTDIR)\scriplib.obj" \ + "$(INTDIR)\texmake.res" \ + "$(INTDIR)\texpaint.obj" \ + "$(INTDIR)\trilib.obj" \ + "$(INTDIR)\win_cam.obj" \ + "$(INTDIR)\win_main.obj" \ + "$(INTDIR)\win_pal.obj" \ + "$(INTDIR)\win_skin.obj" + +"$(OUTDIR)\texpaint.exe" : "$(OUTDIR)" $(DEF_FILE) $(LINK32_OBJS) + $(LINK32) @<< + $(LINK32_FLAGS) $(LINK32_OBJS) +<< + +!ENDIF + +.c{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_OBJS)}.obj: + $(CPP) $(CPP_PROJ) $< + +.c{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cpp{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +.cxx{$(CPP_SBRS)}.sbr: + $(CPP) $(CPP_PROJ) $< + +################################################################################ +# Begin Target + +# Name "texpaint - Win32 Release" +# Name "texpaint - Win32 Debug" + +!IF "$(CFG)" == "texpaint - Win32 Release" + +!ELSEIF "$(CFG)" == "texpaint - Win32 Debug" + +!ENDIF + +################################################################################ +# Begin Source File + +SOURCE=.\texpaint.c +DEP_CPP_TEXPA=\ + "..\common\cmdlib.h"\ + "..\common\l3dslib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\trilib.h"\ + ".\texpaint.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\texpaint.obj" : $(SOURCE) $(DEP_CPP_TEXPA) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\mathlib.c +DEP_CPP_MATHL=\ + "..\..\..\quake\utils2\common\cmdlib.h"\ + "..\..\..\quake\utils2\common\mathlib.h"\ + + +"$(INTDIR)\mathlib.obj" : $(SOURCE) $(DEP_CPP_MATHL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\l3dslib.c +DEP_CPP_L3DSL=\ + "..\..\..\quake\utils2\common\cmdlib.h"\ + "..\..\..\quake\utils2\common\l3dslib.h"\ + "..\..\..\quake\utils2\common\mathlib.h"\ + "..\..\..\quake\utils2\common\trilib.h"\ + + +"$(INTDIR)\l3dslib.obj" : $(SOURCE) $(DEP_CPP_L3DSL) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\lbmlib.c +DEP_CPP_LBMLI=\ + "..\..\..\quake\utils2\common\cmdlib.h"\ + "..\..\..\quake\utils2\common\lbmlib.h"\ + + +"$(INTDIR)\lbmlib.obj" : $(SOURCE) $(DEP_CPP_LBMLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\scriplib.c +DEP_CPP_SCRIP=\ + "..\..\..\quake\utils2\common\cmdlib.h"\ + "..\..\..\quake\utils2\common\scriplib.h"\ + + +"$(INTDIR)\scriplib.obj" : $(SOURCE) $(DEP_CPP_SCRIP) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\trilib.c +DEP_CPP_TRILI=\ + "..\..\..\quake\utils2\common\cmdlib.h"\ + "..\..\..\quake\utils2\common\mathlib.h"\ + "..\..\..\quake\utils2\common\trilib.h"\ + + +"$(INTDIR)\trilib.obj" : $(SOURCE) $(DEP_CPP_TRILI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_skin.c +DEP_CPP_WIN_S=\ + "..\common\cmdlib.h"\ + "..\common\l3dslib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\trilib.h"\ + ".\texpaint.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_skin.obj" : $(SOURCE) $(DEP_CPP_WIN_S) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_main.c +DEP_CPP_WIN_M=\ + "..\common\cmdlib.h"\ + "..\common\l3dslib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\trilib.h"\ + ".\texpaint.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_main.obj" : $(SOURCE) $(DEP_CPP_WIN_M) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_pal.c +DEP_CPP_WIN_P=\ + "..\common\cmdlib.h"\ + "..\common\l3dslib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\trilib.h"\ + ".\texpaint.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_pal.obj" : $(SOURCE) $(DEP_CPP_WIN_P) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\win_cam.c +DEP_CPP_WIN_C=\ + "..\common\cmdlib.h"\ + "..\common\l3dslib.h"\ + "..\common\lbmlib.h"\ + "..\common\mathlib.h"\ + "..\common\trilib.h"\ + ".\texpaint.h"\ + {$(INCLUDE)}"\gl\GL.H"\ + {$(INCLUDE)}"\gl\GLAUX.H"\ + {$(INCLUDE)}"\gl\GLU.H"\ + + +"$(INTDIR)\win_cam.obj" : $(SOURCE) $(DEP_CPP_WIN_C) "$(INTDIR)" + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\texmake.rc + +"$(INTDIR)\texmake.res" : $(SOURCE) "$(INTDIR)" + $(RSC) $(RSC_PROJ) $(SOURCE) + + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=.\texpaint.h + +!IF "$(CFG)" == "texpaint - Win32 Release" + +!ELSEIF "$(CFG)" == "texpaint - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\lbmlib.h + +!IF "$(CFG)" == "texpaint - Win32 Release" + +!ELSEIF "$(CFG)" == "texpaint - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.h + +!IF "$(CFG)" == "texpaint - Win32 Release" + +!ELSEIF "$(CFG)" == "texpaint - Win32 Debug" + +!ENDIF + +# End Source File +################################################################################ +# Begin Source File + +SOURCE=\quake\utils2\common\cmdlib.c +DEP_CPP_CMDLI=\ + "..\..\..\quake\utils2\common\cmdlib.h"\ + {$(INCLUDE)}"\sys\stat.h"\ + {$(INCLUDE)}"\sys\types.h"\ + + +"$(INTDIR)\cmdlib.obj" : $(SOURCE) $(DEP_CPP_CMDLI) "$(INTDIR)" + $(CPP) $(CPP_PROJ) $(SOURCE) + + +# End Source File +# End Target +# End Project +################################################################################ diff --git a/tools/quake2/extra/texpaint/win_cam.c b/tools/quake2/extra/texpaint/win_cam.c new file mode 100644 index 00000000..5e1986d7 --- /dev/null +++ b/tools/quake2/extra/texpaint/win_cam.c @@ -0,0 +1,414 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "texpaint.h" + +#define CAMERA_WINDOW_CLASS "TPCamera" + +HDC camdc; +HGLRC baseRC; + +float pitch, yaw, roll; +qboolean model_lines = false; + +float cam_x, cam_y=-64, cam_z=32; + +int cam_width, cam_height; + +BINDTEXFUNCPTR BindTextureEXT; + +void InitIndexTexture (void) +{ + int i; + + BindTextureEXT (GL_TEXTURE_2D, TEXTURE_INDEX); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + + for (i=0 ; i= width2*height2) + return; + + if (index == cam_last_index) + return; // in same pixel + cam_last_index = index; + if (shift) + { + Pal_SetIndex (pic[index]); + return; + } + + SetSkin (index, selected_rgb); + UpdateWindow (camerawindow); +} + + +void Cam_DrawSetup (void) +{ + glViewport (0,0,cam_width, cam_height); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + gluPerspective (90, (float)cam_width/cam_height, 2, 1024); + gluLookAt (cam_x, cam_y, cam_z, cam_x, cam_y+1, cam_z, 0, 0, 1); + + glRotated (-roll*0.3, 0, 1, 0); + glRotated (-pitch*0.3, 1, 0, 0); + glRotated (yaw*0.3, 0, 0, 1); + + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + glEnable (GL_DEPTH_TEST); + glEnable (GL_CULL_FACE); + glEnable (GL_TEXTURE_2D); + glCullFace (GL_FRONT); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); +} + +void Cam_Draw (void) +{ + if (!cam_width || !cam_height) + return; + + glClearColor (0.3,0.3,0.3,1); + Cam_DrawSetup (); + + BindTextureEXT (GL_TEXTURE_2D, TEXTURE_SKIN); + + DrawModel (); + + if (model_lines) + { + glDisable (GL_TEXTURE_2D); + glPolygonMode (GL_FRONT_AND_BACK, GL_LINE); + glDepthFunc (GL_LEQUAL); + glDepthRange (0, 0.999); // nudge depth to avoid dropouts + DrawModel (); + glDepthRange (0, 1); + + glPolygonMode (GL_FRONT_AND_BACK, GL_FILL); + glEnable (GL_TEXTURE_2D); + } + + SwapBuffers(camdc); + + // now fill the back buffer with the index texture + glClearColor (0,0,0,0); + glClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + BindTextureEXT (GL_TEXTURE_2D, TEXTURE_INDEX); + DrawModel (); + + BindTextureEXT (GL_TEXTURE_2D, TEXTURE_SKIN); +} + + + +/* +============ +CameraWndProc +============ +*/ +LONG WINAPI WCam_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 1; + int fwKeys, xPos, yPos; + RECT rect; + static int oldx, oldy; + POINT pt; + + GetClientRect(hWnd, &rect); + cam_width = rect.right-rect.left; + cam_height = rect.bottom-rect.top; + + switch (uMsg) + { + case WM_CREATE: + camdc = GetDC(hWnd); + bSetupPixelFormat(camdc); + + baseRC = wglCreateContext( camdc ); + if (!baseRC) + Sys_Error ("wglCreateContext failed"); + if (!wglMakeCurrent( camdc, baseRC )) + Sys_Error ("wglMakeCurrent failed"); + BindTextureEXT = (void *)wglGetProcAddress((LPCSTR) "glBindTextureEXT"); + if (!BindTextureEXT) + Sys_Error ("GetProcAddress for BindTextureEXT failed"); + + break; + case WM_PAINT: + { + PAINTSTRUCT ps; + + BeginPaint(hWnd, &ps); + if (!wglMakeCurrent( camdc, baseRC )) + Sys_Error ("wglMakeCurrent failed"); + Cam_Draw (); + EndPaint(hWnd, &ps); + } + break; + + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + if (GetTopWindow(mainwindow) != hWnd) + BringWindowToTop(hWnd); + + SetFocus (camerawindow); + SetCapture (camerawindow); + GetCursorPos (&pt); + xPos = pt.x; + yPos = pt.y; + oldx = xPos; + oldy = yPos; + break; + + case WM_LBUTTONDOWN: + cam_last_index = -1; +draw: + if (GetTopWindow(mainwindow) != hWnd) + BringWindowToTop(hWnd); + + SetFocus (camerawindow); + SetCapture (camerawindow); + fwKeys = wParam; // key flags + xPos = (short)LOWORD(lParam); // horizontal position of cursor + yPos = (short)HIWORD(lParam); // vertical position of cursor + yPos = (int)rect.bottom - 1 - yPos; + if (!wglMakeCurrent( camdc, baseRC )) + Sys_Error ("wglMakeCurrent failed"); + + Cam_Click (xPos, yPos, !!(wParam&(MK_SHIFT|MK_CONTROL)) ); + +// Cam_MouseDown (xPos, yPos, fwKeys); + break; + + case WM_MBUTTONUP: + case WM_RBUTTONUP: + case WM_LBUTTONUP: + if (! (wParam & (MK_LBUTTON|MK_RBUTTON|MK_MBUTTON))) + ReleaseCapture (); + break; + + case WM_MOUSEMOVE: + { + int dx, dy; + + if (wParam & MK_LBUTTON) + goto draw; + + GetCursorPos (&pt); + xPos = pt.x; + yPos = pt.y; + if (!(wParam & (MK_RBUTTON|MK_MBUTTON))) + { + oldx = xPos; + oldy = yPos; + break; + } + dx = xPos-oldx; + dy = oldy-yPos; + if (!dx && !dy) + break; + SetCursorPos (oldx, oldy); + + if (wParam == (MK_RBUTTON|MK_CONTROL) ) + { + if (abs(dx) > abs(dy)) + cam_y -= 0.1*dx; + else + cam_y -= 0.1*dy; + InvalidateRect (camerawindow, NULL, false); + } + if (wParam == MK_RBUTTON) + { + cam_x -= 0.1*dx; + cam_z -= 0.1*dy; + InvalidateRect (camerawindow, NULL, false); + } + if (wParam == (MK_MBUTTON|MK_CONTROL) ) + { + if (abs(dx) > abs(dy)) + roll -= dx; + else + roll -= dy; + InvalidateRect (camerawindow, NULL, false); + } + if (wParam == MK_MBUTTON) + { + yaw += dx; + pitch += dy; + InvalidateRect (camerawindow, NULL, false); + } + } + break; + + + + case WM_SIZE: +// camera.width = rect.right; +// camera.height = rect.bottom; + InvalidateRect(camerawindow, NULL, false); + break; + case WM_NCCALCSIZE:// don't let windows copy pixels + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + case WM_CLOSE: + /* call destroy window to cleanup and go away */ + DestroyWindow (hWnd); + break; + + case WM_DESTROY: + { + HGLRC hRC; + HDC hDC; + + /* release and free the device context and rendering context */ + hRC = wglGetCurrentContext(); + hDC = wglGetCurrentDC(); + + wglMakeCurrent(NULL, NULL); + + if (hRC) + wglDeleteContext(hRC); + if (hDC) + ReleaseDC(hWnd, hDC); + } + break; + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 1 if handled message, 0 if not */ + return lRet; +} + + +/* +============== +WCam_Register +============== +*/ +void WCam_Register (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WCam_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = CAMERA_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Sys_Error ("WCam_Register: failed"); +} + + +void WCam_Create (HINSTANCE hInstance) +{ + WCam_Register (hInstance); + + camerawindow = CreateWindow (CAMERA_WINDOW_CLASS , + "Camera View", + QE3_STYLE, + 0, + 0, + (int)(screen_width*0.5), + (int)(screen_height-20), // size + + mainwindow, // parent window + 0, // no menu + hInstance, + 0); + if (!camerawindow) + Sys_Error ("Couldn't create camerawindow"); + + RestoreWindowState(camerawindow, "camerawindow"); + ShowWindow (camerawindow, SW_SHOWDEFAULT); +} diff --git a/tools/quake2/extra/texpaint/win_main.c b/tools/quake2/extra/texpaint/win_main.c new file mode 100644 index 00000000..d377d7ba --- /dev/null +++ b/tools/quake2/extra/texpaint/win_main.c @@ -0,0 +1,496 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "texpaint.h" + +HINSTANCE main_instance; + +int screen_width, screen_height; + +HWND mainwindow; +HWND camerawindow; +HWND palettewindow; +HWND skinwindow; + +/* +================= +Sys_Error + +For abnormal program terminations +================= +*/ +void Sys_Error (char *error, ...) +{ + va_list argptr; + char text[1024]; + char text2[1024]; + int err; + + err = GetLastError (); + + va_start (argptr,error); + vsprintf (text, error,argptr); + va_end (argptr); + + sprintf (text2, "%s\nGetLastError() = %i", text, err); + MessageBox(mainwindow, text2, "Error", 0 /* MB_OK */ ); + + exit (1); +} + + +/* +====================================================================== + +FILE DIALOGS + +====================================================================== +*/ + +qboolean modified; +qboolean modified_past_autosave; + +qboolean ConfirmModified (void) +{ + if (!modified) + return true; + + if (MessageBox (mainwindow, "This will lose changes to the skin" + , "warning", MB_OKCANCEL) == IDCANCEL) + return false; + return true; +} + +OPENFILENAME ofn; /* common dialog box structure */ +char szDirName[MAX_PATH]; /* directory string */ +char szFile[260]; /* filename string */ +char szFileTitle[260]; /* file title string */ +char szSkinFilter[260] = /* filter string */ + "Skin texture (*.lbm *.pcx)\0*.lbm;*.pcx\0\0"; +char szFrameFilter[260] = /* filter string */ + "Model frame (*.tri)\0*.tri\0\0"; +char chReplace; /* string separator for szFilter */ +int i, cbString; /* integer count variables */ +HANDLE hf; /* file handle */ + +void OpenSkinDialog (void) +{ +// strcpy (szDirName, ValueForKey (project_entity, "basepath") ); +// strcat (szDirName, "\\maps"); + + /* Place the terminating null character in the szFile. */ + + szFile[0] = '\0'; + + /* Set the members of the OPENFILENAME structure. */ + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = mainwindow; + ofn.lpstrFilter = szSkinFilter; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = sizeof(szFileTitle); + ofn.lpstrInitialDir = szDirName; + ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | + OFN_FILEMUSTEXIST; + + /* Display the Open dialog box. */ + + if (!GetOpenFileName(&ofn)) + return; // canceled + + Skin_LoadFile (ofn.lpstrFile); +} + +void OpenFrameDialog (void) +{ +// strcpy (szDirName, ValueForKey (project_entity, "basepath") ); +// strcat (szDirName, "\\maps"); + + /* Place the terminating null character in the szFile. */ + + szFile[0] = '\0'; + + /* Set the members of the OPENFILENAME structure. */ + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = mainwindow; + ofn.lpstrFilter = szFrameFilter; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = sizeof(szFileTitle); + ofn.lpstrInitialDir = szDirName; + ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | + OFN_FILEMUSTEXIST; + + /* Display the Open dialog box. */ + + if (!GetOpenFileName(&ofn)) + return; // canceled + + LoadTriFile (ofn.lpstrFile); +} + +void SaveSkinDialog (void) +{ +// strcpy (szDirName, ValueForKey (project_entity, "basepath") ); +// strcat (szDirName, "\\maps"); + + /* Place the terminating null character in the szFile. */ + + szFile[0] = '\0'; + + /* Set the members of the OPENFILENAME structure. */ + + ofn.lStructSize = sizeof(OPENFILENAME); + ofn.hwndOwner = mainwindow; + ofn.lpstrFilter = szSkinFilter; + ofn.nFilterIndex = 1; + ofn.lpstrFile = szFile; + ofn.nMaxFile = sizeof(szFile); + ofn.lpstrFileTitle = szFileTitle; + ofn.nMaxFileTitle = sizeof(szFileTitle); + ofn.lpstrInitialDir = szDirName; + ofn.Flags = OFN_SHOWHELP | OFN_PATHMUSTEXIST | + OFN_FILEMUSTEXIST; + + /* Display the Open dialog box. */ + + if (!GetSaveFileName(&ofn)) + return; // canceled + + DefaultExtension (ofn.lpstrFile, ".lbm"); + Skin_SaveFile (ofn.lpstrFile); + strcpy (skin_filename, ofn.lpstrFile); +} + +//========================================================================== + +BOOL bSetupPixelFormat(HDC hDC) +{ + static PIXELFORMATDESCRIPTOR pfd = { + sizeof(PIXELFORMATDESCRIPTOR), // size of this pfd + 1, // version number + PFD_DRAW_TO_WINDOW | // support window + PFD_SUPPORT_OPENGL | // support OpenGL + PFD_DOUBLEBUFFER, // double buffered + PFD_TYPE_RGBA, // RGBA type + 24, // 24-bit color depth + 0, 0, 0, 0, 0, 0, // color bits ignored + 0, // no alpha buffer + 0, // shift bit ignored + 0, // no accumulation buffer + 0, 0, 0, 0, // accum bits ignored + 32, // 32-bit z-buffer + 0, // no stencil buffer + 0, // no auxiliary buffer + PFD_MAIN_PLANE, // main layer + 0, // reserved + 0, 0, 0 // layer masks ignored + }; + int pixelformat = 0; + PIXELFORMATDESCRIPTOR newp; + + if ( (pixelformat = ChoosePixelFormat(hDC, &pfd)) == 0 ) + { + printf("%d",GetLastError()); + Error ("ChoosePixelFormat failed"); + } + if (!SetPixelFormat(hDC, pixelformat, &pfd)) + Error ("SetPixelFormat failed"); + + return TRUE; +} + + +/* +============================================================================== + + MENU + +============================================================================== +*/ + + +/* handle all WM_COMMAND messages here */ +LONG WINAPI CommandHandler ( + HWND hWnd, + WPARAM wParam, + LPARAM lParam) +{ + unsigned short cmd; + + cmd = LOWORD(wParam); + + switch (cmd) + { + // + // file menu + // + case ID_FILE_RESAMPLESKIN: + ResampleSkin (); + break; + + case ID_FILE_NEWSKIN: + NewSkin (); + break; + + case ID_FILE_OPENFRAME: + OpenFrameDialog (); + break; + + case ID_FILE_OPENSKIN: + if (!ConfirmModified()) + break; + OpenSkinDialog (); + break; + + case ID_FILE_RELOADSKIN: + if (!ConfirmModified()) + break; + Skin_LoadFile (skin_filename); + break; + + case ID_FILE_SAVESKIN: + Skin_SaveFile (skin_filename); + break; + + case ID_FILE_SAVESKINAS: + SaveSkinDialog (); + break; + case ID_FILE_EXIT: + if (!ConfirmModified()) + break; + PostQuitMessage (0); + break; + + // + // edit menu + // + case ID_EDIT_UNDO: + Undo(); + break; + case ID_EDIT_REDO: + Redo(); + break; + + // + // view menu + // + case ID_VIEW_MODELLINES: + model_lines ^= 1; + CheckMenuItem ( GetSubMenu (GetMenu(mainwindow), MENU_VIEW) + , ID_VIEW_MODELLINES + , MF_BYCOMMAND | (model_lines ? MF_CHECKED : MF_UNCHECKED) ); + InvalidateRect (camerawindow, NULL, false); + break; + case ID_VIEW_TEXTURELINES: + skin_lines ^= 1; + CheckMenuItem ( GetSubMenu (GetMenu(mainwindow), MENU_VIEW) + , ID_VIEW_TEXTURELINES + , MF_BYCOMMAND | (skin_lines ? MF_CHECKED : MF_UNCHECKED) ); + InvalidateRect (skinwindow, NULL, false); + break; + default: + return FALSE; + } + + return TRUE; +} + +/* +============ +WMAIN_WndProc +============ +*/ +LONG WINAPI WMAIN_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + LONG lRet = 1; + RECT rect; + HDC maindc; + + GetClientRect(hWnd, &rect); + + switch (uMsg) + { + case WM_CREATE: + maindc = GetDC(hWnd); + bSetupPixelFormat(maindc); + break; + case WM_COMMAND: + lRet = CommandHandler (hWnd, wParam, lParam); + break; + + case WM_CLOSE: + if (!ConfirmModified()) + break; + PostQuitMessage (0); + break; + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 1 if handled message, 0 if not */ + return lRet; +} + + + + +/* +============== +Main_Create +============== +*/ +void Main_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)WMAIN_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wc.lpszMenuName = MAKEINTRESOURCE(IDR_MENU2); + wc.lpszClassName = "TEXPAINT_MAIN"; + + if (!RegisterClass (&wc) ) + Error ("WCam_Register: failed"); + + + mainwindow = CreateWindow ("TEXPAINT_MAIN" , + "Texpaint", + WS_OVERLAPPEDWINDOW | + WS_CLIPSIBLINGS | + WS_CLIPCHILDREN, + 0,0,screen_width,screen_height, // size + 0, + NULL, // no menu + hInstance, + NULL); + if (!mainwindow) + Error ("Couldn't create main window"); + +// GetWindowInfo("mainwindow", &SavedInfo, NULL); + ShowWindow (mainwindow, SW_SHOWDEFAULT); +} + + + + +BOOL SaveWindowInfo(const char *pszName, void *pvBuf, long lSize) +{ + LONG lres; + DWORD dwDisp; + HKEY hKeyId; + + lres = RegCreateKeyEx(HKEY_CURRENT_USER, "Software\\id\\Texpaint", 0, NULL, + REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKeyId, &dwDisp); + + if (lres != ERROR_SUCCESS) + return FALSE; + + lres = RegSetValueEx(hKeyId, pszName, 0, REG_BINARY, pvBuf, lSize); + + RegCloseKey(hKeyId); + + if (lres != ERROR_SUCCESS) + return FALSE; + + return TRUE; +} + + +BOOL GetWindowInfo(const char *pszName, void *pvBuf, long *plSize) +{ + HKEY hKey; + long lres, lType, lSize; + + if (plSize == NULL) + plSize = &lSize; + + lres = RegOpenKeyEx(HKEY_CURRENT_USER, "Software\\id\\Texpaint", 0, KEY_READ, &hKey); + + if (lres != ERROR_SUCCESS) + return FALSE; + + lres = RegQueryValueEx(hKey, pszName, NULL, &lType, pvBuf, plSize); + + RegCloseKey(hKey); + + if (lres != ERROR_SUCCESS) + return FALSE; + + return TRUE; + +} + +BOOL SaveWindowState(HWND hWnd, const char *pszName) +{ + RECT rc; + + GetWindowRect(hWnd, &rc); + MapWindowPoints(NULL, mainwindow, (POINT *)&rc, 2); + return SaveWindowInfo(pszName, &rc, sizeof(rc)); +} + + +BOOL RestoreWindowState(HWND hWnd, const char *pszName) +{ + RECT rc; + LONG lSize = sizeof(rc); + + if (GetWindowInfo(pszName, &rc, &lSize)) + { + if (rc.left < 0) + rc.left = 0; + if (rc.top < 0) + rc.top = 0; + if (rc.right < rc.left + 16) + rc.right = rc.left + 16; + if (rc.bottom < rc.top + 16) + rc.bottom = rc.top + 16; + + MoveWindow(hWnd, rc.left, rc.top, rc.right - rc.left, + rc.bottom - rc.top, FALSE); + return TRUE; + } + + return FALSE; +} + diff --git a/tools/quake2/extra/texpaint/win_pal.c b/tools/quake2/extra/texpaint/win_pal.c new file mode 100644 index 00000000..09ebe51f --- /dev/null +++ b/tools/quake2/extra/texpaint/win_pal.c @@ -0,0 +1,257 @@ +/* +=========================================================================== +Copyright (C) 1997-2006 Id Software, Inc. + +This file is part of Quake 2 Tools source code. + +Quake 2 Tools source code is free software; you can redistribute it +and/or modify it under the terms of the GNU General Public License as +published by the Free Software Foundation; either version 2 of the License, +or (at your option) any later version. + +Quake 2 Tools source code 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Quake 2 Tools source code; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +=========================================================================== +*/ + +#include "texpaint.h" + +#define PALETTE_WINDOW_CLASS "TPPalette" + +HDC paldc; +int pal_width, pal_height; +int blocks_x, blocks_y; + +int selected_index; +unsigned selected_rgb; + +byte palette[768]; + +float SnapAspect (float aspect) +{ + if (aspect > 128) + return 256; + if (aspect > 32) + return 128; + if (aspect > 8) + return 64; + if (aspect > 2) + return 32; + return 16; +} + +void Pal_SetIndex (int index) +{ + selected_index = index; + selected_rgb = palette[index*3] + (palette[index*3+1]<<8) + (palette[index*3+2]<<16); + InvalidateRect (palettewindow, NULL, false); +} + +void Pal_Draw (void) +{ + int x, y; + float aspect; + float xs, ys; + int c; + + if (pal_width < 1 || pal_height < 1) + return; + + // + // determine the block arrangement + // + if (pal_width > pal_height) + { + aspect = SnapAspect (pal_width / pal_height); + blocks_x = aspect; + blocks_y = 256/blocks_x; + } + else + { + aspect = SnapAspect (pal_height / pal_width); + blocks_y = aspect; + blocks_x = 256/blocks_y; + } + + // + // draw it + // + glViewport (0,0,pal_width, pal_height); + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0,1,0,1,-100,100); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glClear (GL_COLOR_BUFFER_BIT); + glDisable (GL_DEPTH_TEST); + glDisable (GL_CULL_FACE); + glDisable (GL_TEXTURE_2D); + + xs = 1.0/blocks_x; + ys = 1.0/blocks_y; + + for (x=0 ; xoffset = index; + m->oldvalue = pic[index]; + + modify_index = (++undo_index)&(MAX_MODIFY-1); + + // modify it + rgb[index] = selected_rgb; + pic[index] = selected_index; + UpdateTexture (index); + InvalidateRect (skinwindow, NULL, false); + InvalidateRect (camerawindow, NULL, false); +} + +void Undo (void) +{ + modify_t *m; + int temp; + + if (!undo_index) + return; + + if (!--undo_index) + { // back to unmodified state + modified = false; + SetWindowText (skinwindow, skin_filename); + } + m = &modify[undo_index]; + + // modify it + temp = pic[m->offset]; + pic[m->offset] = m->oldvalue; + rgb[m->offset] = palette[m->oldvalue*3] + + (palette[m->oldvalue*3+1]<<8) + (palette[m->oldvalue*3+2]<<16); + m->oldvalue = temp; + UpdateTexture (m->offset); + InvalidateRect (skinwindow, NULL, false); + InvalidateRect (camerawindow, NULL, false); + +} + +void Redo (void) +{ + modify_t *m; + int temp; + + if (undo_index == modify_index) + return; + + m = &modify[undo_index]; + + // modify it + temp = pic[m->offset]; + pic[m->offset] = m->oldvalue; + rgb[m->offset] = palette[m->oldvalue*3] + + (palette[m->oldvalue*3+1]<<8) + (palette[m->oldvalue*3+2]<<16); + m->oldvalue = temp; + UpdateTexture (m->offset); + InvalidateRect (skinwindow, NULL, false); + InvalidateRect (camerawindow, NULL, false); + + if (!undo_index++) + { // modified again + char text[1024]; + + modified = true; + sprintf (text, "%s *", skin_filename); + SetWindowText (skinwindow, text); + } +} + +//=================================================================== + +/* +============= +Skin_SaveFile + +Load a skin texture and the base.tri from the same directory +============= +*/ +void Skin_SaveFile (char *name) +{ + byte *data; + int i, j; + char backup[1024]; + + // back up the current file if it exists + sprintf (backup, "%s.bak", name); + remove (backup); + rename (name, backup); + + modified = false; + modified_past_autosave = false; + modify_index = undo_index = 0; + SetWindowText (skinwindow, skin_filename); + + data = malloc(skin_width*skin_height); + for (i=0 ; i 1024 || skin_height > 512) + Sys_Error ("Skin file is too large"); + + width2 = 1; + height2 = 1; + for (i=0 ; i<12 ; i++) + { + if (width2 < skin_width) + width2<<=1; + if (height2 < skin_height) + height2<<=1; + } + + // compatability shit for auto sizing of old skins + if (skin_width != 320 || skin_height != 200) + { + skinwidth = skin_width; + skinheight = skin_height; + } + else + { + skinwidth = 0; + skinheight = 0; + } +} + +/* +============= +Skin_LoadFile + +Load a skin texture and the base.tri from the same directory +============= +*/ +void Skin_LoadFile (char *name) +{ + int i, j, p; + byte *lbmpic; + byte *lbmpal; + char trifile[1024]; + int width, height; + + modified = false; + modified_past_autosave = false; + modify_index = undo_index = 0; + strcpy (skin_filename, name); + SetWindowText (skinwindow, skin_filename); + + // + // read the texture + // + Load256Image (skin_filename, &lbmpic, &lbmpal, &width, &height); + memcpy (palette, lbmpal, sizeof(palette)); + free (lbmpal); + + SetSizes (width, height); + + memset (pic, 0, sizeof(pic)); + for (i=0 ; i= width2*height2) + return; + + if (index == skin_last_index) + return; // in same pixel + skin_last_index = index; + + if (shift) + { + Pal_SetIndex (pic[index]); + return; + } + + SetSkin (index, selected_index); + UpdateWindow (skinwindow); +} + + +void DrawModelST (void) +{ + int i, j; + + glColor4f (1,1,1,1); + + glBegin (GL_TRIANGLES); + for (i=0 ; i abs(dy)) + skin_z += 0.25*dx; + else + skin_z += 0.25*dy; + InvalidateRect (skinwindow, NULL, false); + } + if (wParam == MK_RBUTTON) + { + skin_x -= 0.25*dx; + skin_y -= 0.25*dy; + InvalidateRect (skinwindow, NULL, false); + } + } + break; + + case WM_SIZE: + InvalidateRect(camerawindow, NULL, false); + break; + case WM_NCCALCSIZE:// don't let windows copy pixels + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + return WVR_REDRAW; + case WM_CLOSE: + DestroyWindow (hWnd); + break; + + default: + /* pass all unhandled messages to DefWindowProc */ + lRet = DefWindowProc (hWnd, uMsg, wParam, lParam); + break; + } + + /* return 1 if handled message, 0 if not */ + return lRet; +} + + +/* +============== +WSkin_Create +============== +*/ +void WSkin_Create (HINSTANCE hInstance) +{ + WNDCLASS wc; + + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)Skin_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = SKIN_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Sys_Error ("RegisterClass failed"); + + skinwindow = CreateWindow (SKIN_WINDOW_CLASS , + "Skin View", + QE3_STYLE, + (int)(screen_width*0.5), + (int)(screen_height*0.2), + (int)(screen_width*0.5), + (int)(screen_height*0.8), // size + mainwindow, // parent window + 0, // no menu + hInstance, + 0); + if (!skinwindow) + Error ("Couldn't create skinwindow"); + +// RestoreWindowState(palettewindow, "palettewindow"); + ShowWindow (skinwindow, SW_SHOWDEFAULT); +} + + +/* +=================================================================== + + SKIN RESAMPLING + +=================================================================== +*/ + +HWND resamplewindow; +HDC resampledc; + +#define RESAMPLE_WINDOW_CLASS "TPResample" + +/* +============ +Resample_WndProc +============ +*/ +LONG WINAPI Resample_WndProc ( + HWND hWnd, + UINT uMsg, + WPARAM wParam, + LPARAM lParam) +{ + switch (uMsg) + { + case WM_CREATE: + resampledc = GetDC(hWnd); + bSetupPixelFormat(resampledc); + break; + } + + return DefWindowProc (hWnd, uMsg, wParam, lParam); +} + +/* +============== +ResampleWindow +============== +*/ +void ResampleWindow (HINSTANCE hInstance) +{ + WNDCLASS wc; + static qboolean registered; + + if (!registered) + { + registered = true; + /* Register the camera class */ + memset (&wc, 0, sizeof(wc)); + + wc.style = 0; + wc.lpfnWndProc = (WNDPROC)Resample_WndProc; + wc.cbClsExtra = 0; + wc.cbWndExtra = 0; + wc.hInstance = hInstance; + wc.hIcon = 0; + wc.hCursor = LoadCursor (NULL,IDC_ARROW); + wc.hbrBackground = NULL; + wc.lpszMenuName = 0; + wc.lpszClassName = RESAMPLE_WINDOW_CLASS; + + if (!RegisterClass (&wc) ) + Sys_Error ("RegisterClass failed"); + } + + resamplewindow = CreateWindow (RESAMPLE_WINDOW_CLASS , + "ResampleWindow", + WS_OVERLAPPED, + 0, 0, width2+32, height2+32, // size + NULL, // parent window + 0, // no menu + hInstance, + 0); + if (!resamplewindow) + Error ("Couldn't create skinwindow"); + + ShowWindow (resamplewindow, SW_SHOWDEFAULT); +} + + +void OutlineTexture (byte *pic) +{ + int i, j; + int x, y; + int empty; + byte oldpic[1024*512]; + + memcpy (oldpic, pic, width2*height2); + + empty = oldpic[0]; + + for (i=0 ; i= height2) + continue; + if (j+x < 0 || j+x >= width2) + continue; + if (oldpic[(i+y)*width2 + j+x] != empty) + { + pic[i*width2+j] = oldpic[(i+y)*width2 + j+x]; + goto done; + } + } + } +done: ; + } + } +} + +void ResampleSkin (void) +{ + int i, j; + static float oldtmcoords[10000][3][2]; + static int newindex[1024*512]; + static byte oldpic[1024*512]; + + // open a window of the texture size + ResampleWindow (main_instance); + + // get new S/T from current frame + memcpy (oldtmcoords, tmcoords, numfaces*3*2*4); + CalcTmCoords (); + + // draw all the triangles with the index texture + if (!wglMakeCurrent( resampledc, baseRC )) + Sys_Error ("wglMakeCurrent failed"); + + glViewport (0,0,width2, height2); + glClearColor (0,0,0,0); + glClear (GL_COLOR_BUFFER_BIT); + + glMatrixMode (GL_PROJECTION); + glLoadIdentity (); + glOrtho (0, width2, 0, height2, -100, 100); + glMatrixMode (GL_MODELVIEW); + glLoadIdentity (); + + glColor4f (1,1,1,1); + glDisable (GL_DEPTH_TEST); + glDisable (GL_CULL_FACE); + BindTextureEXT (GL_TEXTURE_2D, TEXTURE_INDEX); +#if 0 + glDisable(GL_TEXTURE_2D); + glBegin (GL_LINE_LOOP); + glVertex3f (1,1,10); + glVertex3f (skin_width-1,0,10); + glVertex3f (skin_width-1,skin_height-1,10); + glVertex3f (1,skin_height-1,10); + glEnd (); + glEnable(GL_TEXTURE_2D); +#endif + glBegin (GL_TRIANGLES); + for (i=0 ; i Date: Sun, 8 Apr 2012 18:45:33 -0500 Subject: [PATCH 7/7] moved to the web repository. online at http://icculus.org/gtkradiant/documentation/windows_compile_guide/ --- windows_compile_guide/index.html | 226 ------------------- windows_compile_guide/vc-radiant-release.png | Bin 53964 -> 0 bytes 2 files changed, 226 deletions(-) delete mode 100644 windows_compile_guide/index.html delete mode 100644 windows_compile_guide/vc-radiant-release.png diff --git a/windows_compile_guide/index.html b/windows_compile_guide/index.html deleted file mode 100644 index f3676278..00000000 --- a/windows_compile_guide/index.html +++ /dev/null @@ -1,226 +0,0 @@ - - - - Compiling GtkRadiant on Windows - - - -
- - Valid XHTML 1.0! - -
-
-

Compiling GtkRadiant on Windows

-
-

This guide explains how to compile GtkRadiant 1.6.x from source code on Windows operating systems. - The source code is obtained from - the GtkRadiant Git repository, which is open to the public (details follow). - These instructions are aimed at developers wanting to test changes to GtkRadiant source code. - The instructions below have been executed successfully on - Windows XP 32 bit (some late service pack) and on Windows 7 Professional 64 bit.

-

This guide is divided into the following main sections. -

- -
-
- -

Section 1: Installing Git

-

- First to install is the Git, Git is a powerful distributed Source Code Management tool and the versioning tool of choice for GtkRadiant development. -

-

- The hompepage for Git is git-scm.com, but we are more interested in - code.google.com/p/msysgit/ because this is the windows port of git. You should - download and install the newest "Full installer for official Git for Windows". -

-
-
- -

Section 2: Installing Python

-

We will now install the Python programming language, which is needed for SCons to work.

-

- The homepage for Python is www.python.org. You should download and install - a 32 bit version of Python, because scons is only avaiable in 32 bit builds. I would strongly recommend sticking to a version of Python - that is 2.x.x, not 3.x.x. This is because lots of legacy software that uses Python is known to work correctly - with 2.x.x, but might not necessarily work with 3.x.x. At the time of writing this tutorial, the preferred version of Python - was 2.7.1. For purposes of this tutorial, Python is installed to C:\Python27 . All of the default - options for installing Python should be fine. -

-
-
- -

Section 3: Installing SCons

-

We will now install SCons, which is a multi-platform substitute for traditional Make.

-

- The homepage for SCons is www.scons.org. You should download and install the - latest production release. During the install procedure you will be asked to confirm the location of your Python - installation. -

-
-
- -

Section 4: Installing SVN

-

- We're now going to install a command-line version of the SVN client that we can use from cmd. We don't need no - stinkin' GUI. Anyhow, command-line SVN is required to perform the SCons build target later on. - In fact, you don't need to touch TortoiseSVN or any other GUI-based SVN client for any part of this entire tutorial. - (I wouldn't touch a GUI-based SVN client with a 10 foot pole given the opportunity to use command-line SVN instead.) -

-

- The preferred download site for SVN client for Windows is CollabNet. - You should download and install CollabNet Subversion Command-Line Client, - not CollabNet Subversion Edge or something of any other nature. Unfortunately you'll have to create an account with CollabNet - to download this software, but everything is free. You can use all defaults when installing SVN. -

-

- The CollabNet version of SVN client for Windows should automatically modify your PATH , and you should be able to - execute the svn command in cmd after closing cmd and starting it again. If this is not the case for some strange - reason, you'll have to tweak your environment to ensure that you can execute the svn command from cmd. -

-
-
- -

Section 5: Installing Visual C++

-

- The GtkRadiant developers are currently using Microsoft Visual C++ 2008 to compile GtkRadiant. Even though Visual C++ 2010 is a newer - version, don't use it [unless you want to be on your own]. You can download Visual C++ 2008 Express Edition from - this Microsoft webpage. -

-

- When you install Visual C++ 2008 Express Edition, you can install the bare minimum application without any extras such as - Microsoft Silverlight Runtime or Microsoft SQL Server 2008 Express Edition. For the rest of the install options, the - defaults can be chosen. -

-
-
- -

Section 6: Obtaining Source Code, Game Paks, and Libs

-

We are now ready to get the source code for GtkRadiant.

-

Step A: Get Base Project

-

- Open an Git Bash shell. When you start the shell, you will be in what is called your "home directory". You can execute the - pwd command in Git Bash to find out which directory you are currently in. For example, when I start Git Bash, my - current directory is /c/Users/Christian . -

-

- In any case, we need to create ourselves a work area for purposes of downloading files and compiling software. I would recommend - creating a directory radiant-work in your home directory. So: -

-
-
$ mkdir radiant-work
-
-
-

Now, we're going to change to that directory and get the base GtkRadiant project:

-
-
$ cd radiant-work
-$ git clone git://github.com/TTimo/GtkRadiant.git
-
-
-

We created the extra radiant-work parent directory of GtkRadiant because the following step will - place many files into the project's parent directory, and we don't want to litter our home directory with these files.

-

Step B: Execute SCons Build Target

-

- Remember all the work we did earlier in order to install SCons? Well, thanks to all that work we did, - obtaining the remaining things we need for compiling is really really easy: -

-

- Open a cmd shell and execute: -

-
-
$ cd radiant-work\GtkRadiant
-$ C:\Python27\Scripts\scons.bat target=setup
-
-
-

This SCons build target performs several actions:

-
    -
  • Downloads "install paks" for several games such as Quake III Arena and Urban Terror.
  • -
  • Downloads library dependencies (such as GTK+) for building and running GtkRadiant.
  • -
  • Places library dependencies in proper locations.
  • -
  • Performs any other actions needed prior to compiling GtkRadiant.
  • -
-
-
- -

Section 7: Compiling GtkRadiant

-

We are now finally going to compile GtkRadiant using Microsoft Visual C++.

-

- Start Microsoft Visual C++. From the "File" menu, choose "Open" -> "Project/Solution...". - Navigate to your GtkRadiant directory (in my case C:\Users\Christian\radiant-work\GtkRadiant). - Choose the project file radiant.sln from this directory. -

-

- You now have the GtkRadiant project loaded in Visual C++. You can poke around if you like, e.g. open up some source code - files and edit them. -

-

- Before you build the project, you might want to select the "Release" target (as pictured below). -

- - - - - -
 vc-radiant-release.png
-

- To build GtkRadiant, choose "Build Solution" from the "Build" menu. The build will take - about 10 minutes [on a Pentium 4 with HTT], so this would be a good time to go get a cup of tea. -

-

If the build completes successfully, you will get a message similar to the following in the output - of Visual C++:

-
-
radiant - 0 error(s), 0 warning(s)
-========== Build: 38 succeeded, 0 failed, 0 up-to-date, 0 skipped ==========
-
-
-
-
- -

Section 8: Running GtkRadiant

-

All of the files needed to run GtkRadiant are going to be in the folder radiant-work\GtkRadiant\install [relative - to your home directory]. You can copy the entire install folder to some place such as your Desktop - and you can rename this folder to ZeroRadiant for example. - Then, you will use radiant.exe in that directory to launch the application. -

-

- There is one little bit of optional cleanup you can perform on your installation folder. You can remove all SVN-related - files since they are no longer needed and only take up disk space. Let's say that you renamed your installation folder - to ZeroRadiant (as the previous paragraph suggests), and let's say that you're in the cmd shell, and that your current - working directory is the directory of ZeroRadiant. Then, in your cmd shell, you can execute this command to - delete all SVN-related files (all .svn directories): -

-
-
$ for /r %R in (.svn) do if exist %R (rd /s /q "%R")
-
-
-

- That's it! Good luck and thanks for reading this enhanced tutorial! If you have comments or suggestions please email me at nlandys@gmail.com or the updater christian_ratzenhofer@yahoo.de. - More information about GtkRadiant is on icculus.org/gtkradiant. -

-
-
- - diff --git a/windows_compile_guide/vc-radiant-release.png b/windows_compile_guide/vc-radiant-release.png deleted file mode 100644 index 1b8b11c95c7c5b44f446f7be3f1849751af63a9f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53964 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 TzQ~V!00000NkvXXu0mjf#yPTO