finish CKMesh remain reading and ctor
This commit is contained in:
parent
0a85832d63
commit
a06f6a58c9
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user