diff --git a/bbp_ng/OP_IMPORT_virtools.py b/bbp_ng/OP_IMPORT_virtools.py index 14e41fe..1e64722 100644 --- a/bbp_ng/OP_IMPORT_virtools.py +++ b/bbp_ng/OP_IMPORT_virtools.py @@ -3,7 +3,7 @@ from bpy_extras.wm_utils.progress_report import ProgressReport import tempfile, os, typing from . import PROP_preferences from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh -from . import PROP_ballance_element, PROP_virtools_group, PROP_virtools_material, PROP_virtools_texture +from . import PROP_ballance_element, PROP_virtools_group, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh from .PyBMap import bmap_wrapper as bmap class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile): @@ -76,25 +76,32 @@ def _import_virtools_textures( print(f'Texture Raw Data Temp: {rawdata_temp}') for vttexture in reader.get_textures(): - # if this image is raw data, save it in external folder before loading - # the attribute of raw data saving is the file path is not absolute path - texpath_to_load: str = vttexture.get_file_name() - if not os.path.isabs(texpath_to_load): - texpath_to_load = os.path.join( - rawdata_temp, - os.path.basename(texpath_to_load) - ) - vttexture.save_image(texpath_to_load) - - # detect whether it is ballance texture and load - try_blc_tex: str | None = PROP_virtools_texture.get_ballance_texture_filename(texpath_to_load) tex: bpy.types.Image - if try_blc_tex: - # load as ballance texture - tex = PROP_virtools_texture.load_ballance_texture(try_blc_tex) + texpath_to_load: str | None = vttexture.get_file_name() + + # if no assoc file path (what? but it is real happended) + # this is invalid image, create a blank image instead + if texpath_to_load is None: + tex = bpy.data.images.new("", 1, 1) else: - # load as other textures - tex = PROP_virtools_texture.load_other_texture(texpath_to_load) + # if this image is raw data, save it in external folder before loading + # the attribute of raw data saving is the file path is not absolute path + if not os.path.isabs(texpath_to_load): + texpath_to_load = os.path.join( + rawdata_temp, + os.path.basename(texpath_to_load) + ) + vttexture.save_image(texpath_to_load) + + # detect whether it is ballance texture and load + try_blc_tex: str | None = PROP_virtools_texture.get_ballance_texture_filename(texpath_to_load) + + if try_blc_tex: + # load as ballance texture + tex = PROP_virtools_texture.load_ballance_texture(try_blc_tex) + else: + # load as other textures + tex = PROP_virtools_texture.load_other_texture(texpath_to_load) # rename and insert it to map tex.name = UTIL_functions.virtools_name_regulator(vttexture.get_name()) @@ -248,6 +255,11 @@ def _import_virtools_meshes( # end of mesh writer + # set other mesh settings + mesh_settings: PROP_virtools_mesh.RawVirtoolsMesh = PROP_virtools_mesh.RawVirtoolsMesh() + mesh_settings.mLitMode = vtmesh.get_lit_mode() + PROP_virtools_mesh.set_raw_virtools_mesh(mesh, mesh_settings) + # add into map and step mesh_cret_map[vtmesh] = mesh progress.step() diff --git a/bbp_ng/PROP_ballance_element.py b/bbp_ng/PROP_ballance_element.py index b38a18f..338e37c 100644 --- a/bbp_ng/PROP_ballance_element.py +++ b/bbp_ng/PROP_ballance_element.py @@ -1,5 +1,6 @@ import bpy import os, typing, enum, array +from . import PROP_virtools_mesh from . import UTIL_functions, UTIL_file_io, UTIL_blender_mesh, UTIL_virtools_types #region Raw Elements Operations @@ -136,6 +137,8 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None: v.x = vpos[idx] v.y = vpos[idx + 1] v.z = vpos[idx + 2] + # conv co + UTIL_virtools_types.vxvector3_conv_co(v) yield v mesh_part.mVertexPosition = vpos_iterator() def vnml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]: @@ -145,9 +148,12 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None: v.x = vnml[idx] v.y = vnml[idx + 1] v.z = vnml[idx + 2] + # conv co + UTIL_virtools_types.vxvector3_conv_co(v) yield v mesh_part.mVertexNormal = vnml_iterator() def vuv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]: + # no uv, no need to conv co v: UTIL_virtools_types.VxVector2 = UTIL_virtools_types.VxVector2() yield v mesh_part.mVertexUV = vuv_iterator() @@ -165,6 +171,8 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None: f.mIndices[1].mNmlIdx = face[idx + 3] f.mIndices[2].mPosIdx = face[idx + 4] f.mIndices[2].mNmlIdx = face[idx + 5] + # conv co + f.conv_co() yield f mesh_part.mFace = face_iterator() @@ -173,6 +181,12 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None: # end of with writer # write mesh data + # set other mesh settings + # generated mesh always use lit mode. + mesh_settings: PROP_virtools_mesh.RawVirtoolsMesh = PROP_virtools_mesh.RawVirtoolsMesh() + mesh_settings.mLitMode = UTIL_virtools_types.VXMESH_LITMODE.VX_LITMESH + PROP_virtools_mesh.set_raw_virtools_mesh(mesh, mesh_settings) + # end of with fmesh # close file diff --git a/bbp_ng/PROP_virtools_mesh.py b/bbp_ng/PROP_virtools_mesh.py new file mode 100644 index 0000000..f428d37 --- /dev/null +++ b/bbp_ng/PROP_virtools_mesh.py @@ -0,0 +1,94 @@ +import bpy +import typing, enum +from . import UTIL_functions, UTIL_virtools_types + +# Annotation + +from .UTIL_functions import AnnotationData, BlenderEnumPropEntry_t + +g_Annotation_VXMESH_LITMODE: dict[int, AnnotationData] = { + UTIL_virtools_types.VXMESH_LITMODE.VX_PRELITMESH.value: AnnotationData("Prelit", "Lighting use color information store with vertices "), + UTIL_virtools_types.VXMESH_LITMODE.VX_LITMESH.value: AnnotationData("Lit", "Lighting is done by renderer using normals and face material information. "), +} + +# Raw Data + +class RawVirtoolsMesh(): + # Instance Member Declarations + mLitMode: UTIL_virtools_types.VXMESH_LITMODE + # Default Value Declarations + cDefaultLitMode: typing.ClassVar[UTIL_virtools_types.VXMESH_LITMODE] = UTIL_virtools_types.VXMESH_LITMODE.VX_LITMESH + + def __init__(self, **kwargs): + # assign default value for each component + self.mLitMode = kwargs.get('mLitMode', RawVirtoolsMesh.cDefaultLitMode) + +# Blender Property Group + +class BBP_PG_virtools_mesh(bpy.types.PropertyGroup): + lit_mode: bpy.props.EnumProperty( + name = "Lit Mode", + description = "Lighting mode of the mesh.", + items = UTIL_functions.generate_vt_enums_for_bl_enumprop( + UTIL_virtools_types.VXMESH_LITMODE, + g_Annotation_VXMESH_LITMODE + ), + default = RawVirtoolsMesh.cDefaultLitMode.value + ) + +# Getter Setter + +def get_virtools_mesh(mesh: bpy.types.Mesh) -> BBP_PG_virtools_mesh: + return mesh.virtools_mesh + +def get_raw_virtools_mesh(mesh: bpy.types.Mesh) -> RawVirtoolsMesh: + props: BBP_PG_virtools_mesh = get_virtools_mesh(mesh) + rawdata: RawVirtoolsMesh = RawVirtoolsMesh() + + rawdata.mLitMode = UTIL_virtools_types.VXMESH_LITMODE(int(props.lit_mode)) + + return rawdata + +def set_raw_virtools_mesh(mesh: bpy.types.Mesh, rawdata: RawVirtoolsMesh) -> None: + props: BBP_PG_virtools_mesh = get_virtools_mesh(mesh) + + props.lit_mode = str(rawdata.mLitMode.value) + +# Display Panel + +class BBP_PT_virtools_mesh(bpy.types.Panel): + """Show Virtools Mesh Properties.""" + bl_label = "Virtools Mesh" + bl_idname = "BBP_PT_virtools_mesh" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "data" # idk why blender use `data` as the mesh tab. + + @classmethod + def poll(cls, context): + return context.mesh is not None + + def draw(self, context): + # get layout and target + layout = self.layout + props: BBP_PG_virtools_mesh = get_virtools_mesh(context.mesh) + + # draw data + layout.prop(props, 'lit_mode') + +# Register + +def register(): + bpy.utils.register_class(BBP_PG_virtools_mesh) + bpy.utils.register_class(BBP_PT_virtools_mesh) + + # add into mesh metadata + bpy.types.Mesh.virtools_mesh = bpy.props.PointerProperty(type = BBP_PG_virtools_mesh) + +def unregister(): + # remove from metadata + del bpy.types.Mesh.virtools_mesh + + bpy.utils.unregister_class(BBP_PT_virtools_mesh) + bpy.utils.unregister_class(BBP_PG_virtools_mesh) + diff --git a/bbp_ng/PyBMap/bmap.py b/bbp_ng/PyBMap/bmap.py index 0ed4285..466faf6 100644 --- a/bbp_ng/PyBMap/bmap.py +++ b/bbp_ng/PyBMap/bmap.py @@ -32,6 +32,8 @@ bm_bool_p = ctypes.POINTER(bm_bool) bm_void_p = ctypes.c_void_p bm_void_pp = ctypes.POINTER(ctypes.c_void_p) +bm_callback = ctypes.CFUNCTYPE(None, bm_CKSTRING) + class bm_VxVector2(ctypes.Structure): _fields_ = [ ('x', bm_CKFLOAT), @@ -104,19 +106,21 @@ BMDispose = _create_bmap_func('BMDispose', []) # @param file_name[in] Type: LibCmo::CKSTRING. # @param temp_folder[in] Type: LibCmo::CKSTRING. # @param texture_folder[in] Type: LibCmo::CKSTRING. +# @param raw_callback[in] Type: BMap::NakedOutputCallback. # @param encoding_count[in] Type: LibCmo::CKDWORD. # @param encodings[in] Type: LibCmo::CKSTRING*. # @param out_file[out] Type: BMap::BMFile*. Use ctypes.byref(data) pass it. # @return True if no error, otherwise False. -BMFile_Load = _create_bmap_func('BMFile_Load', [bm_CKSTRING, bm_CKSTRING, bm_CKSTRING, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp]) +BMFile_Load = _create_bmap_func('BMFile_Load', [bm_CKSTRING, bm_CKSTRING, bm_CKSTRING, bm_callback, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp]) ## BMFile_Create # @param temp_folder[in] Type: LibCmo::CKSTRING. # @param texture_folder[in] Type: LibCmo::CKSTRING. +# @param raw_callback[in] Type: BMap::NakedOutputCallback. # @param encoding_count[in] Type: LibCmo::CKDWORD. # @param encodings[in] Type: LibCmo::CKSTRING*. # @param out_file[out] Type: BMap::BMFile*. Use ctypes.byref(data) pass it. # @return True if no error, otherwise False. -BMFile_Create = _create_bmap_func('BMFile_Create', [bm_CKSTRING, bm_CKSTRING, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp]) +BMFile_Create = _create_bmap_func('BMFile_Create', [bm_CKSTRING, bm_CKSTRING, bm_callback, bm_CKDWORD, bm_CKSTRING_p, bm_void_pp]) ## BMFile_Save # @param map_file[in] Type: BMap::BMFile*. # @param file_name[in] Type: LibCmo::CKSTRING. @@ -635,6 +639,18 @@ BMMaterial_GetZFunc = _create_bmap_func('BMMaterial_GetZFunc', [bm_void_p, bm_CK # @param val[in] Type: LibCmo::VxMath::VXCMPFUNC. # @return True if no error, otherwise False. BMMaterial_SetZFunc = _create_bmap_func('BMMaterial_SetZFunc', [bm_void_p, bm_CKID, bm_enum]) +## BMMesh_GetLitMode +# @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_mode[out] Type: LibCmo::VxMath::VXMESH_LITMODE. Use ctypes.byref(data) pass it. +# @return True if no error, otherwise False. +BMMesh_GetLitMode = _create_bmap_func('BMMesh_GetLitMode', [bm_void_p, bm_CKID, bm_enum_p]) +## BMMesh_SetLitMode +# @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 mode[in] Type: LibCmo::VxMath::VXMESH_LITMODE. +# @return True if no error, otherwise False. +BMMesh_SetLitMode = _create_bmap_func('BMMesh_SetLitMode', [bm_void_p, bm_CKID, bm_enum]) ## BMMesh_GetVertexCount # @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. diff --git a/bbp_ng/PyBMap/bmap_wrapper.py b/bbp_ng/PyBMap/bmap_wrapper.py index 1e3886a..6c27172 100644 --- a/bbp_ng/PyBMap/bmap_wrapper.py +++ b/bbp_ng/PyBMap/bmap_wrapper.py @@ -7,6 +7,17 @@ g_InvalidPtr: bmap.bm_void_p = bmap.bm_void_p(0) g_InvalidCKID: int = 0 g_BMapEncoding: str = "utf-8" +def python_callback(strl: bytes): + """ + The Python type callback for BMFile. + Simply add a prefix when output. + Need a convertion before passing to BMFile. + """ + # the passing value is bytes, not bmap.bm_CKSTRING. + # i think Python do a auto convertion here. + if strl is not None: + print(f'[PyBMap] {strl.decode(g_BMapEncoding)}') + class _AbstractPointer(): __mRawPointer: int @@ -398,6 +409,16 @@ class BMMaterial(BMObject): bmap.BMMaterial_SetZFunc(self._get_pointer(), self._get_ckid(), data) class BMMesh(BMObject): + + def get_lit_mode(self) -> virtools_types.VXMESH_LITMODE: + mode: bmap.bm_enum = bmap.bm_enum() + bmap.BMMesh_GetLitMode(self._get_pointer(), self._get_ckid(), ctypes.byref(mode)) + return virtools_types.VXMESH_LITMODE(mode.value) + + def set_lit_mode(self, mode: virtools_types.VXMESH_LITMODE) -> None: + mode: bmap.bm_enum = bmap.bm_enum(mode.value) + bmap.BMMesh_SetLitMode(self._get_pointer(), self._get_ckid(), mode) + def get_vertex_count(self) -> int: count: bmap.bm_CKDWORD = bmap.bm_CKDWORD() bmap.BMMesh_GetVertexCount(self._get_pointer(), self._get_ckid(), ctypes.byref(count)) @@ -569,6 +590,7 @@ class BMFileReader(_AbstractPointer): file_name: bmap.bm_CKSTRING = bmap.bm_CKSTRING(file_name_.encode(g_BMapEncoding)) temp_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(temp_folder_.encode(g_BMapEncoding)) texture_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(texture_folder_.encode(g_BMapEncoding)) + raw_callback: bmap.bm_callback = bmap.bm_callback(python_callback) encoding_count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(len(encodings_)) encodings: ctypes.Array = (bmap.bm_CKSTRING * len(encodings_))( *(strl.encode(g_BMapEncoding) for strl in encodings_) @@ -576,7 +598,8 @@ class BMFileReader(_AbstractPointer): out_file: bmap.bm_void_p = bmap.bm_void_p() # exec bmap.BMFile_Load( - file_name, temp_folder, texture_folder, encoding_count, encodings, + file_name, temp_folder, texture_folder, raw_callback, + encoding_count, encodings, ctypes.byref(out_file) ) # init self @@ -666,6 +689,7 @@ class BMFileWriter(_AbstractPointer): # create param temp_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(temp_folder_.encode(g_BMapEncoding)) texture_folder: bmap.bm_CKSTRING = bmap.bm_CKSTRING(texture_folder_.encode(g_BMapEncoding)) + raw_callback: bmap.bm_callback = bmap.bm_callback(python_callback) encoding_count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(len(encodings_)) encodings: ctypes.Array = (bmap.bm_CKSTRING * len(encodings_))( *(strl.encode(g_BMapEncoding) for strl in encodings_) @@ -673,7 +697,8 @@ class BMFileWriter(_AbstractPointer): out_file: bmap.bm_void_p = bmap.bm_void_p() # exec bmap.BMFile_Create( - temp_folder, texture_folder, encoding_count, encodings, + temp_folder, texture_folder, raw_callback, + encoding_count, encodings, ctypes.byref(out_file) ) # init self diff --git a/bbp_ng/PyBMap/virtools_types.py b/bbp_ng/PyBMap/virtools_types.py index bdff974..0b91581 100644 --- a/bbp_ng/PyBMap/virtools_types.py +++ b/bbp_ng/PyBMap/virtools_types.py @@ -304,3 +304,15 @@ class VXCMPFUNC(enum.IntEnum): VXCMP_NOTEQUAL = 6 ##< Accept if value if different than current value. VXCMP_GREATEREQUAL = 7 ##< Accept if value if greater or equal current value. VXCMP_ALWAYS = 8 ##< Always accept the test. + +class VXMESH_LITMODE(enum.IntEnum): + """! + {filename:VXMESH_LITMODE} + Summary: Mesh lighting options + + Remarks: + + The VXMESH_LITMODE is used by CKMesh::SetLitMode to specify how lighting is done. + See Also: CKMaterial,CKMesh + """ + VX_PRELITMESH = 0 ##< Lighting use color information store with vertices + VX_LITMESH = 1 ##< Lighting is done by renderer using normals and face material information. \ No newline at end of file diff --git a/bbp_ng/__init__.py b/bbp_ng/__init__.py index 01a06f4..72ad304 100644 --- a/bbp_ng/__init__.py +++ b/bbp_ng/__init__.py @@ -23,7 +23,7 @@ if "bpy" in locals(): #endregion -from . import PROP_preferences, PROP_virtools_material, PROP_virtools_texture, PROP_ballance_element, PROP_virtools_group +from . import PROP_preferences, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_ballance_element, PROP_virtools_group from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools from . import OP_UV_flatten_uv, OP_UV_rail_uv @@ -87,6 +87,7 @@ def register() -> None: PROP_preferences.register() PROP_virtools_material.register() PROP_virtools_texture.register() + PROP_virtools_mesh.register() PROP_ballance_element.register() PROP_virtools_group.register() @@ -129,6 +130,7 @@ def unregister() -> None: PROP_virtools_group.unregister() PROP_ballance_element.unregister() + PROP_virtools_mesh.unregister() PROP_virtools_texture.unregister() PROP_virtools_material.unregister() PROP_preferences.unregister()