Subresource cooking and various bug fixes

This commit is contained in:
Jack Andersen 2017-02-12 20:51:47 -10:00
parent 242f9e3a2d
commit 7085b837b7
10 changed files with 501 additions and 323 deletions

View File

@ -1077,10 +1077,7 @@ bool ANCS::Extract(const SpecBase& dataSpec,
bool ANCS::Cook(const hecl::ProjectPath& outPath, bool ANCS::Cook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath, const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor, const DNAANCS::Actor& actor)
hecl::BlenderConnection::DataStream& ds,
bool pc,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc)
{ {
/* Search for yaml */ /* Search for yaml */
hecl::ProjectPath yamlPath = inPath.getWithExtension(_S(".yaml"), true); hecl::ProjectPath yamlPath = inPath.getWithExtension(_S(".yaml"), true);
@ -1151,122 +1148,12 @@ bool ANCS::Cook(const hecl::ProjectPath& outPath,
return true; return true;
}); });
std::unordered_map<std::string, atInt32> boneIdMap; /* Gather ANIM resources */
std::experimental::optional<CINF> rigCinf;
std::experimental::optional<DNAANIM::RigInverter<CINF>> rigInv;
/* Write out CINF resources */
for (const DNAANCS::Actor::Armature& arm : actor.armatures)
{
hecl::SystemStringView sysStr(arm.name);
hecl::ProjectPath pathOut = inPath.ensureAuxInfo(sysStr.sys_str() + _S(".CINF")).getCookedPath(SpecEntMP1);
pathOut.makeDirChain(false);
athena::io::FileWriter w(pathOut.getAbsolutePath(), true, false);
if (w.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"),
pathOut.getRelativePath().c_str());
CINF cinf(arm, boneIdMap);
cinf.write(w);
if (!rigInv)
{
rigCinf.emplace(cinf);
auto matrices = ds.getBoneMatrices(arm.name);
rigInv.emplace(*rigCinf, matrices);
}
}
ds.close();
/* Write out CSKR resources */
for (ANCS::CharacterSet::CharacterInfo& ch : ancs.characterSet.characters)
{
const DNAANCS::Actor::Subtype* subtype = nullptr;
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
{
if (!sub.name.compare(ch.name))
{
subtype = &sub;
break;
}
}
if (!subtype)
Log.report(logvisor::Fatal, "unable to find subtype '%s'", ch.name.c_str());
const hecl::ProjectPath& modelPath = subtype->mesh;
if (!modelPath.isFile())
Log.report(logvisor::Fatal, _S("unable to resolve '%s'"), modelPath.getRelativePath().c_str());
hecl::ProjectPath skinIntPath = modelPath.getCookedPath(SpecEntMP1PC).getWithExtension(_S(".skinint"));
if (!skinIntPath.isFileOrGlob() || skinIntPath.getModtime() < modelPath.getModtime())
if (!modelCookFunc(modelPath))
Log.report(logvisor::Fatal, _S("unable to cook '%s'"), modelPath.getRelativePath().c_str());
athena::io::FileReader skinIO(skinIntPath.getAbsolutePath(), 1024*32, false);
if (skinIO.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s'"), skinIntPath.getRelativePath().c_str());
std::vector<std::vector<uint32_t>> skinBanks;
uint32_t bankCount = skinIO.readUint32Big();
skinBanks.reserve(bankCount);
for (uint32_t i=0 ; i<bankCount ; ++i)
{
skinBanks.emplace_back();
std::vector<uint32_t>& bonesOut = skinBanks.back();
uint32_t boneCount = skinIO.readUint32Big();
bonesOut.reserve(boneCount);
for (uint32_t j=0 ; j<boneCount ; ++j)
{
uint32_t idx = skinIO.readUint32Big();
bonesOut.push_back(idx);
}
}
std::vector<std::string> boneNames;
uint32_t boneNameCount = skinIO.readUint32Big();
boneNames.reserve(boneNameCount);
for (uint32_t i=0 ; i<boneNameCount ; ++i)
boneNames.push_back(skinIO.readString());
skinIO.close();
hecl::SystemStringView sysStr(ch.name);
hecl::ProjectPath skinPath = inPath.ensureAuxInfo(sysStr.sys_str() + _S(".CSKR")).getCookedPath(SpecEntMP1PC);
skinPath.makeDirChain(false);
athena::io::FileWriter skinOut(skinPath.getAbsolutePath(), true, false);
if (skinOut.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"),
skinPath.getRelativePath().c_str());
skinOut.writeUint32Big(bankCount);
for (const std::vector<uint32_t>& bank : skinBanks)
{
skinOut.writeUint32Big(bank.size());
for (uint32_t bIdx : bank)
{
const std::string& name = boneNames[bIdx];
auto search = boneIdMap.find(name);
if (search == boneIdMap.cend())
Log.report(logvisor::Fatal, "unable to find bone '%s' in %s",
name.c_str(), inPath.getRelativePathUTF8().c_str());
skinOut.writeUint32Big(search->second);
}
}
}
/* Write out ANIM resources */
ancs.animationSet.animResources.reserve(actor.actions.size()); ancs.animationSet.animResources.reserve(actor.actions.size());
for (const DNAANCS::Actor::Action& act : actor.actions) for (const DNAANCS::Actor::Action& act : actor.actions)
{ {
hecl::SystemStringView sysStr(act.name); hecl::SystemStringView sysStr(act.name);
hecl::ProjectPath pathOut = inPath.ensureAuxInfo(sysStr.sys_str() + _S(".ANIM")); hecl::ProjectPath pathOut = inPath.ensureAuxInfo(sysStr.sys_str() + _S(".ANIM"));
hecl::ProjectPath cookedOut = pathOut.getCookedPath(SpecEntMP1PC);
cookedOut.makeDirChain(false);
athena::io::FileWriter w(cookedOut.getAbsolutePath(), true, false);
if (w.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"),
cookedOut.getRelativePath().c_str());
ANIM anim(act, boneIdMap, *rigInv, pc);
ancs.animationSet.animResources.emplace_back(); ancs.animationSet.animResources.emplace_back();
ancs.animationSet.animResources.back().animId = pathOut; ancs.animationSet.animResources.back().animId = pathOut;
@ -1275,41 +1162,172 @@ bool ANCS::Cook(const hecl::ProjectPath& outPath,
hecl::ProjectPath evntYamlPath = inPath.getWithExtension((hecl::SystemString(_S(".")) + hecl::ProjectPath evntYamlPath = inPath.getWithExtension((hecl::SystemString(_S(".")) +
sysStr.sys_str() + sysStr.sys_str() +
_S(".evnt.yaml")).c_str(), true); _S(".evnt.yaml")).c_str(), true);
evntYamlPath = evntYamlPath.ensureAuxInfo(_S(""));
if (evntYamlPath.isFile()) if (evntYamlPath.isFile())
{ ancs.animationSet.animResources.back().evntId = evntYamlPath;
athena::io::FileReader reader(evntYamlPath.getAbsolutePath());
if (reader.isOpen())
{
EVNT evnt;
evnt.fromYAMLStream(reader);
hecl::ProjectPath evntCookedOut = evntYamlPath.getCookedPath(SpecEntMP1);
evntCookedOut.makeDirChain(false);
athena::io::FileWriter w(evntCookedOut.getAbsolutePath(), true, false);
if (w.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"),
evntCookedOut.getRelativePath().c_str());
evnt.write(w);
ancs.animationSet.animResources.back().evntId = evntYamlPath;
anim.m_anim->evnt = evntYamlPath;
}
}
anim.write(w);
} }
/* Write out ANCS */ /* Write out ANCS */
hecl::ProjectPath pathOut = inPath.ensureAuxInfo("").getCookedPath(SpecEntMP1); athena::io::TransactionalFileWriter w(outPath.getAbsolutePath());
athena::io::FileWriter w(pathOut.getAbsolutePath(), true, false);
if (w.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s' for writing"),
pathOut.getRelativePath().c_str());
ancs.write(w); ancs.write(w);
return true; return true;
} }
bool ANCS::CookCINF(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor)
{
hecl::SystemString armName(inPath.getAuxInfo().begin(),
inPath.getAuxInfo().end() - 5);
for (const DNAANCS::Actor::Armature& arm : actor.armatures)
{
hecl::SystemStringView sysStr(arm.name);
if (sysStr.sys_str() == armName)
{
std::unordered_map<std::string, atInt32> boneIdMap;
CINF cinf(arm, boneIdMap);
/* Write out CINF resource */
athena::io::TransactionalFileWriter w(outPath.getAbsolutePath());
cinf.write(w);
return true;
}
}
return false;
}
bool ANCS::CookCSKR(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc)
{
hecl::SystemString subName(inPath.getAuxInfo().begin(),
inPath.getAuxInfo().end() - 5);
hecl::SystemUTF8View subNameView(subName);
/* Build bone ID map */
std::unordered_map<std::string, atInt32> boneIdMap;
for (const DNAANCS::Actor::Armature& arm : actor.armatures)
{
CINF cinf(arm, boneIdMap);
}
const DNAANCS::Actor::Subtype* subtype = nullptr;
for (const DNAANCS::Actor::Subtype& sub : actor.subtypes)
{
if (!sub.name.compare(subNameView.str()))
{
subtype = &sub;
break;
}
}
if (!subtype)
Log.report(logvisor::Fatal, _S("unable to find subtype '%s'"), subName.c_str());
const hecl::ProjectPath& modelPath = subtype->mesh;
if (!modelPath.isFile())
Log.report(logvisor::Fatal, _S("unable to resolve '%s'"), modelPath.getRelativePath().c_str());
hecl::ProjectPath skinIntPath = modelPath.getCookedPath(SpecEntMP1PC).getWithExtension(_S(".skinint"));
if (!skinIntPath.isFileOrGlob() || skinIntPath.getModtime() < modelPath.getModtime())
if (!modelCookFunc(modelPath))
Log.report(logvisor::Fatal, _S("unable to cook '%s'"), modelPath.getRelativePath().c_str());
athena::io::FileReader skinIO(skinIntPath.getAbsolutePath(), 1024*32, false);
if (skinIO.hasError())
Log.report(logvisor::Fatal, _S("unable to open '%s'"), skinIntPath.getRelativePath().c_str());
std::vector<std::vector<uint32_t>> skinBanks;
uint32_t bankCount = skinIO.readUint32Big();
skinBanks.reserve(bankCount);
for (uint32_t i=0 ; i<bankCount ; ++i)
{
skinBanks.emplace_back();
std::vector<uint32_t>& bonesOut = skinBanks.back();
uint32_t boneCount = skinIO.readUint32Big();
bonesOut.reserve(boneCount);
for (uint32_t j=0 ; j<boneCount ; ++j)
{
uint32_t idx = skinIO.readUint32Big();
bonesOut.push_back(idx);
}
}
std::vector<std::string> boneNames;
uint32_t boneNameCount = skinIO.readUint32Big();
boneNames.reserve(boneNameCount);
for (uint32_t i=0 ; i<boneNameCount ; ++i)
boneNames.push_back(skinIO.readString());
skinIO.close();
athena::io::TransactionalFileWriter skinOut(outPath.getAbsolutePath());
skinOut.writeUint32Big(bankCount);
for (const std::vector<uint32_t>& bank : skinBanks)
{
skinOut.writeUint32Big(bank.size());
for (uint32_t bIdx : bank)
{
const std::string& name = boneNames[bIdx];
auto search = boneIdMap.find(name);
if (search == boneIdMap.cend())
Log.report(logvisor::Fatal, "unable to find bone '%s' in %s",
name.c_str(), inPath.getRelativePathUTF8().c_str());
skinOut.writeUint32Big(search->second);
}
}
return true;
}
bool ANCS::CookANIM(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
hecl::BlenderConnection::DataStream& ds,
bool pc)
{
hecl::SystemString actName(inPath.getAuxInfo().begin(),
inPath.getAuxInfo().end() - 5);
hecl::SystemUTF8View actNameView(actName);
DNAANCS::Actor::Action action = ds.compileActionChannelsOnly(actNameView.str());
if (!actor.armatures.size())
Log.report(logvisor::Fatal, _S("0 armatures in %s"),
inPath.getRelativePath().c_str());
/* Build bone ID map */
std::unordered_map<std::string, atInt32> boneIdMap;
std::experimental::optional<DNAANIM::RigInverter<CINF>> rigInv;
for (const DNAANCS::Actor::Armature& arm : actor.armatures)
{
CINF cinf(arm, boneIdMap);
if (!rigInv)
{
auto matrices = ds.getBoneMatrices(arm.name);
rigInv.emplace(cinf, matrices);
}
}
ANIM anim(action, boneIdMap, *rigInv, pc);
/* Check for associated EVNT YAML */
hecl::ProjectPath evntYamlPath = inPath.getWithExtension((hecl::SystemString(_S(".")) + actName +
_S(".evnt.yaml")).c_str(), true);
evntYamlPath = evntYamlPath.ensureAuxInfo(_S(""));
if (evntYamlPath.isFile())
anim.m_anim->evnt = evntYamlPath;
/* Write out ANIM resource */
athena::io::TransactionalFileWriter w(outPath.getAbsolutePath());
anim.write(w);
return true;
}
} }
} }

