update plugin.
- sync PyBMap work. use different library name in different OS. - add BMap encoding default value according to different OS (Windows and non-Windows) because non-Windows OS, we use libiconv as encoding converter. - move all pointer properties to a single module and give corresponding visitor. - add shared importer exporter parameters module thus bmfile import/export also can ref it.
This commit is contained in:
parent
59a1275f68
commit
1a2dd08092
@ -1,8 +1,11 @@
|
||||
import bpy
|
||||
from . import PROP_preferences, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh
|
||||
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 .PyBMap import bmap_wrapper as bmap
|
||||
|
||||
class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtoolsFile):
|
||||
class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtoolsFile, UTIL_ioport_shared.ExportParams, UTIL_ioport_shared.VirtoolsParams):
|
||||
"""Export Virtools File"""
|
||||
bl_idname = "bbp.export_virtools"
|
||||
bl_label = "Export Virtools File"
|
||||
@ -15,12 +18,50 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
|
||||
and bmap.is_bmap_available())
|
||||
|
||||
def execute(self, context):
|
||||
UTIL_functions.message_box((self.general_get_filename(), ), 'Export Virtools File Path', 'INFO')
|
||||
# check selecting first
|
||||
objls: tuple[bpy.types.Object] | None = self.general_get_export_objects()
|
||||
if objls is None:
|
||||
UTIL_functions.message_box(
|
||||
('No selected target!', ),
|
||||
'Lost Parameters',
|
||||
UTIL_icons_manager.BlenderPresetIcons.Error.value
|
||||
)
|
||||
return {'CANCELLED'}
|
||||
|
||||
# start exporting
|
||||
with UTIL_ioport_shared.ExportEditModeBackup() as editmode_guard:
|
||||
_export_virtools(
|
||||
self.general_get_filename(),
|
||||
self.general_get_vt_encodings(),
|
||||
objls
|
||||
)
|
||||
|
||||
self.report({'INFO'}, "Virtools File Exporting Finished.")
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
pass
|
||||
layout = self.layout
|
||||
layout.label(text = 'Export Target')
|
||||
self.draw_export_params(layout)
|
||||
layout.separator()
|
||||
layout.label(text = 'Virtools Params')
|
||||
self.draw_virtools_params(layout)
|
||||
|
||||
def _export_virtools(file_name_: str, encodings_: tuple[str], 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}')
|
||||
|
||||
# create virtools reader context
|
||||
with bmap.BMFileWriter(
|
||||
vt_temp_folder,
|
||||
PROP_preferences.get_raw_preferences().mBallanceTextureFolder,
|
||||
encodings_) as writer:
|
||||
|
||||
# prepare progress reporter
|
||||
with ProgressReport(wm = bpy.context.window_manager) as progress:
|
||||
pass
|
||||
|
||||
|
||||
def register() -> None:
|
||||
bpy.utils.register_class(BBP_OT_export_virtools)
|
||||
|
@ -1,23 +1,17 @@
|
||||
import bpy
|
||||
from bpy_extras.wm_utils.progress_report import ProgressReport
|
||||
import tempfile, os, typing
|
||||
from . import PROP_preferences
|
||||
from . import PROP_preferences, UTIL_ioport_shared
|
||||
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, PROP_virtools_mesh
|
||||
from . import 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):
|
||||
class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile, UTIL_ioport_shared.ImportParams, UTIL_ioport_shared.VirtoolsParams):
|
||||
"""Import Virtools File"""
|
||||
bl_idname = "bbp.import_virtools"
|
||||
bl_label = "Import Virtools File"
|
||||
bl_options = {'PRESET', 'UNDO'}
|
||||
|
||||
vt_encodings: bpy.props.StringProperty(
|
||||
name = "Encodings",
|
||||
description = "The encoding list used by Virtools engine to resolve object name. Use `;` to split multiple encodings",
|
||||
default = "1252"
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def poll(self, context):
|
||||
return (
|
||||
@ -25,15 +19,21 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool
|
||||
and bmap.is_bmap_available())
|
||||
|
||||
def execute(self, context):
|
||||
# get encoding, split it by `;` and strip blank chars.
|
||||
encodings: str = self.vt_encodings
|
||||
_import_virtools(
|
||||
self.general_get_filename(),
|
||||
tuple(map(lambda x: x.strip(), encodings.split(';')))
|
||||
self.general_get_vt_encodings()
|
||||
)
|
||||
self.report({'INFO'}, "Virtools File Importing Finished.")
|
||||
return {'FINISHED'}
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
layout.label(text = 'Conflict Options')
|
||||
self.draw_import_params(layout)
|
||||
layout.separator()
|
||||
layout.label(text = 'Virtools Params')
|
||||
self.draw_virtools_params(layout)
|
||||
|
||||
def _import_virtools(file_name_: str, encodings_: tuple[str]) -> None:
|
||||
# create temp folder
|
||||
with tempfile.TemporaryDirectory() as vt_temp_folder:
|
||||
|
@ -1,27 +1,8 @@
|
||||
import bpy, bmesh, mathutils
|
||||
import typing
|
||||
from . import PROP_ptrprop_resolver
|
||||
from . import UTIL_virtools_types, UTIL_icons_manager, UTIL_functions
|
||||
|
||||
#region Material Pointer Property Resolver
|
||||
|
||||
class BBP_PG_patch_rail_uv(bpy.types.PropertyGroup):
|
||||
rail_mtl: bpy.props.PointerProperty(
|
||||
name = "Material",
|
||||
description = "The material used for rail",
|
||||
type = bpy.types.Material,
|
||||
)
|
||||
|
||||
def get_rail_uv_patch() -> BBP_PG_patch_rail_uv:
|
||||
return bpy.context.scene.bbp_patch_rail_uv
|
||||
|
||||
def get_raw_rail_uv_patch() -> bpy.types.Material:
|
||||
return get_rail_uv_patch().rail_mtl
|
||||
|
||||
def draw_rail_uv_patch(layout: bpy.types.UILayout) -> None:
|
||||
layout.prop(get_rail_uv_patch(), 'rail_mtl')
|
||||
|
||||
#endregion
|
||||
|
||||
class BBP_OT_rail_uv(bpy.types.Operator):
|
||||
"""Create UV for Rail as Ballance Showen (TT_ReflectionMapping)"""
|
||||
bl_idname = "bbp.rail_uv"
|
||||
@ -38,7 +19,7 @@ class BBP_OT_rail_uv(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
# check material
|
||||
mtl: bpy.types.Material = get_raw_rail_uv_patch()
|
||||
mtl: bpy.types.Material = PROP_ptrprop_resolver.get_rail_uv_material()
|
||||
if mtl is None:
|
||||
UTIL_functions.message_box(
|
||||
("No specific material", ),
|
||||
@ -53,7 +34,7 @@ class BBP_OT_rail_uv(bpy.types.Operator):
|
||||
|
||||
def draw(self, context):
|
||||
layout: bpy.types.UILayout = self.layout
|
||||
draw_rail_uv_patch(layout)
|
||||
PROP_ptrprop_resolver.draw_rail_uv_material(layout)
|
||||
|
||||
#region Real Worker Functions
|
||||
|
||||
@ -200,14 +181,8 @@ def _create_rail_uv(meshes: typing.Iterable[bpy.types.Mesh], mtl: bpy.types.Mate
|
||||
#endregion
|
||||
|
||||
def register() -> None:
|
||||
# register patch first
|
||||
bpy.utils.register_class(BBP_PG_patch_rail_uv)
|
||||
bpy.types.Scene.bbp_patch_rail_uv = bpy.props.PointerProperty(type = BBP_PG_patch_rail_uv)
|
||||
|
||||
bpy.utils.register_class(BBP_OT_rail_uv)
|
||||
|
||||
def unregister() -> None:
|
||||
del bpy.types.Scene.bbp_patch_rail_uv
|
||||
|
||||
bpy.utils.unregister_class(BBP_OT_rail_uv)
|
||||
|
||||
|
51
bbp_ng/PROP_ptrprop_resolver.py
Normal file
51
bbp_ng/PROP_ptrprop_resolver.py
Normal file
@ -0,0 +1,51 @@
|
||||
import bpy
|
||||
|
||||
## Intent
|
||||
# Operator is not allowed to register Pointer Properties.
|
||||
# The solution is register pointer properties in Scene and reference it when drawing operator window.
|
||||
# This module contains all pointer properties used by other operators.
|
||||
|
||||
class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
|
||||
rail_uv_material: bpy.props.PointerProperty(
|
||||
name = "Material",
|
||||
description = "The material used for rail",
|
||||
type = bpy.types.Material,
|
||||
)
|
||||
|
||||
export_collection: bpy.props.PointerProperty(
|
||||
type = bpy.types.Collection,
|
||||
name = "Collection",
|
||||
description = "The collection exported. Nested collections allowed."
|
||||
)
|
||||
|
||||
export_object: bpy.props.PointerProperty(
|
||||
type = bpy.types.Object,
|
||||
name = "Object",
|
||||
description = "The object exported"
|
||||
)
|
||||
|
||||
def get_ptrprop_resolver() -> BBP_PG_ptrprop_resolver:
|
||||
return bpy.context.scene.bbp_ptrprop_resolver
|
||||
|
||||
def get_rail_uv_material() -> bpy.types.Material:
|
||||
return get_ptrprop_resolver().rail_uv_material
|
||||
def draw_rail_uv_material(layout: bpy.types.UILayout) -> None:
|
||||
layout.prop(get_ptrprop_resolver(), 'rail_uv_material')
|
||||
|
||||
def get_export_collection() -> bpy.types.Collection:
|
||||
return get_ptrprop_resolver().export_collection
|
||||
def draw_export_collection(layout: bpy.types.UILayout) -> None:
|
||||
layout.prop(get_ptrprop_resolver(), 'export_collection')
|
||||
|
||||
def get_export_object() -> bpy.types.Object:
|
||||
return get_ptrprop_resolver().export_object
|
||||
def draw_export_object(layout: bpy.types.UILayout) -> None:
|
||||
layout.prop(get_ptrprop_resolver(), 'export_object')
|
||||
|
||||
def register():
|
||||
bpy.utils.register_class(BBP_PG_ptrprop_resolver)
|
||||
bpy.types.Scene.bbp_ptrprop_resolver = bpy.props.PointerProperty(type = BBP_PG_ptrprop_resolver)
|
||||
|
||||
def unregister():
|
||||
del bpy.types.Scene.bbp_ptrprop_resolver
|
||||
bpy.utils.unregister_class(BBP_PG_ptrprop_resolver)
|
@ -1,4 +1,4 @@
|
||||
import ctypes, os
|
||||
import ctypes, os, sys
|
||||
|
||||
#region Type Defines
|
||||
|
||||
@ -67,10 +67,21 @@ bm_VxMatrix_p = ctypes.POINTER(bm_VxMatrix)
|
||||
|
||||
#region BMap Loader
|
||||
|
||||
_g_BMapLibName: str
|
||||
|
||||
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
|
||||
_g_BMapLibName = "BMap.dll"
|
||||
elif sys.platform.startswith('linux') or sys.platform.startswith('freebsd'):
|
||||
_g_BMapLibName = "BMap.so"
|
||||
elif sys.platform.startswith('darwin'):
|
||||
_g_BMapLibName = "BMap.dylib"
|
||||
else:
|
||||
_g_BMapLibName = "BMap.bin"
|
||||
|
||||
_g_BMapModule: ctypes.CDLL = None
|
||||
try:
|
||||
_g_BMapModule = ctypes.cdll.LoadLibrary(
|
||||
os.path.join(os.path.dirname(__file__), "BMap.dll")
|
||||
os.path.join(os.path.dirname(__file__), _g_BMapLibName)
|
||||
)
|
||||
except:
|
||||
_g_BMapModule = None
|
||||
|
@ -1,5 +1,5 @@
|
||||
import bpy
|
||||
import math, typing, enum
|
||||
import math, typing, enum, sys
|
||||
|
||||
class BBPException(Exception):
|
||||
"""
|
||||
@ -84,5 +84,18 @@ def generate_vt_enums_for_bl_enumprop(enum_data: type[InheritingIntEnum_t], anno
|
||||
(str(member.value), get_display_name(member.value, member.name), get_description(member.value, ""), "", member.value) for member in enum_data
|
||||
)
|
||||
|
||||
#endregion
|
||||
|
||||
#region Default Encoding of BMap
|
||||
|
||||
# Use semicolon split each encodings. Support Western European and Simplified Chinese in default.
|
||||
|
||||
g_PyBMapDefaultEncoding: str
|
||||
if sys.platform.startswith('win32') or sys.platform.startswith('cygwin'):
|
||||
# See: https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers
|
||||
g_PyBMapDefaultEncoding = "1252;936"
|
||||
else:
|
||||
# See: https://www.gnu.org/software/libiconv/
|
||||
g_PyBMapDefaultEncoding = "CP1252;CP936"
|
||||
|
||||
#endregion
|
||||
|
130
bbp_ng/UTIL_ioport_shared.py
Normal file
130
bbp_ng/UTIL_ioport_shared.py
Normal file
@ -0,0 +1,130 @@
|
||||
import bpy
|
||||
import enum
|
||||
from . import UTIL_functions
|
||||
from . import PROP_ptrprop_resolver
|
||||
|
||||
## Intent
|
||||
# Some importer or exporter may share same properties.
|
||||
# So we create some shared class and user just need inherit them
|
||||
# and call general getter to get user selected data.
|
||||
# Also provide draw function thus caller do not need draw the params themselves.
|
||||
|
||||
class ImportParams():
|
||||
texture_conflict_strategy: bpy.props.EnumProperty(
|
||||
name = "Texture name conflict",
|
||||
items = (
|
||||
('NEW', "New Instance", "Create a new instance"),
|
||||
('CURRENT', "Use Current", "Use current one"),
|
||||
),
|
||||
description = "Define how to process texture name conflict",
|
||||
default = 'CURRENT',
|
||||
)
|
||||
|
||||
material_conflict_strategy: bpy.props.EnumProperty(
|
||||
name = "Material name conflict",
|
||||
items = (
|
||||
('RENAME', "Rename", "Rename the new one"),
|
||||
('CURRENT', "Use Current", "Use current one"),
|
||||
),
|
||||
description = "Define how to process material name conflict",
|
||||
default = 'RENAME',
|
||||
)
|
||||
|
||||
mesh_conflict_strategy: bpy.props.EnumProperty(
|
||||
name = "Mesh name conflict",
|
||||
items = (
|
||||
('RENAME', "Rename", "Rename the new one"),
|
||||
('CURRENT', "Use Current", "Use current one"),
|
||||
),
|
||||
description = "Define how to process mesh name conflict",
|
||||
default = 'RENAME',
|
||||
)
|
||||
|
||||
object_conflict_strategy: bpy.props.EnumProperty(
|
||||
name = "Object name conflict",
|
||||
items = (
|
||||
('RENAME', "Rename", "Rename the new one"),
|
||||
('CURRENT', "Use Current", "Use current one"),
|
||||
),
|
||||
description = "Define how to process object name conflict",
|
||||
default = 'RENAME',
|
||||
)
|
||||
|
||||
def draw_import_params(self, layout: bpy.types.UILayout) -> None:
|
||||
layout.prop(self, 'object_conflict_strategy')
|
||||
layout.prop(self, 'mesh_conflict_strategy')
|
||||
layout.prop(self, 'material_conflict_strategy')
|
||||
layout.prop(self, 'texture_conflict_strategy')
|
||||
|
||||
class ExportParams():
|
||||
export_mode: bpy.props.EnumProperty(
|
||||
name = "Export Mode",
|
||||
items = (
|
||||
('COLLECTION', "Collection", "Export a collection"),
|
||||
('OBJECT', "Object", "Export an object"),
|
||||
),
|
||||
)
|
||||
|
||||
def draw_export_params(self, layout: bpy.types.UILayout) -> None:
|
||||
# draw switch
|
||||
layout.prop(self, "export_mode", expand = True)
|
||||
# draw picker
|
||||
if self.export_mode == 'COLLECTION':
|
||||
PROP_ptrprop_resolver.draw_export_collection(layout)
|
||||
elif self.export_mode == 'OBJECT':
|
||||
PROP_ptrprop_resolver.draw_export_object(layout)
|
||||
|
||||
def general_get_export_objects(self) -> tuple[bpy.types.Object] | None:
|
||||
"""
|
||||
Return resolved exported objects or None if no selection.
|
||||
"""
|
||||
if self.export_mode == 'COLLECTION':
|
||||
col: bpy.types.Collection = PROP_ptrprop_resolver.get_export_collection()
|
||||
if col is None: return None
|
||||
else:
|
||||
return tuple(col.all_objects)
|
||||
else:
|
||||
obj: bpy.types.Object = PROP_ptrprop_resolver.get_export_object()
|
||||
if obj is None: return None
|
||||
else: return (obj, )
|
||||
|
||||
class VirtoolsParams():
|
||||
vt_encodings: bpy.props.StringProperty(
|
||||
name = "Encodings",
|
||||
description = "The encoding list used by Virtools engine to resolve object name. Use `;` to split multiple encodings",
|
||||
default = UTIL_functions.g_PyBMapDefaultEncoding
|
||||
)
|
||||
|
||||
def draw_virtools_params(self, layout: bpy.types.UILayout) -> None:
|
||||
layout.prop(self, 'vt_encodings')
|
||||
|
||||
def general_get_vt_encodings(self) -> tuple[str]:
|
||||
# get encoding, split it by `;` and strip blank chars.
|
||||
encodings: str = self.vt_encodings
|
||||
return tuple(map(lambda x: x.strip(), encodings.split(';')))
|
||||
|
||||
class ExportEditModeBackup():
|
||||
"""
|
||||
The class which save Edit Mode when exporting and restore it after exporting.
|
||||
Because edit mode is not allowed when exporting.
|
||||
Support `with` statement.
|
||||
"""
|
||||
mInEditMode: bool
|
||||
|
||||
def __init__(self):
|
||||
if bpy.context.object and bpy.context.object.mode == "EDIT":
|
||||
# set and toggle it. otherwise exporting will failed.
|
||||
self.mInEditMode = True
|
||||
bpy.ops.object.editmode_toggle()
|
||||
else:
|
||||
self.mInEditMode = False
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
if self.mInEditMode:
|
||||
bpy.ops.object.editmode_toggle()
|
||||
self.mInEditMode = False
|
||||
|
||||
|
@ -23,7 +23,7 @@ if "bpy" in locals():
|
||||
|
||||
#endregion
|
||||
|
||||
from . import PROP_preferences, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_ballance_element, PROP_virtools_group
|
||||
from . import PROP_preferences, PROP_ptrprop_resolver, 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
|
||||
|
||||
@ -85,6 +85,8 @@ g_BldMenus: tuple[MenuEntry, ...] = (
|
||||
def register() -> None:
|
||||
# register module
|
||||
PROP_preferences.register()
|
||||
PROP_ptrprop_resolver.register()
|
||||
|
||||
PROP_virtools_material.register()
|
||||
PROP_virtools_texture.register()
|
||||
PROP_virtools_mesh.register()
|
||||
@ -133,6 +135,8 @@ def unregister() -> None:
|
||||
PROP_virtools_mesh.unregister()
|
||||
PROP_virtools_texture.unregister()
|
||||
PROP_virtools_material.unregister()
|
||||
|
||||
PROP_ptrprop_resolver.unregister()
|
||||
PROP_preferences.unregister()
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
Loading…
Reference in New Issue
Block a user