Author Topic: Feature request + patch [committed]: allow thrusters to follow a rotating engine  (Read 4284 times)

0 Members and 1 Guest are viewing this topic.

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Feature request + patch [committed]: allow thrusters to follow a rotating engine
While you can currently link thrusters to an engine subsystem (by adding a $engine_subsystem=$myenginesubsys property to the thruster bank in PCS2) so that they'll turn off when that subsystem is destroyed or disabled, the thrusters still won't follow the engine if the engine itself rotates. Therefore, I'd request a way of doing that:

1. By making thrusters automatically follow the rotation of the engine they're linked to, or if that might break backwards compatibility, then...
2. By adding a new thruster property, such as $engine_subsystem_rotate=, which would act exactly like $engine_subsystem= does except that it'd make the thrusters rotate with the engine.

This would finally enable us to make working X-wing S-foils in FotG, and obviously it'd also allow other funky thruster effects.
« Last Edit: November 13, 2011, 04:38:14 am by zookeeper »

 

Offline Trivial Psychic

  • 212
  • Snoop Junkie
Re: Feature request: allow thrusters to follow a rotating engine
I think that there is a way of cheating this, by using the old method of modeled thruster cones.
The Trivial Psychic Strikes Again!

 

Offline Droid803

  • Trusted poster of legit stuff
  • 213
  • /人 ◕ ‿‿ ◕ 人\ Do you want to be a Magical Girl?
    • Skype
    • Steam
