update virtools export

This commit is contained in:
yyc12345 2023-12-01 23:27:53 +08:00
parent 84b3ace13d
commit 52452a96d5
3 changed files with 172 additions and 21 deletions

View File

@ -57,6 +57,11 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
self.draw_virtools_params(layout) self.draw_virtools_params(layout)
layout.prop(self, 'compress_level') layout.prop(self, 'compress_level')
_TObj3dPair = tuple[bpy.types.Object, bmap.BM3dObject]
_TMeshPair = tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh]
_TMaterialPair = tuple[bpy.types.Material, bmap.BMMaterial]
_TTexturePair = tuple[bpy.types.Image, bmap.BMTexture]
def _export_virtools(file_name_: str, encodings_: tuple[str], compress_level_: int, 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 # create temp folder
with tempfile.TemporaryDirectory() as vt_temp_folder: with tempfile.TemporaryDirectory() as vt_temp_folder:
@ -71,12 +76,18 @@ def _export_virtools(file_name_: str, encodings_: tuple[str], compress_level_: i
# prepare progress reporter # prepare progress reporter
with ProgressReport(wm = bpy.context.window_manager) as progress: with ProgressReport(wm = bpy.context.window_manager) as progress:
# prepare 3dobject # prepare 3dobject
obj3d_crets: tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...] = _prepare_virtools_3dobjects( obj3d_crets: tuple[_TObj3dPair, ...] = _prepare_virtools_3dobjects(
writer, progress, export_objects) writer, progress, export_objects)
# export group and 3dobject by prepared 3dobject # export group and 3dobject by prepared 3dobject
_export_virtools_groups(writer, progress, obj3d_crets) _export_virtools_groups(writer, progress, obj3d_crets)
mesh_crets: tuple[tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh], ...] = _export_virtools_3dobjects( mesh_crets: tuple[_TMeshPair, ...] = _export_virtools_3dobjects(
writer, progress, obj3d_crets) writer, progress, obj3d_crets)
# export mesh
material_crets: tuple[_TMaterialPair, ...] = _export_virtools_meshes(
writer, progress, mesh_crets)
# export material
texture_crets: tuple[_TTexturePair, ...] = _export_virtools_materials(
writer, progress, material_crets)
# save document # save document
@ -87,12 +98,12 @@ def _prepare_virtools_3dobjects(
writer: bmap.BMFileWriter, writer: bmap.BMFileWriter,
progress: ProgressReport, progress: ProgressReport,
export_objects: tuple[bpy.types.Object] export_objects: tuple[bpy.types.Object]
) -> tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...]: ) -> tuple[_TObj3dPair, ...]:
# this function only create equvalent entries in virtools engine and do not export anything # 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 # because _export_virtools_3dobjects() and _export_virtools_groups() are need use the return value of this function
# create 3dobject hashset and result # create 3dobject hashset and result
obj3d_crets: list[tuple[bpy.types.Object, bmap.BM3dObject]] = [] obj3d_crets: list[_TObj3dPair] = []
obj3d_cret_set: set[bpy.types.Object] = set() obj3d_cret_set: set[bpy.types.Object] = set()
# start saving # start saving
progress.enter_substeps(len(export_objects), "Creating 3dObjects") progress.enter_substeps(len(export_objects), "Creating 3dObjects")
@ -116,7 +127,7 @@ def _prepare_virtools_3dobjects(
def _export_virtools_groups( def _export_virtools_groups(
writer: bmap.BMFileWriter, writer: bmap.BMFileWriter,
progress: ProgressReport, progress: ProgressReport,
obj3d_crets: tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...] obj3d_crets: tuple[_TObj3dPair, ...]
) -> None: ) -> None:
# create virtools group # create virtools group
group_cret_map: dict[str, bmap.BMGroup] = {} group_cret_map: dict[str, bmap.BMGroup] = {}
@ -146,10 +157,10 @@ def _export_virtools_groups(
def _export_virtools_3dobjects( def _export_virtools_3dobjects(
writer: bmap.BMFileWriter, writer: bmap.BMFileWriter,
progress: ProgressReport, progress: ProgressReport,
obj3d_crets: tuple[tuple[bpy.types.Object, bmap.BM3dObject], ...] obj3d_crets: tuple[_TObj3dPair, ...]
) -> tuple[tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh], ...]: ) -> tuple[_TMeshPair, ...]:
# create virtools mesh # create virtools mesh
mesh_crets: list[tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh]] = [] mesh_crets: list[_TMeshPair] = []
mesh_cret_map: dict[bpy.types.Mesh, bmap.BMMesh] = {} mesh_cret_map: dict[bpy.types.Mesh, bmap.BMMesh] = {}
# start saving # start saving
progress.enter_substeps(len(obj3d_crets), "Saving 3dObjects") progress.enter_substeps(len(obj3d_crets), "Saving 3dObjects")
@ -187,7 +198,143 @@ def _export_virtools_3dobjects(
# leave progress and return # leave progress and return
progress.leave_substeps() progress.leave_substeps()
return tuple(mesh_crets)
def _export_virtools_meshes(
writer: bmap.BMFileWriter,
progress: ProgressReport,
mesh_crets: tuple[_TMeshPair, ...]
) -> tuple[_TMaterialPair, ...]:
# create virtools mesh
material_crets: list[_TMaterialPair] = []
material_cret_map: dict[bpy.types.Material, bmap.BMMaterial] = {}
# start saving
progress.enter_substeps(len(mesh_crets), "Saving Meshes")
# iterate meshes
for obj3d, mesh, vtmesh in mesh_crets:
# we need use temporary mesh function to visit triangulated meshes
# so we ignore mesh factor and use obj3d to create temp mesh to get data
# open temp mesh helper
with UTIL_blender_mesh.TemporaryMesh(obj3d) as tempmesh:
# sync mesh name, lit mode
vtmesh.set_name(mesh.name)
mesh_settings: PROP_virtools_mesh.RawVirtoolsMesh = PROP_virtools_mesh.get_raw_virtools_mesh(mesh)
vtmesh.set_lit_mode(mesh_settings.mLitMode)
# sync mesh main data
# open mesh visitor
with UTIL_blender_mesh.MeshReader(tempmesh.get_temp_mesh()) as mesh_visitor:
# construct data provider
def pos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
for v in mesh_visitor.get_vertex_position():
UTIL_virtools_types.vxvector3_conv_co(v)
yield v
def nml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
for v in mesh_visitor.get_vertex_normal():
UTIL_virtools_types.vxvector3_conv_co(v)
yield v
def uv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]:
for v in mesh_visitor.get_vertex_uv():
UTIL_virtools_types.vxvector2_conv_co(v)
yield v
# construct mtl slot
def mtl_iterator() -> typing.Iterator[bmap.BMMaterial | None]:
for mtl in mesh_visitor.get_material_slot():
if mtl is None: yield None
else:
# get existing one or create new one
vtmaterial: bmap.BMMaterial | None = material_cret_map.get(mtl, None)
if vtmaterial is None:
vtmaterial = writer.create_material()
material_crets.append((mtl, vtmaterial))
material_cret_map[mtl] = vtmaterial
# yield data
yield vtmaterial
def face_idx_iterator(idx_type: int) -> typing.Iterator[UTIL_virtools_types.CKFaceIndices]:
data: UTIL_virtools_types.CKFaceIndices = UTIL_virtools_types.CKFaceIndices()
for fidx in mesh_visitor.get_face():
# swap indices
fidx.conv_co()
# set data by specific index
match(idx_type):
case 0: data.i1, data.i2, data.i3 = fidx.mIndices[0].mPosIdx, fidx.mIndices[1].mPosIdx, fidx.mIndices[2].mPosIdx
case 1: data.i1, data.i2, data.i3 = fidx.mIndices[0].mNmlIdx, fidx.mIndices[1].mNmlIdx, fidx.mIndices[2].mNmlIdx
case 2: data.i1, data.i2, data.i3 = fidx.mIndices[0].mUvIdx, fidx.mIndices[1].mUvIdx, fidx.mIndices[2].mUvIdx
case _: raise UTIL_functions.BBPException('invalid index type.')
# yield data
yield data
def face_mtl_iterator() -> typing.Iterator[int]:
for fidx in mesh_visitor.get_face():
yield fidx.mMtlIdx
# create virtools mesh transition
# and write into mesh
with bmap.BMMeshTrans() as mesh_trans:
# prepare vertices
mesh_trans.prepare_vertex(
mesh_visitor.get_vertex_position_count(),
pos_iterator()
)
mesh_trans.prepare_normal(
mesh_visitor.get_vertex_normal_count(),
nml_iterator()
)
mesh_trans.prepare_uv(
mesh_visitor.get_vertex_uv_count(),
uv_iterator()
)
# prepare mtl slots
mesh_trans.prepare_mtl_slot(
mesh_visitor.get_material_slot_count(),
mtl_iterator()
)
# prepare face
mesh_trans.prepare_face(
mesh_visitor.get_face_count(),
face_idx_iterator(0),
face_idx_iterator(1),
face_idx_iterator(2),
face_mtl_iterator()
)
# parse to vtmesh
mesh_trans.parse(writer, vtmesh)
# end of mesh trans
# end of mesh visitor
# end of temp mesh
# step
progress.step()
# leave progress and return
progress.leave_substeps()
return tuple(material_crets)
def _export_virtools_materials(
writer: bmap.BMFileWriter,
progress: ProgressReport,
material_crets: tuple[_TMaterialPair, ...]
) -> tuple[_TTexturePair, ...]:
# create virtools mesh
texture_crets: list[_TTexturePair] = []
texture_cret_map: dict[bpy.types.Image, bmap.BMTexture] = {}
# start saving
progress.enter_substeps(len(material_crets), "Saving Materials")
for material, vtmaterial in material_crets:
# set name
vtmaterial.set_name(material.name)
# step
progress.step()
# leave progress and return
progress.leave_substeps()
return tuple(texture_crets)
def _save_virtools_document( def _save_virtools_document(
writer: bmap.BMFileWriter, writer: bmap.BMFileWriter,

View File

@ -115,7 +115,11 @@ def _vxvector2_iterator(pvector: bmap.bm_VxVector2_p, count: int) -> typing.Iter
idx += 2 idx += 2
yield ret yield ret
def _ckfaceindices_assigner(pindices: bmap.bm_CKDWORD_p, count: int, itor: typing.Iterator[virtools_types.CKFaceIndices]) -> None: # bmap.bm_CKWORD_p | bmap.bm_CKDWORD_p is just a type hint
# wo do not need distinguish them in code.
# because the type of pindices is decided by runtime.
def _ckfaceindices_assigner(pindices: bmap.bm_CKWORD_p | bmap.bm_CKDWORD_p, count: int, itor: typing.Iterator[virtools_types.CKFaceIndices]) -> None:
idx: int = 0 idx: int = 0
for _ in range(count): for _ in range(count):
userindices: virtools_types.CKFaceIndices = next(itor) userindices: virtools_types.CKFaceIndices = next(itor)
@ -124,7 +128,7 @@ def _ckfaceindices_assigner(pindices: bmap.bm_CKDWORD_p, count: int, itor: typin
pindices[idx + 2] = userindices.i3 pindices[idx + 2] = userindices.i3
idx += 3 idx += 3
def _ckfaceindices_iterator(pindices: bmap.bm_CKDWORD_p, count: int) -> typing.Iterator[virtools_types.CKFaceIndices]: def _ckfaceindices_iterator(pindices: bmap.bm_CKWORD_p | bmap.bm_CKDWORD_p, count: int) -> typing.Iterator[virtools_types.CKFaceIndices]:
ret: virtools_types.CKFaceIndices = virtools_types.CKFaceIndices() ret: virtools_types.CKFaceIndices = virtools_types.CKFaceIndices()
idx: int = 0 idx: int = 0
for _ in range(count): for _ in range(count):
@ -175,12 +179,12 @@ class BMObject(_AbstractCKObject):
else: else:
return name.value.decode(g_BMapEncoding) return name.value.decode(g_BMapEncoding)
def set_name(self, name: str | None) -> None: def set_name(self, name_: str | None) -> None:
name: bmap.bm_CKSTRING name: bmap.bm_CKSTRING
if name is None: if name_ is None:
name = bmap.bm_CKSTRING(0) name = bmap.bm_CKSTRING(0)
else: else:
name = bmap.bm_CKSTRING(name.encode(g_BMapEncoding)) name = bmap.bm_CKSTRING(name_.encode(g_BMapEncoding))
bmap.BMObject_SetName(self._get_pointer(), self._get_ckid(), name) bmap.BMObject_SetName(self._get_pointer(), self._get_ckid(), name)
class BMTexture(BMObject): class BMTexture(BMObject):
@ -415,8 +419,8 @@ class BMMesh(BMObject):
bmap.BMMesh_GetLitMode(self._get_pointer(), self._get_ckid(), ctypes.byref(mode)) bmap.BMMesh_GetLitMode(self._get_pointer(), self._get_ckid(), ctypes.byref(mode))
return virtools_types.VXMESH_LITMODE(mode.value) return virtools_types.VXMESH_LITMODE(mode.value)
def set_lit_mode(self, mode: virtools_types.VXMESH_LITMODE) -> None: def set_lit_mode(self, mode_: virtools_types.VXMESH_LITMODE) -> None:
mode: bmap.bm_enum = bmap.bm_enum(mode.value) mode: bmap.bm_enum = bmap.bm_enum(mode_.value)
bmap.BMMesh_SetLitMode(self._get_pointer(), self._get_ckid(), mode) bmap.BMMesh_SetLitMode(self._get_pointer(), self._get_ckid(), mode)
def get_vertex_count(self) -> int: def get_vertex_count(self) -> int:
@ -535,9 +539,9 @@ class BM3dObject(BMObject):
ret.from_const(tuple(flat[i] for i in range(16))) ret.from_const(tuple(flat[i] for i in range(16)))
return ret return ret
def set_world_matrix(self, mat: virtools_types.VxMatrix) -> None: def set_world_matrix(self, mat_: virtools_types.VxMatrix) -> None:
# star syntax expand the tuple as the argument. # star syntax expand the tuple as the argument.
mat: bmap.bm_VxMatrix = bmap.bm_VxMatrix(*(mat.to_const())) mat: bmap.bm_VxMatrix = bmap.bm_VxMatrix(*(mat_.to_const()))
bmap.BM3dObject_SetWorldMatrix(self._get_pointer(), self._get_ckid(), mat) bmap.BM3dObject_SetWorldMatrix(self._get_pointer(), self._get_ckid(), mat)
def get_current_mesh(self) -> BMMesh | None: def get_current_mesh(self) -> BMMesh | None:
@ -819,7 +823,7 @@ class BMMeshTrans(_AbstractPointer):
idx: int = 0 idx: int = 0
for _ in range(count): for _ in range(count):
usermtl: BMMaterial = next(itor) usermtl: BMMaterial | None = next(itor)
if usermtl is None: if usermtl is None:
raw_ckid[idx] = g_InvalidCKID raw_ckid[idx] = g_InvalidCKID
else: else:

View File

@ -24,12 +24,12 @@ class FaceVertexData():
class FaceData(): class FaceData():
## @remark List or tuple. List is convenient for adding and removing ## @remark List or tuple. List is convenient for adding and removing
mIndices: tuple[FaceVertexData] | list[FaceVertexData] mIndices: tuple[FaceVertexData, ...] | list[FaceVertexData]
## Face used material slot index ## Face used material slot index
# @remark If material slot is empty, or this face do not use material, set this value to 0. # @remark If material slot is empty, or this face do not use material, set this value to 0.
mMtlIdx: int mMtlIdx: int
def __init__(self, indices: tuple[FaceVertexData] | list[FaceVertexData] = tuple(), mtlidx: int = 0): def __init__(self, indices: tuple[FaceVertexData, ...] | list[FaceVertexData] = tuple(), mtlidx: int = 0):
self.mIndices = indices self.mIndices = indices
self.mMtlIdx = mtlidx self.mMtlIdx = mtlidx