finish CKMesh remain reading and ctor

This commit is contained in:
yyc12345 2023-09-20 14:42:44 +08:00
parent 0a85832d63
commit a06f6a58c9
6 changed files with 171 additions and 25 deletions

View File

@ -312,9 +312,13 @@ namespace LibCmo::CK2 {
/* ========== Complex Data Read Functions ==========*/
bool ReadObjectID(CK_ID* id);
bool ReadObjectPointer(ObjImpls::CKObject** obj);
inline bool ReadObjectID(CK_ID& id) {
return ReadObjectID(&id);
}
inline bool ReadObjectPointer(ObjImpls::CKObject*& id) {
return ReadObjectPointer(&id);
}
bool ReadManagerInt(CKGUID* guid, CKINT* intval);
inline bool ReadManagerInt(CKGUID& guid, CKINT& intval) {
@ -424,8 +428,8 @@ namespace LibCmo::CK2 {
/// </summary>
/// <param name="ls"></param>
/// <returns></returns>
bool ReadObjectIDSequence(XContainer::XArray<CK_ID>* ls);
inline bool ReadObjectIDSequence(XContainer::XArray<CK_ID>& ls) {
bool ReadObjectIDSequence(XContainer::XObjectArray* ls);
inline bool ReadObjectIDSequence(XContainer::XObjectArray& ls) {
return ReadObjectIDSequence(&ls);
}

View File

@ -183,6 +183,17 @@ namespace LibCmo::CK2 {
return false;
}
bool CKStateChunk::ReadObjectPointer(ObjImpls::CKObject** obj) {
CK_ID cache;
bool ret = ReadObjectID(&cache);
if (ret) {
*obj = m_BindContext->GetObject(cache);
} else {
*obj = nullptr;
}
return ret;
}
bool CKStateChunk::ReadManagerInt(CKGUID* guid, CKINT* intval) {
if (guid == nullptr || intval == nullptr) return false;
@ -374,7 +385,7 @@ namespace LibCmo::CK2 {
/* ========== Sequence Functions ==========*/
bool CKStateChunk::ReadObjectIDSequence(XContainer::XArray<CK_ID>* ls) {
bool CKStateChunk::ReadObjectIDSequence(XContainer::XObjectArray* ls) {
if (ls == nullptr) return false;
ls->clear();

View File

@ -42,11 +42,10 @@ namespace LibCmo::CK2::ObjImpls {
m_PotentialMeshes.clear();
// read current mesh
CK_ID currentMeshId;
chunk->ReadObjectID(currentMeshId);
CKObject* findobj = m_Context->GetObject(currentMeshId);
if (findobj != nullptr && findobj->GetClassID() == CK_CLASSID::CKCID_MESH) {
m_CurrentMesh = static_cast<CKMesh*>(findobj);
CKObject* pendingMesh = nullptr;
chunk->ReadObjectPointer(pendingMesh);
if (pendingMesh != nullptr && pendingMesh->GetClassID() == CK_CLASSID::CKCID_MESH) {
m_CurrentMesh = static_cast<CKMesh*>(pendingMesh);
}
// read other meshs

View File

@ -70,9 +70,8 @@ namespace LibCmo::CK2::ObjImpls {
chunk->ReadStruct(m_SpecularPower);
// main texture
CK_ID objid;
chunk->ReadObjectID(objid);
CKObject* tex = m_Context->GetObject(objid);
CKObject* tex = nullptr;
chunk->ReadObjectPointer(tex);
if (tex != nullptr && tex->GetClassID() == CK_CLASSID::CKCID_TEXTURE) {
m_Textures[0] = static_cast<CKTexture*>(tex);
}
@ -125,12 +124,10 @@ namespace LibCmo::CK2::ObjImpls {
// extra texture data
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA2)) {
// read 3 extra texture
CK_ID objid;
CKObject* tex = nullptr;
for (size_t i = 1; i < 4; ++i) {
chunk->ReadObjectID(objid);
tex = m_Context->GetObject(objid);
chunk->ReadObjectPointer(tex);
if (tex != nullptr && tex->GetClassID() == CK_CLASSID::CKCID_TEXTURE) {
m_Textures[i] = static_cast<CKTexture*>(tex);
}

View File

@ -6,7 +6,32 @@
namespace LibCmo::CK2::ObjImpls {
CKMesh::CKMesh(CKContext* ctx, CK_ID ckid, CKSTRING name) :
CKBeObject(ctx, ckid, name) {}
CKBeObject(ctx, ckid, name),
// init vertex
m_VertexCount(0),
m_VertexPosition(), m_VertexNormal(), m_VertexUV(),
m_VertexColor(), m_VertexSpecularColor(),
m_VertexWeight(), m_NoVertexWeight(true),
// init mtl slots
m_MtlSlotCount(0),
m_MaterialSlot(),
// init face data
m_FaceCount(0),
m_FaceIndices(), m_FaceMtlIndex(), m_Faces(),
// init line
m_LineCount(0),
m_LineIndices(),
// init mtl channels
m_MtlChannelCount(0),
m_MaterialChannels(),
// init flags
m_Flags(EnumsHelper::Merge({
VxMath::VXMESH_FLAGS::VXMESH_FORCETRANSPARENCY,
VxMath::VXMESH_FLAGS::VXMESH_HASTRANSPARENCY
})) {
// set visible in default
EnumsHelper::Add(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
}
CKMesh::~CKMesh() {}
@ -51,17 +76,15 @@ namespace LibCmo::CK2::ObjImpls {
SetMaterialSlotCount(mtlCount);
// read slot
CK_ID mtlId;
CKDWORD ph;
CKObject* objptr;
CKObject* objptr = nullptr;
for (auto& mtlSlot : m_MaterialSlot) {
// read id
chunk->ReadObjectID(mtlId);
chunk->ReadObjectPointer(objptr);
// and read a place holder idk what the fuck it is.
chunk->ReadStruct(ph);
// try getting object pointer and assign
objptr = m_Context->GetObject(mtlId);
// try to assign
if (objptr != nullptr && objptr->GetClassID() == CK_CLASSID::CKCID_MATERIAL) {
mtlSlot = static_cast<CKMaterial*>(objptr);
} else {
@ -220,6 +243,99 @@ namespace LibCmo::CK2::ObjImpls {
BuildFaceNormals();
}
// read material channels
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHCHANNELS)) {
// read size and resize it
CKDWORD chlSize;
chunk->ReadStruct(chlSize);
SetMtlChannelCount(chlSize);
for (auto& chl : m_MaterialChannels) {
// read material
CKObject* mtlobj = nullptr;
chunk->ReadObjectPointer(mtlobj);
if (mtlobj != nullptr && mtlobj->GetClassID() == CK_CLASSID::CKCID_MATERIAL) {
chl.m_Material = static_cast<CKMaterial*>(mtlobj);
}
// read flags and call function to make sure a custom uv can be created if existed.
chunk->ReadStruct(chl.m_Flags);
SyncVertexCountToMtlChannel();
// read blend modes
chunk->ReadStruct(chl.m_SourceBlend);
chunk->ReadStruct(chl.m_DestBlend);
// read custom vertex
CKDWORD uvcount;
chunk->ReadStruct(uvcount);
if (uvcount != 0) {
// make sure no overflow
uvcount = std::min(uvcount, chl.m_CustomUV.size());
CKDWORD bufsize = uvcount * CKSizeof(VxMath::VxVector2);
auto locker = chunk->LockReadBufferWrapper(bufsize);
std::memcpy(chl.m_CustomUV.data(), locker.get(), bufsize);
locker.reset();
}
}
}
// vertex weight
CKDWORD weightSize;
m_NoVertexWeight = true;
if (chunk->SeekIdentifierAndReturnSize(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHWEIGHTS, &weightSize)) {
// set it has
m_NoVertexWeight = false;
// set count
CKDWORD weightCount;
chunk->ReadStruct(weightCount);
if (weightSize > CKSizeof(CKFLOAT)) {
// a float series
// read as a copy, to make sure no memory overflow
// because i couldn't understand how original CKMesh operate vertex weight count
// seperated with vertex count.
auto buf = chunk->ReadBufferWrapper();
CKDWORD bufsize = std::min(buf.get_deleter().GetBufferSize(), static_cast<CKDWORD>(m_VertexWeight.size()) * CKSizeof(CKFLOAT));
std::memcpy(m_VertexWeight.data(), buf.get(), bufsize);
buf.reset();
} else {
// a single float
CKFLOAT single;
chunk->ReadStruct(single);
for (auto& weight : m_VertexWeight) {
weight = single;
}
}
}
// face mask
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFACECHANMASK)) {
// 2 face mask (2 WORD) are compressed into a single DWORD.
// and if there is a remained WORD, read it as a single WORD.
// according to little endian, the actually stored data is just the mask placed
// one by one.
// so we just need to allocated it directly
// read mask count, and limit it to face count
CKDWORD maskCount;
chunk->ReadStruct(maskCount);
maskCount = std::min(maskCount, m_FaceCount);
auto locker = chunk->LockReadBufferWrapper(maskCount * CKSizeof(CKWORD));
const CKWORD* rawptr = static_cast<const CKWORD*>(locker.get());
for (auto& f : m_Faces) {
f.m_ChannelMask = *rawptr;
++rawptr;
}
locker.reset();
}
// MARK: progressive mesh data is dropper.
return true;
}
@ -240,6 +356,8 @@ namespace LibCmo::CK2::ObjImpls {
SetMtlChannelCount(0);
// then clear other
SetVertexCount(0);
m_NoVertexWeight = true;
SetMaterialSlotCount(0);
SetFaceCount(0);
SetLineCount(0);
@ -406,12 +524,16 @@ namespace LibCmo::CK2::ObjImpls {
}
void CKMesh::SetMtlChannelCount(CKDWORD count) {
// backup old count
CKDWORD oldcount = m_MtlChannelCount;
// set and resize
m_MtlChannelCount = count;
m_MaterialChannels.resize(count);
// sync mask to each face.
// each face accept all mask in default
SyncMtlChannelToFaceMask();
SyncMtlChannelToFaceMask(oldcount, count);
}
CKMaterial** CKMesh::GetMtlChannelMaterials(CKDWORD& stride) {
@ -457,8 +579,20 @@ namespace LibCmo::CK2::ObjImpls {
}
}
void CKMesh::SyncMtlChannelToFaceMask() {
CKWORD mask = static_cast<CKWORD>(~(0xFFFF << m_MtlChannelCount));
void CKMesh::SyncMtlChannelToFaceMask(CKDWORD oldsize, CKDWORD newsize) {
// use oldsize and newsize to build mask
if (oldsize == newsize) return;
CKWORD mask = 0xFFFF;
if (oldsize > newsize) {
// channels shrinks
// set already removed bits to 1
mask = static_cast<CKWORD>(~(0xFFFF << newsize));
} else {
// channels expand
// set new added bits to 1
mask = static_cast<CKWORD>(~(0xFFFF << oldsize));
}
for (auto& face : m_Faces) {
face.m_ChannelMask |= mask;
}

View File

@ -30,7 +30,7 @@ namespace LibCmo::CK2::ObjImpls {
void BuildNormals();
void BuildFaceNormals();
// ===== Line Section =====
// ===== Vertex Section =====
public:
CKDWORD GetVertexCount();
void SetVertexCount(CKDWORD count);
@ -76,7 +76,7 @@ namespace LibCmo::CK2::ObjImpls {
protected:
// 2 sync functions served for material channels.
void SyncVertexCountToMtlChannel(); // setup material channel custom uv properly
void SyncMtlChannelToFaceMask(); // request all face accept all material channels.
void SyncMtlChannelToFaceMask(CKDWORD oldsize, CKDWORD newsize); // request all face accept all material channels.
protected:
enum class VertexSaveFlags : CKDWORD {
@ -123,6 +123,7 @@ namespace LibCmo::CK2::ObjImpls {
XContainer::XArray<CKDWORD> m_VertexColor;
XContainer::XArray<CKDWORD> m_VertexSpecularColor;
XContainer::XArray<CKFLOAT> m_VertexWeight;
bool m_NoVertexWeight; // true if there is actually no vertex weight
XContainer::XArray<CKMaterial*> m_MaterialSlot;