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  * Print debugging info in ui.
23  *
24  */
25 
26 #include <cinttypes>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include "inferno.h"
32 #include "window.h"
33 #include "segment.h"
34 #include "event.h"
35 #include "gr.h"
36 #include "ui.h"
37 #include "editor.h"
38 #include "editor/esegment.h"
39 #include "dxxerror.h"
40 #include "textures.h"
41 #include "object.h"
42 #include "wall.h"
43 #include "switch.h"
44 #include "info.h"
45 #include "d_levelstate.h"
46 
47 int init_info;
48 
49 namespace dcx {
50 
51 namespace {
52 
53 typedef const char object_type_name[13];
54 typedef const char control_type_name[15];
55 typedef const char movement_type_name[15];
56 typedef const char ai_type_name[13];
57 
get_object_type(int num)58 static object_type_name &get_object_type(int num)
59 {
60 	switch (num) {
61 		case OBJ_NONE:
62 			return "OBJ_NONE    ";
63 		case OBJ_WALL:
64 			return "OBJ_WALL    ";
65 		case OBJ_FIREBALL:
66 			return "OBJ_FIREBALL";
67 		case OBJ_ROBOT:
68 			return "OBJ_ROBOT   ";
69 		case OBJ_HOSTAGE:
70 			return "OBJ_HOSTAGE ";
71 		case OBJ_PLAYER:
72 			return "OBJ_PLAYER  ";
73 		case OBJ_WEAPON:
74 			return "OBJ_WEAPON  ";
75 		case OBJ_CAMERA:
76 			return "OBJ_CAMERA  ";
77 		case OBJ_POWERUP:
78 			return "OBJ_POWERUP ";
79 		default:
80 			return " (unknown)  ";
81 	}
82 }
83 
get_control_type(const typename object_base::control_type num)84 static control_type_name &get_control_type(const typename object_base::control_type num)
85 {
86 	switch (num) {
87 		case object::control_type::None:
88 			return "CT_NONE       ";
89 		case object::control_type::ai:
90 			return "CT_AI         ";
91 		case object::control_type::explosion:
92 			return "CT_EXPLOSION  ";
93 		case object::control_type::flying:
94 			return "CT_FLYING     ";
95 		case object::control_type::slew:
96 			return "CT_SLEW       ";
97 		case object::control_type::flythrough:
98 			return "CT_FLYTHROUGH ";
99 		case object::control_type::weapon:
100 			return "CT_WEAPON     ";
101 		default:
102 			return " (unknown)    ";
103 	}
104 }
105 
get_movement_type(const typename object_base::movement_type num)106 static movement_type_name &get_movement_type(const typename object_base::movement_type num)
107 {
108 	switch (num) {
109 		case object::movement_type::None:
110 			return "MT_NONE       ";
111 		case object::movement_type::physics:
112 			return "MT_PHYSICS    ";
113 		case object::movement_type::spinning:
114 			return "MT_SPINNING   ";
115 		default:
116 			return " (unknown)    ";
117 	}
118 }
119 
info_display_object_placement(grs_canvas & canvas,const grs_font & cv_font,const vcobjptridx_t & obj)120 static void info_display_object_placement(grs_canvas &canvas, const grs_font &cv_font, const vcobjptridx_t &obj)
121 {
122 	gr_uprintf(canvas, cv_font, 0, 0, "Object id: %4d\n", obj.get_unchecked_index());
123 	auto &o = *obj;
124 	gr_uprintf(canvas, cv_font, 0, 16, "Type: %s\n", get_object_type(o.type));
125 	gr_uprintf(canvas, cv_font, 0, 32, "Movmnt: %s\n", get_movement_type(o.movement_source));
126 	gr_uprintf(canvas, cv_font, 0, 48, "Cntrl: %s\n", get_control_type(o.control_source));
127 }
128 
129 }
130 
131 }
132 
133 namespace dsx {
134 
135 namespace {
136 
137 struct info_dialog_window : window
138 {
139 	using window::window;
140 	virtual window_event_result event_handler(const d_event &) override;
141 };
142 
get_ai_behavior(ai_behavior num)143 static ai_type_name &get_ai_behavior(ai_behavior num)
144 {
145 	switch (num) {
146 		case ai_behavior::AIB_STILL:
147 			return "STILL       ";
148 		case ai_behavior::AIB_NORMAL:
149 			return "NORMAL      ";
150 #if defined(DXX_BUILD_DESCENT_I)
151 		case ai_behavior::AIB_HIDE:
152 			return "HIDE        ";
153 		case ai_behavior::AIB_FOLLOW_PATH:
154 			return "FOLLOW_PATH ";
155 #elif defined(DXX_BUILD_DESCENT_II)
156 		case ai_behavior::AIB_BEHIND:
157 			return "BEHIND      ";
158 		case ai_behavior::AIB_SNIPE:
159 			return "SNIPE       ";
160 		case ai_behavior::AIB_FOLLOW:
161 			return "FOLLOW      ";
162 #endif
163 		case ai_behavior::AIB_RUN_FROM:
164 			return "RUN_FROM    ";
165 		default:
166 			return " (unknown)  ";
167 	}
168 }
169 
170 //	---------------------------------------------------------------------------------------------------
info_display_object_placement(grs_canvas & canvas,const grs_font & cv_font)171 static void info_display_object_placement(grs_canvas &canvas, const grs_font &cv_font)
172 {
173 	if (Cur_object_index == object_none)
174 	{
175 		gr_ustring(canvas, cv_font, 0, 0, "Object id: None\n");
176 		return;
177 	}
178 	auto &Objects = LevelUniqueObjectState.Objects;
179 	const auto &obj = Objects.vcptridx(Cur_object_index);
180 	gr_uprintf(canvas, cv_font, 0, 64, "Mode: %s\n", get_ai_behavior(obj->ctype.ai_info.behavior));
181 	::dcx::info_display_object_placement(canvas, cv_font, obj);
182 }
183 
184 }
185 
186 }
187 
188 namespace dcx {
189 
190 namespace {
191 
192 //	---------------------------------------------------------------------------------------------------
info_display_segsize(grs_canvas & canvas,const grs_font & cv_font)193 static void info_display_segsize(grs_canvas &canvas, const grs_font &cv_font)
194 {
195 		const char *name;
196 		switch (SegSizeMode) {
197 			case SEGSIZEMODE_FREE:		name = "free   ";	break;
198 			case SEGSIZEMODE_ALL:		name = "all    ";	break;
199 			case SEGSIZEMODE_CURSIDE:	name = "curside";	break;
200 			case SEGSIZEMODE_EDGE:		name = "edge   ";	break;
201 			case SEGSIZEMODE_VERTEX:	name = "vertex ";	break;
202 			default:
203 				throw std::runtime_error("illegal value for SegSizeMode in " __FILE__ "/info_display_segsize");
204 		}
205 	gr_uprintf(canvas, cv_font, 0, 0, "Mode: %s\n", name);
206 }
207 
208 //	------------------------------------------------------------------------------------
clear_pad_display(grs_canvas & canvas)209 static void clear_pad_display(grs_canvas &canvas)
210 {
211 	gr_clear_canvas(canvas, CWHITE);
212 	gr_set_fontcolor(canvas, CBLACK, CWHITE);
213 }
214 
215 }
216 
217 }
218 
219 namespace dsx {
220 
221 namespace {
222 
223 //	---------------------------------------------------------------------------------------------------
info_display_default(grs_canvas & canvas,const grs_font & cv_font)224 static void info_display_default(grs_canvas &canvas, const grs_font &cv_font)
225 {
226 	auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
227 	auto &TmapInfo = LevelUniqueTmapInfoState.TmapInfo;
228 
229 	{
230 		init_info = 0;
231 	}
232 
233 	gr_set_fontcolor(canvas, CBLACK, CWHITE);
234 
235 	//--------------- Number of segments ----------------
236 
237 	gr_uprintf(canvas, cv_font, 0, 0, "Segments: %4d/%4" PRIuFAST32, LevelSharedSegmentState.Num_segments, static_cast<uint_fast32_t>(MAX_SEGMENTS));
238 
239 	//---------------- Number of vertics -----------------
240 
241 	gr_uprintf(canvas, cv_font, 0, 16, "Vertices: %4d/%4" PRIuFAST32, LevelSharedVertexState.Num_vertices, static_cast<uint_fast32_t>(MAX_VERTICES));
242 
243 	//---------------- Number of objects -----------------
244 
245 	{
246 		const auto num_objects = LevelUniqueObjectState.num_objects;
247 		gr_uprintf(canvas, cv_font, 0, 32, "Objs: %3d/%3" DXX_PRI_size_type, num_objects, MAX_OBJECTS.value);
248 	}
249 
250   	//--------------- Current_segment_number -------------
251 	//--------------- Current_side_number -------------
252 
253 	{
254 		gr_uprintf(canvas, cv_font, 0, 48, "Cursegp/side: %3hu/%1d", static_cast<segnum_t>(Cursegp), Curside);
255 		unique_segment &useg = *Cursegp;
256 		auto &uside = useg.sides[Curside];
257 		gr_uprintf(canvas, cv_font, 0, 128, " tmap1,2,o: %3d/%3dx%1u", get_texture_index(uside.tmap_num), get_texture_index(uside.tmap_num2), static_cast<unsigned>(get_texture_rotation_low(uside.tmap_num2)));
258 	}
259 
260 	//--------------- Current_vertex_numbers -------------
261 
262 	{
263 		using U = std::underlying_type<vertnum_t>::type;
264 		gr_uprintf(canvas, cv_font, 0, 64, "{%3u,%3u,%3u,%3u,", static_cast<U>(Cursegp->verts[0]), static_cast<U>(Cursegp->verts[1]), static_cast<U>(Cursegp->verts[2]), static_cast<U>(Cursegp->verts[3]));
265 		gr_uprintf(canvas, cv_font, 0, 80, " %3u,%3u,%3u,%3u}", static_cast<U>(Cursegp->verts[4]), static_cast<U>(Cursegp->verts[5]), static_cast<U>(Cursegp->verts[6]), static_cast<U>(Cursegp->verts[7]));
266 	}
267 
268 	//--------------- Num walls/links/triggers -------------------------
269 
270 	auto &Walls = LevelUniqueWallSubsystemState.Walls;
271 	gr_uprintf(canvas, cv_font, 0, 96, "Walls %3d", Walls.get_count());
272 
273 	//--------------- Num triggers ----------------------
274 
275 	auto &Triggers = LevelUniqueWallSubsystemState.Triggers;
276 	gr_uprintf(canvas, cv_font, 0, 112, "Num_triggers %2d", Triggers.get_count());
277 
278 	//--------------- Current texture number -------------
279 	gr_uprintf(canvas, cv_font, 0, 144, "Tex/Light: %3d %5.2f", CurrentTexture, f2fl(TmapInfo[CurrentTexture].lighting));
280 }
281 
282 //	------------------------------------------------------------------------------------
event_handler(const d_event & event)283 window_event_result info_dialog_window::event_handler(const d_event &event)
284 {
285 	static int old_padnum = -1;
286 	int        padnum;		// always redraw
287 	grs_canvas *save_canvas = grd_curcanv;
288 
289 	switch (event.type)
290 	{
291 		case EVENT_WINDOW_DRAW:
292 		{
293 			gr_set_current_canvas(w_canv);
294 			auto &canvas = *grd_curcanv;
295 
296 			padnum = ui_pad_get_current();
297 			Assert(padnum <= MAX_PAD_ID);
298 
299 			if (padnum != old_padnum) {
300 				old_padnum = padnum;
301 				clear_pad_display(canvas);
302 			}
303 
304 			switch (padnum) {
305 				case OBJECT_PAD_ID:			// Object placement
306 					info_display_object_placement(canvas, *canvas.cv_font);
307 					break;
308 				case SEGSIZE_PAD_ID:			// Segment sizing
309 					info_display_segsize(canvas, *canvas.cv_font);
310 					break;
311 				default:
312 					info_display_default(canvas, *canvas.cv_font);
313 					break;
314 			}
315 			grd_curcanv = save_canvas;
316 			return window_event_result::handled;
317 		}
318 		case EVENT_WINDOW_CLOSE:
319 			Pad_info = NULL;
320 			break;
321 
322 		default:
323 			break;
324 	}
325 	return window_event_result::ignored;
326 }
327 
328 }
329 
330 //	------------------------------------------------------------------------------------
info_window_create(void)331 window *info_window_create(void)
332 {
333 	auto wind = window_create<info_dialog_window>(*Canv_editor, PAD_X + 250, PAD_Y + 8, 180, 160);
334 	wind->set_modal(0);
335 	return wind;
336 }
337 
338 }
339