Skip to content
Open
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
15 changes: 14 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@
gui.OBJECT_OT_dff_add_2dfx_cover_point,
gui.OBJECT_OT_dff_add_2dfx_escalator,
gui.OBJECT_OT_dff_add_cull,
gui.MATERIAL_PT_txdTextures, #
gui.MATERIAL_PT_dffMaterials,
gui.OBJECT_PT_dffObjects,
gui.OBJECT_PT_dffCollections,
Expand All @@ -67,6 +68,7 @@
gui.CULLObjectProps,
gui.IMPORT_OT_ParticleTXDNames,
gui.DFFMaterialProps,
gui.COLMaterialEnumProps,
gui.DFFObjectProps,
gui.DFFCollectionProps,
gui.MapImportPanel,
Expand Down Expand Up @@ -94,7 +96,12 @@
gui.Escalator2DFXGizmoGroup,
gui.UVAnimatorProperties,
gui.UV_OT_AnimateSpriteSheet,
gui.NODE_PT_UVAnimator
gui.NODE_PT_UVAnimator,
gui.COLSceneProps,
gui.TXDImageProps,
gui.TXDTextureListProps,
gui.TEXTURES_UL_txd_image_list,
gui.MATERIAL_OT_dff_import_uv_anim,
]

#######################################################
Expand All @@ -111,6 +118,9 @@ def register():
bpy.types.Object.dff = bpy.props.PointerProperty(type=gui.DFFObjectProps)
bpy.types.Collection.dff = bpy.props.PointerProperty(type=gui.DFFCollectionProps)
bpy.types.Scene.dff_uv_animator_props = bpy.props.PointerProperty(type=gui.UVAnimatorProperties)
bpy.types.Scene.dff_col = bpy.props.PointerProperty(type=gui.COLSceneProps)
bpy.types.Image.dff = bpy.props.PointerProperty(type=gui.TXDImageProps)
bpy.types.Scene.dff_txd_texture_list = bpy.props.PointerProperty(type=gui.TXDTextureListProps)

bpy.types.TOPBAR_MT_file_import.append(gui.import_dff_func)
bpy.types.TOPBAR_MT_file_export.append(gui.export_dff_func)
Expand All @@ -132,6 +142,9 @@ def unregister():
del bpy.types.Object.dff
del bpy.types.Collection.dff
del bpy.types.Scene.dff_uv_animator_props
del bpy.types.Scene.dff_col
del bpy.types.Image.dff
del bpy.types.Scene.dff_txd_texture_list

bpy.types.TOPBAR_MT_file_import.remove(gui.import_dff_func)
bpy.types.TOPBAR_MT_file_export.remove(gui.export_dff_func)
Expand Down
73 changes: 72 additions & 1 deletion gtaLib/txd.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,83 @@ def rgba_to_bgra8888(rgba_data):

