I've committed this to zookeper branch, here's a patch against trunk:
Index: debris/debris.cpp
===================================================================
--- debris/debris.cpp (revision 11268)
+++ debris/debris.cpp (working copy)
@@ -926,6 +926,10 @@
// reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
+ if (Ship_info[Ships[ship_obj->instance].ship_info_index].collision_lod > -1) {
+ mc.lod = Ship_info[Ships[ship_obj->instance].ship_info_index].collision_lod;
+ }
+
// check each submodel in turn
for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
// turn on submodel for collision test
Index: model/model.h
===================================================================
--- model/model.h (revision 11268)
+++ model/model.h (working copy)
@@ -1022,7 +1022,8 @@
vec3d *p0; // The starting point of the ray (sphere) to check
vec3d *p1; // The ending point of the ray (sphere) to check
int flags; // Flags that the model_collide code looks at. See MC_??? defines
- float radius; // If MC_CHECK_THICK is set, checks a sphere moving with the radius.
+ float radius; // If MC_CHECK_THICK is set, checks a sphere moving with the radius.
+ int lod; // Which detail level of the submodel to check instead
// Return values
int num_hits; // How many collisions were found
Index: model/modelcollide.cpp
===================================================================
--- model/modelcollide.cpp (revision 11268)
+++ model/modelcollide.cpp (working copy)
@@ -1130,7 +1130,22 @@
if ( Cmdline_old_collision_sys ) {
model_collide_sub(sm->bsp_data);
} else {
- model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
+ if (Mc->lod > 0 && sm->num_details > 0) {
+ bsp_info *lod_sm = sm;
+
+ for (int i = Mc->lod - 1; i >= 0; i--) {
+ if (sm->details[i] != -1) {
+ lod_sm = &Mc_pm->submodel[sm->details[i]];
+
+ //mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name));
+ break;
+ }
+ }
+
+ model_collide_bsp(model_get_bsp_collision_tree(lod_sm->collision_tree_index), 0);
+ } else {
+ model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
+ }
}
}
}
Index: model/modelread.cpp
===================================================================
--- model/modelread.cpp (revision 11268)
+++ model/modelread.cpp (working copy)
@@ -2639,6 +2639,12 @@
}
dl2 = tolower(sm2->name[first_diff]) - 'a';
+ // Handle LODs named "detail0/1/2/etc" too (as opposed to "detaila/b/c/etc")
+ if (sm1->parent == -1 && sm2->parent == -1 && !sm1->is_damaged && !sm2->is_damaged && !sm1->is_live_debris && !sm2->is_live_debris) {
+ dl2 = dl2 - dl1;
+ dl1 = 0;
+ }
+
if ( (dl1<0) || (dl2<0) || (dl1>=MAX_MODEL_DETAIL_LEVELS) || (dl2>=MAX_MODEL_DETAIL_LEVELS) ) continue; // invalid detail levels
if ( dl1 == 0 ) {
Index: object/collideshipship.cpp
===================================================================
--- object/collideshipship.cpp (revision 11268)
+++ object/collideshipship.cpp (working copy)
@@ -269,6 +269,10 @@
// reset flags to check MC_CHECK_MODEL | MC_CHECK_SPHERELINE and maybe MC_CHECK_INVISIBLE_FACES and MC_SUBMODEL_INSTANCE
mc.flags = copy_flags | MC_SUBMODEL_INSTANCE;
+ if (heavy_sip->collision_lod > -1) {
+ mc.lod = heavy_sip->collision_lod;
+ }
+
// check each submodel in turn
for (smv = submodel_vector.begin(); smv != submodel_vector.end(); ++smv) {
// turn on submodel for collision test
Index: object/collideshipweapon.cpp
===================================================================
--- object/collideshipweapon.cpp (revision 11268)
+++ object/collideshipweapon.cpp (working copy)
@@ -168,6 +168,7 @@
mc.pos = &ship_objp->pos;
mc.p0 = &weapon_objp->last_pos;
mc.p1 = &weapon_end_pos;
+ mc.lod = sip->collision_lod;
memcpy(&mc_shield, &mc, sizeof(mc_info));
memcpy(&mc_hull, &mc, sizeof(mc_info));
Index: ship/ship.cpp
===================================================================
--- ship/ship.cpp (revision 11268)
+++ ship/ship.cpp (working copy)
@@ -690,6 +690,7 @@
sip->pof_file_hud[0] = '\0';
sip->num_detail_levels = 1;
sip->detail_distance[0] = 0;
+ sip->collision_lod = -1;
sip->cockpit_model_num = -1;
sip->model_num = -1;
sip->model_num_hud = -1;
@@ -1611,6 +1612,13 @@
sip->num_detail_levels = stuff_int_list(sip->detail_distance, MAX_SHIP_DETAIL_LEVELS, RAW_INTEGER_TYPE);
}
+ if(optional_string("$Collision LOD:")) {
+ stuff_int(&sip->collision_lod);
+
+ // Cap to sane values, just in case
+ sip->collision_lod = MAX(0, MIN(sip->collision_lod, sip->num_detail_levels));
+ }
+
// check for optional pixel colors
while(optional_string("$ND:")){
ubyte nr, ng, nb;
Index: ship/ship.h
===================================================================
--- ship/ship.h (revision 11268)
+++ ship/ship.h (working copy)
@@ -1175,6 +1175,7 @@
char pof_file_hud[MAX_FILENAME_LEN]; // POF file to load for the HUD target box
int num_detail_levels; // number of detail levels for this ship
int detail_distance[MAX_SHIP_DETAIL_LEVELS]; // distance to change detail levels at
+ int collision_lod; // check for collisions using a LOD
int cockpit_model_num; // cockpit model
int model_num; // ship model
int model_num_hud; // model to use when rendering to the HUD (eg, mini supercap)
In ships.tbl, this goes right below $Detail Distance, like so:
$Detail Distance: (0, 2000, 5000)
$Collision LOD: 2 ;use LOD2 for collisions
As it says on the tin, what this does is allowing LODs to be used as collision meshes. More specifically, collision detection for a submodel (including detail0) proceeds as normal through all the radius and bounding box checks, but once the actual submodel bsp tree needs to be traversed, the bsp tree of a lower LOD of that submodel (if one exists) will be used instead.
Of particular note is that LODs used for collision don't need to have all the same submodels as LOD0. If, for example, you set $Collision LOD: 2, then mesh collisions for engine01a will be done using the mesh of engine01c instead. What if there is no engine01c? No problem, in that case engine01b will be used, and if that doesn't exist either, then it just falls back to engine01a as usual.