add some CK3dEntity code

This commit is contained in:
yyc12345 2023-09-19 22:32:07 +08:00
parent 2d190ea30b
commit 69f702a6d2
6 changed files with 176 additions and 27 deletions

View File

@ -1,8 +1,24 @@
#include "CK3dEntity.hpp" #include "CK3dEntity.hpp"
#include "../CKStateChunk.hpp" #include "../CKStateChunk.hpp"
#include "../CKContext.hpp"
#include "CKMesh.hpp"
namespace LibCmo::CK2::ObjImpls { namespace LibCmo::CK2::ObjImpls {
CK3dEntity::CK3dEntity(CKContext* ctx, CK_ID ckid, CKSTRING name) :
CKRenderObject(ctx, ckid, name),
m_PotentialMeshes(), m_CurrentMesh(nullptr),
m_WorldMatrix(), m_ZOrder(0),
m_MoveableFlags(EnumsHelper::Merge({
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_PICKABLE,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_VISIBLE,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_RENDERCHANNELS,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_INVERSEWORLDMATVALID
})),
m_3dEntityFlags(static_cast<CK_3DENTITY_FLAGS>(0)) {}
CK3dEntity::~CK3dEntity() {}
bool CK3dEntity::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) { bool CK3dEntity::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
bool suc = CKRenderObject::Save(chunk, file, flags); bool suc = CKRenderObject::Save(chunk, file, flags);
if (!suc) return false; if (!suc) return false;
@ -14,6 +30,117 @@ namespace LibCmo::CK2::ObjImpls {
bool suc = CKRenderObject::Load(chunk, file); bool suc = CKRenderObject::Load(chunk, file);
if (!suc) return false; if (!suc) return false;
// backup moveable flags
bool hasWorldAligned = EnumsHelper::Has(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_WORLDALIGNED);
// MARK: object animation is skipped
// read associated meshs data
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_3DENTITY::CK_STATESAVE_MESHS)) {
// MARK: I don't know why origianl code do not clear potential mesh list
// so I clear it in there.
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);
}
// read other meshs
XContainer::XObjectPointerArray potentials;
chunk->ReadXObjectPointerArray(potentials);
for (const auto& ptr : potentials) {
XContainer::NSXObjectPointerArray::AddIfNotHere(m_PotentialMeshes, ptr);
}
}
// read core entity data
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_3DENTITY::CK_STATESAVE_3DENTITYNDATA)) {
// read 2 flags
chunk->ReadStruct(m_3dEntityFlags);
chunk->ReadStruct(m_MoveableFlags);
// remove some properties
EnumsHelper::Rm(m_3dEntityFlags, EnumsHelper::Merge({
CK_3DENTITY_FLAGS::CK_3DENTITY_UPDATELASTFRAME,
CK_3DENTITY_FLAGS::CK_3DENTITY_RESERVED0
}));
EnumsHelper::Rm(m_MoveableFlags, EnumsHelper::Merge({
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_RESERVED2,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_STENCILONLY,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_DONTUPDATEFROMPARENT,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_INVERSEWORLDMATVALID,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HASMOVED,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_BOXVALID,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_USERBOX,
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_UPTODATE
}));
if (hasWorldAligned) {
EnumsHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_WORLDALIGNED);
}
// if order render first
if (EnumsHelper::Has(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_RENDERFIRST)) {
m_ZOrder = 10000;
}
// read matrix
// force read as vector3
chunk->ReadStruct(reinterpret_cast<VxMath::VxVector3*>(&m_WorldMatrix[0]));
chunk->ReadStruct(reinterpret_cast<VxMath::VxVector3*>(&m_WorldMatrix[1]));
chunk->ReadStruct(reinterpret_cast<VxMath::VxVector3*>(&m_WorldMatrix[2]));
chunk->ReadStruct(reinterpret_cast<VxMath::VxVector3*>(&m_WorldMatrix[3]));
// MARK: check right-hand?
// I don't know how it checked, just reinterpter IDA code.
VxMath::VxVector3 col2(*reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[2])),
col1(*reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[1])),
col0(*reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[0]));
VxMath::VxVector3 crossProduct = VxMath::NSVxVector::CrossProduct(col0, col1);
CKFLOAT dotProduct = VxMath::NSVxVector::DotProduct(crossProduct, col2);
if (dotProduct >= 0.0f) {
EnumsHelper::Rm(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_INDIRECTMATRIX);
} else {
EnumsHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_INDIRECTMATRIX);
}
// copy visible data
// process direct visible
// todo add if visible
// and set or unset VX_MOVEABLE_VISIBLE
// process indirect visible
if (EnumsHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CKBEHAVIORLINK_ACTIVATEDLASTFRAME)) {
EnumsHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HIERARCHICALHIDE);
} else {
EnumsHelper::Rm(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HIERARCHICALHIDE);
}
// read associated CKPlace
if (EnumsHelper::Has(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_PLACEVALID)) {
// MARK: we drop the support of CKPlace.
// so we just read it and skip it.
CK_ID placeid;
chunk->ReadObjectID(placeid);
}
// read parent
if (EnumsHelper::Has(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_PARENTVALID)) {
// MAKR: we drop the support of parent and the whole 3dentity hierarchy system
// we ignore this field.
CK_ID parentid;
chunk->ReadObjectID(parentid);
}
// read priority (non-zero zorder)
if (EnumsHelper::Has(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_ZORDERVALID)) {
chunk->ReadStruct(m_ZOrder);
}
}
return true; return true;
} }

