chore: update build script
- change project layout for better understanding. - update build script for more close to standard cmake way.
This commit is contained in:
@@ -1,321 +0,0 @@
|
||||
#include "CK3dEntity.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
#include "CKMesh.hpp"
|
||||
|
||||
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(YYCC::EnumHelper::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() {}
|
||||
|
||||
void CK3dEntity::CheckPreDeletion() {
|
||||
CKRenderObject::CheckPreDeletion();
|
||||
|
||||
// check active mesh
|
||||
if (m_CurrentMesh->IsToBeDeleted()) {
|
||||
m_CurrentMesh = nullptr;
|
||||
}
|
||||
|
||||
// check potential meshes
|
||||
XContainer::NSXObjectPointerArray::PreDeletedCheck(m_PotentialMeshes, m_Context);
|
||||
}
|
||||
|
||||
bool CK3dEntity::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKRenderObject::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// write associated mesh data
|
||||
if (m_CurrentMesh != nullptr || m_PotentialMeshes.size() != 0) {
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_3DENTITY::CK_STATESAVE_MESHS);
|
||||
|
||||
// write current mesh
|
||||
chunk->WriteObjectPointer(m_CurrentMesh);
|
||||
|
||||
// write potential meshes
|
||||
chunk->WriteXObjectPointerArray(m_PotentialMeshes);
|
||||
}
|
||||
|
||||
// write core entity data
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_3DENTITY::CK_STATESAVE_3DENTITYNDATA);
|
||||
|
||||
// regulate self flag again
|
||||
// MARK: originally we should check parent here.
|
||||
// but we do not support parent and hierarchy feature, so we simply remove flag
|
||||
YYCC::EnumHelper::Remove(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_PARENTVALID);
|
||||
// MARK: originally we should check grouped into CKPlace here.
|
||||
// but we do not support CKPlace, so we simply remove this flag
|
||||
YYCC::EnumHelper::Remove(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_PLACEVALID);
|
||||
// check z-order, if not zero, save it
|
||||
if (m_ZOrder != 0) {
|
||||
YYCC::EnumHelper::Add(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_ZORDERVALID);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_ZORDERVALID);
|
||||
}
|
||||
|
||||
// write 2 flags
|
||||
chunk->WriteStruct(m_3dEntityFlags);
|
||||
chunk->WriteStruct(m_MoveableFlags);
|
||||
|
||||
// write world matrix
|
||||
chunk->WriteStruct(reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[0]));
|
||||
chunk->WriteStruct(reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[1]));
|
||||
chunk->WriteStruct(reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[2]));
|
||||
chunk->WriteStruct(reinterpret_cast<const VxMath::VxVector3*>(&m_WorldMatrix[3]));
|
||||
|
||||
// MARK: because we do not support Parent and CKPlace,
|
||||
// and the IDA code also instruct that no need to write any data if no Parent or CKPlace.
|
||||
// so we skip the Parent and CKPlace writing
|
||||
|
||||
// write z-order
|
||||
if (m_ZOrder != 0) {
|
||||
chunk->WriteStruct(m_ZOrder);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_3DENTITY);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CK3dEntity::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKRenderObject::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// backup moveable flags
|
||||
bool hasWorldAligned = YYCC::EnumHelper::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
|
||||
CKObject* pendingMesh = nullptr;
|
||||
chunk->ReadObjectPointer(pendingMesh);
|
||||
if (pendingMesh != nullptr && pendingMesh->GetClassID() == CK_CLASSID::CKCID_MESH) {
|
||||
m_CurrentMesh = static_cast<CKMesh*>(pendingMesh);
|
||||
}
|
||||
|
||||
// read other meshs
|
||||
XContainer::XObjectPointerArray potentials;
|
||||
chunk->ReadXObjectPointerArray(potentials);
|
||||
for (const auto& ptr : potentials) {
|
||||
if (ptr == nullptr) continue;
|
||||
XContainer::NSXObjectPointerArray::AddIfNotHere(m_PotentialMeshes, ptr);
|
||||
}
|
||||
|
||||
// add current mesh to potential meshes
|
||||
if (m_CurrentMesh != nullptr) {
|
||||
XContainer::NSXObjectPointerArray::AddIfNotHere(m_PotentialMeshes, m_CurrentMesh);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// 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
|
||||
YYCC::EnumHelper::Remove(m_3dEntityFlags,
|
||||
CK_3DENTITY_FLAGS::CK_3DENTITY_UPDATELASTFRAME,
|
||||
CK_3DENTITY_FLAGS::CK_3DENTITY_RESERVED0
|
||||
);
|
||||
YYCC::EnumHelper::Remove(m_MoveableFlags,
|
||||
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) {
|
||||
YYCC::EnumHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_WORLDALIGNED);
|
||||
}
|
||||
|
||||
// if order render first
|
||||
if (YYCC::EnumHelper::Has(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_RENDERFIRST)) {
|
||||
m_ZOrder = 10000;
|
||||
}
|
||||
|
||||
// read matrix
|
||||
// reset
|
||||
m_WorldMatrix.SetIdentity();
|
||||
// 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) {
|
||||
YYCC::EnumHelper::Remove(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_INDIRECTMATRIX);
|
||||
} else {
|
||||
YYCC::EnumHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_INDIRECTMATRIX);
|
||||
}
|
||||
|
||||
// copy visible data
|
||||
// process direct visible
|
||||
if (YYCC::EnumHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE)) {
|
||||
YYCC::EnumHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_VISIBLE);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_VISIBLE);
|
||||
}
|
||||
// process indirect visible
|
||||
if (YYCC::EnumHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE)) {
|
||||
YYCC::EnumHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HIERARCHICALHIDE);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HIERARCHICALHIDE);
|
||||
}
|
||||
|
||||
// read associated CKPlace
|
||||
if (YYCC::EnumHelper::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);
|
||||
// and remove this flag
|
||||
YYCC::EnumHelper::Remove(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_PLACEVALID);
|
||||
}
|
||||
|
||||
// read parent
|
||||
if (YYCC::EnumHelper::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);
|
||||
// and remove this flag
|
||||
YYCC::EnumHelper::Remove(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_PARENTVALID);
|
||||
}
|
||||
|
||||
// read priority (non-zero zorder)
|
||||
if (YYCC::EnumHelper::Has(m_3dEntityFlags, CK_3DENTITY_FLAGS::CK_3DENTITY_ZORDERVALID)) {
|
||||
chunk->ReadStruct(m_ZOrder);
|
||||
}
|
||||
|
||||
}
|
||||
// MARK: compatibility alternative core data read code removed because I don't need them
|
||||
|
||||
|
||||
// MARK: skin and bone are skipped.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CK3dEntity::Show(CK_OBJECT_SHOWOPTION show) {
|
||||
CKObject::Show(show);
|
||||
|
||||
YYCC::EnumHelper::Remove(m_MoveableFlags,
|
||||
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_VISIBLE,
|
||||
VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HIERARCHICALHIDE
|
||||
);
|
||||
switch (show) {
|
||||
case CK_OBJECT_SHOWOPTION::CKSHOW:
|
||||
YYCC::EnumHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_VISIBLE);
|
||||
break;
|
||||
case CK_OBJECT_SHOWOPTION::CKHIERARCHICALHIDE:
|
||||
YYCC::EnumHelper::Add(m_MoveableFlags, VxMath::VX_MOVEABLE_FLAGS::VX_MOVEABLE_HIERARCHICALHIDE);
|
||||
break;
|
||||
case CK_OBJECT_SHOWOPTION::CKHIDE:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool CK3dEntity::IsVisible() const {
|
||||
// MARK: originally there is a call to this->IsHiddenByParent.
|
||||
// but we drop the support of parent, so we drop that condition.
|
||||
return CKObject::IsVisible();
|
||||
}
|
||||
|
||||
#pragma region Misc Oper
|
||||
|
||||
const VxMath::VxMatrix& CK3dEntity::GetWorldMatrix() const {
|
||||
return m_WorldMatrix;
|
||||
}
|
||||
|
||||
void CK3dEntity::SetWorldMatrix(const VxMath::VxMatrix& mat) {
|
||||
m_WorldMatrix = mat;
|
||||
}
|
||||
|
||||
CK_3DENTITY_FLAGS CK3dEntity::GetEntityFlags() const {
|
||||
return m_3dEntityFlags;
|
||||
}
|
||||
|
||||
void CK3dEntity::SetEntityFlags(CK_3DENTITY_FLAGS flags) {
|
||||
m_3dEntityFlags = flags;
|
||||
}
|
||||
|
||||
VxMath::VX_MOVEABLE_FLAGS CK3dEntity::GetMoveableFlags() const {
|
||||
return m_MoveableFlags;
|
||||
}
|
||||
|
||||
void CK3dEntity::SetMoveableFlags(VxMath::VX_MOVEABLE_FLAGS flags) {
|
||||
m_MoveableFlags = flags;
|
||||
}
|
||||
|
||||
CKDWORD CK3dEntity::GetZOrder() const {
|
||||
return m_ZOrder;
|
||||
}
|
||||
|
||||
void CK3dEntity::SetZOrder(CKDWORD ord) {
|
||||
m_ZOrder = ord;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Mesh Oper
|
||||
|
||||
void CK3dEntity::AddPotentialMesh(CKMesh* mesh) {
|
||||
XContainer::NSXObjectPointerArray::AddIfNotHere(m_PotentialMeshes, mesh);
|
||||
}
|
||||
|
||||
void CK3dEntity::RemovePotentialMesh(CKMesh* mesh) {
|
||||
std::erase(m_PotentialMeshes, mesh);
|
||||
}
|
||||
|
||||
CKDWORD CK3dEntity::GetPotentialMeshCount() const {
|
||||
return static_cast<CKDWORD>(m_PotentialMeshes.size());
|
||||
}
|
||||
|
||||
CKMesh* CK3dEntity::GetPotentialMesh(CKDWORD idx) const {
|
||||
if (idx >= m_PotentialMeshes.size()) return nullptr;
|
||||
return static_cast<CKMesh*>(m_PotentialMeshes[idx]);
|
||||
}
|
||||
|
||||
CKMesh* CK3dEntity::GetCurrentMesh() const {
|
||||
return m_CurrentMesh;
|
||||
}
|
||||
|
||||
void CK3dEntity::SetCurrentMesh(CKMesh* mesh) {
|
||||
m_CurrentMesh = mesh;
|
||||
if (mesh != nullptr) {
|
||||
AddPotentialMesh(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKRenderObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CK3dEntity : public CKRenderObject {
|
||||
public:
|
||||
CK3dEntity(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CK3dEntity();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CK3dEntity);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_3DENTITY;
|
||||
}
|
||||
|
||||
virtual void CheckPreDeletion() override;
|
||||
|
||||
// 2 RW functions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
// it have special Show and IsVisible method
|
||||
virtual void Show(CK_OBJECT_SHOWOPTION show = CK_OBJECT_SHOWOPTION::CKSHOW) override;
|
||||
virtual bool IsVisible() const override;
|
||||
|
||||
const VxMath::VxMatrix& GetWorldMatrix() const;
|
||||
void SetWorldMatrix(const VxMath::VxMatrix& mat);
|
||||
CK_3DENTITY_FLAGS GetEntityFlags() const;
|
||||
void SetEntityFlags(CK_3DENTITY_FLAGS flags);
|
||||
VxMath::VX_MOVEABLE_FLAGS GetMoveableFlags() const;
|
||||
void SetMoveableFlags(VxMath::VX_MOVEABLE_FLAGS flags);
|
||||
CKDWORD GetZOrder() const;
|
||||
void SetZOrder(CKDWORD ord);
|
||||
|
||||
void AddPotentialMesh(CKMesh* mesh);
|
||||
void RemovePotentialMesh(CKMesh* mesh);
|
||||
CKDWORD GetPotentialMeshCount() const;
|
||||
CKMesh* GetPotentialMesh(CKDWORD idx) const;
|
||||
CKMesh* GetCurrentMesh() const;
|
||||
void SetCurrentMesh(CKMesh* mesh);
|
||||
|
||||
protected:
|
||||
XContainer::XObjectPointerArray m_PotentialMeshes;
|
||||
CKMesh* m_CurrentMesh;
|
||||
VxMath::VxMatrix m_WorldMatrix;
|
||||
CKDWORD m_ZOrder; // replace the whole heavy CKSceneGraphNode
|
||||
|
||||
VxMath::VX_MOVEABLE_FLAGS m_MoveableFlags;
|
||||
// MARK: This field is called m_EntityFlags in reverse project.
|
||||
// I change this because I want to give it a more explicit name to make it is different with other flags.
|
||||
CK_3DENTITY_FLAGS m_3dEntityFlags;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CK3dEntity.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CK3dObject : public CK3dEntity {
|
||||
public:
|
||||
CK3dObject(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CK3dEntity(ctx, ckid, name)
|
||||
{}
|
||||
virtual ~CK3dObject() {}
|
||||
YYCC_DEL_CLS_COPY_MOVE(CK3dObject);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_3DOBJECT;
|
||||
}
|
||||
// CK3dObject do not implement any load/save functions
|
||||
//virtual void PreSave(CKFileVisitor* file, CKDWORD flags) override;
|
||||
//virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
//virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
//virtual void PostLoad() override;
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
#include "CKSceneObject.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
#include "../MgrImpls/CKObjectManager.hpp"
|
||||
#include "CKBeObject.hpp"
|
||||
#include "CKGroup.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKBeObject::CKBeObject(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKSceneObject(ctx, ckid, name), m_Groups() {}
|
||||
|
||||
CKBeObject::~CKBeObject() {}
|
||||
|
||||
bool CKBeObject::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKSceneObject::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_BEOBJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKBeObject::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKSceneObject::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKBeObject::IsInGroup(CKGroup* group) const {
|
||||
if (group == nullptr) return false;
|
||||
CKDWORD idx = group->GetGroupIndex();
|
||||
return XContainer::NSXBitArray::IsSet(m_Groups, idx);
|
||||
}
|
||||
|
||||
void CKBeObject::ExplicitSetGroup(CKDWORD pos, bool val) {
|
||||
if (val) {
|
||||
XContainer::NSXBitArray::Set(m_Groups, pos);
|
||||
} else {
|
||||
XContainer::NSXBitArray::Unset(m_Groups, pos);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKSceneObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKBeObject : public CKSceneObject {
|
||||
public:
|
||||
CKBeObject(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKBeObject();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKBeObject);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_BEOBJECT;
|
||||
}
|
||||
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
/**
|
||||
* @brief Check whether this object is in specified group.
|
||||
* @param group[in] The group to be checked.
|
||||
* @return True if in it.
|
||||
*/
|
||||
bool IsInGroup(CKGroup* group) const;
|
||||
/**
|
||||
* @brief Directly set group data.
|
||||
* @param pos
|
||||
* @param val
|
||||
* @warning This function only should be called by CKGroup. Any other classes should not call this.
|
||||
*/
|
||||
void ExplicitSetGroup(CKDWORD pos, bool val);
|
||||
|
||||
protected:
|
||||
XContainer::XBitArray m_Groups;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,155 +0,0 @@
|
||||
#include "CKCamera.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
// Convenient macro to mark this object is not UPTODATE.
|
||||
#define REMOVE_UPTODATE_FLAG { \
|
||||
CK_OBJECT_FLAGS obj_flags = GetObjectFlags(); \
|
||||
YYCC::EnumHelper::Remove(obj_flags, CK_OBJECT_FLAGS::CK_OBJECT_UPTODATE); \
|
||||
SetObjectFlags(obj_flags); \
|
||||
}
|
||||
|
||||
CKCamera::CKCamera(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CK3dEntity(ctx, ckid, name),
|
||||
m_ProjectType(CK_CAMERA_PROJECTION::CK_PERSPECTIVEPROJECTION),
|
||||
m_Fov(0.5f), m_OrthographicZoom(1.0f),
|
||||
m_Width(4), m_Height(3),
|
||||
m_FrontPlane(1.0f), m_BackPlane(4000.0f) {
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
|
||||
CKCamera::~CKCamera() {}
|
||||
|
||||
bool CKCamera::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CK3dEntity::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// Save main data
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_CAMERA::CK_STATESAVE_CAMERAONLY);
|
||||
chunk->WriteStruct(m_ProjectType);
|
||||
chunk->WriteStruct(m_Fov);
|
||||
chunk->WriteStruct(m_OrthographicZoom);
|
||||
|
||||
// Build width and height compound.
|
||||
CKDWORD widht_and_height = m_Width & 0x0000FFFFu;
|
||||
widht_and_height |= (m_Height << 16) & 0xFFFF0000u;
|
||||
chunk->WriteStruct(widht_and_height);
|
||||
|
||||
chunk->WriteStruct(m_FrontPlane);
|
||||
chunk->WriteStruct(m_BackPlane);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_CAMERA);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKCamera::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CK3dEntity::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// MARK: Drop the support for very old file format.
|
||||
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MAJORCHANGE_VERSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read main data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_CAMERA::CK_STATESAVE_CAMERAONLY)) {
|
||||
chunk->ReadStruct(m_ProjectType);
|
||||
chunk->ReadStruct(m_Fov);
|
||||
chunk->ReadStruct(m_OrthographicZoom);
|
||||
|
||||
// Width and Height is stored in one DWORD
|
||||
// Higher WORD is height and lower WORD is width.
|
||||
// HIGH >>> height (2 bytes), width (2 bytes) <<< LOW
|
||||
CKDWORD widht_and_height;
|
||||
chunk->ReadStruct(widht_and_height);
|
||||
m_Width = widht_and_height & 0x0000FFFFu;
|
||||
m_Height = (widht_and_height & 0xFFFF0000u) >> 16;
|
||||
|
||||
chunk->ReadStruct(m_FrontPlane);
|
||||
chunk->ReadStruct(m_BackPlane);
|
||||
}
|
||||
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma region Class Operations
|
||||
|
||||
CK_CAMERA_PROJECTION CKCamera::GetProjectionType() const {
|
||||
return m_ProjectType;
|
||||
}
|
||||
void CKCamera::SetProjectionType(CK_CAMERA_PROJECTION proj) {
|
||||
m_ProjectType = proj;
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
|
||||
CKFLOAT CKCamera::GetOrthographicZoom() const {
|
||||
return m_OrthographicZoom;
|
||||
}
|
||||
void CKCamera::SetOrthographicZoom(CKFLOAT zoom) {
|
||||
m_OrthographicZoom = zoom;
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
|
||||
CKFLOAT CKCamera::GetFrontPlane() const {
|
||||
return m_FrontPlane;
|
||||
}
|
||||
CKFLOAT CKCamera::GetBackPlane() const {
|
||||
return m_BackPlane;
|
||||
}
|
||||
CKFLOAT CKCamera::GetFov() const {
|
||||
return m_Fov;
|
||||
}
|
||||
void CKCamera::SetFrontPlane(CKFLOAT front) {
|
||||
m_FrontPlane = front;
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
void CKCamera::SetBackPlane(CKFLOAT back) {
|
||||
m_BackPlane = back;
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
void CKCamera::SetFov(CKFLOAT fov) {
|
||||
m_Fov = fov;
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
|
||||
void CKCamera::GetAspectRatio(CKDWORD& width, CKDWORD& height) const {
|
||||
width = m_Width;
|
||||
height = m_Height;
|
||||
}
|
||||
void CKCamera::SetAspectRatio(CKDWORD width, CKDWORD height) {
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
REMOVE_UPTODATE_FLAG;
|
||||
}
|
||||
|
||||
void CKCamera::ComputeProjectionMatrix(VxMath::VxMatrix& mat) const {
|
||||
CKFLOAT aspect = static_cast<CKFLOAT>(m_Width) / m_Height;
|
||||
if (m_ProjectType == CK_CAMERA_PROJECTION::CK_PERSPECTIVEPROJECTION) {
|
||||
mat.Perspective(m_Fov, aspect, m_FrontPlane, m_BackPlane);
|
||||
} else {
|
||||
mat.Orthographic(m_OrthographicZoom, aspect, m_FrontPlane, m_BackPlane);
|
||||
}
|
||||
}
|
||||
|
||||
//void CKCamera::ResetRoll() {}
|
||||
//void CKCamera::Roll(CKFLOAT angle) {}
|
||||
|
||||
CK3dEntity* CKCamera::GetTarget() const {
|
||||
// Not supported, return nullptr anyway.
|
||||
return nullptr;
|
||||
}
|
||||
void CKCamera::SetTarget(CK3dEntity* target) {
|
||||
// Do nothing because no support.
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
// Undef convenient macro
|
||||
#undef REMOVE_UPTODATE_FLAG
|
||||
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CK3dEntity.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKCamera : public CK3dEntity {
|
||||
public:
|
||||
CKCamera(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKCamera();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKCamera);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_CAMERA;
|
||||
}
|
||||
|
||||
// 2 RW funcions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
|
||||
CK_CAMERA_PROJECTION GetProjectionType() const;
|
||||
void SetProjectionType(CK_CAMERA_PROJECTION proj);
|
||||
|
||||
CKFLOAT GetOrthographicZoom() const;
|
||||
void SetOrthographicZoom(CKFLOAT zoom);
|
||||
|
||||
CKFLOAT GetFrontPlane() const;
|
||||
CKFLOAT GetBackPlane() const;
|
||||
CKFLOAT GetFov() const;
|
||||
void SetFrontPlane(CKFLOAT front);
|
||||
void SetBackPlane(CKFLOAT back);
|
||||
void SetFov(CKFLOAT fov);
|
||||
|
||||
void GetAspectRatio(CKDWORD& width, CKDWORD& height) const;
|
||||
void SetAspectRatio(CKDWORD width, CKDWORD height);
|
||||
|
||||
void ComputeProjectionMatrix(VxMath::VxMatrix& mat) const;
|
||||
|
||||
// TODO: Finish CKCamera roll feature because it now involve some functions which is not implemented in CK3dEntity.
|
||||
// Roll Angle
|
||||
//void ResetRoll();
|
||||
//void Roll(CKFLOAT angle);
|
||||
|
||||
// Target access
|
||||
virtual CK3dEntity* GetTarget() const;
|
||||
virtual void SetTarget(CK3dEntity* target);
|
||||
|
||||
protected:
|
||||
CKFLOAT m_Fov;
|
||||
CKFLOAT m_FrontPlane, m_BackPlane;
|
||||
CK_CAMERA_PROJECTION m_ProjectType;
|
||||
CKFLOAT m_OrthographicZoom;
|
||||
CKDWORD m_Width, m_Height;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,153 +0,0 @@
|
||||
#include "CKGroup.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
#include "../MgrImpls/CKObjectManager.hpp"
|
||||
#include <algorithm>
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKGroup::CKGroup(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKBeObject(ctx, ckid, name),
|
||||
m_ObjectArray(),
|
||||
m_GroupIndex(m_Context->GetObjectManager()->AllocateGroupGlobalIndex()) {}
|
||||
|
||||
CKGroup::~CKGroup() {
|
||||
// free self allocated id
|
||||
m_Context->GetObjectManager()->FreeGroupGlobalIndex(m_GroupIndex);
|
||||
}
|
||||
|
||||
void CKGroup::PreDelete() {
|
||||
CKBeObject::PreDelete();
|
||||
|
||||
// unlink all grouped object
|
||||
for (auto& ptr : m_ObjectArray) {
|
||||
static_cast<CKBeObject*>(ptr)->ExplicitSetGroup(m_GroupIndex, false);
|
||||
}
|
||||
m_ObjectArray.clear();
|
||||
}
|
||||
|
||||
void CKGroup::CheckPreDeletion() {
|
||||
CKBeObject::CheckPreDeletion();
|
||||
|
||||
// remove self invalid object ptr
|
||||
XContainer::NSXObjectPointerArray::PreDeletedCheck(m_ObjectArray, m_Context);
|
||||
}
|
||||
|
||||
bool CKGroup::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKBeObject::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// write grouped object
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_GROUP::CK_STATESAVE_GROUPALL);
|
||||
chunk->WriteXObjectPointerArray(m_ObjectArray);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_GROUP);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKGroup::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKBeObject::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// cleat self
|
||||
this->Clear();
|
||||
|
||||
// get grouped objects
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_GROUP::CK_STATESAVE_GROUPALL)) {
|
||||
XContainer::XObjectPointerArray ptrs;
|
||||
chunk->ReadXObjectPointerArray(ptrs);
|
||||
|
||||
// filter pointer and check them type
|
||||
for (auto& ptr : ptrs) {
|
||||
// skip bad one
|
||||
if (ptr == nullptr || ptr == this
|
||||
|| !CKIsChildClassOf(ptr->GetClassID(), CK_CLASSID::CKCID_BEOBJECT)) {
|
||||
continue;
|
||||
}
|
||||
CKBeObject* beobj = static_cast<CKBeObject*>(ptr);
|
||||
if (beobj->IsInGroup(this)) continue;
|
||||
|
||||
// add good one
|
||||
beobj->ExplicitSetGroup(m_GroupIndex, true);
|
||||
m_ObjectArray.emplace_back(beobj);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CKGroup::Show(CK_OBJECT_SHOWOPTION show) {
|
||||
CKObject::Show(show);
|
||||
|
||||
// call Show for all sub object
|
||||
for (auto& ptr : m_ObjectArray) {
|
||||
if (ptr == nullptr) continue;
|
||||
ptr->Show(show);
|
||||
}
|
||||
}
|
||||
|
||||
CKDWORD CKGroup::GetGroupIndex() const {
|
||||
return m_GroupIndex;
|
||||
}
|
||||
|
||||
CKERROR CKGroup::AddObject(CKBeObject* o) {
|
||||
if (o == nullptr || o == this || !CKIsChildClassOf(o->GetClassID(), CK_CLASSID::CKCID_BEOBJECT)) {
|
||||
return CKERROR::CKERR_INVALIDPARAMETER;
|
||||
}
|
||||
if (o->IsInGroup(this)) {
|
||||
return CKERROR::CKERR_ALREADYPRESENT;
|
||||
}
|
||||
|
||||
// set object
|
||||
o->ExplicitSetGroup(m_GroupIndex, true);
|
||||
// set self
|
||||
m_ObjectArray.emplace_back(o);
|
||||
return CKERROR::CKERR_OK;
|
||||
}
|
||||
|
||||
CKBeObject* CKGroup::RemoveObject(CKDWORD pos) {
|
||||
// check pos
|
||||
if (pos >= m_ObjectArray.size()) return nullptr;
|
||||
|
||||
auto it = m_ObjectArray.begin() + pos;
|
||||
CKBeObject* obj = static_cast<CKBeObject*>(*it);
|
||||
// set object
|
||||
obj->ExplicitSetGroup(m_GroupIndex, false);
|
||||
// remove self
|
||||
m_ObjectArray.erase(it);
|
||||
return obj;
|
||||
}
|
||||
|
||||
void CKGroup::RemoveObject(CKBeObject* obj) {
|
||||
// find first
|
||||
auto finder = std::find(m_ObjectArray.begin(), m_ObjectArray.end(), static_cast<CKObject*>(obj));
|
||||
if (finder != m_ObjectArray.end()) {
|
||||
// set object
|
||||
static_cast<CKBeObject*>(*finder)->ExplicitSetGroup(m_GroupIndex, false);
|
||||
// remove self
|
||||
m_ObjectArray.erase(finder);
|
||||
}
|
||||
}
|
||||
|
||||
void CKGroup::Clear() {
|
||||
for (auto& beobj : m_ObjectArray) {
|
||||
// set object
|
||||
static_cast<CKBeObject*>(beobj)->ExplicitSetGroup(m_GroupIndex, false);
|
||||
}
|
||||
|
||||
m_ObjectArray.clear();
|
||||
}
|
||||
|
||||
CKBeObject* CKGroup::GetObject(CKDWORD pos) const {
|
||||
if (pos >= m_ObjectArray.size()) return nullptr;
|
||||
else return static_cast<CKBeObject*>(m_ObjectArray[pos]);
|
||||
}
|
||||
|
||||
CKDWORD CKGroup::GetObjectCount() const {
|
||||
return static_cast<CKDWORD>(m_ObjectArray.size());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKBeObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKGroup : public CKBeObject {
|
||||
public:
|
||||
CKGroup(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKGroup();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKGroup);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_GROUP;
|
||||
}
|
||||
|
||||
virtual void PreDelete() override;
|
||||
virtual void CheckPreDeletion() override;
|
||||
|
||||
//virtual void PreSave(CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
//virtual void PostLoad() override;
|
||||
|
||||
// it only have special Show method
|
||||
virtual void Show(CK_OBJECT_SHOWOPTION show = CK_OBJECT_SHOWOPTION::CKSHOW) override;
|
||||
|
||||
CKDWORD GetGroupIndex() const;
|
||||
|
||||
// ===== Insert =====
|
||||
CKERROR AddObject(CKBeObject *o);
|
||||
|
||||
// ===== Remove =====
|
||||
CKBeObject* RemoveObject(CKDWORD pos);
|
||||
void RemoveObject(CKBeObject *obj);
|
||||
void Clear();
|
||||
|
||||
// ===== Access =====
|
||||
CKBeObject* GetObject(CKDWORD pos) const;
|
||||
CKDWORD GetObjectCount() const;
|
||||
|
||||
protected:
|
||||
XContainer::XObjectPointerArray m_ObjectArray;
|
||||
CKDWORD m_GroupIndex;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,232 +0,0 @@
|
||||
#include "CKLight.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include <numbers>
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKLight::CKLight(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CK3dEntity(ctx, ckid, name),
|
||||
m_LightData(), m_LightFlags(LightFlags::Active), m_LightPower(1.0f) {
|
||||
// Setup light data
|
||||
m_LightData.m_Type = VxMath::VXLIGHT_TYPE::VX_LIGHTPOINT;
|
||||
m_LightData.m_Diffuse = VxMath::VxColor(1.0f, 1.0f, 1.0f);
|
||||
m_LightData.m_Specular = VxMath::VxColor(0);
|
||||
m_LightData.m_Ambient = VxMath::VxColor(0.0f, 0.0f, 0.0f);
|
||||
m_LightData.m_Range = 5000.0f;
|
||||
m_LightData.m_Falloff = 1.0f;
|
||||
m_LightData.m_Attenuation0 = 1.0f;
|
||||
m_LightData.m_Attenuation1 = 0.0f;
|
||||
m_LightData.m_Attenuation2 = 0.0f;
|
||||
m_LightData.m_InnerSpotCone = 40.0f / 180.0f * std::numbers::pi_v<float>; // MARK: Original value is 0.69813174f. Perhaps 40 deg in rad.
|
||||
m_LightData.m_OuterSpotCone = 45.0f / 180.0f * std::numbers::pi_v<float>; // MARK: Original value is 0.78539819f. Perhaps 45 deg in rad.
|
||||
}
|
||||
|
||||
CKLight::~CKLight() {}
|
||||
|
||||
bool CKLight::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CK3dEntity::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// Save main data
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA);
|
||||
|
||||
// Combine light type and flags data.
|
||||
CKDWORD light_type_and_flags = static_cast<CKDWORD>(m_LightFlags) & 0xFFFFFF00u;
|
||||
light_type_and_flags |= static_cast<CKDWORD>(m_LightData.m_Type) & 0xFFu;
|
||||
chunk->WriteStruct(light_type_and_flags);
|
||||
|
||||
// Save diffuse color with constant 1.0 alpha factor.
|
||||
chunk->WriteStruct(m_LightData.m_Diffuse.ToARGB() | 0xFF000000u);
|
||||
|
||||
chunk->WriteStruct(m_LightData.m_Attenuation0);
|
||||
chunk->WriteStruct(m_LightData.m_Attenuation1);
|
||||
chunk->WriteStruct(m_LightData.m_Attenuation2);
|
||||
|
||||
chunk->WriteStruct(m_LightData.m_Range);
|
||||
|
||||
if (m_LightData.m_Type == VxMath::VXLIGHT_TYPE::VX_LIGHTSPOT) {
|
||||
chunk->WriteStruct(m_LightData.m_OuterSpotCone);
|
||||
chunk->WriteStruct(m_LightData.m_InnerSpotCone);
|
||||
chunk->WriteStruct(m_LightData.m_Falloff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Save light power
|
||||
if (m_LightPower != 1.0f) {
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA2);
|
||||
chunk->WriteStruct(m_LightPower);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_LIGHT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKLight::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CK3dEntity::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// MARK: I drop the read process for too low version.
|
||||
// return false anyway.
|
||||
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MAJORCHANGE_VERSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Read main data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA)) {
|
||||
// Read a DWORD storing light type and flags
|
||||
// Because the lowest byte in light flags always is 0x00,
|
||||
// so Virtools use it to store light type.
|
||||
// After removing light type component, the rest of data is light flags.
|
||||
// (do not need any SHIFT! It's okey that just set the lowest byte to zero.)
|
||||
CKDWORD light_type_and_flags;
|
||||
chunk->ReadStruct(light_type_and_flags);
|
||||
m_LightData.m_Type = static_cast<VxMath::VXLIGHT_TYPE>(light_type_and_flags & 0xFFu);
|
||||
m_LightFlags = static_cast<LightFlags>(light_type_and_flags & 0xFFFFFF00u);
|
||||
|
||||
CKDWORD dword_diffuse;
|
||||
chunk->ReadStruct(dword_diffuse);
|
||||
m_LightData.m_Diffuse = VxMath::VxColor(dword_diffuse);
|
||||
|
||||
chunk->ReadStruct(m_LightData.m_Attenuation0);
|
||||
chunk->ReadStruct(m_LightData.m_Attenuation1);
|
||||
chunk->ReadStruct(m_LightData.m_Attenuation2);
|
||||
|
||||
chunk->ReadStruct(m_LightData.m_Range);
|
||||
|
||||
if (m_LightData.m_Type == VxMath::VXLIGHT_TYPE::VX_LIGHTSPOT) {
|
||||
chunk->ReadStruct(m_LightData.m_OuterSpotCone);
|
||||
chunk->ReadStruct(m_LightData.m_InnerSpotCone);
|
||||
chunk->ReadStruct(m_LightData.m_Falloff);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Read light power
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_LIGHTDATA2)) {
|
||||
chunk->ReadStruct(m_LightPower);
|
||||
} else {
|
||||
m_LightPower = 1.0f;
|
||||
}
|
||||
|
||||
// Correct light type to prevent accident out of range value.
|
||||
switch (m_LightData.m_Type) {
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTPOINT:
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTSPOT:
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTDIREC:
|
||||
case VxMath::VXLIGHT_TYPE::VX_LIGHTPARA:
|
||||
// do nothing
|
||||
break;
|
||||
default:
|
||||
// reset it to point
|
||||
m_LightData.m_Type = VxMath::VXLIGHT_TYPE::VX_LIGHTPOINT;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma region Class Operations
|
||||
|
||||
VxMath::VXLIGHT_TYPE CKLight::GetType() const {
|
||||
return m_LightData.m_Type;
|
||||
}
|
||||
void CKLight::SetType(VxMath::VXLIGHT_TYPE light_type) {
|
||||
m_LightData.m_Type = light_type;
|
||||
}
|
||||
|
||||
const VxMath::VxColor& CKLight::GetColor() const {
|
||||
return m_LightData.m_Diffuse;
|
||||
}
|
||||
void CKLight::SetColor(const VxMath::VxColor& c) {
|
||||
m_LightData.m_Diffuse = c;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetConstantAttenuation() const {
|
||||
return m_LightData.m_Attenuation0;
|
||||
}
|
||||
CKFLOAT CKLight::GetLinearAttenuation() const {
|
||||
return m_LightData.m_Attenuation1;
|
||||
}
|
||||
CKFLOAT CKLight::GetQuadraticAttenuation() const {
|
||||
return m_LightData.m_Attenuation2;
|
||||
}
|
||||
void CKLight::SetConstantAttenuation(CKFLOAT value) {
|
||||
m_LightData.m_Attenuation0 = value;
|
||||
}
|
||||
void CKLight::SetLinearAttenuation(CKFLOAT value) {
|
||||
m_LightData.m_Attenuation1 = value;
|
||||
}
|
||||
void CKLight::SetQuadraticAttenuation(CKFLOAT value) {
|
||||
m_LightData.m_Attenuation2 = value;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetRange() const {
|
||||
return m_LightData.m_Range;
|
||||
}
|
||||
void CKLight::SetRange(CKFLOAT value) {
|
||||
m_LightData.m_Range = value;
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetHotSpot() const {
|
||||
return m_LightData.m_InnerSpotCone;
|
||||
}
|
||||
CKFLOAT CKLight::GetFalloff() const {
|
||||
return m_LightData.m_OuterSpotCone;
|
||||
}
|
||||
CKFLOAT CKLight::GetFalloffShape() const {
|
||||
return m_LightData.m_Falloff;
|
||||
}
|
||||
void CKLight::SetHotSpot(CKFLOAT value) {
|
||||
m_LightData.m_InnerSpotCone = value;
|
||||
}
|
||||
void CKLight::SetFalloff(CKFLOAT value) {
|
||||
m_LightData.m_OuterSpotCone = value;
|
||||
}
|
||||
void CKLight::SetFalloffShape(CKFLOAT value) {
|
||||
m_LightData.m_Falloff = value;
|
||||
}
|
||||
|
||||
bool CKLight::GetActivity() const {
|
||||
return YYCC::EnumHelper::Has(m_LightFlags, LightFlags::Active);
|
||||
}
|
||||
void CKLight::Active(bool active) {
|
||||
if (active) {
|
||||
YYCC::EnumHelper::Add(m_LightFlags, LightFlags::Active);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_LightFlags, LightFlags::Active);
|
||||
}
|
||||
}
|
||||
|
||||
bool CKLight::GetSpecularFlag() const {
|
||||
return YYCC::EnumHelper::Has(m_LightFlags, LightFlags::Specular);
|
||||
}
|
||||
void CKLight::SetSpecularFlag(bool specular) {
|
||||
if (specular) {
|
||||
YYCC::EnumHelper::Add(m_LightFlags, LightFlags::Specular);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_LightFlags, LightFlags::Specular);
|
||||
}
|
||||
}
|
||||
|
||||
CK3dEntity* CKLight::GetTarget() const {
|
||||
// Normal light do not support target.
|
||||
// So it always return nullptr.
|
||||
return nullptr;
|
||||
}
|
||||
void CKLight::SetTarget(CK3dEntity* target) {
|
||||
// Normal light do not support target.
|
||||
// So, do nothing.
|
||||
}
|
||||
|
||||
CKFLOAT CKLight::GetLightPower() const {
|
||||
return m_LightPower;
|
||||
}
|
||||
void CKLight::SetLightPower(CKFLOAT power) {
|
||||
m_LightPower = power;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CK3dEntity.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKLight : public CK3dEntity {
|
||||
public:
|
||||
CKLight(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKLight();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKLight);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_LIGHT;
|
||||
}
|
||||
|
||||
// 2 RW funcions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
// Type
|
||||
VxMath::VXLIGHT_TYPE GetType() const;
|
||||
void SetType(VxMath::VXLIGHT_TYPE light_type);
|
||||
|
||||
const VxMath::VxColor& GetColor() const;
|
||||
void SetColor(const VxMath::VxColor& c);
|
||||
|
||||
CKFLOAT GetConstantAttenuation() const;
|
||||
CKFLOAT GetLinearAttenuation() const;
|
||||
CKFLOAT GetQuadraticAttenuation() const;
|
||||
void SetConstantAttenuation(CKFLOAT value);
|
||||
void SetLinearAttenuation(CKFLOAT value);
|
||||
void SetQuadraticAttenuation(CKFLOAT value);
|
||||
|
||||
// Range
|
||||
CKFLOAT GetRange() const;
|
||||
void SetRange(CKFLOAT value);
|
||||
|
||||
// Spotlight options
|
||||
CKFLOAT GetHotSpot() const;
|
||||
CKFLOAT GetFalloff() const;
|
||||
CKFLOAT GetFalloffShape() const;
|
||||
void SetHotSpot(CKFLOAT value);
|
||||
void SetFalloff(CKFLOAT value);
|
||||
void SetFalloffShape(CKFLOAT value);
|
||||
|
||||
// Activity options
|
||||
bool GetActivity() const;
|
||||
void Active(bool active);
|
||||
|
||||
bool GetSpecularFlag() const;
|
||||
void SetSpecularFlag(bool specular);
|
||||
|
||||
// Target access
|
||||
virtual CK3dEntity* GetTarget() const;
|
||||
virtual void SetTarget(CK3dEntity* target);
|
||||
|
||||
CKFLOAT GetLightPower() const;
|
||||
void SetLightPower(CKFLOAT power = 1.0f);
|
||||
|
||||
protected:
|
||||
enum class LightFlags : CKDWORD {
|
||||
None = 0,
|
||||
Active = 0x100u, /**< if set, this light is active. */
|
||||
Specular = 0x200u, /**< if set, this light has specular flag. */
|
||||
};
|
||||
|
||||
CKLightData m_LightData;
|
||||
// MARK: This variable is called in m_Flags in reverse code.
|
||||
LightFlags m_LightFlags;
|
||||
CKFLOAT m_LightPower;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,415 +0,0 @@
|
||||
#include "CKMaterial.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
#include "CKTexture.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKMaterial::CKMaterial(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKBeObject(ctx, ckid, name),
|
||||
// following init are gotten from SDK document.
|
||||
m_Diffuse(0.7f, 0.7f, 0.7f, 1.0f),
|
||||
m_Ambient(0.3f, 0.3f, 0.3f, 1.0f),
|
||||
m_Specular(0.5f, 0.5f, 0.5f, 1.0f), m_SpecularPower(0.0f),
|
||||
m_Emissive(0.0f, 0.0f, 0.0f, 1.0f),
|
||||
m_EnableTwoSided(false),
|
||||
m_Textures { nullptr, nullptr, nullptr, nullptr },
|
||||
m_TextureMinMode(VxMath::VXTEXTURE_FILTERMODE::VXTEXTUREFILTER_LINEAR), m_TextureMagMode(VxMath::VXTEXTURE_FILTERMODE::VXTEXTUREFILTER_LINEAR),
|
||||
m_SourceBlend(VxMath::VXBLEND_MODE::VXBLEND_ONE), m_DestBlend(VxMath::VXBLEND_MODE::VXBLEND_ZERO), m_EnableAlphaBlend(false),
|
||||
m_ShadeMode(VxMath::VXSHADE_MODE::VXSHADE_GOURAUD),
|
||||
m_FillMode(VxMath::VXFILL_MODE::VXFILL_SOLID),
|
||||
m_EnableAlphaTest(false),
|
||||
m_EnableZWrite(true),
|
||||
// following init are gotten from IDA.
|
||||
m_EnablePerspectiveCorrection(true),
|
||||
m_TextureBlendMode(VxMath::VXTEXTURE_BLENDMODE::VXTEXTUREBLEND_MODULATEALPHA),
|
||||
m_TextureAddressMode(VxMath::VXTEXTURE_ADDRESSMODE::VXTEXTURE_ADDRESSWRAP),
|
||||
m_ZFunc(VxMath::VXCMPFUNC::VXCMP_LESSEQUAL),
|
||||
m_AlphaFunc(VxMath::VXCMPFUNC::VXCMP_ALWAYS),
|
||||
m_Effect(VxMath::VX_EFFECT::VXEFFECT_NONE),
|
||||
m_TextureBorderColor(0),
|
||||
m_AlphaRef(0)
|
||||
{}
|
||||
|
||||
CKMaterial::~CKMaterial() {}
|
||||
|
||||
void CKMaterial::CheckPreDeletion() {
|
||||
CKBeObject::CheckPreDeletion();
|
||||
|
||||
// check 4 textures
|
||||
for (auto& tex : m_Textures) {
|
||||
if (tex != nullptr && tex->IsToBeDeleted()) {
|
||||
tex = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CKMaterial::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKBeObject::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// save main data
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA);
|
||||
|
||||
// 4 basic color and some power
|
||||
CKDWORD col;
|
||||
col = m_Diffuse.ToARGB();
|
||||
chunk->WriteStruct(col);
|
||||
col = m_Ambient.ToARGB();
|
||||
chunk->WriteStruct(col);
|
||||
col = m_Specular.ToARGB();
|
||||
chunk->WriteStruct(col);
|
||||
col = m_Emissive.ToARGB();
|
||||
chunk->WriteStruct(col);
|
||||
|
||||
chunk->WriteStruct(m_SpecularPower);
|
||||
|
||||
// write main texture
|
||||
chunk->WriteObjectPointer(m_Textures[0]);
|
||||
|
||||
// misc data
|
||||
chunk->WriteStruct(m_TextureBorderColor);
|
||||
|
||||
// write mix data 1
|
||||
// construct mix data, see Read for more info about this mix data
|
||||
CKDWORD mixdata = 0;
|
||||
mixdata |= static_cast<CKDWORD>(m_TextureAddressMode) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_FillMode) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_ShadeMode) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_DestBlend) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_SourceBlend) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_TextureMagMode) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_TextureMinMode) & 0xF;
|
||||
mixdata <<= 4;
|
||||
mixdata |= static_cast<CKDWORD>(m_TextureBlendMode) & 0xF;
|
||||
// write it
|
||||
chunk->WriteStruct(mixdata);
|
||||
|
||||
// write mix data 2
|
||||
// construct it first, see Read for more info about this mix data
|
||||
mixdata = 0;
|
||||
mixdata |= static_cast<CKDWORD>(m_AlphaRef) & 0xFF;
|
||||
mixdata <<= 8;
|
||||
mixdata |= static_cast<CKDWORD>(m_AlphaFunc) & 0xFF;
|
||||
mixdata <<= 8;
|
||||
mixdata |= static_cast<CKDWORD>(m_ZFunc) & 0xFF;
|
||||
mixdata <<= 8;
|
||||
// sub mix flags
|
||||
CKDWORD mixflags = 0;
|
||||
if (m_EnableTwoSided) mixflags |= 0b1;
|
||||
if (m_EnableZWrite) mixflags |= 0b10;
|
||||
if (m_EnablePerspectiveCorrection) mixflags |= 0b100;
|
||||
if (m_EnableAlphaBlend) mixflags |= 0b1000;
|
||||
if (m_EnableAlphaTest) mixflags |= 0b10000;
|
||||
// merge into mix data
|
||||
mixdata |= mixflags & 0xFF;
|
||||
// write it
|
||||
chunk->WriteStruct(mixdata);
|
||||
|
||||
}
|
||||
|
||||
// write effect and extra texture.
|
||||
// it seems that extra textures only available when a valid effect existing
|
||||
if (m_Effect != VxMath::VX_EFFECT::VXEFFECT_NONE) {
|
||||
// we only support no-parameter effect, write it
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA3);
|
||||
chunk->WriteStruct(m_Effect);
|
||||
|
||||
// if have extra textures, write it
|
||||
if (m_Textures[1] != nullptr || m_Textures[2] != nullptr || m_Textures[3] != nullptr) {
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA2);
|
||||
chunk->WriteObjectPointer(m_Textures[1]);
|
||||
chunk->WriteObjectPointer(m_Textures[2]);
|
||||
chunk->WriteObjectPointer(m_Textures[3]);
|
||||
}
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_MATERIAL);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKMaterial::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKBeObject::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// clear textures
|
||||
for (auto& tex : m_Textures) {
|
||||
tex = nullptr;
|
||||
}
|
||||
|
||||
// read main data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA)) {
|
||||
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MAJORCHANGE_VERSION) {
|
||||
// MARK: old data process. i don't want to implement
|
||||
// because it is not related to my work. return false
|
||||
return false;
|
||||
} else {
|
||||
// 4 basic color and some power
|
||||
CKDWORD col;
|
||||
chunk->ReadStruct(col);
|
||||
m_Diffuse.FromARGB(col);
|
||||
chunk->ReadStruct(col);
|
||||
m_Ambient.FromARGB(col);
|
||||
chunk->ReadStruct(col);
|
||||
m_Specular.FromARGB(col);
|
||||
chunk->ReadStruct(col);
|
||||
m_Emissive.FromARGB(col);
|
||||
|
||||
chunk->ReadStruct(m_SpecularPower);
|
||||
|
||||
// main texture
|
||||
CKObject* tex = nullptr;
|
||||
chunk->ReadObjectPointer(tex);
|
||||
if (tex != nullptr && tex->GetClassID() == CK_CLASSID::CKCID_TEXTURE) {
|
||||
m_Textures[0] = static_cast<CKTexture*>(tex);
|
||||
}
|
||||
|
||||
// misc data
|
||||
chunk->ReadStruct(m_TextureBorderColor);
|
||||
|
||||
// mix data 1, including some blend enums
|
||||
// 32bit data. each 4 bit store a value. total 8 data.
|
||||
// HIGH >>> m_TextureAddressMode, m_FillMode, m_ShadeMode, m_DestBlend, m_SourceBlend, m_TextureMagMode, m_TextureMinMode, m_TextureBlendMode <<< LOW
|
||||
CKDWORD mixdata;
|
||||
chunk->ReadStruct(mixdata);
|
||||
m_TextureBlendMode = static_cast<VxMath::VXTEXTURE_BLENDMODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_TextureMinMode = static_cast<VxMath::VXTEXTURE_FILTERMODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_TextureMagMode = static_cast<VxMath::VXTEXTURE_FILTERMODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_SourceBlend = static_cast<VxMath::VXBLEND_MODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_DestBlend = static_cast<VxMath::VXBLEND_MODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_ShadeMode = static_cast<VxMath::VXSHADE_MODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_FillMode = static_cast<VxMath::VXFILL_MODE>(mixdata & 0xF);
|
||||
mixdata >>= 4;
|
||||
m_TextureAddressMode = static_cast<VxMath::VXTEXTURE_ADDRESSMODE>(mixdata & 0xF);
|
||||
|
||||
// mix data 2, including enable flag and transparent data
|
||||
// 32bit data.
|
||||
// HIGH >>> 0xFFFF(m_AlphaRef) 0xFFFF(m_AlphaFunc) 0xFFFF(m_ZFunc) 0xFFFF(enable flags) <<< LOW
|
||||
// for enable flags, total 8 bit. only low 5 bit used.
|
||||
// HIGH >>> 0(not used) 0(not used) 0(not used) 1(m_EnableAlphaTest) 1(m_EnableAlphaBlend) 1(m_EnablePerspectiveCorrection) 1(m_EnableZWrite) 1(m_EnableTwoSided) <<< LOW
|
||||
chunk->ReadStruct(mixdata);
|
||||
m_EnableTwoSided = mixdata & 0b1;
|
||||
m_EnableZWrite = mixdata & 0b10;
|
||||
m_EnablePerspectiveCorrection = mixdata & 0b100;
|
||||
m_EnableAlphaBlend = mixdata & 0b1000;
|
||||
m_EnableAlphaTest = mixdata & 0b10000;
|
||||
mixdata >>= 8;
|
||||
m_ZFunc = static_cast<VxMath::VXCMPFUNC>(mixdata & 0xFF);
|
||||
mixdata >>= 8;
|
||||
m_AlphaFunc = static_cast<VxMath::VXCMPFUNC>(mixdata & 0xFF);
|
||||
mixdata >>= 8;
|
||||
m_AlphaRef = static_cast<CKBYTE>(mixdata & 0xFF);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// extra texture data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA2)) {
|
||||
// read 3 extra texture
|
||||
CKObject* tex = nullptr;
|
||||
|
||||
for (size_t i = 1; i < 4; ++i) {
|
||||
chunk->ReadObjectPointer(tex);
|
||||
if (tex != nullptr && tex->GetClassID() == CK_CLASSID::CKCID_TEXTURE) {
|
||||
m_Textures[i] = static_cast<CKTexture*>(tex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// single effect
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA3)) {
|
||||
chunk->ReadStruct(m_Effect);
|
||||
}
|
||||
|
||||
// effect with parameter
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MATERIAL::CK_STATESAVE_MATDATA5)) {
|
||||
// MARK: i do not support CKParameter anymore.
|
||||
// so we downgrade it into single effect type.
|
||||
// hope this convertion will not break anything.
|
||||
|
||||
// drop parameter id.
|
||||
CK_ID paramid;
|
||||
chunk->ReadObjectID(paramid);
|
||||
|
||||
// read effect self
|
||||
chunk->ReadStruct(m_Effect);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma region Data Visitor
|
||||
|
||||
const VxMath::VxColor& CKMaterial::GetDiffuse() const {
|
||||
return m_Diffuse;
|
||||
}
|
||||
void CKMaterial::SetDiffuse(const VxMath::VxColor& col) {
|
||||
m_Diffuse = col;
|
||||
}
|
||||
const VxMath::VxColor& CKMaterial::GetAmbient() const {
|
||||
return m_Ambient;
|
||||
}
|
||||
void CKMaterial::SetAmbient(const VxMath::VxColor& col) {
|
||||
m_Ambient = col;
|
||||
}
|
||||
const VxMath::VxColor& CKMaterial::GetSpecular() const {
|
||||
return m_Specular;
|
||||
}
|
||||
void CKMaterial::SetSpecular(const VxMath::VxColor& col) {
|
||||
m_Specular = col;
|
||||
}
|
||||
const VxMath::VxColor& CKMaterial::GetEmissive() const {
|
||||
return m_Emissive;
|
||||
}
|
||||
void CKMaterial::SetEmissive(const VxMath::VxColor& col) {
|
||||
m_Emissive = col;
|
||||
}
|
||||
CKFLOAT CKMaterial::GetSpecularPower() const {
|
||||
return m_SpecularPower;
|
||||
}
|
||||
void CKMaterial::SetSpecularPower(CKFLOAT val) {
|
||||
m_SpecularPower = val;
|
||||
}
|
||||
|
||||
|
||||
CKTexture* CKMaterial::GetTexture(CKDWORD idx) const {
|
||||
if (idx >= m_Textures.size()) return nullptr;
|
||||
return m_Textures[idx];
|
||||
}
|
||||
void CKMaterial::SetTexture(CKTexture* tex, CKDWORD idx) {
|
||||
if (idx >= m_Textures.size()) return;
|
||||
m_Textures[idx] = tex;
|
||||
}
|
||||
CKDWORD CKMaterial::GetTextureBorderColor() const {
|
||||
return m_TextureBorderColor;
|
||||
}
|
||||
void CKMaterial::SetTextureBorderColor(CKDWORD val) {
|
||||
m_TextureBorderColor = val;
|
||||
}
|
||||
|
||||
|
||||
VxMath::VXTEXTURE_BLENDMODE CKMaterial::GetTextureBlendMode() const {
|
||||
return m_TextureBlendMode;
|
||||
}
|
||||
void CKMaterial::SetTextureBlendMode(VxMath::VXTEXTURE_BLENDMODE val) {
|
||||
m_TextureBlendMode = val;
|
||||
}
|
||||
VxMath::VXTEXTURE_FILTERMODE CKMaterial::GetTextureMinMode() const {
|
||||
return m_TextureMinMode;
|
||||
}
|
||||
void CKMaterial::SetTextureMinMode(VxMath::VXTEXTURE_FILTERMODE val) {
|
||||
m_TextureMinMode = val;
|
||||
}
|
||||
VxMath::VXTEXTURE_FILTERMODE CKMaterial::GetTextureMagMode() const {
|
||||
return m_TextureMagMode;
|
||||
}
|
||||
void CKMaterial::SetTextureMagMode(VxMath::VXTEXTURE_FILTERMODE val) {
|
||||
m_TextureMagMode = val;
|
||||
}
|
||||
VxMath::VXTEXTURE_ADDRESSMODE CKMaterial::GetTextureAddressMode() const {
|
||||
return m_TextureAddressMode;
|
||||
}
|
||||
void CKMaterial::SetTextureAddressMode(VxMath::VXTEXTURE_ADDRESSMODE val) {
|
||||
m_TextureAddressMode = val;
|
||||
}
|
||||
|
||||
|
||||
VxMath::VXBLEND_MODE CKMaterial::GetSourceBlend() const {
|
||||
return m_SourceBlend;
|
||||
}
|
||||
void CKMaterial::SetSourceBlend(VxMath::VXBLEND_MODE val) {
|
||||
m_SourceBlend = val;
|
||||
}
|
||||
VxMath::VXBLEND_MODE CKMaterial::GetDestBlend() const {
|
||||
return m_DestBlend;
|
||||
}
|
||||
void CKMaterial::SetDestBlend(VxMath::VXBLEND_MODE val) {
|
||||
m_DestBlend = val;
|
||||
}
|
||||
VxMath::VXFILL_MODE CKMaterial::GetFillMode() const {
|
||||
return m_FillMode;
|
||||
}
|
||||
void CKMaterial::SetFillMode(VxMath::VXFILL_MODE val) {
|
||||
m_FillMode = val;
|
||||
}
|
||||
VxMath::VXSHADE_MODE CKMaterial::GetShadeMode() const {
|
||||
return m_ShadeMode;
|
||||
}
|
||||
void CKMaterial::SetShadeMode(VxMath::VXSHADE_MODE val) {
|
||||
m_ShadeMode = val;
|
||||
}
|
||||
|
||||
|
||||
bool CKMaterial::GetAlphaTestEnabled() const {
|
||||
return m_EnableAlphaTest;
|
||||
}
|
||||
void CKMaterial::SetAlphaTestEnabled(bool enabled) {
|
||||
m_EnableAlphaTest = enabled;
|
||||
}
|
||||
bool CKMaterial::GetAlphaBlendEnabled() const {
|
||||
return m_EnableAlphaBlend;
|
||||
}
|
||||
void CKMaterial::SetAlphaBlendEnabled(bool enabled) {
|
||||
m_EnableAlphaBlend = enabled;
|
||||
}
|
||||
bool CKMaterial::GetPerspectiveCorrectionEnabled() const {
|
||||
return m_EnablePerspectiveCorrection;
|
||||
}
|
||||
void CKMaterial::SetPerspectiveCorrectionEnabled(bool enabled) {
|
||||
m_EnablePerspectiveCorrection = enabled;
|
||||
}
|
||||
bool CKMaterial::GetZWriteEnabled() const {
|
||||
return m_EnableZWrite;
|
||||
}
|
||||
void CKMaterial::SetZWriteEnabled(bool enabled) {
|
||||
m_EnableZWrite = enabled;
|
||||
}
|
||||
bool CKMaterial::GetTwoSidedEnabled() const {
|
||||
return m_EnableTwoSided;
|
||||
}
|
||||
void CKMaterial::SetTwoSidedEnabled(bool enabled) {
|
||||
m_EnableTwoSided = enabled;
|
||||
}
|
||||
|
||||
|
||||
CKBYTE CKMaterial::GetAlphaRef() const {
|
||||
return m_AlphaRef;
|
||||
}
|
||||
void CKMaterial::SetAlphaRef(CKBYTE val) {
|
||||
m_AlphaRef = val;
|
||||
}
|
||||
VxMath::VXCMPFUNC CKMaterial::GetAlphaFunc() const {
|
||||
return m_AlphaFunc;
|
||||
}
|
||||
void CKMaterial::SetAlphaFunc(VxMath::VXCMPFUNC val) {
|
||||
m_AlphaFunc = val;
|
||||
}
|
||||
VxMath::VXCMPFUNC CKMaterial::GetZFunc() const {
|
||||
return m_ZFunc;
|
||||
}
|
||||
void CKMaterial::SetZFunc(VxMath::VXCMPFUNC val) {
|
||||
m_ZFunc = val;
|
||||
}
|
||||
VxMath::VX_EFFECT CKMaterial::GetEffect() const {
|
||||
return m_Effect;
|
||||
}
|
||||
void CKMaterial::SetEffect(VxMath::VX_EFFECT val) {
|
||||
m_Effect = val;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKBeObject.hpp"
|
||||
#include <array>
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKMaterial : public CKBeObject {
|
||||
public:
|
||||
CKMaterial(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKMaterial();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKMaterial);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_MATERIAL;
|
||||
}
|
||||
|
||||
virtual void CheckPreDeletion() override;
|
||||
|
||||
// 2 RW functions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
const VxMath::VxColor& GetDiffuse() const;
|
||||
void SetDiffuse(const VxMath::VxColor& col);
|
||||
const VxMath::VxColor& GetAmbient() const;
|
||||
void SetAmbient(const VxMath::VxColor& col);
|
||||
const VxMath::VxColor& GetSpecular() const;
|
||||
void SetSpecular(const VxMath::VxColor& col);
|
||||
const VxMath::VxColor& GetEmissive() const;
|
||||
void SetEmissive(const VxMath::VxColor& col);
|
||||
CKFLOAT GetSpecularPower() const;
|
||||
void SetSpecularPower(CKFLOAT val);
|
||||
|
||||
CKTexture* GetTexture(CKDWORD idx = 0) const;
|
||||
void SetTexture(CKTexture* tex, CKDWORD idx = 0);
|
||||
CKDWORD GetTextureBorderColor() const;
|
||||
void SetTextureBorderColor(CKDWORD val);
|
||||
|
||||
VxMath::VXTEXTURE_BLENDMODE GetTextureBlendMode() const;
|
||||
void SetTextureBlendMode(VxMath::VXTEXTURE_BLENDMODE val);
|
||||
VxMath::VXTEXTURE_FILTERMODE GetTextureMinMode() const;
|
||||
void SetTextureMinMode(VxMath::VXTEXTURE_FILTERMODE val);
|
||||
VxMath::VXTEXTURE_FILTERMODE GetTextureMagMode() const;
|
||||
void SetTextureMagMode(VxMath::VXTEXTURE_FILTERMODE val);
|
||||
VxMath::VXTEXTURE_ADDRESSMODE GetTextureAddressMode() const;
|
||||
void SetTextureAddressMode(VxMath::VXTEXTURE_ADDRESSMODE val);
|
||||
|
||||
VxMath::VXBLEND_MODE GetSourceBlend() const;
|
||||
void SetSourceBlend(VxMath::VXBLEND_MODE val);
|
||||
VxMath::VXBLEND_MODE GetDestBlend() const;
|
||||
void SetDestBlend(VxMath::VXBLEND_MODE val);
|
||||
VxMath::VXFILL_MODE GetFillMode() const;
|
||||
void SetFillMode(VxMath::VXFILL_MODE val);
|
||||
VxMath::VXSHADE_MODE GetShadeMode() const;
|
||||
void SetShadeMode(VxMath::VXSHADE_MODE val);
|
||||
|
||||
bool GetAlphaTestEnabled() const;
|
||||
void SetAlphaTestEnabled(bool enabled);
|
||||
bool GetAlphaBlendEnabled() const;
|
||||
void SetAlphaBlendEnabled(bool enabled);
|
||||
bool GetPerspectiveCorrectionEnabled() const;
|
||||
void SetPerspectiveCorrectionEnabled(bool enabled);
|
||||
bool GetZWriteEnabled() const;
|
||||
void SetZWriteEnabled(bool enabled);
|
||||
bool GetTwoSidedEnabled() const;
|
||||
void SetTwoSidedEnabled(bool enabled);
|
||||
|
||||
CKBYTE GetAlphaRef() const;
|
||||
void SetAlphaRef(CKBYTE val);
|
||||
VxMath::VXCMPFUNC GetAlphaFunc() const;
|
||||
void SetAlphaFunc(VxMath::VXCMPFUNC val);
|
||||
VxMath::VXCMPFUNC GetZFunc() const;
|
||||
void SetZFunc(VxMath::VXCMPFUNC val);
|
||||
VxMath::VX_EFFECT GetEffect() const;
|
||||
void SetEffect(VxMath::VX_EFFECT val);
|
||||
|
||||
protected:
|
||||
VxMath::VxColor m_Diffuse;
|
||||
VxMath::VxColor m_Ambient;
|
||||
VxMath::VxColor m_Specular;
|
||||
VxMath::VxColor m_Emissive;
|
||||
CKFLOAT m_SpecularPower;
|
||||
|
||||
std::array<CKTexture*, 4> m_Textures;
|
||||
CKDWORD m_TextureBorderColor;
|
||||
|
||||
VxMath::VXTEXTURE_BLENDMODE m_TextureBlendMode;
|
||||
VxMath::VXTEXTURE_FILTERMODE m_TextureMinMode;
|
||||
VxMath::VXTEXTURE_FILTERMODE m_TextureMagMode;
|
||||
VxMath::VXTEXTURE_ADDRESSMODE m_TextureAddressMode;
|
||||
|
||||
VxMath::VXBLEND_MODE m_SourceBlend;
|
||||
VxMath::VXBLEND_MODE m_DestBlend;
|
||||
VxMath::VXFILL_MODE m_FillMode;
|
||||
VxMath::VXSHADE_MODE m_ShadeMode;
|
||||
|
||||
bool m_EnableAlphaTest;
|
||||
bool m_EnableAlphaBlend;
|
||||
bool m_EnablePerspectiveCorrection;
|
||||
bool m_EnableZWrite;
|
||||
bool m_EnableTwoSided;
|
||||
|
||||
CKBYTE m_AlphaRef;
|
||||
VxMath::VXCMPFUNC m_AlphaFunc;
|
||||
VxMath::VXCMPFUNC m_ZFunc;
|
||||
VxMath::VX_EFFECT m_Effect;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@@ -1,743 +0,0 @@
|
||||
#include "CKMesh.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
#include "CKMaterial.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKMesh::CKMesh(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKBeObject(ctx, ckid, name),
|
||||
// init vertex
|
||||
m_VertexCount(0),
|
||||
m_VertexPosition(), m_VertexNormal(), m_VertexUV(),
|
||||
m_VertexColor(), m_VertexSpecularColor(),
|
||||
// init mtl slots
|
||||
m_MaterialSlotCount(0),
|
||||
m_MaterialSlot(),
|
||||
// init face data
|
||||
m_FaceCount(0),
|
||||
m_FaceIndices(), m_FaceMtlIndex(), m_FaceOthers(),
|
||||
// init line
|
||||
m_LineCount(0),
|
||||
m_LineIndices(),
|
||||
// init flags
|
||||
m_Flags(YYCC::EnumHelper::Merge(
|
||||
VxMath::VXMESH_FLAGS::VXMESH_VISIBLE,
|
||||
VxMath::VXMESH_FLAGS::VXMESH_RENDERCHANNELS
|
||||
)) {
|
||||
// set visible in default
|
||||
YYCC::EnumHelper::Add(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
}
|
||||
|
||||
CKMesh::~CKMesh() {}
|
||||
|
||||
void CKMesh::CheckPreDeletion() {
|
||||
CKBeObject::CheckPreDeletion();
|
||||
|
||||
// check material slots
|
||||
for (auto& slot : m_MaterialSlot) {
|
||||
if (slot != nullptr && slot->IsToBeDeleted()) {
|
||||
slot = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool CKMesh::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKBeObject::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// write mesh flags
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFLAGS);
|
||||
chunk->WriteStruct(m_Flags);
|
||||
}
|
||||
|
||||
// write material slots
|
||||
// MARK: due to virtools shit implement, we must make sure there is at least one material channel existed.
|
||||
// so if the material slot is empty, we write a mullptr slot for it.
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHMATERIALS);
|
||||
|
||||
if (GetMaterialSlotCount() != 0) {
|
||||
// write real slots
|
||||
chunk->WriteStruct(GetMaterialSlotCount());
|
||||
for (auto& mtlSlot : m_MaterialSlot) {
|
||||
// write object id
|
||||
chunk->WriteObjectPointer(mtlSlot);
|
||||
// MARK: write a zero? idk what the fuck it is.
|
||||
chunk->WriteStruct(static_cast<CKDWORD>(0));
|
||||
}
|
||||
} else {
|
||||
// write fake one like real one
|
||||
chunk->WriteStruct(static_cast<CKDWORD>(1));
|
||||
// write id and blank
|
||||
chunk->WriteObjectPointer(nullptr);
|
||||
chunk->WriteStruct(static_cast<CKDWORD>(0));
|
||||
}
|
||||
}
|
||||
|
||||
// write face data
|
||||
if (GetFaceCount() != 0) {
|
||||
CKDWORD faceCount = GetFaceCount();
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFACES);
|
||||
chunk->WriteStruct(faceCount);
|
||||
|
||||
// write compressed data, see Read for more info about this struct
|
||||
// lock buffer first
|
||||
auto buf = chunk->LockWriteBufferWrapper(faceCount * CKSizeof(CKDWORD) * 2);
|
||||
CKWORD* rawbuf = static_cast<CKWORD*>(buf.get());
|
||||
|
||||
// copy indice
|
||||
VxMath::VxCopyStructure(
|
||||
faceCount,
|
||||
rawbuf,
|
||||
2 * CKSizeof(CKDWORD),
|
||||
3 * CKSizeof(CKWORD),
|
||||
m_FaceIndices.data(),
|
||||
3 * CKSizeof(CKWORD)
|
||||
);
|
||||
// copy mtl index
|
||||
VxMath::VxCopyStructure(
|
||||
faceCount,
|
||||
rawbuf + 3,
|
||||
2 * CKSizeof(CKDWORD),
|
||||
CKSizeof(CKWORD),
|
||||
m_FaceMtlIndex.data(),
|
||||
CKSizeof(CKWORD)
|
||||
);
|
||||
|
||||
// free buf
|
||||
buf.reset();
|
||||
}
|
||||
|
||||
// write line data
|
||||
if (GetLineCount() != 0) {
|
||||
CKDWORD lineCount = GetLineCount();
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHLINES);
|
||||
chunk->WriteStruct(lineCount);
|
||||
|
||||
chunk->WriteBuffer(m_LineIndices.data(), CKSizeof(CKWORD) * 2 * lineCount);
|
||||
}
|
||||
|
||||
// write vertex data
|
||||
if (GetVertexCount() != 0) {
|
||||
CKDWORD vtxCount = GetVertexCount();
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHVERTICES);
|
||||
chunk->WriteStruct(vtxCount);
|
||||
|
||||
// construct vertex save flags
|
||||
// and save it
|
||||
VertexSaveFlags saveflags = GenerateSaveFlags();
|
||||
chunk->WriteStruct(saveflags);
|
||||
|
||||
// reserve enough space for full data written, but we can specify the real consumed size later
|
||||
// we also need calc the consumed size when writing file
|
||||
auto buf = chunk->LockWriteBufferWrapper((
|
||||
CKSizeof(VxMath::VxVector3) + // vertex position
|
||||
CKSizeof(CKDWORD) + CKSizeof(CKDWORD) + // color and specular color
|
||||
CKSizeof(VxMath::VxVector3) + // vertex normal
|
||||
CKSizeof(VxMath::VxVector2) // vertex uv
|
||||
) * vtxCount); // mul vertex count
|
||||
CKBYTE* rawbuf = static_cast<CKBYTE*>(buf.get());
|
||||
|
||||
// reserve length data
|
||||
CKDWORD* reservedBufDwordSize = reinterpret_cast<CKDWORD*>(rawbuf);
|
||||
rawbuf += CKSizeof(CKDWORD);
|
||||
|
||||
// write vertex position
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::NoPos)) {
|
||||
CKDWORD consumed = CKSizeof(VxMath::VxVector3) * vtxCount;
|
||||
std::memcpy(rawbuf, m_VertexPosition.data(), consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
|
||||
// write color and specular color
|
||||
{
|
||||
CKDWORD consumed = 0;
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::SingleColor)) {
|
||||
consumed = CKSizeof(CKDWORD) * vtxCount;
|
||||
} else {
|
||||
consumed = CKSizeof(CKDWORD);
|
||||
}
|
||||
|
||||
std::memcpy(rawbuf, m_VertexColor.data(), consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
{
|
||||
CKDWORD consumed = 0;
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::SingleSpecularColor)) {
|
||||
consumed = CKSizeof(CKDWORD) * vtxCount;
|
||||
} else {
|
||||
consumed = CKSizeof(CKDWORD);
|
||||
}
|
||||
|
||||
std::memcpy(rawbuf, m_VertexSpecularColor.data(), consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
|
||||
// write normal
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::NoNormal)) {
|
||||
CKDWORD consumed = CKSizeof(VxMath::VxVector3) * vtxCount;
|
||||
std::memcpy(rawbuf, m_VertexNormal.data(), consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
|
||||
// write uv
|
||||
{
|
||||
CKDWORD consumed = 0;
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::SingleUV)) {
|
||||
consumed = CKSizeof(VxMath::VxVector2) * vtxCount;
|
||||
} else {
|
||||
consumed = CKSizeof(VxMath::VxVector2);
|
||||
}
|
||||
|
||||
std::memcpy(rawbuf, m_VertexUV.data(), consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
|
||||
// calc real consumed size
|
||||
CKDWORD realConsumedSize = static_cast<CKDWORD>(rawbuf - static_cast<CKBYTE*>(buf.get()));
|
||||
// assign to reserved length field
|
||||
// length also include length indicator it self
|
||||
*reservedBufDwordSize = realConsumedSize / CKSizeof(CKDWORD);
|
||||
// notify buffer real consumed size
|
||||
buf.get_deleter().SetConsumedSize(realConsumedSize);
|
||||
|
||||
// free buffer
|
||||
buf.reset();
|
||||
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_MESH);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKMesh::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKBeObject::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// clear all data
|
||||
CleanMesh();
|
||||
|
||||
// check data version.
|
||||
// MARK: too low data is not supported.
|
||||
// because my work are not related to them
|
||||
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MESHCHANGE_VERSION) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// read flag
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFLAGS)) {
|
||||
chunk->ReadStruct(m_Flags);
|
||||
YYCC::EnumHelper::Mask(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_ALLFLAGS);
|
||||
|
||||
// I don't know why, just interpter the IDA code.
|
||||
YYCC::EnumHelper::Remove(m_Flags,
|
||||
VxMath::VXMESH_FLAGS::VXMESH_BOUNDINGUPTODATE,
|
||||
VxMath::VXMESH_FLAGS::VXMESH_OPTIMIZED
|
||||
);
|
||||
}
|
||||
|
||||
// read material slots
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHMATERIALS)) {
|
||||
// get and set material count
|
||||
CKDWORD mtlCount;
|
||||
chunk->ReadStruct(mtlCount);
|
||||
SetMaterialSlotCount(mtlCount);
|
||||
|
||||
// read slot
|
||||
CKDWORD ph;
|
||||
CKObject* objptr = nullptr;
|
||||
for (auto& mtlSlot : m_MaterialSlot) {
|
||||
// read id
|
||||
chunk->ReadObjectPointer(objptr);
|
||||
// and read a place holder idk what the fuck it is.
|
||||
chunk->ReadStruct(ph);
|
||||
|
||||
// try to assign
|
||||
if (objptr != nullptr && objptr->GetClassID() == CK_CLASSID::CKCID_MATERIAL) {
|
||||
mtlSlot = static_cast<CKMaterial*>(objptr);
|
||||
} else {
|
||||
mtlSlot = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// read vertex data
|
||||
VertexSaveFlags saveflags = VertexSaveFlags::None;
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHVERTICES)) {
|
||||
// read and set vertex count
|
||||
CKDWORD vertexCount;
|
||||
chunk->ReadStruct(vertexCount);
|
||||
SetVertexCount(vertexCount);
|
||||
|
||||
if (vertexCount != 0) {
|
||||
// read save flags
|
||||
chunk->ReadStruct(saveflags);
|
||||
|
||||
// read size in dword (including it self)
|
||||
CKDWORD sizeInDword;
|
||||
chunk->ReadStruct(sizeInDword);
|
||||
--sizeInDword; // remove self.
|
||||
|
||||
// lock read buffer
|
||||
auto buf = chunk->LockReadBufferWrapper(sizeInDword * CKSizeof(CKDWORD));
|
||||
const CKBYTE* rawbuf = static_cast<const CKBYTE*>(buf.get());
|
||||
|
||||
// copy position if it have
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::NoPos)) {
|
||||
CKDWORD consumed = CKSizeof(VxMath::VxVector3) * vertexCount;
|
||||
std::memcpy(m_VertexPosition.data(), rawbuf, consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
|
||||
// copy color or apply single color
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::SingleColor)) {
|
||||
CKDWORD consumed = CKSizeof(CKDWORD) * vertexCount;
|
||||
std::memcpy(m_VertexColor.data(), rawbuf, consumed);
|
||||
rawbuf += consumed;
|
||||
} else {
|
||||
VxMath::VxCopyStructure(
|
||||
vertexCount,
|
||||
m_VertexColor.data(),
|
||||
CKSizeof(CKDWORD),
|
||||
CKSizeof(CKDWORD),
|
||||
rawbuf,
|
||||
0 // InStride = 0 to make sure copy this single value to every elements.
|
||||
);
|
||||
rawbuf += CKSizeof(CKDWORD);
|
||||
}
|
||||
|
||||
// copy specular color or apply a single color
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::SingleSpecularColor)) {
|
||||
CKDWORD consumed = CKSizeof(CKDWORD) * vertexCount;
|
||||
std::memcpy(m_VertexSpecularColor.data(), rawbuf, consumed);
|
||||
rawbuf += consumed;
|
||||
} else {
|
||||
VxMath::VxCopyStructure(
|
||||
vertexCount,
|
||||
m_VertexSpecularColor.data(),
|
||||
CKSizeof(CKDWORD),
|
||||
CKSizeof(CKDWORD),
|
||||
rawbuf,
|
||||
0 // InStride = 0 to make sure copy this single value to every elements.
|
||||
);
|
||||
rawbuf += CKSizeof(CKDWORD);
|
||||
}
|
||||
|
||||
// copy normals if it has
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::NoNormal)) {
|
||||
CKDWORD consumed = CKSizeof(VxMath::VxVector3) * vertexCount;
|
||||
std::memcpy(m_VertexNormal.data(), rawbuf, consumed);
|
||||
rawbuf += consumed;
|
||||
}
|
||||
|
||||
// copy uv or apply single uv
|
||||
if (!YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::SingleUV)) {
|
||||
CKDWORD consumed = CKSizeof(VxMath::VxVector2) * vertexCount;
|
||||
std::memcpy(m_VertexUV.data(), rawbuf, consumed);
|
||||
rawbuf += consumed;
|
||||
} else {
|
||||
VxMath::VxCopyStructure(
|
||||
vertexCount,
|
||||
m_VertexUV.data(),
|
||||
CKSizeof(VxMath::VxVector2),
|
||||
CKSizeof(VxMath::VxVector2),
|
||||
rawbuf,
|
||||
0 // InStride = 0 to make sure copy this single value to every elements.
|
||||
);
|
||||
rawbuf += CKSizeof(VxMath::VxVector2);
|
||||
}
|
||||
|
||||
// free buf
|
||||
buf.reset();
|
||||
}
|
||||
}
|
||||
|
||||
// read face data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFACES)) {
|
||||
// read face count and set
|
||||
CKDWORD faceCount;
|
||||
chunk->ReadStruct(faceCount);
|
||||
SetFaceCount(faceCount);
|
||||
|
||||
// lock buffer
|
||||
auto buf = chunk->LockReadBufferWrapper(faceCount * CKSizeof(CKDWORD) * 2);
|
||||
const CKWORD* rawbuf = static_cast<const CKWORD*>(buf.get());
|
||||
// each face use 2 CKDWORD to describe
|
||||
// first CKDWORD describe first 2 face vertex indices
|
||||
// HIGH >>> 0xFFFF(indice 1) 0xFFFF(indice 0) <<< LOW
|
||||
// second CKDWORD describe the third indices and used material slot index
|
||||
// HIGH >>> 0xFFFF(mtl slot index) 0xFFFF(indice 2) <<< LOW
|
||||
|
||||
// due to little endian, the data listed before are placed in memory like this:
|
||||
// (indice 0) (indice 1) (indice 2) (mtl idx)
|
||||
|
||||
// copy indice
|
||||
VxMath::VxCopyStructure(
|
||||
faceCount,
|
||||
m_FaceIndices.data(),
|
||||
3 * CKSizeof(CKWORD),
|
||||
3 * CKSizeof(CKWORD),
|
||||
rawbuf,
|
||||
2 * CKSizeof(CKDWORD)
|
||||
);
|
||||
// copy mtl index
|
||||
VxMath::VxCopyStructure(
|
||||
faceCount,
|
||||
m_FaceMtlIndex.data(),
|
||||
CKSizeof(CKWORD),
|
||||
CKSizeof(CKWORD),
|
||||
rawbuf + 3,
|
||||
2 * CKSizeof(CKDWORD)
|
||||
);
|
||||
|
||||
// free buf
|
||||
buf.reset();
|
||||
}
|
||||
|
||||
// read line data
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHLINES)) {
|
||||
// read and set line count;
|
||||
CKDWORD lineCount;
|
||||
chunk->ReadStruct(lineCount);
|
||||
SetLineCount(lineCount);
|
||||
|
||||
chunk->ReadAndFillBuffer(m_LineIndices.data());
|
||||
}
|
||||
|
||||
// build normals
|
||||
if (YYCC::EnumHelper::Has(saveflags, VertexSaveFlags::NoNormal)) {
|
||||
BuildNormals();
|
||||
} else {
|
||||
BuildFaceNormals();
|
||||
}
|
||||
|
||||
// MARK: material channels, vertex weight, face mask added originally
|
||||
// but removed at Oct 1st, 2023 because I will not use them and I couldn't test them.
|
||||
|
||||
// MARK: progressive mesh data is dropper.
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CKMesh::Show(CK_OBJECT_SHOWOPTION show) {
|
||||
CKObject::Show(show);
|
||||
|
||||
if (show == CK_OBJECT_SHOWOPTION::CKSHOW) {
|
||||
YYCC::EnumHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_VISIBLE);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma region Misc Section
|
||||
|
||||
void CKMesh::CleanMesh() {
|
||||
SetVertexCount(0);
|
||||
SetMaterialSlotCount(0);
|
||||
SetFaceCount(0);
|
||||
SetLineCount(0);
|
||||
}
|
||||
|
||||
VxMath::VXMESH_FLAGS CKMesh::GetMeshFlags() const {
|
||||
return m_Flags;
|
||||
}
|
||||
|
||||
void CKMesh::SetMeshFlags(VxMath::VXMESH_FLAGS flags) {
|
||||
// set value
|
||||
m_Flags = flags;
|
||||
|
||||
// sync visibility to CKObject layer.
|
||||
if (YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_VISIBLE)) {
|
||||
YYCC::EnumHelper::Add(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
VxMath::VXMESH_LITMODE CKMesh::GetLitMode() const {
|
||||
if (YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PRELITMODE)) {
|
||||
return VxMath::VXMESH_LITMODE::VX_PRELITMESH;
|
||||
} else {
|
||||
return VxMath::VXMESH_LITMODE::VX_LITMESH;
|
||||
}
|
||||
}
|
||||
|
||||
void CKMesh::SetLitMode(VxMath::VXMESH_LITMODE mode) {
|
||||
switch (mode) {
|
||||
case VxMath::VXMESH_LITMODE::VX_PRELITMESH:
|
||||
YYCC::EnumHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PRELITMODE);
|
||||
break;
|
||||
case VxMath::VXMESH_LITMODE::VX_LITMESH:
|
||||
YYCC::EnumHelper::Remove(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PRELITMODE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
VxMath::VXTEXTURE_WRAPMODE CKMesh::GetWrapMode() const {
|
||||
VxMath::VXTEXTURE_WRAPMODE ret = VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_NONE;
|
||||
|
||||
if (YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPU)) {
|
||||
YYCC::EnumHelper::Add(ret, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_U);
|
||||
}
|
||||
if (YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPV)) {
|
||||
YYCC::EnumHelper::Add(ret, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_V);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void CKMesh::SetWrapMode(VxMath::VXTEXTURE_WRAPMODE mode) {
|
||||
if (YYCC::EnumHelper::Has(mode, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_U)) {
|
||||
YYCC::EnumHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPU);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPU);
|
||||
}
|
||||
|
||||
if (YYCC::EnumHelper::Has(mode, VxMath::VXTEXTURE_WRAPMODE::VXTEXTUREWRAP_V)) {
|
||||
YYCC::EnumHelper::Add(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPV);
|
||||
} else {
|
||||
YYCC::EnumHelper::Remove(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_WRAPV);
|
||||
}
|
||||
}
|
||||
|
||||
CKMesh::VertexSaveFlags CKMesh::GenerateSaveFlags() {
|
||||
// set to initial status
|
||||
VertexSaveFlags saveflags = YYCC::EnumHelper::Merge(
|
||||
VertexSaveFlags::SingleColor,
|
||||
VertexSaveFlags::SingleSpecularColor,
|
||||
VertexSaveFlags::NoNormal,
|
||||
VertexSaveFlags::SingleUV
|
||||
);
|
||||
|
||||
// check no pos
|
||||
// if position is generated, skip saving position
|
||||
if (YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PROCEDURALPOS)) {
|
||||
YYCC::EnumHelper::Add(saveflags, VertexSaveFlags::NoPos);
|
||||
}
|
||||
|
||||
// check uv
|
||||
// if uv is not generated and all uv are not the same value, remove single uv
|
||||
if (!YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PROCEDURALUV)) {
|
||||
for (const auto& uv : m_VertexUV) {
|
||||
if (uv != m_VertexUV.front()) {
|
||||
YYCC::EnumHelper::Remove(saveflags, VertexSaveFlags::SingleUV);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// check color and specular color
|
||||
// if all color are not the same value, remove single color
|
||||
for (const auto& col : m_VertexColor) {
|
||||
if (col != m_VertexColor.front()) {
|
||||
YYCC::EnumHelper::Remove(saveflags, VertexSaveFlags::SingleColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (const auto& col : m_VertexSpecularColor) {
|
||||
if (col != m_VertexSpecularColor.front()) {
|
||||
YYCC::EnumHelper::Remove(saveflags, VertexSaveFlags::SingleSpecularColor);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// if normal not changed, and position is not generated, we should consider whether we need save normal (step into if)
|
||||
if (!YYCC::EnumHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_NORMAL_CHANGED, VxMath::VXMESH_FLAGS::VXMESH_PROCEDURALPOS)) {
|
||||
// MARK: we should build face normal first
|
||||
// then we build vertex normal like BuildNormals.
|
||||
// then, we compare the difference between the generated normals and user specified normals, by simply using operator- (userNml - generatedNml) and abs the result.
|
||||
// then we accumulate these difference, by simply adding them together.
|
||||
// then we div the accumulation by the count of vertex, we got a normalized accumulated difference.
|
||||
// we compare its length with 0.001. if is length is lower than 0.001, it prove that the difference is enough small and we can skip normal save.
|
||||
// othersize we should save normal one by one.
|
||||
|
||||
BuildFaceNormals();
|
||||
|
||||
// init generated nml list first
|
||||
XContainer::XArray<VxMath::VxVector3> generated(m_VertexCount, VxMath::VxVector3());
|
||||
// and accumulated for each normal
|
||||
for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) {
|
||||
generated[m_FaceIndices[fid * 3]] += m_FaceOthers[fid].m_Normal;
|
||||
generated[m_FaceIndices[fid * 3 + 1]] += m_FaceOthers[fid].m_Normal;
|
||||
generated[m_FaceIndices[fid * 3 + 2]] += m_FaceOthers[fid].m_Normal;
|
||||
}
|
||||
|
||||
// init accumulated difference vector first
|
||||
VxMath::VxVector3 accnml;
|
||||
// accumulate difference
|
||||
for (CKDWORD vid = 0; vid < m_VertexCount; ++vid) {
|
||||
// normalize generated normal first
|
||||
generated[vid].Normalized();
|
||||
// get diff by distance
|
||||
VxMath::VxVector3 diff = m_VertexNormal[vid] - generated[vid];
|
||||
// abs the diff and add into accumulated diff
|
||||
VxMath::NSVxVector::Absolute(diff);
|
||||
accnml += diff;
|
||||
}
|
||||
|
||||
// div by vertex count and compare its length
|
||||
accnml /= static_cast<CKFLOAT>(m_VertexCount);
|
||||
if (accnml.Length() > 0.001f) {
|
||||
// too large difference, we need save normal
|
||||
YYCC::EnumHelper::Remove(saveflags, VertexSaveFlags::NoNormal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return saveflags;
|
||||
}
|
||||
|
||||
void CKMesh::BuildNormals() {
|
||||
if (m_FaceCount == 0 || m_VertexCount == 0) return;
|
||||
|
||||
// build face normal first
|
||||
BuildFaceNormals();
|
||||
|
||||
// iterate all face and add face normal to each point's normal
|
||||
for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) {
|
||||
m_VertexNormal[m_FaceIndices[fid * 3]] += m_FaceOthers[fid].m_Normal;
|
||||
m_VertexNormal[m_FaceIndices[fid * 3 + 1]] += m_FaceOthers[fid].m_Normal;
|
||||
m_VertexNormal[m_FaceIndices[fid * 3 + 2]] += m_FaceOthers[fid].m_Normal;
|
||||
}
|
||||
|
||||
// then normalize all vertex normal
|
||||
for (auto& nml : m_VertexNormal) {
|
||||
nml.Normalized();
|
||||
}
|
||||
}
|
||||
|
||||
void CKMesh::BuildFaceNormals() {
|
||||
if (m_FaceCount == 0 || m_VertexCount == 0) return;
|
||||
|
||||
// iertate all face to build face normal according to position data
|
||||
for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) {
|
||||
VxMath::VxVector3 *p0 = &m_VertexPosition[m_FaceIndices[fid * 3]];
|
||||
|
||||
VxMath::VxVector3 p0_p1 = m_VertexPosition[m_FaceIndices[fid * 3 + 1]] - *p0,
|
||||
p0_p2 = m_VertexPosition[m_FaceIndices[fid * 3 + 2]] - *p0;
|
||||
|
||||
// cross product to get normal
|
||||
// and normalize it
|
||||
VxMath::VxVector3 nml = VxMath::NSVxVector::CrossProduct(p0_p1, p0_p2);
|
||||
nml.Normalized();
|
||||
|
||||
// assign it
|
||||
m_FaceOthers[fid].m_Normal = nml;
|
||||
}
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Vertex Section
|
||||
|
||||
CKDWORD CKMesh::GetVertexCount() const {
|
||||
return m_VertexCount;
|
||||
}
|
||||
|
||||
void CKMesh::SetVertexCount(CKDWORD count) {
|
||||
m_VertexCount = count;
|
||||
m_VertexPosition.resize(count);
|
||||
m_VertexNormal.resize(count);
|
||||
m_VertexUV.resize(count);
|
||||
m_VertexColor.resize(count, 0xFFFFFFFF);
|
||||
m_VertexSpecularColor.resize(count, 0x00000000);
|
||||
}
|
||||
|
||||
VxMath::VxVector3* CKMesh::GetVertexPositions() {
|
||||
if (m_VertexCount == 0) return nullptr;
|
||||
return m_VertexPosition.data();
|
||||
}
|
||||
|
||||
VxMath::VxVector3* CKMesh::GetVertexNormals() {
|
||||
if (m_VertexCount == 0) return nullptr;
|
||||
return m_VertexNormal.data();
|
||||
}
|
||||
|
||||
VxMath::VxVector2* CKMesh::GetVertexUVs() {
|
||||
if (m_VertexCount == 0) return nullptr;
|
||||
return m_VertexUV.data();
|
||||
}
|
||||
|
||||
CKDWORD* CKMesh::GetVertexColors() {
|
||||
if (m_VertexCount == 0) return nullptr;
|
||||
return m_VertexColor.data();
|
||||
}
|
||||
|
||||
CKDWORD* CKMesh::GetVertexSpecularColors() {
|
||||
if (m_VertexCount == 0) return nullptr;
|
||||
return m_VertexSpecularColor.data();
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Material Slot Section
|
||||
|
||||
CKDWORD CKMesh::GetMaterialSlotCount() const {
|
||||
return m_MaterialSlotCount;
|
||||
}
|
||||
|
||||
void CKMesh::SetMaterialSlotCount(CKDWORD count) {
|
||||
m_MaterialSlotCount = count;
|
||||
m_MaterialSlot.resize(count, nullptr);
|
||||
}
|
||||
|
||||
CKMaterial** CKMesh::GetMaterialSlots() {
|
||||
if (m_MaterialSlotCount == 0) return nullptr;
|
||||
return m_MaterialSlot.data();
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Face Section
|
||||
|
||||
CKDWORD CKMesh::GetFaceCount() const {
|
||||
return m_FaceCount;
|
||||
}
|
||||
|
||||
void CKMesh::SetFaceCount(CKDWORD count) {
|
||||
m_FaceCount = count;
|
||||
m_FaceIndices.resize(count * 3, 0);
|
||||
m_FaceMtlIndex.resize(count, 0);
|
||||
m_FaceOthers.resize(count);
|
||||
}
|
||||
|
||||
CKWORD* CKMesh::GetFaceIndices() {
|
||||
if (m_FaceCount == 0) return nullptr;
|
||||
return m_FaceIndices.data();
|
||||
}
|
||||
|
||||
CKWORD* CKMesh::GetFaceMaterialSlotIndexs() {
|
||||
if (m_FaceCount == 0) return nullptr;
|
||||
return m_FaceMtlIndex.data();
|
||||
}
|
||||
|
||||
VxMath::VxVector3* CKMesh::GetFaceNormals(CKDWORD& stride) {
|
||||
stride = CKSizeof(FaceData_t);
|
||||
|
||||
if (m_FaceCount == 0) return nullptr;
|
||||
return &m_FaceOthers.data()->m_Normal;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
#pragma region Line Section
|
||||
|
||||
CKDWORD CKMesh::GetLineCount() const {
|
||||
return m_LineCount;
|
||||
}
|
||||
|
||||
void CKMesh::SetLineCount(CKDWORD count) {
|
||||
m_LineCount = count;
|
||||
m_LineIndices.resize(count * 2, 0);
|
||||
}
|
||||
|
||||
CKWORD* CKMesh::GetLineIndices() {
|
||||
if (m_LineCount == 0) return nullptr;
|
||||
return m_LineIndices.data();
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
}
|
||||
@@ -1,110 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKBeObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKMesh : public CKBeObject {
|
||||
protected:
|
||||
enum class VertexSaveFlags : CKDWORD {
|
||||
None = 0,
|
||||
SingleColor = 0x1u, /**< if not set, the VertexColor is a list, otherwise a single global CKDWORD.*/
|
||||
SingleSpecularColor = 0x2u, /**< if not set, the VertexSpecularColor is a list, otherwise a single global CKDWORD. */
|
||||
NoNormal = 0x4u, /**< if set, there are no normal data for vertex. */
|
||||
SingleUV = 0x8u, /**< if not set, the VertexUV is a list, otherwise a single global VxVertex2. */
|
||||
NoPos = 0x10u, /**< if set, there are no position data for vertex. */
|
||||
};
|
||||
|
||||
public:
|
||||
CKMesh(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKMesh();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKMesh);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_MESH;
|
||||
}
|
||||
|
||||
virtual void CheckPreDeletion() override;
|
||||
|
||||
// 2 RW functions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
// it only have special Show method
|
||||
virtual void Show(CK_OBJECT_SHOWOPTION show = CK_OBJECT_SHOWOPTION::CKSHOW) override;
|
||||
|
||||
// ===== Misc Section =====
|
||||
public:
|
||||
void CleanMesh();
|
||||
VxMath::VXMESH_FLAGS GetMeshFlags() const;
|
||||
void SetMeshFlags(VxMath::VXMESH_FLAGS flags);
|
||||
VxMath::VXMESH_LITMODE GetLitMode() const;
|
||||
void SetLitMode(VxMath::VXMESH_LITMODE mode);
|
||||
VxMath::VXTEXTURE_WRAPMODE GetWrapMode() const;
|
||||
void SetWrapMode(VxMath::VXTEXTURE_WRAPMODE mode);
|
||||
protected:
|
||||
VertexSaveFlags GenerateSaveFlags();
|
||||
void BuildNormals();
|
||||
void BuildFaceNormals();
|
||||
|
||||
// ===== Vertex Section =====
|
||||
public:
|
||||
CKDWORD GetVertexCount() const;
|
||||
void SetVertexCount(CKDWORD count);
|
||||
VxMath::VxVector3* GetVertexPositions();
|
||||
VxMath::VxVector3* GetVertexNormals();
|
||||
VxMath::VxVector2* GetVertexUVs();
|
||||
CKDWORD* GetVertexColors();
|
||||
CKDWORD* GetVertexSpecularColors();
|
||||
|
||||
// ===== Material Slot Section =====
|
||||
public:
|
||||
CKDWORD GetMaterialSlotCount() const;
|
||||
void SetMaterialSlotCount(CKDWORD count);
|
||||
CKMaterial** GetMaterialSlots();
|
||||
|
||||
// ===== Face Section =====
|
||||
public:
|
||||
CKDWORD GetFaceCount() const;
|
||||
void SetFaceCount(CKDWORD count);
|
||||
CKWORD* GetFaceIndices();
|
||||
CKWORD* GetFaceMaterialSlotIndexs();
|
||||
VxMath::VxVector3* GetFaceNormals(CKDWORD& stride);
|
||||
|
||||
// ===== Line Section =====
|
||||
public:
|
||||
CKDWORD GetLineCount() const;
|
||||
void SetLineCount(CKDWORD count);
|
||||
CKWORD* GetLineIndices();
|
||||
|
||||
protected:
|
||||
struct FaceData_t {
|
||||
FaceData_t() :
|
||||
m_Normal()
|
||||
{}
|
||||
VxMath::VxVector3 m_Normal;
|
||||
};
|
||||
VxMath::VXMESH_FLAGS m_Flags;
|
||||
CKDWORD m_VertexCount;
|
||||
CKDWORD m_LineCount;
|
||||
CKDWORD m_MaterialSlotCount;
|
||||
CKDWORD m_FaceCount;
|
||||
|
||||
XContainer::XArray<VxMath::VxVector3> m_VertexPosition;
|
||||
XContainer::XArray<VxMath::VxVector3> m_VertexNormal;
|
||||
XContainer::XArray<VxMath::VxVector2> m_VertexUV;
|
||||
XContainer::XArray<CKDWORD> m_VertexColor;
|
||||
XContainer::XArray<CKDWORD> m_VertexSpecularColor;
|
||||
|
||||
XContainer::XArray<CKMaterial*> m_MaterialSlot;
|
||||
|
||||
XContainer::XArray<CKWORD> m_FaceIndices;
|
||||
XContainer::XArray<CKWORD> m_FaceMtlIndex;
|
||||
XContainer::XArray<FaceData_t> m_FaceOthers;
|
||||
|
||||
XContainer::XArray<CKWORD> m_LineIndices;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
#include "CKObject.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
CKObject::CKObject(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
m_ID(ckid),
|
||||
m_Name(),
|
||||
m_Context(ctx),
|
||||
m_ObjectFlags(CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE) {
|
||||
// set name with possible nullptr.
|
||||
XContainer::NSXString::FromCKSTRING(m_Name, name);
|
||||
}
|
||||
|
||||
CKObject::~CKObject() {}
|
||||
|
||||
#pragma region Non-virtual Functions
|
||||
|
||||
CK_ID CKObject::GetID() const {
|
||||
return m_ID;
|
||||
}
|
||||
CKSTRING CKObject::GetName() const {
|
||||
return XContainer::NSXString::ToCKSTRING(m_Name);
|
||||
}
|
||||
void CKObject::SetName(CKSTRING u8_name) {
|
||||
XContainer::NSXString::FromCKSTRING(m_Name, u8_name);
|
||||
}
|
||||
CK_OBJECT_FLAGS CKObject::GetObjectFlags() const {
|
||||
return m_ObjectFlags;
|
||||
}
|
||||
void CKObject::SetObjectFlags(CK_OBJECT_FLAGS flags) {
|
||||
m_ObjectFlags = flags;
|
||||
}
|
||||
bool CKObject::IsToBeDeleted() const {
|
||||
return YYCC::EnumHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_TOBEDELETED);
|
||||
}
|
||||
CKContext* CKObject::GetCKContext() const {
|
||||
return m_Context;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
void CKObject::PreDelete() {}
|
||||
|
||||
void CKObject::CheckPreDeletion() {}
|
||||
|
||||
void CKObject::CheckPostDeletion() {}
|
||||
|
||||
|
||||
void CKObject::PreSave(CKFileVisitor* file, CKDWORD flags) {}
|
||||
|
||||
bool CKObject::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
if (YYCC::EnumHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE)) {
|
||||
// if hierarchy hidden
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIERAHIDDEN);
|
||||
} else if (!YYCC::EnumHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE)) {
|
||||
// if really hidden
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIDDEN);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_OBJECT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKObject::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIDDEN)) {
|
||||
YYCC::EnumHelper::Remove(this->m_ObjectFlags,
|
||||
CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE,
|
||||
CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE
|
||||
);
|
||||
} else {
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_OBJECT::CK_STATESAVE_OBJECTHIERAHIDDEN)) {
|
||||
// != 0
|
||||
YYCC::EnumHelper::Remove(this->m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
YYCC::EnumHelper::Add(this->m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE);
|
||||
|
||||
} else {
|
||||
// == 0
|
||||
YYCC::EnumHelper::Add(this->m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
YYCC::EnumHelper::Remove(this->m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CKObject::PostLoad() {}
|
||||
|
||||
|
||||
void CKObject::Show(CK_OBJECT_SHOWOPTION show) {
|
||||
// clear all visible data of object flags
|
||||
YYCC::EnumHelper::Remove(m_ObjectFlags,
|
||||
CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE,
|
||||
CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE
|
||||
);
|
||||
|
||||
switch (show) {
|
||||
case CK_OBJECT_SHOWOPTION::CKSHOW:
|
||||
YYCC::EnumHelper::Add(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
break;
|
||||
case CK_OBJECT_SHOWOPTION::CKHIERARCHICALHIDE:
|
||||
YYCC::EnumHelper::Add(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_HIERACHICALHIDE);
|
||||
break;
|
||||
case CK_OBJECT_SHOWOPTION::CKHIDE:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool CKObject::IsVisible() const {
|
||||
return YYCC::EnumHelper::Has(m_ObjectFlags, CK_OBJECT_FLAGS::CK_OBJECT_VISIBLE);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
|
||||
/**
|
||||
CKObject virtual functions implementations help
|
||||
|
||||
Implement as original meaning:
|
||||
- PreSave()
|
||||
- Save()
|
||||
- Load()
|
||||
- PostLoad()
|
||||
|
||||
- GetClassID()
|
||||
|
||||
- Show()
|
||||
- IsVisible()
|
||||
|
||||
- PreDelete()
|
||||
- CheckPreDeletion()
|
||||
- CheckPostDeletion()
|
||||
|
||||
No implement because don't care:
|
||||
- GetMemoryOccupation()
|
||||
- IsObjectUsed()
|
||||
- PrepareDependencies()
|
||||
- RemapDependencies()
|
||||
|
||||
- IsHiddenByParent()
|
||||
- CanBeHide()
|
||||
|
||||
Implement moved into other location:
|
||||
- Copy(): Use CKObject::CKObject(CK_ID newid, const CKObject* obj) ctor and CKClassDesc to implement.
|
||||
|
||||
*/
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKObject {
|
||||
public:
|
||||
CKObject(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKObject();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKObject);
|
||||
|
||||
CK_ID GetID() const;
|
||||
CKSTRING GetName() const;
|
||||
void SetName(CKSTRING u8_name);
|
||||
CK_OBJECT_FLAGS GetObjectFlags() const;
|
||||
void SetObjectFlags(CK_OBJECT_FLAGS flags);
|
||||
bool IsToBeDeleted() const;
|
||||
CKContext* GetCKContext() const;
|
||||
|
||||
virtual CK_CLASSID GetClassID() {
|
||||
return CK_CLASSID::CKCID_OBJECT;
|
||||
}
|
||||
|
||||
virtual void PreDelete();
|
||||
virtual void CheckPreDeletion();
|
||||
virtual void CheckPostDeletion();
|
||||
|
||||
virtual void PreSave(CKFileVisitor* file, CKDWORD flags);
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags);
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file);
|
||||
virtual void PostLoad();
|
||||
|
||||
/**
|
||||
* @brief Shows or hides an object
|
||||
* @remark
|
||||
* + If show is set to CKHIERARCHICALHIDE this object will be hidden along with all its children.
|
||||
* + The render engine renders objets in a hierarchical way and stops iterating a hierarchy if it encounters an object which is hierarchically hidden. The problem is that, for performance reason, children objets visibility flags are left unchanged (ie. if a child object was visible CKObject::IsVisible will still return TRUE). To test is a object is hidden because one of its parent object is hierarchically hidden use CKObject::IsHiddenByParent
|
||||
* + The CKHIERARCHICALHIDE option is only relevant for CK2dEntity and CK3dEntity derived classes.
|
||||
* + If show is set to CKSHOW the object will be shown and it also removes the hierarchically hidden flags.
|
||||
* + If show is set to CKHIDE the object will be hidden and it also removes the hierarchically hidden flags.
|
||||
* + This function is overload by CKGroup,CKMesh and CK3dEntity.
|
||||
*/
|
||||
virtual void Show(CK_OBJECT_SHOWOPTION show = CK_OBJECT_SHOWOPTION::CKSHOW);
|
||||
/**
|
||||
* @brief Returns whether this object is visible
|
||||
* @return TRUE if the object is visible, FALSE otherwise
|
||||
* @remark
|
||||
* + Only CKRenderObject and derived classes(CK2dEntity,CK3dEntity),CKMesh and CKGroup return relevant information about their visibility state. Other classes may return any values.
|
||||
* + An object can return CKSHOW and still be hidden if its parent (see CK3dEntity::GetParent and CK2dEntity::GetParent) is hierarchically hidden (see CKObject::Show)
|
||||
*/
|
||||
virtual bool IsVisible() const;
|
||||
|
||||
protected:
|
||||
CK_ID m_ID;
|
||||
XContainer::XString m_Name;
|
||||
CK_OBJECT_FLAGS m_ObjectFlags;
|
||||
CKContext* m_Context;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKBeObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKRenderObject : public CKBeObject {
|
||||
public:
|
||||
CKRenderObject(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKBeObject(ctx, ckid, name)
|
||||
{}
|
||||
virtual ~CKRenderObject() {}
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKRenderObject);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_RENDEROBJECT;
|
||||
}
|
||||
|
||||
// CKRenderObject do not implement any load/save functions
|
||||
//virtual void PreSave(CKFileVisitor* file, CKDWORD flags) override;
|
||||
//virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
//virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
//virtual void PostLoad() override;
|
||||
|
||||
protected:
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKSceneObject : public CKObject {
|
||||
public:
|
||||
CKSceneObject(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKObject(ctx, ckid, name),
|
||||
m_Scenes() {}
|
||||
virtual ~CKSceneObject() {}
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKSceneObject);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_SCENEOBJECT;
|
||||
}
|
||||
// CKSceneObject do not override any RW functions.
|
||||
//virtual void PreSave(CKFileVisitor* file, CKDWORD flags) override;
|
||||
//virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
//virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
//virtual void PostLoad() override;
|
||||
|
||||
protected:
|
||||
XContainer::XBitArray m_Scenes;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,91 +0,0 @@
|
||||
#include "CKTargetCamera.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
// MARK: THIS CODE IS BARELY FULL COPY OF CKTargetLight.
|
||||
// Please sync them if you modify one of them!
|
||||
|
||||
CKTargetCamera::CKTargetCamera(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKCamera(ctx, ckid, name), m_Target3dEntity(0) {}
|
||||
|
||||
CKTargetCamera::~CKTargetCamera() {}
|
||||
|
||||
void CKTargetCamera::PreDelete() {
|
||||
// Remove associated target
|
||||
SetTarget(nullptr);
|
||||
}
|
||||
|
||||
void CKTargetCamera::CheckPostDeletion() {
|
||||
CKCamera::CheckPostDeletion();
|
||||
|
||||
// Remove target if is not existing.
|
||||
CKObject* target = m_Context->GetObject(m_Target3dEntity);
|
||||
if (target == nullptr) {
|
||||
m_Target3dEntity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CKTargetCamera::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKCamera::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// Save target
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_CAMERA::CK_STATESAVE_TCAMERATARGET);
|
||||
CKObject* target = m_Context->GetObject(m_Target3dEntity);
|
||||
chunk->WriteObjectPointer(target);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_TARGETCAMERA);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKTargetCamera::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKCamera::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// Read target
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_CAMERA::CK_STATESAVE_TCAMERATARGET)) {
|
||||
chunk->ReadObjectID(m_Target3dEntity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CK3dEntity* CKTargetCamera::GetTarget() const {
|
||||
return static_cast<CK3dEntity*>(m_Context->GetObject(m_Target3dEntity));
|
||||
}
|
||||
|
||||
void CKTargetCamera::SetTarget(CK3dEntity* target) {
|
||||
// The target can not be self.
|
||||
if (target == this) return;
|
||||
|
||||
// First remove current target
|
||||
CK3dEntity* old_target = static_cast<CK3dEntity*>(m_Context->GetObject(m_Target3dEntity));
|
||||
if (old_target != nullptr) {
|
||||
CK_3DENTITY_FLAGS old_target_flags = old_target->GetEntityFlags();
|
||||
YYCC::EnumHelper::Remove(old_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_TARGETCAMERA);
|
||||
YYCC::EnumHelper::Add(old_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_FRAME);
|
||||
old_target->SetEntityFlags(old_target_flags);
|
||||
}
|
||||
|
||||
// Then add specified target
|
||||
if (target != nullptr) {
|
||||
CK_3DENTITY_FLAGS new_target_flags = target->GetEntityFlags();
|
||||
YYCC::EnumHelper::Add(new_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_TARGETCAMERA);
|
||||
YYCC::EnumHelper::Remove(new_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_FRAME);
|
||||
target->SetEntityFlags(new_target_flags);
|
||||
}
|
||||
|
||||
// Get CK_ID of new target
|
||||
CK_ID target_id = 0;
|
||||
if (target != nullptr)
|
||||
target_id = target->GetID();
|
||||
|
||||
// Assign target id.
|
||||
m_Target3dEntity = target_id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKCamera.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKTargetCamera : public CKCamera {
|
||||
public:
|
||||
CKTargetCamera(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKTargetCamera();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKTargetCamera);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_TARGETCAMERA;
|
||||
}
|
||||
|
||||
virtual void PreDelete() override;
|
||||
virtual void CheckPostDeletion() override;
|
||||
|
||||
// 2 RW funcions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
|
||||
virtual CK3dEntity* GetTarget() const override;
|
||||
virtual void SetTarget(CK3dEntity* target) override;
|
||||
|
||||
protected:
|
||||
CK_ID m_Target3dEntity;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,95 +0,0 @@
|
||||
#include "CKTargetLight.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
// MARK: THIS CODE IS BARELY FULL COPY OF CKTargetCamera.
|
||||
// Please sync them if you modify one of them!
|
||||
|
||||
CKTargetLight::CKTargetLight(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKLight(ctx, ckid, name), m_Target3dEntity(0) {}
|
||||
|
||||
CKTargetLight::~CKTargetLight() {}
|
||||
|
||||
void CKTargetLight::PreDelete() {
|
||||
// MARK: In original code, there is no such override.
|
||||
// Following statement is written in a function called "vector deleting destructor".
|
||||
// Idk what it is. There is no resetting target code in its dtor and elsewhere.
|
||||
// I think this is crucial, so I add this overload as my understandings.
|
||||
|
||||
// Remove associated target
|
||||
SetTarget(nullptr);
|
||||
}
|
||||
|
||||
void CKTargetLight::CheckPostDeletion() {
|
||||
CKLight::CheckPostDeletion();
|
||||
|
||||
// Remove target if is not existing.
|
||||
CKObject* target = m_Context->GetObject(m_Target3dEntity);
|
||||
if (target == nullptr) {
|
||||
m_Target3dEntity = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CKTargetLight::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKLight::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// Save target
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_TLIGHTTARGET);
|
||||
CKObject* target = m_Context->GetObject(m_Target3dEntity);
|
||||
chunk->WriteObjectPointer(target);
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_TARGETLIGHT);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKTargetLight::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKLight::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// Read target
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_LIGHT::CK_STATESAVE_TLIGHTTARGET)) {
|
||||
chunk->ReadObjectID(m_Target3dEntity);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CK3dEntity* CKTargetLight::GetTarget() const {
|
||||
return static_cast<CK3dEntity*>(m_Context->GetObject(m_Target3dEntity));
|
||||
}
|
||||
void CKTargetLight::SetTarget(CK3dEntity* target) {
|
||||
// The target can not be self.
|
||||
if (target == this) return;
|
||||
|
||||
// First remove current target
|
||||
CK3dEntity* old_target = static_cast<CK3dEntity*>(m_Context->GetObject(m_Target3dEntity));
|
||||
if (old_target != nullptr) {
|
||||
CK_3DENTITY_FLAGS old_target_flags = old_target->GetEntityFlags();
|
||||
YYCC::EnumHelper::Remove(old_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_TARGETLIGHT);
|
||||
YYCC::EnumHelper::Add(old_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_FRAME);
|
||||
old_target->SetEntityFlags(old_target_flags);
|
||||
}
|
||||
|
||||
// Then add specified target
|
||||
if (target != nullptr) {
|
||||
CK_3DENTITY_FLAGS new_target_flags = target->GetEntityFlags();
|
||||
YYCC::EnumHelper::Add(new_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_TARGETLIGHT);
|
||||
YYCC::EnumHelper::Remove(new_target_flags, CK_3DENTITY_FLAGS::CK_3DENTITY_FRAME);
|
||||
target->SetEntityFlags(new_target_flags);
|
||||
}
|
||||
|
||||
// Get CK_ID of new target
|
||||
CK_ID target_id = 0;
|
||||
if (target != nullptr)
|
||||
target_id = target->GetID();
|
||||
|
||||
// Assign target id.
|
||||
m_Target3dEntity = target_id;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "CKLight.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKTargetLight : public CKLight {
|
||||
public:
|
||||
CKTargetLight(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKTargetLight();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKTargetLight);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_TARGETLIGHT;
|
||||
}
|
||||
|
||||
virtual void PreDelete() override;
|
||||
virtual void CheckPostDeletion() override;
|
||||
|
||||
// 2 RW funcions
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
|
||||
virtual CK3dEntity* GetTarget() const override;
|
||||
virtual void SetTarget(CK3dEntity* target) override;
|
||||
|
||||
protected:
|
||||
CK_ID m_Target3dEntity;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,400 +0,0 @@
|
||||
#include "CKTexture.hpp"
|
||||
#include "../CKStateChunk.hpp"
|
||||
#include "../CKContext.hpp"
|
||||
#include "../MgrImpls/CKPathManager.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
/**
|
||||
* @brief A fake struct define.
|
||||
* This define is served for a buffer read / write in CKTexture.
|
||||
* Because Virtools directly write a raw struct into file,
|
||||
* and our defines are different with Virtools.
|
||||
* So we need create a fake struct.
|
||||
* @remark
|
||||
* All pointers should translate to DWORD(32 bit) for platform independent.
|
||||
* Otherwise this struct may be corrupted in x64 platform because pointer is QWORD in x64.
|
||||
*/
|
||||
#pragma pack(4)
|
||||
struct FakeBitmapProperties {
|
||||
CKINT m_Size;
|
||||
struct {
|
||||
// fake CKGUID
|
||||
CKDWORD d1, d2;
|
||||
}m_ReaderGuid;
|
||||
struct {
|
||||
// fake CKFileExtension
|
||||
char m_Data[4];
|
||||
}m_Ext;
|
||||
struct {
|
||||
// fake VxImageDescEx
|
||||
CKINT Size; ///< Size of the structure
|
||||
CKDWORD Flags; ///< Reserved for special formats (such as compressed ) 0 otherwise
|
||||
|
||||
CKINT Width; ///< Width in pixel of the image
|
||||
CKINT Height; ///< Height in pixel of the image
|
||||
union {
|
||||
CKINT BytesPerLine; ///< Pitch (width in bytes) of the image
|
||||
CKINT TotalImageSize; ///< For compressed image (DXT1...) the total size of the image
|
||||
};
|
||||
CKINT BitsPerPixel; ///< Number of bits per pixel
|
||||
union {
|
||||
CKDWORD RedMask; ///< Mask for Red component
|
||||
CKDWORD BumpDuMask; ///< Mask for Bump Du component
|
||||
};
|
||||
union {
|
||||
CKDWORD GreenMask; ///< Mask for Green component
|
||||
CKDWORD BumpDvMask; ///< Mask for Bump Dv component
|
||||
};
|
||||
union {
|
||||
CKDWORD BlueMask; ///< Mask for Blue component
|
||||
CKDWORD BumpLumMask; ///< Mask for Luminance component
|
||||
|
||||
};
|
||||
CKDWORD AlphaMask; ///< Mask for Alpha component
|
||||
|
||||
CKWORD BytesPerColorEntry; ///< ColorMap Stride
|
||||
CKWORD ColorMapEntries; ///< If other than 0 image is palletized
|
||||
|
||||
/*CKBYTE**/CKPTR ColorMap; ///< Palette colors
|
||||
/*CKBYTE**/CKPTR Image; ///< Image
|
||||
}m_Format;
|
||||
/*void**/CKPTR m_Data;
|
||||
};
|
||||
#pragma pack()
|
||||
|
||||
CKTexture::CKTexture(CKContext* ctx, CK_ID ckid, CKSTRING name) :
|
||||
CKBeObject(ctx, ckid, name),
|
||||
m_ImageHost(ctx),
|
||||
m_VideoFormat(VxMath::VX_PIXELFORMAT::_16_ARGB1555), m_UseMipMap(false), m_MipmapImages() {}
|
||||
|
||||
CKTexture::~CKTexture() {}
|
||||
|
||||
bool CKTexture::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
|
||||
bool suc = CKBeObject::Save(chunk, file, flags);
|
||||
if (!suc) return false;
|
||||
|
||||
// save base image
|
||||
suc = m_ImageHost.DumpToChunk(chunk, file, CKBitmapDataWriteIdentifiers {
|
||||
.m_SpecificFormat = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXREADER),
|
||||
.m_RawData = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXCOMPRESSED),
|
||||
.m_FileNames = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXFILENAMES),
|
||||
.m_MovieFileName = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXAVIFILENAME)
|
||||
});
|
||||
if (!suc) return false;
|
||||
|
||||
// write main properties
|
||||
{
|
||||
// write ident
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_OLDTEXONLY);
|
||||
|
||||
// prepare mix data. see Read for more info about the struct of this mix data
|
||||
CKDWORD mixdata = 0;
|
||||
// save options
|
||||
mixdata |= static_cast<CKDWORD>(m_ImageHost.GetSaveOptions()) & 0xFF;
|
||||
mixdata <<= 8;
|
||||
// mix flags
|
||||
CKDWORD mixflags = 0;
|
||||
if (m_ImageHost.IsTransparent()) {
|
||||
mixflags |= 0x1;
|
||||
}
|
||||
if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) {
|
||||
mixflags |= 0x2;
|
||||
}
|
||||
if (m_ImageHost.IsCubeMap()) {
|
||||
mixflags |= 0x4;
|
||||
}
|
||||
mixdata |= mixflags & 0xFF;
|
||||
mixdata <<= 8;
|
||||
// mipmap
|
||||
mixdata |= (IsUseMipmap() ? 0xFF : 0);
|
||||
|
||||
// write mix data
|
||||
chunk->WriteStruct(mixdata);
|
||||
|
||||
// transparent color
|
||||
chunk->WriteStruct(m_ImageHost.GetTransparentColor());
|
||||
// current slot
|
||||
if (m_ImageHost.GetSlotCount() > 1) {
|
||||
chunk->WriteStruct(m_ImageHost.GetCurrentSlot());
|
||||
}
|
||||
// video fmt
|
||||
if (m_VideoFormat != VxMath::VX_PIXELFORMAT::UNKNOWN_PF) {
|
||||
chunk->WriteStruct(m_VideoFormat);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// mipmap
|
||||
if (GetMipmapLevel() != 0) {
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_USERMIPMAP);
|
||||
|
||||
// write mipmap level
|
||||
chunk->WriteStruct(GetMipmapLevel());
|
||||
|
||||
// write data
|
||||
for (auto& level : m_MipmapImages) {
|
||||
if (level.IsValid()) {
|
||||
// do upside down and write
|
||||
VxMath::VxImageDescEx upsidedown(level.GetWidth(), level.GetHeight());
|
||||
VxMath::VxDoBlitUpsideDown(&level, &upsidedown);
|
||||
CKBitmapData::WriteRawBitmap(chunk, &upsidedown);
|
||||
} else {
|
||||
// write it directly
|
||||
CKBitmapData::WriteRawBitmap(chunk, &level);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// pick threshold
|
||||
if (m_ImageHost.GetPickThreshold() != 0) {
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_PICKTHRESHOLD);
|
||||
chunk->WriteStruct(m_ImageHost.GetPickThreshold());
|
||||
}
|
||||
|
||||
// bitmap properties
|
||||
{
|
||||
chunk->WriteIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXSAVEFORMAT);
|
||||
|
||||
// prepare a fake one
|
||||
FakeBitmapProperties props;
|
||||
const CKBitmapProperties& realprops = m_ImageHost.GetSaveFormat();
|
||||
|
||||
// setup fake self
|
||||
props.m_Size = CKSizeof(props);
|
||||
props.m_Data = 0;
|
||||
|
||||
// setup fake VxImageDescEx
|
||||
props.m_Format.Size = CKSizeof(props.m_Format);
|
||||
props.m_Format.Flags = static_cast<CKDWORD>(VxMath::VX_PIXELFORMAT::_32_ARGB8888);
|
||||
props.m_Format.Width = m_ImageHost.GetWidth();
|
||||
props.m_Format.Height = m_ImageHost.GetHeight();
|
||||
props.m_Format.BytesPerLine = VxMath::VxImageDescEx::PixelSize * props.m_Format.Width;
|
||||
props.m_Format.BitsPerPixel = 32;
|
||||
|
||||
props.m_Format.RedMask = 0x00FF0000;
|
||||
props.m_Format.GreenMask = 0x0000FF00;
|
||||
props.m_Format.BlueMask = 0x000000FF;
|
||||
props.m_Format.AlphaMask = 0xFF000000;
|
||||
|
||||
props.m_Format.BytesPerColorEntry = 0;
|
||||
props.m_Format.ColorMapEntries = 0;
|
||||
|
||||
props.m_Format.ColorMap = 0;
|
||||
props.m_Format.Image = 0;
|
||||
|
||||
// setup ext and guid
|
||||
props.m_ReaderGuid.d1 = realprops.m_ReaderGuid.d1;
|
||||
props.m_ReaderGuid.d2 = realprops.m_ReaderGuid.d2;
|
||||
std::string ext;
|
||||
if (!m_Context->GetOrdinaryString(realprops.m_Ext.GetExt(), ext))
|
||||
m_Context->OutputToConsole(u8"Fail to get ordinary string for the extension of bitmap properties when saving CKTexture. Some textures may be saved with blank extension.");
|
||||
std::memcpy(
|
||||
props.m_Ext.m_Data,
|
||||
ext.c_str(),
|
||||
std::min(CKSizeof(props.m_Ext.m_Data) - CKDWORD_C(1), static_cast<CKDWORD>(ext.size()))
|
||||
);
|
||||
|
||||
// write fake one
|
||||
chunk->WriteBuffer(&props, CKSizeof(props));
|
||||
}
|
||||
|
||||
chunk->SetClassId(CK_CLASSID::CKCID_TEXTURE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CKTexture::Load(CKStateChunk* chunk, CKFileVisitor* file) {
|
||||
bool suc = CKBeObject::Load(chunk, file);
|
||||
if (!suc) return false;
|
||||
|
||||
// read base image
|
||||
suc = m_ImageHost.ReadFromChunk(chunk, file, CKBitmapDataReadIdentifiers {
|
||||
.m_SpecificFormat = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXREADER),
|
||||
.m_RawData = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXCOMPRESSED),
|
||||
.m_OldRawData = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXBITMAPS),
|
||||
.m_FileNames = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXFILENAMES),
|
||||
.m_MovieFileName = static_cast<CKDWORD>(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXAVIFILENAME)
|
||||
});
|
||||
if (!suc) return false;
|
||||
|
||||
if (chunk->GetDataVersion() < CK_STATECHUNK_DATAVERSION::CHUNK_MAJORCHANGE_VERSION) {
|
||||
// MARK: old data process. i don't want to process it anymore.
|
||||
// thus return false directly.
|
||||
return false;
|
||||
} else {
|
||||
CKDWORD fmtbytesize;
|
||||
// MARK: there is a patch for virtools 2.1 implement.
|
||||
// CK_STATESAVE_TEXONLY is noy valid in 2.1 but we add it for cpmpatibility reason.
|
||||
if (chunk->SeekIdentifierAndReturnSize(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_OLDTEXONLY, &fmtbytesize) ||
|
||||
chunk->SeekIdentifierAndReturnSize(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXONLY, &fmtbytesize)) {
|
||||
// for mid data:
|
||||
// HIGH >>> 0xFF (blank) 0xFF (save options) 0xFF (transparent + movie info + video fmt) 0xFF (mip map) <<< LOW
|
||||
// for mixed flags:
|
||||
// HIGH >>> 1(blank) 1(cubemap) 1(has video fmt) 1(is transparent)
|
||||
CKDWORD mixdata;
|
||||
chunk->ReadStruct(mixdata);
|
||||
// set mipmap
|
||||
UseMipmap(mixdata & 0xFF);
|
||||
mixdata >>= 8;
|
||||
// mix flags
|
||||
CKDWORD mixflags = mixdata & 0xFF;
|
||||
mixdata >>= 8;
|
||||
m_ImageHost.SetTransparent(mixflags & 0x1);
|
||||
bool hasVideoFmt = mixflags & 0x2;
|
||||
m_ImageHost.SetCubeMap(mixflags & 0x4);
|
||||
// save options
|
||||
m_ImageHost.SetSaveOptions(static_cast<CK_TEXTURE_SAVEOPTIONS>(mixdata & 0xFF));
|
||||
mixdata >>= 8;
|
||||
|
||||
// set current slot, transparent color, and video format.
|
||||
CKDWORD currentSlot, transColor;
|
||||
fmtbytesize -= CKSizeof(CKDWORD);
|
||||
switch (fmtbytesize) {
|
||||
case (3 * CKSizeof(CKDWORD)):
|
||||
chunk->ReadStruct(transColor);
|
||||
m_ImageHost.SetTransparentColor(transColor);
|
||||
chunk->ReadStruct(currentSlot);
|
||||
m_ImageHost.SetCurrentSlot(currentSlot);
|
||||
chunk->ReadStruct(m_VideoFormat);
|
||||
break;
|
||||
case (2 * CKSizeof(CKDWORD)):
|
||||
if (m_ImageHost.GetSlotCount() <= 1 || !hasVideoFmt) {
|
||||
chunk->ReadStruct(transColor);
|
||||
m_ImageHost.SetTransparentColor(transColor);
|
||||
}
|
||||
if (m_ImageHost.GetSlotCount() > 1) {
|
||||
chunk->ReadStruct(currentSlot);
|
||||
m_ImageHost.SetCurrentSlot(currentSlot);
|
||||
}
|
||||
if (hasVideoFmt) {
|
||||
chunk->ReadStruct(m_VideoFormat);
|
||||
}
|
||||
break;
|
||||
case (CKSizeof(CKDWORD)):
|
||||
if (hasVideoFmt) {
|
||||
chunk->ReadStruct(m_VideoFormat);
|
||||
} else if (m_ImageHost.GetSlotCount() <= 1) {
|
||||
chunk->ReadStruct(transColor);
|
||||
m_ImageHost.SetTransparentColor(transColor);
|
||||
} else {
|
||||
chunk->ReadStruct(currentSlot);
|
||||
m_ImageHost.SetCurrentSlot(currentSlot);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// read mipmap
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_USERMIPMAP)) {
|
||||
CKDWORD mipmapCount;
|
||||
chunk->ReadStruct(mipmapCount);
|
||||
SetMipmapLevel(mipmapCount);
|
||||
|
||||
for (CKDWORD i = 0; i < mipmapCount; ++i) {
|
||||
VxMath::VxImageDescEx cache;
|
||||
if (CKBitmapData::ReadRawBitmap(chunk, &cache)) {
|
||||
VxMath::VxDoBlitUpsideDown(&cache, &m_MipmapImages[i]);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// pick threshold
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_PICKTHRESHOLD)) {
|
||||
CKDWORD threshold;
|
||||
chunk->ReadStruct(threshold);
|
||||
m_ImageHost.SetPickThreshold(threshold);
|
||||
}
|
||||
|
||||
// save properties
|
||||
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_TEXTURE::CK_STATESAVE_TEXSAVEFORMAT)) {
|
||||
auto buf = chunk->ReadBufferWrapper();
|
||||
if (buf != nullptr) {
|
||||
FakeBitmapProperties* props = static_cast<FakeBitmapProperties*>(buf.get());
|
||||
|
||||
// get utf8 extension
|
||||
XContainer::XString ext;
|
||||
if (!m_Context->GetUTF8String(props->m_Ext.m_Data, ext))
|
||||
m_Context->OutputToConsole(u8"Fail to get UTF8 extension when loading CKTexture. Some textures may have blank extension in bitmap properties.");
|
||||
|
||||
// get my bitmap prop
|
||||
CKBitmapProperties myprops(
|
||||
CKGUID(props->m_ReaderGuid.d1, props->m_ReaderGuid.d2),
|
||||
ext.c_str()
|
||||
);
|
||||
m_ImageHost.SetSaveFormat(myprops);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// correct video format
|
||||
if (m_VideoFormat > VxMath::VX_PIXELFORMAT::_32_X8L8V8U8) {
|
||||
m_VideoFormat = VxMath::VX_PIXELFORMAT::_16_ARGB1555;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#pragma region Visitor
|
||||
|
||||
CKBitmapData& CKTexture::GetUnderlyingData() {
|
||||
return m_ImageHost;
|
||||
}
|
||||
|
||||
bool CKTexture::LoadImage(CKSTRING filename, CKDWORD slot) {
|
||||
// check file name
|
||||
if (filename == nullptr) return false;
|
||||
// check slot
|
||||
if (slot >= m_ImageHost.GetSlotCount()) return false;
|
||||
|
||||
// resolve file name first
|
||||
XContainer::XString filepath;
|
||||
XContainer::NSXString::FromCKSTRING(filepath, filename);
|
||||
if (!m_Context->GetPathManager()->ResolveFileName(filepath)) return false;
|
||||
|
||||
// try loading image
|
||||
if (!m_ImageHost.LoadImage(XContainer::NSXString::ToCKSTRING(filepath), slot)) return false;
|
||||
|
||||
// sync file name
|
||||
return m_ImageHost.SetSlotFileName(slot, XContainer::NSXString::ToCKSTRING(filepath));
|
||||
}
|
||||
|
||||
bool CKTexture::IsUseMipmap() const {
|
||||
return m_UseMipMap;
|
||||
}
|
||||
|
||||
void CKTexture::UseMipmap(bool isUse) {
|
||||
m_UseMipMap = isUse;
|
||||
|
||||
if (!m_UseMipMap) {
|
||||
m_MipmapImages.clear();
|
||||
}
|
||||
}
|
||||
|
||||
CKDWORD CKTexture::GetMipmapLevel() const {
|
||||
return static_cast<CKDWORD>(m_MipmapImages.size());
|
||||
}
|
||||
|
||||
void CKTexture::SetMipmapLevel(CKDWORD level) {
|
||||
m_MipmapImages.resize(level);
|
||||
}
|
||||
|
||||
VxMath::VxImageDescEx* CKTexture::GetMipmapLevelData(CKDWORD level) {
|
||||
if (!m_UseMipMap || level >= m_MipmapImages.size()) return nullptr;
|
||||
return &m_MipmapImages[level];
|
||||
}
|
||||
|
||||
VxMath::VX_PIXELFORMAT CKTexture::GetVideoFormat() const {
|
||||
return m_VideoFormat;
|
||||
}
|
||||
|
||||
void CKTexture::SetVideoFormat(VxMath::VX_PIXELFORMAT fmt) {
|
||||
m_VideoFormat = fmt;
|
||||
}
|
||||
|
||||
#pragma endregion
|
||||
|
||||
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../../VTInternal.hpp"
|
||||
#include "../CKBitmapData.hpp"
|
||||
#include "CKBeObject.hpp"
|
||||
|
||||
namespace LibCmo::CK2::ObjImpls {
|
||||
|
||||
class CKTexture : public CKBeObject {
|
||||
public:
|
||||
CKTexture(CKContext* ctx, CK_ID ckid, CKSTRING name);
|
||||
virtual ~CKTexture();
|
||||
YYCC_DEL_CLS_COPY_MOVE(CKTexture);
|
||||
|
||||
virtual CK_CLASSID GetClassID() override {
|
||||
return CK_CLASSID::CKCID_TEXTURE;
|
||||
}
|
||||
|
||||
virtual bool Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) override;
|
||||
virtual bool Load(CKStateChunk* chunk, CKFileVisitor* file) override;
|
||||
|
||||
CKBitmapData& GetUnderlyingData();
|
||||
|
||||
/**
|
||||
* @brief A wrapper of underlying CKBitmapData::LoadImage. Not only load image, but also set file name.
|
||||
* @param filename[in] File name of loading image.
|
||||
* @param slot[in] The slot that image will be loaded into.
|
||||
* @return True if success.
|
||||
*/
|
||||
bool LoadImage(CKSTRING filename, CKDWORD slot);
|
||||
|
||||
bool IsUseMipmap() const;
|
||||
void UseMipmap(bool isUse);
|
||||
CKDWORD GetMipmapLevel() const;
|
||||
void SetMipmapLevel(CKDWORD level);
|
||||
VxMath::VxImageDescEx* GetMipmapLevelData(CKDWORD level);
|
||||
|
||||
VxMath::VX_PIXELFORMAT GetVideoFormat() const;
|
||||
void SetVideoFormat(VxMath::VX_PIXELFORMAT fmt);
|
||||
|
||||
protected:
|
||||
CKBitmapData m_ImageHost;
|
||||
VxMath::VX_PIXELFORMAT m_VideoFormat;
|
||||
bool m_UseMipMap;
|
||||
XContainer::XArray<VxMath::VxImageDescEx> m_MipmapImages;
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user