@@ -1370,16 +1370,24 @@ void determine_submodel_movement(bool is_rotation, const char *filename, bsp_inf
13701370 if (in (p, props, axis_string))
13711371 {
13721372 if (get_user_vec3d_value (p + 20 , movement_axis, true , sm->name , filename))
1373- vm_vec_normalize (movement_axis);
1373+ {
1374+ if (!fl_near_zero (vm_vec_mag (movement_axis)))
1375+ vm_vec_normalize (movement_axis);
1376+ else
1377+ {
1378+ Warning (LOCATION , " %s on submodel '%s' on ship %s has a magnitude near zero!" , axis_string, sm->name , filename);
1379+ *movement_type = MOVEMENT_TYPE_NONE ;
1380+ }
1381+ }
13741382 else
13751383 {
1376- Warning (LOCATION , " Failed to parse %s on subsystem '%s' on ship %s!" , axis_string, sm->name , filename);
1384+ Warning (LOCATION , " Failed to parse %s on submodel '%s' on ship %s!" , axis_string, sm->name , filename);
13771385 *movement_type = MOVEMENT_TYPE_NONE ;
13781386 }
13791387 }
13801388 else
13811389 {
1382- Warning (LOCATION , " A %s was not specified for subsystem '%s' on ship %s!" , axis_string, sm->name , filename);
1390+ Warning (LOCATION , " A %s was not specified for submodel '%s' on ship %s!" , axis_string, sm->name , filename);
13831391 *movement_type = MOVEMENT_TYPE_NONE ;
13841392 }
13851393 }
@@ -1483,8 +1491,9 @@ void do_movement_sanity_checks(bsp_info *sm, bsp_info *parent_sm, const char *fi
14831491
14841492 extract_movement_info (sm, is_rotation, movement_axis_id, movement_axis, movement_type);
14851493
1486- // make sure this is a validly normalized axis
1487- if (vm_vec_mag (movement_axis) < 0 .999f || vm_vec_mag (movement_axis) > 1 .001f )
1494+ // make sure this is a validly normalized axis - also catch axes that are unspecified or 0,0,0
1495+ // (it would be nice to warn here, but the signal to noise ratio is extremely poor)
1496+ if (!vm_vec_is_normalized (movement_axis))
14881497 *movement_type = MOVEMENT_TYPE_NONE ;
14891498
14901499 // maybe use the FOR to manipulate the axes
@@ -2055,45 +2064,38 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
20552064 }
20562065
20572066 // KeldorKatarn, with modifications
2058- if (in (p, props, " $uvec" )) {
2059- matrix submodel_orient;
2060-
2061- if (get_user_vec3d_value (p + 5 , &submodel_orient.vec .uvec , false , sm->name , pm->filename )) {
2062-
2063- if (in (p, props, " $fvec" )) {
2064-
2065- if (get_user_vec3d_value (p + 5 , &submodel_orient.vec .fvec , false , sm->name , pm->filename )) {
2066-
2067- vm_vec_normalize (&submodel_orient.vec .uvec );
2068- vm_vec_normalize (&submodel_orient.vec .fvec );
2069-
2070- vm_vec_cross (&submodel_orient.vec .rvec , &submodel_orient.vec .uvec , &submodel_orient.vec .fvec );
2071- vm_vec_cross (&submodel_orient.vec .fvec , &submodel_orient.vec .rvec , &submodel_orient.vec .uvec );
2067+ {
2068+ bool has_fvec = false , has_uvec = false , has_rvec = false ;
2069+ vec3d fvec, uvec, rvec;
20722070
2073- vm_vec_normalize (&submodel_orient. vec . fvec );
2074- vm_vec_normalize (&submodel_orient. vec . rvec ) ;
2071+ // default
2072+ sm-> frame_of_reference = parent_sm ? parent_sm-> frame_of_reference : vmd_identity_matrix ;
20752073
2076- vm_orthogonalize_matrix (&submodel_orient);
2074+ // parse what we can
2075+ auto vectors = { std::make_tuple (" $fvec" , &fvec, &has_fvec), std::make_tuple (" $uvec" , &uvec, &has_uvec), std::make_tuple (" $rvec" , &rvec, &has_rvec) };
2076+ for (auto &item : vectors)
2077+ {
2078+ if (in (p, props, std::get<0 >(item)))
2079+ {
2080+ if (get_user_vec3d_value (p + 5 , std::get<1 >(item), false , sm->name , pm->filename ))
2081+ *std::get<2 >(item) = true ;
2082+ else
2083+ Warning (LOCATION , " Submodel '%s' of model '%s' has an improperly formatted %s declaration in its properties.\n\n %s should be followed by 3 numbers separated with commas." , sm->name , filename, std::get<0 >(item), std::get<0 >(item));
2084+ }
2085+ }
20772086
2078- sm->frame_of_reference = submodel_orient;
2087+ // make a matrix if we have at least the fvec
2088+ if (has_fvec)
2089+ {
2090+ vm_vector_2_matrix (&sm->frame_of_reference , &fvec, has_uvec ? &uvec : nullptr , has_rvec ? &rvec : nullptr );
20792091
2080- } else {
2081- Warning (LOCATION ,
2082- " Submodel '%s' of model '%s' has an improperly formatted $fvec declaration in its properties."
2083- " \n\n $fvec should be followed by 3 numbers separated with commas." ,
2084- sm->name , filename);
2085- }
2086- } else {
2087- Warning (LOCATION , " Improper custom orientation matrix for subsystem %s; you must define both an up vector and a forward vector" , sm->name );
2088- }
2089- } else {
2090- Warning (LOCATION ,
2091- " Submodel '%s' of model '%s' has an improperly formatted $uvec declaration in its properties."
2092- " \n\n $uvec should be followed by 3 numbers separated with commas." ,
2093- sm->name , filename);
2092+ // if the look_at_offset is still the default value (hasn't been set by submodel properties), assume that
2093+ // by specifying the submodel orientation matrix we are also specifying the "looking" direction
2094+ if (sm->look_at_offset == -1 .0f )
2095+ sm->look_at_offset = 0 .0f ;
20942096 }
2095- } else {
2096- sm-> frame_of_reference = parent_sm ? parent_sm-> frame_of_reference : vmd_identity_matrix ;
2097+ else if (has_uvec || has_rvec)
2098+ Warning ( LOCATION , " Improper custom orientation matrix for subsystem %s; you must define an $fvec " , sm-> name ) ;
20972099 }
20982100
20992101 {
@@ -2939,6 +2941,7 @@ modelread_status read_model_file_no_subsys(polymodel * pm, const char* filename,
29392941
29402942 // if we couldn't find it, we shouldn't move
29412943 if (sm->look_at_submodel < 0 ) {
2944+ Warning (LOCATION , " Could not find $look_at target for %s %s!" , pm->filename , sm->name );
29422945 sm->rotation_type = MOVEMENT_TYPE_NONE ;
29432946 }
29442947 // are we navel-gazing?
0 commit comments