| 
									
										
										
										
											2025-01-03 23:42:44 +08:00
										 |  |  | import bpy, mathutils | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  | from bpy_extras.wm_utils.progress_report import ProgressReport | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  | import tempfile, os, typing | 
					
						
							| 
									
										
										
										
											2023-11-16 22:41:03 +08:00
										 |  |  | from . import PROP_preferences, UTIL_ioport_shared | 
					
						
							| 
									
										
										
										
											2024-04-01 14:39:11 +08:00
										 |  |  | from . import UTIL_virtools_types, UTIL_functions, UTIL_file_browser, UTIL_blender_mesh, UTIL_ballance_texture, UTIL_naming_convension | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  | from . import PROP_virtools_group, PROP_virtools_material, PROP_virtools_mesh, PROP_virtools_texture, PROP_virtools_light, PROP_ballance_map_info | 
					
						
							| 
									
										
										
										
											2023-11-09 17:20:57 +08:00
										 |  |  | from .PyBMap import bmap_wrapper as bmap | 
					
						
							| 
									
										
										
										
											2023-10-18 21:23:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-12-30 17:53:42 +08:00
										 |  |  | class BBP_OT_import_virtools(bpy.types.Operator, UTIL_file_browser.ImportVirtoolsFile, UTIL_ioport_shared.ImportParams, UTIL_ioport_shared.VirtoolsParams, UTIL_ioport_shared.BallanceParams): | 
					
						
							| 
									
										
										
										
											2023-10-18 21:23:04 +08:00
										 |  |  |     """Import Virtools File""" | 
					
						
							|  |  |  |     bl_idname = "bbp.import_virtools" | 
					
						
							|  |  |  |     bl_label = "Import Virtools File" | 
					
						
							|  |  |  |     bl_options = {'PRESET', 'UNDO'} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     @classmethod | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |     def poll(cls, context): | 
					
						
							| 
									
										
										
										
											2023-11-09 17:20:57 +08:00
										 |  |  |         return ( | 
					
						
							|  |  |  |             PROP_preferences.get_raw_preferences().has_valid_blc_tex_folder() | 
					
						
							|  |  |  |             and bmap.is_bmap_available()) | 
					
						
							| 
									
										
										
										
											2023-10-18 21:23:04 +08:00
										 |  |  |      | 
					
						
							|  |  |  |     def execute(self, context): | 
					
						
							| 
									
										
										
										
											2025-01-08 20:20:10 +08:00
										 |  |  |         # check whether encoding list is empty to avoid real stupid user. | 
					
						
							|  |  |  |         encodings = self.general_get_vt_encodings(context) | 
					
						
							|  |  |  |         if len(encodings) == 0: | 
					
						
							|  |  |  |             self.report({'ERROR'}, 'You must specify at least one encoding for file loading (e.g. cp1252, gb2312)!') | 
					
						
							|  |  |  |             return {'CANCELLED'} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 17:20:57 +08:00
										 |  |  |         _import_virtools( | 
					
						
							|  |  |  |             self.general_get_filename(), | 
					
						
							| 
									
										
										
										
											2025-01-08 20:20:10 +08:00
										 |  |  |             encodings, | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |             self.general_get_conflict_resolver() | 
					
						
							| 
									
										
										
										
											2023-11-09 17:20:57 +08:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2023-10-18 21:23:04 +08:00
										 |  |  |         self.report({'INFO'}, "Virtools File Importing Finished.") | 
					
						
							|  |  |  |         return {'FINISHED'} | 
					
						
							|  |  |  |      | 
					
						
							| 
									
										
										
										
											2023-11-16 22:41:03 +08:00
										 |  |  |     def draw(self, context): | 
					
						
							|  |  |  |         layout = self.layout | 
					
						
							| 
									
										
										
										
											2024-12-30 17:53:42 +08:00
										 |  |  |         self.draw_import_params(layout) | 
					
						
							| 
									
										
										
										
											2025-01-08 20:20:10 +08:00
										 |  |  |         self.draw_virtools_params(context, layout, True) | 
					
						
							| 
									
										
										
										
											2024-12-30 17:53:42 +08:00
										 |  |  |         self.draw_ballance_params(layout, True) | 
					
						
							| 
									
										
										
										
											2023-11-16 22:41:03 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  | def _import_virtools(file_name_: str, encodings_: tuple[str], resolver: UTIL_ioport_shared.ConflictResolver) -> None: | 
					
						
							| 
									
										
										
										
											2023-11-09 17:20:57 +08:00
										 |  |  |     # create temp folder | 
					
						
							|  |  |  |     with tempfile.TemporaryDirectory() as vt_temp_folder: | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         print(f'Virtools Engine Temp: {vt_temp_folder}') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 17:20:57 +08:00
										 |  |  |         # create virtools reader context | 
					
						
							|  |  |  |         with bmap.BMFileReader( | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |             file_name_,  | 
					
						
							|  |  |  |             vt_temp_folder, | 
					
						
							|  |  |  |             PROP_preferences.get_raw_preferences().mBallanceTextureFolder, | 
					
						
							|  |  |  |             encodings_) as reader: | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # prepare progress reporter | 
					
						
							|  |  |  |             with ProgressReport(wm = bpy.context.window_manager) as progress: | 
					
						
							|  |  |  |                 # import textures | 
					
						
							|  |  |  |                 texture_cret_map: dict[bmap.BMTexture, bpy.types.Image] = _import_virtools_textures( | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                     reader, progress, resolver) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |                 # import materials | 
					
						
							|  |  |  |                 material_cret_map: dict[bmap.BMMaterial, bpy.types.Material] = _import_virtools_materials( | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                     reader, progress, resolver, texture_cret_map) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |                 # import meshes | 
					
						
							|  |  |  |                 mesh_cret_map: dict[bmap.BMMesh, bpy.types.Mesh] = _import_virtools_meshes( | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                     reader, progress, resolver, material_cret_map) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |                 # import 3dobjects | 
					
						
							|  |  |  |                 obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] = _import_virtools_3dobjects( | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                     reader, progress, resolver, mesh_cret_map) | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |                 # import light | 
					
						
							|  |  |  |                 _import_virtools_lights(reader, progress, resolver) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |                 # import groups | 
					
						
							|  |  |  |                 _import_virtools_groups(reader, progress, obj3d_cret_map) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _import_virtools_textures( | 
					
						
							|  |  |  |         reader: bmap.BMFileReader,  | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         progress: ProgressReport, | 
					
						
							|  |  |  |         resolver: UTIL_ioport_shared.ConflictResolver | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         ) -> dict[bmap.BMTexture, bpy.types.Image]: | 
					
						
							|  |  |  |     # create map | 
					
						
							|  |  |  |     texture_cret_map: dict[bmap.BMTexture, bpy.types.Image] = {} | 
					
						
							|  |  |  |     progress.enter_substeps(reader.get_texture_count(), "Loading Textures") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # create another temp folder for raw data virtools texture importing | 
					
						
							|  |  |  |     with tempfile.TemporaryDirectory() as rawdata_temp: | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         print(f'Texture Raw Data Temp: {rawdata_temp}') | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         for vttexture in reader.get_textures(): | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |             tex_cret: typing.Callable[[], bpy.types.Image] | 
					
						
							| 
									
										
										
										
											2023-11-15 23:05:00 +08:00
										 |  |  |             texpath_to_load: str | None = vttexture.get_file_name() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # if no assoc file path (what? but it is real happended) | 
					
						
							|  |  |  |             # this is invalid image, create a blank image instead | 
					
						
							|  |  |  |             if texpath_to_load is None: | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                 tex_cret = lambda: bpy.data.images.new("", 1, 1) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |             else: | 
					
						
							| 
									
										
										
										
											2023-11-15 23:05:00 +08:00
										 |  |  |                 # if this image is raw data, save it in external folder before loading | 
					
						
							|  |  |  |                 # the attribute of raw data saving is the file path is not absolute path | 
					
						
							|  |  |  |                 if not os.path.isabs(texpath_to_load): | 
					
						
							|  |  |  |                     texpath_to_load = os.path.join( | 
					
						
							|  |  |  |                         rawdata_temp, | 
					
						
							|  |  |  |                         os.path.basename(texpath_to_load) | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  |                     vttexture.save_image(texpath_to_load) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # detect whether it is ballance texture and load | 
					
						
							| 
									
										
										
										
											2023-11-23 22:34:06 +08:00
										 |  |  |                 try_blc_tex: str | None = UTIL_ballance_texture.get_ballance_texture_filename(texpath_to_load) | 
					
						
							| 
									
										
										
										
											2023-11-15 23:05:00 +08:00
										 |  |  |                  | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                 if try_blc_tex is not None: | 
					
						
							| 
									
										
										
										
											2023-11-15 23:05:00 +08:00
										 |  |  |                     # load as ballance texture | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                     tex_cret = lambda: UTIL_ballance_texture.load_ballance_texture(typing.cast(str, try_blc_tex)) | 
					
						
							| 
									
										
										
										
											2023-11-15 23:05:00 +08:00
										 |  |  |                 else: | 
					
						
							|  |  |  |                     # load as other textures | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |                     tex_cret = lambda: UTIL_ballance_texture.load_other_texture(typing.cast(str, texpath_to_load)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # create real texture by tex cret fct | 
					
						
							|  |  |  |             (tex, init_tex) = resolver.create_texture( | 
					
						
							|  |  |  |                 UTIL_virtools_types.virtools_name_regulator(vttexture.get_name()),  | 
					
						
							|  |  |  |                 tex_cret | 
					
						
							|  |  |  |             ) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             # init tex if needed | 
					
						
							|  |  |  |             if init_tex: | 
					
						
							|  |  |  |                 # set texture cfg | 
					
						
							|  |  |  |                 rawtex: PROP_virtools_texture.RawVirtoolsTexture = PROP_virtools_texture.RawVirtoolsTexture() | 
					
						
							|  |  |  |                 rawtex.mSaveOptions = vttexture.get_save_options() | 
					
						
							|  |  |  |                 rawtex.mVideoFormat = vttexture.get_video_format() | 
					
						
							|  |  |  |                 PROP_virtools_texture.set_raw_virtools_texture(tex, rawtex) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # insert it to map | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |             texture_cret_map[vttexture] = tex | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # inc steps | 
					
						
							|  |  |  |             progress.step() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # leave progress and return map | 
					
						
							|  |  |  |     progress.leave_substeps() | 
					
						
							|  |  |  |     return texture_cret_map | 
					
						
							|  |  |  |      | 
					
						
							|  |  |  | def _import_virtools_materials( | 
					
						
							|  |  |  |         reader: bmap.BMFileReader,  | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         progress: ProgressReport, | 
					
						
							|  |  |  |         resolver: UTIL_ioport_shared.ConflictResolver, | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         texture_cret_map: dict[bmap.BMTexture, bpy.types.Image] | 
					
						
							|  |  |  |         ) -> dict[bmap.BMMaterial, bpy.types.Material]: | 
					
						
							|  |  |  |     # create map and prepare progress | 
					
						
							|  |  |  |     material_cret_map: dict[bmap.BMMaterial, bpy.types.Material] = {} | 
					
						
							|  |  |  |     progress.enter_substeps(reader.get_material_count(), "Loading Materials") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     for vtmaterial in reader.get_materials(): | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         # create mtl | 
					
						
							|  |  |  |         (mtl, init_mtl) = resolver.create_material( | 
					
						
							| 
									
										
										
										
											2023-11-26 20:37:19 +08:00
										 |  |  |             UTIL_virtools_types.virtools_name_regulator(vtmaterial.get_name()) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         ) | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # apply it if necessary | 
					
						
							|  |  |  |         if init_mtl: | 
					
						
							|  |  |  |             # create new raw material | 
					
						
							|  |  |  |             rawmtl: PROP_virtools_material.RawVirtoolsMaterial = PROP_virtools_material.RawVirtoolsMaterial() | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |             rawmtl.mDiffuse = vtmaterial.get_diffuse() | 
					
						
							|  |  |  |             rawmtl.mAmbient = vtmaterial.get_ambient() | 
					
						
							|  |  |  |             rawmtl.mSpecular = vtmaterial.get_specular() | 
					
						
							|  |  |  |             rawmtl.mEmissive = vtmaterial.get_emissive() | 
					
						
							|  |  |  |             rawmtl.mSpecularPower = vtmaterial.get_specular_power() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             mtltex: bmap.BMTexture | None = vtmaterial.get_texture() | 
					
						
							|  |  |  |             if mtltex: | 
					
						
							|  |  |  |                 rawmtl.mTexture = texture_cret_map.get(mtltex, None) | 
					
						
							|  |  |  |             else: | 
					
						
							|  |  |  |                 rawmtl.mTexture = None | 
					
						
							|  |  |  |             rawmtl.mTextureBorderColor = vtmaterial.get_texture_border_color() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rawmtl.mTextureBlendMode = vtmaterial.get_texture_blend_mode() | 
					
						
							|  |  |  |             rawmtl.mTextureMinMode = vtmaterial.get_texture_min_mode() | 
					
						
							|  |  |  |             rawmtl.mTextureMagMode = vtmaterial.get_texture_mag_mode() | 
					
						
							|  |  |  |             rawmtl.mTextureAddressMode = vtmaterial.get_texture_address_mode() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rawmtl.mSourceBlend = vtmaterial.get_source_blend() | 
					
						
							|  |  |  |             rawmtl.mDestBlend = vtmaterial.get_dest_blend() | 
					
						
							|  |  |  |             rawmtl.mFillMode = vtmaterial.get_fill_mode() | 
					
						
							|  |  |  |             rawmtl.mShadeMode = vtmaterial.get_shade_mode() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rawmtl.mEnableAlphaTest = vtmaterial.get_alpha_test_enabled() | 
					
						
							|  |  |  |             rawmtl.mEnableAlphaBlend = vtmaterial.get_alpha_blend_enabled() | 
					
						
							|  |  |  |             rawmtl.mEnablePerspectiveCorrection = vtmaterial.get_perspective_correction_enabled() | 
					
						
							|  |  |  |             rawmtl.mEnableZWrite = vtmaterial.get_z_write_enabled() | 
					
						
							|  |  |  |             rawmtl.mEnableTwoSided = vtmaterial.get_two_sided_enabled() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             rawmtl.mAlphaRef = vtmaterial.get_alpha_ref() | 
					
						
							|  |  |  |             rawmtl.mAlphaFunc = vtmaterial.get_alpha_func() | 
					
						
							|  |  |  |             rawmtl.mZFunc = vtmaterial.get_z_func() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             PROP_virtools_material.set_raw_virtools_material(mtl, rawmtl) | 
					
						
							|  |  |  |             PROP_virtools_material.apply_to_blender_material(mtl) | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |         # add into map and step | 
					
						
							|  |  |  |         material_cret_map[vtmaterial] = mtl | 
					
						
							|  |  |  |         progress.step() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # leave progress and return | 
					
						
							|  |  |  |     progress.leave_substeps() | 
					
						
							|  |  |  |     return material_cret_map | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _import_virtools_meshes( | 
					
						
							|  |  |  |         reader: bmap.BMFileReader,  | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         progress: ProgressReport, | 
					
						
							|  |  |  |         resolver: UTIL_ioport_shared.ConflictResolver,  | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         material_cret_map: dict[bmap.BMMaterial, bpy.types.Material] | 
					
						
							|  |  |  |         ) -> dict[bmap.BMMesh, bpy.types.Mesh]: | 
					
						
							|  |  |  |     # create map and prepare progress | 
					
						
							|  |  |  |     mesh_cret_map: dict[bmap.BMMesh, bpy.types.Mesh] = {} | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |     progress.enter_substeps(reader.get_mesh_count(), "Loading Meshes") | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for vtmesh in reader.get_meshs(): | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         # create mesh | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         (mesh, init_mesh) = resolver.create_mesh( | 
					
						
							| 
									
										
										
										
											2023-11-26 20:37:19 +08:00
										 |  |  |             UTIL_virtools_types.virtools_name_regulator(vtmesh.get_name()) | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         # set mesh data if necessary | 
					
						
							|  |  |  |         if init_mesh: | 
					
						
							|  |  |  |             # open mesh writer | 
					
						
							|  |  |  |             with UTIL_blender_mesh.MeshWriter(mesh) as meshoper: | 
					
						
							|  |  |  |                 # construct data provider | 
					
						
							|  |  |  |                 data_prov: UTIL_blender_mesh.MeshWriterIngredient = UTIL_blender_mesh.MeshWriterIngredient() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # constructor data itor | 
					
						
							|  |  |  |                 def pos_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]: | 
					
						
							|  |  |  |                     for v in vtmesh.get_vertex_positions(): | 
					
						
							|  |  |  |                         UTIL_virtools_types.vxvector3_conv_co(v) | 
					
						
							|  |  |  |                         yield v | 
					
						
							|  |  |  |                 def nml_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector3]: | 
					
						
							|  |  |  |                     for v in vtmesh.get_vertex_normals(): | 
					
						
							|  |  |  |                         UTIL_virtools_types.vxvector3_conv_co(v) | 
					
						
							|  |  |  |                         yield v | 
					
						
							|  |  |  |                 def uv_iterator() -> typing.Iterator[UTIL_virtools_types.VxVector2]: | 
					
						
							|  |  |  |                     for v in vtmesh.get_vertex_uvs(): | 
					
						
							|  |  |  |                         UTIL_virtools_types.vxvector2_conv_co(v) | 
					
						
							|  |  |  |                         yield v | 
					
						
							|  |  |  |                 def face_iterator() -> typing.Iterator[UTIL_blender_mesh.FaceData]: | 
					
						
							|  |  |  |                     face: UTIL_blender_mesh.FaceData = UTIL_blender_mesh.FaceData( | 
					
						
							|  |  |  |                         [UTIL_blender_mesh.FaceVertexData() for i in range(3)] | 
					
						
							|  |  |  |                     ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                     findices_itor = vtmesh.get_face_indices() | 
					
						
							|  |  |  |                     fmtl_itor = vtmesh.get_face_material_slot_indexs() | 
					
						
							|  |  |  |                     for _ in range(vtmesh.get_face_count()): | 
					
						
							|  |  |  |                         # set indices data | 
					
						
							|  |  |  |                         vtindices = next(findices_itor) | 
					
						
							|  |  |  |                         face.mIndices[0].mPosIdx = vtindices.i1 | 
					
						
							|  |  |  |                         face.mIndices[0].mNmlIdx = vtindices.i1 | 
					
						
							|  |  |  |                         face.mIndices[0].mUvIdx = vtindices.i1 | 
					
						
							|  |  |  |                         face.mIndices[1].mPosIdx = vtindices.i2 | 
					
						
							|  |  |  |                         face.mIndices[1].mNmlIdx = vtindices.i2 | 
					
						
							|  |  |  |                         face.mIndices[1].mUvIdx = vtindices.i2 | 
					
						
							|  |  |  |                         face.mIndices[2].mPosIdx = vtindices.i3 | 
					
						
							|  |  |  |                         face.mIndices[2].mNmlIdx = vtindices.i3 | 
					
						
							|  |  |  |                         face.mIndices[2].mUvIdx = vtindices.i3 | 
					
						
							|  |  |  |                         # swap indices | 
					
						
							|  |  |  |                         face.conv_co() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         # set mtl data | 
					
						
							|  |  |  |                         vtmtl = next(fmtl_itor) | 
					
						
							|  |  |  |                         face.mMtlIdx = vtmtl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                         # return | 
					
						
							|  |  |  |                         yield face | 
					
						
							|  |  |  |                 def mtl_iterator() -> typing.Iterator[bpy.types.Material | None]: | 
					
						
							|  |  |  |                     for vtmtl in vtmesh.get_material_slots(): | 
					
						
							|  |  |  |                         if vtmtl: | 
					
						
							|  |  |  |                             yield material_cret_map.get(vtmtl, None) | 
					
						
							|  |  |  |                         else: | 
					
						
							|  |  |  |                             yield None | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # assign to data provider | 
					
						
							|  |  |  |                 data_prov.mVertexPosition = pos_iterator() | 
					
						
							|  |  |  |                 data_prov.mVertexNormal = nml_iterator() | 
					
						
							|  |  |  |                 data_prov.mVertexUV = uv_iterator() | 
					
						
							|  |  |  |                 data_prov.mFace = face_iterator() | 
					
						
							|  |  |  |                 data_prov.mMaterial = mtl_iterator() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |                 # add part | 
					
						
							|  |  |  |                 meshoper.add_ingredient(data_prov) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # end of mesh writer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # set other mesh settings | 
					
						
							|  |  |  |             mesh_settings: PROP_virtools_mesh.RawVirtoolsMesh = PROP_virtools_mesh.RawVirtoolsMesh() | 
					
						
							|  |  |  |             mesh_settings.mLitMode = vtmesh.get_lit_mode() | 
					
						
							|  |  |  |             PROP_virtools_mesh.set_raw_virtools_mesh(mesh, mesh_settings) | 
					
						
							| 
									
										
										
										
											2023-11-15 23:05:00 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         # add into map and step | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         mesh_cret_map[vtmesh] = mesh | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         progress.step() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # leave progress and return | 
					
						
							|  |  |  |     progress.leave_substeps() | 
					
						
							|  |  |  |     return mesh_cret_map | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def _import_virtools_3dobjects( | 
					
						
							|  |  |  |         reader: bmap.BMFileReader,  | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         progress: ProgressReport, | 
					
						
							|  |  |  |         resolver: UTIL_ioport_shared.ConflictResolver,  | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         mesh_cret_map: dict[bmap.BMMesh, bpy.types.Mesh] | 
					
						
							|  |  |  |         ) -> dict[bmap.BM3dObject, bpy.types.Object]: | 
					
						
							|  |  |  |     # create map and prepare progress | 
					
						
							|  |  |  |     obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] = {} | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |     progress.enter_substeps(reader.get_3dobject_count(), "Loading 3dObjects") | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |     for vt3dobj in reader.get_3dobjects(): | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         # get virtools binding mesh data first | 
					
						
							|  |  |  |         vt3dobj_data: bmap.BMMesh | None = vt3dobj.get_current_mesh() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         # create 3d object with mesh | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         (obj3d, init_obj3d) = resolver.create_object( | 
					
						
							| 
									
										
										
										
											2023-11-26 20:37:19 +08:00
										 |  |  |             UTIL_virtools_types.virtools_name_regulator(vt3dobj.get_name()), | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |             None if vt3dobj_data is None else mesh_cret_map.get(vt3dobj_data, None) | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |         # setup if necessary | 
					
						
							|  |  |  |         if init_obj3d: | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |             # add into scene | 
					
						
							|  |  |  |             UTIL_functions.add_into_scene(obj3d) | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |             # set world matrix | 
					
						
							|  |  |  |             vtmat: UTIL_virtools_types.VxMatrix = vt3dobj.get_world_matrix() | 
					
						
							|  |  |  |             UTIL_virtools_types.vxmatrix_conv_co(vtmat) | 
					
						
							|  |  |  |             obj3d.matrix_world = UTIL_virtools_types.vxmatrix_to_blender(vtmat) | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |             # set visibility | 
					
						
							|  |  |  |             obj3d.hide_set(not vt3dobj.get_visibility()) | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-01-04 10:35:52 +08:00
										 |  |  |             # add into map | 
					
						
							|  |  |  |             # NOTE: the return value only provided to group setter | 
					
						
							|  |  |  |             # and group setter should only set group data to new created 3d objects | 
					
						
							|  |  |  |             # thus we only insert pair when this 3d obj is new created. | 
					
						
							|  |  |  |             obj3d_cret_map[vt3dobj] = obj3d | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # step forward | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         progress.step() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # leave progress and return | 
					
						
							|  |  |  |     progress.leave_substeps() | 
					
						
							|  |  |  |     return obj3d_cret_map | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  | 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 | 
					
						
							|  |  |  |             vtmat: UTIL_virtools_types.VxMatrix = vtlight.get_world_matrix() | 
					
						
							|  |  |  |             UTIL_virtools_types.vxmatrix_conv_co(vtmat) | 
					
						
							| 
									
										
										
										
											2025-01-03 23:42:44 +08:00
										 |  |  |             bldmat: mathutils.Matrix = UTIL_virtools_types.vxmatrix_to_blender(vtmat) | 
					
						
							|  |  |  |             light_3dobj.matrix_world = UTIL_virtools_types.bldmatrix_patch_light_obj(bldmat) | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |             # set visibility | 
					
						
							|  |  |  |             light_3dobj.hide_set(not vtlight.get_visibility()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # leave progress | 
					
						
							|  |  |  |     progress.leave_substeps() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  | def _import_virtools_groups( | 
					
						
							|  |  |  |         reader: bmap.BMFileReader,  | 
					
						
							|  |  |  |         progress: ProgressReport,  | 
					
						
							|  |  |  |         obj3d_cret_map: dict[bmap.BM3dObject, bpy.types.Object] | 
					
						
							| 
									
										
										
										
											2024-04-01 14:39:11 +08:00
										 |  |  |         ) -> None: | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |     # we need iterate all groups to construct a reversed map | 
					
						
							|  |  |  |     # to indicate which groups should this 3dobject be grouped into. | 
					
						
							|  |  |  |     reverse_map: dict[bmap.BM3dObject, set[str]] = {} | 
					
						
							| 
									
										
										
										
											2024-04-01 14:39:11 +08:00
										 |  |  |     # sector counter to record the maximum sector we have processed. | 
					
						
							|  |  |  |     sector_count: int = 1 | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |     # prepare progress | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |     progress.enter_substeps(reader.get_group_count(), "Loading Groups") | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  |     for vtgroup in reader.get_groups(): | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         # if this group do not have name, skip it | 
					
						
							|  |  |  |         group_name: str | None = vtgroup.get_name() | 
					
						
							|  |  |  |         if group_name is None: continue | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 14:39:11 +08:00
										 |  |  |         # try extracting sector info | 
					
						
							|  |  |  |         potential_sector_count: int | None = UTIL_naming_convension.extract_sector_from_name(group_name) | 
					
						
							|  |  |  |         if potential_sector_count is not None: | 
					
						
							|  |  |  |             sector_count = max(sector_count, potential_sector_count) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # creating map | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |         for item in vtgroup.get_objects(): | 
					
						
							|  |  |  |             # get or create set | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |             objgroups: set[str] | None = reverse_map.get(item, None) | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |             if objgroups is None: | 
					
						
							|  |  |  |                 objgroups = set() | 
					
						
							|  |  |  |                 reverse_map[item] = objgroups | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             # add into list | 
					
						
							|  |  |  |             objgroups.add(group_name) | 
					
						
							|  |  |  |              | 
					
						
							|  |  |  |         # step | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |         progress.step() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-01 14:39:11 +08:00
										 |  |  |     # assign to ballance map info according to gotten sector count | 
					
						
							|  |  |  |     map_info: PROP_ballance_map_info.RawBallanceMapInfo = PROP_ballance_map_info.get_raw_ballance_map_info(bpy.context.scene) | 
					
						
							|  |  |  |     map_info.mSectorCount = max(map_info.mSectorCount, sector_count) | 
					
						
							|  |  |  |     PROP_ballance_map_info.set_raw_ballance_map_info(bpy.context.scene, map_info) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-09 21:41:26 +08:00
										 |  |  |     # leave progress | 
					
						
							|  |  |  |     progress.leave_substeps() | 
					
						
							| 
									
										
										
										
											2023-10-18 21:23:04 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |     # now we can assign 3dobject group data by reverse map | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |     progress.enter_substeps(len(reverse_map), "Applying Groups") | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |     for mapk, mapv in reverse_map.items(): | 
					
						
							|  |  |  |         # check object | 
					
						
							|  |  |  |         assoc_obj = obj3d_cret_map.get(mapk, None) | 
					
						
							|  |  |  |         if assoc_obj is None: continue | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         # assign group | 
					
						
							|  |  |  |         with PROP_virtools_group.VirtoolsGroupsHelper(assoc_obj) as gpoper: | 
					
						
							| 
									
										
										
										
											2023-11-30 22:38:53 +08:00
										 |  |  |             gpoper.clear_groups() | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |             gpoper.add_groups(mapv) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2025-01-03 09:36:32 +08:00
										 |  |  |         # step | 
					
						
							|  |  |  |         progress.step() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     # leave progress | 
					
						
							| 
									
										
										
										
											2023-11-10 12:26:04 +08:00
										 |  |  |     progress.leave_substeps() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-10-18 21:23:04 +08:00
										 |  |  | def register() -> None: | 
					
						
							|  |  |  |     bpy.utils.register_class(BBP_OT_import_virtools) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | def unregister() -> None: | 
					
						
							|  |  |  |     bpy.utils.unregister_class(BBP_OT_import_virtools) |