From 84b3ace13d7976807a4e8fb8856e14e671ef7fe4 Mon Sep 17 00:00:00 2001 From: yyc12345 Date: Thu, 30 Nov 2023 22:38:53 +0800 Subject: [PATCH] start exporing virtools file --- bbp_ng/OP_EXPORT_virtools.py | 147 +++++++++++++++++++++++++++++++++- bbp_ng/OP_IMPORT_virtools.py | 4 +- bbp_ng/PROP_virtools_group.py | 8 +- bbp_ng/PyBMap/bmap_wrapper.py | 16 ++-- 4 files changed, 159 insertions(+), 16 deletions(-) diff --git a/bbp_ng/OP_EXPORT_virtools.py b/bbp_ng/OP_EXPORT_virtools.py index 130675c..c22ecc9 100644 --- a/bbp_ng/OP_EXPORT_virtools.py +++ b/bbp_ng/OP_EXPORT_virtools.py @@ -1,8 +1,9 @@ import bpy from bpy_extras.wm_utils.progress_report import ProgressReport import tempfile, os, typing -from . import PROP_preferences, PROP_ptrprop_resolver, UTIL_ioport_shared -from . import UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_icons_manager +from . import PROP_preferences, UTIL_ioport_shared +from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_icons_manager +from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh from .PyBMap import bmap_wrapper as bmap class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtoolsFile, UTIL_ioport_shared.ExportParams, UTIL_ioport_shared.VirtoolsParams): @@ -11,6 +12,13 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool bl_label = "Export Virtools File" bl_options = {'PRESET'} + compress_level: bpy.props.IntProperty( + name = "Compress Level", + description = "The ZLib compress level used by Virtools Engine when saving composition.", + min = 1, max = 9, + default = 5, + ) + @classmethod def poll(self, context): return ( @@ -33,6 +41,7 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool _export_virtools( self.general_get_filename(), self.general_get_vt_encodings(), + self.compress_level, objls ) @@ -46,8 +55,9 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool layout.separator() layout.label(text = 'Virtools Params') self.draw_virtools_params(layout) + layout.prop(self, 'compress_level') -def _export_virtools(file_name_: str, encodings_: tuple[str], export_objects: tuple[bpy.types.Object]) -> None: +def _export_virtools(file_name_: str, encodings_: tuple[str], compress_level_: int, export_objects: tuple[bpy.types.Object, ...]) -> None: # create temp folder with tempfile.TemporaryDirectory() as vt_temp_folder: print(f'Virtools Engine Temp: {vt_temp_folder}') @@ -60,8 +70,137 @@ def _export_virtools(file_name_: str, encodings_: tuple[str], export_objects: tu # prepare progress reporter with ProgressReport(wm = bpy.context.window_manager) as progress: - pass + # prepare 3dobject + obj3d_crets: tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...] = _prepare_virtools_3dobjects( + writer, progress, export_objects) + # export group and 3dobject by prepared 3dobject + _export_virtools_groups(writer, progress, obj3d_crets) + mesh_crets: tuple[tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh], ...] = _export_virtools_3dobjects( + writer, progress, obj3d_crets) + + # save document + _save_virtools_document( + writer, progress, file_name_, compress_level_) + +def _prepare_virtools_3dobjects( + writer: bmap.BMFileWriter, + progress: ProgressReport, + export_objects: tuple[bpy.types.Object] + ) -> tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...]: + # this function only create equvalent entries in virtools engine and do not export anything + # because _export_virtools_3dobjects() and _export_virtools_groups() are need use the return value of this function + + # create 3dobject hashset and result + obj3d_crets: list[tuple[bpy.types.Object, bmap.BM3dObject]] = [] + obj3d_cret_set: set[bpy.types.Object] = set() + # start saving + progress.enter_substeps(len(export_objects), "Creating 3dObjects") + + for obj3d in export_objects: + if obj3d not in obj3d_cret_set: + # add into set + obj3d_cret_set.add(obj3d) + # create virtools instance + vtobj3d: bmap.BM3dObject = writer.create_3dobject() + # add into result list + obj3d_crets.append((obj3d, vtobj3d)) + + # step progress no matter whether create new one + progress.step() + + # leave progress and return + progress.leave_substeps() + return tuple(obj3d_crets) + +def _export_virtools_groups( + writer: bmap.BMFileWriter, + progress: ProgressReport, + obj3d_crets: tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...] + ) -> None: + # create virtools group + group_cret_map: dict[str, bmap.BMGroup] = {} + # start saving + progress.enter_substeps(len(obj3d_crets), "Saving Groups") + + for obj3d, vtobj3d in obj3d_crets: + # open group visitor + with PROP_virtools_group.VirtoolsGroupsHelper(obj3d) as gp_visitor: + for gp_name in gp_visitor.iterate_groups(): + # get group or create new group + vtgroup: bmap.BMGroup | None = group_cret_map.get(gp_name, None) + if vtgroup is None: + vtgroup = writer.create_group() + vtgroup.set_name(gp_name) + group_cret_map[gp_name] = vtgroup + + # group this object + vtgroup.add_object(vtobj3d) + + # leave group visitor and step + progress.step() + + # leave progress and return + progress.leave_substeps() + +def _export_virtools_3dobjects( + writer: bmap.BMFileWriter, + progress: ProgressReport, + obj3d_crets: tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...] + ) -> tuple[tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh], ...]: + # create virtools mesh + mesh_crets: list[tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh]] = [] + mesh_cret_map: dict[bpy.types.Mesh, bmap.BMMesh] = {} + # start saving + progress.enter_substeps(len(obj3d_crets), "Saving 3dObjects") + + for obj3d, vtobj3d in obj3d_crets: + # set name + vtobj3d.set_name(obj3d.name) + + # check mesh + mesh: bpy.types.Mesh | None = obj3d.data + if mesh is not None: + # get existing vt mesh or create new one + vtmesh: bmap.BMMesh | None = mesh_cret_map.get(mesh, None) + if vtmesh is None: + vtmesh = writer.create_mesh() + mesh_crets.append((obj3d, mesh, vtmesh)) + mesh_cret_map[mesh] = vtmesh + + # assign mesh + vtobj3d.set_current_mesh(vtmesh) + else: + vtobj3d.set_current_mesh(None) + + # set world matrix + vtmat: UTIL_virtools_types.VxMatrix = UTIL_virtools_types.VxMatrix() + UTIL_virtools_types.vxmatrix_from_blender(vtmat, obj3d.matrix_world) + UTIL_virtools_types.vxmatrix_conv_co(vtmat) + vtobj3d.set_world_matrix(vtmat) + + # set visibility + vtobj3d.set_visibility(not obj3d.hide_get()) + + # step + progress.step() + + # leave progress and return + progress.leave_substeps() + + +def _save_virtools_document( + writer: bmap.BMFileWriter, + progress: ProgressReport, + file_name: str, + compress_level: int + ) -> None: + + progress.enter_substeps(1, "Saving Document") + writer.save(file_name, compress_level) + progress.step() + progress.leave_substeps() + def register() -> None: bpy.utils.register_class(BBP_OT_export_virtools) diff --git a/bbp_ng/OP_IMPORT_virtools.py b/bbp_ng/OP_IMPORT_virtools.py index 982f8d2..356e3bd 100644 --- a/bbp_ng/OP_IMPORT_virtools.py +++ b/bbp_ng/OP_IMPORT_virtools.py @@ -292,7 +292,7 @@ def _import_virtools_3dobjects( blender_collection.objects.link(obj3d) # set world matrix - vtmat = vt3dobj.get_world_matrix() + vtmat: UTIL_virtools_types.VxMatrix = vt3dobj.get_world_matrix() UTIL_virtools_types.vxmatrix_conv_co(vtmat) obj3d.matrix_world = UTIL_virtools_types.vxmatrix_to_blender(vtmat) @@ -349,7 +349,7 @@ def _import_virtools_groups( # assign group with PROP_virtools_group.VirtoolsGroupsHelper(assoc_obj) as gpoper: - gpoper.clear_all_groups() + gpoper.clear_groups() gpoper.add_groups(mapv) progress.leave_substeps() diff --git a/bbp_ng/PROP_virtools_group.py b/bbp_ng/PROP_virtools_group.py index 92eda73..ca236d8 100644 --- a/bbp_ng/PROP_virtools_group.py +++ b/bbp_ng/PROP_virtools_group.py @@ -109,7 +109,11 @@ class VirtoolsGroupsHelper(): return True return False - def clear_all_groups(self): + def iterate_groups(self) -> typing.Iterator[str]: + self.__check_valid() + return iter(self.__mGroupsSet) + + def clear_groups(self): self.__check_valid() self.__mNoChange = False self.__mGroupsSet.clear() @@ -342,7 +346,7 @@ class BBP_OT_clear_virtools_groups(bpy.types.Operator): def execute(self, context): with VirtoolsGroupsHelper(context.object) as hlp: - hlp.clear_all_groups() + hlp.clear_groups() return {'FINISHED'} class BBP_PT_virtools_groups(bpy.types.Panel): diff --git a/bbp_ng/PyBMap/bmap_wrapper.py b/bbp_ng/PyBMap/bmap_wrapper.py index 6c27172..8ac79d9 100644 --- a/bbp_ng/PyBMap/bmap_wrapper.py +++ b/bbp_ng/PyBMap/bmap_wrapper.py @@ -279,7 +279,7 @@ class BMMaterial(BMObject): def set_texture(self, tex_: BMTexture | None) -> None: objid: bmap.bm_CKID = bmap.bm_CKID(g_InvalidCKID) if tex_ is not None: - objid.value = tex_._get_ckid() + objid = tex_._get_ckid() bmap.BMMaterial_SetTexture(self._get_pointer(), self._get_ckid(), objid) def get_texture_border_color(self) -> virtools_types.VxColor: @@ -521,7 +521,7 @@ class BMMesh(BMObject): if mtlobj is None: mtlid.value = g_InvalidCKID else: - mtlid.value = mtlobj._get_ckid() + mtlid = mtlobj._get_ckid() # set bmap.BMMesh_SetMaterialSlot(self._get_pointer(), self._get_ckid(), idx, mtlid) @@ -551,7 +551,7 @@ class BM3dObject(BMObject): def set_current_mesh(self, mesh: BMMesh | None) -> None: ckid: bmap.bm_CKID = bmap.bm_CKID(g_InvalidCKID) if mesh is not None: - ckid.value = mesh._get_ckid() + ckid = mesh._get_ckid() bmap.BM3dObject_SetCurrentMesh(self._get_pointer(), self._get_ckid(), ckid) def get_visibility(self) -> bool: @@ -733,31 +733,31 @@ class BMFileWriter(_AbstractPointer): return class_type(self._get_pointer(), retid) def create_texture(self) -> BMTexture: - self.__create_ckobject( + return self.__create_ckobject( BMTexture, bmap.BMFile_CreateTexture ) def create_material(self) -> BMMaterial: - self.__create_ckobject( + return self.__create_ckobject( BMMaterial, bmap.BMFile_CreateMaterial ) def create_mesh(self) -> BMMesh: - self.__create_ckobject( + return self.__create_ckobject( BMMesh, bmap.BMFile_CreateMesh ) def create_3dobject(self) -> BM3dObject: - self.__create_ckobject( + return self.__create_ckobject( BM3dObject, bmap.BMFile_Create3dObject ) def create_group(self) -> BMGroup: - self.__create_ckobject( + return self.__create_ckobject( BMGroup, bmap.BMFile_CreateGroup )