@staticmethod
def rgba_to_bgra888(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r = rgba_data[i]
g = rgba_data[i + 1]
b = rgba_data[i + 2]
ret.extend([b, g, r, 0xFF])
return bytes(ret)

@staticmethod
def rgba_to_rgb565(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r, g, b = rgba_data[i:i+3]
r5 = (r * 31) // 255
g6 = (g * 63) // 255
b5 = (b * 31) // 255
rgb565 = (r5 << 11) | (g6 << 5) | b5
ret.extend(rgb565.to_bytes(2, 'little'))
return bytes(ret)

@staticmethod
def rgba_to_rgba1555(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r, g, b, a = rgba_data[i:i+4]
a1 = 1 if a > 127 else 0
r5 = (r * 31) // 255
g5 = (g * 31) // 255
b5 = (b * 31) // 255
rgba1555 = (a1 << 15) | (r5 << 10) | (g5 << 5) | b5
ret.extend(rgba1555.to_bytes(2, 'little'))
return bytes(ret)

@staticmethod
def rgba_to_rgba4444(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r, g, b, a = rgba_data[i:i+4]
a4 = (a * 15) // 255
r4 = (r * 15) // 255
g4 = (g * 15) // 255
b4 = (b * 15) // 255
rgba4444 = (a4 << 12) | (r4 << 8) | (g4 << 4) | b4
ret.extend(rgba4444.to_bytes(2, 'little'))
return bytes(ret)

@staticmethod
def rgba_to_rgb555(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r, g, b = rgba_data[i:i+3]
r5 = (r * 31) // 255
g5 = (g * 31) // 255
b5 = (b * 31) // 255
rgb555 = (r5 << 10) | (g5 << 5) | b5
ret.extend(rgb555.to_bytes(2, 'little'))
return bytes(ret)

@staticmethod
def rgba_to_lum8(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r, g, b = rgba_data[i:i+3]
ret.extend([b, g, r])
lum = int(0.299 * r + 0.587 * g + 0.114 * b)
ret.append(lum)
return bytes(ret)

@staticmethod
def rgba_to_lum8a8(rgba_data):
ret = bytearray()
for i in range(0, len(rgba_data), 4):
r, g, b, a = rgba_data[i:i+4]
lum = int(0.299 * r + 0.587 * g + 0.114 * b)
ret.extend([lum, a])
return bytes(ret)


#######################################################
class ImageDecoder:

Expand Down
176 changes: 176 additions & 0 deletions gui/col_menus.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,176 @@
import bpy
from ..gtaLib.data.col_materials import COL_PRESET_SA, COL_PRESET_VC, COL_PRESET_GROUP

_ENUM_CACHE = {}

########################################################
def generate_col_mat_enums():
global _ENUM_CACHE

for game in ["SA", "VC"]:
mats = COL_PRESET_SA if game == "SA" else COL_PRESET_VC

for group_id in COL_PRESET_GROUP.keys():

normal_items = [("NONE", "Select a material below", "")]
proc_items = [("NONE", "Select a material below", "")]

for gid, flag_id, mat_id, name, is_proc in mats:
if gid != group_id:
continue

item = (f"{flag_id}|{mat_id}", name, "")

if game == "VC":
normal_items.append(item)
else:
if is_proc:
proc_items.append(item)
else:
normal_items.append(item)

_ENUM_CACHE[f"{game}_{group_id}_normal"] = normal_items
_ENUM_CACHE[f"{game}_{group_id}_proc"] = proc_items

generate_col_mat_enums()


#######################################################
def get_col_mat_items_normal(self, context):
scn = context.scene
game = scn.dff_col.col_game_vers
group = scn.dff_col.col_mat_group
key = f"{game}_{group}_normal"
return _ENUM_CACHE.get(key, [("NONE", "No materials", "")])

def get_col_mat_items_proc(self, context):
scn = context.scene
game = scn.dff_col.col_game_vers
group = scn.dff_col.col_mat_group
key = f"{game}_{group}_proc"
return _ENUM_CACHE.get(key, [("NONE", "No materials", "")])


#######################################################
def apply_collision_material(self, context):
if self.col_mat_enum_normal != "NONE":
enum_value = self.col_mat_enum_normal
elif self.col_mat_enum_proc != "NONE":
enum_value = self.col_mat_enum_proc
else:
return

flag_id, mat_id = enum_value.split('|')
flag_id = int(flag_id)
mat_id = int(mat_id)

if context.object:
obj = context.object
mat = context.material

if mat and obj.type == 'MESH':
mat.dff.col_mat_index = mat_id
mat.dff.col_flags = flag_id

elif obj.type == 'EMPTY' and obj.dff.type == 'COL':
obj.dff.col_material = mat_id
obj.dff.col_flags = flag_id


#######################################################
def update_type(self, context, changed):
if changed == "normal" and self.col_mat_norm:
self.col_mat_proc = False
elif changed == "proc" and self.col_mat_proc:
self.col_mat_norm = False

if not self.col_mat_norm and not self.col_mat_proc:
if changed == "normal":
self.col_mat_norm = True
else:
self.col_mat_proc = True


#######################################################
def draw_col_preset_helper(layout, context):

box = layout.box()
box.label(text="Collision Presets")

split = box.split(factor=0.4)
split.label(text="Game")
split.prop(context.scene.dff_col, "col_game_vers", text="")

split = box.split(factor=0.4)
split.label(text="Group")
split.prop(context.scene.dff_col, "col_mat_group", text="")

row = box.row(align=True)
row.prop(context.scene.dff_col, "col_mat_norm", toggle=True)
row.prop(context.scene.dff_col, "col_mat_proc", toggle=True)

if context.scene.dff_col.col_mat_norm:
box.prop(context.object.dff.col_mat, "col_mat_enum_normal", expand=True)
else:
box.prop(context.object.dff.col_mat, "col_mat_enum_proc", expand=True)


#######################################################
def reset_col_mat_enum(self, context):
obj = context.object
if obj and hasattr(obj.dff, "col_mat"):
obj.dff.col_mat.col_mat_enum_normal = "NONE"
obj.dff.col_mat.col_mat_enum_proc = "NONE"


########################################################
def update_col_mat_norm(self, context):
update_type(self, context, "normal")
reset_col_mat_enum(self, context)


#########################################################
def update_col_mat_proc(self, context):
update_type(self, context, "proc")
reset_col_mat_enum(self, context)


#######################################################
class COLSceneProps(bpy.types.PropertyGroup):
col_game_vers: bpy.props.EnumProperty(
items=[("SA", "San Andreas", ""), ("VC", "Vice City", "")],
default="SA",
update=reset_col_mat_enum
)

col_mat_group: bpy.props.EnumProperty(
items=[(str(k), v[0], "", v[1], k) for k, v in COL_PRESET_GROUP.items()],
update=reset_col_mat_enum
)

col_mat_norm: bpy.props.BoolProperty(
name="Normal",
default=True,
update=update_col_mat_norm
)

col_mat_proc: bpy.props.BoolProperty(
name="Procedural",
default=False,
update=update_col_mat_proc
)


########################################################
class COLMaterialEnumProps(bpy.types.PropertyGroup):
col_mat_enum_normal: bpy.props.EnumProperty(
name="Material",
items=get_col_mat_items_normal,
update=apply_collision_material
)

col_mat_enum_proc: bpy.props.EnumProperty(
name="Material",
items=get_col_mat_items_proc,
update=apply_collision_material
)
Loading