attempt at support for editor, makefile changes, etc
authorBradley Bell <btb@icculus.org>
Thu, 25 Oct 2001 02:27:57 +0000 (02:27 +0000)
committerBradley Bell <btb@icculus.org>
Thu, 25 Oct 2001 02:27:57 +0000 (02:27 +0000)
Makefile.am
configure.in
main/Makefile.am
main/editor/Makefile.am [new file with mode: 0644]
main/editor/med.c [new file with mode: 0644]
main/editor/medwall.h [new file with mode: 0644]
main/editor/segment.c [new file with mode: 0644]
main/editor/seguvs.h [new file with mode: 0644]
sound/Makefile.am
video/Makefile.am

index fc7eeac..2c61aec 100644 (file)
@@ -21,13 +21,17 @@ ARCH_LIBS = arch/linux/libarch_linux.a arch/sdl/libarch_sdl.a
 endif
 endif
 
+if EDITOR
+EDITOR_LIBS = main/editor/libeditor.a
+endif
+
 d2x_SOURCES =
 d2x_sdl_SOURCES =
 d2x_ogl_SOURCES =
 d2x_svga_SOURCES =
 d2x_ggi_SOURCES =
 
-d2x_LDADD = ${LD_KLUDGE} main/libmain.a 3d/lib3d.a 2d/lib2d.a ${ARCH_LIBS} mem/libmem.a cfile/libcfile.a iff/libiff.a texmap/libtexmap.a misc/libmisc.a maths/libmaths.a video/libvideo.a sound/libsound.a input/libinput.a
+d2x_LDADD = ${LD_KLUDGE} main/libmain.a ${EDITOR_LIBS} 3d/lib3d.a 2d/lib2d.a ${ARCH_LIBS} mem/libmem.a cfile/libcfile.a iff/libiff.a texmap/libtexmap.a misc/libmisc.a maths/libmaths.a video/libvideo.a sound/libsound.a
 
 if MINGW32
 if USE_NETWORK
index 5fedb04..a30e89c 100644 (file)
@@ -43,6 +43,7 @@ AC_ARG_ENABLE(editor,
   [  --enable-editor         Build editor? (not functional)],,)
 if test x$enable_editor = xyes; then
     AC_DEFINE(EDITOR)
+    D2X_MAIN_SUBDIRS=editor
 fi
 AM_CONDITIONAL(EDITOR, test x$enable_editor = xyes)
 
@@ -88,8 +89,6 @@ else
   )
   AC_SUBST(SDL_LIBS)
 
-  CFLAGS="$SDL_CFLAGS $CFLAGS"
-
   TARGETS=d2x-sdl
   D2X_ARCH_SUBDIRS=sdl
 
@@ -196,8 +195,12 @@ else
 fi
 AM_CONDITIONAL(USE_ASM, test x$enable_assembler != xno)
 
+AM_PROG_AS
+
 AC_SUBST(D2X_ARCH_SUBDIRS)
 
+AC_SUBST(D2X_MAIN_SUBDIRS)
+
 AC_SUBST(TARGETS)
 
 AC_SUBST(NASMFLAGS)
@@ -218,6 +221,7 @@ arch/win32/Makefile
 cfile/Makefile
 iff/Makefile
 main/Makefile
+main/editor/Makefile
 maths/Makefile
 mem/Makefile
 misc/Makefile
index 44705fe..66254bb 100644 (file)
@@ -1,11 +1,15 @@
-EXTRA_SUBDIRS = editor old
+SUBDIRS = @D2X_MAIN_SUBDIRS@
 
-noinst_LIBRARIES = libmain.a
+DIST_SUBDIRS = editor
+
+EXTRA_SUBDIRS = old
 
-CFLAGS += -fwritable-strings
+noinst_LIBRARIES = libmain.a
 
 INCLUDES = -I$(top_srcdir)/includes -I$(top_srcdir)/arch/include
 
+CFLAGS += -fwritable-strings ${SDL_CFLAGS}
+
 if USE_NETWORK
 NETWORK_SRCS = ipx_drv.c kmatrix.c multi.c multibot.c network.c
 else
