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. // 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)); 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; if (!file->Load(file_name)) return false;
// add into list and return // add into list and return
@ -124,7 +124,7 @@ bool BMFile_Create(
// create a now one // create a now one
std::unique_ptr<BMap::BMFile> file(new BMap::BMFile(temp_folder, texture_folder, encoding_count, encodings, false)); 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 // add into list and return if success
g_AllBMFiles.emplace(file.get()); 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()); BMPARAM_OUT_ASSIGN(out_mem, trans->PrepareFaceMtlSlot());
return BMPARAM_OUT_VAL(out_mem) != nullptr; 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; if (!CheckBMMeshTrans(trans)) return false;
return trans->Parse(write_into_mesh); if (!CheckBMFile(bmfile)) return false;
return trans->Parse(bmfile, objid);
} }
#pragma endregion #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_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_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_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 #pragma endregion

View File

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

View File

@ -8,6 +8,127 @@
namespace BMap { 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 { class BMMeshTransition {
private: private:
struct TransitionVertex { struct TransitionVertex {
@ -47,11 +168,11 @@ namespace BMap {
LibCmo::CKDWORD* PrepareFaceUVIndices(); LibCmo::CKDWORD* PrepareFaceUVIndices();
LibCmo::CKDWORD* PrepareFaceMtlSlot(); LibCmo::CKDWORD* PrepareFaceMtlSlot();
bool Parse(LibCmo::CK2::ObjImpls::CKMesh* write_into_mesh); bool Parse(BMFile* bmfile, LibCmo::CK2::CK_ID mesh_id);
private: private:
void DoRealParse(); 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_IsVertexOK, m_IsNormalOK, m_IsUVOK, m_IsFaceOK, m_IsMtlSlotOK;
bool m_IsParsed; bool m_IsParsed;
@ -73,79 +194,4 @@ namespace BMap {
std::map<TransitionVertex, LibCmo::CKDWORD, TransitionVertexCompare> m_ProcDupRemover; 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 # 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 ## Status
@ -43,9 +44,9 @@ There are 3 lists which indicate our accept guideline.
These features will be accepted as soon as possible. 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. * Class layout, `Load()` functions of following `CKObject` based classes.
- `CK3dEntity` - None
* Class layout, and `LoadData()` functions of following `CKBaseManager` based classes. * Class layout, and `LoadData()` functions of following `CKBaseManager` based classes.
- `CKAttributeManager` - `CKAttributeManager`
@ -53,8 +54,8 @@ These features will be accepted as soon as possible.
These features are in plan, but not urge to merge. These features are in plan, but not urge to merge.
* The `CK_ID` remap system of Reader & Writer. * The `CK_ID` remap system of Reader.
* Any Save functions. * CK3dEntity hierarchy system.
* Other CK classes implementations. * Other CK classes implementations.
* Non-Virtools 2.1 implementations. * Non-Virtools 2.1 implementations.