Compare commits

...

10 Commits

Author SHA1 Message Date
3372c7a4b7 feat: add light support in exporting virtools file.
Some checks failed
Publish docs via GitHub Pages / Deploy docs (push) Has been cancelled
- support light type when exporting virtools.
- both import and export virtools file now support light type. however there is a slight bug about light direction need to be resolved.
- fix bug that exporter throw exception if exported collection contain non-mesh object or exported object is not mesh object.
- fix the usage of BMMeshTrans according to upstream changes.
2025-01-03 17:36:44 +08:00
4181096a9e fix: redirect some reference of bpy.context to context passed by operator argument 2025-01-03 10:37:26 +08:00
89a5e6367b feat: improve name conflict strategy UI layout 2025-01-03 09:55:02 +08:00
cb893b770a feat: add light object support in importing virtools file.
- fix all `def poll(self)` to `def poll(cls)` to let it fit class method name convention.
- fix wrong progress counter when importing virtools file.
- add light support when importing virtools file.
- add corresponding conflict strategy and resolver for light.
2025-01-03 09:36:32 +08:00
2f08455518 feat: add virtools light features.
- add virtools light feature for blender light type and add all essential operators, functions and structs.
- remove PyBMap from repository. order builder fetch it on their own.
- update gitignore.
2024-12-31 14:40:41 +08:00
729e12ed7b feat: update virtools file importer and exporter
- use panel to organise property group in virtools file importer and exporter.
- move all ballance params and virtools params into ioport_shared module and enable different showcase according to the argument passed to show function presenting whether current window is importer or exporter.
- add multiple type ignore to ignore the error of bpy operator member field type hints.
2024-12-30 17:53:42 +08:00
fe47861bd0 fix: fix issue of BME module prototype 2024-11-02 17:44:06 +08:00
c894d88c54 doc: modify document to mark changes
- add universal encoding infos in documentation.
- bump up version to 4.1 for release.
2024-09-21 23:30:56 +08:00
c8d59ef5f4 feat: update PyBMap dependency.
- update PyBMap dependency.
- use BMap 0.2 instead of old one.
- change default encoding name string according to the change of LibCmo changes.
2024-09-21 22:59:14 +08:00
f5c50ae079 fix: fix legacy align issue.
- fix issus that legacy align can not align object with non-1 scale factors.
- refactor some functions in legacy align to have better looking.
- fix issus that legacy fail to align objects since second executing by forcely updating view layer.
2024-09-07 20:34:22 +08:00
36 changed files with 832 additions and 2221 deletions

3
.gitignore vendored
View File

@ -1,2 +1,3 @@
# disable distribution build folder
## ===== Personal =====
# Disable distribution build folder
redist/

12
bbp_ng/.gitignore vendored
View File

