Skip to main content

Python library for reading and writing GTA RenderWare DFF and TXD files

Project description

rwfury

Python library for reading and writing GTA RenderWare DFF (3D model) and TXD (texture dictionary) files. Supports GTA III, Vice City, and San Andreas.

Features

  • DFF parsing with full plugin support: BinMesh, Skin, HAnim, 2dfx, Material Effects, Night Colors, Collision, Specular/Reflection materials
  • DFF writing back to binary (round-trip)
  • TXD parsing with DDS export and raw RGBA decoding
  • Version-aware: handles RW 3.1 (GTA III) through 3.6 (San Andreas) struct differences automatically
  • GenericMesh: format-agnostic mesh representation with flat arrays and byte-packing helpers for easy porting to glTF, FBX, or any custom format
  • Zero external dependencies (pure Python, stdlib only)

Installation

Copy the rwfury/ folder into your project, or add the parent directory to your Python path.

Quick start

Parse a DFF and extract meshes

from rwfury import Dff

dff = Dff.from_file("model.dff")

# High-level mesh extraction (grouped by material)
for entry in dff.get_meshes():
    print(entry["name"], entry["texture"])
    for mesh in entry["meshes"]:
        print(f"  {len(mesh.positions)} vertices, {len(mesh.indices)//3} triangles")
        print(f"  UV sets: {len(mesh.texcoords)}")

Format-agnostic export with GenericMesh

from rwfury import Dff

dff = Dff.from_file("model.dff")

for mesh in dff.to_generic_meshes():
    # Flat arrays ready for GPU upload or any format conversion
    pos_bytes = mesh.positions_as_bytes()      # float32 LE, 3 per vertex
    idx_bytes = mesh.indices_as_bytes("u16")   # uint16 LE (or "u32")
    uv_bytes  = mesh.texcoords_as_bytes(0)     # float32 LE, 2 per vertex
    norm_bytes = mesh.normals_as_bytes()       # float32 LE, 3 per vertex

    # Material info
    print(mesh.texture_name, mesh.diffuse_color)

    # 4x4 transform matrix (row-major, 16 floats)
    print(mesh.transform)

    # Skinning data (if present)
    if mesh.has_skinning:
        bi = mesh.bone_indices_as_bytes()   # uint8, 4 per vertex
        bw = mesh.bone_weights_as_bytes()   # float32, 4 per vertex

Extract textures from a TXD

from rwfury import Txd

txd = Txd.from_file("textures.txd")

# Export all textures as .dds files
txd.export_to_dds("output_folder/")

# Or get raw RGBA pixel data (for compression, processing, etc.)
for tex in txd.textures:
    rgba_mipmaps, has_alpha = tex.to_rgba()
    # rgba_mipmaps[0] = bytes, width * height * 4, R,G,B,A order
    print(f"{tex.name}: {tex.width}x{tex.height}, alpha={has_alpha}")

Write a modified DFF

from rwfury import Dff

dff = Dff.from_file("original.dff")

# Modify frames, geometry, materials, etc.
dff.frames[0].name = "renamed_frame"

# Write back to binary
dff.to_file("modified.dff")

Access low-level data

from rwfury import Dff

dff = Dff.from_file("model.dff")

# Frames (skeleton/hierarchy)
for frame in dff.frames:
    print(frame.name, frame.position, frame.parent)
    if frame.hanim:
        print(f"  HAnim: {len(frame.hanim.bones)} bones")

# Geometry details
for geom in dff.geometries:
    print(f"{len(geom.vertices)} verts, {len(geom.triangles)} tris")
    print(f"UV sets: {geom.num_uv_sets}, flags: 0x{geom.flags:04X}")

    # Plugins
    if geom.bin_mesh:
        print(f"BinMesh: {len(geom.bin_mesh.splits)} splits")
    if geom.skin:
        print(f"Skin: {geom.skin.num_bones} bones")
    if geom.night_colors:
        print(f"Night colors: {len(geom.night_colors)} vertices")
    if geom.effects_2dfx:
        print(f"2dfx: {len(geom.effects_2dfx)} effects")

    # Materials
    for mat in geom.materials:
        print(f"  {mat.texture_name} color={mat.color}")
        if mat.specular_texture:
            print(f"    specular: {mat.specular_texture} level={mat.specular_level}")
        if mat.reflection:
            print(f"    reflection: intensity={mat.reflection['intensity']}")

