1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
|
#pragma once
#include "ieclass.h"
#include "parser/DefTokeniser.h"
#include "decl/DeclarationBase.h"
namespace eclass
{
class Doom3ModelDef :
public decl::DeclarationBase<IModelDef>
{
private:
Ptr _parent;
std::string _mesh;
std::string _skin;
Anims _anims;
public:
using Ptr = std::shared_ptr<Doom3ModelDef>;
Doom3ModelDef(const std::string& name) :
DeclarationBase<IModelDef>(decl::Type::ModelDef, name)
{}
const std::string& getMesh() override
{
ensureParsed();
return _mesh;
}
const IModelDef::Ptr& getParent() override
{
ensureParsed();
return _parent;
}
const std::string& getSkin() override
{
ensureParsed();
return _skin;
}
std::string getAnim(const std::string& animKey) override
{
ensureParsed();
auto existing = _anims.find(animKey);
return existing != _anims.end() ? existing->second : std::string();
}
const Anims& getAnims() override
{
ensureParsed();
return _anims;
}
protected:
void onBeginParsing() override
{
clearContents();
}
// Reads the data from the given tokens into the member variables
void parseFromTokens(parser::DefTokeniser& tokeniser) override
{
// State enum
enum
{
NONE, // usual state
ANIM // parsed anim, may get a { ... } block with further info
} state = NONE;
while (tokeniser.hasMoreTokens())
{
auto parameter = tokeniser.nextToken();
if (parameter == "inherit")
{
inheritFrom(tokeniser.nextToken());
}
else if (parameter == "mesh")
{
_mesh = tokeniser.nextToken();
}
else if (parameter == "skin")
{
_skin = tokeniser.nextToken();
}
else if (parameter == "offset")
{
tokeniser.skipTokens(5);
}
else if (parameter == "channel")
{
// SYNTAX: "channel" <name> "(" <blah> [ <blah> ... ] ")"
tokeniser.skipTokens(2);
while (tokeniser.nextToken() != ")") continue;
}
else if (parameter == "anim")
{
// SYNTAX: "anim" <name> <md5file> [ "{" <blah> [ <blah> ... ] "}" ]
auto animName = tokeniser.nextToken();
auto file = tokeniser.nextToken();
// Overwrite any existing animation with the same key
_anims[animName] = file;
state = ANIM; // check for the braces on the next iteration
}
else if (state == ANIM && parameter == "{")
{
// anim braces
while (tokeniser.nextToken() != "}") continue;
state = NONE;
}
}
}
private:
void clearContents()
{
// Don't clear the name
_mesh.clear();
_skin.clear();
_parent.reset();
_anims.clear();
}
void inheritFrom(const std::string& parentName)
{
auto parent = GlobalEntityClassManager().findModel(parentName);
if (!parent)
{
rWarning() << "ModelDef " << getDeclName() << " inherits from unknown parent: " << parentName << std::endl;
return;
}
_parent = parent;
// greebo: Only inherit the "mesh" of the parent if the current declaration doesn't have one
if (_mesh.empty())
{
_mesh = parent->getMesh();
}
// Only inherit the "skin" of the parent if the current declaration doesn't have one
if (_skin.empty())
{
_skin = parent->getSkin();
}
// Append all inherited animations, if missing on the child
const auto& parentAnims = parent->getAnims();
_anims.insert(parentAnims.begin(), parentAnims.end());
}
};
} // namespace
|