Skip to content

Commit

Permalink
Fixed|Resources: Crash when loading/rendering models (boxed jDRP)
Browse files Browse the repository at this point in the history
There were two issues after the removal of the fixed submodel limit:

1) A model definition may have no submodels at all, but the code still
accesses submodel #0 in some places, causing a crash.

2) The stateModefs array contained pointers, but as the modeldefs are
now stored in a dynamic array, existing pointers are invalidated when
the array grows. The stateModefs array now stores indexes instead of
pointers.
  • Loading branch information
skyjake committed Jun 6, 2013
1 parent 5d3d2a9 commit a6d2275
Show file tree
Hide file tree
Showing 2 changed files with 39 additions and 19 deletions.
2 changes: 1 addition & 1 deletion doomsday/client/src/render/r_things.cpp
Expand Up @@ -1157,7 +1157,7 @@ void R_ProjectSprite(mobj_t *mo)
floorClip += R_GetBobOffset(mo);
}

if(mf)
if(mf && !mf->sub.empty())
{
// Determine the rotation angles (in degrees).
if(mf->sub[0].flags & MFF_ALIGN_YAW)
Expand Down
56 changes: 38 additions & 18 deletions doomsday/client/src/resource/models.cpp
Expand Up @@ -59,12 +59,30 @@ byte useModels = true;
float rModelAspectMod = 1 / 1.2f; //.833334f;

static StringPool* modelRepository; // Owns model_t instances.
static modeldef_t** stateModefs;
static std::vector<int> stateModefs; // Index to the modefs array.

static float avertexnormals[NUMVERTEXNORMALS][3] = {
#include "tab_anorms.h"
};

static int indexOfModelDef(ModelDef const *mf)
{
return mf - &modefs[0];
}

static ModelDef *modelDefForState(int stateIndex)
{
DENG2_ASSERT(stateIndex >= 0);
DENG2_ASSERT(stateIndex < int(stateModefs.size()));

if(stateModefs[stateIndex] < 0) return 0;

DENG2_ASSERT(stateModefs[stateIndex] >= 0);
DENG2_ASSERT(stateModefs[stateIndex] < int(modefs.size()));

return &modefs[stateModefs[stateIndex]];
}

/**
* Packed: pppppppy yyyyyyyy. Yaw is on the XY plane.
*/
Expand Down Expand Up @@ -721,7 +739,7 @@ static model_t *loadModel(String path)
*/
static modeldef_t *getStateModel(state_t &st, int select)
{
modeldef_t *modef = stateModefs[&st - states];
modeldef_t *modef = modelDefForState(&st - states);
if(!modef) return 0;

if(select)
Expand Down Expand Up @@ -835,7 +853,7 @@ float Models_ModelForMobj(mobj_t* mo, modeldef_t** modef, modeldef_t** nextmodef
int max = 20; // Let's not be here forever...
while(!stopScan)
{
if(!((!stateModefs[it - states] ||
if(!((!modelDefForState(it - states) ||
getStateModel(*it, mo->selector)->interRange[0] > 0) &&
it->nextState > 0))
{
Expand Down Expand Up @@ -935,7 +953,7 @@ static void scaleModelToSprite(modeldef_t &mf, int sprite, int frame)

static float calcModelVisualRadius(modeldef_t *def)
{
if(!def || !def->sub[0].modelId) return 0;
if(!def || def->sub.empty() || !def->sub[0].modelId) return 0;

// Use the first frame bounds.
float min[3], max[3];
Expand Down Expand Up @@ -1186,7 +1204,7 @@ static void setupModel(ded_model_t& def)
{
scaleModel(*modef, modef->resize, modef->offset[VY]);
}
else if(modef->state && modef->sub[0].flags & MFF_AUTOSCALE)
else if(modef->state && !modef->sub.empty() && modef->sub[0].flags & MFF_AUTOSCALE)
{
int sprNum = Def_GetSpriteNum(def.sprite.id);
int sprFrame = def.spriteFrame;
Expand All @@ -1206,19 +1224,21 @@ static void setupModel(ded_model_t& def)
int stateNum = modef->state - states;

// Associate this modeldef with its state.
if(!stateModefs[stateNum])
if(stateModefs[stateNum] < 0)
{
// No modef; use this.
stateModefs[stateNum] = modef;
stateModefs[stateNum] = indexOfModelDef(modef);
}
else
{
// Must check intermark; smallest wins!
modeldef_t* other = stateModefs[stateNum];
modeldef_t* other = modelDefForState(stateNum);

if((modef->interMark <= other->interMark && // Should never be ==
modef->select == other->select) || modef->select < other->select) // Smallest selector?
stateModefs[stateNum] = modef;
{
stateModefs[stateNum] = indexOfModelDef(modef);
}
}
}

Expand Down Expand Up @@ -1306,8 +1326,11 @@ void Models_Init(void)
}

// Clear the modef pointers of all States.
stateModefs = (modeldef_t**) M_Realloc(stateModefs, countStates.num * sizeof(*stateModefs));
memset(stateModefs, 0, countStates.num * sizeof(*stateModefs));
stateModefs.clear();
for(int i = 0; i < countStates.num; ++i)
{
stateModefs.push_back(-1);
}

// Read in the model files and their data.
// Use the latest definition available for each sprite ID.
Expand Down Expand Up @@ -1382,12 +1405,9 @@ void Models_Init(void)

void Models_Shutdown(void)
{
/// @todo Why only centralized memory deallocation? Bad design...
/// @todo Why only centralized memory deallocation? Bad (lazy) design...
modefs.clear();
if(stateModefs)
{
M_Free(stateModefs); stateModefs = 0;
}
stateModefs.clear();

clearModelList();

Expand Down Expand Up @@ -1429,9 +1449,9 @@ DENG_EXTERN_C void Models_CacheForState(int stateIndex)
{
if(!useModels) return;
if(stateIndex <= 0 || stateIndex >= defs.count.states.num) return;
if(!stateModefs[stateIndex]) return;
if(stateModefs[stateIndex] < 0) return;

Models_Cache(stateModefs[stateIndex]);
Models_Cache(modelDefForState(stateIndex));
}

int Models_CacheForMobj(thinker_t* th, void* /*context*/)
Expand Down

0 comments on commit a6d2275

Please sign in to comment.