# Collision data
if dff.collision:
    print(f"Embedded collision: {len(dff.collision.raw)} bytes")

API reference

Core classes

Class Description
Dff DFF file parser/writer. from_file(path), to_file(path), get_meshes(), to_generic_meshes()
Txd TXD file parser. from_file(path), export_to_dds(folder)
TxdTexture Single texture entry. to_rgba() decodes any format to raw RGBA bytes
GenericMesh Flat-array mesh with *_as_bytes() helpers for format-agnostic export

DFF data classes

Class Description
DffGeometry Vertices, normals, triangles, texcoords, vertex colors, materials, and plugins
DffMaterial Color, texture name, ambient/diffuse/specular, material effects, specular/reflection extensions
DffFrame Name, position, rotation matrix, parent index, HAnim skeleton data
DffAtomic Links a frame to a geometry
MorphTarget Per-morph-target vertices and normals with bounding sphere
BinMeshPLG Triangle strip/list splits by material
SkinPLG Bone indices, weights, and inverse bind matrices per vertex
HAnimPLG Skeleton hierarchy with bone IDs and flags
Effect2dfxEntry 2dfx effect (lights, particles, etc.) with position and typed data
CollisionData Raw embedded COL data blob

GenericMesh properties and methods

Member Description
vertex_count, triangle_count Derived from flat array lengths
has_normals, has_colors, has_skinning Quick checks for optional data
uv_set_count Number of UV coordinate sets
positions_as_bytes() Packed float32 LE (12 bytes/vertex)
normals_as_bytes() Packed float32 LE (12 bytes/vertex)
texcoords_as_bytes(uv_set) Packed float32 LE (8 bytes/vertex)
colors_as_bytes() Packed uint8 RGBA (4 bytes/vertex)
indices_as_bytes(fmt) "u16" or "u32" packed indices
bone_indices_as_bytes() Packed uint8 (4 bytes/vertex)
bone_weights_as_bytes() Packed float32 LE (16 bytes/vertex)

Supported formats

Game RW Version DFF TXD
GTA III 3.1 - 3.3 Read/Write Read + DDS export
GTA Vice City 3.4 - 3.5 Read/Write Read + DDS export
GTA San Andreas 3.6 Read/Write Read + DDS export

TXD supports D3D8/D3D9 platform textures: PAL4, PAL8, 16-bit (R5G6B5, A1R5G5B5, A4R4G4B4), 32-bit (A8R8G8B8, X8R8G8B8), and DXT1/DXT3/DXT5 compressed.

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rwfury-0.1.0.tar.gz (24.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rwfury-0.1.0-py3-none-any.whl (22.4 kB view details)

Uploaded Python 3

File details

Details for the file rwfury-0.1.0.tar.gz.

File metadata

  • Download URL: rwfury-0.1.0.tar.gz
  • Upload date:
  • Size: 24.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for rwfury-0.1.0.tar.gz
Algorithm Hash digest
SHA256 adf453e969c26592021c2040f9c62d571c1a6940b2d1ab3c0b29503934f18357
MD5 963203c438bff09634043e29c7c8c215
BLAKE2b-256 2912c471b3829ca158edad6768f3b1b35e855095a5b618d4700ef26d6b325591

See more details on using hashes here.

File details

Details for the file rwfury-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: rwfury-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.3

File hashes

Hashes for rwfury-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 5d1ae50cacc3b6947aaf645ab31cc9d8dcf563dd06a868111fb327ee66e50f79
MD5 1385b9451c885ee7f2929e8be6dc1d93
BLAKE2b-256 f449c898a72f46df00b66e62107056e5cc25fdadbe47108ae1cb3006ebc6c223

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page