View File

@ -542,10 +542,22 @@ struct ANCS : BigYAML
static bool Cook(const hecl::ProjectPath& outPath, static bool Cook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath, const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor, const DNAANCS::Actor& actor);
hecl::BlenderConnection::DataStream& ds,
bool pc, static bool CookCINF(const hecl::ProjectPath& outPath,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc); const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor);
static bool CookCSKR(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
const std::function<bool(const hecl::ProjectPath& modelPath)>& modelCookFunc);
static bool CookANIM(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const DNAANCS::Actor& actor,
hecl::BlenderConnection::DataStream& ds,
bool pc);
}; };
} }

View File

@ -395,7 +395,7 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
frameCount += 1; frameCount += 1;
} }
} }
head.keyBitmapBitCount = frameCount; head.keyBitmapBitCount = keyBmp.getBitCount();
head.duration = frameCount * mainInterval; head.duration = frameCount * mainInterval;
head.boneChannelCount = bones.size(); head.boneChannelCount = bones.size();

View File

@ -89,6 +89,22 @@ struct EVNT : BigYAML
evnt.toYAMLStream(writer); evnt.toYAMLStream(writer);
return true; return true;
} }
static bool Cook(const hecl::ProjectPath& inPath, const hecl::ProjectPath& outPath)
{
EVNT evnt;
athena::io::FileReader reader(inPath.getAbsolutePath());
evnt.fromYAMLStream(reader);
athena::io::FileWriter ws(outPath.getAbsolutePath());
evnt.write(ws);
return true;
}
void gatherDependencies(std::vector<hecl::ProjectPath>& pathsOut) const
{
for (const ParticlePOINode& node : particlePOINodes)
g_curSpec->flattenDependencies(node.id, pathsOut);
}
}; };
} }

View File

@ -78,14 +78,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
hecl::ProjectPath mapwPath = inPath.ensureAuxInfo(_S("MAPW")); hecl::ProjectPath mapwPath = inPath.ensureAuxInfo(_S("MAPW"));
mlvl.worldMap = mapwPath; mlvl.worldMap = mapwPath;
std::vector<urde::SObjectTag> mapaTags;
mapaTags.reserve(wld.areas.size());
SAVW savw = {};
savw.header.magic = 0xC001D00D;
savw.header.version = 0x3;
std::unordered_set<UniqueID32> addedScans;
size_t areaIdx = 0; size_t areaIdx = 0;
size_t nameOffset = 0; size_t nameOffset = 0;
for (const World::Area& area : wld.areas) for (const World::Area& area : wld.areas)
@ -109,8 +101,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
r.enumerate<atUint32>("memrelays", memRelays); r.enumerate<atUint32>("memrelays", memRelays);
} }
savw.relays.insert(savw.relays.end(), memRelays.begin(), memRelays.end());
/* Bare minimum we'll need exactly the same number of links as relays */ /* Bare minimum we'll need exactly the same number of links as relays */
std::vector<MemRelayLink> memRelayLinks(memRelays.size()); std::vector<MemRelayLink> memRelayLinks(memRelays.size());
@ -156,11 +146,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
/* Finish last area */ /* Finish last area */
mlvl.finishLastArea(); mlvl.finishLastArea();
/* Area map */
hecl::ProjectPath mapPath(area.path, _S("/!map.blend"));
if (mapPath.isFile())
mapaTags.push_back(g_curSpec->BuildTagFromPath(mapPath, btok));
/* Populate area record */ /* Populate area record */
mlvl.areas.emplace_back(); mlvl.areas.emplace_back();
MLVL::Area& areaOut = mlvl.areas.back(); MLVL::Area& areaOut = mlvl.areas.back();
@ -242,7 +227,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
{ {
g_ThreadBlenderToken.reset(&btok); g_ThreadBlenderToken.reset(&btok);
std::vector<hecl::ProjectPath> depPaths; std::vector<hecl::ProjectPath> depPaths;
std::vector<Scan> scans;
for (std::unique_ptr<IScriptObject>& obj : layer.objects) for (std::unique_ptr<IScriptObject>& obj : layer.objects)
{ {
if (obj->type == int(urde::EScriptObjectType::MemoryRelay)) if (obj->type == int(urde::EScriptObjectType::MemoryRelay))
@ -260,7 +244,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
{ {
/* We must have a new relay, let's track it */ /* We must have a new relay, let's track it */
memRelayLinks.push_back(linkOut); memRelayLinks.push_back(linkOut);
savw.relays.push_back(memRelay.id);
memRelays.push_back(memRelay.id); memRelays.push_back(memRelay.id);
} }
else /* Lets insert this in it's appropriate location, target order doesn't matter */ else /* Lets insert this in it's appropriate location, target order doesn't matter */
@ -273,27 +256,8 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
} }
} }
} }
else if (obj->type == int(urde::EScriptObjectType::SpecialFunction))
{
SpecialFunction& specialFunc = static_cast<SpecialFunction&>(*obj);
if (specialFunc.function == ESpecialFunctionType::CinematicSkip)
savw.skippableCutscenes.push_back(specialFunc.id);
else if (specialFunc.function == ESpecialFunctionType::ScriptLayerController)
{
savw.layers.emplace_back();
SAVWCommon::Layer& layer = savw.layers.back();
layer.areaId = specialFunc.layerSwitch.area;
layer.layer = specialFunc.layerSwitch.layerIdx;
}
}
else if (obj->type == int(urde::EScriptObjectType::Door))
{
DoorArea& doorArea = static_cast<DoorArea&>(*obj);
savw.doors.push_back(doorArea.id);
}
obj->gatherDependencies(depPaths); obj->gatherDependencies(depPaths);
obj->gatherScans(scans);
} }
/* Cull duplicate paths and add typed hash to list */ /* Cull duplicate paths and add typed hash to list */
@ -307,22 +271,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
areaOut.deps.emplace_back(tag.id, tag.type); areaOut.deps.emplace_back(tag.id, tag.type);
} }
} }
/* Cull duplicate scans and add to list */
for (const Scan& scan : scans)
{
if (!scan.scanId)
continue;
if (addedScans.find(scan.scanId) == addedScans.cend())
{
addedScans.insert(scan.scanId);
hecl::ProjectPath scanPath = UniqueIDBridge::TranslatePakIdToPath(scan.scanId);
savw.scans.emplace_back();
Scan& scanOut = savw.scans.back();
scanOut.scanId = scan.scanId;
scanOut.category = SAVWCommon::EScanCategory(SCAN::GetCategory(scanPath));
}
}
} }
hecl::SystemUTF8View layerU8(layerName); hecl::SystemUTF8View layerU8(layerName);
@ -382,32 +330,176 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
{ {
athena::io::FileWriter fo(outPath.getAbsolutePath()); athena::io::FileWriter fo(outPath.getAbsolutePath());
mlvl.write(fo); mlvl.write(fo);
int64_t rem = fo.position() % 32;
if (rem)
for (int64_t i=0 ; i<32-rem ; ++i)
fo.writeBytes((atInt8*)"\xff", 1);
}
return true;
}
bool MLVL::CookMAPW(const hecl::ProjectPath& outPath,
const World& wld,
hecl::BlenderToken& btok)
{
std::vector<urde::SObjectTag> mapaTags;
mapaTags.reserve(wld.areas.size());
for (const World::Area& area : wld.areas)
{
if (area.path.getPathType() != hecl::ProjectPath::Type::Directory)
continue;
/* Area map */
hecl::ProjectPath mapPath(area.path, _S("/!map.blend"));
if (mapPath.isFile())
mapaTags.push_back(g_curSpec->BuildTagFromPath(mapPath, btok));
} }
/* Write out MAPW */ /* Write out MAPW */
{ {
hecl::ProjectPath mapwCooked = mapwPath.getCookedPath(*g_curSpec->overrideDataSpec(mapwPath, nullptr, btok)); athena::io::FileWriter fo(outPath.getAbsolutePath());
mapwCooked.makeDirChain(false);
athena::io::FileWriter fo(mapwCooked.getAbsolutePath());
fo.writeUint32Big(0xDEADF00D); fo.writeUint32Big(0xDEADF00D);
fo.writeUint32Big(1); fo.writeUint32Big(1);
fo.writeUint32Big(mapaTags.size()); fo.writeUint32Big(mapaTags.size());
for (const urde::SObjectTag& mapa : mapaTags) for (const urde::SObjectTag& mapa : mapaTags)
fo.writeUint32Big(mapa.id); fo.writeUint32Big(mapa.id);
int64_t rem = fo.position() % 32;
if (rem)
for (int64_t i=0 ; i<32-rem ; ++i)
fo.writeBytes((atInt8*)"\xff", 1);
}
return true;
}
bool MLVL::CookSAVW(const hecl::ProjectPath& outPath,
const World& wld)
{
SAVW savw = {};
savw.header.magic = 0xC001D00D;
savw.header.version = 0x3;
std::unordered_set<UniqueID32> addedScans;
for (const World::Area& area : wld.areas)
{
if (area.path.getPathType() != hecl::ProjectPath::Type::Directory)
continue;
hecl::ProjectPath areaPath(area.path, _S("/!area.blend"));
if (!areaPath.isFile())
continue;
hecl::ProjectPath memRelayPath(area.path, _S("/!memoryrelays.yaml"));
std::vector<atUint32> memRelays;
if (memRelayPath.isFile())
{
athena::io::FileReader fr(memRelayPath.getAbsolutePath());
athena::io::YAMLDocReader r;
if (r.parse(&fr))
r.enumerate<atUint32>("memrelays", memRelays);
}
savw.relays.insert(savw.relays.end(), memRelays.begin(), memRelays.end());
hecl::DirectoryEnumerator dEnum(area.path.getAbsolutePath(), hecl::DirectoryEnumerator::Mode::DirsSorted);
for (const hecl::DirectoryEnumerator::Entry& e : dEnum)
{
hecl::SystemString layerName;
hecl::SystemChar* endCh = nullptr;
hecl::StrToUl(e.m_name.c_str(), &endCh, 0);
if (!endCh)
layerName = hecl::StringUtils::TrimWhitespace(e.m_name);
else
layerName = hecl::StringUtils::TrimWhitespace(hecl::SystemString(endCh));
hecl::ProjectPath objectsPath(area.path, e.m_name + _S("/!objects.yaml"));
if (objectsPath.isNone())
continue;
SCLY::ScriptLayer layer;
{
athena::io::FileReader freader(objectsPath.getAbsolutePath());
if (!freader.isOpen())
continue;
if (!BigYAML::ValidateFromYAMLStream<DNAMP1::SCLY::ScriptLayer>(freader))
continue;
athena::io::YAMLDocReader reader;
if (!reader.parse(&freader))
continue;
layer.read(reader);
}
/* Gather memory relays, scans, and dependencies */
{
std::vector<Scan> scans;
for (std::unique_ptr<IScriptObject>& obj : layer.objects)
{
if (obj->type == int(urde::EScriptObjectType::MemoryRelay))
{
MemoryRelay& memRelay = static_cast<MemoryRelay&>(*obj);
auto iter = std::find(memRelays.begin(), memRelays.end(), memRelay.id);
if (iter == memRelays.end())
{
/* We must have a new relay, let's track it */
savw.relays.push_back(memRelay.id);
memRelays.push_back(memRelay.id);
}
}
else if (obj->type == int(urde::EScriptObjectType::SpecialFunction))
{
SpecialFunction& specialFunc = static_cast<SpecialFunction&>(*obj);
if (specialFunc.function == ESpecialFunctionType::CinematicSkip)
savw.skippableCutscenes.push_back(specialFunc.id);
else if (specialFunc.function == ESpecialFunctionType::ScriptLayerController)
{
savw.layers.emplace_back();
SAVWCommon::Layer& layer = savw.layers.back();
layer.areaId = specialFunc.layerSwitch.area;
layer.layer = specialFunc.layerSwitch.layerIdx;
}
}
else if (obj->type == int(urde::EScriptObjectType::Door))
{
DoorArea& doorArea = static_cast<DoorArea&>(*obj);
savw.doors.push_back(doorArea.id);
}
obj->gatherScans(scans);
}
/* Cull duplicate scans and add to list */
for (const Scan& scan : scans)
{
if (!scan.scanId)
continue;
if (addedScans.find(scan.scanId) == addedScans.cend())
{
addedScans.insert(scan.scanId);
hecl::ProjectPath scanPath = UniqueIDBridge::TranslatePakIdToPath(scan.scanId);
savw.scans.emplace_back();
Scan& scanOut = savw.scans.back();
scanOut.scanId = scan.scanId;
scanOut.category = SAVWCommon::EScanCategory(SCAN::GetCategory(scanPath));
}
}
}
}
} }
/* Write out SAVW */ /* Write out SAVW */
{ {
savw.header.areaCount = mlvl.areaCount; savw.header.areaCount = wld.areas.size();
savw.skippableCutsceneCount = savw.skippableCutscenes.size(); savw.skippableCutsceneCount = savw.skippableCutscenes.size();
savw.relayCount = savw.relays.size(); savw.relayCount = savw.relays.size();
savw.layerCount = savw.layers.size(); savw.layerCount = savw.layers.size();
savw.doorCount = savw.doors.size(); savw.doorCount = savw.doors.size();
savw.scanCount = savw.scans.size(); savw.scanCount = savw.scans.size();
hecl::ProjectPath savwCooked = savwPath.getCookedPath(*g_curSpec->overrideDataSpec(savwPath, nullptr, btok)); athena::io::FileWriter fo(outPath.getAbsolutePath());
savwCooked.makeDirChain(false);
athena::io::FileWriter fo(savwCooked.getAbsolutePath());
savw.write(fo); savw.write(fo);
int64_t rem = fo.position() % 32; int64_t rem = fo.position() % 32;
if (rem) if (rem)
@ -417,5 +509,6 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
return true; return true;
} }
} }
} }

View File

@ -155,6 +155,13 @@ struct MLVL : BigYAML
const hecl::ProjectPath& inPath, const hecl::ProjectPath& inPath,
const World& wld, const World& wld,
hecl::BlenderToken& btok); hecl::BlenderToken& btok);
static bool CookMAPW(const hecl::ProjectPath& outPath,
const World& wld,
hecl::BlenderToken& btok);
static bool CookSAVW(const hecl::ProjectPath& outPath,
const World& wld);
}; };
} }

View File

@ -493,7 +493,7 @@ void ANIM::ANIM2::write(athena::io::IStreamWriter& writer) const
keyBmp.setBit(frame); keyBmp.setBit(frame);
frameCount = frame + 1; frameCount = frame + 1;
} }
head.keyBitmapBitCount = frameCount; head.keyBitmapBitCount = keyBmp.getBitCount();
head.duration = frameCount * mainInterval; head.duration = frameCount * mainInterval;
head.boneChannelCount = bones.size(); head.boneChannelCount = bones.size();

View File

@ -463,6 +463,8 @@ struct SpecMP1 : SpecBase
return true; return true;
else if (!strcmp(classType, DNAMP1::HINT::DNAType())) else if (!strcmp(classType, DNAMP1::HINT::DNAType()))
return true; return true;
else if (!strcmp(classType, DNAMP1::EVNT::DNAType()))
return true;
else if (!strcmp(classType, "ATBL")) else if (!strcmp(classType, "ATBL"))
return true; return true;
else if (!strcmp(classType, "MP1OriginalIDs")) else if (!strcmp(classType, "MP1OriginalIDs"))
@ -559,97 +561,97 @@ struct SpecMP1 : SpecBase
urde::SObjectTag resTag; urde::SObjectTag resTag;
if (reader.ClassTypeOperation([&](const char* className) -> bool { if (reader.ClassTypeOperation([&](const char* className) -> bool {
if (!strcmp(className, "GPSM")) if (!strcmp(className, DNAParticle::GPSM<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('PART'); resTag.type = SBIG('PART');
return true; return true;
} }
if (!strcmp(className, "SWSH")) if (!strcmp(className, DNAParticle::SWSH<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('SWHC'); resTag.type = SBIG('SWHC');
return true; return true;
} }
if (!strcmp(className, "ELSM")) if (!strcmp(className, DNAParticle::ELSM<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('ELSC'); resTag.type = SBIG('ELSC');
return true; return true;
} }
if (!strcmp(className, "WPSM")) if (!strcmp(className, DNAParticle::WPSM<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('WPSC'); resTag.type = SBIG('WPSC');
return true; return true;
} }
if (!strcmp(className, "CRSM")) if (!strcmp(className, DNAParticle::CRSM<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('CRSC'); resTag.type = SBIG('CRSC');
return true; return true;
} }
if (!strcmp(className, "DPSM")) if (!strcmp(className, DNAParticle::DPSM<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('DPSC'); resTag.type = SBIG('DPSC');
return true; return true;
} }
else if (!strcmp(className, "FONT")) else if (!strcmp(className, DNAFont::FONT<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('FONT'); resTag.type = SBIG('FONT');
return true; return true;
} }
else if (!strcmp(className, "urde::DNAMP1::EVNT")) else if (!strcmp(className, DNAMP1::EVNT::DNAType()))
{ {
resTag.type = SBIG('EVNT'); resTag.type = SBIG('EVNT');
return true; return true;
} }
else if (!strcmp(className, "urde::DGRP")) else if (!strcmp(className, DNADGRP::DGRP<UniqueID32>::DNAType()))
{ {
resTag.type = SBIG('DGRP'); resTag.type = SBIG('DGRP');
return true; return true;
} }
else if (!strcmp(className, "urde::DNAMP1::STRG")) else if (!strcmp(className, DataSpec::DNAMP1::STRG::DNAType()))
{ {
resTag.type = SBIG('STRG'); resTag.type = SBIG('STRG');
return true; return true;
} }
else if (!strcmp(className, "urde::DNAMP1::SCAN")) else if (!strcmp(className, DataSpec::DNAMP1::SCAN::DNAType()))
{ {
resTag.type = SBIG('SCAN'); resTag.type = SBIG('SCAN');
return true; return true;
} }
else if (!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerRes") || else if (!strcmp(className, DataSpec::DNAMP1::CTweakPlayerRes::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakGunRes") || !strcmp(className, DataSpec::DNAMP1::CTweakGunRes::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakSlideShow") || !strcmp(className, DataSpec::DNAMP1::CTweakSlideShow::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayer") || !strcmp(className, DataSpec::DNAMP1::CTweakPlayer::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakCameraBob") || !strcmp(className, DataSpec::DNAMP1::CTweakCameraBob::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakGame") || !strcmp(className, DataSpec::DNAMP1::CTweakGame::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakTargeting") || !strcmp(className, DataSpec::DNAMP1::CTweakTargeting::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakAutoMapper") || !strcmp(className, DataSpec::DNAMP1::CTweakAutoMapper::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakGui") || !strcmp(className, DataSpec::DNAMP1::CTweakGui::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerControl") || !strcmp(className, DataSpec::DNAMP1::CTweakPlayerControl::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakBall") || !strcmp(className, DataSpec::DNAMP1::CTweakBall::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakParticle") || !strcmp(className, DataSpec::DNAMP1::CTweakParticle::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakGuiColors") || !strcmp(className, DataSpec::DNAMP1::CTweakGuiColors::DNAType()) ||
!strcmp(className, "DataSpec::DNAMP1::CTweakPlayerGun")) !strcmp(className, DataSpec::DNAMP1::CTweakPlayerGun::DNAType()))
{ {
resTag.type = SBIG('CTWK'); resTag.type = SBIG('CTWK');
return true; return true;
} }
else if (!strcmp(className, "DataSpec::DNAMP1::HINT")) else if (!strcmp(className, DataSpec::DNAMP1::HINT::DNAType()))
{ {
resTag.type = SBIG('HINT'); resTag.type = SBIG('HINT');
return true; return true;
} }
else if (!strcmp(className, "ATBL")) else if (!strcmp(className, "ATBL"))
{ {
resTag.type = SBIG('ATBL'); resTag.type = SBIG('ATBL');
return true; return true;
} }
else if (!strcmp(className, "MP1OriginalIDs")) else if (!strcmp(className, "MP1OriginalIDs"))
{ {
resTag.type = SBIG('OIDS'); resTag.type = SBIG('OIDS');
return true; return true;
} }
return false; return false;
})) }))
{ {
resTag.id = path.hash().val32(); resTag.id = path.hash().val32();
fclose(fp); fclose(fp);
@ -676,25 +678,35 @@ struct SpecMP1 : SpecBase
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast, void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
hecl::BlenderToken& btok, FCookProgress progress) hecl::BlenderToken& btok, FCookProgress progress)
{ {
/*
if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".CINF"))) if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".CINF")))
return {SBIG('CINF'), path.hash().val32()}; {
Actor actor = ds.compileActorCharacterOnly();
DNAMP1::ANCS::CookCINF(out, in, actor);
}
else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".CSKR"))) else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".CSKR")))
return {SBIG('CSKR'), path.hash().val32()}; {
Actor actor = ds.compileActorCharacterOnly();
ds.close();
DNAMP1::ANCS::CookCSKR(out, in, actor, [&](const hecl::ProjectPath& modelPath) -> bool {
hecl::ProjectPath cooked;
if (m_pc)
cooked = modelPath.getCookedPath(SpecEntMP1PC);
else
cooked = modelPath.getCookedPath(SpecEntMP1);
doCook(modelPath, cooked, fast, btok, progress);
return true;
});
}
else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".ANIM"))) else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S(".ANIM")))
return {SBIG('ANIM'), path.hash().val32()}; {
*/ Actor actor = ds.compileActorCharacterOnly();
DNAMP1::ANCS::CookANIM(out, in, actor, ds, m_pc);
Actor actor = ds.compileActor(); }
DNAMP1::ANCS::Cook(out, in, actor, ds, m_pc, [&](const hecl::ProjectPath& modelPath) -> bool { else
hecl::ProjectPath cooked; {
if (m_pc) Actor actor = ds.compileActor();
cooked = modelPath.getCookedPath(SpecEntMP1PC); DNAMP1::ANCS::Cook(out, in, actor);
else }
cooked = modelPath.getCookedPath(SpecEntMP1);
doCook(modelPath, cooked, fast, btok, progress);
return true;
});
} }
void cookArea(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast, void cookArea(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
@ -734,9 +746,24 @@ struct SpecMP1 : SpecBase
void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast, void cookWorld(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
hecl::BlenderToken& btok, FCookProgress progress) hecl::BlenderToken& btok, FCookProgress progress)
{ {
BlendStream::World world = ds.compileWorld(); if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S("MAPW")))
ds.close(); {
DNAMP1::MLVL::Cook(out, in, world, btok); BlendStream::World world = ds.compileWorld();
ds.close();
DNAMP1::MLVL::CookMAPW(out, world, btok);
}
else if (hecl::StringUtils::EndsWith(in.getAuxInfo(), _S("SAVW")))
{
BlendStream::World world = ds.compileWorld();
ds.close();
DNAMP1::MLVL::CookSAVW(out, world);
}
else
{
BlendStream::World world = ds.compileWorld();
ds.close();
DNAMP1::MLVL::Cook(out, in, world, btok);
}
} }
void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, void cookGuiFrame(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds,
@ -909,6 +936,10 @@ struct SpecMP1 : SpecBase
{ {
DNAMP1::HINT::Cook(in, out); DNAMP1::HINT::Cook(in, out);
} }
else if (!classStr.compare(DNAMP1::EVNT::DNAType()))
{
DNAMP1::EVNT::Cook(in, out);
}
else if (!classStr.compare("ATBL")) else if (!classStr.compare("ATBL"))
{ {
DNAAudio::ATBL::Cook(in, out); DNAAudio::ATBL::Cook(in, out);
@ -984,6 +1015,12 @@ struct SpecMP1 : SpecBase
font.read(reader); font.read(reader);
font.gatherDependencies(pathsOut); font.gatherDependencies(pathsOut);
} }
else if (!classStr.compare(DNAMP1::EVNT::DNAType()))
{
DNAMP1::EVNT evnt;
evnt.read(reader);
evnt.gatherDependencies(pathsOut);
}
} }
} }

