finish virtools file importer

This commit is contained in:
yyc12345 2023-11-10 12:26:04 +08:00
parent 8fad643dd9
commit 1299a14f3b
9 changed files with 230 additions and 95 deletions

View File

@ -1,6 +1,6 @@
import bpy import bpy
from bpy_extras.wm_utils.progress_report import ProgressReport from bpy_extras.wm_utils.progress_report import ProgressReport
import tempfile, os import tempfile, os, typing
from . import PROP_preferences from . import PROP_preferences
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture
from . import PROP_ballance_element, PROP_virtools_group, PROP_virtools_material from . import PROP_ballance_element, PROP_virtools_group, PROP_virtools_material
@ -37,6 +37,8 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool
def _import_virtools(file_name_: str, encodings_: tuple[str]) -> None: def _import_virtools(file_name_: str, encodings_: tuple[str]) -> None:
# create temp folder # create temp folder
with tempfile.TemporaryDirectory() as vt_temp_folder: with tempfile.TemporaryDirectory() as vt_temp_folder:
print(f'Virtools Engine Temp: {vt_temp_folder}')
# create virtools reader context # create virtools reader context
with bmap.BMFileReader( with bmap.BMFileReader(
file_name_, file_name_,
@ -48,7 +50,7 @@ def _import_virtools(file_name_: str, encodings_: tuple[str]) -> None:
with ProgressReport(wm = bpy.context.window_manager) as progress: with ProgressReport(wm = bpy.context.window_manager) as progress:
# import textures # import textures
texture_cret_map: dict[bmap.BMTexture, bpy.types.Image] = _import_virtools_textures( texture_cret_map: dict[bmap.BMTexture, bpy.types.Image] = _import_virtools_textures(
reader, progress, texture_cret_map) reader, progress)
# import materials # import materials
material_cret_map: dict[bmap.BMMaterial, bpy.types.Material] = _import_virtools_materials( material_cret_map: dict[bmap.BMMaterial, bpy.types.Material] = _import_virtools_materials(
reader, progress, texture_cret_map) reader, progress, texture_cret_map)
@ -71,6 +73,7 @@ def _import_virtools_textures(
# create another temp folder for raw data virtools texture importing # create another temp folder for raw data virtools texture importing
with tempfile.TemporaryDirectory() as rawdata_temp: with tempfile.TemporaryDirectory() as rawdata_temp:
print(f'Texture Raw Data Temp: {rawdata_temp}')
for vttexture in reader.get_textures(): for vttexture in reader.get_textures():
# if this image is raw data, save it in external folder before loading # if this image is raw data, save it in external folder before loading
@ -174,8 +177,78 @@ def _import_virtools_meshes(
progress.enter_substeps(reader.get_material_count(), "Loading Meshes") progress.enter_substeps(reader.get_material_count(), "Loading Meshes")
for vtmesh in reader.get_meshs(): for vtmesh in reader.get_meshs():
# create mesh
mesh: bpy.types.Mesh = bpy.data.meshes.new(
UTIL_functions.virtools_name_regulator(vtmesh.get_name())
)
# open mesh writer
with UTIL_blender_mesh.MeshWriter(mesh) as meshoper:
# construct data provider
data_prov: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient()
# constructor data itor
def pos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
for v in vtmesh.get_vertex_positions():
UTIL_virtools_types.vxvector3_conv_co(v)
yield v
def nml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
for v in vtmesh.get_vertex_normals():
UTIL_virtools_types.vxvector3_conv_co(v)
yield v
def uv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]:
for v in vtmesh.get_vertex_uvs():
UTIL_virtools_types.vxvector2_conv_co(v)
yield v
def face_iterator() -> typing.Iterator[UTIL_blender_mesh.FaceData]:
face: UTIL_blender_mesh.FaceData = UTIL_blender_mesh.FaceData(
[UTIL_blender_mesh.FaceVertexData() for i in range(3)]
)
findices_itor = vtmesh.get_face_indices()
fmtl_itor = vtmesh.get_face_material_slot_indexs()
for _ in range(vtmesh.get_face_count()):
# set indices data
vtindices = next(findices_itor)
face.mIndices[0].mPosIdx = vtindices.i1
face.mIndices[0].mNmlIdx = vtindices.i1
face.mIndices[0].mUvIdx = vtindices.i1
face.mIndices[1].mPosIdx = vtindices.i2
face.mIndices[1].mNmlIdx = vtindices.i2
face.mIndices[1].mUvIdx = vtindices.i2
face.mIndices[2].mPosIdx = vtindices.i3
face.mIndices[2].mNmlIdx = vtindices.i3
face.mIndices[2].mUvIdx = vtindices.i3
# swap indices
face.conv_co()
# set mtl data
vtmtl = next(fmtl_itor)
face.mMtlIdx = vtmtl
# return
yield face
def mtl_iterator() -> typing.Iterator[bpy.types.Material]:
for vtmtl in vtmesh.get_material_slots():
if vtmtl:
yield material_cret_map.get(vtmtl, None)
else:
yield None
# assign to data provider
data_prov.mVertexPosition = pos_iterator()
data_prov.mVertexNormal = nml_iterator()
data_prov.mVertexUV = uv_iterator()
data_prov.mFace = face_iterator()
data_prov.mMaterial = mtl_iterator()
# add part
meshoper.add_ingredient(data_prov)
# end of mesh writer
# add into map and step # add into map and step
#mesh_cret_map[vtmaterial] = mtl mesh_cret_map[vtmesh] = mesh
progress.step() progress.step()
# leave progress and return # leave progress and return
@ -191,9 +264,30 @@ def _import_virtools_3dobjects(
obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] = {} obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] = {}
progress.enter_substeps(reader.get_material_count(), "Loading 3dObjects") progress.enter_substeps(reader.get_material_count(), "Loading 3dObjects")
# get some essential blender data
blender_view_layer = bpy.context.view_layer
blender_collection = blender_view_layer.active_layer_collection.collection
for vt3dobj in reader.get_3dobjects(): for vt3dobj in reader.get_3dobjects():
# create 3d object with mesh
obj3d: bpy.types.Object = bpy.data.objects.new(
UTIL_functions.virtools_name_regulator(vt3dobj.get_name()),
mesh_cret_map.get(vt3dobj.get_current_mesh(), None)
)
# link to collection
blender_collection.objects.link(obj3d)
# set world matrix
vtmat = vt3dobj.get_world_matrix()
UTIL_virtools_types.vxmatrix_conv_co(vtmat)
obj3d.matrix_world = UTIL_virtools_types.vxmatrix_to_blender(vtmat)
# set visibility
obj3d.hide_set(not vt3dobj.get_visibility())
# add into map and step # add into map and step
#obj3d_cret_map[vtmaterial] = mtl obj3d_cret_map[vt3dobj] = obj3d
progress.step() progress.step()
# leave progress and return # leave progress and return
@ -205,17 +299,49 @@ def _import_virtools_groups(
progress: ProgressReport, progress: ProgressReport,
obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object]
) -> dict[bmap.BM3dObject, bpy.types.Object]: ) -> dict[bmap.BM3dObject, bpy.types.Object]:
# we need iterate all groups to construct a reversed map
# to indicate which groups should this 3dobject be grouped into.
reverse_map: dict[bmap.BM3dObject, set[str]] = {}
# prepare progress # prepare progress
progress.enter_substeps(reader.get_material_count(), "Loading Groups") progress.enter_substeps(reader.get_material_count(), "Loading Groups")
for vtgroup in reader.get_groups(): for vtgroup in reader.get_groups():
# add into map and step # if this group do not have name, skip it
#obj3d_cret_map[vtmaterial] = mtl group_name: str | None = vtgroup.get_name()
if group_name is None: continue
for item in vtgroup.get_objects():
# get or create set
objgroups: set[str] = reverse_map.get(item, None)
if objgroups is None:
objgroups = set()
reverse_map[item] = objgroups
# add into list
objgroups.add(group_name)
# step
progress.step() progress.step()
# leave progress # leave progress
progress.leave_substeps() progress.leave_substeps()
# now we can assign 3dobject group data by reverse map
progress.enter_substeps(reader.get_material_count(), "Applying Groups")
for mapk, mapv in reverse_map.items():
# check object
assoc_obj = obj3d_cret_map.get(mapk, None)
if assoc_obj is None: continue
# assign group
with PROP_virtools_group.VirtoolsGroupsHelper(assoc_obj) as gpoper:
gpoper.clear_all_groups()
gpoper.add_groups(mapv)
progress.leave_substeps()
def register() -> None: def register() -> None:
bpy.utils.register_class(BBP_OT_import_virtools) bpy.utils.register_class(BBP_OT_import_virtools)

