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:
parent
ee4b621cac
commit
92f4271124
|
@ -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
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -94,6 +94,8 @@ namespace LibCmo::VxMath {
|
||||||
|
|
||||||
VxVector3 CrossProduct(const VxVector3& lhs, const VxVector3& rhs);
|
VxVector3 CrossProduct(const VxVector3& lhs, const VxVector3& rhs);
|
||||||
|
|
||||||
|
void Abs(VxVector3& lhs);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user