Skip to content

Commit

Permalink
Merge pull request #64 from Robert-N7/develop
Browse files Browse the repository at this point in the history
Fix for older model versions.
  • Loading branch information
Robert-N7 authored Jun 11, 2021
2 parents b74a5fd + 789277a commit 927fceb
Show file tree
Hide file tree
Showing 44 changed files with 856 additions and 1,137 deletions.
37 changes: 32 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
This tool is used to convert and edit *Brres* files in *Mario Kart Wii*.

## Installation
It is recommended to install as a python package:
Compiled [releases](https://github.com/Robert-N7/abmatt/releases) are available for Linux and Windows.

Or, install as python package:
```
pip install git+https://github.com/Robert-N7/abmatt.git
```
Alternatively, download compiled [releases](https://github.com/Robert-N7/abmatt/releases) for Linux and Windows.

## Dependencies
ABMatt uses [Wiimm's Image Tool](https://szs.wiimm.de/download.html) which must be installed on your system path.
Expand All @@ -32,10 +33,11 @@ The material is copied and pasted, which includes shader and animation data.
## Command Line Usage
ABMatt supports a command line (see [FileFormat](##FileFormat)) followed by options.
```
abmatt [command_line][--interactive -f <file> -b <brres-file> -d <destination> --overwrite]
abmatt [command_line][flags]
```
| Flag |Expanded| Description |
|---|---|---|
| -a | --auto-fix | Set the autofix level (0 to turn off fixes). |
| -b | --brres | Brres file selection. |
| -d | --destination | The file path to be written to. Multiple destinations are not supported. |
| -f | --file | File with ABMatt commands to be processed as specified in file format. |
Expand All @@ -56,7 +58,7 @@ abmatt -b course_model.brres -o -n xlu.* -k xlu -v true
```

### Examples
Example command lines:
Example command_line:
```
convert course_model.obj # Converts obj to brres
set xlu:true for xlu.* in model course # Sets all materials in course starting with xlu to transparent
Expand Down Expand Up @@ -100,9 +102,11 @@ preset = 'preset' preset_name;
save = 'save' [filename] ['as' destination] ['overwrite']
copy = 'copy' type;
paste = 'paste' type;
convert = 'convert' filename ['to' destination] ['--no-colors'] ['--no-normals'] ['--single-bone'] ['--no-uvs']
convert = 'convert' filename ['to' destination] ['include' poly-list] ['exclude' poly-list] [convert-flags]
load = 'load' command-file
convert-flags = ['patch'] ['no-colors'] ['no-normals'] ['single-bone'] ['no-uvs']
poly-list = [polygon-name[,polygon-name]*]
selection = name ['in' container]
container = ['brres' filename] ['model' name];
type = 'material' | 'layer' [':' id] | 'shader' | 'stage' [':' id]
Expand Down Expand Up @@ -242,6 +246,22 @@ tex0-dimension = width ',' height;
tex0-format = 'cmpr' | 'c14x2' | 'c8' | 'c4' | 'rgba32' | 'rgb5a3' | 'rgb565'
| 'ia8' | 'ia4' | 'i8' | 'i4';
```
## Convert Examples
Convert `course_model.brres` to a Dae file
```
convert course_model.brres to course_model.dae
```

Convert `course_model.dae` to a Brres file, excluding polygons `road` and `boost`, and renaming materials to satisfy
Moonview Highway conditions:
```
convert course_model.dae to course_model.brres exclude road,boost --moonview
```

Convert `course_model.dae` patching over _only_ the `road` and `boost` polygons while keeping the existing model intact.
```
convert course_model.dae to course_model.brres include road,boost --patch
```

### Presets and Command Files
Presets are a way of grouping commands together. They can be defined in `presets.txt` or in command files.
Expand All @@ -259,6 +279,13 @@ To call the preset:
The `load` command can be used to load additional commands and presets.
As with all recursive things, be careful not to create an infinite loop!

## Additional Configuration
[An example configuration](etc/abmatt/config.conf)

# Contributing
Contributions are welcome! Feel free to submit a pull request.


## Known Limitations and Bugs
* Windows installer sometimes hangs in the background until the process is terminated.
* Non-standard files in Brres are not supported.
5 changes: 1 addition & 4 deletions abmatt/autofix.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,6 @@ def __init__(self, bug_level, notify_level, description, fix_des=None):
self.is_resolved = False
AutoFix.notify(self)

# def should_fix(self):
# return not self.is_resolved and AutoFix.should_fix(self)

def resolve(self):
self.is_resolved = True
AutoFix.info(f'(FIXED): {self.fix_des}', self.notify_level)
Expand Down Expand Up @@ -166,7 +163,7 @@ def set_fix_level(self, fix_level, zero_level_func=None):
self.fix_level = 4
elif fix_level in self.ERROR_LEVELS:
self.fix_level = self.ERROR_LEVELS.index(fix_level)
if fix_level == 0 and self.zero_level_func:
if self.fix_level == 0 and self.zero_level_func:
self.zero_level_func()

def can_prompt(self):
Expand Down
5 changes: 4 additions & 1 deletion abmatt/brres/brres.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,9 @@ def get_full_path(self):
@staticmethod
def add_open_file(file):
Brres.OPEN_FILES.append(file)
if len(Brres.OPEN_FILES) > 10:
for i in range(5):
Brres.OPEN_FILES.pop(0).close()

@staticmethod
def close_files():
Expand Down Expand Up @@ -366,7 +369,7 @@ def pack(self, binfile):
def check(self):
AutoFix.info('checking file {}'.format(self.name), 4)
expected = self.get_expected_mdl_name()
if self.MOONVIEW or 'ridgehighway_course' in self.name:
if self.MOONVIEW:
self.check_moonview()
Brres.MOONVIEW = False
for mdl in self.models:
Expand Down
12 changes: 4 additions & 8 deletions abmatt/brres/lib/decoder.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from copy import deepcopy
from struct import unpack_from, unpack
from struct import unpack_from

import numpy as np

Expand Down Expand Up @@ -93,8 +93,6 @@ def decode_rgba6(data, num_colors):


def decode_mdl0_influences(mdl0):
if mdl0.influences is not None:
return mdl0.influences
influences = {}
bones = mdl0.bones
bonetable = mdl0.bone_table
Expand All @@ -103,7 +101,7 @@ def decode_mdl0_influences(mdl0):
index = bonetable[i]
if index >= 0:
bone = bones[index]
influences[i] = Influence(bone_weights={bone.name: Weight(bone, 1)}, influence_id=index)
influences[i] = Influence(bone_weights={bone.name: Weight(bone, 1)}, influence_id=i)

# Get mixed influences
nodemix = mdl0.NodeMix
Expand All @@ -114,8 +112,7 @@ def decode_mdl0_influences(mdl0):
for x in inf:
bone = bones[bonetable[x[0]]]
influence[bone.name] = Weight(bone, x[1])
mdl0.influences = InfluenceCollection(influences)
return mdl0.influences
return InfluenceCollection(influences)


def decode_polygon(polygon, influences=None):
Expand All @@ -124,7 +121,7 @@ def decode_polygon(polygon, influences=None):
"""
# build the decoder_string decoder
if influences is None:
influences = decode_mdl0_influences(polygon.parent)
influences = polygon.parent.get_influences()
pos_matrix_index = polygon.get_weight_index()
vertex_index = polygon.get_vertex_index()
vertices = polygon.get_vertex_group()
Expand Down Expand Up @@ -273,7 +270,6 @@ def decode_pos_mtx_indices(all_influences, weight_groups, vertices, pos_mtx_indi
slicer.append(len(vert_indices)) # add the max onto the end for slicing

remapper = {}
max_vert = np.max(vert_indices)
new_points = []
new_face_indices = deepcopy(vert_indices)
# Each weighting slice group
Expand Down
1 change: 0 additions & 1 deletion abmatt/brres/lib/packing/pack_mdl0/pack_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,6 @@ def pack(self, material, binfile):
binfile.mark() # matgx
else:
binfile.mark() # matgx
binfile.advance(4)
# ignore precompiled code space
binfile.advance(360)
self.pack_layers(binfile)
Expand Down
33 changes: 19 additions & 14 deletions abmatt/brres/lib/packing/pack_mdl0/pack_mdl0.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ class PackMdl0(PackSubfile):
def pack(self, mdl0, binfile):
""" Packs the model data """
self.sections = self.pre_pack(mdl0)
if self.sections[6] or self.sections[7]:
raise PackingError(binfile, 'Packing Fur not supported')
super(PackMdl0, self).pack(mdl0, binfile)
binfile.start() # header
binfile.write('I', 0x40)
Expand All @@ -38,15 +36,15 @@ def pack(self, mdl0, binfile):
folders = self.packFolders(binfile)

# texture links
texture_link_map = self.packTextureLinks(binfile, folders[11])
texture_link_map = self.packTextureLinks(binfile, folders[-1])
self.pack_definitions(binfile, folders[0])
self.pack_section(binfile, 1, folders[1], PackBone) # bones
i = 8
self.pack_materials(binfile, folders[i], texture_link_map)
i = len(self.sections) - 4
self.pack_materials(binfile, i, folders[i], texture_link_map)
i += 1
self.pack_shaders(binfile, folders[i])
i += 1
self.pack_section(binfile, 10, folders[i], PackPolygon) # objects
self.pack_section(binfile, i, folders[i], PackPolygon) # objects
i = 2
self.pack_section(binfile, i, folders[i], PackVertex)
i += 1
Expand Down Expand Up @@ -93,7 +91,7 @@ def packTextureLinks(self, binfile, folder):
"""Packs texture link section, returning map of names:offsets be filled in by mat/layer refs"""
# binfile.section_offsets.append((binfile.offset, 'Textures')) #- debug
tex_map = {}
links = self.sections[11]
links = self.sections[-1]
for x in links:
folder.createEntryRefI()
tex_map[x.name] = self.PackTextureLink(x.name, binfile, x.num_refs)
Expand All @@ -106,11 +104,11 @@ def pack_definitions(self, binfile, folder):
x.pack(binfile)
binfile.align(4)

def pack_materials(self, binfile, folder, texture_link_map):
def pack_materials(self, binfile, section_index, folder, texture_link_map):
"""packs materials, requires texture link map to offsets that need to be filled"""
# self.binfile.section_offsets.append((binfile.offset, folder.name)) #- debug
mat_packers = self.mat_packers
section = self.sections[8]
section = self.sections[section_index]
for i in range(len(section)):
mat = section[i]
folder.createEntryRefI()
Expand Down Expand Up @@ -152,23 +150,22 @@ def packFolders(self, binfile):
root_folders = [] # for storing Index Groups
sections = self.sections
# Create folder for each section the MDL0 has
i = j = 0
i = 0
while i < len(sections):
section = sections[i]
if i == 9: # special case for shaders: must add entry for each material
if i == len(sections) - 3: # special case for shaders: must add entry for each material
section = sections[i - 1]
if section:
f = Folder(binfile, self.SECTION_NAMES[i])
f = Folder(binfile, self.section_names[i])
for x in section:
assert x
f.addEntry(x.name)
root_folders.append(f)
binfile.createRef(j, False) # create the ref from stored offsets
binfile.createRef(i, False) # create the ref from stored offsets
f.pack(binfile)
else:
root_folders.append(None) # create placeholder
i += 1
j += 1
return root_folders

def build_texture_links(self, materials):
Expand Down Expand Up @@ -223,6 +220,14 @@ def pre_pack(self, mdl0):
for i in range(1, len(sections) - 1):
if sections[i]:
self.rebuild_indexes(sections[i])
if mdl0.version < 10:
start = sections[:6]
start.extend(sections[8:])
sections = start
self.section_names = list(self.SECTION_NAMES[:6])
self.section_names.extend(self.SECTION_NAMES[8:])
else:
self.section_names = self.SECTION_NAMES
sections[0] = self.build_definitions()
return sections

Expand Down
4 changes: 2 additions & 2 deletions abmatt/brres/lib/packing/pack_mdl0/pack_polygon.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ def pack(self, poly, binfile):

def get_cp_vertex_format(self):
poly = self.node
lo = poly.has_weighted_matrix()
lo = poly.has_weights()
for i in range(8):
lo |= poly.has_uv_matrix(i) << i + 1

Expand Down Expand Up @@ -156,7 +156,7 @@ def get_xf_array_flags(self):
flag |= bit
bit <<= 1
flag <<= 9
flag |= poly.has_weighted_matrix()
flag |= poly.has_weights()
for i in range(8):
flag |= poly.has_uv_matrix(i) << i + 1
return flag
2 changes: 1 addition & 1 deletion abmatt/brres/lib/packing/pack_subfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,6 @@ def pack(self, subfile, binfile):
binfile.write("I", subfile.version)
binfile.writeOuterOffset()
# mark section offsets to be added later
binfile.mark(subfile._getNumSections())
binfile.mark(subfile.get_num_sections())
# name offset to be packed separately
binfile.storeNameRef(subfile.name)
2 changes: 1 addition & 1 deletion abmatt/brres/lib/unpacking/unpack_mdl0/unpack_bone.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
def unpack_bonetable(binfile, format):
[length] = binfile.read("I", 4)
if length:
return binfile.read("{}{}".format(length, format), length * 4)
return list(binfile.read("{}{}".format(length, format), length * 4))


class UnpackBone(Unpacker):
Expand Down
1 change: 0 additions & 1 deletion abmatt/brres/lib/unpacking/unpack_mdl0/unpack_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,6 @@ def unpack(self, material, binfile):
else:
binfile.advance(4)
binfile.store() # store matgx offset
# binfile.advance(4)
# ignore precompiled code space
binfile.advance(360)
startlayerInfo = binfile.offset
Expand Down
2 changes: 1 addition & 1 deletion abmatt/brres/lib/unpacking/unpack_mdl0/unpack_mdl0.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def unpack(self, mdl0, binfile):
fh, mdl0.scaling_rule, mdl0.texture_matrix_mode, mdl0.facepoint_count, \
mdl0.face_count, _, mdl0.boneCount, _ = binfile.read("i7I", 32)
binfile.store() # bone table offset
if binfile.offset - offset < ln:
if mdl0.version >= 10:
mdl0.minimum = binfile.read("3f", 12)
mdl0.maximum = binfile.read("3f", 12)
else:
Expand Down
4 changes: 2 additions & 2 deletions abmatt/brres/lib/unpacking/unpack_subfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ def unpack_default(subfile, binfile):
UnpackSubfile(subfile, binfile)
subfile.data = binfile.readRemaining()
offsets = []
for i in range(subfile._getNumSections()):
for i in range(subfile.get_num_sections()):
offsets.append(binfile.recall())
subfile.offsets = offsets
binfile.end()
Expand All @@ -22,7 +22,7 @@ def unpack(self, subfile, binfile):
binfile.readLen()
subfile.version, outerOffset = binfile.read("Ii", 8)
try:
subfile.numSections = subfile._getNumSections()
subfile.numSections = subfile.get_num_sections()
except KeyError:
raise UnpackingError(binfile,
"{} {} unsupported version {}".format(subfile.MAGIC, subfile.name, subfile.version))
Expand Down
24 changes: 0 additions & 24 deletions abmatt/brres/mdl0/bone.py
Original file line number Diff line number Diff line change
Expand Up @@ -105,27 +105,3 @@ def get_last_child(self):
return bone



# class BoneTable:
# """ Bonetable class """
# def __init__(self, binfile=None):
# if binfile:
# self.unpack(binfile)
# else:
# self.entries = []
#
# def __getitem__(self, item):
# return self.entries[item]
#
# def __len__(self):
# return len(self.entries)
#
# def add_entry(self, entry):
# self.entries.append(entry)
# return len(self.entries) - 1
#
#
# def pack(self, binfile):
# length = len(self.entries)
# binfile.write("I", length)
# binfile.write("{}i".format(length), *self.entries)
3 changes: 3 additions & 0 deletions abmatt/brres/mdl0/color.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ def __deepcopy__(self, memodict=None):
copy = Color(self.name, None)
return copy.paste(self)

def __hash__(self):
return super().__hash__()

def paste(self, item):
self.flags = item.flags
self.index = item.index
Expand Down
Loading

0 comments on commit 927fceb

Please sign in to comment.