Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Editor loop for Inferno
  23.  *
  24.  */
  25.  
  26. //#define DEMO 1
  27.  
  28. #define DIAGNOSTIC_MESSAGE_MAX                          90
  29. #define EDITOR_STATUS_MESSAGE_DURATION  4               //      Shows for 3+..4 seconds
  30.  
  31. #include <stdio.h>
  32. #include <stdlib.h>
  33. #include <stdarg.h>
  34. #include <string.h>
  35. #include <time.h>
  36.  
  37. #include "inferno.h"
  38. #include "args.h"
  39. #include "segment.h"
  40. #include "gr.h"
  41. #include "palette.h"
  42. #include "physfsx.h"
  43. #include "event.h"
  44. #include "window.h"
  45. #include "game.h"
  46. #include "messagebox.h"
  47. #include "ui.h"
  48. #include "editor.h"
  49. #include "editor/esegment.h"
  50. #include "state.h"
  51. #include "gamesave.h"
  52. #include "gameseg.h"
  53. #include "key.h"
  54. #include "kconfig.h"
  55. #include "mouse.h"
  56. #include "dxxerror.h"
  57. #include "kfuncs.h"
  58. #include "macro.h"
  59. #ifdef INCLUDE_XLISP
  60. #include "medlisp.h"
  61. #endif
  62. #include "u_mem.h"
  63. #include "render.h"
  64. #include "game.h"
  65. #include "gamefont.h"
  66. #include "menu.h"
  67. #include "slew.h"
  68. #include "player.h"
  69. #include "kdefs.h"
  70. #include "func.h"
  71. #include "textures.h"
  72. #include "screens.h"
  73. #include "texmap.h"
  74. #include "object.h"
  75. #include "effects.h"
  76. #include "info.h"
  77. #include "ai.h"
  78. #include "console.h"
  79. #include "texpage.h"            // Textue selection paging stuff
  80. #include "objpage.h"            // Object selection paging stuff
  81. #include "d_enumerate.h"
  82.  
  83. #include "medmisc.h"
  84. #include "meddraw.h"
  85. #include "medsel.h"
  86. #include "medrobot.h"
  87. #include "medwall.h"
  88. #include "eswitch.h"
  89. #include "ehostage.h"
  90. #include "centers.h"
  91.  
  92. #include "fuelcen.h"
  93. #include "gameseq.h"
  94. #include "mission.h"
  95. #include "newmenu.h"
  96.  
  97. #if defined(DXX_BUILD_DESCENT_II)
  98. #include "gamepal.h"
  99. #endif
  100.  
  101. #include "dxxsconf.h"
  102. #include "compiler-range_for.h"
  103.  
  104. //#define _MARK_ON 1
  105. //#include <wsample.h>          //should come after inferno.h to get mark setting //Not included here.
  106.  
  107. #define COMPRESS_INTERVAL       5                       // seconds
  108.  
  109. static void med_show_warning(const char *s);
  110.  
  111. //char *undo_status[128];
  112.  
  113. int initializing;
  114.  
  115. //these are instances of canvases, pointed to by variables below
  116. grs_canvas _canv_editor_game, _canv_editor; //the game on the editor screen, the canvas that the editor writes to
  117.  
  118. //these are pointers to our canvases
  119. grs_canvas *Canv_editor;                        //the editor screen
  120. grs_canvas *const Canv_editor_game = &_canv_editor_game; //the game on the editor screen
  121.  
  122. window *Pad_info;               // Keypad text
  123.  
  124. grs_font_ptr editor_font;
  125.  
  126. //where the editor is looking
  127. vms_vector Ed_view_target;
  128.  
  129. editor_gamestate gamestate = editor_gamestate::none;
  130.  
  131. UI_DIALOG * EditorWindow = NULL;
  132.  
  133. int     Large_view_index = -1;
  134.  
  135. std::unique_ptr<UI_GADGET_USERBOX> GameViewBox, LargeViewBox, GroupViewBox;
  136.  
  137. #if ORTHO_VIEWS
  138. UI_GADGET_USERBOX * TopViewBox;
  139. UI_GADGET_USERBOX * FrontViewBox;
  140. UI_GADGET_USERBOX * RightViewBox;
  141. #endif
  142.  
  143. static std::unique_ptr<UI_GADGET_ICON>
  144.         ViewIcon,
  145.         AllIcon,
  146.         AxesIcon,
  147.         ChaseIcon,
  148.         OutlineIcon,
  149.         LockIcon;
  150.  
  151. //grs_canvas * BigCanvas[2];
  152. //int CurrentBigCanvas = 0;
  153. //int BigCanvasFirstTime = 1;
  154.  
  155. int     Found_seg_index=0;                              // Index in Found_segs corresponding to Cursegp
  156.  
  157. namespace {
  158.        
  159. class editor_dialog
  160. {
  161. public:
  162.         std::array<std::unique_ptr<UI_GADGET_BUTTON>, 9> pad_goto;
  163.         std::unique_ptr<UI_GADGET_BUTTON>
  164.                 pad_prev,
  165.                 pad_next;
  166. };
  167.  
  168. }
  169.  
  170. static editor_dialog editor_window;
  171.  
  172. static void print_status_bar(const std::array<char, DIAGNOSTIC_MESSAGE_MAX> &message)
  173. {
  174.         gr_set_default_canvas();
  175.         auto &canvas = *grd_curcanv;
  176.         const auto &editor_font = *::editor_font;
  177.         gr_set_fontcolor(canvas, CBLACK, CGREY);
  178.         int w,h;
  179.         gr_get_string_size(editor_font, message.data(), &w, &h, nullptr);
  180.         gr_string(canvas, editor_font, 4, 583, message.data(), w, h);
  181.         gr_set_fontcolor(canvas, CBLACK, CWHITE);
  182.         gr_rect(canvas, 4+w, 583, 799, 599, CGREY);
  183. }
  184.  
  185. static std::array<char, DIAGNOSTIC_MESSAGE_MAX> status_line;
  186.  
  187. struct tm       Editor_status_last_time;
  188.  
  189. void (editor_status_fmt)( const char *format, ... )
  190. {
  191.         va_list ap;
  192.  
  193.         va_start(ap, format);
  194.         vsnprintf(status_line.data(), status_line.size(), format, ap);
  195.         va_end(ap);
  196.  
  197.         Editor_status_last_time = Editor_time_of_day;
  198. }
  199.  
  200. void editor_status( const char *text)
  201. {
  202.         Editor_status_last_time = Editor_time_of_day;
  203.         strcpy(status_line.data(), text);
  204. }
  205.  
  206. //      int  tm_sec;    /* seconds after the minute -- [0,61] */
  207. //      int  tm_min;    /* minutes after the hour       -- [0,59] */
  208. //      int  tm_hour;   /* hours after midnight -- [0,23] */
  209. //      int  tm_mday;   /* day of the month             -- [1,31] */
  210. //      int  tm_mon;    /* months since January -- [0,11] */
  211. //      int  tm_year;   /* years since 1900                             */
  212. //      int  tm_wday;   /* days since Sunday            -- [0,6]  */
  213. //      int  tm_yday;   /* days since January 1 -- [0,365]*/
  214. //      int  tm_isdst;  /* Daylight Savings Time flag */
  215.  
  216. static void clear_editor_status(void)
  217. {
  218.         int cur_time = Editor_time_of_day.tm_hour * 3600 + Editor_time_of_day.tm_min*60 + Editor_time_of_day.tm_sec;
  219.         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;
  220.  
  221.         if (cur_time > erase_time) {
  222.                 std::fill(status_line.begin(), std::prev(status_line.end()), ' ');
  223.                 status_line.back() = 0;
  224.                 Editor_status_last_time.tm_hour = 99;
  225.         }
  226. }
  227.  
  228. static inline void editor_slew_init()
  229. {
  230.         auto &Objects = LevelUniqueObjectState.Objects;
  231.         auto &vmobjptr = Objects.vmptr;
  232.         Viewer = ConsoleObject;
  233.         slew_init(vmobjptr(ConsoleObject));
  234.         init_player_object();
  235. }
  236.  
  237. int DropIntoDebugger()
  238. {
  239.         Int3();
  240.         return 1;
  241. }
  242.  
  243.  
  244. #ifdef INCLUDE_XLISP
  245. int CallLisp()
  246. {
  247.         medlisp_go();
  248.         return 1;
  249. }
  250. #endif
  251.  
  252.  
  253. int ExitEditor()
  254. {
  255.         if (SafetyCheck())  {
  256.                 ModeFlag = 1;
  257.         }
  258.         return 1;
  259. }
  260.  
  261. int     GotoGameScreen()
  262. {
  263.         auto &Objects = LevelUniqueObjectState.Objects;
  264.         auto &vmobjptr = Objects.vmptr;
  265.         pause_game_world_time p;
  266.  
  267. //@@    init_player_stats();
  268. //@@
  269. //@@    Player_init.pos = Player->pos;
  270. //@@    Player_init.orient = Player->orient;
  271. //@@    Player_init.segnum = Player->segnum;   
  272.  
  273.  
  274. // -- must always save gamesave.sge/lvl because the restore-objects code relies on it
  275. // -- that code could be made smarter and use the original file, if appropriate.
  276. //      if (mine_changed)
  277.         switch (gamestate)
  278.         {
  279.                 case editor_gamestate::none:
  280.                         // Always use the simple mission when playing level (for now at least)
  281.                         create_new_mission();
  282.                         Current_level_num = 1;
  283.                         if (save_level(
  284. #if defined(DXX_BUILD_DESCENT_II)
  285.                                         LevelSharedSegmentState.DestructibleLights,
  286. #endif
  287.                                         "GAMESAVE.LVL"))
  288.                                 return 0;
  289.                         editor_status("Level saved.\n");
  290.                         break;
  291.  
  292.                 case editor_gamestate::unsaved:
  293.                 case editor_gamestate::saved:
  294.                         if (!SafetyCheck())             // if mine edited but not saved, warn the user!
  295.                                 return 0;
  296.  
  297.                         const auto &&console = vmobjptr(get_local_player().objnum);
  298.                         Viewer = ConsoleObject = console;
  299.                         set_player_id(console, Player_num);
  300.                         fly_init(*ConsoleObject);
  301.  
  302.                         if (!state_save_all_sub(PLAYER_DIRECTORY_STRING("gamesave.sge"), "Editor generated"))
  303.                         {
  304.                                 editor_slew_init();
  305.  
  306.                                 return 0;
  307.                         }
  308.                         gamestate = editor_gamestate::saved;
  309.                         editor_status("Game saved.\n");
  310.                         break;
  311.         }
  312.  
  313.         ModeFlag = 3;
  314.         return 1;
  315. }
  316.  
  317. int GotoMainMenu()
  318. {
  319.         ModeFlag = 2;
  320.         return 1;
  321. }
  322.  
  323. static std::array<int (*)(), 2048> KeyFunction;
  324.  
  325. static void medkey_init()
  326. {
  327.         char keypress[100];
  328.         int key;
  329.         int np;
  330.         char LispCommand[DIAGNOSTIC_MESSAGE_MAX];
  331.  
  332.         KeyFunction = {};
  333.  
  334.         if (auto keyfile = PHYSFSX_openReadBuffered("GLOBAL.KEY"))
  335.         {
  336.                 PHYSFSX_gets_line_t<200> line_buffer;
  337.                 while (PHYSFSX_fgets(line_buffer, keyfile))
  338.                 {
  339.                         sscanf(line_buffer, " %s %s ", keypress, LispCommand);
  340.                         //ReadLispMacro( keyfile, LispCommand );
  341.  
  342.                         if ( (key=DecodeKeyText( keypress ))!= -1 )
  343.                         {
  344.                                 Assert( key < 2048);
  345.                                 KeyFunction[key] = func_get( LispCommand, &np );
  346.                         } else {
  347.                                 UserError( "Bad key %s in GLOBAL.KEY!", keypress );
  348.                         }
  349.                 }
  350.         }
  351. }
  352.  
  353. static int padnum=0;
  354. //@@short camera_objnum;                        //a camera for viewing. Who knows, might become handy
  355.  
  356. static void init_editor_screen(grs_canvas &canvas);
  357. static void gamestate_restore_check();
  358. static window_event_result editor_handler(UI_DIALOG *dlg,const d_event &event, unused_ui_userdata_t *data);
  359. static void close_editor();
  360.  
  361. namespace dsx {
  362. void init_editor()
  363. {
  364.         static const char pads[][13] = {
  365.                 "segmove.pad",
  366.                 "segsize.pad",
  367.                 "curve.pad",
  368.                 "texture.pad",
  369.                 "object.pad",
  370.                 "objmov.pad",
  371.                 "group.pad",
  372.                 "lighting.pad",
  373.                 "test.pad"
  374.                                         };
  375.         ModeFlag = Game_wind ? 3 : 2;   // go back to where we were unless we loaded everything properly
  376.  
  377.         // first, make sure we can find the files we need
  378.         PHYSFSX_addRelToSearchPath("editor/data", 1);   // look in source directory first (for work in progress)
  379.         PHYSFSX_addRelToSearchPath("editor", 1);                // then in editor directory
  380.         PHYSFSX_addRelToSearchPath("editor.zip", 1);    // then in a zip file
  381.         PHYSFSX_addRelToSearchPath("editor.dxa", 1);    // or addon pack
  382.  
  383.         if (!ui_init())
  384.         {
  385.                 close_editor();
  386.                 return;
  387.         }
  388.  
  389.         init_med_functions();   // Must be called before medlisp_init
  390.  
  391.         range_for (auto &&e, enumerate(pads))
  392.                 if (!ui_pad_read(e.idx, e.value))
  393.                 {
  394.                         close_editor();
  395.                         return;
  396.                 }
  397.  
  398.         medkey_init();
  399.  
  400.         game_flush_inputs();
  401.        
  402.         editor_font = gr_init_font(*grd_curcanv, "pc8x16.fnt");
  403.         if (!editor_font)
  404.         {
  405.                 Warning("Could not find pc8x16.fnt");
  406.                 close_editor();
  407.                 return;
  408.         }
  409.        
  410.         if (!menubar_init(*grd_curcanv, "MED.MNU"))
  411.         {
  412.                 close_editor();
  413.                 return;
  414.         }
  415.  
  416.         Draw_all_segments = 1;                                          // Say draw all segments, not just connected ones
  417.        
  418.         if (!Cursegp)
  419.                 Cursegp = imsegptridx(segment_first);
  420.  
  421.         init_autosave();
  422.  
  423.         Clear_window = 1;       //      do full window clear.
  424.        
  425.         InitCurve();
  426.        
  427.         restore_effect_bitmap_icons();
  428.        
  429.         if (!set_screen_mode(SCREEN_EDITOR))
  430.         {
  431.                 close_editor();
  432.                 return;
  433.         }
  434. #if defined(DXX_BUILD_DESCENT_I)
  435.         gr_use_palette_table( "palette.256" );
  436.         gr_palette_load( gr_palette );
  437. #elif defined(DXX_BUILD_DESCENT_II)
  438.         load_palette(Current_level_palette,1,0);
  439. #endif
  440.        
  441.         //Editor renders into full (320x200) game screen
  442.        
  443.         game_init_render_buffers(320, 200);
  444.         gr_init_sub_canvas(_canv_editor, grd_curscreen->sc_canvas, 0, 0, SWIDTH, SHEIGHT);
  445.         Canv_editor = &_canv_editor;
  446.         gr_set_current_canvas(*Canv_editor);
  447.         init_editor_screen(*grd_curcanv); // load the main editor dialog
  448.         gr_set_default_canvas();
  449.         set_warn_func(med_show_warning);
  450.        
  451.         //      _MARK_("start of editor");//Nuked to compile -KRB
  452.        
  453.         //@@    //create a camera for viewing in the editor. copy position from ConsoleObject
  454.         //@@    camera_objnum = obj_create(OBJ_CAMERA,0,ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0);
  455.         //@@    Viewer = &Objects[camera_objnum];
  456.         //@@    slew_init(Viewer);              //camera is slewing
  457.        
  458.         editor_slew_init();
  459.        
  460.         Update_flags = UF_ALL;
  461.        
  462.         //set the wire-frame window to be the current view
  463.         current_view = &LargeView;
  464.        
  465.         gr_set_current_canvas( GameViewBox->canvas );
  466.         gr_set_curfont(*grd_curcanv, editor_font);
  467.         // No font scaling!
  468.         FNTScaleX.reset(1);
  469.         FNTScaleY.reset(1);
  470.         ui_pad_goto(padnum);
  471.        
  472.         ModeFlag = 0;   // success!
  473.        
  474.         gamestate_restore_check();
  475. }
  476. }
  477.  
  478. int ShowAbout()
  479. {
  480.         ui_messagebox( -2, -2, 1,       "INFERNO Mine Editor\n\n"               \
  481.                                                                         "Copyright (c) 1993  Parallax Software Corp.",
  482.                                                                         "OK");
  483.         return 0;
  484. }
  485.  
  486. int SetPlayerFromCurseg()
  487. {
  488.         move_player_2_segment(Cursegp,Curside);
  489.         Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED;
  490.         return 1;
  491. }
  492.  
  493. int fuelcen_create_from_curseg()
  494. {
  495.         Cursegp->special = SEGMENT_IS_FUELCEN;
  496.         fuelcen_activate(Cursegp);
  497.         return 1;
  498. }
  499.  
  500. int repaircen_create_from_curseg()
  501. {
  502.         Int3(); //      -- no longer supported!
  503. //      Cursegp->special = SEGMENT_IS_REPAIRCEN;
  504. //      fuelcen_activate(Cursegp, Cursegp->special);
  505.         return 1;
  506. }
  507.  
  508. int controlcen_create_from_curseg()
  509. {
  510.         Cursegp->special = SEGMENT_IS_CONTROLCEN;
  511.         fuelcen_activate(Cursegp);
  512.         return 1;
  513. }
  514.  
  515. int robotmaker_create_from_curseg()
  516. {
  517.         Cursegp->special = SEGMENT_IS_ROBOTMAKER;
  518.         fuelcen_activate(Cursegp);
  519.         return 1;
  520. }
  521.  
  522. int fuelcen_reset_all() {
  523.         fuelcen_reset();
  524.         return 1;
  525. }
  526.  
  527. int fuelcen_delete_from_curseg() {
  528.         fuelcen_delete( Cursegp );
  529.         return 1;
  530. }
  531.  
  532.  
  533. //@@//this routine places the viewer in the center of the side opposite to curside,
  534. //@@//with the view toward the center of curside
  535. //@@int SetPlayerFromCursegMinusOne()
  536. //@@{
  537. //@@    vms_vector vp;
  538. //@@
  539. //@@//  int newseg,newside;
  540. //@@//  get_previous_segment(SEG_PTR_2_NUM(Cursegp),Curside,&newseg,&newside);
  541. //@@//  move_player_2_segment(&Segments[newseg],newside);
  542. //@@
  543. //@@    med_compute_center_point_on_side(&Player->obj_position,Cursegp,Side_opposite[Curside]);
  544. //@@    med_compute_center_point_on_side(&vp,Cursegp,Curside);
  545. //@@    vm_vec_sub2(&vp,&Player->position);
  546. //@@    vm_vector_2_matrix(&Player->orient,&vp,NULL,NULL);
  547. //@@
  548. //@@    Player->seg = SEG_PTR_2_NUM(Cursegp);
  549. //@@
  550. //@@    Update_flags |= UF_GAME_VIEW_CHANGED;
  551. //@@    return 1;
  552. //@@}
  553.  
  554. //this constant determines how much of the window will be occupied by the
  555. //viewed side when SetPlayerFromCursegMinusOne() is called.  It actually
  556. //determine how from from the center of the window the farthest point will be
  557. #define SIDE_VIEW_FRAC (f1_0*8/10)      //80%
  558.  
  559.  
  560. static void move_player_2_segment_and_rotate(const vmsegptridx_t seg, const unsigned side)
  561. {
  562.         auto &Objects = LevelUniqueObjectState.Objects;
  563.         auto &vmobjptr = Objects.vmptr;
  564.         auto &vmobjptridx = Objects.vmptridx;
  565.         static int edgenum=0;
  566.  
  567.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  568.         auto &Vertices = LevelSharedVertexState.get_vertices();
  569.         auto &vcvertptr = Vertices.vcptr;
  570.         compute_segment_center(vcvertptr, ConsoleObject->pos,seg);
  571.         auto vp = compute_center_point_on_side(vcvertptr, seg, side);
  572.         vm_vec_sub2(vp,ConsoleObject->pos);
  573.  
  574.         auto &sv = Side_to_verts[Curside];
  575.         auto &verts = Cursegp->verts;
  576.         const auto upvec = vm_vec_sub(vcvertptr(verts[sv[edgenum % 4]]), vcvertptr(verts[sv[(edgenum + 3) % 4]]));
  577.         edgenum++;
  578.  
  579.         vm_vector_2_matrix(ConsoleObject->orient,vp,&upvec,nullptr);
  580. //      vm_vector_2_matrix(&ConsoleObject->orient,&vp,NULL,NULL);
  581.  
  582.         obj_relink(vmobjptr, vmsegptr, vmobjptridx(ConsoleObject), seg);
  583. }
  584.  
  585. int SetPlayerFromCursegAndRotate()
  586. {
  587.         move_player_2_segment_and_rotate(Cursegp,Curside);
  588.         Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED;
  589.         return 1;
  590. }
  591.  
  592.  
  593. //sets the player facing curseg/curside, normal to face0 of curside, and
  594. //far enough away to see all of curside
  595. int SetPlayerFromCursegMinusOne()
  596. {
  597.         auto &Objects = LevelUniqueObjectState.Objects;
  598.         auto &vmobjptr = Objects.vmptr;
  599.         auto &vmobjptridx = Objects.vmptridx;
  600.         std::array<g3s_point, 4> corner_p;
  601.         fix max,view_dist=f1_0*10;
  602.         static int edgenum=0;
  603.         const auto view_vec = vm_vec_negated(Cursegp->shared_segment::sides[Curside].normals[0]);
  604.  
  605.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  606.         auto &Vertices = LevelSharedVertexState.get_vertices();
  607.         auto &vcvertptr = Vertices.vcptr;
  608.         const auto &&side_center = compute_center_point_on_side(vcvertptr, Cursegp, Curside);
  609.         const auto view_vec2 = vm_vec_copy_scale(view_vec,view_dist);
  610.         vm_vec_sub(ConsoleObject->pos,side_center,view_vec2);
  611.  
  612.         auto &sv = Side_to_verts[Curside];
  613.         auto &verts = Cursegp->verts;
  614.         const auto upvec = vm_vec_sub(vcvertptr(verts[sv[edgenum % 4]]), vcvertptr(verts[sv[(edgenum + 3) % 4]]));
  615.         edgenum++;
  616.  
  617.         vm_vector_2_matrix(ConsoleObject->orient,view_vec,&upvec,nullptr);
  618.  
  619.         gr_set_current_canvas(*Canv_editor_game);
  620.         g3_start_frame(*grd_curcanv);
  621.         g3_set_view_matrix(ConsoleObject->pos,ConsoleObject->orient,Render_zoom);
  622.  
  623.         for (unsigned i = max = 0; i < 4; ++i)
  624.         {
  625.                 g3_rotate_point(corner_p[i], vcvertptr(verts[sv[i]]));
  626.                 if (labs(corner_p[i].p3_x) > max) max = labs(corner_p[i].p3_x);
  627.                 if (labs(corner_p[i].p3_y) > max) max = labs(corner_p[i].p3_y);
  628.         }
  629.  
  630.         view_dist = fixmul(view_dist,fixdiv(fixdiv(max,SIDE_VIEW_FRAC),corner_p[0].p3_z));
  631.         const auto view_vec3 = vm_vec_copy_scale(view_vec,view_dist);
  632.         vm_vec_sub(ConsoleObject->pos,side_center,view_vec3);
  633.  
  634.         //obj_relink(ConsoleObject-Objects, SEG_PTR_2_NUM(Cursegp) );
  635.         //update_object_seg(ConsoleObject);             //might have backed right out of curseg
  636.  
  637.         const auto &&newseg = find_point_seg(LevelSharedSegmentState, LevelUniqueSegmentState, ConsoleObject->pos, Cursegp);
  638.         if (newseg != segment_none)
  639.                 obj_relink(vmobjptr, vmsegptr, vmobjptridx(ConsoleObject), newseg);
  640.  
  641.         Update_flags |= UF_ED_STATE_CHANGED | UF_GAME_VIEW_CHANGED;
  642.         return 1;
  643. }
  644.  
  645. #if !DXX_USE_OGL
  646. static int ToggleLighting(void)
  647. {
  648.         Lighting_on++;
  649.         if (Lighting_on >= 2)
  650.                 Lighting_on = 0;
  651.  
  652.         Update_flags |= UF_GAME_VIEW_CHANGED;
  653.  
  654.         switch (Lighting_on) {
  655.                 case 0:
  656.                         diagnostic_message("Lighting off.");
  657.                         break;
  658.                 case 1:
  659.                         diagnostic_message("Static lighting.");
  660.                         break;
  661.                 case 2:
  662.                         diagnostic_message("Ship lighting.");
  663.                         break;
  664.                 case 3:
  665.                         diagnostic_message("Ship and static lighting.");
  666.                         break;
  667.         }
  668.  
  669.         return Lighting_on;
  670. }
  671. #endif
  672.  
  673. int FindConcaveSegs()
  674. {
  675.         find_concave_segs();
  676.  
  677.         Update_flags |= UF_ED_STATE_CHANGED;            //list may have changed
  678.  
  679.         return 1;
  680. }
  681.  
  682. static int ToggleOutlineMode()
  683. {
  684. #ifndef NDEBUG
  685.         int mode;
  686.  
  687.         mode=toggle_outline_mode();
  688.  
  689.         if (mode)
  690.          {
  691.                 //if (keypress != KEY_O)
  692.                         diagnostic_message("[Ctrl-O] Outline Mode ON.");
  693.                 //else
  694.                 //      diagnostic_message("Outline Mode ON.");
  695.          }
  696.         else
  697.          {
  698.                 //if (keypress != KEY_O)
  699.                         diagnostic_message("[Ctrl-O] Outline Mode OFF.");
  700.                 //else
  701.                 //      diagnostic_message("Outline Mode OFF.");
  702.          }
  703.  
  704.         Update_flags |= UF_GAME_VIEW_CHANGED;
  705.         return mode;
  706. #else
  707.         return 1;
  708. #endif
  709. }
  710.  
  711. //@@int do_reset_orient()
  712. //@@{
  713. //@@    slew_reset_orient(SlewObj);
  714. //@@
  715. //@@    Update_flags |= UF_GAME_VIEW_CHANGED;
  716. //@@
  717. //@@    * reinterpret_cast<uint8_t *>(0x417) &= ~0x20;
  718. //@@
  719. //@@    return 1;
  720. //@@}
  721.  
  722. int GameZoomOut()
  723. {
  724.         Render_zoom = fixmul(Render_zoom,68985);
  725.         Update_flags |= UF_GAME_VIEW_CHANGED;
  726.         return 1;
  727. }
  728.  
  729. int GameZoomIn()
  730. {
  731.         Render_zoom = fixmul(Render_zoom,62259);
  732.         Update_flags |= UF_GAME_VIEW_CHANGED;
  733.         return 1;
  734. }
  735.  
  736.  
  737. static int med_keypad_goto_0()  {       ui_pad_goto(0); return 0;       }
  738. static int med_keypad_goto_1()  {       ui_pad_goto(1); return 0;       }
  739. static int med_keypad_goto_2()  {       ui_pad_goto(2); return 0;       }
  740. static int med_keypad_goto_3()  {       ui_pad_goto(3); return 0;       }
  741. static int med_keypad_goto_4()  {       ui_pad_goto(4); return 0;       }
  742. static int med_keypad_goto_5()  {       ui_pad_goto(5); return 0;       }
  743. static int med_keypad_goto_6()  {       ui_pad_goto(6); return 0;       }
  744. static int med_keypad_goto_7()  {       ui_pad_goto(7); return 0;       }
  745. static int med_keypad_goto_8()  {       ui_pad_goto(8); return 0;       }
  746.  
  747. #define PAD_WIDTH       30
  748. #define PAD_WIDTH1      (PAD_WIDTH + 7)
  749.  
  750. int editor_screen_open = 0;
  751.  
  752. //setup the editors windows, canvases, gadgets, etc.
  753. static void init_editor_screen(grs_canvas &canvas)
  754. {      
  755. //      grs_bitmap * bmp;
  756.  
  757.         if (editor_screen_open) return;
  758.  
  759.         grd_curscreen->sc_canvas.cv_font = editor_font.get();
  760.        
  761.         //create canvas for game on the editor screen
  762.         initializing = 1;
  763.         gr_set_current_canvas(*Canv_editor);
  764.         Canv_editor->cv_font = editor_font.get();
  765.         gr_init_sub_canvas(*Canv_editor_game, *Canv_editor, GAMEVIEW_X, GAMEVIEW_Y, GAMEVIEW_W, GAMEVIEW_H);
  766.        
  767.         //Editor renders into full (320x200) game screen
  768.  
  769.         init_info = 1;
  770.  
  771.         //do other editor screen setup
  772.  
  773.         // Since the palette might have changed, find some good colors...
  774.         CBLACK = gr_find_closest_color( 1, 1, 1 );
  775.         CGREY = gr_find_closest_color( 28, 28, 28 );
  776.         CWHITE = gr_find_closest_color( 38, 38, 38 );
  777.         CBRIGHT = gr_find_closest_color( 60, 60, 60 );
  778.         CRED = gr_find_closest_color( 63, 0, 0 );
  779.  
  780.         gr_set_curfont(canvas, editor_font);
  781.         gr_set_fontcolor(canvas, CBLACK, CWHITE);
  782.  
  783.         EditorWindow = ui_create_dialog( 0 , 0, ED_SCREEN_W, ED_SCREEN_H, DF_FILLED, editor_handler, unused_ui_userdata );
  784.  
  785.         LargeViewBox    = ui_add_gadget_userbox( EditorWindow,LVIEW_X,LVIEW_Y,LVIEW_W,LVIEW_H);
  786. #if ORTHO_VIEWS
  787.         TopViewBox              = ui_add_gadget_userbox( EditorWindow,TVIEW_X,TVIEW_Y,TVIEW_W,TVIEW_H);
  788.         FrontViewBox    = ui_add_gadget_userbox( EditorWindow,FVIEW_X,FVIEW_Y,FVIEW_W,FVIEW_H);
  789.         RightViewBox    = ui_add_gadget_userbox( EditorWindow,RVIEW_X,RVIEW_Y,RVIEW_W,RVIEW_H);
  790. #endif
  791.         ui_gadget_calc_keys(EditorWindow);      //make tab work for all windows
  792.  
  793.         GameViewBox     = ui_add_gadget_userbox( EditorWindow, GAMEVIEW_X, GAMEVIEW_Y, GAMEVIEW_W, GAMEVIEW_H );
  794. //      GroupViewBox    = ui_add_gadget_userbox( EditorWindow,GVIEW_X,GVIEW_Y,GVIEW_W,GVIEW_H);
  795.  
  796. //      GameViewBox->when_tab = GameViewBox->when_btab =  LargeViewBox;
  797. //      LargeViewBox->when_tab = LargeViewBox->when_btab =  GameViewBox;
  798.  
  799. //      ui_gadget_calc_keys(EditorWindow);      //make tab work for all windows
  800.  
  801.         ViewIcon        = ui_add_gadget_icon( EditorWindow, "Lock\nview",       455,25+530,     40, 22, KEY_V+KEY_CTRLED, ToggleLockViewToCursegp );
  802.         AllIcon = ui_add_gadget_icon( EditorWindow, "Draw\nall",        500,25+530,     40, 22, -1, ToggleDrawAllSegments );
  803.         AxesIcon        = ui_add_gadget_icon( EditorWindow, "Coord\naxes",545,25+530,           40, 22, KEY_D+KEY_CTRLED, ToggleCoordAxes );
  804.         ChaseIcon       = ui_add_gadget_icon( EditorWindow, "Chase\nmode",635,25+530,           40, 22, -1,                             ToggleChaseMode );
  805.         OutlineIcon = ui_add_gadget_icon( EditorWindow, "Out\nline",    680,25+530,     40, 22, KEY_O+KEY_CTRLED,                       ToggleOutlineMode );
  806.         LockIcon        = ui_add_gadget_icon( EditorWindow, "Lock\nstep", 725,25+530,   40, 22, KEY_L+KEY_CTRLED,                       ToggleLockstep );
  807.  
  808.         meddraw_init_views(LargeViewBox->canvas.get());
  809.  
  810.         //ui_add_gadget_button( EditorWindow, 460, 510, 50, 25, "Quit", ExitEditor );
  811.         //ui_add_gadget_button( EditorWindow, 520, 510, 50, 25, "Lisp", CallLisp );
  812.         //ui_add_gadget_button( EditorWindow, 580, 510, 50, 25, "Mine", MineMenu );
  813.         //ui_add_gadget_button( EditorWindow, 640, 510, 50, 25, "Help", DoHelp );
  814.         //ui_add_gadget_button( EditorWindow, 460, 540, 50, 25, "Macro", MacroMenu );
  815.         //ui_add_gadget_button( EditorWindow, 520, 540, 50, 25, "About", ShowAbout );
  816.         //ui_add_gadget_button( EditorWindow, 640, 540, 50, 25, "Shell", DosShell );
  817.  
  818.         auto &e = editor_window;
  819.  
  820.         ui_pad_activate(*EditorWindow, PAD_X, PAD_Y);
  821.         Pad_info = info_window_create();
  822.         e.pad_prev = ui_add_gadget_button( EditorWindow, PAD_X+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, "<<",  med_keypad_goto_prev );
  823.         e.pad_next = ui_add_gadget_button( EditorWindow, PAD_X+PAD_WIDTH1+6, PAD_Y+(30*5)+22, PAD_WIDTH, 20, ">>",  med_keypad_goto_next );
  824.  
  825.         {       int     i;
  826.                 i = 0;  e.pad_goto[i] = 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 );
  827.                 i++;            e.pad_goto[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 );
  828.                 i++;            e.pad_goto[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 );
  829.                 i++;            e.pad_goto[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 );
  830.                 i++;            e.pad_goto[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 );
  831.                 i++;            e.pad_goto[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 );
  832.                 i++;            e.pad_goto[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 );
  833.                 i++;            e.pad_goto[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 );
  834.                 i++;            e.pad_goto[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 );
  835.         }
  836.  
  837.         menubar_show();
  838.  
  839.         // INIT TEXTURE STUFF
  840.         texpage_init( EditorWindow );
  841.         objpage_init( EditorWindow );
  842.  
  843.         EditorWindow->keyboard_focus_gadget = LargeViewBox.get();
  844.  
  845. //      BigCanvas[0]->cv_font = grd_curscreen->sc_canvas.cv_font;
  846. //      BigCanvas[1]->cv_font = grd_curscreen->sc_canvas.cv_font;
  847. //      BigCanvasFirstTime = 1;
  848.  
  849.         Update_flags = UF_ALL;
  850.         initializing = 0;
  851.         editor_screen_open = 1;
  852. }
  853.  
  854. //shutdown ui on the editor screen
  855. void close_editor_screen()
  856. {
  857.         if (!editor_screen_open) return;
  858.  
  859.         editor_screen_open = 0;
  860.         ui_pad_deactivate();
  861.         if (Pad_info)
  862.                 window_close(Pad_info);
  863.  
  864.         //ui_close_dialog(EditorWindow);        // moved into handler, so we can handle the quit request
  865.         //EditorWindow = NULL;
  866.  
  867.         close_all_windows();
  868.  
  869.         // CLOSE TEXTURE STUFF
  870.         texpage_close();
  871.         objpage_close();
  872.  
  873.         menubar_hide();
  874.  
  875. }
  876.  
  877. static void med_show_warning(const char *s)
  878. {
  879.         grs_canvas &save_canv = *grd_curcanv;
  880.  
  881.         //gr_pal_fade_in(grd_curscreen->pal);   //in case palette is blacked
  882.  
  883.         ui_messagebox(-2,-2,1,s,"OK");
  884.  
  885.         gr_set_current_canvas(save_canv);
  886. }
  887.  
  888. // Returns 1 if OK to trash current mine.
  889. int SafetyCheck()
  890. {
  891.         int x;
  892.                        
  893.         if (mine_changed) {
  894.                 x = nm_messagebox( "Warning!", 2, "Cancel", "OK", "You are about to lose work." );
  895.                 if (x<1) {
  896.                         return 0;
  897.                 }
  898.         }
  899.         return 1;
  900. }
  901.  
  902. //called at the end of the program
  903.  
  904. static void close_editor()
  905. {
  906.         //      _MARK_("end of editor");//Nuked to compile -KRB
  907.        
  908. #if defined(WIN32) || defined(__APPLE__) || defined(__MACH__)
  909.         set_warn_func(msgbox_warning);
  910. #else
  911.         clear_warn_func();
  912. #endif
  913.        
  914.         close_editor_screen();
  915.        
  916.         //kill our camera object
  917.        
  918.         Viewer = ConsoleObject;                                 //reset viewer
  919.         //@@obj_delete(camera_objnum);
  920.        
  921.         padnum = ui_pad_get_current();
  922.        
  923.         close_autosave();
  924.  
  925.         ui_close();
  926.  
  927.         editor_font.reset();
  928.  
  929.         PHYSFSX_removeRelFromSearchPath("editor/data");
  930.         PHYSFSX_removeRelFromSearchPath("editor");
  931.         PHYSFSX_removeRelFromSearchPath("editor.zip");
  932.         PHYSFSX_removeRelFromSearchPath("editor.dxa");
  933.  
  934.         switch (ModeFlag)
  935.         {
  936.                 case 1:
  937.                         break;
  938.  
  939.                 case 2:
  940.                         set_screen_mode(SCREEN_MENU);           //put up menu screen
  941.                         show_menus();
  942.                         break;
  943.  
  944.                 case 3:
  945.                         if (Game_wind)
  946.                                 return; // if we're already playing a game, don't touch!
  947.  
  948.                         switch (gamestate)
  949.                         {
  950.                                 case editor_gamestate::none:
  951.                                         StartNewGame(Current_level_num);
  952.                                         break;
  953.  
  954.                                 case editor_gamestate::saved:
  955.                                         state_restore_all_sub(
  956. #if defined(DXX_BUILD_DESCENT_II)
  957.                                                 LevelSharedSegmentState.DestructibleLights, secret_restore::none,
  958. #endif
  959.                                                 PLAYER_DIRECTORY_STRING("gamesave.sge")
  960.                                         );
  961.                                         break;
  962.  
  963.                                 default:
  964.                                         Int3(); // shouldn't happen
  965.                                         break;
  966.                         }
  967.                         break;
  968.         }
  969.  
  970.         return;
  971. }
  972.  
  973. //variables for find segments process
  974.  
  975. // ---------------------------------------------------------------------------------------------------
  976. //      Subtract all elements in Found_segs from selected list.
  977. static void subtract_found_segments_from_selected_list(void)
  978. {
  979.         range_for (const auto &foundnum, Found_segs)
  980.         {
  981.                 selected_segment_array_t::iterator i = Selected_segs.find(foundnum), e = Selected_segs.end();
  982.                 if (i != e)
  983.                 {
  984.                         *i = *-- e;
  985.                         Selected_segs.erase(e);
  986.                 }
  987.         }
  988. }
  989.  
  990. // ---------------------------------------------------------------------------------------------------
  991. //      Add all elements in Found_segs to selected list.
  992. static void add_found_segments_to_selected_list(void) {
  993.         range_for (const auto &foundnum, Found_segs)
  994.         {
  995.                 selected_segment_array_t::iterator i = Selected_segs.find(foundnum), e = Selected_segs.end();
  996.                 if (i == e)
  997.                         Selected_segs.emplace_back(foundnum);
  998.         }
  999. }
  1000.  
  1001. void gamestate_restore_check()
  1002. {
  1003.         auto &Objects = LevelUniqueObjectState.Objects;
  1004.         auto &vmobjptr = Objects.vmptr;
  1005.         auto &vmobjptridx = Objects.vmptridx;
  1006.         obj_position Save_position;
  1007.  
  1008.         if (gamestate == editor_gamestate::saved)
  1009.         {
  1010.                 if (ui_messagebox(-2, -2, 2, "Do you wish to restore game state?\n", "Yes", "No") == 1)
  1011.                 {
  1012.  
  1013.                         // Save current position
  1014.                         Save_position.pos = ConsoleObject->pos;
  1015.                         Save_position.orient = ConsoleObject->orient;
  1016.                         Save_position.segnum = ConsoleObject->segnum;
  1017.  
  1018.                         if (!state_restore_all_sub(
  1019. #if defined(DXX_BUILD_DESCENT_II)
  1020.                                         LevelSharedSegmentState.DestructibleLights, secret_restore::none,
  1021. #endif
  1022.                                         PLAYER_DIRECTORY_STRING("gamesave.sge")
  1023.                         ))
  1024.                                 return;
  1025.  
  1026.                         // Switch back to slew mode - loading saved game made ConsoleObject flying
  1027.                         editor_slew_init();
  1028.  
  1029.                         // Restore current position
  1030.                         if (Save_position.segnum <= Highest_segment_index) {
  1031.                                 ConsoleObject->pos = Save_position.pos;
  1032.                                 ConsoleObject->orient = Save_position.orient;
  1033.                                 obj_relink(vmobjptr, vmsegptr, vmobjptridx(ConsoleObject), vmsegptridx(Save_position.segnum));
  1034.                         }
  1035.  
  1036.                         Update_flags |= UF_WORLD_CHANGED;      
  1037.                 }
  1038.                 else
  1039.                         gamestate = editor_gamestate::none;
  1040.         }
  1041. }
  1042.  
  1043. int RestoreGameState()
  1044. {
  1045.         if (!SafetyCheck())
  1046.                 return 0;
  1047.  
  1048.         if (!state_restore_all_sub(
  1049. #if defined(DXX_BUILD_DESCENT_II)
  1050.                         LevelSharedSegmentState.DestructibleLights, secret_restore::none,
  1051. #endif
  1052.                         PLAYER_DIRECTORY_STRING("gamesave.sge")
  1053.         ))
  1054.                 return 0;
  1055.  
  1056.         // Switch back to slew mode - loading saved game made ConsoleObject flying
  1057.         editor_slew_init();
  1058.        
  1059.         gamestate = editor_gamestate::saved;
  1060.  
  1061.         editor_status("Gamestate restored.\n");
  1062.  
  1063.         Update_flags |= UF_WORLD_CHANGED;
  1064.         return 1;
  1065. }
  1066.  
  1067. // Handler for the main editor dialog
  1068. window_event_result editor_handler(UI_DIALOG *, const d_event &event, unused_ui_userdata_t *)
  1069. {
  1070.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  1071.         auto &Vertices = LevelSharedVertexState.get_vertices();
  1072.         editor_view *new_cv;
  1073.         int keypress = 0;
  1074.         window_event_result rval = window_event_result::ignored;
  1075.  
  1076.         if (event.type == EVENT_WINDOW_CREATED)
  1077.                 return window_event_result::ignored;
  1078.  
  1079.         if (event.type == EVENT_KEY_COMMAND)
  1080.                 keypress = event_key_get(event);
  1081.         else if (event.type == EVENT_WINDOW_CLOSE)
  1082.         {
  1083.                 EditorWindow = NULL;
  1084.                 close_editor();
  1085.                 return window_event_result::ignored;
  1086.         }
  1087.        
  1088.         // Update the windows
  1089.  
  1090.         if (event.type == EVENT_UI_DIALOG_DRAW)
  1091.         {
  1092.                 // Draw status box
  1093.                 gr_set_default_canvas();
  1094.                 gr_rect(*grd_curcanv, STATUS_X,STATUS_Y,STATUS_X+STATUS_W-1,STATUS_Y+STATUS_H-1, CGREY);
  1095.                
  1096.                 medlisp_update_screen();
  1097.                 calc_frame_time();
  1098.                 texpage_do(event);
  1099.                 objpage_do(event);
  1100.                 ui_pad_draw(EditorWindow, PAD_X, PAD_Y);
  1101.  
  1102.                 print_status_bar(status_line);
  1103.                 TimedAutosave(mine_filename);   // shows the time, hence here
  1104.                 set_editor_time_of_day();
  1105.                 return window_event_result::handled;
  1106.         }
  1107.        
  1108.         if ((selected_gadget == GameViewBox.get() && !render_3d_in_big_window) ||
  1109.                 (selected_gadget == LargeViewBox.get() && render_3d_in_big_window))
  1110.                 switch (event.type)
  1111.                 {
  1112.                         case EVENT_MOUSE_BUTTON_UP:
  1113.                         case EVENT_MOUSE_BUTTON_DOWN:
  1114.                                 break;
  1115.                         case EVENT_MOUSE_MOVED:
  1116.                                 if (!keyd_pressed[ KEY_LCTRL ] && !keyd_pressed[ KEY_RCTRL ])
  1117.                                         break;
  1118.                                 DXX_BOOST_FALLTHROUGH;
  1119.                         case EVENT_JOYSTICK_BUTTON_UP:
  1120.                         case EVENT_JOYSTICK_BUTTON_DOWN:
  1121.                         case EVENT_JOYSTICK_MOVED:
  1122.                         case EVENT_KEY_COMMAND:
  1123.                         case EVENT_KEY_RELEASE:
  1124.                         case EVENT_IDLE:
  1125.                                 kconfig_read_controls(Controls, event, 1);
  1126.  
  1127.                                 if (slew_frame(0))
  1128.                                 {               //do movement and check keys
  1129.                                         Update_flags |= UF_GAME_VIEW_CHANGED;
  1130.                                         if (Gameview_lockstep)
  1131.                                         {
  1132.                                                 Cursegp = imsegptridx(ConsoleObject->segnum);
  1133.                                                 med_create_new_segment_from_cursegp();
  1134.                                                 Update_flags |= UF_ED_STATE_CHANGED;
  1135.                                         }
  1136.  
  1137.                                         rval = window_event_result::handled;
  1138.                                 }
  1139.                                 break;
  1140.                         case EVENT_LOOP_BEGIN_LOOP:
  1141.                                 kconfig_begin_loop(Controls);
  1142.                                 break;
  1143.  
  1144.                         default:
  1145.                                 break;
  1146.                 }
  1147.  
  1148.         //do non-essential stuff in idle event
  1149.         if (event.type == EVENT_IDLE)
  1150.         {
  1151.                 check_wall_validity();
  1152.  
  1153.                 if (Gameview_lockstep) {
  1154.                         static segment *old_cursegp=NULL;
  1155.                         static int old_curside=-1;
  1156.  
  1157.                         if (old_cursegp!=Cursegp || old_curside!=Curside) {
  1158.                                 SetPlayerFromCursegMinusOne();
  1159.                                 old_cursegp = Cursegp;
  1160.                                 old_curside = Curside;
  1161.                         }
  1162.                 }
  1163.  
  1164.                 if ( event_get_idle_seconds() > COMPRESS_INTERVAL )
  1165.                 {
  1166.                         med_compress_mine();
  1167.                         event_reset_idle_seconds();
  1168.                 }
  1169.  
  1170.         //      Commented out because it occupies about 25% of time in twirling the mine.
  1171.         // Removes some Asserts....
  1172.         //              med_check_all_vertices();
  1173.                 clear_editor_status();          // if enough time elapsed, clear editor status message
  1174.         }
  1175.  
  1176.         gr_set_current_canvas( GameViewBox->canvas );
  1177.        
  1178.         // Remove keys used for slew
  1179.         switch(keypress)
  1180.         {
  1181.                 case KEY_PAD9:
  1182.                 case KEY_PAD7:
  1183.                 case KEY_PADPLUS:
  1184.                 case KEY_PADMINUS:
  1185.                 case KEY_PAD8:
  1186.                 case KEY_PAD2:
  1187.                 case KEY_LBRACKET:
  1188.                 case KEY_RBRACKET:
  1189.                 case KEY_PAD1:
  1190.                 case KEY_PAD3:
  1191.                 case KEY_PAD6:
  1192.                 case KEY_PAD4:
  1193.                         keypress = 0;
  1194.         }
  1195.         if ((keypress&0xff)==KEY_LSHIFT) keypress=0;
  1196.         if ((keypress&0xff)==KEY_RSHIFT) keypress=0;
  1197.         if ((keypress&0xff)==KEY_LCTRL) keypress=0;
  1198.         if ((keypress&0xff)==KEY_RCTRL) keypress=0;
  1199.         if ((keypress&0xff)==KEY_LMETA) keypress=0;
  1200.         if ((keypress&0xff)==KEY_RMETA) keypress=0;
  1201. //              if ((keypress&0xff)==KEY_LALT) keypress=0;
  1202. //              if ((keypress&0xff)==KEY_RALT) keypress=0;
  1203.  
  1204.         //=================== DO FUNCTIONS ====================
  1205.  
  1206.         if ( KeyFunction[ keypress ] != NULL )
  1207.         {
  1208.                 KeyFunction[keypress]();
  1209.                 keypress = 0;
  1210.                 rval = window_event_result::handled;
  1211.         }
  1212.  
  1213.         switch (keypress)
  1214.         {
  1215.                 case 0:
  1216.                 case KEY_Z:
  1217.                 case KEY_G:
  1218.                 case KEY_LALT:
  1219.                 case KEY_RALT:
  1220.                 case KEY_LCTRL:
  1221.                 case KEY_RCTRL:
  1222.                 case KEY_LSHIFT:
  1223.                 case KEY_RSHIFT:
  1224.                 case KEY_LAPOSTRO:
  1225.                         break;
  1226.                 case KEY_SHIFTED + KEY_L:
  1227. #if !DXX_USE_OGL
  1228.                         ToggleLighting();
  1229. #endif
  1230.                         rval = window_event_result::handled;
  1231.                         break;
  1232.                 case KEY_F1:
  1233.                         render_3d_in_big_window = !render_3d_in_big_window;
  1234.                         Update_flags |= UF_ALL;
  1235.                         rval = window_event_result::handled;
  1236.                         break;                 
  1237.                 default:
  1238.                         if (rval == window_event_result::ignored)
  1239.                         {
  1240.                                 char kdesc[100];
  1241.                                 GetKeyDescription( kdesc, keypress );
  1242.                                 editor_status_fmt("Error: %s isn't bound to anything.", kdesc  );
  1243.                         }
  1244.         }
  1245.  
  1246.         //================================================================
  1247.  
  1248.         if (ModeFlag)
  1249.         {
  1250.                 return window_event_result::close;
  1251.         }
  1252.  
  1253. //              if (EditorWindow->keyboard_focus_gadget == GameViewBox) current_view=NULL;
  1254. //              if (EditorWindow->keyboard_focus_gadget == GroupViewBox) current_view=NULL;
  1255.  
  1256.         new_cv = current_view;
  1257.  
  1258. #if ORTHO_VIEWS
  1259.         if (EditorWindow->keyboard_focus_gadget == LargeViewBox) new_cv=&LargeView;
  1260.         if (EditorWindow->keyboard_focus_gadget == TopViewBox)  new_cv=&TopView;
  1261.         if (EditorWindow->keyboard_focus_gadget == FrontViewBox) new_cv=&FrontView;
  1262.         if (EditorWindow->keyboard_focus_gadget == RightViewBox) new_cv=&RightView;
  1263. #endif
  1264.         if (new_cv != current_view ) {
  1265.                 current_view->ev_changed = 1;
  1266.                 new_cv->ev_changed = 1;
  1267.                 current_view = new_cv;
  1268.         }
  1269.  
  1270.         // DO TEXTURE STUFF
  1271.         if (texpage_do(event))
  1272.                 rval = window_event_result::handled;
  1273.        
  1274.         if (objpage_do(event))
  1275.                 rval = window_event_result::handled;
  1276.  
  1277.  
  1278.         // Process selection of Cursegp using mouse.
  1279.         if (GADGET_PRESSED(LargeViewBox.get()) && !render_3d_in_big_window)
  1280.         {
  1281.                 int     xcrd,ycrd;
  1282.                 xcrd = LargeViewBox->b1_drag_x1;
  1283.                 ycrd = LargeViewBox->b1_drag_y1;
  1284.  
  1285.                 find_segments(xcrd,ycrd,LargeViewBox->canvas.get(),&LargeView,Cursegp,Big_depth);       // Sets globals N_found_segs, Found_segs
  1286.  
  1287.                 // If shift is down, then add segment to found list
  1288.                 if (keyd_pressed[ KEY_LSHIFT ] || keyd_pressed[ KEY_RSHIFT ])
  1289.                         subtract_found_segments_from_selected_list();
  1290.                 else
  1291.                         add_found_segments_to_selected_list();
  1292.  
  1293.                 Found_seg_index = 0;   
  1294.        
  1295.                 if (!Found_segs.empty())
  1296.                 {
  1297.                         sort_seg_list(Found_segs,ConsoleObject->pos);
  1298.                         Cursegp = imsegptridx(Found_segs[0]);
  1299.                         med_create_new_segment_from_cursegp();
  1300.                         if (Lock_view_to_cursegp)
  1301.                         {
  1302.                                 auto &vcvertptr = Vertices.vcptr;
  1303.                                 set_view_target_from_segment(vcvertptr, Cursegp);
  1304.                         }
  1305.                 }
  1306.  
  1307.                 Update_flags |= UF_ED_STATE_CHANGED | UF_VIEWPOINT_MOVED;
  1308.         }
  1309.  
  1310.         if ((event.type == EVENT_UI_USERBOX_DRAGGED) && (ui_event_get_gadget(event) == GameViewBox.get()))
  1311.         {
  1312.                 int     x, y;
  1313.                 x = GameViewBox->b1_drag_x2;
  1314.                 y = GameViewBox->b1_drag_y2;
  1315.  
  1316.                 gr_set_current_canvas( GameViewBox->canvas );
  1317.                 gr_rect(*grd_curcanv, x-1, y-1, x+1, y+1, 15);
  1318.         }
  1319.        
  1320.         // Set current segment and side by clicking on a polygon in game window.
  1321.         //      If ctrl pressed, also assign current texture map to that side.
  1322.         //if (GameViewBox->mouse_onme && (GameViewBox->b1_done_dragging || GameViewBox->b1_clicked)) {
  1323.         if ((GADGET_PRESSED(GameViewBox.get()) && !render_3d_in_big_window) ||
  1324.                 (GADGET_PRESSED(LargeViewBox.get()) && render_3d_in_big_window))
  1325.         {
  1326.                 int     xcrd,ycrd;
  1327.                 int side,face,tmap;
  1328.  
  1329.                 if (render_3d_in_big_window) {
  1330.                         xcrd = LargeViewBox->b1_drag_x1;
  1331.                         ycrd = LargeViewBox->b1_drag_y1;
  1332.                 }
  1333.                 else {
  1334.                         xcrd = GameViewBox->b1_drag_x1;
  1335.                         ycrd = GameViewBox->b1_drag_y1;
  1336.                 }
  1337.  
  1338.                 //Int3();
  1339.  
  1340.                 segnum_t seg;
  1341.                 objnum_t obj;
  1342.                 if (find_seg_side_face(xcrd,ycrd,seg,obj,side,face))
  1343.                 {
  1344.  
  1345.                         if (obj != object_none) {                                                       //found an object
  1346.  
  1347.                                 Cur_object_index = obj;
  1348.                                 editor_status_fmt("Object %d selected.",Cur_object_index);
  1349.  
  1350.                                 Update_flags |= UF_ED_STATE_CHANGED;
  1351.                         }
  1352.                         else {
  1353.  
  1354.                                 //      See if either shift key is down and, if so, assign texture map
  1355.                                 if (keyd_pressed[KEY_LSHIFT] || keyd_pressed[KEY_RSHIFT]) {
  1356.                                         Cursegp = imsegptridx(seg);
  1357.                                         Curside = side;
  1358.                                         AssignTexture();
  1359.                                         med_create_new_segment_from_cursegp();
  1360.                                         editor_status("Texture assigned");
  1361.                                 } else if (keyd_pressed[KEY_G]) {
  1362.                                         tmap = Segments[seg].unique_segment::sides[side].tmap_num;
  1363.                                         texpage_grab_current(tmap);
  1364.                                         editor_status( "Texture grabbed." );
  1365.                                 } else if (keyd_pressed[ KEY_LAPOSTRO] ) {
  1366.                                         move_object_to_mouse_click();
  1367.                                 } else {
  1368.                                         Cursegp = imsegptridx(seg);
  1369.                                         Curside = side;
  1370.                                         med_create_new_segment_from_cursegp();
  1371.                                         editor_status("Curseg and curside selected");
  1372.                                 }
  1373.                         }
  1374.  
  1375.                         Update_flags |= UF_ED_STATE_CHANGED;
  1376.                 }
  1377.                 else
  1378.                         editor_status("Click on non-texture ingored");
  1379.  
  1380.         }
  1381.  
  1382.         // Allow specification of LargeView using mouse
  1383.         if (event.type == EVENT_MOUSE_MOVED && (keyd_pressed[ KEY_LCTRL ] || keyd_pressed[ KEY_RCTRL ]))
  1384.         {
  1385.                 int dx, dy, dz;
  1386.  
  1387.                 event_mouse_get_delta(event, &dx, &dy, &dz);
  1388.                 if ((dx != 0) && (dy != 0))
  1389.                 {
  1390.                         vms_matrix      MouseRotMat;
  1391.                        
  1392.                         GetMouseRotation( dx, dy, &MouseRotMat );
  1393.                         LargeView.ev_matrix = vm_matrix_x_matrix(LargeView.ev_matrix,MouseRotMat);
  1394.                         LargeView.ev_changed = 1;
  1395.                         Large_view_index = -1;                  // say not one of the orthogonal views
  1396.                         rval = window_event_result::handled;
  1397.                 }
  1398.         }
  1399.  
  1400.         if (event.type == EVENT_MOUSE_MOVED)
  1401.         {
  1402.                 int dx, dy, dz;
  1403.  
  1404.                 event_mouse_get_delta(event, &dx, &dy, &dz);
  1405.                 if (dz != 0)
  1406.                 {
  1407.                         current_view->ev_dist += dz*10000;
  1408.                         current_view->ev_changed = 1;
  1409.                 }
  1410.         }
  1411.        
  1412.         return rval;
  1413. }
  1414.