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:
		| @ -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); | ||||||
|  |  | ||||||
| 	} | 	} | ||||||
|  |  | ||||||
| } | } | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user