From d938b6c2236c26de6163f0f92e6c9afbbdb06e2f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jaakko=20Kera=CC=88nen?= Date: Sat, 27 Oct 2018 10:13:32 +0300 Subject: [PATCH] Renderer|Resources: Improved 3D model error checking Invalid animation and mesh IDs and material definitions should be reported. --- .../apps/client/src/render/modelloader.cpp | 75 ++++++++++++------- .../apps/client/src/render/modelrenderer.cpp | 11 +++ .../apps/client/src/render/stateanimator.cpp | 22 +++++- 3 files changed, 77 insertions(+), 31 deletions(-) diff --git a/doomsday/apps/client/src/render/modelloader.cpp b/doomsday/apps/client/src/render/modelloader.cpp index 371019b5b4..469ea5304a 100644 --- a/doomsday/apps/client/src/render/modelloader.cpp +++ b/doomsday/apps/client/src/render/modelloader.cpp @@ -461,31 +461,41 @@ DENG2_PIMPL(ModelLoader) model.materialIndexForName.insert(MATERIAL_DEFAULT, 0); if (asset.has(DEF_MATERIAL)) { - asset.subrecord(DEF_MATERIAL).forSubrecords( - [this, &model] (String const &blockName, Record const &block) - { - if (ScriptedInfo::blockType(block) == DEF_VARIANT) - { - String const materialName = blockName; - if (!model.materialIndexForName.contains(materialName)) + asset.subrecord(DEF_MATERIAL) + .forSubrecords([this, &model](String const &blockName, Record const &block) { + try { - // Add a new material. - model.materialIndexForName.insert(materialName, model.addMaterial()); + if (ScriptedInfo::blockType(block) == DEF_VARIANT) + { + String const materialName = blockName; + if (!model.materialIndexForName.contains(materialName)) + { + // Add a new material. + model.materialIndexForName.insert(materialName, + model.addMaterial()); + } + block.forSubrecords([this, &model, &materialName]( + String const &matName, Record const &matDef) { + setupMaterial(model, + matName, + model.materialIndexForName[materialName], + matDef); + return LoopContinue; + }); + } + else + { + // The default material. + setupMaterial(model, blockName, 0, block); + } } - block.forSubrecords([this, &model, &materialName] - (String const &matName, Record const &matDef) + catch (const Error &er) { - setupMaterial(model, matName, model.materialIndexForName[materialName], matDef); - return LoopContinue; - }); - } - else - { - // The default material. - setupMaterial(model, blockName, 0, block); - } - return LoopContinue; - }); + LOG_GL_ERROR("Material variant \"%s\" is invalid: %s") + << blockName << er.asText(); + } + return LoopContinue; + }); } // Set up the animation sequences for states. @@ -551,6 +561,12 @@ DENG2_PIMPL(ModelLoader) int meshId = identifierFromText(value->asText(), [&model] (String const &text) { return model.meshId(text); }); + if (meshId < 0 || meshId >= model.meshCount()) + { + throw DefinitionError("ModelLoader::bankLoaded", + "Unknown mesh \"" + value->asText() + "\" in " + + ScriptedInfo::sourceLocation(def)); + } pass.meshes.setBit(meshId, true); } @@ -651,11 +667,16 @@ DENG2_PIMPL(ModelLoader) duint materialIndex, Record const &matDef) { - ModelDrawable::MeshId const mesh { - duint(identifierFromText(meshName, [&model] (String const &text) { - return model.meshId(text); })), - materialIndex - }; + int mid = identifierFromText(meshName, + [&model](const String &text) { return model.meshId(text); }); + if (mid < 0 || mid >= model.meshCount()) + { + throw DefinitionError("ModelLoader::setupMaterial", + "Mesh \"" + meshName + "\" not found in " + + ScriptedInfo::sourceLocation(matDef)); + } + + const ModelDrawable::MeshId mesh{duint(mid), materialIndex}; setupMaterialTexture(model, mesh, matDef, QStringLiteral("diffuseMap"), ModelDrawable::Diffuse); setupMaterialTexture(model, mesh, matDef, QStringLiteral("normalMap"), ModelDrawable::Normals); diff --git a/doomsday/apps/client/src/render/modelrenderer.cpp b/doomsday/apps/client/src/render/modelrenderer.cpp index 204013701d..8b922aec9b 100644 --- a/doomsday/apps/client/src/render/modelrenderer.cpp +++ b/doomsday/apps/client/src/render/modelrenderer.cpp @@ -374,6 +374,12 @@ static Value *Function_StateAnimator_StartSequence(Context &ctx, Function::Argum anim.startAnimation(animId, priority, looping, node); } + else + { + LOG_SCR_ERROR("%s has no animation \"%s\"") + << anim.objectNamespace().gets("ID") + << args.at(0)->asText(); + } return nullptr; } @@ -389,6 +395,11 @@ static Value *Function_StateAnimator_StartTimeline(Context &ctx, Function::Argum timelineName); return new TextValue(timelineName); } + else + { + LOG_SCR_ERROR("%s has no timeline \"%s\"") + << anim.objectNamespace().gets("ID") << timelineName; + } return nullptr; } diff --git a/doomsday/apps/client/src/render/stateanimator.cpp b/doomsday/apps/client/src/render/stateanimator.cpp index e3ac8166fc..423cd0697e 100644 --- a/doomsday/apps/client/src/render/stateanimator.cpp +++ b/doomsday/apps/client/src/render/stateanimator.cpp @@ -657,6 +657,13 @@ void StateAnimator::triggerByState(String const &stateName) String const node = seq.def->gets(DEF_NODE, ""); int animId = d->animationId(seq.name); + if (animId < 0) + { + LOG_GL_ERROR("%s: animation sequence \"%s\" not found") + << ScriptedInfo::sourceLocation(*seq.def) << seq.name; + break; + } + bool const alwaysTrigger = ScriptedInfo::isTrue(*seq.def, DEF_ALWAYS_TRIGGER, false); if (!alwaysTrigger) { @@ -711,7 +718,7 @@ void StateAnimator::triggerByState(String const &stateName) } catch (ModelDrawable::Animator::InvalidError const &er) { - LOGDEV_GL_WARNING("Failed to start animation \"%s\": %s") + LOG_GL_WARNING("Failed to start animation \"%s\": %s") << seq.name << er.asText(); continue; } @@ -748,9 +755,16 @@ void StateAnimator::triggerDamage(int points, struct mobj_s const *inflictor) void StateAnimator::startAnimation(int animationId, int priority, bool looping, String const &node) { - using Seq = Impl::Sequence; - d->start(Seq(animationId, node, looping? Seq::Looping : Seq::NotLooping, - priority)); + LOG_AS("StateAnimator::startAnimation"); + try + { + using Seq = Impl::Sequence; + d->start(Seq(animationId, node, looping ? Seq::Looping : Seq::NotLooping, priority)); + } + catch (const Error &er) + { + LOG_GL_ERROR("%s: %s") << d->names.gets(VAR_ID) << er.asText(); + } } int StateAnimator::animationId(String const &name) const