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-1999 PARALLAX SOFTWARE CORPORATION. ALL RIGHTS RESERVED. 18 */ 19 20 /* 21 * 22 * Header for editor functions, data strcutures, etc. 23 * 24 */ 25 26 #pragma once 27 28 #include "dxxsconf.h" 29 #include "dsx-ns.h" 30 #include "vecmat.h" 31 #include "ui.h" 32 #include "fmtcheck.h" 33 34 #ifdef __cplusplus 35 #include "fwd-window.h" 36 #include "fwd-segment.h" 37 #include "objnum.h" 38 39 /* 40 * Constants 41 * 42 */ 43 44 #define ED_SCREEN_W 800 //width of editor screen 45 #define ED_SCREEN_H 600 //height of editor screen 46 47 #define MENUBAR_H 16 48 49 #define GAMEVIEW_X 1 //where the 320x200 game window goes 50 #define GAMEVIEW_Y 1+MENUBAR_H 51 #define GAMEVIEW_W 320 52 #define GAMEVIEW_H 200 53 54 #define STATUS_X 0 55 #define STATUS_H 18 56 #define STATUS_Y (ED_SCREEN_H-STATUS_H) 57 #define STATUS_W ED_SCREEN_W 58 59 #define LVIEW_X 1 //large view 60 #define LVIEW_Y (GAMEVIEW_Y+GAMEVIEW_H+2) 61 #define LVIEW_W 447 62 #define LVIEW_H (STATUS_Y-LVIEW_Y-2) 63 64 #define TMAPBOX_X (LVIEW_X+LVIEW_W+4) //location of first one 65 #define TMAPBOX_Y (LVIEW_Y+2) 66 #define TMAPBOX_W 64 67 #define TMAPBOX_H 64 68 69 #define TMAPCURBOX_X (TMAPBOX_X + 4*(TMAPBOX_W + 3)) 70 #define TMAPCURBOX_Y (TMAPBOX_Y + TMAPBOX_H) 71 72 #define OBJCURBOX_X (TMAPCURBOX_X) 73 #define OBJCURBOX_Y (TMAPCURBOX_Y + 3*(TMAPBOX_H + 2) -40) 74 75 #define PAD_X (GAMEVIEW_X + GAMEVIEW_W + 16) 76 #define PAD_Y (GAMEVIEW_Y + 4) 77 78 #define SMALLVIEW_W 173 //width of small view windows 79 #define SMALLVIEW_H 148 //height of small view windows 80 81 #define TVIEW_X (LVIEW_X+LVIEW_W+2) //top view 82 #define TVIEW_Y LVIEW_Y 83 #define TVIEW_W SMALLVIEW_W 84 #define TVIEW_H SMALLVIEW_H 85 86 #define FVIEW_X TVIEW_X //front view 87 #define FVIEW_Y (TVIEW_Y+SMALLVIEW_H+2) 88 #define FVIEW_W SMALLVIEW_W 89 #define FVIEW_H SMALLVIEW_H 90 91 #define RVIEW_X (TVIEW_X+SMALLVIEW_W+2) //right view 92 #define RVIEW_Y FVIEW_Y 93 #define RVIEW_W SMALLVIEW_W 94 #define RVIEW_H SMALLVIEW_H 95 96 #define GVIEW_X RVIEW_X //group view 97 #define GVIEW_Y TVIEW_Y 98 #define GVIEW_W SMALLVIEW_W 99 #define GVIEW_H SMALLVIEW_H 100 101 //there were color constants here, but I moved them to meddraw.c - Matt 102 103 #define SEGMOVE_PAD_ID 0 104 #define SEGSIZE_PAD_ID 1 105 #define CURVE_PAD_ID 2 106 #define TEXTURE_PAD_ID 3 107 #define OBJECT_PAD_ID 4 108 #define OBJMOV_PAD_ID 5 109 #define GROUP_PAD_ID 6 110 #define LIGHTING_PAD_ID 7 111 #define TEST_PAD_ID 8 112 #define MAX_PAD_ID 8 113 114 /* 115 * Strucures 116 * 117 */ 118 119 #define VF_ANGLES 0 120 #define VF_MATRIX 1 121 122 // Default size of a segment 123 #define DEFAULT_X_SIZE F1_0*20 124 #define DEFAULT_Y_SIZE F1_0*20 125 #define DEFAULT_Z_SIZE F1_0*20 126 127 // Scale factor from 3d units (integer portion) to uv coordinates (integer portion) 128 #define VMAG (F1_0 / (DEFAULT_X_SIZE/F1_0)) 129 #define UMAG VMAG // unused 130 131 // Number of segments which can be found (size of Found_segs[]) 132 133 #define MAX_GROUPS 10 134 #define ROT_GROUP MAX_GROUPS 135 136 // Modes for segment sizing 137 #define SEGSIZEMODE_FREE 1 138 #define SEGSIZEMODE_ALL 2 139 #define SEGSIZEMODE_CURSIDE 3 140 #define SEGSIZEMODE_EDGE 4 141 #define SEGSIZEMODE_VERTEX 5 142 143 #define SEGSIZEMODE_MIN SEGSIZEMODE_FREE 144 #define SEGSIZEMODE_MAX SEGSIZEMODE_VERTEX 145 146 //defines a view for an editor window 147 struct editor_view 148 { 149 short ev_num; //each view has it's own number 150 short ev_changed; //set to true if view changed 151 grs_canvas *ev_canv; //points to this window's canvas 152 fix ev_dist; //the distance from the view point 153 vms_matrix ev_matrix; //the view matrix 154 fix ev_zoom; //zoom for this window 155 }; 156 157 enum class editor_gamestate : uint8_t 158 { 159 none, // editing a level, not a gamestate 160 unsaved, // just pressed delete-e from a game 161 saved // saved state. Do we want to restore it when launching editor from menu? Ask user. 162 }; 163 164 /* 165 * Global variables 166 * 167 */ 168 169 extern std::array<editor_view *, 1> Views; 170 extern int Large_view_index; 171 extern std::unique_ptr<UI_GADGET_USERBOX> LargeViewBox, GameViewBox, GroupViewBox; 172 extern int Found_seg_index; // Index in Found_segs corresponding to Cursegp 173 extern editor_gamestate gamestate; 174 extern grs_font_ptr editor_font; 175 176 extern vms_vector Ed_view_target; // what editor is looking at 177 178 extern class window *Pad_info; // Keypad text 179 180 extern int Show_axes_flag; // 0 = don't show, !0 = do show coordinate axes in *Cursegp orientation 181 182 namespace dcx { 183 extern int Autosave_count; // Current counter for which autosave mine we are "on" 184 extern int Autosave_flag; // Whether or not Autosave is on. 185 extern struct tm Editor_time_of_day; 186 187 using mine_filename_type = std::array<char, PATH_MAX>; 188 extern mine_filename_type mine_filename; 189 } 190 191 extern int SegSizeMode; // Mode = 0/1 = not/is legal to move bound vertices, 192 193 #ifdef dsx 194 namespace dsx { 195 void init_editor(void); 196 // Initialize all vertices to inactive status. 197 extern void init_all_vertices(void); 198 } 199 #endif 200 201 void med_combine_duplicate_vertices(enumerated_array<uint8_t, MAX_VERTICES, vertnum_t> &); 202 203 #ifdef dsx 204 namespace dsx { 205 // Attach side newside of newseg to side destside of destseg. 206 // Copies *newseg into global array Segments, increments Num_segments. 207 // Forms a weld between the two segments by making the new segment fit to the old segment. 208 // Updates number of faces per side if necessitated by new vertex coordinates. 209 // Return value: 210 // 0 = successful attach 211 // 1 = No room in Segments[]. 212 // 2 = No room in Vertices[]. 213 int med_attach_segment(vmsegptridx_t destseg, csmusegment newseg, unsigned destside, unsigned newside); 214 215 // Delete a segment. 216 // Deletes a segment from the global array Segments. 217 // Updates Cursegp to be the segment to which the deleted segment was connected. If there is 218 // more than one connected segment, the new Cursegp will be the segment with the highest index 219 // of connection in the deleted segment (highest index = front) 220 // Return value: 221 // 0 = successful deletion 222 // 1 = unable to delete 223 int med_delete_segment(vmsegptridx_t sp); 224 225 // Rotate the segment *seg by the pitch, bank, heading defined by *rot, destructively 226 // modifying its four free vertices in the global array Vertices. 227 // It is illegal to rotate a segment which has MAX_SIDES_PER_SEGMENT != 1. 228 // Pitch, bank, heading are about the point which is the average of the four points 229 // forming the side of connection. 230 // Return value: 231 // 0 = successful rotation 232 // 1 = MAX_SIDES_PER_SEGMENT makes rotation illegal (connected to 0 or 2+ segments) 233 // 2 = Rotation causes degeneracy, such as self-intersecting segment. 234 int med_rotate_segment(vmsegptridx_t seg, const vms_matrix &rotmat); 235 236 // Create a wall which can be removed. 237 // Creates wall at sp->sides[side], making it part of segment sp 238 // Removable walls must be placed between two connected segments. You should add the removable 239 // wall on both sides. In fact, you really must. 240 void create_removable_wall(fvcvertptr &vcvertptr, vmsegptridx_t sp, unsigned side, texture1_value tmap_num); 241 } 242 #endif 243 244 // Saves mine contained in Segments[] and Vertices[]. 245 // Num_segments = number of segments in mine. 246 // Num_vertices = number of vertices in mine. 247 // Cursegp = current segment. 248 // Saves Num_segments, and index of current segment (which is Cursegp - Segments), which will be converted to a pointer 249 // and written to Cursegp in med_load_mine. 250 // Returns: 251 // 0 = successfully saved. 252 // 1 = unable to save. 253 int med_save_mine(const mine_filename_type &name); 254 255 // Updates the screen... (I put the prototype here for curves.c) 256 extern int medlisp_update_screen(); 257 258 // Returns 0 if no error, 1 if error, whatever that might be. 259 // Sets globals: 260 // Num_segments 261 // Num_vertices 262 // Cursegp = pointer to only segment. 263 #ifdef dsx 264 namespace dsx { 265 extern int create_new_mine(void); 266 267 } 268 #endif 269 #ifdef dsx 270 namespace dsx { 271 // Create a segment given center, dimensions, rotation matrix. 272 // Note that the created segment will always have planar sides and rectangular cross sections. 273 // It will be created with walls on all sides, ie not connected to anything. 274 void med_create_segment(vmsegptridx_t sp,fix cx, fix cy, fix cz, fix length, fix width, fix height, const vms_matrix &mp); 275 276 // Create New_segment with sizes found in *scale. 277 void med_create_new_segment(const vms_vector &scale); 278 279 // Create New_segment with sizes found in Cursegp. 280 extern void med_create_new_segment_from_cursegp(void); 281 282 // Create a new segment and use it to form a bridge between two existing segments. 283 // Specify two segment:side pairs. If either segment:side is not open (ie, segment->children[side] != -1) 284 // then it is not legal to form the brider. 285 // Return: 286 // 0 bridge segment formed 287 // 1 unable to form bridge because one (or both) of the sides is not open. 288 // Note that no new vertices are created by this process. 289 int med_form_bridge_segment(vmsegptridx_t seg1, int side1, vmsegptridx_t seg2, int side2); 290 } 291 #endif 292 293 // Compress mine at Segments and Vertices by squeezing out all holes. 294 // If no holes (ie, an unused segment followed by a used segment), then no action. 295 // If Cursegp or Markedsegp is a segment which gets moved to fill in a hole, then 296 // they are properly updated. 297 extern void med_compress_mine(void); 298 299 void update_matrix_based_on_side(vms_matrix &rotmat,int destside); 300 301 // Curves stuff. 302 303 #define ACCURACY 0.1*F1_0 304 305 struct vms_equation 306 { 307 union { 308 struct {fix x3, x2, x1, x0, y3, y2, y1, y0, z3, z2, z1, z0;} n; 309 std::array<std::array<fix, 4>, 3> xyz; 310 }; 311 }; 312 313 // Q(t) = (2t^3 - 3t^2 + 1) p1 + (-2t^3 + 3t^2) p4 + (t^3 - 2t^2 + t) r1 + (t^3 - t^2 ) r4 314 315 extern vms_vector evaluate_curve(vms_equation *coeffs, int degree, fix t); 316 317 fix curve_dist(vms_equation *coeffs, int degree, fix t0, const vms_vector &p0, fix dist); 318 319 extern void plot_parametric(vms_equation *coeffs, fix min_t, fix max_t, fix del_t); 320 321 // Curve generation routine. 322 // Returns 1 if curve is generated. 323 // Returns 0 if no curve. 324 extern int generate_curve( fix r1scale, fix r4scale ); 325 326 // Deletes existing curve generated in generate_curve(). 327 extern void delete_curve(); 328 329 #ifdef dsx 330 namespace dsx { 331 void med_extract_matrix_from_segment(const shared_segment &sp, vms_matrix &rotmat); 332 333 // Assign default u,v coordinates to all sides of a segment. 334 // This routine should only be used for segments which are not connected to anything else, 335 // ie the segment created at mine creation. 336 void assign_default_uvs_to_segment(vmsegptridx_t segp); 337 void assign_default_uvs_to_side(vmsegptridx_t segp, unsigned side); 338 339 // Create coordinate axes in orientation of specified segment, stores vertices at *vp. 340 void create_coordinate_axes_from_segment(const shared_segment &sp, std::array<vertnum_t, 16> &vertnums); 341 342 // Set Vertex_active to number of occurrences of each vertex. 343 // Set Num_vertices. 344 extern void set_vertex_counts(void); 345 346 // Modify seg2 to share side2 with seg1:side1. This forms a connection between 347 // two segments without creating a new segment. It modifies seg2 by sharing 348 // vertices from seg1. seg1 is not modified. Four vertices from seg2 are 349 // deleted. 350 // If the four vertices forming side2 in seg2 are not free, the joint is not formed. 351 // Return code: 352 // 0 joint formed 353 // 1 unable to form joint because one or more vertices of side2 is not free 354 // 2 unable to form joint because side1 is already used 355 int med_form_joint(vmsegptridx_t seg1, int side1, vmsegptridx_t seg2, int side2); 356 } 357 358 // The current texture... use by saying something=bm_lock_bitmap(CurrentTexture) 359 extern texture_index CurrentTexture; 360 361 namespace dsx { 362 void med_propagate_tmaps_to_segments(vcsegptridx_t base_seg,vmsegptridx_t con_seg, int uv_only_flag); 363 void med_propagate_tmaps_to_back_side(vmsegptridx_t base_seg, int back_side, int uv_only_flag); 364 365 // Find segment adjacent to sp:side. 366 // Adjacent means a segment which shares all four vertices. 367 // Return true if segment found and fill in segment in adj_sp and side in adj_side. 368 // Return false if unable to find, in which case adj_sp and adj_side are undefined. 369 int med_find_adjacent_segment_side(vmsegptridx_t sp, int side, imsegptridx_t &adj_sp, int *adj_side); 370 371 // Finds the closest segment and side to sp:side. 372 int med_find_closest_threshold_segment_side(vmsegptridx_t sp, int side, imsegptridx_t &adj_sp, int *adj_side, fix threshold); 373 374 // Select previous segment. 375 // If there is a connection on the side opposite to the current side, then choose that segment. 376 // If there is no connecting segment on the opposite face, try any segment. 377 378 // Select next segment. 379 // If there is a connection on the current side, then choose that segment. 380 // If there is no connecting segment on the current side, try any segment. 381 382 // Copy texture maps in newseg to nsp. 383 void copy_uvs_seg_to_seg(unique_segment &destseg, const unique_segment &srcseg); 384 385 // Return true if segment is concave. 386 387 // Return N_found_segs = number of concave segments in mine. 388 // Segment ids stored at Found_segs 389 extern void find_concave_segs(void); 390 391 // High level call. Check for concave segments, print warning message (using editor_status) 392 // if any concave segments. 393 // Calls find_concave_segs, therefore N_found_segs gets set, and Found_segs filled in. 394 extern void warn_if_concave_segments(void); 395 396 // Warn if segment s is concave. 397 void warn_if_concave_segment(vmsegptridx_t s); 398 } 399 400 // Add a vertex to the vertex list. 401 vertnum_t med_add_vertex(const vertex &vp); 402 403 // Add a vertex to the vertex list which may be identical to another vertex (in terms of coordinates). 404 // Don't scan list, looking for presence of a vertex with same coords, add this one. 405 vertnum_t med_create_duplicate_vertex(const vertex &vp); 406 407 namespace dsx { 408 // Create a new segment, duplicating exactly, including vertex ids and children, the passed segment. 409 segnum_t med_create_duplicate_segment(segment_array &, const segment &sp); 410 411 // Returns the index of a free segment. 412 // Scans the Segments array. 413 segnum_t get_free_segment_number(segment_array &); 414 } 415 #endif 416 417 // Diagnostic message. 418 #define diagnostic_message editor_status 419 #define diagnostic_message_fmt editor_status_fmt 420 421 // Editor status message. 422 extern void editor_status_fmt(const char *format, ... ) __attribute_format_printf(1, 2); 423 #define editor_status_fmt(F,...) dxx_call_printf_checked(editor_status_fmt,editor_status,(),(F),##__VA_ARGS__) 424 425 // Variables in editor.c that the k*.c files need 426 427 #define UF_NONE 0x000 //nothing has changed 428 #define UF_WORLD_CHANGED 0x001 //something added or deleted 429 #define UF_VIEWPOINT_MOVED 0x002 //what we're watching has moved 430 431 #define UF_GAME_VIEW_CHANGED 0x004 //the game window changed 432 #define UF_ED_STATE_CHANGED 0x008 //something like curside,curseg changed 433 434 #define UF_ALL 0xffffffff //all flags 435 436 extern uint Update_flags; 437 extern int Funky_chase_mode; 438 extern vms_angvec Seg_orientation; 439 extern int mine_changed; 440 extern int ModeFlag; 441 extern editor_view *current_view; 442 443 //the view for the different windows 444 extern editor_view LargeView; 445 extern editor_view TopView; 446 extern editor_view FrontView; 447 extern editor_view RightView; 448 449 extern int SafetyCheck(); 450 #ifdef dsx 451 namespace dsx { 452 int save_mine_data_compiled(PHYSFS_File *SaveFile); 453 454 } 455 #endif 456 void editor_status( const char *text); 457 458 extern int MacroNumEvents; 459 extern int MacroStatus; 460 461 //extern int Highest_segment_index; // Highest index in Segments, an efficiency hack 462 extern int Lock_view_to_cursegp; // !0 means whenever cursegp changes, view it 463 464 // eglobal.c 465 extern int Num_tilings; // number of tilings/wall 466 extern int Degenerate_segment_found; 467 468 namespace dcx { 469 470 #ifdef dsx 471 // Returns true if vertex vi is contained in exactly one segment, else returns false. 472 int is_free_vertex(const fvcsegptr &vcsegptr, vertnum_t vi); 473 #endif 474 475 // Initializes autosave system. 476 // Sets global Autosave_count to 0. 477 extern void init_autosave(void); 478 479 // Closes autosave system. 480 // Deletes all autosaved files. 481 extern void close_autosave(void); 482 483 // Saves current mine to name.miX where name = suffix of mine name and X = Autosave_count. 484 // For example, if name = "cookie.min", and Autosave_count = 3, then writes "cookie.mi3". 485 // Increments Autosave_count, wrapping from 9 to 0. 486 // (If there is no current mine name, assume "temp.min") 487 // Call med_save_mine to save the mine. 488 void autosave_mine(const std::array<char, PATH_MAX> &name); 489 490 // Timed autosave 491 void TimedAutosave(const std::array<char, PATH_MAX> &name); 492 extern void set_editor_time_of_day(); 493 494 // Undo function 495 extern int undo(void); 496 extern std::array<const char *, 10> undo_status; 497 498 } 499 500 // group.c 501 int RotateSegmentNew(vms_angvec *pbh); 502 int rotate_segment_new(const vms_angvec &pbh); 503 504 // The current object type and id declared in eglobal.c 505 extern short Cur_object_type; 506 extern short Cur_object_id; 507 508 // From med.c 509 extern int DisplayCurrentRobotType(void); 510 extern objnum_t Cur_object_index; 511 512 extern int render_3d_in_big_window; 513 extern void move_object_to_mouse_click(void); 514 515 //these are instances of canvases, pointed to by variables below 516 extern grs_subcanvas _canv_editor_game; //the game on the editor screen 517 518 //these are pointers to our canvases 519 extern grs_canvas *Canv_editor; //the editor screen 520 extern grs_subcanvas *const Canv_editor_game; //the game on the editor screen 521 522 struct editor_dialog : UI_DIALOG 523 { 524 using UI_DIALOG::UI_DIALOG; 525 std::array<std::unique_ptr<UI_GADGET_BUTTON>, 9> pad_goto; 526 std::unique_ptr<UI_GADGET_BUTTON> 527 pad_prev, 528 pad_next; 529 virtual window_event_result callback_handler(const d_event &) override; 530 }; 531 532 extern editor_dialog *EditorWindow; 533 534 void med_point_2_vec(grs_canvas *canv,vms_vector &v,short sx,short sy); 535 536 //shutdown ui on the editor screen 537 void close_editor_screen(void); 538 539 #ifdef dsx 540 namespace dsx { 541 // From eobject.c 542 int place_object(vmsegptridx_t segp, const vms_vector &object_pos, short object_type, short object_id); 543 544 // from ksegsize.c 545 void med_extract_up_vector_from_segment_side(const shared_segment &sp, int sidenum, vms_vector &vp); 546 void med_extract_right_vector_from_segment_side(const shared_segment &sp, int sidenum, vms_vector &vp); 547 } 548 #endif 549 550 // In medmisc.c 551 extern void draw_world_from_game(void); 552 553 // In medrobot.c 554 extern void close_all_windows(void); 555 556 // In seguvs.c 557 558 // Amount to stretch a texture map by. 559 // The two different ones are for the two dimensions of a texture map. 560 extern fix Stretch_scale_x, Stretch_scale_y; 561 562 #endif 563