Re: Feature request: allow thrusters to follow a rotating engine
Or using glowpoint thrusters :nervous:
(´・ω・`)
=============================================================

 

Offline FUBAR-BDHR

  • Self-Propelled Trouble Magnet
  • 212
  • Master Drunk
    • 165th Beer Drinking Hell Raisers
Re: Feature request: allow thrusters to follow a rotating engine
Thruster cones cannot be attached to any subobject/subsystem and must be attached to detailx or they do not render at all.  So if the ship has multiple engine subsystems they will only turn off when all engines are killed.  They can $dumb_rotate though. 
No-one ever listens to Zathras. Quite mad, they say. It is good that Zathras does not mind. He's even grown to like it. Oh yes. -Zathras

 

Offline chief1983

  • Still lacks a custom title
  • Moderator
  • 212
  • ⬇️⬆️⬅️⬅️🅰➡️⬇️
    • Minecraft
    • Skype
    • Steam
    • Twitter
    • Fate of the Galaxy
Re: Feature request: allow thrusters to follow a rotating engine
We don't need them to go out independently I don't think, just move with the subsystem if it moves.
Fate of the Galaxy - Now Hiring!  Apply within | Diaspora | SCP Home | Collada Importer for PCS2
Karajorma's 'How to report bugs' | Mantis
#freespace | #scp-swc | #diaspora | #SCP | #hard-light on EsperNet

"You may not sell or otherwise commercially exploit the source or things you created based on the source." -- Excerpt from FSO license, for reference

Nuclear1:  Jesus Christ zack you're a little too hamyurger for HLP right now...
iamzack:  i dont have hamynerge i just want ptatoc hips D:
redsniper:  Platonic hips?!
iamzack:  lays

 

Offline Bobboau

  • Just a MODern kinda guy
    Just MODerately cool
    And MODest too
  • 213
Re: Feature request: allow thrusters to follow a rotating engine
I did have this implemented once...

Easiest way for someone to implement it again would be to look at the way glow points do it, the glow points were basically a copy and paste of the thruster code, so it should translate back easily enough. that said, the way glow points are done is not necessarily the best way to do it, I remember when I had this implemented it was after reworking how both of them worked using a rendering buffer (or batcher or whatever the object is that collects a bunch of rendering commands and sorts them by texture and render style). it might also be a good idea to implement a properties flag to disable vectoring on a per thruster basis.
Bobboau, bringing you products that work... in theory
learn to use PCS
creator of the ProXimus Procedural Texture and Effect Generator
My latest build of PCS2, get it while it's hot!
PCS 2.0.3


DEUTERONOMY 22:11
Thou shalt not wear a garment of diverse sorts, [as] of woollen and linen together

 

Offline Nuke

  • Ka-Boom!
  • 212
  • Mutants Worship Me
Re: Feature request: allow thrusters to follow a rotating engine
While you can currently link thrusters to an engine subsystem (by adding a $engine_subsystem=$myenginesubsys property to the thruster bank in PCS2) so that they'll turn off when that subsystem is destroyed or disabled, the thrusters still won't follow the engine if the engine itself rotates. Therefore, I'd request a way of doing that:

1. By making thrusters automatically follow the rotation of the engine they're linked to, or if that might break backwards compatibility, then...
2. By adding a new thruster property, such as $engine_subsystem_rotate=, which would act exactly like $engine_subsystem= does except that it'd make the thrusters rotate with the engine.

This would finally enable us to make working X-wing S-foils in FotG, and obviously it'd also allow other funky thruster effects.

the catch is that those points would need to be in the subobjects frame of reference to work right. this could be done at model load by simply subtracting the parent subobject position from the glowpoint position. then it would just be a matter of applying the parent subobject's orientation to the point's positions and normals, and pass that on to whatever code is used to place the thruster effects.

is there any limit to the size of the thruster's properties string? i mean pcs2 gives you one line but if the size of the sting is of arbitrary length, then it would be very possible to parse multiple lines of text.

such as:
Code: [Select]
$engine_subsystem=$engine \cr\nl
$parent_sobj_number=4 \0

this also would make it possible use a completely different subsystem for the engine that what the thruster points are attatched to. also if this is possible it would be very useful for other thruster related features which would otherwise need a pof rewrite.
« Last Edit: February 05, 2011, 06:47:32 am by Nuke »
I can no longer sit back and allow communist infiltration, communist indoctrination, communist subversion, and the international communist conspiracy to sap and impurify all of our precious bodily fluids.

Nuke's Scripting SVN

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: Feature request: allow thrusters to follow a rotating engine
Here's a patch which allows one to give an engine subobject an $attach_thrusters prop, which makes thrusterpoints associated with it to follow its rotations. I feel the patch is a bit non-trivial so I'm posting it here so more people can take a look at it.

Unfortunately, this won't work in the ship lab: this is, I think, because the ship lab doesn't pass a valid objnum to the rendering functions it calls, thus leading to render_thrusters() receiving a null ship pointer and being unable to find the subsystem info it needs. Fixing this would probably require someone who's more familiar with the ship lab code.

Code: [Select]
Index: model.h
===================================================================
--- model.h (revision 7910)
+++ model.h (working copy)
@@ -324,6 +324,7 @@
  bool collide_invisible; //SUSHI: If set, this submodel should allow collisions for invisible textures. For the "replacement" collision model scheme.
  bool force_turret_normal; //Wanderer: Sets the turret uvec to override any input of for turret normal.
  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
+ bool attach_thrusters; //zookeeper: If set and this is an engine which rotates, rotates thrusters as well.
 
  float dumb_turn_rate;
 
@@ -359,6 +360,7 @@
  bsp_data = NULL;
  rad = 0.f;
  lod_name[ 0 ] = '\0'; 
+ attach_thrusters = false;
 
  /* Compound types */
  memset( live_debris, 0, sizeof( live_debris ) );
@@ -435,7 +437,8 @@
  // Engine wash info
  struct engine_wash_info *wash_info_pointer; // index into Engine_wash_info
 
- int obj_num; // what subsystem number this thruster is on
+ int obj_num; // what subsystem number this thruster is on; index into ship_info->subsystems
+ int submodel_num; // what submodel number this thruster is on; index into polymodel->submodel
 } thruster_bank;
 
 typedef struct glow_point_bank {  // glow bank structure -Bobboau
Index: modelinterp.cpp
===================================================================
--- modelinterp.cpp (revision 7910)
+++ modelinterp.cpp (working copy)
@@ -2204,16 +2204,69 @@
  if ( !model_should_render_engine_glow(objnum, bank->obj_num) )
  continue;
 
+
+ // The following block sets up submodel_matrix so that thrusters can
+ // follow the rotation of their associated engine submodel
+ submodel_instance_info *engine_submodel_instance_info = NULL;
+ ship_subsys *engine_subsys = NULL;
+ matrix submodel_matrix;
+ bool apply_submodel_rotation = false;
+ if ( Objects[objnum].type == OBJ_SHIP && bank->submodel_num >= 0 ) {
+ ship_subsys *ssp;
+ ssp = GET_FIRST(&shipp->subsys_list);
+ while ( ssp != END_OF_LIST( &shipp->subsys_list ) ) {
+ if ( pm->submodel[bank->submodel_num].attach_thrusters && ssp->system_info->subobj_num == bank->submodel_num ) {
+ engine_submodel_instance_info = &ssp->submodel_info_1;
+ engine_subsys = ssp;
+ break;
+ }
+ ssp = GET_NEXT( ssp );
+ }
+
+ if ( engine_submodel_instance_info != NULL && engine_subsys != NULL ) {
+ // Uses the same logic as the glowpoint rotation code in model_render_glow_points
+ angles angs = engine_submodel_instance_info->angs;
+ angs.b = PI2 - angs.b;
+ angs.p = PI2 - angs.p;
+ angs.h = PI2 - angs.h;
+
+ matrix rotation_matrix = pm->submodel[engine_subsys->system_info->subobj_num].orientation;
+ vm_rotate_matrix_by_angles(&rotation_matrix, &angs);
+
+ matrix inv_orientation;
+ vm_copy_transpose_matrix(&inv_orientation, &pm->submodel[engine_subsys->system_info->subobj_num].orientation);
+
+ vm_matrix_x_matrix(&submodel_matrix, &rotation_matrix, &inv_orientation);
+
+ apply_submodel_rotation = true;
+ }
+ }
+
  for (j = 0; j < bank->num_points; j++) {
  Assert( bank->points != NULL );
 
  float d, D;
  vec3d tempv;
  glow_point *gpt = &bank->points[j];
+ vec3d loc_pnt;
+ vec3d loc_norm;
  vec3d world_pnt;
  vec3d world_norm;
+
+ loc_pnt = gpt->pnt;
+ loc_norm = gpt->norm;
 
- vm_vec_unrotate(&world_pnt, &gpt->pnt, orient);
+ if ( apply_submodel_rotation ) {
+ vec3d offset = pm->submodel[engine_subsys->system_info->subobj_num].offset;
+ vm_vec_sub(&loc_pnt, &loc_pnt, &offset);
+ vec3d temp_p = loc_pnt;
+ vec3d temp_n = loc_norm;
+ vm_vec_rotate(&loc_pnt, &temp_p, &submodel_matrix);
+ vm_vec_add2(&loc_pnt, &offset);
+ vm_vec_rotate(&loc_norm, &temp_n, &submodel_matrix);
+ }
+
+ vm_vec_unrotate(&world_pnt, &loc_pnt, orient);
  vm_vec_add2(&world_pnt, pos);
 
  if (shipp) {
@@ -2238,7 +2291,7 @@
 
  vm_vec_sub(&tempv, &View_position, &world_pnt);
  vm_vec_normalize(&tempv);
- vm_vec_unrotate(&world_norm, &gpt->norm, orient);
+ vm_vec_unrotate(&world_norm, &loc_norm, orient);
  D = d = vm_vec_dot(&tempv, &world_norm);
 
  // ADAM: Min throttle draws rad*MIN_SCALE, max uses max.
Index: modelread.cpp
===================================================================
--- modelread.cpp (revision 7910)
+++ modelread.cpp (working copy)
@@ -1310,6 +1310,11 @@
  if ( (p = strstr(props, "$lod0_name")) != NULL)
  get_user_prop_value(p+10, pm->submodel[n].lod_name);
 
+ if (strstr(props, "$attach_thrusters") != NULL )
+ pm->submodel[n].attach_thrusters = true;
+ else
+ pm->submodel[n].attach_thrusters = false;
+
  if ( (p = strstr(props, "$detail_box:")) != NULL ) {
  p += 12;
  while (*p == ' ') p++;
@@ -1810,6 +1815,8 @@
  bank->wash_info_pointer = NULL;
  for (int k=0; k<n_subsystems; k++) {
  if ( !subsystem_stricmp(subsystems[k].subobj_name, engine_subsys_name) ) {
+ bank->submodel_num = subsystems[k].subobj_num;
+
  bank->wash_info_pointer = subsystems[k].engine_wash_pointer;
  if (bank->wash_info_pointer != NULL) {
  table_error = 0;

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: Feature request: allow thrusters to follow a rotating engine
After massive headaches, I've managed to put together a better version of the patch. What this does is allows thrusters to be attached to a rotating submodel attached to a rotating submodel attached to a rotating submodel ..., whereas the previous one didn't manage that.

Also, apparently the submodel doesn't even have to be an engine, although if you do that then you can't have multiple thrusterbank-engine pairs which can be made to go off independently of each other.

There's some room for optimizations here, but I didn't go there just yet. Finally, things like engine wash would need to be given the same treatment, which would probably involve some refactoring of the code and that's another thing I didn't want to go into yet.

Code: [Select]
Index: model.h
===================================================================
--- model.h (revision 7921)
+++ model.h (working copy)
@@ -90,10 +90,11 @@
  bool blown_off;
 } submodel_instance;
 
+// Data specific to a particular instance of a model.
 typedef struct polymodel_instance {
- int model_num;
- int root_submodel_num;
- submodel_instance *submodel;
+ int model_num; // global model num index, same as polymodel->id
+ int root_submodel_num; // unused?
+ submodel_instance *submodel; // array of submodel instances; mirrors the polymodel->submodel array
  //float gun_submodel_rotation;
 } polymodel_instance;
 
@@ -166,8 +167,8 @@
  char subobj_name[MAX_NAME_LEN]; // Temporary (hopefully) parameter used to match stuff in ships.tbl
  char alt_sub_name[NAME_LENGTH]; //Karajorma - Name that overrides name of original
  char alt_dmg_sub_name[NAME_LENGTH];      // Name for the damage popup subsystems, allows for translation
- int subobj_num; // subobject number (from bspgen) -- used to match subobjects of subsystems to these entries
- int model_num; // Which model this is attached to (i.e. the polymodel[] index)
+ int subobj_num; // subobject number (from bspgen) -- used to match subobjects of subsystems to these entries; index to polymodel->submodel
+ int model_num; // Which model this is attached to (i.e. the polymodel[] index); same as polymodel->id
  int type; // type. see SUBSYSTEM_* types above.  A generic type thing
  vec3d pnt; // center point of this subsystem
  float radius; // the extent of the subsystem
@@ -324,6 +325,7 @@
  bool collide_invisible; //SUSHI: If set, this submodel should allow collisions for invisible textures. For the "replacement" collision model scheme.
  bool force_turret_normal; //Wanderer: Sets the turret uvec to override any input of for turret normal.
  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
+ bool attach_thrusters; //zookeeper: If set and this submodel or any of its parents rotates, also rotates associated thrusters.
 
  float dumb_turn_rate;
 
@@ -359,6 +361,7 @@
  bsp_data = NULL;
  rad = 0.f;
  lod_name[ 0 ] = '\0'; 
+ attach_thrusters = false;
 
  /* Compound types */
  memset( live_debris, 0, sizeof( live_debris ) );
@@ -435,7 +438,8 @@
  // Engine wash info
  struct engine_wash_info *wash_info_pointer; // index into Engine_wash_info
 
- int obj_num; // what subsystem number this thruster is on
+ int obj_num; // what subsystem number this thruster is on; index to ship_info->subsystems
+ int submodel_num; // what submodel number this thruster is on; index to polymodel->submodel and polymodel_instance->submodel
 } thruster_bank;
 
 typedef struct glow_point_bank {  // glow bank structure -Bobboau
@@ -870,6 +874,8 @@
 
 void world_find_model_instance_point(vec3d *out, vec3d *world_pt, polymodel *pm, polymodel_instance *pmi, int submodel_num, matrix *orient, vec3d *pos);
 
+extern void find_submodel_instance_point(vec3d *outpnt, vec3d *outnorm, object *ship_obj, int submodel_num, vec3d *submodel_pnt, vec3d *submodel_norm);
+
 // Given a polygon model index, find a list of rotating submodels to be used for collision
 void model_get_rotating_submodel_list(SCP_vector<int> *submodel_vector, object *objp);
 
Index: modelinterp.cpp
===================================================================
--- modelinterp.cpp (revision 7921)
+++ modelinterp.cpp (working copy)
@@ -2210,10 +2210,25 @@
  float d, D;
  vec3d tempv;
  glow_point *gpt = &bank->points[j];
+ vec3d loc_offset = gpt->pnt;
+ vec3d loc_norm = gpt->norm;
  vec3d world_pnt;
  vec3d world_norm;
 
- vm_vec_unrotate(&world_pnt, &gpt->pnt, orient);
+ // If bank is attached to a submodel, account for rotations
+ if ( bank->submodel_num > -1) {
+ vec3d submodel_static_offset;
+
+ // Calculates the offset in the associated submodel's frame of reference
+ model_find_submodel_offset(&submodel_static_offset, Ship_info[shipp->ship_info_index].model_num, bank->submodel_num);
+ vm_vec_sub(&loc_offset, &gpt->pnt, &submodel_static_offset);
+
+ // Gets the final offset in the ship's frame of reference
+ tempv = loc_offset;
+ find_submodel_instance_point(&loc_offset, &loc_norm, &Objects[objnum], bank->submodel_num, &tempv, &loc_norm);
+ }
+
+ vm_vec_unrotate(&world_pnt, &loc_offset, orient);
  vm_vec_add2(&world_pnt, pos);
 
  if (shipp) {
@@ -2238,7 +2253,7 @@
 
  vm_vec_sub(&tempv, &View_position, &world_pnt);
  vm_vec_normalize(&tempv);
- vm_vec_unrotate(&world_norm, &gpt->norm, orient);
+ vm_vec_unrotate(&world_norm, &loc_norm, orient);
  D = d = vm_vec_dot(&tempv, &world_norm);
 
  // ADAM: Min throttle draws rad*MIN_SCALE, max uses max.
Index: modelread.cpp
===================================================================
--- modelread.cpp (revision 7921)
+++ modelread.cpp (working copy)
@@ -1310,6 +1310,11 @@
  if ( (p = strstr(props, "$lod0_name")) != NULL)
  get_user_prop_value(p+10, pm->submodel[n].lod_name);
 
+ if (strstr(props, "$attach_thrusters") != NULL )
+ pm->submodel[n].attach_thrusters = true;
+ else
+ pm->submodel[n].attach_thrusters = false;
+
  if ( (p = strstr(props, "$detail_box:")) != NULL ) {
  p += 12;
  while (*p == ' ') p++;
@@ -1786,7 +1791,8 @@
  if (bank->num_points > 0)
  bank->points = (glow_point *) vm_malloc(sizeof(glow_point) * bank->num_points);
 
- bank ->obj_num = -1;
+ bank->obj_num = -1;
+ bank->submodel_num = -1;
 
  if (pm->version < 2117) {
  bank->wash_info_pointer = NULL;
@@ -1810,6 +1816,8 @@
  bank->wash_info_pointer = NULL;
  for (int k=0; k<n_subsystems; k++) {
  if ( !subsystem_stricmp(subsystems[k].subobj_name, engine_subsys_name) ) {
+ bank->submodel_num = subsystems[k].subobj_num;
+
  bank->wash_info_pointer = subsystems[k].engine_wash_pointer;
  if (bank->wash_info_pointer != NULL) {
  table_error = 0;
@@ -3878,6 +3886,72 @@
  vm_vec_rotate(out, &tempv2, &m);
 }
 
+/**
+ * Finds the current location and rotation of a submodel point, taking into account the
+ * rotations of the submodel and any parent submodels it might have.
+ * 
+ * @param *outpnt Output point
+ * @param *outnorm Output normal
+ * @param *ship_obj Ship object
+ * @param submodel_num The number of the submodel we're interested in
+ * @param *submodel_pnt The point which's current position we want, in the submodel's frame of reference
+ * @param *submodel_norm The normal which's current direction we want, in the ship's frame of reference
+ */
+void find_submodel_instance_point(vec3d *outpnt, vec3d *outnorm, object *ship_obj, int submodel_num, vec3d *submodel_pnt, vec3d *submodel_norm)
+{
+ Assert(ship_obj->type == OBJ_SHIP);
+
+ outnorm = submodel_norm;
+ vm_vec_zero(outpnt);
+ matrix submodel_instance_matrix, rotation_matrix, inv_orientation;
+
+ polymodel_instance *pmi = model_get_instance(Ships[ship_obj->instance].model_instance_num);
+ polymodel *pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);
+
+ int mn = submodel_num;
+ while ( (mn >= 0) && (pm->submodel[mn].parent >= 0) ) {
+ vec3d offset = pm->submodel[mn].offset;
+
+ if ( mn == submodel_num) {
+ vec3d submodel_pnt_offset = *submodel_pnt;
+
+ rotation_matrix = pm->submodel[submodel_num].orientation;
+ vm_rotate_matrix_by_angles(&rotation_matrix, &pmi->submodel[submodel_num].angs);
+
+ vm_copy_transpose_matrix(&inv_orientation, &pm->submodel[submodel_num].orientation);
+
+ vm_matrix_x_matrix(&submodel_instance_matrix, &rotation_matrix, &inv_orientation);
+
+ vec3d tvec = submodel_pnt_offset;
+ vm_vec_unrotate(&submodel_pnt_offset, &tvec, &submodel_instance_matrix);
+
+ vec3d tnorm = *outnorm;
+ vm_vec_unrotate(outnorm, &tnorm, &submodel_instance_matrix);
+
+ vm_vec_add2(&offset, &submodel_pnt_offset);
+ }
+
+ int parent_model_num = pm->submodel[mn].parent;
+
+ rotation_matrix = pm->submodel[parent_model_num].orientation;
+ vm_rotate_matrix_by_angles(&rotation_matrix, &pmi->submodel[parent_model_num].angs);
+
+ vm_copy_transpose_matrix(&inv_orientation, &pm->submodel[parent_model_num].orientation);
+
+ vm_matrix_x_matrix(&submodel_instance_matrix, &rotation_matrix, &inv_orientation);
+
+ vec3d tvec = offset;
+ vm_vec_unrotate(&offset, &tvec, &submodel_instance_matrix);
+
+ vec3d tnorm = *outnorm;
+ vm_vec_unrotate(outnorm, &tnorm, &submodel_instance_matrix);
+
+ vm_vec_add2(outpnt, &offset);
+
+ mn = pm->submodel[mn].parent;
+ }
+}
+
 // Verify rotating submodel has corresponding ship subsystem -- info in which to store rotation angle
 int rotating_submodel_has_ship_subsys(int submodel, ship *shipp)
 {

  

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: Feature request: allow thrusters to follow a rotating engine
And here's what I hope to be the final version; engine wash works correctly and there's no crash in the ship lab anymore.

I also added a few comments to model.h which would have saved quite a bit of my time had they been there before.

It'd be great if someone could optimize find_submodel_instance_point_normal so that it'd give you a single matrix instead of two vec3d's which you'd then use to transform the thrusterpoint location and normal; I think that way it wouldn't need to get called once per every thrusterpoint, but only once per bank. I might be wrong though.

Code: [Select]
Index: gamesequence/gamesequence.cpp
===================================================================
--- gamesequence/gamesequence.cpp (revision 7926)
+++ gamesequence/gamesequence.cpp (working copy)
@@ -433,3 +433,16 @@
 
  return -1;
 }
+
+// If the given state exists in the stack then return the index, -1 if not
+int gameseq_get_state_idx(int state)
+{
+ for(int i = 0; i <= gs_current_stack; i++)
+ {
+ if(gs[i].current_state == state) {
+ return i;
+ }
+ }
+
+ return -1;
+}
Index: gamesequence/gamesequence.h
===================================================================
--- gamesequence/gamesequence.h (revision 7926)
+++ gamesequence/gamesequence.h (working copy)
@@ -193,4 +193,7 @@
 int gameseq_get_event_idx(char *s);
 int gameseq_get_state_idx(char *s);
 
+//zookeeper
+int gameseq_get_state_idx(int state);
+
 #endif /* __GAMESEQUENCE_H__ */
Index: model/model.h
===================================================================
--- model/model.h (revision 7926)
+++ model/model.h (working copy)
@@ -90,10 +90,11 @@
  bool blown_off;
 } submodel_instance;
 
+// Data specific to a particular instance of a model.
 typedef struct polymodel_instance {
- int model_num;
- int root_submodel_num;
- submodel_instance *submodel;
+ int model_num; // global model num index, same as polymodel->id
+ int root_submodel_num; // unused?
+ submodel_instance *submodel; // array of submodel instances; mirrors the polymodel->submodel array
  //float gun_submodel_rotation;
 } polymodel_instance;
 
@@ -166,8 +167,8 @@
  char subobj_name[MAX_NAME_LEN]; // Temporary (hopefully) parameter used to match stuff in ships.tbl
  char alt_sub_name[NAME_LENGTH]; //Karajorma - Name that overrides name of original
  char alt_dmg_sub_name[NAME_LENGTH];      // Name for the damage popup subsystems, allows for translation
- int subobj_num; // subobject number (from bspgen) -- used to match subobjects of subsystems to these entries
- int model_num; // Which model this is attached to (i.e. the polymodel[] index)
+ int subobj_num; // subobject number (from bspgen) -- used to match subobjects of subsystems to these entries; index to polymodel->submodel
+ int model_num; // Which model this is attached to (i.e. the polymodel[] index); same as polymodel->id
  int type; // type. see SUBSYSTEM_* types above.  A generic type thing
  vec3d pnt; // center point of this subsystem
  float radius; // the extent of the subsystem
@@ -324,6 +325,7 @@
  bool collide_invisible; //SUSHI: If set, this submodel should allow collisions for invisible textures. For the "replacement" collision model scheme.
  bool force_turret_normal; //Wanderer: Sets the turret uvec to override any input of for turret normal.
  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
+ bool attach_thrusters; //zookeeper: If set and this submodel or any of its parents rotates, also rotates associated thrusters.
 
  float dumb_turn_rate;
 
@@ -359,6 +361,7 @@
  bsp_data = NULL;
  rad = 0.f;
  lod_name[ 0 ] = '\0'; 
+ attach_thrusters = false;
 
  /* Compound types */
  memset( live_debris, 0, sizeof( live_debris ) );
@@ -435,7 +438,8 @@
  // Engine wash info
  struct engine_wash_info *wash_info_pointer; // index into Engine_wash_info
 
- int obj_num; // what subsystem number this thruster is on
+ int obj_num; // what subsystem number this bank is on; index to ship_info->subsystems
+ int submodel_num; // what submodel number this bank is on; index to polymodel->submodel/polymodel_instance->submodel
 } thruster_bank;
 
 typedef struct glow_point_bank {  // glow bank structure -Bobboau
@@ -870,6 +874,8 @@
 
 void world_find_model_instance_point(vec3d *out, vec3d *world_pt, polymodel *pm, polymodel_instance *pmi, int submodel_num, matrix *orient, vec3d *pos);
 
+extern void find_submodel_instance_point_normal(vec3d *outpnt, vec3d *outnorm, object *ship_obj, int submodel_num, vec3d *submodel_pnt, vec3d *submodel_norm);
+
 // Given a polygon model index, find a list of rotating submodels to be used for collision
 void model_get_rotating_submodel_list(SCP_vector<int> *submodel_vector, object *objp);
 
Index: model/modelinterp.cpp
===================================================================
--- model/modelinterp.cpp (revision 7926)
+++ model/modelinterp.cpp (working copy)
@@ -32,6 +32,7 @@
 #include "parse/parselo.h"
 #include "graphics/gropengllight.h"
 #include "ship/shipfx.h"
+#include "gamesequence/gamesequence.h"
 
 #include <limits.h>
 
@@ -2198,22 +2199,46 @@
  gr_fog_set(GR_FOGMODE_NONE, 0, 0, 0);
 
  for (i = 0; i < pm->n_thrusters; i++ ) {
+ vec3d submodel_static_offset; // The associated submodel's static offset in the ship's frame of reference
+ bool submodel_rotation = false;
+
  bank = &pm->thrusters[i];
 
  // don't draw this thruster if the engine is destroyed or just not on
  if ( !model_should_render_engine_glow(objnum, bank->obj_num) )
  continue;
 
+ // If bank is attached to a submodel, prepare to account for rotations
+ //
+ // TODO: This won't work in the ship lab, because the lab code doesn't
+ // set the the necessary submodel instance info needed here. The second
+ // condition is thus a hack to disable the feature while in the lab, and
+ // can be removed if the lab is re-structured accordingly. -zookeeper
+ if ( bank->submodel_num > -1 && (gameseq_get_state_idx(GS_STATE_LAB) == -1) ) {
+ model_find_submodel_offset(&submodel_static_offset, Ship_info[shipp->ship_info_index].model_num, bank->submodel_num);
+
+ submodel_rotation = true;
+ }
+
  for (j = 0; j < bank->num_points; j++) {
  Assert( bank->points != NULL );
 
  float d, D;
  vec3d tempv;
  glow_point *gpt = &bank->points[j];
+ vec3d loc_offset = gpt->pnt;
+ vec3d loc_norm = gpt->norm;
  vec3d world_pnt;
  vec3d world_norm;
 
- vm_vec_unrotate(&world_pnt, &gpt->pnt, orient);
+ if ( submodel_rotation ) {
+ vm_vec_sub(&loc_offset, &gpt->pnt, &submodel_static_offset);
+
+ tempv = loc_offset;
+ find_submodel_instance_point_normal(&loc_offset, &loc_norm, &Objects[objnum], bank->submodel_num, &tempv, &loc_norm);
+ }
+
+ vm_vec_unrotate(&world_pnt, &loc_offset, orient);
  vm_vec_add2(&world_pnt, pos);
 
  if (shipp) {
@@ -2238,7 +2263,7 @@
 
  vm_vec_sub(&tempv, &View_position, &world_pnt);
  vm_vec_normalize(&tempv);
- vm_vec_unrotate(&world_norm, &gpt->norm, orient);
+ vm_vec_unrotate(&world_norm, &loc_norm, orient);
  D = d = vm_vec_dot(&tempv, &world_norm);
 
  // ADAM: Min throttle draws rad*MIN_SCALE, max uses max.
Index: model/modelread.cpp
===================================================================
--- model/modelread.cpp (revision 7926)
+++ model/modelread.cpp (working copy)
@@ -1310,6 +1310,11 @@
  if ( (p = strstr(props, "$lod0_name")) != NULL)
  get_user_prop_value(p+10, pm->submodel[n].lod_name);
 
+ if (strstr(props, "$attach_thrusters") != NULL )
+ pm->submodel[n].attach_thrusters = true;
+ else
+ pm->submodel[n].attach_thrusters = false;
+
  if ( (p = strstr(props, "$detail_box:")) != NULL ) {
  p += 12;
  while (*p == ' ') p++;
@@ -1786,7 +1791,8 @@
  if (bank->num_points > 0)
  bank->points = (glow_point *) vm_malloc(sizeof(glow_point) * bank->num_points);
 
- bank ->obj_num = -1;
+ bank->obj_num = -1;
+ bank->submodel_num = -1;
 
  if (pm->version < 2117) {
  bank->wash_info_pointer = NULL;
@@ -1810,6 +1816,8 @@
  bank->wash_info_pointer = NULL;
  for (int k=0; k<n_subsystems; k++) {
  if ( !subsystem_stricmp(subsystems[k].subobj_name, engine_subsys_name) ) {
+ bank->submodel_num = subsystems[k].subobj_num;
+
  bank->wash_info_pointer = subsystems[k].engine_wash_pointer;
  if (bank->wash_info_pointer != NULL) {
  table_error = 0;
@@ -3878,6 +3886,72 @@
  vm_vec_rotate(out, &tempv2, &m);
 }
 
+/**
+ * Finds the current location and rotation of a submodel point, taking into account the
+ * rotations of the submodel and any parent submodels it might have.
+ * 
+ * @param *outpnt Output point
+ * @param *outnorm Output normal
+ * @param *ship_obj Ship object
+ * @param submodel_num The number of the submodel we're interested in
+ * @param *submodel_pnt The point which's current position we want, in the submodel's frame of reference
+ * @param *submodel_norm The normal which's current direction we want, in the ship's frame of reference
+ */
+void find_submodel_instance_point_normal(vec3d *outpnt, vec3d *outnorm, object *ship_obj, int submodel_num, vec3d *submodel_pnt, vec3d *submodel_norm)
+{
+ Assert(ship_obj->type == OBJ_SHIP);
+
+ outnorm = submodel_norm;
+ vm_vec_zero(outpnt);
+ matrix submodel_instance_matrix, rotation_matrix, inv_orientation;
+
+ polymodel_instance *pmi = model_get_instance(Ships[ship_obj->instance].model_instance_num);
+ polymodel *pm = model_get(Ship_info[Ships[ship_obj->instance].ship_info_index].model_num);
+
+ int mn = submodel_num;
+ while ( (mn >= 0) && (pm->submodel[mn].parent >= 0) ) {
+ vec3d offset = pm->submodel[mn].offset;
+
+ if ( mn == submodel_num) {
+ vec3d submodel_pnt_offset = *submodel_pnt;
+
+ rotation_matrix = pm->submodel[submodel_num].orientation;
+ vm_rotate_matrix_by_angles(&rotation_matrix, &pmi->submodel[submodel_num].angs);
+
+ vm_copy_transpose_matrix(&inv_orientation, &pm->submodel[submodel_num].orientation);
+
+ vm_matrix_x_matrix(&submodel_instance_matrix, &rotation_matrix, &inv_orientation);
+
+ vec3d tvec = submodel_pnt_offset;
+ vm_vec_unrotate(&submodel_pnt_offset, &tvec, &submodel_instance_matrix);
+
+ vec3d tnorm = *outnorm;
+ vm_vec_unrotate(outnorm, &tnorm, &submodel_instance_matrix);
+
+ vm_vec_add2(&offset, &submodel_pnt_offset);
+ }
+
+ int parent_model_num = pm->submodel[mn].parent;
+
+ rotation_matrix = pm->submodel[parent_model_num].orientation;
+ vm_rotate_matrix_by_angles(&rotation_matrix, &pmi->submodel[parent_model_num].angs);
+
+ vm_copy_transpose_matrix(&inv_orientation, &pm->submodel[parent_model_num].orientation);
+
+ vm_matrix_x_matrix(&submodel_instance_matrix, &rotation_matrix, &inv_orientation);
+
+ vec3d tvec = offset;
+ vm_vec_unrotate(&offset, &tvec, &submodel_instance_matrix);
+
+ vec3d tnorm = *outnorm;
+ vm_vec_unrotate(outnorm, &tnorm, &submodel_instance_matrix);
+
+ vm_vec_add2(outpnt, &offset);
+
+ mn = pm->submodel[mn].parent;
+ }
+}
+
 // Verify rotating submodel has corresponding ship subsystem -- info in which to store rotation angle
 int rotating_submodel_has_ship_subsys(int submodel, ship *shipp)
 {
Index: ship/shipfx.cpp
===================================================================
--- ship/shipfx.cpp (revision 7926)
+++ ship/shipfx.cpp (working copy)
@@ -38,6 +38,7 @@
 #include "parse/scripting.h"
 #include "asteroid/asteroid.h"
 #include "bmpman/bmpman.h"
+#include "model/model.h"
 
 
 
@@ -2697,7 +2698,6 @@
  objp = &Objects[shipp->objnum];
  ship_obj *so;
 
- vec3d world_thruster_pos, world_thruster_norm, apex, thruster_to_ship, apex_to_ship, temp;
  float dist_sqr, inset_depth, dot_to_ship, max_ship_intensity;
  polymodel *pm;
 
@@ -2766,6 +2766,8 @@
 
  for (idx = 0; idx < pm->n_thrusters; idx++) {
  thruster_bank *bank = &pm->thrusters[idx];
+ vec3d submodel_static_offset; // The associated submodel's static offset in the ship's frame of reference
+ bool submodel_rotation = false;
 
  // make sure this engine is functional before we try to process a wash from it
  if ( !model_should_render_engine_glow(OBJ_INDEX(wash_objp), bank->obj_num) ) {
@@ -2787,13 +2789,38 @@
  half_angle = ewp->angle;
  radius_mult = ewp->radius_mult;
 
+
+ // If bank is attached to a submodel, prepare to account for rotations
+ //
+ // TODO: This won't work in the ship lab, because the lab code doesn't
+ // set the the necessary submodel instance info needed here. The second
+ // condition is thus a hack to disable the feature while in the lab, and
+ // can be removed if the lab is re-structured accordingly. -zookeeper
+ if ( bank->submodel_num > -1 && (gameseq_get_state_idx(GS_STATE_LAB) == -1) ) {
+ model_find_submodel_offset(&submodel_static_offset, wash_sip->model_num, bank->submodel_num);
+
+ submodel_rotation = true;
+ }
+
  for (j=0; j<bank->num_points; j++) {
+ vec3d world_thruster_pos, world_thruster_norm, apex, thruster_to_ship, apex_to_ship, temp;
+ vec3d loc_pos = bank->points[j].pnt;
+ vec3d loc_norm = bank->points[j].norm;
+
+ if ( submodel_rotation ) {
+ vm_vec_sub(&loc_pos, &bank->points[j].pnt, &submodel_static_offset);
+
+ // Gets the final offset and normal in the ship's frame of reference
+ temp = loc_pos;
+ find_submodel_instance_point_normal(&loc_pos, &loc_norm, wash_objp, bank->submodel_num, &temp, &loc_norm);
+ }
+
  // get world pos of thruster
- vm_vec_unrotate(&world_thruster_pos, &bank->points[j].pnt, &wash_objp->orient);
+ vm_vec_unrotate(&world_thruster_pos, &loc_pos, &wash_objp->orient);
  vm_vec_add2(&world_thruster_pos, &wash_objp->pos);
 
  // get world norm of thruster;
- vm_vec_unrotate(&world_thruster_norm, &bank->points[j].norm, &wash_objp->orient);
+ vm_vec_unrotate(&world_thruster_norm, &loc_norm, &wash_objp->orient);
 
  // get vector from thruster to ship
  vm_vec_sub(&thruster_to_ship, &objp->pos, &world_thruster_pos);
@@ -4287,4 +4314,4 @@
  vm_vec_scale_add(&objp->pos, &pos_final, &objp->orient.vec.fvec, scale);
  }
  return 1;
-}
+}
\ No newline at end of file
« Last Edit: October 24, 2011, 06:23:32 am by zookeeper »

 

Offline Eli2

  • 26
Re: Feature request: allow thrusters to follow a rotating engine
I don't think checking the game state and adding a special code path for the lab is a good way of making this work.

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: Feature request: allow thrusters to follow a rotating engine
I don't think checking the game state and adding a special code path for the lab is a good way of making this work.

What would be a better one?

 

Offline Eli2

  • 26
Re: Feature request: allow thrusters to follow a rotating engine
Refactor the Lab code, so that this check is not needed.

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: Feature request: allow thrusters to follow a rotating engine
Refactor the Lab code, so that this check is not needed.

Well, yes, sure. I bet no one's gonna do it just to make this patch a little bit cleaner, though.

 

Offline Eli2

  • 26
Re: Feature request: allow thrusters to follow a rotating engine
You think it is little bit unclean.
I think it is a major hack!

But ultimately, this has to be decided by someone with more authority than me.

 

Offline zookeeper

  • *knock knock* Who's there? Poe. Poe who?
  • 210
Re: Feature request: allow thrusters to follow a rotating engine
Updated the last version with extra comments as suggested.

Anyone up for review and commit?

EDIT: Committed to trunk in r7983.
« Last Edit: November 13, 2011, 04:38:26 am by zookeeper »