View File

@ -128,7 +128,7 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None:
# open mesh writer and write data # open mesh writer and write data
with UTIL_blender_mesh.MeshWriter(mesh) as writer: with UTIL_blender_mesh.MeshWriter(mesh) as writer:
# prepare writer essential function # prepare writer essential function
mesh_part: UTIL_blender_mesh.MeshWriter.MeshWriterPartData = UTIL_blender_mesh.MeshWriter.MeshWriterPartData() mesh_part: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient()
def vpos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]: def vpos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]:
v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3() v: UTIL_virtools_types.VxVector3 = UTIL_virtools_types.VxVector3()
for i in range(vpos_count): for i in range(vpos_count):
@ -154,7 +154,9 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None:
mesh_part.mMaterial = iter(tuple()) mesh_part.mMaterial = iter(tuple())
def face_iterator() -> typing.Iterator[UTIL_blender_mesh.FaceData]: def face_iterator() -> typing.Iterator[UTIL_blender_mesh.FaceData]:
# create face data with 3 placeholder # create face data with 3 placeholder
f: UTIL_blender_mesh.FaceData = UTIL_blender_mesh.FaceData([UTIL_blender_mesh.FaceVertexData() for i in range(3)]) f: UTIL_blender_mesh.FaceData = UTIL_blender_mesh.FaceData(
[UTIL_blender_mesh.FaceVertexData() for i in range(3)]
)
for i in range(face_count): for i in range(face_count):
idx: int = i * 6 idx: int = i * 6
f.mIndices[0].mPosIdx = face[idx] f.mIndices[0].mPosIdx = face[idx]
@ -166,7 +168,7 @@ def _load_element(mesh: bpy.types.Mesh, element_id: int) -> None:
yield f yield f
mesh_part.mFace = face_iterator() mesh_part.mFace = face_iterator()
writer.add_part(mesh_part) writer.add_ingredient(mesh_part)
# end of with writer # end of with writer
# write mesh data # write mesh data