View File

@ -7,11 +7,8 @@ namespace LibCmo::CK2::ObjImpls {
class CK3dEntity : public CKRenderObject { class CK3dEntity : public CKRenderObject {
public: public:
CK3dEntity(CKContext* ctx, CK_ID ckid, CKSTRING name) : CK3dEntity(CKContext* ctx, CK_ID ckid, CKSTRING name);
CKRenderObject(ctx, ckid, name), virtual ~CK3dEntity();
m_Meshes(), m_CurrentMesh(nullptr), m_WorldMatrix()
{}
virtual ~CK3dEntity() {}
LIBCMO_DISABLE_COPY_MOVE(CK3dEntity); LIBCMO_DISABLE_COPY_MOVE(CK3dEntity);
virtual CK_CLASSID GetClassID(void) override { virtual CK_CLASSID GetClassID(void) override {
@ -23,10 +20,14 @@ namespace LibCmo::CK2::ObjImpls {
//virtual void PostLoad() override; //virtual void PostLoad() override;
protected: protected:
XContainer::XObjectPointerArray m_Meshes; XContainer::XObjectPointerArray m_PotentialMeshes;
CKMesh* m_CurrentMesh; CKMesh* m_CurrentMesh;
VxMath::VxMatrix m_WorldMatrix; VxMath::VxMatrix m_WorldMatrix;
CKDWORD m_ZOrder; // replace the whole heavy CKSceneGraphNode
VxMath::VX_MOVEABLE_FLAGS m_MoveableFlags;
CK_3DENTITY_FLAGS m_3dEntityFlags;
}; };
} }

View File

@ -371,16 +371,22 @@ namespace LibCmo::VxMath {
CKFLOAT m_Data[4][4]; CKFLOAT m_Data[4][4];
VxMatrix() : m_Data() { VxMatrix() : m_Data() {
std::memset(m_Data, 0, sizeof(m_Data)); ResetToIdentity();
m_Data[0][0] = m_Data[1][1] = m_Data[2][2] = m_Data[3][3] = 1.0f;
} }
VxMatrix(CKFLOAT m[4][4]) : m_Data() { std::memcpy(m_Data, m, sizeof(m_Data)); } VxMatrix(CKFLOAT m[4][4]) : m_Data() { std::memcpy(m_Data, m, sizeof(m_Data)); }
LIBCMO_DEFAULT_COPY_MOVE(VxMatrix); LIBCMO_DEFAULT_COPY_MOVE(VxMatrix);
void ResetToIdentity() {
std::memset(m_Data, 0, sizeof(m_Data));
m_Data[0][0] = m_Data[1][1] = m_Data[2][2] = m_Data[3][3] = 1.0f;
}
VxVector4& operator[](size_t i) { VxVector4& operator[](size_t i) {
if (i >= 4) i = 0; if (i >= 4) i = 0;
return *(reinterpret_cast<VxVector4*>(m_Data) + i); return *(reinterpret_cast<VxVector4*>(m_Data) + i);
} }
const VxVector4& operator[](size_t i) const {
if (i >= 4) i = 0;
return *(reinterpret_cast<const VxVector4*>(m_Data) + i);
}
bool operator==(const VxMatrix& rhs) const { bool operator==(const VxMatrix& rhs) const {
return std::memcmp(m_Data, rhs.m_Data, sizeof(m_Data)) == 0; return std::memcmp(m_Data, rhs.m_Data, sizeof(m_Data)) == 0;
} }

View File

@ -3,6 +3,7 @@
#include "../CK2/MgrImpls/CKObjectManager.hpp" #include "../CK2/MgrImpls/CKObjectManager.hpp"
#include "../CK2/ObjImpls/CKObject.hpp" #include "../CK2/ObjImpls/CKObject.hpp"
#include <type_traits> #include <type_traits>
#include <algorithm>
namespace LibCmo::XContainer { namespace LibCmo::XContainer {
@ -143,6 +144,13 @@ namespace LibCmo::XContainer {
} }
namespace NSXObjectPointerArray { namespace NSXObjectPointerArray {
void AddIfNotHere(XObjectPointerArray& objarray, CK2::ObjImpls::CKObject* const obj) {
auto finder = std::find(objarray.begin(), objarray.end(), obj);
if (finder == objarray.end()) {
objarray.emplace_back(obj);
}
}
void PreDeletedCheck(XObjectPointerArray& objarray, CK2::CKContext* ctx) { void PreDeletedCheck(XObjectPointerArray& objarray, CK2::CKContext* ctx) {
if (ctx == nullptr) return; if (ctx == nullptr) return;
std::erase_if(objarray, [ctx](CK2::ObjImpls::CKObject* const& item) -> bool { std::erase_if(objarray, [ctx](CK2::ObjImpls::CKObject* const& item) -> bool {

View File

@ -180,6 +180,13 @@ namespace LibCmo::XContainer {
namespace NSXObjectPointerArray { namespace NSXObjectPointerArray {
/**
* @brief Add object pointer if it is not list.
* @param objarray
* @param obj
*/
void AddIfNotHere(XObjectPointerArray& objarray, CK2::ObjImpls::CKObject* const obj);
/** /**
* @brief Check Object pointer validation and remove invalid pointers before deletion. * @brief Check Object pointer validation and remove invalid pointers before deletion.
* @param objarray * @param objarray

View File

@ -118,37 +118,37 @@ namespace Unvirt::StructFormatter {
PrintCKBeObjectDetail(obj); PrintCKBeObjectDetail(obj);
fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMesh\n")), stdout); fputs(UNVIRT_TERMCOL_LIGHT_YELLOW(("CKMesh\n")), stdout);
fputs("Vertex:\n", stdout);
fprintf(stdout, "Vertex Count: %" PRIuCKDWORD "\n", obj->GetVertexCount()); fprintf(stdout, "Vertex Count: %" PRIuCKDWORD "\n", obj->GetVertexCount());
fputs("Type\tAddress\tSize\n", stdout);
fputs("VertexPositions: ", stdout); fputs("Positions\t", stdout);
PrintPointer(obj->GetVertexPositions()); PrintPointer(obj->GetVertexPositions());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3));
fputs("VertexNormals: ", stdout); fputs("Normals\t", stdout);
PrintPointer(obj->GetVertexNormals()); PrintPointer(obj->GetVertexNormals());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector3));
fputs("VertexUVs: ", stdout); fputs("UVs\t", stdout);
PrintPointer(obj->GetVertexUVs()); PrintPointer(obj->GetVertexUVs());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector2)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetVertexCount() * CKSizeof(LibCmo::VxMath::VxVector2));
fputs("VertexColors: ", stdout); fputs("Colors\t", stdout);
PrintPointer(obj->GetVertexColors()); PrintPointer(obj->GetVertexColors());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD));
fputs("VertexSpecularColors: ", stdout); fputs("SpecularColors\t", stdout);
PrintPointer(obj->GetVertexSpecularColors()); PrintPointer(obj->GetVertexSpecularColors());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKDWORD));
fputs("VertexWeights: ", stdout); fputs("Weights\t", stdout);
PrintPointer(obj->GetVertexWeights()); PrintPointer(obj->GetVertexWeights());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKFLOAT)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetVertexCount() * CKSizeof(LibCmo::CKFLOAT));
fputs("Face:\n", stdout);
fprintf(stdout, "Face Count: %" PRIuCKDWORD "\n", obj->GetFaceCount()); fprintf(stdout, "Face Count: %" PRIuCKDWORD "\n", obj->GetFaceCount());
fputs("Type\tAddress\tSize\n", stdout);
fputs("FaceIndices: ", stdout); fputs("Indices\t", stdout);
PrintPointer(obj->GetFaceIndices()); PrintPointer(obj->GetFaceIndices());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetFaceCount() * 3 * CKSizeof(LibCmo::CKWORD)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetFaceCount() * 3 * CKSizeof(LibCmo::CKWORD));
fputs("FaceMaterialSlotIndexs: ", stdout); fputs("MaterialSlotIndexs\t", stdout);
PrintPointer(obj->GetFaceMaterialSlotIndexs()); PrintPointer(obj->GetFaceMaterialSlotIndexs());
fprintf(stdout, " (0x%" PRIxCKDWORD " bytes)\n", obj->GetFaceCount() * CKSizeof(LibCmo::CKWORD)); fprintf(stdout, "\t0x%" PRIxCKDWORD " bytes\n", obj->GetFaceCount() * CKSizeof(LibCmo::CKWORD));
} }