1 /*
2  * Copyright (C) Volition, Inc. 1999.  All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 #ifndef _MODEL_H
13 #define _MODEL_H
14 
15 #include "globalincs/globals.h" // for NAME_LENGTH
16 #include "globalincs/pstypes.h"
17 
18 #include "actions/Program.h"
19 #include "gamesnd/gamesnd.h"
20 #include "graphics/2d.h"
21 #include "io/timer.h"
22 #include "model/model_flags.h"
23 #include "object/object.h"
24 #include "ship/ship_flags.h"
25 
26 class object;
27 class ship_info;
28 class model_render_params;
29 
30 extern flag_def_list model_render_flags[];
31 extern int model_render_flags_size;
32 
33 #define MAX_DEBRIS_OBJECTS	32
34 #define MAX_MODEL_DETAIL_LEVELS	8
35 #define MAX_PROP_LEN			256
36 #define MAX_NAME_LEN			32
37 #define MAX_ARC_EFFECTS		8
38 
39 #define MOVEMENT_TYPE_NONE				-1
40 #define MOVEMENT_TYPE_POS				0
41 #define MOVEMENT_TYPE_ROT				1
42 #define MOVEMENT_TYPE_ROT_SPECIAL		2	// for turrets only
43 #define MOVEMENT_TYPE_TRIGGERED			3	// triggered rotation
44 #define MOVEMENT_TYPE_INTRINSIC_ROTATE	4	// intrinsic (non-subsystem-based) rotation
45 
46 
47 // DA 11/13/98 Reordered to account for difference between max and game
48 #define MOVEMENT_AXIS_NONE		-1
49 #define MOVEMENT_AXIS_X			0
50 #define MOVEMENT_AXIS_Y			2
51 #define MOVEMENT_AXIS_Z			1
52 #define MOVEMENT_AXIS_OTHER		3
53 
54 // defines for special objects like gun and missile points, docking point, etc
55 // Hoffoss: Please make sure that subsystem NONE is always index 0, and UNKNOWN is
56 // always the last subsystem in the list.  Also, make sure that MAX is correct.
57 // Otherwise, problems will arise in Fred.
58 
59 #define SUBSYSTEM_NONE				0
60 #define SUBSYSTEM_ENGINE			1
61 #define SUBSYSTEM_TURRET			2
62 #define SUBSYSTEM_RADAR				3
63 #define SUBSYSTEM_NAVIGATION		4
64 #define SUBSYSTEM_COMMUNICATION	5
65 #define SUBSYSTEM_WEAPONS			6
66 #define SUBSYSTEM_SENSORS			7
67 #define SUBSYSTEM_SOLAR				8
68 #define SUBSYSTEM_GAS_COLLECT		9
69 #define SUBSYSTEM_ACTIVATION		10
70 #define SUBSYSTEM_UNKNOWN			11
71 #define SUBSYSTEM_MAX				12				//	maximum value for subsystem_xxx, for error checking
72 
73 // Goober5000
74 extern const char *Subsystem_types[SUBSYSTEM_MAX];
75 
76 #define MAX_TFP						10				// maximum number of turret firing points
77 
78 #define MAX_SPLIT_PLANE				5				// number of artist specified split planes (used in big ship explosions)
79 
80 // Data specific to a particular instance of a submodel.
81 struct submodel_instance
82 {
83 	float	cur_angle = 0.0f;							// The current angle this thing is turned to.
84 	float	prev_angle = 0.0f;
85 	float	turret_idle_angle = 0.0f;				// If this is a turret, this is the expected idling angle of the submodel
86 
87 	float	current_turn_rate = 0.0f;
88 	float	desired_turn_rate = 0.0f;
89 	float	turn_accel = 0.0f;
90 	int		step_zero_timestamp = timestamp();		// timestamp determines when next step is to begin (for stepped rotation)
91 
92 	vec3d	point_on_axis;							// in ship RF
93 	bool	axis_set = false;
94 	bool	blown_off = false;						// If set, this subobject is blown off
95 
96 	bool collision_checked = false;
97 
98 	// These fields are the true standard reference for submodel rotation.  They should seldom be read directly
99 	// and should almost never be written directly.  In most cases, coders should prefer cur_angle and prev_angle.
100 	matrix	canonical_orient = vmd_identity_matrix;
101 	matrix	canonical_prev_orient = vmd_identity_matrix;
102 
103 	// --- these fields used to be in bsp_info ---
104 
105 	// Electrical Arc Effect Info
106 	// Sets a spark for this submodel between vertex v1 and v2
107 	int		num_arcs = 0;											// See model_add_arc for more info
108 	vec3d	arc_pts[MAX_ARC_EFFECTS][2];
109 	ubyte		arc_type[MAX_ARC_EFFECTS];							// see MARC_TYPE_* defines
110 
submodel_instancesubmodel_instance111 	submodel_instance()
112 	{
113 		memset(&arc_pts, 0, MAX_ARC_EFFECTS * 2 * sizeof(vec3d));
114 		memset(&arc_type, 0, MAX_ARC_EFFECTS * sizeof(ubyte));
115 	}
116 };
117 
118 // Data specific to a particular instance of a model.
119 struct polymodel_instance
120 {
121 	int id = -1;							// global model_instance num index
122 	int model_num = -1;						// global model num index, same as polymodel->id
123 	submodel_instance *submodel = nullptr;	// array of submodel instances; mirrors the polymodel->submodel array
124 };
125 
126 #define MAX_MODEL_SUBSYSTEMS		200				// used in ships.cpp (only place?) for local stack variable DTP; bumped to 200
127 													// when reading in ships.tbl
128 
129 // definition of stepped rotation struct
130 typedef struct stepped_rotation {
131 	int num_steps;				// number of steps in complete revolution
132 	float fraction;			// fraction of time in step spent in accel
133 	float t_transit;			// time spent moving from one step to next
134 	float t_pause;				// time at rest between steps
135 	float max_turn_rate;		// max turn rate going betweens steps
136 	float max_turn_accel;	// max accel going between steps
137 } stepped_rotation_t;
138 
139 struct queued_animation;
140 
141 // definition for model subsystems.
142 class model_subsystem {					/* contains rotation rate info */
143 public:
144 	flagset<Model::Subsystem_Flags>	flags;	    // See model_flags.h
145     char	name[MAX_NAME_LEN];					// name of the subsystem.  Probably displayed on HUD
146     char	subobj_name[MAX_NAME_LEN];			// Temporary (hopefully) parameter used to match stuff in ships.tbl
147     char	alt_sub_name[NAME_LENGTH];			// Karajorma - Name that overrides name of original
148     char	alt_dmg_sub_name[NAME_LENGTH];		// Name for the damage popup subsystems, allows for translation
149 	int		subobj_num;							// subobject number (from bspgen) -- used to match subobjects of subsystems to these entries; index to polymodel->submodel
150 	int		model_num;							// Which model this is attached to (i.e. the polymodel[] index); same as polymodel->id
151 	int		type;								// type. see SUBSYSTEM_* types above.  A generic type thing
152 	vec3d	pnt;								// center point of this subsystem
153 	float	radius;								// the extent of the subsystem
154 	float	max_subsys_strength;				// maximum hits of this subsystem
155 	int		armor_type_idx;						// Armor type on teh subsystem -C
156 
157 	//	The following items are specific to turrets and will probably be moved to
158 	//	a separate struct so they don't take up space for all subsystem types.
159     char	crewspot[MAX_NAME_LEN];	    		// unique identifying name for this turret -- used to assign AI class and multiplayer people
160 	vec3d	turret_norm;						//	direction this turret faces (i.e. the normal to the turret base, or the center of the field of view)
161 	float	turret_fov;							//	dot of turret_norm:vec_to_enemy > this means can see
162 	float	turret_max_fov;						//  dot of turret_norm:vec_to_enemy <= this means barrels can elevate up to the target
163 	float	turret_base_fov;						//  turret's base's fov
164 	int		turret_num_firing_points;			// number of firing points on this turret
165 	vec3d	turret_firing_point[MAX_TFP];		//	in parent object's reference frame, point from which to fire.
166 	int		turret_gun_sobj;					// Which subobject in this model the firing points are linked to.
167 	float	turret_turning_rate;				// How fast the turret turns. Read from ships.tbl
168 	gamesnd_id	turret_base_rotation_snd;				// Sound to make when the turret moves
169 	float	turret_base_rotation_snd_mult;			// Volume multiplier for the turret sounds
170 	gamesnd_id		turret_gun_rotation_snd;				// Sound to make when the turret moves
171 	float	turret_gun_rotation_snd_mult;			// Volume multiplier for the turret sounds
172 
173 
174 	//Sound stuff
175 	gamesnd_id	alive_snd;		//Sound to make while the subsystem is not-dead
176 	gamesnd_id	dead_snd;		//Sound to make when the subsystem is dead.
177 	gamesnd_id	rotation_snd;	//Sound to make when the subsystem is rotating. (ie turrets)
178 
179 	// engine wash info
180 	struct engine_wash_info		*engine_wash_pointer;					// index into Engine_wash_info
181 
182 	// rotation specific info
183 	float		turn_rate;							// The turning rate of this subobject, if MSS_FLAG_ROTATES is set.
184 	int			weapon_rotation_pbank;				// weapon-controlled rotation - Goober5000
185 	stepped_rotation_t	*stepped_rotation;			// turn rotation struct
186 
187 	// AWACS specific information
188 	float		awacs_intensity;						// awacs intensity of this subsystem
189 	float		awacs_radius;							// radius of effect of the AWACS
190 
191 	int		primary_banks[MAX_SHIP_PRIMARY_BANKS];					// default primary weapons -hoffoss
192 	int		primary_bank_capacity[MAX_SHIP_PRIMARY_BANKS];		// capacity of a bank - Goober5000
193 	int		secondary_banks[MAX_SHIP_SECONDARY_BANKS];				// default secondary weapons -hoffoss
194 	int		secondary_bank_capacity[MAX_SHIP_SECONDARY_BANKS];	// capacity of a bank -hoffoss
195 	int		path_num;								// path index into polymodel .paths array.  -2 if none exists, -1 if not defined
196 
197 	int n_triggers;
198 	queued_animation *triggers;		//all the triggered animations associated with this object
199 
200 	int		turret_reset_delay;
201 
202 	// target priority setting for turrets
203 	int      target_priority[32];
204 	int      num_target_priorities;
205 
206 	float	optimum_range;
207 	float	favor_current_facing;
208 
209 	float	turret_rof_scaler;
210 
211 	//Per-turret ownage settings - SUSHI
212 	int turret_max_bomb_ownage;
213 	int turret_max_target_ownage;
214 
215 	actions::ProgramSet beam_warmdown_program;
216 
217     void reset();
218 
219     model_subsystem();
220 };
221 
222 typedef struct model_special {
223 	struct	model_special *next, *prev;		// for using as a linked list
224 	int		bank;										// used for sequencing gun/missile backs. approach/docking points
225 	int		slot;										// location for gun or missile in this bank
226 	vec3d	pnt;										// point where this special submodel thingy is at
227 	vec3d	norm;										// normal for the special submodel thingy
228 } model_special;
229 
230 // model arc types
231 #define MARC_TYPE_NORMAL					0		// standard freespace 1 blue lightning arcs
232 #define MARC_TYPE_EMP						1		// EMP blast type arcs
233 
234 #define MAX_LIVE_DEBRIS	7
235 
236 typedef struct model_tmap_vert {
237 	ushort vertnum;
238 	ushort normnum;
239 	float u,v;
240 } model_tmap_vert;
241 
242 struct bsp_collision_node {
243 	vec3d min;
244 	vec3d max;
245 
246 	int back;
247 	int front;
248 
249 	int leaf;
250 };
251 
252 struct bsp_collision_leaf {
253 	vec3d plane_pnt;
254 	vec3d plane_norm;
255 	float face_rad;
256 	int vert_start;
257 	ubyte num_verts;
258 	ubyte tmap_num;
259 
260 	int next;
261 };
262 
263 struct bsp_collision_tree {
264 	bsp_collision_node *node_list;
265 	int n_nodes;
266 
267 	bsp_collision_leaf *leaf_list;
268 	int n_leaves;
269 
270 	model_tmap_vert *vert_list;
271 	vec3d *point_list;
272 
273 	int n_verts;
274 	bool used;
275 };
276 
277 class bsp_info
278 {
279 public:
bsp_info()280 	bsp_info()
281 		: can_move(false), bsp_data_size(0), bsp_data(nullptr), collision_tree_index(-1),
282 		rad(0.0f), my_replacement(-1), i_replace(-1), is_live_debris(false), num_live_debris(0),
283 		parent(-1), num_children(0), first_child(-1), next_sibling(-1), num_details(0),
284 		outline_buffer(nullptr), n_verts_outline(0), render_sphere_radius(0.0f), use_render_box(0), use_render_box_offset(false),
285 		use_render_sphere(0), use_render_sphere_offset(false), gun_rotation(false), no_collisions(false),
286 		nocollide_this_only(false), collide_invisible(false), attach_thrusters(false)
287 	{
288 		name[0] = 0;
289 		lod_name[0] = 0;
290 
291 		offset = geometric_center = min = max = render_box_min = render_box_max = render_box_offset = render_sphere_offset = vmd_zero_vector;
292 		frame_of_reference = vmd_identity_matrix;
293 
294 		memset(&bounding_box, 0, 8 * sizeof(vec3d));
295 		memset(&live_debris, 0, MAX_LIVE_DEBRIS * sizeof(int));
296 		memset(&details, 0, MAX_MODEL_DETAIL_LEVELS * sizeof(int));
297 	}
298 
299 	char	name[MAX_NAME_LEN];						// name of the subsystem.  Probably displayed on HUD
300 	int		movement_type = -1;						// -1 if no movement, otherwise rotational or positional movement -- subobjects only
301 	vec3d	movement_axis = vmd_zero_vector;		// which axis this subobject moves or rotates on.
302 	int		movement_axis_id = -1;					// for optimization
303 	bool	can_move;				// If true, the position and/or orientation of this submodel can change due to rotation of itself OR a parent
304 
305 	vec3d	offset;					// 3d offset from parent object
306 	matrix	frame_of_reference;		// used to be called 'orientation' - this is just used for setting the rotation axis and the animation angles
307 
308 	int		bsp_data_size;
309 	ubyte		*bsp_data;
310 
311 	int collision_tree_index;
312 
313 	vec3d	geometric_center;		// geometric center of this subobject.  In the same Frame Of
314 	                              //  Reference as all other vertices in this submodel. (Relative to pivot point)
315 	float		rad;						// radius for each submodel
316 
317 	vec3d	min;						// The min point of this object's geometry
318 	vec3d	max;						// The max point of this object's geometry
319 	vec3d	bounding_box[8];		// calculated fron min/max
320 
321 	int		my_replacement;		// If not -1 this subobject is what should get rendered instead of this one
322 	int		i_replace;				// If this is not -1, then this subobject will replace i_replace when it is damaged
323 
324 	bool	is_live_debris;		// whether current submodel is a live debris model
325 	int		num_live_debris;		// num live debris models assocaiated with a submodel
326 	int		live_debris[MAX_LIVE_DEBRIS];	// array of live debris submodels for a submodel
327 
328 	bool	is_thruster	= false;		// is an engine thruster submodel
329 	bool	is_damaged = false;			// is a submodel that represents a damaged submodel (e.g. a -destroyed version of some other submodel)
330 
331 	// Tree info
332 	int		parent;					// what is parent for each submodel, -1 if none
333 	int		num_children;			// How many children this model has
334 	int		first_child;			// The first_child of this model, -1 if none
335 	int		next_sibling;			// This submodel's next sibling, -1 if none
336 
337 	int		num_details;			// How many submodels are lower detail "mirrors" of this submodel
338 	int		details[MAX_MODEL_DETAIL_LEVELS];		// A list of all the lower detail "mirrors" of this submodel
339 
340 	// buffers used by HT&L
341 	vertex_buffer buffer;
342 	vertex_buffer trans_buffer;
343 
344 	vertex *outline_buffer;
345 	uint n_verts_outline;
346 
347 	vec3d	render_box_min;
348 	vec3d	render_box_max;
349 	vec3d	render_box_offset;
350 	float	render_sphere_radius;
351 	vec3d	render_sphere_offset;
352 	int		use_render_box;			// 0==do nothing, 1==only render this object if you are inside the box, -1==only if you're outside
353 	bool	use_render_box_offset;		// whether an offset has been defined; needed because one can't tell just by looking at render_box_offset
354 	int		use_render_sphere;		// 0==do nothing, 1==only render this object if you are inside the sphere, -1==only if you're outside
355 	bool 	use_render_sphere_offset;// whether an offset has been defined; needed because one can't tell just by looking at render_sphere_offset
356 	bool    do_not_scale_detail_distances{false}; // if set should not scale boxes or spheres based on 'model detail' settings
357 	bool	gun_rotation;			// for animated weapon models
358 	bool	no_collisions;			// for $no_collisions property - kazan
359 	bool	nocollide_this_only;	//SUSHI: Like no_collisions, but not recursive. For the "replacement" collision model scheme.
360 	bool	collide_invisible;		//SUSHI: If set, this submodel should allow collisions for invisible textures. For the "replacement" collision model scheme.
361 	char	lod_name[MAX_NAME_LEN];	//FUBAR:  Name to be used for LOD naming comparison to preserve compatibility with older tables.  Only used on LOD0
362 	bool	attach_thrusters;		//zookeeper: If set and this submodel or any of its parents rotates, also rotates associated thrusters.
363 
364 	float	dumb_turn_rate = 0.0f;		//Bobboau
365 	int		look_at_submodel = -1;		//VA - number of the submodel to be looked at by this submodel (-1 if none)
366 	float	look_at_offset = -1.0f;		//angle in radians that the submodel should be turned from its initial orientation to be considered "looking at" something (-1 if set on first eval)
367 };
368 
369 #define MP_TYPE_UNUSED 0
370 #define MP_TYPE_SUBSYS 1
371 
372 typedef struct mp_vert {
373 	vec3d		pos;				// xyz coordinates of vertex in object's frame of reference
374 	int			nturrets;		// number of turrets guarding this vertex
375 	int			*turret_ids;	// array of indices into ship_subsys linked list (can't index using [] though)
376 	float			radius;			// How far the closest obstruction is from this vertex
377 } mp_vert;
378 
379 typedef struct model_path {
380 	char			name[MAX_NAME_LEN];					// name of the path.  Should be unique
381 	char			parent_name[MAX_NAME_LEN];			// parent name of submodel that path is linked to in POF
382 	int			parent_submodel;
383 	int			nverts;
384 	mp_vert		*verts;
385 	int			goal;			// Which of the verts is the one closest to the goal of this path
386 	int			type;			// What this path takes you to... See MP_TYPE_??? defines above for details
387 	int			value;		// This depends on the type.
388 									// For MP_TYPE_UNUSED, this means nothing.
389 									// For MP_TYPE_SUBSYS, this is the subsystem number this path takes you to.
390 } model_path;
391 
392 // info for gun and missile banks.  Also used for docking points.  There should always
393 // only be two slots for each docking bay
394 
395 struct w_bank
396 {
397 	int		num_slots = 0;
398 	vec3d	*pnt = nullptr;
399 	vec3d	*norm = nullptr;
400 	float   *external_model_angle_offset = nullptr;
401 
~w_bankw_bank402 	~w_bank()
403 	{
404 		delete[] pnt;
405 		delete[] norm;
406 		delete[] external_model_angle_offset;
407 	}
408 };
409 
410 struct glow_point{
411 	vec3d	pnt;
412 	vec3d	norm;
413 	float	radius;
414 };
415 
416 typedef struct thruster_bank {
417 	int		num_points;
418 	glow_point *points;
419 
420 	// Engine wash info
421 	struct engine_wash_info	*wash_info_pointer;		// index into Engine_wash_info
422 	int		obj_num;		// what subsystem number this bank is on; index to ship_info->subsystems
423 	int		submodel_num;	// what submodel number this bank is on; index to polymodel->submodel/polymodel_instance->submodel
424 } thruster_bank;
425 
426 #define PULSE_SIN 1
427 #define PULSE_COS 2
428 #define PULSE_TRI 3
429 #define PULSE_SHIFTTRI 4
430 
431 typedef struct glow_point_bank {  // glow bank structure -Bobboau
432 	int			type;
433 	int			glow_timestamp;
434 	int			on_time;
435 	int			off_time;
436 	int			disp_time;
437 	bool		is_on;
438 	int			submodel_parent;
439 	int			LOD;
440 	int			num_points;
441 	glow_point	*points;
442 	int			glow_bitmap;
443 	int			glow_neb_bitmap;
444 } glow_point_bank;
445 
446 typedef struct glow_point_bank_override {
447 	char		name[33];
448 	int			type;
449 	int			on_time;
450 	int			off_time;
451 	int			disp_time;
452 	int			glow_bitmap;
453 	int			glow_neb_bitmap;
454 	bool		is_on;
455 
456 	bool		type_override;
457 	bool		on_time_override;
458 	bool		off_time_override;
459 	bool		disp_time_override;
460 	bool		glow_bitmap_override;
461 
462 	ubyte		pulse_type;
463 	int			pulse_period;
464 	float		pulse_amplitude;
465 	float		pulse_bias;
466 	float		pulse_exponent;
467 	bool		is_lightsource;
468 	float		radius_multi;
469 	vec3d		light_color;
470 	vec3d		light_mix_color;
471 	bool		lightcone;
472 	float		cone_angle;
473 	float		cone_inner_angle;
474 	vec3d		cone_direction;
475 	bool		dualcone;
476 	bool		rotating;
477 	vec3d		rotation_axis;
478 	float		rotation_speed;
479 
480 	bool		pulse_period_override;
481 } glow_point_bank_override;
482 
483 // defines for docking bay things.  The types are essentially flags since docking bays can probably
484 // be used for multiple things in some cases (i.e. rearming and general docking)
485 //WMC - IMPORTANT, update Dock_type_names array if you add a new one of these
486 extern flag_def_list Dock_type_names[];
487 extern int Num_dock_type_names;
488 
489 #define DOCK_TYPE_CARGO				(1<<0)
490 #define DOCK_TYPE_REARM				(1<<1)
491 #define DOCK_TYPE_GENERIC			(1<<2)
492 
493 #define MAX_DOCK_SLOTS	2
494 
495 typedef struct dock_bay {
496 	int		num_slots;
497 	int		type_flags;					// indicates what this docking bay can be used for (i.e. cargo/rearm, etc)
498 	int		num_spline_paths;			// number of spline paths which lead to this docking bay
499 	int		*splines;					// array of indices into the Spline_path array
500 	char		name[MAX_NAME_LEN];		// name of this docking location
501 	vec3d	pnt[MAX_DOCK_SLOTS];
502 	vec3d	norm[MAX_DOCK_SLOTS];
503 } dock_bay;
504 
505 // struct that holds the indicies into path information associated with a fighter bay on a capital ship
506 // NOTE: Fighter bay paths are identified by the path_name $bayN (where N is numbered from 1).
507 //			Capital ships only have ONE fighter bay on the entire ship
508 // NOTE: MAX_SHIP_BAY_PATHS cannot be bumped higher than 31 without rewriting the arrival/departure flag logic.
509 #define MAX_SHIP_BAY_PATHS		31
510 typedef struct ship_bay {
511 	int	num_paths;							// how many paths are associated with the model's fighter bay
512 	int	path_indexes[MAX_SHIP_BAY_PATHS];	// index into polymodel->paths[] array
513 	int	arrive_flags;	// bitfield, set to 1 when that path number is reserved for an arrival
514 	int	depart_flags;	// bitfield, set to 1 when that path number is reserved for a departure
515 } ship_bay_t;
516 
517 // three structures now used for representing shields.
518 // shield_tri structure stores information concerning each face of the shield.
519 // verts indexes into the verts array in the higher level structure
520 // neighbors indexes into the tris array in the higher level structure
521 typedef struct shield_tri {
522   int used;
523   int verts[3];			// 3 indices into vertex list of the shield.  list found in shield_info struct
524   int neighbors[3];		// indices into array of triangles. neighbor = shares edge.  list found in shield_info struct
525   vec3d norm;				// norm of this triangle
526 } shield_tri;
527 
528 // a list of these shield_vertex structures comprimises the vertex list of the shield.
529 // The verts array in the shield_tri structure points to one of these members
530 typedef struct shield_vertex {
531 	vec3d	pos;
532 	float		u,v;
533 } shield_vertex;
534 
535 // the high level shield structure.  A ship without any shield has nverts and ntris set to 0.
536 // The vertex list and the tris list are used by the shield_tri structure
537 struct shield_info {
538 	int				nverts;
539 	int				ntris;
540 	shield_vertex	*verts;
541 	shield_tri		*tris;
542 
543 	gr_buffer_handle buffer_id;
544 	int buffer_n_verts;
545 	vertex_layout layout;
546 
shield_infoshield_info547 	shield_info() : nverts(0), ntris(0), verts(NULL), tris(NULL), buffer_id(-1), buffer_n_verts(0), layout() {	}
548 };
549 
550 #define BSP_LIGHT_TYPE_WEAPON 1
551 #define BSP_LIGHT_TYPE_THRUSTER 2
552 
553 typedef struct bsp_light {
554 	vec3d			pos;
555 	int				type;		// See BSP_LIGHT_TYPE_?? for values
556 } bsp_light;
557 
558 // model_octant - There are 8 of these per model.  They are a handy way to categorize
559 // a lot of model properties to get some easy 8x optimizations for model stuff.
560 typedef struct model_octant {
561 	vec3d		min, max;				// The bounding box that makes up this octant defined as 2 points.
562 	int			nverts;					// how many vertices are in this octant
563 	vec3d		**verts;					// The vertices in this octant in the high-res hull.  A vertex can only be in one octant.
564 	int			nshield_tris;			// how many shield triangles are in the octant
565 	shield_tri	**shield_tris;			// the shield triangles that make up this octant. A tri could be in multiple octants.
566 } model_octant;
567 
568 #define MAX_EYES	10
569 
570 typedef struct eye {
571 	int		parent;			// parent's subobject number
572 	vec3d	pnt;				// the point for the eye
573 	vec3d	norm;				// direction the eye faces.  Not used with first eye since player orient is used
574 } eye;
575 
576 typedef struct cross_section {
577 	float z;
578 	float radius;
579 } cross_section;
580 
581 #define MAX_MODEL_INSIGNIAS		6
582 #define MAX_INS_FACE_VECS			3
583 #define MAX_INS_VECS					81
584 #define MAX_INS_FACES				128
585 typedef struct insignia {
586 	int detail_level;
587 	int num_faces;
588 	int faces[MAX_INS_FACES][MAX_INS_FACE_VECS];		// indices into the vecs array
589 	float u[MAX_INS_FACES][MAX_INS_FACE_VECS];		// u tex coords on a per-face-per-vertex basis
590 	float v[MAX_INS_FACES][MAX_INS_FACE_VECS];		// v tex coords on a per-face-per-vertex bases
591 	vec3d vecs[MAX_INS_VECS];								// vertex list
592 	vec3d offset;	// global position offset for this insignia
593 	vec3d norm[MAX_INS_VECS]	;					//normal of the insignia-Bobboau
594 } insignia;
595 
596 #define PM_FLAG_ALLOW_TILING			(1<<0)					// Allow texture tiling
597 #define PM_FLAG_AUTOCEN					(1<<1)					// contains autocentering info
598 #define PM_FLAG_TRANS_BUFFER			(1<<2)					// render transparency buffer
599 #define PM_FLAG_BATCHED					(1<<3)					// this model can be batch rendered
600 #define PM_FLAG_HAS_INTRINSIC_ROTATE	(1<<4)					// whether this model has an intrinsic rotation submodel somewhere
601 
602 // Goober5000
603 class texture_info
604 {
605 private:
606 	int original_texture;	// what gets read in from file
607 	int texture;			// what texture you draw with; reset to original_textures by model_set_instance
608 
609 	//WMC - Removed unneeded struct and is_anim to clean this up.
610 	//If num_frames is < 2, it doesn't need to be treated like an animation.
611 	int num_frames;
612 	float total_time;		// in seconds
613 
614 public:
615 	texture_info();
616 	texture_info(int bm_handle);
617 	void clear();
618 
619 	int GetNumFrames();
620 	int GetOriginalTexture();
621 	int GetTexture();
622 	float GetTotalTime();
623 
624 	int LoadTexture(const char *filename, const char *dbg_name = "<UNKNOWN>");
625 
626 	void PageIn();
627 	void PageOut(bool release);
628 
629 	int ResetTexture();
630 	int SetTexture(int n_tex);
631 };
632 
633 #define TM_BASE_TYPE		0		// the standard base map
634 #define TM_GLOW_TYPE		1		// optional glow map
635 #define TM_SPECULAR_TYPE	2		// optional specular map
636 #define TM_NORMAL_TYPE		3		// optional normal map
637 #define TM_HEIGHT_TYPE		4		// optional height map (for parallax mapping)
638 #define TM_MISC_TYPE		5		// optional utility map
639 #define TM_SPEC_GLOSS_TYPE	6		// optional reflectance map (specular and gloss)
640 #define TM_AMBIENT_TYPE		7		// optional ambient occlusion map with ambient occlusion and cavity occlusion factors for red and green channels.
641 #define TM_NUM_TYPES		8		//WMC - Number of texture_info objects in texture_map
642 									//Used by scripting - if you change this, do a search
643 									//to update switch() statement in lua.cpp
644 // taylor
645 //WMC - OOPified
646 class texture_map
647 {
648 public:
649 	texture_info textures[TM_NUM_TYPES];
650 
651 	bool is_ambient;
652 	bool is_transparent;
653 
654 	int FindTexture(int bm_handle);
655 	int FindTexture(const char* name);
656 
657 	void PageIn();
658 	void PageOut(bool release);
659 
660 	void Clear();
661 	void ResetToOriginal();
662 
texture_map()663 	texture_map()
664 		: is_ambient(false), is_transparent(false)
665 	{}
666 };
667 
668 #define MAX_REPLACEMENT_TEXTURES MAX_MODEL_TEXTURES * TM_NUM_TYPES
669 
670 // Goober5000 - since we need something < 0
671 #define REPLACE_WITH_INVISIBLE	-47
672 
673 //used to describe a polygon model
674 // NOTE: Because WMC OOPified the textures, this must now be treated as a class, rather than a struct.
675 //       Additionally, a lot of model initialization and de-initialization is currently done in model_load or model_unload.
676 class polymodel
677 {
678 public:
679 	// initialize to 0 and NULL because previously a memset was used
polymodel()680 	polymodel()
681 		: id(-1), version(0), flags(0), n_detail_levels(0), num_debris_objects(0), n_models(0), num_lights(0), lights(NULL),
682 		n_view_positions(0), rad(0.0f), core_radius(0.0f), n_textures(0), submodel(NULL), n_guns(0), n_missiles(0), n_docks(0),
683 		n_thrusters(0), gun_banks(NULL), missile_banks(NULL), docking_bays(NULL), thrusters(NULL), ship_bay(NULL), shield(),
684 		shield_collision_tree(NULL), sldc_size(0), n_paths(0), paths(NULL), mass(0), num_xc(0), xc(NULL), num_split_plane(0),
685 		num_ins(0), used_this_mission(0), n_glow_point_banks(0), glow_point_banks(nullptr),
686 		vert_source()
687 	{
688 		filename[0] = 0;
689 		mins = maxs = autocenter = center_of_mass = vmd_zero_vector;
690 		moment_of_inertia = vmd_identity_matrix;
691 
692 		memset(&detail, 0, MAX_MODEL_DETAIL_LEVELS * sizeof(int));
693 		memset(&detail_depth, 0, MAX_MODEL_DETAIL_LEVELS * sizeof(float));
694 		memset(&debris_objects, 0, MAX_DEBRIS_OBJECTS * sizeof(int));
695 		memset(&bounding_box, 0, 8 * sizeof(vec3d));
696 		memset(&view_positions, 0, MAX_EYES * sizeof(eye));
697 		memset(&octants, 0, 8 * sizeof(model_octant));
698 		memset(&split_plane, 0, MAX_SPLIT_PLANE * sizeof(float));
699 		memset(&ins, 0, MAX_MODEL_INSIGNIAS * sizeof(insignia));
700 
701 #ifndef NDEBUG
702 		ram_used = 0;
703 		debug_info_size = 0;
704 		debug_info = NULL;
705 #endif
706 	}
707 
708 
709 	int			id;				// what the polygon model number is.  (Index in Polygon_models)
710 	int			version;
711 	char			filename[FILESPEC_LENGTH];
712 
713 	uint			flags;			// 1=allow tiling
714 	int			n_detail_levels;
715 	int			detail[MAX_MODEL_DETAIL_LEVELS];
716 	float			detail_depth[MAX_MODEL_DETAIL_LEVELS];
717 
718 	int			num_debris_objects;
719 	int			debris_objects[MAX_DEBRIS_OBJECTS];
720 
721 	int			n_models;
722 
723 	vec3d		mins,maxs;							//min,max for whole model
724 	vec3d		bounding_box[8];
725 
726 	int			num_lights;							// how many lights there are
727 	bsp_light *	lights;								// array of light info
728 
729 	int			n_view_positions;					// number of viewing positions available on this ship
730 	eye			view_positions[MAX_EYES];		//viewing positions.  Default to {0,0,0}. in location 0
731 
732 	vec3d		autocenter;							// valid only if PM_FLAG_AUTOCEN is set
733 
734 	float			rad;									// The radius of everything in the model; shields, thrusters.
735 	float			core_radius;						// The radius to be used for collision detection in small ship vs big ships.
736 															// This is equal to 1/2 of the smallest dimension of the hull's bounding box.
737 	// texture maps for model
738 	int n_textures;
739 	texture_map	maps[MAX_MODEL_TEXTURES];
740 
741 	bsp_info		*submodel;							// an array of size n_models of submodel info.
742 
743 	// linked lists for special polygon types on this model.  Most ships I think will have most
744 	// of these.  (most ships however, probably won't have approach points).
745 	int			n_guns;								// number of primary gun points (not counting turrets)
746 	int			n_missiles;							// number of secondary missile points (not counting turrets)
747 	int			n_docks;								// number of docking points
748 	int			n_thrusters;						// number of thrusters on this ship.
749 	w_bank		*gun_banks;							// array of gun banks
750 	w_bank		*missile_banks;					// array of missile banks
751 	dock_bay		*docking_bays;						// array of docking point pairs
752 	thruster_bank		*thrusters;							// array of thruster objects -- likely to change in the future
753 	ship_bay_t		*ship_bay;							// contains path indexes for ship bay approach/depart paths
754 
755 	shield_info	shield;								// new shield information
756 	ubyte	*shield_collision_tree;
757 	int		sldc_size;
758 	SCP_vector<vec3d>		shield_points;
759 
760 	int			n_paths;
761 	model_path	*paths;
762 
763 	// physics info
764 	float			mass;
765 	vec3d		center_of_mass;
766 	matrix		moment_of_inertia;
767 
768 	model_octant	octants[8];
769 
770 	int num_xc;				// number of cross sections
771 	cross_section* xc;	// pointer to array of cross sections (used in big ship explosions)
772 
773 	int num_split_plane;	// number of split planes
774 	float split_plane[MAX_SPLIT_PLANE];	// actual split plane z coords (for big ship explosions)
775 
776 	insignia		ins[MAX_MODEL_INSIGNIAS];
777 	int			num_ins;
778 
779 #ifndef NDEBUG
780 	int			ram_used;		// How much RAM this model uses
781 	int			debug_info_size;
782 	char			*debug_info;
783 #endif
784 
785 	int used_this_mission;		// used for page-in system, how many times this model has been loaded per mission - taylor
786 
787 	int n_glow_point_banks;						// number of glow points on this ship. -Bobboau
788 	glow_point_bank *glow_point_banks;			// array of glow objects -Bobboau
789 
790 	indexed_vertex_source vert_source;
791 
792 	vertex_buffer detail_buffers[MAX_MODEL_DETAIL_LEVELS];
793 };
794 
795 // Call once to initialize the model system
796 void model_init();
797 
798 // call to unload a model (works like bm_unload()), "force" SHOULD NEVER BE SET outside of modelread.cpp!!!!
799 void model_unload(int modelnum, int force = 0);
800 
801 // Call to free all existing models
802 void model_free_all();
803 void model_instance_free_all();
804 
805 // Loads a model from disk and returns the model number it loaded into.
806 int model_load(const char *filename, int n_subsystems, model_subsystem *subsystems, int ferror = 1, int duplicate = 0);
807 
808 int model_create_instance(bool is_ship, int model_num);
809 void model_delete_instance(int model_instance_num);
810 
811 // Goober5000
812 void model_load_texture(polymodel *pm, int i, char *file);
813 
814 // Returns a pointer to the polymodel structure for model 'n'
815 polymodel *model_get(int model_num);
816 
817 polymodel_instance* model_get_instance(int model_instance_num);
818 
819 // routine to copy subsystems.  Must be called when subsystems sets are the same -- see ship.cpp
820 void model_copy_subsystems(int n_subsystems, model_subsystem *d_sp, model_subsystem *s_sp);
821 
822 // If MR_FLAG_OUTLINE bit set this color will be used for outlines.
823 // This defaults to black.
824 void model_set_outline_color(int r, int g, int b);
825 
826 // IF MR_LOCK_DETAIL is set, then it will always draw detail level 'n'
827 // This defaults to 0. (0=highest, larger=lower)
828 void model_set_detail_level(int n);
829 
830 // Flags you can pass to model_render
831 #define MR_NORMAL					(0)			// Draw a normal object
832 #define MR_SHOW_OUTLINE				(1<<0)		// Draw the object in outline mode. Color specified by model_set_outline_color
833 #define MR_SKYBOX					(1<<1)		// Draw as a skybox
834 #define MR_DESATURATED				(1<<2)		// Draw model in monochrome using outline color
835 #define MR_STENCIL_WRITE			(1<<3)		// Write stencil buffere where the model was rendered
836 #define MR_STENCIL_READ				(1<<4)		// Only draw pixels of the model where the stencil buffer has the right value (see MR_STENCIL_WRITE)
837 #define MR_SHOW_THRUSTERS			(1<<5)		// Show the engine thrusters. See model_set_thrust for how long it draws.
838 #define MR_NO_COLOR_WRITES			(1<<6)		// Don't write anything to the color buffers (used when setting the stencil buffer)
839 #define MR_NO_POLYS					(1<<7)		// Don't draw the polygons.
840 #define MR_NO_LIGHTING				(1<<8)		// Don't perform any lighting on the model.
841 #define MR_NO_TEXTURING				(1<<9)		// Draw textures as flat-shaded polygons.
842 #define MR_NO_CORRECT				(1<<10)		// Don't to correct texture mapping
843 #define MR_NO_SMOOTHING				(1<<11)		// Don't perform smoothing on vertices.
844 #define MR_IS_ASTEROID				(1<<12)		// When set, treat this as an asteroid.
845 #define MR_IS_MISSILE				(1<<13)		// When set, treat this as a missilie.  No lighting, small thrusters.
846 #define MR_SHOW_OUTLINE_PRESET		(1<<14)		// Draw the object in outline mode. Color assumed to be set already.
847 #define MR_SHOW_INVISIBLE_FACES		(1<<15)		// Show invisible faces as green...
848 #define MR_AUTOCENTER				(1<<16)		// Always use the center of the hull bounding box as the center, instead of the pivot point
849 #define MR_EMPTY_SLOT3				(1<<17)		// draw bay paths
850 #define MR_ALL_XPARENT				(1<<18)		// render it fully transparent
851 #define MR_NO_ZBUFFER				(1<<19)		// switch z-buffering off completely
852 #define MR_NO_CULL					(1<<20)		// don't cull backfacing poly's
853 #define MR_EMPTY_SLOT4				(1<<21)		// force a given texture to always be used
854 #define MR_NO_BATCH					(1<<22)		// don't use submodel batching when rendering
855 #define MR_EDGE_ALPHA				(1<<23)		// makes norms that are faceing away from you render more transparent -Bobboau
856 #define MR_CENTER_ALPHA				(1<<24)		// oposite of above -Bobboau
857 #define MR_NO_FOGGING				(1<<25)		// Don't fog - taylor
858 #define MR_SHOW_OUTLINE_HTL			(1<<26)		// Show outlines (wireframe view) using HTL method
859 #define MR_NO_GLOWMAPS				(1<<27)		// disable rendering of glowmaps - taylor
860 #define MR_FULL_DETAIL				(1<<28)		// render all valid objects, particularly ones that are otherwise in/out of render boxes - taylor
861 #define MR_FORCE_CLAMP				(1<<29)		// force clamp - Hery
862 #define MR_EMPTY_SLOT5				(1<<30)		// Use a animated Shader - Valathil
863 #define MR_ATTACHED_MODEL			(1<<31)		// Used for attached weapon model lodding
864 
865 #define MR_DEBUG_PIVOTS				(1<<0)		// Show the pivot points
866 #define MR_DEBUG_PATHS				(1<<1)		// Show the paths associated with a model
867 #define MR_DEBUG_RADIUS				(1<<2)		// Show the radius around the object
868 #define MR_DEBUG_SHIELDS			(1<<3)		// Show the shield mesh
869 #define MR_DEBUG_BAY_PATHS			(1<<4)		// draw bay paths
870 #define MR_DEBUG_NO_DIFFUSE			(1<<5)
871 #define MR_DEBUG_NO_SPEC			(1<<6)
872 #define MR_DEBUG_NO_NORMAL			(1<<7)
873 #define MR_DEBUG_NO_ENV				(1<<8)
874 #define MR_DEBUG_NO_GLOW			(1<<9)
875 #define MR_DEBUG_NO_HEIGHT			(1<<10)
876 #define MR_DEBUG_NO_AMBIENT			(1<<11)
877 #define MR_DEBUG_NO_MISC			(1<<12)
878 #define MR_DEBUG_NO_REFLECT			(1<<13)
879 
880 //Defines for the render parameter of model_render, model_really_render and model_render_buffers
881 #define MODEL_RENDER_OPAQUE 1
882 #define MODEL_RENDER_TRANS 2
883 #define MODEL_RENDER_ALL 3
884 
885 // Returns the radius of a model
886 float model_get_radius(int modelnum);
887 float submodel_get_radius(int modelnum, int submodelnum);
888 
889 // Returns the core radius (smallest dimension of hull's bounding box, used for collision detection with big ships only)
890 float model_get_core_radius(int modelnum);
891 
892 // Returns zero is x1,y1,x2,y2 are valid
893 // returns 1 for invalid model, 2 for point offscreen.
894 // note that x1,y1,x2,y2 aren't clipped to 2d screen coordinates!
895 // This function looks at the object's bounding box and it's orientation,
896 // so the bounds will change as the object rotates, to give the minimum bouding
897 // rect.
898 extern int model_find_2d_bound_min(int model_num,matrix *orient, vec3d * pos,int *x1, int *y1, int *x2, int *y2);
899 
900 // Returns zero is x1,y1,x2,y2 are valid
901 // returns 1 for invalid model, 2 for point offscreen.
902 // note that x1,y1,x2,y2 aren't clipped to 2d screen coordinates!
903 // This function looks at the object's bounding box and it's orientation,
904 // so the bounds will change as the object rotates, to give the minimum bouding
905 // rect.
906 int submodel_find_2d_bound_min(int model_num,int submodel, matrix *orient, vec3d * pos,int *x1, int *y1, int *x2, int *y2);
907 
908 
909 // Returns zero is x1,y1,x2,y2 are valid
910 // Returns 2 for point offscreen.
911 // note that x1,y1,x2,y2 aren't clipped to 2d screen coordinates!
912 // This function just looks at the radius, and not the orientation, so the
913 // bounding box won't change depending on the obj's orient.
914 int subobj_find_2d_bound(float radius, matrix *orient, vec3d * pos,int *x1, int *y1, int *x2, int *y2);
915 
916 // stats variables
917 #ifndef NDEBUG
918 extern int modelstats_num_polys;
919 extern int modelstats_num_polys_drawn;
920 extern int modelstats_num_verts;
921 extern int modelstats_num_sortnorms;
922 #endif
923 
924 // Tries to move joints so that the turret points to the point dst.
925 extern int model_rotate_gun(object *objp, polymodel *pm, polymodel_instance *pmi, ship_subsys *ss, vec3d *dst, bool reset = false);
926 
927 // Rotates the angle of a submodel.  Use this so the right unlocked axis
928 // gets stuffed.
929 extern void submodel_canonicalize(bsp_info *sm, submodel_instance *smi, bool clamp);
930 extern void submodel_rotate(model_subsystem *psub, submodel_instance *smi);
931 extern void submodel_rotate(bsp_info *sm, submodel_instance *smi);
932 
933 // Rotates the angle of a submodel.  Use this so the right unlocked axis
934 // gets stuffed.  Does this for stepped rotations
935 void submodel_stepped_rotate(model_subsystem *psub, submodel_instance *smi);
936 
937 // Goober5000
938 // For a submodel, return its overall offset from the main model.
939 extern void model_find_submodel_offset(vec3d *outpnt, const polymodel *pm, int sub_model_num);
940 
941 // Given a point (pnt) that is in sub_model_num's frame of
942 // reference, and given the object's orient and position,
943 // return the point in 3-space in outpnt.
944 extern void model_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_num, int submodel_num, const matrix *objorient, const vec3d *objpos);
945 extern void model_instance_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_instance_num, int submodel_num, const matrix *objorient, const vec3d *objpos);
946 extern void model_find_world_point(vec3d *outpnt, vec3d *mpnt, const polymodel *pm, int submodel_num, const matrix *objorient, const vec3d *objpos);
947 extern void model_instance_find_world_point(vec3d *outpnt, vec3d *mpnt, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const matrix *objorient, const vec3d *objpos);
948 
949 // Given a point in the world RF, find the corresponding point in the model RF.
950 // This is special purpose code, specific for model collision.
951 // NOTE - this code ASSUMES submodel is 1 level down from hull (detail[0])
952 void world_find_model_instance_point(vec3d *out, vec3d *world_pt, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const matrix *orient, const vec3d *pos);
953 
954 extern void find_submodel_instance_point(vec3d *outpnt, const polymodel *pm, const polymodel_instance *pmi, int submodel_num);
955 extern void find_submodel_instance_point_normal(vec3d *outpnt, vec3d *outnorm, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const vec3d *submodel_pnt, const vec3d *submodel_norm);
956 extern void find_submodel_instance_point_orient(vec3d *outpnt, matrix *outorient, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const vec3d *submodel_pnt, const matrix *submodel_orient);
957 extern void find_submodel_instance_world_point(vec3d *outpnt, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const matrix *objorient, const vec3d *objpos);
958 
959 // Given a polygon model index, find a list of rotating submodels to be used for collision
960 void model_get_rotating_submodel_list(SCP_vector<int> *submodel_vector, object *objp);
961 
962 // Given a polygon model index, get a list of a model tree starting from that index
963 void model_get_submodel_tree_list(SCP_vector<int> &submodel_vector, polymodel* pm, int mn);
964 
965 // For a rotating submodel, find a point on the axis
966 void model_init_submodel_axis_pt(polymodel *pm, polymodel_instance *pmi, int submodel_num);
967 
968 // Given a direction (pnt) that is in sub_model_num's frame of
969 // reference, and given the object's orient and position,
970 // return the point in 3-space in outpnt.
971 extern void model_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_num, int submodel_num, const matrix *objorient);
972 extern void model_find_world_dir(vec3d *out_dir, const vec3d *in_dir, const polymodel *pm, int submodel_num, const matrix *objorient);
973 extern void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, int model_instance_num, int submodel_num, const matrix *objorient, bool use_submodel_parent = false);
974 extern void model_instance_find_world_dir(vec3d *out_dir, const vec3d *in_dir, const polymodel *pm, const polymodel_instance *pmi, int submodel_num, const matrix *objorient);
975 
976 // Clears all the submodel instances stored in a model to their defaults.
977 extern void model_clear_instance(int model_num);
978 
979 // Sets rotating submodel turn info to that stored in model
980 extern void model_set_submodel_turn_info(submodel_instance *smi, float turn_rate, float turn_accel);
981 
982 // Sets the submodel instance data in a submodel
983 extern void model_set_up_techroom_instance(ship_info *sip, int model_instance_num);
984 
985 void model_update_instance(int model_instance_num, int submodel_num, flagset<Ship::Subsystem_Flags>& flags);
986 void model_update_instance(polymodel *pm, polymodel_instance *pmi, int submodel_num, flagset<Ship::Subsystem_Flags>& flags);
987 
988 // Adds an electrical arcing effect to a submodel
989 void model_instance_clear_arcs(polymodel *pm, polymodel_instance *pmi);
990 void model_instance_add_arc(polymodel *pm, polymodel_instance *pmi, int sub_model_num, vec3d *v1, vec3d *v2, int arc_type);
991 
992 // Gets two random points on the surface of a submodel
993 extern void submodel_get_two_random_points(int model_num, int submodel_num, vec3d *v1, vec3d *v2, vec3d *n1 = NULL, vec3d *n2 = NULL);
994 
995 extern void submodel_get_two_random_points_better(int model_num, int submodel_num, vec3d * v1, vec3d * v2, int seed = -1);
996 
997 // gets the average position of the mesh at a particular z slice, approximately
998 void submodel_get_cross_sectional_avg_pos(int model_num, int submodel_num, float z_slice_pos, vec3d* pos);
999 // generates a random position more or less inside-ish a mesh at a particular z slice
1000 void submodel_get_cross_sectional_random_pos(int model_num, int submodel_num, float z_slice_pos, vec3d* pos);
1001 
1002 // gets the index into the docking_bays array of the specified type of docking point
1003 // Returns the index.  second functions returns the index of the docking bay with
1004 // the specified name
1005 extern int model_find_dock_index(int modelnum, int dock_type, int index_to_start_at = 0);
1006 extern int model_find_dock_name_index(int modelnum, const char* name);
1007 
1008 // returns the actual name of a docking point on a model, needed by Fred.
1009 char *model_get_dock_name(int modelnum, int index);
1010 
1011 // returns number of docking points for a model
1012 int model_get_num_dock_points(int modelnum);
1013 int model_get_dock_index_type(int modelnum, int index);
1014 
1015 // get all the different docking point types on a model
1016 int model_get_dock_types(int modelnum);
1017 
1018 // Goober5000
1019 // returns index in [0, MAX_SHIP_BAY_PATHS)
1020 int model_find_bay_path(int modelnum, char *bay_path_name);
1021 
1022 // Returns number of polygons in a submodel;
1023 int submodel_get_num_polys(int model_num, int submodel_num);
1024 
1025 
1026 // This is the interface to model_check_collision.  Rather than passing all these
1027 // values and returning values in globals, just fill in a temporary variable with
1028 // the input values and call model_check_collision
1029 typedef struct mc_info {
1030 	// Input values
1031 	int		model_instance_num;
1032 	int		model_num;			// What model to check
1033 	int		submodel_num;		// What submodel to check if MC_SUBMODEL is set
1034 	matrix	*orient;				// The orient of the model
1035 	vec3d	*pos;					// The pos of the model in world coordinates
1036 	vec3d	*p0;					// The starting point of the ray (sphere) to check
1037 	vec3d	*p1;					// The ending point of the ray (sphere) to check
1038 	int		flags;				// Flags that the model_collide code looks at.  See MC_??? defines
1039 	float		radius;				// If MC_CHECK_THICK is set, checks a sphere moving with the radius.
1040 	int		lod;				// Which detail level of the submodel to check instead
1041 
1042 	// Return values
1043 	int		num_hits;			// How many collisions were found
1044 	float		hit_dist;			// The distance from p0 to hitpoint
1045 	vec3d	hit_point;			// Where the collision occurred at in hit_submodel's coordinate system
1046 	vec3d	hit_point_world;	// Where the collision occurred at in world coordinates
1047 	int		hit_submodel;		// Which submodel got hit.
1048 	int		hit_bitmap;			// Which texture got hit.  -1 if not a textured poly
1049 	float		hit_u, hit_v;		// Where on hit_bitmap the ray hit.  Invalid if hit_bitmap < 0
1050 	int		shield_hit_tri;	// Which triangle on the shield got hit or -1 if none
1051 	vec3d	hit_normal;			//	Vector normal of polygon of collision.  (This is in submodel RF)
1052 	int		edge_hit;			// Set if an edge got hit.  Only valid if MC_CHECK_THICK is set.
1053 	ubyte		*f_poly;				// pointer to flat poly where we intersected
1054 	ubyte		*t_poly;				// pointer to tmap poly where we intersected
1055 	bsp_collision_leaf *bsp_leaf;
1056 
1057 										// flags can be changed for the case of sphere check finds an edge hit
1058 } mc_info;
1059 
mc_info_init(mc_info * mc)1060 inline void mc_info_init(mc_info *mc)
1061 {
1062 	mc->model_instance_num = -1;
1063 	mc->model_num = -1;
1064 	mc->submodel_num = -1;
1065 	mc->orient = nullptr;
1066 	mc->pos = nullptr;
1067 	mc->p0 = nullptr;
1068 	mc->p1 = nullptr;
1069 	mc->flags = 0;
1070 	mc->lod = 0;
1071 	mc->radius = 0;
1072 	mc->num_hits = 0;
1073 	mc->hit_dist = 0;
1074 	mc->hit_point = vmd_zero_vector;
1075 	mc->hit_point_world = vmd_zero_vector;
1076 	mc->hit_submodel = -1;
1077 	mc->hit_bitmap = -1;
1078 	mc->hit_u = 0; mc->hit_v = 0;
1079 	mc->shield_hit_tri = -1;
1080 	mc->hit_normal = vmd_zero_vector;
1081 	mc->edge_hit = 0;
1082 	mc->f_poly = nullptr;
1083 	mc->t_poly = nullptr;
1084 	mc->bsp_leaf = nullptr;
1085 }
1086 
1087 
1088 //======== MODEL_COLLIDE ============
1089 
1090 //	Model Collision flags, used in model_collide()
1091 #define MC_CHECK_MODEL			(1<<0)			// Check the polygons in the model.
1092 #define MC_CHECK_SHIELD			(1<<1)			//	check for collision against shield, if it exists.
1093 #define MC_ONLY_SPHERE			(1<<2)			// Only check bounding sphere. Not accurate, but fast.
1094 															// NOTE!  This doesn't set hit_point correctly with MC_CHECK_SPHERELINE
1095 #define MC_ONLY_BOUND_BOX		(1<<3)			// Only check bounding boxes.  Pretty accurate and slower than MC_ONLY_SPHERE.
1096 															// Checks the rotatated bounding box of each submodel.
1097 															// NOTE!  This doesn't set hit_point correctly with MC_CHECK_SPHERELINE
1098 #define MC_CHECK_RAY				(1<<4)			// Checks a ray from p0 *through* p1 on to infinity
1099 #define MC_CHECK_SPHERELINE	(1<<5)			// Checks a moving sphere rather than just a ray.  Radius
1100 #define MC_SUBMODEL				(1<<6)			// If this is set, only check the submodel specified in mc->submodel_num. Use with MC_CHECK_MODEL
1101 #define MC_SUBMODEL_INSTANCE	(1<<7)			// Check submodel and its children (of a rotating submodel)
1102 #define MC_CHECK_INVISIBLE_FACES (1<<8)		// Check the invisible faces.
1103 
1104 
1105 /*
1106    Checks to see if a vector from p0 to p0 collides with a model of
1107    type 'model_num' at 'orient' 'pos'.
1108 
1109    Returns the number of polys that were hit.  Zero is none, obviously.
1110   	Return true if a collision with hull (or shield, if MC_CHECK_SHIELD set),
1111 	else return false.
1112 
1113    If it did it one or more, then hitpt is the closest 3d point that the
1114    vector hit.  See the MC_? defines for flag values.
1115 
1116    Model_collide can test a sphere against either (1) shield or (2) model.
1117 
1118    To check a sphere, set the radius of sphere in mc_info structure and
1119    set the flag MC_CHECK_SPHERE.
1120 
1121    Here is a sample for how to use:
1122 
1123 	mc_info mc;
1124 
1125 	mc.model_num = ???;			// Fill in the model to check
1126 	mc.orient = &obj->orient;	// The object's orient
1127 	mc.pos = &obj->pos;			// The object's position
1128 	mc.p0 = &p0;					// Point 1 of ray to check
1129 	mc.p1 = &p1;					// Point 2 of ray to check
1130 	mc.flags = MC_CHECK_MODEL;	// flags
1131 
1132 ** TO COLLIDE AGAINST A LINE SEGMENT
1133 
1134   model_collide(&mc);
1135 	if (mc.num_hits) {
1136 		// We hit submodel mc.hit_submodel on texture mc.hitbitmap,
1137 		// at point mc.hit_point_world, with uv's of mc.hit_u, mc.hit_v.
1138 	}
1139 
1140 ** TO COLLIDE AGAINST A SPHERE
1141 	mc.flags |= MC_CHECK_SPHERELINE;
1142 	mc.radius = radius;
1143 
1144 	model_collide(&mc, radius);
1145 	if (mc.num_hits) {
1146 		// We hit submodel mc.hit_submodel on texture mc.hitbitmap,
1147 		// at point mc.hit_point_world, with uv's of mc.hit_u, mc.hit_v.
1148 		// Check (mc.edge_hit) to see if we hit an edge
1149 	}
1150 */
1151 
1152 int model_collide(mc_info *mc_info_obj);
1153 void model_collide_parse_bsp(bsp_collision_tree *tree, void *model_ptr, int version);
1154 
1155 bsp_collision_tree *model_get_bsp_collision_tree(int tree_index);
1156 void model_remove_bsp_collision_tree(int tree_index);
1157 int model_create_bsp_collision_tree();
1158 
1159 //=========================== MODEL OCTANT STUFF ================================
1160 
1161 //  Models are now divided into 8 octants.    Shields too.
1162 //  This made the collision code faster.   Shield is 4x and ship faces
1163 //  are about 2x faster.
1164 
1165 //  Before, calling model_collide with flags=0 didn't check the shield
1166 //  but did check the model itself.   Setting the shield flags caused
1167 //  the shield to get check along with the ship.
1168 //  Now, you need to explicitly tell the model_collide code to check
1169 //  the model, so you can check the model or shield or both.
1170 
1171 //  If you need to check them both, do it in one call; this saves some
1172 //  time.    If checking the shield is sufficient for determining
1173 //  something   (like if it is under the hud) then use just shield
1174 //  check, it is at least 5x faster than checking the model itself.
1175 
1176 
1177 // Model octant ordering - this is a made up ordering, but it makes sense.
1178 // X Y Z  index description
1179 // - - -  0     left bottom rear
1180 // - - +  1     left bottom front
1181 // - + -  2     left top rear
1182 // - + +  3     left top front
1183 // + - -  4     right bottom rear
1184 // + - +  5     right bottom front
1185 // + + -  6     right top rear
1186 // + + +  7     right top front
1187 
1188 typedef struct mst_info {
1189 	int primary_bitmap;
1190 	int primary_glow_bitmap;
1191 	int secondary_glow_bitmap;
1192 	int tertiary_glow_bitmap;
1193 	int distortion_bitmap;
1194 
1195 	bool use_ab;
1196 	float glow_noise;
1197 	vec3d rotvel;
1198 	vec3d length;
1199 
1200 	float glow_rad_factor;
1201 	float secondary_glow_rad_factor;
1202 	float tertiary_glow_rad_factor;
1203 	float glow_length_factor;
1204 	float distortion_rad_factor;
1205 	float distortion_length_factor;
1206 	bool draw_distortion;
1207 
mst_infomst_info1208 	mst_info() : primary_bitmap(-1), primary_glow_bitmap(-1), secondary_glow_bitmap(-1), tertiary_glow_bitmap(-1), distortion_bitmap(-1),
1209 					use_ab(false), glow_noise(1.0f), rotvel(vmd_zero_vector), length(vmd_zero_vector), glow_rad_factor(1.0f),
1210 					secondary_glow_rad_factor(1.0f), tertiary_glow_rad_factor(1.0f), glow_length_factor(1.0f), distortion_rad_factor(1.0f), distortion_length_factor(1.0f),
1211 					draw_distortion(true)
1212 				{}
1213 } mst_info;
1214 
1215 // scale the engines thrusters by this much
1216 // Only enabled if MR_SHOW_THRUSTERS is on
1217 void model_set_thrust(int model_num = -1, mst_info *mst = NULL);
1218 
1219 
1220 //=======================================================================================
1221 // Finds the closest point on a model to a point in space.  Actually only finds a point
1222 // on the bounding box of the model.
1223 // Given:
1224 //   model_num      Which model
1225 //   submodel_num   Which submodel, -1 for hull
1226 //   orient         Orientation of the model
1227 //   pos            Position of the model
1228 //   eye_pos        Point that you want to find the closest point to
1229 // Returns:
1230 //   distance from eye_pos to closest_point.  0 means eye_pos is
1231 //   on or inside the bounding box.
1232 //   Also fills in outpnt with the actual closest point.
1233 float model_find_closest_point(vec3d *outpnt, int model_num, int submodel_num, const matrix *orient, const vec3d *pos, const vec3d *eye_pos);
1234 
1235 // Like the above, but finds the closest two points to each other.
1236 float model_find_closest_points(vec3d *outpnt1, int model_num1, int submodel_num1, const matrix *orient1, const vec3d *pos1, vec3d *outpnt2, int model_num2, int submodel_num2, const matrix *orient2, const vec3d *pos2);
1237 
1238 // see if the given texture is used by the passed model. 0 if not used, 1 if used, -1 on error
1239 int model_find_texture(int model_num, int bitmap);
1240 
1241 // find closest point on extended bounding box (the bounding box plus all the planes that make it up)
1242 // returns closest distance to extended box
1243 // positive return value means start_point is outside extended box
1244 // displaces closest point an optional amount delta to the outside of the box
1245 // closest_box_point can be NULL.
1246 float get_world_closest_box_point_with_delta(vec3d *closest_box_point, object *box_obj, vec3d *start_point, int *is_inside, float delta);
1247 
1248 // given a newly loaded model, page in all textures
1249 void model_page_in_textures(int modelnum, int ship_info_index = -1);
1250 
1251 // given a model, unload all of its textures
1252 void model_page_out_textures(int model_num, bool release = false);
1253 
1254 void model_do_intrinsic_rotations(int model_instance_num = -1);
1255 
1256 int model_should_render_engine_glow(int objnum, int bank_obj);
1257 
1258 bool model_get_team_color(team_color *clr, const SCP_string &team, const SCP_string &secondaryteam, fix timestamp, int fadetime);
1259 
1260 void moldel_calc_facing_pts( vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w, float z_add, vec3d *Eyeposition );
1261 
1262 void model_render_insignias(polymodel *pm, int detail_level, int bitmap_num);
1263 
1264 void model_draw_debug_points( polymodel *pm, bsp_info * submodel, uint flags );
1265 
1266 void model_render_shields( polymodel * pm, uint flags );
1267 
1268 void model_draw_paths_htl( int model_num, uint flags );
1269 
1270 void model_draw_bay_paths_htl(int model_num);
1271 
1272 bool model_interp_config_buffer(indexed_vertex_source *vert_src, vertex_buffer *vb, bool update_ibuffer_only);
1273 bool model_interp_pack_buffer(indexed_vertex_source *vert_src, vertex_buffer *vb);
1274 void model_interp_submit_buffers(indexed_vertex_source *vert_src, size_t vertex_stride);
1275 void model_allocate_interp_data(int n_verts = 0, int n_norms = 0);
1276 
1277 void glowpoint_init();
1278 SCP_vector<glow_point_bank_override>::iterator get_glowpoint_bank_override_by_name(const char* name);
1279 extern SCP_vector<glow_point_bank_override> glowpoint_bank_overrides;
1280 
1281 #endif // _MODEL_H
1282