Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@
gui.IMPORT_OT_dff,
gui.EXPORT_OT_dff,
gui.EXPORT_OT_col,
gui.EXPORT_OT_ipl_cull,
gui.EXPORT_OT_ipl,
gui.EXPORT_OT_ide,
gui.SCENE_OT_dff_frame_move,
gui.SCENE_OT_dff_atomic_move,
gui.SCENE_OT_dff_update,
Expand Down Expand Up @@ -69,9 +70,12 @@
gui.DFFObjectProps,
gui.DFFCollectionProps,
gui.MapImportPanel,
gui.MapObjectPanel,
gui.DFFFrameProps,
gui.DFFAtomicProps,
gui.DFFSceneProps,
gui.IDEObjectProps,
gui.IPLObjectProps,
gui.DFF_MT_ExportChoice,
gui.DFF_MT_EditArmature,
gui.DFF_MT_Pose,
Expand Down Expand Up @@ -105,6 +109,8 @@ def register():
bpy.types.TextCurve.ext_2dfx = bpy.props.PointerProperty(type=gui.RoadSign2DFXObjectProps)
bpy.types.Material.dff = bpy.props.PointerProperty(type=gui.DFFMaterialProps)
bpy.types.Object.dff = bpy.props.PointerProperty(type=gui.DFFObjectProps)
bpy.types.Object.ide = bpy.props.PointerProperty(type=gui.IDEObjectProps)
bpy.types.Object.ipl = bpy.props.PointerProperty(type=gui.IPLObjectProps)
bpy.types.Collection.dff = bpy.props.PointerProperty(type=gui.DFFCollectionProps)

bpy.types.TOPBAR_MT_file_import.append(gui.import_dff_func)
Expand All @@ -125,6 +131,8 @@ def unregister():
del bpy.types.TextCurve.ext_2dfx
del bpy.types.Material.dff
del bpy.types.Object.dff
del bpy.types.Object.ide
del bpy.types.Object.ipl
del bpy.types.Collection.dff

bpy.types.TOPBAR_MT_file_import.remove(gui.import_dff_func)
Expand Down
25 changes: 25 additions & 0 deletions gtaLib/map.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,12 @@ class TextIPLData:
object_instances: list
cull_instances: list

#######################################################
@dataclass
class TextIDEData:
objs_instances: list
tobj_instances: list

# Base for all IPL / IDE section reader / writer classes
#######################################################
class SectionUtility:
Expand Down Expand Up @@ -436,10 +442,29 @@ def write_text_ipl_to_stream(file_stream, game_id, ipl_data:TextIPLData):
section_utility = SectionUtility("mult")
section_utility.write(file_stream, [])

########################################################################
@staticmethod
def write_text_ide_to_stream(file_stream, ide_data:TextIDEData):
file_stream.write("# IDE generated with DragonFF\n")

section_utility = SectionUtility("objs")
section_utility.write(file_stream, ide_data.objs_instances)

section_utility = SectionUtility("tobj")
section_utility.write(file_stream, ide_data.tobj_instances)

########################################################################
@staticmethod
def write_ipl_data(filename, game_id, ipl_data:TextIPLData):
self = MapDataUtility

with open(filename, 'w') as file_stream:
self.write_text_ipl_to_stream(file_stream, game_id, ipl_data)

########################################################################
@staticmethod
def write_ide_data(filename, ide_data:TextIDEData):
self = MapDataUtility

with open(filename, 'w') as file_stream:
self.write_text_ide_to_stream(file_stream, ide_data)
5 changes: 1 addition & 4 deletions gui/dff_menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
COLLECTION_OT_dff_generate_bounds, \
OBJECT_OT_dff_add_collision_box, OBJECT_OT_dff_add_collision_sphere
from .ext_2dfx_menus import EXT2DFXObjectProps, EXT2DFXMenus
from .map_ot import EXPORT_OT_ipl_cull
from .map_ot import EXPORT_OT_ipl, EXPORT_OT_ide
from .cull_menus import CULLObjectProps, CULLMenus
from ..gtaLib.data import presets

Expand Down Expand Up @@ -243,9 +243,6 @@ 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_ipl_cull.bl_idname,
text="DragonFF CULL (.ipl)")


#######################################################
def import_dff_func(self, context):
Expand Down
202 changes: 200 additions & 2 deletions gui/map_menus.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,96 @@
from .map_ot import SCENE_OT_ipl_select, OBJECT_OT_dff_add_cull
from ..gtaLib.data import map_data

#######################################################
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)
Expand Down Expand Up @@ -227,7 +317,7 @@ def atomics_active_changed(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'
Expand Down Expand Up @@ -274,7 +364,115 @@ def draw(self, context):
row = layout.row()
row.operator("scene.dragonff_map_import")

#######################################################@
layout.separator()

row = layout.row()
row.operator("export_scene.dff_ipl", text="Export IPL")

row = layout.row()
row.operator("export_scene.dff_ide", 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 == map_data.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")

#######################################################
class DFF_MT_AddMapObject(bpy.types.Menu):
bl_label = "Map"

Expand Down
Loading