Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}