View File

@ -413,14 +413,14 @@ def get_raw_virtools_material(mtl: bpy.types.Material) -> RawVirtoolsMaterial:
props: BBP_PG_virtools_material = get_virtools_material(mtl) props: BBP_PG_virtools_material = get_virtools_material(mtl)
rawdata: RawVirtoolsMaterial = RawVirtoolsMaterial() rawdata: RawVirtoolsMaterial = RawVirtoolsMaterial()
rawdata.mDiffuse.from_tuple_rgba(props.diffuse) rawdata.mDiffuse.from_const_rgba(props.diffuse)
rawdata.mAmbient.from_tuple_rgb(props.ambient) rawdata.mAmbient.from_const_rgb(props.ambient)
rawdata.mSpecular.from_tuple_rgb(props.specular) rawdata.mSpecular.from_const_rgb(props.specular)
rawdata.mEmissive.from_tuple_rgb(props.emissive) rawdata.mEmissive.from_const_rgb(props.emissive)
rawdata.mSpecularPower = props.specular_power rawdata.mSpecularPower = props.specular_power
rawdata.mTexture = props.texture rawdata.mTexture = props.texture
rawdata.mTextureBorderColor.from_tuple_rgba(props.texture_border_color) rawdata.mTextureBorderColor.from_const_rgba(props.texture_border_color)
rawdata.mTextureBlendMode = UTIL_virtools_types.VXTEXTURE_BLENDMODE(int(props.texture_blend_mode)) rawdata.mTextureBlendMode = UTIL_virtools_types.VXTEXTURE_BLENDMODE(int(props.texture_blend_mode))
rawdata.mTextureMinMode = UTIL_virtools_types.VXTEXTURE_FILTERMODE(int(props.texture_min_mode)) rawdata.mTextureMinMode = UTIL_virtools_types.VXTEXTURE_FILTERMODE(int(props.texture_min_mode))

View File

