change bmap interface. update bmfile safe guard

This commit is contained in:
yyc12345 2023-10-30 10:25:31 +08:00
parent 9475e2abc5
commit 1d9bd09224
5 changed files with 155 additions and 114 deletions

View File

@ -105,7 +105,7 @@ bool BMFile_Load(
// create a now one and try to load data.
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, encoding_count, encodings, false));
if (file->IsFreezed()) return false;
if (file->IsInitError()) return false;
if (!file->Load(file_name)) return false;
// add into list and return
@ -124,7 +124,7 @@ bool BMFile_Create(
// create a now one
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, encoding_count, encodings, false));
if (file->IsFreezed()) return false;
if (file->IsInitError()) return false;
// add into list and return if success
g_AllBMFiles.emplace(file.get());
@ -307,9 +307,10 @@ bool BMMeshTrans_PrepareFaceMtlSlot(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_OUT(L
BMPARAM_OUT_ASSIGN(out_mem, trans->PrepareFaceMtlSlot());
return BMPARAM_OUT_VAL(out_mem) != nullptr;
}
bool BMMeshTrans_Parse(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_IN(LibCmo::CK2::ObjImpls::CKMesh*, write_into_mesh)) {
bool BMMeshTrans_Parse(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_IN(BMap::BMFile*, bmfile), BMPARAM_IN(LibCmo::CK2::CK_ID, objid)) {
if (!CheckBMMeshTrans(trans)) return false;
return trans->Parse(write_into_mesh);
if (!CheckBMFile(bmfile)) return false;
return trans->Parse(bmfile, objid);
}
#pragma endregion

View File

@ -130,7 +130,7 @@ LIBCMO_EXPORT bool BMMeshTrans_PrepareFaceVertexIndices(BMPARAM_MESHTRANS_DECL(t
LIBCMO_EXPORT bool BMMeshTrans_PrepareFaceNormalIndices(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_OUT(LibCmo::CKDWORD*, out_mem));
LIBCMO_EXPORT bool BMMeshTrans_PrepareFaceUVIndices(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_OUT(LibCmo::CKDWORD*, out_mem));
LIBCMO_EXPORT bool BMMeshTrans_PrepareFaceMtlSlot(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_OUT(LibCmo::CKDWORD*, out_mem));
LIBCMO_EXPORT bool BMMeshTrans_Parse(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_IN(LibCmo::CK2::ObjImpls::CKMesh*, write_into_mesh));
LIBCMO_EXPORT bool BMMeshTrans_Parse(BMPARAM_MESHTRANS_DECL(trans), BMPARAM_IN(BMap::BMFile*, bmfile), BMPARAM_IN(LibCmo::CK2::CK_ID, objid));
#pragma endregion

View File

@ -107,12 +107,16 @@ namespace BMap {
return m_FaceVertexs.data();
}
bool BMMeshTransition::Parse(LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh) {
if (m_IsParsed || write_into_mesh == nullptr) return false;
bool BMMeshTransition::Parse(BMFile* bmfile, LibCmo::CK2::CK_ID mesh_id) {
// check basic status
if (m_IsParsed || bmfile == nullptr) return false;
if (!m_IsVertexOK || !m_IsNormalOK || !m_IsUVOK || !m_IsFaceOK || !m_IsMtlSlotOK) return false;
m_IsParsed = true;
// check pointer assign
LibCmo::CK2::ObjImpls::CKObject* writing_mesh = bmfile->GetObjectPtr(mesh_id);
if (writing_mesh == nullptr || writing_mesh->GetClassID() != LibCmo::CK2::CK_CLASSID::CKCID_MESH) return false;
// do parse
m_IsParsed = true;
DoRealParse();
// check vertex overflow
@ -125,7 +129,7 @@ namespace BMap {
}
// apply to mesh
ApplyToMesh(write_into_mesh);
ApplyToMesh(bmfile, static_cast<LibCmo::CK2::ObjImpls::CKMesh*>(writing_mesh));
return true;
}
@ -139,7 +143,7 @@ namespace BMap {
// iterate face
for (size_t faceid = 0; faceid < face_size; ++faceid) {
LibCmo::CKDWORD idx[3];
LibCmo::CKDWORD idx[3] { 0, 0, 0 };
for (int j = 0; j < 3; ++j) {
// create one first
TransitionVertex tvec(
@ -163,7 +167,7 @@ namespace BMap {
}
}
void BMMeshTransition::ApplyToMesh(LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh) {
void BMMeshTransition::ApplyToMesh(BMFile* bmfile, LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh) {
LibCmo::CKDWORD vec_count = static_cast<LibCmo::CKDWORD>(m_ProcVertexs.size()),
face_count = static_cast<LibCmo::CKDWORD>(m_ProcFaces.size()),
mtl_count = static_cast<LibCmo::CKDWORD>(m_MtlSlots.size());
@ -209,13 +213,12 @@ namespace BMap {
}
// set mtl slot
LibCmo::CK2::CKContext* correspondingCtx = write_into_mesh->GetCKContext();
write_into_mesh->SetMaterialSlotCount(mtl_count);
LibCmo::CK2::ObjImpls::CKMaterial** pMtlSlot = write_into_mesh->GetMaterialSlots();
for (LibCmo::CKDWORD i = 0; i < mtl_count; ++i) {
// convert id to CKMaterial* and check its type
LibCmo::CK2::ObjImpls::CKObject* mtlptr = correspondingCtx->GetObject(m_MtlSlots[i]);
if (mtlptr != nullptr && LibCmo::CK2::CKIsChildClassOf(mtlptr->GetClassID(), LibCmo::CK2::CK_CLASSID::CKCID_MATERIAL)) {
LibCmo::CK2::ObjImpls::CKObject* mtlptr = bmfile->GetObjectPtr(m_MtlSlots[i]);
if (mtlptr != nullptr && mtlptr->GetClassID() == LibCmo::CK2::CK_CLASSID::CKCID_MATERIAL) {
*(pMtlSlot++) = static_cast<LibCmo::CK2::ObjImpls::CKMaterial*>(mtlptr);
} else {
*(pMtlSlot++) = nullptr;
@ -228,13 +231,13 @@ namespace BMap {
#pragma region BMfile
BMFile::BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_reader) :
m_IsReader(is_reader), m_IsFreezed(false) {
BMFile::BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_loader) :
m_IsInitError(false), m_IsLoader(is_loader), m_HasLoaded(false), m_HasSaved(false), m_Context(nullptr) {
m_Context = new LibCmo::CK2::CKContext();
// set temp folder and texture folder
auto pm = m_Context->GetPathManager();
m_IsFreezed = m_IsFreezed || !pm->AddPath(texture_folder);
m_IsFreezed = m_IsFreezed || !pm->SetTempFolder(temp_folder);
m_IsInitError = m_IsInitError || !pm->AddPath(texture_folder);
m_IsInitError = m_IsInitError || !pm->SetTempFolder(temp_folder);
// set encoding
LibCmo::XContainer::XArray<LibCmo::XContainer::XString> cache;
for (LibCmo::CKDWORD i = 0; i < encoding_count; ++i) {
@ -253,12 +256,8 @@ namespace BMap {
delete m_Context;
}
bool BMFile::IsFreezed() {
return m_IsFreezed;
}
bool BMFile::Load(LibCmo::CKSTRING filename) {
if (m_IsFreezed || !m_IsReader) return false;
if (!CanExecLoad()) return false;
// create temp ckfile and load
LibCmo::CK2::CKFileReader reader(m_Context);
@ -299,11 +298,12 @@ namespace BMap {
}
}
m_HasLoaded = true;
return true;
}
bool BMFile::Save(LibCmo::CKSTRING filename, LibCmo::CKINT compress_level) {
if (m_IsFreezed || m_IsReader) return false;
if (!CanExecSave()) return false;
// create temp writer
LibCmo::CK2::CKFileWriter writer(m_Context);
@ -331,18 +331,11 @@ namespace BMap {
// save to file and detect error
LibCmo::CK2::CKERROR err = writer.Save(filename);
// set freezed to stop any change again.
// aka, only allow save once.
m_IsFreezed = true;
// return with error detect.
m_HasSaved = true;
return err == LibCmo::CK2::CKERROR::CKERR_OK;
}
LibCmo::CK2::ObjImpls::CKObject* BMFile::GetObjectPtr(LibCmo::CK2::CK_ID objid) {
return m_Context->GetObject(objid);;
}
LibCmo::CKDWORD BMFile::GetGroupCount() { return CommonGetObjectCount(m_ObjGroups); }
LibCmo::CK2::CK_ID BMFile::GetGroup(LibCmo::CKDWORD idx) { return CommonGetObject(m_ObjGroups, idx); }
LibCmo::CK2::CK_ID BMFile::CreateGroup() { return CommonCreateObject(m_ObjGroups, LibCmo::CK2::CK_CLASSID::CKCID_GROUP); }

View File

@ -8,6 +8,127 @@
namespace BMap {
class BMFile {
public:
BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_reader);
~BMFile();
LIBCMO_DISABLE_COPY_MOVE(BMFile);
// ===== safe visit functions =====
/**
Safe Visit Function will make sure this class is visited with safe mode.
These function will block all other functions if this class init failed.
Or, block any more operations if this class has loaded or saved once. In this time you only can free this class
*/
public:
bool IsInitError() {
return m_IsInitError;
}
private:
bool CanExecLoad() {
// no error, is loader, no prev load
return (!m_IsInitError && m_IsLoader && !m_HasLoaded);
}
bool CanExecSave() {
// no error, is saver, no prev save
return (!m_IsInitError && !m_IsLoader && !m_HasSaved);
}
bool CanExecLoaderVisitor() {
// no error, is loader, has loaded
return (!m_IsInitError && m_IsLoader && m_HasLoaded);
}
bool CanExecSaverVisitor() {
// no error, is saver, not saveed yet
// same as CanExecSave
return (!m_IsInitError && !m_IsLoader && !m_HasSaved);
}
private:
/**
* @brief True if an error occurs when initializing this class.
*/
bool m_IsInitError;
/**
* @brief True if this class is a reader.
*/
bool m_IsLoader;
/**
* @brief True if this class has read. Only valid when this class is reader.
*/
bool m_HasLoaded;
/**
* @brief True if this class has written. Only valid when this class is writer.
*/
bool m_HasSaved;
// ===== help functions =====
public:
bool Load(LibCmo::CKSTRING filename);
bool Save(LibCmo::CKSTRING filename, LibCmo::CKINT compress_level);
LibCmo::CK2::ObjImpls::CKObject* GetObjectPtr(LibCmo::CK2::CK_ID objid) {
return m_Context->GetObject(objid);;
}
// ===== visitors =====
private:
LibCmo::CKDWORD CommonGetObjectCount(std::vector<LibCmo::CK2::CK_ID>& container) {
// only available in loader
if (!CanExecLoaderVisitor()) return 0;
return static_cast<LibCmo::CKDWORD>(container.size());
}
LibCmo::CK2::CK_ID CommonGetObject(std::vector<LibCmo::CK2::CK_ID>& container, LibCmo::CKDWORD idx) {
// only available in loader
if (!CanExecLoaderVisitor()) return 0;
return container[idx];
}
LibCmo::CK2::CK_ID CommonCreateObject(std::vector<LibCmo::CK2::CK_ID>& container, LibCmo::CK2::CK_CLASSID cid) {
// only available in saver
if (!CanExecSaverVisitor()) return 0;
// try create object and get its pointer
LibCmo::CK2::ObjImpls::CKObject* obj = m_Context->CreateObject(cid, nullptr);
// check creation validation
if (obj == nullptr) return 0;
// if success, write its id and emplace its id into list
LibCmo::CK2::CK_ID objid = obj->GetID();
container.emplace_back(objid);
return objid;
}
public:
LibCmo::CKDWORD GetGroupCount();
LibCmo::CK2::CK_ID GetGroup(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateGroup();
LibCmo::CKDWORD Get3dObjectCount();
LibCmo::CK2::CK_ID Get3dObject(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID Create3dObject();
LibCmo::CKDWORD GetMeshCount();
LibCmo::CK2::CK_ID GetMesh(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateMesh();
LibCmo::CKDWORD GetMaterialCount();
LibCmo::CK2::CK_ID GetMaterial(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateMaterial();
LibCmo::CKDWORD GetTextureCount();
LibCmo::CK2::CK_ID GetTexture(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateTexture();
private:
LibCmo::CK2::CKContext* m_Context;
std::vector<LibCmo::CK2::CK_ID> m_ObjGroups;
std::vector<LibCmo::CK2::CK_ID> m_Obj3dObjects;
std::vector<LibCmo::CK2::CK_ID> m_ObjMeshs;
std::vector<LibCmo::CK2::CK_ID> m_ObjMaterials;
std::vector<LibCmo::CK2::CK_ID> m_ObjTextures;
};
class BMMeshTransition {
private:
struct TransitionVertex {
@ -47,11 +168,11 @@ namespace BMap {
LibCmo::CKDWORD* PrepareFaceUVIndices();
LibCmo::CKDWORD* PrepareFaceMtlSlot();
bool Parse(LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh);
bool Parse(BMFile* bmfile, LibCmo::CK2::CK_ID mesh_id);
private:
void DoRealParse();
void ApplyToMesh(LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh);
void ApplyToMesh(BMFile* bmfile, LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh);
bool m_IsVertexOK, m_IsNormalOK, m_IsUVOK, m_IsFaceOK, m_IsMtlSlotOK;
bool m_IsParsed;
@ -73,79 +194,4 @@ namespace BMap {
std::map<TransitionVertex, LibCmo::CKDWORD, TransitionVertexCompare> m_ProcDupRemover;
};
class BMFile {
public:
BMFile(LibCmo::CKSTRING temp_folder, LibCmo::CKSTRING texture_folder, LibCmo::CKDWORD encoding_count, LibCmo::CKSTRING* encodings, bool is_reader);
~BMFile();
LIBCMO_DISABLE_COPY_MOVE(BMFile);
// ===== help functions =====
/**
* @brief Check whether this instance is freezed.
* @return True if freezed. This instance should be free immediately.
*/
bool IsFreezed();
bool Load(LibCmo::CKSTRING filename);
bool Save(LibCmo::CKSTRING filename, LibCmo::CKINT compress_level);
LibCmo::CK2::ObjImpls::CKObject* GetObjectPtr(LibCmo::CK2::CK_ID objid);
// ===== visitors =====
private:
LibCmo::CKDWORD CommonGetObjectCount(std::vector<LibCmo::CK2::CK_ID>& container) {
if (m_IsFreezed || !m_IsReader) return 0;
return static_cast<LibCmo::CKDWORD>(container.size());
}
LibCmo::CK2::CK_ID CommonGetObject(std::vector<LibCmo::CK2::CK_ID>& container, LibCmo::CKDWORD idx) {
if (m_IsFreezed || !m_IsReader || idx >= container.size()) return 0;
return container[idx];
}
LibCmo::CK2::CK_ID CommonCreateObject(std::vector<LibCmo::CK2::CK_ID>& container, LibCmo::CK2::CK_CLASSID cid) {
// only available in writer
if (m_IsFreezed || m_IsReader) return 0;
// try create object and get its pointer
LibCmo::CK2::ObjImpls::CKObject* obj = m_Context->CreateObject(cid, nullptr);
// check creation validation
if (obj == nullptr) return 0;
// if success, write its id and emplace its id into list
LibCmo::CK2::CK_ID objid = obj->GetID();
container.emplace_back(objid);
return objid;
}
public:
LibCmo::CKDWORD GetGroupCount();
LibCmo::CK2::CK_ID GetGroup(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateGroup();
LibCmo::CKDWORD Get3dObjectCount();
LibCmo::CK2::CK_ID Get3dObject(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID Create3dObject();
LibCmo::CKDWORD GetMeshCount();
LibCmo::CK2::CK_ID GetMesh(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateMesh();
LibCmo::CKDWORD GetMaterialCount();
LibCmo::CK2::CK_ID GetMaterial(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateMaterial();
LibCmo::CKDWORD GetTextureCount();
LibCmo::CK2::CK_ID GetTexture(LibCmo::CKDWORD idx);
LibCmo::CK2::CK_ID CreateTexture();
private:
/**
* @brief True if all operation of this instance should be rejected.
*/
bool m_IsFreezed;
bool m_IsReader;
LibCmo::CK2::CKContext* m_Context;
std::vector<LibCmo::CK2::CK_ID> m_ObjGroups;
std::vector<LibCmo::CK2::CK_ID> m_Obj3dObjects;
std::vector<LibCmo::CK2::CK_ID> m_ObjMeshs;
std::vector<LibCmo::CK2::CK_ID> m_ObjMaterials;
std::vector<LibCmo::CK2::CK_ID> m_ObjTextures;
};
}

View File

@ -1,6 +1,7 @@
# libcmo21
The Library for CMO File Read/Write. Also the Minimalist Virtools Environment.
The Library for CMO (also accept NMO, VMO and NMS) File Read/Write. Also the Minimalist Virtools Environment.
Write with one Library and Load Virtools File Everywhere.
## Status
@ -43,9 +44,9 @@ There are 3 lists which indicate our accept guideline.
These features will be accepted as soon as possible.
* The bug fix of Virtools file reader.
* The bug fix of any existing code.
* Class layout, `Load()` functions of following `CKObject` based classes.
- `CK3dEntity`
- None
* Class layout, and `LoadData()` functions of following `CKBaseManager` based classes.
- `CKAttributeManager`
@ -53,8 +54,8 @@ These features will be accepted as soon as possible.
These features are in plan, but not urge to merge.
* The `CK_ID` remap system of Reader & Writer.
* Any Save functions.
* The `CK_ID` remap system of Reader.
* CK3dEntity hierarchy system.
* Other CK classes implementations.
* Non-Virtools 2.1 implementations.