@ -1,15 +1,15 @@
# My Ban
PyBMap/*.dll
PyBMap/*.so
PyBMap/*.dylib
PyBMap/*.bin
PyBMap/*.pdb
## ===== Personal =====
# Do not include PyBMap in this repository.
# Order build fetch it manually.
PyBMap/
# Disable generated icons and jsons but keep the directory hierarchy.
icons/*
!icons/.gitkeep
jsons/*
!jsons/.gitkeep
## ===== Python =====
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]

View File

@ -8,7 +8,7 @@ class BBP_OT_export_bmfile(bpy.types.Operator, UTIL_file_browser.ExportBmxFile,
bl_options = {'PRESET'}
@classmethod
def poll(self, context):
def poll(cls, context):
return PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder()
def execute(self, context):

View File

@ -3,46 +3,17 @@ from bpy_extras.wm_utils.progress_report import ProgressReport
import tempfile, os, typing
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, UTIL_naming_convension
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_ballance_map_info
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_virtools_light
from .PyBMap import bmap_wrapper as bmap
# define global tex save opt blender enum prop helper
_g_EnumHelper_CK_TEXTURE_SAVEOPTIONS: UTIL_virtools_types.EnumPropHelper = UTIL_virtools_types.EnumPropHelper(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS)
class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtoolsFile, UTIL_ioport_shared.ExportParams, UTIL_ioport_shared.VirtoolsParams):
class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtoolsFile, UTIL_ioport_shared.ExportParams, UTIL_ioport_shared.VirtoolsParams, UTIL_ioport_shared.BallanceParams):
"""Export Virtools File"""
bl_idname = "bbp.export_virtools"
bl_label = "Export Virtools File"
bl_options = {'PRESET'}
texture_save_opt: bpy.props.EnumProperty(
name = "Global Texture Save Options",
description = "Decide how texture saved if texture is specified as Use Global as its Save Options.",
items = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
default = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.to_selection(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_EXTERNAL)
) # type: ignore
use_compress: bpy.props.BoolProperty(
name="Use Compress",
description = "Whether use ZLib to compress result when saving composition.",
default = True,
) # type: ignore
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,
) # type: ignore
successive_sector: bpy.props.BoolProperty(
name="Successive Sector",
description = "Whether order exporter to use document specified sector count to make sure sector is successive.",
default = True,
) # type: ignore
@classmethod
def poll(self, context):
def poll(cls, context):
return (
PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder()
and bmap.is_bmap_available())
@ -58,15 +29,26 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
)
return {'CANCELLED'}
# check texture save option to prevent real stupid user.
texture_save_opt = self.general_get_texture_save_opt()
if texture_save_opt == UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_USEGLOBAL:
UTIL_functions.message_box(
('You can not specify "Use Global" as global texture save option!', ),
'Wrong 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(),
_g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.get_selection(self.texture_save_opt),
self.use_compress,
self.compress_level,
self.successive_sector,
texture_save_opt,
self.general_get_use_compress(),
self.general_get_compress_level(),
self.general_get_successive_sector(),
self.general_get_successive_sector_count(),
objls
)
@ -75,32 +57,12 @@ class BBP_OT_export_virtools(bpy.types.Operator, UTIL_file_browser.ExportVirtool
def draw(self, context):
layout = self.layout
layout.label(text = 'Export Target')
self.draw_export_params(layout.box())
layout.separator()
layout.label(text = 'Virtools Params')
box = layout.box()
self.draw_virtools_params(box)
box.separator()
box.label(text = 'Global Texture Save Option')
box.prop(self, 'texture_save_opt', text = '')
box.separator()
box.prop(self, 'use_compress')
if self.use_compress:
box.prop(self, 'compress_level')
# show sector info to notice user
layout.separator()
layout.label(text = 'Ballance Params')
box = layout.box()
map_info: PROP_ballance_map_info.RawBallanceMapInfo = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
box.prop(self, 'successive_sector')
box.label(text = f'Map Sectors: {map_info.mSectorCount}')
self.draw_export_params(layout)
self.draw_virtools_params(layout, False)
self.draw_ballance_params(layout, False)
_TObj3dPair = tuple[bpy.types.Object, bmap.BM3dObject]
_TLightPair = tuple[bpy.types.Object, bpy.types.Light, bmap.BMTargetLight]
_TMeshPair = tuple[bpy.types.Object, bpy.types.Mesh, bmap.BMMesh]
_TMaterialPair = tuple[bpy.types.Material, bmap.BMMaterial]
_TTexturePair = tuple[bpy.types.Image, bmap.BMTexture]
@ -112,6 +74,7 @@ def _export_virtools(
use_compress_: bool,
compress_level_: int,
successive_sector_: bool,
successive_sector_count_: int,
export_objects: tuple[bpy.types.Object, ...]
) -> None:
@ -127,11 +90,15 @@ def _export_virtools(
# prepare progress reporter
with ProgressReport(wm = bpy.context.window_manager) as progress:
# prepare 3dobject
obj3d_crets: tuple[_TObj3dPair, ...] = _prepare_virtools_3dobjects(
writer, progress, export_objects)
# export group and 3dobject by prepared 3dobject
_export_virtools_groups(writer, progress, successive_sector_, obj3d_crets)
# prepare 3dobject and light
obj3d_crets: tuple[_TObj3dPair, ...]
light_crets: tuple[_TLightPair, ...]
(obj3d_crets, light_crets) = _prepare_virtools_3dobjects(writer, progress, export_objects)
# export group according to prepared 3dobject
_export_virtools_groups(writer, progress, successive_sector_, successive_sector_count_, obj3d_crets)
# export prepared light
_export_virtools_light(writer, progress, light_crets)
# export prepared 3dobject
mesh_crets: tuple[_TMeshPair, ...] = _export_virtools_3dobjects(
writer, progress, obj3d_crets)
# export mesh
@ -150,37 +117,59 @@ def _export_virtools(
def _prepare_virtools_3dobjects(
writer: bmap.BMFileWriter,
progress: ProgressReport,
export_objects: tuple[bpy.types.Object]
) -> tuple[_TObj3dPair, ...]:
export_objects: tuple[bpy.types.Object, ...]
) -> tuple[tuple[_TObj3dPair, ...], tuple[_TLightPair, ...]]:
# 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
#
# at the same time, due to the difference of light object between virtools and blender,
# we also need extract exported lights and create equvalent entries in virtools for them.
# create 3dobject hashset and result
obj3d_crets: list[_TObj3dPair] = []
obj3d_cret_set: set[bpy.types.Object] = set()
# create light hashset and result
light_crets: list[_TLightPair] = []
light_cret_set: set[bpy.types.Object] = set()
# start saving
progress.enter_substeps(len(export_objects), "Creating 3dObjects")
progress.enter_substeps(len(export_objects), "Creating 3dObjects and Lights")
# iterate exported object list
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))
# only accept mesh object and light object
# all of other objects will be discard.
match(obj3d.type):
case 'MESH':
# mesh object
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))
case 'LIGHT':
# light object
if obj3d not in light_cret_set:
# add into set
light_cret_set.add(obj3d)
# create virtools instance
vtlight: bmap.BMTargetLight = writer.create_target_light()
# add into result list
light_crets.append((obj3d, typing.cast(bpy.types.Light, obj3d.data), vtlight))
# step progress no matter whether create new one
progress.step()
# leave progress and return
progress.leave_substeps()
return tuple(obj3d_crets)
return (tuple(obj3d_crets), tuple(light_crets))
def _export_virtools_groups(
writer: bmap.BMFileWriter,
progress: ProgressReport,
successive_sector: bool,
successive_sector_count: int,
obj3d_crets: tuple[_TObj3dPair, ...]
) -> None:
# create virtools group
@ -197,9 +186,7 @@ def _export_virtools_groups(
#
# So we create all needed sector group in here to make sure exported virtools file can be read by Ballancde correctly.
if successive_sector:
map_info: PROP_ballance_map_info.RawBallanceMapInfo
map_info = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
for i in range(map_info.mSectorCount):
for i in range(successive_sector_count):
gp_name: str = UTIL_naming_convension.build_name_from_sector_index(i + 1)
vtgroup: bmap.BMGroup | None = group_cret_map.get(gp_name, None)
if vtgroup is None:
@ -227,6 +214,50 @@ def _export_virtools_groups(
# leave progress and return
progress.leave_substeps()
def _export_virtools_light(
writer: bmap.BMFileWriter,
progress: ProgressReport,
light_crets: tuple[_TLightPair, ...]
) -> None:
# start saving
progress.enter_substeps(0, "Saving Lights")
for obj3d, light, vtlight in light_crets:
# set name
vtlight.set_name(obj3d.name)
# setup 3d entity parts
# set world matrix
# TODO: fix light direction matrix issue.
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)
vtlight.set_world_matrix(vtmat)
# set visibility
vtlight.set_visibility(not obj3d.hide_get())
# setup light data
rawlight: PROP_virtools_light.RawVirtoolsLight = PROP_virtools_light.get_raw_virtools_light(light)
vtlight.set_type(rawlight.mType)
vtlight.set_color(rawlight.mColor)
vtlight.set_constant_attenuation(rawlight.mConstantAttenuation)
vtlight.set_linear_attenuation(rawlight.mLinearAttenuation)
vtlight.set_quadratic_attenuation(rawlight.mQuadraticAttenuation)
vtlight.set_range(rawlight.mRange)
vtlight.set_hot_spot(rawlight.mHotSpot)
vtlight.set_falloff(rawlight.mFalloff)
vtlight.set_falloff_shape(rawlight.mFalloffShape)
# step
progress.step()
# leave progress and return
progress.leave_substeps()
def _export_virtools_3dobjects(
writer: bmap.BMFileWriter,
progress: ProgressReport,
@ -243,7 +274,7 @@ def _export_virtools_3dobjects(
vtobj3d.set_name(obj3d.name)
# check mesh
mesh: bpy.types.Mesh | None = obj3d.data
mesh: bpy.types.Mesh | None = typing.cast(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)
@ -374,7 +405,7 @@ def _export_virtools_meshes(
)
# parse to vtmesh
mesh_trans.parse(writer, vtmesh)
mesh_trans.parse(vtmesh)
# end of mesh trans
# end of mesh visitor

View File

@ -8,7 +8,7 @@ class BBP_OT_import_bmfile(bpy.types.Operator, UTIL_file_browser.ImportBmxFile,
bl_options = {'PRESET', 'UNDO'}
@classmethod
def poll(self, context):
def poll(cls, context):
return PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder()
def execute(self, context):

View File

@ -3,17 +3,17 @@ from bpy_extras.wm_utils.progress_report import ProgressReport
import tempfile, os, typing
from . import PROP_preferences, UTIL_ioport_shared
from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_naming_convension
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_ballance_map_info
from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_virtools_light, PROP_ballance_map_info
from .PyBMap import bmap_wrapper as bmap
class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile, UTIL_ioport_shared.ImportParams, UTIL_ioport_shared.VirtoolsParams):
class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile, UTIL_ioport_shared.ImportParams, UTIL_ioport_shared.VirtoolsParams, UTIL_ioport_shared.BallanceParams):
"""Import Virtools File"""
bl_idname = "bbp.import_virtools"
bl_label = "Import Virtools File"
bl_options = {'PRESET', 'UNDO'}
@classmethod
def poll(self, context):
def poll(cls, context):
return (
PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder()
and bmap.is_bmap_available())
@ -29,11 +29,9 @@ class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtool
def draw(self, context):
layout = self.layout
layout.label(text = 'Conflict Options')
self.draw_import_params(layout.box())
layout.separator()
layout.label(text = 'Virtools Params')
self.draw_virtools_params(layout.box())
self.draw_import_params(layout)
self.draw_virtools_params(layout, True)
self.draw_ballance_params(layout, True)
def _import_virtools(file_name_: str, encodings_: tuple[str], resolver: UTIL_ioport_shared.ConflictResolver) -> None:
# create temp folder
@ -61,6 +59,8 @@ def _import_virtools(file_name_: str, encodings_: tuple[str], resolver: UTIL_iop
# import 3dobjects
obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] = _import_virtools_3dobjects(
reader, progress, resolver, mesh_cret_map)
# import light
_import_virtools_lights(reader, progress, resolver)
# import groups
_import_virtools_groups(reader, progress, obj3d_cret_map)
@ -202,7 +202,7 @@ def _import_virtools_meshes(
) -> dict[bmap.BMMesh, bpy.types.Mesh]:
# create map and prepare progress
mesh_cret_map: dict[bmap.BMMesh, bpy.types.Mesh] = {}
progress.enter_substeps(reader.get_material_count(), "Loading Meshes")
progress.enter_substeps(reader.get_mesh_count(), "Loading Meshes")
for vtmesh in reader.get_meshs():
# create mesh
@ -298,11 +298,7 @@ def _import_virtools_3dobjects(
) -> dict[bmap.BM3dObject, bpy.types.Object]:
# create map and prepare progress
obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] = {}
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
progress.enter_substeps(reader.get_3dobject_count(), "Loading 3dObjects")
for vt3dobj in reader.get_3dobjects():
# get virtools binding mesh data first
@ -316,8 +312,8 @@ def _import_virtools_3dobjects(
# setup if necessary
if init_obj3d:
# link to collection
blender_collection.objects.link(obj3d)
# add into scene
UTIL_functions.add_into_scene(obj3d)
# set world matrix
vtmat: UTIL_virtools_types.VxMatrix = vt3dobj.get_world_matrix()
@ -340,6 +336,61 @@ def _import_virtools_3dobjects(
progress.leave_substeps()
return obj3d_cret_map
def _import_virtools_lights(
reader: bmap.BMFileReader,
progress: ProgressReport,
resolver: UTIL_ioport_shared.ConflictResolver
) -> None:
# prepare progress
progress.enter_substeps(reader.get_target_light_count(), "Loading Lights")
# please note light is slightly different between virtools and blender.
# in virtools, light is the sub class of 3d entity.
# it means that virtools use class inheritance to implement light.
# however, in blender, light is the data property of object.
# comparing with normal mesh object, it just replace the data property of object to a light.
# so in blender, light is implemented as a data struct attached to object.
# thus we can reuse light data for multiple objects but virtools can not.
# in virtools, every light are individual objects.
for vtlight in reader.get_target_lights():
# create light data block and 3d object together
(light_3dobj, light, init_light) = resolver.create_light(
UTIL_virtools_types.virtools_name_regulator(vtlight.get_name())
)
if init_light:
# setup light data block
rawlight: PROP_virtools_light.RawVirtoolsLight = PROP_virtools_light.RawVirtoolsLight()
rawlight.mType = vtlight.get_type()
rawlight.mColor = vtlight.get_color()
rawlight.mConstantAttenuation = vtlight.get_constant_attenuation()
rawlight.mLinearAttenuation = vtlight.get_linear_attenuation()
rawlight.mQuadraticAttenuation = vtlight.get_quadratic_attenuation()
rawlight.mRange = vtlight.get_range()
rawlight.mHotSpot = vtlight.get_hot_spot()
rawlight.mFalloff = vtlight.get_falloff()
rawlight.mFalloffShape = vtlight.get_falloff_shape()
PROP_virtools_light.set_raw_virtools_light(light, rawlight)
PROP_virtools_light.apply_to_blender_light(light)
# setup light associated 3d object
# add into scene
UTIL_functions.add_into_scene(light_3dobj)
# set world matrix
# TODO: fix light direction
vtmat: UTIL_virtools_types.VxMatrix = vtlight.get_world_matrix()
UTIL_virtools_types.vxmatrix_conv_co(vtmat)
light_3dobj.matrix_world = UTIL_virtools_types.vxmatrix_to_blender(vtmat)
# set visibility
light_3dobj.hide_set(not vtlight.get_visibility())
# leave progress
progress.leave_substeps()
def _import_virtools_groups(
reader: bmap.BMFileReader,
progress: ProgressReport,
@ -352,7 +403,7 @@ def _import_virtools_groups(
sector_count: int = 1
# prepare progress
progress.enter_substeps(reader.get_material_count(), "Loading Groups")
progress.enter_substeps(reader.get_group_count(), "Loading Groups")
for vtgroup in reader.get_groups():
# if this group do not have name, skip it
@ -367,7 +418,7 @@ def _import_virtools_groups(
# creating map
for item in vtgroup.get_objects():
# get or create set
objgroups: set[str] = reverse_map.get(item, None)
objgroups: set[str] | None = reverse_map.get(item, None)
if objgroups is None:
objgroups = set()
reverse_map[item] = objgroups
@ -387,7 +438,7 @@ def _import_virtools_groups(
progress.leave_substeps()
# now we can assign 3dobject group data by reverse map
progress.enter_substeps(reader.get_material_count(), "Applying Groups")
progress.enter_substeps(len(reverse_map), "Applying Groups")
for mapk, mapv in reverse_map.items():
# check object
assoc_obj = obj3d_cret_map.get(mapk, None)
@ -398,6 +449,10 @@ def _import_virtools_groups(
gpoper.clear_groups()
gpoper.add_groups(mapv)
# step
progress.step()
# leave progress
progress.leave_substeps()

View File

@ -136,6 +136,14 @@ class BBP_OT_legacy_align(bpy.types.Operator):
def execute(self, context):
# get processed objects
(current_obj, target_objs) = _prepare_objects()
# INFO: YYC MARK:
# This statement is VERY IMPORTANT.
# If this statement is not presented, Blender will return identity matrix
# when getting world matrix from Object since the second execution of this function.
# It seems that Blender fail to read restored value from a new execution.
# Additionally, this statement only can be placed in there.
# If you place it at the end of this function, it doesn't work.
context.view_layer.update()
# iterate history to align objects
entry: BBP_PG_legacy_align_history
for entry in self.align_history:
@ -212,56 +220,52 @@ def _align_objects(
# if no align, skip
if not (align_x or align_y or align_z):
return
# calc current object data
current_obj_bbox: tuple[mathutils.Vector] = tuple(current_obj.matrix_world @ mathutils.Vector(corner) for corner in current_obj.bound_box)
current_obj_ref: mathutils.Vector = _get_object_ref_point(current_obj, current_obj_bbox, current_mode)
current_obj_ref: mathutils.Vector = _get_object_ref_point(current_obj, current_mode)
# process each target obj
for target_obj in target_objs:
# calc target object data
target_obj_bbox: tuple[mathutils.Vector] = tuple(target_obj.matrix_world @ mathutils.Vector(corner) for corner in target_obj.bound_box)
target_obj_ref: mathutils.Vector = _get_object_ref_point(target_obj, target_obj_bbox, target_mode)
# do align
if align_x:
target_obj.location.x += current_obj_ref.x - target_obj_ref.x
if align_y:
target_obj.location.y += current_obj_ref.y - target_obj_ref.y
if align_z:
target_obj.location.z += current_obj_ref.z - target_obj_ref.z
target_obj_ref: mathutils.Vector = _get_object_ref_point(target_obj, target_mode)
# build translation transform
target_obj_translation: mathutils.Vector = current_obj_ref - target_obj_ref
if not align_x: target_obj_translation.x = 0
if not align_y: target_obj_translation.y = 0
if not align_z: target_obj_translation.z = 0
# target_obj.location += target_obj_translation
target_obj_translation_matrix: mathutils.Matrix = mathutils.Matrix.Translation(target_obj_translation)
# apply translation transform to left side (add into original matrix)
target_obj.matrix_world = target_obj_translation_matrix @ target_obj.matrix_world
def _get_object_ref_point(obj: bpy.types.Object, corners: tuple[mathutils.Vector], mode: AlignMode) -> mathutils.Vector:
bpy.context.scene.update_tag
def _get_object_ref_point(obj: bpy.types.Object, mode: AlignMode) -> mathutils.Vector:
ref_pos: mathutils.Vector = mathutils.Vector((0, 0, 0))
# calc bounding box data
corners: tuple[mathutils.Vector] = tuple(obj.matrix_world @ mathutils.Vector(corner) for corner in obj.bound_box)
bbox_min_corner: mathutils.Vector = mathutils.Vector((0, 0, 0))
bbox_min_corner.x = min((vec.x for vec in corners))
bbox_min_corner.y = min((vec.y for vec in corners))
bbox_min_corner.z = min((vec.z for vec in corners))
bbox_max_corner: mathutils.Vector = mathutils.Vector((0, 0, 0))
bbox_max_corner.x = max((vec.x for vec in corners))
bbox_max_corner.y = max((vec.y for vec in corners))
bbox_max_corner.z = max((vec.z for vec in corners))
# return value by given align mode
match(mode):
case AlignMode.Min:
ref_pos.x = min((vec.x for vec in corners))
ref_pos.y = min((vec.y for vec in corners))
ref_pos.z = min((vec.z for vec in corners))
ref_pos = bbox_min_corner
case AlignMode.Max:
ref_pos.x = max((vec.x for vec in corners))
ref_pos.y = max((vec.y for vec in corners))
ref_pos.z = max((vec.z for vec in corners))
ref_pos = bbox_max_corner
case AlignMode.BBoxCenter:
max_vec_cache: mathutils.Vector = mathutils.Vector((0, 0, 0))
min_vec_cache: mathutils.Vector = mathutils.Vector((0, 0, 0))
min_vec_cache.x = min((vec.x for vec in corners))
min_vec_cache.y = min((vec.y for vec in corners))
min_vec_cache.z = min((vec.z for vec in corners))
max_vec_cache.x = max((vec.x for vec in corners))
max_vec_cache.y = max((vec.y for vec in corners))
max_vec_cache.z = max((vec.z for vec in corners))
ref_pos.x = (max_vec_cache.x + min_vec_cache.x) / 2
ref_pos.y = (max_vec_cache.y + min_vec_cache.y) / 2
ref_pos.z = (max_vec_cache.z + min_vec_cache.z) / 2
ref_pos = (bbox_max_corner + bbox_min_corner) / 2
case AlignMode.AxisCenter:
ref_pos.x = obj.location.x
ref_pos.y = obj.location.y
ref_pos.z = obj.location.z
ref_pos = obj.matrix_world.translation
case _:
raise UTIL_functions.BBPException('inpossible align mode.')
raise UTIL_functions.BBPException('impossible align mode.')
return ref_pos

View File

@ -50,6 +50,7 @@ class BBP_OT_select_object_by_virtools_group(bpy.types.Operator, PROP_virtools_g
def execute(self, context):
_select_object_by_virtools_group(
context,
self.general_get_group_name(),
_g_EnumHelper_SelectMode.get_selection(self.selection_mode)
)
@ -65,17 +66,17 @@ class BBP_OT_select_object_by_virtools_group(bpy.types.Operator, PROP_virtools_g
layout.label(text='Group Parameters')
self.draw_group_name_input(layout)
def _select_object_by_virtools_group(group_name: str, mode: SelectMode) -> None:
def _select_object_by_virtools_group(context: bpy.types.Context, group_name: str, mode: SelectMode) -> None:
match(mode):
case SelectMode.Set:
# iterate all objects and directly set
for obj in bpy.context.scene.objects:
for obj in context.scene.objects:
# check group and decide whether select this obj
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
obj.select_set(gp.contain_group(group_name))
case SelectMode.Extend:
# also iterate all objects
for obj in bpy.context.scene.objects:
for obj in context.scene.objects:
# but only increase selection, for selected object, skip check
if obj.select_get(): continue
# if not selected, check whether add it.
@ -86,7 +87,7 @@ def _select_object_by_virtools_group(group_name: str, mode: SelectMode) -> None:
# subtract only involving selected item. so we get selected objest first
# and copy it (because we need modify it)
# and iterate it to reduce useless operations
selected = bpy.context.selected_objects[:]
selected = context.selected_objects[:]
for obj in selected:
# remove matched only
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
@ -94,16 +95,16 @@ def _select_object_by_virtools_group(group_name: str, mode: SelectMode) -> None:
obj.select_set(False)
case SelectMode.Difference:
# construct a selected obj set for convenient operations
selected_set = set(bpy.context.selected_objects)
selected_set = set(context.selected_objects)
# iterate all objects
for obj in bpy.context.scene.objects:
for obj in context.scene.objects:
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
# use xor to select
# in_selected XOR in_group
obj.select_set((obj in selected_set) ^ gp.contain_group(group_name))
case SelectMode.Intersect:
# like subtract, only iterate selected obj
selected = bpy.context.selected_objects[:]
selected = context.selected_objects[:]
for obj in selected:
# but remove not matched
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
@ -124,7 +125,7 @@ class BBP_OT_add_objects_virtools_group(bpy.types.Operator, PROP_virtools_group.
@classmethod
def poll(cls, context):
return len(bpy.context.selected_objects) != 0
return len(context.selected_objects) != 0
def invoke(self, context, event):
wm = context.window_manager
@ -132,7 +133,7 @@ class BBP_OT_add_objects_virtools_group(bpy.types.Operator, PROP_virtools_group.
def execute(self, context):
group_name: str = self.general_get_group_name()
for obj in bpy.context.selected_objects:
for obj in context.selected_objects:
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
gp.add_group(group_name)
self.report({'INFO'}, "Grouping objects successfully.")
@ -149,7 +150,7 @@ class BBP_OT_rm_objects_virtools_group(bpy.types.Operator, PROP_virtools_group.S
@classmethod
def poll(cls, context):
return len(bpy.context.selected_objects) != 0
return len(context.selected_objects) != 0
def invoke(self, context, event):
wm = context.window_manager
@ -157,7 +158,7 @@ class BBP_OT_rm_objects_virtools_group(bpy.types.Operator, PROP_virtools_group.S
def execute(self, context):
group_name: str = self.general_get_group_name()
for obj in bpy.context.selected_objects:
for obj in context.selected_objects:
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
gp.remove_group(group_name)
self.report({'INFO'}, "Ungrouping objects successfully.")
@ -174,7 +175,7 @@ class BBP_OT_clear_objects_virtools_group(bpy.types.Operator):
@classmethod
def poll(cls, context):
return len(bpy.context.selected_objects) != 0
return len(context.selected_objects) != 0
def invoke(self, context, event):
wm = context.window_manager
@ -182,7 +183,7 @@ class BBP_OT_clear_objects_virtools_group(bpy.types.Operator):
def execute(self, context):
# iterate object
for obj in bpy.context.selected_objects:
for obj in context.selected_objects:
with PROP_virtools_group.VirtoolsGroupsHelper(obj) as gp:
gp.clear_groups()
self.report({'INFO'}, "Clear objects groups successfully.")

View File

@ -135,7 +135,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
@classmethod
def poll(cls, context):
obj = bpy.context.active_object
obj = context.active_object
if obj is None:
return False
if obj.type != 'MESH':
@ -162,7 +162,7 @@ class BBP_OT_flatten_uv(bpy.types.Operator):
return {'CANCELLED'}
# do flatten uv and report
failed: int = _flatten_uv_wrapper(bpy.context.active_object.data, flatten_param_)
failed: int = _flatten_uv_wrapper(context.active_object.data, flatten_param_)
if failed != 0:
print(f'[Flatten UV] {failed} faces are not be processed correctly because process failed.')
return {'FINISHED'}

View File

@ -10,7 +10,7 @@ class BBP_OT_rail_uv(bpy.types.Operator):
bl_options = {'UNDO'}
@classmethod
def poll(self, context):
def poll(cls, context):
return _check_rail_target()
def invoke(self, context, event):

View File

@ -97,12 +97,12 @@ class BBP_PG_ballance_element(bpy.types.PropertyGroup):
element_id: bpy.props.IntProperty(
name = "Element Id",
default = 0
)
) # type: ignore
mesh_ptr: bpy.props.PointerProperty(
name = "Mesh",
type = bpy.types.Mesh
)
) # type: ignore
def get_ballance_elements(scene: bpy.types.Scene) -> bpy.types.CollectionProperty:
return scene.ballance_elements

View File

@ -73,12 +73,12 @@ class BBP_PG_bme_material(bpy.types.PropertyGroup):
bme_material_name: bpy.props.StringProperty(
name = "Name",
default = ""
)
) # type: ignore
material_ptr: bpy.props.PointerProperty(
name = "Material",
type = bpy.types.Material
)
) # type: ignore
def get_bme_materials(scene: bpy.types.Scene) -> bpy.types.CollectionProperty:
return scene.bme_materials

View File

@ -24,13 +24,13 @@ class BBPPreferences(bpy.types.AddonPreferences):
description = "The path to folder which will be used by this plugin to get external Ballance texture.",
subtype='DIR_PATH',
default = RawPreferences.cBallanceTextureFolder,
)
) # type: ignore
no_component_collection: bpy.props.StringProperty(
name = "No Component Collection",
description = "(Import) The object which stored in this collectiion will not be saved as component. (Export) All forced no component objects will be stored in this collection",
default = RawPreferences.cNoComponentCollection,
)
) # type: ignore
def draw(self, context):
layout = self.layout

View File

@ -10,19 +10,19 @@ class BBP_PG_ptrprop_resolver(bpy.types.PropertyGroup):
name = "Material",
description = "The material used for rail",
type = bpy.types.Material,
)
) # type: ignore
export_collection: bpy.props.PointerProperty(
type = bpy.types.Collection,
name = "Collection",
description = "The collection exported. Nested collections allowed."
)
) # type: ignore
export_object: bpy.props.PointerProperty(
type = bpy.types.Object,
name = "Object",
description = "The object exported"
)
) # type: ignore
def get_ptrprop_resolver() -> BBP_PG_ptrprop_resolver:
return bpy.context.scene.bbp_ptrprop_resolver

View File

@ -255,19 +255,19 @@ class SharedGroupNameInputProperties():
('DEFINED', "Predefined", "Pre-defined group name."),
('CUSTOM', "Custom", "User specified group name."),
),
)
) # type: ignore
preset_group_name: bpy.props.EnumProperty(
name = "Group Name",
description = "Pick vanilla Ballance group name.",
items = _g_EnumHelper_Group.generate_items(),
)
) # type: ignore
custom_group_name: bpy.props.StringProperty(
name = "Custom Group Name",
description = "Input your custom group name.",
default = "",
)
) # type: ignore
def draw_group_name_input(self, layout: bpy.types.UILayout) -> None:
layout.prop(self, 'group_name_source', expand = True)
@ -297,7 +297,7 @@ class BBP_OT_add_virtools_group(bpy.types.Operator, SharedGroupNameInputProperti
bl_options = {'UNDO'}
@classmethod
def poll(self, context: bpy.types.Context):
def poll(cls, context: bpy.types.Context):
return context.object is not None
def invoke(self, context, event):
@ -324,7 +324,7 @@ class BBP_OT_rm_virtools_group(bpy.types.Operator):
# Then pass it to helper.
@classmethod
def poll(self, context: bpy.types.Context):
def poll(cls, context: bpy.types.Context):
if context.object is None:
return False
@ -351,7 +351,7 @@ class BBP_OT_clear_virtools_groups(bpy.types.Operator):
bl_options = {'UNDO'}
@classmethod
def poll(self, context: bpy.types.Context):
def poll(cls, context: bpy.types.Context):
return context.object is not None
def invoke(self, context, event):

View File

@ -0,0 +1,321 @@
import bpy, mathutils
from bpy.types import Context
import typing, math
from . import UTIL_functions, UTIL_virtools_types
# Raw Data
class RawVirtoolsLight():
# Class member
mType: UTIL_virtools_types.VXLIGHT_TYPE
mColor: UTIL_virtools_types.VxColor
mConstantAttenuation: float
mLinearAttenuation: float
mQuadraticAttenuation: float
mRange: float
mHotSpot: float
mFalloff: float
mFalloffShape: float
# Class member default value
cDefaultType: typing.ClassVar[UTIL_virtools_types.VXLIGHT_TYPE] = UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTPOINT
cDefaultColor: typing.ClassVar[UTIL_virtools_types.VxColor] = UTIL_virtools_types.VxColor(1.0, 1.0, 1.0, 1.0)
cDefaultConstantAttenuation: typing.ClassVar[float] = 1.0
cDefaultLinearAttenuation: typing.ClassVar[float] = 0.0
cDefaultQuadraticAttenuation: typing.ClassVar[float] = 0.0
cDefaultRange: typing.ClassVar[float] = 100.0
cDefaultHotSpot: typing.ClassVar[float] = math.radians(40)
cDefaultFalloff: typing.ClassVar[float] = math.radians(45)
cDefaultFalloffShape: typing.ClassVar[float] = 1.0
def __init__(self, **kwargs):
# assign default value for each component
self.mType = kwargs.get('mType', RawVirtoolsLight.cDefaultType)
self.mColor = kwargs.get('mColor', RawVirtoolsLight.cDefaultColor).clone()
self.mConstantAttenuation = kwargs.get('mConstantAttenuation', RawVirtoolsLight.cDefaultConstantAttenuation)
self.mLinearAttenuation = kwargs.get('mLinearAttenuation', RawVirtoolsLight.cDefaultLinearAttenuation)
self.mQuadraticAttenuation = kwargs.get('mQuadraticAttenuation', RawVirtoolsLight.cDefaultQuadraticAttenuation)
self.mRange = kwargs.get('mRange', RawVirtoolsLight.cDefaultRange)
self.mHotSpot = kwargs.get('mHotSpot', RawVirtoolsLight.cDefaultHotSpot)
self.mFalloff = kwargs.get('mFalloff', RawVirtoolsLight.cDefaultFalloff)
self.mFalloffShape = kwargs.get('mFalloffShape', RawVirtoolsLight.cDefaultFalloffShape)
def regulate(self) -> None:
# regulate color and reset its alpha value
self.mColor.regulate()
self.mColor.a = 1.0
# regulate range
self.mRange = UTIL_functions.clamp_float(self.mRange, 0.0, 200.0)
# regulate attenuation
self.mConstantAttenuation = UTIL_functions.clamp_float(self.mConstantAttenuation, 0.0, 10.0)
self.mLinearAttenuation = UTIL_functions.clamp_float(self.mLinearAttenuation, 0.0, 10.0)
self.mQuadraticAttenuation = UTIL_functions.clamp_float(self.mQuadraticAttenuation, 0.0, 10.0)
# regulate spot cone
self.mHotSpot = UTIL_functions.clamp_float(self.mHotSpot, 0.0, math.radians(180))
self.mFalloff = UTIL_functions.clamp_float(self.mFalloff, 0.0, math.radians(180))
self.mFalloffShape = UTIL_functions.clamp_float(self.mFalloffShape, 0.0, 10.0)
# regulate spot cone size order
if self.mFalloff < self.mHotSpot:
self.mFalloff = self.mHotSpot
# Blender Property Group
_g_Helper_VXLIGHT_TYPE: UTIL_virtools_types.EnumPropHelper = UTIL_virtools_types.EnumPropHelper(UTIL_virtools_types.VXLIGHT_TYPE)
class BBP_PG_virtools_light(bpy.types.PropertyGroup):
light_type: bpy.props.EnumProperty(
name = "Type",
description = "The type of this light",
items = _g_Helper_VXLIGHT_TYPE.generate_items(),
default = _g_Helper_VXLIGHT_TYPE.to_selection(RawVirtoolsLight.cDefaultType)
) # type: ignore
light_color: bpy.props.FloatVectorProperty(
name = "Color",
description = "Defines the red, green and blue components of the light.",
subtype = 'COLOR',
min = 0.0,
max = 1.0,
size = 3,
default = RawVirtoolsLight.cDefaultColor.to_const_rgb()
) # type: ignore
constant_attenuation: bpy.props.FloatProperty(
name = "Constant Attenuation",
description = "Defines the constant attenuation factor.",
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultConstantAttenuation
) # type: ignore
linear_attenuation: bpy.props.FloatProperty(
name = "Linear Attenuation",
description = "Defines the linear attenuation factor.",
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultLinearAttenuation
) # type: ignore
quadratic_attenuation: bpy.props.FloatProperty(
name = "Quadratic Attenuation",
description = "Defines the quadratic attenuation factor.",
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultQuadraticAttenuation
) # type: ignore
light_range: bpy.props.FloatProperty(
name = "Range",
description = "Defines the radius of the lighting area.",
min = 0.0,
max = 200.0,
step = 100,
default = RawVirtoolsLight.cDefaultRange
) # type: ignore
hot_spot: bpy.props.FloatProperty(
name = "Hot Spot",
description = "Sets the value of the hot spot of the light.",
min = 0.0,
max = math.radians(180),
subtype = 'ANGLE',
default = RawVirtoolsLight.cDefaultHotSpot
) # type: ignore
falloff: bpy.props.FloatProperty(
name = "Fall Off",
description = "Sets the light fall off rate.",
min = 0.0,
max = math.radians(180),
subtype = 'ANGLE',
default = RawVirtoolsLight.cDefaultFalloff
) # type: ignore
falloff_shape: bpy.props.FloatProperty(
name = "Fall Off Shape",
description = "Sets the value of the light fall off shape.",
min = 0.0,
max = 10.0,
step = 10,
default = RawVirtoolsLight.cDefaultFalloffShape
) # type: ignore
# Getter Setter and Applyer
def get_virtools_light(lit: bpy.types.Light) -> BBP_PG_virtools_light:
return lit.virtools_light
def get_raw_virtools_light(lit: bpy.types.Light) -> RawVirtoolsLight:
props: BBP_PG_virtools_light = get_virtools_light(lit)
rawdata: RawVirtoolsLight = RawVirtoolsLight()
rawdata.mType = _g_Helper_VXLIGHT_TYPE.get_selection(props.light_type)
rawdata.mColor.from_const_rgb(props.light_color)
rawdata.mConstantAttenuation = props.constant_attenuation
rawdata.mLinearAttenuation = props.linear_attenuation
rawdata.mQuadraticAttenuation = props.quadratic_attenuation
rawdata.mRange = props.light_range
rawdata.mHotSpot = props.hot_spot
rawdata.mFalloff = props.falloff
rawdata.mFalloffShape = props.falloff_shape
rawdata.regulate()
return rawdata
def set_raw_virtools_light(lit: bpy.types.Light, rawdata: RawVirtoolsLight) -> None:
props: BBP_PG_virtools_light = get_virtools_light(lit)
props.light_type = _g_Helper_VXLIGHT_TYPE.to_selection(rawdata.mType)
props.light_color = rawdata.mColor.to_const_rgb()
props.constant_attenuation = rawdata.mConstantAttenuation
props.linear_attenuation = rawdata.mLinearAttenuation
props.quadratic_attenuation = rawdata.mQuadraticAttenuation
props.light_range = rawdata.mRange
props.hot_spot = rawdata.mHotSpot
props.falloff = rawdata.mFalloff
props.falloff_shape = rawdata.mFalloffShape
def apply_to_blender_light(lit: bpy.types.Light) -> None:
# get raw data first
rawdata: RawVirtoolsLight = get_raw_virtools_light(lit)
# set light type and color
match(rawdata.mType):
case UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTPOINT:
lit.type = 'POINT'
case UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTSPOT:
lit.type = 'SPOT'
case UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTDIREC:
lit.type = 'SUN'
lit.color = rawdata.mColor.to_const_rgb()
# MARK:
# After set light type, we must re-fetch light object,
# because it seems that the object hold by this variable
# is not the object after light type changes.
#
# If I do not do this, function will throw exception
# like `'PointLight' object has no attribute 'spot_size'`.
lit = bpy.data.lights[lit.name]
match(rawdata.mType):
case UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTPOINT:
point_lit: bpy.types.PointLight = typing.cast(bpy.types.PointLight, lit)
point_lit.shadow_soft_size = rawdata.mRange
case UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTSPOT:
spot_lit: bpy.types.SpotLight = typing.cast(bpy.types.SpotLight, lit)
spot_lit.shadow_soft_size = rawdata.mRange
spot_lit.spot_size = rawdata.mFalloff
if rawdata.mFalloff == 0: spot_lit.spot_blend = 0.0
else: spot_lit.spot_blend = 1.0 - rawdata.mHotSpot / rawdata.mFalloff
case UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTDIREC:
pass
# Operators
class BBP_OT_apply_virtools_light(bpy.types.Operator):
"""Apply Virtools Light to Blender Light."""
bl_idname = "bbp.apply_virtools_light"
bl_label = "Apply to Blender Light"
bl_options = {'UNDO'}
@classmethod
def poll(cls, context):
return context.light is not None
def execute(self, context):
lit: bpy.types.Light = context.light
apply_to_blender_light(lit)
return {'FINISHED'}
# Display Panel
class BBP_PT_virtools_light(bpy.types.Panel):
"""Show Virtools Light Properties"""
bl_label = "Virtools Light"
bl_idname = "BBP_PT_virtools_light"
bl_space_type = 'PROPERTIES'
bl_region_type = 'WINDOW'
bl_context = "data" # idk why blender use `data` as the light tab same as mesh.
@classmethod
def poll(cls, context):
return context.light is not None
def draw(self, context):
# get layout and target
layout = self.layout
layout.use_property_split = True
lit: bpy.types.Light = context.light
props: BBP_PG_virtools_light = get_virtools_light(lit)
rawdata: RawVirtoolsLight = get_raw_virtools_light(lit)
# draw operator
layout.operator(BBP_OT_apply_virtools_light.bl_idname, text = 'Apply', icon = 'NODETREE')
# draw data
layout.separator()
layout.label(text = 'Basics')
# all lights has type and color property
sublayout = layout.row()
sublayout.use_property_split = False
sublayout.prop(props, 'light_type', expand = True)
layout.prop(props, 'light_color')
# all light has range property exception directional light
if rawdata.mType != UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTDIREC:
layout.prop(props, 'light_range')
# all light has attenuation exception directional light
if rawdata.mType != UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTDIREC:
layout.separator()
layout.label(text = 'Attenuation')
layout.prop(props, 'constant_attenuation', text = 'Constant')
layout.prop(props, 'linear_attenuation', text = 'Linear')
layout.prop(props, 'quadratic_attenuation', text = 'Quadratic')
# only spot light has spot cone properties.
if rawdata.mType == UTIL_virtools_types.VXLIGHT_TYPE.VX_LIGHTSPOT:
layout.separator()
layout.label(text = 'Spot Cone')
layout.prop(props, 'hot_spot')
layout.prop(props, 'falloff')
layout.prop(props, 'falloff_shape')
# Register
def register() -> None:
bpy.utils.register_class(BBP_PG_virtools_light)
bpy.utils.register_class(BBP_OT_apply_virtools_light)
bpy.utils.register_class(BBP_PT_virtools_light)
# add into light metadata
bpy.types.Light.virtools_light = bpy.props.PointerProperty(type = BBP_PG_virtools_light)
def unregister() -> None:
# remove from metadata
del bpy.types.Light.virtools_light
bpy.utils.unregister_class(BBP_PT_virtools_light)
bpy.utils.unregister_class(BBP_OT_apply_virtools_light)
bpy.utils.unregister_class(BBP_PG_virtools_light)

View File

@ -94,7 +94,7 @@ class RawVirtoolsMaterial():
self.mTextureBorderColor = kwargs.get('mTextureBorderColor', RawVirtoolsMaterial.cDefaultTextureBorderColor).clone()
self.mAlphaRef = kwargs.get('mAlphaRef', RawVirtoolsMaterial.cDefaultAlphaRef)
def regulate(self):
def regulate(self) -> None:
# regulate colors
self.mDiffuse.regulate()
self.mAmbient.regulate()
@ -1017,7 +1017,9 @@ class BBP_PT_virtools_material(bpy.types.Panel):
def draw(self, context):
# get layout and target
layout = self.layout
props: BBP_PG_virtools_material = get_virtools_material(context.material)
mtl: bpy.types.Material = context.material
props: BBP_PG_virtools_material = get_virtools_material(mtl)
rawdata: RawVirtoolsMaterial = get_raw_virtools_material(mtl)
# draw operator
row = layout.row()
@ -1046,7 +1048,7 @@ class BBP_PT_virtools_material(bpy.types.Panel):
sublay.prop(props, 'texture', emboss = True)
sublay.operator(BBP_OT_direct_set_virtools_texture.bl_idname, text = '', icon = 'FILEBROWSER')
# texture detail
if props.texture is not None:
if rawdata.mTexture is not None:
# have texture, show texture settings and enclosed by a border.
boxlayout = layout.box()
boxlayout.label(text="Virtools Texture Settings")
@ -1057,27 +1059,27 @@ class BBP_PT_virtools_material(bpy.types.Panel):
layout.prop(props, 'texture_mag_mode')
layout.prop(props, 'texture_address_mode')
layout.prop(props, 'enable_perspective_correction')
if (int(props.texture_address_mode) == UTIL_virtools_types.VXTEXTURE_ADDRESSMODE.VXTEXTURE_ADDRESSBORDER.value):
if rawdata.mTextureAddressMode == UTIL_virtools_types.VXTEXTURE_ADDRESSMODE.VXTEXTURE_ADDRESSBORDER:
layout.prop(props, 'texture_border_color')
layout.separator()
layout.label(text="Alpha Test Parameters")
layout.prop(props, 'enable_alpha_test')
if props.enable_alpha_test:
if rawdata.mEnableAlphaTest:
layout.prop(props, 'alpha_func')
layout.prop(props, 'alpha_ref')
layout.separator()
layout.label(text="Alpha Blend Parameters")
layout.prop(props, 'enable_alpha_blend')
if props.enable_alpha_blend:
if rawdata.mEnableAlphaBlend:
layout.prop(props, 'source_blend')
layout.prop(props, 'dest_blend')
layout.separator()
layout.label(text="Z Write Parameters")
layout.prop(props, 'enable_z_write')
if props.enable_z_write:
if rawdata.mEnableZWrite:
layout.prop(props, 'z_func')
def register() -> None:

View File

@ -25,7 +25,7 @@ class BBP_PG_virtools_mesh(bpy.types.PropertyGroup):
description = "Lighting mode of the mesh.",
items = _g_Helper_VXMESH_LITMODE.generate_items(),
default = _g_Helper_VXMESH_LITMODE.to_selection(RawVirtoolsMesh.cDefaultLitMode)
)
) # type: ignore
# Getter Setter

View File

@ -30,14 +30,14 @@ class BBP_PG_virtools_texture(bpy.types.PropertyGroup):
description = "When saving a composition textures or sprites can be kept as reference to external files or converted to a given format and saved inside the composition file.",
items = _g_Helper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
default = _g_Helper_CK_TEXTURE_SAVEOPTIONS.to_selection(RawVirtoolsTexture.cDefaultSaveOptions)
)
) # type: ignore
video_format: bpy.props.EnumProperty(
name = "Video Format",
description = "The desired surface pixel format in video memory.",
items = _g_Helper_VX_PIXELFORMAT.generate_items(),
default = _g_Helper_VX_PIXELFORMAT.to_selection(RawVirtoolsTexture.cDefaultVideoFormat)
)
) # type: ignore
#region Virtools Texture Getter Setter

View File

@ -1,3 +0,0 @@
# PyBMap Binding
Please note that this folder is a part of [libcmo21](https://github.com/yyc12345/libcmo21). And all Python scripts is copied from source project. If any issues raised in this sub module, please correct it in parent project and this project will sync to parent project's work.

View File

@ -1,785 +0,0 @@
import ctypes, os, sys, typing
#region Type Defines
class BMapException(Exception):
"""
The exception thrown by BMap bindings.
"""
pass
bm_CKSTRING = ctypes.c_char_p
bm_CKSTRING_p = ctypes.POINTER(bm_CKSTRING)
bm_CKDWORD = ctypes.c_uint32
bm_CKDWORD_p = ctypes.POINTER(bm_CKDWORD)
bm_CKDWORD_pp = ctypes.POINTER(bm_CKDWORD_p)
bm_CKWORD = ctypes.c_uint16
bm_CKWORD_p = ctypes.POINTER(bm_CKWORD)
bm_CKWORD_pp = ctypes.POINTER(bm_CKWORD_p)
bm_CKID = ctypes.c_uint32
bm_CKID_p = ctypes.POINTER(bm_CKID)
bm_CKID_pp = ctypes.POINTER(bm_CKID_p)
bm_CKFLOAT = ctypes.c_float
bm_CKFLOAT_p = ctypes.POINTER(bm_CKFLOAT)
bm_CKINT = ctypes.c_int32
bm_CKBYTE = ctypes.c_uint8
bm_CKBYTE_p = ctypes.POINTER(bm_CKBYTE)
bm_enum = bm_CKDWORD
bm_enum_p = ctypes.POINTER(bm_enum)
bm_bool = ctypes.c_bool
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),
('y', bm_CKFLOAT),
]
bm_VxVector2_p = ctypes.POINTER(bm_VxVector2)
bm_VxVector2_pp = ctypes.POINTER(bm_VxVector2_p)
class bm_VxVector3(ctypes.Structure):
_fields_ = [
('x', bm_CKFLOAT),
('y', bm_CKFLOAT),
('z', bm_CKFLOAT),
]
bm_VxVector3_p = ctypes.POINTER(bm_VxVector3)
bm_VxVector3_pp = ctypes.POINTER(bm_VxVector3_p)
class bm_VxColor(ctypes.Structure):
_fields_ = [
('r', bm_CKFLOAT),
('g', bm_CKFLOAT),
('b', bm_CKFLOAT),
('a', bm_CKFLOAT),
]
bm_VxColor_p = ctypes.POINTER(bm_VxColor)
class bm_VxMatrix(ctypes.Structure):
_fields_ = list(
(f'i{idx}', bm_CKFLOAT) for idx in range(16)
)
bm_VxMatrix_p = ctypes.POINTER(bm_VxMatrix)
#endregion
#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 = None
try:
_g_BMapModule = ctypes.cdll.LoadLibrary(
os.path.join(os.path.dirname(__file__), _g_BMapLibName)
)
except:
_g_BMapModule = None
def is_bmap_available() -> bool:
return _g_BMapModule is not None
def _bmap_error_check(result: bool, func, args):
if not result:
raise BMapException("BMap operation failed.")
return result
def _create_bmap_func(fct_name: str, fct_params: list[typing.Any]) -> typing.Callable[..., bm_bool]:
if _g_BMapModule is None: return None
cache: typing.Callable[..., bm_bool] = getattr(_g_BMapModule, fct_name)
cache.argtypes = fct_params
cache.restype = bm_bool
cache.errcheck = _bmap_error_check
return cache
#endregion
#region Function Defines
## BMInit
# @return True if no error, otherwise False.
BMInit = _create_bmap_func('BMInit', [])
## BMDispose
# @return True if no error, otherwise False.
BMDispose = _create_bmap_func('BMDispose', [])
## BMFile_Load
# @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_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_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.
# @param texture_save_opt[in] Type: LibCmo::CK2::CK_TEXTURE_SAVEOPTIONS.
# @param use_compress[in] Type: bool.
# @param compreess_level[in] Type: LibCmo::CKINT.
# @return True if no error, otherwise False.
BMFile_Save = _create_bmap_func('BMFile_Save', [bm_void_p, bm_CKSTRING, bm_enum, bm_bool, bm_CKINT])
## BMFile_Free
# @param map_file[in] Type: BMap::BMFile*.
# @return True if no error, otherwise False.
BMFile_Free = _create_bmap_func('BMFile_Free', [bm_void_p])
## BMFile_GetGroupCount
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetGroupCount = _create_bmap_func('BMFile_GetGroupCount', [bm_void_p, bm_CKDWORD_p])
## BMFile_GetGroup
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param idx[in] Type: LibCmo::CKDWORD.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetGroup = _create_bmap_func('BMFile_GetGroup', [bm_void_p, bm_CKDWORD, bm_CKID_p])
## BMFile_CreateGroup
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_CreateGroup = _create_bmap_func('BMFile_CreateGroup', [bm_void_p, bm_CKID_p])
## BMFile_Get3dObjectCount
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_Get3dObjectCount = _create_bmap_func('BMFile_Get3dObjectCount', [bm_void_p, bm_CKDWORD_p])
## BMFile_Get3dObject
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param idx[in] Type: LibCmo::CKDWORD.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_Get3dObject = _create_bmap_func('BMFile_Get3dObject', [bm_void_p, bm_CKDWORD, bm_CKID_p])
## BMFile_Create3dObject
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_Create3dObject = _create_bmap_func('BMFile_Create3dObject', [bm_void_p, bm_CKID_p])
## BMFile_GetMeshCount
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetMeshCount = _create_bmap_func('BMFile_GetMeshCount', [bm_void_p, bm_CKDWORD_p])
## BMFile_GetMesh
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param idx[in] Type: LibCmo::CKDWORD.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetMesh = _create_bmap_func('BMFile_GetMesh', [bm_void_p, bm_CKDWORD, bm_CKID_p])
## BMFile_CreateMesh
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_CreateMesh = _create_bmap_func('BMFile_CreateMesh', [bm_void_p, bm_CKID_p])
## BMFile_GetMaterialCount
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetMaterialCount = _create_bmap_func('BMFile_GetMaterialCount', [bm_void_p, bm_CKDWORD_p])
## BMFile_GetMaterial
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param idx[in] Type: LibCmo::CKDWORD.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetMaterial = _create_bmap_func('BMFile_GetMaterial', [bm_void_p, bm_CKDWORD, bm_CKID_p])
## BMFile_CreateMaterial
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_CreateMaterial = _create_bmap_func('BMFile_CreateMaterial', [bm_void_p, bm_CKID_p])
## BMFile_GetTextureCount
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetTextureCount = _create_bmap_func('BMFile_GetTextureCount', [bm_void_p, bm_CKDWORD_p])
## BMFile_GetTexture
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param idx[in] Type: LibCmo::CKDWORD.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_GetTexture = _create_bmap_func('BMFile_GetTexture', [bm_void_p, bm_CKDWORD, bm_CKID_p])
## BMFile_CreateTexture
# @param bmfile[in] Type: BMap::BMFile*. The pointer to corresponding BMFile.
# @param out_id[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMFile_CreateTexture = _create_bmap_func('BMFile_CreateTexture', [bm_void_p, bm_CKID_p])
## BMMeshTrans_New
# @param out_trans[out] Type: BMap::BMMeshTransition*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_New = _create_bmap_func('BMMeshTrans_New', [bm_void_pp])
## BMMeshTrans_Delete
# @param trans[in] Type: BMap::BMMeshTransition*.
# @return True if no error, otherwise False.
BMMeshTrans_Delete = _create_bmap_func('BMMeshTrans_Delete', [bm_void_p])
## BMMeshTrans_PrepareVertexCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareVertexCount = _create_bmap_func('BMMeshTrans_PrepareVertexCount', [bm_void_p, bm_CKDWORD])
## BMMeshTrans_PrepareVertex
# @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.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareVertex = _create_bmap_func('BMMeshTrans_PrepareVertex', [bm_void_p, bm_VxVector3_pp])
## BMMeshTrans_PrepareNormalCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareNormalCount = _create_bmap_func('BMMeshTrans_PrepareNormalCount', [bm_void_p, bm_CKDWORD])
## BMMeshTrans_PrepareNormal
# @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.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareNormal = _create_bmap_func('BMMeshTrans_PrepareNormal', [bm_void_p, bm_VxVector3_pp])
## BMMeshTrans_PrepareUVCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareUVCount = _create_bmap_func('BMMeshTrans_PrepareUVCount', [bm_void_p, bm_CKDWORD])
## BMMeshTrans_PrepareUV
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::VxMath::VxVector2*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareUV = _create_bmap_func('BMMeshTrans_PrepareUV', [bm_void_p, bm_VxVector2_pp])
## BMMeshTrans_PrepareMtlSlotCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareMtlSlotCount = _create_bmap_func('BMMeshTrans_PrepareMtlSlotCount', [bm_void_p, bm_CKDWORD])
## BMMeshTrans_PrepareMtlSlot
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::CK2::CK_ID*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareMtlSlot = _create_bmap_func('BMMeshTrans_PrepareMtlSlot', [bm_void_p, bm_CKID_pp])
## BMMeshTrans_PrepareFaceCount
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareFaceCount = _create_bmap_func('BMMeshTrans_PrepareFaceCount', [bm_void_p, bm_CKDWORD])
## BMMeshTrans_PrepareFaceVertexIndices
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::CKDWORD*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareFaceVertexIndices = _create_bmap_func('BMMeshTrans_PrepareFaceVertexIndices', [bm_void_p, bm_CKDWORD_pp])
## BMMeshTrans_PrepareFaceNormalIndices
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::CKDWORD*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareFaceNormalIndices = _create_bmap_func('BMMeshTrans_PrepareFaceNormalIndices', [bm_void_p, bm_CKDWORD_pp])
## BMMeshTrans_PrepareFaceUVIndices
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::CKDWORD*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareFaceUVIndices = _create_bmap_func('BMMeshTrans_PrepareFaceUVIndices', [bm_void_p, bm_CKDWORD_pp])
## BMMeshTrans_PrepareFaceMtlSlot
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param out_mem[out] Type: LibCmo::CKDWORD*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMeshTrans_PrepareFaceMtlSlot = _create_bmap_func('BMMeshTrans_PrepareFaceMtlSlot', [bm_void_p, bm_CKDWORD_pp])
## BMMeshTrans_Parse
# @param trans[in] Type: BMap::BMMeshTransition*. The pointer to corresponding BMMeshTransition.
# @param bmfile[in] Type: BMap::BMFile*.
# @param objid[in] Type: LibCmo::CK2::CK_ID.
# @return True if no error, otherwise False.
BMMeshTrans_Parse = _create_bmap_func('BMMeshTrans_Parse', [bm_void_p, bm_void_p, bm_CKID])
## BMObject_GetName
# @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_name[out] Type: LibCmo::CKSTRING. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMObject_GetName = _create_bmap_func('BMObject_GetName', [bm_void_p, bm_CKID, bm_CKSTRING_p])
## BMObject_SetName
# @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 name[in] Type: LibCmo::CKSTRING.
# @return True if no error, otherwise False.
BMObject_SetName = _create_bmap_func('BMObject_SetName', [bm_void_p, bm_CKID, bm_CKSTRING])
## BMGroup_AddObject
# @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 memberid[in] Type: LibCmo::CK2::CK_ID.
# @return True if no error, otherwise False.
BMGroup_AddObject = _create_bmap_func('BMGroup_AddObject', [bm_void_p, bm_CKID, bm_CKID])
## BMGroup_GetObjectCount
# @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_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMGroup_GetObjectCount = _create_bmap_func('BMGroup_GetObjectCount', [bm_void_p, bm_CKID, bm_CKDWORD_p])
## BMGroup_GetObject
# @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 pos[in] Type: LibCmo::CKDWORD.
# @param out_objid[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMGroup_GetObject = _create_bmap_func('BMGroup_GetObject', [bm_void_p, bm_CKID, bm_CKDWORD, bm_CKID_p])
## BMTexture_GetFileName
# @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_filename[out] Type: LibCmo::CKSTRING. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMTexture_GetFileName = _create_bmap_func('BMTexture_GetFileName', [bm_void_p, bm_CKID, bm_CKSTRING_p])
## BMTexture_LoadImage
# @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 filename[in] Type: LibCmo::CKSTRING.
# @return True if no error, otherwise False.
BMTexture_LoadImage = _create_bmap_func('BMTexture_LoadImage', [bm_void_p, bm_CKID, bm_CKSTRING])
## BMTexture_SaveImage
# @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 filename[in] Type: LibCmo::CKSTRING.
# @return True if no error, otherwise False.
BMTexture_SaveImage = _create_bmap_func('BMTexture_SaveImage', [bm_void_p, bm_CKID, bm_CKSTRING])
## BMTexture_GetSaveOptions
# @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_saveopt[out] Type: LibCmo::CK2::CK_TEXTURE_SAVEOPTIONS. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMTexture_GetSaveOptions = _create_bmap_func('BMTexture_GetSaveOptions', [bm_void_p, bm_CKID, bm_enum_p])
## BMTexture_SetSaveOptions
# @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 saveopt[in] Type: LibCmo::CK2::CK_TEXTURE_SAVEOPTIONS.
# @return True if no error, otherwise False.
BMTexture_SetSaveOptions = _create_bmap_func('BMTexture_SetSaveOptions', [bm_void_p, bm_CKID, bm_enum])
## BMTexture_GetVideoFormat
# @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_vfmt[out] Type: LibCmo::VxMath::VX_PIXELFORMAT. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMTexture_GetVideoFormat = _create_bmap_func('BMTexture_GetVideoFormat', [bm_void_p, bm_CKID, bm_enum_p])
## BMTexture_SetVideoFormat
# @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 vfmt[in] Type: LibCmo::VxMath::VX_PIXELFORMAT.
# @return True if no error, otherwise False.
BMTexture_SetVideoFormat = _create_bmap_func('BMTexture_SetVideoFormat', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetDiffuse
# @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_val[out] Type: LibCmo::VxMath::VxColor. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetDiffuse = _create_bmap_func('BMMaterial_GetDiffuse', [bm_void_p, bm_CKID, bm_VxColor_p])
## BMMaterial_SetDiffuse
# @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 col[in] Type: LibCmo::VxMath::VxColor.
# @return True if no error, otherwise False.
BMMaterial_SetDiffuse = _create_bmap_func('BMMaterial_SetDiffuse', [bm_void_p, bm_CKID, bm_VxColor])
## BMMaterial_GetAmbient
# @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_val[out] Type: LibCmo::VxMath::VxColor. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetAmbient = _create_bmap_func('BMMaterial_GetAmbient', [bm_void_p, bm_CKID, bm_VxColor_p])
## BMMaterial_SetAmbient
# @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 col[in] Type: LibCmo::VxMath::VxColor.
# @return True if no error, otherwise False.
BMMaterial_SetAmbient = _create_bmap_func('BMMaterial_SetAmbient', [bm_void_p, bm_CKID, bm_VxColor])
## BMMaterial_GetSpecular
# @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_val[out] Type: LibCmo::VxMath::VxColor. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetSpecular = _create_bmap_func('BMMaterial_GetSpecular', [bm_void_p, bm_CKID, bm_VxColor_p])
## BMMaterial_SetSpecular
# @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 col[in] Type: LibCmo::VxMath::VxColor.
# @return True if no error, otherwise False.
BMMaterial_SetSpecular = _create_bmap_func('BMMaterial_SetSpecular', [bm_void_p, bm_CKID, bm_VxColor])
## BMMaterial_GetEmissive
# @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_val[out] Type: LibCmo::VxMath::VxColor. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetEmissive = _create_bmap_func('BMMaterial_GetEmissive', [bm_void_p, bm_CKID, bm_VxColor_p])
## BMMaterial_SetEmissive
# @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 col[in] Type: LibCmo::VxMath::VxColor.
# @return True if no error, otherwise False.
BMMaterial_SetEmissive = _create_bmap_func('BMMaterial_SetEmissive', [bm_void_p, bm_CKID, bm_VxColor])
## BMMaterial_GetSpecularPower
# @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_val[out] Type: LibCmo::CKFLOAT. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetSpecularPower = _create_bmap_func('BMMaterial_GetSpecularPower', [bm_void_p, bm_CKID, bm_CKFLOAT_p])
## BMMaterial_SetSpecularPower
# @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 val[in] Type: LibCmo::CKFLOAT.
# @return True if no error, otherwise False.
BMMaterial_SetSpecularPower = _create_bmap_func('BMMaterial_SetSpecularPower', [bm_void_p, bm_CKID, bm_CKFLOAT])
## BMMaterial_GetTexture
# @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_texid[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTexture = _create_bmap_func('BMMaterial_GetTexture', [bm_void_p, bm_CKID, bm_CKID_p])
## BMMaterial_SetTexture
# @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 texid[in] Type: LibCmo::CK2::CK_ID.
# @return True if no error, otherwise False.
BMMaterial_SetTexture = _create_bmap_func('BMMaterial_SetTexture', [bm_void_p, bm_CKID, bm_CKID])
## BMMaterial_GetTextureBorderColor
# @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_val[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTextureBorderColor = _create_bmap_func('BMMaterial_GetTextureBorderColor', [bm_void_p, bm_CKID, bm_CKDWORD_p])
## BMMaterial_SetTextureBorderColor
# @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 val[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMaterial_SetTextureBorderColor = _create_bmap_func('BMMaterial_SetTextureBorderColor', [bm_void_p, bm_CKID, bm_CKDWORD])
## BMMaterial_GetTextureBlendMode
# @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_val[out] Type: LibCmo::VxMath::VXTEXTURE_BLENDMODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTextureBlendMode = _create_bmap_func('BMMaterial_GetTextureBlendMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetTextureBlendMode
# @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 val[in] Type: LibCmo::VxMath::VXTEXTURE_BLENDMODE.
# @return True if no error, otherwise False.
BMMaterial_SetTextureBlendMode = _create_bmap_func('BMMaterial_SetTextureBlendMode', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetTextureMinMode
# @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_val[out] Type: LibCmo::VxMath::VXTEXTURE_FILTERMODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTextureMinMode = _create_bmap_func('BMMaterial_GetTextureMinMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetTextureMinMode
# @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 val[in] Type: LibCmo::VxMath::VXTEXTURE_FILTERMODE.
# @return True if no error, otherwise False.
BMMaterial_SetTextureMinMode = _create_bmap_func('BMMaterial_SetTextureMinMode', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetTextureMagMode
# @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_val[out] Type: LibCmo::VxMath::VXTEXTURE_FILTERMODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTextureMagMode = _create_bmap_func('BMMaterial_GetTextureMagMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetTextureMagMode
# @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 val[in] Type: LibCmo::VxMath::VXTEXTURE_FILTERMODE.
# @return True if no error, otherwise False.
BMMaterial_SetTextureMagMode = _create_bmap_func('BMMaterial_SetTextureMagMode', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetTextureAddressMode
# @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_val[out] Type: LibCmo::VxMath::VXTEXTURE_ADDRESSMODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTextureAddressMode = _create_bmap_func('BMMaterial_GetTextureAddressMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetTextureAddressMode
# @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 val[in] Type: LibCmo::VxMath::VXTEXTURE_ADDRESSMODE.
# @return True if no error, otherwise False.
BMMaterial_SetTextureAddressMode = _create_bmap_func('BMMaterial_SetTextureAddressMode', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetSourceBlend
# @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_val[out] Type: LibCmo::VxMath::VXBLEND_MODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetSourceBlend = _create_bmap_func('BMMaterial_GetSourceBlend', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetSourceBlend
# @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 val[in] Type: LibCmo::VxMath::VXBLEND_MODE.
# @return True if no error, otherwise False.
BMMaterial_SetSourceBlend = _create_bmap_func('BMMaterial_SetSourceBlend', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetDestBlend
# @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_val[out] Type: LibCmo::VxMath::VXBLEND_MODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetDestBlend = _create_bmap_func('BMMaterial_GetDestBlend', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetDestBlend
# @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 val[in] Type: LibCmo::VxMath::VXBLEND_MODE.
# @return True if no error, otherwise False.
BMMaterial_SetDestBlend = _create_bmap_func('BMMaterial_SetDestBlend', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetFillMode
# @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_val[out] Type: LibCmo::VxMath::VXFILL_MODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetFillMode = _create_bmap_func('BMMaterial_GetFillMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetFillMode
# @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 val[in] Type: LibCmo::VxMath::VXFILL_MODE.
# @return True if no error, otherwise False.
BMMaterial_SetFillMode = _create_bmap_func('BMMaterial_SetFillMode', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetShadeMode
# @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_val[out] Type: LibCmo::VxMath::VXSHADE_MODE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetShadeMode = _create_bmap_func('BMMaterial_GetShadeMode', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetShadeMode
# @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 val[in] Type: LibCmo::VxMath::VXSHADE_MODE.
# @return True if no error, otherwise False.
BMMaterial_SetShadeMode = _create_bmap_func('BMMaterial_SetShadeMode', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetAlphaTestEnabled
# @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_val[out] Type: bool. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetAlphaTestEnabled = _create_bmap_func('BMMaterial_GetAlphaTestEnabled', [bm_void_p, bm_CKID, bm_bool_p])
## BMMaterial_SetAlphaTestEnabled
# @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 enabled[in] Type: bool.
# @return True if no error, otherwise False.
BMMaterial_SetAlphaTestEnabled = _create_bmap_func('BMMaterial_SetAlphaTestEnabled', [bm_void_p, bm_CKID, bm_bool])
## BMMaterial_GetAlphaBlendEnabled
# @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_val[out] Type: bool. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetAlphaBlendEnabled = _create_bmap_func('BMMaterial_GetAlphaBlendEnabled', [bm_void_p, bm_CKID, bm_bool_p])
## BMMaterial_SetAlphaBlendEnabled
# @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 enabled[in] Type: bool.
# @return True if no error, otherwise False.
BMMaterial_SetAlphaBlendEnabled = _create_bmap_func('BMMaterial_SetAlphaBlendEnabled', [bm_void_p, bm_CKID, bm_bool])
## BMMaterial_GetPerspectiveCorrectionEnabled
# @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_val[out] Type: bool. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetPerspectiveCorrectionEnabled = _create_bmap_func('BMMaterial_GetPerspectiveCorrectionEnabled', [bm_void_p, bm_CKID, bm_bool_p])
## BMMaterial_SetPerspectiveCorrectionEnabled
# @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 enabled[in] Type: bool.
# @return True if no error, otherwise False.
BMMaterial_SetPerspectiveCorrectionEnabled = _create_bmap_func('BMMaterial_SetPerspectiveCorrectionEnabled', [bm_void_p, bm_CKID, bm_bool])
## BMMaterial_GetZWriteEnabled
# @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_val[out] Type: bool. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetZWriteEnabled = _create_bmap_func('BMMaterial_GetZWriteEnabled', [bm_void_p, bm_CKID, bm_bool_p])
## BMMaterial_SetZWriteEnabled
# @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 enabled[in] Type: bool.
# @return True if no error, otherwise False.
BMMaterial_SetZWriteEnabled = _create_bmap_func('BMMaterial_SetZWriteEnabled', [bm_void_p, bm_CKID, bm_bool])
## BMMaterial_GetTwoSidedEnabled
# @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_val[out] Type: bool. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetTwoSidedEnabled = _create_bmap_func('BMMaterial_GetTwoSidedEnabled', [bm_void_p, bm_CKID, bm_bool_p])
## BMMaterial_SetTwoSidedEnabled
# @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 enabled[in] Type: bool.
# @return True if no error, otherwise False.
BMMaterial_SetTwoSidedEnabled = _create_bmap_func('BMMaterial_SetTwoSidedEnabled', [bm_void_p, bm_CKID, bm_bool])
## BMMaterial_GetAlphaRef
# @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_val[out] Type: LibCmo::CKBYTE. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetAlphaRef = _create_bmap_func('BMMaterial_GetAlphaRef', [bm_void_p, bm_CKID, bm_CKBYTE_p])
## BMMaterial_SetAlphaRef
# @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 val[in] Type: LibCmo::CKBYTE.
# @return True if no error, otherwise False.
BMMaterial_SetAlphaRef = _create_bmap_func('BMMaterial_SetAlphaRef', [bm_void_p, bm_CKID, bm_CKBYTE])
## BMMaterial_GetAlphaFunc
# @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_val[out] Type: LibCmo::VxMath::VXCMPFUNC. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetAlphaFunc = _create_bmap_func('BMMaterial_GetAlphaFunc', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetAlphaFunc
# @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 val[in] Type: LibCmo::VxMath::VXCMPFUNC.
# @return True if no error, otherwise False.
BMMaterial_SetAlphaFunc = _create_bmap_func('BMMaterial_SetAlphaFunc', [bm_void_p, bm_CKID, bm_enum])
## BMMaterial_GetZFunc
# @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_val[out] Type: LibCmo::VxMath::VXCMPFUNC. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMaterial_GetZFunc = _create_bmap_func('BMMaterial_GetZFunc', [bm_void_p, bm_CKID, bm_enum_p])
## BMMaterial_SetZFunc
# @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 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.
# @param out_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetVertexCount = _create_bmap_func('BMMesh_GetVertexCount', [bm_void_p, bm_CKID, bm_CKDWORD_p])
## BMMesh_SetVertexCount
# @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 count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMesh_SetVertexCount = _create_bmap_func('BMMesh_SetVertexCount', [bm_void_p, bm_CKID, bm_CKDWORD])
## BMMesh_GetVertexPositions
# @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_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetVertexPositions = _create_bmap_func('BMMesh_GetVertexPositions', [bm_void_p, bm_CKID, bm_VxVector3_pp])
## BMMesh_GetVertexNormals
# @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_mem[out] Type: LibCmo::VxMath::VxVector3*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetVertexNormals = _create_bmap_func('BMMesh_GetVertexNormals', [bm_void_p, bm_CKID, bm_VxVector3_pp])
## BMMesh_GetVertexUVs
# @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_mem[out] Type: LibCmo::VxMath::VxVector2*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetVertexUVs = _create_bmap_func('BMMesh_GetVertexUVs', [bm_void_p, bm_CKID, bm_VxVector2_pp])
## BMMesh_GetFaceCount
# @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_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetFaceCount = _create_bmap_func('BMMesh_GetFaceCount', [bm_void_p, bm_CKID, bm_CKDWORD_p])
## BMMesh_SetFaceCount
# @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 count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMesh_SetFaceCount = _create_bmap_func('BMMesh_SetFaceCount', [bm_void_p, bm_CKID, bm_CKDWORD])
## BMMesh_GetFaceIndices
# @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_mem[out] Type: LibCmo::CKWORD*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetFaceIndices = _create_bmap_func('BMMesh_GetFaceIndices', [bm_void_p, bm_CKID, bm_CKWORD_pp])
## BMMesh_GetFaceMaterialSlotIndexs
# @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_mem[out] Type: LibCmo::CKWORD*. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetFaceMaterialSlotIndexs = _create_bmap_func('BMMesh_GetFaceMaterialSlotIndexs', [bm_void_p, bm_CKID, bm_CKWORD_pp])
## BMMesh_GetMaterialSlotCount
# @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_count[out] Type: LibCmo::CKDWORD. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetMaterialSlotCount = _create_bmap_func('BMMesh_GetMaterialSlotCount', [bm_void_p, bm_CKID, bm_CKDWORD_p])
## BMMesh_SetMaterialSlotCount
# @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 count[in] Type: LibCmo::CKDWORD.
# @return True if no error, otherwise False.
BMMesh_SetMaterialSlotCount = _create_bmap_func('BMMesh_SetMaterialSlotCount', [bm_void_p, bm_CKID, bm_CKDWORD])
## BMMesh_GetMaterialSlot
# @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 index[in] Type: LibCmo::CKDWORD.
# @param out_mtlid[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BMMesh_GetMaterialSlot = _create_bmap_func('BMMesh_GetMaterialSlot', [bm_void_p, bm_CKID, bm_CKDWORD, bm_CKID_p])
## BMMesh_SetMaterialSlot
# @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 index[in] Type: LibCmo::CKDWORD.
# @param mtlid[in] Type: LibCmo::CK2::CK_ID.
# @return True if no error, otherwise False.
BMMesh_SetMaterialSlot = _create_bmap_func('BMMesh_SetMaterialSlot', [bm_void_p, bm_CKID, bm_CKDWORD, bm_CKID])
## BM3dObject_GetWorldMatrix
# @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_mat[out] Type: LibCmo::VxMath::VxMatrix. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BM3dObject_GetWorldMatrix = _create_bmap_func('BM3dObject_GetWorldMatrix', [bm_void_p, bm_CKID, bm_VxMatrix_p])
## BM3dObject_SetWorldMatrix
# @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 mat[in] Type: LibCmo::VxMath::VxMatrix.
# @return True if no error, otherwise False.
BM3dObject_SetWorldMatrix = _create_bmap_func('BM3dObject_SetWorldMatrix', [bm_void_p, bm_CKID, bm_VxMatrix])
## BM3dObject_GetCurrentMesh
# @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_meshid[out] Type: LibCmo::CK2::CK_ID. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BM3dObject_GetCurrentMesh = _create_bmap_func('BM3dObject_GetCurrentMesh', [bm_void_p, bm_CKID, bm_CKID_p])
## BM3dObject_SetCurrentMesh
# @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 meshid[in] Type: LibCmo::CK2::CK_ID.
# @return True if no error, otherwise False.
BM3dObject_SetCurrentMesh = _create_bmap_func('BM3dObject_SetCurrentMesh', [bm_void_p, bm_CKID, bm_CKID])
## BM3dObject_GetVisibility
# @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_isVisible[out] Type: bool. Use ctypes.byref(data) pass it.
# @return True if no error, otherwise False.
BM3dObject_GetVisibility = _create_bmap_func('BM3dObject_GetVisibility', [bm_void_p, bm_CKID, bm_bool_p])
## BM3dObject_SetVisibility
# @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 is_visible[in] Type: bool.
# @return True if no error, otherwise False.
BM3dObject_SetVisibility = _create_bmap_func('BM3dObject_SetVisibility', [bm_void_p, bm_CKID, bm_bool])
#endregion

View File

@ -1,865 +0,0 @@
import ctypes, typing, atexit
from . import bmap, virtools_types
#region Basic Class & Constant Defines
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)}')
_g_RawCallback: bmap.bm_callback = bmap.bm_callback(_python_callback)
class _AbstractPointer():
__mRawPointer: int
def __init__(self, raw_pointer: bmap.bm_void_p):
self._set_pointer(raw_pointer)
def _is_valid(self) -> bool:
return self.__mRawPointer != 0
def _get_pointer(self) -> bmap.bm_void_p:
return bmap.bm_void_p(self.__mRawPointer)
def _set_pointer(self, raw_pointer: bmap.bm_void_p):
if raw_pointer.value is None:
self.__mRawPointer = 0
else:
self.__mRawPointer = raw_pointer.value
def __eq__(self, obj: object) -> bool:
if isinstance(obj, self.__class__):
return obj.__mRawPointer == self.__mRawPointer
else:
return False
def __hash__(self) -> int:
return hash(self.__mRawPointer)
class _AbstractCKObject(_AbstractPointer):
__mCKID: int
def __init__(self, raw_pointer: bmap.bm_void_p, ckid: bmap.bm_CKID):
_AbstractPointer.__init__(self, raw_pointer)
self.__mCKID = ckid.value
def _is_valid(self) -> bool:
return _AbstractPointer._is_valid(self) and self.__mCKID != 0
def _get_ckid(self) -> bmap.bm_CKID:
return bmap.bm_CKID(self.__mCKID)
def __eq__(self, obj: object) -> bool:
if not _AbstractPointer.__eq__(self, obj): return False
if isinstance(obj, self.__class__):
return obj.__mCKID == self.__mCKID
else:
return False
def __hash__(self) -> int:
return hash((_AbstractPointer.__hash__(self), self.__mCKID))
#endregion
#region Help Function & Type Define
TCKObj = typing.TypeVar('TCKObj', bound = _AbstractCKObject)
def _vxvector3_assigner(pvector: bmap.bm_VxVector3_p, count: int, itor: typing.Iterator[virtools_types.VxVector3]) -> None:
pfloat: bmap.bm_CKFLOAT_p = ctypes.cast(pvector, bmap.bm_CKFLOAT_p)
idx: int = 0
for _ in range(count):
uservector: virtools_types.VxVector3 = next(itor)
pfloat[idx] = uservector.x
pfloat[idx + 1] = uservector.y
pfloat[idx + 2] = uservector.z
idx += 3
def _vxvector3_iterator(pvector: bmap.bm_VxVector3_p, count: int) -> typing.Iterator[virtools_types.VxVector3]:
ret: virtools_types.VxVector3 = virtools_types.VxVector3()
pfloat: bmap.bm_CKFLOAT_p = ctypes.cast(pvector, bmap.bm_CKFLOAT_p)
idx: int = 0
for _ in range(count):
ret.x = pfloat[idx]
ret.y = pfloat[idx + 1]
ret.z = pfloat[idx + 2]
idx += 3
yield ret
def _vxvector2_assigner(pvector: bmap.bm_VxVector2_p, count: int, itor: typing.Iterator[virtools_types.VxVector2]) -> None:
pfloat: bmap.bm_CKFLOAT_p = ctypes.cast(pvector, bmap.bm_CKFLOAT_p)
idx: int = 0
for _ in range(count):
uservector: virtools_types.VxVector2 = next(itor)
pfloat[idx] = uservector.x
pfloat[idx + 1] = uservector.y
idx += 2
def _vxvector2_iterator(pvector: bmap.bm_VxVector2_p, count: int) -> typing.Iterator[virtools_types.VxVector2]:
ret: virtools_types.VxVector2 = virtools_types.VxVector2()
pfloat: bmap.bm_CKFLOAT_p = ctypes.cast(pvector, bmap.bm_CKFLOAT_p)
idx: int = 0
for _ in range(count):
ret.x = pfloat[idx]
ret.y = pfloat[idx + 1]
idx += 2
yield ret
# 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
for _ in range(count):
userindices: virtools_types.CKFaceIndices = next(itor)
pindices[idx] = userindices.i1
pindices[idx + 1] = userindices.i2
pindices[idx + 2] = userindices.i3
idx += 3
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()
idx: int = 0
for _ in range(count):
ret.i1 = pindices[idx]
ret.i2 = pindices[idx + 1]
ret.i3 = pindices[idx + 2]
idx += 3
yield ret
#endregion
#region Valid Check, Init and Dispose
def is_bmap_available() -> bool:
return bmap.is_bmap_available()
# init module self and register exit function
if is_bmap_available():
bmap.BMInit()
def _auto_exit():
bmap.BMDispose()
atexit.register(_auto_exit)
#endregion
#region Real Type Defines
"""!
@remark
BMFileReader, BMFileWriter, and BMMeshTrans can be create by given constructor.
But they must be destroyed by calling dispose(). Otherwise it may cause memory leak.
You also can use python `with` statement to achieve this automatically.
BMObject, BMTexture, BMMaterial, BMMesh, and BM3dObject should NOT be constructed from given constructor.
They must be obtained from BMFileReader, BMFileWriter, and BMMeshTrans.
Thus BMObject, BMTexture, BMMaterial, BMMesh, and BM3dObject also do not need to free
because these resources are sotred in BMFileReader, BMFileWriter, and BMMeshTrans.
We just provide them as a visitor.
"""
class BMObject(_AbstractCKObject):
def get_name(self) -> str | None:
name: bmap.bm_CKSTRING = bmap.bm_CKSTRING()
bmap.BMObject_GetName(self._get_pointer(), self._get_ckid(), ctypes.byref(name))
if name.value is None:
return None
else:
return name.value.decode(g_BMapEncoding)
def set_name(self, name_: str | None) -> None:
name: bmap.bm_CKSTRING
if name_ is None:
name = bmap.bm_CKSTRING(0)
else:
name = bmap.bm_CKSTRING(name_.encode(g_BMapEncoding))
bmap.BMObject_SetName(self._get_pointer(), self._get_ckid(), name)
class BMTexture(BMObject):
def get_file_name(self) -> str | None:
filename: bmap.bm_CKSTRING = bmap.bm_CKSTRING()
bmap.BMTexture_GetFileName(self._get_pointer(), self._get_ckid(), ctypes.byref(filename))
if filename.value is None:
return None
else:
return filename.value.decode(g_BMapEncoding)
def load_image(self, filepath: str) -> None:
filename: bmap.bm_CKSTRING = bmap.bm_CKSTRING(filepath.encode(g_BMapEncoding))
bmap.BMTexture_LoadImage(self._get_pointer(), self._get_ckid(), filename)
def save_image(self, filepath: str) -> None:
filename: bmap.bm_CKSTRING = bmap.bm_CKSTRING(filepath.encode(g_BMapEncoding))
bmap.BMTexture_SaveImage(self._get_pointer(), self._get_ckid(), filename)
def get_save_options(self) -> virtools_types.CK_TEXTURE_SAVEOPTIONS:
opt: bmap.bm_enum = bmap.bm_enum()
bmap.BMTexture_GetSaveOptions(self._get_pointer(), self._get_ckid(), ctypes.byref(opt))
return virtools_types.CK_TEXTURE_SAVEOPTIONS(opt.value)
def set_save_options(self, opt_: virtools_types.CK_TEXTURE_SAVEOPTIONS) -> None:
opt: bmap.bm_enum = bmap.bm_enum(opt_.value)
bmap.BMTexture_SetSaveOptions(self._get_pointer(), self._get_ckid(), opt)
def get_video_format(self) -> virtools_types.VX_PIXELFORMAT:
fmt: bmap.bm_enum = bmap.bm_enum()
bmap.BMTexture_GetVideoFormat(self._get_pointer(), self._get_ckid(), ctypes.byref(fmt))
return virtools_types.VX_PIXELFORMAT(fmt.value)
def set_video_format(self, fmt_: virtools_types.VX_PIXELFORMAT) -> None:
fmt: bmap.bm_enum = bmap.bm_enum(fmt_.value)
bmap.BMTexture_SetVideoFormat(self._get_pointer(), self._get_ckid(), fmt)
class BMMaterial(BMObject):
def _set_vxcolor(self,
setter_: typing.Callable[[bmap.bm_void_p, bmap.bm_CKID, bmap.bm_VxColor], bool],
col_: virtools_types.VxColor) -> None:
# set to raw color
col: bmap.bm_VxColor = bmap.bm_VxColor()
col.r = col_.r
col.g = col_.g
col.b = col_.b
col.a = col_.a
# assign
setter_(self._get_pointer(), self._get_ckid(), col)
def _get_vxcolor(self,
getter_: typing.Callable[[bmap.bm_void_p, bmap.bm_CKID, bmap.bm_VxColor_p], bool]) -> virtools_types.VxColor:
# get raw color
col: bmap.bm_VxColor = bmap.bm_VxColor()
getter_(self._get_pointer(), self._get_ckid(), ctypes.byref(col))
# get from raw color
ret: virtools_types.VxColor = virtools_types.VxColor()
ret.r = col.r
ret.g = col.g
ret.b = col.b
ret.a = col.a
return ret
def get_diffuse(self) -> virtools_types.VxColor:
return self._get_vxcolor(bmap.BMMaterial_GetDiffuse)
def set_diffuse(self, col: virtools_types.VxColor) -> None:
self._set_vxcolor(bmap.BMMaterial_SetDiffuse, col)
def get_ambient(self) -> virtools_types.VxColor:
return self._get_vxcolor(bmap.BMMaterial_GetAmbient)
def set_ambient(self, col: virtools_types.VxColor) -> None:
self._set_vxcolor(bmap.BMMaterial_SetAmbient, col)
def get_specular(self) -> virtools_types.VxColor:
return self._get_vxcolor(bmap.BMMaterial_GetSpecular)
def set_specular(self, col: virtools_types.VxColor) -> None:
self._set_vxcolor(bmap.BMMaterial_SetSpecular, col)
def get_emissive(self) -> virtools_types.VxColor:
return self._get_vxcolor(bmap.BMMaterial_GetEmissive)
def set_emissive(self, col: virtools_types.VxColor) -> None:
self._set_vxcolor(bmap.BMMaterial_SetEmissive, col)
def get_specular_power(self) -> float:
power: bmap.bm_CKFLOAT = bmap.bm_CKFLOAT()
bmap.BMMaterial_GetSpecularPower(self._get_pointer(), self._get_ckid(), ctypes.byref(power))
return power.value
def set_specular_power(self, power_: float) -> None:
power: bmap.bm_CKFLOAT = bmap.bm_CKFLOAT(power_)
bmap.BMMaterial_SetSpecularPower(self._get_pointer(), self._get_ckid(), power)
def get_texture(self) -> BMTexture | None:
objid: bmap.bm_CKID = bmap.bm_CKID()
bmap.BMMaterial_GetTexture(self._get_pointer(), self._get_ckid(), ctypes.byref(objid))
if objid.value == g_InvalidCKID:
return None
else:
return BMTexture(self._get_pointer(), objid)
def set_texture(self, tex_: BMTexture | None) -> None:
objid: bmap.bm_CKID = bmap.bm_CKID(g_InvalidCKID)
if tex_ is not None:
objid = tex_._get_ckid()
bmap.BMMaterial_SetTexture(self._get_pointer(), self._get_ckid(), objid)
def get_texture_border_color(self) -> virtools_types.VxColor:
col: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
bmap.BMMaterial_GetTextureBorderColor(self._get_pointer(), self._get_ckid(), ctypes.byref(col))
ret: virtools_types.VxColor = virtools_types.VxColor()
ret.from_dword(col.value)
return ret
def set_texture_border_color(self, col_: virtools_types.VxColor) -> None:
col: bmap.bm_CKDWORD = bmap.bm_CKDWORD(col_.to_dword())
bmap.BMMaterial_SetTextureBorderColor(self._get_pointer(), self._get_ckid(), col)
def get_texture_blend_mode(self) -> virtools_types.VXTEXTURE_BLENDMODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetTextureBlendMode(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXTEXTURE_BLENDMODE(data.value)
def set_texture_blend_mode(self, data_: virtools_types.VXTEXTURE_BLENDMODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetTextureBlendMode(self._get_pointer(), self._get_ckid(), data)
def get_texture_min_mode(self) -> virtools_types.VXTEXTURE_FILTERMODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetTextureMinMode(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXTEXTURE_FILTERMODE(data.value)
def set_texture_min_mode(self, data_: virtools_types.VXTEXTURE_FILTERMODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetTextureMinMode(self._get_pointer(), self._get_ckid(), data)
def get_texture_mag_mode(self) -> virtools_types.VXTEXTURE_FILTERMODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetTextureMagMode(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXTEXTURE_FILTERMODE(data.value)
def set_texture_mag_mode(self, data_: virtools_types.VXTEXTURE_FILTERMODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetTextureMagMode(self._get_pointer(), self._get_ckid(), data)
def get_texture_address_mode(self) -> virtools_types.VXTEXTURE_ADDRESSMODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetTextureAddressMode(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXTEXTURE_ADDRESSMODE(data.value)
def set_texture_address_mode(self, data_: virtools_types.VXTEXTURE_ADDRESSMODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetTextureAddressMode(self._get_pointer(), self._get_ckid(), data)
def get_source_blend(self) -> virtools_types.VXBLEND_MODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetSourceBlend(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXBLEND_MODE(data.value)
def set_source_blend(self, data_: virtools_types.VXBLEND_MODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetSourceBlend(self._get_pointer(), self._get_ckid(), data)
def get_dest_blend(self) -> virtools_types.VXBLEND_MODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetDestBlend(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXBLEND_MODE(data.value)
def set_dest_blend(self, data_: virtools_types.VXBLEND_MODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetDestBlend(self._get_pointer(), self._get_ckid(), data)
def get_fill_mode(self) -> virtools_types.VXFILL_MODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetFillMode(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXFILL_MODE(data.value)
def set_fill_mode(self, data_: virtools_types.VXFILL_MODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetFillMode(self._get_pointer(), self._get_ckid(), data)
def get_shade_mode(self) -> virtools_types.VXSHADE_MODE:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetShadeMode(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXSHADE_MODE(data.value)
def set_shade_mode(self, data_: virtools_types.VXSHADE_MODE) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetShadeMode(self._get_pointer(), self._get_ckid(), data)
def get_alpha_test_enabled(self) -> bool:
data: bmap.bm_bool = bmap.bm_bool()
bmap.BMMaterial_GetAlphaTestEnabled(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return data.value
def set_alpha_test_enabled(self, data_: bool) -> None:
data: bmap.bm_bool = bmap.bm_bool(data_)
bmap.BMMaterial_SetAlphaTestEnabled(self._get_pointer(), self._get_ckid(), data)
def get_alpha_blend_enabled(self) -> bool:
data: bmap.bm_bool = bmap.bm_bool()
bmap.BMMaterial_GetAlphaBlendEnabled(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return data.value
def set_alpha_blend_enabled(self, data_: bool) -> None:
data: bmap.bm_bool = bmap.bm_bool(data_)
bmap.BMMaterial_SetAlphaBlendEnabled(self._get_pointer(), self._get_ckid(), data)
def get_perspective_correction_enabled(self) -> bool:
data: bmap.bm_bool = bmap.bm_bool()
bmap.BMMaterial_GetPerspectiveCorrectionEnabled(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return data.value
def set_perspective_correction_enabled(self, data_: bool) -> None:
data: bmap.bm_bool = bmap.bm_bool(data_)
bmap.BMMaterial_SetPerspectiveCorrectionEnabled(self._get_pointer(), self._get_ckid(), data)
def get_z_write_enabled(self) -> bool:
data: bmap.bm_bool = bmap.bm_bool()
bmap.BMMaterial_GetZWriteEnabled(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return data.value
def set_z_write_enabled(self, data_: bool) -> None:
data: bmap.bm_bool = bmap.bm_bool(data_)
bmap.BMMaterial_SetZWriteEnabled(self._get_pointer(), self._get_ckid(), data)
def get_two_sided_enabled(self) -> bool:
data: bmap.bm_bool = bmap.bm_bool()
bmap.BMMaterial_GetTwoSidedEnabled(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return data.value
def set_two_sided_enabled(self, data_: bool) -> None:
data: bmap.bm_bool = bmap.bm_bool(data_)
bmap.BMMaterial_SetTwoSidedEnabled(self._get_pointer(), self._get_ckid(), data)
def get_alpha_ref(self) -> int:
data: bmap.bm_CKBYTE = bmap.bm_CKBYTE()
bmap.BMMaterial_GetAlphaRef(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return data.value
def set_alpha_ref(self, data_: int):
data: bmap.bm_CKBYTE = bmap.bm_CKBYTE(data_)
bmap.BMMaterial_SetAlphaRef(self._get_pointer(), self._get_ckid(), data)
def get_alpha_func(self) -> virtools_types.VXCMPFUNC:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetAlphaFunc(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXCMPFUNC(data.value)
def set_alpha_func(self, data_: virtools_types.VXCMPFUNC) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
bmap.BMMaterial_SetAlphaFunc(self._get_pointer(), self._get_ckid(), data)
def get_z_func(self) -> virtools_types.VXCMPFUNC:
data: bmap.bm_enum = bmap.bm_enum()
bmap.BMMaterial_GetZFunc(self._get_pointer(), self._get_ckid(), ctypes.byref(data))
return virtools_types.VXCMPFUNC(data.value)
def set_z_func(self, data_: virtools_types.VXCMPFUNC) -> None:
data: bmap.bm_enum = bmap.bm_enum(data_.value)
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))
return count.value
def set_vertex_count(self, count_: int) -> None:
count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count_)
bmap.BMMesh_SetVertexCount(self._get_pointer(), self._get_ckid(), count)
def get_vertex_positions(self) -> typing.Iterator[virtools_types.VxVector3]:
# get raw pointer and return
raw_vector: bmap.bm_VxVector3_p = bmap.bm_VxVector3_p()
bmap.BMMesh_GetVertexPositions(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
return _vxvector3_iterator(raw_vector, self.get_vertex_count())
def set_vertex_positions(self, itor: typing.Iterator[virtools_types.VxVector3]) -> None:
# get raw float pointer and assign
raw_vector: bmap.bm_VxVector3_p = bmap.bm_VxVector3_p()
bmap.BMMesh_GetVertexPositions(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
_vxvector3_assigner(raw_vector, self.get_vertex_count(), itor)
def get_vertex_normals(self) -> typing.Iterator[virtools_types.VxVector3]:
raw_vector: bmap.bm_VxVector3_p = bmap.bm_VxVector3_p()
bmap.BMMesh_GetVertexNormals(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
return _vxvector3_iterator(raw_vector, self.get_vertex_count())
def set_vertex_normals(self, itor: typing.Iterator[virtools_types.VxVector3]) -> None:
raw_vector: bmap.bm_VxVector3_p = bmap.bm_VxVector3_p()
bmap.BMMesh_GetVertexNormals(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
_vxvector3_assigner(raw_vector, self.get_vertex_count(), itor)
def get_vertex_uvs(self) -> typing.Iterator[virtools_types.VxVector2]:
raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p()
bmap.BMMesh_GetVertexUVs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
return _vxvector2_iterator(raw_vector, self.get_vertex_count())
def set_vertex_uvs(self, itor: typing.Iterator[virtools_types.VxVector2]) -> None:
raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p()
bmap.BMMesh_GetVertexUVs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_vector))
_vxvector2_assigner(raw_vector, self.get_vertex_count(), itor)
def get_face_count(self) -> int:
count: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
bmap.BMMesh_GetFaceCount(self._get_pointer(), self._get_ckid(), ctypes.byref(count))
return count.value
def set_face_count(self, count_: int) -> None:
count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count_)
bmap.BMMesh_SetFaceCount(self._get_pointer(), self._get_ckid(), count)
def get_face_indices(self) -> typing.Iterator[virtools_types.CKFaceIndices]:
raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p()
bmap.BMMesh_GetFaceIndices(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx))
return _ckfaceindices_iterator(raw_idx, self.get_face_count())
def set_face_indices(self, itor: typing.Iterator[virtools_types.CKFaceIndices]) -> None:
raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p()
bmap.BMMesh_GetFaceIndices(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx))
_ckfaceindices_assigner(raw_idx, self.get_face_count(), itor)
def get_face_material_slot_indexs(self) -> typing.Iterator[int]:
raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p()
bmap.BMMesh_GetFaceMaterialSlotIndexs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx))
for i in range(self.get_face_count()):
yield raw_idx[i]
def set_face_material_slot_indexs(self, itor: typing.Iterator[int]) -> None:
raw_idx: bmap.bm_CKWORD_p = bmap.bm_CKWORD_p()
bmap.BMMesh_GetFaceMaterialSlotIndexs(self._get_pointer(), self._get_ckid(), ctypes.byref(raw_idx))
for i in range(self.get_face_count()):
raw_idx[i] = next(itor)
def get_material_slot_count(self) -> int:
count: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
bmap.BMMesh_GetMaterialSlotCount(self._get_pointer(), self._get_ckid(), ctypes.byref(count))
return count.value
def set_material_slot_count(self, count_: int) -> None:
count: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count_)
bmap.BMMesh_SetMaterialSlotCount(self._get_pointer(), self._get_ckid(), count)
def get_material_slots(self) -> typing.Iterator[BMMaterial | None]:
idx: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
mtlid: bmap.bm_CKID = bmap.bm_CKID()
for i in range(self.get_material_slot_count()):
idx.value = i
bmap.BMMesh_GetMaterialSlot(self._get_pointer(), self._get_ckid(), idx, ctypes.byref(mtlid))
if mtlid.value == g_InvalidCKID:
yield None
else:
yield BMMaterial(self._get_pointer(), mtlid)
def set_material_slots(self, itor: typing.Iterator[BMMaterial | None]) -> None:
idx: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
mtlid: bmap.bm_CKID = bmap.bm_CKID()
for i in range(self.get_material_slot_count()):
idx.value = i
# analyze mtl item
mtlobj: BMMaterial | None = next(itor)
if mtlobj is None:
mtlid.value = g_InvalidCKID
else:
mtlid = mtlobj._get_ckid()
# set
bmap.BMMesh_SetMaterialSlot(self._get_pointer(), self._get_ckid(), idx, mtlid)
class BM3dObject(BMObject):
def get_world_matrix(self) -> virtools_types.VxMatrix:
mat: bmap.bm_VxMatrix = bmap.bm_VxMatrix()
bmap.BM3dObject_GetWorldMatrix(self._get_pointer(), self._get_ckid(), ctypes.byref(mat))
# use cast & pointer to get matrix data conveniently
flat: bmap.bm_CKFLOAT_p = ctypes.cast(ctypes.byref(mat), bmap.bm_CKFLOAT_p)
ret: virtools_types.VxMatrix = virtools_types.VxMatrix()
ret.from_const(tuple(flat[i] for i in range(16)))
return ret
def set_world_matrix(self, mat_: virtools_types.VxMatrix) -> None:
# star syntax expand the tuple as the argument.
mat: bmap.bm_VxMatrix = bmap.bm_VxMatrix(*(mat_.to_const()))
bmap.BM3dObject_SetWorldMatrix(self._get_pointer(), self._get_ckid(), mat)
def get_current_mesh(self) -> BMMesh | None:
ckid: bmap.bm_CKID = bmap.bm_CKID()
bmap.BM3dObject_GetCurrentMesh(self._get_pointer(), self._get_ckid(), ctypes.byref(ckid))
if ckid.value == g_InvalidCKID:
return None
else:
return BMMesh(self._get_pointer(), ckid)
def set_current_mesh(self, mesh: BMMesh | None) -> None:
ckid: bmap.bm_CKID = bmap.bm_CKID(g_InvalidCKID)
if mesh is not None:
ckid = mesh._get_ckid()
bmap.BM3dObject_SetCurrentMesh(self._get_pointer(), self._get_ckid(), ckid)
def get_visibility(self) -> bool:
visb: bmap.bm_bool = bmap.bm_bool()
bmap.BM3dObject_GetVisibility(self._get_pointer(), self._get_ckid(), ctypes.byref(visb))
return visb.value
def set_visibility(self, visb_: bool) -> None:
visb: bmap.bm_bool = bmap.bm_bool(visb_)
bmap.BM3dObject_SetVisibility(self._get_pointer(), self._get_ckid(), visb)
class BMGroup(BMObject):
def add_object(self, member: BM3dObject) -> None:
bmap.BMGroup_AddObject(self._get_pointer(), self._get_ckid(), member._get_ckid())
def get_object_count(self) -> int:
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
bmap.BMGroup_GetObjectCount(self._get_pointer(), self._get_ckid(), ctypes.byref(csize))
return csize.value
def get_objects(self) -> typing.Iterator[BM3dObject]:
csize: int = self.get_object_count()
# iterate list
cidx: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
retid: bmap.bm_CKID = bmap.bm_CKID()
for i in range(csize):
cidx.value = i
bmap.BMGroup_GetObject(self._get_pointer(), self._get_ckid(), cidx, ctypes.byref(retid))
# return visitor
yield BM3dObject(self._get_pointer(), retid)
class BMFileReader(_AbstractPointer):
def __init__(self, file_name_: str, temp_folder_: str, texture_folder_: str, encodings_: tuple[str]):
# create param
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))
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_)
)
out_file: bmap.bm_void_p = bmap.bm_void_p()
# exec
bmap.BMFile_Load(
file_name, temp_folder, texture_folder, _g_RawCallback,
encoding_count, encodings,
ctypes.byref(out_file)
)
# init self
_AbstractPointer.__init__(self, out_file)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.dispose()
def dispose(self) -> None:
if self._is_valid():
bmap.BMFile_Free(self._get_pointer())
self._set_pointer(g_InvalidPtr)
def __get_ckobject_count(self,
count_getter: typing.Callable[[bmap.bm_void_p, bmap.bm_CKDWORD_p], bool]) -> int:
# get size
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
count_getter(self._get_pointer(), ctypes.byref(csize))
return csize.value
def __get_ckobjects(self,
class_type: type[TCKObj],
count_getter: typing.Callable[[bmap.bm_void_p, bmap.bm_CKDWORD_p], bool],
obj_getter: typing.Callable[[bmap.bm_void_p, bmap.bm_CKDWORD, bmap.bm_CKID_p], bool]) -> typing.Iterator[TCKObj]:
# get size first
csize: int = self.__get_ckobject_count(count_getter)
# iterate list
cidx: bmap.bm_CKDWORD = bmap.bm_CKDWORD()
retid: bmap.bm_CKID = bmap.bm_CKID()
for i in range(csize):
cidx.value = i
obj_getter(self._get_pointer(), cidx, ctypes.byref(retid))
# yield return constructed obj visitor
yield class_type(self._get_pointer(), retid)
def get_texture_count(self) -> int:
return self.__get_ckobject_count(bmap.BMFile_GetTextureCount)
def get_textures(self) -> typing.Iterator[BMTexture]:
return self.__get_ckobjects(
BMTexture,
bmap.BMFile_GetTextureCount,
bmap.BMFile_GetTexture
)
def get_material_count(self) -> int:
return self.__get_ckobject_count(bmap.BMFile_GetMaterialCount)
def get_materials(self) -> typing.Iterator[BMMaterial]:
return self.__get_ckobjects(
BMMaterial,
bmap.BMFile_GetMaterialCount,
bmap.BMFile_GetMaterial
)
def get_mesh_count(self) -> int:
return self.__get_ckobject_count(bmap.BMFile_GetMeshCount)
def get_meshs(self) -> typing.Iterator[BMMesh]:
return self.__get_ckobjects(
BMMesh,
bmap.BMFile_GetMeshCount,
bmap.BMFile_GetMesh
)
def get_3dobject_count(self) -> int:
return self.__get_ckobject_count(bmap.BMFile_Get3dObjectCount)
def get_3dobjects(self) -> typing.Iterator[BM3dObject]:
return self.__get_ckobjects(
BM3dObject,
bmap.BMFile_Get3dObjectCount,
bmap.BMFile_Get3dObject
)
def get_group_count(self) -> int:
return self.__get_ckobject_count(bmap.BMFile_GetGroupCount)
def get_groups(self) -> typing.Iterator[BMGroup]:
return self.__get_ckobjects(
BMGroup,
bmap.BMFile_GetGroupCount,
bmap.BMFile_GetGroup
)
class BMFileWriter(_AbstractPointer):
def __init__(self, temp_folder_: str, texture_folder_: str, encodings_: tuple[str]):
# 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))
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_)
)
out_file: bmap.bm_void_p = bmap.bm_void_p()
# exec
bmap.BMFile_Create(
temp_folder, texture_folder, _g_RawCallback,
encoding_count, encodings,
ctypes.byref(out_file)
)
# init self
_AbstractPointer.__init__(self, out_file)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.dispose()
def save(self, file_name_: str, texture_save_opt_: virtools_types.CK_TEXTURE_SAVEOPTIONS, use_compress_: bool, compress_level_: int) -> None:
# create param
file_name: bmap.bm_CKSTRING = bmap.bm_CKSTRING(file_name_.encode(g_BMapEncoding))
texture_save_opt: bmap.bm_enum = bmap.bm_enum(texture_save_opt_.value)
use_compress: bmap.bm_bool = bmap.bm_bool(use_compress_)
compress_level: bmap.bm_CKINT = bmap.bm_CKINT(compress_level_)
# exec
bmap.BMFile_Save(self._get_pointer(), file_name, texture_save_opt, use_compress, compress_level)
def dispose(self) -> None:
if self._is_valid():
bmap.BMFile_Free(self._get_pointer())
self._set_pointer(g_InvalidPtr)
def __create_ckobject(self,
class_type: type[TCKObj],
creator: typing.Callable[[bmap.bm_void_p, bmap.bm_CKID_p], bool]) -> TCKObj:
# prepare id container
retid: bmap.bm_CKID = bmap.bm_CKID()
# create new one
creator(self._get_pointer(), ctypes.byref(retid))
# return visitor
return class_type(self._get_pointer(), retid)
def create_texture(self) -> BMTexture:
return self.__create_ckobject(
BMTexture,
bmap.BMFile_CreateTexture
)
def create_material(self) -> BMMaterial:
return self.__create_ckobject(
BMMaterial,
bmap.BMFile_CreateMaterial
)
def create_mesh(self) -> BMMesh:
return self.__create_ckobject(
BMMesh,
bmap.BMFile_CreateMesh
)
def create_3dobject(self) -> BM3dObject:
return self.__create_ckobject(
BM3dObject,
bmap.BMFile_Create3dObject
)
def create_group(self) -> BMGroup:
return self.__create_ckobject(
BMGroup,
bmap.BMFile_CreateGroup
)
class BMMeshTrans(_AbstractPointer):
def __init__(self):
ptr: bmap.bm_void_p = bmap.bm_void_p()
bmap.BMMeshTrans_New(ctypes.byref(ptr))
_AbstractPointer.__init__(self, ptr)
def __enter__(self):
return self
def __exit__(self, exc_type, exc_value, traceback):
self.dispose()
def dispose(self) -> None:
if self._is_valid():
bmap.BMMeshTrans_Delete(self._get_pointer())
self._set_pointer(g_InvalidPtr)
def parse(self, bmfile: BMFileWriter, objmesh: BMMesh) -> None:
bmap.BMMeshTrans_Parse(self._get_pointer(), bmfile._get_pointer(), objmesh._get_ckid())
def prepare_vertex(self, count: int, itor: typing.Iterator[virtools_types.VxVector3]) -> None:
# prepare count first
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count)
bmap.BMMeshTrans_PrepareVertexCount(self._get_pointer(), csize)
# get raw pointer and conv to float ptr for convenient visit
raw_vector: bmap.bm_VxVector3_p = bmap.bm_VxVector3_p()
bmap.BMMeshTrans_PrepareVertex(self._get_pointer(), ctypes.byref(raw_vector))
# set by pointer
_vxvector3_assigner(raw_vector, count, itor)
def prepare_normal(self, count: int, itor: typing.Iterator[virtools_types.VxVector3]) -> None:
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count)
bmap.BMMeshTrans_PrepareNormalCount(self._get_pointer(), csize)
raw_vector: bmap.bm_VxVector3_p = bmap.bm_VxVector3_p()
bmap.BMMeshTrans_PrepareNormal(self._get_pointer(), ctypes.byref(raw_vector))
_vxvector3_assigner(raw_vector, count, itor)
def prepare_uv(self, count: int, itor: typing.Iterator[virtools_types.VxVector2]) -> None:
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count)
bmap.BMMeshTrans_PrepareUVCount(self._get_pointer(), csize)
raw_vector: bmap.bm_VxVector2_p = bmap.bm_VxVector2_p()
bmap.BMMeshTrans_PrepareUV(self._get_pointer(), ctypes.byref(raw_vector))
_vxvector2_assigner(raw_vector, count, itor)
def prepare_mtl_slot(self, count: int, itor: typing.Iterator[BMMaterial | None]) -> None:
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count)
bmap.BMMeshTrans_PrepareMtlSlotCount(self._get_pointer(), csize)
raw_ckid: bmap.bm_CKID_p = bmap.bm_CKID_p()
bmap.BMMeshTrans_PrepareMtlSlot(self._get_pointer(), ctypes.byref(raw_ckid))
idx: int = 0
for _ in range(count):
usermtl: BMMaterial | None = next(itor)
if usermtl is None:
raw_ckid[idx] = g_InvalidCKID
else:
raw_ckid[idx] = usermtl._get_ckid().value
idx += 1
def prepare_face(self,
count: int,
vec_idx: typing.Iterator[virtools_types.CKFaceIndices],
nml_idx: typing.Iterator[virtools_types.CKFaceIndices],
uv_idx: typing.Iterator[virtools_types.CKFaceIndices],
mtl_idx: typing.Iterator[int]) -> None:
# prepare face size
csize: bmap.bm_CKDWORD = bmap.bm_CKDWORD(count)
bmap.BMMeshTrans_PrepareFaceCount(self._get_pointer(), csize)
# get 4 raw pointer for following assign
raw_vec_idx: bmap.bm_CKDWORD_p = bmap.bm_CKDWORD_p()
raw_nml_idx: bmap.bm_CKDWORD_p = bmap.bm_CKDWORD_p()
raw_uv_idx: bmap.bm_CKDWORD_p = bmap.bm_CKDWORD_p()
raw_mtl_idx: bmap.bm_CKDWORD_p = bmap.bm_CKDWORD_p()
bmap.BMMeshTrans_PrepareFaceVertexIndices(self._get_pointer(), ctypes.byref(raw_vec_idx))
bmap.BMMeshTrans_PrepareFaceNormalIndices(self._get_pointer(), ctypes.byref(raw_nml_idx))
bmap.BMMeshTrans_PrepareFaceUVIndices(self._get_pointer(), ctypes.byref(raw_uv_idx))
bmap.BMMeshTrans_PrepareFaceMtlSlot(self._get_pointer(), ctypes.byref(raw_mtl_idx))
# iterate and assign
# assigne triple indices
_ckfaceindices_assigner(raw_vec_idx, count, vec_idx)
_ckfaceindices_assigner(raw_nml_idx, count, nml_idx)
_ckfaceindices_assigner(raw_uv_idx, count, uv_idx)
# assign mtl index
idx: int = 0
for _ in range(count):
raw_mtl_idx[idx] = next(mtl_idx)
idx += 1
#endregion

View File

@ -1,318 +0,0 @@
import typing, enum
ConstVxVector2 = tuple[float, float]
ConstVxVector3 = tuple[float, float, float]
ConstVxVector4 = tuple[float, float, float, float]
class VxVector2():
x: float
y: float
def __init__(self, _x: float = 0.0, _y: float = 0.0):
self.x = _x
self.y = _y
def from_const(self, cv: ConstVxVector2) -> None:
(self.x, self.y, ) = cv
def to_const(self) -> ConstVxVector2:
return (self.x, self.y, )
class VxVector3():
x: float
y: float
z: float
def __init__(self, _x: float = 0.0, _y: float = 0.0, _z: float = 0.0):
self.x = _x
self.y = _y
self.z = _z
def from_const(self, cv: ConstVxVector3) -> None:
(self.x, self.y, self.z) = cv
def to_const(self) -> ConstVxVector3:
return (self.x, self.y, self.z)
ConstCKFaceIndices = tuple[int, int, int]
class CKFaceIndices():
i1: int
i2: int
i3: int
def __init__(self, i1_: int = 0, i2_: int = 0, i3_: int = 0):
self.i1 = i1_
self.i2 = i2_
self.i3 = i3_
def from_const(self, cv: ConstCKFaceIndices) -> None:
(self.i1, self.i2, self.i3) = cv
def to_const(self) -> ConstCKFaceIndices:
return (self.i1, self.i2, self.i3)
ConstVxColorRGBA = tuple[float, float, float, float]
ConstVxColorRGB = tuple[float, float, float]
class VxColor():
"""
The Color struct support RGBA.
"""
a: float
r: float
g: float
b: float
def __init__(self, _r: float = 0.0, _g: float = 0.0, _b: float = 0.0, _a: float = 1.0):
self.r = _r
self.g = _g
self.b = _b
self.a = _a
self.regulate()
def to_const_rgba(self) -> ConstVxColorRGBA:
return (self.r, self.g, self.b, self.a)
def to_const_rgb(self) -> ConstVxColorRGB:
return (self.r, self.g, self.b)
def from_const_rgba(self, val: ConstVxColorRGBA) -> None:
(self.r, self.g, self.b, self.a) = val
self.regulate()
def from_const_rgb(self, val: ConstVxColorRGB) -> None:
(self.r, self.g, self.b) = val
self.a = 1.0
self.regulate()
def from_dword(self, val: int) -> None:
self.b = float(val & 0xFF) / 255.0
val >>= 8
self.g = float(val & 0xFF) / 255.0
val >>= 8
self.r = float(val & 0xFF) / 255.0
val >>= 8
self.a = float(val & 0xFF) / 255.0
val >>= 8
def to_dword(self) -> int:
# regulate self
self.regulate()
# construct value
val: int = 0
val |= int(self.a * 255)
val <<= 8
val |= int(self.r * 255)
val <<= 8
val |= int(self.g * 255)
val <<= 8
val |= int(self.b * 255)
return val
def clone(self):
return VxColor(self.r, self.g, self.b, self.a)
@staticmethod
def _clamp_factor(val: float) -> float:
if val > 1.0: return 1.0
elif val < 0.0: return 0.0
else: return val
def regulate(self):
self.a = VxColor._clamp_factor(self.a)
self.r = VxColor._clamp_factor(self.r)
self.g = VxColor._clamp_factor(self.g)
self.b = VxColor._clamp_factor(self.b)
ConstVxMatrix = tuple[
float, float, float, float,
float, float, float, float,
float, float, float, float,
float, float, float, float
]
class VxMatrix():
"""
The Matrix representation.
The bracket statement exactly equal with Virtools.
"""
data: list[list[float]]
def __init__(self):
# init array
self.data = [[0] * 4 for i in range(4)]
# set to identy
self.reset()
def _get_raw(self) -> list[list[float]]:
return self.data
def reset(self) -> None:
# reset to identy
for i in range(4):
for j in range(4):
self.data[i][j] = 0.0
self.data[0][0] = 1.0
self.data[1][1] = 1.0
self.data[2][2] = 1.0
self.data[3][3] = 1.0
def from_const(self, cm: ConstVxMatrix) -> None:
(
self.data[0][0], self.data[0][1], self.data[0][2], self.data[0][3],
self.data[1][0], self.data[1][1], self.data[1][2], self.data[1][3],
self.data[2][0], self.data[2][1], self.data[2][2], self.data[2][3],
self.data[3][0], self.data[3][1], self.data[3][2], self.data[3][3]
) = cm
def to_const(self) -> ConstVxMatrix:
return (
self.data[0][0], self.data[0][1], self.data[0][2], self.data[0][3],
self.data[1][0], self.data[1][1], self.data[1][2], self.data[1][3],
self.data[2][0], self.data[2][1], self.data[2][2], self.data[2][3],
self.data[3][0], self.data[3][1], self.data[3][2], self.data[3][3]
)
class CK_TEXTURE_SAVEOPTIONS(enum.IntEnum):
"""!
Specify the way textures or sprites will be saved
"""
CKTEXTURE_RAWDATA = 0 ##< Save raw data inside file. The bitmap is saved in a raw 32 bit per pixel format.
CKTEXTURE_EXTERNAL = 1 ##< Store only the file name for the texture. The bitmap file must be present in the bitmap paths when loading the composition.
CKTEXTURE_IMAGEFORMAT = 2 ##< Save using format specified. The bitmap data will be converted to the specified format by the correspondant bitmap plugin and saved inside file.
CKTEXTURE_USEGLOBAL = 3 ##< Use Global settings, that is the settings given with CKContext::SetGlobalImagesSaveOptions. (Not valid when using CKContext::SetImagesSaveOptions).
CKTEXTURE_INCLUDEORIGINALFILE = 4 ##< Insert original image file inside CMO file. The bitmap file that was used originally for the texture or sprite will be append to the composition file and extracted when the file is loaded.
class VX_PIXELFORMAT(enum.IntEnum):
"""!
Pixel format types.
"""
#UNKNOWN_PF = 0 ##< Unknown pixel format
_32_ARGB8888 = 1 ##< 32-bit ARGB pixel format with alpha
_32_RGB888 = 2 ##< 32-bit RGB pixel format without alpha
_24_RGB888 = 3 ##< 24-bit RGB pixel format
_16_RGB565 = 4 ##< 16-bit RGB pixel format
_16_RGB555 = 5 ##< 16-bit RGB pixel format (5 bits per color)
_16_ARGB1555 = 6 ##< 16-bit ARGB pixel format (5 bits per color + 1 bit for alpha)
_16_ARGB4444 = 7 ##< 16-bit ARGB pixel format (4 bits per color)
_8_RGB332 = 8 ##< 8-bit RGB pixel format
_8_ARGB2222 = 9 ##< 8-bit ARGB pixel format
_32_ABGR8888 = 10 ##< 32-bit ABGR pixel format
_32_RGBA8888 = 11 ##< 32-bit RGBA pixel format
_32_BGRA8888 = 12 ##< 32-bit BGRA pixel format
_32_BGR888 = 13 ##< 32-bit BGR pixel format
_24_BGR888 = 14 ##< 24-bit BGR pixel format
_16_BGR565 = 15 ##< 16-bit BGR pixel format
_16_BGR555 = 16 ##< 16-bit BGR pixel format (5 bits per color)
_16_ABGR1555 = 17 ##< 16-bit ABGR pixel format (5 bits per color + 1 bit for alpha)
_16_ABGR4444 = 18 ##< 16-bit ABGR pixel format (4 bits per color)
_DXT1 = 19 ##< S3/DirectX Texture Compression 1
_DXT2 = 20 ##< S3/DirectX Texture Compression 2
_DXT3 = 21 ##< S3/DirectX Texture Compression 3
_DXT4 = 22 ##< S3/DirectX Texture Compression 4
_DXT5 = 23 ##< S3/DirectX Texture Compression 5
_16_V8U8 = 24 ##< 16-bit Bump Map format format (8 bits per color)
_32_V16U16 = 25 ##< 32-bit Bump Map format format (16 bits per color)
_16_L6V5U5 = 26 ##< 16-bit Bump Map format format with luminance
_32_X8L8V8U8 = 27 ##< 32-bit Bump Map format format with luminance
_8_ABGR8888_CLUT = 28 ##< 8 bits indexed CLUT (ABGR)
_8_ARGB8888_CLUT = 29 ##< 8 bits indexed CLUT (ARGB)
_4_ABGR8888_CLUT = 30 ##< 4 bits indexed CLUT (ABGR)
_4_ARGB8888_CLUT = 31 ##< 4 bits indexed CLUT (ARGB)
class VXTEXTURE_BLENDMODE(enum.IntEnum):
"""!
Blend Mode Flags
"""
VXTEXTUREBLEND_DECAL = 1 ##< Texture replace any material information
VXTEXTUREBLEND_MODULATE = 2 ##< Texture and material are combine. Alpha information of the texture replace material alpha component.
VXTEXTUREBLEND_DECALALPHA = 3 ##< Alpha information in the texture specify how material and texture are combined. Alpha information of the texture replace material alpha component.
VXTEXTUREBLEND_MODULATEALPHA = 4 ##< Alpha information in the texture specify how material and texture are combined
VXTEXTUREBLEND_DECALMASK = 5
VXTEXTUREBLEND_MODULATEMASK = 6
VXTEXTUREBLEND_COPY = 7 ##< Equivalent to DECAL
VXTEXTUREBLEND_ADD = 8
VXTEXTUREBLEND_DOTPRODUCT3 = 9 ##< Perform a Dot Product 3 between texture (normal map) and a referential vector given in VXRENDERSTATE_TEXTUREFACTOR.
VXTEXTUREBLEND_MAX = 10
class VXTEXTURE_FILTERMODE(enum.IntEnum):
"""!
Filter Mode Options
"""
VXTEXTUREFILTER_NEAREST = 1 ##< No Filter
VXTEXTUREFILTER_LINEAR = 2 ##< Bilinear Interpolation
VXTEXTUREFILTER_MIPNEAREST = 3 ##< Mip mapping
VXTEXTUREFILTER_MIPLINEAR = 4 ##< Mip Mapping with Bilinear interpolation
VXTEXTUREFILTER_LINEARMIPNEAREST = 5 ##< Mip Mapping with Bilinear interpolation between mipmap levels.
VXTEXTUREFILTER_LINEARMIPLINEAR = 6 ##< Trilinear Filtering
VXTEXTUREFILTER_ANISOTROPIC = 7 ##< Anisotropic filtering
class VXTEXTURE_ADDRESSMODE(enum.IntEnum):
"""!
Texture addressing modes.
"""
VXTEXTURE_ADDRESSWRAP = 1 ##< Default mesh wrap mode is used (see CKMesh::SetWrapMode)
VXTEXTURE_ADDRESSMIRROR = 2 ##< Texture coordinates outside the range [0..1] are flipped evenly.
VXTEXTURE_ADDRESSCLAMP = 3 ##< Texture coordinates greater than 1.0 are set to 1.0, and values less than 0.0 are set to 0.0.
VXTEXTURE_ADDRESSBORDER = 4 ##< When texture coordinates are greater than 1.0 or less than 0.0 texture is set to a color defined in CKMaterial::SetTextureBorderColor.
VXTEXTURE_ADDRESSMIRRORONCE = 5 ##<
class VXBLEND_MODE(enum.IntEnum):
"""!
Blending Mode options
"""
VXBLEND_ZERO = 1 ##< Blend factor is (0, 0, 0, 0).
VXBLEND_ONE = 2 ##< Blend factor is (1, 1, 1, 1).
VXBLEND_SRCCOLOR = 3 ##< Blend factor is (Rs, Gs, Bs, As).
VXBLEND_INVSRCCOLOR = 4 ##< Blend factor is (1-Rs, 1-Gs, 1-Bs, 1-As).
VXBLEND_SRCALPHA = 5 ##< Blend factor is (As, As, As, As).
VXBLEND_INVSRCALPHA = 6 ##< Blend factor is (1-As, 1-As, 1-As, 1-As).
VXBLEND_DESTALPHA = 7 ##< Blend factor is (Ad, Ad, Ad, Ad).
VXBLEND_INVDESTALPHA = 8 ##< Blend factor is (1-Ad, 1-Ad, 1-Ad, 1-Ad).
VXBLEND_DESTCOLOR = 9 ##< Blend factor is (Rd, Gd, Bd, Ad).
VXBLEND_INVDESTCOLOR = 10 ##< Blend factor is (1-Rd, 1-Gd, 1-Bd, 1-Ad).
VXBLEND_SRCALPHASAT = 11 ##< Blend factor is (f, f, f, 1); f = min(As, 1-Ad).
#VXBLEND_BOTHSRCALPHA = 12 ##< Source blend factor is (As, As, As, As) and destination blend factor is (1-As, 1-As, 1-As, 1-As)
#VXBLEND_BOTHINVSRCALPHA = 13 ##< Source blend factor is (1-As, 1-As, 1-As, 1-As) and destination blend factor is (As, As, As, As)
class VXFILL_MODE(enum.IntEnum):
"""!
Fill Mode Options
"""
VXFILL_POINT = 1 ##< Vertices rendering
VXFILL_WIREFRAME = 2 ##< Edges rendering
VXFILL_SOLID = 3 ##< Face rendering
class VXSHADE_MODE(enum.IntEnum):
"""!
Shade Mode Options
"""
VXSHADE_FLAT = 1 ##< Flat Shading
VXSHADE_GOURAUD = 2 ##< Gouraud Shading
VXSHADE_PHONG = 3 ##< Phong Shading (Not yet supported by most implementation)
class VXCMPFUNC(enum.IntEnum):
"""!
Comparison Function
"""
VXCMP_NEVER = 1 ##< Always fail the test.
VXCMP_LESS = 2 ##< Accept if value if less than current value.
VXCMP_EQUAL = 3 ##< Accept if value if equal than current value.
VXCMP_LESSEQUAL = 4 ##< Accept if value if less or equal than current value.
VXCMP_GREATER = 5 ##< Accept if value if greater than current value.
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.

View File

@ -104,7 +104,11 @@ def _nest_custom_split_normal(nml_array: array.array) -> typing.Iterator[UTIL_vi
class TemporaryMesh():
"""
Create a temporary mesh for convenient exporting.
When exporting mesh, we need triangulate it first.
We create a temporary mesh to hold the triangulated mesh result.
So that original object will not be affected and keep its original geometry.
Please note passed bpy.types.Object must be Mesh Object.
"""
__mBindingObject: bpy.types.Object

View File

@ -29,7 +29,7 @@ class ImportBallanceImage(bpy_extras.io_utils.ImportHelper):
filter_glob: bpy.props.StringProperty(
default = "*.bmp;*.tga",
options = {'HIDDEN'}
)
) # type: ignore
def general_set_filename(self, filename: str) -> None:
self.filepath = filename
@ -44,7 +44,7 @@ class ImportBmxFile(bpy_extras.io_utils.ImportHelper):
filter_glob: bpy.props.StringProperty(
default = "*.bmx",
options = {'HIDDEN'}
)
) # type: ignore
def general_get_filename(self) -> str:
return self.filepath
@ -56,7 +56,7 @@ class ExportBmxFile(bpy_extras.io_utils.ExportHelper):
filter_glob: bpy.props.StringProperty(
default = "*.bmx",
options = {'HIDDEN'}
)
) # type: ignore
def general_get_filename(self) -> str:
return self.filepath
@ -68,7 +68,7 @@ class ImportVirtoolsFile(bpy_extras.io_utils.ImportHelper):
filter_glob: bpy.props.StringProperty(
default = "*.nmo;*.cmo;*.vmo",
options = {'HIDDEN'}
)
) # type: ignore
def general_get_filename(self) -> str:
return self.filepath
@ -80,7 +80,7 @@ class ExportVirtoolsFile(bpy_extras.io_utils.ExportHelper):
filter_glob: bpy.props.StringProperty(
default = "*.nmo",
options = {'HIDDEN'}
)
) # type: ignore
def general_get_filename(self) -> str:
return self.filepath
@ -94,7 +94,7 @@ class ImportDirectory(bpy_extras.io_utils.ImportHelper):
filter_glob: bpy.props.StringProperty(
default = "",
options = {'HIDDEN'}
)
) # type: ignore
def general_get_directory(self) -> str:
return self.directory

View File

@ -2,6 +2,10 @@ import bpy, mathutils
import struct, os, io, typing
from . import UTIL_virtools_types
## MARK:
# This module may be deprecated because the host refering this module,
# BM file import and export is no longer existing.
_FileWriter_t = io.BufferedWriter
_FileReader_t = io.BufferedReader
@ -31,10 +35,10 @@ def write_float(fs: _FileWriter_t, fl: float) -> None:
fs.write(struct.pack("<f", fl))
def write_world_matrix(fs: _FileWriter_t, mat: UTIL_virtools_types.VxMatrix) -> None:
fs.write(struct.pack("<16f", *mat.to_tuple()))
fs.write(struct.pack("<16f", *mat.to_const()))
def write_color(fs: _FileWriter_t, colors: UTIL_virtools_types.VxColor) -> None:
fs.write(struct.pack("<fff", *colors.to_tuple_rgb()))
fs.write(struct.pack("<fff", *colors.to_const_rgb()))
def write_uint32_array(fs: _FileWriter_t, vals: typing.Iterable[int], count: int) -> None:
fs.write(struct.pack('<' + str(count) + 'I', *vals))
@ -67,11 +71,11 @@ def read_string(fs: _FileReader_t) -> str:
count = read_uint32(fs)
return fs.read(count * 4).decode("utf_32_le")
def read_bool(fs: _FileReader_t) -> None:
def read_bool(fs: _FileReader_t) -> bool:
return read_uint8(fs) != 0
def read_world_materix(fs: _FileReader_t, mat: UTIL_virtools_types.VxMatrix) -> None:
mat.from_tuple(struct.unpack("<16f", fs.read(16 * 4)))
mat.from_const(struct.unpack("<16f", fs.read(16 * 4)))
def read_color(fs: _FileReader_t, target: UTIL_virtools_types.VxColor) -> None:
target.from_const_rgb(struct.unpack("fff", fs.read(3 * 4)))

View File

@ -52,6 +52,11 @@ def message_box(message: tuple[str, ...], title: str, icon: str):
bpy.context.window_manager.popup_menu(draw, title = title, icon = icon)
def add_into_scene(obj: bpy.types.Object):
view_layer = bpy.context.view_layer
collection = view_layer.active_layer_collection.collection
collection.objects.link(obj)
def move_to_cursor(obj: bpy.types.Object):
# use obj.matrix_world to move, not obj.location because this bug:
# https://blender.stackexchange.com/questions/27667/incorrect-matrix-world-after-transformation
@ -62,10 +67,7 @@ def move_to_cursor(obj: bpy.types.Object):
obj.matrix_world = obj.matrix_world @ mathutils.Matrix.Translation(bpy.context.scene.cursor.location - obj.location)
def add_into_scene_and_move_to_cursor(obj: bpy.types.Object):
view_layer = bpy.context.view_layer
collection = view_layer.active_layer_collection.collection
collection.objects.link(obj)
add_into_scene(obj)
move_to_cursor(obj)
def select_certain_objects(objs: tuple[bpy.types.Object, ...]) -> None:

View File

@ -1,7 +1,7 @@
import bpy
import enum, typing
from . import UTIL_virtools_types, UTIL_functions
from . import PROP_ptrprop_resolver
from . import PROP_ptrprop_resolver, PROP_ballance_map_info
## Intent
# Some importer or exporter may share same properties.
@ -67,20 +67,31 @@ class ConflictResolver():
"""
__mObjectStrategy: ConflictStrategy
__mLightStrategy: ConflictStrategy
__mMeshStrategy: ConflictStrategy
__mMaterialStrategy: ConflictStrategy
__mTextureStrategy: ConflictStrategy
def __init__(self, obj_strategy: ConflictStrategy, mesh_strategy: ConflictStrategy, mtl_strategy: ConflictStrategy, tex_strategy: ConflictStrategy):
def __init__(self,
obj_strategy: ConflictStrategy,
light_strategy: ConflictStrategy,
mesh_strategy: ConflictStrategy,
mtl_strategy: ConflictStrategy,
tex_strategy: ConflictStrategy):
self.__mObjectStrategy = obj_strategy
self.__mLightStrategy = light_strategy
self.__mMeshStrategy = mesh_strategy
self.__mMaterialStrategy = mtl_strategy
self.__mTextureStrategy = tex_strategy
def create_object(self, name: str, data: bpy.types.Mesh) -> tuple[bpy.types.Object, bool]:
def create_object(self, name: str, data: bpy.types.Mesh | None) -> tuple[bpy.types.Object, bool]:
"""
Create object according to conflict strategy.
`data` will only be applied when creating new object (no existing instance or strategy order rename)
`data` will only be applied when creating new object (no existing instance or strategy order rename).
Please note this function is only used to create mesh 3d object.
If you want to create light object, please use other functions provided by this class.
The 3d object and data block of light is created together.
"""
if self.__mObjectStrategy == ConflictStrategy.Current:
old: bpy.types.Object | None = bpy.data.objects.get(name, None)
@ -88,6 +99,26 @@ class ConflictResolver():
return (old, False)
return (bpy.data.objects.new(name, data), True)
def create_light(self, name: str) -> tuple[bpy.types.Object, bpy.types.Light, bool]:
"""
Create light data block and associated 3d object.
If conflict strategy is "Current", we try fetch 3d object with given name first,
then check whether it is light.
If no given name object or this object is not light, we create a new one,
otherwise return old one.
"""
if self.__mLightStrategy == ConflictStrategy.Current:
old_obj: bpy.types.Object | None = bpy.data.objects.get(name, None)
if old_obj is not None and old_obj.type == 'LIGHT':
return (old_obj, typing.cast(bpy.types.Light, old_obj.data), False)
# create new object.
# if object or light name is conflict, rename it directly without considering conflict strategy.
# create light with default point light type
new_light: bpy.types.Light = bpy.data.lights.new(name, 'POINT')
new_obj: bpy.types.Object = bpy.data.objects.new(name, new_light)
return (new_obj, new_light, True)
def create_mesh(self, name: str) -> tuple[bpy.types.Mesh, bool]:
if self.__mMeshStrategy == ConflictStrategy.Current:
old: bpy.types.Mesh | None = bpy.data.meshes.get(name, None)
@ -128,38 +159,55 @@ class ImportParams():
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process texture name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Current),
)
) # type: ignore
material_conflict_strategy: bpy.props.EnumProperty(
name = "Material Name Conflict",
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process material name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
)
) # type: ignore
mesh_conflict_strategy: bpy.props.EnumProperty(
name = "Mesh Name Conflict",
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process mesh name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
)
) # type: ignore
light_conflict_strategy: bpy.props.EnumProperty(
name = "Light Name Conflict",
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process light name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
) # type: ignore
object_conflict_strategy: bpy.props.EnumProperty(
name = "Object Name Conflict",
items = _g_EnumHelper_ConflictStrategy.generate_items(),
description = "Define how to process object name conflict",
default = _g_EnumHelper_ConflictStrategy.to_selection(ConflictStrategy.Rename),
)
) # type: ignore
def draw_import_params(self, layout: bpy.types.UILayout) -> None:
layout.label(text = 'Object Name Conflict')
layout.prop(self, 'object_conflict_strategy', text = '')
layout.label(text = 'Mesh Name Conflict')
layout.prop(self, 'mesh_conflict_strategy', text = '')
layout.label(text = 'Material Name Conflict')
layout.prop(self, 'material_conflict_strategy', text = '')
layout.label(text = 'Texture Name Conflict')
layout.prop(self, 'texture_conflict_strategy', text = '')
header: bpy.types.UILayout
body: bpy.types.UILayout
header, body = layout.panel("BBP_PT_ioport_shared_import_params", default_closed=False)
header.label(text = 'Import Parameters')
if body is None: return
body.label(text = 'Name Conflict Strategy')
grid = body.grid_flow(row_major = False, columns = 2)
grid.label(text = 'Object', icon = 'CUBE')
grid.label(text = 'Light', icon = 'LIGHT')
grid.label(text = 'Mesh', icon = 'MESH_DATA')
grid.label(text = 'Material', icon = 'MATERIAL')
grid.label(text = 'Texture', icon = 'TEXTURE')
grid.prop(self, 'object_conflict_strategy', text = '')
grid.prop(self, 'light_conflict_strategy', text = '')
grid.prop(self, 'mesh_conflict_strategy', text = '')
grid.prop(self, 'material_conflict_strategy', text = '')
grid.prop(self, 'texture_conflict_strategy', text = '')
def general_get_texture_conflict_strategy(self) -> ConflictStrategy:
return _g_EnumHelper_ConflictStrategy.get_selection(self.texture_conflict_strategy)
@ -170,12 +218,16 @@ class ImportParams():
def general_get_mesh_conflict_strategy(self) -> ConflictStrategy:
return _g_EnumHelper_ConflictStrategy.get_selection(self.mesh_conflict_strategy)
def general_get_light_conflict_strategy(self) -> ConflictStrategy:
return _g_EnumHelper_ConflictStrategy.get_selection(self.light_conflict_strategy)
def general_get_object_conflict_strategy(self) -> ConflictStrategy:
return _g_EnumHelper_ConflictStrategy.get_selection(self.object_conflict_strategy)
def general_get_conflict_resolver(self) -> ConflictResolver:
return ConflictResolver(
self.general_get_object_conflict_strategy(),
self.general_get_light_conflict_strategy(),
self.general_get_mesh_conflict_strategy(),
self.general_get_material_conflict_strategy(),
self.general_get_texture_conflict_strategy()
@ -188,19 +240,25 @@ class ExportParams():
('COLLECTION', "Collection", "Export a collection", 'OUTLINER_COLLECTION', 0),
('OBJECT', "Object", "Export an object", 'OBJECT_DATA', 1),
),
)
) # type: ignore
def draw_export_params(self, layout: bpy.types.UILayout) -> None:
header: bpy.types.UILayout
body: bpy.types.UILayout
header, body = layout.panel("BBP_PT_ioport_shared_export_params", default_closed=False)
header.label(text = 'Export Parameters')
if body is None: return
# make prop expand horizontaly, not vertical.
sublayout = layout.row()
horizon_body = body.row()
# draw switch
sublayout.prop(self, "export_mode", expand = True)
horizon_body.prop(self, "export_mode", expand = True)
# draw picker
if self.export_mode == 'COLLECTION':
PROP_ptrprop_resolver.draw_export_collection(layout)
PROP_ptrprop_resolver.draw_export_collection(body)
elif self.export_mode == 'OBJECT':
PROP_ptrprop_resolver.draw_export_object(layout)
PROP_ptrprop_resolver.draw_export_object(body)
def general_get_export_objects(self) -> tuple[bpy.types.Object] | None:
"""
@ -216,18 +274,106 @@ class ExportParams():
if obj is None: return None
else: return (obj, )
# define global tex save opt blender enum prop helper
_g_EnumHelper_CK_TEXTURE_SAVEOPTIONS: UTIL_virtools_types.EnumPropHelper = UTIL_virtools_types.EnumPropHelper(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS)
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_virtools_types.g_PyBMapDefaultEncoding
)
) # type: ignore
texture_save_opt: bpy.props.EnumProperty(
name = "Global Texture Save Options",
description = "Decide how texture saved if texture is specified as Use Global as its Save Options.",
items = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.generate_items(),
default = _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.to_selection(UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS.CKTEXTURE_EXTERNAL)
) # type: ignore
use_compress: bpy.props.BoolProperty(
name="Use Compress",
description = "Whether use ZLib to compress result when saving composition.",
default = True,
) # type: ignore
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,
) # type: ignore
def draw_virtools_params(self, layout: bpy.types.UILayout, is_importer: bool) -> None:
header: bpy.types.UILayout
body: bpy.types.UILayout
header, body = layout.panel("BBP_PT_ioport_shared_virtools_params", default_closed=False)
header.label(text = 'Virtools Parameters')
if body is None: return
# draw encodings
body.label(text = 'Encodings')
body.prop(self, 'vt_encodings', text = '')
# following field are only valid in exporter
if not is_importer:
body.separator()
body.label(text = 'Global Texture Save Options')
body.prop(self, 'texture_save_opt', text = '')
body.separator()
body.label(text = 'Compression')
body.prop(self, 'use_compress')
if self.use_compress:
body.prop(self, 'compress_level')
def draw_virtools_params(self, layout: bpy.types.UILayout) -> None:
layout.label(text = 'Encodings')
layout.prop(self, 'vt_encodings', text = '')
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(';')))
def general_get_texture_save_opt(self) -> UTIL_virtools_types.CK_TEXTURE_SAVEOPTIONS:
return _g_EnumHelper_CK_TEXTURE_SAVEOPTIONS.get_selection(self.texture_save_opt)
def general_get_use_compress(self) -> bool:
return self.use_compress
def general_get_compress_level(self) -> int:
return self.compress_level
class BallanceParams():
successive_sector: bpy.props.BoolProperty(
name="Successive Sector",
description = "Whether order exporter to use document specified sector count to make sure sector is successive.",
default = True,
) # type: ignore
def draw_ballance_params(self, layout: bpy.types.UILayout, is_importer: bool) -> None:
# ballance params only presented in exporter.
# so if we are in impoerter, we skip the whole function
# because we don't want to create an empty panel.
if is_importer: return
header: bpy.types.UILayout
body: bpy.types.UILayout
header, body = layout.panel("BBP_PT_ioport_shared_ballance_params", default_closed=False)
header.label(text = 'Ballance Parameters')
if body is None: return
map_info: PROP_ballance_map_info.RawBallanceMapInfo = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
body.prop(self, 'successive_sector')
body.label(text = f'Map Sectors: {map_info.mSectorCount}')
def general_get_successive_sector(self) -> bool:
return self.successive_sector
def general_get_successive_sector_count(self) -> int:
# if user do not pick successive sector, return a random int directly.
if not self.general_get_successive_sector():
return 0
# otherwise fetch user specified sector number
map_info: PROP_ballance_map_info.RawBallanceMapInfo
map_info = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene)
return map_info.mSectorCount

View File

@ -189,6 +189,12 @@ _g_Annotation: dict[type, dict[int, EnumAnnotation]] = {
VX_PIXELFORMAT._4_ABGR8888_CLUT.value: EnumAnnotation("4 Bits ABGR8888 CLUT", "4 bits indexed CLUT (ABGR) "),
VX_PIXELFORMAT._4_ARGB8888_CLUT.value: EnumAnnotation("4 Bits ARGB8888 CLUT", "4 bits indexed CLUT (ARGB) "),
},
VXLIGHT_TYPE: {
VXLIGHT_TYPE.VX_LIGHTPOINT.value: EnumAnnotation("Point", "The Light is a point of light "),
VXLIGHT_TYPE.VX_LIGHTSPOT.value: EnumAnnotation("Spot", "The light is a spotlight "),
VXLIGHT_TYPE.VX_LIGHTDIREC.value: EnumAnnotation("Directional", "The light is directional light : Lights comes from an infinite point so only direction of light can be given "),
#VXLIGHT_TYPE.VX_LIGHTPARA.value: EnumAnnotation("Lightpara", "Obsolete, do not use "),
},
VXMESH_LITMODE: {
VXMESH_LITMODE.VX_PRELITMESH.value: EnumAnnotation("Prelit", "Lighting use color information store with vertices "),
VXMESH_LITMODE.VX_LITMESH.value: EnumAnnotation("Lit", "Lighting is done by renderer using normals and face material information. "),
@ -227,12 +233,9 @@ def virtools_name_regulator(name: str | None) -> str:
## Default Encoding for PyBMap
# 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"
# Since LibCmo 0.2, the encoding name of LibCmo become universal encoding which is platfoorm independent.
# So no need set it according to different platform.
# Use universal encoding name (like Python).
g_PyBMapDefaultEncoding: str = 'cp1252;gb2312'
#endregion

View File

@ -16,7 +16,7 @@ from . import UTIL_icons_manager
UTIL_icons_manager.register()
# then load other modules
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_group
from . import PROP_preferences, PROP_ptrprop_resolver, PROP_virtools_material, PROP_virtools_texture, PROP_virtools_mesh, PROP_virtools_light, PROP_virtools_group
from . import PROP_ballance_element, PROP_bme_material, PROP_ballance_map_info
from . import OP_IMPORT_bmfile, OP_EXPORT_bmfile, OP_IMPORT_virtools, OP_EXPORT_virtools
from . import OP_UV_flatten_uv, OP_UV_rail_uv
@ -202,6 +202,7 @@ def register() -> None:
PROP_virtools_material.register()
PROP_virtools_texture.register()
PROP_virtools_mesh.register()
PROP_virtools_light.register()
PROP_virtools_group.register()
PROP_ballance_element.register()
PROP_bme_material.register()
@ -268,6 +269,7 @@ def unregister() -> None:
PROP_bme_material.unregister()
PROP_ballance_element.unregister()
PROP_virtools_group.unregister()
PROP_virtools_light.unregister()
PROP_virtools_mesh.unregister()
PROP_virtools_texture.unregister()
PROP_virtools_material.unregister()

View File

@ -6,7 +6,7 @@ schema_version = "1.0.0"
# Example of manifest file for a Blender extension
# Change the values according to your extension
id = "bbp_ng"
version = "4.0.0"
version = "4.1.0"
name = "Ballance Blender Plugin"
tagline = "The specialized add-on served for creating game map of Ballance"
maintainer = "yyc12345 <yyc12321@outlook.com>"

Binary file not shown.

2
docs/.gitignore vendored
View File

@ -1,2 +1,2 @@
# mkdocs
# ===== MkDocs =====
site/

View File

@ -20,15 +20,18 @@ The default values for the options in the Conflict Options section are the solut
It is well known that Virtools uses a system-based multi-byte character encoding to process documents, and is therefore prone to what is known as garbling; Blender itself does not suffer from garbling, however, if we do not read a Virtools document with the correct encoding, the characters stored in it may still appear garbled when the Virtools document is imported into Blender. The Encodings property in the Virtools Params section specifies the encodings for reading Virtools documents. Multiple encodings can be specified, separated by a `;` (semicolon). Some common encodings are listed below:
* 1252 (Windows only): Western European encoding used by Ballance.
* 936 (Windows only): the default encoding for Chinese Windows system.
* CP1252 (non-Windows): Western European encoding used by Ballance.
* CP936 (non-Windows): the default encoding for Chinese Windows system.
* cp1252: Western European encoding used by Ballance.
* gb2312: The default encoding for Chinese Windows system.
The encoding attribute is very important, if you set the wrong encoding, the names of the various objects imported into Blender will be unrecognizable.
The encoding attribute is very important. If the wrong encoding is set, the names of the various objects imported into Blender will be unrecognizable, or will cause the program to make an error.
!!! warning "Encoding is a platform dependent setting"
According to the implementation of LibCmo, the underlying library used by BBP's Virtools documentation for the import module, the encoding attribute is a platform dependent setting. Under Windows, the [Windows Code Page](https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers) number is required here. Under other operating systems, LibCmo uses iconv for character encoding and decoding, so you need to use the legal [Iconv Encoding Identifier](https://www.gnu.org/software/libiconv/).
!!! info "What encodings are available?"
Since BBP version 4.1, the names of the encodings we use are basically just copied from the Python encoding names. Most of the commonly used encoding names in Most of the commonly used encoding names in Python are mapped, with only a few particularly rare encodings unsupported, and for specific supported encodings it is necessary to check the source code. See [Python documentation](https://docs.python.org/3/library/codecs.html#standard-encodings) for information on Python's supported encodings. Encodings are not case-sensitive.
!!! warning "Warning about migration from older versions"
Starting with BBP version 4.1, the version number of LibCmo, the underlying library used by BBP's Virtools document import module, has been bumped to 0.2. Before this version, the encoding attribute was a platform-dependent setting. Under Windows, the [Windows Code Page](https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers) number is required here. Under other operating systems, LibCmo uses iconv for character encoding decoding, so the legal [iconv encoding identifier](hhttps://www.gnu.org/software/libiconv/) is required.
This all changed with LibCmo 0.2, from which LibCmo uses Python-like universal encoding names. It is platform-independent, you no longer need to check whether the operating system you are using is Windows or Linux, the encoded characters are the same string for all platforms. This also means that if you have customized your encoding settings before, you need to be careful to convert them to the new universal encoding name, because the old encoding name may not have a corresponding mapping under the universal encoding name system, for example, `1252` specified on Windows before should be written as `cp1252` under the new universal encoding name, and the original encoding name won't be recognized correctly on the new system.
## Export Virtools File

View File

@ -20,15 +20,18 @@ Conflict Options冲突解决选项章节指示了当导入器遇到物体
众所周知Virtools使用基于系统的多字节字符编码来处理文档因而很容易出现所谓乱码问题。Blender本身不会出现乱码问题然而如果我们不能以正确的编码读取Virtools文档则当Virtools文档被导入Blender时其中存储的字符仍然可能会呈现乱码状态。Virtools ParamsVirtools参数章节的Encodings编码属性用于指定读取Virtools文档的编码。可以指定多个编码多个编码之间用`;`(分号)分隔。下面列出一些常用的编码:
* 1252Windows下Ballance所用的西欧编码
* 936Windows下中文Windows系统默认编码
* CP1252非Windows下Ballance所用的西欧编码
* CP936非Windows下中文默认编码
* cp1252Ballance所用的西欧编码
* gb2312中文Windows系统默认编码
编码属性非常重要如果设置了错误的编码导入Blender的各类物体的名称会出现不可认知的情况。
编码属性非常重要如果设置了错误的编码导入Blender的各类物体的名称会出现不可认知的情况又或者会导致程序出错。
!!! warning "编码是一个平台相关的设定"
根据BBP的Virtools文档导入模块使用的底层库LibCmo的实现编码属性是一个平台相关的设定。在Windows下这里需要填写的是[Windows代码页](https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers)数字。而在其它操作系统下LibCmo使用iconv进行字符编码解码因此需要使用合法的[iconv编码标识符](https://www.gnu.org/software/libiconv/)。
!!! info "有哪些编码可以使用?"
自BBP 4.1版本后我们使用编码的名字基本上就是照抄Python的编码名。大多数Python中常用的编码名都有映射只有一些特别罕见的编码没有支持对于具体支持的编码则需要查看源码。有关Python支持的编码请查看[Python相关文档](https://docs.python.org/3/library/codecs.html#standard-encodings)。编码名不区分大小写。
!!! warning "从旧版本迁移的警告"
自BBP 4.1版本开始BBP的Virtools文档导入模块使用的底层库LibCmo版本号提升为0.2。在此版本前编码属性是一个平台相关的设定。在Windows下这里需要填写的是[Windows代码页](https://learn.microsoft.com/en-us/windows/win32/intl/code-page-identifiers)数字。而在其它操作系统下LibCmo使用iconv进行字符编码解码因此需要使用合法的[iconv编码标识符](https://www.gnu.org/software/libiconv/)。
这一切在LibCmo 0.2后发生了改变从这个版本开始LibCmo采用了类似Python的统一编码名。它是平台无关的你不再需要检查你正在使用的操作系统是Windows还是Linux所有平台的编码字符均为相同的字符串。这也就意味着如果您之前自定义过编码设置你需要注意将他们转换到新的统一编码名因为旧的编码名可能在统一编码名下没有对应映射例如之前在Windows上指定的`1252`,在新的统一编码名下应当被书写为`cp1252`,原编码在新系统下无法被正确识别。
## 导出Virtools文档