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