diff --git a/README.md b/README.md index 525991d..1509334 100644 --- a/README.md +++ b/README.md @@ -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. @@ -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 -b -d --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. | @@ -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 @@ -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] @@ -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. @@ -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. \ No newline at end of file diff --git a/abmatt/autofix.py b/abmatt/autofix.py index 5071c5f..af47d78 100644 --- a/abmatt/autofix.py +++ b/abmatt/autofix.py @@ -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) @@ -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): diff --git a/abmatt/brres/brres.py b/abmatt/brres/brres.py index 14cdd3c..41b576e 100644 --- a/abmatt/brres/brres.py +++ b/abmatt/brres/brres.py @@ -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(): @@ -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: diff --git a/abmatt/brres/lib/decoder.py b/abmatt/brres/lib/decoder.py index a82d365..0a84d9e 100644 --- a/abmatt/brres/lib/decoder.py +++ b/abmatt/brres/lib/decoder.py @@ -1,5 +1,5 @@ from copy import deepcopy -from struct import unpack_from, unpack +from struct import unpack_from import numpy as np @@ -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 @@ -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 @@ -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): @@ -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() @@ -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 diff --git a/abmatt/brres/lib/packing/pack_mdl0/pack_material.py b/abmatt/brres/lib/packing/pack_mdl0/pack_material.py index 32e9652..fae60e5 100644 --- a/abmatt/brres/lib/packing/pack_mdl0/pack_material.py +++ b/abmatt/brres/lib/packing/pack_mdl0/pack_material.py @@ -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) diff --git a/abmatt/brres/lib/packing/pack_mdl0/pack_mdl0.py b/abmatt/brres/lib/packing/pack_mdl0/pack_mdl0.py index 036dd8c..c477be0 100644 --- a/abmatt/brres/lib/packing/pack_mdl0/pack_mdl0.py +++ b/abmatt/brres/lib/packing/pack_mdl0/pack_mdl0.py @@ -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) @@ -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 @@ -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) @@ -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() @@ -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): @@ -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 diff --git a/abmatt/brres/lib/packing/pack_mdl0/pack_polygon.py b/abmatt/brres/lib/packing/pack_mdl0/pack_polygon.py index 8c98b9b..fd3ae68 100644 --- a/abmatt/brres/lib/packing/pack_mdl0/pack_polygon.py +++ b/abmatt/brres/lib/packing/pack_mdl0/pack_polygon.py @@ -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 @@ -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 diff --git a/abmatt/brres/lib/packing/pack_subfile.py b/abmatt/brres/lib/packing/pack_subfile.py index 68f4f5d..7b149c7 100644 --- a/abmatt/brres/lib/packing/pack_subfile.py +++ b/abmatt/brres/lib/packing/pack_subfile.py @@ -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) diff --git a/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_bone.py b/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_bone.py index 762d117..5f0c2c4 100644 --- a/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_bone.py +++ b/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_bone.py @@ -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): diff --git a/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_material.py b/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_material.py index 192ed6a..889d906 100644 --- a/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_material.py +++ b/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_material.py @@ -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 diff --git a/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_mdl0.py b/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_mdl0.py index e0cfd07..327754f 100644 --- a/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_mdl0.py +++ b/abmatt/brres/lib/unpacking/unpack_mdl0/unpack_mdl0.py @@ -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: diff --git a/abmatt/brres/lib/unpacking/unpack_subfile.py b/abmatt/brres/lib/unpacking/unpack_subfile.py index 8ccec4d..e3ea812 100644 --- a/abmatt/brres/lib/unpacking/unpack_subfile.py +++ b/abmatt/brres/lib/unpacking/unpack_subfile.py @@ -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() @@ -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)) diff --git a/abmatt/brres/mdl0/bone.py b/abmatt/brres/mdl0/bone.py index d87c5b3..ac376b5 100644 --- a/abmatt/brres/mdl0/bone.py +++ b/abmatt/brres/mdl0/bone.py @@ -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) diff --git a/abmatt/brres/mdl0/color.py b/abmatt/brres/mdl0/color.py index dc2b9c7..f9fb300 100644 --- a/abmatt/brres/mdl0/color.py +++ b/abmatt/brres/mdl0/color.py @@ -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 diff --git a/abmatt/brres/mdl0/mdl0.py b/abmatt/brres/mdl0/mdl0.py index 7ba3b3a..ea77e60 100644 --- a/abmatt/brres/mdl0/mdl0.py +++ b/abmatt/brres/mdl0/mdl0.py @@ -4,6 +4,7 @@ import string from abmatt.autofix import AutoFix, Bug +from abmatt.brres.lib.decoder import decode_mdl0_influences from abmatt.brres.lib.matching import fuzzy_match, MATCHING, it_eq from abmatt.brres.lib.node import Node, get_name_mapping from abmatt.brres.lib.packing.pack_mdl0.pack_mdl0 import PackMdl0 @@ -62,7 +63,7 @@ class Mdl0(SubFile): VERSION_SECTIONCOUNT = {8: 11, 9: 11, 10: 14, 11: 14} EXPECTED_VERSION = 11 - SETTINGS = ('name') + SETTINGS = ('name',) DETECT_MODEL_NAME = True RENAME_UNKNOWN_REFS = True REMOVE_UNKNOWN_REFS = True @@ -109,6 +110,8 @@ def __eq__(self, other): and self.bone_table == other.bone_table def get_influences(self): + if self.influences is None: + self.influences = decode_mdl0_influences(self) return self.influences def begin(self): @@ -218,30 +221,28 @@ def update_polygon_material(self, polygon, old_mat, new_mat): # self.mark_modified() return new_mat - def __remove_and_rebuild_index(self, item, group, if_not_in_group): + def __remove_group_item(self, item, group, if_not_in_group): if item is not None and item not in if_not_in_group: group.remove(item) - self.rebuild_indexes(group) def remove_polygon(self, polygon): self.objects.remove(polygon) - self.rebuild_indexes(self.objects) self.rebuild_head = True if len(polygon.material.polygons) == 1: self.remove_material(polygon.material) - self.__remove_and_rebuild_index(polygon.get_vertex_group(), self.vertices, - [x.get_vertex_group() for x in self.objects]) - self.__remove_and_rebuild_index(polygon.get_normal_group(), self.normals, - [x.get_normal_group() for x in self.objects]) - self.__remove_and_rebuild_index(polygon.get_color_group(), self.colors, - [x.get_color_group() for x in self.objects]) + self.__remove_group_item(polygon.get_vertex_group(), self.vertices, + [x.get_vertex_group() for x in self.objects]) + self.__remove_group_item(polygon.get_normal_group(), self.normals, + [x.get_normal_group() for x in self.objects]) + self.__remove_group_item(polygon.get_color_group(), self.colors, + [x.get_color_group() for x in self.objects]) if polygon.uv_count: uv_groups = set() for x in self.objects: for i in range(x.uv_count): uv_groups.add(x.get_uv_group(i)) for i in range(polygon.uv_count): - self.__remove_and_rebuild_index(polygon.get_uv_group(i), self.uvs, uv_groups) + self.__remove_group_item(polygon.get_uv_group(i), self.uvs, uv_groups) self.mark_modified() def add_material(self, material): @@ -271,12 +272,15 @@ def remove_material(self, material): def get_polys_using_material(self, material): return [x for x in self.objects if x.get_material() == material] - def add_bone(self, name, parent_bone=None, has_geometry=False, + def add_bone(self, bone, parent_bone=None, has_geometry=False, scale_equal=True, fixed_scale=True, fixed_rotation=True, fixed_translation=True): - b = Bone(name, self, has_geometry=has_geometry, - scale_equal=scale_equal, fixed_scale=fixed_scale, - fixed_rotation=fixed_rotation, fixed_translation=fixed_translation) + if type(bone) is not Bone: + b = Bone(bone, self, has_geometry=has_geometry, + scale_equal=scale_equal, fixed_scale=fixed_scale, + fixed_rotation=fixed_rotation, fixed_translation=fixed_translation) + else: + b = bone b.index = len(self.bones) self.bones.append(b) if self.bone_table is None: @@ -293,7 +297,7 @@ def add_definition(self, material, polygon, visible_bone=None, priority=0): material.add_poly_ref(polygon) polygon.material = material polygon.visible_bone = visible_bone - polygon.draw_priority = priority + polygon.priority = priority self.rebuild_head = True # ------------------ Name -------------------------------------- @@ -394,11 +398,6 @@ def getTextureMap(self): return self.parent.get_texture_map() # --------------------------------------- Check ----------------------------------- - @staticmethod - def rebuild_indexes(group): - for i in range(len(group)): - group[i].index = i - def check_group(self, group, used_set, extras=None): """ helper function for check @@ -419,7 +418,6 @@ def check_group(self, group, used_set, extras=None): AutoFix.info('(FIXED) Removed unused refs') for x in to_remove: group.remove(x) - self.rebuild_indexes(group) def check(self, expected_name=None): """ diff --git a/abmatt/brres/mdl0/normal.py b/abmatt/brres/mdl0/normal.py index 090929b..6f72951 100644 --- a/abmatt/brres/mdl0/normal.py +++ b/abmatt/brres/mdl0/normal.py @@ -10,6 +10,9 @@ def __deepcopy__(self, memodict=None): copy = Normal(self.name, None) return copy.paste(self) + def __hash__(self): + return super().__hash__() + @property def point_width(self): if self.comp_count == TYPE_NORMAL_BINORMAL_TANGENT: diff --git a/abmatt/brres/mdl0/point.py b/abmatt/brres/mdl0/point.py index 5857220..959dded 100644 --- a/abmatt/brres/mdl0/point.py +++ b/abmatt/brres/mdl0/point.py @@ -19,6 +19,9 @@ def __init__(self, name, parent, binfile=None): self.decoded = None super().__init__(name, parent, binfile) + def __hash__(self): + return super().__hash__() + def paste(self, item): self.comp_count = item.comp_count self.divisor = item.divisor diff --git a/abmatt/brres/mdl0/polygon.py b/abmatt/brres/mdl0/polygon.py index a2f0670..5bfb946 100644 --- a/abmatt/brres/mdl0/polygon.py +++ b/abmatt/brres/mdl0/polygon.py @@ -1,4 +1,5 @@ """Objects (Polygons)""" +from copy import deepcopy from abmatt.autofix import AutoFix, Bug from abmatt.brres.lib import decoder @@ -21,8 +22,69 @@ def set_str(self, key, value): def get_str(self, key): raise NotImplementedError() - def paste(self, item): - raise NotImplementedError() + def paste(self, other): + parent = self.parent + self.tex_e = other.tex_e + i = parent.bones.index(other.visible_bone) + if i < 0: + b = deepcopy(other.visible_bone) + parent.add_bone(b) + else: + b = parent.bones[i] + self.visible_bone = b + i = parent.bones.index(other.linked_bone) + if i < 0: + b = deepcopy(other.linked_bone) + parent.add_bone(b) + else: + b = parent.bones[i] + self.linked_bone = b + parent.update_polygon_material(self, self.material, other.material) + self.decoded = None + self.priority = other.priority + self.vertex_index = other.vertex_index + self.normal_index = other.normal_index + self.color0_index = other.color0_index + self.color1_index = other.color1_index + self.uv_indices = deepcopy(other.uv_indices) + self.weight_index = other.weight_index + self.uv_mtx_indices = deepcopy(other.uv_mtx_indices) + parent.vertices.remove(self.vertices) + self.vertices = deepcopy(other.vertices) + parent.vertices.append(self.vertices) + self.facepoint_count = other.facepoint_count + self.face_count = other.face_count + for c in self.colors: + if c: + found = False + for poly in parent.objects: + if c in poly.colors: + found = True + break + if not found: + parent.colors.remove(c) + self.colors = deepcopy(other.colors) + for c in self.colors: + parent.colors.append(c) + self.color_count = other.color_count + parent.normals.remove(self.normals) + self.normals = deepcopy(other.normals) + parent.normals.append(self.normals) + self.encode_str = other.encode_str + for uv in self.uvs: + parent.uvs.remove(uv) + self.uvs = deepcopy(other.uvs) + for uv in self.uvs: + parent.uvs.append(uv) + self.uv_count = other.uv_count + self.data = deepcopy(other.data) + self.flags = deepcopy(other.flags) + self.bone_table = deepcopy(other.bone_table) + self.fur_vector = other.fur_vector + self.fur_coord = other.fur_coord + self.vertex_e = other.vertex_e + self.normal_index3 = other.normal_index3 + self.color0_e = other.color0_e def __init__(self, name, parent, binfile=None): self.tex_e = [1] * 8 @@ -45,6 +107,9 @@ def __eq__(self, other): and self.color0_e == other.color0_e and self.normal_e == other.normal_e \ and self.priority == other.priority and self.material == other.material and self.data == other.data + def __hash__(self): + return super().__hash__() + def begin(self): # The face point indices, also indexes into the encode string self.vertex_index = -1 @@ -228,7 +293,7 @@ def has_color1(self): def has_uv_group(self, i): return self.uvs[i] is not None - def has_weighted_matrix(self): + def has_weights(self): return self.weight_index >= 0 def has_uv_matrix(self, i): diff --git a/abmatt/brres/mdl0/texcoord.py b/abmatt/brres/mdl0/texcoord.py index f50b2cd..52ae5eb 100644 --- a/abmatt/brres/mdl0/texcoord.py +++ b/abmatt/brres/mdl0/texcoord.py @@ -7,6 +7,9 @@ class TexCoord(Point): flip_on_decode = True + def __hash__(self): + return super().__hash__() + def __deepcopy__(self, memodict=None): copy = TexCoord(self.name, None) return copy.paste(self) diff --git a/abmatt/brres/mdl0/vertex.py b/abmatt/brres/mdl0/vertex.py index 50ec335..e291ebd 100644 --- a/abmatt/brres/mdl0/vertex.py +++ b/abmatt/brres/mdl0/vertex.py @@ -10,6 +10,8 @@ class Vertex(Point): __MAX_COORD = 131071 """ Vertex class for storing vertices data """ + def __hash__(self): + return super().__hash__() def __deepcopy__(self, memodict=None): copy = Vertex(self.name, None) diff --git a/abmatt/brres/subfile.py b/abmatt/brres/subfile.py index 65728e3..0279e77 100644 --- a/abmatt/brres/subfile.py +++ b/abmatt/brres/subfile.py @@ -63,7 +63,7 @@ def __init__(self, name, parent, binfile): if binfile: self.unpack(binfile) - def _getNumSections(self): + def get_num_sections(self): return self.VERSION_SECTIONCOUNT[self.version] def get_anim_base_name(self): diff --git a/abmatt/build/config.txt b/abmatt/build/config.txt index 3af18c8..39a3616 100644 --- a/abmatt/build/config.txt +++ b/abmatt/build/config.txt @@ -1,5 +1,5 @@ build_name = main # build output name build_type = onedir # the type of build, (auto|onefile|onedir) -version = 1.0.2 +version = 1.1.0 run_integration_tests = False run_unit_tests = False diff --git a/abmatt/command.py b/abmatt/command.py index 1f1a57a..dd3ea7f 100644 --- a/abmatt/command.py +++ b/abmatt/command.py @@ -198,7 +198,7 @@ def set_load(self, params): def set_convert(self, params): flags = 0 - self.name = self.destination = self.model = None + self.name = self.destination = self.model = self.include = self.exclude = None while len(params): param = params.pop(0) lower = param.lower() @@ -213,6 +213,16 @@ def set_convert(self, params): self.name = os.path.normpath(params.pop(0)) except IndexError: raise ParsingException('Expected brres filename after keyword "in"') + elif lower == 'include': + try: + self.include = params.pop(0).split(',') + except IndexError: + raise ParsingException('Expected polygon list after include!') + elif lower == 'exclude': + try: + self.exclude = params.pop(0).split(',') + except IndexError: + raise ParsingException('Expected polygon list after exclude!') else: if lower.startswith('--'): lower = lower.lstrip('-') @@ -224,6 +234,8 @@ def set_convert(self, params): flags |= 4 elif lower == 'no-uvs': flags |= 8 + elif lower == 'patch': + flags |= 0x10 elif not self.name: self.name = os.path.normpath(param) else: @@ -830,7 +842,7 @@ def run_convert(self): destination = self.destination if not dest_auto \ else os.path.join(os.path.dirname(self.destination), convert_file_ext(os.path.basename(file), self.ext)) brres = self.create_or_open(file) - converter = klass(brres, destination, self.flags) + converter = klass(brres, destination, self.flags, include=self.include, exclude=self.exclude) models = MATCHING.findAll(self.model, brres.models) if len(models) > 1: multi_model = True diff --git a/abmatt/converters/convert_dae.py b/abmatt/converters/convert_dae.py index d178829..0b8155b 100644 --- a/abmatt/converters/convert_dae.py +++ b/abmatt/converters/convert_dae.py @@ -4,11 +4,10 @@ import numpy as np from abmatt.autofix import AutoFix -from abmatt.converters.arg_parse import cmdline_convert -from abmatt.converters import influence from abmatt.converters import convert_lib from abmatt.converters import dae as collada from abmatt.converters import matrix as mtx +from abmatt.converters.arg_parse import cmdline_convert from abmatt.converters.controller import get_controller from abmatt.converters.material import Material from abmatt.converters.matrix import rotate_z_up_to_y_up @@ -21,24 +20,25 @@ def load_model(self, model_name=None): self.bones = {} self.bones_by_name = {} self.dae = dae = collada.Dae(self.mdl_file) - materials = self.__parse_materials(dae.get_materials()) - material_names = {x.name for x in materials} + materials = dae.get_materials() + self.material_names = material_names = {} + for x in materials: + material_names[x.name] = x self.controllers = [] - self.influences = influence.InfluenceManager() # this is to track all influences, consolidating from each controller + # this is to track all influences, consolidating from each controller + self.influences = InfluenceManager() # geometry matrix = np.identity(4) if self.DETECT_FILE_UNITS: if not np.isclose(dae.unit_meter, 1.0): # set the matrix scale to convert to meters for i in range(3): matrix[i][i] = dae.unit_meter - material_geometry_map = {} + self.material_geometry_map = material_geometry_map = {} self.__parse_nodes(dae.get_scene(), material_geometry_map, matrix) self.__combine_bones_map() self.__parse_controllers(material_geometry_map) - for material in material_geometry_map: - if material not in material_names: - self._encode_material(material.Material(material)) - material_names.add(material) + if self.patch_existing and len(self.influences.mixed_influences): + raise RuntimeError('Patching rigged models is not supported!') self._before_encoding() self.influences.encode_bone_weights(self.mdl0) @@ -49,16 +49,27 @@ def load_model(self, model_name=None): self.import_textures_map = dae.get_images() return self._end_loading() + def encode_materials(self): + encoded = set() + for material in self.material_geometry_map: + if material not in encoded: + if material not in self.material_names: + self._encode_material(material.Material(material)) + else: + self._encode_material(self.material_names[material]) + encoded.add(material) + def save_model(self, mdl0=None): base_name, mdl0 = self._start_saving(mdl0) mesh = collada.Dae(initial_scene_name=base_name) - self.decoded_mats = [self.__decode_material(x, mesh) for x in mdl0.materials] + decoded_mats = [self.__decode_material(x, mesh) for x in self.materials] # polygons - polygons = mdl0.objects mesh.add_node(self.__decode_bone(mdl0.bones[0])) - for polygon in polygons: - mesh.add_node(self.__decode_geometry(polygon)) - for mat in self.decoded_mats: + for polygon in self.polygons: + x = self.__decode_geometry(polygon) + if x: + mesh.add_node(x) + for mat in decoded_mats: mesh.add_material(mat) self._end_saving(mesh) @@ -84,11 +95,12 @@ def __decode_bone(self, mdl0_bone, collada_parent=None, matrix=None): def __decode_geometry(self, polygon): geo = super()._decode_geometry(polygon) - name = polygon.name - node = collada.ColladaNode(name) - node.geometries.append(geo) - node.controller = get_controller(geo) - return node + if geo: + name = polygon.name + node = collada.ColladaNode(name) + node.geometries.append(geo) + node.controller = get_controller(geo) + return node def __decode_material(self, material, mesh): diffuse_map = ambient_map = specular_map = None @@ -112,7 +124,12 @@ def __decode_material(self, material, mesh): def __parse_controllers(self, material_geometry_map): for controller, matrix in self.controllers: - self.__parse_controller(controller, matrix, material_geometry_map) + if type(controller.geometry) is list: + controller.geometry = [x for x in controller.geometry if self._should_include_geometry(x)] + elif not self._should_include_geometry(controller.geometry): + controller.geometry = None + if controller.geometry: + self.__parse_controller(controller, matrix, material_geometry_map) def __parse_controller(self, controller, matrix, material_geometry_map): geometry, influences = controller.get_bound_geometry(self.bones, self.influences, matrix) @@ -125,9 +142,6 @@ def __parse_controller(self, controller, matrix, material_geometry_map): def __encode_geometry(self, geometry): if not self.dae.y_up: geometry.swap_y_z_axis() - replace = 'Mesh' - if geometry.name.endswith(replace) and len(replace) < len(geometry.name): - geometry.name = geometry.name[:len(replace) * -1] super()._encode_geometry(geometry) def __add_bone(self, node, parent_bone=None, matrix=None): @@ -138,14 +152,25 @@ def __add_bone(self, node, parent_bone=None, matrix=None): else: if not self.dae.y_up: matrix = rotate_z_up_to_y_up(matrix) - self.bones[name] = bone = self.mdl0.add_bone(name, parent_bone) - self.set_bone_matrix(bone, matrix) + bone = None + for x in self.mdl0.bones: + if x.name == name: + self.bones[name] = bone = x + break + if not bone: + self.bones[name] = bone = self.mdl0.add_bone(name, parent_bone) + self.set_bone_matrix(bone, matrix) name = node.attrib.get('name') if name is not None and name not in self.bones_by_name: self.bones_by_name[name] = bone return bone def __add_geometry(self, geometry, material_geometry_map): + replace = 'Mesh' + if geometry.name.endswith(replace) and len(replace) < len(geometry.name): + geometry.name = geometry.name[:len(replace) * -1] + if not self._should_include_geometry(geometry): + return geo = material_geometry_map.get(geometry.material_name) if geo is not None: if not geo[0].combine(geometry): @@ -188,10 +213,91 @@ def __parse_materials(self, materials): return [self._encode_material(material) for material in materials] - def main(): cmdline_convert(sys.argv[1:], '.dae', DaeConverter) if __name__ == '__main__': main() + + +class InfluenceManager: + """Manages all influences""" + + def __init__(self, influence_collection=None): + self.mixed_influences = [] # influences with mixed weights + self.single_influences = [] # influences with single weights + if influence_collection: + for x in influence_collection: + inf = influence_collection[x] + if inf.is_mixed(): + self.mixed_influences.append(inf) + else: + self.single_influences.append(inf) + + def encode_bone_weights(self, mdl0): + bone_sorted_single_bind_infs = sorted(self.single_influences, key=lambda x: x.get_single_bone_bind().index) + self.__create_inf_ids(bone_sorted_single_bind_infs) + bones_with_infs = [x.get_single_bone_bind() for x in bone_sorted_single_bind_infs] + remaining_bones = self.__create_bone_table(mdl0, bones_with_infs) + if self.mixed_influences: # create node mix + bones_to_infs = {} + for x in bone_sorted_single_bind_infs: + bones_to_infs[x.get_single_bone_bind().index] = x + self.__create_node_mix(mdl0, remaining_bones, bones_to_infs) + + def create_or_find(self, influence): + inf_list = self.mixed_influences if influence.is_mixed() else self.single_influences + for x in inf_list: + if x == influence: + return x + inf_list.append(influence) + return influence + + def __create_node_mix(self, mdl0, remaining_bones, bones_to_infs): + """Creates the mdl0 node mix""" + node_mix = mdl0.NodeMix + used_weights = set() + for inf in self.mixed_influences: + for x in inf.bone_weights.values(): + used_weights.add(x.bone.weight_id) + node_mix.add_mixed_weight(inf.influence_id, + [(x.bone.weight_id, x.weight) for x in inf.bone_weights.values()]) + for bone in mdl0.bones: + if bone not in remaining_bones: + weight_id = bones_to_infs[bone.index].influence_id + else: + weight_id = bone.weight_id + if weight_id in used_weights: + node_mix.add_fixed_weight(weight_id, bone.index) + return node_mix + + def __create_inf_ids(self, bone_sorted_singles): + index = 0 + for x in bone_sorted_singles: + x.influence_id = index + index += 1 + for x in self.mixed_influences: + x.influence_id = index + index += 1 + return index + + def __create_bone_table(self, mdl0, single_binds): + bonetable = [] + for i in range(len(single_binds)): + bone = single_binds[i] + bone.weight_id = i + bonetable.append(bone.index) + # influence ids for mixed + mixed_length = len(self.mixed_influences) + if mixed_length: + bonetable += [-1] * mixed_length + # now gather up remaining bones + remaining = sorted([x for x in mdl0.bones if x not in single_binds], key=lambda x: x.index) + index = len(bonetable) + for x in remaining: + bonetable.append(x.index) + x.weight_id = index + index += 1 + mdl0.set_bonetable(bonetable) + return remaining diff --git a/abmatt/converters/convert_lib.py b/abmatt/converters/convert_lib.py index 614e60d..9293372 100644 --- a/abmatt/converters/convert_lib.py +++ b/abmatt/converters/convert_lib.py @@ -22,12 +22,14 @@ class Converter: NO_COLORS = 0x2 SINGLE_BONE = 0x4 NO_UVS = 0x8 + PATCH = 0x10 DETECT_FILE_UNITS = True OVERWRITE_IMAGES = False ENCODE_PRESET = None ENCODE_PRESET_ON_NEW = True - def __init__(self, brres, mdl_file, flags=0, encode=True, mdl0=None, encoder=None): + def __init__(self, brres, mdl_file, flags=0, encode=True, mdl0=None, encoder=None, + include=None, exclude=None): if not brres: # filename = Brres.getExpectedBrresFileName(mdl_file) d, f = os.path.split(mdl_file) @@ -36,6 +38,9 @@ def __init__(self, brres, mdl_file, flags=0, encode=True, mdl0=None, encoder=Non elif type(brres) == str: brres = Brres.get_brres(brres, True) self.brres = brres + self.include = include + self.exclude = exclude + self.patch_existing = False self.texture_library = brres.get_texture_map() self.mdl_file = mdl_file self.mdl0 = mdl0 if type(mdl0) == Mdl0 else brres.get_model(mdl0) @@ -47,8 +52,6 @@ def __init__(self, brres, mdl_file, flags=0, encode=True, mdl0=None, encoder=Non def _start_saving(self, mdl0): AutoFix.info('Exporting {} to {}...'.format(os.path.basename(self.brres.name), self.mdl_file)) - if 'sand_battle.d' in self.brres.name and 'map_model' in self.brres.name: - print('debug') self.start = time.time() self.image_library = set() if mdl0 is None: @@ -61,6 +64,12 @@ def _start_saving(self, mdl0): self.mdl0 = mdl0 = self.brres.get_model(mdl0) if mdl0 is None: raise RuntimeError('No mdl0 file found to export!') + self.polygons = [x for x in mdl0.objects if self._should_include_geometry(x)] + mats = [] + for x in self.polygons: + if x.material not in mats: + mats.append(x.material) + self.materials = mats self.cwd = os.getcwd() work_dir, name = os.path.split(self.mdl_file) if work_dir: @@ -104,6 +113,11 @@ def _start_loading(self, model_name): return self._init_mdl0(brres_name, os.path.splitext(name)[0], model_name) def _before_encoding(self): + if self.patch_existing: + replace_names = [x.name for x in self.geometries] + for poly in [x for x in self.replacement_model.objects if x.name in replace_names]: + self.replacement_model.remove_polygon(poly) + self.encode_materials() if os.path.exists(self.json_file): converter = MatsToJsonConverter(self.json_file) converter.load_into(self.mdl0.materials) @@ -124,7 +138,8 @@ def _end_loading(self): os.chdir(self.cwd) if self.ENCODE_PRESET: if not self.ENCODE_PRESET_ON_NEW or (self.replacement_model is None and self.json_polygon_encoding is None): - Command('preset ' + self.ENCODE_PRESET + ' for * in ' + self.brres.name + ' model ' + self.mdl0.name).run_cmd() + Command( + 'preset ' + self.ENCODE_PRESET + ' for * in ' + self.brres.name + ' model ' + self.mdl0.name).run_cmd() AutoFix.info('\t... finished in {} secs'.format(round(time.time() - self.start, 2))) if self.encoder: self.encoder.after_encode(mdl0) @@ -137,10 +152,22 @@ def _init_mdl0(self, brres_name, mdl_name, mdl0_name): else: if mdl0_name is None: mdl0_name = self.__get_mdl0_name(brres_name, mdl_name) - self.replacement_model = self.brres.get_model(mdl0_name) - self.mdl0 = Mdl0(mdl0_name, self.brres) + self.replacement_model = self.mdl0 = self.brres.get_model(mdl0_name) + if self.flags & self.PATCH and self.replacement_model: + self.patch_existing = True + if any(x.has_weights() for x in self.replacement_model.objects): + raise RuntimeError('Patching rigged models is not supported!') + if not self.patch_existing or not self.replacement_model: + self.mdl0 = Mdl0(mdl0_name, self.brres) return self.mdl0 + def _should_include_geometry(self, geometry): + if self.include: + return geometry.name in self.include + elif self.exclude: + return geometry.name not in self.exclude + return True + @staticmethod def __get_mdl0_name(brres_name, model_name): common_models = ('course', 'map', 'vrcorn') @@ -259,6 +286,8 @@ def __get_single_bone_influence(self): bone_weights={bone.name: influence.Weight(bone, 1.0)})}) def _decode_geometry(self, polygon): + if not self._should_include_geometry(polygon): + return geo = polygon.get_decoded() if geo.colors and self.flags & self.NO_COLORS: geo.colors = None @@ -271,6 +300,8 @@ def _decode_geometry(self, polygon): return geo def _encode_geometry(self, geometry): + if not self._should_include_geometry(geometry): + return if self.flags & self.NO_COLORS: geometry.colors = None if self.flags & self.NO_NORMALS: @@ -285,8 +316,11 @@ def _encode_geometry(self, geometry): elif self.replacement_model: replace_geometry = [x for x in self.replacement_model.objects if x.name == geometry.name] if replace_geometry: - has_uv_mtx = [replace_geometry[0].has_uv_matrix(i) for i in range(8)] - priority = replace_geometry[0].priority + replace_geometry = replace_geometry[0] + has_uv_mtx = [replace_geometry.has_uv_matrix(i) for i in range(8)] + priority = replace_geometry.priority + if self.patch_existing: + self.mdl0.remove_polygon(replace_geometry) encoder = self.encoder.get_encoder(geometry) if self.encoder else None return geometry.encode(self.mdl0, encoder=encoder, priority=priority, @@ -310,6 +344,9 @@ def load_model(self, model_name=None): def save_model(self, mdl0=None): raise NotImplementedError() + def encode_materials(self): + raise NotImplementedError() + def float_to_str(fl): return ('%f' % fl).rstrip('0').rstrip('.') diff --git a/abmatt/converters/convert_obj.py b/abmatt/converters/convert_obj.py index b6968a2..93c2443 100644 --- a/abmatt/converters/convert_obj.py +++ b/abmatt/converters/convert_obj.py @@ -17,52 +17,55 @@ def __collect_geometries(self, obj_geometries, bone): material_geometry_map = {} # first collect geometries for geometry in obj_geometries: - normals = None if self.NO_NORMALS & self.flags else geometry.normals - texcoords = [geometry.texcoords] if geometry.has_texcoords else None - geo = Geometry(geometry.name, geometry.material_name, geometry.vertices, texcoords, normals, - triangles=geometry.triangles, linked_bone=bone) - # geo.encode(self.mdl0) - mat = geometry.material_name - if mat in material_geometry_map: - material_geometry_map[mat].combine(geo) - else: - material_geometry_map[mat] = geo - self.geometries.append(geo) + if self._should_include_geometry(geometry): + normals = None if self.NO_NORMALS & self.flags else geometry.normals + texcoords = [geometry.texcoords] if geometry.has_texcoords else None + geo = Geometry(geometry.name, geometry.material_name, geometry.vertices, texcoords, normals, + triangles=geometry.triangles, linked_bone=bone) + # geo.encode(self.mdl0) + mat = geometry.material_name + if mat in material_geometry_map: + material_geometry_map[mat].combine(geo) + else: + material_geometry_map[mat] = geo + self.geometries.append(geo) return material_geometry_map def load_model(self, model_name=None): mdl = self._start_loading(model_name) bone = mdl.add_bone(mdl.name) - obj = Obj(self.mdl_file) - material_geometry_map = self.__collect_geometries(obj.geometries, bone) - for material in material_geometry_map: - try: - self.__encode_material(obj.materials[material]) - except KeyError: - self._encode_material(Material(material)) - + self.obj = obj = Obj(self.mdl_file) + self.material_geometry_map = material_geometry_map = self.__collect_geometries(obj.geometries, bone) self._before_encoding() for material in material_geometry_map: super()._encode_geometry(material_geometry_map[material]) self.import_textures_map = self.__convert_set_to_map(obj.images) return self._end_loading() + def encode_materials(self): + for material in self.material_geometry_map: + try: + self.__encode_material(self.obj.materials[material]) + except KeyError: + self._encode_material(Material(material)) + def save_model(self, mdl0=None): base_name, mdl0 = self._start_saving(mdl0) - polygons = mdl0.objects + polygons = self.polygons obj = Obj(self.mdl_file, False) obj_materials = obj.materials - for mat in mdl0.materials: + for mat in self.materials: obj_mat = self.__decode_material(mat) obj_materials[obj_mat.name] = obj_mat obj_geometries = obj.geometries has_colors = False for x in polygons: - geometry = x.get_decoded() - material = geometry.material_name - obj_geometries.append(self.__decode_geometry(geometry, material)) - if x.get_color_group(): - has_colors = True + geometry = super()._decode_geometry(x) + if geometry: + material = geometry.material_name + obj_geometries.append(self.__decode_geometry(geometry, material)) + if x.get_color_group(): + has_colors = True if has_colors: AutoFix.warn('Loss of color data exporting obj') self._end_saving(obj) diff --git a/abmatt/converters/dae.py b/abmatt/converters/dae.py index f5ac7bb..cad31f2 100644 --- a/abmatt/converters/dae.py +++ b/abmatt/converters/dae.py @@ -73,6 +73,7 @@ def __init__(self, filename=None, initial_scene_name=None): self.unit_meter = 1 self.elements_by_id = {} self.node_ids = None + self.scene = None if filename: with open(filename) as f: self.xml = self.__read_xml(f) @@ -92,9 +93,11 @@ def write(self, filename): self.xml.write(filename, pretty_print=True, xml_declaration=True, encoding='utf-8') def get_scene(self): + if self.scene: + return self.scene self.node_ids = set() - nodes = [] - for x in self.scene: + self.scene = nodes = [] + for x in self.scene_xml: if x.tag == 'node': node = self.decode_node(x) if node is not None: @@ -108,8 +111,9 @@ def get_all_nodes_recurse(nodes, node_condition=None, ret_list=None): if nodes: for node in nodes: if node_condition is not None: - if node_condition(node): - ret_list.append(node) + n = node_condition(node) + if n: + ret_list.append(n) else: ret_list.append(node) Dae.get_all_nodes_recurse(node.nodes, node_condition, ret_list) @@ -117,18 +121,23 @@ def get_all_nodes_recurse(nodes, node_condition=None, ret_list=None): @staticmethod def get_all_joints(nodes): - return Dae.get_all_nodes_recurse(nodes, node_condition=lambda x: x.attrib.get('type') == 'JOINT') + return Dae.get_all_nodes_recurse(nodes, node_condition=lambda x: x if x.attrib.get('type') == 'JOINT' else None) @staticmethod def get_all_controllers(nodes): - return [x.controller for x in - Dae.get_all_nodes_recurse(nodes, node_condition=lambda x: x.controller is not None)] + return [x for x in + Dae.get_all_nodes_recurse(nodes, node_condition=lambda x: x if x.controller is not None else None)] @staticmethod def get_all_geometries(nodes): geometries = [] - for x in Dae.get_all_nodes_recurse(nodes, node_condition=lambda x: x.geometries): - geometries.extend(x.geometries) + def get_geo_node(x): + if x.geometries: + return x.geometries + elif x.controller: + return x.controller.geometry + for x in Dae.get_all_nodes_recurse(nodes, node_condition=get_geo_node): + geometries.extend(x) return geometries def __eq__(self, other): @@ -217,7 +226,7 @@ def decode_node(self, xml_node): def add_node(self, node, parent=None): if parent is None: - parent = self.scene + parent = self.scene_xml xml_node = XMLNode('node', id=node.name, name=node.name, parent=parent) if node.attrib: att = node.attrib @@ -574,18 +583,18 @@ def __initialize_libraries(self, initial_name): self.__setattr__(library, node) if initial_name: scene_id = initial_name + '-scene' - self.scene = XMLNode('visual_scene', id=scene_id, name=initial_name, parent=self.visual_scenes) + self.scene_xml = XMLNode('visual_scene', id=scene_id, name=initial_name, parent=self.visual_scenes) scene = XMLNode('scene', parent=root) instance_scene = XMLNode('instance_visual_scene', parent=scene) instance_scene.attrib['url'] = '#' + scene_id else: - self.scene = self.get_referenced_element( + self.scene_xml = self.get_referenced_element( first(first(root, 'scene'), 'instance_visual_scene'), 'url') def __initialize_assets(self, root): asset = XMLNode('asset', parent=root) contributor = XMLNode('contributor', parent=asset) - authoring_tool = XMLNode('authoring_tool', 'ABMATT COLLADA exporter v1.0.2', parent=contributor) + authoring_tool = XMLNode('authoring_tool', 'ABMATT COLLADA exporter v1.1.0', parent=contributor) time_stamp = datetime.now() created = XMLNode('created', str(time_stamp), parent=asset) modified = XMLNode('modified', str(time_stamp), parent=asset) diff --git a/abmatt/converters/geometry.py b/abmatt/converters/geometry.py index 5978bd9..c295a4a 100644 --- a/abmatt/converters/geometry.py +++ b/abmatt/converters/geometry.py @@ -114,8 +114,8 @@ def encode(self, mdl, visible_bone=None, encoder=None, if self.__encode_colors(p, self.colors, mdl, use_default_colors_if_none_found): p.color0_index = self.ipp() self.__encode_texcoords(p, self.texcoords, mdl) - tris = self.__construct_tris(p, p.has_weighted_matrix()) - data, p.face_count, p.facepoint_count = self.__encode_tris(tris, p.has_weighted_matrix()) + tris = self.__construct_tris(p, p.has_weights()) + data, p.face_count, p.facepoint_count = self.__encode_tris(tris, p.has_weights()) past_align = len(data) % 0x20 if past_align: data.extend(b'\0' * (0x20 - past_align)) @@ -225,7 +225,7 @@ def __encode_vertices(self, polygon, vertices, mdl0): mdl0.vertices.append(vert) points = vertices.points encoder = self.encoder.vertex_encoder if self.encoder is not None else None - if polygon.has_weighted_matrix(): + if polygon.has_weights(): for i in range(len(vertices)): influence = self.influences[i] points[i] = influence.apply_to(points[i], decode=False) diff --git a/abmatt/converters/influence.py b/abmatt/converters/influence.py index 083e940..b91f9e3 100644 --- a/abmatt/converters/influence.py +++ b/abmatt/converters/influence.py @@ -269,83 +269,3 @@ def get_influence_indices(self): return matrices, np.array(facepoint_indexer, np.uint) -class InfluenceManager: - """Manages all influences""" - - def __init__(self, influence_collection=None): - self.mixed_influences = [] # influences with mixed weights - self.single_influences = [] # influences with single weights - if influence_collection: - for x in influence_collection: - inf = influence_collection[x] - if inf.is_mixed(): - self.mixed_influences.append(inf) - else: - self.single_influences.append(inf) - - def encode_bone_weights(self, mdl0): - bone_sorted_single_bind_infs = sorted(self.single_influences, key=lambda x: x.get_single_bone_bind().index) - self.__create_inf_ids(bone_sorted_single_bind_infs) - bones_with_infs = [x.get_single_bone_bind() for x in bone_sorted_single_bind_infs] - remaining_bones = self.__create_bone_table(mdl0, bones_with_infs) - if self.mixed_influences: # create node mix - bones_to_infs = {} - for x in bone_sorted_single_bind_infs: - bones_to_infs[x.get_single_bone_bind().index] = x - self.__create_node_mix(mdl0, remaining_bones, bones_to_infs) - - def create_or_find(self, influence): - inf_list = self.mixed_influences if influence.is_mixed() else self.single_influences - for x in inf_list: - if x == influence: - return x - inf_list.append(influence) - return influence - - def __create_node_mix(self, mdl0, remaining_bones, bones_to_infs): - """Creates the mdl0 node mix""" - node_mix = mdl0.NodeMix - used_weights = set() - for inf in self.mixed_influences: - for x in inf.bone_weights.values(): - used_weights.add(x.bone.weight_id) - node_mix.add_mixed_weight(inf.influence_id, - [(x.bone.weight_id, x.weight) for x in inf.bone_weights.values()]) - for bone in mdl0.bones: - if bone not in remaining_bones: - weight_id = bones_to_infs[bone.index].influence_id - else: - weight_id = bone.weight_id - if weight_id in used_weights: - node_mix.add_fixed_weight(weight_id, bone.index) - return node_mix - - def __create_inf_ids(self, bone_sorted_singles): - index = 0 - for x in bone_sorted_singles: - x.influence_id = index - index += 1 - for x in self.mixed_influences: - x.influence_id = index - index += 1 - return index - - def __create_bone_table(self, mdl0, single_binds): - bonetable = [] - for i in range(len(single_binds)): - bone = single_binds[i] - bone.weight_id = i - bonetable.append(bone.index) - # influence ids for mixed - mixed_length = len(self.mixed_influences) - if mixed_length: - bonetable += [-1] * mixed_length - # now gather up remaining bones - remaining = sorted([x for x in mdl0.bones if x not in single_binds], key=lambda x: x.index) - index = len(bonetable) - for x in remaining: - bonetable.append(x.index) - x.weight_id = index - index += 1 - mdl0.set_bonetable(bonetable) - return remaining diff --git a/abmatt/converters/obj.py b/abmatt/converters/obj.py index 550488d..ef80eeb 100644 --- a/abmatt/converters/obj.py +++ b/abmatt/converters/obj.py @@ -138,7 +138,7 @@ def save(self): self.save_obj() def save_mtllib(self, folder): - s = '# Wavefront MTL exported with ABMATT v1.0.2' + s = '# Wavefront MTL exported with ABMATT v1.1.0' materials = self.materials for x in materials: s += '\n' + materials[x].get_save_str() @@ -146,7 +146,7 @@ def save_mtllib(self, folder): f.write(s) def save_obj(self): - s = '# Wavefront OBJ exported with ABMATT v1.0.2\n\nmtllib ' + self.mtllib + '\n\n' + s = '# Wavefront OBJ exported with ABMATT v1.1.0\n\nmtllib ' + self.mtllib + '\n\n' vertex_index = 1 normal_index = 1 normal_offset = -1 diff --git a/abmatt/converters/points.py b/abmatt/converters/points.py index b964457..b03a72e 100644 --- a/abmatt/converters/points.py +++ b/abmatt/converters/points.py @@ -152,7 +152,8 @@ def encode_data(self, mdl0_points, get_index_remapper=False, encoder=None, influ if divisor: multiplyBy = 2 ** divisor self.encode_points(multiplyBy, dtype) - should_consolidate = False if self.influences and self.influences.is_mixed() else encoder is None or encoder.should_consolidate() + should_consolidate = False if self.influences and self.influences.is_mixed() \ + else encoder is None or encoder.should_consolidate() if should_consolidate: points, face_indices, index_remapper = self.__consolidate_points() self.points = points diff --git a/abmatt/dist/install-ubu.txt b/abmatt/dist/install-ubu.txt index 3bd0ed2..b8c6317 100644 --- a/abmatt/dist/install-ubu.txt +++ b/abmatt/dist/install-ubu.txt @@ -1,6 +1,6 @@ ==================================================================================== ANOOB'S BRRES MATERIAL TOOL -Version: 1.0.2 +Version: 1.1.0 Author: Robert Nelson OS: linux Github: https://github.com/Robert-N7/abmatt diff --git a/abmatt/dist/install-win.txt b/abmatt/dist/install-win.txt index 19e8d54..c9e7bf9 100644 --- a/abmatt/dist/install-win.txt +++ b/abmatt/dist/install-win.txt @@ -1,6 +1,6 @@ =================================================================================================== ANOOB'S BRRES MATERIAL TOOL -Version 1.0.2 +Version 1.1.0 Robert Nelson OS: Windows 10 64-bit Github: https://github.com/Robert-N7/abmatt diff --git a/abmatt/dist/make_installer.nsi b/abmatt/dist/make_installer.nsi index c343731..389264a 100644 --- a/abmatt/dist/make_installer.nsi +++ b/abmatt/dist/make_installer.nsi @@ -1,4 +1,4 @@ -!define VERSION "1.0.2" +!define VERSION "1.1.0" !define PROGRAM_NAME "ANoob's Brres Material Tool ${VERSION}" InstallDir "$Documents\abmatt" Name "${PROGRAM_NAME}" diff --git a/abmatt/load_config.py b/abmatt/load_config.py index 003a12f..27d797f 100644 --- a/abmatt/load_config.py +++ b/abmatt/load_config.py @@ -43,7 +43,9 @@ def set_remove_unused(val): pass -def load_config(app_dir, loudness=None, autofix_level=None): +def load_config(app_dir=None, loudness=None, autofix_level=None): + if app_dir is None: + app_dir = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'etc', 'abmatt') conf = Config.get_instance(os.path.join(app_dir, 'config.conf')) tmp_dir = os.path.join(app_dir, 'temp_files') converter = ImgConverter(tmp_dir) @@ -84,10 +86,6 @@ def load_config(app_dir, loudness=None, autofix_level=None): Mdl0.DETECT_MODEL_NAME = validBool(conf['detect_model_name']) except ValueError: pass - # try: - # Mdl0.DRAW_PASS_AUTO = validBool(conf['draw_pass_auto']) - # except ValueError: - # pass try: Shader.MAP_ID_AUTO = validBool(conf['map_id_auto']) except ValueError: @@ -119,7 +117,7 @@ def load_config(app_dir, loudness=None, autofix_level=None): return conf -VERSION = '1.0.2' +VERSION = '1.1.0' USAGE = "USAGE: abmatt [command_line][--interactive -f -b -d --overwrite]" @@ -138,26 +136,20 @@ def hlp(cmd=None): ==================================================================================== ANOOB'S BRRES MATERIAL TOOL Version {} -commands = set | info | add | remove | select | preset | save | copy | paste | convert -type = 'material' | 'layer' [':' id] | 'shader' | 'stage' [':' id] - | 'srt0' | 'srt0layer' [':' id] | 'pat0' - | 'mdl0' | 'brres'; -To see what keys are available, try `info keys` ==================================================================================== -## Command Line Usage: +Command Line Usage: +abmatt [command_line][flags] + +| -a | --auto-fix | Set the autofix level (0 to turn off fixes). | | -b | --brres | Brres file selection. | | -c | --command | Command name to run. | | -d | --destination | The file path to be written to. Mutliple destinations are not supported. | | -f | --file | File with ABMatt commands to be processed as specified in file format. | | -h | --help | Displays a help message about program usage. | | -i | --interactive | Interactive shell mode. | -| -k | --key | Setting key to be updated. | | -l | --loudness | Sets the verbosity level. (0-5) -| -m | --model | Model selection. | -| -n | --name | Material or layer name or regular expression to be found. | | -o | --overwrite | Overwrite existing files. | -| -t | --type | Type selection. | -| -v | --value | Value to set corresponding with key. (set command) | +| | --moonview | Treat the Brres as Moonview course, adjusting material names. | command_line = cmd-prefix ['for' selection] EOL; cmd-prefix = set | info | add | remove | select | preset | save | copy | paste | convert; @@ -170,7 +162,11 @@ def hlp(cmd=None): save = 'save' [filename] ['as' destination] ['overwrite'] copy = 'copy' type; paste = 'paste' type; -convert = 'convert' filename ['to' destination] ['no-colors'] ['no-normals'] ['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]; @@ -204,7 +200,7 @@ def parse_args(argv, app_dir): command = destination = brres_file = command_file = model = value = key = "" autofix = loudness = None name = None - no_normals = no_colors = single_bone = no_uvs = moonview = False + no_normals = no_colors = single_bone = no_uvs = moonview = patch = False do_help = False for i in range(len(argv)): if argv[i][0] == '-': @@ -214,12 +210,13 @@ def parse_args(argv, app_dir): break try: - opts, args = getopt.gnu_getopt(argv, "hd:oc:t:k:v:n:b:m:f:iul:g", - ["help", "destination=", "overwrite", + opts, args = getopt.gnu_getopt(argv, "ahd:oc:t:k:v:n:b:m:f:iul:g", + ["auto-fix", "help", "destination=", "overwrite", "command=", "type=", "key=", "value=", "name=", "brres=", "model=", "file=", "interactive", "loudness=", "debug", - "single-bone", "no-colors", "no-normals", "no-uvs", "moonview"]) + "single-bone", "no-colors", "no-normals", "no-uvs", "moonview", + "patch"]) except getopt.GetoptError as e: print(e) print(USAGE) @@ -264,6 +261,8 @@ def parse_args(argv, app_dir): no_colors = True elif opt == '--no-uvs': no_uvs = True + elif opt == '--patch': + patch = True elif opt == '--moonview': moonview = True else: @@ -306,6 +305,8 @@ def parse_args(argv, app_dir): cmd_args.append('--no-normals') if no_uvs: cmd_args.append('--no-uvs') + if patch: + cmd_args.append('--patch') cmds.append(Command(arg_list=cmd_args)) if command: args = [command, type] @@ -329,6 +330,8 @@ def parse_args(argv, app_dir): args.append('--no-normals') if no_uvs: args.append('--no-uvs') + if patch: + args.append('--patch') cmds.append(Command(arg_list=args)) if destination: Command.DESTINATION = destination diff --git a/brres_files/old_mario_gc_hayasi.brres b/brres_files/old_mario_gc_hayasi.brres new file mode 100644 index 0000000..72abf60 Binary files /dev/null and b/brres_files/old_mario_gc_hayasi.brres differ diff --git a/debug/converters/mirror_encoder.py b/debug/converters/mirror_encoder.py index 84c3fe0..66dc66e 100644 --- a/debug/converters/mirror_encoder.py +++ b/debug/converters/mirror_encoder.py @@ -5,13 +5,12 @@ from abmatt.brres import Brres from abmatt.brres.lib import matching +from abmatt.brres.lib.decoder import get_stride from abmatt.brres.mdl0.normal import Normal +from abmatt.brres.mdl0.polygon import Polygon from abmatt.brres.mdl0.vertex import Vertex -from abmatt.converters import DaeConverter +from abmatt.converters.convert_dae import DaeConverter, InfluenceManager from abmatt.converters.encoder import GeometryEncoder, PointEncoder, ModelEncoder, ColorEncoder -from abmatt.brres.mdl0.polygon import Polygon -from abmatt.converters import get_stride -from abmatt.converters.influence import decode_mdl0_influences, InfluenceManager def create_mirror(brres_file_name, working_folder='tmp', mdl0_name=None, new_file_name=None, mirror_encoder=None): @@ -42,7 +41,8 @@ class MirrorEncoder(ModelEncoder): """Mirrors a model encoding""" def __init__(self, mdl0=None, geo_name_mapping=None, match_min_max=False, - replace_polygons=False, replace_vertices=False, replace_normals=False, replace_uvs=False, replace_colors=False): + replace_polygons=False, replace_vertices=False, replace_normals=False, replace_uvs=False, + replace_colors=False): """ :param mdl0: existing model :param geo_name_mapping: How to map the incoming geometry names to the polygons, the default is to match names @@ -69,7 +69,7 @@ def before_encoding(self, converter): def __mirror_influences(self, inf): my_node_mix = self.mdl0.NodeMix if my_node_mix is not None: - my_inf = InfluenceManager(decode_mdl0_influences(self.mdl0)) + my_inf = InfluenceManager(self.mdl0.get_influences()) inf.single_influences = self.__order_influence_list(my_inf.single_influences, inf.single_influences) inf.mixed_influences = self.__order_influence_list(my_inf.mixed_influences, inf.mixed_influences) @@ -134,8 +134,6 @@ def after_encode(self, new_mdl0): new_mdl0.rebuild_color_refs() else: self.reorder_group(new_mdl0.colors, self.mdl0.colors) - self.reorder_anims(new_mdl0.srt0_collection, self.mdl0.srt0_collection) - self.reorder_anims(new_mdl0.pat0_collection, self.mdl0.pat0_collection) if self.replace_polygons: self.replace_polys(new_mdl0.objects, self.mdl0.objects) new_mdl0.facepoint_count = self.mdl0.facepoint_count diff --git a/debug/test_brres.py b/debug/test_brres.py index ddfed4a..0dccbf0 100644 --- a/debug/test_brres.py +++ b/debug/test_brres.py @@ -49,10 +49,13 @@ def test_export_import_dae_eq(self): converter.save_model(model) importer = DaeConverter(Brres(tmp_brres, read_file=False), tmp) importer.load_model() - self.assertTrue(node_eq(model.materials, importer.mdl0.materials)) + mats = sorted(model.materials, key=lambda x: x.name) + imported_mats = sorted(importer.mdl0.materials, key=lambda x: x.name) + self.assertTrue(node_eq(mats, imported_mats)) except: print(f'ERROR converting {x}') - raise + if converter.brres.version == 11: + raise def test_export_all_obj(self): tmp = self._get_tmp('.obj') diff --git a/setup.py b/setup.py index e3d5018..32b52c2 100755 --- a/setup.py +++ b/setup.py @@ -27,7 +27,7 @@ # calling the setup function setup(name='abmatt', - version='1.0.2', + version='1.1.0', entry_points={ 'console_scripts': [ 'abmatt = abmatt.__main__:main' diff --git a/test_files/simple_multi_bone_multi_bind.dae b/test_files/simple_multi_bone_multi_bind.dae index 1c8aa88..08cb502 100644 --- a/test_files/simple_multi_bone_multi_bind.dae +++ b/test_files/simple_multi_bone_multi_bind.dae @@ -1,106 +1,122 @@ - + - - FBX COLLADA exporter - + ABMATT COLLADA exporter v1.0.2 - 2021-04-30T03:40:17Z - - 2021-04-30T03:40:17Z - - - - <unit meter="1.000000" name="centimeter"/> + <created>2021-05-31 17:57:45.326116</created> + <modified>2021-05-31 17:57:45.326116</modified> + <unit name="centimeter" meter="1"/> <up_axis>Y_UP</up_axis> </asset> <library_images> - <image id="MapFBXASC032FBXASC0352-image" name="MapFBXASC032FBXASC0352"> - <init_from>mtx.skp_simple_Textures\Material1.PNG</init_from> + <image id="Wax_02-image" name="Wax_02"> + <init_from>simple_multi_bone_multi_bind_maps\Wax_02.png</init_from> </image> - <image id="MapFBXASC032FBXASC0351-image" name="MapFBXASC032FBXASC0351"> - <init_from>mtx.skp_simple_Textures\Wax_02.PNG</init_from> + <image id="Material1-image" name="Material1"> + <init_from>simple_multi_bone_multi_bind_maps\Material1.png</init_from> </image> - <image id="MapFBXASC032FBXASC0353-image" name="MapFBXASC032FBXASC0353"> - <init_from>mtx.skp_simple_Textures\Material2.PNG</init_from> + <image id="Material2-image" name="Material2"> + <init_from>simple_multi_bone_multi_bind_maps\Material2.png</init_from> </image> </library_images> <library_materials> - <material id="Material1" name="Material1"> - <instance_effect url="#Material1-fx"/> - </material> <material id="Wax_02" name="Wax_02"> <instance_effect url="#Wax_02-fx"/> </material> + <material id="Material1" name="Material1"> + <instance_effect url="#Material1-fx"/> + </material> <material id="Material2" name="Material2"> <instance_effect url="#Material2-fx"/> </material> </library_materials> <library_effects> - <effect id="Material1-fx" name="Material1"> + <effect id="Wax_02-fx" name="Wax_02"> <profile_COMMON> - <technique sid="standard"> + <newparam sid="Wax_02-surface"> + <surface type="2D"> + <init_from>Wax_02-image</init_from> + </surface> + </newparam> + <newparam sid="Wax_02-sampler"> + <sampler2D> + <source>Wax_02-surface</source> + </sampler2D> + </newparam> + <technique sid="COMMON"> <phong> <emission> - <color sid="emission">0.000000 0.000000 0.000000 1.000000</color> + <color sid="emission">0.02 0.02 0.02 1</color> </emission> <ambient> - <color sid="ambient">0.800000 0.800000 0.800000 1.000000</color> + <color sid="ambient">0.8 0.8 0.8 1</color> </ambient> <diffuse> - <texture texture="MapFBXASC032FBXASC0352-image" texcoord="CHANNEL0"> - <extra> - <technique profile="MAYA"> - <wrapU sid="wrapU0">TRUE</wrapU> - <wrapV sid="wrapV0">TRUE</wrapV> - <blend_mode>ADD</blend_mode> - </technique> - </extra> - </texture> + <texture texture="Wax_02-sampler" texcoord="CHANNEL0"/> </diffuse> <specular> - <color sid="specular">0.000133 0.000133 0.000133 1.000000</color> + <color sid="specular">0.3 0.3 0.3 1</color> </specular> <shininess> <float sid="shininess">1.071773</float> </shininess> + <reflective> + <color sid="reflective">0 0 0 1</color> + </reflective> + <reflectivity> + <float sid="reflectivity">1</float> + </reflectivity> + <transparent opaque="RGB_ZERO"> + <color sid="transparent">1 1 1 1</color> + </transparent> <transparency> - <float sid="transparency">0.600000</float> + <float sid="transparency">0</float> </transparency> </phong> </technique> </profile_COMMON> </effect> - <effect id="Wax_02-fx" name="Wax_02"> + <effect id="Material1-fx" name="Material1"> <profile_COMMON> - <technique sid="standard"> + <newparam sid="Material1-surface"> + <surface type="2D"> + <init_from>Material1-image</init_from> + </surface> + </newparam> + <newparam sid="Material1-sampler"> + <sampler2D> + <source>Material1-surface</source> + </sampler2D> + </newparam> + <technique sid="COMMON"> <phong> <emission> - <color sid="emission">0.000000 0.000000 0.000000 1.000000</color> + <color sid="emission">0.02 0.02 0.02 1</color> </emission> <ambient> - <color sid="ambient">0.800000 0.800000 0.800000 1.000000</color> + <color sid="ambient">0.8 0.8 0.8 1</color> </ambient> <diffuse> - <texture texture="MapFBXASC032FBXASC0351-image" texcoord="CHANNEL0"> - <extra> - <technique profile="MAYA"> - <wrapU sid="wrapU0">TRUE</wrapU> - <wrapV sid="wrapV0">TRUE</wrapV> - <blend_mode>ADD</blend_mode> - </technique> - </extra> - </texture> + <texture texture="Material1-sampler" texcoord="CHANNEL0"/> </diffuse> <specular> - <color sid="specular">0.000133 0.000133 0.000133 1.000000</color> + <color sid="specular">0.3 0.3 0.3 1</color> </specular> <shininess> <float sid="shininess">1.071773</float> </shininess> + <reflective> + <color sid="reflective">0 0 0 1</color> + </reflective> + <reflectivity> + <float sid="reflectivity">1</float> + </reflectivity> + <transparent opaque="RGB_ZERO"> + <color sid="transparent">1 1 1 1</color> + </transparent> <transparency> - <float sid="transparency">0.600000</float> + <float sid="transparency">0</float> </transparency> </phong> </technique> @@ -108,33 +124,44 @@ </effect> <effect id="Material2-fx" name="Material2"> <profile_COMMON> - <technique sid="standard"> + <newparam sid="Material2-surface"> + <surface type="2D"> + <init_from>Material2-image</init_from> + </surface> + </newparam> + <newparam sid="Material2-sampler"> + <sampler2D> + <source>Material2-surface</source> + </sampler2D> + </newparam> + <technique sid="COMMON"> <phong> <emission> - <color sid="emission">0.000000 0.000000 0.000000 1.000000</color> + <color sid="emission">0.02 0.02 0.02 1</color> </emission> <ambient> - <color sid="ambient">0.800000 0.800000 0.800000 1.000000</color> + <color sid="ambient">0.8 0.8 0.8 1</color> </ambient> <diffuse> - <texture texture="MapFBXASC032FBXASC0353-image" texcoord="CHANNEL0"> - <extra> - <technique profile="MAYA"> - <wrapU sid="wrapU0">TRUE</wrapU> - <wrapV sid="wrapV0">TRUE</wrapV> - <blend_mode>ADD</blend_mode> - </technique> - </extra> - </texture> + <texture texture="Material2-sampler" texcoord="CHANNEL0"/> </diffuse> <specular> - <color sid="specular">0.000133 0.000133 0.000133 1.000000</color> + <color sid="specular">0.3 0.3 0.3 1</color> </specular> <shininess> <float sid="shininess">1.071773</float> </shininess> + <reflective> + <color sid="reflective">0 0 0 1</color> + </reflective> + <reflectivity> + <float sid="reflectivity">1</float> + </reflectivity> + <transparent opaque="RGB_ZERO"> + <color sid="transparent">1 1 1 1</color> + </transparent> <transparency> - <float sid="transparency">0.600000</float> + <float sid="transparency">0</float> </transparency> </phong> </technique> @@ -142,931 +169,318 @@ </effect> </library_effects> <library_geometries> - <geometry id="BlackNWhite1-lib" name="BlackNWhite1Mesh"> + <geometry id="simple_SKP__Wax_02-lib" name="simple_SKP__Wax_02"> <mesh> - <source id="BlackNWhite1-POSITION"> - <float_array id="BlackNWhite1-POSITION-array" count="12"> -0.000000 4000.000000 3703.520020 -0.000000 0.000000 0.000000 -0.000000 0.000000 2000.000000 -0.000000 4000.000000 0.000000 -</float_array> + <source id="simple_SKP__Wax_02-POSITION"> + <float_array id="simple_SKP__Wax_02-POSITION-array" count="12">4000 2000.000244 0.000464 0 0 0 4000 -0.000244 0.000732 0.000412 1999.999756 -0.000079 </float_array> <technique_common> - <accessor source="#BlackNWhite1-POSITION-array" count="4" stride="3"> + <accessor source="#simple_SKP__Wax_02-POSITION-array" count="4" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> - <source id="BlackNWhite1-Normal0"> - <float_array id="BlackNWhite1-Normal0-array" count="18"> --1.000000 0.000000 0.000000 --1.000000 0.000000 0.000000 --1.000000 0.000000 0.000000 --1.000000 0.000000 0.000000 --1.000000 0.000000 0.000000 --1.000000 0.000000 0.000000 -</float_array> + <source id="simple_SKP__Wax_02-NORMAL0"> + <float_array id="simple_SKP__Wax_02-NORMAL0-array" count="3">0 -1 0 </float_array> <technique_common> - <accessor source="#BlackNWhite1-Normal0-array" count="6" stride="3"> + <accessor source="#simple_SKP__Wax_02-NORMAL0-array" count="1" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> - <source id="BlackNWhite1-UV0"> - <float_array id="BlackNWhite1-UV0-array" count="16"> -2.000000 0.000000 -0.000000 1.000000 -0.000000 0.000000 -2.000000 1.851760 --2.000000 1.851760 -0.000000 0.000000 -0.000000 1.000000 --2.000000 0.000000 -</float_array> + <source id="simple_SKP__Wax_02-UV0"> + <float_array id="simple_SKP__Wax_02-UV0-array" count="8">2 1 0 0 2 0 0 1 </float_array> <technique_common> - <accessor source="#BlackNWhite1-UV0-array" count="8" stride="2"> + <accessor source="#simple_SKP__Wax_02-UV0-array" count="4" stride="2"> <param name="S" type="float"/> <param name="T" type="float"/> </accessor> </technique_common> </source> - <source id="BlackNWhite1-UV1"> - <float_array id="BlackNWhite1-UV1-array" count="16"> -1.000000 0.046115 -0.000000 0.546115 -0.000000 0.046115 -1.000000 0.971995 -0.000000 0.971995 -1.000000 0.046115 -1.000000 0.546115 -0.000000 0.046115 -</float_array> - <technique_common> - <accessor source="#BlackNWhite1-UV1-array" count="8" stride="2"> - <param name="S" type="float"/> - <param name="T" type="float"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite1-VERTEX_COLOR0"> - <float_array id="BlackNWhite1-VERTEX_COLOR0-array" count="24"> -0.000000 0.000000 0.000000 1.000000 -1.000000 1.000000 1.000000 1.000000 -1.000000 1.000000 1.000000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -</float_array> - <technique_common> - <accessor source="#BlackNWhite1-VERTEX_COLOR0-array" count="6" stride="4"> - <param name="R" type="double"/> - <param name="G" type="double"/> - <param name="B" type="double"/> - <param name="A" type="double"/> - </accessor> - </technique_common> - </source> - <vertices id="BlackNWhite1-VERTEX"> - <input semantic="POSITION" source="#BlackNWhite1-POSITION"/> + <vertices id="simple_SKP__Wax_02-VERTEX"> + <input semantic="POSITION" source="#simple_SKP__Wax_02-POSITION"/> </vertices> - <triangles count="2" material="Material1"> - <input semantic="VERTEX" offset="0" source="#BlackNWhite1-VERTEX"/> - <input semantic="NORMAL" offset="1" source="#BlackNWhite1-Normal0"/> - <input semantic="TEXCOORD" offset="2" set="0" source="#BlackNWhite1-UV0"/> - <input semantic="COLOR" offset="3" set="0" source="#BlackNWhite1-VERTEX_COLOR0"/> - <input semantic="TEXCOORD" offset="4" set="1" source="#BlackNWhite1-UV1"/> - <p> 0 0 4 0 4 1 1 5 1 5 2 2 6 2 6 1 3 5 3 5 0 4 4 4 4 3 5 7 5 7</p> + <triangles material="Wax_02" count="2"> + <input semantic="VERTEX" offset="0" source="#simple_SKP__Wax_02-VERTEX"/> + <input semantic="NORMAL" offset="1" source="#simple_SKP__Wax_02-NORMAL0"/> + <input semantic="TEXCOORD" offset="2" source="#simple_SKP__Wax_02-UV0" set="0"/> + <p>1 0 1 2 0 2 0 0 0 1 0 1 0 0 0 3 0 3</p> </triangles> </mesh> </geometry> - <geometry id="GreenCloud-lib" name="GreenCloudMesh"> + <geometry id="simple_SKP__Material1-lib" name="simple_SKP__Material1"> <mesh> - <source id="GreenCloud-POSITION"> - <float_array id="GreenCloud-POSITION-array" count="12"> -4000.000000 2000.000000 0.000000 -0.000000 0.000000 0.000000 -4000.000000 0.000000 0.000000 -0.000000 2000.000000 0.000000 -</float_array> + <source id="simple_SKP__Material1-POSITION"> + <float_array id="simple_SKP__Material1-POSITION-array" count="24">0 -0.000488 0.001465 0 2000.001465 0.001377 0.00045 3703.519775 -4000 0 0 -4000 4000 -0.000335 -4000.001276 4000.000276 3703.520155 -3999.999967 4000 2000.001465 0.001377 4000 -0.000488 0.001465 </float_array> <technique_common> - <accessor source="#GreenCloud-POSITION-array" count="4" stride="3"> + <accessor source="#simple_SKP__Material1-POSITION-array" count="8" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> - <source id="GreenCloud-Normal0"> - <float_array id="GreenCloud-Normal0-array" count="18"> -0.000000 0.000000 1.000000 -0.000000 0.000000 1.000000 -0.000000 0.000000 1.000000 -0.000000 0.000000 1.000000 -0.000000 0.000000 1.000000 -0.000000 0.000000 1.000000 -</float_array> + <source id="simple_SKP__Material1-NORMAL0"> + <float_array id="simple_SKP__Material1-NORMAL0-array" count="9">-1 0 0 1 0 0 0.949097 -0.171753 -0.263672 </float_array> <technique_common> - <accessor source="#GreenCloud-Normal0-array" count="6" stride="3"> + <accessor source="#simple_SKP__Material1-NORMAL0-array" count="3" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> - <source id="GreenCloud-UV0"> - <float_array id="GreenCloud-UV0-array" count="8"> -2.000000 1.000000 -0.000000 0.000000 -2.000000 0.000000 -0.000000 1.000000 -</float_array> - <technique_common> - <accessor source="#GreenCloud-UV0-array" count="4" stride="2"> - <param name="S" type="float"/> - <param name="T" type="float"/> - </accessor> - </technique_common> - </source> - <vertices id="GreenCloud-VERTEX"> - <input semantic="POSITION" source="#GreenCloud-POSITION"/> - </vertices> - <triangles count="2" material="Wax_02"> - <input semantic="VERTEX" offset="0" source="#GreenCloud-VERTEX"/> - <input semantic="NORMAL" offset="1" source="#GreenCloud-Normal0"/> - <input semantic="TEXCOORD" offset="2" set="0" source="#GreenCloud-UV0"/> - <p> 0 0 0 1 1 1 2 2 2 1 3 1 0 4 0 3 5 3</p> - </triangles> - </mesh> - </geometry> - <geometry id="Yellow-lib" name="YellowMesh"> - <mesh> - <source id="Yellow-POSITION"> - <float_array id="Yellow-POSITION-array" count="36"> -4000.000000 4000.000000 0.000000 -0.000000 0.000000 0.000000 -0.000000 4000.000000 0.000000 -4000.000000 0.000000 0.000000 -0.000000 4000.000000 3703.520020 -4000.000000 4000.000000 0.000000 -0.000000 4000.000000 0.000000 -4000.000000 4000.000000 3703.520020 -4000.000000 0.000000 2000.000000 -0.000000 4000.000000 3703.520020 -0.000000 0.000000 2000.000000 -4000.000000 4000.000000 3703.520020 -</float_array> + <source id="simple_SKP__Material1-COLOR"> + <float_array id="simple_SKP__Material1-COLOR-array" count="8">0 0 0 1 1 1 1 1 </float_array> <technique_common> - <accessor source="#Yellow-POSITION-array" count="12" stride="3"> - <param name="X" type="float"/> - <param name="Y" type="float"/> - <param name="Z" type="float"/> + <accessor source="#simple_SKP__Material1-COLOR-array" count="2" stride="4"> + <param name="R" type="float"/> + <param name="G" type="float"/> + <param name="B" type="float"/> + <param name="A" type="float"/> </accessor> </technique_common> </source> - <source id="Yellow-Normal0"> - <float_array id="Yellow-Normal0-array" count="54"> -0.000000 0.000000 -1.000000 -0.000000 0.000000 -1.000000 -0.000000 0.000000 -1.000000 -0.000000 0.000000 -1.000000 -0.000000 0.000000 -1.000000 -0.000000 0.000000 -1.000000 -0.000000 1.000000 0.000000 -0.000000 1.000000 0.000000 -0.000000 1.000000 0.000000 -0.000000 1.000000 0.000000 -0.000000 1.000000 0.000000 -0.000000 1.000000 0.000000 -0.000000 -0.391826 0.920039 -0.000000 -0.391826 0.920039 -0.000000 -0.391826 0.920039 -0.000000 -0.391826 0.920039 -0.000000 -0.391826 0.920039 -0.000000 -0.391826 0.920039 -</float_array> + <source id="simple_SKP__Material1-UV0"> + <float_array id="simple_SKP__Material1-UV0-array" count="12">0 0 0 1 -2 1.851807 -2 0 2 0 2 1.851807 </float_array> <technique_common> - <accessor source="#Yellow-Normal0-array" count="18" stride="3"> - <param name="X" type="float"/> - <param name="Y" type="float"/> - <param name="Z" type="float"/> + <accessor source="#simple_SKP__Material1-UV0-array" count="6" stride="2"> + <param name="S" type="float"/> + <param name="T" type="float"/> </accessor> </technique_common> </source> - <source id="Yellow-UV0"> - <float_array id="Yellow-UV0-array" count="24"> --2.000000 2.000000 -0.000000 0.000000 -0.000000 2.000000 --2.000000 0.000000 -0.000000 1.851760 --2.000000 0.000000 -0.000000 0.000000 --2.000000 1.851760 -2.000000 0.391826 -0.000000 2.565647 -0.000000 0.391826 -2.000000 2.565647 -</float_array> + <source id="simple_SKP__Material1-UV1"> + <float_array id="simple_SKP__Material1-UV1-array" count="12">1 0.125 1 0.625 0 1 0 0.125 0 0.625 1 1 </float_array> <technique_common> - <accessor source="#Yellow-UV0-array" count="12" stride="2"> + <accessor source="#simple_SKP__Material1-UV1-array" count="6" stride="2"> <param name="S" type="float"/> <param name="T" type="float"/> </accessor> </technique_common> </source> - <vertices id="Yellow-VERTEX"> - <input semantic="POSITION" source="#Yellow-POSITION"/> + <vertices id="simple_SKP__Material1-VERTEX"> + <input semantic="POSITION" source="#simple_SKP__Material1-POSITION"/> </vertices> - <triangles count="6" material="Material2"> - <input semantic="VERTEX" offset="0" source="#Yellow-VERTEX"/> - <input semantic="NORMAL" offset="1" source="#Yellow-Normal0"/> - <input semantic="TEXCOORD" offset="2" set="0" source="#Yellow-UV0"/> - <p> 0 0 0 1 1 1 2 2 2 1 3 1 0 4 0 3 5 3 4 6 4 5 7 5 6 8 6 5 9 5 4 10 4 7 11 7 8 12 8 9 13 9 10 14 10 9 15 9 8 16 8 11 17 11</p> + <triangles material="Material1" count="4"> + <input semantic="VERTEX" offset="0" source="#simple_SKP__Material1-VERTEX"/> + <input semantic="NORMAL" offset="1" source="#simple_SKP__Material1-NORMAL0"/> + <input semantic="COLOR" offset="2" source="#simple_SKP__Material1-COLOR"/> + <input semantic="TEXCOORD" offset="3" source="#simple_SKP__Material1-UV0" set="0"/> + <input semantic="TEXCOORD" offset="4" source="#simple_SKP__Material1-UV1" set="1"/> + <p>0 0 1 0 0 1 0 1 1 1 2 0 0 2 2 0 0 1 0 0 2 0 0 2 2 3 0 0 3 3 4 1 0 4 0 5 2 0 5 5 6 1 1 1 4 4 1 0 4 0 6 1 1 1 4 7 1 1 0 3</p> </triangles> </mesh> </geometry> - <geometry id="BlackNWhite2-lib" name="BlackNWhite2Mesh"> + <geometry id="simple_SKP__Material2-lib" name="simple_SKP__Material2"> <mesh> - <source id="BlackNWhite2-POSITION"> - <float_array id="BlackNWhite2-POSITION-array" count="12"> -4000.000000 4000.000000 0.000000 -4000.000000 0.000000 2000.000000 -4000.000000 0.000000 0.000000 -4000.000000 4000.000000 3703.520020 -</float_array> + <source id="simple_SKP__Material2-POSITION"> + <float_array id="simple_SKP__Material2-POSITION-array" count="24">4000 -0.000332 -4000.001221 0 0 0 0 0 -4000 4000 -0.000244 0.000732 0.00045 3703.519775 -4000 4000 3703.522705 -4000.002686 4000 2000.000244 0.000464 0.000412 1999.999756 -0.000079 </float_array> <technique_common> - <accessor source="#BlackNWhite2-POSITION-array" count="4" stride="3"> + <accessor source="#simple_SKP__Material2-POSITION-array" count="8" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> - <source id="BlackNWhite2-Normal0"> - <float_array id="BlackNWhite2-Normal0-array" count="18"> -1.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 -1.000000 0.000000 0.000000 -</float_array> + <source id="simple_SKP__Material2-NORMAL0"> + <float_array id="simple_SKP__Material2-NORMAL0-array" count="15">0 1 0 0 -0.396851 0.917847 0 -0.390381 0.920532 0 -0.387939 0.921631 0 0 -1 </float_array> <technique_common> - <accessor source="#BlackNWhite2-Normal0-array" count="6" stride="3"> + <accessor source="#simple_SKP__Material2-NORMAL0-array" count="5" stride="3"> <param name="X" type="float"/> <param name="Y" type="float"/> <param name="Z" type="float"/> </accessor> </technique_common> </source> - <source id="BlackNWhite2-UV0"> - <float_array id="BlackNWhite2-UV0-array" count="8"> -2.000000 0.000000 -0.000000 1.000000 -0.000000 0.000000 -2.000000 1.851760 -</float_array> - <technique_common> - <accessor source="#BlackNWhite2-UV0-array" count="4" stride="2"> - <param name="S" type="float"/> - <param name="T" type="float"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite2-UV1"> - <float_array id="BlackNWhite2-UV1-array" count="8"> -1.000000 0.046115 -0.000000 0.546115 -0.000000 0.046115 -1.000000 0.971995 -</float_array> + <source id="simple_SKP__Material2-UV0"> + <float_array id="simple_SKP__Material2-UV0-array" count="20">-2 0 0 0 0 1.851807 -2 1.851807 0 2.565674 0 0.39209 2 0.39209 2 2.565674 -2 2 0 2 </float_array> <technique_common> - <accessor source="#BlackNWhite2-UV1-array" count="4" stride="2"> + <accessor source="#simple_SKP__Material2-UV0-array" count="10" stride="2"> <param name="S" type="float"/> <param name="T" type="float"/> </accessor> </technique_common> </source> - <source id="BlackNWhite2-VERTEX_COLOR0"> - <float_array id="BlackNWhite2-VERTEX_COLOR0-array" count="24"> -0.000000 0.000000 0.000000 1.000000 -1.000000 1.000000 1.000000 1.000000 -1.000000 1.000000 1.000000 1.000000 -1.000000 1.000000 1.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -0.000000 0.000000 0.000000 1.000000 -</float_array> - <technique_common> - <accessor source="#BlackNWhite2-VERTEX_COLOR0-array" count="6" stride="4"> - <param name="R" type="double"/> - <param name="G" type="double"/> - <param name="B" type="double"/> - <param name="A" type="double"/> - </accessor> - </technique_common> - </source> - <vertices id="BlackNWhite2-VERTEX"> - <input semantic="POSITION" source="#BlackNWhite2-POSITION"/> + <vertices id="simple_SKP__Material2-VERTEX"> + <input semantic="POSITION" source="#simple_SKP__Material2-POSITION"/> </vertices> - <triangles count="2" material="Material1"> - <input semantic="VERTEX" offset="0" source="#BlackNWhite2-VERTEX"/> - <input semantic="NORMAL" offset="1" source="#BlackNWhite2-Normal0"/> - <input semantic="TEXCOORD" offset="2" set="0" source="#BlackNWhite2-UV0"/> - <input semantic="COLOR" offset="3" set="0" source="#BlackNWhite2-VERTEX_COLOR0"/> - <input semantic="TEXCOORD" offset="4" set="1" source="#BlackNWhite2-UV1"/> - <p> 0 0 0 0 0 1 1 1 1 1 2 2 2 2 2 1 3 1 3 1 0 4 0 4 0 3 5 3 5 3</p> + <triangles material="Material2" count="6"> + <input semantic="VERTEX" offset="0" source="#simple_SKP__Material2-VERTEX"/> + <input semantic="NORMAL" offset="1" source="#simple_SKP__Material2-NORMAL0"/> + <input semantic="TEXCOORD" offset="2" source="#simple_SKP__Material2-UV0" set="0"/> + <p>0 0 0 2 0 1 4 0 2 0 0 0 4 0 2 5 0 3 6 2 6 5 3 7 4 1 4 6 2 6 4 1 4 7 2 5 0 4 8 3 4 0 1 4 1 0 4 8 1 4 1 2 4 9</p> </triangles> </mesh> </geometry> </library_geometries> <library_controllers> - <controller id="BlackNWhite1Controller"> - <skin source="#BlackNWhite1-lib"> - <bind_shape_matrix>1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 -</bind_shape_matrix> - <source id="BlackNWhite1Controller-Joints"> - <Name_array id="BlackNWhite1Controller-Joints-array" count="1"> - simple001_BNW</Name_array> + <controller id="simple_SKP__Wax_02-controller"> + <skin source="#simple_SKP__Wax_02-lib"> + <bind_shape_matrix>1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</bind_shape_matrix> + <source id="simple_SKP__Wax_02-controller-joints"> + <Name_array id="simple_SKP__Wax_02-controller-joints-array" count="1">FBXASC051ds_simple</Name_array> <technique_common> - <accessor source="#BlackNWhite1Controller-Joints-array" count="1"> + <accessor source="#simple_SKP__Wax_02-controller-joints-array" count="1"> <param type="name"/> </accessor> </technique_common> </source> - <source id="BlackNWhite1Controller-Matrices"> - <float_array id="BlackNWhite1Controller-Matrices-array" count="16"> - --0.030064 -0.999548 -0.000000 2157.175428 0.000000 -0.000000 1.000000 -1324.162259 -0.999548 0.030064 0.000000 -64.882972 0.000000 0.000000 0.000000 1.000000</float_array> + <source id="simple_SKP__Wax_02-controller-matrices"> + <float_array id="simple_SKP__Wax_02-controller-matrices-array" count="16">1 0 0 -0 -0 1 0 0 0 -0 1 0 0 0 0 1</float_array> <technique_common> - <accessor source="#BlackNWhite1Controller-Matrices-array" count="1" stride="16"> + <accessor source="#simple_SKP__Wax_02-controller-matrices-array" count="1" stride="16"> <param type="float4x4"/> </accessor> </technique_common> </source> - <source id="BlackNWhite1Controller-Weights"> - <float_array id="BlackNWhite1Controller-Weights-array" count="5"> - -1.000000 1.000000 1.000000 1.000000 1.000000</float_array> + <source id="simple_SKP__Wax_02-controller-weights"> + <float_array id="simple_SKP__Wax_02-controller-weights-array" count="1">1</float_array> <technique_common> - <accessor source="#BlackNWhite1Controller-Weights-array" count="5"> + <accessor source="#simple_SKP__Wax_02-controller-weights-array" count="1"> <param type="float"/> </accessor> </technique_common> </source> <joints> - <input semantic="JOINT" source="#BlackNWhite1Controller-Joints"/> - <input semantic="INV_BIND_MATRIX" source="#BlackNWhite1Controller-Matrices"/> + <input semantic="JOINT" source="#simple_SKP__Wax_02-controller-joints"/> + <input semantic="INV_BIND_MATRIX" source="#simple_SKP__Wax_02-controller-matrices"/> </joints> <vertex_weights count="4"> - <input semantic="JOINT" offset="0" source="#BlackNWhite1Controller-Joints"/> - <input semantic="WEIGHT" offset="1" source="#BlackNWhite1Controller-Weights"/> + <input semantic="JOINT" offset="0" source="#simple_SKP__Wax_02-controller-joints"/> + <input semantic="WEIGHT" offset="1" source="#simple_SKP__Wax_02-controller-weights"/> <vcount>1 1 1 1</vcount> - <v>0 1 0 2 0 3 0 4</v> + <v>0 0 0 0 0 0 0 0</v> </vertex_weights> </skin> </controller> - <controller id="GreenCloudController"> - <skin source="#GreenCloud-lib"> - <bind_shape_matrix>1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 -</bind_shape_matrix> - <source id="GreenCloudController-Joints"> - <Name_array id="GreenCloudController-Joints-array" count="3"> - simple002_Green simple simple011</Name_array> + <controller id="simple_SKP__Material1-controller"> + <skin source="#simple_SKP__Material1-lib"> + <bind_shape_matrix>1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</bind_shape_matrix> + <source id="simple_SKP__Material1-controller-joints"> + <Name_array id="simple_SKP__Material1-controller-joints-array" count="4">FBXASC051ds_simple Dummy002 Dummy001 Dummy003</Name_array> <technique_common> - <accessor source="#GreenCloudController-Joints-array" count="3"> + <accessor source="#simple_SKP__Material1-controller-joints-array" count="4"> <param type="name"/> </accessor> </technique_common> </source> - <source id="GreenCloudController-Matrices"> - <float_array id="GreenCloudController-Matrices-array" count="48"> - -1.000000 0.000000 0.000000 -2314.532227 -0.000000 1.000000 0.000000 -1036.097168 0.000000 -0.000000 1.000000 0.000045 0.000000 0.000000 0.000000 1.000000 -1.000000 0.000000 0.000000 -0.000000 -0.000000 1.000000 0.000000 -0.000000 0.000000 -0.000000 1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 --0.030064 0.888602 0.457693 -233.174179 -0.000000 0.457900 -0.889004 -2203.056697 -0.999548 -0.026727 -0.013766 4047.772023 0.000000 0.000000 0.000000 1.000000</float_array> + <source id="simple_SKP__Material1-controller-matrices"> + <float_array id="simple_SKP__Material1-controller-matrices-array" count="64">1 0 0 -0 -0 1 0 0 0 -0 1 0 0 0 0 1 0.808652 0.588287 0 -1894.685303 -0 0 -1 -2248.627441 -0.588287 0.808652 0 -1996.730591 0 0 0 1 1 0 0 -3420.69043 0 0.938329 -0.345745 -1544.227905 0 0.345745 0.938329 2539.585205 0 0 0 1 0.949183 0.314724 -0 -4792.002441 -0.171837 0.518246 -0.837791 -4190.138672 -0.263673 0.795217 0.545992 220.114975 0 0 0 1</float_array> <technique_common> - <accessor source="#GreenCloudController-Matrices-array" count="3" stride="16"> + <accessor source="#simple_SKP__Material1-controller-matrices-array" count="4" stride="16"> <param type="float4x4"/> </accessor> </technique_common> </source> - <source id="GreenCloudController-Weights"> - <float_array id="GreenCloudController-Weights-array" count="10"> - -1.000000 0.562500 0.187500 0.250000 1.000000 0.143020 0.047673 0.809306 0.750000 0.250000</float_array> + <source id="simple_SKP__Material1-controller-weights"> + <float_array id="simple_SKP__Material1-controller-weights-array" count="10">1 0.75 0.25 0.75 0.25 1 1 1 1 1</float_array> <technique_common> - <accessor source="#GreenCloudController-Weights-array" count="10"> + <accessor source="#simple_SKP__Material1-controller-weights-array" count="10"> <param type="float"/> </accessor> </technique_common> </source> <joints> - <input semantic="JOINT" source="#GreenCloudController-Joints"/> - <input semantic="INV_BIND_MATRIX" source="#GreenCloudController-Matrices"/> + <input semantic="JOINT" source="#simple_SKP__Material1-controller-joints"/> + <input semantic="INV_BIND_MATRIX" source="#simple_SKP__Material1-controller-matrices"/> </joints> - <vertex_weights count="4"> - <input semantic="JOINT" offset="0" source="#GreenCloudController-Joints"/> - <input semantic="WEIGHT" offset="1" source="#GreenCloudController-Weights"/> - <vcount>3 1 3 2</vcount> - <v>0 1 1 2 2 3 1 4 0 5 1 6 2 7 0 8 1 9</v> + <vertex_weights count="8"> + <input semantic="JOINT" offset="0" source="#simple_SKP__Material1-controller-joints"/> + <input semantic="WEIGHT" offset="1" source="#simple_SKP__Material1-controller-weights"/> + <vcount>1 2 2 1 1 1 1 1</vcount> + <v>0 0 0 1 1 2 0 3 1 4 0 5 2 6 3 7 0 8 0 9</v> </vertex_weights> </skin> </controller> - <controller id="YellowController"> - <skin source="#Yellow-lib"> - <bind_shape_matrix>1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 -</bind_shape_matrix> - <source id="YellowController-Joints"> - <Name_array id="YellowController-Joints-array" count="1"> - simple</Name_array> + <controller id="simple_SKP__Material2-controller"> + <skin source="#simple_SKP__Material2-lib"> + <bind_shape_matrix>1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</bind_shape_matrix> + <source id="simple_SKP__Material2-controller-joints"> + <Name_array id="simple_SKP__Material2-controller-joints-array" count="1">FBXASC051ds_simple</Name_array> <technique_common> - <accessor source="#YellowController-Joints-array" count="1"> + <accessor source="#simple_SKP__Material2-controller-joints-array" count="1"> <param type="name"/> </accessor> </technique_common> </source> - <source id="YellowController-Matrices"> - <float_array id="YellowController-Matrices-array" count="16"> - -1.000000 0.000000 0.000000 -0.000000 -0.000000 -0.000000 1.000000 -0.000000 0.000000 -1.000000 -0.000000 -0.000000 0.000000 0.000000 0.000000 1.000000</float_array> + <source id="simple_SKP__Material2-controller-matrices"> + <float_array id="simple_SKP__Material2-controller-matrices-array" count="16">1 0 0 -0 -0 1 0 0 0 -0 1 0 0 0 0 1</float_array> <technique_common> - <accessor source="#YellowController-Matrices-array" count="1" stride="16"> + <accessor source="#simple_SKP__Material2-controller-matrices-array" count="1" stride="16"> <param type="float4x4"/> </accessor> </technique_common> </source> - <source id="YellowController-Weights"> - <float_array id="YellowController-Weights-array" count="13"> - -1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000</float_array> + <source id="simple_SKP__Material2-controller-weights"> + <float_array id="simple_SKP__Material2-controller-weights-array" count="1">1</float_array> <technique_common> - <accessor source="#YellowController-Weights-array" count="13"> + <accessor source="#simple_SKP__Material2-controller-weights-array" count="1"> <param type="float"/> </accessor> </technique_common> </source> <joints> - <input semantic="JOINT" source="#YellowController-Joints"/> - <input semantic="INV_BIND_MATRIX" source="#YellowController-Matrices"/> + <input semantic="JOINT" source="#simple_SKP__Material2-controller-joints"/> + <input semantic="INV_BIND_MATRIX" source="#simple_SKP__Material2-controller-matrices"/> </joints> - <vertex_weights count="12"> - <input semantic="JOINT" offset="0" source="#YellowController-Joints"/> - <input semantic="WEIGHT" offset="1" source="#YellowController-Weights"/> - <vcount>1 1 1 1 1 1 1 1 1 1 1 1</vcount> - <v>0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12</v> - </vertex_weights> - </skin> - </controller> - <controller id="BlackNWhite2Controller"> - <skin source="#BlackNWhite2-lib"> - <bind_shape_matrix>1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 -0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 -</bind_shape_matrix> - <source id="BlackNWhite2Controller-Joints"> - <Name_array id="BlackNWhite2Controller-Joints-array" count="1"> - simple011</Name_array> - <technique_common> - <accessor source="#BlackNWhite2Controller-Joints-array" count="1"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite2Controller-Matrices"> - <float_array id="BlackNWhite2Controller-Matrices-array" count="16"> - --0.030064 -0.457693 0.888602 -233.173198 0.000000 0.889004 0.457900 -2203.056398 -0.999548 0.013766 -0.026727 4047.771078 0.000000 0.000000 0.000000 1.000000</float_array> - <technique_common> - <accessor source="#BlackNWhite2Controller-Matrices-array" count="1" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite2Controller-Weights"> - <float_array id="BlackNWhite2Controller-Weights-array" count="5"> - -1.000000 1.000000 1.000000 1.000000 1.000000</float_array> - <technique_common> - <accessor source="#BlackNWhite2Controller-Weights-array" count="5"> - <param type="float"/> - </accessor> - </technique_common> - </source> - <joints> - <input semantic="JOINT" source="#BlackNWhite2Controller-Joints"/> - <input semantic="INV_BIND_MATRIX" source="#BlackNWhite2Controller-Matrices"/> - </joints> - <vertex_weights count="4"> - <input semantic="JOINT" offset="0" source="#BlackNWhite2Controller-Joints"/> - <input semantic="WEIGHT" offset="1" source="#BlackNWhite2Controller-Weights"/> - <vcount>1 1 1 1</vcount> - <v>0 1 0 2 0 3 0 4</v> + <vertex_weights count="8"> + <input semantic="JOINT" offset="0" source="#simple_SKP__Material2-controller-joints"/> + <input semantic="WEIGHT" offset="1" source="#simple_SKP__Material2-controller-weights"/> + <vcount>1 1 1 1 1 1 1 1</vcount> + <v>0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0</v> </vertex_weights> </skin> </controller> </library_controllers> - <library_animations> - <animation id="BlackNWhite1-anim" name="BlackNWhite1"> - <animation> - <source id="BlackNWhite1-Matrix-animation-input"> - <float_array id="BlackNWhite1-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#BlackNWhite1-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite1-Matrix-animation-output-transform"> - <float_array id="BlackNWhite1-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#BlackNWhite1-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite1-Interpolations"> - <Name_array id="BlackNWhite1-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#BlackNWhite1-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="BlackNWhite1-Matrix-animation-transform"> - <input semantic="INPUT" source="#BlackNWhite1-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#BlackNWhite1-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#BlackNWhite1-Interpolations"/> - </sampler> - <channel source="#BlackNWhite1-Matrix-animation-transform" target="BlackNWhite1/matrix"/> - </animation> - </animation> - <animation id="simple-anim" name="simple"> - <animation> - <source id="simple-Matrix-animation-input"> - <float_array id="simple-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="simple-Matrix-animation-output-transform"> - <float_array id="simple-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="simple-Interpolations"> - <Name_array id="simple-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#simple-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="simple-Matrix-animation-transform"> - <input semantic="INPUT" source="#simple-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#simple-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#simple-Interpolations"/> - </sampler> - <channel source="#simple-Matrix-animation-transform" target="simple/matrix"/> - </animation> - </animation> - <animation id="simple001_BNW-anim" name="simple001_BNW"> - <animation> - <source id="simple001_BNW-Matrix-animation-input"> - <float_array id="simple001_BNW-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple001_BNW-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="simple001_BNW-Matrix-animation-output-transform"> - <float_array id="simple001_BNW-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple001_BNW-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="simple001_BNW-Interpolations"> - <Name_array id="simple001_BNW-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#simple001_BNW-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="simple001_BNW-Matrix-animation-transform"> - <input semantic="INPUT" source="#simple001_BNW-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#simple001_BNW-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#simple001_BNW-Interpolations"/> - </sampler> - <channel source="#simple001_BNW-Matrix-animation-transform" target="simple001_BNW/matrix"/> - </animation> - </animation> - <animation id="simple011-anim" name="simple011"> - <animation> - <source id="simple011-Matrix-animation-input"> - <float_array id="simple011-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple011-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="simple011-Matrix-animation-output-transform"> - <float_array id="simple011-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple011-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="simple011-Interpolations"> - <Name_array id="simple011-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#simple011-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="simple011-Matrix-animation-transform"> - <input semantic="INPUT" source="#simple011-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#simple011-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#simple011-Interpolations"/> - </sampler> - <channel source="#simple011-Matrix-animation-transform" target="simple011/matrix"/> - </animation> - </animation> - <animation id="simple002_Green-anim" name="simple002_Green"> - <animation> - <source id="simple002_Green-Matrix-animation-input"> - <float_array id="simple002_Green-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple002_Green-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="simple002_Green-Matrix-animation-output-transform"> - <float_array id="simple002_Green-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#simple002_Green-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="simple002_Green-Interpolations"> - <Name_array id="simple002_Green-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#simple002_Green-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="simple002_Green-Matrix-animation-transform"> - <input semantic="INPUT" source="#simple002_Green-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#simple002_Green-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#simple002_Green-Interpolations"/> - </sampler> - <channel source="#simple002_Green-Matrix-animation-transform" target="simple002_Green/matrix"/> - </animation> - </animation> - <animation id="GreenCloud-anim" name="GreenCloud"> - <animation> - <source id="GreenCloud-Matrix-animation-input"> - <float_array id="GreenCloud-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#GreenCloud-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="GreenCloud-Matrix-animation-output-transform"> - <float_array id="GreenCloud-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#GreenCloud-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="GreenCloud-Interpolations"> - <Name_array id="GreenCloud-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#GreenCloud-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="GreenCloud-Matrix-animation-transform"> - <input semantic="INPUT" source="#GreenCloud-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#GreenCloud-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#GreenCloud-Interpolations"/> - </sampler> - <channel source="#GreenCloud-Matrix-animation-transform" target="GreenCloud/matrix"/> - </animation> - </animation> - <animation id="Yellow-anim" name="Yellow"> - <animation> - <source id="Yellow-Matrix-animation-input"> - <float_array id="Yellow-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#Yellow-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="Yellow-Matrix-animation-output-transform"> - <float_array id="Yellow-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#Yellow-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="Yellow-Interpolations"> - <Name_array id="Yellow-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#Yellow-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="Yellow-Matrix-animation-transform"> - <input semantic="INPUT" source="#Yellow-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#Yellow-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#Yellow-Interpolations"/> - </sampler> - <channel source="#Yellow-Matrix-animation-transform" target="Yellow/matrix"/> - </animation> - </animation> - <animation id="BlackNWhite2-anim" name="BlackNWhite2"> - <animation> - <source id="BlackNWhite2-Matrix-animation-input"> - <float_array id="BlackNWhite2-Matrix-animation-input-array" count="0"> -</float_array> - <technique_common> - <accessor source="#BlackNWhite2-Matrix-animation-input-array" count="0"> - <param name="TIME" type="float"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite2-Matrix-animation-output-transform"> - <float_array id="BlackNWhite2-Matrix-animation-output-transform-array" count="0"> -</float_array> - <technique_common> - <accessor source="#BlackNWhite2-Matrix-animation-output-transform-array" count="0" stride="16"> - <param type="float4x4"/> - </accessor> - </technique_common> - </source> - <source id="BlackNWhite2-Interpolations"> - <Name_array id="BlackNWhite2-Interpolations-array" count="0"> -</Name_array> - <technique_common> - <accessor source="#BlackNWhite2-Interpolations-array" count="0"> - <param type="name"/> - </accessor> - </technique_common> - </source> - <sampler id="BlackNWhite2-Matrix-animation-transform"> - <input semantic="INPUT" source="#BlackNWhite2-Matrix-animation-input"/> - <input semantic="OUTPUT" source="#BlackNWhite2-Matrix-animation-output-transform"/> - <input semantic="INTERPOLATION" source="#BlackNWhite2-Interpolations"/> - </sampler> - <channel source="#BlackNWhite2-Matrix-animation-transform" target="BlackNWhite2/matrix"/> - </animation> - </animation> - </library_animations> <library_visual_scenes> - <visual_scene id="simple_multi_bone_multi_bind" name="simple_multi_bone_multi_bind"> - <node name="BlackNWhite1" id="BlackNWhite1" sid="BlackNWhite1"> - <instance_controller url="#BlackNWhite1Controller"> - <bind_material> - <technique_common> - <instance_material symbol="Material1" target="#Material1"/> - </technique_common> - </bind_material> - </instance_controller> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> - </node> - <node name="simple" id="simple" sid="simple" type="JOINT"> - <matrix sid="matrix">1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000 0.000000 0.000000 0.000000 0.000000 1.000000</matrix> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> - <node name="simple001_BNW" id="simple001_BNW" sid="simple001_BNW" type="JOINT"> - <matrix sid="matrix">-0.030064 0.000000 -0.999548 0.000000 0.000000 1.000000 0.000000 1324.162231 0.999548 0.000000 -0.030064 -2158.150879 0.000000 0.000000 0.000000 1.000000</matrix> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> - <node name="simple011" id="simple011" sid="simple011" type="JOINT"> - <matrix sid="matrix">0.458390 -0.888602 0.016290 240.479248 0.888602 0.457900 -0.026727 0.000122 0.016290 0.026727 0.999510 -4047.991943 0.000000 0.000000 0.000000 1.000000</matrix> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> + <visual_scene id="simple_multi_bone_multi_bind-scene" name="simple_multi_bone_multi_bind"> + <node id="FBXASC051ds_simple" name="FBXASC051ds_simple" type="JOINT" sid="FBXASC051ds_simple"> + <matrix sid="matrix">1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1</matrix> + <node id="Dummy001" name="Dummy001" type="JOINT" sid="Dummy001"> + <matrix sid="matrix">1 0 0 3420.69043 0 0.93833 0.34574 570.945679 0 -0.34574 0.93833 -2916.874023 0 0 0 1</matrix> + <node id="Dummy003" name="Dummy003" type="JOINT" sid="Dummy003"> + <matrix sid="matrix">0.94918 -0.17184 -0.26367 465.814697 0.29532 0.77595 0.5574 2999.553711 0.10881 -0.60694 0.78726 344.561768 0 0 0 1</matrix> </node> </node> - <node name="simple002_Green" id="simple002_Green" sid="simple002_Green" type="JOINT"> - <matrix sid="matrix">1.000000 0.000000 0.000000 2314.532227 0.000000 1.000000 0.000000 1036.097168 0.000000 0.000000 1.000000 -0.000045 0.000000 0.000000 0.000000 1.000000</matrix> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> + <node id="Dummy002" name="Dummy002" type="JOINT" sid="Dummy002"> + <matrix sid="matrix">0.80865 -0 -0.58829 357.490479 0.58829 0 0.80865 2729.279297 0 -1 0 -2248.627441 0 0 0 1</matrix> </node> </node> - <node name="GreenCloud" id="GreenCloud" sid="GreenCloud"> - <instance_controller url="#GreenCloudController"> + <node id="simple_SKP__Wax_02" name="simple_SKP__Wax_02" sid="simple_SKP__Wax_02"> + <instance_controller url="#simple_SKP__Wax_02-controller"> <bind_material> <technique_common> <instance_material symbol="Wax_02" target="#Wax_02"/> </technique_common> </bind_material> </instance_controller> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> </node> - <node name="Yellow" id="Yellow" sid="Yellow"> - <instance_controller url="#YellowController"> + <node id="simple_SKP__Material1" name="simple_SKP__Material1" sid="simple_SKP__Material1"> + <instance_controller url="#simple_SKP__Material1-controller"> <bind_material> <technique_common> - <instance_material symbol="Material2" target="#Material2"/> + <instance_material symbol="Material1" target="#Material1"/> </technique_common> </bind_material> </instance_controller> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> </node> - <node name="BlackNWhite2" id="BlackNWhite2" sid="BlackNWhite2"> - <instance_controller url="#BlackNWhite2Controller"> + <node id="simple_SKP__Material2" name="simple_SKP__Material2" sid="simple_SKP__Material2"> + <instance_controller url="#simple_SKP__Material2-controller"> <bind_material> <technique_common> - <instance_material symbol="Material1" target="#Material1"/> + <instance_material symbol="Material2" target="#Material2"/> </technique_common> </bind_material> </instance_controller> - <extra> - <technique profile="FCOLLADA"> - <visibility>1.000000</visibility> - </technique> - </extra> </node> - <extra> - <technique profile="MAX3D"> - <frame_rate>30.000000</frame_rate> - </technique> - <technique profile="FCOLLADA"> - <start_time>0.000000</start_time> - <end_time>3.333333</end_time> - </technique> - </extra> </visual_scene> </library_visual_scenes> <scene> - <instance_visual_scene url="#simple_multi_bone_multi_bind"/> + <instance_visual_scene url="#simple_multi_bone_multi_bind-scene"/> </scene> </COLLADA> diff --git a/tests/converters/test_convert_dae.py b/tests/converters/test_convert_dae.py index 66058e8..e0fbde5 100644 --- a/tests/converters/test_convert_dae.py +++ b/tests/converters/test_convert_dae.py @@ -1,8 +1,8 @@ import os from abmatt.brres import Brres -from abmatt.command import load_preset_file from abmatt.converters.convert_dae import DaeConverter +from abmatt.converters.dae import Dae from tests.lib import AbmattTest, CheckPositions @@ -27,7 +27,7 @@ def test_convert_with_json(self): dae_file = self._get_test_fname('beginner.dae') converter = DaeConverter(Brres(self._get_tmp('.brres'), read_file=False), dae_file) converter.load_model() - self._test_mats_equal(converter.brres.models[0].materials, brres.models[0].materials) + self._test_mats_equal(converter.brres.models[0].materials, brres.models[0].materials, sort=True) def test_convert_multi_material_geometry(self): """Tests converting dae file that has multiple materials associated with geometry""" @@ -100,7 +100,49 @@ def test_convert_cow(self): mdl0 = converter.mdl0 # converter.brres.save(overwrite=True) # Ensure that the bones are correct - CheckPositions.bones_equal(original.bones, mdl0.bones, 0.0001) + self.assertTrue(CheckPositions.bones_equal(original.bones, mdl0.bones, 0.0001)) + + def test_patch_rigged_not_implemented(self): + converter = DaeConverter(self._get_brres('kuribo.brres'), + self._get_test_fname('simple_multi_bone_single_bind.dae'), + flags=DaeConverter.PATCH, mdl0='kuribo') + with self.assertRaises(RuntimeError): + converter.load_model() + with self.assertRaises(RuntimeError): + DaeConverter(self._get_brres('simple.brres'), self._get_test_fname('simple_multi_bone_multi_bind.dae'), + flags=DaeConverter.PATCH, mdl0='3ds_simple').load_model() + + def test_patch_adds_polys(self): + converter = DaeConverter(self._get_brres('castleflower1.brres'), + self._get_test_fname('simple_multi_bone_single_bind.dae'), + flags=DaeConverter.PATCH, mdl0='castleflower1').convert() + # converter.brres.save(self._get_tmp('.brres'), overwrite=True) + expected = ['polygon0', 'polygon1', 'BlackNWhite1', 'BlackNWhite2', 'GreenCloud', 'Yellow'] + actual = [x.name for x in converter.mdl0.objects] + self.assertEqual(expected, actual) + + def test_patch_replaces_polys(self): + original = self._get_brres('simple.brres') + mdl0 = original.models[0] + replace = mdl0.objects[0] + DaeConverter(original, + self._get_test_fname('3ds_simple.DAE'), + flags=DaeConverter.PATCH, + include=[replace.name], + mdl0=mdl0).convert() + new = [x for x in mdl0.objects if x.name == replace.name][0] + self.assertIsNot(replace, new) + + def test_load_excludes(self): + converter = DaeConverter(self._get_tmp('.brres'), self._get_test_fname('3ds_simple.DAE'), + exclude=('simple_SKP__Wax_02', 'simple_SKP__Material2')).convert() + self.assertEqual(['simple_SKP__Material1'], [x.name for x in converter.mdl0.objects]) + + def test_load_older_version(self): + # This is just to test that it can convert, not that they convert equal + converter = DaeConverter(self._get_brres('old_mario_gc_hayasi.brres'), self._get_tmp('.dae'), + encode=False).convert() + converter = DaeConverter(Brres(self._get_tmp('.brres'), read_file=False), converter.mdl_file).convert() # endregion load_model # ------------------------------------------------------------------ @@ -165,11 +207,15 @@ def test_save_and_load_uv_mtx(self): poly = converter.mdl0.objects[0] expected = [False, True, True] expected.extend([False] * 5) - for i in range(8): - self.assertEqual(expected[i], poly.has_uv_matrix(i)) + self.assertEqual(expected, [poly.has_uv_matrix(i) for i in range(8)]) def test_save_multi_influence_per_face_index(self): - DaeConverter(self._get_brres('koopaFigure.brres'), self._get_tmp('.dae')).save_model() + converter = DaeConverter(self._get_brres('koopaFigure.brres'), self._get_tmp('.dae')) + converter.save_model() + original = converter.mdl0 + new = DaeConverter(self._get_tmp('.brres'), converter.mdl_file).load_model() + self.assertTrue(CheckPositions.positions_equal(original.vertices, new.vertices, rtol=0.1, atol=0.01)) + self.assertTrue(CheckPositions.bones_equal(original.bones, new.bones)) def test_save_and_load_polygons_bound_to_single_material(self): converter = DaeConverter(self._get_brres('castleflower1.brres'), self._get_tmp('.dae')) @@ -180,4 +226,11 @@ def test_save_and_load_polygons_bound_to_single_material(self): self.assertTrue(CheckPositions.bones_equal([x.linked_bone for x in original.objects], [x.linked_bone for x in new.objects])) + def test_save_exclude(self): + converter = DaeConverter(self._get_brres('simple.brres'), self._get_tmp('.dae'), + encode=False, + exclude=['simple_SKP__Wax_02', 'simple_SKP__Material1']).convert() + geometry = Dae.get_all_geometries(Dae(converter.mdl_file).get_scene()) + self.assertEqual(['simple_SKP__Material2'], [x.name for x in geometry]) + # endregion save_model diff --git a/tests/converters/test_convert_obj.py b/tests/converters/test_convert_obj.py index 74aa048..1220a56 100644 --- a/tests/converters/test_convert_obj.py +++ b/tests/converters/test_convert_obj.py @@ -1,5 +1,5 @@ from abmatt.converters.convert_obj import ObjConverter -from tests.lib import AbmattTest +from tests.lib import AbmattTest, CheckPositions class TestConvertObj(AbmattTest): @@ -16,3 +16,21 @@ def test_load_map_model(self): for poly in converter.mdl0.objects: self.assertEqual(map_bone, poly.linked_bone) self.assertEqual(map_bone, poly.visible_bone) + + def test_load_patch(self): + original = self._get_brres('simple.brres') + replace = original.models[0].objects[0] + converter = ObjConverter(original, + self._get_test_fname('3ds_simple.obj'), + flags=ObjConverter.PATCH, + include=[replace.name], + ).convert() + item = [x for x in converter.mdl0.objects if x.name == replace.name][0] + self.assertIsNot(replace, item) + + def test_save_load_eq(self): + original = self._get_brres('beginner_course.brres') + converter = ObjConverter(original, self._get_tmp('.obj'), + encode=False).convert() + encoder = ObjConverter(self._get_tmp('.brres'), converter.mdl_file).convert() + self.assertTrue(CheckPositions.positions_equal(original.models[0].vertices, encoder.mdl0.vertices)) diff --git a/tests/lib.py b/tests/lib.py index b6b6d87..8d70b73 100644 --- a/tests/lib.py +++ b/tests/lib.py @@ -43,7 +43,7 @@ def _get_test_fname(filename): return os.path.join(AbmattTest.base_path, 'test_files', filename) @staticmethod - def _get_tmp(extension, remove_if_exists=True): + def _get_tmp(extension='.brres', remove_if_exists=True): if not extension.startswith('.'): extension = '.' + extension f = os.path.join(AbmattTest.base_path, 'test_files', 'tmp' + extension) @@ -53,15 +53,20 @@ def _get_tmp(extension, remove_if_exists=True): @staticmethod def _get_brres(filename): + if not filename.endswith('.brres'): + filename += '.brres' return Brres(AbmattTest._get_brres_fname(filename)) @staticmethod - def _test_mats_equal(materials, updated): + def _test_mats_equal(materials, updated, sort=False): """A more in depth test for material equality""" err = False if len(materials) != len(updated): print('Lengths different') err = True + if sort: + materials = sorted(materials, key=lambda x: x.name) + updated = sorted(materials, key=lambda x: x.name) for i in range(len(materials)): if materials[i] != updated[i]: err = True @@ -123,6 +128,11 @@ def setUpClass(cls): class CheckPositions: @staticmethod def __pre_process(vertices1, vertices2, group_type): + if vertices1 is None or vertices2 is None: + if vertices1 is not None or vertices2 is not None: + print(f'{vertices1} != {vertices2}') + return vertices1, vertices2, True + return vertices1, vertices2, False if type(vertices1) != list and type(vertices1) != np.array: vertices1 = [vertices1] if type(vertices2) != list and type(vertices2) != np.array: @@ -143,9 +153,35 @@ def __pre_process(vertices1, vertices2, group_type): return v1, v2, mismatched_len + @staticmethod + def polygons_equal(poly1, poly2, rtol=-1.e-2, atol=1.e-3): + p1, p2, err = CheckPositions.__pre_process(poly1, poly2, 'polygons') + if not err: + for i in range(len(p1)): + t1 = p1[i] + t2 = p2[i] + n1 = t1.get_normal_group() + n2 = t2.get_normal_group() + if not (CheckPositions.bones_equal(t1.get_linked_bone(), t2.get_linked_bone(), rtol, atol) and + CheckPositions.positions_equal(t1.get_vertex_group(), t2.get_vertex_group(), rtol, atol, + group_name='vertices') and + (not n1 or not n2 or CheckPositions.positions_equal(n1, n2, + group_name='normals')) and + all(CheckPositions.positions_equal(t1.get_uv_group(x), t2.get_uv_group(x), rtol, atol, + group_name='uvs') + for x in range(8)) + and CheckPositions.colors_equal(t1.get_color_group(), t2.get_color_group())): + print(f'polygons {t1.name} != {t2.name}') + err = True + return not err + + + @staticmethod def colors_equal(colr1, colr2, rtol=1.e-2, atol=1.e-3): c1, c2, err = CheckPositions.__pre_process(colr1, colr2, 'colors') + if not c1 or not c2: + return not err if not err: for i in range(len(c1)): colr1 = c1[i] @@ -160,6 +196,8 @@ def colors_equal(colr1, colr2, rtol=1.e-2, atol=1.e-3): print('Color {} length does not match count!'.format(colr1.name)) if len(decoded_c2) != colr2.count: print('Color {} length does not match count!'.format(colr2.name)) + decoded_c2 = sorted(decoded_c2, key=lambda x: tuple(x)) + decoded_c1 = sorted(decoded_c1, key=lambda x: tuple(x)) current_err = False for j in range(min(len(decoded_c2), len(decoded_c1))): if not np.isclose(decoded_c1[j], decoded_c2[j], rtol, atol).all(): @@ -171,16 +209,12 @@ def colors_equal(colr1, colr2, rtol=1.e-2, atol=1.e-3): @staticmethod def model_equal(mdl1, mdl2, rtol=1.e-2, atol=1.e-3): - return CheckPositions.bones_equal(mdl1.bones, mdl2.bones, rtol, atol) \ - and CheckPositions.positions_equal(mdl1.vertices, mdl2.vertices, rtol, atol) \ - and CheckPositions.positions_equal(mdl1.uvs, mdl2.uvs, rtol, atol) \ - and CheckPositions.positions_equal(mdl1.normals, mdl2.normals, rtol, atol) \ - and CheckPositions.colors_equal(mdl1.colors, mdl2.colors, rtol, atol) + return CheckPositions.polygons_equal(mdl1.objects, mdl2.objects, rtol, atol) @staticmethod def bones_equal(bone_list1, bone_list2, rtol=1.e-2, atol=1.e-3): bone_list1, bone_list2, err = CheckPositions.__pre_process(bone_list1, bone_list2, 'bones') - if not err: + if not err and bone_list1 is not None: for i in range(len(bone_list1)): b1 = bone_list1[i] b2 = bone_list2[i] @@ -202,28 +236,49 @@ def bones_equal(bone_list1, bone_list2, rtol=1.e-2, atol=1.e-3): return not err @staticmethod - def positions_equal(vertices1, vertices2, rtol=1.e-2, atol=1.e-3): + def pos_eq_helper(points1, points2, v1_name, v2_name, rtol, atol, err_points): + if points1.shape != points2.shape: + print('points {} and {} have different shapes {} and {}'.format(v1_name, + v2_name, + points1.shape, + points2.shape)) + return False + if not len(points1): + return True + current_err = False + for i in range(len(points1)): + if not np.isclose(points1[i], points2[i], rtol, atol).all(): + err_points.append(i) + current_err = True + return not current_err + + @staticmethod + def positions_equal(vertices1, vertices2, rtol=1.e-2, atol=1.e-3, group_name='points'): """Checks if the vertices are the same""" - vertices1, vertices2, err = CheckPositions.__pre_process(vertices1, vertices2, 'points') + vertices1, vertices2, err = CheckPositions.__pre_process(vertices1, vertices2, group_name) + if not vertices1 or not vertices2: + return not err if not err: # Check each vertex group for k in range(len(vertices1)): - points1 = np.array(sorted(vertices1[k].get_decoded(), key=lambda x: tuple(np.around(x, 2)))) - points2 = np.array(sorted(vertices2[k].get_decoded(), key=lambda x: tuple(np.around(x, 2)))) - if points1.shape != points2.shape: - print('points {} and {} have different shapes {} and {}'.format(vertices1[k].name, - vertices2[k].name, - points1.shape, - points2.shape)) - err = True - continue - if not len(points1): - continue + v1_decoded = vertices1[k].get_decoded() + v2_decoded = vertices2[k].get_decoded() + points1 = np.array(sorted(v1_decoded, key=lambda x: tuple(np.around(x, 2)))) + points2 = np.array(sorted(v2_decoded, key=lambda x: tuple(np.around(x, 2)))) + errs = [] current_err = False - for i in range(len(points1)): - if not np.isclose(points1[i], points2[i], rtol, atol).all(): - print('Points mismatch at {} Expected {}, found {} '.format(i, points1[i], points2[i])) - current_err = err = True + if not CheckPositions.pos_eq_helper(points1, points2, vertices1[k].name, vertices2[k].name, + rtol, atol, errs): + if errs: + p1 = np.array(sorted([points1[z] for z in errs], key=lambda x: tuple(x))) + p2 = np.array(sorted([points2[z] for z in errs], key=lambda x: tuple(x))) + if CheckPositions.pos_eq_helper(p1, p2, + vertices1[k].name, vertices2[k].name, rtol, atol, []): + continue + for x in errs: + print('Points mismatch at {} Expected {}, found {} '.format(x, points1[x], points2[x])) + + err = current_err = True if current_err: print('{} and {} mismatch'.format(vertices1[k].name, vertices2[k].name)) return not err diff --git a/tests/test_brres.py b/tests/test_brres.py index d4a0a60..bb790cf 100644 --- a/tests/test_brres.py +++ b/tests/test_brres.py @@ -2,7 +2,9 @@ import sys import unittest +from abmatt import load_config from abmatt.brres import Brres +from abmatt.command import Command from tests.lib import AbmattTest, node_eq @@ -61,6 +63,12 @@ def test_save_flagb2(self): # has shp0 def test_save_with_unknown_files(self): # various txt files self.assertTrue(self._test_save_eq(self._get_brres('kuribo_with_txt.brres'))) + def test_older_brres_version(self): + load_config.turn_off_fixes() + self.assertTrue(self._test_save_eq(self._get_brres('old_mario_gc_hayasi'))) + load_config.load_config(loudness=0) + self.assertTrue(self._test_save_eq(self._get_brres('old_mario_gc_hayasi'))) + if __name__ == '__main__': unittest.main()