@ -46,6 +46,7 @@ class bm_VxVector3(ctypes.Structure):
('z', bm_CKFLOAT), ('z', bm_CKFLOAT),
] ]
bm_VxVector3_p = ctypes.POINTER(bm_VxVector3) bm_VxVector3_p = ctypes.POINTER(bm_VxVector3)
bm_VxVector3_pp = ctypes.POINTER(bm_VxVector3_p)
class bm_VxColor(ctypes.Structure): class bm_VxColor(ctypes.Structure):
_fields_ = [ _fields_ = [
('r', bm_CKFLOAT), ('r', bm_CKFLOAT),
@ -223,7 +224,7 @@ BMMeshTrans_PrepareVertexCount = _create_bmap_func('BMMeshTrans_PrepareVertexCou
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition. # @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it. # @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False. # @return True if no error, otherwise False.
BMMeshTrans_PrepareVertex = _create_bmap_func('BMMeshTrans_PrepareVertex', [bm_void_p, bm_VxVector2_pp]) BMMeshTrans_PrepareVertex = _create_bmap_func('BMMeshTrans_PrepareVertex', [bm_void_p, bm_VxVector3_pp])
## BMMeshTrans_PrepareNormalCount ## BMMeshTrans_PrepareNormalCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition. # @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD. # @param count[in] Type: LibCmo::CKDWORD.
@ -233,7 +234,7 @@ BMMeshTrans_PrepareNormalCount = _create_bmap_func('BMMeshTrans_PrepareNormalCou
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition. # @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it. # @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False. # @return True if no error, otherwise False.
BMMeshTrans_PrepareNormal = _create_bmap_func('BMMeshTrans_PrepareNormal', [bm_void_p, bm_VxVector2_pp]) BMMeshTrans_PrepareNormal = _create_bmap_func('BMMeshTrans_PrepareNormal', [bm_void_p, bm_VxVector3_pp])
## BMMeshTrans_PrepareUVCount ## BMMeshTrans_PrepareUVCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition. # @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD. # @param count[in] Type: LibCmo::CKDWORD.
@ -651,13 +652,13 @@ BMMesh_SetVertexCount = _create_bmap_func('BMMesh_SetVertexCount', [bm_void_p, b
# @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing. # @param objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.
# @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it. # @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False. # @return True if no error, otherwise False.
BMMesh_GetVertexPositions = _create_bmap_func('BMMesh_GetVertexPositions', [bm_void_p, bm_CKID, bm_VxVector2_pp]) BMMesh_GetVertexPositions = _create_bmap_func('BMMesh_GetVertexPositions', [bm_void_p, bm_CKID, bm_VxVector3_pp])
## BMMesh_GetVertexNormals ## BMMesh_GetVertexNormals
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @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 objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.
# @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it. # @param out_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False. # @return True if no error, otherwise False.
BMMesh_GetVertexNormals = _create_bmap_func('BMMesh_GetVertexNormals', [bm_void_p, bm_CKID, bm_VxVector2_pp]) BMMesh_GetVertexNormals = _create_bmap_func('BMMesh_GetVertexNormals', [bm_void_p, bm_CKID, bm_VxVector3_pp])
## BMMesh_GetVertexUVs ## BMMesh_GetVertexUVs
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile. # @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 objid[in] Type: LibCmo::CK2::CK_ID. The CKID of object you accessing.

View File

@ -48,13 +48,15 @@ class _AbstractCKObject(_AbstractPointer):
return bmap.bm_CKID(self.__mCKID) return bmap.bm_CKID(self.__mCKID)
def __eq__(self, obj: object) -> bool: def __eq__(self, obj: object) -> bool:
if not _AbstractPointer.__eq__(self, obj): return False
if isinstance(obj, self.__class__): if isinstance(obj, self.__class__):
return obj.__mRawPointer == self.__mRawPointer and obj.__mCKID == self.__mCKID return obj.__mCKID == self.__mCKID
else: else:
return False return False
def __hash__(self) -> int: def __hash__(self) -> int:
return hash((self.__mRawPointer, self.__mCKID)) return hash((_AbstractPointer.__hash__(self), self.__mCKID))
#endregion #endregion
@ -119,6 +121,7 @@ def _ckfaceindices_iterator(pindices: bmap.bm_CKDWORD_p, count: int) -> typing.I
ret.i2 = pindices[idx + 1] ret.i2 = pindices[idx + 1]
ret.i3 = pindices[idx + 2] ret.i3 = pindices[idx + 2]
idx += 3 idx += 3
yield ret
#endregion #endregion
@ -429,7 +432,7 @@ class BMMesh(BMObject):
def get_vertex_uvs(self) -> typing.Iterator[virtools_types.VxVector2]: def get_vertex_uvs(self) -> typing.Iterator[virtools_types.VxVector2]:
raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p() raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p()
bmap.BMMesh_GetVertexUVs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector)) bmap.BMMesh_GetVertexUVs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
_vxvector2_iterator(raw_vector, self.get_vertex_count()) return _vxvector2_iterator(raw_vector, self.get_vertex_count())
def set_vertex_uvs(self, itor: typing.Iterator[virtools_types.VxVector2]) -> None: def set_vertex_uvs(self, itor: typing.Iterator[virtools_types.VxVector2]) -> None:
raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p() raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p()
@ -457,13 +460,13 @@ class BMMesh(BMObject):
def get_face_material_slot_indexs(self) -> typing.Iterator[int]: def get_face_material_slot_indexs(self) -> typing.Iterator[int]:
raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p() raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p()
bmap.BMMesh_GetFaceIndices(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx)) bmap.BMMesh_GetFaceMaterialSlotIndexs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx))
for i in range(self.get_face_count()): for i in range(self.get_face_count()):
yield raw_idx[i] yield raw_idx[i]
def set_face_material_slot_indexs(self, itor: typing.Iterator[int]) -> None: def set_face_material_slot_indexs(self, itor: typing.Iterator[int]) -> None:
raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p() raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p()
bmap.BMMesh_GetFaceIndices(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx)) bmap.BMMesh_GetFaceMaterialSlotIndexs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx))
for i in range(self.get_face_count()): for i in range(self.get_face_count()):
raw_idx[i] = next(itor) raw_idx[i] = next(itor)

