From 43713086d43b400d51bdb1a67e1b5603a4a3c65b Mon Sep 17 00:00:00 2001 From: Deinyon Davies Date: Tue, 17 Jun 2025 19:56:09 +1000 Subject: [PATCH] WIP Map Export --- __init__.py | 11 ++- gui/dff_menus.py | 6 ++ gui/gui.py | 2 + gui/ide_ot.py | 62 ++++++++++++++ gui/ipl_ot.py | 62 ++++++++++++++ gui/map.py | 199 +++++++++++++++++++++++++++++++++++++++++++- ops/ide_exporter.py | 176 +++++++++++++++++++++++++++++++++++++++ ops/ipl_exporter.py | 116 ++++++++++++++++++++++++++ ops/map_importer.py | 50 +++++++++++ 9 files changed, 682 insertions(+), 2 deletions(-) create mode 100644 gui/ide_ot.py create mode 100644 gui/ipl_ot.py create mode 100644 ops/ide_exporter.py create mode 100644 ops/ipl_exporter.py diff --git a/__init__.py b/__init__.py index ddd6a04..be633e2 100644 --- a/__init__.py +++ b/__init__.py @@ -75,7 +75,12 @@ gui.CollisionCollectionGizmoGroup, gui.RoadSign2DFXGizmoGroup, gui.Escalator2DFXGizmoGroup, - map_importer.Map_Import_Operator + map_importer.Map_Import_Operator, + gui.EXPORT_OT_ipl, + gui.EXPORT_OT_ide, + gui.IDEObjectProps, + gui.IPLObjectProps, + gui.MapObjectPanel ] _draw_3d_handler = None @@ -97,6 +102,8 @@ def register(): bpy.types.Material.dff = bpy.props.PointerProperty(type=gui.DFFMaterialProps) bpy.types.Object.dff = bpy.props.PointerProperty(type=gui.DFFObjectProps) bpy.types.Collection.dff = bpy.props.PointerProperty(type=gui.DFFCollectionProps) + bpy.types.Object.ide = bpy.props.PointerProperty(type=gui.IDEObjectProps) + bpy.types.Object.ipl = bpy.props.PointerProperty(type=gui.IPLObjectProps) bpy.types.TOPBAR_MT_file_import.append(gui.import_dff_func) bpy.types.TOPBAR_MT_file_export.append(gui.export_dff_func) @@ -119,6 +126,8 @@ def unregister(): del bpy.types.Material.dff del bpy.types.Object.dff del bpy.types.Collection.dff + del bpy.types.Object.ide + del bpy.types.Object.ipl bpy.types.TOPBAR_MT_file_import.remove(gui.import_dff_func) bpy.types.TOPBAR_MT_file_export.remove(gui.export_dff_func) diff --git a/gui/dff_menus.py b/gui/dff_menus.py index 802f105..9552ffa 100644 --- a/gui/dff_menus.py +++ b/gui/dff_menus.py @@ -6,6 +6,8 @@ from .dff_ot import SCENE_OT_dff_frame_move, SCENE_OT_dff_atomic_move, SCENE_OT_dff_update from .col_ot import EXPORT_OT_col, OBJECT_OT_facegoups_col, COLLECTION_OT_dff_generate_bounds from .ext_2dfx_menus import EXT2DFXObjectProps, EXT2DFXMenus +from .ide_ot import EXPORT_OT_ide +from .ipl_ot import EXPORT_OT_ipl texture_filters_items = ( ("0", "Disabled", ""), @@ -225,6 +227,10 @@ def draw(self, context): op = self.layout.operator(EXPORT_OT_col.bl_idname, text="DragonFF Collision (.col)") op.use_active_collection = False + self.layout.operator(EXPORT_OT_ide.bl_idname, + text="DragonFF IDE (.ide)") + self.layout.operator(EXPORT_OT_ipl.bl_idname, + text="DragonFF IPL (.ipl)") ####################################################### diff --git a/gui/gui.py b/gui/gui.py index 3b733b7..efcb177 100644 --- a/gui/gui.py +++ b/gui/gui.py @@ -20,3 +20,5 @@ from .dff_ot import * from .map import * from .gizmos import * +from .ipl_ot import * +from .ide_ot import * diff --git a/gui/ide_ot.py b/gui/ide_ot.py new file mode 100644 index 0000000..ce515ed --- /dev/null +++ b/gui/ide_ot.py @@ -0,0 +1,62 @@ +import bpy +from bpy_extras.io_utils import ExportHelper +from ..ops import ide_exporter +from ..ops.importer_common import game_version + + +class EXPORT_OT_ide(bpy.types.Operator, ExportHelper): + """Export IDE file""" + bl_idname = "export_ide.scene" + bl_description = "Export a GTA IDE File" + bl_label = "DragonFF IDE (.ide)" + filename_ext = ".ide" + + filepath: bpy.props.StringProperty( + name="File path", + maxlen=1024, + default="", + subtype='FILE_PATH' + ) + + filter_glob: bpy.props.StringProperty( + default="*.ide", + options={'HIDDEN'} + ) + + only_selected: bpy.props.BoolProperty( + name="Only Selected", + description="Export only selected objects", + default=False + ) + + game_version_dropdown: bpy.props.EnumProperty( + name='Game Version', + items=( + (game_version.III, 'GTA III', 'Export for GTA III'), + (game_version.VC, 'GTA VC', 'Export for GTA Vice City'), + (game_version.SA, 'GTA SA', 'Export for GTA San Andreas'), + ), + default=game_version.SA + ) + + def execute(self, context): + result, message = ide_exporter.export_ide( + self.filepath, + self.game_version_dropdown, + self.only_selected + ) + + if result == {'FINISHED'}: + self.report({'INFO'}, message) + else: + self.report({'ERROR'}, message) + + return result + + def invoke(self, context, event): + # Try to get game version from scene settings + if hasattr(context.scene, 'dff'): + self.game_version_dropdown = context.scene.dff.game_version_dropdown + + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} diff --git a/gui/ipl_ot.py b/gui/ipl_ot.py new file mode 100644 index 0000000..3ba92a6 --- /dev/null +++ b/gui/ipl_ot.py @@ -0,0 +1,62 @@ +import bpy +from bpy_extras.io_utils import ExportHelper +from ..ops import ipl_exporter +from ..ops.importer_common import game_version + + +class EXPORT_OT_ipl(bpy.types.Operator, ExportHelper): + """Export IPL file""" + bl_idname = "export_ipl.scene" + bl_description = "Export a GTA IPL File" + bl_label = "DragonFF IPL (.ipl)" + filename_ext = ".ipl" + + filepath: bpy.props.StringProperty( + name="File path", + maxlen=1024, + default="", + subtype='FILE_PATH' + ) + + filter_glob: bpy.props.StringProperty( + default="*.ipl", + options={'HIDDEN'} + ) + + only_selected: bpy.props.BoolProperty( + name="Only Selected", + description="Export only selected objects", + default=False + ) + + game_version_dropdown: bpy.props.EnumProperty( + name='Game Version', + items=( + (game_version.III, 'GTA III', 'Export for GTA III'), + (game_version.VC, 'GTA VC', 'Export for GTA Vice City'), + (game_version.SA, 'GTA SA', 'Export for GTA San Andreas'), + ), + default=game_version.SA + ) + + def execute(self, context): + result, message = ipl_exporter.export_ipl( + self.filepath, + self.game_version_dropdown, + self.only_selected + ) + + if result == {'FINISHED'}: + self.report({'INFO'}, message) + else: + self.report({'ERROR'}, message) + + return result + + def invoke(self, context, event): + # Try to get game version from scene settings + if hasattr(context.scene, 'dff'): + self.game_version_dropdown = context.scene.dff.game_version_dropdown + + context.window_manager.fileselect_add(self) + return {'RUNNING_MODAL'} diff --git a/gui/map.py b/gui/map.py index 96daabc..309d29e 100644 --- a/gui/map.py +++ b/gui/map.py @@ -7,6 +7,96 @@ from ..data import map_data from ..ops.importer_common import game_version +####################################################### +class IDEObjectProps(bpy.types.PropertyGroup): + """IDE properties for objects""" + + obj_id: bpy.props.StringProperty( + name="Object ID", + description="Unique object ID in IDE files", + default="" + ) + + model_name: bpy.props.StringProperty( + name="Model Name", + description="Model name (should match DFF filename)", + default="" + ) + + txd_name: bpy.props.StringProperty( + name="TXD Name", + description="Texture dictionary name", + default="" + ) + + flags: bpy.props.StringProperty( + name="Flags", + description="Object flags", + default="0" + ) + + draw_distance: bpy.props.StringProperty( + name="Draw Distance", + description="Single draw distance", + default="100" + ) + + draw_distance1: bpy.props.StringProperty( + name="Draw Distance 1", + description="First draw distance (for multi-LOD objects)", + default="" + ) + + draw_distance2: bpy.props.StringProperty( + name="Draw Distance 2", + description="Second draw distance (for multi-LOD objects)", + default="" + ) + + draw_distance3: bpy.props.StringProperty( + name="Draw Distance 3", + description="Third draw distance (for multi-LOD objects)", + default="" + ) + + obj_type: bpy.props.EnumProperty( + name="Object Type", + description="IDE object type", + items=[ + ('objs', 'Regular Object', 'Standard object'), + ('tobj', 'Time Object', 'Time-based object') + ], + default='objs' + ) + + time_on: bpy.props.StringProperty( + name="Time On", + description="Hour when object appears (0-23)", + default="0" + ) + + time_off: bpy.props.StringProperty( + name="Time Off", + description="Hour when object disappears (0-23)", + default="24" + ) + +####################################################### +class IPLObjectProps(bpy.types.PropertyGroup): + """IPL properties for objects""" + + interior: bpy.props.StringProperty( + name="Interior", + description="Interior ID (0 for exterior)", + default="0" + ) + + lod: bpy.props.StringProperty( + name="LOD", + description="LOD object ID (-1 for no LOD)", + default="-1" + ) + ####################################################### class DFFFrameProps(bpy.types.PropertyGroup): obj : bpy.props.PointerProperty(type=bpy.types.Object) @@ -283,7 +373,7 @@ def execute(self, context): ####################################################### class MapImportPanel(bpy.types.Panel): """Creates a Panel in the scene context of the properties editor""" - bl_label = "DragonFF - Map Import" + bl_label = "DragonFF - Map I/O" bl_idname = "SCENE_PT_layout" bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' @@ -322,3 +412,110 @@ def draw(self, context): row = layout.row() row.operator("scene.dragonff_map_import") + + layout.separator() + + row = layout.row() + row.operator("export_ipl.scene", text="Export IPL") + + row = layout.row() + row.operator("export_ide.scene", text="Export IDE") + + +####################################################### +class MapObjectPanel(bpy.types.Panel): + """Panel for IPL/IDE object properties""" + bl_label = "DragonFF - Map Properties" + bl_idname = "OBJECT_PT_map_props" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "object" + + @classmethod + def poll(cls, context): + return context.object is not None + + def draw(self, context): + layout = self.layout + obj = context.object + + # IPL Data + box = layout.box() + box.label(text="IPL Data (Instance Placement):", icon='OUTLINER_OB_EMPTY') + + col = box.column() + + row = col.row() + row.label(text="Object ID:") + row.label(text=obj.ide.obj_id if obj.ide.obj_id else "Not Set") + + row = col.row() + row.label(text="Model Name:") + row.label(text=obj.ide.model_name if obj.ide.model_name else "Not Set") + + row = col.row() + row.prop(obj.ipl, "interior") + + if context.scene.dff.game_version_dropdown == game_version.SA: + row = col.row() + row.prop(obj.ipl, "lod") + + # Show current transform + col.separator() + col.label(text="Transform:") + col.label(text=f"Position: {obj.location.x:.3f}, {obj.location.y:.3f}, {obj.location.z:.3f}") + rot = obj.rotation_quaternion + col.label(text=f"Rotation: {rot.x:.3f}, {rot.y:.3f}, {rot.z:.3f}, {rot.w:.3f}") + + # IDE Data + box = layout.box() + box.label(text="IDE Data (Object Definition):", icon='OUTLINER_DATA_MESH') + + col = box.column() + + # Object ID + row = col.row(align=True) + row.prop(obj.ide, "obj_id") + + # Model Name + row = col.row() + row.prop(obj.ide, "model_name") + + # Object Type + row = col.row() + row.prop(obj.ide, "obj_type") + + # TXD Name + row = col.row() + row.prop(obj.ide, "txd_name") + + # Flags + row = col.row() + row.prop(obj.ide, "flags") + + # Draw Distances + col.separator() + col.label(text="Draw Distances:") + + # Check which draw distance format to use + if obj.ide.draw_distance1 or obj.ide.draw_distance2 or obj.ide.draw_distance3: + # Multiple draw distances + row = col.row() + row.prop(obj.ide, "draw_distance1") + row = col.row() + row.prop(obj.ide, "draw_distance2") + row = col.row() + row.prop(obj.ide, "draw_distance3") + else: + # Single draw distance + row = col.row() + row.prop(obj.ide, "draw_distance") + + # Time Object Properties + if obj.ide.obj_type == 'tobj': + col.separator() + col.label(text="Time Object Properties:") + + row = col.row() + row.prop(obj.ide, "time_on") + row.prop(obj.ide, "time_off") diff --git a/ops/ide_exporter.py b/ops/ide_exporter.py new file mode 100644 index 0000000..ebccfc8 --- /dev/null +++ b/ops/ide_exporter.py @@ -0,0 +1,176 @@ +# GTA DragonFF - Blender scripts to edit basic GTA formats +# Copyright (C) 2019 Parik + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import bpy +import os +from .importer_common import game_version + + +class IDEExporter: + + def __init__(self): + self.game_version = None + self.objects = [] + self.selected_only = False + + def collect_objects(self, context): + """Collect objects that have IDE data""" + objects_to_export = [] + ide_objects = {} # Group by ID to avoid duplicates + + if self.selected_only: + objects = context.selected_objects + else: + objects = context.scene.objects + + for obj in objects: + # Export objects that have IDE data + if hasattr(obj, 'ide') and obj.ide.obj_id and obj.ide.txd_name: + obj_id = obj.ide.obj_id + # Only add if we haven't seen this ID before + if obj_id not in ide_objects: + ide_objects[obj_id] = obj + + return list(ide_objects.values()) + + def get_draw_distances(self, obj): + """Get draw distances for the object""" + distances = [] + + # Check for single draw distance + if obj.ide.draw_distance: + distances.append(obj.ide.draw_distance) + + # Check for multiple draw distances + if obj.ide.draw_distance1: + distances.append(obj.ide.draw_distance1) + if obj.ide.draw_distance2: + distances.append(obj.ide.draw_distance2) + if obj.ide.draw_distance3: + distances.append(obj.ide.draw_distance3) + + # Default to single distance of 100 if none found + if not distances: + distances = ['100'] + + return distances + + def format_objs_line(self, obj): + """Format an object as an objs line based on game version""" + + obj_id = obj.ide.obj_id + model_name = obj.ide.model_name or obj.name + txd_name = obj.ide.txd_name or model_name + flags = obj.ide.flags or '0' + + distances = self.get_draw_distances(obj) + + # Format based on number of draw distances + if len(distances) == 1: + # Format: ID, ModelName, TxdName, DrawDistance, Flags + return f"{obj_id}, {model_name}, {txd_name}, {distances[0]}, {flags}" + elif len(distances) == 2: + # Format: ID, ModelName, TxdName, MeshCount, DrawDistance1, DrawDistance2, Flags + mesh_count = '1' # Default to 1 for now + return f"{obj_id}, {model_name}, {txd_name}, {mesh_count}, {distances[0]}, {distances[1]}, {flags}" + elif len(distances) == 3: + # Format: ID, ModelName, TxdName, MeshCount, DrawDistance1, DrawDistance2, DrawDistance3, Flags + mesh_count = '1' # Default to 1 for now + return f"{obj_id}, {model_name}, {txd_name}, {mesh_count}, {distances[0]}, {distances[1]}, {distances[2]}, {flags}" + else: + # Default format + return f"{obj_id}, {model_name}, {txd_name}, {distances[0]}, {flags}" + + def format_tobj_line(self, obj): + """Format an object as a tobj line""" + + obj_id = obj.ide.obj_id + model_name = obj.ide.model_name or obj.name + txd_name = obj.ide.txd_name or model_name + flags = obj.ide.flags or '0' + time_on = obj.ide.time_on or '0' + time_off = obj.ide.time_off or '24' + + distances = self.get_draw_distances(obj) + + # Format based on number of draw distances + if len(distances) == 1: + # Format: ID, ModelName, TxdName, DrawDistance, Flags, TimeOn, TimeOff + return f"{obj_id}, {model_name}, {txd_name}, {distances[0]}, {flags}, {time_on}, {time_off}" + elif len(distances) == 2: + # Format: ID, ModelName, TxdName, MeshCount, DrawDistance1, DrawDistance2, Flags, TimeOn, TimeOff + mesh_count = '1' # Default to 1 for now + return f"{obj_id}, {model_name}, {txd_name}, {mesh_count}, {distances[0]}, {distances[1]}, {flags}, {time_on}, {time_off}" + elif len(distances) == 3: + # Format: ID, ModelName, TxdName, MeshCount, DrawDistance1, DrawDistance2, DrawDistance3, Flags, TimeOn, TimeOff + mesh_count = '1' # Default to 1 for now + return f"{obj_id}, {model_name}, {txd_name}, {mesh_count}, {distances[0]}, {distances[1]}, {distances[2]}, {flags}, {time_on}, {time_off}" + else: + # Default format + return f"{obj_id}, {model_name}, {txd_name}, {distances[0]}, {flags}, {time_on}, {time_off}" + + def export(self, context, filepath): + """Export IDE file""" + + # Collect objects + objects_to_export = self.collect_objects(context) + + if not objects_to_export: + return {'CANCELLED'}, "No objects with IDE data found" + + # Separate objects by type + objs_objects = [] + tobj_objects = [] + + for obj in objects_to_export: + ide_type = obj.ide.obj_type + if ide_type == 'tobj': + tobj_objects.append(obj) + else: + objs_objects.append(obj) + + # Write IDE file + try: + with open(filepath, 'w') as f: + if objs_objects: + f.write("objs\n") + for obj in objs_objects: + line = self.format_objs_line(obj) + f.write(line + "\n") + f.write("end\n") + + # Write tobj section if we have time objects + if tobj_objects: + f.write("tobj\n") + for obj in tobj_objects: + line = self.format_tobj_line(obj) + f.write(line + "\n") + f.write("end\n") + + total_count = len(objs_objects) + len(tobj_objects) + return {'FINISHED'}, f"Exported {total_count} objects to IDE ({len(objs_objects)} objs, {len(tobj_objects)} tobj)" + + except Exception as e: + return {'CANCELLED'}, f"Failed to export IDE: {str(e)}" + + +def export_ide(filepath, game_version, selected_only=False): + """Main export function""" + exporter = IDEExporter() + exporter.game_version = game_version + exporter.selected_only = selected_only + + return exporter.export(bpy.context, filepath) \ No newline at end of file diff --git a/ops/ipl_exporter.py b/ops/ipl_exporter.py new file mode 100644 index 0000000..653249b --- /dev/null +++ b/ops/ipl_exporter.py @@ -0,0 +1,116 @@ +# GTA DragonFF - Blender scripts to edit basic GTA formats +# Copyright (C) 2019 Parik + +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. + +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +import bpy +import os +from mathutils import Matrix, Quaternion +from .importer_common import game_version + + +class IPLExporter: + + def __init__(self): + self.game_version = None + self.objects = [] + self.selected_only = False + + def collect_objects(self, context): + """Collect objects that have IPL data""" + objects_to_export = [] + + if self.selected_only: + objects = context.selected_objects + else: + objects = context.scene.objects + + for obj in objects: + # Export objects that have an ID set + if hasattr(obj, 'ide') and obj.ide.obj_id and not obj.parent: + objects_to_export.append(obj) + + return objects_to_export + + def format_inst_line(self, obj): + """Format an object as an inst line based on game version""" + + # Get data from ide/ipl properties + obj_id = obj.ide.obj_id + model_name = obj.ide.model_name or obj.name + interior = obj.ipl.interior or '0' + lod = obj.ipl.lod or '-1' + + # Get transformation data + loc = obj.location + rot = obj.rotation_quaternion + scale = obj.scale + + # Note: the W component is negated + rot_w = -rot.w + rot_x = rot.x + rot_y = rot.y + rot_z = rot.z + + if self.game_version == game_version.III: + # GTA III format: ID, ModelName, PosX, PosY, PosZ, ScaleX, ScaleY, ScaleZ, RotX, RotY, RotZ, RotW + return f"{obj_id}, {model_name}, {loc.x:.6f}, {loc.y:.6f}, {loc.z:.6f}, {scale.x:.6f}, {scale.y:.6f}, {scale.z:.6f}, {rot_x:.6f}, {rot_y:.6f}, {rot_z:.6f}, {rot_w:.6f}" + + elif self.game_version == game_version.VC: + # GTA VC format: ID, ModelName, Interior, PosX, PosY, PosZ, ScaleX, ScaleY, ScaleZ, RotX, RotY, RotZ, RotW + return f"{obj_id}, {model_name}, {interior}, {loc.x:.6f}, {loc.y:.6f}, {loc.z:.6f}, {scale.x:.6f}, {scale.y:.6f}, {scale.z:.6f}, {rot_x:.6f}, {rot_y:.6f}, {rot_z:.6f}, {rot_w:.6f}" + + elif self.game_version == game_version.SA: + # GTA SA format: ID, ModelName, Interior, PosX, PosY, PosZ, RotX, RotY, RotZ, RotW, LOD + # Note: SA doesn't have scale in IPL + return f"{obj_id}, {model_name}, {interior}, {loc.x:.6f}, {loc.y:.6f}, {loc.z:.6f}, {rot_x:.6f}, {rot_y:.6f}, {rot_z:.6f}, {rot_w:.6f}, {lod}" + + else: + # Default to SA format + return f"{obj_id}, {model_name}, {interior}, {loc.x:.6f}, {loc.y:.6f}, {loc.z:.6f}, {rot_x:.6f}, {rot_y:.6f}, {rot_z:.6f}, {rot_w:.6f}, {lod}" + + def export(self, context, filepath): + """Export IPL file""" + + # Collect objects + objects_to_export = self.collect_objects(context) + + if not objects_to_export: + return {'CANCELLED'}, "No objects with IPL data found" + + # Write IPL file + try: + with open(filepath, 'w') as f: + # Write inst section + f.write("inst\n") + + for obj in objects_to_export: + line = self.format_inst_line(obj) + f.write(line + "\n") + + f.write("end\n") + + return {'FINISHED'}, f"Exported {len(objects_to_export)} objects to IPL" + + except Exception as e: + return {'CANCELLED'}, f"Failed to export IPL: {str(e)}" + + +def export_ipl(filepath, game_version, selected_only=False): + """Main export function""" + exporter = IPLExporter() + exporter.game_version = game_version + exporter.selected_only = selected_only + + return exporter.export(bpy.context, filepath) \ No newline at end of file diff --git a/ops/map_importer.py b/ops/map_importer.py index cdaabfd..cf35ce6 100644 --- a/ops/map_importer.py +++ b/ops/map_importer.py @@ -104,6 +104,31 @@ def import_object(self, context): Map_Import_Operator.apply_transformation_to_object( obj, inst ) + # Store IPL + obj.ide.obj_id = inst.id + obj.ide.model_name = self._object_data[inst.id].modelName + if hasattr(inst, 'interior'): + obj.ipl.interior = inst.interior + if hasattr(inst, 'lod'): + obj.ipl.lod = inst.lod + + # Store IDE data + ide_data = self._object_data[inst.id] + obj.ide.txd_name = ide_data.txdName + if hasattr(ide_data, 'drawDistance'): + obj.ide.draw_distance = ide_data.drawDistance + if hasattr(ide_data, 'drawDistance1'): + obj.ide.draw_distance1 = ide_data.drawDistance1 + if hasattr(ide_data, 'drawDistance2'): + obj.ide.draw_distance2 = ide_data.drawDistance2 + if hasattr(ide_data, 'drawDistance3'): + obj.ide.draw_distance3 = ide_data.drawDistance3 + obj.ide.flags = ide_data.flags + obj.ide.obj_type = 'objs' # Mark as regular object + if hasattr(ide_data, 'timeOn'): + obj.ide.obj_type = 'tobj' # Mark as time object + obj.ide.time_on = ide_data.timeOn + obj.ide.time_off = ide_data.timeOff cached_2dfx = [obj for obj in model_cache if obj.dff.type == "2DFX"] for obj in cached_2dfx: @@ -161,6 +186,31 @@ def import_object(self, context): Map_Import_Operator.apply_transformation_to_object( obj, inst ) + # Store IPL data + obj.ide.obj_id = inst.id + obj.ide.model_name = self._object_data[inst.id].modelName + if hasattr(inst, 'interior'): + obj.ipl.interior = inst.interior + if hasattr(inst, 'lod'): + obj.ipl.lod = inst.lod + + # Store IDE data + ide_data = self._object_data[inst.id] + obj.ide.txd_name = ide_data.txdName + if hasattr(ide_data, 'drawDistance'): + obj.ide.draw_distance = ide_data.drawDistance + if hasattr(ide_data, 'drawDistance1'): + obj.ide.draw_distance1 = ide_data.drawDistance1 + if hasattr(ide_data, 'drawDistance2'): + obj.ide.draw_distance2 = ide_data.drawDistance2 + if hasattr(ide_data, 'drawDistance3'): + obj.ide.draw_distance3 = ide_data.drawDistance3 + obj.ide.flags = ide_data.flags + obj.ide.obj_type = 'objs' # Mark as regular object + if hasattr(ide_data, 'timeOn'): + obj.ide.obj_type = 'tobj' # Mark as time object + obj.ide.time_on = ide_data.timeOn + obj.ide.time_off = ide_data.timeOff # Set root object as 2DFX parent if root_objects: