CScriptMidi and work on CGameArea loading

This commit is contained in:
Jack Andersen 2017-02-26 19:25:14 -10:00
parent 628e5b41df
commit e923d83617
28 changed files with 446 additions and 112 deletions

View File

@ -70,6 +70,10 @@ void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPo
if (poolIdx > 65535)
Log.report(logvisor::Fatal, "AROT bitmap exceeds 16-bit node addressing; area too complex");
uint32_t childCount = AROTChildCounts[flags];
nodeOff = curOff;
nodeSz = childCount * 2 + 4;
curOff += nodeSz;
if (childNodes.size())
{
for (int i=0 ; i < 1 + ((flags & 0x1) != 0) ; ++i)
@ -82,10 +86,6 @@ void AROTBuilder::Node::nodeCount(size_t& sz, size_t& idxRefs, BitmapPool& bmpPo
}
}
}
uint32_t childCount = AROTChildCounts[flags];
nodeOff = curOff;
nodeSz = childCount * 2 + 4;
curOff += nodeSz;
idxRefs += childCount;
}
}

View File

@ -270,7 +270,8 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
{
addedPaths.insert(path.hash());
urde::SObjectTag tag = g_curSpec->BuildTagFromPath(path, btok);
areaOut.deps.emplace_back(tag.id, tag.type);
if (tag.id != -1)
areaOut.deps.emplace_back(tag.id, tag.type);
}
}
}
@ -308,12 +309,14 @@ bool MLVL::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat
{
addedPaths.insert(path.hash());
urde::SObjectTag tag = g_curSpec->BuildTagFromPath(path, btok);
areaOut.deps.emplace_back(tag.id, tag.type);
if (tag.id != -1)
areaOut.deps.emplace_back(tag.id, tag.type);
}
}
urde::SObjectTag tag = g_curSpec->BuildTagFromPath(areaPath, btok);
areaOut.deps.emplace_back(tag.id, tag.type);
if (tag.id != -1)
areaOut.deps.emplace_back(tag.id, tag.type);
}
++areaIdx;

View File

@ -518,7 +518,7 @@ bool MREA::PCCook(const hecl::ProjectPath& outPath,
}
}
if (!good)
secs.emplace_back(0, 0);
secs.emplace_back(4, 0);
}
/* PATH */

View File

@ -13,11 +13,11 @@ struct Midi : IScriptObject
{
DECL_YAML
String<-1> name;
Value<bool> unknown1;
Value<bool> active;
UniqueID32 song;
Value<float> unknown2;
Value<float> unknown3;
Value<atUint32> unknown4;
Value<float> fadeInTime;
Value<float> fadeOutTime;
Value<atUint32> volume;
void nameIDs(PAKRouter<PAKBridge>& pakRouter) const
{

View File

@ -532,10 +532,19 @@ void ProjectResourceFactoryBase::AsyncTask::CookComplete()
/* Ready for buffer transaction at this point */
u32 availSz = std::max(0, s32(fr.length()) - s32(x14_resOffset));
x14_resSize = std::min(x14_resSize, availSz);
x10_loadBuffer.reset(new u8[x14_resSize]);
m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath,
x10_loadBuffer.get(),
x14_resSize, x14_resOffset);
if (xc_targetDataRawPtr)
{
m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath,
xc_targetDataRawPtr,
x14_resSize, x14_resOffset);
}
else
{
x10_loadBuffer.reset(new u8[x14_resSize]);
m_bufTransaction = m_parent.m_clientProc.addBufferTransaction(m_cookedPath,
x10_loadBuffer.get(),
x14_resSize, x14_resOffset);
}
}
bool ProjectResourceFactoryBase::AsyncTask::AsyncPump()
@ -778,6 +787,17 @@ ProjectResourceFactoryBase::LoadResourcePartAsync(const urde::SObjectTag& tag,
std::make_shared<AsyncTask>(*this, tag, target, size, off))).first->second;
}
std::shared_ptr<ProjectResourceFactoryBase::AsyncTask>
ProjectResourceFactoryBase::LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, u8* target)
{
if ((tag.id & 0xffffffff) == 0xffffffff || !tag.id)
Log.report(logvisor::Fatal, "attempted to access null id");
if (m_asyncLoadList.find(tag) != m_asyncLoadList.end())
return {};
return m_asyncLoadList.emplace(std::make_pair(tag,
std::make_shared<AsyncTask>(*this, tag, target, size, off))).first->second;
}
std::unique_ptr<u8[]> ProjectResourceFactoryBase::LoadResourceSync(const urde::SObjectTag& tag)
{
if ((tag.id & 0xffffffff) == 0xffffffff || !tag.id)
@ -986,6 +1006,13 @@ bool ProjectResourceFactoryBase::AsyncPumpTask(
task.x0_tag.type.toString().c_str(),
u32(task.x0_tag.id));
}
else if (task.xc_targetDataRawPtr)
{
/* Buffer only raw */
Log.report(logvisor::Info, "async-loaded %.4s %08X",
task.x0_tag.type.toString().c_str(),
u32(task.x0_tag.id));
}
}
it = m_asyncLoadList.erase(it);

View File

@ -27,6 +27,7 @@ public:
SObjectTag x0_tag;
//IDvdRequest* x8_dvdReq = nullptr;
std::unique_ptr<u8[]>* xc_targetDataPtr = nullptr;
u8* xc_targetDataRawPtr = nullptr;
IObj** xc_targetObjPtr = nullptr;
std::unique_ptr<u8[]> x10_loadBuffer;
u32 x14_resSize = UINT32_MAX;
@ -50,6 +51,11 @@ public:
: m_parent(parent), x0_tag(tag), xc_targetDataPtr(&ptr), x14_resSize(size),
x14_resOffset(off) {}
AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag,
u8* ptr, u32 size, u32 off)
: m_parent(parent), x0_tag(tag), xc_targetDataRawPtr(ptr), x14_resSize(size),
x14_resOffset(off) {}
AsyncTask(ProjectResourceFactoryBase& parent, const SObjectTag& tag,
IObj** ptr, const CVParamTransfer& xfer, CObjectReference* selfRef)
: m_parent(parent), x0_tag(tag), xc_targetObjPtr(ptr), x18_cvXfer(xfer), m_selfRef(selfRef) {}
@ -131,6 +137,7 @@ public:
u32 ResourceSize(const SObjectTag& tag);
std::shared_ptr<AsyncTask> LoadResourceAsync(const urde::SObjectTag& tag, std::unique_ptr<u8[]>& target);
std::shared_ptr<AsyncTask> LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, std::unique_ptr<u8[]>& target);
std::shared_ptr<AsyncTask> LoadResourcePartAsync(const urde::SObjectTag& tag, u32 size, u32 off, u8* target);
std::unique_ptr<u8[]> LoadResourceSync(const urde::SObjectTag& tag);
std::unique_ptr<u8[]> LoadResourcePartSync(const urde::SObjectTag& tag, u32 size, u32 off);

View File

@ -28,6 +28,7 @@
#include "Runtime/CScannableObjectInfo.hpp"
#include "Audio/CAudioGroupSet.hpp"
#include "Audio/CSfxManager.hpp"
#include "Audio/CMidiManager.hpp"
#include "Runtime/CDependencyGroup.hpp"
#include "DataSpec/DNACommon/TXTR.hpp"
#include "CSimplePool.hpp"
@ -109,6 +110,7 @@ ProjectResourceFactoryMP1::ProjectResourceFactoryMP1(hecl::ClientProcess& client
m_factoryMgr.AddFactory(FOURCC('DCLN'), FFactoryFunc(FCollidableOBBTreeGroupFactory));
m_factoryMgr.AddFactory(FOURCC('DGRP'), FFactoryFunc(FDependencyGroupFactory));
m_factoryMgr.AddFactory(FOURCC('AGSC'), FMemFactoryFunc(FAudioGroupSetDataFactory));
m_factoryMgr.AddFactory(FOURCC('CSNG'), FFactoryFunc(FMidiDataFactory));
m_factoryMgr.AddFactory(FOURCC('ATBL'), FFactoryFunc(FAudioTranslationTableFactory));
m_factoryMgr.AddFactory(FOURCC('STRG'), FFactoryFunc(FStringTableFactory));
m_factoryMgr.AddFactory(FOURCC('HINT'), FFactoryFunc(FHintFactory));

View File

@ -3,9 +3,58 @@
namespace urde
{
std::unordered_set<CMidiHandle> CMidiManager::m_MidiWrappers = {};
void CMidiManager::StopAll()
{
for (auto it = m_MidiWrappers.begin() ; it != m_MidiWrappers.end() ;)
it = Stop(it, 0);
}
void CMidiManager::Stop(const CMidiHandle& handle, float fadeTime)
{
handle->GetAudioSysHandle()->stopSong(fadeTime);
m_MidiWrappers.erase(handle);
}
std::unordered_set<CMidiHandle>::iterator
CMidiManager::Stop(std::unordered_set<CMidiHandle>::iterator handle, float fadeTime)
{
const CMidiHandle& h = *handle;
h->GetAudioSysHandle()->stopSong(fadeTime);
return m_MidiWrappers.erase(handle);
}
CMidiHandle CMidiManager::Play(const CMidiData& data, float fadeTime, bool stopExisting, float volume)
{
if (stopExisting)
for (auto it = m_MidiWrappers.begin() ; it != m_MidiWrappers.end() ;)
it = Stop(it, fadeTime);
CMidiHandle handle = *m_MidiWrappers.insert(std::make_shared<CMidiWrapper>()).first;
handle->SetAudioSysHandle(CAudioSys::GetAmuseEngine().seqPlay(
data.GetGroupId(), data.GetSetupId(), data.GetArrData()));
handle->GetAudioSysHandle()->setVolume(volume, fadeTime);
handle->SetSongId(data.GetSetupId());
return handle;
}
CMidiManager::CMidiData::CMidiData(CInputStream& in)
{
in.readUint32Big();
x0_setupId = in.readUint32Big();
x2_groupId = in.readUint32Big();
x4_agscId = in.readUint32Big();
u32 length = in.readUint32Big();
x8_arrData.reset(new u8[length]);
in.readUBytesToBuf(x8_arrData.get(), length);
}
CFactoryFnReturn FMidiDataFactory(const SObjectTag& tag, CInputStream& in,
const CVParamTransfer& parms,
CObjectReference* selfRef)
{
return TToken<CMidiManager::CMidiData>::GetIObjObjectFor(std::make_unique<CMidiManager::CMidiData>(in));
}
}

View File

@ -1,15 +1,62 @@
#ifndef __URDE_CMIDIMANAGER_HPP__
#define __URDE_CMIDIMANAGER_HPP__
#include "CSfxManager.hpp"
namespace urde
{
class CMidiManager
{
public:
class CMidiData
{
u16 x0_setupId;
u16 x2_groupId;
ResId x4_agscId;
std::unique_ptr<u8[]> x8_arrData;
public:
u16 GetSetupId() const { return x0_setupId; }
u16 GetGroupId() const { return x2_groupId; }
ResId GetAGSCAssetId() const { return x4_agscId; }
const u8* GetArrData() const { return x8_arrData.get(); }
CMidiData(CInputStream& in);
};
class CMidiWrapper
{
std::shared_ptr<amuse::Sequencer> x0_sequencer;
//CSfxHandle x4_handle;
u16 x8_songId;
bool xa_available = true;
public:
const std::shared_ptr<amuse::Sequencer>& GetAudioSysHandle() const { return x0_sequencer; }
void SetAudioSysHandle(const std::shared_ptr<amuse::Sequencer>& sequencer) { x0_sequencer = sequencer; }
//const CSfxHandle& GetManagerHandle() const { return x4_handle; }
//void SetMidiHandle(const CSfxHandle& handle) { x4_handle = handle; }
bool IsAvailable() const { return xa_available; }
void SetAvailable(bool available) { xa_available = available; }
u16 GetSongId() const { return x8_songId; }
void SetSongId(u16 songId) { x8_songId = songId; }
};
using CMidiHandle = std::shared_ptr<CMidiWrapper>;
static void StopAll();
static void Stop(const CMidiHandle& handle, float fadeTime);
static std::unordered_set<CMidiHandle>::iterator
Stop(std::unordered_set<CMidiHandle>::iterator handle, float fadeTime);
static CMidiHandle Play(const CMidiData& data, float fadeTime, bool stopExisting, float volume);
private:
static std::unordered_set<CMidiHandle> m_MidiWrappers;
};
CFactoryFnReturn FMidiDataFactory(const SObjectTag& tag, CInputStream& in,
const CVParamTransfer& parms,
CObjectReference* selfRef);
using CMidiHandle = CMidiManager::CMidiHandle;
}
#endif // __URDE_CMIDIMANAGER_HPP__

View File

@ -16,14 +16,14 @@ public:
{
float x0_fadeIn, x4_fadeOut, x8_volume;
std::string xc_fileName;
u32 x1c_handle;
ResId x1c_res;
Audio(float fadeIn, float fadeOut, float vol, const std::string& fileName, u32 handle)
: x0_fadeIn(fadeIn), x4_fadeOut(fadeOut), x8_volume(vol), xc_fileName(fileName), x1c_handle(handle) {}
: x0_fadeIn(fadeIn), x4_fadeOut(fadeOut), x8_volume(vol), xc_fileName(fileName), x1c_res(handle) {}
float GetFadeIn() const { return x0_fadeIn; }
float GetFadeOut() const { return x4_fadeOut; }
float GetVolume() const { return x8_volume; }
const std::string& GetFileName() const { return xc_fileName; }
u32 GetHandle() const { return x1c_handle; }
ResId GetResId() const { return x1c_res; }
static Audio None() { return Audio{0.f, 0.f, 0.f, "", 0}; }
};
enum class EType

View File

@ -703,14 +703,14 @@ void CStateManager::InitializeState(ResId mlvlId, TAreaId aid, ResId mreaId)
bool hadRandom = x900_activeRandom != nullptr;
SetActiveRandomToDefault();
if (xb3c_initPhase == InitPhase::LoadWorld)
if (xb3c_initPhase == EInitPhase::LoadWorld)
{
CreateStandardGameObjects();
x850_world.reset(new CWorld(*g_SimplePool, *g_ResFactory, mlvlId));
xb3c_initPhase = InitPhase::LoadFirstArea;
xb3c_initPhase = EInitPhase::LoadFirstArea;
}
if (xb3c_initPhase == InitPhase::LoadFirstArea)
if (xb3c_initPhase == EInitPhase::LoadFirstArea)
{
if (!x8f0_shadowTex.IsLoaded())
return;
@ -725,7 +725,7 @@ void CStateManager::InitializeState(ResId mlvlId, TAreaId aid, ResId mreaId)
area->StartStreamIn(*this);
return;
}
xb3c_initPhase = InitPhase::Done;
xb3c_initPhase = EInitPhase::Done;
}
SetCurrentAreaId(x8cc_nextAreaId);

View File

@ -147,12 +147,12 @@ class CStateManager
std::set<std::string> xab4_uniqueInstanceNames;
enum class InitPhase
enum class EInitPhase
{
LoadWorld,
LoadFirstArea,
Done
} xb3c_initPhase = InitPhase::LoadWorld;
} xb3c_initPhase = EInitPhase::LoadWorld;
CFinalInput xb54_finalInput;
CCameraFilterPass xb84_camFilterPasses[9];

View File

@ -99,10 +99,10 @@ void CAreaOctTree::SwapTreeNode(u8* ptr, Node::ETreeType type)
}
}
CAreaOctTree::CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, u8* buf, std::unique_ptr<u8[]>&& treeBuf,
u32 matCount, u32* materials, u8* vertMats, u8* edgeMats, u8* polyMats,
u32 edgeCount, CCollisionEdge* edges, u32 polyCount, u16* polyEdges,
u32 vertCount, zeus::CVector3f* verts)
CAreaOctTree::CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, const u8* buf, std::unique_ptr<u8[]>&& treeBuf,
u32 matCount, const u32* materials, const u8* vertMats, const u8* edgeMats, const u8* polyMats,
u32 edgeCount, const CCollisionEdge* edges, u32 polyCount, const u16* polyEdges,
u32 vertCount, const zeus::CVector3f* verts)
: x0_aabb(aabb), x18_treeType(treeType), x1c_buf(buf), x20_treeBuf(std::move(treeBuf)),
x24_matCount(matCount), x2c_vertMats(vertMats),
x30_edgeMats(edgeMats), x34_polyMats(polyMats), x38_edgeCount(edgeCount),
@ -140,7 +140,7 @@ CAreaOctTree::CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, u
}
}
std::unique_ptr<CAreaOctTree> CAreaOctTree::MakeFromMemory(void* buf, unsigned int size)
std::unique_ptr<CAreaOctTree> CAreaOctTree::MakeFromMemory(const void* buf, unsigned int size)
{
athena::io::MemoryReader r(buf, size);
r.readUint32Big();
@ -149,48 +149,48 @@ std::unique_ptr<CAreaOctTree> CAreaOctTree::MakeFromMemory(void* buf, unsigned i
aabb.readBoundingBoxBig(r);
Node::ETreeType nodeType = Node::ETreeType(r.readUint32Big());
u32 treeSize = r.readUint32Big();
u8* cur = reinterpret_cast<u8*>(buf) + r.position();
const u8* cur = reinterpret_cast<const u8*>(buf) + r.position();
std::unique_ptr<u8[]> treeBuf(new u8[treeSize]);
memmove(treeBuf.get(), cur, treeSize);
cur += treeSize;
u32 matCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 matCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
u32* matBuf = reinterpret_cast<u32*>(cur);
const u32* matBuf = reinterpret_cast<const u32*>(cur);
cur += 4 * matCount;
u32 vertMatsCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 vertMatsCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
u8* vertMatsBuf = cur;
const u8* vertMatsBuf = cur;
cur += vertMatsCount;
u32 edgeMatsCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 edgeMatsCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
u8* edgeMatsBuf = cur;
const u8* edgeMatsBuf = cur;
cur += edgeMatsCount;
u32 polyMatsCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 polyMatsCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
u8* polyMatsBuf = cur;
const u8* polyMatsBuf = cur;
cur += polyMatsCount;
u32 edgeCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 edgeCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
CCollisionEdge* edgeBuf = reinterpret_cast<CCollisionEdge*>(cur);
const CCollisionEdge* edgeBuf = reinterpret_cast<const CCollisionEdge*>(cur);
cur += edgeCount * sizeof(edgeCount);
u32 polyCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 polyCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
u16* polyBuf = reinterpret_cast<u16*>(cur);
const u16* polyBuf = reinterpret_cast<const u16*>(cur);
cur += polyCount * 2;
u32 vertCount = hecl::SBig(*reinterpret_cast<u32*>(cur));
u32 vertCount = hecl::SBig(*reinterpret_cast<const u32*>(cur));
cur += 4;
zeus::CVector3f* vertBuf = reinterpret_cast<zeus::CVector3f*>(cur);
const zeus::CVector3f* vertBuf = reinterpret_cast<const zeus::CVector3f*>(cur);
cur += polyCount * 2;
return std::make_unique<CAreaOctTree>(aabb, nodeType, reinterpret_cast<u8*>(buf), std::move(treeBuf),
return std::make_unique<CAreaOctTree>(aabb, nodeType, reinterpret_cast<const u8*>(buf), std::move(treeBuf),
matCount, matBuf, vertMatsBuf, edgeMatsBuf, polyMatsBuf,
edgeCount, edgeBuf, polyCount, polyBuf, vertCount, vertBuf);
}

View File

@ -94,13 +94,13 @@ public:
zeus::CAABox x0_aabb;
Node::ETreeType x18_treeType;
u8* x1c_buf;
const u8* x1c_buf;
std::unique_ptr<u8[]> x20_treeBuf;
u32 x24_matCount;
std::vector<u32> x28_materials;
u8* x2c_vertMats;
u8* x30_edgeMats;
u8* x34_polyMats;
const u8* x2c_vertMats;
const u8* x30_edgeMats;
const u8* x34_polyMats;
u32 x38_edgeCount;
std::vector<CCollisionEdge> x3c_edges;
u32 x40_polyCount;
@ -111,10 +111,10 @@ public:
void SwapTreeNode(u8* ptr, Node::ETreeType type);
public:
CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, u8* buf, std::unique_ptr<u8[]>&& treeBuf,
u32 matCount, u32* materials, u8* vertMats, u8* edgeMats, u8* polyMats,
u32 edgeCount, CCollisionEdge* edges, u32 polyCount, u16* polyEdges,
u32 vertCount, zeus::CVector3f* verts);
CAreaOctTree(const zeus::CAABox& aabb, Node::ETreeType treeType, const u8* buf, std::unique_ptr<u8[]>&& treeBuf,
u32 matCount, const u32* materials, const u8* vertMats, const u8* edgeMats, const u8* polyMats,
u32 edgeCount, const CCollisionEdge* edges, u32 polyCount, const u16* polyEdges,
u32 vertCount, const zeus::CVector3f* verts);
Node GetRootNode() const { return Node(x20_treeBuf.get(), x0_aabb, *this, x18_treeType); }
const u8* GetTreeMemory() const { return x20_treeBuf.get(); }
@ -129,7 +129,7 @@ public:
const u16* GetTriangleVertexIndices(u16 idx) const;
const u16* GetTriangleEdgeIndices(u16 idx) const;
static std::unique_ptr<CAreaOctTree> MakeFromMemory(void* buf, unsigned int size);
static std::unique_ptr<CAreaOctTree> MakeFromMemory(const void* buf, unsigned int size);
};
}

View File

@ -353,5 +353,12 @@ bool CInGameGuiManager::GetIsGameDraw() const
return x3c_pauseScreen->GetX50_25();
}
std::string CInGameGuiManager::GetIdentifierForMidiEvent(ResId world, ResId area,
const std::string& midiObj)
{
return hecl::Format("World %8.8x Area %8.8x MidiObject: %s",
u32(world), u32(area), midiObj.c_str());
}
}
}

View File

@ -135,6 +135,7 @@ public:
bool IsInGame() const { return x1c0_nextState >= EInGameGuiState::Zero && x1c0_nextState <= EInGameGuiState::InGame; }
bool IsInSaveUI() const { return x1f8_27_inSaveUI; }
bool GetIsGameDraw() const;
static std::string GetIdentifierForMidiEvent(ResId world, ResId area, const std::string& midiObj);
};
}

View File

@ -379,7 +379,7 @@ CIOWin::EMessageReturn CMFGameLoader::OnMessage(const CArchitectureMessage& msg,
wldState.GetLayerState());
}
if (x14_stateMgr->xb3c_initPhase != CStateManager::InitPhase::Done)
if (x14_stateMgr->xb3c_initPhase != CStateManager::EInitPhase::Done)
{
CWorldState& wldState = g_GameState->CurrentWorldState();
x14_stateMgr->InitializeState(wldState.GetWorldAssetId(),

View File

@ -53,6 +53,7 @@ CENTITY_TYPES = (
('CScriptPointOfInterest', 'World/CScriptPointOfInterest.hpp'),
('CScriptRoomAcoustics', 'World/CScriptRoomAcoustics.hpp'),
('CScriptSound', 'World/CScriptSound.hpp'),
('CScriptMidi', 'World/CScriptMidi.hpp'),
('CScriptSpawnPoint', 'World/CScriptSpawnPoint.hpp'),
('CScriptSpecialFunction', 'World/CScriptSpecialFunction.hpp'),
('CScriptSpiderBallAttractionSurface', 'World/CScriptSpiderBallAttractionSurface.hpp'),

View File

@ -9,27 +9,29 @@
namespace urde
{
CAreaRenderOctTree::CAreaRenderOctTree(std::unique_ptr<u8[]>&& buf)
: x0_buf(std::move(buf))
static logvisor::Module Log("CGameArea");
CAreaRenderOctTree::CAreaRenderOctTree(const u8* buf)
: x0_buf(buf)
{
athena::io::MemoryReader r(x0_buf.get() + 8, INT32_MAX);
athena::io::MemoryReader r(x0_buf + 8, INT32_MAX);
x8_bitmapCount = r.readUint32Big();
xc_meshCount = r.readUint32Big();
x10_nodeCount = r.readUint32Big();
x14_bitmapWordCount = (xc_meshCount + 31) / 32;
x18_aabb.readBoundingBoxBig(r);
x30_bitmaps = reinterpret_cast<u32*>(x0_buf.get() + 64);
x30_bitmaps = reinterpret_cast<const u32*>(x0_buf + 64);
u32 wc = x14_bitmapWordCount * x8_bitmapCount;
for (u32 i=0 ; i<wc ; ++i)
x30_bitmaps[i] = hecl::SBig(x30_bitmaps[i]);
const_cast<u32*>(x30_bitmaps)[i] = hecl::SBig(x30_bitmaps[i]);
x34_indirectionTable = x30_bitmaps + wc;
x38_entries = reinterpret_cast<u8*>(x34_indirectionTable) + x10_nodeCount;
x38_entries = reinterpret_cast<const u8*>(x34_indirectionTable + x10_nodeCount);
for (u32 i=0 ; i<x10_nodeCount ; ++i)
{
x34_indirectionTable[i] = hecl::SBig(x34_indirectionTable[i]);
Node* n = reinterpret_cast<Node*>(x38_entries + x34_indirectionTable[i]);
const_cast<u32*>(x34_indirectionTable)[i] = hecl::SBig(x34_indirectionTable[i]);
Node* n = reinterpret_cast<Node*>(const_cast<u8*>(x38_entries) + x34_indirectionTable[i]);
n->x0_bitmapIdx = hecl::SBig(n->x0_bitmapIdx);
n->x2_flags = hecl::SBig(n->x2_flags);
if (n->x2_flags)
@ -596,42 +598,42 @@ bool CGameArea::StartStreamingMainArea()
switch (xf4_phase)
{
case Phase::LoadHeader:
case EPhase::LoadHeader:
{
x110_mreaSecBufs.reserve(3);
AllocNewAreaData(0, 96);
x12c_postConstructed.reset(new CPostConstructed());
xf4_phase = Phase::LoadSecSizes;
xf4_phase = EPhase::LoadSecSizes;
break;
}
case Phase::LoadSecSizes:
case EPhase::LoadSecSizes:
{
CullDeadAreaRequests();
if (xf8_loadTransactions.size())
break;
MREAHeader header = VerifyHeader();
AllocNewAreaData(x110_mreaSecBufs[0].second, ROUND_UP_32(header.secCount * 4));
xf4_phase = Phase::ReserveSections;
xf4_phase = EPhase::ReserveSections;
break;
}
case Phase::ReserveSections:
case EPhase::ReserveSections:
{
CullDeadAreaRequests();
if (xf8_loadTransactions.size())
break;
x110_mreaSecBufs.reserve(GetNumPartSizes() + 2);
//x110_mreaSecBufs.reserve(GetNumPartSizes() + 2);
x124_secCount = 0;
x128_mreaDataOffset = x110_mreaSecBufs[0].second + x110_mreaSecBufs[1].second;
xf4_phase = Phase::LoadDataSections;
xf4_phase = EPhase::LoadDataSections;
break;
}
case Phase::LoadDataSections:
case EPhase::LoadDataSections:
{
CullDeadAreaRequests();
u32 totalSz = 0;
u32 secCount = GetNumPartSizes();
for (u32 i=2 ; i<secCount ; ++i)
for (u32 i=0 ; i<secCount ; ++i)
totalSz += hecl::SBig(reinterpret_cast<u32*>(x110_mreaSecBufs[1].first.get())[i]);
AllocNewAreaData(x128_mreaDataOffset, totalSz);
@ -641,17 +643,17 @@ bool CGameArea::StartStreamingMainArea()
m_resolvedBufs.emplace_back(x110_mreaSecBufs[1].first.get(), x110_mreaSecBufs[1].second);
u32 curOff = 0;
for (u32 i=2 ; i<secCount ; ++i)
for (u32 i=0 ; i<secCount ; ++i)
{
u32 size = hecl::SBig(reinterpret_cast<u32*>(x110_mreaSecBufs[1].first.get())[i]);
m_resolvedBufs.emplace_back(x110_mreaSecBufs[2].first.get() + curOff, size);
curOff += size;
}
xf4_phase = Phase::WaitForFinish;
xf4_phase = EPhase::WaitForFinish;
break;
}
case Phase::WaitForFinish:
case EPhase::WaitForFinish:
{
CullDeadAreaRequests();
if (xf8_loadTransactions.size())
@ -684,7 +686,7 @@ void CGameArea::AllocNewAreaData(int offset, int size)
xf8_loadTransactions.push_back(
static_cast<ProjectResourceFactoryBase*>(g_ResFactory)->
LoadResourcePartAsync(SObjectTag{FOURCC('MREA'), x84_mrea}, size, offset,
x110_mreaSecBufs.back().first));
x110_mreaSecBufs.back().first.get()));
}
bool CGameArea::Invalidate(CStateManager& mgr)
@ -707,6 +709,32 @@ void CGameArea::CullDeadAreaRequests()
void CGameArea::StartStreamIn(CStateManager& mgr)
{
if (xf0_24_postConstructed || xf0_27_paused)
return;
VerifyTokenList(mgr);
if (!xf0_26_tokensReady)
{
u32 notLoaded = 0;
for (CToken& tok : xdc_tokens)
{
tok.Lock();
if (!tok.IsLoaded())
++notLoaded;
}
if (notLoaded)
return;
xf0_26_tokensReady = true;
}
StartStreamingMainArea();
if (xf4_phase != EPhase::WaitForFinish)
return;
CullDeadAreaRequests();
if (xf8_loadTransactions.size())
return;
Validate(mgr);
}
void CGameArea::Validate(CStateManager& mgr)
@ -774,7 +802,7 @@ void CGameArea::LoadScriptObjects(CStateManager& mgr)
mgr.InitScriptObjects(objIds);
}
std::pair<u8*, u32> CGameArea::GetLayerScriptBuffer(int layer)
std::pair<const u8*, u32> CGameArea::GetLayerScriptBuffer(int layer)
{
if (!xf0_24_postConstructed)
return {};
@ -785,32 +813,35 @@ void CGameArea::PostConstructArea()
{
MREAHeader header = VerifyHeader();
auto secIt = x110_mreaSecBufs.begin() + 2;
auto secIt = m_resolvedBufs.begin() + 2;
/* Materials */
++secIt;
u32 sec = 3;
/* Models */
if (header.modelCount)
for (u32 i=0 ; i<header.modelCount ; ++i)
{
for (u32 i=0 ; i<header.modelCount ; ++i)
{
u32 surfCount = hecl::SBig(*reinterpret_cast<u32*>((secIt+6)->first.get()));
secIt += 7 + surfCount;
}
u32 surfCount = hecl::SBig(*reinterpret_cast<const u32*>((secIt+4)->first));
secIt += 5 + surfCount;
sec += 5 + surfCount;
}
/* Render octree */
if (header.version == 15 && header.arotSecIdx != -1)
{
x12c_postConstructed->xc_octTree.emplace(std::move(secIt->first));
x12c_postConstructed->xc_octTree.emplace(secIt->first);
++secIt;
}
/* Scriptable layer section */
x12c_postConstructed->x10c8_sclyBuf = std::move(secIt->first);
x12c_postConstructed->x10c8_sclyBuf = secIt->first;
x12c_postConstructed->x10d0_sclySize = secIt->second;
++secIt;
/* Collision section */
std::unique_ptr<CAreaOctTree> collision = CAreaOctTree::MakeFromMemory(secIt->first.get(), secIt->second);
std::unique_ptr<CAreaOctTree> collision = CAreaOctTree::MakeFromMemory(secIt->first, secIt->second);
if (collision)
{
x12c_postConstructed->x0_collision = std::move(collision);
@ -824,7 +855,7 @@ void CGameArea::PostConstructArea()
/* Lights section */
if (header.version > 6)
{
athena::io::MemoryReader r(secIt->first.get(), secIt->second);
athena::io::MemoryReader r(secIt->first, secIt->second);
u32 magic = r.readUint32Big();
if (magic == 0xBABEDEAD)
{
@ -855,7 +886,7 @@ void CGameArea::PostConstructArea()
/* PVS section */
if (header.version > 7)
{
athena::io::MemoryReader r(secIt->first.get(), secIt->second);
athena::io::MemoryReader r(secIt->first, secIt->second);
u32 magic = r.readUint32Big();
if (magic == 'VISI')
{
@ -864,7 +895,7 @@ void CGameArea::PostConstructArea()
{
x12c_postConstructed->x1108_29_ = r.readBool();
x12c_postConstructed->x1108_30_ = r.readBool();
x12c_postConstructed->xa0_pvs = std::make_unique<CPVSAreaSet>(secIt->first.get() + r.position(),
x12c_postConstructed->xa0_pvs = std::make_unique<CPVSAreaSet>(secIt->first + r.position(),
secIt->second - r.position());
}
}
@ -875,7 +906,7 @@ void CGameArea::PostConstructArea()
/* Pathfinding section */
if (header.version > 9)
{
athena::io::MemoryReader r(secIt->first.get(), secIt->second);
athena::io::MemoryReader r(secIt->first, secIt->second);
ResId pathId = r.readUint32Big();
x12c_postConstructed->x10ac_path = g_SimplePool->GetObj(SObjectTag{FOURCC('PATH'), pathId});
++secIt;
@ -889,7 +920,7 @@ void CGameArea::PostConstructArea()
/* Resolve layer pointers */
if (x12c_postConstructed->x10c8_sclyBuf)
{
athena::io::MemoryReader r(x12c_postConstructed->x10c8_sclyBuf.get(), x12c_postConstructed->x10d0_sclySize);
athena::io::MemoryReader r(x12c_postConstructed->x10c8_sclyBuf, x12c_postConstructed->x10d0_sclySize);
u32 magic = r.readUint32Big();
if (magic == 'SCLY')
{
@ -898,7 +929,7 @@ void CGameArea::PostConstructArea()
x12c_postConstructed->x110c_layerPtrs.resize(layerCount);
for (u32 l=0 ; l<layerCount ; ++l)
x12c_postConstructed->x110c_layerPtrs[l].second = r.readUint32Big();
u8* ptr = x12c_postConstructed->x10c8_sclyBuf.get() + r.position();
const u8* ptr = x12c_postConstructed->x10c8_sclyBuf + r.position();
for (u32 l=0 ; l<layerCount ; ++l)
{
x12c_postConstructed->x110c_layerPtrs[l].first = ptr;
@ -967,6 +998,9 @@ CGameArea::MREAHeader CGameArea::VerifyHeader() const
MREAHeader header;
athena::io::MemoryReader r(x110_mreaSecBufs[0].first.get() + 4, INT32_MAX);
u32 version = r.readUint32Big();
if (!(version & 0x10000))
Log.report(logvisor::Fatal, "Attempted to load non-URDE MREA");
version &= ~0x10000;
header.version = (version >= 12 && version <= 15) ? version : 0;
if (!header.version)
return {};

View File

@ -61,17 +61,17 @@ struct CAreaRenderOctTree
const zeus::CAABox& testAABB) const;
};
std::unique_ptr<u8[]> x0_buf;
const u8* x0_buf;
u32 x8_bitmapCount;
u32 xc_meshCount;
u32 x10_nodeCount;
u32 x14_bitmapWordCount;
zeus::CAABox x18_aabb;
u32* x30_bitmaps;
u32* x34_indirectionTable;
u8* x38_entries;
const u32* x30_bitmaps;
const u32* x34_indirectionTable;
const u8* x38_entries;
CAreaRenderOctTree(std::unique_ptr<u8[]>&& buf);
CAreaRenderOctTree(const u8* buf);
void FindOverlappingModels(std::vector<u32>& out, const zeus::CAABox& testAABB) const;
};
@ -110,14 +110,14 @@ class CGameArea : public IGameArea
u8 _dummy = 0;
};
enum class Phase
enum class EPhase
{
LoadHeader,
LoadSecSizes,
ReserveSections,
LoadDataSections,
WaitForFinish
} xf4_phase = Phase::LoadHeader;
} xf4_phase = EPhase::LoadHeader;
std::list<std::shared_ptr<ProjectResourceFactoryBase::AsyncTask>> xf8_loadTransactions;
@ -187,7 +187,7 @@ public:
u32 x10bc_ = 0;
std::unique_ptr<CAreaObjectList> x10c0_areaObjs;
std::unique_ptr<CAreaFog> x10c4_areaFog;
std::unique_ptr<u8[]> x10c8_sclyBuf;
const u8* x10c8_sclyBuf = nullptr;
u32 x10d0_sclySize = 0;
u32 x10d4_ = 0;
const CScriptAreaAttributes* x10d8_areaAttributes = nullptr;
@ -213,7 +213,7 @@ public:
};
u8 _dummy = 0;
};
std::vector<std::pair<u8*, u32>> x110c_layerPtrs;
std::vector<std::pair<const u8*, u32>> x110c_layerPtrs;
float x111c_thermalCurrent = 0.f;
float x1120_thermalSpeed = 0.f;
float x1124_thermalTarget = 0.f;
@ -226,7 +226,7 @@ public:
};
private:
std::vector<std::pair<std::unique_ptr<u8[]>, int>> x110_mreaSecBufs;
std::vector<std::pair<u8*, int>> m_resolvedBufs;
std::vector<std::pair<const u8*, int>> m_resolvedBufs;
u32 x124_secCount = 0;
u32 x128_mreaDataOffset = 0;
std::unique_ptr<CPostConstructed> x12c_postConstructed;
@ -303,7 +303,7 @@ public:
void StartStreamIn(CStateManager& mgr);
void Validate(CStateManager& mgr);
void LoadScriptObjects(CStateManager& mgr);
std::pair<u8*, u32> GetLayerScriptBuffer(int layer);
std::pair<const u8*, u32> GetLayerScriptBuffer(int layer);
void PostConstructArea();
void FillInStaticGeometry();
void VerifyTokenList(CStateManager& stateMgr);

View File

@ -74,6 +74,7 @@ set(WORLD_SOURCES
CScriptRoomAcoustics.hpp CScriptRoomAcoustics.cpp
CScriptColorModulate.hpp CScriptColorModulate.cpp
CScriptStreamedMusic.hpp CScriptStreamedMusic.cpp
CScriptMidi.hpp CScriptMidi.cpp
CRepulsor.hpp CRepulsor.cpp
CScriptGunTurret.hpp CScriptGunTurret.cpp
CScriptCameraPitchVolume.hpp CScriptCameraPitchVolume.cpp

View File

@ -0,0 +1,89 @@
#include "CScriptMidi.hpp"
#include "TCastTo.hpp"
#include "CSimplePool.hpp"
#include "GameGlobalObjects.hpp"
#include "CStateManager.hpp"
#include "MP1/CInGameGuiManager.hpp"
#include "CInGameTweakManagerBase.hpp"
namespace urde
{
CScriptMidi::CScriptMidi(TUniqueId id, const CEntityInfo& info, const std::string& name,
bool active, ResId csng, float fadeIn, float fadeOut, s32 volume)
: CEntity(id, info, active, name), x40_fadeInTime(fadeIn), x44_fadeOutTime(fadeOut),
x48_volume(volume)
{
x34_song = g_SimplePool->GetObj(SObjectTag{FOURCC('CSNG'), csng});
}
void CScriptMidi::StopInternal(float fadeTime)
{
if (x3c_handle)
{
CMidiManager::Stop(x3c_handle, fadeTime);
x3c_handle.reset();
}
}
void CScriptMidi::Stop(CStateManager& mgr, float fadeTime)
{
const CWorld* wld = mgr.GetWorld();
const CGameArea* area = wld->GetAreaAlways(x4_areaId);
std::string twkName = MP1::CInGameGuiManager::GetIdentifierForMidiEvent(wld->IGetWorldAssetId(),
area->GetAreaAssetId(),
x10_name);
if (g_TweakManager->HasTweakValue(twkName))
{
const CTweakValue::Audio& audio = g_TweakManager->GetTweakValue(twkName)->GetAudio();
fadeTime = audio.GetFadeOut();
}
StopInternal(fadeTime);
}
void CScriptMidi::Play(CStateManager& mgr, float fadeTime)
{
u32 volume = x48_volume;
const CWorld* wld = mgr.GetWorld();
const CGameArea* area = wld->GetAreaAlways(x4_areaId);
std::string twkName = MP1::CInGameGuiManager::GetIdentifierForMidiEvent(wld->IGetWorldAssetId(),
area->GetAreaAssetId(),
x10_name);
if (g_TweakManager->HasTweakValue(twkName))
{
const CTweakValue::Audio& audio = g_TweakManager->GetTweakValue(twkName)->GetAudio();
x34_song = g_SimplePool->GetObj(SObjectTag{FOURCC('CSNG'), audio.GetResId()});
fadeTime = audio.GetFadeIn();
volume = audio.GetVolume() * 127.f;
}
x3c_handle = CMidiManager::Play(*x34_song, fadeTime, false, volume / 127.f);
}
void CScriptMidi::Accept(IVisitor& visitor)
{
visitor.Visit(this);
}
void CScriptMidi::AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr)
{
CEntity::AcceptScriptMsg(msg, objId, stateMgr);
switch (msg)
{
case EScriptObjectMessage::Play:
if (GetActive())
Play(stateMgr, x40_fadeInTime);
break;
case EScriptObjectMessage::Stop:
if (GetActive())
Stop(stateMgr, x44_fadeOutTime);
break;
case EScriptObjectMessage::Deactivate:
StopInternal(0.f);
break;
default: break;
}
}
}

View File

@ -0,0 +1,33 @@
#ifndef __URDE_CSCRIPTMIDI_HPP__
#define __URDE_CSCRIPTMIDI_HPP__
#include "CEntity.hpp"
#include "CToken.hpp"
#include "Audio/CMidiManager.hpp"
namespace urde
{
class CScriptMidi : public CEntity
{
TToken<CMidiManager::CMidiData> x34_song;
CMidiHandle x3c_handle;
float x40_fadeInTime;
float x44_fadeOutTime;
u16 x48_volume;
void StopInternal(float fadeTime);
public:
CScriptMidi(TUniqueId id, const CEntityInfo& info, const std::string& name,
bool active, ResId csng, float, float, s32);
void Stop(CStateManager& mgr, float fadeTime);
void Play(CStateManager& mgr, float fadeTime);
void Accept(IVisitor& visitor);
void AcceptScriptMsg(EScriptObjectMessage msg, TUniqueId objId, CStateManager& stateMgr);
};
}
#endif // __URDE_CSCRIPTSTREAMEDMUSIC_HPP__

View File

@ -64,6 +64,7 @@
#include "MP1/World/CActorContraption.hpp"
#include "CScriptShadowProjector.hpp"
#include "CScriptStreamedMusic.hpp"
#include "CScriptMidi.hpp"
#include "CScriptRoomAcoustics.hpp"
#include "CPatternedInfo.hpp"
#include "CSimplePool.hpp"
@ -1916,7 +1917,16 @@ CEntity* ScriptLoader::LoadThardusRockProjectile(CStateManager& mgr, CInputStrea
CEntity* ScriptLoader::LoadMidi(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)
{
return nullptr;
if (!EnsurePropertyCount(propCount, 6, "Midi"))
return nullptr;
std::string name = mgr.HashInstanceName(in);
bool active = in.readBool();
u32 csng = in.readUint32Big();
float fadeIn = in.readFloatBig();
float fadeOut = in.readFloatBig();
u32 vol = in.readUint32Big();
return new CScriptMidi(mgr.AllocateUniqueId(), info, name, active, csng, fadeIn, fadeOut, vol);
}
CEntity* ScriptLoader::LoadStreamedAudio(CStateManager& mgr, CInputStream& in, int propCount, const CEntityInfo& info)

2
amuse

@ -1 +1 @@
Subproject commit 5c8fa2e8ab76cb95dad7a6add9efd8ecb9bfbbfe
Subproject commit a23af16349383be647494e9ae245568cc5194eae

View File

@ -4,7 +4,6 @@
#define VISI_MIN_LENGTH 8.0
static logvisor::Module Log("VISIBuilder");
const VISIBuilder::Leaf VISIBuilder::NullLeaf = {};
VISIBuilder::PVSRenderCache::PVSRenderCache(VISIRenderer& renderer)
: m_renderer(renderer)
@ -245,7 +244,10 @@ void VISIBuilder::Node::calculateSizesAndOffs(size_t& cur, size_t leafSz)
}
else
{
cur += leafSz;
if (!leaf)
flags &= ~0x8;
else
cur += leafSz;
}
}
@ -294,7 +296,7 @@ void VISIBuilder::Node::writeNodes(athena::io::MemoryWriter& w, size_t leafBytes
childNodes[nodeSel].writeNodes(w, leafBytes);
}
}
else
else if (leaf)
{
leaf.write(w, leafBytes);
}

View File

@ -77,7 +77,6 @@ struct VISIBuilder
}
}
};
static const Leaf NullLeaf;
class PVSRenderCache
{
@ -113,7 +112,7 @@ struct VISIBuilder
bool operator==(const Node& other) const
{
if (!leaf || !other.leaf)
if ((flags & 0x7) || (other.flags & 0x7))
return false;
return leaf == other.leaf;
}

View File

@ -296,6 +296,10 @@ void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bo
zeus::CFrustum frustum;
frustum.updatePlanes(mv, g_Proj);
// Fill depth buffer with backfaces initially
glCullFace(GL_FRONT);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
for (const Model& model : m_models)
{
if (!frustum.aabbFrustumTest(model.aabb))
@ -311,6 +315,24 @@ void VISIRenderer::RenderPVSOpaque(RGBA8* bufOut, const zeus::CVector3f& pos, bo
needTransparent = true;
}
}
// Draw frontfaces
glCullFace(GL_BACK);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
for (const Model& model : m_models)
{
if (!frustum.aabbFrustumTest(model.aabb))
continue;
glBindVertexArray(model.vao);
for (const Model::Surface& surf : model.surfaces)
{
// Non-transparents first
if (!surf.transparent)
glDrawElements(model.topology, surf.count, GL_UNSIGNED_INT,
reinterpret_cast<void*>(uintptr_t(surf.first * 4)));
}
}
}
//m_swapFunc();