From fcd1fa81db6cb0d98f3f75d03c4e4645e60c33c8 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Sun, 5 Nov 2023 10:44:11 +0800 Subject: [PATCH] rename BM3dEntity to BM3dObject in BMap. continue writing python bmao binding. fix doc --- BMap/BMExports.cpp | 12 +-- BMap/BMExports.hpp | 12 +-- BMapBindings/PyBMap/bmap.py | 26 +++--- BMapBindings/PyBMap/bmap_wrapper.py | 113 +++++++++++++++++++++--- BMapBindings/PyBMap/virtools_types.py | 23 +++++ CodeGen/BMapBindings/snippets/header.py | 2 +- Documents/CKStateChunk.html | 7 +- 7 files changed, 155 insertions(+), 40 deletions(-) diff --git a/BMap/BMExports.cpp b/BMap/BMExports.cpp index 6430a28..0b49b4c 100644 --- a/BMap/BMExports.cpp +++ b/BMap/BMExports.cpp @@ -820,7 +820,7 @@ bool BMMesh_SetMaterialSlot(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCm #pragma region CK3dObject -bool BM3dEntity_GetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VxMatrix, out_mat)) { +bool BM3dObject_GetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VxMatrix, out_mat)) { auto obj = CheckCK3dObject(bmfile, objid); if (obj == nullptr) return false; @@ -828,7 +828,7 @@ bool BM3dEntity_GetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(L return true; } -bool BM3dEntity_SetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::VxMath::VxMatrix, mat)) { +bool BM3dObject_SetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::VxMath::VxMatrix, mat)) { auto obj = CheckCK3dObject(bmfile, objid); if (obj == nullptr) return false; @@ -836,7 +836,7 @@ bool BM3dEntity_SetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(Li return true; } -bool BM3dEntity_GetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::CK2::CK_ID, out_meshid)) { +bool BM3dObject_GetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::CK2::CK_ID, out_meshid)) { auto obj = CheckCK3dObject(bmfile, objid); if (obj == nullptr) return false; @@ -844,7 +844,7 @@ bool BM3dEntity_GetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(L return true; } -bool BM3dEntity_SetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::CK2::CK_ID, meshid)) { +bool BM3dObject_SetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::CK2::CK_ID, meshid)) { auto obj = CheckCK3dObject(bmfile, objid); auto meshobj = CheckCKMesh(bmfile, meshid); if (obj == nullptr /*|| meshobj == nullptr*/) return false; //allow nullptr assign @@ -853,7 +853,7 @@ bool BM3dEntity_SetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(Li return true; } -bool BM3dEntity_GetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(bool, out_isVisible)) { +bool BM3dObject_GetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(bool, out_isVisible)) { auto obj = CheckCK3dObject(bmfile, objid); if (obj == nullptr) return false; @@ -861,7 +861,7 @@ bool BM3dEntity_GetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(bo return true; } -bool BM3dEntity_SetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(bool, is_visible)) { +bool BM3dObject_SetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(bool, is_visible)) { auto obj = CheckCK3dObject(bmfile, objid); if (obj == nullptr) return false; diff --git a/BMap/BMExports.hpp b/BMap/BMExports.hpp index 3fdd154..30f12ad 100644 --- a/BMap/BMExports.hpp +++ b/BMap/BMExports.hpp @@ -239,11 +239,11 @@ LIBCMO_EXPORT bool BMMesh_SetMaterialSlot(BMPARAM_OBJECT_DECL(bmfile, objid), BM #pragma region CK3dObject -LIBCMO_EXPORT bool BM3dEntity_GetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VxMatrix, out_mat)); -LIBCMO_EXPORT bool BM3dEntity_SetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::VxMath::VxMatrix, mat)); -LIBCMO_EXPORT bool BM3dEntity_GetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::CK2::CK_ID, out_meshid)); -LIBCMO_EXPORT bool BM3dEntity_SetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::CK2::CK_ID, meshid)); -LIBCMO_EXPORT bool BM3dEntity_GetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(bool, out_isVisible)); -LIBCMO_EXPORT bool BM3dEntity_SetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(bool, is_visible)); +LIBCMO_EXPORT bool BM3dObject_GetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::VxMath::VxMatrix, out_mat)); +LIBCMO_EXPORT bool BM3dObject_SetWorldMatrix(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::VxMath::VxMatrix, mat)); +LIBCMO_EXPORT bool BM3dObject_GetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(LibCmo::CK2::CK_ID, out_meshid)); +LIBCMO_EXPORT bool BM3dObject_SetCurrentMesh(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(LibCmo::CK2::CK_ID, meshid)); +LIBCMO_EXPORT bool BM3dObject_GetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_OUT(bool, out_isVisible)); +LIBCMO_EXPORT bool BM3dObject_SetVisibility(BMPARAM_OBJECT_DECL(bmfile, objid), BMPARAM_IN(bool, is_visible)); #pragma endregion diff --git a/BMapBindings/PyBMap/bmap.py b/BMapBindings/PyBMap/bmap.py index eb665c1..1b6c7af 100644 --- a/BMapBindings/PyBMap/bmap.py +++ b/BMapBindings/PyBMap/bmap.py @@ -76,7 +76,7 @@ def is_bmap_available() -> bool: return _g_BMapModule is not None def _bmap_error_check(result: bm_bool, func, args): - if not bm_bool.value: + if not result: raise BMapException("BMap operation failed.") return result @@ -714,42 +714,42 @@ BMMesh_GetMaterialSlot = _create_bmap_func('BMMesh_GetMaterialSlot', [bm_void_p, # @param mtlid[in] Type: LibCmo::CK2::CK_ID. # @return True if no error, otherwise False. BMMesh_SetMaterialSlot = _create_bmap_func('BMMesh_SetMaterialSlot', [bm_void_p, bm_CKID, bm_CKDWORD, bm_CKID]) -## BM3dEntity_GetWorldMatrix +## BM3dObject_GetWorldMatrix # @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param out_mat[out] Type: LibCmo::VxMath::VxMatrix. Use ctypes.byref(data) pass it. # @return True if no error, otherwise False. -BM3dEntity_GetWorldMatrix = _create_bmap_func('BM3dEntity_GetWorldMatrix', [bm_void_p, bm_CKID, bm_VxMatrix_p]) -## BM3dEntity_SetWorldMatrix +BM3dObject_GetWorldMatrix = _create_bmap_func('BM3dObject_GetWorldMatrix', [bm_void_p, bm_CKID, bm_VxMatrix_p]) +## BM3dObject_SetWorldMatrix # @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param mat[in] Type: LibCmo::VxMath::VxMatrix. # @return True if no error, otherwise False. -BM3dEntity_SetWorldMatrix = _create_bmap_func('BM3dEntity_SetWorldMatrix', [bm_void_p, bm_CKID, bm_VxMatrix]) -## BM3dEntity_GetCurrentMesh +BM3dObject_SetWorldMatrix = _create_bmap_func('BM3dObject_SetWorldMatrix', [bm_void_p, bm_CKID, bm_VxMatrix]) +## BM3dObject_GetCurrentMesh # @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param out_meshid[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it. # @return True if no error, otherwise False. -BM3dEntity_GetCurrentMesh = _create_bmap_func('BM3dEntity_GetCurrentMesh', [bm_void_p, bm_CKID, bm_CKID_p]) -## BM3dEntity_SetCurrentMesh +BM3dObject_GetCurrentMesh = _create_bmap_func('BM3dObject_GetCurrentMesh', [bm_void_p, bm_CKID, bm_CKID_p]) +## BM3dObject_SetCurrentMesh # @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param meshid[in] Type: LibCmo::CK2::CK_ID. # @return True if no error, otherwise False. -BM3dEntity_SetCurrentMesh = _create_bmap_func('BM3dEntity_SetCurrentMesh', [bm_void_p, bm_CKID, bm_CKID]) -## BM3dEntity_GetVisibility +BM3dObject_SetCurrentMesh = _create_bmap_func('BM3dObject_SetCurrentMesh', [bm_void_p, bm_CKID, bm_CKID]) +## BM3dObject_GetVisibility # @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param out_isVisible[out] Type: bool. Use ctypes.byref(data) pass it. # @return True if no error, otherwise False. -BM3dEntity_GetVisibility = _create_bmap_func('BM3dEntity_GetVisibility', [bm_void_p, bm_CKID, bm_bool_p]) -## BM3dEntity_SetVisibility +BM3dObject_GetVisibility = _create_bmap_func('BM3dObject_GetVisibility', [bm_void_p, bm_CKID, bm_bool_p]) +## BM3dObject_SetVisibility # @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param is_visible[in] Type: bool. # @return True if no error, otherwise False. -BM3dEntity_SetVisibility = _create_bmap_func('BM3dEntity_SetVisibility', [bm_void_p, bm_CKID, bm_bool]) +BM3dObject_SetVisibility = _create_bmap_func('BM3dObject_SetVisibility', [bm_void_p, bm_CKID, bm_bool]) #endregion diff --git a/BMapBindings/PyBMap/bmap_wrapper.py b/BMapBindings/PyBMap/bmap_wrapper.py index 0d0e612..0ae7dbd 100644 --- a/BMapBindings/PyBMap/bmap_wrapper.py +++ b/BMapBindings/PyBMap/bmap_wrapper.py @@ -3,6 +3,7 @@ from . import bmap, virtools_types #region Basic Class Defines +g_InvalidCKID: int = 0 g_BMapEncoding: str = "utf-8" class _AbstractPointer(): @@ -70,26 +71,81 @@ if is_bmap_available(): #region Real Type Defines +"""! +BMFileReader, BMFileWriter, and BMMeshTrans can be create by given constructor. +But they must be destroyed by calling dispose(). Otherwise it may cause memory leak. +You also can use python `with` statement to achieve this automatically. + +BMObject, BMTexture, BMMaterial, BMMesh, and BM3dObject should NOT be constructed from given constructor. +They must be obtained from BMFileReader, BMFileWriter, and BMMeshTrans. +Thus BMObject, BMTexture, BMMaterial, BMMesh, and BM3dObject also do not need to free +because these resources are sotred in BMFileReader, BMFileWriter, and BMMeshTrans. +We just provide them as a visitor. +""" + class BMFileReader(_AbstractPointer): - pass - # write with `with` syntax + def __init__(self, file_name: str, temp_folder: str, texture_folder: str, encodings: tuple[str]): + pass + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.dispose() + + def dispose(self) -> None: + if self.is_valid(): + bmap.BMFile_Free(self._get_pointer()) class BMFileWriter(_AbstractPointer): - pass - # write with `with` syntax + def __init__(self, temp_folder: str, texture_folder: str, encodings: tuple[str]): + pass + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.dispose() + + def save(self, file_name: str, compress_level: int) -> None: + pass + + def dispose(self) -> None: + if self.is_valid(): + bmap.BMFile_Free(self._get_pointer()) class BMMeshTrans(_AbstractPointer): - pass - # write with `with` syntax + def __init__(self): + ptr: bmap.bm_void_p = bmap.bm_void_p() + bmap.BMMeshTrans_New(ctypes.byref(ptr)) + _AbstractPointer.__init__(ptr) + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_value, traceback): + self.dispose() + + def dispose(self) -> None: + if self.is_valid(): + bmap.BMMeshTrans_Delete(self._get_pointer()) + class BMObject(_AbstractCKObject): - def get_name(self) -> str: + def get_name(self) -> str | None: name: bmap.bm_CKSTRING = bmap.bm_CKSTRING() bmap.BMObject_GetName(self._get_pointer(), self._get_ckid(), ctypes.byref(name)) - return name.value.decode(g_BMapEncoding) + if name.value is None: + return None + else: + return name.value.decode(g_BMapEncoding) - def set_name(self, name: str) -> None: - name: bmap.bm_CKSTRING = bmap.bm_CKSTRING(name.encode(g_BMapEncoding)) + def set_name(self, name: str | None) -> None: + name: bmap.bm_CKSTRING + if name is None: + name = bmap.bm_CKSTRING(0) + else: + name = bmap.bm_CKSTRING(name.encode(g_BMapEncoding)) bmap.BMObject_SetName(self._get_pointer(), self._get_ckid(), name) class BMGroup(BMObject): @@ -105,6 +161,41 @@ class BMMesh(BMObject): pass class BM3dObject(BMObject): - pass + def get_world_matrix(self) -> virtools_types.ConstVxMatrix: + mat: bmap.bm_VxMatrix = bmap.bm_VxMatrix() + bmap.BM3dObject_GetWorldMatrix(self._get_pointer(), self._get_ckid(), ctypes.byref(mat)) + # use cast & pointer to get matrix data conveniently + flat: bmap.bm_CKFLOAT_p = ctypes.cast(ctypes.byref(mat), bmap.bm_CKFLOAT_p) + return tuple(flat[i] for i in range(16)) + + def set_world_matrix(self, mat: virtools_types.ConstVxMatrix) -> None: + # star syntax expand the tuple as the argument. + mat: bmap.bm_VxMatrix = bmap.bm_VxMatrix(*mat) + bmap.BM3dObject_SetWorldMatrix(self._get_pointer(), self._get_ckid(), mat) + + def get_current_mesh(self) -> BMMesh | None: + ckid: bmap.bm_CKID = bmap.bm_CKID() + bmap.BM3dObject_GetCurrentMesh(self._get_pointer(), self._get_ckid(), ctypes.byref(ckid)) + if ckid.value == g_InvalidCKID: + return None + else: + return BMMesh(self._get_pointer(), ckid) + + def set_current_mesh(self, mesh: BMMesh | None) -> None: + ckid: bmap.bm_CKID + if mesh is None: + ckid = bmap.bm_CKID(g_InvalidCKID) + else: + ckid = bmap.bm_CKID(mesh._get_ckid()) + bmap.BM3dObject_SetCurrentMesh(self._get_pointer(), self._get_ckid(), ckid) + + def get_visibility(self) -> bool: + visb: bmap.bm_bool = bmap.bm_bool() + bmap.BM3dObject_GetVisibility(self._get_pointer(), self._get_ckid(), ctypes.byref(visb)) + return visb.value + + def set_visibility(self, visb_: bool) -> None: + visb: bmap.bm_bool = bmap.bm_bool(visb_) + bmap.BM3dObject_SetVisibility(self._get_pointer(), self._get_ckid(), visb) #endregion diff --git a/BMapBindings/PyBMap/virtools_types.py b/BMapBindings/PyBMap/virtools_types.py index 24e45c6..bbfd7c8 100644 --- a/BMapBindings/PyBMap/virtools_types.py +++ b/BMapBindings/PyBMap/virtools_types.py @@ -82,6 +82,13 @@ class VxColor(): self.g = VxColor._clamp_factor(self.g) self.b = VxColor._clamp_factor(self.b) +ConstVxMatrix = tuple[ + float, float, float, float, + float, float, float, float, + float, float, float, float, + float, float, float, float +] + class VxMatrix(): """ The Matrix representation. @@ -109,6 +116,22 @@ class VxMatrix(): self.__mData[2][2] = 1.0 self.__mData[3][3] = 1.0 + def from_const(self, cm: ConstVxMatrix) -> None: + ( + self.__mData[0][0], self.__mData[0][1], self.__mData[0][2], self.__mData[0][3], + self.__mData[1][0], self.__mData[1][1], self.__mData[1][2], self.__mData[1][3], + self.__mData[2][0], self.__mData[2][1], self.__mData[2][2], self.__mData[2][3], + self.__mData[3][0], self.__mData[3][1], self.__mData[3][2], self.__mData[3][3] + ) = cm + + def to_const(self) -> ConstVxMatrix: + return ( + self.__mData[0][0], self.__mData[0][1], self.__mData[0][2], self.__mData[0][3], + self.__mData[1][0], self.__mData[1][1], self.__mData[1][2], self.__mData[1][3], + self.__mData[2][0], self.__mData[2][1], self.__mData[2][2], self.__mData[2][3], + self.__mData[3][0], self.__mData[3][1], self.__mData[3][2], self.__mData[3][3] + ) + class VXTEXTURE_BLENDMODE(enum.IntEnum): """! Blend Mode Flags diff --git a/CodeGen/BMapBindings/snippets/header.py b/CodeGen/BMapBindings/snippets/header.py index fac1e94..794fa9e 100644 --- a/CodeGen/BMapBindings/snippets/header.py +++ b/CodeGen/BMapBindings/snippets/header.py @@ -76,7 +76,7 @@ def is_bmap_available() -> bool: return _g_BMapModule is not None def _bmap_error_check(result: bm_bool, func, args): - if not bm_bool.value: + if not result: raise BMapException("BMap operation failed.") return result diff --git a/Documents/CKStateChunk.html b/Documents/CKStateChunk.html index e5b0476..a1c1d72 100644 --- a/Documents/CKStateChunk.html +++ b/Documents/CKStateChunk.html @@ -161,15 +161,16 @@ uint32 m_Identifier uint32 m_NextIdentifier - variable[] m_Payload + uint32[] m_Payload

A single identifier area.
m_Identifier is the unique magic word of this identifier area for CKStateChunk locating this area.
- m_NextIdentifier point to the m_Identifier in next identifier area.
+ m_NextIdentifier is a relative pointer. It point to the m_Identifier in next identifier area and is relative to the start of core data.
+ Thus, the size of each identifier area can be simply computed by the absolute diff to adjacent m_NextIdentifier (*m_pData[pos] - pos)
m_Payload is the data of this identifier area and can be read or written by various CKStateChunk read write functions.
- The size of each identifier area can be simply computed by the diff of m_NextIdentifier (*m_pData[pos] - pos) + The minimum block size of m_Payload is uint32. It mean that all data must be aligned to uint32 boundary when saving.