diff --git a/main/editor/Makefile.am b/main/editor/Makefile.am
new file mode 100644 (file)
index 0000000..935fa6a
--- /dev/null
@@ -0,0 +1,6 @@
+noinst_LIBRARIES = libeditor.a
+INCLUDES = -I$(top_srcdir)/includes -I$(top_srcdir)/arch/include -I$(top_srcdir)/main
+
+libeditor_a_SOURCES = med.c segment.c
+
+EXTRA_DIST = editor.h kdefs.h medwall.h seguvs.h texpage.h
diff --git a/main/editor/med.c b/main/editor/med.c
new file mode 100644 (file)
index 0000000..416b55c
--- /dev/null
@@ -0,0 +1,1610 @@
+/*
+THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
+SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
+END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
+ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
+IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
+SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
+FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
+CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
+AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
+COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
+*/
+/*
+ * $Source: /cvs/cvsroot/d2x/main/editor/med.c,v $
+ * $Revision: 1.1 $
+ * $Author: bradleyb $
+ * $Date: 2001-10-25 02:27:17 $
+ *
+ * Editor loop for Inferno
+ *
+ * $Log: not supported by cvs2svn $
+ * Revision 1.1.1.1  1999/06/14 22:03:43  donut
+ * Import of d1x 1.37 source.
+ *
+ * Revision 2.3  1995/03/06  18:23:52  john
+ * Fixed bug with font screwing up.
+ * 
+ * Revision 2.2  1995/03/06  16:34:55  john
+ * Fixed bug with previous.
+ * 
+ * Revision 2.1  1995/03/06  15:20:57  john
+ * New screen mode method.
+ * 
+ * Revision 2.0  1995/02/27  11:35:54  john
+ * Version 2.0! No anonymous unions, Watcom 10.0, with no need
+ * for bitmaps.tbl.
+ * 
+ * Revision 1.192  1994/11/30  12:33:55  mike
+ * set window clearing mode for editor.
+ * 
+ * Revision 1.191  1994/11/27  23:17:02  matt
+ * Made changes for new mprintf calling convention
+ * 
+ * Revision 1.190  1994/11/19  00:04:33  john
+ * Changed some shorts to ints.
+ * 
+ * Revision 1.189  1994/11/17  14:47:57  mike
+ * validation functions moved from editor to game.
+ * 
+ * Revision 1.188  1994/11/14  11:41:38  john
+ * Fixed bug with editor/game sequencing.
+ * 
+ * Revision 1.187  1994/11/13  15:36:44  john
+ * Changed game sequencing with editor.
+ * 
+ * Revision 1.186  1994/11/10  16:49:12  matt
+ * Don't sort seg list if no segs in list
+ * 
+ * Revision 1.185  1994/11/08  09:28:39  mike
+ * reset ai paths on going to game.
+ * 
+ * Revision 1.184  1994/10/30  14:13:05  mike
+ * rip out repair center stuff.
+ * 
+ * Revision 1.183  1994/10/27  10:07:06  mike
+ * adapt to no inverse table.
+ * 
+ * Revision 1.182  1994/10/20  12:48:03  matt
+ * Replaced old save files (MIN/SAV/HOT) with new LVL files
+ * 
+ * Revision 1.181  1994/10/13  11:39:22  john
+ * Took out network stuff/.
+ * 
+ * Revision 1.180  1994/10/07  22:21:38  mike
+ * Stop Delete-{whatever} from hanging you!
+ * 
+ * Revision 1.179  1994/10/03  23:39:37  mike
+ * Adapt to newer, better, fuelcen_activate function.
+ * 
+ * Revision 1.178  1994/09/30  00:38:05  mike
+ * Shorten diagnostic message erase -- was erasing outside canvas.
+ * 
+ * Revision 1.177  1994/09/28  17:31:37  mike
+ * Add call to check_wall_validity();
+ * 
+ * Revision 1.176  1994/08/19  10:57:42  mike
+ * Fix status message erase bug.
+ * 
+ * Revision 1.175  1994/08/18  10:48:12  john
+ * Cleaned up game sequencing.
+ * 
+ * Revision 1.174  1994/08/16  18:11:04  yuan
+ * Maded C place you in the center of a segment.
+ * 
+ * Revision 1.173  1994/08/10  19:55:05  john
+ * Changed font stuff.
+ * 
+ * Revision 1.172  1994/08/09  16:06:06  john
+ * Added the ability to place players.  Made old
+ * Player variable be ConsoleObject.
+ * 
+ * Revision 1.171  1994/08/04  09:14:11  matt
+ * Fixed problem I said I fixed last time
+ * 
+ * Revision 1.170  1994/08/04  00:27:57  matt
+ * When viewing a wall, update the objects segnum if moved out of the segment
+ * 
+ * Revision 1.169  1994/08/02  14:18:12  mike
+ * Clean up dialog boxes.
+ * 
+ * Revision 1.168  1994/07/29  15:34:35  mike
+ * Kill some mprintfs.
+ * 
+ * Revision 1.167  1994/07/29  14:56:46  yuan
+ * Close centers window, when you go into game.
+ * 
+ * Revision 1.166  1994/07/28  17:16:20  john
+ * MAde editor use Network stuff.
+ * 
+ * Revision 1.165  1994/07/28  16:59:10  mike
+ * objects containing objects.
+ * 
+ * Revision 1.164  1994/07/22  12:37:07  matt
+ * Cleaned up editor/game interactions some more.
+ * 
+ * Revision 1.163  1994/07/21  19:35:11  yuan
+ * Fixed #include problem
+ * 
+ * Revision 1.162  1994/07/21  18:02:09  matt
+ * Don't re-init player stats when going from editor -> game
+ * 
+ * Revision 1.161  1994/07/21  12:47:53  mike
+ * Add tilde key functionality for object movement.
+ * 
+ * Revision 1.160  1994/07/18  10:44:55  mike
+ * One-click access to keypads.
+ * 
+ * Revision 1.159  1994/07/01  18:05:54  john
+ * *** empty log message ***
+ * 
+ * Revision 1.158  1994/07/01  17:57:06  john
+ * First version of not-working hostage system
+ * 
+ * 
+ * Revision 1.157  1994/07/01  11:32:29  john
+ * *** empty log message ***
+ * 
+ * Revision 1.156  1994/06/24  17:04:36  john
+ * *** empty log message ***
+ * 
+ * Revision 1.155  1994/06/23  15:53:47  matt
+ * Finished hacking in 3d rendering in big window
+ * 
+ * Revision 1.154  1994/06/21  16:17:54  yuan
+ * Init stats when you go to game from editor
+ * 
+ * Revision 1.153  1994/06/21  12:57:14  yuan
+ * Remove center from segment function added to menu.
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <conf.h>
+#endif
+
+//#define DEMO 1
+
+#define        DIAGNOSTIC_MESSAGE_MAX                          90
+#define        EDITOR_STATUS_MESSAGE_DURATION  4               //      Shows for 3+..4 seconds
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <time.h>
+
+#ifdef __MSDOS__
+#include <process.h>
+#endif
+
+
+//#define INCLUDE_XLISP
+
+#include "inferno.h"
+#include "segment.h"
+#include "gr.h"
+#include "ui.h"
+#include "editor.h"
+//#include "gamemine.h"
+#include "gamesave.h"
+#include "gameseg.h"
+
+#include "key.h"
+#include "mono.h"
+#include "error.h"
+#include "kfuncs.h"
+#include "macro.h"
+
+#ifdef INCLUDE_XLISP
+#include "medlisp.h"
+#endif
+#include "u_mem.h"
+#include "render.h"
+#include "game.h"
+#include "slew.h"
+#include "kdefs.h"
+#include "func.h"
+#include "textures.h"
+#include "screens.h"
+#include "texmap.h"
+#include "object.h"
+#include "effects.h"
+#include "wall.h"
+#include "info.h"
+#include "ai.h"
+
+#include "texpage.h"           // Textue selection paging stuff
+#include "objpage.h"           // Object selection paging stuff
+
+#include "medmisc.h"
+#include "meddraw.h"
+#include "medsel.h"
+#include "medrobot.h"
+#include "medwall.h"
+#include "eswitch.h"
+#include "ehostage.h"
+#include "centers.h"
+
+#include "fuelcen.h"
+#include "gameseq.h"
+#include "newmenu.h"
+
+//#define _MARK_ON 1
+//#include <wsample.h>         //should come after inferno.h to get mark setting //Not included here.
+
+#define COMPRESS_INTERVAL      5                       // seconds
+
+//char *undo_status[128];
+
+int initializing;
+
+//these are instances of canvases, pointed to by variables below
+grs_canvas _canv_editor_game;          //the game on the editor screen
+
+//these are pointers to our canvases
+grs_canvas *Canv_editor;                       //the editor screen
+grs_canvas *Canv_editor_game=&_canv_editor_game; //the game on the editor screen
+
+grs_canvas *canv_offscreen;            //for off-screen rendering
+grs_canvas *Pad_text_canvas;           // Keypad text
+
+grs_font *editor_font=NULL;
+
+//where the editor is looking
+vms_vector Ed_view_target={0,0,0};
+
+int gamestate_not_restored = 0;
+
+UI_WINDOW * EditorWindow;
+
+int    Large_view_index = -1;
+
+UI_GADGET_USERBOX * GameViewBox;
+UI_GADGET_USERBOX * LargeViewBox;
+UI_GADGET_USERBOX * GroupViewBox;
+
+#if ORTHO_VIEWS
+UI_GADGET_USERBOX * TopViewBox;
+UI_GADGET_USERBOX * FrontViewBox;
+UI_GADGET_USERBOX * RightViewBox;
+#endif
+
+UI_GADGET_ICON * ViewIcon;
+UI_GADGET_ICON * AllIcon;
+UI_GADGET_ICON * AxesIcon;
+UI_GADGET_ICON * ChaseIcon;
+UI_GADGET_ICON * OutlineIcon;
+UI_GADGET_ICON * LockIcon;
+//-NOLIGHTICON- UI_GADGET_ICON * LightIcon;
+
+UI_EVENT * DemoBuffer = NULL;
+
+//grs_canvas * BigCanvas[2];
+//int CurrentBigCanvas = 0;
+//int BigCanvasFirstTime = 1;
+
+int    Found_seg_index=0;                              // Index in Found_segs corresponding to Cursegp
+
+
+void print_status_bar( char message[DIAGNOSTIC_MESSAGE_MAX] ) {
+       int w,h,aw;
+
+       gr_set_current_canvas( NULL );
+       gr_set_curfont(editor_font);
+       gr_set_fontcolor( CBLACK, CGREY );
+       gr_get_string_size( message, &w, &h, &aw );
+       gr_string( 4, 583, message );
+       gr_set_fontcolor( CBLACK, CWHITE );
+       gr_setcolor( CGREY );
+       gr_rect( 4+w, 583, 799, 599 );
+}
+
+void print_diagnostic( char message[DIAGNOSTIC_MESSAGE_MAX] ) {
+       int w,h,aw;
+
+       gr_set_current_canvas( NULL );
+       gr_set_curfont(editor_font);
+       gr_set_fontcolor( CBLACK, CGREY );
+       gr_get_string_size( message, &w, &h, &aw );
+       gr_string( 4, 583, message );
+       gr_set_fontcolor( CBLACK, CWHITE );
+       gr_setcolor( CGREY );
+       gr_rect( 4+w, 583, 799, 599 );
+}
+
+static char status_line[DIAGNOSTIC_MESSAGE_MAX];
+
+struct tm      Editor_status_last_time;
+
+void editor_status( const char *format, ... )
+{
+       va_list ap;
+
+       va_start(ap, format);
+       vsprintf(status_line, format, ap);
+       va_end(ap);
+
+       print_status_bar(status_line);
+
+       Editor_status_last_time = Editor_time_of_day;
+
+}
+
+//     int  tm_sec;    /* seconds after the minute -- [0,61] */
+//     int  tm_min;    /* minutes after the hour       -- [0,59] */
+//     int  tm_hour;   /* hours after midnight -- [0,23] */
+//     int  tm_mday;   /* day of the month             -- [1,31] */
+//     int  tm_mon;    /* months since January -- [0,11] */
+//     int  tm_year;   /* years since 1900                             */
+//     int  tm_wday;   /* days since Sunday            -- [0,6]  */
+//     int  tm_yday;   /* days since January 1 -- [0,365]*/
+//     int  tm_isdst;  /* Daylight Savings Time flag */
+
+void clear_editor_status(void)
+{
+       int cur_time = Editor_time_of_day.tm_hour * 3600 + Editor_time_of_day.tm_min*60 + Editor_time_of_day.tm_sec;
+       int erase_time = Editor_status_last_time.tm_hour * 3600 + Editor_status_last_time.tm_min*60 + Editor_status_last_time.tm_sec + EDITOR_STATUS_MESSAGE_DURATION;
+
+       if (cur_time > erase_time) {
+               int     i;
+               char    message[DIAGNOSTIC_MESSAGE_MAX];
+
+               for (i=0; i<DIAGNOSTIC_MESSAGE_MAX-1; i++)
+                       message[i] = ' ';
+
+               message[i] = 0;
+               print_status_bar(message);
+               Editor_status_last_time.tm_hour = 99;
+       }
+}
+
+
+void diagnostic_message( const char *format, ... )
+{
+       char diag_line[DIAGNOSTIC_MESSAGE_MAX];
+
+       va_list ap;
+
+       va_start(ap, format);
+       vsprintf(diag_line, format, ap);
+       va_end(ap);
+
+       editor_status(diag_line);
+}
+
+
+static char sub_status_line[DIAGNOSTIC_MESSAGE_MAX];
+
+void editor_sub_status( const char *format, ... )
+{
+       int w,h,aw;
+       va_list ap;
+
+       va_start(ap, format);
+       vsprintf(sub_status_line, format, ap);
+       va_end(ap);
+
+       gr_set_current_canvas( NULL );
+       gr_set_curfont(editor_font);
+       gr_set_fontcolor( BM_XRGB(0,0,31), CGREY );
+       gr_get_string_size( sub_status_line, &w, &h, &aw );
+       gr_string( 500, 583, sub_status_line );
+       gr_set_fontcolor( CBLACK, CWHITE );
+       gr_setcolor( CGREY );
+       gr_rect( 500+w, 583, 799, 599 );
+}
+
+int DropIntoDebugger()
+{
+       Int3();
+       return 1;
+}
+
+
+#ifdef INCLUDE_XLISP
+int CallLisp()
+{
+       medlisp_go();
+       return 1;
+}
+#endif
+
+
+int ExitEditor()
+{
+       if (SafetyCheck())  {
+               ModeFlag = 1;
+       }
+       return 1;
+}
+
+int    GotoGameCommon(int mode) {
+       stop_time();
+
+//@@   init_player_stats();
+//@@
+//@@   Player_init.pos = Player->pos;
+//@@   Player_init.orient = Player->orient;
+//@@   Player_init.segnum = Player->segnum;    
+       
+// -- must always save gamesave.sav because the restore-objects code relies on it
+// -- that code could be made smarter and use the original file, if appropriate.
+//     if (mine_changed) 
+       if (gamestate_not_restored == 0) {
+               gamestate_not_restored = 1;
+               save_level("GAMESAVE.LVL");
+               editor_status("Gamestate saved.\n");
+               mprintf((0, "Gamestate saved.\n"));
+       }
+
+       ai_reset_all_paths();
+
+       start_time();
+
+       ModeFlag = mode;
+       return 1;
+}
+
+int GotoGameScreen()
+{
+       return GotoGameCommon(3);
+}
+
+int GotoGame()
+{
+       return GotoGameCommon(2);
+}
+
+
+void ReadLispMacro( FILE * file, char * buffer )
+{
+//     char c;
+//     int size=0;
+//     int pcount = 0;
+//     char text[100];
+//     int i=0;
+       
+       fscanf( file, " { %s } ", buffer );
+
+/*
+       while (1)
+       {
+               c = text[i++];
+               if (pcount > 0 )
+                       buffer[size++] = c;
+               if ( c == '(' ) pcount++;
+               if ( c == ')' ) break;
+       }
+       buffer[size++] = 0;
+*/
+
+       return;
+}
+
+static int (*KeyFunction[2048])();
+
+void medkey_init()
+{
+       FILE * keyfile;
+       char keypress[100];
+       int key;
+       int i;  //, size;
+       int np;
+       char * LispCommand;
+
+       MALLOC( LispCommand, char, DIAGNOSTIC_MESSAGE_MAX );
+
+       for (i=0; i<2048; i++ )
+               KeyFunction[i] = NULL;
+
+       keyfile = fopen( "GLOBAL.KEY", "rt" );
+       if (keyfile)
+       {
+               while (fscanf( keyfile, " %s %s ", keypress, LispCommand ) != EOF )
+               {
+                       //ReadLispMacro( keyfile, LispCommand );
+
+                       if ( (key=DecodeKeyText( keypress ))!= -1 )
+                       {
+                               Assert( key < 2048);
+                               KeyFunction[key] = func_get( LispCommand, &np );
+                       } else {
+                               Error( "Bad key %s in GLOBAL.KEY!", keypress );
+                       }
+               }
+               fclose(keyfile);
+       }
+       free( LispCommand );
+}
+
+void init_editor()
+{
+       minit();
+
+       ui_init();
+
+       init_med_functions();   // Must be called before medlisp_init
+
+       ui_pad_read( 0, "segmove.pad" );
+       ui_pad_read( 1, "segsize.pad" );
+       ui_pad_read( 2, "curve.pad" );
+       ui_pad_read( 3, "texture.pad" );
+       ui_pad_read( 4, "object.pad" );
+       ui_pad_read( 5, "objmov.pad" );
+       ui_pad_read( 6, "group.pad" );
+       ui_pad_read( 7, "lighting.pad" );
+       ui_pad_read( 8, "test.pad" );
+
+       medkey_init();
+
+       editor_font = gr_init_font( "pc8x16.fnt" );
+       
+       menubar_init( "MED.MNU" );
+
+       canv_offscreen = gr_create_canvas(LVIEW_W,LVIEW_H);
+       
+       Draw_all_segments = 1;                                          // Say draw all segments, not just connected ones
+
+       init_autosave();
+  
+//     atexit(close_editor);
+
+       Clear_window = 1;       //      do full window clear.
+}
+
+int ShowAbout()
+{
+       MessageBox( -2, -2, 1,  "INFERNO Mine Editor\n\n"               \
+                                                                       "Copyright (c) 1993  Parallax Software Corp.",
+                                                                       "OK");
+       return 0;
+}
+
+void move_player_2_segment(segment *seg,int side);
+
+int SetPlayerFromCurseg()
+{
+       move_player_2_segment(Cursegp,Curside);
+       Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED;
+       return 1;
+}
+
+int fuelcen_create_from_curseg()
+{
+       Cursegp->special = SEGMENT_IS_FUELCEN;
+       fuelcen_activate( Cursegp, Cursegp->special);
+       return 1;
+}
+
+int repaircen_create_from_curseg()
+{
+       Int3(); //      -- no longer supported!
+//     Cursegp->special = SEGMENT_IS_REPAIRCEN;
+//     fuelcen_activate( Cursegp, Cursegp->special);
+       return 1;
+}
+
+int controlcen_create_from_curseg()
+{
+       Cursegp->special = SEGMENT_IS_CONTROLCEN;
+       fuelcen_activate( Cursegp, Cursegp->special);
+       return 1;
+}
+
+int robotmaker_create_from_curseg()
+{
+       Cursegp->special = SEGMENT_IS_ROBOTMAKER;
+       fuelcen_activate( Cursegp, Cursegp->special);
+       return 1;
+}
+
+int fuelcen_reset_all()        {
+       fuelcen_reset();
+       return 1;
+}
+
+int fuelcen_delete_from_curseg() {
+       fuelcen_delete( Cursegp );
+       return 1;
+}
+
+
+//@@//this routine places the viewer in the center of the side opposite to curside,
+//@@//with the view toward the center of curside
+//@@int SetPlayerFromCursegMinusOne()
+//@@{
+//@@   vms_vector vp;
+//@@
+//@@// int newseg,newside;
+//@@// get_previous_segment(SEG_PTR_2_NUM(Cursegp),Curside,&newseg,&newside);
+//@@// move_player_2_segment(&Segments[newseg],newside);
+//@@
+//@@   med_compute_center_point_on_side(&Player->obj_position,Cursegp,Side_opposite[Curside]);
+//@@   med_compute_center_point_on_side(&vp,Cursegp,Curside);
+//@@   vm_vec_sub2(&vp,&Player->position);
+//@@   vm_vector_2_matrix(&Player->orient,&vp,NULL,NULL);
+//@@
+//@@   Player->seg = SEG_PTR_2_NUM(Cursegp);
+//@@
+//@@   Update_flags |= UF_GAME_VIEW_CHANGED;
+//@@   return 1;
+//@@}
+
+//this constant determines how much of the window will be occupied by the
+//viewed side when SetPlayerFromCursegMinusOne() is called.  It actually
+//determine how from from the center of the window the farthest point will be
+#define SIDE_VIEW_FRAC (f1_0*8/10)     //80%
+
+
+void move_player_2_segment_and_rotate(segment *seg,int side)
+{
+       vms_vector vp;
+       vms_vector      upvec;
+        static int edgenum=0;
+
+       compute_segment_center(&ConsoleObject->pos,seg);
+       compute_center_point_on_side(&vp,seg,side);
+       vm_vec_sub2(&vp,&ConsoleObject->pos);
+
+       vm_vec_sub(&upvec, &Vertices[Cursegp->verts[Side_to_verts[Curside][edgenum%4]]], &Vertices[Cursegp->verts[Side_to_verts[Curside][(edgenum+3)%4]]]);
+       edgenum++;
+
+       vm_vector_2_matrix(&ConsoleObject->orient,&vp,&upvec,NULL);
+//     vm_vector_2_matrix(&ConsoleObject->orient,&vp,NULL,NULL);
+
+       obj_relink( ConsoleObject-Objects, SEG_PTR_2_NUM(seg) );
+       
+}
+
+int SetPlayerFromCursegAndRotate()
+{
+       move_player_2_segment_and_rotate(Cursegp,Curside);
+       Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED;
+       return 1;
+}
+
+
+//sets the player facing curseg/curside, normal to face0 of curside, and
+//far enough away to see all of curside
+int SetPlayerFromCursegMinusOne()
+{
+       vms_vector view_vec,view_vec2,side_center;
+       vms_vector corner_v[4];
+       vms_vector      upvec;
+       g3s_point corner_p[4];
+       int i;
+       fix max,view_dist=f1_0*10;
+        static int edgenum=0;
+       int newseg;
+
+       view_vec = Cursegp->sides[Curside].normals[0];
+       vm_vec_negate(&view_vec);
+
+       compute_center_point_on_side(&side_center,Cursegp,Curside);
+       vm_vec_copy_scale(&view_vec2,&view_vec,view_dist);
+       vm_vec_sub(&ConsoleObject->pos,&side_center,&view_vec2);
+
+       vm_vec_sub(&upvec, &Vertices[Cursegp->verts[Side_to_verts[Curside][edgenum%4]]], &Vertices[Cursegp->verts[Side_to_verts[Curside][(edgenum+3)%4]]]);
+       edgenum++;
+
+       vm_vector_2_matrix(&ConsoleObject->orient,&view_vec,&upvec,NULL);
+
+       gr_set_current_canvas(Canv_editor_game);
+       g3_start_frame();
+       g3_set_view_matrix(&ConsoleObject->pos,&ConsoleObject->orient,Render_zoom);
+
+       for (i=max=0;i<4;i++) {
+               corner_v[i] = Vertices[Cursegp->verts[Side_to_verts[Curside][i]]];
+               g3_rotate_point(&corner_p[i],&corner_v[i]);
+               if (labs(corner_p[i].p3_x) > max) max = labs(corner_p[i].p3_x);
+               if (labs(corner_p[i].p3_y) > max) max = labs(corner_p[i].p3_y);
+       }
+
+       view_dist = fixmul(view_dist,fixdiv(fixdiv(max,SIDE_VIEW_FRAC),corner_p[0].p3_z));
+       vm_vec_copy_scale(&view_vec2,&view_vec,view_dist);
+       vm_vec_sub(&ConsoleObject->pos,&side_center,&view_vec2);
+
+       //obj_relink(ConsoleObject-Objects, SEG_PTR_2_NUM(Cursegp) );
+       //update_object_seg(ConsoleObject);             //might have backed right out of curseg
+
+       newseg = find_point_seg(&ConsoleObject->pos,SEG_PTR_2_NUM(Cursegp) );
+       if (newseg != -1)
+               obj_relink(ConsoleObject-Objects,newseg);
+
+       Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED;
+       return 1;
+}
+
+int ToggleLighting(void)
+{
+       char    outstr[80] = "[shift-L] ";
+       int     chindex;
+
+       Lighting_on++;
+       if (Lighting_on >= 2)
+               Lighting_on = 0;
+
+       Update_flags |= UF_GAME_VIEW_CHANGED;
+
+       if (last_keypress == KEY_L + KEY_SHIFTED)
+               chindex = 0;
+       else
+               chindex = 10;
+
+       switch (Lighting_on) {
+               case 0:
+                       strcpy(&outstr[chindex],"Lighting off.");
+                       break;
+               case 1:
+                       strcpy(&outstr[chindex],"Static lighting.");
+                       break;
+               case 2:
+                       strcpy(&outstr[chindex],"Ship lighting.");
+                       break;
+               case 3:
+                       strcpy(&outstr[chindex],"Ship and static lighting.");
+                       break;
+       }
+
+       diagnostic_message(outstr);
+
+       return Lighting_on;
+}
+
+void find_concave_segs();
+
+int FindConcaveSegs()
+{
+       find_concave_segs();
+
+       Update_flags |= UF_ED_STATE_CHANGED;            //list may have changed
+
+       return 1;
+}
+
+int DosShell()
+{
+       int ok, w, h;
+       grs_bitmap * save_bitmap;
+
+       // Save the current graphics state.
+
+       w = grd_curscreen->sc_canvas.cv_bitmap.bm_w;
+       h = grd_curscreen->sc_canvas.cv_bitmap.bm_h;
+
+       save_bitmap = gr_create_bitmap( w, h );
+       gr_bm_ubitblt(w, h, 0, 0, 0, 0, &(grd_curscreen->sc_canvas.cv_bitmap), save_bitmap );
+
+       gr_set_mode( SM_ORIGINAL );
+
+       printf( "\n\nType EXIT to return to Inferno" );
+       fflush(stdout);
+
+       key_close();
+#ifndef __LINUX__
+       ok = spawnl(P_WAIT,getenv("COMSPEC"), NULL );
+#else
+        system("");
+#endif
+       key_init();
+
+       gr_set_mode(grd_curscreen->sc_mode);
+       gr_bm_ubitblt(w, h, 0, 0, 0, 0, save_bitmap, &(grd_curscreen->sc_canvas.cv_bitmap));
+       gr_free_bitmap( save_bitmap );
+       //gr_pal_setblock( 0, 256, grd_curscreen->pal );
+       //gr_use_palette_table();
+
+       return 1;
+
+}
+
+int ToggleOutlineMode()
+{      int mode;
+
+       mode=toggle_outline_mode();
+
+        if (mode)
+         {
+               if (last_keypress != KEY_O)
+                       diagnostic_message("[O] Outline Mode ON.");
+               else
+                       diagnostic_message("Outline Mode ON.");
+         }
+       else
+         {
+               if (last_keypress != KEY_O)
+                       diagnostic_message("[O] Outline Mode OFF.");
+               else
+                       diagnostic_message("Outline Mode OFF.");
+         }
+
+       Update_flags |= UF_GAME_VIEW_CHANGED;
+       return mode;
+}
+
+//@@int do_reset_orient()
+//@@{
+//@@   slew_reset_orient(SlewObj);
+//@@
+//@@   Update_flags |= UF_GAME_VIEW_CHANGED;
+//@@
+//@@   * (ubyte *) 0x417 &= ~0x20;
+//@@
+//@@   return 1;
+//@@}
+
+int GameZoomOut()
+{
+       Render_zoom = fixmul(Render_zoom,68985);
+       Update_flags |= UF_GAME_VIEW_CHANGED;
+       return 1;
+}
+
+int GameZoomIn()
+{
+       Render_zoom = fixmul(Render_zoom,62259);
+       Update_flags |= UF_GAME_VIEW_CHANGED;
+       return 1;
+}
+
+
+int med_keypad_goto_0()        {       ui_pad_goto(0); return 0;       }
+int med_keypad_goto_1()        {       ui_pad_goto(1); return 0;       }
+int med_keypad_goto_2()        {       ui_pad_goto(2); return 0;       }
+int med_keypad_goto_3()        {       ui_pad_goto(3); return 0;       }
+int med_keypad_goto_4()        {       ui_pad_goto(4); return 0;       }
+int med_keypad_goto_5()        {       ui_pad_goto(5); return 0;       }
+int med_keypad_goto_6()        {       ui_pad_goto(6); return 0;       }
+int med_keypad_goto_7()        {       ui_pad_goto(7); return 0;       }
+int med_keypad_goto_8()        {       ui_pad_goto(8); return 0;       }
+
+#define        PAD_WIDTH       30
+#define        PAD_WIDTH1      (PAD_WIDTH + 7)
+
+int editor_screen_open = 0;
+
+//setup the editors windows, canvases, gadgets, etc.
+//called whenever the editor screen is selected
+void init_editor_screen()
+{      
+//     grs_bitmap * bmp;
+
+       if (editor_screen_open) return;
+
+       grd_curscreen->sc_canvas.cv_font = editor_font;
+       
+       //create canvas for game on the editor screen
+       initializing = 1;
+       gr_set_current_canvas(Canv_editor);
+       Canv_editor->cv_font = editor_font;
+       gr_init_sub_canvas(Canv_editor_game,Canv_editor,GAMEVIEW_X,GAMEVIEW_Y,GAMEVIEW_W,GAMEVIEW_H);
+       
+       //Editor renders into full (320x200) game screen 
+
+       init_info = 1;
+
+       //do other editor screen setup
+
+       // Since the palette might have changed, find some good colors...
+       CBLACK = gr_find_closest_color( 1, 1, 1 );
+       CGREY = gr_find_closest_color( 28, 28, 28 );
+       CWHITE = gr_find_closest_color( 38, 38, 38 );
+       CBRIGHT = gr_find_closest_color( 60, 60, 60 );
+       CRED = gr_find_closest_color( 63, 0, 0 );
+
+       gr_set_curfont(editor_font);
+       gr_set_fontcolor( CBLACK, CWHITE );
+
+       EditorWindow = ui_open_window( 0 , 0, ED_SCREEN_W, ED_SCREEN_H, WIN_FILLED );
+
+       LargeViewBox    = ui_add_gadget_userbox( EditorWindow,LVIEW_X,LVIEW_Y,LVIEW_W,LVIEW_H);
+#if ORTHO_VIEWS
+       TopViewBox              = ui_add_gadget_userbox( EditorWindow,TVIEW_X,TVIEW_Y,TVIEW_W,TVIEW_H);
+       FrontViewBox    = ui_add_gadget_userbox( EditorWindow,FVIEW_X,FVIEW_Y,FVIEW_W,FVIEW_H);
+       RightViewBox    = ui_add_gadget_userbox( EditorWindow,RVIEW_X,RVIEW_Y,RVIEW_W,RVIEW_H);
+#endif
+       ui_gadget_calc_keys(EditorWindow);      //make tab work for all windows
+
+       GameViewBox     = ui_add_gadget_userbox( EditorWindow, GAMEVIEW_X, GAMEVIEW_Y, GAMEVIEW_W, GAMEVIEW_H );
+//     GroupViewBox    = ui_add_gadget_userbox( EditorWindow,GVIEW_X,GVIEW_Y,GVIEW_W,GVIEW_H);
+
+//     GameViewBox->when_tab = GameViewBox->when_btab = (UI_GADGET *) LargeViewBox;
+//     LargeViewBox->when_tab = LargeViewBox->when_btab = (UI_GADGET *) GameViewBox;
+
+//     ui_gadget_calc_keys(EditorWindow);      //make tab work for all windows
+
+       ViewIcon        = ui_add_gadget_icon( EditorWindow, "Lock\nview",       455,25+530,     40, 22, KEY_V+KEY_CTRLED, ToggleLockViewToCursegp );
+       AllIcon = ui_add_gadget_icon( EditorWindow, "Draw\nall",        500,25+530,     40, 22, KEY_A+KEY_CTRLED, ToggleDrawAllSegments );
+       AxesIcon        = ui_add_gadget_icon( EditorWindow, "Coord\naxes",545,25+530,           40, 22, KEY_D+KEY_CTRLED, ToggleCoordAxes );
+//-NOLIGHTICON-        LightIcon       = ui_add_gadget_icon( EditorWindow, "Light\ning",       590,25+530,     40, 22, KEY_L+KEY_SHIFTED,ToggleLighting );
+       ChaseIcon       = ui_add_gadget_icon( EditorWindow, "Chase\nmode",635,25+530,           40, 22, -1,                             ToggleChaseMode );
+       OutlineIcon = ui_add_gadget_icon( EditorWindow, "Out\nline",    680,25+530,     40, 22, KEY_O,                  ToggleOutlineMode );
+       LockIcon        = ui_add_gadget_icon( EditorWindow, "Lock\nstep", 725,25+530,   40, 22, KEY_L,                  ToggleLockstep );
+
+       meddraw_init_views(LargeViewBox->canvas);
+
+       //ui_add_gadget_button( EditorWindow, 460, 510, 50, 25, "Quit", ExitEditor );
+       //ui_add_gadget_button( EditorWindow, 520, 510, 50, 25, "Lisp", CallLisp );
+       //ui_add_gadget_button( EditorWindow, 580, 510, 50, 25, "Mine", MineMenu );
+       //ui_add_gadget_button( EditorWindow, 640, 510, 50, 25, "Help", DoHelp );
+       //ui_add_gadget_button( EditorWindow, 460, 540, 50, 25, "Macro", MacroMenu );
+       //ui_add_gadget_button( EditorWindow, 520, 540, 50, 25, "About", ShowAbout );
+       //ui_add_gadget_button( EditorWindow, 640, 540, 50, 25, "Shell", DosShell );
+
+       ui_pad_activate( EditorWindow, PAD_X, PAD_Y );
+       Pad_text_canvas = gr_create_sub_canvas(Canv_editor, PAD_X + 250, PAD_Y + 8, 180, 160);
+       ui_add_gadget_button( EditorWindow, PAD_X+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "<<",  med_keypad_goto_prev );
+       ui_add_gadget_button( EditorWindow, PAD_X+PAD_WIDTH1+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, ">>",  med_keypad_goto_next );
+
+       {       int     i;
+               i = 0;  ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "SR",  med_keypad_goto_0 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "SS",  med_keypad_goto_1 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "CF",  med_keypad_goto_2 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "TM",  med_keypad_goto_3 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "OP",  med_keypad_goto_4 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "OR",  med_keypad_goto_5 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "GE",  med_keypad_goto_6 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "LI",  med_keypad_goto_7 );
+               i++;            ui_add_gadget_button( EditorWindow, PAD_X+16+(i+2)*PAD_WIDTH1, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "TT",  med_keypad_goto_8 );
+       }
+
+       gr_set_curfont(editor_font);
+       menubar_show();
+
+       // INIT TEXTURE STUFF
+       texpage_init( EditorWindow );
+       objpage_init( EditorWindow );
+
+       EditorWindow->keyboard_focus_gadget = (UI_GADGET *)LargeViewBox;
+
+       canv_offscreen->cv_font = grd_curscreen->sc_canvas.cv_font;
+//     BigCanvas[0]->cv_font = grd_curscreen->sc_canvas.cv_font; 
+//     BigCanvas[1]->cv_font = grd_curscreen->sc_canvas.cv_font; 
+//     BigCanvasFirstTime = 1;
+
+       // Draw status box
+       gr_set_current_canvas( NULL );
+       gr_setcolor( CGREY );
+       gr_rect(STATUS_X,STATUS_Y,STATUS_X+STATUS_W-1,STATUS_Y+STATUS_H-1);                     //0, 582, 799, 599 );
+
+       // Draw icon box
+       // gr_set_current_canvas( NULL );
+       //  gr_setcolor( CBRIGHT );
+       //  gr_rect( 528, 2, 798, 22);
+       //  gr_setcolor( CGREY);
+       //  gr_rect( 530, 2, 799, 20);
+
+       Update_flags = UF_ALL;
+       initializing = 0;
+       editor_screen_open = 1;
+}
+
+//shutdown ui on the editor screen
+void close_editor_screen()
+{
+       if (!editor_screen_open) return;
+
+       editor_screen_open = 0;
+       ui_pad_deactivate();
+       gr_free_sub_canvas(Pad_text_canvas);
+
+       ui_close_window(EditorWindow);
+
+       close_all_windows();
+
+       // CLOSE TEXTURE STUFF
+       texpage_close();
+       objpage_close();
+
+       menubar_hide();
+
+}
+
+void med_show_warning(char *s)
+{
+       grs_canvas *save_canv=grd_curcanv;
+
+       //gr_pal_fade_in(grd_curscreen->pal);   //in case palette is blacked
+
+       MessageBox(-2,-2,1,s,"OK");
+
+       gr_set_current_canvas(save_canv);
+
+}
+
+// Returns 1 if OK to trash current mine.
+int SafetyCheck()
+{
+       int x;
+                       
+       if (mine_changed) {
+               stop_time();                            
+               x = nm_messagebox( "Warning!", 2, "Cancel", "OK", "You are about to lose work." );
+               if (x<1) {
+                       start_time();
+                       return 0;
+               }
+               start_time();
+       }
+       return 1;
+}
+
+//called at the end of the program
+void close_editor() {
+
+       close_autosave();
+
+       menubar_close();
+       
+       gr_close_font(editor_font);
+
+       gr_free_canvas(canv_offscreen); canv_offscreen = NULL;
+
+       return;
+
+}
+
+//variables for find segments process
+
+// ---------------------------------------------------------------------------------------------------
+//     Subtract all elements in Found_segs from selected list.
+void subtract_found_segments_from_selected_list(void)
+{
+       int     s,f;
+
+       for (f=0; f<N_found_segs; f++) {
+               int     foundnum = Found_segs[f];
+
+               for (s=0; s<N_selected_segs; s++) {
+                       if (Selected_segs[s] == foundnum) {
+                               Selected_segs[s] = Selected_segs[N_selected_segs-1];
+                               N_selected_segs--;
+                               break;
+                       }
+               }
+       }
+}
+
+// ---------------------------------------------------------------------------------------------------
+//     Add all elements in Found_segs to selected list.
+void add_found_segments_to_selected_list(void) {
+       int     s,f;
+
+       for (f=0; f<N_found_segs; f++) {
+               int     foundnum = Found_segs[f];
+
+               for (s=0; s<N_selected_segs; s++)
+                       if (Selected_segs[s] == foundnum)
+                               break;
+
+               if (s == N_selected_segs)
+                       Selected_segs[N_selected_segs++] = foundnum;
+       }
+}
+
+void gamestate_restore_check() {
+       char Message[DIAGNOSTIC_MESSAGE_MAX];
+       obj_position Save_position;
+
+       if (gamestate_not_restored) {
+               sprintf( Message, "Do you wish to restore game state?\n");
+       
+               if (MessageBox( -2, -2, 2, Message, "Yes", "No" )==1) {
+
+                       // Save current position
+                       Save_position.pos = ConsoleObject->pos;
+                       Save_position.orient = ConsoleObject->orient;
+                       Save_position.segnum = ConsoleObject->segnum;
+
+                       load_level("GAMESAVE.LVL");
+
+                       // Restore current position
+                       if (Save_position.segnum <= Highest_segment_index) {
+                               ConsoleObject->pos = Save_position.pos;
+                               ConsoleObject->orient = Save_position.orient;
+                               obj_relink(ConsoleObject-Objects,Save_position.segnum);
+                       }
+
+                       gamestate_not_restored = 0;
+                       Update_flags |= UF_WORLD_CHANGED;       
+                       }
+               else
+                       gamestate_not_restored = 1;
+               }
+}
+
+int RestoreGameState() {
+       load_level("GAMESAVE.LVL");
+       gamestate_not_restored = 0;
+
+       mprintf((0, "Gamestate restored.\n"));
+       editor_status("Gamestate restored.\n");
+
+       Update_flags |= UF_WORLD_CHANGED;
+       return 0;
+}
+
+extern void check_wall_validity(void);
+
+// ---------------------------------------------------------------------------------------------------
+//this function is the editor. called when editor mode selected.  runs until
+//game mode or exit selected
+void editor(void)
+{
+       int w,h;
+       grs_bitmap * savedbitmap;
+       editor_view *new_cv;
+        static int padnum=0;
+       vms_matrix      MouseRotMat,tempm;
+       //@@short camera_objnum;                        //a camera for viewing
+
+       init_editor();
+
+       InitCurve();
+
+       restore_effect_bitmap_icons();
+
+       if (!set_screen_mode(SCREEN_EDITOR))    {
+               set_screen_mode(SCREEN_GAME);
+               Function_mode=FMODE_GAME;                       //force back into game
+               return;
+       }
+
+       gr_set_current_canvas( NULL );
+       gr_set_curfont(editor_font);
+
+       //Editor renders into full (320x200) game screen 
+
+       set_warn_func(med_show_warning);
+
+       keyd_repeat = 1;                // Allow repeat in editor
+
+//     _MARK_("start of editor");//Nuked to compile -KRB
+
+       ui_mouse_hide();
+
+       ui_reset_idle_seconds();
+
+//@@   //create a camera for viewing in the editor. copy position from ConsoleObject
+//@@   camera_objnum = obj_create(OBJ_CAMERA,0,ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0);
+//@@   Viewer = &Objects[camera_objnum];
+//@@   slew_init(Viewer);              //camera is slewing
+
+       Viewer = ConsoleObject;
+       slew_init(ConsoleObject);
+
+       Update_flags = UF_ALL;
+
+       medlisp_update_screen();
+
+       //set the wire-frame window to be the current view
+       current_view = &LargeView;
+
+       if (faded_in==0)
+       {
+               faded_in = 1;
+               //gr_pal_fade_in( grd_curscreen->pal );
+       }
+
+       w = GameViewBox->canvas->cv_bitmap.bm_w;
+       h = GameViewBox->canvas->cv_bitmap.bm_h;
+       
+       savedbitmap = gr_create_bitmap(w, h );
+
+       gr_bm_ubitblt( w, h, 0, 0, 0, 0, &GameViewBox->canvas->cv_bitmap, savedbitmap );
+
+       gr_set_current_canvas( GameViewBox->canvas );
+       gr_set_curfont(editor_font);
+       //gr_setcolor( CBLACK );
+       //gr_deaccent_canvas();
+       //gr_grey_canvas();
+       
+       ui_mouse_show();
+
+       gr_set_curfont(editor_font);
+       ui_pad_goto(padnum);
+
+       gamestate_restore_check();
+
+       while (Function_mode == FMODE_EDITOR) {
+
+               gr_set_curfont(editor_font);
+               info_display_all(EditorWindow);
+
+               ModeFlag = 0;
+
+               // Update the windows
+
+               // Only update if there is no key waiting and we're not in
+               // fast play mode.
+               if (!key_peekkey()) //-- && (MacroStatus != UI_STATUS_FASTPLAY))
+                       medlisp_update_screen();
+
+               //do editor stuff
+               gr_set_curfont(editor_font);
+               ui_mega_process();
+               last_keypress &= ~KEY_DEBUGGED;         //      mask off delete key bit which has no function in editor.
+               ui_window_do_gadgets(EditorWindow);
+               do_robot_window();
+               do_object_window();
+               do_wall_window();
+               do_trigger_window();
+               do_hostage_window();
+               do_centers_window();
+               check_wall_validity();
+               Assert(Num_walls>=0);
+
+               if (Gameview_lockstep) {
+                       static segment *old_cursegp=NULL;
+                       static int old_curside=-1;
+
+                       if (old_cursegp!=Cursegp || old_curside!=Curside) {
+                               SetPlayerFromCursegMinusOne();
+                               old_cursegp = Cursegp;
+                               old_curside = Curside;
+                       }
+               }
+
+//             mprintf((0, "%d ", ui_get_idle_seconds() ));
+
+               if ( ui_get_idle_seconds() > COMPRESS_INTERVAL ) 
+                       {
+                       med_compress_mine();
+                       ui_reset_idle_seconds();
+                       }
+  
+//     Commented out because it occupies about 25% of time in twirling the mine.
+// Removes some Asserts....
+//             med_check_all_vertices();
+               clear_editor_status();          // if enough time elapsed, clear editor status message
+               TimedAutosave(mine_filename);
+               set_editor_time_of_day();
+               gr_set_current_canvas( GameViewBox->canvas );
+               
+               // Remove keys used for slew
+               switch(last_keypress)
+               {
+               case KEY_PAD9:
+               case KEY_PAD7:
+               case KEY_PADPLUS:
+               case KEY_PADMINUS:
+               case KEY_PAD8:
+               case KEY_PAD2:
+               case KEY_LBRACKET:
+               case KEY_RBRACKET:
+               case KEY_PAD1:
+               case KEY_PAD3:
+               case KEY_PAD6:
+               case KEY_PAD4:
+                       last_keypress = 0;
+               }
+               if ((last_keypress&0xff)==KEY_LSHIFT) last_keypress=0;
+               if ((last_keypress&0xff)==KEY_RSHIFT) last_keypress=0;
+               if ((last_keypress&0xff)==KEY_LCTRL) last_keypress=0;
+               if ((last_keypress&0xff)==KEY_RCTRL) last_keypress=0;
+//             if ((last_keypress&0xff)==KEY_LALT) last_keypress=0;
+//             if ((last_keypress&0xff)==KEY_RALT) last_keypress=0;
+
+               gr_set_curfont(editor_font);
+               menubar_do( last_keypress );
+
+               //=================== DO FUNCTIONS ====================
+
+               if ( KeyFunction[ last_keypress ] != NULL )     {
+                       KeyFunction[last_keypress]();
+                       last_keypress = 0;
+               }
+               switch (last_keypress)
+               {
+               case 0:
+               case KEY_Z:
+               case KEY_G:
+               case KEY_LALT:
+               case KEY_RALT:
+               case KEY_LCTRL:
+               case KEY_RCTRL:
+               case KEY_LSHIFT:
+               case KEY_RSHIFT:
+               case KEY_LAPOSTRO:
+                       break;
+               case KEY_SHIFTED + KEY_L:
+                       ToggleLighting();
+                       break;
+               case KEY_F1:
+                       render_3d_in_big_window = !render_3d_in_big_window;
+                       Update_flags |= UF_ALL;
+                       break;                  
+               default:
+                       {
+                       char kdesc[100];
+                       GetKeyDescription( kdesc, last_keypress );
+                       editor_status("Error: %s isn't bound to anything.", kdesc  );
+                       }
+               }
+
+               //================================================================
+
+               if (ModeFlag==1)
+               {
+                       close_editor_screen();
+                       Function_mode=FMODE_EXIT;
+                               gr_free_bitmap( savedbitmap );
+                       break;
+               }
+
+               if (ModeFlag==2) //-- && MacroStatus==UI_STATUS_NORMAL )
+               {
+                       ui_mouse_hide();
+                       Function_mode = FMODE_GAME;
+                       gr_bm_ubitblt( w, h, 0, 0, 0, 0, savedbitmap, &GameViewBox->canvas->cv_bitmap);
+                       gr_free_bitmap( savedbitmap );
+                       break;
+               }
+
+               if (ModeFlag==3) //-- && MacroStatus==UI_STATUS_NORMAL )
+               {
+//                     med_compress_mine();                                            //will be called anyways before game.
+                       close_editor_screen();
+                       Function_mode=FMODE_GAME;                       //force back into game
+                       set_screen_mode(SCREEN_GAME);           //put up game screen
+                       gr_free_bitmap( savedbitmap );
+                       break;
+               }
+
+//             if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)GameViewBox) current_view=NULL;
+//             if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)GroupViewBox) current_view=NULL;
+
+               new_cv = current_view ;
+
+#if ORTHO_VIEWS
+               if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)LargeViewBox) new_cv=&LargeView;
+               if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)TopViewBox)        new_cv=&TopView;
+               if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)FrontViewBox) new_cv=&FrontView;
+               if (CurWindow->keyboard_focus_gadget == (UI_GADGET *)RightViewBox) new_cv=&RightView;
+#endif
+               if (new_cv != current_view ) {
+                       current_view->ev_changed = 1;
+                       new_cv->ev_changed = 1;
+                       current_view = new_cv;
+               }
+
+               calc_frame_time();
+               if (slew_frame(0)) {            //do movement and check keys
+                       Update_flags |= UF_GAME_VIEW_CHANGED;
+                       if (Gameview_lockstep) {
+                               Cursegp = &Segments[ConsoleObject->segnum];
+                               med_create_new_segment_from_cursegp();
+                               Update_flags |= UF_ED_STATE_CHANGED;
+                       }
+               }
+
+               // DO TEXTURE STUFF
+               texpage_do();
+               objpage_do();
+
+
+               // Process selection of Cursegp using mouse.
+               if (LargeViewBox->mouse_onme && LargeViewBox->b1_clicked && !render_3d_in_big_window) 
+               {
+                       int     xcrd,ycrd;
+                       xcrd = LargeViewBox->b1_drag_x1;
+                       ycrd = LargeViewBox->b1_drag_y1;
+
+                       find_segments(xcrd,ycrd,LargeViewBox->canvas,&LargeView,Cursegp,Big_depth);     // Sets globals N_found_segs, Found_segs
+
+                       // If shift is down, then add segment to found list
+                       if (keyd_pressed[ KEY_LSHIFT ] || keyd_pressed[ KEY_RSHIFT ])
+                               subtract_found_segments_from_selected_list();
+                       else
+                               add_found_segments_to_selected_list();
+
+                       Found_seg_index = 0;    
+               
+                       if (N_found_segs > 0) {
+                               sort_seg_list(N_found_segs,Found_segs,&ConsoleObject->pos);
+                               Cursegp = &Segments[Found_segs[0]];
+                               med_create_new_segment_from_cursegp();
+                               if (Lock_view_to_cursegp)
+                                       set_view_target_from_segment(Cursegp);
+                       }
+
+                       Update_flags |= UF_ED_STATE_CHANGED | UF_VIEWPOINT_MOVED;
+               }
+
+               if (GameViewBox->mouse_onme && GameViewBox->b1_dragging) {
+                       int     x, y;
+                       x = GameViewBox->b1_drag_x2;
+                       y = GameViewBox->b1_drag_y2;
+
+                       ui_mouse_hide();
+                       gr_set_current_canvas( GameViewBox->canvas );
+                       gr_setcolor( 15 );
+                       gr_rect( x-1, y-1, x+1, y+1 );
+                       ui_mouse_show();
+
+               }
+               
+               // Set current segment and side by clicking on a polygon in game window.
+               //      If ctrl pressed, also assign current texture map to that side.
+               //if (GameViewBox->mouse_onme && (GameViewBox->b1_done_dragging || GameViewBox->b1_clicked)) {
+               if ((GameViewBox->mouse_onme && GameViewBox->b1_clicked && !render_3d_in_big_window) ||
+                       (LargeViewBox->mouse_onme && LargeViewBox->b1_clicked && render_3d_in_big_window)) {
+
+                       int     xcrd,ycrd;
+                       int seg,side,face,poly,tmap;
+
+                       if (render_3d_in_big_window) {
+                               xcrd = LargeViewBox->b1_drag_x1;
+                               ycrd = LargeViewBox->b1_drag_y1;
+                       }
+                       else {
+                               xcrd = GameViewBox->b1_drag_x1;
+                               ycrd = GameViewBox->b1_drag_y1;
+                       }
+       
+                       //Int3();
+
+                       if (find_seg_side_face(xcrd,ycrd,&seg,&side,&face,&poly)) {
+
+
+                               if (seg<0) {                                                    //found an object
+
+                                       Cur_object_index = -seg-1;
+                                       editor_status("Object %d selected.",Cur_object_index);
+
+                                       Update_flags |= UF_ED_STATE_CHANGED;
+                               }
+                               else {
+
+                                       //      See if either shift key is down and, if so, assign texture map
+                                       if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) {
+                                               Cursegp = &Segments[seg];
+                                               Curside = side;
+                                               AssignTexture();
+                                               med_create_new_segment_from_cursegp();
+                                               editor_status("Texture assigned");
+                                       } else if (keyd_pressed[KEY_G]) {
+                                               tmap = Segments[seg].sides[side].tmap_num;
+                                               texpage_grab_current(tmap);
+                                               editor_status( "Texture grabbed." );
+                                       } else if (keyd_pressed[ KEY_LAPOSTRO] ) {
+                                               ui_mouse_hide();
+                                               move_object_to_mouse_click();
+                                       } else {
+                                               Cursegp = &Segments[seg];
+                                               Curside = side;
+                                               med_create_new_segment_from_cursegp();
+                                               editor_status("Curseg and curside selected");
+                                       }
+                               }
+
+                               Update_flags |= UF_ED_STATE_CHANGED;
+                       }
+                       else 
+                               editor_status("Click on non-texture ingored");
+
+               }
+
+               // Allow specification of LargeView using mouse
+               if (keyd_pressed[ KEY_LCTRL ] || keyd_pressed[ KEY_RCTRL ]) {
+                       ui_mouse_hide();
+                       if ( (Mouse.dx!=0) && (Mouse.dy!=0) ) {
+                               GetMouseRotation( Mouse.dx, Mouse.dy, &MouseRotMat );
+                               vm_matrix_x_matrix(&tempm,&LargeView.ev_matrix,&MouseRotMat);
+                               LargeView.ev_matrix = tempm;
+                               LargeView.ev_changed = 1;
+                               Large_view_index = -1;                  // say not one of the orthogonal views
+                       }
+               } else  {
+                       ui_mouse_show();
+               }
+
+               if ( keyd_pressed[ KEY_Z ] ) {
+                       ui_mouse_hide();
+                       if ( Mouse.dy!=0 ) {
+                               current_view->ev_dist += Mouse.dy*10000;
+                               current_view->ev_changed = 1;
+                       }
+               } else {
+                       ui_mouse_show();
+               }
+
+       }
+
+//     _MARK_("end of editor");//Nuked to compile -KRB
+
+       clear_warn_func(med_show_warning);
+
+       //kill our camera object
+
+       Viewer = ConsoleObject;                                 //reset viewer
+       //@@obj_delete(camera_objnum);
+
+       padnum = ui_pad_get_current();
+
+       close_editor();
+       ui_close();
+
+
+}
+
+void test_fade(void)
+{
+       int     i,c;
+
+       for (c=0; c<256; c++) {
+               printf("%4i: {%3i %3i %3i} ",c,gr_palette[3*c],gr_palette[3*c+1],gr_palette[3*c+2]);
+               for (i=0; i<16; i++) {
+                       int col = gr_fade_table[256*i+c];
+
+                       printf("[%3i %3i %3i] ",gr_palette[3*col],gr_palette[3*col+1],gr_palette[3*col+2]);
+               }
+               if ( (c%16) == 15)
+                       printf("\n");
+               printf("\n");
+       }
+}
+
+void dump_stuff(void)
+{
+       int     i,j,prev_color;
+
+       printf("Palette:\n");
+
+       for (i=0; i<256; i++)
+               printf("%3i: %2i %2i %2i\n",i,gr_palette[3*i],gr_palette[3*i+1],gr_palette[3*i+2]);
+
+       for (i=0; i<16; i++) {
+               printf("\nFade table #%i\n",i);
+               for (j=0; j<256; j++) {
+                       int     c = gr_fade_table[i*256 + j];
+                       printf("[%3i %2i %2i %2i] ",c, gr_palette[3*c], gr_palette[3*c+1], gr_palette[3*c+2]);
+                       if ((j % 8) == 7)
+                               printf("\n");
+               }
+       }
+
+       printf("Colors indexed by intensity:\n");
+       printf(". = change from previous, * = no change\n");
+       for (j=0; j<256; j++) {
+               printf("%3i: ",j);
+               prev_color = -1;
+               for (i=0; i<16; i++) {
+                       int     c = gr_fade_table[i*256 + j];
+                       if (c == prev_color)
+                               printf("*");
+                       else
+                               printf(".");
+                       prev_color = c;
+               }
+               printf("  ");
+               for (i=0; i<16; i++) {
+                       int     c = gr_fade_table[i*256 + j];
+                       printf("[%3i %2i %2i %2i] ", c, gr_palette[3*c], gr_palette[3*c+1], gr_palette[3*c+2]);
+               }
+               printf("\n");
+       }
+
+}
+
+
+int MarkStart(void)
+{
+       char mystr[30];
+       sprintf(mystr,"mark %i start",Mark_count);
+//     _MARK_(mystr);//Nuked to compile -KRB
+
+       return 1;
+}
+
+int MarkEnd(void)
+{
+       char mystr[30];
+       sprintf(mystr,"mark %i end",Mark_count);
+       Mark_count++;
+//     _MARK_(mystr);//Nuked to compile -KRB
+
+       return 1;
+}
+
diff --git a/main/editor/medwall.h b/main/editor/medwall.h
new file mode 100644 (file)
index 0000000..4364192
--- /dev/null
@@ -0,0 +1,109 @@
+/*
+THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
+SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
+END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
+ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
+IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
+SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
+FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
+CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
+AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
+COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
+*/
+/*
+ * $Source: /cvs/cvsroot/d2x/main/editor/medwall.h,v $
+ * $Revision: 1.1 $
+ * $Author: bradleyb $
+ * $Date: 2001-10-25 02:27:17 $
+ * 
+ * Created from version 1.6 of main\wall.h
+ * 
+ * $Log: not supported by cvs2svn $
+ * Revision 1.1.1.1  1999/06/14 22:02:40  donut
+ * Import of d1x 1.37 source.
+ *
+ * Revision 2.0  1995/02/27  11:35:10  john
+ * Version 2.0! No anonymous unions, Watcom 10.0, with no need
+ * for bitmaps.tbl.
+ * 
+ * Revision 1.9  1994/09/28  17:31:51  mike
+ * Prototype copy_group_walls().
+ * 
+ * Revision 1.8  1994/08/05  21:18:16  matt
+ * Allow two doors to be linked together
+ * 
+ * Revision 1.7  1994/06/20  22:30:10  yuan
+ * Fixed crazy runaway trigger bug that Adam found
+ * 
+ * Revision 1.6  1994/05/30  20:22:58  yuan
+ * New triggers.
+ * 
+ * Revision 1.5  1994/05/25  18:08:37  yuan
+ * Revamping walls and triggers interface.
+ * Wall interface complete, but triggers are still in progress.
+ * 
+ * Revision 1.4  1994/05/18  18:22:04  yuan
+ * Fixed delete segment and walls bug.
+ * 
+ * Revision 1.3  1994/03/17  18:08:41  yuan
+ * New wall stuff... Cut out switches....
+ * 
+ * Revision 1.2  1994/03/15  16:34:10  yuan
+ * Fixed bm loader (might have some changes in walls and switches)
+ * 
+ * Revision 1.1  1994/02/10  17:52:01  matt
+ * Initial revision
+ * 
+ * 
+ * 
+ */
+
+#ifndef _MEDWALL_H
+#define _MEDWALL_H
+
+#include "wall.h"
+#include "inferno.h"
+#include "segment.h"
+
+extern int wall_add_removable(); 
+
+// Restores all the walls to original status
+extern int wall_restore_all();
+
+// Reset a wall.
+extern void wall_reset(segment *seg, short side);
+
+// Adds a removable wall (medwall.c)
+extern int wall_add_removable();
+
+// Adds a door (medwall.c)
+extern int wall_add_door();
+
+// Adds an illusory wall (medwall.c)
+extern int wall_add_illusion();
+
+// Removes a removable wall (medwall.c) 
+extern int wall_remove_blastable(); 
+
+// Adds a wall. (visually)
+extern int wall_add_to_curside();
+extern int wall_add_to_markedside(byte type);
+// Removes a wall. (visually)
+extern int wall_remove();
+
+// Removes a specific side.
+int wall_remove_side(segment *seg, short side);
+
+extern int bind_wall_to_control_center();
+
+extern void close_wall_window();
+
+extern void do_wall_window();
+
+extern int wall_link_doors();
+extern int wall_unlink_door();
+extern void copy_group_walls(int old_group, int new_group);
+
+#endif
+
diff --git a/main/editor/segment.c b/main/editor/segment.c
new file mode 100644 (file)
index 0000000..d8b4795
--- /dev/null
@@ -0,0 +1,2271 @@
+/*
+THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
+SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
+END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
+ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
+IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
+SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
+FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
+CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
+AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
+COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
+*/
+
+/*
+ * $Source: /cvs/cvsroot/d2x/main/editor/segment.c,v $
+ * $Revision: 1.1 $
+ * $Author: bradleyb $
+ * $Date: 2001-10-25 02:27:17 $
+ *
+ * Interrogation functions for segment data structure.
+ *
+ * $Log: not supported by cvs2svn $
+ * Revision 1.2  1999/09/02 13:37:06  sekmu
+ * remove warning in editor compile
+ *
+ * Revision 1.1.1.1  1999/06/14 22:04:21  donut
+ * Import of d1x 1.37 source.
+ *
+ * Revision 2.0  1995/02/27  11:35:21  john
+ * Version 2.0! No anonymous unions, Watcom 10.0, with no need
+ * for bitmaps.tbl.
+ * 
+ * Revision 1.191  1995/02/22  15:28:30  allender
+ * remove anonymous unions from object structure
+ * 
+ * Revision 1.190  1995/02/02  02:59:40  yuan
+ * Working on exterminating bogus matcen_nums... (harmless though)
+ * 
+ * Revision 1.189  1995/02/01  16:29:51  yuan
+ * Stabilizing triggers and matcens.
+ * 
+ * Revision 1.188  1995/02/01  11:31:47  yuan
+ * Trigger bug fixed.
+ * 
+ * Revision 1.187  1994/11/27  23:17:24  matt
+ * Made changes for new mprintf calling convention
+ * 
+ * Revision 1.186  1994/11/17  14:48:12  mike
+ * validation functions moved from editor to game.
+ * 
+ * Revision 1.185  1994/10/30  14:13:17  mike
+ * rip out local segment stuff.
+ * 
+ * Revision 1.184  1994/10/27  10:04:24  matt
+ * When triangulating, don't use WID() to see if connected, look at children
+ * 
+ * Revision 1.183  1994/10/26  13:40:23  mike
+ * debug code for matt.
+ * 
+ * Revision 1.182  1994/10/24  16:34:00  mike
+ * Force render after mine compress to prevent bugs in segment selection via clicking in 3d window.
+ * 
+ * Revision 1.181  1994/10/20  18:16:15  mike
+ * Initialize ControlCenterTriggers.num_links in create_new_mine.
+ * 
+ * Revision 1.180  1994/10/18  16:29:14  mike
+ * Write function to automatically fix bogus segnums in segment array.
+ * 
+ * Revision 1.179  1994/10/08  17:10:41  matt
+ * Correctly set current_level_num when loading/creating mine in editor
+ * 
+ * Revision 1.178  1994/09/25  14:17:51  mike
+ * Initialize (to 0) Num_robot_centers and Num_open_doors at mine creation.
+ * 
+ * Revision 1.177  1994/09/20  14:36:06  mike
+ * Write function to find overlapping segments.
+ * 
+ * Revision 1.176  1994/08/25  21:55:57  mike
+ * IS_CHILD stuff.
+ * 
+ * Revision 1.175  1994/08/23  15:28:03  mike
+ * Fix peculiarity in med_combine_duplicate_vertices.
+ * 
+ * Revision 1.174  1994/08/09  16:06:17  john
+ * Added the ability to place players.  Made old
+ * Player variable be ConsoleObject.
+ * 
+ * Revision 1.173  1994/08/05  21:18:10  matt
+ * Allow two doors to be linked together
+ * 
+ * Revision 1.172  1994/08/04  19:13:16  matt
+ * Changed a bunch of vecmat calls to use multiple-function routines, and to
+ * allow the use of C macros for some functions
+ * 
+ * Revision 1.171  1994/07/22  12:37:00  matt
+ * Cleaned up editor/game interactions some more.
+ * 
+ * Revision 1.170  1994/07/22  11:20:08  mike
+ * Set Lsegments validity.
+ * 
+ * Revision 1.169  1994/07/21  19:02:49  mike
+ * lsegment stuff.
+ * 
+ * Revision 1.168  1994/07/21  13:27:17  matt
+ * Ripped out remants of old demo system, and added demo
+ * disables object movement and game options from menu.
+ * 
+ * Revision 1.167  1994/07/19  20:15:48  matt
+ * Name for each level now saved in the .SAV file & stored in Current_level_name
+ * 
+ * Revision 1.166  1994/07/06  12:42:45  john
+ * Made generic messages for hostages.
+ * 
+ * Revision 1.165  1994/06/24  17:04:29  john
+ * *** empty log message ***
+ * 
+ * Revision 1.164  1994/06/15  15:42:40  mike
+ * Initialize static_light field in new segments.
+ * 
+ * Revision 1.163  1994/06/13  17:49:19  mike
+ * Fix bug in med_validate_side which was toasting lighting for removable walls.
+ * 
+ * Revision 1.162  1994/06/13  10:52:20  mike
+ * Fix bug in triangulation of sides between connected segments.
+ * Was assigning SIDE_IS_02 regardless of how triangulated, was
+ * causing physics bugs.
+ * 
+ * Revision 1.161  1994/06/08  18:14:16  mike
+ * Fix triangulation of sides in hallways (ie, where there is no wall),
+ * so they get triangulated the same way, so find_new_seg doesn't get
+ * stuck in an infinite recursion.
+ * 
+ * Revision 1.160  1994/06/08  11:44:31  mike
+ * Fix bug in normals not being opposite on opposite sides of a segment.
+ * Problem occurred due to difference in handling of remainder in signed divide.
+ * 
+ * Revision 1.159  1994/05/31  19:00:15  yuan
+ * Fixed gamestate restore.
+ * 
+ * Revision 1.158  1994/05/30  20:22:36  yuan
+ * New triggers.
+ * 
+ * Revision 1.157  1994/05/26  19:32:51  mike
+ * Add bfs_parse.
+ * 
+ * Revision 1.156  1994/05/23  14:56:46  mike
+ * make current segment be add segment.,
+ * 
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <conf.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+
+#include "mono.h"
+#include "key.h"
+#include "gr.h"
+
+#include "inferno.h"
+#include "segment.h"
+// #include "segment2.h"
+#include "editor.h"
+#include "error.h"
+#include "object.h"
+
+#include "gameseg.h"
+#include "render.h"
+#include "game.h"
+
+#include "wall.h"
+#include "switch.h"
+#include "fuelcen.h"
+#include "cntrlcen.h"
+#include "seguvs.h"
+#include "gameseq.h"
+
+#include "medwall.h"
+#include "hostage.h"
+
+int    Do_duplicate_vertex_check = 0;          // Gets set to 1 in med_create_duplicate_vertex, means to check for duplicate vertices in compress_mine
+
+#define        BOTTOM_STUFF    0
+
+//     Remap all vertices in polygons in a segment through translation table xlate_verts.
+#if BOTTOM_STUFF
+void remap_vertices(segment *segp, int *xlate_verts)
+{
+       int     sidenum, facenum, polynum, v;
+
+       for (sidenum=0; sidenum<MAX_SIDES_PER_SEGMENT; sidenum++)
+               for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++)
+                       for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
+                               poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
+                               for (v=0; v<pp->num_vertices; v++)
+                                       pp->verts[v] = xlate_verts[pp->verts[v]];
+                       }
+}
+
+//     Copy everything from sourceside to destside except sourceside->faces[xx].polys[xx].verts
+void copy_side_except_vertex_ids(side *destside, side *sourceside)
+{
+       int     facenum, polynum, v;
+
+       destside->num_faces = sourceside->num_faces;
+       destside->tri_edge = sourceside->tri_edge;
+       destside->wall_num = sourceside->wall_num;
+
+       for (facenum=0; facenum<sourceside->num_faces; facenum++) {
+               face *destface = &destside->faces[facenum];
+               face *sourceface = &sourceside->faces[facenum];
+
+               destface->num_polys = sourceface->num_polys;
+               destface->normal = sourceface->normal;
+
+               for (polynum=0; polynum<sourceface->num_polys; polynum++) {
+                       poly *destpoly = &destface->polys[polynum];
+                       poly *sourcepoly = &sourceface->polys[polynum];
+
+                       destpoly->num_vertices = sourcepoly->num_vertices;
+                       destpoly->face_type = sourcepoly->face_type;
+                       destpoly->tmap_num = sourcepoly->tmap_num;
+                       destpoly->tmap_num2 = sourcepoly->tmap_num2;
+
+                       for (v=0; v<sourcepoly->num_vertices; v++)
+                               destpoly->uvls[v] = sourcepoly->uvls[v];
+               }
+
+       }
+}
+
+//     [side] [index] [cur:next]
+//     To remap the vertices on a side after a forward rotation
+byte xlate_previous[6][4][2] = {
+{ {7, 3}, {3, 2}, {2, 6}, {6, 7} },            // remapping left to left
+{ {5, 4}, {4, 0}, {7, 3}, {6, 7} },            // remapping back to top
+{ {5, 4}, {1, 5}, {0, 1}, {4, 0} },            // remapping right to right
+{ {0, 1}, {1, 5}, {2, 6}, {3, 2} },            //      remapping front to bottom
+{ {1, 5}, {5, 4}, {6, 7}, {2, 6} },            // remapping bottom to back
+{ {4, 0}, {0, 1}, {3, 2}, {7, 3} },            // remapping top to front
+};
+
+void remap_vertices_previous(segment *segp, int sidenum)
+{
+       int     v, w, facenum, polynum;
+
+       for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
+               for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
+                       poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
+
+                       for (v=0; v<pp->num_vertices; v++) {
+                               for (w=0; w<4; w++) {
+                                       if (pp->verts[v] == xlate_previous[sidenum][w][0]) {
+                                               pp->verts[v] = xlate_previous[sidenum][w][1];
+                                               break;
+                                       }
+                               }
+                               Assert(w<4);    // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
+                       }
+               }
+       }
+}
+
+byte xlate_previous_right[6][4][2] = {
+{ {5, 6}, {6, 7}, {2, 3}, {1, 2} },            // bottom to left
+{ {6, 7}, {7, 4}, {3, 0}, {2, 3} },            // left to top
+{ {7, 4}, {4, 5}, {0, 1}, {3, 0} },            // top to right
+{ {4, 5}, {5, 6}, {1, 2}, {0, 1} },            // right to bottom
+{ {6, 7}, {5, 6}, {4, 5}, {7, 4} },            // back to back
+{ {3, 2}, {0, 3}, {1, 0}, {2, 1} },            // front to front
+};
+
+void remap_vertices_previous_right(segment *segp, int sidenum)
+{
+       int     v, w, facenum, polynum;
+
+       for (facenum=0; facenum<segp->sides[sidenum].num_faces; facenum++) {
+               for (polynum=0; polynum<segp->sides[sidenum].faces[facenum].num_polys; polynum++) {
+                       poly *pp = &segp->sides[sidenum].faces[facenum].polys[polynum];
+
+                       for (v=0; v<pp->num_vertices; v++) {
+                               for (w=0; w<4; w++) {
+                                       if (pp->verts[v] == xlate_previous_right[sidenum][w][0]) {
+                                               pp->verts[v] = xlate_previous_right[sidenum][w][1];
+                                               break;
+                                       }
+                               }
+                               Assert(w<4);    // If w == 4, then didn't find current vertex in list, which means xlate_previous table is bogus
+                       }
+               }
+       }
+}
+
+
+// -----------------------------------------------------------------------------------
+//     Takes top to front
+void med_rotate_segment_forward(segment *segp)
+{
+       segment seg_copy;
+       int             i;
+
+       seg_copy = *segp;
+
+       seg_copy.verts[0] = segp->verts[4];
+       seg_copy.verts[1] = segp->verts[0];
+       seg_copy.verts[2] = segp->verts[3];
+       seg_copy.verts[3] = segp->verts[7];
+       seg_copy.verts[4] = segp->verts[5];
+       seg_copy.verts[5] = segp->verts[1];
+       seg_copy.verts[6] = segp->verts[2];
+       seg_copy.verts[7] = segp->verts[6];
+
+       seg_copy.children[WFRONT] = segp->children[WTOP];
+       seg_copy.children[WTOP] = segp->children[WBACK];
+       seg_copy.children[WBACK] = segp->children[WBOTTOM];
+       seg_copy.children[WBOTTOM] = segp->children[WFRONT];
+
+       seg_copy.sides[WFRONT] = segp->sides[WTOP];
+       seg_copy.sides[WTOP] = segp->sides[WBACK];
+       seg_copy.sides[WBACK] = segp->sides[WBOTTOM];
+       seg_copy.sides[WBOTTOM] = segp->sides[WFRONT];
+
+       for (i=0; i<6; i++)
+               remap_vertices_previous(&seg_copy, i);
+
+       *segp = seg_copy;
+}
+
+// -----------------------------------------------------------------------------------
+//     Takes top to right
+void med_rotate_segment_right(segment *segp)
+{
+       segment seg_copy;
+       int             i;
+
+       seg_copy = *segp;
+
+       seg_copy.verts[4] = segp->verts[7];
+       seg_copy.verts[5] = segp->verts[4];
+       seg_copy.verts[1] = segp->verts[0];
+       seg_copy.verts[0] = segp->verts[3];
+       seg_copy.verts[3] = segp->verts[2];
+       seg_copy.verts[2] = segp->verts[1];
+       seg_copy.verts[6] = segp->verts[5];
+       seg_copy.verts[7] = segp->verts[6];
+
+       seg_copy.children[WRIGHT] = segp->children[WTOP];
+       seg_copy.children[WBOTTOM] = segp->children[WRIGHT];
+       seg_copy.children[WLEFT] = segp->children[WBOTTOM];
+       seg_copy.children[WTOP] = segp->children[WLEFT];
+
+       seg_copy.sides[WRIGHT] = segp->sides[WTOP];
+       seg_copy.sides[WBOTTOM] = segp->sides[WRIGHT];
+       seg_copy.sides[WLEFT] = segp->sides[WBOTTOM];
+       seg_copy.sides[WTOP] = segp->sides[WLEFT];
+
+       for (i=0; i<6; i++)
+               remap_vertices_previous_right(&seg_copy, i);
+
+       *segp = seg_copy;
+}
+
+void make_curside_bottom_side(void)
+{
+       switch (Curside) {
+               case WRIGHT:    med_rotate_segment_right(Cursegp);              break;
+               case WTOP:              med_rotate_segment_right(Cursegp);              med_rotate_segment_right(Cursegp);              break;
+               case WLEFT:             med_rotate_segment_right(Cursegp);              med_rotate_segment_right(Cursegp);              med_rotate_segment_right(Cursegp);              break;
+               case WBOTTOM:   break;
+               case WFRONT:    med_rotate_segment_forward(Cursegp);    break;
+               case WBACK:             med_rotate_segment_forward(Cursegp);    med_rotate_segment_forward(Cursegp);    med_rotate_segment_forward(Cursegp);    break;
+       }
+       Update_flags = UF_WORLD_CHANGED;
+}
+#endif
+
+int ToggleBottom(void)
+{
+       Render_only_bottom = !Render_only_bottom;
+       Update_flags = UF_WORLD_CHANGED;
+       return 0;
+}
+               
+// ---------------------------------------------------------------------------------------------
+//           ---------- Segment interrogation functions ----------
+// ----------------------------------------------------------------------------
+//     Return a pointer to the list of vertex indices for the current segment in vp and
+//     the number of vertices in *nv.
+void med_get_vertex_list(segment *s,int *nv,short **vp)
+{
+       *vp = s->verts;
+       *nv = MAX_VERTICES_PER_SEGMENT;
+}
+
+// -------------------------------------------------------------------------------
+//     Return number of times vertex vi appears in all segments.
+//     This function can be used to determine whether a vertex is used exactly once in
+//     all segments, in which case it can be freely moved because it is not connected
+//     to any other segment.
+int med_vertex_count(int vi)
+{
+       int             s,v;
+       segment *sp;
+       int             count;
+
+       count = 0;
+
+       for (s=0; s<MAX_SEGMENTS; s++) {
+               sp = &Segments[s];
+               if (sp->segnum != -1)
+                       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+                               if (sp->verts[v] == vi)
+                                       count++;
+       }
+
+       return count;
+}
+
+// -------------------------------------------------------------------------------
+int is_free_vertex(int vi)
+{
+       return med_vertex_count(vi) == 1;
+}
+
+
+// -------------------------------------------------------------------------------
+// Move a free vertex in the segment by adding the vector *vofs to its coordinates.
+//     Error handling:
+//     If the point is not free then:
+//             If the point is not valid (probably valid = in 0..7) then:
+//             If adding *vofs will cause a degenerate segment then:
+//     Note, pi is the point index relative to the segment, not an absolute point index.
+// For example, 3 is always the front upper left vertex.
+void med_move_vertex(segment *sp, int pi, vms_vector *vofs)
+{
+       int     abspi;
+
+       Assert((pi >= 0) && (pi <= 7));         // check valid range of point indices.
+
+       abspi = sp->verts[pi];
+
+       // Make sure vertex abspi is free.  If it is free, it appears exactly once in Vertices
+       Assert(med_vertex_count(abspi) == 1);
+
+       Assert(abspi <= MAX_SEGMENT_VERTICES);                  // Make sure vertex id is not bogus.
+
+       vm_vec_add(&Vertices[abspi],&Vertices[abspi],vofs);
+
+       // Here you need to validate the geometry of the segment, which will be quite tricky.
+       // You need to make sure:
+       //              The segment is not concave.
+       //              None of the sides are concave.
+       validate_segment(sp);
+
+}
+
+// -------------------------------------------------------------------------------
+//     Move a free wall in the segment by adding the vector *vofs to its coordinates.
+//     Wall indices: 0/1/2/3/4/5 = left/top/right/bottom/back/front
+void med_move_wall(segment *sp,int wi, vms_vector *vofs)
+{
+       char *vp;
+       int     i;
+
+       Assert( (wi >= 0) && (wi <= 5) );
+
+       vp = Side_to_verts[wi];
+       for (i=0; i<4; i++) {
+               med_move_vertex(sp,*vp,vofs);
+               vp++;
+       }
+
+       validate_segment(sp);
+}
+
+// -------------------------------------------------------------------------------
+//     Return true if one fixed point number is very close to another, else return false.
+int fnear(fix f1, fix f2)
+{
+       return (abs(f1 - f2) <= FIX_EPSILON);
+}
+
+// -------------------------------------------------------------------------------
+int vnear(vms_vector *vp1, vms_vector *vp2)
+{
+       return fnear(vp1->x, vp2->x) && fnear(vp1->y, vp2->y) && fnear(vp1->z, vp2->z);
+}
+
+// -------------------------------------------------------------------------------
+//     Add the vertex *vp to the global list of vertices, return its index.
+//     Search until a matching vertex is found (has nearly the same coordinates) or until Num_vertices
+// vertices have been looked at without a match.  If no match, add a new vertex.
+int med_add_vertex(vms_vector *vp)
+{
+       int     v,free_index;
+       int     count;                                  // number of used vertices found, for loops exits when count == Num_vertices
+
+//     set_vertex_counts();
+
+       Assert(Num_vertices < MAX_SEGMENT_VERTICES);
+
+       count = 0;
+       free_index = -1;
+       for (v=0; (v < MAX_SEGMENT_VERTICES) && (count < Num_vertices); v++)
+               if (Vertex_active[v]) {
+                       count++;
+                       if (vnear(vp,&Vertices[v])) {
+                               // mprintf((0,"[%4i]  ",v));
+                               return v;
+                       }
+               } else if (free_index == -1)
+                       free_index = v;                                 // we want free_index to be the first free slot to add a vertex
+
+       if (free_index == -1)
+               free_index = Num_vertices;
+
+       while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
+               free_index++;
+
+       Assert(free_index < MAX_VERTICES);
+
+       Vertices[free_index] = *vp;
+       Vertex_active[free_index] = 1;
+
+       Num_vertices++;
+
+       if (free_index > Highest_vertex_index)
+               Highest_vertex_index = free_index;
+
+       return free_index;
+}
+
+// ------------------------------------------------------------------------------------------
+//     Returns the index of a free segment.
+//     Scans the Segments array.
+int get_free_segment_number(void)
+{
+       int     segnum;
+
+       for (segnum=0; segnum<MAX_SEGMENTS; segnum++)
+               if (Segments[segnum].segnum == -1) {
+                       Num_segments++;
+                       if (segnum > Highest_segment_index)
+                               Highest_segment_index = segnum;
+                       return segnum;
+               }
+
+       Assert(0);
+
+       return 0;
+}
+
+// -------------------------------------------------------------------------------
+//     Create a new segment, duplicating exactly, including vertex ids and children, the passed segment.
+int med_create_duplicate_segment(segment *sp)
+{
+       int     segnum;
+
+       segnum = get_free_segment_number();
+
+       Segments[segnum] = *sp; 
+
+       return segnum;
+}
+
+// -------------------------------------------------------------------------------
+//     Add the vertex *vp to the global list of vertices, return its index.
+//     This is the same as med_add_vertex, except that it does not search for the presence of the vertex.
+int med_create_duplicate_vertex(vms_vector *vp)
+{
+       int     free_index;
+
+       Assert(Num_vertices < MAX_SEGMENT_VERTICES);
+
+       Do_duplicate_vertex_check = 1;
+
+       free_index = Num_vertices;
+
+       while (Vertex_active[free_index] && (free_index < MAX_VERTICES))
+               free_index++;
+
+       Assert(free_index < MAX_VERTICES);
+
+       Vertices[free_index] = *vp;
+       Vertex_active[free_index] = 1;
+
+       Num_vertices++;
+
+       if (free_index > Highest_vertex_index)
+               Highest_vertex_index = free_index;
+
+       return free_index;
+}
+
+
+// -------------------------------------------------------------------------------
+//     Set the vertex *vp at index vnum in the global list of vertices, return its index (just for compatibility).
+int med_set_vertex(int vnum,vms_vector *vp)
+{
+       Assert(vnum < MAX_VERTICES);
+
+       Vertices[vnum] = *vp;
+
+       // Just in case this vertex wasn't active, mark it as active.
+       if (!Vertex_active[vnum]) {
+               Vertex_active[vnum] = 1;
+               Num_vertices++;
+               if ((vnum > Highest_vertex_index) && (vnum < NEW_SEGMENT_VERTICES)) {
+                       mprintf((0,"Warning -- setting a previously unset vertex, index = %i.\n",vnum));
+                       Highest_vertex_index = vnum;
+               }
+       }
+
+       return vnum;
+}
+
+
+
+//     ----
+//     A side is determined to be degenerate if the cross products of 3 consecutive points does not point outward.
+int check_for_degenerate_side(segment *sp, int sidenum)
+{
+       char                    *vp = Side_to_verts[sidenum];
+       vms_vector      vec1, vec2, cross, vec_to_center;
+       vms_vector      segc, sidec;
+       fix                     dot;
+       int                     degeneracy_flag = 0;
+
+       compute_segment_center(&segc, sp);
+       compute_center_point_on_side(&sidec, sp, sidenum);
+       vm_vec_sub(&vec_to_center, &segc, &sidec);
+
+       //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[1]]], &Vertices[sp->verts[vp[0]]]);
+       //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
+       //vm_vec_normalize(&vec1);
+       //vm_vec_normalize(&vec2);
+        vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[1]]], &Vertices[sp->verts[(int) vp[0]]]);
+        vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]);
+       vm_vec_cross(&cross, &vec1, &vec2);
+
+       dot = vm_vec_dot(&vec_to_center, &cross);
+       if (dot <= 0)
+               degeneracy_flag |= 1;
+
+       //vm_vec_sub(&vec1, &Vertices[sp->verts[vp[2]]], &Vertices[sp->verts[vp[1]]]);
+       //vm_vec_sub(&vec2, &Vertices[sp->verts[vp[3]]], &Vertices[sp->verts[vp[2]]]);
+       //vm_vec_normalize(&vec1);
+       //vm_vec_normalize(&vec2);
+        vm_vec_normalized_dir(&vec1, &Vertices[sp->verts[(int) vp[2]]], &Vertices[sp->verts[(int) vp[1]]]);
+        vm_vec_normalized_dir(&vec2, &Vertices[sp->verts[(int) vp[3]]], &Vertices[sp->verts[(int) vp[2]]]);
+       vm_vec_cross(&cross, &vec1, &vec2);
+
+       dot = vm_vec_dot(&vec_to_center, &cross);
+       if (dot <= 0)
+               degeneracy_flag |= 1;
+
+       return degeneracy_flag;
+
+}
+
+// -------------------------------------------------------------------------------
+void create_removable_wall(segment *sp, int sidenum, int tmap_num)
+{
+       create_walls_on_side(sp, sidenum);
+
+       sp->sides[sidenum].tmap_num = tmap_num;
+
+       assign_default_uvs_to_side(sp, sidenum);
+       assign_light_to_side(sp, sidenum);
+}
+
+//     ----
+//     See if a segment has gotten turned inside out, or something.
+//     If so, set global Degenerate_segment_found and return 1, else return 0.
+int check_for_degenerate_segment(segment *sp)
+{
+       vms_vector      fvec, rvec, uvec, cross;
+       fix                     dot;
+       int                     i, degeneracy_flag = 0;                         // degeneracy flag for current segment
+
+       extract_forward_vector_from_segment(sp, &fvec);
+       extract_right_vector_from_segment(sp, &rvec);
+       extract_up_vector_from_segment(sp, &uvec);
+
+       vm_vec_normalize(&fvec);
+       vm_vec_normalize(&rvec);
+       vm_vec_normalize(&uvec);
+
+       vm_vec_cross(&cross, &fvec, &rvec);
+       dot = vm_vec_dot(&cross, &uvec);
+
+       if (dot > 0)
+               degeneracy_flag = 0;
+       else {
+               mprintf((0, "segment #%i is degenerate due to cross product check.\n", sp-Segments));
+               degeneracy_flag = 1;
+       }
+
+       //      Now, see if degenerate because of any side.
+       for (i=0; i<MAX_SIDES_PER_SEGMENT; i++)
+               degeneracy_flag |= check_for_degenerate_side(sp, i);
+
+       Degenerate_segment_found |= degeneracy_flag;
+
+       return degeneracy_flag;
+
+}
+
+#if 0
+
+// ---------------------------------------------------------------------------------------------
+//     Orthogonalize matrix smat, returning result in rmat.
+//     Does not modify smat.
+//     Uses Gram-Schmidt process.
+//     See page 172 of Strang, Gilbert, Linear Algebra and its Applications
+//     Matt -- This routine should be moved to the vector matrix library.
+//     It IS legal for smat == rmat.
+//     We should also have the functions:
+//             mat_a = mat_b * scalar;                         // we now have mat_a = mat_a * scalar;
+//             mat_a = mat_b + mat_c * scalar; // or maybe not, maybe this is not primitive
+void make_orthogonal(vms_matrix *rmat,vms_matrix *smat)
+{
+       vms_matrix              tmat;
+       vms_vector              tvec1,tvec2;
+       float                           dot;
+
+       // Copy source matrix to work area.
+       tmat = *smat;
+
+       // Normalize the three rows of the matrix tmat.
+       vm_vec_normalize(&tmat.xrow);
+       vm_vec_normalize(&tmat.yrow);
+       vm_vec_normalize(&tmat.zrow);
+
+       //      Now, compute the first vector.
+       // This is very easy -- just copy the (normalized) source vector.
+       rmat->zrow = tmat.zrow;
+
+       // Now, compute the second vector.
+       // From page 172 of Strang, we use the equation:
+       //              b' = b - [transpose(q1) * b] * q1
+       //      where:  b  = the second row of tmat
+       //                              q1 = the first row of rmat
+       //                              b' = the second row of rmat
+
+       // Compute: transpose(q1) * b
+       dot = vm_vec_dotprod(&rmat->zrow,&tmat.yrow);
+
+       // Compute: b - dot * q1
+       rmat->yrow.x = tmat.yrow.x - fixmul(dot,rmat->zrow.x);
+       rmat->yrow.y = tmat.yrow.y - fixmul(dot,rmat->zrow.y);
+       rmat->yrow.z = tmat.yrow.z - fixmul(dot,rmat->zrow.z);
+
+       // Now, compute the third vector.
+       // From page 173 of Strang, we use the equation:
+       //              c' = c - (q1*c)*q1 - (q2*c)*q2
+       //      where:  c  = the third row of tmat
+       //                              q1 = the first row of rmat
+       //                              q2 = the second row of rmat
+       //                              c' = the third row of rmat
+
+       // Compute: q1*c
+       dot = vm_vec_dotprod(&rmat->zrow,&tmat.xrow);
+
+       tvec1.x = fixmul(dot,rmat->zrow.x);
+       tvec1.y = fixmul(dot,rmat->zrow.y);
+       tvec1.z = fixmul(dot,rmat->zrow.z);
+
+       // Compute: q2*c
+       dot = vm_vec_dotprod(&rmat->yrow,&tmat.xrow);
+
+       tvec2.x = fixmul(dot,rmat->yrow.x);
+       tvec2.y = fixmul(dot,rmat->yrow.y);
+       tvec2.z = fixmul(dot,rmat->yrow.z);
+
+       vm_vec_sub(&rmat->xrow,vm_vec_sub(&rmat->xrow,&tmat.xrow,&tvec1),&tvec2);
+}
+
+#endif
+
+// ------------------------------------------------------------------------------------------
+// Given a segment, extract the rotation matrix which defines it.
+// Do this by extracting the forward, right, up vectors and then making them orthogonal.
+// In the process of making the vectors orthogonal, favor them in the order forward, up, right.
+// This means that the forward vector will remain unchanged.
+void med_extract_matrix_from_segment(segment *sp,vms_matrix *rotmat)
+{
+       vms_vector      forwardvec,upvec;
+
+       extract_forward_vector_from_segment(sp,&forwardvec);
+       extract_up_vector_from_segment(sp,&upvec);
+
+       if (((forwardvec.x == 0) && (forwardvec.y == 0) && (forwardvec.z == 0)) || ((upvec.x == 0) && (upvec.y == 0) && (upvec.z == 0))) {
+               mprintf((0, "Trapped null vector in med_extract_matrix_from_segment, returning identity matrix.\n"));
+               *rotmat = vmd_identity_matrix;
+               return;
+       }
+
+
+       vm_vector_2_matrix(rotmat,&forwardvec,&upvec,NULL);
+
+#if 0
+       vms_matrix      rm;
+
+       extract_forward_vector_from_segment(sp,&rm.zrow);
+       extract_right_vector_from_segment(sp,&rm.xrow);
+       extract_up_vector_from_segment(sp,&rm.yrow);
+
+       vm_vec_normalize(&rm.xrow);
+       vm_vec_normalize(&rm.yrow);
+       vm_vec_normalize(&rm.zrow);
+
+       make_orthogonal(rotmat,&rm);
+
+       vm_vec_normalize(&rotmat->xrow);
+       vm_vec_normalize(&rotmat->yrow);
+       vm_vec_normalize(&rotmat->zrow);
+
+// *rotmat = rm; // include this line (and remove the call to make_orthogonal) if you don't want the matrix orthogonalized
+#endif
+
+}
+
+// ------------------------------------------------------------------------------------------
+//     Given a rotation matrix *rotmat which describes the orientation of a segment
+//     and a side destside, return the rotation matrix which describes the orientation for the side.
+void   set_matrix_based_on_side(vms_matrix *rotmat,int destside)
+{
+        vms_angvec      rotvec,*tmpvec;
+        vms_matrix      r1,rtemp;
+
+       switch (destside) {
+               case WLEFT:
+                        tmpvec=vm_angvec_make(&rotvec,0,0,-16384);
+                       vm_angles_2_matrix(&r1,&rotvec);
+                       vm_matrix_x_matrix(&rtemp,rotmat,&r1);
+                       *rotmat = rtemp;
+                       break;
+
+               case WTOP:
+                        tmpvec=vm_angvec_make(&rotvec,-16384,0,0);
+                       vm_angles_2_matrix(&r1,&rotvec);
+                       vm_matrix_x_matrix(&rtemp,rotmat,&r1);
+                       *rotmat = rtemp;
+                       break;
+
+               case WRIGHT:
+                        tmpvec=vm_angvec_make(&rotvec,0,0,16384);
+                       vm_angles_2_matrix(&r1,&rotvec);
+                       vm_matrix_x_matrix(&rtemp,rotmat,&r1);
+                       *rotmat = rtemp;
+                       break;
+
+               case WBOTTOM:
+                        tmpvec=vm_angvec_make(&rotvec,+16384,-32768,0);        // bank was -32768, but I think that was an erroneous compensation
+                       vm_angles_2_matrix(&r1,&rotvec);
+                       vm_matrix_x_matrix(&rtemp,rotmat,&r1);
+                       *rotmat = rtemp;
+                       break;
+
+               case WFRONT:
+                        tmpvec=vm_angvec_make(&rotvec,0,0,-32768);
+                       vm_angles_2_matrix(&r1,&rotvec);
+                       vm_matrix_x_matrix(&rtemp,rotmat,&r1);
+                       *rotmat = rtemp;
+                       break;
+
+               case WBACK:
+                       break;
+       }
+
+}
+
+//     -------------------------------------------------------------------------------------
+void change_vertex_occurrences(int dest, int src)
+{
+       int     g,s,v;
+
+       // Fix vertices in groups
+       for (g=0;g<num_groups;g++) 
+               for (v=0; v<GroupList[g].num_vertices; v++)
+                       if (GroupList[g].vertices[v] == src)
+                               GroupList[g].vertices[v] = dest;
+
+       // now scan all segments, changing occurrences of src to dest
+       for (s=0; s<=Highest_segment_index; s++)
+               if (Segments[s].segnum != -1)
+                       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+                               if (Segments[s].verts[v] == src)
+                                       Segments[s].verts[v] = dest;
+}
+
+// --------------------------------------------------------------------------------------------------
+void compress_vertices(void)
+{
+       int             hole,vert;
+
+       if (Highest_vertex_index == Num_vertices - 1)
+               return;
+
+       vert = Highest_vertex_index;    //MAX_SEGMENT_VERTICES-1;
+
+       for (hole=0; hole < vert; hole++)
+               if (!Vertex_active[hole]) {
+                       // found an unused vertex which is a hole if a used vertex follows (not necessarily immediately) it.
+                       for ( ; (vert>hole) && (!Vertex_active[vert]); vert--)
+                               ;
+
+                       if (vert > hole) {
+
+                               // Ok, hole is the index of a hole, vert is the index of a vertex which follows it.
+                               // Copy vert into hole, update pointers to it.
+                               Vertices[hole] = Vertices[vert];
+                               
+                               change_vertex_occurrences(hole, vert);
+
+                               vert--;
+                       }
+               }
+
+       Highest_vertex_index = Num_vertices-1;
+}
+
+// --------------------------------------------------------------------------------------------------
+void compress_segments(void)
+{
+       int             hole,seg;
+
+       if (Highest_segment_index == Num_segments - 1)
+               return;
+
+       seg = Highest_segment_index;
+
+       for (hole=0; hole < seg; hole++)
+               if (Segments[hole].segnum == -1) {
+                       // found an unused segment which is a hole if a used segment follows (not necessarily immediately) it.
+                       for ( ; (seg>hole) && (Segments[seg].segnum == -1); seg--)
+                               ;
+
+                       if (seg > hole) {
+                               int             f,g,l,s,t,w;
+                               segment *sp;
+                               int objnum;
+
+                               // Ok, hole is the index of a hole, seg is the index of a segment which follows it.
+                               // Copy seg into hole, update pointers to it, update Cursegp, Markedsegp if necessary.
+                               Segments[hole] = Segments[seg];
+                               Segments[seg].segnum = -1;
+
+                               if (Cursegp == &Segments[seg])
+                                       Cursegp = &Segments[hole];
+
+                               if (Markedsegp == &Segments[seg])
+                                       Markedsegp = &Segments[hole];
+
+                               // Fix segments in groups
+                               for (g=0;g<num_groups;g++) 
+                                       for (s=0; s<GroupList[g].num_segments; s++)
+                                               if (GroupList[g].segments[s] == seg)
+                                                       GroupList[g].segments[s] = hole;
+
+                               // Fix walls
+                               for (w=0;w<Num_walls;w++)
+                                       if (Walls[w].segnum == seg)
+                                               Walls[w].segnum = hole;
+
+                               // Fix fuelcenters, robotcens, and triggers... added 2/1/95 -Yuan
+                               for (f=0;f<Num_fuelcenters;f++)
+                                       if (Station[f].segnum == seg)
+                                               Station[f].segnum = hole;
+
+                               for (f=0;f<Num_robot_centers;f++)
+                                       if (RobotCenters[f].segnum == seg)
+                                               RobotCenters[f].segnum = hole;
+
+                               for (t=0;t<Num_triggers;t++)
+                                       for (l=0;l<Triggers[t].num_links;l++)
+                                               if (Triggers[t].seg[l] == seg)
+                                                       Triggers[t].seg[l] = hole;
+
+                               sp = &Segments[hole];
+                               for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
+                                       if (IS_CHILD(sp->children[s])) {
+                                               segment *csegp;
+                                               csegp = &Segments[sp->children[s]];
+
+                                               // Find out on what side the segment connection to the former seg is on in *csegp.
+                                               for (t=0; t<MAX_SIDES_PER_SEGMENT; t++) {
+                                                       if (csegp->children[t] == seg) {
+                                                               csegp->children[t] = hole;                                      // It used to be connected to seg, so make it connected to hole
+                                                       }
+                                               }       // end for t
+                                       }       // end if
+                               }       // end for s
+
+                               //Update object segment pointers
+                               for (objnum = sp->objects; objnum != -1; objnum = Objects[objnum].next) {
+                                       Assert(Objects[objnum].segnum == seg);
+                                       Objects[objnum].segnum = hole;
+                               }
+
+                               seg--;
+
+                       }       // end if (seg > hole)
+               }       // end if
+
+       Highest_segment_index = Num_segments-1;
+       med_create_new_segment_from_cursegp();
+
+}
+
+
+// -------------------------------------------------------------------------------
+//     Combine duplicate vertices.
+//     If two vertices have the same coordinates, within some small tolerance, then assign
+//     the same vertex number to the two vertices, freeing up one of the vertices.
+void med_combine_duplicate_vertices(byte *vlp)
+{
+       int     v,w;
+
+       for (v=0; v<Highest_vertex_index; v++)          // Note: ok to do to <, rather than <= because w for loop starts at v+1
+               if (vlp[v]) {
+                       vms_vector *vvp = &Vertices[v];
+                       for (w=v+1; w<=Highest_vertex_index; w++)
+                               if (vlp[w]) {   //      used to be Vertex_active[w]
+                                       if (vnear(vvp, &Vertices[w])) {
+                                               change_vertex_occurrences(v, w);
+                                       }
+                               }
+               }
+
+}
+
+// ------------------------------------------------------------------------------
+//     Compress mine at Segments and Vertices by squeezing out all holes.
+//     If no holes (ie, an unused segment followed by a used segment), then no action.
+//     If Cursegp or Markedsegp is a segment which gets moved to fill in a hole, then
+//     they are properly updated.
+void med_compress_mine(void)
+{
+       if (Do_duplicate_vertex_check) {
+               med_combine_duplicate_vertices(Vertex_active);
+               Do_duplicate_vertex_check = 0;
+       }
+
+       compress_segments();
+       compress_vertices();
+       set_vertex_counts();
+
+       //--repair-- create_local_segment_data();
+
+       //      This is necessary becuase a segment search (due to click in 3d window) uses the previous frame's
+       //      segment information, which could get changed by this.
+       Update_flags = UF_WORLD_CHANGED;
+}
+
+
+// ------------------------------------------------------------------------------------------
+//     Copy texture map ids for each face in sseg to dseg.
+void copy_tmap_ids(segment *dseg, segment *sseg)
+{
+       int     s;
+
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
+               dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
+               dseg->sides[s].tmap_num2 = 0;
+       }
+}
+
+// ------------------------------------------------------------------------------------------
+//     Attach a segment with a rotated orientation.
+// Return value:
+//  0 = successful attach
+//  1 = No room in Segments[].
+//  2 = No room in Vertices[].
+//  3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
+//      4 = already a face attached on destseg:destside
+int med_attach_segment_rotated(segment *destseg, segment *newseg, int destside, int newside,vms_matrix *attmat)
+{
+       char                    *dvp;
+       segment         *nsp;
+       segment2        *nsp2;
+       int                     side,v;
+       vms_matrix      rotmat,rotmat1,rotmat2,rotmat3,rotmat4;
+       vms_vector      vr,vc,tvs[4],xlate_vec;
+       int                     segnum;
+       vms_vector      forvec,upvec;
+
+       // Return if already a face attached on this side.
+       if (IS_CHILD(destseg->children[destside]))
+               return 4;
+
+       segnum = get_free_segment_number();
+
+       forvec = attmat->fvec;
+       upvec = attmat->uvec;
+
+       //      We are pretty confident we can add the segment.
+       nsp = &Segments[segnum];
+       nsp2 = &Segment2s[segnum];
+
+       nsp->segnum = segnum;
+       nsp->objects = -1;
+       nsp2->matcen_num = -1;
+
+       // Copy group value.
+       nsp->group = destseg->group;
+
+       // Add segment to proper group list.
+       if (nsp->group > -1)
+               add_segment_to_group(nsp-Segments, nsp->group);
+
+       // Copy the texture map ids.
+       copy_tmap_ids(nsp,newseg);
+
+       // clear all connections
+       for (side=0; side<MAX_SIDES_PER_SEGMENT; side++) {
+               nsp->children[side] = -1;
+               nsp->sides[side].wall_num = -1; 
+       }
+
+       // Form the connection
+       destseg->children[destside] = segnum;
+//     destseg->sides[destside].render_flag = 0;
+       nsp->children[newside] = destseg-Segments;
+
+       // Copy vertex indices of the four vertices forming the joint
+       dvp = Side_to_verts[destside];
+
+       // Set the vertex indices for the four vertices forming the front of the new side
+       for (v=0; v<4; v++)
+                nsp->verts[v] = destseg->verts[(int) dvp[v]];
+
+       // The other 4 vertices must be created.
+       // Their coordinates are determined by the 4 welded vertices and the vector from front
+       // to back of the original *newseg.
+
+       // Do lots of hideous matrix stuff, about 3/4 of which could probably be simplified out.
+       med_extract_matrix_from_segment(destseg,&rotmat);               // get orientation matrix for destseg (orthogonal rotation matrix)
+       set_matrix_based_on_side(&rotmat,destside);
+       vm_vector_2_matrix(&rotmat1,&forvec,&upvec,NULL);
+       vm_matrix_x_matrix(&rotmat4,&rotmat,&rotmat1);                  // this is the desired orientation of the new segment
+       med_extract_matrix_from_segment(newseg,&rotmat3);               // this is the current orientation of the new segment
+       vm_transpose_matrix(&rotmat3);                                                          // get the inverse of the current orientation matrix
+       vm_matrix_x_matrix(&rotmat2,&rotmat4,&rotmat3);                 // now rotmat2 takes the current segment to the desired orientation
+
+       // Warning -- look at this line!
+       vm_transpose_matrix(&rotmat2);  // added 12:33 pm, 10/01/93
+
+       // Compute and rotate the center point of the attaching face.
+       compute_center_point_on_side(&vc,newseg,newside);
+       vm_vec_rotate(&vr,&vc,&rotmat2);
+
+       // Now rotate the free vertices in the segment
+       for (v=0; v<4; v++)
+               vm_vec_rotate(&tvs[v],&Vertices[newseg->verts[v+4]],&rotmat2);
+
+       // Now translate the new segment so that the center point of the attaching faces are the same.
+       compute_center_point_on_side(&vc,destseg,destside);
+       vm_vec_sub(&xlate_vec,&vc,&vr);
+
+       // Create and add the 4 new vertices.
+       for (v=0; v<4; v++) {
+               vm_vec_add2(&tvs[v],&xlate_vec);
+               nsp->verts[v+4] = med_add_vertex(&tvs[v]);
+       }
+
+       set_vertex_counts();
+
+       // Now all the vertices are in place.  Create the faces.
+       validate_segment(nsp);
+
+       //      Say to not render at the joint.
+//     destseg->sides[destside].render_flag = 0;
+//     nsp->sides[newside].render_flag = 0;
+
+       Cursegp = nsp;
+
+       return  0;
+}
+
+// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+// ------------------------------------------------------------------------------------------
+void scale_free_vertices(segment *sp,vms_vector *vp,fix scale_factor,int min_side,int max_side)
+{
+       int     i;
+       char    *verts;
+
+       verts = Side_to_verts[min_side];
+
+       for (i=0; i<4; i++)
+                if (is_free_vertex(sp->verts[(int) verts[i]])) {
+                        Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2;
+                        Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2;
+                        Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2;
+               }
+
+       verts = Side_to_verts[max_side];
+
+       for (i=0; i<4; i++)
+                if (is_free_vertex(sp->verts[(int) verts[i]])) {
+                        Vertices[sp->verts[(int) verts[i]]].x = fixmul(vp->x,scale_factor)/2;
+                        Vertices[sp->verts[(int) verts[i]]].y = fixmul(vp->y,scale_factor)/2;
+                        Vertices[sp->verts[(int) verts[i]]].z = fixmul(vp->z,scale_factor)/2;
+               }
+}
+
+
+// ------------------------------------------------------------------------------------------
+// Attach side newside of newseg to side destside of destseg.
+// Copies *newseg into global array Segments, increments Num_segments.
+// Forms a weld between the two segments by making the new segment fit to the old segment.
+// Updates number of faces per side if necessitated by new vertex coordinates.
+//     Updates Cursegp.
+// Return value:
+//  0 = successful attach
+//  1 = No room in Segments[].
+//  2 = No room in Vertices[].
+//  3 = newside != WFRONT -- for now, the new segment must be attached at its (own) front side
+//      4 = already a face attached on side newside
+int med_attach_segment(segment *destseg, segment *newseg, int destside, int newside)
+{
+       int             rval;
+       segment *ocursegp = Cursegp;
+
+       vms_angvec      tang = {0,0,0};
+       vms_matrix      rotmat;
+
+       vm_angles_2_matrix(&rotmat,&tang);
+       rval = med_attach_segment_rotated(destseg,newseg,destside,newside,&rotmat);
+       med_propagate_tmaps_to_segments(ocursegp,Cursegp,0);
+       med_propagate_tmaps_to_back_side(Cursegp, Side_opposite[newside],0);
+       copy_uvs_seg_to_seg(&New_segment,Cursegp);
+
+       return rval;
+}
+
+// -------------------------------------------------------------------------------
+//     Delete a vertex, sort of.
+//     Decrement the vertex count.  If the count goes to 0, then the vertex is free (has been deleted).
+void delete_vertex(short v)
+{
+       Assert(v < MAX_VERTICES);                       // abort if vertex is not in array Vertices
+       Assert(Vertex_active[v] >= 1);  // abort if trying to delete a non-existent vertex
+
+       Vertex_active[v]--;
+}
+
+// -------------------------------------------------------------------------------
+//     Update Num_vertices.
+//     This routine should be called by anyone who calls delete_vertex.  It could be called in delete_vertex,
+//     but then it would be called much more often than necessary, and it is a slow routine.
+void update_num_vertices(void)
+{
+       int     v;
+
+       // Now count the number of vertices.
+       Num_vertices = 0;
+       for (v=0; v<=Highest_vertex_index; v++)
+               if (Vertex_active[v])
+                       Num_vertices++;
+}
+
+// -------------------------------------------------------------------------------
+//     Set Vertex_active to number of occurrences of each vertex.
+//     Set Num_vertices.
+void set_vertex_counts(void)
+{
+       int     s,v;
+
+       Num_vertices = 0;
+
+       for (v=0; v<=Highest_vertex_index; v++)
+               Vertex_active[v] = 0;
+
+       // Count number of occurrences of each vertex.
+       for (s=0; s<=Highest_segment_index; s++)
+               if (Segments[s].segnum != -1)
+                       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++) {
+                               if (!Vertex_active[Segments[s].verts[v]])
+                                       Num_vertices++;
+                               Vertex_active[Segments[s].verts[v]]++;
+                       }
+}
+
+// -------------------------------------------------------------------------------
+//     Delete all vertices in segment *sp from the vertex list if they are not contained in another segment.
+//     This is kind of a dangerous routine.  It modifies the global array Vertex_active, using the field as
+//     a count.
+void delete_vertices_in_segment(segment *sp)
+{
+       int     v;
+
+//     init_vertices();
+
+       set_vertex_counts();
+
+       // Subtract one count for each appearance of vertex in deleted segment
+       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+               delete_vertex(sp->verts[v]);
+
+       update_num_vertices();
+}
+
+extern void validate_segment_side(segment *sp, int sidenum);
+
+// -------------------------------------------------------------------------------
+//     Delete segment *sp in Segments array.
+// Return value:
+//             0       successfully deleted.
+//             1       unable to delete.
+int med_delete_segment(segment *sp)
+{
+       int             s,side,segnum;
+       int             objnum;
+
+       segnum = sp-Segments;
+
+       // Cannot delete segment if only segment.
+       if (Num_segments == 1)
+               return 1;
+
+       // Don't try to delete if segment doesn't exist.
+       if (sp->segnum == -1) {
+               mprintf((0,"Hey -- you tried to delete a non-existent segment (segnum == -1)\n"));
+               return 1;
+       }
+
+       // Delete its refueling center if it has one
+       fuelcen_delete(sp);
+
+       delete_vertices_in_segment(sp);
+
+       Num_segments--;
+
+       // If deleted segment has walls on any side, wipe out the wall.
+       for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
+               if (sp->sides[side].wall_num != -1) 
+                       wall_remove_side(sp, side);
+
+       // Find out what this segment was connected to and break those connections at the other end.
+       for (side=0; side < MAX_SIDES_PER_SEGMENT; side++)
+               if (IS_CHILD(sp->children[side])) {
+                       segment *csp;                                                                   // the connecting segment
+                       int             s;
+
+                       csp = &Segments[sp->children[side]];
+                       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
+                               if (csp->children[s] == segnum) {
+                                       csp->children[s] = -1;                          // this is the side of connection, break it
+                                       validate_segment_side(csp,s);                                   // we have converted a connection to a side so validate the segment
+                                       med_propagate_tmaps_to_back_side(csp,s,0);
+                               }
+                       Cursegp = csp;
+                       med_create_new_segment_from_cursegp();
+                       copy_uvs_seg_to_seg(&New_segment,Cursegp);
+               }
+
+       sp->segnum = -1;                                                                                // Mark segment as inactive.
+
+       // If deleted segment = marked segment, then say there is no marked segment
+       if (sp == Markedsegp)
+               Markedsegp = 0;
+       
+       //      If deleted segment = a Group segment ptr, then wipe it out.
+       for (s=0;s<num_groups;s++) 
+               if (sp == Groupsegp[s]) 
+                       Groupsegp[s] = 0;
+
+       // If deleted segment = group segment, wipe it off the group list.
+       if (sp->group > -1) 
+                       delete_segment_from_group(sp-Segments, sp->group);
+
+       // If we deleted something which was not connected to anything, must now select a new current segment.
+       if (Cursegp == sp)
+               for (s=0; s<MAX_SEGMENTS; s++)
+                       if ((Segments[s].segnum != -1) && (s!=segnum) ) {
+                               Cursegp = &Segments[s];
+                               med_create_new_segment_from_cursegp();
+                       break;
+                       }
+
+       // If deleted segment contains objects, wipe out all objects
+       if (sp->objects != -1)  {
+//             if (objnum == Objects[objnum].next) {
+//                     mprintf((0, "Warning -- object #%i points to itself.  Setting next to -1.\n", objnum));
+//                     Objects[objnum].next = -1;
+//             }
+               for (objnum=sp->objects;objnum!=-1;objnum=Objects[objnum].next)         {
+
+                       //if an object is in the seg, delete it
+                       //if the object is the player, move to new curseg
+
+                       if (objnum == (ConsoleObject-Objects))  {
+                               compute_segment_center(&ConsoleObject->pos,Cursegp);
+                               obj_relink(objnum,Cursegp-Segments);
+                       } else
+                               obj_delete(objnum);
+               }
+       }
+
+       // Make sure everything deleted ok...
+       Assert( sp->objects==-1 );
+
+       // If we are leaving many holes in Segments or Vertices, then compress mine, because it is inefficient to be that way
+//     if ((Highest_segment_index > Num_segments+4) || (Highest_vertex_index > Num_vertices+4*8))
+//             med_compress_mine();
+
+       return 0;
+}
+
+// ------------------------------------------------------------------------------------------
+//     Copy texture maps from sseg to dseg
+void copy_tmaps_to_segment(segment *dseg, segment *sseg)
+{
+       int     s;
+
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
+               dseg->sides[s].type = sseg->sides[s].type;
+               dseg->sides[s].tmap_num = sseg->sides[s].tmap_num;
+               dseg->sides[s].tmap_num2 = sseg->sides[s].tmap_num2;
+       }
+
+}
+
+// ------------------------------------------------------------------------------------------
+// Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively
+// modifying its four free vertices in the global array Vertices.
+// It is illegal to rotate a segment which has connectivity != 1.
+// Pitch, bank, heading are about the point which is the average of the four points
+// forming the side of connection.
+// Return value:
+//  0 = successful rotation
+//  1 = Connectivity makes rotation illegal (connected to 0 or 2+ segments)
+//  2 = Rotation causes degeneracy, such as self-intersecting segment.
+//      3 = Unable to rotate because not connected to exactly 1 segment.
+int med_rotate_segment(segment *seg, vms_matrix *rotmat)
+{
+       segment *destseg;
+        int             newside=0,destside,s;
+       int             count;
+       int             back_side,side_tmaps[MAX_SIDES_PER_SEGMENT];
+
+       // Find side of attachment
+       count = 0;
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
+               if (IS_CHILD(seg->children[s])) {
+                       count++;
+                       newside = s;
+               }
+
+       // Return if passed in segment is connected to other than 1 segment.
+       if (count != 1)
+               return 3;
+
+       destseg = &Segments[seg->children[newside]];
+
+       destside = 0;
+       while ((destseg->children[destside] != seg-Segments) && (destside < MAX_SIDES_PER_SEGMENT))
+               destside++;
+               
+       // Before deleting the segment, copy its texture maps to New_segment
+       copy_tmaps_to_segment(&New_segment,seg);
+
+       if (med_delete_segment(seg))
+               mprintf((0,"Error in rotation: Unable to delete segment %i\n",seg-Segments));
+
+       if (Curside == WFRONT)
+               Curside = WBACK;
+
+       med_attach_segment_rotated(destseg,&New_segment,destside,AttachSide,rotmat);
+
+       //      Save tmap_num on each side to restore after call to med_propagate_tmaps_to_segments and _back_side
+       //      which will change the tmap nums.
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
+               side_tmaps[s] = seg->sides[s].tmap_num;
+
+       back_side = Side_opposite[find_connect_side(destseg, seg)];
+
+       med_propagate_tmaps_to_segments(destseg, seg,0);
+       med_propagate_tmaps_to_back_side(seg, back_side,0);
+
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
+               if (s != back_side)
+                       seg->sides[s].tmap_num = side_tmaps[s];
+
+       return  0;
+}
+
+// ----------------------------------------------------------------------------------------
+int med_rotate_segment_ang(segment *seg, vms_angvec *ang)
+{
+       vms_matrix      rotmat;
+
+       return med_rotate_segment(seg,vm_angles_2_matrix(&rotmat,ang));
+}
+
+// @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
+
+// ----------------------------------------------------------------------------
+//     Compute the sum of the distances between the four pairs of points.
+//     The connections are:
+//             firstv1 : 0             (firstv1+1)%4 : 1               (firstv1+2)%4 : 2               (firstv1+3)%4 : 3
+fix seg_seg_vertex_distsum(segment *seg1, int side1, segment *seg2, int side2, int firstv1)
+{
+       fix     distsum;
+       int     secondv;
+
+       distsum = 0;
+       for (secondv=0; secondv<4; secondv++) {
+               int                     firstv;
+
+               firstv = (4-secondv + (3 - firstv1)) % 4;
+               distsum += vm_vec_dist(&Vertices[seg1->verts[Side_to_verts[side1][firstv]]],&Vertices[seg2->verts[Side_to_verts[side2][secondv]]]);
+       }
+
+       return distsum;
+
+}
+
+// ----------------------------------------------------------------------------
+//     Determine how to connect two segments together with the least amount of twisting.
+//     Returns vertex index in 0..3 on first segment.  Assumed ordering of vertices
+//     on second segment is 0,1,2,3.
+//     So, if return value is 2, connect 2:0 3:1 0:2 1:3.
+//     Theory:
+//             We select an ordering of vertices for connection.  For the first pair of vertices to be connected,
+//             compute the vector.  For the three remaining pairs of vertices, compute the vectors from one vertex
+//             to the other.  Compute the dot products of these vectors with the original vector.  Add them up.
+//             The close we are to 3, the better fit we have.  Reason:  The largest value for the dot product is
+//             1.0, and this occurs for a parallel set of vectors.
+int get_index_of_best_fit(segment *seg1, int side1, segment *seg2, int side2)
+{
+       int     firstv;
+       fix     min_distance;
+       int     best_index=0;
+
+       min_distance = F1_0*30000;
+
+       for (firstv=0; firstv<4; firstv++) {
+               fix t;
+               t = seg_seg_vertex_distsum(seg1, side1, seg2, side2, firstv);
+               if (t <= min_distance) {
+                       min_distance = t;
+                       best_index = firstv;
+               }
+       }
+
+       return best_index;
+
+}
+
+
+#define MAX_VALIDATIONS 50
+
+// ----------------------------------------------------------------------------
+//     Remap uv coordinates in all sides in segment *sp which have a vertex in vp[4].
+//     vp contains absolute vertex indices.
+void remap_side_uvs(segment *sp,int *vp)
+{
+       int     s,i,v;
+
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
+               for (v=0; v<4; v++)
+                       for (i=0; i<4; i++)                                                                                             // scan each vertex in vp[4]
+                               if (Side_to_verts[s][v] == vp[i]) {
+                                       assign_default_uvs_to_side(sp,s);                                       // Side s needs to be remapped
+                                       goto next_side;
+                               }
+next_side: ;
+       }
+}
+
+// ----------------------------------------------------------------------------
+//     Assign default uv coordinates to Curside.
+void assign_default_uvs_to_curside(void)
+{
+       assign_default_uvs_to_side(Cursegp, Curside);
+}
+
+// ----------------------------------------------------------------------------
+//     Assign default uv coordinates to all sides in Curside.
+void assign_default_uvs_to_curseg(void)
+{
+       int     s;
+
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++)
+               assign_default_uvs_to_side(Cursegp,s);                                  // Side s needs to be remapped
+}
+
+// ----------------------------------------------------------------------------
+//     Modify seg2 to share side2 with seg1:side1.  This forms a connection between
+//     two segments without creating a new segment.  It modifies seg2 by sharing
+//     vertices from seg1.  seg1 is not modified.  Four vertices from seg2 are
+//     deleted.
+//     Return code:
+//             0                       joint formed
+//             1                       -- no, this is legal! -- unable to form joint because one or more vertices of side2 is not free
+//             2                       unable to form joint because side1 is already used
+int med_form_joint(segment *seg1, int side1, segment *seg2, int side2)
+{
+       char            *vp1,*vp2;
+       int             bfi,v,s,sv,s1,nv;
+       int             lost_vertices[4],remap_vertices[4];
+       int             validation_list[MAX_VALIDATIONS];
+
+       //      Make sure that neither side is connected.
+       if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
+               return 2;
+
+       // Make sure there is no wall there 
+       if ((seg1->sides[side1].wall_num != -1) || (seg2->sides[side2].wall_num != -1))
+               return 2;
+
+       //      We can form the joint.  Find the best orientation of vertices.
+       bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
+
+       vp1 = Side_to_verts[side1];
+       vp2 = Side_to_verts[side2];
+
+       //      Make a copy of the list of vertices in seg2 which will be deleted and set the
+       //      associated vertex number, so that all occurrences of the vertices can be replaced.
+       for (v=0; v<4; v++)
+                lost_vertices[v] = seg2->verts[(int) vp2[v]];
+
+       //      Now, for each vertex in lost_vertices, determine which vertex it maps to.
+       for (v=0; v<4; v++)
+                remap_vertices[3 - ((v + bfi) % 4)] = seg1->verts[(int) vp1[v]];
+
+       // Now, in all segments, replace all occurrences of vertices in lost_vertices with remap_vertices
+
+       // Put the one segment we know are being modified into the validation list.
+       // Note: seg1 does not require a full validation, only a validation of the affected side.  Its vertices do not move.
+       nv = 1;
+       validation_list[0] = seg2 - Segments;
+
+       for (v=0; v<4; v++)
+               for (s=0; s<=Highest_segment_index; s++)
+                       if (Segments[s].segnum != -1)
+                               for (sv=0; sv<MAX_VERTICES_PER_SEGMENT; sv++)
+                                       if (Segments[s].verts[sv] == lost_vertices[v]) {
+                                               Segments[s].verts[sv] = remap_vertices[v];
+                                               // Add segment to list of segments to be validated.
+                                               for (s1=0; s1<nv; s1++)
+                                                       if (validation_list[s1] == s)
+                                                               break;
+                                               if (s1 == nv)
+                                                       validation_list[nv++] = s;
+                                               Assert(nv < MAX_VALIDATIONS);
+                                       }
+
+       //      Form new connections.
+       seg1->children[side1] = seg2 - Segments;
+       seg2->children[side2] = seg1 - Segments;
+
+       // validate all segments
+       validate_segment_side(seg1,side1);
+       for (s=0; s<nv; s++) {
+               validate_segment(&Segments[validation_list[s]]);
+               remap_side_uvs(&Segments[validation_list[s]],remap_vertices);   // remap uv coordinates on sides which were reshaped (ie, have a vertex in lost_vertices)
+               warn_if_concave_segment(&Segments[validation_list[s]]);
+       }
+
+       set_vertex_counts();
+
+       //      Make sure connection is open, ie renderable.
+//     seg1->sides[side1].render_flag = 0;
+//     seg2->sides[side2].render_flag = 0;
+
+//--// debug -- check all segments, make sure if a children[s] == -1, then side[s].num_faces != 0
+//--{
+//--int seg,side;
+//--for (seg=0; seg<MAX_SEGMENTS; seg++)
+//--   if (Segments[seg].segnum != -1)
+//--           for (side=0; side<MAX_SIDES_PER_SEGMENT; side++)
+//--                   if (Segments[seg].children[side] == -1) {
+//--                           if (Segments[seg].sides[side].num_faces == 0) {
+//--                                   mprintf((0,"Error: Segment %i, side %i is not connected, but has 0 faces.\n",seg,side));
+//--                                   Int3();
+//--                           }
+//--                   } else if (Segments[seg].sides[side].num_faces != 0) {
+//--                           mprintf((0,"Error: Segment %i, side %i is connected, but has %i faces.\n",seg,side,Segments[seg].sides[side].num_faces));
+//--                           Int3();
+//--                   }
+//--}
+
+       return 0;
+}
+
+// ----------------------------------------------------------------------------
+//     Create a new segment and use it to form a bridge between two existing segments.
+//     Specify two segment:side pairs.  If either segment:side is not open (ie, segment->children[side] != -1)
+//     then it is not legal to form the brider.
+//     Return:
+//             0       bridge segment formed
+//             1       unable to form bridge because one (or both) of the sides is not open.
+//     Note that no new vertices are created by this process.
+int med_form_bridge_segment(segment *seg1, int side1, segment *seg2, int side2)
+{
+       segment         *bs;
+       char                    *sv;
+       int                     v,bfi,i;
+
+       if (IS_CHILD(seg1->children[side1]) || IS_CHILD(seg2->children[side2]))
+               return 1;
+
+       bs = &Segments[get_free_segment_number()];
+// mprintf((0,"Forming bridge segment %i from %i to %i\n",bs-Segments,seg1-Segments,seg2-Segments));
+
+       bs->segnum = bs-Segments;
+       bs->objects = -1;
+
+       // Copy vertices from seg2 into last 4 vertices of bridge segment.
+       sv = Side_to_verts[side2];
+       for (v=0; v<4; v++)
+                bs->verts[(3-v)+4] = seg2->verts[(int) sv[v]];
+
+       // Copy vertices from seg1 into first 4 vertices of bridge segment.
+       bfi = get_index_of_best_fit(seg1, side1, seg2, side2);
+
+       sv = Side_to_verts[side1];
+       for (v=0; v<4; v++)
+                bs->verts[(v + bfi) % 4] = seg1->verts[(int) sv[v]];
+
+       // Form connections to children, first initialize all to unconnected.
+       for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
+               bs->children[i] = -1;
+               bs->sides[i].wall_num = -1;
+       }
+
+       // Now form connections between segments.
+
+       bs->children[AttachSide] = seg1 - Segments;
+        bs->children[(int) Side_opposite[AttachSide]] = seg2 - Segments;
+
+       seg1->children[side1] = bs-Segments; //seg2 - Segments;
+       seg2->children[side2] = bs-Segments; //seg1 - Segments;
+
+       //      Validate bridge segment, and if degenerate, clean up mess.
+       Degenerate_segment_found = 0;
+
+       validate_segment(bs);
+
+       if (Degenerate_segment_found) {
+               seg1->children[side1] = -1;
+               seg2->children[side2] = -1;
+               bs->children[AttachSide] = -1;
+                bs->children[(int) Side_opposite[AttachSide]] = -1;
+               if (med_delete_segment(bs)) {
+                       mprintf((0, "Oops, tried to delete bridge segment (because it's degenerate), but couldn't.\n"));
+                       Int3();
+               }
+               editor_status("Bridge segment would be degenerate, not created.\n");
+               return 1;
+       } else {
+               validate_segment(seg1); // used to only validate side, but segment does more error checking: ,side1);
+               validate_segment(seg2); // ,side2);
+               med_propagate_tmaps_to_segments(seg1,bs,0);
+
+               editor_status("Bridge segment formed.");
+               warn_if_concave_segment(bs);
+               return 0;
+       }
+}
+
+// -------------------------------------------------------------------------------
+//     Create a segment given center, dimensions, rotation matrix.
+//     Note that the created segment will always have planar sides and rectangular cross sections.
+//     It will be created with walls on all sides, ie not connected to anything.
+void med_create_segment(segment *sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, vms_matrix *mp)
+{
+       int                     i,f;
+       vms_vector      v0,v1,cv;
+       segment2 *sp2;
+
+       Num_segments++;
+
+       sp->segnum = 1;                                         // What to put here?  I don't know.
+       sp2 = &Segment2s[sp->segnum];
+
+       // Form connections to children, of which it has none.
+       for (i=0; i<MAX_SIDES_PER_SEGMENT; i++) {
+               sp->children[i] = -1;
+//             sp->sides[i].render_flag = 0;
+               sp->sides[i].wall_num  = -1;
+       }
+
+       sp->group = -1;
+       sp2->matcen_num = -1;
+
+       //      Create relative-to-center vertices, which are the rotated points on the box defined by length, width, height
+       sp->verts[0] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,-length/2),mp));
+       sp->verts[1] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,-length/2),mp));
+       sp->verts[2] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,-length/2),mp));
+       sp->verts[3] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,-length/2),mp));
+       sp->verts[4] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,+height/2,+length/2),mp));
+       sp->verts[5] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,+width/2,-height/2,+length/2),mp));
+       sp->verts[6] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,-height/2,+length/2),mp));
+       sp->verts[7] = med_add_vertex(vm_vec_rotate(&v1,vm_vec_make(&v0,-width/2,+height/2,+length/2),mp));
+
+       // Now create the vector which is the center of the segment and add that to all vertices.
+       while (!vm_vec_make(&cv,cx,cy,cz));
+
+       //      Now, add the center to all vertices, placing the segment in 3 space.
+       for (i=0; i<MAX_VERTICES_PER_SEGMENT; i++)
+               vm_vec_add(&Vertices[sp->verts[i]],&Vertices[sp->verts[i]],&cv);
+
+       //      Set scale vector.
+//     sp->scale.x = width;
+//     sp->scale.y = height;
+//     sp->scale.z = length;
+
+       //      Add faces to all sides.
+       for (f=0; f<MAX_SIDES_PER_SEGMENT; f++)
+               create_walls_on_side(sp,f);
+
+       sp->objects = -1;               //no objects in this segment
+
+       // Assume nothing special about this segment
+       sp2->special = 0;
+       sp2->value = 0;
+       sp2->static_light = 0;
+       sp2->matcen_num = -1;
+
+       copy_tmaps_to_segment(sp, &New_segment);
+
+       assign_default_uvs_to_segment(sp);
+}
+
+// ----------------------------------------------------------------------------------------------
+//     Create New_segment using a specified scale factor.
+void med_create_new_segment(vms_vector *scale)
+{
+       int                     s,t;
+       vms_vector      v0;
+       segment         *sp = &New_segment;
+       segment2 *sp2;
+
+       fix                     length,width,height;
+
+       length = scale->z;
+       width = scale->x;
+       height = scale->y;
+
+       sp->segnum = 1;                                         // What to put here?  I don't know.
+       sp2 = &Segment2s[sp->segnum];
+
+       //      Create relative-to-center vertices, which are the points on the box defined by length, width, height
+       t = Num_vertices;
+       sp->verts[0] = med_set_vertex(NEW_SEGMENT_VERTICES+0,vm_vec_make(&v0,+width/2,+height/2,-length/2));
+       sp->verts[1] = med_set_vertex(NEW_SEGMENT_VERTICES+1,vm_vec_make(&v0,+width/2,-height/2,-length/2));
+       sp->verts[2] = med_set_vertex(NEW_SEGMENT_VERTICES+2,vm_vec_make(&v0,-width/2,-height/2,-length/2));
+       sp->verts[3] = med_set_vertex(NEW_SEGMENT_VERTICES+3,vm_vec_make(&v0,-width/2,+height/2,-length/2));
+       sp->verts[4] = med_set_vertex(NEW_SEGMENT_VERTICES+4,vm_vec_make(&v0,+width/2,+height/2,+length/2));
+       sp->verts[5] = med_set_vertex(NEW_SEGMENT_VERTICES+5,vm_vec_make(&v0,+width/2,-height/2,+length/2));
+       sp->verts[6] = med_set_vertex(NEW_SEGMENT_VERTICES+6,vm_vec_make(&v0,-width/2,-height/2,+length/2));
+       sp->verts[7] = med_set_vertex(NEW_SEGMENT_VERTICES+7,vm_vec_make(&v0,-width/2,+height/2,+length/2));
+       Num_vertices = t;
+
+//     sp->scale = *scale;
+
+       // Form connections to children, of which it has none, init faces and tmaps.
+       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
+               sp->children[s] = -1;
+//             sp->sides[s].render_flag = 0;
+               sp->sides[s].wall_num = -1;
+               create_walls_on_side(sp,s);
+               sp->sides[s].tmap_num = s;                                      // assign some stupid old tmap to this side.
+               sp->sides[s].tmap_num2 = 0;
+       }
+
+       Seg_orientation.p = 0;  Seg_orientation.b = 0;  Seg_orientation.h = 0;
+
+       sp->objects = -1;               //no objects in this segment
+
+       assign_default_uvs_to_segment(sp);
+
+       // Assume nothing special about this segment
+       sp2->special = 0;
+       sp2->value = 0;
+       sp2->static_light = 0;
+       sp2->matcen_num = -1;
+}
+
+// -------------------------------------------------------------------------------
+void med_create_new_segment_from_cursegp(void)
+{
+       vms_vector      scalevec;
+       vms_vector      uvec, rvec, fvec;
+
+       med_extract_up_vector_from_segment_side(Cursegp, Curside, &uvec);
+       med_extract_right_vector_from_segment_side(Cursegp, Curside, &rvec);
+       extract_forward_vector_from_segment(Cursegp, &fvec);
+
+       scalevec.x = vm_vec_mag(&rvec);
+       scalevec.y = vm_vec_mag(&uvec);
+       scalevec.z = vm_vec_mag(&fvec);
+
+       med_create_new_segment(&scalevec);
+}
+
+// -------------------------------------------------------------------------------
+//     Initialize all vertices to inactive status.
+void init_all_vertices(void)
+{
+       int             v;
+       int     s;
+
+       for (v=0; v<MAX_SEGMENT_VERTICES; v++)
+               Vertex_active[v] = 0;
+
+       for (s=0; s<MAX_SEGMENTS; s++)
+               Segments[s].segnum = -1;
+
+}
+
+// --------------------------------------------------------------------------------------
+//     Create a new mine, set global variables.
+int create_new_mine(void)
+{
+       int     s;
+       vms_vector      sizevec;
+       vms_matrix      m1 = IDENTITY_MATRIX;
+
+       // initialize_mine_arrays();
+
+//     gamestate_not_restored = 1;
+
+       // Clear refueling center code
+       fuelcen_reset();
+       hostage_init_all();
+
+       init_all_vertices();
+
+       Current_level_num = 0;          //0 means not a real level
+       Current_level_name[0] = 0;
+
+       Cur_object_index = -1;
+       reset_objects(1);               //just one object, the player
+
+       num_groups = 0;
+       current_group = -1;
+
+       Num_vertices = 0;               // Number of vertices in global array.
+       Num_segments = 0;               // Number of segments in global array, will get increased in med_create_segment
+       Cursegp = Segments;     // Say current segment is the only segment.
+       Curside = WBACK;                // The active side is the back side
+       Markedsegp = 0;         // Say there is no marked segment.
+       Markedside = WBACK;     //      Shouldn't matter since Markedsegp == 0, but just in case...
+       for (s=0;s<MAX_GROUPS+1;s++) {
+               GroupList[s].num_segments = 0;          
+               GroupList[s].num_vertices = 0;          
+               Groupsegp[s] = NULL;
+               Groupside[s] = 0;
+       }
+
+       Num_robot_centers = 0;
+       Num_open_doors = 0;
+       wall_init();
+       trigger_init();
+
+       // Create New_segment, which is the segment we will be adding at each instance.
+       med_create_new_segment(vm_vec_make(&sizevec,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE));             // New_segment = Segments[0];
+//     med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,vm_mat_make(&m1,F1_0,0,0,0,F1_0,0,0,0,F1_0));
+       med_create_segment(Segments,0,0,0,DEFAULT_X_SIZE,DEFAULT_Y_SIZE,DEFAULT_Z_SIZE,&m1);
+
+       N_found_segs = 0;
+       N_selected_segs = 0;
+       N_warning_segs = 0;
+
+       //--repair-- create_local_segment_data();
+
+       ControlCenterTriggers.num_links = 0;
+
+    //editor_status("New mine created.");
+       return  0;                      // say no error
+}
+
+// --------------------------------------------------------------------------------------------------
+// Copy a segment from *ssp to *dsp.  Do not simply copy the struct.  Use *dsp's vertices, copying in
+//     just the values, not the indices.
+void med_copy_segment(segment *dsp,segment *ssp)
+{
+       int     v;
+       int     verts_copy[MAX_VERTICES_PER_SEGMENT];
+
+       //      First make a copy of the vertex list.
+       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+               verts_copy[v] = dsp->verts[v];
+
+       // Now copy the whole struct.
+       *dsp = *ssp;
+
+       // Now restore the vertex indices.
+       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+               dsp->verts[v] = verts_copy[v];
+
+       // Now destructively modify the vertex values for all vertex indices.
+       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+               Vertices[dsp->verts[v]] = Vertices[ssp->verts[v]];
+}
+
+// -----------------------------------------------------------------------------
+//     Create coordinate axes in orientation of specified segment, stores vertices at *vp.
+void create_coordinate_axes_from_segment(segment *sp,short *vertnums)
+{
+       vms_matrix      rotmat;
+       vms_vector t;
+
+       med_extract_matrix_from_segment(sp,&rotmat);
+
+       compute_segment_center(&Vertices[vertnums[0]],sp);
+
+       t = rotmat.rvec;
+       vm_vec_scale(&t,i2f(32));
+       vm_vec_add(&Vertices[vertnums[1]],&Vertices[vertnums[0]],&t);
+
+       t = rotmat.uvec;
+       vm_vec_scale(&t,i2f(32));
+       vm_vec_add(&Vertices[vertnums[2]],&Vertices[vertnums[0]],&t);
+
+       t = rotmat.fvec;
+       vm_vec_scale(&t,i2f(32));
+       vm_vec_add(&Vertices[vertnums[3]],&Vertices[vertnums[0]],&t);
+}
+
+// -----------------------------------------------------------------------------
+//     Determine if a segment is concave. Returns true if concave
+int check_seg_concavity(segment *s)
+{
+       int sn,vn;
+       vms_vector n0,n1;
+
+       for (sn=0;sn<MAX_SIDES_PER_SEGMENT;sn++)
+               for (vn=0;vn<=4;vn++) {
+
+                       vm_vec_normal(&n1,
+                               &Vertices[s->verts[Side_to_verts[sn][vn%4]]],
+                               &Vertices[s->verts[Side_to_verts[sn][(vn+1)%4]]],
+                               &Vertices[s->verts[Side_to_verts[sn][(vn+2)%4]]]);
+
+                       //vm_vec_normalize(&n1);
+
+                       if (vn>0) if (vm_vec_dotprod(&n0,&n1) < f0_5) return 1;
+
+                       n0 = n1;
+               }
+
+       return 0;
+}
+
+
+// -----------------------------------------------------------------------------
+//     Find all concave segments and add to list
+void find_concave_segs()
+{
+       int i;
+       segment *s;
+
+       N_warning_segs = 0;
+
+       for (s=Segments,i=Highest_segment_index;i>=0;s++,i--)
+               if (s->segnum != -1)
+                       if (check_seg_concavity(s)) Warning_segs[N_warning_segs++]=SEG_PTR_2_NUM(s);
+
+
+}
+
+
+// -----------------------------------------------------------------------------
+void warn_if_concave_segments(void)
+{
+       char temp[1];
+
+       find_concave_segs();
+
+       if (N_warning_segs) {
+               editor_status("*** WARNING *** %d concave segments in mine! *** WARNING ***",N_warning_segs);
+               sprintf( temp, "%d", N_warning_segs );
+    }
+}
+
+// -----------------------------------------------------------------------------
+//     Check segment s, if concave, warn
+void warn_if_concave_segment(segment *s)
+{
+    char temp[1];
+       int     result;
+
+       result = check_seg_concavity(s);
+
+       if (result) {
+               Warning_segs[N_warning_segs++] = s-Segments;
+
+        if (N_warning_segs) {
+                       editor_status("*** WARNING *** New segment is concave! *** WARNING ***");
+            sprintf( temp, "%d", N_warning_segs );
+        }
+        //else
+           // editor_status("");
+       } //else
+        //editor_status("");
+}
+
+
+// -------------------------------------------------------------------------------
+//     Find segment adjacent to sp:side.
+//     Adjacent means a segment which shares all four vertices.
+//     Return true if segment found and fill in segment in adj_sp and side in adj_side.
+//     Return false if unable to find, in which case adj_sp and adj_side are undefined.
+int med_find_adjacent_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side)
+{
+       int                     seg,s,v,vv;
+       int                     abs_verts[4];
+
+       //      Stuff abs_verts[4] array with absolute vertex indices
+       for (v=0; v<4; v++)
+               abs_verts[v] = sp->verts[Side_to_verts[side][v]];
+
+       //      Scan all segments, looking for a segment which contains the four abs_verts
+       for (seg=0; seg<=Highest_segment_index; seg++) {
+               if (seg != sp-Segments) {
+                       for (v=0; v<4; v++) {                                                                                           // do for each vertex in abs_verts
+                               for (vv=0; vv<MAX_VERTICES_PER_SEGMENT; vv++)                   // do for each vertex in segment
+                                       if (abs_verts[v] == Segments[seg].verts[vv])
+                                               goto fass_found1;                                                                                       // Current vertex (indexed by v) is present in segment, try next
+                               goto fass_next_seg;                                                                                             // This segment doesn't contain the vertex indexed by v
+                       fass_found1: ;
+                       }               // end for v
+
+                       //      All four vertices in sp:side are present in segment seg.
+                       //      Determine side and return
+                       for (s=0; s<MAX_SIDES_PER_SEGMENT; s++) {
+                               for (v=0; v<4; v++) {
+                                       for (vv=0; vv<4; vv++) {
+                                               if (Segments[seg].verts[Side_to_verts[s][v]] == abs_verts[vv])
+                                                       goto fass_found2;
+                                       }
+                                       goto fass_next_side;                                                                                    // Couldn't find vertex v in current side, so try next side.
+                               fass_found2: ;
+                               }
+                               // Found all four vertices in current side.  We are done!
+                               *adj_sp = &Segments[seg];
+                               *adj_side = s;
+                               return 1;
+                       fass_next_side: ;
+                       }
+                       Assert(0);      // Impossible -- we identified this segment as containing all 4 vertices of side "side", but we couldn't find them.
+                       return 0;
+               fass_next_seg: ;
+               }
+       }
+
+       return 0;
+}
+
+
+#define JOINT_THRESHOLD        10000*F1_0              // (Huge threshold)
+
+// -------------------------------------------------------------------------------
+//     Find segment closest to sp:side.
+//     Return true if segment found and fill in segment in adj_sp and side in adj_side.
+//     Return false if unable to find, in which case adj_sp and adj_side are undefined.
+int med_find_closest_threshold_segment_side(segment *sp, int side, segment **adj_sp, int *adj_side, fix threshold)
+{
+       int                     seg,s;
+       vms_vector  vsc, vtc;           // original segment center, test segment center
+       fix                     current_dist, closest_seg_dist;
+
+       if (IS_CHILD(sp->children[side]))
+               return 0;
+
+       compute_center_point_on_side(&vsc, sp, side); 
+
+       closest_seg_dist = JOINT_THRESHOLD;
+
+       //      Scan all segments, looking for a segment which contains the four abs_verts
+       for (seg=0; seg<=Highest_segment_index; seg++) 
+               if (seg != sp-Segments) 
+                       for (s=0;s<MAX_SIDES_PER_SEGMENT;s++) {
+                               if (!IS_CHILD(Segments[seg].children[s])) {
+                                       compute_center_point_on_side(&vtc, &Segments[seg], s); 
+                                       current_dist = vm_vec_dist( &vsc, &vtc );
+                                       if (current_dist < closest_seg_dist) {
+                                               *adj_sp = &Segments[seg];
+                                               *adj_side = s;
+                                               closest_seg_dist = current_dist;
+                                       }
+                               }
+                       }       
+
+       if (closest_seg_dist < threshold)
+               return 1;
+       else
+               return 0;
+}
+
+
+
+void med_check_all_vertices()
+{
+       int             s,v;
+       segment *sp;
+       int             count;
+
+       count = 0;
+
+       for (s=0; s<Num_segments; s++) {
+               sp = &Segments[s];
+               if (sp->segnum != -1)
+                       for (v=0; v<MAX_VERTICES_PER_SEGMENT; v++)
+                               Assert(sp->verts[v] <= Highest_vertex_index);
+                                       
+       }
+
+}
+
+//     -----------------------------------------------------------------------------------------------------
+void check_for_overlapping_segment(int segnum)
+{
+       int     i, v;
+       segmasks        masks;
+       vms_vector      segcenter;
+
+       compute_segment_center(&segcenter, &Segments[segnum]);
+
+       for (i=0;i<=Highest_segment_index; i++) {
+               if (i != segnum) {
+                       masks = get_seg_masks(&segcenter, i, 0);
+                       if (masks.centermask == 0) {
+                               mprintf((0, "Segment %i center is contained in segment %i\n", segnum, i));
+                               continue;
+                       }
+
+                       for (v=0; v<8; v++) {
+                               vms_vector      pdel, presult;
+
+                               vm_vec_sub(&pdel, &Vertices[Segments[segnum].verts[v]], &segcenter);
+                               vm_vec_scale_add(&presult, &segcenter, &pdel, (F1_0*15)/16);
+                               masks = get_seg_masks(&presult, i, 0);
+                               if (masks.centermask == 0) {
+                                       mprintf((0, "Segment %i near vertex %i is contained in segment %i\n", segnum, v, i));
+                                       break;
+                               }
+                       }
+               }
+       }
+
+}
+
+//     -----------------------------------------------------------------------------------------------------
+//     Check for overlapping segments.
+void check_for_overlapping_segments(void)
+{
+       int     i;
+
+       med_compress_mine();
+
+       for (i=0; i<=Highest_segment_index; i++) {
+               mprintf((0, "+"));
+               check_for_overlapping_segment(i);
+       }
+
+       mprintf((0, "\nDone!\n"));
+}
+
diff --git a/main/editor/seguvs.h b/main/editor/seguvs.h
new file mode 100644 (file)
index 0000000..76c6775
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
+SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
+END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
+ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
+IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
+SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
+FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
+CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
+AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.  
+COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
+*/
+/*
+ * $Source: /cvs/cvsroot/d2x/main/editor/seguvs.h,v $
+ * $Revision: 1.1 $
+ * $Author: bradleyb $
+ * $Date: 2001-10-25 02:27:17 $
+ * 
+ * Header for seguvs.c
+ * 
+ * $Log: not supported by cvs2svn $
+ * Revision 1.1.1.1  1999/06/14 22:02:40  donut
+ * Import of d1x 1.37 source.
+ *
+ * Revision 2.0  1995/02/27  11:34:58  john
+ * Version 2.0! No anonymous unions, Watcom 10.0, with no need
+ * for bitmaps.tbl.
+ * 
+ * Revision 1.3  1994/08/03  10:32:28  mike
+ * Add stretch_uvs_from_curedge.
+ * 
+ * Revision 1.2  1994/05/14  18:00:58  matt
+ * Got rid of externs in source (non-header) files
+ * 
+ * Revision 1.1  1994/05/14  17:27:26  matt
+ * Initial revision
+ * 
+ * 
+ */
+
+
+
+#ifndef _SEGUVS_H
+#define _SEGUVS_H
+
+extern void assign_light_to_side(segment *sp, int sidenum);
+extern void assign_default_lighting_all(void);
+extern void stretch_uvs_from_curedge(segment *segp, int side);
+
+#endif
index 6f86f57..c5a84ac 100644 (file)
@@ -1,5 +1,7 @@
 INCLUDES = -I $(top_srcdir) -I$(top_srcdir)/includes -I$(top_srcdir)/main
 
+CFLAGS += ${SDL_CFLAGS}
+
 noinst_LIBRARIES = libsound.a
 
 if ENV_DJGPP
index 8889686..251a1a4 100644 (file)
@@ -2,6 +2,8 @@ noinst_LIBRARIES = libvideo.a
 
 INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/includes -I$(top_srcdir)/main -I$(top_srcdir)/arch/include
 
+CFLAGS += ${SDL_CFLAGS}
+
 if ENV_DJGPP
 libvideo_a_SOURCES = dos_gr.c
 else