View File

@ -136,42 +136,42 @@ class VxMatrix():
The Matrix representation. The Matrix representation.
The bracket statement exactly equal with Virtools. The bracket statement exactly equal with Virtools.
""" """
__mData: list[list[float]] data: list[list[float]]
def __init__(self): def __init__(self):
# init array # init array
self.__mData = [[0] * 4 for i in range(4)] self.data = [[0] * 4 for i in range(4)]
# set to identy # set to identy
self.reset() self.reset()
def _get_raw(self) -> list[list[float]]: def _get_raw(self) -> list[list[float]]:
return self.__mData return self.data
def reset(self) -> None: def reset(self) -> None:
# reset to identy # reset to identy
for i in range(4): for i in range(4):
for j in range(4): for j in range(4):
self.__mData[i][j] = 0.0 self.data[i][j] = 0.0
self.__mData[0][0] = 1.0 self.data[0][0] = 1.0
self.__mData[1][1] = 1.0 self.data[1][1] = 1.0
self.__mData[2][2] = 1.0 self.data[2][2] = 1.0
self.__mData[3][3] = 1.0 self.data[3][3] = 1.0
def from_const(self, cm: ConstVxMatrix) -> None: def from_const(self, cm: ConstVxMatrix) -> None:
( (
self.__mData[0][0], self.__mData[0][1], self.__mData[0][2], self.__mData[0][3], self.data[0][0], self.data[0][1], self.data[0][2], self.data[0][3],
self.__mData[1][0], self.__mData[1][1], self.__mData[1][2], self.__mData[1][3], self.data[1][0], self.data[1][1], self.data[1][2], self.data[1][3],
self.__mData[2][0], self.__mData[2][1], self.__mData[2][2], self.__mData[2][3], self.data[2][0], self.data[2][1], self.data[2][2], self.data[2][3],
self.__mData[3][0], self.__mData[3][1], self.__mData[3][2], self.__mData[3][3] self.data[3][0], self.data[3][1], self.data[3][2], self.data[3][3]
) = cm ) = cm
def to_const(self) -> ConstVxMatrix: def to_const(self) -> ConstVxMatrix:
return ( return (
self.__mData[0][0], self.__mData[0][1], self.__mData[0][2], self.__mData[0][3], self.data[0][0], self.data[0][1], self.data[0][2], self.data[0][3],
self.__mData[1][0], self.__mData[1][1], self.__mData[1][2], self.__mData[1][3], self.data[1][0], self.data[1][1], self.data[1][2], self.data[1][3],
self.__mData[2][0], self.__mData[2][1], self.__mData[2][2], self.__mData[2][3], self.data[2][0], self.data[2][1], self.data[2][2], self.data[2][3],
self.__mData[3][0], self.__mData[3][1], self.__mData[3][2], self.__mData[3][3] self.data[3][0], self.data[3][1], self.data[3][2], self.data[3][3]
) )
class CK_TEXTURE_SAVEOPTIONS(enum.IntEnum): class CK_TEXTURE_SAVEOPTIONS(enum.IntEnum):

