finish CKMesh writing (no test)

- finish CKMesh writing function
- remove useless CKMesh functions: material channels, vertex weight and face mask.
This commit is contained in:
yyc12345 2023-10-01 23:48:55 +08:00
parent ee4b621cac
commit 92f4271124
4 changed files with 270 additions and 261 deletions

View File

@ -11,19 +11,15 @@ namespace LibCmo::CK2::ObjImpls {
m_VertexCount(0), m_VertexCount(0),
m_VertexPosition(), m_VertexNormal(), m_VertexUV(), m_VertexPosition(), m_VertexNormal(), m_VertexUV(),
m_VertexColor(), m_VertexSpecularColor(), m_VertexColor(), m_VertexSpecularColor(),
m_VertexWeight(), m_NoVertexWeight(true),
// init mtl slots // init mtl slots
m_MtlSlotCount(0), m_MtlSlotCount(0),
m_MaterialSlot(), m_MaterialSlot(),
// init face data // init face data
m_FaceCount(0), m_FaceCount(0),
m_FaceIndices(), m_FaceMtlIndex(), m_Faces(), m_FaceIndices(), m_FaceMtlIndex(), m_FaceOthers(),
// init line // init line
m_LineCount(0), m_LineCount(0),
m_LineIndices(), m_LineIndices(),
// init mtl channels
m_MtlChannelCount(0),
m_MaterialChannels(),
// init flags // init flags
m_Flags(EnumsHelper::Merge({ m_Flags(EnumsHelper::Merge({
VxMath::VXMESH_FLAGS::VXMESH_FORCETRANSPARENCY, VxMath::VXMESH_FLAGS::VXMESH_FORCETRANSPARENCY,
@ -44,19 +40,163 @@ namespace LibCmo::CK2::ObjImpls {
slot = nullptr; slot = nullptr;
} }
} }
// check mtl channels
for (auto& chl : m_MaterialChannels) {
if (chl.m_Material != nullptr && chl.m_Material->IsToBeDeleted()) {
chl.m_Material = nullptr;
}
}
} }
bool CKMesh::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) { bool CKMesh::Save(CKStateChunk* chunk, CKFileVisitor* file, CKDWORD flags) {
bool suc = CKBeObject::Save(chunk, file, flags); bool suc = CKBeObject::Save(chunk, file, flags);
if (!suc) return false; if (!suc) return false;
// write mesh flags
{
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFLAGS);
chunk->WriteStruct(m_Flags);
}
// write material slots
if (GetMaterialSlotCount() != 0) {
chunk->WriteIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHMATERIALS);
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));
}
}
// 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* reservedBufSize = reinterpret_cast<CKDWORD*>(rawbuf);
rawbuf += CKSizeof(CKDWORD);
// write vertex position
if (!EnumsHelper::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 (!EnumsHelper::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 (!EnumsHelper::Has(saveflags, VertexSaveFlags::SingleSpecularColor)) {
consumed = CKSizeof(CKDWORD) * vtxCount;
} else {
consumed = CKSizeof(CKDWORD);
}
std::memcpy(rawbuf, m_VertexSpecularColor.data(), consumed);
rawbuf += consumed;
}
// write normal
if (!EnumsHelper::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 (!EnumsHelper::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 = rawbuf - static_cast<CKBYTE*>(buf.get());
// assign to reserved length field
// length also include length indicator it self
*reservedBufSize = realConsumedSize;
// notify buffer real consumed size
buf.get_deleter().SetConsumedSize(realConsumedSize);
// free buffer
buf.reset();
}
return true; return true;
} }
@ -251,7 +391,7 @@ namespace LibCmo::CK2::ObjImpls {
chunk->ReadStruct(lineCount); chunk->ReadStruct(lineCount);
SetLineCount(lineCount); SetLineCount(lineCount);
chunk->ReadAndFillBuffer(m_LineIndices.data(), CKSizeof(CKWORD) * lineCount * 2); chunk->ReadAndFillBuffer(m_LineIndices.data());
} }
// build normals // build normals
@ -261,96 +401,8 @@ namespace LibCmo::CK2::ObjImpls {
BuildFaceNormals(); BuildFaceNormals();
} }
// read material channels // MARK: material channels, vertex weight, face mask added originally
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHCHANNELS)) { // but removed at Oct 1st, 2023 because I will not use them and I couldn't test them.
// read size and resize it
CKDWORD chlSize;
chunk->ReadStruct(chlSize);
SetMtlChannelCount(chlSize);
for (auto& chl : m_MaterialChannels) {
// read material
CKObject* mtlobj = nullptr;
chunk->ReadObjectPointer(mtlobj);
if (mtlobj != nullptr && mtlobj->GetClassID() == CK_CLASSID::CKCID_MATERIAL) {
chl.m_Material = static_cast<CKMaterial*>(mtlobj);
}
// read flags and call function to make sure a custom uv can be created if existed.
chunk->ReadStruct(chl.m_Flags);
SyncVertexCountToMtlChannel();
// read blend modes
chunk->ReadStruct(chl.m_SourceBlend);
chunk->ReadStruct(chl.m_DestBlend);
// read custom vertex
CKDWORD uvcount;
chunk->ReadStruct(uvcount);
if (uvcount != 0) {
// make sure no overflow
uvcount = std::min(uvcount, static_cast<CKDWORD>(chl.m_CustomUV.size()));
CKDWORD bufsize = uvcount * CKSizeof(VxMath::VxVector2);
auto locker = chunk->LockReadBufferWrapper(bufsize);
std::memcpy(chl.m_CustomUV.data(), locker.get(), bufsize);
locker.reset();
}
}
}
// vertex weight
CKDWORD weightSize;
m_NoVertexWeight = true;
if (chunk->SeekIdentifierAndReturnSize(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHWEIGHTS, &weightSize)) {
// set it has
m_NoVertexWeight = false;
// set count
CKDWORD weightCount;
chunk->ReadStruct(weightCount);
if (weightSize > CKSizeof(CKFLOAT)) {
// a float series
// read as a copy, to make sure no memory overflow
// because i couldn't understand how original CKMesh operate vertex weight count
// seperated with vertex count.
auto buf = chunk->ReadBufferWrapper();
CKDWORD bufsize = std::min(buf.get_deleter().GetBufferSize(), static_cast<CKDWORD>(m_VertexWeight.size()) * CKSizeof(CKFLOAT));
std::memcpy(m_VertexWeight.data(), buf.get(), bufsize);
buf.reset();
} else {
// a single float
CKFLOAT single;
chunk->ReadStruct(single);
for (auto& weight : m_VertexWeight) {
weight = single;
}
}
}
// face mask
if (chunk->SeekIdentifier(CK_STATESAVEFLAGS_MESH::CK_STATESAVE_MESHFACECHANMASK)) {
// 2 face mask (2 WORD) are compressed into a single DWORD.
// and if there is a remained WORD, read it as a single WORD.
// according to little endian, the actually stored data is just the mask placed
// one by one.
// so we just need to allocated it directly
// read mask count, and limit it to face count
CKDWORD maskCount;
chunk->ReadStruct(maskCount);
maskCount = std::min(maskCount, m_FaceCount);
auto locker = chunk->LockReadBufferWrapper(maskCount * CKSizeof(CKWORD));
const CKWORD* rawptr = static_cast<const CKWORD*>(locker.get());
for (auto& f : m_Faces) {
f.m_ChannelMask = *rawptr;
++rawptr;
}
locker.reset();
}
// MARK: progressive mesh data is dropper. // MARK: progressive mesh data is dropper.
@ -370,12 +422,7 @@ namespace LibCmo::CK2::ObjImpls {
#pragma region Misc Section #pragma region Misc Section
void CKMesh::CleanMesh() { void CKMesh::CleanMesh() {
// clear material channel first
SetMtlChannelCount(0);
// then clear other
SetVertexCount(0); SetVertexCount(0);
m_NoVertexWeight = true;
SetMaterialSlotCount(0); SetMaterialSlotCount(0);
SetFaceCount(0); SetFaceCount(0);
SetLineCount(0); SetLineCount(0);
@ -385,6 +432,93 @@ namespace LibCmo::CK2::ObjImpls {
return m_Flags; return m_Flags;
} }
CKMesh::VertexSaveFlags CKMesh::GenerateSaveFlags() {
// set to initial status
VertexSaveFlags saveflags = EnumsHelper::Merge({
VertexSaveFlags::SingleColor,
VertexSaveFlags::SingleSpecularColor,
VertexSaveFlags::NoNormal,
VertexSaveFlags::SingleUV
});
// check no pos
// if position is generated, skip saving position
if (EnumsHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PROCEDURALPOS)) {
EnumsHelper::Add(saveflags, VertexSaveFlags::NoPos);
}
// check uv
// if uv is not generated and all uv are not the same value, remove single uv
if (!EnumsHelper::Has(m_Flags, VxMath::VXMESH_FLAGS::VXMESH_PROCEDURALUV)) {
for (const auto& uv : m_VertexUV) {
if (uv != m_VertexUV.front()) {
EnumsHelper::Rm(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()) {
EnumsHelper::Rm(saveflags, VertexSaveFlags::SingleColor);
break;
}
}
for (const auto& col : m_VertexSpecularColor) {
if (col != m_VertexSpecularColor.front()) {
EnumsHelper::Rm(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 (!EnumsHelper::Has(m_Flags, EnumsHelper::Merge({ 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::Abs(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
EnumsHelper::Rm(saveflags, VertexSaveFlags::NoNormal);
}
}
return saveflags;
}
void CKMesh::BuildNormals() { void CKMesh::BuildNormals() {
if (m_FaceCount == 0 || m_VertexCount == 0) return; if (m_FaceCount == 0 || m_VertexCount == 0) return;
@ -393,9 +527,9 @@ namespace LibCmo::CK2::ObjImpls {
// iterate all face and add face normal to each point's normal // iterate all face and add face normal to each point's normal
for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) { for (CKDWORD fid = 0; fid < m_FaceCount; ++fid) {
m_VertexNormal[m_FaceIndices[fid * 3]] += m_Faces[fid].m_Normal; m_VertexNormal[m_FaceIndices[fid * 3]] += m_FaceOthers[fid].m_Normal;
m_VertexNormal[m_FaceIndices[fid * 3 + 1]] += m_Faces[fid].m_Normal; m_VertexNormal[m_FaceIndices[fid * 3 + 1]] += m_FaceOthers[fid].m_Normal;
m_VertexNormal[m_FaceIndices[fid * 3 + 2]] += m_Faces[fid].m_Normal; m_VertexNormal[m_FaceIndices[fid * 3 + 2]] += m_FaceOthers[fid].m_Normal;
} }
// then normalize all vertex normal // then normalize all vertex normal
@ -420,7 +554,7 @@ namespace LibCmo::CK2::ObjImpls {
nml.Normalized(); nml.Normalized();
// assign it // assign it
m_Faces[fid].m_Normal = nml; m_FaceOthers[fid].m_Normal = nml;
} }
} }
@ -439,10 +573,6 @@ namespace LibCmo::CK2::ObjImpls {
m_VertexUV.resize(count); m_VertexUV.resize(count);
m_VertexColor.resize(count, 0xFFFFFFFF); m_VertexColor.resize(count, 0xFFFFFFFF);
m_VertexSpecularColor.resize(count, 0x00000000); m_VertexSpecularColor.resize(count, 0x00000000);
m_VertexWeight.resize(count, 0.0f);
// notify mtl channels refresh its custom uv
SyncVertexCountToMtlChannel();
} }
VxMath::VxVector3* CKMesh::GetVertexPositions() { VxMath::VxVector3* CKMesh::GetVertexPositions() {
@ -465,10 +595,6 @@ namespace LibCmo::CK2::ObjImpls {
return m_VertexSpecularColor.data(); return m_VertexSpecularColor.data();
} }
CKFLOAT* CKMesh::GetVertexWeights() {
return m_VertexWeight.data();
}
#pragma endregion #pragma endregion
#pragma region Material Slot Section #pragma region Material Slot Section
@ -498,7 +624,7 @@ namespace LibCmo::CK2::ObjImpls {
m_FaceCount = count; m_FaceCount = count;
m_FaceIndices.resize(count * 3, 0); m_FaceIndices.resize(count * 3, 0);
m_FaceMtlIndex.resize(count, 0); m_FaceMtlIndex.resize(count, 0);
m_Faces.resize(count); m_FaceOthers.resize(count);
} }
CKWORD* CKMesh::GetFaceIndices() { CKWORD* CKMesh::GetFaceIndices() {
@ -511,12 +637,7 @@ namespace LibCmo::CK2::ObjImpls {
VxMath::VxVector3* CKMesh::GetFaceNormals(CKDWORD& stride) { VxMath::VxVector3* CKMesh::GetFaceNormals(CKDWORD& stride) {
stride = CKSizeof(FaceData_t); stride = CKSizeof(FaceData_t);
return &m_Faces.data()->m_Normal; return &m_FaceOthers.data()->m_Normal;
}
CKWORD* CKMesh::GetFaceChannelMasks(CKDWORD& stride) {
stride = CKSizeof(FaceData_t);
return &m_Faces.data()->m_ChannelMask;
} }
#pragma endregion #pragma endregion
@ -538,88 +659,4 @@ namespace LibCmo::CK2::ObjImpls {
#pragma endregion #pragma endregion
#pragma region Mtl Channel Section
CKDWORD CKMesh::GetMtlChannelCount() const {
return m_MtlChannelCount;
}
void CKMesh::SetMtlChannelCount(CKDWORD count) {
// backup old count
CKDWORD oldcount = m_MtlChannelCount;
// set and resize
m_MtlChannelCount = count;
m_MaterialChannels.resize(count);
// sync mask to each face.
// each face accept all mask in default
SyncMtlChannelToFaceMask(oldcount, count);
}
CKMaterial** CKMesh::GetMtlChannelMaterials(CKDWORD& stride) {
stride = CKSizeof(MaterialChannel_t);
return &m_MaterialChannels.data()->m_Material;
}
VxMath::VXBLEND_MODE* CKMesh::GetMtlChannelSourceBlends(CKDWORD& stride) {
stride = CKSizeof(MaterialChannel_t);
return &m_MaterialChannels.data()->m_SourceBlend;
}
VxMath::VXBLEND_MODE* CKMesh::GetMtlChannelDestBlends(CKDWORD& stride) {
stride = CKSizeof(MaterialChannel_t);
return &m_MaterialChannels.data()->m_DestBlend;
}
VxMath::VxVector2* CKMesh::GetMtlChannelCustomUVs(CKDWORD idx) {
if (idx >= m_MtlChannelCount) return nullptr;
return m_MaterialChannels[idx].m_CustomUV.data();
}
VxMath::VXCHANNEL_FLAGS CKMesh::GetMtlChannelFlags(CKDWORD idx) const {
if (idx >= m_MtlChannelCount) return static_cast<VxMath::VXCHANNEL_FLAGS>(0);
return m_MaterialChannels[idx].m_Flags;
}
void CKMesh::SetMtlChannelFlags(CKDWORD idx, VxMath::VXCHANNEL_FLAGS flags) {
if (idx >= m_MtlChannelCount) return;
m_MaterialChannels[idx].m_Flags = flags;
// refresh self custom uv
SyncVertexCountToMtlChannel();
}
void CKMesh::SyncVertexCountToMtlChannel() {
for (auto& channel : m_MaterialChannels) {
if (!EnumsHelper::Has(channel.m_Flags, VxMath::VXCHANNEL_FLAGS::VXCHANNEL_SAMEUV)) {
channel.m_CustomUV.resize(m_VertexCount);
} else {
channel.m_CustomUV.clear();
}
}
}
void CKMesh::SyncMtlChannelToFaceMask(CKDWORD oldsize, CKDWORD newsize) {
// use oldsize and newsize to build mask
if (oldsize == newsize) return;
CKWORD mask = 0xFFFF;
if (oldsize > newsize) {
// channels shrinks
// set already removed bits to 1
mask = static_cast<CKWORD>(~(0xFFFF << newsize));
} else {
// channels expand
// set new added bits to 1
mask = static_cast<CKWORD>(~(0xFFFF << oldsize));
}
for (auto& face : m_Faces) {
face.m_ChannelMask |= mask;
}
}
#pragma endregion
} }

View File

@ -6,6 +6,16 @@
namespace LibCmo::CK2::ObjImpls { namespace LibCmo::CK2::ObjImpls {
class CKMesh : public CKBeObject { 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: public:
CKMesh(CKContext* ctx, CK_ID ckid, CKSTRING name); CKMesh(CKContext* ctx, CK_ID ckid, CKSTRING name);
virtual ~CKMesh(); virtual ~CKMesh();
@ -29,6 +39,7 @@ namespace LibCmo::CK2::ObjImpls {
void CleanMesh(); void CleanMesh();
VxMath::VXMESH_FLAGS GetMeshFlags() const; VxMath::VXMESH_FLAGS GetMeshFlags() const;
protected: protected:
VertexSaveFlags GenerateSaveFlags();
void BuildNormals(); void BuildNormals();
void BuildFaceNormals(); void BuildFaceNormals();
@ -41,7 +52,6 @@ namespace LibCmo::CK2::ObjImpls {
VxMath::VxVector2* GetVertexUVs(); VxMath::VxVector2* GetVertexUVs();
CKDWORD* GetVertexColors(); CKDWORD* GetVertexColors();
CKDWORD* GetVertexSpecularColors(); CKDWORD* GetVertexSpecularColors();
CKFLOAT* GetVertexWeights();
// ===== Material Slot Section ===== // ===== Material Slot Section =====
public: public:
@ -56,7 +66,6 @@ namespace LibCmo::CK2::ObjImpls {
CKWORD* GetFaceIndices(); CKWORD* GetFaceIndices();
CKWORD* GetFaceMaterialSlotIndexs(); CKWORD* GetFaceMaterialSlotIndexs();
VxMath::VxVector3* GetFaceNormals(CKDWORD& stride); VxMath::VxVector3* GetFaceNormals(CKDWORD& stride);
CKWORD* GetFaceChannelMasks(CKDWORD& stride);
// ===== Line Section ===== // ===== Line Section =====
public: public:
@ -64,78 +73,33 @@ namespace LibCmo::CK2::ObjImpls {
void SetLineCount(CKDWORD count); void SetLineCount(CKDWORD count);
CKWORD* GetLineIndices(); CKWORD* GetLineIndices();
// ===== Material Channel Section =====
public:
CKDWORD GetMtlChannelCount() const;
void SetMtlChannelCount(CKDWORD count);
CKMaterial** GetMtlChannelMaterials(CKDWORD& stride);
VxMath::VXBLEND_MODE* GetMtlChannelSourceBlends(CKDWORD& stride);
VxMath::VXBLEND_MODE* GetMtlChannelDestBlends(CKDWORD& stride);
VxMath::VxVector2* GetMtlChannelCustomUVs(CKDWORD idx);
VxMath::VXCHANNEL_FLAGS GetMtlChannelFlags(CKDWORD idx) const;
void SetMtlChannelFlags(CKDWORD idx, VxMath::VXCHANNEL_FLAGS flags);
protected: protected:
// 2 sync functions served for material channels.
void SyncVertexCountToMtlChannel(); // setup material channel custom uv properly
void SyncMtlChannelToFaceMask(CKDWORD oldsize, CKDWORD newsize); // request all face accept all material channels.
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. */
};
struct FaceData_t { struct FaceData_t {
FaceData_t() : FaceData_t() :
m_Normal(), m_Normal()
m_ChannelMask(0xFFFF)
{} {}
VxMath::VxVector3 m_Normal; VxMath::VxVector3 m_Normal;
CKWORD m_ChannelMask;
}; };
struct MaterialChannel_t {
MaterialChannel_t() :
m_Material(nullptr),
m_SourceBlend(VxMath::VXBLEND_MODE::VXBLEND_ZERO),
m_DestBlend(VxMath::VXBLEND_MODE::VXBLEND_SRCCOLOR),
m_CustomUV(),
m_Flags(EnumsHelper::Merge({ VxMath::VXCHANNEL_FLAGS::VXCHANNEL_ACTIVE, VxMath::VXCHANNEL_FLAGS::VXCHANNEL_SAMEUV }))
{}
CKMaterial* m_Material;
VxMath::VXBLEND_MODE m_SourceBlend;
VxMath::VXBLEND_MODE m_DestBlend;
XContainer::XArray<VxMath::VxVector2> m_CustomUV;
VxMath::VXCHANNEL_FLAGS m_Flags;
};
VxMath::VXMESH_FLAGS m_Flags; VxMath::VXMESH_FLAGS m_Flags;
CKDWORD m_VertexCount; CKDWORD m_VertexCount;
CKDWORD m_LineCount; CKDWORD m_LineCount;
CKDWORD m_MtlSlotCount; CKDWORD m_MtlSlotCount;
CKDWORD m_FaceCount; CKDWORD m_FaceCount;
CKDWORD m_MtlChannelCount;
XContainer::XArray<VxMath::VxVector3> m_VertexPosition; XContainer::XArray<VxMath::VxVector3> m_VertexPosition;
XContainer::XArray<VxMath::VxVector3> m_VertexNormal; XContainer::XArray<VxMath::VxVector3> m_VertexNormal;
XContainer::XArray<VxMath::VxVector2> m_VertexUV; XContainer::XArray<VxMath::VxVector2> m_VertexUV;
XContainer::XArray<CKDWORD> m_VertexColor; XContainer::XArray<CKDWORD> m_VertexColor;
XContainer::XArray<CKDWORD> m_VertexSpecularColor; XContainer::XArray<CKDWORD> m_VertexSpecularColor;
XContainer::XArray<CKFLOAT> m_VertexWeight;
bool m_NoVertexWeight; // true if there is actually no vertex weight
XContainer::XArray<CKMaterial*> m_MaterialSlot; XContainer::XArray<CKMaterial*> m_MaterialSlot;
XContainer::XArray<CKWORD> m_FaceIndices; XContainer::XArray<CKWORD> m_FaceIndices;
XContainer::XArray<CKWORD> m_FaceMtlIndex; XContainer::XArray<CKWORD> m_FaceMtlIndex;
XContainer::XArray<FaceData_t> m_Faces; XContainer::XArray<FaceData_t> m_FaceOthers;
XContainer::XArray<CKWORD> m_LineIndices; XContainer::XArray<CKWORD> m_LineIndices;
XContainer::XArray<MaterialChannel_t> m_MaterialChannels;
}; };
} }

View File

@ -1,7 +1,7 @@
#include "VxMath.hpp" #include "VxMath.hpp"
#include <cmath>
#include "stb_image_resize.h" #include "stb_image_resize.h"
namespace LibCmo::VxMath { namespace LibCmo::VxMath {
#pragma region Structure copying #pragma region Structure copying
@ -149,6 +149,12 @@ namespace LibCmo::VxMath {
); );
} }
void Abs(VxVector3& lhs) {
lhs.x = std::fabs(lhs.x);
lhs.y = std::fabs(lhs.y);
lhs.z = std::fabs(lhs.z);
}
} }
#pragma endregion #pragma endregion

View File

@ -93,6 +93,8 @@ namespace LibCmo::VxMath {
CKFLOAT DotProduct(const VxVector4& lhs, const VxVector4& rhs); CKFLOAT DotProduct(const VxVector4& lhs, const VxVector4& rhs);
VxVector3 CrossProduct(const VxVector3& lhs, const VxVector3& rhs); VxVector3 CrossProduct(const VxVector3& lhs, const VxVector3& rhs);
void Abs(VxVector3& lhs);
} }