View File

@ -103,9 +103,9 @@ void CGuiTextSupport::Update(float dt)
{ {
if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer()) if (CTextRenderBuffer* buf = GetCurrentPageRenderBuffer())
{ {
float chStartTime = 0.f;
for (s32 i=0 ; i<buf->GetPrimitiveCount() ; ++i) for (s32 i=0 ; i<buf->GetPrimitiveCount() ; ++i)
{ {
float chStartTime = 0.f;
for (const std::pair<float, int>& p : x40_primStartTimes) for (const std::pair<float, int>& p : x40_primStartTimes)
{ {
if (p.second < i) if (p.second < i)
@ -116,14 +116,9 @@ void CGuiTextSupport::Update(float dt)
break; break;
} }
#if 0
CTextRenderBuffer::Primitive prim = x54_renderBuf->GetPrimitive(i);
prim.x0_color1.a = std::min(std::max(0.f, (x30_curTime - chStartTime) / x48_chFadeTime), 1.f);
x54_renderBuf->SetPrimitive(prim, i);
#else
buf->SetPrimitiveOpacity(i, buf->SetPrimitiveOpacity(i,
std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f)); std::min(std::max(0.f, (x3c_curTime - chStartTime) / x54_chFadeTime), 1.f));
#endif chStartTime += 1.f / x58_chRate;
} }
} }
x3c_curTime += dt; x3c_curTime += dt;

2
hecl

@ -1 +1 @@
Subproject commit bcffcf3105090648ba44b3aa69a5d906986be531 Subproject commit 406079b5bcfffd2953f541d27fdc869a07c88c95