View File

@ -32,10 +32,43 @@ class FaceData():
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
def conv_co(self) -> None:
"""
Change indice order between Virtools and Blender
"""
if isinstance(self.mIndices, list):
self.mIndices.reverse()
elif isinstance(self.mIndices, tuple):
self.mIndices = self.mIndices[::-1]
else:
raise UTIL_functions.BBPException('invalid indices container.')
def is_indices_legal(self) -> bool: def is_indices_legal(self) -> bool:
return len(self.mIndices) >= 3 return len(self.mIndices) >= 3
class MeshWriterIngredient():
mVertexPosition: typing.Iterator[UTIL_virtools_types.VxVector3] | None
mVertexNormal: typing.Iterator[UTIL_virtools_types.VxVector3] | None
mVertexUV: typing.Iterator[UTIL_virtools_types.VxVector2] | None
mFace: typing.Iterator[FaceData] | None
mMaterial: typing.Iterator[bpy.types.Material] | None
def __init__(self):
self.mVertexPosition = None
self.mVertexNormal = None
self.mVertexUV = None
self.mFace = None
self.mMaterial = None
def is_valid(self) -> bool:
if self.mVertexPosition is None: return False
if self.mVertexNormal is None: return False
if self.mVertexUV is None: return False
if self.mFace is None: return False
if self.mMaterial is None: return False
return True
def _flat_vxvector3(it: typing.Iterator[UTIL_virtools_types.VxVector3]) -> typing.Iterator[float]: def _flat_vxvector3(it: typing.Iterator[UTIL_virtools_types.VxVector3]) -> typing.Iterator[float]:
for entry in it: for entry in it:
yield entry.x yield entry.x
@ -268,7 +301,7 @@ class MeshReader():
pass pass
def __triangulate_mesh(self) -> None: def __triangulate_mesh(self) -> None:
bm = bmesh.new() bm: bmesh.types.BMesh = bmesh.new()
bm.from_mesh(self.__mAssocMesh) bm.from_mesh(self.__mAssocMesh)
bmesh.ops.triangulate(bm, faces = bm.faces) bmesh.ops.triangulate(bm, faces = bm.faces)
bm.to_mesh(self.__mAssocMesh) bm.to_mesh(self.__mAssocMesh)
@ -281,28 +314,6 @@ class MeshWriter():
then refer it to all face uv. then refer it to all face uv.
""" """
class MeshWriterPartData():
mVertexPosition: typing.Iterator[UTIL_virtools_types.VxVector3] | None
mVertexNormal: typing.Iterator[UTIL_virtools_types.VxVector3] | None
mVertexUV: typing.Iterator[UTIL_virtools_types.VxVector2] | None
mFace: typing.Iterator[FaceData] | None
mMaterial: typing.Iterator[bpy.types.Material] | None
def __init__(self):
self.mVertexPosition = None
self.mVertexNormal = None
self.mVertexUV = None
self.mFace = None
self.mMaterial = None
def is_valid(self) -> bool:
if self.mVertexPosition is None: return False
if self.mVertexNormal is None: return False
if self.mVertexUV is None: return False
if self.mFace is None: return False
if self.mMaterial is None: return False
return True
__mAssocMesh: bpy.types.Mesh | None ##< The binding mesh for this writer. None if this writer is invalid. __mAssocMesh: bpy.types.Mesh | None ##< The binding mesh for this writer. None if this writer is invalid.
__mVertexPos: array.array ##< Array item is float(f). Length must be an integer multiple of 3. __mVertexPos: array.array ##< Array item is float(f). Length must be an integer multiple of 3.
@ -365,25 +376,25 @@ class MeshWriter():
# reset mesh # reset mesh
self.__mAssocMesh = None self.__mAssocMesh = None
def add_part(self, data: MeshWriterPartData): def add_ingredient(self, data: MeshWriterIngredient):
if not self.is_valid(): if not self.is_valid():
raise UTIL_functions.BBPException('try to call an invalid MeshWriter.') raise UTIL_functions.BBPException('try to call an invalid MeshWriter.')
if not data.is_valid(): if not data.is_valid():
raise UTIL_functions.BBPException('invalid mesh part data.') raise UTIL_functions.BBPException('invalid mesh part data.')
# add vertex data # add vertex data
prev_vertex_pos_count: int = len(self.__mVertexPos) prev_vertex_pos_count: int = len(self.__mVertexPos) // 3
self.__mVertexPos.extend(_flat_vxvector3(data.mVertexPosition)) self.__mVertexPos.extend(_flat_vxvector3(data.mVertexPosition))
prev_vertex_nml_count: int = len(self.__mVertexNormal) prev_vertex_nml_count: int = len(self.__mVertexNormal) // 3
self.__mVertexNormal.extend(_flat_vxvector3(data.mVertexNormal)) self.__mVertexNormal.extend(_flat_vxvector3(data.mVertexNormal))
prev_vertex_uv_count: int = len(self.__mVertexUV) prev_vertex_uv_count: int = len(self.__mVertexUV) // 2
self.__mVertexUV.extend(_flat_vxvector2(data.mVertexUV)) self.__mVertexUV.extend(_flat_vxvector2(data.mVertexUV))
# add material slot data and create mtl remap # add material slot data and create mtl remap
mtl_remap: list[int] = [] mtl_remap: list[int] = []
for mtl in data.mMaterial: for mtl in data.mMaterial:
idx: int | None = self.__mMtlSlotMap.get(mtl, None) idx: int | None = self.__mMtlSlotMap.get(mtl, None)
if idx: if idx is not None:
mtl_remap.append(idx) mtl_remap.append(idx)
else: else:
self.__mMtlSlotMap[mtl] = len(self.__mMtlSlot) self.__mMtlSlotMap[mtl] = len(self.__mMtlSlot)
@ -405,7 +416,7 @@ class MeshWriter():
# add face mtl with remap # add face mtl with remap
mtl_idx: int = face.mMtlIdx mtl_idx: int = face.mMtlIdx
if mtl_idx < 0 or mtl_idx > len(mtl_remap): if mtl_idx < 0 or mtl_idx >= len(mtl_remap):
# fall back. add 0 # fall back. add 0
self.__mFaceMtlIdx.append(0) self.__mFaceMtlIdx.append(0)
else: else:
@ -423,7 +434,7 @@ class MeshWriter():
self.__mAssocMesh.materials.append(mtl) self.__mAssocMesh.materials.append(mtl)
# add corresponding count for vertex position # add corresponding count for vertex position
self.__mAssocMesh.vertices.add(len(self.__mVertexPos)) self.__mAssocMesh.vertices.add(len(self.__mVertexPos) // 3)
# add loops data, it is the sum count of indices # add loops data, it is the sum count of indices
# we use face pos indices size to get it # we use face pos indices size to get it
self.__mAssocMesh.loops.add(len(self.__mFacePosIndices)) self.__mAssocMesh.loops.add(len(self.__mFacePosIndices))

View File

@ -74,7 +74,7 @@ def read_world_materix(fs: _FileReader_t, mat: UTIL_virtools_types.VxMatrix) ->
mat.from_tuple(struct.unpack("<16f", fs.read(16 * 4))) mat.from_tuple(struct.unpack("<16f", fs.read(16 * 4)))
def read_color(fs: _FileReader_t, target: UTIL_virtools_types.VxColor) -> None: def read_color(fs: _FileReader_t, target: UTIL_virtools_types.VxColor) -> None:
target.from_tuple_rgb(struct.unpack("fff", fs.read(3 * 4))) target.from_const_rgb(struct.unpack("fff", fs.read(3 * 4)))
def read_uint32_array(fs: _FileReader_t, count: int) -> tuple[int, ...]: def read_uint32_array(fs: _FileReader_t, count: int) -> tuple[int, ...]:
fmt: struct.Struct = struct.Struct('<' + str(count) + 'I') fmt: struct.Struct = struct.Struct('<' + str(count) + 'I')

View File

@ -10,52 +10,48 @@ from .PyBMap.virtools_types import *
#region VxVector2 Patch #region VxVector2 Patch
def _vxvector2_conv_co(self: VxVector2) -> None: def vxvector2_conv_co(self: VxVector2) -> None:
""" """
Convert UV coordinate system between Virtools and Blender. Convert UV coordinate system between Virtools and Blender.
""" """
self.y = -self.y self.y = -self.y
VxVector2.conv_co = _vxvector2_conv_co
#endregion #endregion
#region VxVector3 Patch #region VxVector3 Patch
def _vxvector3_conv_co(self: VxVector3) -> None: def vxvector3_conv_co(self: VxVector3) -> None:
""" """
Convert Position or Normal coordinate system between Virtools and Blender. Convert Position or Normal coordinate system between Virtools and Blender.
""" """
self.y, self.z = self.z, self.y self.y, self.z = self.z, self.y
VxVector3.conv_co = _vxvector3_conv_co
#endregion #endregion
#region VxMatrix Patch #region VxMatrix Patch
def _vxmatrix_conv_co(self: VxMatrix) -> None: def vxmatrix_conv_co(self: VxMatrix) -> None:
""" """
Convert World Matrix coordinate system between Virtools and Blender. Convert World Matrix coordinate system between Virtools and Blender.
""" """
# swap column 1 and 2 # swap column 1 and 2
for i in range(4): for i in range(4):
self.__mData[i][1], self.__mData[i][2] = self.__mData[i][2], self.__mData[i][1] self.data[i][1], self.data[i][2] = self.data[i][2], self.data[i][1]
# swap row 1 and 2 # swap row 1 and 2
for i in range(4): for i in range(4):
self.__mData[1][i], self.__mData[2][i] = self.__mData[2][i], self.__mData[1][i] self.data[1][i], self.data[2][i] = self.data[2][i], self.data[1][i]
def _vxmatrix_from_blender(self: VxMatrix, data_: mathutils.Matrix) -> None: def vxmatrix_from_blender(self: VxMatrix, data_: mathutils.Matrix) -> None:
""" """
Set matrix by blender matrix. Set matrix by blender matrix.
""" """
# transposed first # transposed first
data: mathutils.Matrix = data_.transposed() data: mathutils.Matrix = data_.transposed()
( (
self.__mData[0][0], self.__mData[0][1], self.__mData[0][2], self.__mData[0][3], self.data[0][0], self.data[0][1], self.data[0][2], self.data[0][3],
self.__mData[1][0], self.__mData[1][1], self.__mData[1][2], self.__mData[1][3], self.data[1][0], self.data[1][1], self.data[1][2], self.data[1][3],
self.__mData[2][0], self.__mData[2][1], self.__mData[2][2], self.__mData[2][3], self.data[2][0], self.data[2][1], self.data[2][2], self.data[2][3],
self.__mData[3][0], self.__mData[3][1], self.__mData[3][2], self.__mData[3][3] self.data[3][0], self.data[3][1], self.data[3][2], self.data[3][3]
) = ( ) = (
data[0][0], data[0][1], data[0][2], data[0][3], data[0][0], data[0][1], data[0][2], data[0][3],
data[1][0], data[1][1], data[1][2], data[1][3], data[1][0], data[1][1], data[1][2], data[1][3],
@ -63,23 +59,19 @@ def _vxmatrix_from_blender(self: VxMatrix, data_: mathutils.Matrix) -> None:
data[3][0], data[3][1], data[3][2], data[3][3] data[3][0], data[3][1], data[3][2], data[3][3]
) )
def _vxmatrix_to_blender(self: VxMatrix) -> mathutils.Matrix: def vxmatrix_to_blender(self: VxMatrix) -> mathutils.Matrix:
""" """
Get blender matrix from this matrix Get blender matrix from this matrix
""" """
data: mathutils.Matrix = mathutils.Matrix( data: mathutils.Matrix = mathutils.Matrix((
(self.__mData[0][0], self.__mData[0][1], self.__mData[0][2], self.__mData[0][3]), (self.data[0][0], self.data[0][1], self.data[0][2], self.data[0][3]),
(self.__mData[1][0], self.__mData[1][1], self.__mData[1][2], self.__mData[1][3]), (self.data[1][0], self.data[1][1], self.data[1][2], self.data[1][3]),
(self.__mData[2][0], self.__mData[2][1], self.__mData[2][2], self.__mData[2][3]), (self.data[2][0], self.data[2][1], self.data[2][2], self.data[2][3]),
(self.__mData[3][0], self.__mData[3][1], self.__mData[3][2], self.__mData[3][3]), (self.data[3][0], self.data[3][1], self.data[3][2], self.data[3][3]),
) ))
# transpose self # transpose self
data.transpose() data.transpose()
return data return data
VxMatrix.conv_co = _vxmatrix_conv_co
VxMatrix.from_blender = _vxmatrix_from_blender
VxMatrix.to_blender = _vxmatrix_to_blender
#endregion #endregion