diff --git a/abmatt/brres/lib/decoder.py b/abmatt/brres/lib/decoder.py index f2c76d0..6b69cea 100644 --- a/abmatt/brres/lib/decoder.py +++ b/abmatt/brres/lib/decoder.py @@ -145,12 +145,12 @@ def decode_polygon(polygon, influences=None): influence = influences[linked_bone.weight_id] g_verts.apply_affine_matrix(np.array(linked_bone.get_transform_matrix()), apply=True) influence_collection = InfluenceCollection({0: influence}) - for x in polygon.uv_mtx_indices: - if x >= 0: - AutoFix.warn('{} uv matrices data lost in export.'.format(polygon.name)) - indices = face_point_indices[:, :, x] // 3 - if (indices < 10).any(): - print('Less than 10!') + # for x in polygon.uv_mtx_indices: + # if x >= 0: + # AutoFix.warn('{} uv matrices data lost in export.'.format(polygon.name)) + # indices = face_point_indices[:, :, x] // 3 + # if (indices < 10).any(): + # print('Less than 10!') from abmatt.converters.geometry import Geometry geometry = Geometry(polygon.name, polygon.get_material().name, g_verts, triangles=None, influences=influence_collection, diff --git a/abmatt/build/config.txt b/abmatt/build/config.txt index c81b269..5457b6c 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 = 0.9.7 +version = 0.9.8 run_integration_tests = False run_unit_tests = False diff --git a/abmatt/converters/convert_dae.py b/abmatt/converters/convert_dae.py index e0cd3c6..d178829 100644 --- a/abmatt/converters/convert_dae.py +++ b/abmatt/converters/convert_dae.py @@ -35,13 +35,14 @@ def load_model(self, model_name=None): self.__parse_nodes(dae.get_scene(), material_geometry_map, matrix) self.__combine_bones_map() self.__parse_controllers(material_geometry_map) - - self._before_encoding() - self.influences.encode_bone_weights(self.mdl0) for material in material_geometry_map: if material not in material_names: self._encode_material(material.Material(material)) material_names.add(material) + + self._before_encoding() + self.influences.encode_bone_weights(self.mdl0) + for material in material_geometry_map: geometries = material_geometry_map[material] for x in geometries: self.__encode_geometry(x) diff --git a/abmatt/converters/convert_lib.py b/abmatt/converters/convert_lib.py index e6ce096..af346d6 100644 --- a/abmatt/converters/convert_lib.py +++ b/abmatt/converters/convert_lib.py @@ -97,13 +97,17 @@ def _start_loading(self, model_name): return self._init_mdl0(brres_name, os.path.splitext(name)[0], model_name) def _before_encoding(self): + if os.path.exists(self.json_file): + converter = MatsToJsonConverter(self.json_file) + converter.load_into(self.mdl0.materials) + self.json_polygon_encoding = converter.polygons_by_name + else: + self.json_polygon_encoding = None if self.encoder: self.encoder.before_encoding(self) def _end_loading(self): mdl0 = self.mdl0 - if os.path.exists(self.json_file): - MatsToJsonConverter(self.json_file).load_into(mdl0.materials) import_path_map = self.__normalize_image_path_map(self.import_textures_map) self._import_images(import_path_map) mdl0.rebuild_header() @@ -262,8 +266,20 @@ def _encode_geometry(self, geometry): geometry.normals = None if self.flags & self.NO_UVS: geometry.texcoords = [] + has_uv_mtx = priority = None + json_data = self.json_polygon_encoding.get(geometry.name) if self.json_polygon_encoding else None + if json_data: + has_uv_mtx = json_data.get('has_uv_matrix') + priority = json_data.get('draw_priority') + 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 encoder = self.encoder.get_encoder(geometry) if self.encoder else None - return geometry.encode(self.mdl0, encoder=encoder) + return geometry.encode(self.mdl0, encoder=encoder, + priority=priority, + has_uv_mtx=has_uv_mtx) def convert(self): if self.encode: diff --git a/abmatt/converters/convert_mats_to_json.py b/abmatt/converters/convert_mats_to_json.py index e0d905c..6eceeae 100644 --- a/abmatt/converters/convert_mats_to_json.py +++ b/abmatt/converters/convert_mats_to_json.py @@ -17,6 +17,7 @@ def __init__(self, filename): """ self.filename = filename self.materials_by_name = {} + self.polygons_by_name = {} def export(self, materials): """ Exports the materials to a JSON file @@ -67,8 +68,15 @@ def __load_material(self, material, data): if pat0_data is not None: material.add_pat0() self.__load_pat0(material.pat0, pat0_data) + poly_data = data.get('polygons') + if poly_data: + self.__load_polygons(poly_data) return material + def __load_polygons(self, poly_data): + for x in poly_data: + self.polygons_by_name[x] = poly_data[x] + def __load_srt0(self, srt0, data): self.__load_settings(srt0, data.get('settings')) d = data.get('texture_animations') @@ -135,13 +143,26 @@ def __load_settings(item, settings): def __get_material_str(self, material): x = {'settings': self.__get_settings(material), 'layers': self.__get_items_str(material.layers), - 'shader': self.__get_shader_str(material.shader)} + 'shader': self.__get_shader_str(material.shader), + 'polygons': self.__get_polygons_str(material.polygons)} if material.srt0 is not None: x['srt0'] = self.__get_srt0_str(material.srt0) if material.pat0 is not None: x['pat0'] = self.__get_pat0_str(material.pat0) return x + def __get_polygons_str(self, polygons): + d = {} + for poly in polygons: + d[poly.name] = self.__get_polygon_str(poly) + return d + + def __get_polygon_str(self, poly): + return { + 'has_uv_matrix': [x >= 0 for x in poly.uv_mtx_indices], + 'draw_priority': poly.priority + } + def __get_shader_str(self, shader): return {'settings': self.__get_settings(shader), 'stages': self.__get_items_str(shader.stages)} diff --git a/abmatt/converters/convert_obj.py b/abmatt/converters/convert_obj.py index b216ee1..bc55862 100644 --- a/abmatt/converters/convert_obj.py +++ b/abmatt/converters/convert_obj.py @@ -35,13 +35,14 @@ def load_model(self, model_name=None): bone = mdl.add_bone(mdl.name) obj = Obj(self.mdl_file) material_geometry_map = self.__collect_geometries(obj.geometries, bone) - - self._before_encoding() for material in material_geometry_map: try: self.__encode_material(obj.materials[material]) except KeyError: self._encode_material(Material(material)) + + 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() diff --git a/abmatt/converters/dae.py b/abmatt/converters/dae.py index d6c9acb..131d2fd 100644 --- a/abmatt/converters/dae.py +++ b/abmatt/converters/dae.py @@ -585,7 +585,7 @@ def __initialize_libraries(self, initial_name): def __initialize_assets(self, root): asset = XMLNode('asset', parent=root) contributor = XMLNode('contributor', parent=asset) - authoring_tool = XMLNode('authoring_tool', 'ABMATT COLLADA exporter v0.9.7', parent=contributor) + authoring_tool = XMLNode('authoring_tool', 'ABMATT COLLADA exporter v0.9.8', 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 5dd58a4..571ae87 100644 --- a/abmatt/converters/geometry.py +++ b/abmatt/converters/geometry.py @@ -29,6 +29,8 @@ def __init__(self, name, material_name, vertices, texcoords=None, normals=None, self.influences = influences self.triangles = triangles self.linked_bone = linked_bone + self.has_uv_mtx = None + self.priority = 0 def __eq__(self, other): return other is not None and type(other) == Geometry and self.name == other.name and \ @@ -80,7 +82,13 @@ def ipp(self): self.index += 1 return j - def encode(self, mdl, visible_bone=None, encoder=None, use_default_colors_if_none_found=True): + def encode(self, mdl, visible_bone=None, encoder=None, + use_default_colors_if_none_found=True, + priority=None, has_uv_mtx=None): + if priority is not None: + self.priority = priority + if has_uv_mtx is not None: + self.has_uv_mtx = has_uv_mtx if not visible_bone: if not mdl.bones: mdl.add_bone(mdl.name) @@ -95,6 +103,7 @@ def encode(self, mdl, visible_bone=None, encoder=None, use_default_colors_if_non self.fmt_str = '>' if self.__encode_influences(p, self.influences, mdl, visible_bone): p.weight_index = self.ipp() + self.__encode_tex_matrices(p, self.has_uv_mtx) if self.__encode_vertices(p, self.vertices, mdl): p.vertex_index = self.ipp() if self.__encode_normals(p, self.normals, mdl): @@ -115,13 +124,20 @@ def encode(self, mdl, visible_bone=None, encoder=None, use_default_colors_if_non p.encode_str = self.fmt_str mdl.objects.append(p) material = mdl.get_material_by_name(self.material_name) - mdl.add_definition(material, p, visible_bone) + mdl.add_definition(material, p, visible_bone, self.priority) if self.colors: material.enable_vertex_color() if encoder: encoder.after_encode(p) return p + def __encode_tex_matrices(self, poly, has_uv_mtx): + if has_uv_mtx: + for i in range(8): + if has_uv_mtx[i]: + poly.uv_mtx_indices[i] = self.ipp() + self.fmt_str += 'B' + @staticmethod def __encode_load_matrices_helper(data, indices, xf_address, matrix_len, cmd): mtx_len_shifted = matrix_len - 1 << 12 @@ -139,9 +155,9 @@ def __encode_load_matrices(indices): Geometry.__encode_load_matrices_helper(data, indices, 1024, 9, 0x28) return data - @staticmethod - def __remap_inf_group(group, tris, matrices): + def __remap_inf_group(self, group, tris, matrices): remapper = {} + uv_mtx_count = sum(self.has_uv_mtx) if self.has_uv_mtx is not None else 0 matrices = list(matrices) for i in range(len(matrices)): remapper[matrices[i]] = i * 3 @@ -149,12 +165,16 @@ def __remap_inf_group(group, tris, matrices): for strip in group: arr = np.array(strip) for item in arr: + if uv_mtx_count: + item[1:1+uv_mtx_count] = (item[0] + 10) * 3 item[0] = remapper[item[0]] n_group.append(arr) n_tris = [] for tri in tris: arr = np.array(tri.vertices) for item in arr: + if uv_mtx_count: + item[1:1 + uv_mtx_count] = (item[0] + 10) * 3 item[0] = remapper[item[0]] n_tris.append(arr) return n_group, n_tris @@ -275,6 +295,10 @@ def __construct_tris(self, polygon, weighted=False): pos_indices = np.array([[remapper[y].influence_id for y in tri] for tri in self.vertices.face_indices]) polygon.bone_table = [i for i in range(np.max(pos_indices) + 1)] tris.append(pos_indices) + if self.has_uv_mtx is not None: + for x in self.has_uv_mtx: + if x: + tris.append(pos_indices) # this just serves as a placeholder tris.append(self.vertices.face_indices) if self.normals: tris.append(self.normals.face_indices) diff --git a/abmatt/converters/obj.py b/abmatt/converters/obj.py index 48097e8..2d45d51 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 v0.9.7' + s = '# Wavefront MTL exported with ABMATT v0.9.8' 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 v0.9.7\n\nmtllib ' + self.mtllib + '\n\n' + s = '# Wavefront OBJ exported with ABMATT v0.9.8\n\nmtllib ' + self.mtllib + '\n\n' vertex_index = 1 normal_index = 1 normal_offset = -1 diff --git a/abmatt/dist/install-ubu.txt b/abmatt/dist/install-ubu.txt index af0e6f0..923daf9 100644 --- a/abmatt/dist/install-ubu.txt +++ b/abmatt/dist/install-ubu.txt @@ -1,6 +1,6 @@ ==================================================================================== ANOOB'S BRRES MATERIAL TOOL -Version: 0.9.7 +Version: 0.9.8 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 5057241..a5f5e3f 100644 --- a/abmatt/dist/install-win.txt +++ b/abmatt/dist/install-win.txt @@ -1,6 +1,6 @@ =================================================================================================== ANOOB'S BRRES MATERIAL TOOL -Version 0.9.7 +Version 0.9.8 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 7aa16e8..53f7d6e 100644 --- a/abmatt/dist/make_installer.nsi +++ b/abmatt/dist/make_installer.nsi @@ -1,4 +1,4 @@ -!define VERSION "0.9.7" +!define VERSION "0.9.8" !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 0f029b0..cc1a174 100644 --- a/abmatt/load_config.py +++ b/abmatt/load_config.py @@ -108,7 +108,7 @@ def load_config(app_dir, loudness=None, autofix_level=None): return conf -VERSION = '0.9.7' +VERSION = '0.9.8' USAGE = "USAGE: abmatt [command_line][--interactive -f -b -d --overwrite]" diff --git a/debug/analyze.py b/debug/analyze.py index a496c2e..927332e 100644 --- a/debug/analyze.py +++ b/debug/analyze.py @@ -1,8 +1,10 @@ +import fnmatch import os import sys from abmatt.autofix import AutoFix from abmatt.brres import Brres +from abmatt.converters.convert_dae import DaeConverter def analyze_material(mat): @@ -20,43 +22,43 @@ def analyze_material(mat): # print('Use prev!') # if s.ind_unmodify_lod: # print('Unmodify lod!') - # DOES NOT CHANGE - # if stage.map_id != stage.coord_id: - # print(f'{mat.name} shader has map id that does not match coord id') - - # ONLY 1 INSTANCE OF CHANGING - # if stage.texture_swap_sel: - # print(f'{mat.name} texture swap sel enabled!') - # if stage.raster_swap_sel: - # print(f'{mat.name} raster swap sel enabled!') - - # CHANGES - # if stage.bias: - # print(f'{mat.name} bias enabled!') - # if stage.oper: - # print(f'{mat.name} operation not add.') - # if stage.clamp != True: - # print(f'{mat.name} clamp not enabled') - - # THESE CHANGE - # if layer.scn0_light_ref != -1: - # print(f'{layer.name} scn0 light ref not -1 in {layer.parent.getBrres().name}!') - # if layer.scn0_camera_ref != -1: - # print(f'{layer.name} scn0 camera ref not -1 in {layer.parent.getBrres().name}!') - # if layer.clamp_bias: - # print(f'{layer.name} clamp enabled!') - # if layer.texel_interpolate: - # print(f'{layer.name} interpolate enabled!') - # if layer.magfilter != 1: - # print(f'{layer.name} magfilter {layer.magfilter}') - - # THESE DON"T CHANGE - # if layer.emboss_source != 5: - # print(f'{layer.name} emboss source {layer.emboss_source}!') - # if layer.type: - # print(f'{layer.name} type {layer.type}!') - # if layer.emboss_light: - # print(f'{layer.name} emboss light {layer.emboss_light}!') + # DOES NOT CHANGE + # if stage.map_id != stage.coord_id: + # print(f'{mat.name} shader has map id that does not match coord id') + + # ONLY 1 INSTANCE OF CHANGING + # if stage.texture_swap_sel: + # print(f'{mat.name} texture swap sel enabled!') + # if stage.raster_swap_sel: + # print(f'{mat.name} raster swap sel enabled!') + + # CHANGES + # if stage.bias: + # print(f'{mat.name} bias enabled!') + # if stage.oper: + # print(f'{mat.name} operation not add.') + # if stage.clamp != True: + # print(f'{mat.name} clamp not enabled') + + # THESE CHANGE + # if layer.scn0_light_ref != -1: + # print(f'{layer.name} scn0 light ref not -1 in {layer.parent.getBrres().name}!') + # if layer.scn0_camera_ref != -1: + # print(f'{layer.name} scn0 camera ref not -1 in {layer.parent.getBrres().name}!') + # if layer.clamp_bias: + # print(f'{layer.name} clamp enabled!') + # if layer.texel_interpolate: + # print(f'{layer.name} interpolate enabled!') + # if layer.magfilter != 1: + # print(f'{layer.name} magfilter {layer.magfilter}') + + # THESE DON"T CHANGE + # if layer.emboss_source != 5: + # print(f'{layer.name} emboss source {layer.emboss_source}!') + # if layer.type: + # print(f'{layer.name} type {layer.type}!') + # if layer.emboss_light: + # print(f'{layer.name} emboss light {layer.emboss_light}!') # changes # if not mat.depth_test: @@ -91,11 +93,13 @@ def analyze_material(mat): def perform_analysis(brres): print('Analyzing {}'.format(brres.name)) + export = False for model in brres.models: - pass + if len(model.colors) > 0 and model.colors[0].count > 1: + export = True # for mat in model.materials: - # if len(mat.polygons) > 1: - # print('Mat {} used more than once by {}'.format(mat.name, [x.name for x in mat.polygons])) + # if len(mat.polygons) > 1: + # print('Mat {} used more than once by {}'.format(mat.name, [x.name for x in mat.polygons])) # for poly in model.objects: # # has_uv_mtx = False @@ -105,13 +109,14 @@ def perform_analysis(brres): # break # if has_uv_mtx: # decode_polygon(poly, decode_mdl0_influences(model)) - # DaeConverter(brres, os.path.join(os.getcwd(), 'tmp', 'tmp.dae'), encode=False).convert() + if export: + DaeConverter(brres, os.path.join(os.getcwd(), 'tmp', 'tmp.dae'), encode=False).convert() # for model in brres.models: # for material in model.materials: # analyze_material(material) -def gather_brres_files(root, brres_files): +def gather_brres_files(root, brres_files, filter=None): """ Recursively gathers brres files in root :param root: path @@ -122,14 +127,16 @@ def gather_brres_files(root, brres_files): if file.startswith('.'): continue if os.path.isdir(path): - gather_brres_files(path, brres_files) + gather_brres_files(path, brres_files, filter) elif file.endswith('.brres'): - brres_files.append(path) + if filter is None or fnmatch.fnmatch(file, filter): + brres_files.append(path) return brres_files if __name__ == '__main__': args = sys.argv[1:] + filter = 'water_course.d\\map_model.brres' if not len(args): root = os.getcwd() else: @@ -138,6 +145,5 @@ def gather_brres_files(root, brres_files): print('Invalid root path') sys.exit(1) files = [] - for x in gather_brres_files(root, files): + for x in gather_brres_files(root, files, filter): perform_analysis(Brres(x)) - AutoFix.quit() diff --git a/setup.py b/setup.py index 7b66023..1d32d21 100755 --- a/setup.py +++ b/setup.py @@ -28,7 +28,7 @@ # calling the setup function setup(name='abmatt', - version='0.9.7', + version='0.9.8', entry_points={ 'console_scripts': [ 'abmatt = abmatt.__main__:main' diff --git a/tests/converters/test_convert_dae.py b/tests/converters/test_convert_dae.py index 0cabc93..e4c5d8c 100644 --- a/tests/converters/test_convert_dae.py +++ b/tests/converters/test_convert_dae.py @@ -1,3 +1,5 @@ +import os + from abmatt.brres import Brres from abmatt.converters.convert_dae import DaeConverter from tests.lib import AbmattTest, CheckPositions @@ -80,11 +82,14 @@ def test_convert_multi_bone_single_bind(self): def test_kuribo_loads(self): b = self._get_brres('kuribo.brres') model = b.models[1] - converter = DaeConverter(self._get_tmp('.brres'), self._get_test_fname('kuribo.dae')) + converter = DaeConverter(b, self._get_test_fname('kuribo.dae')) converter.load_model() - # converter.brres.save(overwrite=True) + # converter.brres.save('../../tmp/kuribo.brres', overwrite=True) self.assertTrue(CheckPositions().positions_equal(model.vertices, converter.mdl0.vertices, rtol=1e-1, atol=1e-2)) self.assertTrue(CheckPositions().bones_equal(model.bones, converter.mdl0.bones)) + poly = converter.mdl0.objects[0] + for i in range(1, 3): + self.assertTrue(poly.has_uv_matrix(i)) def test_convert_cow(self): original = self._get_brres('cow.brres').models[1] @@ -119,7 +124,7 @@ def test_save_multi_bone_as_single_bone(self): # load it to test against original converter = DaeConverter(self._get_tmp('.brres'), fname) converter.load_model() - converter.brres.save(overwrite=True) + # converter.brres.save(overwrite=True) original = self._get_brres('simple.brres').models[0] new = converter.mdl0 self.assertTrue(CheckPositions().bones_equal(original.bones, new.bones, 0.01, @@ -149,4 +154,16 @@ def test_save_and_load_multi_bind_equal(self): converter.load_model() self.assertTrue(CheckPositions().model_equal(original, converter.mdl0)) + def test_save_and_load_uv_mtx(self): + fname = self._get_tmp('.dae') + converter = DaeConverter(self._get_brres('kuribo.brres'), fname) + converter.save_model('kuribo') + converter = DaeConverter(self._get_tmp('.brres'), fname) + converter.load_model() + # converter.brres.save(overwrite=True) + 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)) # endregion save_model diff --git a/tests/test_brres.py b/tests/test_brres.py index 0c161d5..9259b6f 100644 --- a/tests/test_brres.py +++ b/tests/test_brres.py @@ -6,7 +6,7 @@ from tests.lib import AbmattTest -class MyTestCase(AbmattTest): +class TestBrresLoadsCorrectly(AbmattTest): @classmethod def setUpClass(cls): cls.brres = cls._get_brres('beginner_course.brres')