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,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
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user