diff --git a/__init__.py b/__init__.py index 3f3ee11..90ace2a 100644 --- a/__init__.py +++ b/__init__.py @@ -17,440 +17,454 @@ from . import addon_updater_ops # info about add on bl_info = { - "name": "Fast64", - "version": (1, 0, 0), - "author": "kurethedead", - "location": "3DView", - "description": "Plugin for exporting F3D display lists and other game data related to Super Mario 64.", - "category": "Import-Export", - "blender": (2, 82, 0), - } + "name": "Fast64", + "version": (1, 0, 0), + "author": "kurethedead", + "location": "3DView", + "description": "Plugin for exporting F3D display lists and other game data related to Super Mario 64.", + "category": "Import-Export", + "blender": (2, 82, 0), +} gameEditorEnum = ( - ("SM64", "SM64", "Super Mario 64"), - ("OOT", "OOT", "Ocarina Of Time"), + ("SM64", "SM64", "Super Mario 64"), + ("OOT", "OOT", "Ocarina Of Time"), ) + class ArmatureApplyWithMesh(bpy.types.Operator): - # set bl_ properties - bl_description = 'Applies current pose as default pose. Useful for ' + \ - "rigging an armature that is not in T/A pose. Note that when using " +\ - " with an SM64 armature, you must revert to the default pose after " +\ - "skinning." - bl_idname = 'object.armature_apply_w_mesh' - bl_label = "Apply As Rest Pose" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_description = ( + "Applies current pose as default pose. Useful for " + + "rigging an armature that is not in T/A pose. Note that when using " + + " with an SM64 armature, you must revert to the default pose after " + + "skinning." + ) + bl_idname = "object.armature_apply_w_mesh" + bl_label = "Apply As Rest Pose" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - try: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + try: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") - if len(context.selected_objects) == 0: - raise PluginError("Armature not selected.") - elif type(context.selected_objects[0].data) is not\ - bpy.types.Armature: - raise PluginError("Armature not selected.") - - armatureObj = context.selected_objects[0] - for child in armatureObj.children: - if type(child.data) is not bpy.types.Mesh: - continue - armatureModifier = None - for modifier in child.modifiers: - if isinstance(modifier, bpy.types.ArmatureModifier): - armatureModifier = modifier - if armatureModifier is None: - continue - print(armatureModifier.name) - bpy.ops.object.select_all(action = "DESELECT") - context.view_layer.objects.active = child - bpy.ops.object.modifier_copy(modifier=armatureModifier.name) - print(len(child.modifiers)) - attemptModifierApply(armatureModifier) + if len(context.selected_objects) == 0: + raise PluginError("Armature not selected.") + elif type(context.selected_objects[0].data) is not bpy.types.Armature: + raise PluginError("Armature not selected.") - bpy.ops.object.select_all(action = "DESELECT") - context.view_layer.objects.active = armatureObj - bpy.ops.object.mode_set(mode = "POSE") - bpy.ops.pose.armature_apply() - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") - except Exception as e: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") - raisePluginError(self, e) - return {"CANCELLED"} + armatureObj = context.selected_objects[0] + for child in armatureObj.children: + if type(child.data) is not bpy.types.Mesh: + continue + armatureModifier = None + for modifier in child.modifiers: + if isinstance(modifier, bpy.types.ArmatureModifier): + armatureModifier = modifier + if armatureModifier is None: + continue + print(armatureModifier.name) + bpy.ops.object.select_all(action="DESELECT") + context.view_layer.objects.active = child + bpy.ops.object.modifier_copy(modifier=armatureModifier.name) + print(len(child.modifiers)) + attemptModifierApply(armatureModifier) + + bpy.ops.object.select_all(action="DESELECT") + context.view_layer.objects.active = armatureObj + bpy.ops.object.mode_set(mode="POSE") + bpy.ops.pose.armature_apply() + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + except Exception as e: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + raisePluginError(self, e) + return {"CANCELLED"} + + self.report({"INFO"}, "Applied armature with mesh.") + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Applied armature with mesh.') - return {'FINISHED'} # must return a set class AddBoneGroups(bpy.types.Operator): - # set bl_ properties - bl_description = 'Add bone groups respresenting other node types in ' +\ - 'SM64 geolayouts (ex. Shadow, Switch, Function).' - bl_idname = 'object.add_bone_groups' - bl_label = "Add Bone Groups" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_description = ( + "Add bone groups respresenting other node types in " + "SM64 geolayouts (ex. Shadow, Switch, Function)." + ) + bl_idname = "object.add_bone_groups" + bl_label = "Add Bone Groups" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - try: - if context.mode != 'OBJECT' and context.mode != 'POSE': - raise PluginError("Operator can only be used in object or pose mode.") - elif context.mode == 'POSE': - bpy.ops.object.mode_set(mode = "OBJECT") + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + try: + if context.mode != "OBJECT" and context.mode != "POSE": + raise PluginError("Operator can only be used in object or pose mode.") + elif context.mode == "POSE": + bpy.ops.object.mode_set(mode="OBJECT") - if len(context.selected_objects) == 0: - raise PluginError("Armature not selected.") - elif type(context.selected_objects[0].data) is not\ - bpy.types.Armature: - raise PluginError("Armature not selected.") - - armatureObj = context.selected_objects[0] - createBoneGroups(armatureObj) - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + if len(context.selected_objects) == 0: + raise PluginError("Armature not selected.") + elif type(context.selected_objects[0].data) is not bpy.types.Armature: + raise PluginError("Armature not selected.") + + armatureObj = context.selected_objects[0] + createBoneGroups(armatureObj) + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + + self.report({"INFO"}, "Created bone groups.") + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Created bone groups.') - return {'FINISHED'} # must return a set class CreateMetarig(bpy.types.Operator): - # set bl_ properties - bl_description = 'SM64 imported armatures are usually not good for ' + \ - 'rigging. There are often intermediate bones between deform bones ' + \ - 'and they don\'t usually point to their children. This operator ' +\ - 'creates a metarig on armature layer 4 useful for IK.' - bl_idname = 'object.create_metarig' - bl_label = "Create Animatable Metarig" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_description = ( + "SM64 imported armatures are usually not good for " + + "rigging. There are often intermediate bones between deform bones " + + "and they don't usually point to their children. This operator " + + "creates a metarig on armature layer 4 useful for IK." + ) + bl_idname = "object.create_metarig" + bl_label = "Create Animatable Metarig" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - try: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + try: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") - if len(context.selected_objects) == 0: - raise PluginError("Armature not selected.") - elif type(context.selected_objects[0].data) is not\ - bpy.types.Armature: - raise PluginError("Armature not selected.") - - armatureObj = context.selected_objects[0] - generateMetarig(armatureObj) - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + if len(context.selected_objects) == 0: + raise PluginError("Armature not selected.") + elif type(context.selected_objects[0].data) is not bpy.types.Armature: + raise PluginError("Armature not selected.") + + armatureObj = context.selected_objects[0] + generateMetarig(armatureObj) + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + + self.report({"INFO"}, "Created metarig.") + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Created metarig.') - return {'FINISHED'} # must return a set class SM64_AddWaterBox(AddWaterBox): - bl_idname = 'object.sm64_add_water_box' + bl_idname = "object.sm64_add_water_box" + + scale: bpy.props.FloatProperty(default=10) + preset: bpy.props.StringProperty(default="Shaded Solid") + matName: bpy.props.StringProperty(default="sm64_water_mat") + + def setEmptyType(self, emptyObj): + emptyObj.sm64_obj_type = "Water Box" - scale : bpy.props.FloatProperty(default = 10) - preset : bpy.props.StringProperty(default = "Shaded Solid") - matName : bpy.props.StringProperty(default = "sm64_water_mat") - - def setEmptyType(self, emptyObj): - emptyObj.sm64_obj_type = "Water Box" class SM64_ArmatureToolsPanel(SM64_Panel): - bl_idname = "SM64_PT_armature_tools" - bl_label = "SM64 Tools" + bl_idname = "SM64_PT_armature_tools" + bl_label = "SM64 Tools" + + # called every frame + def draw(self, context): + col = self.layout.column() + col.operator(ArmatureApplyWithMesh.bl_idname) + col.operator(AddBoneGroups.bl_idname) + col.operator(CreateMetarig.bl_idname) + col.operator(SM64_AddWaterBox.bl_idname) + - # called every frame - def draw(self, context): - col = self.layout.column() - col.operator(ArmatureApplyWithMesh.bl_idname) - col.operator(AddBoneGroups.bl_idname) - col.operator(CreateMetarig.bl_idname) - col.operator(SM64_AddWaterBox.bl_idname) - class F3D_GlobalSettingsPanel(bpy.types.Panel): - bl_idname = "F3D_PT_global_settings" - bl_label = "F3D Global Settings" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'Fast64' + bl_idname = "F3D_PT_global_settings" + bl_label = "F3D Global Settings" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Fast64" - @classmethod - def poll(cls, context): - return True + @classmethod + def poll(cls, context): + return True + + # called every frame + def draw(self, context): + col = self.layout.column() + col.scale_y = 1.1 # extra padding + prop_split(col, context.scene, "f3d_type", "F3D Microcode") + col.prop(context.scene, "isHWv1") + col.prop(context.scene, "saveTextures") + col.prop(context.scene, "f3d_simple", text="Simple Material UI") + col.prop(context.scene, "generateF3DNodeGraph", text="Generate F3D Node Graph For Materials") + col.prop(context.scene, "decomp_compatible", invert_checkbox=True, text="Homebrew Compatibility") + col.prop(context.scene, "ignoreTextureRestrictions") + if context.scene.ignoreTextureRestrictions: + col.box().label(text="Width/height must be < 1024. Must be RGBA32. Must be png format.") - # called every frame - def draw(self, context): - col = self.layout.column() - col.scale_y = 1.1 # extra padding - prop_split(col, context.scene, 'f3d_type', "F3D Microcode") - col.prop(context.scene, 'isHWv1') - col.prop(context.scene, 'saveTextures') - col.prop(context.scene, 'f3d_simple', text = "Simple Material UI") - col.prop(context.scene, 'generateF3DNodeGraph', text = "Generate F3D Node Graph For Materials") - col.prop(context.scene, 'decomp_compatible', invert_checkbox = True, text = 'Homebrew Compatibility') - col.prop(context.scene, 'ignoreTextureRestrictions') - if context.scene.ignoreTextureRestrictions: - col.box().label(text = "Width/height must be < 1024. Must be RGBA32. Must be png format.") class Fast64_GlobalObjectPanel(bpy.types.Panel): - bl_label = "Global Object Inspector" - bl_idname = "OBJECT_PT_OOT_Global_Object_Inspector" - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "object" - bl_options = {'HIDE_HEADER'} + bl_label = "Global Object Inspector" + bl_idname = "OBJECT_PT_OOT_Global_Object_Inspector" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + bl_options = {"HIDE_HEADER"} - @classmethod - def poll(cls, context): - return (context.object is not None and context.object.data is None) + @classmethod + def poll(cls, context): + return context.object is not None and context.object.data is None + + def draw(self, context): + box = self.layout + prop_split(box, context.scene, "gameEditorMode", "Game") - def draw(self, context): - box = self.layout - prop_split(box, context.scene, 'gameEditorMode', "Game") class Fast64_GlobalSettingsPanel(bpy.types.Panel): - bl_idname = "FAST64_PT_global_settings" - bl_label = "Fast64 Global Settings" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'Fast64' + bl_idname = "FAST64_PT_global_settings" + bl_label = "Fast64 Global Settings" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Fast64" - @classmethod - def poll(cls, context): - return True + @classmethod + def poll(cls, context): + return True + + # called every frame + def draw(self, context): + col = self.layout.column() + col.scale_y = 1.1 # extra padding + prop_split(col, context.scene, "gameEditorMode", "Game") + col.prop(context.scene, "exportHiddenGeometry") + col.prop(context.scene, "fullTraceback") + prop_split(col, context.scene.fast64.settings, "anim_range_choice", "Anim Range") - # called every frame - def draw(self, context): - col = self.layout.column() - col.scale_y = 1.1 # extra padding - prop_split(col, context.scene, 'gameEditorMode', "Game") - col.prop(context.scene, 'exportHiddenGeometry') - col.prop(context.scene, 'fullTraceback') - prop_split(col, context.scene.fast64.settings, 'anim_range_choice', 'Anim Range') class Fast64_GlobalToolsPanel(bpy.types.Panel): - bl_idname = "FAST64_PT_global_tools" - bl_label = "Fast64 Tools" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'Fast64' + bl_idname = "FAST64_PT_global_tools" + bl_label = "Fast64 Tools" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Fast64" - @classmethod - def poll(cls, context): - return True + @classmethod + def poll(cls, context): + return True + + # called every frame + def draw(self, context): + col = self.layout.column() + col.operator(ArmatureApplyWithMesh.bl_idname) + # col.operator(CreateMetarig.bl_idname) + addon_updater_ops.update_notice_box_ui(self, context) - # called every frame - def draw(self, context): - col = self.layout.column() - col.operator(ArmatureApplyWithMesh.bl_idname) - #col.operator(CreateMetarig.bl_idname) - addon_updater_ops.update_notice_box_ui(self, context) class Fast64Settings_Properties(bpy.types.PropertyGroup): - '''Settings affecting exports for all games found in scene.fast64.settings''' - version: bpy.props.IntProperty(name="Fast64Settings_Properties Version", default=0) + """Settings affecting exports for all games found in scene.fast64.settings""" + + version: bpy.props.IntProperty(name="Fast64Settings_Properties Version", default=0) + + anim_range_choice: bpy.props.EnumProperty( + name="Anim Range", + description="What to use to determine what frames of the animation to export", + items=[ + ("action", "Action", "Export all frames from the action", 0), + ( + "scene", + "Playback", + ( + "Export all frames in the scene's animation preview playback range.\n" + "(export frames being played in Blender)" + ), + 1, + ), + ( + "intersect_action_and_scene", + "Smart", + ( + "Intersect Action & Scene\n" + "Export all frames from the action that are also in the scene playback range.\n" + "(export frames being played in Blender that also are part of the action frames)" + ), + 2, + ), + ], + default="intersect_action_and_scene", + ) - anim_range_choice: bpy.props.EnumProperty( - name="Anim Range", - description="What to use to determine what frames of the animation to export", - items=[ - ( - "action", - "Action", - "Export all frames from the action", - 0 - ), - ( - "scene", - "Playback", - ( - "Export all frames in the scene's animation preview playback range.\n" - "(export frames being played in Blender)" - ), - 1, - ), - ( - "intersect_action_and_scene", - "Smart", - ( - "Intersect Action & Scene\n" - "Export all frames from the action that are also in the scene playback range.\n" - "(export frames being played in Blender that also are part of the action frames)" - ), - 2, - ), - ], - default="intersect_action_and_scene", - ) class Fast64_Properties(bpy.types.PropertyGroup): - ''' - Properties in scene.fast64. - All new properties should be children of one of these three property groups. - ''' - sm64: bpy.props.PointerProperty(type=SM64_Properties, name="SM64 Properties") - oot: bpy.props.PointerProperty(type=OOT_Properties, name="OOT Properties") - settings: bpy.props.PointerProperty(type=Fast64Settings_Properties, name="Fast64 Settings") + """ + Properties in scene.fast64. + All new properties should be children of one of these three property groups. + """ + + sm64: bpy.props.PointerProperty(type=SM64_Properties, name="SM64 Properties") + oot: bpy.props.PointerProperty(type=OOT_Properties, name="OOT Properties") + settings: bpy.props.PointerProperty(type=Fast64Settings_Properties, name="Fast64 Settings") + class Fast64_BoneProperties(bpy.types.PropertyGroup): - ''' - Properties in bone.fast64 (bpy.types.Bone) - All new bone properties should be children of this property group. - ''' - sm64: bpy.props.PointerProperty(type=SM64_BoneProperties, name="SM64 Properties") + """ + Properties in bone.fast64 (bpy.types.Bone) + All new bone properties should be children of this property group. + """ + + sm64: bpy.props.PointerProperty(type=SM64_BoneProperties, name="SM64 Properties") + class Fast64_ObjectProperties(bpy.types.PropertyGroup): - ''' - Properties in object.fast64 (bpy.types.Object) - All new object properties should be children of this property group. - ''' - sm64: bpy.props.PointerProperty(type=SM64_ObjectProperties, name="SM64 Object Properties") - oot: bpy.props.PointerProperty(type=OOT_ObjectProperties, name="OOT Object Properties") + """ + Properties in object.fast64 (bpy.types.Object) + All new object properties should be children of this property group. + """ + + sm64: bpy.props.PointerProperty(type=SM64_ObjectProperties, name="SM64 Object Properties") + oot: bpy.props.PointerProperty(type=OOT_ObjectProperties, name="OOT Object Properties") -#def updateGameEditor(scene, context): -# if scene.currentGameEditorMode == 'SM64': -# sm64_panel_unregister() -# elif scene.currentGameEditorMode == 'Z64': -# oot_panel_unregister() -# else: -# raise PluginError("Unhandled game editor mode " + str(scene.currentGameEditorMode)) +# def updateGameEditor(scene, context): +# if scene.currentGameEditorMode == 'SM64': +# sm64_panel_unregister() +# elif scene.currentGameEditorMode == 'Z64': +# oot_panel_unregister() +# else: +# raise PluginError("Unhandled game editor mode " + str(scene.currentGameEditorMode)) # -# if scene.gameEditorMode == 'SM64': -# sm64_panel_register() -# elif scene.gameEditorMode == 'Z64': -# oot_panel_register() -# else: -# raise PluginError("Unhandled game editor mode " + str(scene.gameEditorMode)) +# if scene.gameEditorMode == 'SM64': +# sm64_panel_register() +# elif scene.gameEditorMode == 'Z64': +# oot_panel_register() +# else: +# raise PluginError("Unhandled game editor mode " + str(scene.gameEditorMode)) # -# scene.currentGameEditorMode = scene.gameEditorMode +# scene.currentGameEditorMode = scene.gameEditorMode + class ExampleAddonPreferences(bpy.types.AddonPreferences, addon_updater_ops.AddonUpdaterPreferences): - bl_idname = __package__ + bl_idname = __package__ - def draw(self, context): - addon_updater_ops.update_settings_ui(self, context) + def draw(self, context): + addon_updater_ops.update_settings_ui(self, context) classes = ( - Fast64Settings_Properties, - Fast64_Properties, - Fast64_BoneProperties, - Fast64_ObjectProperties, - - ArmatureApplyWithMesh, - AddBoneGroups, - CreateMetarig, - SM64_AddWaterBox, - - #Fast64_GlobalObjectPanel, - F3D_GlobalSettingsPanel, - Fast64_GlobalSettingsPanel, - SM64_ArmatureToolsPanel, - Fast64_GlobalToolsPanel, + Fast64Settings_Properties, + Fast64_Properties, + Fast64_BoneProperties, + Fast64_ObjectProperties, + ArmatureApplyWithMesh, + AddBoneGroups, + CreateMetarig, + SM64_AddWaterBox, + # Fast64_GlobalObjectPanel, + F3D_GlobalSettingsPanel, + Fast64_GlobalSettingsPanel, + SM64_ArmatureToolsPanel, + Fast64_GlobalToolsPanel, ) + def upgrade_changed_props(): - '''Set scene properties after a scene loads, used for migrating old properties''' - SM64_Properties.upgrade_changed_props() - SM64_ObjectProperties.upgrade_changed_props() + """Set scene properties after a scene loads, used for migrating old properties""" + SM64_Properties.upgrade_changed_props() + SM64_ObjectProperties.upgrade_changed_props() + @bpy.app.handlers.persistent def after_load(_a, _b): - upgrade_changed_props() + upgrade_changed_props() + # called on add-on enabling # register operators and panels here # append menu layout drawing function to an existing window def register(): - if bpy.app.version >= (3, 1, 0): - msg = "\n".join( - ( - "This version of Fast64 does not work properly in Blender 3.1.0 and later Blender versions.", - "Your Blender version is: " + ".".join(str(i) for i in bpy.app.version), - "This is a known issue, the fix is not trivial and is in progress.", - "See the GitHub issue: https://github.com/Fast-64/fast64/issues/85", - "If it has been resolved, update Fast64.", - ) - ) - print(msg) - blender_3_1_0_and_later_unsupported = Exception("\n\n" + msg) - raise blender_3_1_0_and_later_unsupported + if bpy.app.version >= (3, 1, 0): + msg = "\n".join( + ( + "This version of Fast64 does not work properly in Blender 3.1.0 and later Blender versions.", + "Your Blender version is: " + ".".join(str(i) for i in bpy.app.version), + "This is a known issue, the fix is not trivial and is in progress.", + "See the GitHub issue: https://github.com/Fast-64/fast64/issues/85", + "If it has been resolved, update Fast64.", + ) + ) + print(msg) + blender_3_1_0_and_later_unsupported = Exception("\n\n" + msg) + raise blender_3_1_0_and_later_unsupported - # Register addon updater first, - # this way if a broken version fails to register the user can still pick another version. - register_class(ExampleAddonPreferences) - addon_updater_ops.register(bl_info) + # Register addon updater first, + # this way if a broken version fails to register the user can still pick another version. + register_class(ExampleAddonPreferences) + addon_updater_ops.register(bl_info) - mat_register() - render_engine_register() - bsdf_conv_register() - sm64_register(True) - oot_register(True) + mat_register() + render_engine_register() + bsdf_conv_register() + sm64_register(True) + oot_register(True) - for cls in classes: - register_class(cls) + for cls in classes: + register_class(cls) - bsdf_conv_panel_regsiter() - f3d_writer_register() - f3d_parser_register() + bsdf_conv_panel_regsiter() + f3d_writer_register() + f3d_parser_register() - # ROM - - bpy.types.Scene.decomp_compatible = bpy.props.BoolProperty( - name = 'Decomp Compatibility', default = True) - bpy.types.Scene.ignoreTextureRestrictions = bpy.props.BoolProperty( - name = 'Ignore Texture Restrictions (Breaks CI Textures)') - bpy.types.Scene.fullTraceback = \ - bpy.props.BoolProperty(name = 'Show Full Error Traceback', default = False) - bpy.types.Scene.gameEditorMode = bpy.props.EnumProperty( - name = 'Game', default = 'SM64', items = gameEditorEnum) - bpy.types.Scene.saveTextures = bpy.props.BoolProperty( - name = 'Save Textures As PNGs (Breaks CI Textures)') - bpy.types.Scene.generateF3DNodeGraph = bpy.props.BoolProperty(name = "Generate F3D Node Graph", default = True) - bpy.types.Scene.exportHiddenGeometry = bpy.props.BoolProperty(name = "Export Hidden Geometry", default = True) - bpy.types.Scene.blenderF3DScale = bpy.props.FloatProperty(name = "F3D Blender Scale", default = 100) + # ROM - bpy.types.Scene.fast64 = bpy.props.PointerProperty(type=Fast64_Properties, name="Fast64 Properties") - bpy.types.Bone.fast64 = bpy.props.PointerProperty(type=Fast64_BoneProperties, name="Fast64 Bone Properties") - bpy.types.Object.fast64 = bpy.props.PointerProperty(type=Fast64_ObjectProperties, name="Fast64 Object Properties") + bpy.types.Scene.decomp_compatible = bpy.props.BoolProperty(name="Decomp Compatibility", default=True) + bpy.types.Scene.ignoreTextureRestrictions = bpy.props.BoolProperty( + name="Ignore Texture Restrictions (Breaks CI Textures)" + ) + bpy.types.Scene.fullTraceback = bpy.props.BoolProperty(name="Show Full Error Traceback", default=False) + bpy.types.Scene.gameEditorMode = bpy.props.EnumProperty(name="Game", default="SM64", items=gameEditorEnum) + bpy.types.Scene.saveTextures = bpy.props.BoolProperty(name="Save Textures As PNGs (Breaks CI Textures)") + bpy.types.Scene.generateF3DNodeGraph = bpy.props.BoolProperty(name="Generate F3D Node Graph", default=True) + bpy.types.Scene.exportHiddenGeometry = bpy.props.BoolProperty(name="Export Hidden Geometry", default=True) + bpy.types.Scene.blenderF3DScale = bpy.props.FloatProperty(name="F3D Blender Scale", default=100) + + bpy.types.Scene.fast64 = bpy.props.PointerProperty(type=Fast64_Properties, name="Fast64 Properties") + bpy.types.Bone.fast64 = bpy.props.PointerProperty(type=Fast64_BoneProperties, name="Fast64 Bone Properties") + bpy.types.Object.fast64 = bpy.props.PointerProperty(type=Fast64_ObjectProperties, name="Fast64 Object Properties") + + bpy.app.handlers.load_post.append(after_load) - bpy.app.handlers.load_post.append(after_load) # called on add-on disabling def unregister(): - f3d_writer_unregister() - f3d_parser_unregister() - sm64_unregister(True) - oot_unregister(True) - mat_unregister() - bsdf_conv_unregister() - bsdf_conv_panel_unregsiter() - render_engine_unregister() + f3d_writer_unregister() + f3d_parser_unregister() + sm64_unregister(True) + oot_unregister(True) + mat_unregister() + bsdf_conv_unregister() + bsdf_conv_panel_unregsiter() + render_engine_unregister() - del bpy.types.Scene.fullTraceback - del bpy.types.Scene.decomp_compatible - del bpy.types.Scene.ignoreTextureRestrictions - del bpy.types.Scene.saveTextures - del bpy.types.Scene.gameEditorMode - del bpy.types.Scene.generateF3DNodeGraph - del bpy.types.Scene.exportHiddenGeometry - del bpy.types.Scene.blenderF3DScale + del bpy.types.Scene.fullTraceback + del bpy.types.Scene.decomp_compatible + del bpy.types.Scene.ignoreTextureRestrictions + del bpy.types.Scene.saveTextures + del bpy.types.Scene.gameEditorMode + del bpy.types.Scene.generateF3DNodeGraph + del bpy.types.Scene.exportHiddenGeometry + del bpy.types.Scene.blenderF3DScale - del bpy.types.Scene.fast64 - del bpy.types.Bone.fast64 - del bpy.types.Object.fast64 + del bpy.types.Scene.fast64 + del bpy.types.Bone.fast64 + del bpy.types.Object.fast64 - for cls in classes: - unregister_class(cls) - - bpy.app.handlers.load_post.remove(after_load) + for cls in classes: + unregister_class(cls) - addon_updater_ops.unregister() - unregister_class(ExampleAddonPreferences) + bpy.app.handlers.load_post.remove(after_load) + + addon_updater_ops.unregister() + unregister_class(ExampleAddonPreferences) diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 0793203..5884cdd 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -3,1299 +3,1553 @@ import bpy, os, copy, enum from math import ceil from ..utility import * + class ScrollMethod(enum.Enum): - Vertex = 1 - Tile = 2 - Ignore = 3 + Vertex = 1 + Tile = 2 + Ignore = 3 + class DLFormat(enum.Enum): - Static = 1 - Dynamic = 2 + Static = 1 + Dynamic = 2 + class GfxListTag(enum.Enum): - Geometry = 1 - Material = 2 - MaterialRevert = 3 - Draw = 3 + Geometry = 1 + Material = 2 + MaterialRevert = 3 + Draw = 3 + class GfxMatWriteMethod(enum.Enum): - WriteAll = 1 - WriteDifferingAndRevert = 2 + WriteAll = 1 + WriteDifferingAndRevert = 2 + enumTexScroll = [ - ("None", "None", "None"), - ("Linear", "Linear", "Linear"), - ("Sine", "Sine", "Sine"), - ("Noise", "Noise", "Noise"), + ("None", "None", "None"), + ("Linear", "Linear", "Linear"), + ("Sine", "Sine", "Sine"), + ("Noise", "Noise", "Noise"), ] dlTypeEnum = [ - ('STATIC', "Static", "Static"), - ('MATERIAL', 'Dynamic Material', 'Dynamic Material'), - ('PROCEDURAL', 'Procedural', 'Procedural'), + ("STATIC", "Static", "Static"), + ("MATERIAL", "Dynamic Material", "Dynamic Material"), + ("PROCEDURAL", "Procedural", "Procedural"), ] lightIndex = { - 'LIGHT_1' : 1, - 'LIGHT_2' : 2, - 'LIGHT_3' : 3, - 'LIGHT_4' : 4, - 'LIGHT_5' : 5, - 'LIGHT_6' : 6, - 'LIGHT_7' : 7, - 'LIGHT_8' : 8, + "LIGHT_1": 1, + "LIGHT_2": 2, + "LIGHT_3": 3, + "LIGHT_4": 4, + "LIGHT_5": 5, + "LIGHT_6": 6, + "LIGHT_7": 7, + "LIGHT_8": 8, } # tuple of max buffer size, max load count. vertexBufferSize = { - 'F3D' : (16, 16), - 'F3DEX/LX' : (32, 32), - 'F3DLX.Rej' : (64, 32), - 'F3DLP.Rej' : (80, 32), - 'F3DEX2/LX2' : (32, 32), - 'F3DEX2.Rej/LX2.Rej' : (64, 64), + "F3D": (16, 16), + "F3DEX/LX": (32, 32), + "F3DLX.Rej": (64, 32), + "F3DLP.Rej": (80, 32), + "F3DEX2/LX2": (32, 32), + "F3DEX2.Rej/LX2.Rej": (64, 64), } drawLayerRenderMode = { - 0: ('G_RM_ZB_OPA_SURF', 'G_RM_NOOP2'), - 1: ('G_RM_AA_ZB_OPA_SURF', 'G_RM_NOOP2'), - 2: ('G_RM_AA_ZB_OPA_DECAL', 'G_RM_NOOP2'), - 3: ('G_RM_AA_ZB_OPA_INTER', 'G_RM_NOOP2'), - 4: ('G_RM_AA_ZB_TEX_EDGE', 'G_RM_NOOP2'), - 5: ('G_RM_AA_ZB_XLU_SURF', 'G_RM_NOOP2'), - 6: ('G_RM_AA_ZB_XLU_DECAL', 'G_RM_NOOP2'), - 7: ('G_RM_AA_ZB_XLU_INTER', 'G_RM_NOOP2'), + 0: ("G_RM_ZB_OPA_SURF", "G_RM_NOOP2"), + 1: ("G_RM_AA_ZB_OPA_SURF", "G_RM_NOOP2"), + 2: ("G_RM_AA_ZB_OPA_DECAL", "G_RM_NOOP2"), + 3: ("G_RM_AA_ZB_OPA_INTER", "G_RM_NOOP2"), + 4: ("G_RM_AA_ZB_TEX_EDGE", "G_RM_NOOP2"), + 5: ("G_RM_AA_ZB_XLU_SURF", "G_RM_NOOP2"), + 6: ("G_RM_AA_ZB_XLU_DECAL", "G_RM_NOOP2"), + 7: ("G_RM_AA_ZB_XLU_INTER", "G_RM_NOOP2"), } + class F3D: - def __init__(self, F3D_VER, _HW_VERSION_1): - if F3D_VER == 'F3DEX2.Rej/LX2.Rej' or \ - F3D_VER == 'F3DEX2/LX2': - self.F3DEX_GBI = False - self.F3DEX_GBI_2 = True - self.F3DLP_GBI = False - elif F3D_VER == 'F3DLP.Rej' or F3D_VER == 'F3DLX.Rej' or \ - F3D_VER == 'F3DEX/LX': - self.F3DEX_GBI = True - self.F3DEX_GBI_2 = False - self.F3DLP_GBI = True - elif F3D_VER == 'F3D': - self.F3DEX_GBI = False - self.F3DEX_GBI_2 = False - self.F3DLP_GBI = False - else: - raise PluginError("Invalid F3D version " + F3D_VER + ".") - - self.vert_buffer_size = vertexBufferSize[F3D_VER][0] - self.vert_load_size = vertexBufferSize[F3D_VER][1] - - F3DEX_GBI = self.F3DEX_GBI - F3DEX_GBI_2 = self.F3DEX_GBI_2 - F3DLP_GBI = self.F3DLP_GBI - self._HW_VERSION_1 = _HW_VERSION_1 - self.F3D_VER = F3D_VER - #self._LANGUAGE_ASSEMBLY = _LANGUAGE_ASSEMBLY - - if F3DEX_GBI_2: - self.F3DEX_GBI = True - F3DEX_GBI = True - - self.G_NOOP = 0x00 - self.G_RDPHALF_2 = 0xf1 - self.G_SETOTHERMODE_H = 0xe3 - self.G_SETOTHERMODE_L = 0xe2 - self.G_RDPHALF_1 = 0xe1 - self.G_SPNOOP = 0xe0 - self.G_ENDDL = 0xdf - self.G_DL = 0xde - self.G_LOAD_UCODE = 0xdd - self.G_MOVEMEM = 0xdc - self.G_MOVEWORD = 0xdb - self.G_MTX = 0xda - self.G_GEOMETRYMODE = 0xd9 - self.G_POPMTX = 0xd8 - self.G_TEXTURE = 0xd7 - self.G_DMA_IO = 0xd6 - self.G_SPECIAL_1 = 0xd5 - self.G_SPECIAL_2 = 0xd4 - self.G_SPECIAL_3 = 0xd3 - - self.G_VTX = 0x01 - self.G_MODIFYVTX = 0x02 - self.G_CULLDL = 0x03 - self.G_BRANCH_Z = 0x04 - self.G_TRI1 = 0x05 - self.G_TRI2 = 0x06 - self.G_QUAD = 0x07 - self.G_LINE3D = 0x08 - - else: - # DMA commands - self.G_SPNOOP = 0 # handle 0 gracefully - self.G_MTX = 1 - self.G_RESERVED0 = 2 # not implemeted - self.G_MOVEMEM = 3 # move a block of memory (up to 4 words) to dmem - self.G_VTX = 4 - self.G_RESERVED1 = 5 # not implemeted - self.G_DL = 6 - self.G_RESERVED2 = 7 # not implemeted - self.G_RESERVED3 = 8 # not implemeted - self.G_SPRITE2D_BASE = 9 # sprite command - - # IMMEDIATE commands - self.G_IMMFIRST = -65 - self.G_TRI1 = (self.G_IMMFIRST-0) - self.G_CULLDL = (self.G_IMMFIRST-1) - self.G_POPMTX = (self.G_IMMFIRST-2) - self.G_MOVEWORD = (self.G_IMMFIRST-3) - self.G_TEXTURE = (self.G_IMMFIRST-4) - self.G_SETOTHERMODE_H = (self.G_IMMFIRST-5) - self.G_SETOTHERMODE_L = (self.G_IMMFIRST-6) - self.G_ENDDL = (self.G_IMMFIRST-7) - self.G_SETGEOMETRYMODE = (self.G_IMMFIRST-8) - self.G_CLEARGEOMETRYMODE = (self.G_IMMFIRST-9) - self.G_LINE3D = (self.G_IMMFIRST-10) - self.G_RDPHALF_1 = (self.G_IMMFIRST-11) - self.G_RDPHALF_2 = (self.G_IMMFIRST-12) - if F3DEX_GBI or F3DLP_GBI: - self.G_MODIFYVTX = (self.G_IMMFIRST-13) - self.G_TRI2 = (self.G_IMMFIRST-14) - self.G_BRANCH_Z = (self.G_IMMFIRST-15) - self.G_LOAD_UCODE = (self.G_IMMFIRST-16) - else: - self.G_RDPHALF_CONT = (self.G_IMMFIRST-13) - - # We are overloading 2 of the immediate commands - # to keep the byte alignment of dmem the same - - self.G_SPRITE2D_SCALEFLIP = (self.G_IMMFIRST-1) - self.G_SPRITE2D_DRAW = (self.G_IMMFIRST-2) - - # RDP commands - self.G_NOOP = 0xc0 - - # RDP commands - self.G_SETCIMG = 0xff # -1 - self.G_SETZIMG = 0xfe # -2 - self.G_SETTIMG = 0xfd # -3 - self.G_SETCOMBINE = 0xfc # -4 - self.G_SETENVCOLOR = 0xfb # -5 - self.G_SETPRIMCOLOR = 0xfa # -6 - self.G_SETBLENDCOLOR = 0xf9 # -7 - self.G_SETFOGCOLOR = 0xf8 # -8 - self.G_SETFILLCOLOR = 0xf7 # -9 - self.G_FILLRECT = 0xf6 # -10 - self.G_SETTILE = 0xf5 # -11 - self.G_LOADTILE = 0xf4 # -12 - self.G_LOADBLOCK = 0xf3 # -13 - self.G_SETTILESIZE = 0xf2 # -14 - self.G_LOADTLUT = 0xf0 # -16 - self.G_RDPSETOTHERMODE = 0xef # -17 - self.G_SETPRIMDEPTH = 0xee # -18 - self.G_SETSCISSOR = 0xed # -19 - self.G_SETCONVERT = 0xec # -20 - self.G_SETKEYR = 0xeb # -21 - self.G_SETKEYGB = 0xea # -22 - self.G_RDPFULLSYNC = 0xe9 # -23 - self.G_RDPTILESYNC = 0xe8 # -24 - self.G_RDPPIPESYNC = 0xe7 # -25 - self.G_RDPLOADSYNC = 0xe6 # -26 - self.G_TEXRECTFLIP = 0xe5 # -27 - self.G_TEXRECT = 0xe4 # -28 - - self.G_TRI_FILL = 0xc8 # fill triangle: 11001000 - self.G_TRI_SHADE = 0xcc # shade triangle: 11001100 - self.G_TRI_TXTR = 0xca # texture triangle: 11001010 - self.G_TRI_SHADE_TXTR = 0xce # shade, texture triangle: 11001110 - self.G_TRI_FILL_ZBUFF = 0xc9 # fill, zbuff triangle: 11001001 - self.G_TRI_SHADE_ZBUFF = 0xcd # shade, zbuff triangle: 11001101 - self.G_TRI_TXTR_ZBUFF = 0xcb # texture, zbuff triangle: 11001011 - self.G_TRI_SHADE_TXTR_ZBUFF=0xcf # shade, txtr, zbuff trngl: 11001111 - - # masks to build RDP triangle commands - self.G_RDP_TRI_FILL_MASK = 0x08 - self.G_RDP_TRI_SHADE_MASK = 0x04 - self.G_RDP_TRI_TXTR_MASK = 0x02 - self.G_RDP_TRI_ZBUFF_MASK = 0x01 - - self.BOWTIE_VAL = 0 - - # gets added to RDP command, in order to test for addres fixup - self.G_RDP_ADDR_FIXUP = 3 # |RDP cmds| <= this, do addr fixup - # if _LANGUAGE_ASSEMBLY: - self.G_RDP_TEXRECT_CHECK = ((-1*self.G_TEXRECTFLIP)& 0xff) - #endif - - self.G_DMACMDSIZ = 128 - self.G_IMMCMDSIZ = 64 - self.G_RDPCMDSIZ = 64 - - # Coordinate shift values, number of bits of fraction - self.G_TEXTURE_IMAGE_FRAC = 2 - self.G_TEXTURE_SCALE_FRAC = 16 - self.G_SCALE_FRAC = 8 - self.G_ROTATE_FRAC = 16 - - self.G_MAXFBZ = 0x3fff # 3b exp, 11b mantissa - - - # G_MTX: parameter flags - - if F3DEX_GBI_2: - self.G_MTX_MODELVIEW = 0x00 # matrix types - self.G_MTX_PROJECTION = 0x04 - self.G_MTX_MUL = 0x00 # concat or load - self.G_MTX_LOAD = 0x02 - self.G_MTX_NOPUSH = 0x00 # push or not - self.G_MTX_PUSH = 0x01 - else: - self.G_MTX_MODELVIEW = 0x00 # matrix types - self.G_MTX_PROJECTION = 0x01 - self.G_MTX_MUL = 0x00 # concat or load - self.G_MTX_LOAD = 0x02 - self.G_MTX_NOPUSH = 0x00 # push or not - self.G_MTX_PUSH = 0x04 - - self.G_ZBUFFER = 0x00000001 - self.G_SHADE = 0x00000004 # enable Gouraud interp - # rest of low byte reserved for setup ucode - if F3DEX_GBI_2: - self.G_TEXTURE_ENABLE = 0x00000000 # Ignored - self.G_SHADING_SMOOTH = 0x00200000 # flat or smooth shaded - self.G_CULL_FRONT = 0x00000200 - self.G_CULL_BACK = 0x00000400 - self.G_CULL_BOTH = 0x00000600 # To make code cleaner - else: - self.G_TEXTURE_ENABLE = 0x00000002 # Microcode use only - self.G_SHADING_SMOOTH = 0x00000200 # flat or smooth shaded - self.G_CULL_FRONT = 0x00001000 - self.G_CULL_BACK = 0x00002000 - self.G_CULL_BOTH = 0x00003000 # To make code cleaner - self.G_FOG = 0x00010000 - self.G_LIGHTING = 0x00020000 - self.G_TEXTURE_GEN = 0x00040000 - self.G_TEXTURE_GEN_LINEAR = 0x00080000 - self.G_LOD = 0x00100000 # NOT IMPLEMENTED - if F3DEX_GBI or F3DLP_GBI: - self.G_CLIPPING = 0x00800000 - else: - self.G_CLIPPING = 0x00000000 - - #if _LANGUAGE_ASSEMBLY: - self.G_FOG_H = (self.G_FOG/0x10000) - self.G_LIGHTING_H = (self.G_LIGHTING/0x10000) - self.G_TEXTURE_GEN_H = (self.G_TEXTURE_GEN/0x10000) - self.G_TEXTURE_GEN_LINEAR_H = (self.G_TEXTURE_GEN_LINEAR/0x10000) - self.G_LOD_H = (self.G_LOD/0x10000) # NOT IMPLEMENTED - if F3DEX_GBI or F3DLP_GBI: - self.G_CLIPPING_H = (self.G_CLIPPING/0x10000) - #endif - - # Need these defined for Sprite Microcode - # if _LANGUAGE_ASSEMBLY: - self.G_TX_LOADTILE = 7 - self.G_TX_RENDERTILE = 0 - - self.G_TX_NOMIRROR = 0 - self.G_TX_WRAP = 0 - self.G_TX_MIRROR = 0x1 - self.G_TX_CLAMP = 0x2 - self.G_TX_NOMASK = 0 - self.G_TX_NOLOD = 0 - #endif - - self.G_TX_VARS = { - 'G_TX_NOMIRROR' : 0, - 'G_TX_WRAP' : 0, - 'G_TX_MIRROR' : 1, - 'G_TX_CLAMP' : 2, - 'G_TX_NOMASK' : 0, - 'G_TX_NOLOD' : 0, - } - - # G_SETIMG fmt: set image formats - self.G_IM_FMT_RGBA = 0 - self.G_IM_FMT_YUV = 1 - self.G_IM_FMT_CI = 2 - self.G_IM_FMT_IA = 3 - self.G_IM_FMT_I = 4 - - self.G_IM_FMT_VARS = { - '0' : 0, - 'G_IM_FMT_RGBA' : 0, - 'G_IM_FMT_YUV' : 1, - 'G_IM_FMT_CI' : 2, - 'G_IM_FMT_IA' : 3, - 'G_IM_FMT_I' : 4, - } - - # G_SETIMG siz: set image pixel size - self.G_IM_SIZ_4b = 0 - self.G_IM_SIZ_8b = 1 - self.G_IM_SIZ_16b = 2 - self.G_IM_SIZ_32b = 3 - self.G_IM_SIZ_DD = 5 - - self.G_IM_SIZ_4b_BYTES = 0 - self.G_IM_SIZ_4b_TILE_BYTES = self.G_IM_SIZ_4b_BYTES - self.G_IM_SIZ_4b_LINE_BYTES = self.G_IM_SIZ_4b_BYTES - - self.G_IM_SIZ_8b_BYTES = 1 - self.G_IM_SIZ_8b_TILE_BYTES = self.G_IM_SIZ_8b_BYTES - self.G_IM_SIZ_8b_LINE_BYTES = self.G_IM_SIZ_8b_BYTES - - self.G_IM_SIZ_16b_BYTES = 2 - self.G_IM_SIZ_16b_TILE_BYTES = self.G_IM_SIZ_16b_BYTES - self.G_IM_SIZ_16b_LINE_BYTES = self.G_IM_SIZ_16b_BYTES - - self.G_IM_SIZ_32b_BYTES = 4 - self.G_IM_SIZ_32b_TILE_BYTES = 2 - self.G_IM_SIZ_32b_LINE_BYTES = 2 - - self.G_IM_SIZ_4b_LOAD_BLOCK = self.G_IM_SIZ_16b - self.G_IM_SIZ_8b_LOAD_BLOCK = self.G_IM_SIZ_16b - self.G_IM_SIZ_16b_LOAD_BLOCK = self.G_IM_SIZ_16b - self.G_IM_SIZ_32b_LOAD_BLOCK = self.G_IM_SIZ_32b - - self.G_IM_SIZ_4b_SHIFT = 2 - self.G_IM_SIZ_8b_SHIFT = 1 - self.G_IM_SIZ_16b_SHIFT = 0 - self.G_IM_SIZ_32b_SHIFT = 0 - - self.G_IM_SIZ_4b_INCR = 3 - self.G_IM_SIZ_8b_INCR = 1 - self.G_IM_SIZ_16b_INCR = 0 - self.G_IM_SIZ_32b_INCR = 0 - - self.G_IM_SIZ_VARS = { - '0' : 0, - 'G_IM_SIZ_4b' : 0, - 'G_IM_SIZ_8b' : 1, - 'G_IM_SIZ_16b' : 2, - 'G_IM_SIZ_32b' : 3, - 'G_IM_SIZ_DD' : 5, - 'G_IM_SIZ_4b_BYTES' : 0, - 'G_IM_SIZ_4b_TILE_BYTES' : self.G_IM_SIZ_4b_BYTES, - 'G_IM_SIZ_4b_LINE_BYTES' : self.G_IM_SIZ_4b_BYTES, - 'G_IM_SIZ_8b_BYTES' : 1, - 'G_IM_SIZ_8b_TILE_BYTES' : self.G_IM_SIZ_8b_BYTES, - 'G_IM_SIZ_8b_LINE_BYTES' : self.G_IM_SIZ_8b_BYTES, - 'G_IM_SIZ_16b_BYTES' : 2, - 'G_IM_SIZ_16b_TILE_BYTES' : self.G_IM_SIZ_16b_BYTES, - 'G_IM_SIZ_16b_LINE_BYTES' : self.G_IM_SIZ_16b_BYTES, - 'G_IM_SIZ_32b_BYTES' : 4, - 'G_IM_SIZ_32b_TILE_BYTES' : 2, - 'G_IM_SIZ_32b_LINE_BYTES' : 2, - 'G_IM_SIZ_4b_LOAD_BLOCK' : self.G_IM_SIZ_16b, - 'G_IM_SIZ_8b_LOAD_BLOCK' : self.G_IM_SIZ_16b, - 'G_IM_SIZ_16b_LOAD_BLOCK' : self.G_IM_SIZ_16b, - 'G_IM_SIZ_32b_LOAD_BLOCK' : self.G_IM_SIZ_32b, - 'G_IM_SIZ_4b_SHIFT' : 2, - 'G_IM_SIZ_8b_SHIFT' : 1, - 'G_IM_SIZ_16b_SHIFT' : 0, - 'G_IM_SIZ_32b_SHIFT' : 0, - 'G_IM_SIZ_4b_INCR' : 3, - 'G_IM_SIZ_8b_INCR' : 1, - 'G_IM_SIZ_16b_INCR' : 0, - 'G_IM_SIZ_32b_INCR' : 0 - } - - # G_SETCOMBINE: color combine modes - - # Color combiner constants: - self.G_CCMUX_COMBINED = 0 - self.G_CCMUX_TEXEL0 = 1 - self.G_CCMUX_TEXEL1 = 2 - self.G_CCMUX_PRIMITIVE = 3 - self.G_CCMUX_SHADE = 4 - self.G_CCMUX_ENVIRONMENT = 5 - self.G_CCMUX_CENTER = 6 - self.G_CCMUX_SCALE = 6 - self.G_CCMUX_COMBINED_ALPHA = 7 - self.G_CCMUX_TEXEL0_ALPHA = 8 - self.G_CCMUX_TEXEL1_ALPHA = 9 - self.G_CCMUX_PRIMITIVE_ALPHA = 10 - self.G_CCMUX_SHADE_ALPHA = 11 - self.G_CCMUX_ENV_ALPHA = 12 - self.G_CCMUX_LOD_FRACTION = 13 - self.G_CCMUX_PRIM_LOD_FRAC = 14 - self.G_CCMUX_NOISE = 7 - self.G_CCMUX_K4 = 7 - self.G_CCMUX_K5 = 15 - self.G_CCMUX_1 = 6 - self.G_CCMUX_0 = 31 - - self.CCMUXDict = { - 'COMBINED' : 0, - 'TEXEL0' : 1, - 'TEXEL1' : 2, - 'PRIMITIVE' : 3, - 'SHADE' : 4, - 'ENVIRONMENT' : 5, - 'CENTER' : 6, - 'SCALE' : 6, - 'COMBINED_ALPHA' : 7, - 'TEXEL0_ALPHA' : 8, - 'TEXEL1_ALPHA' : 9, - 'PRIMITIVE_ALPHA' : 10, - 'SHADE_ALPHA' : 11, - 'ENV_ALPHA' : 12, - 'LOD_FRACTION' : 13, - 'PRIM_LOD_FRAC' : 14, - 'NOISE' : 7, - 'K4' : 7, - 'K5' : 15, - '1' : 6, - '0' : 31 - } - - self.ACMUXDict = { - 'COMBINED' : 0, - 'TEXEL0' : 1, - 'TEXEL1' : 2, - 'PRIMITIVE' : 3, - 'SHADE' : 4, - 'ENVIRONMENT' : 5, - 'LOD_FRACTION' : 0, - 'PRIM_LOD_FRAC' : 6, - '1' : 6, - '0' : 7, - } - - # Alpha combiner constants: - self.G_ACMUX_COMBINED = 0 - self.G_ACMUX_TEXEL0 = 1 - self.G_ACMUX_TEXEL1 = 2 - self.G_ACMUX_PRIMITIVE = 3 - self.G_ACMUX_SHADE = 4 - self.G_ACMUX_ENVIRONMENT = 5 - self.G_ACMUX_LOD_FRACTION = 0 - self.G_ACMUX_PRIM_LOD_FRAC = 6 - self.G_ACMUX_1 = 6 - self.G_ACMUX_0 = 7 - - # typical CC cycle 1 modes - self.G_CC_PRIMITIVE = '0', '0', '0', 'PRIMITIVE', '0', '0', '0', 'PRIMITIVE' - self.G_CC_SHADE = '0', '0', '0', 'SHADE', '0', '0', '0', 'SHADE' - - self.G_CC_MODULATEI = 'TEXEL0', '0', 'SHADE', '0', '0', '0', '0', 'SHADE' - self.G_CC_MODULATEIDECALA = 'TEXEL0', '0', 'SHADE', '0', '0', '0', '0', 'TEXEL0' - self.G_CC_MODULATEIFADE = 'TEXEL0', '0', 'SHADE', '0', '0', '0', '0', 'ENVIRONMENT' - - self.G_CC_MODULATERGB = self.G_CC_MODULATEI - self.G_CC_MODULATERGBDECALA = self.G_CC_MODULATEIDECALA - self.G_CC_MODULATERGBFADE = self.G_CC_MODULATEIFADE - - self.G_CC_MODULATEIA = 'TEXEL0', '0', 'SHADE', '0', 'TEXEL0', '0', 'SHADE', '0' - self.G_CC_MODULATEIFADEA = 'TEXEL0', '0', 'SHADE', '0', 'TEXEL0', '0', 'ENVIRONMENT', '0' - - self.G_CC_MODULATEFADE = 'TEXEL0', '0', 'SHADE', '0', 'ENVIRONMENT', '0', 'TEXEL0', '0' - - self.G_CC_MODULATERGBA = self.G_CC_MODULATEIA - self.G_CC_MODULATERGBFADEA = self.G_CC_MODULATEIFADEA - - self.G_CC_MODULATEI_PRIM = 'TEXEL0', '0', 'PRIMITIVE', '0', '0', '0', '0', 'PRIMITIVE' - self.G_CC_MODULATEIA_PRIM = 'TEXEL0', '0', 'PRIMITIVE', '0', 'TEXEL0', '0', 'PRIMITIVE', '0' - self.G_CC_MODULATEIDECALA_PRIM = 'TEXEL0', '0', 'PRIMITIVE', '0', '0', '0', '0', 'TEXEL0' - - self.G_CC_MODULATERGB_PRIM = self.G_CC_MODULATEI_PRIM - self.G_CC_MODULATERGBA_PRIM = self.G_CC_MODULATEIA_PRIM - self.G_CC_MODULATERGBDECALA_PRIM = self.G_CC_MODULATEIDECALA_PRIM - - self.G_CC_FADE = 'SHADE', '0', 'ENVIRONMENT', '0', 'SHADE', '0', 'ENVIRONMENT', '0' - self.G_CC_FADEA = 'TEXEL0', '0', 'ENVIRONMENT', '0', 'TEXEL0', '0', 'ENVIRONMENT', '0' - - self.G_CC_DECALRGB = '0', '0', '0', 'TEXEL0', '0', '0', '0', 'SHADE' - self.G_CC_DECALRGBA = '0', '0', '0', 'TEXEL0', '0', '0', '0', 'TEXEL0' - self.G_CC_DECALFADE = '0', '0', '0', 'TEXEL0', '0', '0', '0', 'ENVIRONMENT' - - self.G_CC_DECALFADEA = '0', '0', '0', 'TEXEL0', 'TEXEL0', '0', 'ENVIRONMENT', '0' - - self.G_CC_BLENDI = 'ENVIRONMENT', 'SHADE', 'TEXEL0', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_BLENDIA = 'ENVIRONMENT', 'SHADE', 'TEXEL0', 'SHADE', 'TEXEL0', '0', 'SHADE', '0' - self.G_CC_BLENDIDECALA = 'ENVIRONMENT', 'SHADE', 'TEXEL0', 'SHADE', '0', '0', '0', 'TEXEL0' - - self.G_CC_BLENDRGBA = 'TEXEL0', 'SHADE', 'TEXEL0_ALPHA', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_BLENDRGBDECALA = 'TEXEL0', 'SHADE', 'TEXEL0_ALPHA', 'SHADE', '0', '0', '0', 'TEXEL0' - self.G_CC_BLENDRGBFADEA = 'TEXEL0', 'SHADE', 'TEXEL0_ALPHA', 'SHADE', '0', '0', '0', 'ENVIRONMENT' - - self.G_CC_ADDRGB = 'TEXEL0', '0', 'TEXEL0', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_ADDRGBDECALA = 'TEXEL0', '0', 'TEXEL0', 'SHADE', '0', '0', '0', 'TEXEL0' - self.G_CC_ADDRGBFADE = 'TEXEL0', '0', 'TEXEL0', 'SHADE', '0', '0', '0', 'ENVIRONMENT' - - self.G_CC_REFLECTRGB = 'ENVIRONMENT', '0', 'TEXEL0', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_REFLECTRGBDECALA = 'ENVIRONMENT', '0', 'TEXEL0', 'SHADE', '0', '0', '0', 'TEXEL0' - - self.G_CC_HILITERGB = 'PRIMITIVE', 'SHADE', 'TEXEL0', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_HILITERGBA = 'PRIMITIVE', 'SHADE', 'TEXEL0', 'SHADE', 'PRIMITIVE', 'SHADE', 'TEXEL0', 'SHADE' - self.G_CC_HILITERGBDECALA = 'PRIMITIVE', 'SHADE', 'TEXEL0', 'SHADE', '0', '0', '0', 'TEXEL0' - - self.G_CC_SHADEDECALA = '0', '0', '0', 'SHADE', '0', '0', '0', 'TEXEL0' - self.G_CC_SHADEFADEA = '0', '0', '0', 'SHADE', '0', '0', '0', 'ENVIRONMENT' - - self.G_CC_BLENDPE = 'PRIMITIVE', 'ENVIRONMENT', 'TEXEL0', 'ENVIRONMENT', 'TEXEL0', '0', 'SHADE', '0' - self.G_CC_BLENDPEDECALA = 'PRIMITIVE', 'ENVIRONMENT', 'TEXEL0', 'ENVIRONMENT', '0', '0', '0', 'TEXEL0' - - # oddball modes - self._G_CC_BLENDPE = 'ENVIRONMENT', 'PRIMITIVE', 'TEXEL0', 'PRIMITIVE', 'TEXEL0', '0', 'SHADE', '0' - self._G_CC_BLENDPEDECALA = 'ENVIRONMENT', 'PRIMITIVE', 'TEXEL0', 'PRIMITIVE', '0', '0', '0', 'TEXEL0' - self._G_CC_TWOCOLORTEX = 'PRIMITIVE', 'SHADE', 'TEXEL0', 'SHADE', '0', '0', '0', 'SHADE' - - # used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD - self._G_CC_SPARSEST = 'PRIMITIVE', 'TEXEL0', 'LOD_FRACTION', 'TEXEL0', 'PRIMITIVE', 'TEXEL0', 'LOD_FRACTION', 'TEXEL0' - self.G_CC_TEMPLERP = 'TEXEL1', 'TEXEL0', 'PRIM_LOD_FRAC', 'TEXEL0', 'TEXEL1', 'TEXEL0', 'PRIM_LOD_FRAC', 'TEXEL0' - - # typical CC cycle 1 modes, usually followed by other cycle 2 modes - self.G_CC_TRILERP = 'TEXEL1', 'TEXEL0', 'LOD_FRACTION', 'TEXEL0', 'TEXEL1', 'TEXEL0', 'LOD_FRACTION', 'TEXEL0' - self.G_CC_INTERFERENCE = 'TEXEL0', '0', 'TEXEL1', '0', 'TEXEL0', '0', 'TEXEL1', '0' - - self.G_CC_1CYUV2RGB = 'TEXEL0', 'K4', 'K5', 'TEXEL0', '0', '0', '0', 'SHADE' - self.G_CC_YUV2RGB = 'TEXEL1', 'K4', 'K5', 'TEXEL1', '0', '0', '0', '0' - - #typical CC cycle 2 modes - self.G_CC_PASS2 = '0', '0', '0', 'COMBINED', '0', '0', '0', 'COMBINED' - self.G_CC_MODULATEI2 = 'COMBINED', '0', 'SHADE', '0', '0', '0', '0', 'SHADE' - self.G_CC_MODULATEIA2 = 'COMBINED', '0', 'SHADE', '0', 'COMBINED', '0', 'SHADE', '0' - self.G_CC_MODULATERGB2 = self.G_CC_MODULATEI2 - self.G_CC_MODULATERGBA2 = self.G_CC_MODULATEIA2 - self.G_CC_MODULATEI_PRIM2 = 'COMBINED', '0', 'PRIMITIVE', '0', '0', '0', '0', 'PRIMITIVE' - self.G_CC_MODULATEIA_PRIM2 = 'COMBINED', '0', 'PRIMITIVE', '0', 'COMBINED', '0', 'PRIMITIVE', '0' - self.G_CC_MODULATERGB_PRIM2 = self.G_CC_MODULATEI_PRIM2 - self.G_CC_MODULATERGBA_PRIM2 = self.G_CC_MODULATEIA_PRIM2 - self.G_CC_DECALRGB2 = '0', '0', '0', 'COMBINED', '0', '0', '0', 'SHADE' - - self.G_CC_DECALRGBA2 = 'COMBINED', 'SHADE', 'COMBINED_ALPHA', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_BLENDI2 = 'ENVIRONMENT', 'SHADE', 'COMBINED', 'SHADE', '0', '0', '0', 'SHADE' - self.G_CC_BLENDIA2 = 'ENVIRONMENT', 'SHADE', 'COMBINED', 'SHADE', 'COMBINED', '0', 'SHADE', '0' - self.G_CC_CHROMA_KEY2 = 'TEXEL0', 'CENTER', 'SCALE', '0', '0', '0', '0', '0' - self.G_CC_HILITERGB2 = 'ENVIRONMENT', 'COMBINED', 'TEXEL0', 'COMBINED', '0', '0', '0', 'SHADE' - self.G_CC_HILITERGBA2 = 'ENVIRONMENT', 'COMBINED', 'TEXEL0', 'COMBINED', 'ENVIRONMENT', 'COMBINED', 'TEXEL0', 'COMBINED' - self.G_CC_HILITERGBDECALA2 = 'ENVIRONMENT', 'COMBINED', 'TEXEL0', 'COMBINED', '0', '0', '0', 'TEXEL0' - self.G_CC_HILITERGBPASSA2 = 'ENVIRONMENT', 'COMBINED', 'TEXEL0', 'COMBINED', '0', '0', '0', 'COMBINED' - - # G_SETOTHERMODE_L sft: shift count - - self.G_MDSFT_ALPHACOMPARE = G_MDSFT_ALPHACOMPARE = 0 - self.G_MDSFT_ZSRCSEL = G_MDSFT_ZSRCSEL = 2 - self.G_MDSFT_RENDERMODE = G_MDSFT_RENDERMODE = 3 - self.G_MDSFT_BLENDER = G_MDSFT_BLENDER = 16 - - - # G_SETOTHERMODE_H sft: shift count - - self.G_MDSFT_BLENDMASK = G_MDSFT_BLENDMASK = 0 # unsupported - self.G_MDSFT_ALPHADITHER = G_MDSFT_ALPHADITHER = 4 - self.G_MDSFT_RGBDITHER = G_MDSFT_RGBDITHER = 6 - - self.G_MDSFT_COMBKEY = G_MDSFT_COMBKEY = 8 - self.G_MDSFT_TEXTCONV = G_MDSFT_TEXTCONV = 9 - self.G_MDSFT_TEXTFILT = G_MDSFT_TEXTFILT = 12 - self.G_MDSFT_TEXTLUT = G_MDSFT_TEXTLUT = 14 - self.G_MDSFT_TEXTLOD = G_MDSFT_TEXTLOD = 16 - self.G_MDSFT_TEXTDETAIL = G_MDSFT_TEXTDETAIL = 17 - self.G_MDSFT_TEXTPERSP = G_MDSFT_TEXTPERSP = 19 - self.G_MDSFT_CYCLETYPE = G_MDSFT_CYCLETYPE = 20 - self.G_MDSFT_COLORDITHER = G_MDSFT_COLORDITHER = 22 # unsupported in HW 2.0 - self.G_MDSFT_PIPELINE = G_MDSFT_PIPELINE = 23 - - # G_SETOTHERMODE_H gPipelineMode - self.G_PM_1PRIMITIVE = (1 << G_MDSFT_PIPELINE) - self.G_PM_NPRIMITIVE = (0 << G_MDSFT_PIPELINE) - - # G_SETOTHERMODE_H gSetCycleType - self.G_CYC_1CYCLE = (0 << G_MDSFT_CYCLETYPE) - self.G_CYC_2CYCLE = (1 << G_MDSFT_CYCLETYPE) - self.G_CYC_COPY = (2 << G_MDSFT_CYCLETYPE) - self.G_CYC_FILL = (3 << G_MDSFT_CYCLETYPE) - - # G_SETOTHERMODE_H gSetTexturePersp - self.G_TP_NONE = (0 << G_MDSFT_TEXTPERSP) - self.G_TP_PERSP = (1 << G_MDSFT_TEXTPERSP) - - # G_SETOTHERMODE_H gSetTextureDetail - self.G_TD_CLAMP = (0 << G_MDSFT_TEXTDETAIL) - self.G_TD_SHARPEN = (1 << G_MDSFT_TEXTDETAIL) - self.G_TD_DETAIL = (2 << G_MDSFT_TEXTDETAIL) - - # G_SETOTHERMODE_H gSetTextureLOD - self.G_TL_TILE = (0 << G_MDSFT_TEXTLOD) - self.G_TL_LOD = (1 << G_MDSFT_TEXTLOD) - - # G_SETOTHERMODE_H gSetTextureLUT - self.G_TT_NONE = (0 << G_MDSFT_TEXTLUT) - self.G_TT_RGBA16 = (2 << G_MDSFT_TEXTLUT) - self.G_TT_IA16 = (3 << G_MDSFT_TEXTLUT) - - # G_SETOTHERMODE_H gSetTextureFilter - self.G_TF_POINT = (0 << G_MDSFT_TEXTFILT) - self.G_TF_AVERAGE = (3 << G_MDSFT_TEXTFILT) - self.G_TF_BILERP = (2 << G_MDSFT_TEXTFILT) - - # G_SETOTHERMODE_H gSetTextureConvert - self.G_TC_CONV = (0 << G_MDSFT_TEXTCONV) - self.G_TC_FILTCONV = (5 << G_MDSFT_TEXTCONV) - self.G_TC_FILT = (6 << G_MDSFT_TEXTCONV) - - # G_SETOTHERMODE_H gSetCombineKey - self.G_CK_NONE = (0 << G_MDSFT_COMBKEY) - self.G_CK_KEY = (1 << G_MDSFT_COMBKEY) - - # G_SETOTHERMODE_H gSetColorDither - self.G_CD_MAGICSQ = (0 << G_MDSFT_RGBDITHER) - self.G_CD_BAYER = (1 << G_MDSFT_RGBDITHER) - self.G_CD_NOISE = (2 << G_MDSFT_RGBDITHER) - - if not _HW_VERSION_1: - self.G_CD_DISABLE = (3 << G_MDSFT_RGBDITHER) - self.G_CD_ENABLE = self.G_CD_NOISE # HW 1.0 compatibility mode - else: - self.G_CD_ENABLE = (1 << G_MDSFT_COLORDITHER) - self.G_CD_DISABLE = (0 << G_MDSFT_COLORDITHER) - - # G_SETOTHERMODE_H gSetAlphaDither - self.G_AD_PATTERN = (0 << G_MDSFT_ALPHADITHER) - self.G_AD_NOTPATTERN = (1 << G_MDSFT_ALPHADITHER) - self.G_AD_NOISE = (2 << G_MDSFT_ALPHADITHER) - self.G_AD_DISABLE = (3 << G_MDSFT_ALPHADITHER) - - # G_SETOTHERMODE_L gSetAlphaCompare - self.G_AC_NONE = (0 << G_MDSFT_ALPHACOMPARE) - self.G_AC_THRESHOLD = (1 << G_MDSFT_ALPHACOMPARE) - self.G_AC_DITHER = (3 << G_MDSFT_ALPHACOMPARE) - - # G_SETOTHERMODE_L gSetDepthSource - self.G_ZS_PIXEL = (0 << G_MDSFT_ZSRCSEL) - self.G_ZS_PRIM = (1 << G_MDSFT_ZSRCSEL) - - # G_SETOTHERMODE_L gSetRenderMode - self.AA_EN = AA_EN = 0x8 - self.Z_CMP = Z_CMP = 0x10 - self.Z_UPD = Z_UPD = 0x20 - self.IM_RD = IM_RD = 0x40 - self.CLR_ON_CVG = CLR_ON_CVG = 0x80 - self.CVG_DST_CLAMP = CVG_DST_CLAMP = 0 - self.CVG_DST_WRAP = CVG_DST_WRAP = 0x100 - self.CVG_DST_FULL = CVG_DST_FULL = 0x200 - self.CVG_DST_SAVE = CVG_DST_SAVE = 0x300 - self.ZMODE_OPA = ZMODE_OPA = 0 - self.ZMODE_INTER = ZMODE_INTER = 0x400 - self.ZMODE_XLU = ZMODE_XLU = 0x800 - self.ZMODE_DEC = ZMODE_DEC = 0xc00 - self.CVG_X_ALPHA = CVG_X_ALPHA = 0x1000 - self.ALPHA_CVG_SEL = ALPHA_CVG_SEL = 0x2000 - self.FORCE_BL = FORCE_BL = 0x4000 - self.TEX_EDGE = TEX_EDGE = 0x0000 # used to be 0x8000 - - self.G_BL_CLR_IN = G_BL_CLR_IN = 0 - self.G_BL_CLR_MEM = G_BL_CLR_MEM = 1 - self.G_BL_CLR_BL = G_BL_CLR_BL = 2 - self.G_BL_CLR_FOG = G_BL_CLR_FOG = 3 - self.G_BL_1MA = G_BL_1MA = 0 - self.G_BL_A_MEM = G_BL_A_MEM = 1 - self.G_BL_A_IN = G_BL_A_IN = 0 - self.G_BL_A_FOG = G_BL_A_FOG = 1 - self.G_BL_A_SHADE = G_BL_A_SHADE = 2 - self.G_BL_1 = G_BL_1 = 2 - self.G_BL_0 = G_BL_0 = 3 - - self.cvgDstDict = { - CVG_DST_CLAMP : "CVG_DST_CLAMP", - CVG_DST_WRAP : "CVG_DST_WRAP", - CVG_DST_FULL : "CVG_DST_FULL", - CVG_DST_SAVE : "CVG_DST_SAVE", - } - - self.zmodeDict = { - ZMODE_OPA : "ZMODE_OPA", - ZMODE_INTER : "ZMODE_INTER", - ZMODE_XLU : "ZMODE_XLU", - ZMODE_DEC : "ZMODE_DEC", - } - - self.blendColorDict = { - G_BL_CLR_IN : "G_BL_CLR_IN", - G_BL_CLR_MEM : "G_BL_CLR_MEM", - G_BL_CLR_BL : "G_BL_CLR_BL", - G_BL_CLR_FOG : "G_BL_CLR_FOG", - } - - self.blendAlphaDict = { - G_BL_A_IN : 'G_BL_A_IN', - G_BL_A_FOG : 'G_BL_A_FOG', - G_BL_A_SHADE : 'G_BL_A_SHADE', - G_BL_0 : 'G_BL_0', - } - - self.blendMixDict = { - G_BL_1MA : 'G_BL_1MA', - G_BL_A_MEM : 'G_BL_A_MEM', - G_BL_1 : 'G_BL_1', - G_BL_0 : 'G_BL_0', - } - - def GBL_c1(m1a, m1b, m2a, m2b): - return (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 - def GBL_c2(m1a, m1b, m2a, m2b): - return (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 - - def RM_AA_ZB_OPA_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_RA_ZB_OPA_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_ZB_XLU_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ - FORCE_BL | ZMODE_XLU | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_OPA_DECAL(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | ALPHA_CVG_SEL | \ - ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_RA_ZB_OPA_DECAL(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | CVG_DST_WRAP | ALPHA_CVG_SEL | \ - ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_ZB_XLU_DECAL(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ - FORCE_BL | ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_OPA_INTER(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - ALPHA_CVG_SEL | ZMODE_INTER | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_RA_ZB_OPA_INTER(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | CVG_DST_CLAMP | \ - ALPHA_CVG_SEL | ZMODE_INTER | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_ZB_XLU_INTER(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | \ - FORCE_BL | ZMODE_INTER | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_XLU_LINE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ - ALPHA_CVG_SEL | FORCE_BL | ZMODE_XLU | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_DEC_LINE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | IM_RD | CVG_DST_SAVE | CVG_X_ALPHA | \ - ALPHA_CVG_SEL | FORCE_BL | ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_TEX_EDGE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_ZB_TEX_INTER(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_INTER | TEX_EDGE | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_ZB_SUB_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_ZB_PCL_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - ZMODE_OPA | self.G_AC_DITHER | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_OPA_TERR(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_TEX_TERR(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_CLAMP | \ - CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_ZB_SUB_TERR(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | Z_CMP | Z_UPD | IM_RD | CVG_DST_FULL | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - - def RM_AA_OPA_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_CLAMP | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_RA_OPA_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | CVG_DST_CLAMP | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_XLU_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_WRAP | CLR_ON_CVG | FORCE_BL | \ - ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_XLU_LINE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_CLAMP | CVG_X_ALPHA | \ - ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_DEC_LINE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_FULL | CVG_X_ALPHA | \ - ALPHA_CVG_SEL | FORCE_BL | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_TEX_EDGE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_CLAMP | \ - CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_SUB_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_FULL | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_AA_PCL_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_CLAMP | \ - ZMODE_OPA | self.G_AC_DITHER | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_OPA_TERR(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_CLAMP | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_TEX_TERR(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_CLAMP | \ - CVG_X_ALPHA | ALPHA_CVG_SEL | ZMODE_OPA | TEX_EDGE | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_AA_SUB_TERR(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return AA_EN | IM_RD | CVG_DST_FULL | \ - ZMODE_OPA | ALPHA_CVG_SEL | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - - def RM_ZB_OPA_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | Z_UPD | CVG_DST_FULL | ALPHA_CVG_SEL | \ - ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_ZB_XLU_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_XLU | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_ZB_OPA_DECAL(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | CVG_DST_FULL | ALPHA_CVG_SEL | ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) - - def RM_ZB_XLU_DECAL(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_ZB_CLD_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_XLU | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_ZB_OVL_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_DEC | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_ZB_PCL_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return Z_CMP | Z_UPD | CVG_DST_FULL | ZMODE_OPA | \ - self.G_AC_DITHER | \ - func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) - - - def RM_OPA_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) - - def RM_XLU_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_TEX_EDGE(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return CVG_DST_CLAMP | CVG_X_ALPHA | ALPHA_CVG_SEL | FORCE_BL |\ - ZMODE_OPA | TEX_EDGE | AA_EN | \ - func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) - - def RM_CLD_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) - - def RM_PCL_SURF(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return CVG_DST_FULL | FORCE_BL | ZMODE_OPA | \ - self.G_AC_DITHER | \ - func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) - - def RM_ADD(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) - - def RM_NOOP(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return func(0, 0, 0, 0) - - def RM_VISCVG(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return IM_RD | FORCE_BL | \ - func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) - - # for rendering to an 8-bit framebuffer - def RM_OPA_CI(clk): - func = GBL_c1 if clk == 1 else GBL_c2 - return CVG_DST_CLAMP | ZMODE_OPA | \ - func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) - - self.G_RM_AA_ZB_OPA_SURF = RM_AA_ZB_OPA_SURF(1) - self.G_RM_AA_ZB_OPA_SURF2 = RM_AA_ZB_OPA_SURF(2) - self.G_RM_AA_ZB_XLU_SURF = RM_AA_ZB_XLU_SURF(1) - self.G_RM_AA_ZB_XLU_SURF2 = RM_AA_ZB_XLU_SURF(2) - self.G_RM_AA_ZB_OPA_DECAL = RM_AA_ZB_OPA_DECAL(1) - self.G_RM_AA_ZB_OPA_DECAL2 = RM_AA_ZB_OPA_DECAL(2) - self.G_RM_AA_ZB_XLU_DECAL = RM_AA_ZB_XLU_DECAL(1) - self.G_RM_AA_ZB_XLU_DECAL2 = RM_AA_ZB_XLU_DECAL(2) - self.G_RM_AA_ZB_OPA_INTER = RM_AA_ZB_OPA_INTER(1) - self.G_RM_AA_ZB_OPA_INTER2 = RM_AA_ZB_OPA_INTER(2) - self.G_RM_AA_ZB_XLU_INTER = RM_AA_ZB_XLU_INTER(1) - self.G_RM_AA_ZB_XLU_INTER2 = RM_AA_ZB_XLU_INTER(2) - self.G_RM_AA_ZB_XLU_LINE = RM_AA_ZB_XLU_LINE(1) - self.G_RM_AA_ZB_XLU_LINE2 = RM_AA_ZB_XLU_LINE(2) - self.G_RM_AA_ZB_DEC_LINE = RM_AA_ZB_DEC_LINE(1) - self.G_RM_AA_ZB_DEC_LINE2 = RM_AA_ZB_DEC_LINE(2) - self.G_RM_AA_ZB_TEX_EDGE = RM_AA_ZB_TEX_EDGE(1) - self.G_RM_AA_ZB_TEX_EDGE2 = RM_AA_ZB_TEX_EDGE(2) - self.G_RM_AA_ZB_TEX_INTER = RM_AA_ZB_TEX_INTER(1) - self.G_RM_AA_ZB_TEX_INTER2 = RM_AA_ZB_TEX_INTER(2) - self.G_RM_AA_ZB_SUB_SURF = RM_AA_ZB_SUB_SURF(1) - self.G_RM_AA_ZB_SUB_SURF2 = RM_AA_ZB_SUB_SURF(2) - self.G_RM_AA_ZB_PCL_SURF = RM_AA_ZB_PCL_SURF(1) - self.G_RM_AA_ZB_PCL_SURF2 = RM_AA_ZB_PCL_SURF(2) - self.G_RM_AA_ZB_OPA_TERR = RM_AA_ZB_OPA_TERR(1) - self.G_RM_AA_ZB_OPA_TERR2 = RM_AA_ZB_OPA_TERR(2) - self.G_RM_AA_ZB_TEX_TERR = RM_AA_ZB_TEX_TERR(1) - self.G_RM_AA_ZB_TEX_TERR2 = RM_AA_ZB_TEX_TERR(2) - self.G_RM_AA_ZB_SUB_TERR = RM_AA_ZB_SUB_TERR(1) - self.G_RM_AA_ZB_SUB_TERR2 = RM_AA_ZB_SUB_TERR(2) - - self.G_RM_RA_ZB_OPA_SURF = RM_RA_ZB_OPA_SURF(1) - self.G_RM_RA_ZB_OPA_SURF2 = RM_RA_ZB_OPA_SURF(2) - self.G_RM_RA_ZB_OPA_DECAL = RM_RA_ZB_OPA_DECAL(1) - self.G_RM_RA_ZB_OPA_DECAL2 = RM_RA_ZB_OPA_DECAL(2) - self.G_RM_RA_ZB_OPA_INTER = RM_RA_ZB_OPA_INTER(1) - self.G_RM_RA_ZB_OPA_INTER2 = RM_RA_ZB_OPA_INTER(2) - - self.G_RM_AA_OPA_SURF = RM_AA_OPA_SURF(1) - self.G_RM_AA_OPA_SURF2 = RM_AA_OPA_SURF(2) - self.G_RM_AA_XLU_SURF = RM_AA_XLU_SURF(1) - self.G_RM_AA_XLU_SURF2 = RM_AA_XLU_SURF(2) - self.G_RM_AA_XLU_LINE = RM_AA_XLU_LINE(1) - self.G_RM_AA_XLU_LINE2 = RM_AA_XLU_LINE(2) - self.G_RM_AA_DEC_LINE = RM_AA_DEC_LINE(1) - self.G_RM_AA_DEC_LINE2 = RM_AA_DEC_LINE(2) - self.G_RM_AA_TEX_EDGE = RM_AA_TEX_EDGE(1) - self.G_RM_AA_TEX_EDGE2 = RM_AA_TEX_EDGE(2) - self.G_RM_AA_SUB_SURF = RM_AA_SUB_SURF(1) - self.G_RM_AA_SUB_SURF2 = RM_AA_SUB_SURF(2) - self.G_RM_AA_PCL_SURF = RM_AA_PCL_SURF(1) - self.G_RM_AA_PCL_SURF2 = RM_AA_PCL_SURF(2) - self.G_RM_AA_OPA_TERR = RM_AA_OPA_TERR(1) - self.G_RM_AA_OPA_TERR2 = RM_AA_OPA_TERR(2) - self.G_RM_AA_TEX_TERR = RM_AA_TEX_TERR(1) - self.G_RM_AA_TEX_TERR2 = RM_AA_TEX_TERR(2) - self.G_RM_AA_SUB_TERR = RM_AA_SUB_TERR(1) - self.G_RM_AA_SUB_TERR2 = RM_AA_SUB_TERR(2) - - self.G_RM_RA_OPA_SURF = RM_RA_OPA_SURF(1) - self.G_RM_RA_OPA_SURF2 = RM_RA_OPA_SURF(2) - - self.G_RM_ZB_OPA_SURF = RM_ZB_OPA_SURF(1) - self.G_RM_ZB_OPA_SURF2 = RM_ZB_OPA_SURF(2) - self.G_RM_ZB_XLU_SURF = RM_ZB_XLU_SURF(1) - self.G_RM_ZB_XLU_SURF2 = RM_ZB_XLU_SURF(2) - self.G_RM_ZB_OPA_DECAL = RM_ZB_OPA_DECAL(1) - self.G_RM_ZB_OPA_DECAL2 = RM_ZB_OPA_DECAL(2) - self.G_RM_ZB_XLU_DECAL = RM_ZB_XLU_DECAL(1) - self.G_RM_ZB_XLU_DECAL2 = RM_ZB_XLU_DECAL(2) - self.G_RM_ZB_CLD_SURF = RM_ZB_CLD_SURF(1) - self.G_RM_ZB_CLD_SURF2 = RM_ZB_CLD_SURF(2) - self.G_RM_ZB_OVL_SURF = RM_ZB_OVL_SURF(1) - self.G_RM_ZB_OVL_SURF2 = RM_ZB_OVL_SURF(2) - self.G_RM_ZB_PCL_SURF = RM_ZB_PCL_SURF(1) - self.G_RM_ZB_PCL_SURF2 = RM_ZB_PCL_SURF(2) - - self.G_RM_OPA_SURF = RM_OPA_SURF(1) - self.G_RM_OPA_SURF2 = RM_OPA_SURF(2) - self.G_RM_XLU_SURF = RM_XLU_SURF(1) - self.G_RM_XLU_SURF2 = RM_XLU_SURF(2) - self.G_RM_CLD_SURF = RM_CLD_SURF(1) - self.G_RM_CLD_SURF2 = RM_CLD_SURF(2) - self.G_RM_TEX_EDGE = RM_TEX_EDGE(1) - self.G_RM_TEX_EDGE2 = RM_TEX_EDGE(2) - self.G_RM_PCL_SURF = RM_PCL_SURF(1) - self.G_RM_PCL_SURF2 = RM_PCL_SURF(2) - self.G_RM_ADD = RM_ADD(1) - self.G_RM_ADD2 = RM_ADD(2) - self.G_RM_NOOP = RM_NOOP(1) - self.G_RM_NOOP2 = RM_NOOP(2) - self.G_RM_VISCVG = RM_VISCVG(1) - self.G_RM_VISCVG2 = RM_VISCVG(2) - self.G_RM_OPA_CI = RM_OPA_CI(1) - self.G_RM_OPA_CI2 = RM_OPA_CI(2) - - - self.G_RM_FOG_SHADE_A = GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA) - self.G_RM_FOG_PRIM_A = GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA) - self.G_RM_PASS = GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) - - - # G_SETCONVERT: K0-5 - - self.G_CV_K0 = 175 - self.G_CV_K1 = -43 - self.G_CV_K2 = -89 - self.G_CV_K3 = 222 - self.G_CV_K4 = 114 - self.G_CV_K5 = 42 - - - # G_SETSCISSOR: interlace mode - - self.G_SC_NON_INTERLACE = 0 - self.G_SC_ODD_INTERLACE = 3 - self.G_SC_EVEN_INTERLACE = 2 - - # flags to inhibit pushing of the display list (on branch) - self.G_DL_PUSH = 0x00 - self.G_DL_NOPUSH = 0x01 - - # Some structs here - - self.G_MAXZ = 0x03ff # 10 bits of integer screen-Z precision - - # more structs here - - ''' + def __init__(self, F3D_VER, _HW_VERSION_1): + if F3D_VER == "F3DEX2.Rej/LX2.Rej" or F3D_VER == "F3DEX2/LX2": + self.F3DEX_GBI = False + self.F3DEX_GBI_2 = True + self.F3DLP_GBI = False + elif F3D_VER == "F3DLP.Rej" or F3D_VER == "F3DLX.Rej" or F3D_VER == "F3DEX/LX": + self.F3DEX_GBI = True + self.F3DEX_GBI_2 = False + self.F3DLP_GBI = True + elif F3D_VER == "F3D": + self.F3DEX_GBI = False + self.F3DEX_GBI_2 = False + self.F3DLP_GBI = False + else: + raise PluginError("Invalid F3D version " + F3D_VER + ".") + + self.vert_buffer_size = vertexBufferSize[F3D_VER][0] + self.vert_load_size = vertexBufferSize[F3D_VER][1] + + F3DEX_GBI = self.F3DEX_GBI + F3DEX_GBI_2 = self.F3DEX_GBI_2 + F3DLP_GBI = self.F3DLP_GBI + self._HW_VERSION_1 = _HW_VERSION_1 + self.F3D_VER = F3D_VER + # self._LANGUAGE_ASSEMBLY = _LANGUAGE_ASSEMBLY + + if F3DEX_GBI_2: + self.F3DEX_GBI = True + F3DEX_GBI = True + + self.G_NOOP = 0x00 + self.G_RDPHALF_2 = 0xF1 + self.G_SETOTHERMODE_H = 0xE3 + self.G_SETOTHERMODE_L = 0xE2 + self.G_RDPHALF_1 = 0xE1 + self.G_SPNOOP = 0xE0 + self.G_ENDDL = 0xDF + self.G_DL = 0xDE + self.G_LOAD_UCODE = 0xDD + self.G_MOVEMEM = 0xDC + self.G_MOVEWORD = 0xDB + self.G_MTX = 0xDA + self.G_GEOMETRYMODE = 0xD9 + self.G_POPMTX = 0xD8 + self.G_TEXTURE = 0xD7 + self.G_DMA_IO = 0xD6 + self.G_SPECIAL_1 = 0xD5 + self.G_SPECIAL_2 = 0xD4 + self.G_SPECIAL_3 = 0xD3 + + self.G_VTX = 0x01 + self.G_MODIFYVTX = 0x02 + self.G_CULLDL = 0x03 + self.G_BRANCH_Z = 0x04 + self.G_TRI1 = 0x05 + self.G_TRI2 = 0x06 + self.G_QUAD = 0x07 + self.G_LINE3D = 0x08 + + else: + # DMA commands + self.G_SPNOOP = 0 # handle 0 gracefully + self.G_MTX = 1 + self.G_RESERVED0 = 2 # not implemeted + self.G_MOVEMEM = 3 # move a block of memory (up to 4 words) to dmem + self.G_VTX = 4 + self.G_RESERVED1 = 5 # not implemeted + self.G_DL = 6 + self.G_RESERVED2 = 7 # not implemeted + self.G_RESERVED3 = 8 # not implemeted + self.G_SPRITE2D_BASE = 9 # sprite command + + # IMMEDIATE commands + self.G_IMMFIRST = -65 + self.G_TRI1 = self.G_IMMFIRST - 0 + self.G_CULLDL = self.G_IMMFIRST - 1 + self.G_POPMTX = self.G_IMMFIRST - 2 + self.G_MOVEWORD = self.G_IMMFIRST - 3 + self.G_TEXTURE = self.G_IMMFIRST - 4 + self.G_SETOTHERMODE_H = self.G_IMMFIRST - 5 + self.G_SETOTHERMODE_L = self.G_IMMFIRST - 6 + self.G_ENDDL = self.G_IMMFIRST - 7 + self.G_SETGEOMETRYMODE = self.G_IMMFIRST - 8 + self.G_CLEARGEOMETRYMODE = self.G_IMMFIRST - 9 + self.G_LINE3D = self.G_IMMFIRST - 10 + self.G_RDPHALF_1 = self.G_IMMFIRST - 11 + self.G_RDPHALF_2 = self.G_IMMFIRST - 12 + if F3DEX_GBI or F3DLP_GBI: + self.G_MODIFYVTX = self.G_IMMFIRST - 13 + self.G_TRI2 = self.G_IMMFIRST - 14 + self.G_BRANCH_Z = self.G_IMMFIRST - 15 + self.G_LOAD_UCODE = self.G_IMMFIRST - 16 + else: + self.G_RDPHALF_CONT = self.G_IMMFIRST - 13 + + # We are overloading 2 of the immediate commands + # to keep the byte alignment of dmem the same + + self.G_SPRITE2D_SCALEFLIP = self.G_IMMFIRST - 1 + self.G_SPRITE2D_DRAW = self.G_IMMFIRST - 2 + + # RDP commands + self.G_NOOP = 0xC0 + + # RDP commands + self.G_SETCIMG = 0xFF # -1 + self.G_SETZIMG = 0xFE # -2 + self.G_SETTIMG = 0xFD # -3 + self.G_SETCOMBINE = 0xFC # -4 + self.G_SETENVCOLOR = 0xFB # -5 + self.G_SETPRIMCOLOR = 0xFA # -6 + self.G_SETBLENDCOLOR = 0xF9 # -7 + self.G_SETFOGCOLOR = 0xF8 # -8 + self.G_SETFILLCOLOR = 0xF7 # -9 + self.G_FILLRECT = 0xF6 # -10 + self.G_SETTILE = 0xF5 # -11 + self.G_LOADTILE = 0xF4 # -12 + self.G_LOADBLOCK = 0xF3 # -13 + self.G_SETTILESIZE = 0xF2 # -14 + self.G_LOADTLUT = 0xF0 # -16 + self.G_RDPSETOTHERMODE = 0xEF # -17 + self.G_SETPRIMDEPTH = 0xEE # -18 + self.G_SETSCISSOR = 0xED # -19 + self.G_SETCONVERT = 0xEC # -20 + self.G_SETKEYR = 0xEB # -21 + self.G_SETKEYGB = 0xEA # -22 + self.G_RDPFULLSYNC = 0xE9 # -23 + self.G_RDPTILESYNC = 0xE8 # -24 + self.G_RDPPIPESYNC = 0xE7 # -25 + self.G_RDPLOADSYNC = 0xE6 # -26 + self.G_TEXRECTFLIP = 0xE5 # -27 + self.G_TEXRECT = 0xE4 # -28 + + self.G_TRI_FILL = 0xC8 # fill triangle: 11001000 + self.G_TRI_SHADE = 0xCC # shade triangle: 11001100 + self.G_TRI_TXTR = 0xCA # texture triangle: 11001010 + self.G_TRI_SHADE_TXTR = 0xCE # shade, texture triangle: 11001110 + self.G_TRI_FILL_ZBUFF = 0xC9 # fill, zbuff triangle: 11001001 + self.G_TRI_SHADE_ZBUFF = 0xCD # shade, zbuff triangle: 11001101 + self.G_TRI_TXTR_ZBUFF = 0xCB # texture, zbuff triangle: 11001011 + self.G_TRI_SHADE_TXTR_ZBUFF = 0xCF # shade, txtr, zbuff trngl: 11001111 + + # masks to build RDP triangle commands + self.G_RDP_TRI_FILL_MASK = 0x08 + self.G_RDP_TRI_SHADE_MASK = 0x04 + self.G_RDP_TRI_TXTR_MASK = 0x02 + self.G_RDP_TRI_ZBUFF_MASK = 0x01 + + self.BOWTIE_VAL = 0 + + # gets added to RDP command, in order to test for addres fixup + self.G_RDP_ADDR_FIXUP = 3 # |RDP cmds| <= this, do addr fixup + # if _LANGUAGE_ASSEMBLY: + self.G_RDP_TEXRECT_CHECK = (-1 * self.G_TEXRECTFLIP) & 0xFF + # endif + + self.G_DMACMDSIZ = 128 + self.G_IMMCMDSIZ = 64 + self.G_RDPCMDSIZ = 64 + + # Coordinate shift values, number of bits of fraction + self.G_TEXTURE_IMAGE_FRAC = 2 + self.G_TEXTURE_SCALE_FRAC = 16 + self.G_SCALE_FRAC = 8 + self.G_ROTATE_FRAC = 16 + + self.G_MAXFBZ = 0x3FFF # 3b exp, 11b mantissa + + # G_MTX: parameter flags + + if F3DEX_GBI_2: + self.G_MTX_MODELVIEW = 0x00 # matrix types + self.G_MTX_PROJECTION = 0x04 + self.G_MTX_MUL = 0x00 # concat or load + self.G_MTX_LOAD = 0x02 + self.G_MTX_NOPUSH = 0x00 # push or not + self.G_MTX_PUSH = 0x01 + else: + self.G_MTX_MODELVIEW = 0x00 # matrix types + self.G_MTX_PROJECTION = 0x01 + self.G_MTX_MUL = 0x00 # concat or load + self.G_MTX_LOAD = 0x02 + self.G_MTX_NOPUSH = 0x00 # push or not + self.G_MTX_PUSH = 0x04 + + self.G_ZBUFFER = 0x00000001 + self.G_SHADE = 0x00000004 # enable Gouraud interp + # rest of low byte reserved for setup ucode + if F3DEX_GBI_2: + self.G_TEXTURE_ENABLE = 0x00000000 # Ignored + self.G_SHADING_SMOOTH = 0x00200000 # flat or smooth shaded + self.G_CULL_FRONT = 0x00000200 + self.G_CULL_BACK = 0x00000400 + self.G_CULL_BOTH = 0x00000600 # To make code cleaner + else: + self.G_TEXTURE_ENABLE = 0x00000002 # Microcode use only + self.G_SHADING_SMOOTH = 0x00000200 # flat or smooth shaded + self.G_CULL_FRONT = 0x00001000 + self.G_CULL_BACK = 0x00002000 + self.G_CULL_BOTH = 0x00003000 # To make code cleaner + self.G_FOG = 0x00010000 + self.G_LIGHTING = 0x00020000 + self.G_TEXTURE_GEN = 0x00040000 + self.G_TEXTURE_GEN_LINEAR = 0x00080000 + self.G_LOD = 0x00100000 # NOT IMPLEMENTED + if F3DEX_GBI or F3DLP_GBI: + self.G_CLIPPING = 0x00800000 + else: + self.G_CLIPPING = 0x00000000 + + # if _LANGUAGE_ASSEMBLY: + self.G_FOG_H = self.G_FOG / 0x10000 + self.G_LIGHTING_H = self.G_LIGHTING / 0x10000 + self.G_TEXTURE_GEN_H = self.G_TEXTURE_GEN / 0x10000 + self.G_TEXTURE_GEN_LINEAR_H = self.G_TEXTURE_GEN_LINEAR / 0x10000 + self.G_LOD_H = self.G_LOD / 0x10000 # NOT IMPLEMENTED + if F3DEX_GBI or F3DLP_GBI: + self.G_CLIPPING_H = self.G_CLIPPING / 0x10000 + # endif + + # Need these defined for Sprite Microcode + # if _LANGUAGE_ASSEMBLY: + self.G_TX_LOADTILE = 7 + self.G_TX_RENDERTILE = 0 + + self.G_TX_NOMIRROR = 0 + self.G_TX_WRAP = 0 + self.G_TX_MIRROR = 0x1 + self.G_TX_CLAMP = 0x2 + self.G_TX_NOMASK = 0 + self.G_TX_NOLOD = 0 + # endif + + self.G_TX_VARS = { + "G_TX_NOMIRROR": 0, + "G_TX_WRAP": 0, + "G_TX_MIRROR": 1, + "G_TX_CLAMP": 2, + "G_TX_NOMASK": 0, + "G_TX_NOLOD": 0, + } + + # G_SETIMG fmt: set image formats + self.G_IM_FMT_RGBA = 0 + self.G_IM_FMT_YUV = 1 + self.G_IM_FMT_CI = 2 + self.G_IM_FMT_IA = 3 + self.G_IM_FMT_I = 4 + + self.G_IM_FMT_VARS = { + "0": 0, + "G_IM_FMT_RGBA": 0, + "G_IM_FMT_YUV": 1, + "G_IM_FMT_CI": 2, + "G_IM_FMT_IA": 3, + "G_IM_FMT_I": 4, + } + + # G_SETIMG siz: set image pixel size + self.G_IM_SIZ_4b = 0 + self.G_IM_SIZ_8b = 1 + self.G_IM_SIZ_16b = 2 + self.G_IM_SIZ_32b = 3 + self.G_IM_SIZ_DD = 5 + + self.G_IM_SIZ_4b_BYTES = 0 + self.G_IM_SIZ_4b_TILE_BYTES = self.G_IM_SIZ_4b_BYTES + self.G_IM_SIZ_4b_LINE_BYTES = self.G_IM_SIZ_4b_BYTES + + self.G_IM_SIZ_8b_BYTES = 1 + self.G_IM_SIZ_8b_TILE_BYTES = self.G_IM_SIZ_8b_BYTES + self.G_IM_SIZ_8b_LINE_BYTES = self.G_IM_SIZ_8b_BYTES + + self.G_IM_SIZ_16b_BYTES = 2 + self.G_IM_SIZ_16b_TILE_BYTES = self.G_IM_SIZ_16b_BYTES + self.G_IM_SIZ_16b_LINE_BYTES = self.G_IM_SIZ_16b_BYTES + + self.G_IM_SIZ_32b_BYTES = 4 + self.G_IM_SIZ_32b_TILE_BYTES = 2 + self.G_IM_SIZ_32b_LINE_BYTES = 2 + + self.G_IM_SIZ_4b_LOAD_BLOCK = self.G_IM_SIZ_16b + self.G_IM_SIZ_8b_LOAD_BLOCK = self.G_IM_SIZ_16b + self.G_IM_SIZ_16b_LOAD_BLOCK = self.G_IM_SIZ_16b + self.G_IM_SIZ_32b_LOAD_BLOCK = self.G_IM_SIZ_32b + + self.G_IM_SIZ_4b_SHIFT = 2 + self.G_IM_SIZ_8b_SHIFT = 1 + self.G_IM_SIZ_16b_SHIFT = 0 + self.G_IM_SIZ_32b_SHIFT = 0 + + self.G_IM_SIZ_4b_INCR = 3 + self.G_IM_SIZ_8b_INCR = 1 + self.G_IM_SIZ_16b_INCR = 0 + self.G_IM_SIZ_32b_INCR = 0 + + self.G_IM_SIZ_VARS = { + "0": 0, + "G_IM_SIZ_4b": 0, + "G_IM_SIZ_8b": 1, + "G_IM_SIZ_16b": 2, + "G_IM_SIZ_32b": 3, + "G_IM_SIZ_DD": 5, + "G_IM_SIZ_4b_BYTES": 0, + "G_IM_SIZ_4b_TILE_BYTES": self.G_IM_SIZ_4b_BYTES, + "G_IM_SIZ_4b_LINE_BYTES": self.G_IM_SIZ_4b_BYTES, + "G_IM_SIZ_8b_BYTES": 1, + "G_IM_SIZ_8b_TILE_BYTES": self.G_IM_SIZ_8b_BYTES, + "G_IM_SIZ_8b_LINE_BYTES": self.G_IM_SIZ_8b_BYTES, + "G_IM_SIZ_16b_BYTES": 2, + "G_IM_SIZ_16b_TILE_BYTES": self.G_IM_SIZ_16b_BYTES, + "G_IM_SIZ_16b_LINE_BYTES": self.G_IM_SIZ_16b_BYTES, + "G_IM_SIZ_32b_BYTES": 4, + "G_IM_SIZ_32b_TILE_BYTES": 2, + "G_IM_SIZ_32b_LINE_BYTES": 2, + "G_IM_SIZ_4b_LOAD_BLOCK": self.G_IM_SIZ_16b, + "G_IM_SIZ_8b_LOAD_BLOCK": self.G_IM_SIZ_16b, + "G_IM_SIZ_16b_LOAD_BLOCK": self.G_IM_SIZ_16b, + "G_IM_SIZ_32b_LOAD_BLOCK": self.G_IM_SIZ_32b, + "G_IM_SIZ_4b_SHIFT": 2, + "G_IM_SIZ_8b_SHIFT": 1, + "G_IM_SIZ_16b_SHIFT": 0, + "G_IM_SIZ_32b_SHIFT": 0, + "G_IM_SIZ_4b_INCR": 3, + "G_IM_SIZ_8b_INCR": 1, + "G_IM_SIZ_16b_INCR": 0, + "G_IM_SIZ_32b_INCR": 0, + } + + # G_SETCOMBINE: color combine modes + + # Color combiner constants: + self.G_CCMUX_COMBINED = 0 + self.G_CCMUX_TEXEL0 = 1 + self.G_CCMUX_TEXEL1 = 2 + self.G_CCMUX_PRIMITIVE = 3 + self.G_CCMUX_SHADE = 4 + self.G_CCMUX_ENVIRONMENT = 5 + self.G_CCMUX_CENTER = 6 + self.G_CCMUX_SCALE = 6 + self.G_CCMUX_COMBINED_ALPHA = 7 + self.G_CCMUX_TEXEL0_ALPHA = 8 + self.G_CCMUX_TEXEL1_ALPHA = 9 + self.G_CCMUX_PRIMITIVE_ALPHA = 10 + self.G_CCMUX_SHADE_ALPHA = 11 + self.G_CCMUX_ENV_ALPHA = 12 + self.G_CCMUX_LOD_FRACTION = 13 + self.G_CCMUX_PRIM_LOD_FRAC = 14 + self.G_CCMUX_NOISE = 7 + self.G_CCMUX_K4 = 7 + self.G_CCMUX_K5 = 15 + self.G_CCMUX_1 = 6 + self.G_CCMUX_0 = 31 + + self.CCMUXDict = { + "COMBINED": 0, + "TEXEL0": 1, + "TEXEL1": 2, + "PRIMITIVE": 3, + "SHADE": 4, + "ENVIRONMENT": 5, + "CENTER": 6, + "SCALE": 6, + "COMBINED_ALPHA": 7, + "TEXEL0_ALPHA": 8, + "TEXEL1_ALPHA": 9, + "PRIMITIVE_ALPHA": 10, + "SHADE_ALPHA": 11, + "ENV_ALPHA": 12, + "LOD_FRACTION": 13, + "PRIM_LOD_FRAC": 14, + "NOISE": 7, + "K4": 7, + "K5": 15, + "1": 6, + "0": 31, + } + + self.ACMUXDict = { + "COMBINED": 0, + "TEXEL0": 1, + "TEXEL1": 2, + "PRIMITIVE": 3, + "SHADE": 4, + "ENVIRONMENT": 5, + "LOD_FRACTION": 0, + "PRIM_LOD_FRAC": 6, + "1": 6, + "0": 7, + } + + # Alpha combiner constants: + self.G_ACMUX_COMBINED = 0 + self.G_ACMUX_TEXEL0 = 1 + self.G_ACMUX_TEXEL1 = 2 + self.G_ACMUX_PRIMITIVE = 3 + self.G_ACMUX_SHADE = 4 + self.G_ACMUX_ENVIRONMENT = 5 + self.G_ACMUX_LOD_FRACTION = 0 + self.G_ACMUX_PRIM_LOD_FRAC = 6 + self.G_ACMUX_1 = 6 + self.G_ACMUX_0 = 7 + + # typical CC cycle 1 modes + self.G_CC_PRIMITIVE = "0", "0", "0", "PRIMITIVE", "0", "0", "0", "PRIMITIVE" + self.G_CC_SHADE = "0", "0", "0", "SHADE", "0", "0", "0", "SHADE" + + self.G_CC_MODULATEI = "TEXEL0", "0", "SHADE", "0", "0", "0", "0", "SHADE" + self.G_CC_MODULATEIDECALA = "TEXEL0", "0", "SHADE", "0", "0", "0", "0", "TEXEL0" + self.G_CC_MODULATEIFADE = "TEXEL0", "0", "SHADE", "0", "0", "0", "0", "ENVIRONMENT" + + self.G_CC_MODULATERGB = self.G_CC_MODULATEI + self.G_CC_MODULATERGBDECALA = self.G_CC_MODULATEIDECALA + self.G_CC_MODULATERGBFADE = self.G_CC_MODULATEIFADE + + self.G_CC_MODULATEIA = "TEXEL0", "0", "SHADE", "0", "TEXEL0", "0", "SHADE", "0" + self.G_CC_MODULATEIFADEA = "TEXEL0", "0", "SHADE", "0", "TEXEL0", "0", "ENVIRONMENT", "0" + + self.G_CC_MODULATEFADE = "TEXEL0", "0", "SHADE", "0", "ENVIRONMENT", "0", "TEXEL0", "0" + + self.G_CC_MODULATERGBA = self.G_CC_MODULATEIA + self.G_CC_MODULATERGBFADEA = self.G_CC_MODULATEIFADEA + + self.G_CC_MODULATEI_PRIM = "TEXEL0", "0", "PRIMITIVE", "0", "0", "0", "0", "PRIMITIVE" + self.G_CC_MODULATEIA_PRIM = "TEXEL0", "0", "PRIMITIVE", "0", "TEXEL0", "0", "PRIMITIVE", "0" + self.G_CC_MODULATEIDECALA_PRIM = "TEXEL0", "0", "PRIMITIVE", "0", "0", "0", "0", "TEXEL0" + + self.G_CC_MODULATERGB_PRIM = self.G_CC_MODULATEI_PRIM + self.G_CC_MODULATERGBA_PRIM = self.G_CC_MODULATEIA_PRIM + self.G_CC_MODULATERGBDECALA_PRIM = self.G_CC_MODULATEIDECALA_PRIM + + self.G_CC_FADE = "SHADE", "0", "ENVIRONMENT", "0", "SHADE", "0", "ENVIRONMENT", "0" + self.G_CC_FADEA = "TEXEL0", "0", "ENVIRONMENT", "0", "TEXEL0", "0", "ENVIRONMENT", "0" + + self.G_CC_DECALRGB = "0", "0", "0", "TEXEL0", "0", "0", "0", "SHADE" + self.G_CC_DECALRGBA = "0", "0", "0", "TEXEL0", "0", "0", "0", "TEXEL0" + self.G_CC_DECALFADE = "0", "0", "0", "TEXEL0", "0", "0", "0", "ENVIRONMENT" + + self.G_CC_DECALFADEA = "0", "0", "0", "TEXEL0", "TEXEL0", "0", "ENVIRONMENT", "0" + + self.G_CC_BLENDI = "ENVIRONMENT", "SHADE", "TEXEL0", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_BLENDIA = "ENVIRONMENT", "SHADE", "TEXEL0", "SHADE", "TEXEL0", "0", "SHADE", "0" + self.G_CC_BLENDIDECALA = "ENVIRONMENT", "SHADE", "TEXEL0", "SHADE", "0", "0", "0", "TEXEL0" + + self.G_CC_BLENDRGBA = "TEXEL0", "SHADE", "TEXEL0_ALPHA", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_BLENDRGBDECALA = "TEXEL0", "SHADE", "TEXEL0_ALPHA", "SHADE", "0", "0", "0", "TEXEL0" + self.G_CC_BLENDRGBFADEA = "TEXEL0", "SHADE", "TEXEL0_ALPHA", "SHADE", "0", "0", "0", "ENVIRONMENT" + + self.G_CC_ADDRGB = "TEXEL0", "0", "TEXEL0", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_ADDRGBDECALA = "TEXEL0", "0", "TEXEL0", "SHADE", "0", "0", "0", "TEXEL0" + self.G_CC_ADDRGBFADE = "TEXEL0", "0", "TEXEL0", "SHADE", "0", "0", "0", "ENVIRONMENT" + + self.G_CC_REFLECTRGB = "ENVIRONMENT", "0", "TEXEL0", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_REFLECTRGBDECALA = "ENVIRONMENT", "0", "TEXEL0", "SHADE", "0", "0", "0", "TEXEL0" + + self.G_CC_HILITERGB = "PRIMITIVE", "SHADE", "TEXEL0", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_HILITERGBA = "PRIMITIVE", "SHADE", "TEXEL0", "SHADE", "PRIMITIVE", "SHADE", "TEXEL0", "SHADE" + self.G_CC_HILITERGBDECALA = "PRIMITIVE", "SHADE", "TEXEL0", "SHADE", "0", "0", "0", "TEXEL0" + + self.G_CC_SHADEDECALA = "0", "0", "0", "SHADE", "0", "0", "0", "TEXEL0" + self.G_CC_SHADEFADEA = "0", "0", "0", "SHADE", "0", "0", "0", "ENVIRONMENT" + + self.G_CC_BLENDPE = "PRIMITIVE", "ENVIRONMENT", "TEXEL0", "ENVIRONMENT", "TEXEL0", "0", "SHADE", "0" + self.G_CC_BLENDPEDECALA = "PRIMITIVE", "ENVIRONMENT", "TEXEL0", "ENVIRONMENT", "0", "0", "0", "TEXEL0" + + # oddball modes + self._G_CC_BLENDPE = "ENVIRONMENT", "PRIMITIVE", "TEXEL0", "PRIMITIVE", "TEXEL0", "0", "SHADE", "0" + self._G_CC_BLENDPEDECALA = "ENVIRONMENT", "PRIMITIVE", "TEXEL0", "PRIMITIVE", "0", "0", "0", "TEXEL0" + self._G_CC_TWOCOLORTEX = "PRIMITIVE", "SHADE", "TEXEL0", "SHADE", "0", "0", "0", "SHADE" + + # used for 1-cycle sparse mip-maps, primitive color has color of lowest LOD + self._G_CC_SPARSEST = ( + "PRIMITIVE", + "TEXEL0", + "LOD_FRACTION", + "TEXEL0", + "PRIMITIVE", + "TEXEL0", + "LOD_FRACTION", + "TEXEL0", + ) + self.G_CC_TEMPLERP = ( + "TEXEL1", + "TEXEL0", + "PRIM_LOD_FRAC", + "TEXEL0", + "TEXEL1", + "TEXEL0", + "PRIM_LOD_FRAC", + "TEXEL0", + ) + + # typical CC cycle 1 modes, usually followed by other cycle 2 modes + self.G_CC_TRILERP = "TEXEL1", "TEXEL0", "LOD_FRACTION", "TEXEL0", "TEXEL1", "TEXEL0", "LOD_FRACTION", "TEXEL0" + self.G_CC_INTERFERENCE = "TEXEL0", "0", "TEXEL1", "0", "TEXEL0", "0", "TEXEL1", "0" + + self.G_CC_1CYUV2RGB = "TEXEL0", "K4", "K5", "TEXEL0", "0", "0", "0", "SHADE" + self.G_CC_YUV2RGB = "TEXEL1", "K4", "K5", "TEXEL1", "0", "0", "0", "0" + + # typical CC cycle 2 modes + self.G_CC_PASS2 = "0", "0", "0", "COMBINED", "0", "0", "0", "COMBINED" + self.G_CC_MODULATEI2 = "COMBINED", "0", "SHADE", "0", "0", "0", "0", "SHADE" + self.G_CC_MODULATEIA2 = "COMBINED", "0", "SHADE", "0", "COMBINED", "0", "SHADE", "0" + self.G_CC_MODULATERGB2 = self.G_CC_MODULATEI2 + self.G_CC_MODULATERGBA2 = self.G_CC_MODULATEIA2 + self.G_CC_MODULATEI_PRIM2 = "COMBINED", "0", "PRIMITIVE", "0", "0", "0", "0", "PRIMITIVE" + self.G_CC_MODULATEIA_PRIM2 = "COMBINED", "0", "PRIMITIVE", "0", "COMBINED", "0", "PRIMITIVE", "0" + self.G_CC_MODULATERGB_PRIM2 = self.G_CC_MODULATEI_PRIM2 + self.G_CC_MODULATERGBA_PRIM2 = self.G_CC_MODULATEIA_PRIM2 + self.G_CC_DECALRGB2 = "0", "0", "0", "COMBINED", "0", "0", "0", "SHADE" + + self.G_CC_DECALRGBA2 = "COMBINED", "SHADE", "COMBINED_ALPHA", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_BLENDI2 = "ENVIRONMENT", "SHADE", "COMBINED", "SHADE", "0", "0", "0", "SHADE" + self.G_CC_BLENDIA2 = "ENVIRONMENT", "SHADE", "COMBINED", "SHADE", "COMBINED", "0", "SHADE", "0" + self.G_CC_CHROMA_KEY2 = "TEXEL0", "CENTER", "SCALE", "0", "0", "0", "0", "0" + self.G_CC_HILITERGB2 = "ENVIRONMENT", "COMBINED", "TEXEL0", "COMBINED", "0", "0", "0", "SHADE" + self.G_CC_HILITERGBA2 = ( + "ENVIRONMENT", + "COMBINED", + "TEXEL0", + "COMBINED", + "ENVIRONMENT", + "COMBINED", + "TEXEL0", + "COMBINED", + ) + self.G_CC_HILITERGBDECALA2 = "ENVIRONMENT", "COMBINED", "TEXEL0", "COMBINED", "0", "0", "0", "TEXEL0" + self.G_CC_HILITERGBPASSA2 = "ENVIRONMENT", "COMBINED", "TEXEL0", "COMBINED", "0", "0", "0", "COMBINED" + + # G_SETOTHERMODE_L sft: shift count + + self.G_MDSFT_ALPHACOMPARE = G_MDSFT_ALPHACOMPARE = 0 + self.G_MDSFT_ZSRCSEL = G_MDSFT_ZSRCSEL = 2 + self.G_MDSFT_RENDERMODE = G_MDSFT_RENDERMODE = 3 + self.G_MDSFT_BLENDER = G_MDSFT_BLENDER = 16 + + # G_SETOTHERMODE_H sft: shift count + + self.G_MDSFT_BLENDMASK = G_MDSFT_BLENDMASK = 0 # unsupported + self.G_MDSFT_ALPHADITHER = G_MDSFT_ALPHADITHER = 4 + self.G_MDSFT_RGBDITHER = G_MDSFT_RGBDITHER = 6 + + self.G_MDSFT_COMBKEY = G_MDSFT_COMBKEY = 8 + self.G_MDSFT_TEXTCONV = G_MDSFT_TEXTCONV = 9 + self.G_MDSFT_TEXTFILT = G_MDSFT_TEXTFILT = 12 + self.G_MDSFT_TEXTLUT = G_MDSFT_TEXTLUT = 14 + self.G_MDSFT_TEXTLOD = G_MDSFT_TEXTLOD = 16 + self.G_MDSFT_TEXTDETAIL = G_MDSFT_TEXTDETAIL = 17 + self.G_MDSFT_TEXTPERSP = G_MDSFT_TEXTPERSP = 19 + self.G_MDSFT_CYCLETYPE = G_MDSFT_CYCLETYPE = 20 + self.G_MDSFT_COLORDITHER = G_MDSFT_COLORDITHER = 22 # unsupported in HW 2.0 + self.G_MDSFT_PIPELINE = G_MDSFT_PIPELINE = 23 + + # G_SETOTHERMODE_H gPipelineMode + self.G_PM_1PRIMITIVE = 1 << G_MDSFT_PIPELINE + self.G_PM_NPRIMITIVE = 0 << G_MDSFT_PIPELINE + + # G_SETOTHERMODE_H gSetCycleType + self.G_CYC_1CYCLE = 0 << G_MDSFT_CYCLETYPE + self.G_CYC_2CYCLE = 1 << G_MDSFT_CYCLETYPE + self.G_CYC_COPY = 2 << G_MDSFT_CYCLETYPE + self.G_CYC_FILL = 3 << G_MDSFT_CYCLETYPE + + # G_SETOTHERMODE_H gSetTexturePersp + self.G_TP_NONE = 0 << G_MDSFT_TEXTPERSP + self.G_TP_PERSP = 1 << G_MDSFT_TEXTPERSP + + # G_SETOTHERMODE_H gSetTextureDetail + self.G_TD_CLAMP = 0 << G_MDSFT_TEXTDETAIL + self.G_TD_SHARPEN = 1 << G_MDSFT_TEXTDETAIL + self.G_TD_DETAIL = 2 << G_MDSFT_TEXTDETAIL + + # G_SETOTHERMODE_H gSetTextureLOD + self.G_TL_TILE = 0 << G_MDSFT_TEXTLOD + self.G_TL_LOD = 1 << G_MDSFT_TEXTLOD + + # G_SETOTHERMODE_H gSetTextureLUT + self.G_TT_NONE = 0 << G_MDSFT_TEXTLUT + self.G_TT_RGBA16 = 2 << G_MDSFT_TEXTLUT + self.G_TT_IA16 = 3 << G_MDSFT_TEXTLUT + + # G_SETOTHERMODE_H gSetTextureFilter + self.G_TF_POINT = 0 << G_MDSFT_TEXTFILT + self.G_TF_AVERAGE = 3 << G_MDSFT_TEXTFILT + self.G_TF_BILERP = 2 << G_MDSFT_TEXTFILT + + # G_SETOTHERMODE_H gSetTextureConvert + self.G_TC_CONV = 0 << G_MDSFT_TEXTCONV + self.G_TC_FILTCONV = 5 << G_MDSFT_TEXTCONV + self.G_TC_FILT = 6 << G_MDSFT_TEXTCONV + + # G_SETOTHERMODE_H gSetCombineKey + self.G_CK_NONE = 0 << G_MDSFT_COMBKEY + self.G_CK_KEY = 1 << G_MDSFT_COMBKEY + + # G_SETOTHERMODE_H gSetColorDither + self.G_CD_MAGICSQ = 0 << G_MDSFT_RGBDITHER + self.G_CD_BAYER = 1 << G_MDSFT_RGBDITHER + self.G_CD_NOISE = 2 << G_MDSFT_RGBDITHER + + if not _HW_VERSION_1: + self.G_CD_DISABLE = 3 << G_MDSFT_RGBDITHER + self.G_CD_ENABLE = self.G_CD_NOISE # HW 1.0 compatibility mode + else: + self.G_CD_ENABLE = 1 << G_MDSFT_COLORDITHER + self.G_CD_DISABLE = 0 << G_MDSFT_COLORDITHER + + # G_SETOTHERMODE_H gSetAlphaDither + self.G_AD_PATTERN = 0 << G_MDSFT_ALPHADITHER + self.G_AD_NOTPATTERN = 1 << G_MDSFT_ALPHADITHER + self.G_AD_NOISE = 2 << G_MDSFT_ALPHADITHER + self.G_AD_DISABLE = 3 << G_MDSFT_ALPHADITHER + + # G_SETOTHERMODE_L gSetAlphaCompare + self.G_AC_NONE = 0 << G_MDSFT_ALPHACOMPARE + self.G_AC_THRESHOLD = 1 << G_MDSFT_ALPHACOMPARE + self.G_AC_DITHER = 3 << G_MDSFT_ALPHACOMPARE + + # G_SETOTHERMODE_L gSetDepthSource + self.G_ZS_PIXEL = 0 << G_MDSFT_ZSRCSEL + self.G_ZS_PRIM = 1 << G_MDSFT_ZSRCSEL + + # G_SETOTHERMODE_L gSetRenderMode + self.AA_EN = AA_EN = 0x8 + self.Z_CMP = Z_CMP = 0x10 + self.Z_UPD = Z_UPD = 0x20 + self.IM_RD = IM_RD = 0x40 + self.CLR_ON_CVG = CLR_ON_CVG = 0x80 + self.CVG_DST_CLAMP = CVG_DST_CLAMP = 0 + self.CVG_DST_WRAP = CVG_DST_WRAP = 0x100 + self.CVG_DST_FULL = CVG_DST_FULL = 0x200 + self.CVG_DST_SAVE = CVG_DST_SAVE = 0x300 + self.ZMODE_OPA = ZMODE_OPA = 0 + self.ZMODE_INTER = ZMODE_INTER = 0x400 + self.ZMODE_XLU = ZMODE_XLU = 0x800 + self.ZMODE_DEC = ZMODE_DEC = 0xC00 + self.CVG_X_ALPHA = CVG_X_ALPHA = 0x1000 + self.ALPHA_CVG_SEL = ALPHA_CVG_SEL = 0x2000 + self.FORCE_BL = FORCE_BL = 0x4000 + self.TEX_EDGE = TEX_EDGE = 0x0000 # used to be 0x8000 + + self.G_BL_CLR_IN = G_BL_CLR_IN = 0 + self.G_BL_CLR_MEM = G_BL_CLR_MEM = 1 + self.G_BL_CLR_BL = G_BL_CLR_BL = 2 + self.G_BL_CLR_FOG = G_BL_CLR_FOG = 3 + self.G_BL_1MA = G_BL_1MA = 0 + self.G_BL_A_MEM = G_BL_A_MEM = 1 + self.G_BL_A_IN = G_BL_A_IN = 0 + self.G_BL_A_FOG = G_BL_A_FOG = 1 + self.G_BL_A_SHADE = G_BL_A_SHADE = 2 + self.G_BL_1 = G_BL_1 = 2 + self.G_BL_0 = G_BL_0 = 3 + + self.cvgDstDict = { + CVG_DST_CLAMP: "CVG_DST_CLAMP", + CVG_DST_WRAP: "CVG_DST_WRAP", + CVG_DST_FULL: "CVG_DST_FULL", + CVG_DST_SAVE: "CVG_DST_SAVE", + } + + self.zmodeDict = { + ZMODE_OPA: "ZMODE_OPA", + ZMODE_INTER: "ZMODE_INTER", + ZMODE_XLU: "ZMODE_XLU", + ZMODE_DEC: "ZMODE_DEC", + } + + self.blendColorDict = { + G_BL_CLR_IN: "G_BL_CLR_IN", + G_BL_CLR_MEM: "G_BL_CLR_MEM", + G_BL_CLR_BL: "G_BL_CLR_BL", + G_BL_CLR_FOG: "G_BL_CLR_FOG", + } + + self.blendAlphaDict = { + G_BL_A_IN: "G_BL_A_IN", + G_BL_A_FOG: "G_BL_A_FOG", + G_BL_A_SHADE: "G_BL_A_SHADE", + G_BL_0: "G_BL_0", + } + + self.blendMixDict = { + G_BL_1MA: "G_BL_1MA", + G_BL_A_MEM: "G_BL_A_MEM", + G_BL_1: "G_BL_1", + G_BL_0: "G_BL_0", + } + + def GBL_c1(m1a, m1b, m2a, m2b): + return (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 + + def GBL_c2(m1a, m1b, m2a, m2b): + return (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 + + def RM_AA_ZB_OPA_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_RA_ZB_OPA_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | CVG_DST_CLAMP + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_ZB_XLU_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | IM_RD + | CVG_DST_WRAP + | CLR_ON_CVG + | FORCE_BL + | ZMODE_XLU + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_OPA_DECAL(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | IM_RD + | CVG_DST_WRAP + | ALPHA_CVG_SEL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_RA_ZB_OPA_DECAL(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | CVG_DST_WRAP + | ALPHA_CVG_SEL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_ZB_XLU_DECAL(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | IM_RD + | CVG_DST_WRAP + | CLR_ON_CVG + | FORCE_BL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_OPA_INTER(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | ALPHA_CVG_SEL + | ZMODE_INTER + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_RA_ZB_OPA_INTER(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | CVG_DST_CLAMP + | ALPHA_CVG_SEL + | ZMODE_INTER + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_ZB_XLU_INTER(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | IM_RD + | CVG_DST_WRAP + | CLR_ON_CVG + | FORCE_BL + | ZMODE_INTER + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_XLU_LINE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | FORCE_BL + | ZMODE_XLU + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_DEC_LINE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | IM_RD + | CVG_DST_SAVE + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | FORCE_BL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_TEX_EDGE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | ZMODE_OPA + | TEX_EDGE + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_ZB_TEX_INTER(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | ZMODE_INTER + | TEX_EDGE + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_ZB_SUB_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_FULL + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_ZB_PCL_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | ZMODE_OPA + | self.G_AC_DITHER + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_OPA_TERR(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_TEX_TERR(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | ZMODE_OPA + | TEX_EDGE + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_ZB_SUB_TERR(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | Z_CMP + | Z_UPD + | IM_RD + | CVG_DST_FULL + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_OPA_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_CLAMP + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_RA_OPA_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | CVG_DST_CLAMP + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_XLU_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_WRAP + | CLR_ON_CVG + | FORCE_BL + | ZMODE_OPA + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_XLU_LINE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | FORCE_BL + | ZMODE_OPA + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_DEC_LINE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_FULL + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | FORCE_BL + | ZMODE_OPA + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_TEX_EDGE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | ZMODE_OPA + | TEX_EDGE + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_SUB_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_FULL + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_AA_PCL_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_CLAMP + | ZMODE_OPA + | self.G_AC_DITHER + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_OPA_TERR(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_CLAMP + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_TEX_TERR(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | ZMODE_OPA + | TEX_EDGE + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_AA_SUB_TERR(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + AA_EN + | IM_RD + | CVG_DST_FULL + | ZMODE_OPA + | ALPHA_CVG_SEL + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_ZB_OPA_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | Z_UPD + | CVG_DST_FULL + | ALPHA_CVG_SEL + | ZMODE_OPA + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_ZB_XLU_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | IM_RD + | CVG_DST_FULL + | FORCE_BL + | ZMODE_XLU + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_ZB_OPA_DECAL(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | CVG_DST_FULL + | ALPHA_CVG_SEL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_A_MEM) + ) + + def RM_ZB_XLU_DECAL(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | IM_RD + | CVG_DST_FULL + | FORCE_BL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_ZB_CLD_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | IM_RD + | CVG_DST_SAVE + | FORCE_BL + | ZMODE_XLU + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_ZB_OVL_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | IM_RD + | CVG_DST_SAVE + | FORCE_BL + | ZMODE_DEC + | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + ) + + def RM_ZB_PCL_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + Z_CMP + | Z_UPD + | CVG_DST_FULL + | ZMODE_OPA + | self.G_AC_DITHER + | func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + ) + + def RM_OPA_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return CVG_DST_CLAMP | FORCE_BL | ZMODE_OPA | func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + + def RM_XLU_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return IM_RD | CVG_DST_FULL | FORCE_BL | ZMODE_OPA | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + + def RM_TEX_EDGE(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + CVG_DST_CLAMP + | CVG_X_ALPHA + | ALPHA_CVG_SEL + | FORCE_BL + | ZMODE_OPA + | TEX_EDGE + | AA_EN + | func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + ) + + def RM_CLD_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | func(G_BL_CLR_IN, G_BL_A_IN, G_BL_CLR_MEM, G_BL_1MA) + + def RM_PCL_SURF(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return ( + CVG_DST_FULL | FORCE_BL | ZMODE_OPA | self.G_AC_DITHER | func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + ) + + def RM_ADD(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return IM_RD | CVG_DST_SAVE | FORCE_BL | ZMODE_OPA | func(G_BL_CLR_IN, G_BL_A_FOG, G_BL_CLR_MEM, G_BL_1) + + def RM_NOOP(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return func(0, 0, 0, 0) + + def RM_VISCVG(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return IM_RD | FORCE_BL | func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_BL, G_BL_A_MEM) + + # for rendering to an 8-bit framebuffer + def RM_OPA_CI(clk): + func = GBL_c1 if clk == 1 else GBL_c2 + return CVG_DST_CLAMP | ZMODE_OPA | func(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + + self.G_RM_AA_ZB_OPA_SURF = RM_AA_ZB_OPA_SURF(1) + self.G_RM_AA_ZB_OPA_SURF2 = RM_AA_ZB_OPA_SURF(2) + self.G_RM_AA_ZB_XLU_SURF = RM_AA_ZB_XLU_SURF(1) + self.G_RM_AA_ZB_XLU_SURF2 = RM_AA_ZB_XLU_SURF(2) + self.G_RM_AA_ZB_OPA_DECAL = RM_AA_ZB_OPA_DECAL(1) + self.G_RM_AA_ZB_OPA_DECAL2 = RM_AA_ZB_OPA_DECAL(2) + self.G_RM_AA_ZB_XLU_DECAL = RM_AA_ZB_XLU_DECAL(1) + self.G_RM_AA_ZB_XLU_DECAL2 = RM_AA_ZB_XLU_DECAL(2) + self.G_RM_AA_ZB_OPA_INTER = RM_AA_ZB_OPA_INTER(1) + self.G_RM_AA_ZB_OPA_INTER2 = RM_AA_ZB_OPA_INTER(2) + self.G_RM_AA_ZB_XLU_INTER = RM_AA_ZB_XLU_INTER(1) + self.G_RM_AA_ZB_XLU_INTER2 = RM_AA_ZB_XLU_INTER(2) + self.G_RM_AA_ZB_XLU_LINE = RM_AA_ZB_XLU_LINE(1) + self.G_RM_AA_ZB_XLU_LINE2 = RM_AA_ZB_XLU_LINE(2) + self.G_RM_AA_ZB_DEC_LINE = RM_AA_ZB_DEC_LINE(1) + self.G_RM_AA_ZB_DEC_LINE2 = RM_AA_ZB_DEC_LINE(2) + self.G_RM_AA_ZB_TEX_EDGE = RM_AA_ZB_TEX_EDGE(1) + self.G_RM_AA_ZB_TEX_EDGE2 = RM_AA_ZB_TEX_EDGE(2) + self.G_RM_AA_ZB_TEX_INTER = RM_AA_ZB_TEX_INTER(1) + self.G_RM_AA_ZB_TEX_INTER2 = RM_AA_ZB_TEX_INTER(2) + self.G_RM_AA_ZB_SUB_SURF = RM_AA_ZB_SUB_SURF(1) + self.G_RM_AA_ZB_SUB_SURF2 = RM_AA_ZB_SUB_SURF(2) + self.G_RM_AA_ZB_PCL_SURF = RM_AA_ZB_PCL_SURF(1) + self.G_RM_AA_ZB_PCL_SURF2 = RM_AA_ZB_PCL_SURF(2) + self.G_RM_AA_ZB_OPA_TERR = RM_AA_ZB_OPA_TERR(1) + self.G_RM_AA_ZB_OPA_TERR2 = RM_AA_ZB_OPA_TERR(2) + self.G_RM_AA_ZB_TEX_TERR = RM_AA_ZB_TEX_TERR(1) + self.G_RM_AA_ZB_TEX_TERR2 = RM_AA_ZB_TEX_TERR(2) + self.G_RM_AA_ZB_SUB_TERR = RM_AA_ZB_SUB_TERR(1) + self.G_RM_AA_ZB_SUB_TERR2 = RM_AA_ZB_SUB_TERR(2) + + self.G_RM_RA_ZB_OPA_SURF = RM_RA_ZB_OPA_SURF(1) + self.G_RM_RA_ZB_OPA_SURF2 = RM_RA_ZB_OPA_SURF(2) + self.G_RM_RA_ZB_OPA_DECAL = RM_RA_ZB_OPA_DECAL(1) + self.G_RM_RA_ZB_OPA_DECAL2 = RM_RA_ZB_OPA_DECAL(2) + self.G_RM_RA_ZB_OPA_INTER = RM_RA_ZB_OPA_INTER(1) + self.G_RM_RA_ZB_OPA_INTER2 = RM_RA_ZB_OPA_INTER(2) + + self.G_RM_AA_OPA_SURF = RM_AA_OPA_SURF(1) + self.G_RM_AA_OPA_SURF2 = RM_AA_OPA_SURF(2) + self.G_RM_AA_XLU_SURF = RM_AA_XLU_SURF(1) + self.G_RM_AA_XLU_SURF2 = RM_AA_XLU_SURF(2) + self.G_RM_AA_XLU_LINE = RM_AA_XLU_LINE(1) + self.G_RM_AA_XLU_LINE2 = RM_AA_XLU_LINE(2) + self.G_RM_AA_DEC_LINE = RM_AA_DEC_LINE(1) + self.G_RM_AA_DEC_LINE2 = RM_AA_DEC_LINE(2) + self.G_RM_AA_TEX_EDGE = RM_AA_TEX_EDGE(1) + self.G_RM_AA_TEX_EDGE2 = RM_AA_TEX_EDGE(2) + self.G_RM_AA_SUB_SURF = RM_AA_SUB_SURF(1) + self.G_RM_AA_SUB_SURF2 = RM_AA_SUB_SURF(2) + self.G_RM_AA_PCL_SURF = RM_AA_PCL_SURF(1) + self.G_RM_AA_PCL_SURF2 = RM_AA_PCL_SURF(2) + self.G_RM_AA_OPA_TERR = RM_AA_OPA_TERR(1) + self.G_RM_AA_OPA_TERR2 = RM_AA_OPA_TERR(2) + self.G_RM_AA_TEX_TERR = RM_AA_TEX_TERR(1) + self.G_RM_AA_TEX_TERR2 = RM_AA_TEX_TERR(2) + self.G_RM_AA_SUB_TERR = RM_AA_SUB_TERR(1) + self.G_RM_AA_SUB_TERR2 = RM_AA_SUB_TERR(2) + + self.G_RM_RA_OPA_SURF = RM_RA_OPA_SURF(1) + self.G_RM_RA_OPA_SURF2 = RM_RA_OPA_SURF(2) + + self.G_RM_ZB_OPA_SURF = RM_ZB_OPA_SURF(1) + self.G_RM_ZB_OPA_SURF2 = RM_ZB_OPA_SURF(2) + self.G_RM_ZB_XLU_SURF = RM_ZB_XLU_SURF(1) + self.G_RM_ZB_XLU_SURF2 = RM_ZB_XLU_SURF(2) + self.G_RM_ZB_OPA_DECAL = RM_ZB_OPA_DECAL(1) + self.G_RM_ZB_OPA_DECAL2 = RM_ZB_OPA_DECAL(2) + self.G_RM_ZB_XLU_DECAL = RM_ZB_XLU_DECAL(1) + self.G_RM_ZB_XLU_DECAL2 = RM_ZB_XLU_DECAL(2) + self.G_RM_ZB_CLD_SURF = RM_ZB_CLD_SURF(1) + self.G_RM_ZB_CLD_SURF2 = RM_ZB_CLD_SURF(2) + self.G_RM_ZB_OVL_SURF = RM_ZB_OVL_SURF(1) + self.G_RM_ZB_OVL_SURF2 = RM_ZB_OVL_SURF(2) + self.G_RM_ZB_PCL_SURF = RM_ZB_PCL_SURF(1) + self.G_RM_ZB_PCL_SURF2 = RM_ZB_PCL_SURF(2) + + self.G_RM_OPA_SURF = RM_OPA_SURF(1) + self.G_RM_OPA_SURF2 = RM_OPA_SURF(2) + self.G_RM_XLU_SURF = RM_XLU_SURF(1) + self.G_RM_XLU_SURF2 = RM_XLU_SURF(2) + self.G_RM_CLD_SURF = RM_CLD_SURF(1) + self.G_RM_CLD_SURF2 = RM_CLD_SURF(2) + self.G_RM_TEX_EDGE = RM_TEX_EDGE(1) + self.G_RM_TEX_EDGE2 = RM_TEX_EDGE(2) + self.G_RM_PCL_SURF = RM_PCL_SURF(1) + self.G_RM_PCL_SURF2 = RM_PCL_SURF(2) + self.G_RM_ADD = RM_ADD(1) + self.G_RM_ADD2 = RM_ADD(2) + self.G_RM_NOOP = RM_NOOP(1) + self.G_RM_NOOP2 = RM_NOOP(2) + self.G_RM_VISCVG = RM_VISCVG(1) + self.G_RM_VISCVG2 = RM_VISCVG(2) + self.G_RM_OPA_CI = RM_OPA_CI(1) + self.G_RM_OPA_CI2 = RM_OPA_CI(2) + + self.G_RM_FOG_SHADE_A = GBL_c1(G_BL_CLR_FOG, G_BL_A_SHADE, G_BL_CLR_IN, G_BL_1MA) + self.G_RM_FOG_PRIM_A = GBL_c1(G_BL_CLR_FOG, G_BL_A_FOG, G_BL_CLR_IN, G_BL_1MA) + self.G_RM_PASS = GBL_c1(G_BL_CLR_IN, G_BL_0, G_BL_CLR_IN, G_BL_1) + + # G_SETCONVERT: K0-5 + + self.G_CV_K0 = 175 + self.G_CV_K1 = -43 + self.G_CV_K2 = -89 + self.G_CV_K3 = 222 + self.G_CV_K4 = 114 + self.G_CV_K5 = 42 + + # G_SETSCISSOR: interlace mode + + self.G_SC_NON_INTERLACE = 0 + self.G_SC_ODD_INTERLACE = 3 + self.G_SC_EVEN_INTERLACE = 2 + + # flags to inhibit pushing of the display list (on branch) + self.G_DL_PUSH = 0x00 + self.G_DL_NOPUSH = 0x01 + + # Some structs here + + self.G_MAXZ = 0x03FF # 10 bits of integer screen-Z precision + + # more structs here + + """ MOVEMEM indices Each of these indexes an entry in a dmem table which points to a 1-4 word block of dmem in which to store a 1-4 word DMA. - ''' - - if F3DEX_GBI_2: - # 0,4 are reserved by G_MTX - self.G_MV_MMTX = 2 - self.G_MV_PMTX = 6 - self.G_MV_VIEWPORT = 8 - self.G_MV_LIGHT = 10 - self.G_MV_POINT = 12 - self.G_MV_MATRIX = 14 # NOTE: this is in moveword table - self.G_MVO_LOOKATX = (0*24) - self.G_MVO_LOOKATY = (1*24) - self.G_MVO_L0 = (2*24) - self.G_MVO_L1 = (3*24) - self.G_MVO_L2 = (4*24) - self.G_MVO_L3 = (5*24) - self.G_MVO_L4 = (6*24) - self.G_MVO_L5 = (7*24) - self.G_MVO_L6 = (8*24) - self.G_MVO_L7 = (9*24) - else: - self.G_MV_VIEWPORT = 0x80 - self.G_MV_LOOKATY = 0x82 - self.G_MV_LOOKATX = 0x84 - self.G_MV_L0 = 0x86 - self.G_MV_L1 = 0x88 - self.G_MV_L2 = 0x8a - self.G_MV_L3 = 0x8c - self.G_MV_L4 = 0x8e - self.G_MV_L5 = 0x90 - self.G_MV_L6 = 0x92 - self.G_MV_L7 = 0x94 - self.G_MV_TXTATT = 0x96 - self.G_MV_MATRIX_1 = 0x9e # NOTE: this is in moveword table - self.G_MV_MATRIX_2 = 0x98 - self.G_MV_MATRIX_3 = 0x9a - self.G_MV_MATRIX_4 = 0x9c + """ - ''' + if F3DEX_GBI_2: + # 0,4 are reserved by G_MTX + self.G_MV_MMTX = 2 + self.G_MV_PMTX = 6 + self.G_MV_VIEWPORT = 8 + self.G_MV_LIGHT = 10 + self.G_MV_POINT = 12 + self.G_MV_MATRIX = 14 # NOTE: this is in moveword table + self.G_MVO_LOOKATX = 0 * 24 + self.G_MVO_LOOKATY = 1 * 24 + self.G_MVO_L0 = 2 * 24 + self.G_MVO_L1 = 3 * 24 + self.G_MVO_L2 = 4 * 24 + self.G_MVO_L3 = 5 * 24 + self.G_MVO_L4 = 6 * 24 + self.G_MVO_L5 = 7 * 24 + self.G_MVO_L6 = 8 * 24 + self.G_MVO_L7 = 9 * 24 + else: + self.G_MV_VIEWPORT = 0x80 + self.G_MV_LOOKATY = 0x82 + self.G_MV_LOOKATX = 0x84 + self.G_MV_L0 = 0x86 + self.G_MV_L1 = 0x88 + self.G_MV_L2 = 0x8A + self.G_MV_L3 = 0x8C + self.G_MV_L4 = 0x8E + self.G_MV_L5 = 0x90 + self.G_MV_L6 = 0x92 + self.G_MV_L7 = 0x94 + self.G_MV_TXTATT = 0x96 + self.G_MV_MATRIX_1 = 0x9E # NOTE: this is in moveword table + self.G_MV_MATRIX_2 = 0x98 + self.G_MV_MATRIX_3 = 0x9A + self.G_MV_MATRIX_4 = 0x9C + + """ MOVEWORD indices Each of these indexes an entry in a dmem table which points to a word in dmem in dmem where an immediate word will be stored. - ''' - - self.G_MW_MATRIX = 0x00 # NOTE: also used by movemem - self.G_MW_NUMLIGHT = 0x02 - self.G_MW_CLIP = 0x04 - self.G_MW_SEGMENT = 0x06 - self.G_MW_FOG = 0x08 - self.G_MW_LIGHTCOL = 0x0a - if F3DEX_GBI_2: - self.G_MW_FORCEMTX = 0x0c - else: - self.G_MW_POINTS = 0x0c - self.G_MW_PERSPNORM = 0x0e + """ - - # These are offsets from the address in the dmem table - - self.G_MWO_NUMLIGHT = 0x00 - self.G_MWO_CLIP_RNX = 0x04 - self.G_MWO_CLIP_RNY = 0x0c - self.G_MWO_CLIP_RPX = 0x14 - self.G_MWO_CLIP_RPY = 0x1c - self.G_MWO_SEGMENT_0 = 0x00 - self.G_MWO_SEGMENT_1 = 0x01 - self.G_MWO_SEGMENT_2 = 0x02 - self.G_MWO_SEGMENT_3 = 0x03 - self.G_MWO_SEGMENT_4 = 0x04 - self.G_MWO_SEGMENT_5 = 0x05 - self.G_MWO_SEGMENT_6 = 0x06 - self.G_MWO_SEGMENT_7 = 0x07 - self.G_MWO_SEGMENT_8 = 0x08 - self.G_MWO_SEGMENT_9 = 0x09 - self.G_MWO_SEGMENT_A = 0x0a - self.G_MWO_SEGMENT_B = 0x0b - self.G_MWO_SEGMENT_C = 0x0c - self.G_MWO_SEGMENT_D = 0x0d - self.G_MWO_SEGMENT_E = 0x0e - self.G_MWO_SEGMENT_F = 0x0f - self.G_MWO_FOG = 0x00 - self.G_MWO_aLIGHT_1 = 0x00 - self.G_MWO_bLIGHT_1 = 0x04 + self.G_MW_MATRIX = 0x00 # NOTE: also used by movemem + self.G_MW_NUMLIGHT = 0x02 + self.G_MW_CLIP = 0x04 + self.G_MW_SEGMENT = 0x06 + self.G_MW_FOG = 0x08 + self.G_MW_LIGHTCOL = 0x0A + if F3DEX_GBI_2: + self.G_MW_FORCEMTX = 0x0C + else: + self.G_MW_POINTS = 0x0C + self.G_MW_PERSPNORM = 0x0E - if F3DEX_GBI_2: - self.G_MWO_aLIGHT_2 = 0x18 - self.G_MWO_bLIGHT_2 = 0x1c - self.G_MWO_aLIGHT_3 = 0x30 - self.G_MWO_bLIGHT_3 = 0x34 - self.G_MWO_aLIGHT_4 = 0x48 - self.G_MWO_bLIGHT_4 = 0x4c - self.G_MWO_aLIGHT_5 = 0x60 - self.G_MWO_bLIGHT_5 = 0x64 - self.G_MWO_aLIGHT_6 = 0x78 - self.G_MWO_bLIGHT_6 = 0x7c - self.G_MWO_aLIGHT_7 = 0x90 - self.G_MWO_bLIGHT_7 = 0x94 - self.G_MWO_aLIGHT_8 = 0xa8 - self.G_MWO_bLIGHT_8 = 0xac - else: - self.G_MWO_aLIGHT_2 = 0x20 - self.G_MWO_bLIGHT_2 = 0x24 - self.G_MWO_aLIGHT_3 = 0x40 - self.G_MWO_bLIGHT_3 = 0x44 - self.G_MWO_aLIGHT_4 = 0x60 - self.G_MWO_bLIGHT_4 = 0x64 - self.G_MWO_aLIGHT_5 = 0x80 - self.G_MWO_bLIGHT_5 = 0x84 - self.G_MWO_aLIGHT_6 = 0xa0 - self.G_MWO_bLIGHT_6 = 0xa4 - self.G_MWO_aLIGHT_7 = 0xc0 - self.G_MWO_bLIGHT_7 = 0xc4 - self.G_MWO_aLIGHT_8 = 0xe0 - self.G_MWO_bLIGHT_8 = 0xe4 + # These are offsets from the address in the dmem table - self.G_MWO_MATRIX_XX_XY_I = 0x00 - self.G_MWO_MATRIX_XZ_XW_I = 0x04 - self.G_MWO_MATRIX_YX_YY_I = 0x08 - self.G_MWO_MATRIX_YZ_YW_I = 0x0c - self.G_MWO_MATRIX_ZX_ZY_I = 0x10 - self.G_MWO_MATRIX_ZZ_ZW_I = 0x14 - self.G_MWO_MATRIX_WX_WY_I = 0x18 - self.G_MWO_MATRIX_WZ_WW_I = 0x1c - self.G_MWO_MATRIX_XX_XY_F = 0x20 - self.G_MWO_MATRIX_XZ_XW_F = 0x24 - self.G_MWO_MATRIX_YX_YY_F = 0x28 - self.G_MWO_MATRIX_YZ_YW_F = 0x2c - self.G_MWO_MATRIX_ZX_ZY_F = 0x30 - self.G_MWO_MATRIX_ZZ_ZW_F = 0x34 - self.G_MWO_MATRIX_WX_WY_F = 0x38 - self.G_MWO_MATRIX_WZ_WW_F = 0x3c - self.G_MWO_POINT_RGBA = 0x10 - self.G_MWO_POINT_ST = 0x14 - self.G_MWO_POINT_XYSCREEN = 0x18 - self.G_MWO_POINT_ZSCREEN = 0x1c + self.G_MWO_NUMLIGHT = 0x00 + self.G_MWO_CLIP_RNX = 0x04 + self.G_MWO_CLIP_RNY = 0x0C + self.G_MWO_CLIP_RPX = 0x14 + self.G_MWO_CLIP_RPY = 0x1C + self.G_MWO_SEGMENT_0 = 0x00 + self.G_MWO_SEGMENT_1 = 0x01 + self.G_MWO_SEGMENT_2 = 0x02 + self.G_MWO_SEGMENT_3 = 0x03 + self.G_MWO_SEGMENT_4 = 0x04 + self.G_MWO_SEGMENT_5 = 0x05 + self.G_MWO_SEGMENT_6 = 0x06 + self.G_MWO_SEGMENT_7 = 0x07 + self.G_MWO_SEGMENT_8 = 0x08 + self.G_MWO_SEGMENT_9 = 0x09 + self.G_MWO_SEGMENT_A = 0x0A + self.G_MWO_SEGMENT_B = 0x0B + self.G_MWO_SEGMENT_C = 0x0C + self.G_MWO_SEGMENT_D = 0x0D + self.G_MWO_SEGMENT_E = 0x0E + self.G_MWO_SEGMENT_F = 0x0F + self.G_MWO_FOG = 0x00 + self.G_MWO_aLIGHT_1 = 0x00 + self.G_MWO_bLIGHT_1 = 0x04 - - # Texturing macros + if F3DEX_GBI_2: + self.G_MWO_aLIGHT_2 = 0x18 + self.G_MWO_bLIGHT_2 = 0x1C + self.G_MWO_aLIGHT_3 = 0x30 + self.G_MWO_bLIGHT_3 = 0x34 + self.G_MWO_aLIGHT_4 = 0x48 + self.G_MWO_bLIGHT_4 = 0x4C + self.G_MWO_aLIGHT_5 = 0x60 + self.G_MWO_bLIGHT_5 = 0x64 + self.G_MWO_aLIGHT_6 = 0x78 + self.G_MWO_bLIGHT_6 = 0x7C + self.G_MWO_aLIGHT_7 = 0x90 + self.G_MWO_bLIGHT_7 = 0x94 + self.G_MWO_aLIGHT_8 = 0xA8 + self.G_MWO_bLIGHT_8 = 0xAC + else: + self.G_MWO_aLIGHT_2 = 0x20 + self.G_MWO_bLIGHT_2 = 0x24 + self.G_MWO_aLIGHT_3 = 0x40 + self.G_MWO_bLIGHT_3 = 0x44 + self.G_MWO_aLIGHT_4 = 0x60 + self.G_MWO_bLIGHT_4 = 0x64 + self.G_MWO_aLIGHT_5 = 0x80 + self.G_MWO_bLIGHT_5 = 0x84 + self.G_MWO_aLIGHT_6 = 0xA0 + self.G_MWO_bLIGHT_6 = 0xA4 + self.G_MWO_aLIGHT_7 = 0xC0 + self.G_MWO_bLIGHT_7 = 0xC4 + self.G_MWO_aLIGHT_8 = 0xE0 + self.G_MWO_bLIGHT_8 = 0xE4 - # These are also defined defined above for Sprite Microcode - self.G_TX_LOADTILE = 7 - self.G_TX_RENDERTILE = 0 + self.G_MWO_MATRIX_XX_XY_I = 0x00 + self.G_MWO_MATRIX_XZ_XW_I = 0x04 + self.G_MWO_MATRIX_YX_YY_I = 0x08 + self.G_MWO_MATRIX_YZ_YW_I = 0x0C + self.G_MWO_MATRIX_ZX_ZY_I = 0x10 + self.G_MWO_MATRIX_ZZ_ZW_I = 0x14 + self.G_MWO_MATRIX_WX_WY_I = 0x18 + self.G_MWO_MATRIX_WZ_WW_I = 0x1C + self.G_MWO_MATRIX_XX_XY_F = 0x20 + self.G_MWO_MATRIX_XZ_XW_F = 0x24 + self.G_MWO_MATRIX_YX_YY_F = 0x28 + self.G_MWO_MATRIX_YZ_YW_F = 0x2C + self.G_MWO_MATRIX_ZX_ZY_F = 0x30 + self.G_MWO_MATRIX_ZZ_ZW_F = 0x34 + self.G_MWO_MATRIX_WX_WY_F = 0x38 + self.G_MWO_MATRIX_WZ_WW_F = 0x3C + self.G_MWO_POINT_RGBA = 0x10 + self.G_MWO_POINT_ST = 0x14 + self.G_MWO_POINT_XYSCREEN = 0x18 + self.G_MWO_POINT_ZSCREEN = 0x1C - self.G_TX_NOMIRROR = 0 - self.G_TX_WRAP = 0 - self.G_TX_MIRROR = 0x1 - self.G_TX_CLAMP = 0x2 - self.G_TX_NOMASK = 0 - self.G_TX_NOLOD = 0 + # Texturing macros - ''' + # These are also defined defined above for Sprite Microcode + self.G_TX_LOADTILE = 7 + self.G_TX_RENDERTILE = 0 + + self.G_TX_NOMIRROR = 0 + self.G_TX_WRAP = 0 + self.G_TX_MIRROR = 0x1 + self.G_TX_CLAMP = 0x2 + self.G_TX_NOMASK = 0 + self.G_TX_NOLOD = 0 + + """ Dxt is the inverse of the number of 64-bit words in a line of the texture being loaded using the load_block command. If there are any 1's to the right of the 11th fractional bit, dxt should be rounded up. The following macros accomplish this. The 4b macros are a special case since 4-bit textures are loaded as 8-bit textures. Dxt is fixed point 1.11. RJM - ''' - self.G_TX_DXT_FRAC = 11 + """ + self.G_TX_DXT_FRAC = 11 - ''' + """ For RCP 2.0, the maximum number of texels that can be loaded using a load_block command is 2048. In order to load the total 4kB of Tmem, change the texel size when loading to be G_IM_SIZ_16b, @@ -1304,1778 +1558,2036 @@ class F3D: will be transparent if you use these macros. If you use the g*DPLoadBlock macros directly, you will need to handle this tile manipulation yourself. RJM. - ''' - - if _HW_VERSION_1: - self.G_TX_LDBLK_MAX_TXL = 4095 - else: - self.G_TX_LDBLK_MAX_TXL = 2047 + """ - - # Clipping Macros - self.FR_NEG_FRUSTRATIO_1 = 0x00000001 - self.FR_POS_FRUSTRATIO_1 = 0x0000ffff - self.FR_NEG_FRUSTRATIO_2 = 0x00000002 - self.FR_POS_FRUSTRATIO_2 = 0x0000fffe - self.FR_NEG_FRUSTRATIO_3 = 0x00000003 - self.FR_POS_FRUSTRATIO_3 = 0x0000fffd - self.FR_NEG_FRUSTRATIO_4 = 0x00000004 - self.FR_POS_FRUSTRATIO_4 = 0x0000fffc - self.FR_NEG_FRUSTRATIO_5 = 0x00000005 - self.FR_POS_FRUSTRATIO_5 = 0x0000fffb - self.FR_NEG_FRUSTRATIO_6 = 0x00000006 - self.FR_POS_FRUSTRATIO_6 = 0x0000fffa + if _HW_VERSION_1: + self.G_TX_LDBLK_MAX_TXL = 4095 + else: + self.G_TX_LDBLK_MAX_TXL = 2047 - self.G_BZ_PERSP = 0 - self.G_BZ_ORTHO = 1 + # Clipping Macros + self.FR_NEG_FRUSTRATIO_1 = 0x00000001 + self.FR_POS_FRUSTRATIO_1 = 0x0000FFFF + self.FR_NEG_FRUSTRATIO_2 = 0x00000002 + self.FR_POS_FRUSTRATIO_2 = 0x0000FFFE + self.FR_NEG_FRUSTRATIO_3 = 0x00000003 + self.FR_POS_FRUSTRATIO_3 = 0x0000FFFD + self.FR_NEG_FRUSTRATIO_4 = 0x00000004 + self.FR_POS_FRUSTRATIO_4 = 0x0000FFFC + self.FR_NEG_FRUSTRATIO_5 = 0x00000005 + self.FR_POS_FRUSTRATIO_5 = 0x0000FFFB + self.FR_NEG_FRUSTRATIO_6 = 0x00000006 + self.FR_POS_FRUSTRATIO_6 = 0x0000FFFA - - # Lighting Macros - self.numLights = { - 'NUMLIGHTS_0' : 1, - 'NUMLIGHTS_1' : 1, - 'NUMLIGHTS_2' : 2, - 'NUMLIGHTS_3' : 3, - 'NUMLIGHTS_4' : 4, - 'NUMLIGHTS_5' : 5, - 'NUMLIGHTS_6' : 6, - 'NUMLIGHTS_7' : 7, - } + self.G_BZ_PERSP = 0 + self.G_BZ_ORTHO = 1 - def GBL_c1(self, m1a, m1b, m2a, m2b): - return (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 - def GBL_c2(self, m1a, m1b, m2a, m2b): - return (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 + # Lighting Macros + self.numLights = { + "NUMLIGHTS_0": 1, + "NUMLIGHTS_1": 1, + "NUMLIGHTS_2": 2, + "NUMLIGHTS_3": 3, + "NUMLIGHTS_4": 4, + "NUMLIGHTS_5": 5, + "NUMLIGHTS_6": 6, + "NUMLIGHTS_7": 7, + } - # macros for command parsing - def GDMACMD(self, x): return (x) - def GIMMCMD(self, x): return (self.G_IMMFIRST-(x)) - def GRDPCMD(self, x): return (0xff-(x)) + def GBL_c1(self, m1a, m1b, m2a, m2b): + return (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 - def GPACK_RGBA5551(self, r, g, b, a): - return ((((r)<<8) & 0xf800) | \ - (((g)<<3) & 0x7c0) | \ - (((b)>>2) & 0x3e) | ((a) & 0x1)) - def GPACK_ZDZ(self, z, dz): - return ((z) << 2 | (dz)) + def GBL_c2(self, m1a, m1b, m2a, m2b): + return (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 - def TXL2WORDS(self, txls, b_txl): return int(max(1, ((txls)*(b_txl)/8))) - def CALC_DXT(self, width, b_txl): - return int(((1 << self.G_TX_DXT_FRAC) + self.TXL2WORDS(width, b_txl) -\ - 1) / self.TXL2WORDS(width, b_txl)) + # macros for command parsing + def GDMACMD(self, x): + return x + + def GIMMCMD(self, x): + return self.G_IMMFIRST - (x) + + def GRDPCMD(self, x): + return 0xFF - (x) + + def GPACK_RGBA5551(self, r, g, b, a): + return (((r) << 8) & 0xF800) | (((g) << 3) & 0x7C0) | (((b) >> 2) & 0x3E) | ((a) & 0x1) + + def GPACK_ZDZ(self, z, dz): + return (z) << 2 | (dz) + + def TXL2WORDS(self, txls, b_txl): + return int(max(1, ((txls) * (b_txl) / 8))) + + def CALC_DXT(self, width, b_txl): + return int(((1 << self.G_TX_DXT_FRAC) + self.TXL2WORDS(width, b_txl) - 1) / self.TXL2WORDS(width, b_txl)) + + def TXL2WORDS_4b(self, txls): + return int(max(1, ((txls) / 16))) + + def CALC_DXT_4b(self, width): + return int(((1 << self.G_TX_DXT_FRAC) + self.TXL2WORDS_4b(width) - 1) / self.TXL2WORDS_4b(width)) + + def NUML(self, n): + nVal = self.numLights[n] + return ((nVal) * 24) if self.F3DEX_GBI_2 else (((nVal) + 1) * 32 + 0x80000000) + + def getLightMWO_a(self, n): + if n == "G_MWO_aLIGHT_1": + return self.G_MWO_aLIGHT_1 + elif n == "G_MWO_aLIGHT_2": + return self.G_MWO_aLIGHT_2 + elif n == "G_MWO_aLIGHT_3": + return self.G_MWO_aLIGHT_3 + elif n == "G_MWO_aLIGHT_4": + return self.G_MWO_aLIGHT_4 + elif n == "G_MWO_aLIGHT_5": + return self.G_MWO_aLIGHT_5 + elif n == "G_MWO_aLIGHT_6": + return self.G_MWO_aLIGHT_6 + elif n == "G_MWO_aLIGHT_7": + return self.G_MWO_aLIGHT_7 + elif n == "G_MWO_aLIGHT_8": + return self.G_MWO_aLIGHT_8 + else: + raise PluginError("Invalid G_MWO_a value for lights: " + n) + + def getLightMWO_b(self, n): + if n == "G_MWO_bLIGHT_1": + return self.G_MWO_bLIGHT_1 + elif n == "G_MWO_bLIGHT_2": + return self.G_MWO_bLIGHT_2 + elif n == "G_MWO_bLIGHT_3": + return self.G_MWO_bLIGHT_3 + elif n == "G_MWO_bLIGHT_4": + return self.G_MWO_bLIGHT_4 + elif n == "G_MWO_bLIGHT_5": + return self.G_MWO_bLIGHT_5 + elif n == "G_MWO_bLIGHT_6": + return self.G_MWO_bLIGHT_6 + elif n == "G_MWO_bLIGHT_7": + return self.G_MWO_bLIGHT_7 + elif n == "G_MWO_bLIGHT_8": + return self.G_MWO_bLIGHT_8 + else: + raise PluginError("Invalid G_MWO_b value for lights: " + n) - def TXL2WORDS_4b(self, txls): return int(max(1, ((txls)/16))) - def CALC_DXT_4b(self, width): - return int(((1 << self.G_TX_DXT_FRAC) + self.TXL2WORDS_4b(width) - 1)/\ - self.TXL2WORDS_4b(width)) - - def NUML(self, n): - nVal = self.numLights[n] - return ((nVal)*24) if self.F3DEX_GBI_2 else (((nVal)+1)*32 + 0x80000000) - - def getLightMWO_a(self, n): - if n == 'G_MWO_aLIGHT_1': return self.G_MWO_aLIGHT_1 - elif n == 'G_MWO_aLIGHT_2': return self.G_MWO_aLIGHT_2 - elif n == 'G_MWO_aLIGHT_3': return self.G_MWO_aLIGHT_3 - elif n == 'G_MWO_aLIGHT_4': return self.G_MWO_aLIGHT_4 - elif n == 'G_MWO_aLIGHT_5': return self.G_MWO_aLIGHT_5 - elif n == 'G_MWO_aLIGHT_6': return self.G_MWO_aLIGHT_6 - elif n == 'G_MWO_aLIGHT_7': return self.G_MWO_aLIGHT_7 - elif n == 'G_MWO_aLIGHT_8': return self.G_MWO_aLIGHT_8 - else: raise PluginError('Invalid G_MWO_a value for lights: ' + n) - - def getLightMWO_b(self, n): - if n == 'G_MWO_bLIGHT_1': return self.G_MWO_bLIGHT_1 - elif n == 'G_MWO_bLIGHT_2': return self.G_MWO_bLIGHT_2 - elif n == 'G_MWO_bLIGHT_3': return self.G_MWO_bLIGHT_3 - elif n == 'G_MWO_bLIGHT_4': return self.G_MWO_bLIGHT_4 - elif n == 'G_MWO_bLIGHT_5': return self.G_MWO_bLIGHT_5 - elif n == 'G_MWO_bLIGHT_6': return self.G_MWO_bLIGHT_6 - elif n == 'G_MWO_bLIGHT_7': return self.G_MWO_bLIGHT_7 - elif n == 'G_MWO_bLIGHT_8': return self.G_MWO_bLIGHT_8 - else: raise PluginError('Invalid G_MWO_b value for lights: ' + n) def _SHIFTL(value, amount, mask): - return (int(value) & ((1 << mask) - 1)) << amount + return (int(value) & ((1 << mask) - 1)) << amount + MTX_SIZE = 64 VTX_SIZE = 16 GFX_SIZE = 8 VP_SIZE = 8 -LIGHT_SIZE = 16 # 12, but padded to 64bit alignment +LIGHT_SIZE = 16 # 12, but padded to 64bit alignment AMBIENT_SIZE = 8 HILITE_SIZE = 16 + class ExportCData: - def __init__(self, staticData, dynamicData, textureData): - self.staticData = staticData - self.dynamicData = dynamicData - self.textureData = textureData - - def all(self): - data = CData() - data.append(self.staticData) - data.append(self.dynamicData) - data.append(self.textureData) - return data + def __init__(self, staticData, dynamicData, textureData): + self.staticData = staticData + self.dynamicData = dynamicData + self.textureData = textureData + + def all(self): + data = CData() + data.append(self.staticData) + data.append(self.dynamicData) + data.append(self.textureData) + return data + class TextureExportSettings: - def __init__(self, texCSeparate, savePNG, includeDir, exportPath = ''): - self.texCSeparate = texCSeparate - self.savePNG = savePNG - self.includeDir = includeDir - self.exportPath = exportPath + def __init__(self, texCSeparate, savePNG, includeDir, exportPath=""): + self.texCSeparate = texCSeparate + self.savePNG = savePNG + self.includeDir = includeDir + self.exportPath = exportPath + # SetTileSize Scroll Data class FSetTileSizeScrollField: - def __init__(self): - self.s = 0 - self.t = 0 - self.interval = 1 + def __init__(self): + self.s = 0 + self.t = 0 + self.interval = 1 + def tile_func(direction: str, speed: int, cmd_num: int): - if speed == 0 or speed is None: - return None + if speed == 0 or speed is None: + return None - func = f'shift_{direction}' + func = f"shift_{direction}" - if speed < 0: - func += '_down' + if speed < 0: + func += "_down" + + return f"\t{func}(mat, {cmd_num}, PACK_TILESIZE(0, {abs(speed)}));" - return f'\t{func}(mat, {cmd_num}, PACK_TILESIZE(0, {abs(speed)}));' def get_sts_interval_vars(tex_num: str): - return f'intervalTex{tex_num}', f'curInterval{tex_num}' + return f"intervalTex{tex_num}", f"curInterval{tex_num}" + def get_tex_sts_code(tex: FSetTileSizeScrollField, tex_num: int, cmd_num: int): - variables = [] - # create func calls - lines = [ - tile_func('s', tex.s, cmd_num), - tile_func('t', tex.t, cmd_num), - ] - # filter lines - lines = [func for func in lines if func] - # add interval logic if needed - if len(lines) and tex.interval > 1: - # get interval and variable for tracking interval - interval, cur_interval = get_sts_interval_vars(tex_num) - # pass each var and its value to variables - variables.extend([(interval, tex.interval), (cur_interval, tex.interval)]) + variables = [] + # create func calls + lines = [ + tile_func("s", tex.s, cmd_num), + tile_func("t", tex.t, cmd_num), + ] + # filter lines + lines = [func for func in lines if func] + # add interval logic if needed + if len(lines) and tex.interval > 1: + # get interval and variable for tracking interval + interval, cur_interval = get_sts_interval_vars(tex_num) + # pass each var and its value to variables + variables.extend([(interval, tex.interval), (cur_interval, tex.interval)]) - # indent again for if statement - lines = [('\t' + func) for func in lines] + # indent again for if statement + lines = [("\t" + func) for func in lines] - lines = [ - f'\n\tif (--{cur_interval} <= 0) {{', - *lines, - f'\t\t{cur_interval} = {interval};', - '\t}' - ] - return variables, lines + lines = [f"\n\tif (--{cur_interval} <= 0) {{", *lines, f"\t\t{cur_interval} = {interval};", "\t}"] + return variables, lines def mat_tile_scroll( - mat: str, - tex0: FSetTileSizeScrollField, - tex1: FSetTileSizeScrollField, - cmd_num0: int, - cmd_num1: int + mat: str, tex0: FSetTileSizeScrollField, tex1: FSetTileSizeScrollField, cmd_num0: int, cmd_num1: int ): - func = f'void scroll_sts_{mat}()' - lines = [f'{func} {{'] + func = f"void scroll_sts_{mat}()" + lines = [f"{func} {{"] - tex0_variables, tex0_lines = get_tex_sts_code(tex0, 0, cmd_num0) - tex1_variables, tex1_lines = get_tex_sts_code(tex1, 1, cmd_num1) - static_variables = [*tex0_variables, *tex1_variables] + tex0_variables, tex0_lines = get_tex_sts_code(tex0, 0, cmd_num0) + tex1_variables, tex1_lines = get_tex_sts_code(tex1, 1, cmd_num1) + static_variables = [*tex0_variables, *tex1_variables] - for variable, val in static_variables: - lines.append(f'\tstatic int {variable} = {val};') - - lines.append(f'\tGfx *mat = segmented_to_virtual({mat});') - lines.extend(tex0_lines) - lines.extend(tex1_lines) - lines.append('};\n\n') + for variable, val in static_variables: + lines.append(f"\tstatic int {variable} = {val};") - return func, '\n'.join([line for line in lines if line]) + lines.append(f"\tGfx *mat = segmented_to_virtual({mat});") + lines.extend(tex0_lines) + lines.extend(tex1_lines) + lines.append("};\n\n") + + return func, "\n".join([line for line in lines if line]) class GfxFormatter: - def __init__(self, scrollMethod: ScrollMethod, texArrayBitSize): - self.scrollMethod: ScrollMethod = scrollMethod - self.texArrayBitSize = texArrayBitSize - self.tileScrollFunc = None # Used to add tile scroll func to headers - - def vertexScrollTemplate(self, fScrollData, name, count, - absFunc, signFunc, cosFunc, randomFloatFunc, randomSignFunc, segToVirtualFunc): - scrollDataFields = fScrollData.fields[0] - if scrollDataFields[0].animType == "None" and\ - scrollDataFields[1].animType == "None": - return '' + def __init__(self, scrollMethod: ScrollMethod, texArrayBitSize): + self.scrollMethod: ScrollMethod = scrollMethod + self.texArrayBitSize = texArrayBitSize + self.tileScrollFunc = None # Used to add tile scroll func to headers - data = 'void scroll_' + name + "() {\n" +\ - "\tint i = 0;\n" +\ - "\tint count = " + str(count) + ';\n' +\ - "\tint width = " + str(fScrollData.dimensions[0]) + ' * 0x20;\n' +\ - "\tint height = " + str(fScrollData.dimensions[1]) + ' * 0x20;' - - variables = "" - currentVars = "" - deltaCalculate = "" - checkOverflow = "" - scrolling = "" - increaseCurrentDelta = "" - for i in range(2): - field = 'XYZ'[i] - axis = ['width', 'height'][i] - if scrollDataFields[i].animType != "None": - currentVars += "\tstatic int current" + field + ' = 0;\n\tint delta' + field + ';\n' - checkOverflow += '\tif (' + absFunc + '(current' + field + ') > ' + axis + ') {\n' +\ - '\t\tdelta' + field + ' -= (int)(absi(current' + field + ') / ' + axis + ') * ' + axis +\ - ' * ' + signFunc + '(delta' + field + ');\n\t}\n' - scrolling += '\t\tvertices[i].n.tc[' + str(i) + '] += delta' + field + ';\n' - increaseCurrentDelta += '\tcurrent' + field + ' += delta' + field + ';' + def vertexScrollTemplate( + self, fScrollData, name, count, absFunc, signFunc, cosFunc, randomFloatFunc, randomSignFunc, segToVirtualFunc + ): + scrollDataFields = fScrollData.fields[0] + if scrollDataFields[0].animType == "None" and scrollDataFields[1].animType == "None": + return "" - if scrollDataFields[i].animType == "Linear": - deltaCalculate += '\tdelta' + field + ' = (int)(' + str(scrollDataFields[i].speed) + ' * 0x20) % ' + axis + ';\n' - elif scrollDataFields[i].animType == "Sine": - currentVars += '\tstatic int time' + field + ';\n' +\ - '\tfloat amplitude' + field + ' = ' + str(scrollDataFields[i].amplitude) + ';\n' +\ - '\tfloat frequency' + field + ' = ' + str(scrollDataFields[i].frequency) + ';\n' +\ - '\tfloat offset' + field + ' = ' + str(scrollDataFields[i].offset) + ';\n' + data = ( + "void scroll_" + + name + + "() {\n" + + "\tint i = 0;\n" + + "\tint count = " + + str(count) + + ";\n" + + "\tint width = " + + str(fScrollData.dimensions[0]) + + " * 0x20;\n" + + "\tint height = " + + str(fScrollData.dimensions[1]) + + " * 0x20;" + ) - deltaCalculate += '\tdelta' + field + ' = (int)(amplitude' + field + ' * frequency' +\ - field + ' * ' + cosFunc + '((frequency' + field + ' * time' + field + ' + offset' + field + \ - ') * (1024 * 16 - 1) / 6.28318530718) * 0x20);\n' - # Conversion from s10.5 to u16 - #checkOverflow += '\tif (frequency' + field + ' * current' + field + ' / 2 > 6.28318530718) {\n' +\ - # '\t\tcurrent' + field + ' -= 6.28318530718 * 2 / frequency' + field + ';\n\t}\n' - increaseCurrentDelta += '\ttime' + field + ' += 1;' - elif scrollDataFields[i].animType == "Noise": - deltaCalculate += '\tdelta' + field + ' = (int)(' + str(scrollDataFields[i].noiseAmplitude) + ' * 0x20 * ' +\ - randomFloatFunc + '() * ' + randomSignFunc + '()) % ' + axis + ';\n' - else: - raise PluginError("Unhandled scroll type: " + str(scrollDataFields[i].animType)) + variables = "" + currentVars = "" + deltaCalculate = "" + checkOverflow = "" + scrolling = "" + increaseCurrentDelta = "" + for i in range(2): + field = "XYZ"[i] + axis = ["width", "height"][i] + if scrollDataFields[i].animType != "None": + currentVars += "\tstatic int current" + field + " = 0;\n\tint delta" + field + ";\n" + checkOverflow += ( + "\tif (" + + absFunc + + "(current" + + field + + ") > " + + axis + + ") {\n" + + "\t\tdelta" + + field + + " -= (int)(absi(current" + + field + + ") / " + + axis + + ") * " + + axis + + " * " + + signFunc + + "(delta" + + field + + ");\n\t}\n" + ) + scrolling += "\t\tvertices[i].n.tc[" + str(i) + "] += delta" + field + ";\n" + increaseCurrentDelta += "\tcurrent" + field + " += delta" + field + ";" - return data + '\n' + variables + '\n' + currentVars +\ - '\tVtx *vertices = ' + segToVirtualFunc + '(' + name + ');\n\n' +\ - deltaCalculate + '\n' + checkOverflow + '\n' +\ - "\tfor (i = 0; i < count; i++) {\n" +\ - scrolling + '\t}\n' + increaseCurrentDelta + '\n}\n\n' + if scrollDataFields[i].animType == "Linear": + deltaCalculate += ( + "\tdelta" + field + " = (int)(" + str(scrollDataFields[i].speed) + " * 0x20) % " + axis + ";\n" + ) + elif scrollDataFields[i].animType == "Sine": + currentVars += ( + "\tstatic int time" + + field + + ";\n" + + "\tfloat amplitude" + + field + + " = " + + str(scrollDataFields[i].amplitude) + + ";\n" + + "\tfloat frequency" + + field + + " = " + + str(scrollDataFields[i].frequency) + + ";\n" + + "\tfloat offset" + + field + + " = " + + str(scrollDataFields[i].offset) + + ";\n" + ) - # Called for handling vertex texture scrolling. - def vertexScrollToC(self, fScrollData, name, vertexCount): - raise PluginError("Use of unimplemented GfxFormatter function vertexScrollToC.") + deltaCalculate += ( + "\tdelta" + + field + + " = (int)(amplitude" + + field + + " * frequency" + + field + + " * " + + cosFunc + + "((frequency" + + field + + " * time" + + field + + " + offset" + + field + + ") * (1024 * 16 - 1) / 6.28318530718) * 0x20);\n" + ) + # Conversion from s10.5 to u16 + # checkOverflow += '\tif (frequency' + field + ' * current' + field + ' / 2 > 6.28318530718) {\n' +\ + # '\t\tcurrent' + field + ' -= 6.28318530718 * 2 / frequency' + field + ';\n\t}\n' + increaseCurrentDelta += "\ttime" + field + " += 1;" + elif scrollDataFields[i].animType == "Noise": + deltaCalculate += ( + "\tdelta" + + field + + " = (int)(" + + str(scrollDataFields[i].noiseAmplitude) + + " * 0x20 * " + + randomFloatFunc + + "() * " + + randomSignFunc + + "()) % " + + axis + + ";\n" + ) + else: + raise PluginError("Unhandled scroll type: " + str(scrollDataFields[i].animType)) - # Called for building the entry point DL for drawing a model. - def drawToC(self, f3d, gfxList): - return gfxList.to_c(f3d) + return ( + data + + "\n" + + variables + + "\n" + + currentVars + + "\tVtx *vertices = " + + segToVirtualFunc + + "(" + + name + + ");\n\n" + + deltaCalculate + + "\n" + + checkOverflow + + "\n" + + "\tfor (i = 0; i < count; i++) {\n" + + scrolling + + "\t}\n" + + increaseCurrentDelta + + "\n}\n\n" + ) - # Called for creating a dynamic material using tile texture scrolling. - # ScrollMethod and DLFormat checks are already handled. - def tileScrollMaterialToC(self, f3d, fMaterial): - raise PluginError("No tile scroll implementation specified.") + # Called for handling vertex texture scrolling. + def vertexScrollToC(self, fScrollData, name, vertexCount): + raise PluginError("Use of unimplemented GfxFormatter function vertexScrollToC.") - # Modify static material using tile texture scrolling. - def tileScrollStaticMaterialToC(self, fMaterial): - setTileSizeIndex0 = -1 - setTileSizeIndex1 = -1 + # Called for building the entry point DL for drawing a model. + def drawToC(self, f3d, gfxList): + return gfxList.to_c(f3d) - # Find index of SetTileSize commands - for i, c in enumerate(fMaterial.material.commands): - if isinstance(c, DPSetTileSize): - if setTileSizeIndex0 >= 0: - setTileSizeIndex1 = i - break - else: - setTileSizeIndex0 = i - mat_name = fMaterial.material.name + # Called for creating a dynamic material using tile texture scrolling. + # ScrollMethod and DLFormat checks are already handled. + def tileScrollMaterialToC(self, f3d, fMaterial): + raise PluginError("No tile scroll implementation specified.") - tile_scroll_tex0 = fMaterial.scrollData.tile_scroll_tex0 - tile_scroll_tex1 = fMaterial.scrollData.tile_scroll_tex1 - if fMaterial.scrollData.tile_scroll_exported: - return None - if tile_scroll_tex0.s or tile_scroll_tex0.t or tile_scroll_tex1.s or tile_scroll_tex1.t: - func, data = mat_tile_scroll( - mat_name, tile_scroll_tex0, tile_scroll_tex1, setTileSizeIndex0, setTileSizeIndex1 - ) - self.tileScrollFunc = f'extern {func};' # save for later - fMaterial.scrollData.tile_scroll_exported = True - return data + # Modify static material using tile texture scrolling. + def tileScrollStaticMaterialToC(self, fMaterial): + setTileSizeIndex0 = -1 + setTileSizeIndex1 = -1 - return None + # Find index of SetTileSize commands + for i, c in enumerate(fMaterial.material.commands): + if isinstance(c, DPSetTileSize): + if setTileSizeIndex0 >= 0: + setTileSizeIndex1 = i + break + else: + setTileSizeIndex0 = i + mat_name = fMaterial.material.name + + tile_scroll_tex0 = fMaterial.scrollData.tile_scroll_tex0 + tile_scroll_tex1 = fMaterial.scrollData.tile_scroll_tex1 + if fMaterial.scrollData.tile_scroll_exported: + return None + if tile_scroll_tex0.s or tile_scroll_tex0.t or tile_scroll_tex1.s or tile_scroll_tex1.t: + func, data = mat_tile_scroll( + mat_name, tile_scroll_tex0, tile_scroll_tex1, setTileSizeIndex0, setTileSizeIndex1 + ) + self.tileScrollFunc = f"extern {func};" # save for later + fMaterial.scrollData.tile_scroll_exported = True + return data + + return None class Vtx: - def __init__(self, position, uv, colorOrNormal): - self.position = position - self.uv = uv - self.colorOrNormal = colorOrNormal - - def to_binary(self): - signX = 1 if self.uv[0] >= 0 else -1 - signY = 1 if self.uv[1] >= 0 else -1 - uv = [self.uv[0] % (signX * 2**15), self.uv[1] % (signY * 2**15)] - return self.position[0].to_bytes(2, 'big', signed=True) + \ - self.position[1].to_bytes(2, 'big', signed=True) + \ - self.position[2].to_bytes(2, 'big', signed=True) + \ - bytearray([0x00, 0x00]) + \ - uv[0].to_bytes(2, 'big', signed = True) +\ - uv[1].to_bytes(2, 'big', signed = True) +\ - bytearray(self.colorOrNormal) + def __init__(self, position, uv, colorOrNormal): + self.position = position + self.uv = uv + self.colorOrNormal = colorOrNormal + + def to_binary(self): + signX = 1 if self.uv[0] >= 0 else -1 + signY = 1 if self.uv[1] >= 0 else -1 + uv = [self.uv[0] % (signX * 2**15), self.uv[1] % (signY * 2**15)] + return ( + self.position[0].to_bytes(2, "big", signed=True) + + self.position[1].to_bytes(2, "big", signed=True) + + self.position[2].to_bytes(2, "big", signed=True) + + bytearray([0x00, 0x00]) + + uv[0].to_bytes(2, "big", signed=True) + + uv[1].to_bytes(2, "big", signed=True) + + bytearray(self.colorOrNormal) + ) + + def to_c(self): + if bpy.context.scene.decomp_compatible: + return ( + "{{" + + "{" + + str(self.position[0]) + + ", " + + str(self.position[1]) + + ", " + + str(self.position[2]) + + "}," + + "0, " + + "{" + + str(self.uv[0]) + + ", " + + str(self.uv[1]) + + "}," + + "{" + + "0x" + + format(self.colorOrNormal[0], "X") + + ", " + + "0x" + + format(self.colorOrNormal[1], "X") + + ", " + + "0x" + + format(self.colorOrNormal[2], "X") + + ", " + + "0x" + + format(self.colorOrNormal[3], "X") + + "}" + + "}}" + ) + else: + return ( + "{" + + str(self.position[0]) + + ", " + + str(self.position[1]) + + ", " + + str(self.position[2]) + + ", " + + "0, " + + str(self.uv[0]) + + ", " + + str(self.uv[1]) + + ", " + + "0x" + + format(self.colorOrNormal[0], "X") + + ", " + + "0x" + + format(self.colorOrNormal[1], "X") + + ", " + + "0x" + + format(self.colorOrNormal[2], "X") + + ", " + + "0x" + + format(self.colorOrNormal[3], "X") + + "}" + ) + + def to_sm64_decomp_s(self): + return ( + "vertex " + + str(self.position[0]) + + ", " + + str(self.position[1]) + + ", " + + str(self.position[2]) + + ", " + + "0, " + + "0x" + + format(self.uv[0], "X") + + ", " + + "0x" + + format(self.uv[1], "X") + + ", " + + "0x" + + format(self.colorOrNormal[0], "X") + + ", " + + "0x" + + format(self.colorOrNormal[1], "X") + + ", " + + "0x" + + format(self.colorOrNormal[2], "X") + + ", " + + "0x" + + format(self.colorOrNormal[3], "X") + ) - def to_c(self): - if bpy.context.scene.decomp_compatible: - return '{{' + \ - '{' +\ - str(self.position[0]) + ', ' + \ - str(self.position[1]) + ', ' + \ - str(self.position[2]) + \ - '},' +\ - '0, ' + \ - '{' +\ - str(self.uv[0]) + ", " +\ - str(self.uv[1]) + \ - '},' +\ - '{' +\ - '0x' + format(self.colorOrNormal[0], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[1], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[2], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[3], 'X') + \ - '}' + '}}' - else: - return '{' + \ - str(self.position[0]) + ', ' + \ - str(self.position[1]) + ', ' + \ - str(self.position[2]) + ', ' + \ - '0, ' + \ - str(self.uv[0]) + ", " +\ - str(self.uv[1]) + ", " +\ - '0x' + format(self.colorOrNormal[0], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[1], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[2], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[3], 'X') + \ - '}' - - def to_sm64_decomp_s(self): - return 'vertex ' + \ - str(self.position[0]) + ', ' + \ - str(self.position[1]) + ', ' + \ - str(self.position[2]) + ', ' + \ - '0, ' + \ - '0x' + format(self.uv[0], 'X') + ", " +\ - '0x' + format(self.uv[1], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[0], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[1], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[2], 'X') + ', ' + \ - '0x' + format(self.colorOrNormal[3], 'X') class VtxList: - def __init__(self, name): - self.vertices = [] - self.name = name - self.startAddress = 0 - - def set_addr(self, startAddress): - startAddress = get64bitAlignedAddr(startAddress) - self.startAddress = startAddress - print('VtxList ' + self.name + ': ' + str(startAddress) + \ - ', ' + str(self.size())) - return startAddress, startAddress + self.size() - - def save_binary(self, romfile): - romfile.seek(self.startAddress) - romfile.write(self.to_binary()) - - def size(self): - return len(self.vertices) * VTX_SIZE - - def to_binary(self): - data = bytearray(0) - for vert in self.vertices: - data.extend(vert.to_binary()) - return data - - def to_c(self): - data = CData() - data.header = 'extern Vtx ' + self.name + '[' + str(len(self.vertices)) + '];\n' - data.source = 'Vtx ' + self.name + '[' + str(len(self.vertices)) + '] = {\n' - for vert in self.vertices: - data.source += '\t' + vert.to_c() + ',\n' - data.source += '};\n\n' - return data - - def to_sm64_decomp_s(self): - data = self.name + ':\n' - for vert in self.vertices: - data += vert.to_sm64_decomp_s() + '\n' - return data + def __init__(self, name): + self.vertices = [] + self.name = name + self.startAddress = 0 + + def set_addr(self, startAddress): + startAddress = get64bitAlignedAddr(startAddress) + self.startAddress = startAddress + print("VtxList " + self.name + ": " + str(startAddress) + ", " + str(self.size())) + return startAddress, startAddress + self.size() + + def save_binary(self, romfile): + romfile.seek(self.startAddress) + romfile.write(self.to_binary()) + + def size(self): + return len(self.vertices) * VTX_SIZE + + def to_binary(self): + data = bytearray(0) + for vert in self.vertices: + data.extend(vert.to_binary()) + return data + + def to_c(self): + data = CData() + data.header = "extern Vtx " + self.name + "[" + str(len(self.vertices)) + "];\n" + data.source = "Vtx " + self.name + "[" + str(len(self.vertices)) + "] = {\n" + for vert in self.vertices: + data.source += "\t" + vert.to_c() + ",\n" + data.source += "};\n\n" + return data + + def to_sm64_decomp_s(self): + data = self.name + ":\n" + for vert in self.vertices: + data += vert.to_sm64_decomp_s() + "\n" + return data + class GfxList: - def __init__(self, name, tag, DLFormat): - self.commands = [] - self.name = name - self.startAddress = 0 - self.tag = tag - self.DLFormat = DLFormat - - def set_addr(self, startAddress, f3d): - startAddress = get64bitAlignedAddr(startAddress) - self.startAddress = startAddress - print('GfxList ' + self.name + ': ' + str(startAddress) + \ - ', ' + str(self.size(f3d))) - return startAddress, startAddress + self.size(f3d) - - def save_binary(self, romfile, f3d, segments): - print('GfxList ' + self.name + ': ' + str(self.startAddress) + \ - ', ' + str(self.size(f3d))) - romfile.seek(self.startAddress) - romfile.write(self.to_binary(f3d, segments)) - - def size(self, f3d): - size = 0 - for command in self.commands: - size += command.size(f3d) - return size + def __init__(self, name, tag, DLFormat): + self.commands = [] + self.name = name + self.startAddress = 0 + self.tag = tag + self.DLFormat = DLFormat - # Size, including display lists called with SPDisplayList - def size_total(self,f3d): - size = 0 - for command in self.commands: - if isinstance(command, SPDisplayList) and command.displayList.DLFormat != DLFormat.Static: - size += command.displayList.size_total(f3d) - else: - size += command.size(f3d) - return size - - def get_ptr_addresses(self, f3d): - ptrs = [] - address = self.startAddress - for command in self.commands: - if type(command) in F3DClassesWithPointers: - for offset in command.get_ptr_offsets(f3d): - ptrs.append(address + offset) - address += command.size(f3d) - return ptrs - - def to_binary(self, f3d, segments): - data = bytearray(0) - for command in self.commands: - data.extend(command.to_binary(f3d, segments)) - - return data - - def to_c_static(self): - data = 'Gfx ' + self.name + '[] = {\n' - for command in self.commands: - data += '\t' + command.to_c(True) + ',\n' - data += '};\n\n' - return data + def set_addr(self, startAddress, f3d): + startAddress = get64bitAlignedAddr(startAddress) + self.startAddress = startAddress + print("GfxList " + self.name + ": " + str(startAddress) + ", " + str(self.size(f3d))) + return startAddress, startAddress + self.size(f3d) - def to_c_dynamic(self): - data = 'Gfx* ' + self.name + '(Gfx* glistp) {\n' - for command in self.commands: - data += '\t' + command.to_c(False) + ';\n' - data += '\treturn glistp;\n}\n\n' - return data + def save_binary(self, romfile, f3d, segments): + print("GfxList " + self.name + ": " + str(self.startAddress) + ", " + str(self.size(f3d))) + romfile.seek(self.startAddress) + romfile.write(self.to_binary(f3d, segments)) + + def size(self, f3d): + size = 0 + for command in self.commands: + size += command.size(f3d) + return size + + # Size, including display lists called with SPDisplayList + def size_total(self, f3d): + size = 0 + for command in self.commands: + if isinstance(command, SPDisplayList) and command.displayList.DLFormat != DLFormat.Static: + size += command.displayList.size_total(f3d) + else: + size += command.size(f3d) + return size + + def get_ptr_addresses(self, f3d): + ptrs = [] + address = self.startAddress + for command in self.commands: + if type(command) in F3DClassesWithPointers: + for offset in command.get_ptr_offsets(f3d): + ptrs.append(address + offset) + address += command.size(f3d) + return ptrs + + def to_binary(self, f3d, segments): + data = bytearray(0) + for command in self.commands: + data.extend(command.to_binary(f3d, segments)) + + return data + + def to_c_static(self): + data = "Gfx " + self.name + "[] = {\n" + for command in self.commands: + data += "\t" + command.to_c(True) + ",\n" + data += "};\n\n" + return data + + def to_c_dynamic(self): + data = "Gfx* " + self.name + "(Gfx* glistp) {\n" + for command in self.commands: + data += "\t" + command.to_c(False) + ";\n" + data += "\treturn glistp;\n}\n\n" + return data + + def to_c(self, f3d): + data = CData() + if self.DLFormat == DLFormat.Static: + data.header = "extern Gfx " + self.name + "[];\n" + data.source = self.to_c_static() + elif self.DLFormat == DLFormat.Dynamic: + data.header = "Gfx* " + self.name + "(Gfx* glistp);\n" + data.source = self.to_c_dynamic() + else: + raise PluginError("Invalid GfxList format: " + str(self.DLFormat)) + return data + + def to_sm64_decomp_s(self): + data = "glabel " + self.name + "\n" + for command in self.commands: + data += command.to_sm64_decomp_s() + "\n" + return data - def to_c(self, f3d): - data = CData() - if self.DLFormat == DLFormat.Static: - data.header = 'extern Gfx ' + self.name + '[];\n' - data.source = self.to_c_static() - elif self.DLFormat == DLFormat.Dynamic: - data.header = 'Gfx* ' + self.name + '(Gfx* glistp);\n' - data.source = self.to_c_dynamic() - else: - raise PluginError("Invalid GfxList format: " + str(self.DLFormat)) - return data - - def to_sm64_decomp_s(self): - data = 'glabel ' + self.name + '\n' - for command in self.commands: - data += command.to_sm64_decomp_s() + '\n' - return data class FFogData: - def __init__(self, position = (970, 1000), color = (0,0,0,1)): - self.position = tuple(position) - self.color = ( - round(color[0], 8), - round(color[1], 8), - round(color[2], 8), - round(color[3], 8)) + def __init__(self, position=(970, 1000), color=(0, 0, 0, 1)): + self.position = tuple(position) + self.color = (round(color[0], 8), round(color[1], 8), round(color[2], 8), round(color[3], 8)) + + def __eq__(self, other): + return tuple(self.position) == tuple(other.position) and tuple(self.color) == tuple(other.color) + + def makeKey(self): + return (self.position, self.color) + + def requiresKey(self, material): + return material.set_fog and material.use_global_fog - def __eq__(self, other): - return tuple(self.position) == tuple(other.position) and \ - tuple(self.color) == tuple(other.color) - - def makeKey(self): - return (self.position, self.color) - def requiresKey(self, material): - return material.set_fog and material.use_global_fog - class FAreaData: - def __eq__(self, other): - return self.fog_data == other.fog_data + def __eq__(self, other): + return self.fog_data == other.fog_data - def __init__(self, fog_data): - self.fog_data = fog_data + def __init__(self, fog_data): + self.fog_data = fog_data + + def makeKey(self): + return self.fog_data.makeKey() + + def requiresKey(self, material): + return self.fog_data.requiresKey(material) - def makeKey(self): - return self.fog_data.makeKey() - - def requiresKey(self, material): - return self.fog_data.requiresKey(material) class FGlobalData: - def __init__(self): - # dict of area index : FFogData - self.area_data = {} - self.current_area_index = 1 - - def addAreaData(self, areaIndex : int, areaData : FAreaData): - if areaIndex in self.area_data: - raise ValueError("Error: Detected repeat FAreaData.") - self.area_data[areaIndex] = areaData - self.current_area_index = areaIndex + def __init__(self): + # dict of area index : FFogData + self.area_data = {} + self.current_area_index = 1 + + def addAreaData(self, areaIndex: int, areaData: FAreaData): + if areaIndex in self.area_data: + raise ValueError("Error: Detected repeat FAreaData.") + self.area_data[areaIndex] = areaData + self.current_area_index = areaIndex + + def getCurrentAreaData(self): + if len(self.area_data) == 0: + return None + else: + return self.area_data[self.current_area_index] + + def getCurrentAreaKey(self, material): + if len(self.area_data) == 0: + return None + # No need to have area specific variants of a material if they don't use global fog. + # Without this, a non-global-fog material used across areas will have redefined duplicate light names. + elif not self.area_data[self.current_area_index].requiresKey(material): + return None + else: + return self.area_data[self.current_area_index].makeKey() - def getCurrentAreaData(self): - if len(self.area_data) == 0: - return None - else: - return self.area_data[self.current_area_index] - - def getCurrentAreaKey(self, material): - if len(self.area_data) == 0: - return None - # No need to have area specific variants of a material if they don't use global fog. - # Without this, a non-global-fog material used across areas will have redefined duplicate light names. - elif not self.area_data[self.current_area_index].requiresKey(material): - return None - else: - return self.area_data[self.current_area_index].makeKey() class FModel: - def __init__(self, f3dType, isHWv1, name, DLFormat, matWriteMethod): - self.name = name # used for texture prefixing - # dict of light name : Lights - self.lights = {} - # dict of (texture, (texture format, palette format)) : FImage - self.textures = {} - # dict of (material, drawLayer, FAreaData): (FMaterial, (width, height)) - self.materials = {} - # dict of body part name : FMesh - self.meshes = {} - # GfxList - self.materialRevert = None - # F3D library - self.f3d = F3D(f3dType, isHWv1) - # array of FModel - self.subModels = [] - self.parentModel = None - - # dict of name : FLODGroup - self.LODGroups = {} - self.DLFormat = DLFormat - self.matWriteMethod = matWriteMethod - self.global_data = FGlobalData() - self.texturesSavedLastExport = 0 # hacky + def __init__(self, f3dType, isHWv1, name, DLFormat, matWriteMethod): + self.name = name # used for texture prefixing + # dict of light name : Lights + self.lights = {} + # dict of (texture, (texture format, palette format)) : FImage + self.textures = {} + # dict of (material, drawLayer, FAreaData): (FMaterial, (width, height)) + self.materials = {} + # dict of body part name : FMesh + self.meshes = {} + # GfxList + self.materialRevert = None + # F3D library + self.f3d = F3D(f3dType, isHWv1) + # array of FModel + self.subModels = [] + self.parentModel = None - # Called before SPEndDisplayList - def onMaterialCommandsBuilt(self, gfxList, revertList, material, drawLayer): - return + # dict of name : FLODGroup + self.LODGroups = {} + self.DLFormat = DLFormat + self.matWriteMethod = matWriteMethod + self.global_data = FGlobalData() + self.texturesSavedLastExport = 0 # hacky - def getTextureSuffixFromFormat(self, texFmt): - return texFmt.lower() + # Called before SPEndDisplayList + def onMaterialCommandsBuilt(self, gfxList, revertList, material, drawLayer): + return - def getDrawLayerV3(self, obj): - return None + def getTextureSuffixFromFormat(self, texFmt): + return texFmt.lower() - def getRenderMode(self, drawLayer): - return None + def getDrawLayerV3(self, obj): + return None - def addLODGroup(self, name, position, alwaysRenderFarthest): - if name in self.LODGroups: - raise PluginError("Duplicate LOD group: " + str(name)) - lod = FLODGroup(name, position, alwaysRenderFarthest, self.DLFormat) - self.LODGroups[name] = lod - return lod - - def addSubModel(self, subModel): - self.subModels.append(subModel) - subModel.parentModel = self - return subModel + def getRenderMode(self, drawLayer): + return None - def addTexture(self, key, value, fMaterial): - fMaterial.usedImages.append(key) - self.textures[key] = value + def addLODGroup(self, name, position, alwaysRenderFarthest): + if name in self.LODGroups: + raise PluginError("Duplicate LOD group: " + str(name)) + lod = FLODGroup(name, position, alwaysRenderFarthest, self.DLFormat) + self.LODGroups[name] = lod + return lod - def addLight(self, key, value, fMaterial): - fMaterial.usedLights.append(key) - self.lights[key] = value + def addSubModel(self, subModel): + self.subModels.append(subModel) + subModel.parentModel = self + return subModel - def addMesh(self, name, namePrefix, drawLayer, isSkinned, contextObj): - meshName = getFMeshName(name, namePrefix, drawLayer, isSkinned) - checkUniqueBoneNames(self, meshName, name) - self.meshes[meshName] = FMesh(meshName, self.DLFormat) + def addTexture(self, key, value, fMaterial): + fMaterial.usedImages.append(key) + self.textures[key] = value - self.onAddMesh(self.meshes[meshName], contextObj) + def addLight(self, key, value, fMaterial): + fMaterial.usedLights.append(key) + self.lights[key] = value - return self.meshes[meshName] + def addMesh(self, name, namePrefix, drawLayer, isSkinned, contextObj): + meshName = getFMeshName(name, namePrefix, drawLayer, isSkinned) + checkUniqueBoneNames(self, meshName, name) + self.meshes[meshName] = FMesh(meshName, self.DLFormat) - def onAddMesh(self, fMesh, contextObj): - return + self.onAddMesh(self.meshes[meshName], contextObj) - def endDraw(self, fMesh, contextObj): - self.onEndDraw(fMesh, contextObj) - fMesh.draw.commands.append(SPEndDisplayList()) + return self.meshes[meshName] - def onEndDraw(self, fMesh, contextObj): - return - - def getTextureAndHandleShared(self, imageKey): - # Check if texture is in self - if imageKey in self.textures: - fImage = self.textures[imageKey] - fPalette = self.textures[fImage.paletteKey] if fImage.paletteKey is not None else None - return fImage, fPalette + def onAddMesh(self, fMesh, contextObj): + return - if self.parentModel is not None: - # Check if texture is in parent - if imageKey in self.parentModel.textures: - fImage = self.parentModel.textures[imageKey] - fPalette = self.parentModel.textures[fImage.paletteKey] if fImage.paletteKey is not None else None - return fImage, fPalette - - # Check if texture is in siblings - for subModel in self.parentModel.subModels: - if imageKey in subModel.textures: - fImage = subModel.textures.pop(imageKey) - self.parentModel.textures[imageKey] = fImage + def endDraw(self, fMesh, contextObj): + self.onEndDraw(fMesh, contextObj) + fMesh.draw.commands.append(SPEndDisplayList()) - paletteKey = fImage.paletteKey - fPalette = None - if paletteKey is not None: - fPalette = subModel.textures.pop(paletteKey) - self.parentModel.textures[paletteKey] = fPalette - return fImage, fPalette - return None, None - else: - return None, None + def onEndDraw(self, fMesh, contextObj): + return - def getLightAndHandleShared(self, lightName): - # Check if light is in self - if lightName in self.lights: - return self.lights[lightName] + def getTextureAndHandleShared(self, imageKey): + # Check if texture is in self + if imageKey in self.textures: + fImage = self.textures[imageKey] + fPalette = self.textures[fImage.paletteKey] if fImage.paletteKey is not None else None + return fImage, fPalette - if self.parentModel is not None: - # Check if light is in parent - if lightName in self.parentModel.lights: - return self.parentModel.lights[lightName] - - # Check if light is in siblings - for subModel in self.parentModel.subModels: - if lightName in subModel.lights: - light = subModel.lights.pop(lightName) - self.parentModel.lights[lightName] = light - return light - else: - return None + if self.parentModel is not None: + # Check if texture is in parent + if imageKey in self.parentModel.textures: + fImage = self.parentModel.textures[imageKey] + fPalette = self.parentModel.textures[fImage.paletteKey] if fImage.paletteKey is not None else None + return fImage, fPalette - - def getMaterialAndHandleShared(self, materialKey): - # Check if material is in self - if materialKey in self.materials: - return self.materials[materialKey] - - if self.parentModel is not None: - # Check if material is in parent - if materialKey in self.parentModel.materials: - return self.parentModel.materials[materialKey] + # Check if texture is in siblings + for subModel in self.parentModel.subModels: + if imageKey in subModel.textures: + fImage = subModel.textures.pop(imageKey) + self.parentModel.textures[imageKey] = fImage - # Check if material is in siblings - for subModel in self.parentModel.subModels: - if materialKey in subModel.materials: - materialItem = subModel.materials.pop(materialKey) - self.parentModel.materials[materialKey] = materialItem + paletteKey = fImage.paletteKey + fPalette = None + if paletteKey is not None: + fPalette = subModel.textures.pop(paletteKey) + self.parentModel.textures[paletteKey] = fPalette + return fImage, fPalette + return None, None + else: + return None, None - # If material is in sibling, handle the material's textures as well. - for imageKey in materialItem[0].usedImages: - fImage, fPalette = self.getTextureAndHandleShared(imageKey) - if fImage is None: - raise PluginError("Error: If a material exists, its textures should exist too.") + def getLightAndHandleShared(self, lightName): + # Check if light is in self + if lightName in self.lights: + return self.lights[lightName] - for lightName in materialItem[0].usedLights: - light = self.getLightAndHandleShared(lightName) - if light is None: - raise PluginError("Error: If a material exists, its lights should exist too.") - return materialItem - else: - return None + if self.parentModel is not None: + # Check if light is in parent + if lightName in self.parentModel.lights: + return self.parentModel.lights[lightName] - def getAllMaterials(self): - materials = {} - materials.update(self.materials) - for subModel in self.subModels: - materials.update(subModel.getAllMaterials()) - return materials + # Check if light is in siblings + for subModel in self.parentModel.subModels: + if lightName in subModel.lights: + light = subModel.lights.pop(lightName) + self.parentModel.lights[lightName] = light + return light + else: + return None - def get_ptr_addresses(self, f3d): - addresses = [] - for name, lod in self.LODGroups.items(): - addresses.extend(lod.get_ptr_addresses(f3d)) - for name, mesh in self.meshes.items(): - addresses.extend(mesh.get_ptr_addresses(f3d)) - for materialKey, (fMaterial, texDimensions) in self.materials.items(): - addresses.extend(fMaterial.get_ptr_addresses(f3d)) - if self.materialRevert is not None: - addresses.extend(self.materialRevert.get_ptr_addresses(f3d)) - return addresses - - def set_addr(self, startAddress): - addrRange = (startAddress, startAddress) - startAddrSet = False - for name, lod in self.LODGroups.items(): - addrRange = lod.set_addr(addrRange[1], self.f3d) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - # Important to set mesh groups first, so that - # export address corrseponds to drawing start. - for name, mesh in self.meshes.items(): - addrRange = mesh.set_addr(addrRange[1], self.f3d) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - for name, light in self.lights.items(): - addrRange = light.set_addr(addrRange[1]) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - for info, texture in self.textures.items(): - addrRange = texture.set_addr(addrRange[1]) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - for materialKey, (fMaterial, texDimensions) in self.materials.items(): - addrRange = fMaterial.set_addr(addrRange[1], self.f3d) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - if self.materialRevert is not None: - addrRange = self.materialRevert.set_addr(addrRange[1], self.f3d) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - for subModel in self.subModels: - addrRange = subModel.set_addr(addrRange[1]) - if not startAddrSet: - startAddrSet = True - startAddress = addrRange[0] - return startAddress, addrRange[1] + def getMaterialAndHandleShared(self, materialKey): + # Check if material is in self + if materialKey in self.materials: + return self.materials[materialKey] - def save_binary(self, romfile, segments): - for name, light in self.lights.items(): - light.save_binary(romfile) - for info, texture in self.textures.items(): - texture.save_binary(romfile) - for materialKey, (fMaterial, texDimensions) in self.materials.items(): - if fMaterial.useLargeTextures and (fMaterial.saveLargeTextures[0] or fMaterial.saveLargeTextures[0]): - raise PluginError("Large texture mode textures must have their texture specific 'Save As PNG' disabled for binary export.") - fMaterial.save_binary(romfile, self.f3d, segments) - for name, mesh in self.meshes.items(): - mesh.save_binary(romfile, self.f3d, segments) - for name, lod in self.LODGroups.items(): - lod.save_binary(romfile, self.f3d, segments) - if self.materialRevert is not None: - self.materialRevert.save_binary(romfile, self.f3d, segments) - for subModel in self.subModels: - subModel.save_binary(romfile, segments) + if self.parentModel is not None: + # Check if material is in parent + if materialKey in self.parentModel.materials: + return self.parentModel.materials[materialKey] - def to_c_lights(self): - data = CData() - for name, light in self.lights.items(): - data.append(light.to_c()) - return data + # Check if material is in siblings + for subModel in self.parentModel.subModels: + if materialKey in subModel.materials: + materialItem = subModel.materials.pop(materialKey) + self.parentModel.materials[materialKey] = materialItem - def to_c_textures(self, texCSeparate, savePNG, texDir, texArrayBitSize): - # since decomp is linux, don't use os.path.join - # on windows this results in '\', which is incorrect (should be '/') - if len(texDir) > 0 and texDir[-1] != '/': - texDir += '/' - data = CData() - for info, texture in self.textures.items(): - if savePNG or texture.isLargeTexture: - data.append(texture.to_c_tex_separate(texDir, texArrayBitSize)) - else: - data.append(texture.to_c(texArrayBitSize)) - return data + # If material is in sibling, handle the material's textures as well. + for imageKey in materialItem[0].usedImages: + fImage, fPalette = self.getTextureAndHandleShared(imageKey) + if fImage is None: + raise PluginError("Error: If a material exists, its textures should exist too.") - def to_c_materials(self, gfxFormatter): - data = CData() - for materialKey, (fMaterial, texDimensions) in self.materials.items(): - if gfxFormatter.scrollMethod == ScrollMethod.Tile: - if fMaterial.material.DLFormat == DLFormat.Static: - raise PluginError("Tile scrolling cannot be done with static DLs.") - data.append(gfxFormatter.tileScrollMaterialToC(self.f3d, fMaterial)) - else: - data.append(fMaterial.to_c(self.f3d)) - return data + for lightName in materialItem[0].usedLights: + light = self.getLightAndHandleShared(lightName) + if light is None: + raise PluginError("Error: If a material exists, its lights should exist too.") + return materialItem + else: + return None - def to_c_material_revert(self, gfxFormatter): - data = CData() - if self.materialRevert is not None: - data.append(self.materialRevert.to_c(self.f3d)) - return data + def getAllMaterials(self): + materials = {} + materials.update(self.materials) + for subModel in self.subModels: + materials.update(subModel.getAllMaterials()) + return materials - def to_c(self, textureExportSettings, gfxFormatter): - texCSeparate = textureExportSettings.texCSeparate - savePNG = textureExportSettings.savePNG - texDir = textureExportSettings.includeDir - - staticData = CData() - dynamicData = CData() - texC = CData() + def get_ptr_addresses(self, f3d): + addresses = [] + for name, lod in self.LODGroups.items(): + addresses.extend(lod.get_ptr_addresses(f3d)) + for name, mesh in self.meshes.items(): + addresses.extend(mesh.get_ptr_addresses(f3d)) + for materialKey, (fMaterial, texDimensions) in self.materials.items(): + addresses.extend(fMaterial.get_ptr_addresses(f3d)) + if self.materialRevert is not None: + addresses.extend(self.materialRevert.get_ptr_addresses(f3d)) + return addresses - # Source - staticData.append(self.to_c_lights()) - - texData = self.to_c_textures(texCSeparate, savePNG, texDir, gfxFormatter.texArrayBitSize) - staticData.header += texData.header - if texCSeparate: - texC.source += texData.source - else: - staticData.source += texData.source + def set_addr(self, startAddress): + addrRange = (startAddress, startAddress) + startAddrSet = False + for name, lod in self.LODGroups.items(): + addrRange = lod.set_addr(addrRange[1], self.f3d) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + # Important to set mesh groups first, so that + # export address corrseponds to drawing start. + for name, mesh in self.meshes.items(): + addrRange = mesh.set_addr(addrRange[1], self.f3d) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + for name, light in self.lights.items(): + addrRange = light.set_addr(addrRange[1]) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + for info, texture in self.textures.items(): + addrRange = texture.set_addr(addrRange[1]) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + for materialKey, (fMaterial, texDimensions) in self.materials.items(): + addrRange = fMaterial.set_addr(addrRange[1], self.f3d) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + if self.materialRevert is not None: + addrRange = self.materialRevert.set_addr(addrRange[1], self.f3d) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + for subModel in self.subModels: + addrRange = subModel.set_addr(addrRange[1]) + if not startAddrSet: + startAddrSet = True + startAddress = addrRange[0] + return startAddress, addrRange[1] - dynamicData.append(self.to_c_materials(gfxFormatter)) + def save_binary(self, romfile, segments): + for name, light in self.lights.items(): + light.save_binary(romfile) + for info, texture in self.textures.items(): + texture.save_binary(romfile) + for materialKey, (fMaterial, texDimensions) in self.materials.items(): + if fMaterial.useLargeTextures and (fMaterial.saveLargeTextures[0] or fMaterial.saveLargeTextures[0]): + raise PluginError( + "Large texture mode textures must have their texture specific 'Save As PNG' disabled for binary export." + ) + fMaterial.save_binary(romfile, self.f3d, segments) + for name, mesh in self.meshes.items(): + mesh.save_binary(romfile, self.f3d, segments) + for name, lod in self.LODGroups.items(): + lod.save_binary(romfile, self.f3d, segments) + if self.materialRevert is not None: + self.materialRevert.save_binary(romfile, self.f3d, segments) + for subModel in self.subModels: + subModel.save_binary(romfile, segments) - for name, lod in self.LODGroups.items(): - lodStatic, lodDynamic = lod.to_c(self.f3d, gfxFormatter) - staticData.append(lodStatic) - dynamicData.append(lodDynamic) + def to_c_lights(self): + data = CData() + for name, light in self.lights.items(): + data.append(light.to_c()) + return data - for name, mesh in self.meshes.items(): - meshStatic, meshDynamic = mesh.to_c(self.f3d, gfxFormatter) - staticData.append(meshStatic) - dynamicData.append(meshDynamic) + def to_c_textures(self, texCSeparate, savePNG, texDir, texArrayBitSize): + # since decomp is linux, don't use os.path.join + # on windows this results in '\', which is incorrect (should be '/') + if len(texDir) > 0 and texDir[-1] != "/": + texDir += "/" + data = CData() + for info, texture in self.textures.items(): + if savePNG or texture.isLargeTexture: + data.append(texture.to_c_tex_separate(texDir, texArrayBitSize)) + else: + data.append(texture.to_c(texArrayBitSize)) + return data - dynamicData.append(self.to_c_material_revert(gfxFormatter)) + def to_c_materials(self, gfxFormatter): + data = CData() + for materialKey, (fMaterial, texDimensions) in self.materials.items(): + if gfxFormatter.scrollMethod == ScrollMethod.Tile: + if fMaterial.material.DLFormat == DLFormat.Static: + raise PluginError("Tile scrolling cannot be done with static DLs.") + data.append(gfxFormatter.tileScrollMaterialToC(self.f3d, fMaterial)) + else: + data.append(fMaterial.to_c(self.f3d)) + return data - self.texturesSavedLastExport = self.save_textures(textureExportSettings.exportPath, not savePNG) - self.freePalettes() - return ExportCData(staticData, dynamicData, texC) - - def to_c_vertex_scroll(self, scrollName, gfxFormatter): - scrollData = CData() - for name, mesh in self.meshes.items(): - scrollData.append(mesh.to_c_vertex_scroll(gfxFormatter)) - - hasScrolling = len(scrollData.header) > 0 + def to_c_material_revert(self, gfxFormatter): + data = CData() + if self.materialRevert is not None: + data.append(self.materialRevert.to_c(self.f3d)) + return data - scrollDefinesSplit = scrollData.header.split('extern void ') - scrollData.source += 'void scroll_' + scrollName + '() {\n' - for scrollFunc in scrollDefinesSplit: - if scrollFunc == '': - continue - scrollData.source += '\t' + scrollFunc - scrollData.source += '}\n' + def to_c(self, textureExportSettings, gfxFormatter): + texCSeparate = textureExportSettings.texCSeparate + savePNG = textureExportSettings.savePNG + texDir = textureExportSettings.includeDir - scrollData.header += 'extern void scroll_' + scrollName + '();\n' - return scrollData, hasScrolling + staticData = CData() + dynamicData = CData() + texC = CData() - def save_textures(self, dirpath, largeTexturesOnly): - texturesSaved = 0 - for (image, texInfo), texture in self.textures.items(): - if texInfo[1] == 'PAL' or (largeTexturesOnly and not texture.isLargeTexture): - continue - - # remove '.inc.c' - imageFileName = texture.filename[:-6] + '.png' + # Source + staticData.append(self.to_c_lights()) - # image.save_render(os.path.join(dirpath, imageFileName)) + texData = self.to_c_textures(texCSeparate, savePNG, texDir, gfxFormatter.texArrayBitSize) + staticData.header += texData.header + if texCSeparate: + texC.source += texData.source + else: + staticData.source += texData.source + + dynamicData.append(self.to_c_materials(gfxFormatter)) + + for name, lod in self.LODGroups.items(): + lodStatic, lodDynamic = lod.to_c(self.f3d, gfxFormatter) + staticData.append(lodStatic) + dynamicData.append(lodDynamic) + + for name, mesh in self.meshes.items(): + meshStatic, meshDynamic = mesh.to_c(self.f3d, gfxFormatter) + staticData.append(meshStatic) + dynamicData.append(meshDynamic) + + dynamicData.append(self.to_c_material_revert(gfxFormatter)) + + self.texturesSavedLastExport = self.save_textures(textureExportSettings.exportPath, not savePNG) + self.freePalettes() + return ExportCData(staticData, dynamicData, texC) + + def to_c_vertex_scroll(self, scrollName, gfxFormatter): + scrollData = CData() + for name, mesh in self.meshes.items(): + scrollData.append(mesh.to_c_vertex_scroll(gfxFormatter)) + + hasScrolling = len(scrollData.header) > 0 + + scrollDefinesSplit = scrollData.header.split("extern void ") + scrollData.source += "void scroll_" + scrollName + "() {\n" + for scrollFunc in scrollDefinesSplit: + if scrollFunc == "": + continue + scrollData.source += "\t" + scrollFunc + scrollData.source += "}\n" + + scrollData.header += "extern void scroll_" + scrollName + "();\n" + return scrollData, hasScrolling + + def save_textures(self, dirpath, largeTexturesOnly): + texturesSaved = 0 + for (image, texInfo), texture in self.textures.items(): + if texInfo[1] == "PAL" or (largeTexturesOnly and not texture.isLargeTexture): + continue + + # remove '.inc.c' + imageFileName = texture.filename[:-6] + ".png" + + # image.save_render(os.path.join(dirpath, imageFileName)) + + isPacked = image.packed_file is not None + if not isPacked: + image.pack() + oldpath = image.filepath + try: + image.filepath = bpy.path.abspath(os.path.join(dirpath, imageFileName)) + image.save() + texturesSaved += 1 + if not isPacked: + image.unpack() + except Exception as e: + image.filepath = oldpath + raise Exception(str(e)) + image.filepath = oldpath + return texturesSaved + + def freePalettes(self): + # Palettes no longer saved + return + for (image, texInfo), texture in self.textures.items(): + # texDict[name] = texture.to_c_data() + '\n' + if texInfo[1] == "PAL": + bpy.data.images.remove(image) - isPacked = image.packed_file is not None - if not isPacked: - image.pack() - oldpath = image.filepath - try: - image.filepath = \ - bpy.path.abspath(os.path.join(dirpath, imageFileName)) - image.save() - texturesSaved += 1 - if not isPacked: - image.unpack() - except Exception as e: - image.filepath = oldpath - raise Exception(str(e)) - image.filepath = oldpath - return texturesSaved - - def freePalettes(self): - # Palettes no longer saved - return - for (image, texInfo), texture in self.textures.items(): - #texDict[name] = texture.to_c_data() + '\n' - if texInfo[1] == 'PAL': - bpy.data.images.remove(image) class FTexRect(FModel): - def __init__(self, f3dType, isHWv1, name, matWriteMethod): - self.draw = GfxList(name, GfxListTag.Draw, DLFormat.Dynamic) - FModel.__init__(self, f3dType, isHWv1, name, DLFormat, matWriteMethod) + def __init__(self, f3dType, isHWv1, name, matWriteMethod): + self.draw = GfxList(name, GfxListTag.Draw, DLFormat.Dynamic) + FModel.__init__(self, f3dType, isHWv1, name, DLFormat, matWriteMethod) + + def to_c(self, savePNG, texDir, gfxFormatter): + staticData = CData() + dynamicData = CData() + # since decomp is linux, don't use os.path.join + # on windows this results in '\', which is incorrect (should be '/') + if texDir[-1] != "/": + texDir += "/" + for info, texture in self.textures.items(): + if savePNG: + staticData.append(texture.to_c_tex_separate(texDir, gfxFormatter.texArrayBitSize)) + else: + staticData.append(texture.to_c(gfxFormatter.texArrayBitSize)) + dynamicData.append(self.draw.to_c(self.f3d)) + return ExportCData(staticData, dynamicData, CData()) - def to_c(self, savePNG, texDir, gfxFormatter): - staticData = CData() - dynamicData = CData() - # since decomp is linux, don't use os.path.join - # on windows this results in '\', which is incorrect (should be '/') - if texDir[-1] != '/': - texDir += '/' - for info, texture in self.textures.items(): - if savePNG: - staticData.append(texture.to_c_tex_separate(texDir, gfxFormatter.texArrayBitSize)) - else: - staticData.append(texture.to_c(gfxFormatter.texArrayBitSize)) - dynamicData.append(self.draw.to_c(self.f3d)) - return ExportCData(staticData, dynamicData, CData()) class FLODGroup: - def __init__(self, name, position, alwaysRenderFarthest, DLFormat): - self.name = name - self.DLFormat = DLFormat - self.lodEntries = [] # list of tuple(z, DL) - self.alwaysRenderFarthest = alwaysRenderFarthest + def __init__(self, name, position, alwaysRenderFarthest, DLFormat): + self.name = name + self.DLFormat = DLFormat + self.lodEntries = [] # list of tuple(z, DL) + self.alwaysRenderFarthest = alwaysRenderFarthest - self.vertexList = VtxList(self.get_vtx_name()) - self.vertexList.vertices.append(Vtx(position, [0,0], [0,0,0,0])) + self.vertexList = VtxList(self.get_vtx_name()) + self.vertexList.vertices.append(Vtx(position, [0, 0], [0, 0, 0, 0])) - self.draw = None - self.subdraws = [] - self.drawCommandsBuilt = False + self.draw = None + self.subdraws = [] + self.drawCommandsBuilt = False - def add_lod(self, displayList, zValue): - if displayList is not None: - self.lodEntries.append((abs(int(round(zValue))), displayList)) + def add_lod(self, displayList, zValue): + if displayList is not None: + self.lodEntries.append((abs(int(round(zValue))), displayList)) - def get_dl_name(self): - return self.name + "_lod" + def get_dl_name(self): + return self.name + "_lod" - def get_vtx_name(self): - return self.name + "_vtx" - - def get_ptr_addresses(self, f3d): - addresses = self.draw.get_ptr_addresses(f3d) - for displayList in self.subdraws: - if displayList is not None: - addresses.extend(displayList.get_ptr_addresses(f3d)) - return addresses - - def set_addr(self, startAddress, f3d): - self.create_data() - addrRange = self.draw.set_addr(startAddress, f3d) - for displayList in self.subdraws: - if displayList is not None: - addrRange = displayList.set_addr(addrRange[1], f3d) - addrRange = self.vertexList.set_addr(addrRange[1]) - return startAddress, addrRange[1] + def get_vtx_name(self): + return self.name + "_vtx" - def save_binary(self, romfile, f3d, segments): - self.draw.save_binary(romfile, f3d, segments) - for displayList in self.subdraws: - if displayList is not None: - displayList.save_binary(romfile,f3d, segments) - self.vertexList.save_binary(romfile) - - def to_c(self, f3d, gfxFormatter): - self.create_data() + def get_ptr_addresses(self, f3d): + addresses = self.draw.get_ptr_addresses(f3d) + for displayList in self.subdraws: + if displayList is not None: + addresses.extend(displayList.get_ptr_addresses(f3d)) + return addresses - staticData = CData() - dynamicData = CData() - staticData.append(self.vertexList.to_c()) - for displayList in self.subdraws: - if displayList is not None: - dynamicData.append(displayList.to_c(f3d)) - dynamicData.append(self.draw.to_c(f3d)) - return staticData, dynamicData + def set_addr(self, startAddress, f3d): + self.create_data() + addrRange = self.draw.set_addr(startAddress, f3d) + for displayList in self.subdraws: + if displayList is not None: + addrRange = displayList.set_addr(addrRange[1], f3d) + addrRange = self.vertexList.set_addr(addrRange[1]) + return startAddress, addrRange[1] - def create_data(self): - if self.drawCommandsBuilt: - return + def save_binary(self, romfile, f3d, segments): + self.draw.save_binary(romfile, f3d, segments) + for displayList in self.subdraws: + if displayList is not None: + displayList.save_binary(romfile, f3d, segments) + self.vertexList.save_binary(romfile) - self.drawCommandsBuilt = True - self.draw = GfxList(self.get_dl_name(), GfxListTag.Draw, self.DLFormat) + def to_c(self, f3d, gfxFormatter): + self.create_data() - index = 0 - self.draw.commands.append(SPVertex(self.vertexList, 0, 1, index)) + staticData = CData() + dynamicData = CData() + staticData.append(self.vertexList.to_c()) + for displayList in self.subdraws: + if displayList is not None: + dynamicData.append(displayList.to_c(f3d)) + dynamicData.append(self.draw.to_c(f3d)) + return staticData, dynamicData - sortedList = sorted(self.lodEntries, key = lambda tup: tup[0]) - hasAnyDLs = False - for item in sortedList: - - # If no DLs are called, we still need an empty DL to preserve LOD. - if len(item[1].commands) < 2: - DL = item[1] - self.subdraws.append(DL) - # If one DL is called, we can just call it directly. - elif len(item[1].commands) == 2: # branch DL, then end DL: - DL = item[1].commands[0].displayList - hasAnyDLs = True - # If more DLs are called, we have to use a sub DL. - else: - DL = item[1] - self.subdraws.append(DL) - hasAnyDLs = True + def create_data(self): + if self.drawCommandsBuilt: + return - self.draw.commands.append(SPBranchLessZraw(DL, index, item[0])) + self.drawCommandsBuilt = True + self.draw = GfxList(self.get_dl_name(), GfxListTag.Draw, self.DLFormat) - if len(sortedList) > 0: - lastCmd = self.draw.commands[-1] - if self.alwaysRenderFarthest: - self.draw.commands.remove(lastCmd) - self.draw.commands.append(SPBranchList(lastCmd.dl)) + index = 0 + self.draw.commands.append(SPVertex(self.vertexList, 0, 1, index)) - if not hasAnyDLs: - self.draw.commands.clear() - self.subdraws.clear() - - self.draw.commands.append(SPEndDisplayList()) + sortedList = sorted(self.lodEntries, key=lambda tup: tup[0]) + hasAnyDLs = False + for item in sortedList: + + # If no DLs are called, we still need an empty DL to preserve LOD. + if len(item[1].commands) < 2: + DL = item[1] + self.subdraws.append(DL) + # If one DL is called, we can just call it directly. + elif len(item[1].commands) == 2: # branch DL, then end DL: + DL = item[1].commands[0].displayList + hasAnyDLs = True + # If more DLs are called, we have to use a sub DL. + else: + DL = item[1] + self.subdraws.append(DL) + hasAnyDLs = True + + self.draw.commands.append(SPBranchLessZraw(DL, index, item[0])) + + if len(sortedList) > 0: + lastCmd = self.draw.commands[-1] + if self.alwaysRenderFarthest: + self.draw.commands.remove(lastCmd) + self.draw.commands.append(SPBranchList(lastCmd.dl)) + + if not hasAnyDLs: + self.draw.commands.clear() + self.subdraws.clear() + + self.draw.commands.append(SPEndDisplayList()) class FMesh: - def __init__(self, name, DLFormat): - self.name = name - # GfxList - self.draw = GfxList(name, GfxListTag.Draw, DLFormat) - # list of FTriGroup - self.triangleGroups: list[FTriGroup] = [] - # VtxList - self.cullVertexList = None - # dict of (override Material, specified Material to override, - # overrideType, draw layer) : GfxList - self.drawMatOverrides = {} - self.DLFormat = DLFormat + def __init__(self, name, DLFormat): + self.name = name + # GfxList + self.draw = GfxList(name, GfxListTag.Draw, DLFormat) + # list of FTriGroup + self.triangleGroups: list[FTriGroup] = [] + # VtxList + self.cullVertexList = None + # dict of (override Material, specified Material to override, + # overrideType, draw layer) : GfxList + self.drawMatOverrides = {} + self.DLFormat = DLFormat - # Used to avoid consecutive calls to the same material if unnecessary - self.currentFMaterial = None + # Used to avoid consecutive calls to the same material if unnecessary + self.currentFMaterial = None - def add_material_call(self, fMaterial): - sameMaterial = self.currentFMaterial is fMaterial - if not sameMaterial: - self.currentFMaterial = fMaterial - self.draw.commands.append(SPDisplayList(fMaterial.material)) - else: - lastCommand = self.draw.commands[-1] - if isinstance(lastCommand, SPDisplayList) and \ - lastCommand.displayList == fMaterial.revert: - self.draw.commands.remove(lastCommand) - - def add_cull_vtx(self): - self.cullVertexList = VtxList(self.name + '_vtx_cull') - - def get_ptr_addresses(self, f3d): - addresses = self.draw.get_ptr_addresses(f3d) - for triGroup in self.triangleGroups: - addresses.extend(triGroup.get_ptr_addresses(f3d)) - for materialTuple, drawOverride in self.drawMatOverrides.items(): - addresses.extend(drawOverride.get_ptr_addresses(f3d)) - return addresses + def add_material_call(self, fMaterial): + sameMaterial = self.currentFMaterial is fMaterial + if not sameMaterial: + self.currentFMaterial = fMaterial + self.draw.commands.append(SPDisplayList(fMaterial.material)) + else: + lastCommand = self.draw.commands[-1] + if isinstance(lastCommand, SPDisplayList) and lastCommand.displayList == fMaterial.revert: + self.draw.commands.remove(lastCommand) - def tri_group_new(self, fMaterial): - # Always static DL - triGroup = FTriGroup(self.name, len(self.triangleGroups), fMaterial) - self.triangleGroups.append(triGroup) - return triGroup - - def set_addr(self, startAddress, f3d): - addrRange = self.draw.set_addr(startAddress, f3d) - startAddress = addrRange[0] - for triGroup in self.triangleGroups: - addrRange = triGroup.set_addr(addrRange[1], f3d) - if self.cullVertexList is not None: - addrRange = self.cullVertexList.set_addr(addrRange[1]) - for materialTuple, drawOverride in self.drawMatOverrides.items(): - addrRange = drawOverride.set_addr(addrRange[1], f3d) - return startAddress, addrRange[1] + def add_cull_vtx(self): + self.cullVertexList = VtxList(self.name + "_vtx_cull") - def save_binary(self, romfile, f3d, segments): - self.draw.save_binary(romfile, f3d, segments) - for triGroup in self.triangleGroups: - triGroup.save_binary(romfile, f3d, segments) - if self.cullVertexList is not None: - self.cullVertexList.save_binary(romfile) - for materialTuple, drawOverride in self.drawMatOverrides.items(): - drawOverride.save_binary(romfile, f3d, segments) - - def to_c(self, f3d, gfxFormatter): - staticData = CData() - if self.cullVertexList is not None: - staticData.append(self.cullVertexList.to_c()) - for triGroup in self.triangleGroups: - staticData.append(triGroup.to_c(f3d, gfxFormatter)) - dynamicData = gfxFormatter.drawToC(f3d, self.draw) - for materialTuple, drawOverride in self.drawMatOverrides.items(): - dynamicData.append(drawOverride.to_c(f3d)) - return staticData, dynamicData + def get_ptr_addresses(self, f3d): + addresses = self.draw.get_ptr_addresses(f3d) + for triGroup in self.triangleGroups: + addresses.extend(triGroup.get_ptr_addresses(f3d)) + for materialTuple, drawOverride in self.drawMatOverrides.items(): + addresses.extend(drawOverride.get_ptr_addresses(f3d)) + return addresses - def to_c_vertex_scroll(self, gfxFormatter): - cData = CData() - scrollData = [] - stsScrollData = [] - for triGroup in self.triangleGroups: - data, sts_data = triGroup.to_c_vertex_scroll(gfxFormatter) - cData.append(data) - if sts_data is not None: - stsScrollData.append(sts_data) - - filtered_sts: list[CData] = [] - for d in stsScrollData: - if not d.header or not d.source: - continue - new_one = True - for stsd in filtered_sts: - if stsd.header == d.header or stsd.source == d.source: - new_one = False - break - if new_one: - filtered_sts.append(d) - - for fsts in filtered_sts: - cData.append(fsts) + def tri_group_new(self, fMaterial): + # Always static DL + triGroup = FTriGroup(self.name, len(self.triangleGroups), fMaterial) + self.triangleGroups.append(triGroup) + return triGroup + + def set_addr(self, startAddress, f3d): + addrRange = self.draw.set_addr(startAddress, f3d) + startAddress = addrRange[0] + for triGroup in self.triangleGroups: + addrRange = triGroup.set_addr(addrRange[1], f3d) + if self.cullVertexList is not None: + addrRange = self.cullVertexList.set_addr(addrRange[1]) + for materialTuple, drawOverride in self.drawMatOverrides.items(): + addrRange = drawOverride.set_addr(addrRange[1], f3d) + return startAddress, addrRange[1] + + def save_binary(self, romfile, f3d, segments): + self.draw.save_binary(romfile, f3d, segments) + for triGroup in self.triangleGroups: + triGroup.save_binary(romfile, f3d, segments) + if self.cullVertexList is not None: + self.cullVertexList.save_binary(romfile) + for materialTuple, drawOverride in self.drawMatOverrides.items(): + drawOverride.save_binary(romfile, f3d, segments) + + def to_c(self, f3d, gfxFormatter): + staticData = CData() + if self.cullVertexList is not None: + staticData.append(self.cullVertexList.to_c()) + for triGroup in self.triangleGroups: + staticData.append(triGroup.to_c(f3d, gfxFormatter)) + dynamicData = gfxFormatter.drawToC(f3d, self.draw) + for materialTuple, drawOverride in self.drawMatOverrides.items(): + dynamicData.append(drawOverride.to_c(f3d)) + return staticData, dynamicData + + def to_c_vertex_scroll(self, gfxFormatter): + cData = CData() + scrollData = [] + stsScrollData = [] + for triGroup in self.triangleGroups: + data, sts_data = triGroup.to_c_vertex_scroll(gfxFormatter) + cData.append(data) + if sts_data is not None: + stsScrollData.append(sts_data) + + filtered_sts: list[CData] = [] + for d in stsScrollData: + if not d.header or not d.source: + continue + new_one = True + for stsd in filtered_sts: + if stsd.header == d.header or stsd.source == d.source: + new_one = False + break + if new_one: + filtered_sts.append(d) + + for fsts in filtered_sts: + cData.append(fsts) + + return cData - return cData class FTriGroup: - def __init__(self, name, index, fMaterial): - self.fMaterial = fMaterial - self.vertexList = VtxList(name + '_vtx_' + str(index)) - self.triList = GfxList(name + '_tri_' + str(index), GfxListTag.Geometry, DLFormat.Static) - - def get_ptr_addresses(self, f3d): - return self.triList.get_ptr_addresses(f3d) - - def set_addr(self, startAddress, f3d): - addrRange = self.triList.set_addr(startAddress, f3d) - addrRange = self.vertexList.set_addr(addrRange[1]) - return startAddress, addrRange[1] + def __init__(self, name, index, fMaterial): + self.fMaterial = fMaterial + self.vertexList = VtxList(name + "_vtx_" + str(index)) + self.triList = GfxList(name + "_tri_" + str(index), GfxListTag.Geometry, DLFormat.Static) + + def get_ptr_addresses(self, f3d): + return self.triList.get_ptr_addresses(f3d) + + def set_addr(self, startAddress, f3d): + addrRange = self.triList.set_addr(startAddress, f3d) + addrRange = self.vertexList.set_addr(addrRange[1]) + return startAddress, addrRange[1] + + def save_binary(self, romfile, f3d, segments): + self.triList.save_binary(romfile, f3d, segments) + self.vertexList.save_binary(romfile) + + def to_c(self, f3d, gfxFormatter): + data = CData() + data.append(self.vertexList.to_c()) + data.append(self.triList.to_c(f3d)) + return data + + def to_c_vertex_scroll(self, gfxFormatter: GfxFormatter): + if self.fMaterial.scrollData is not None: + return gfxFormatter.vertexScrollToC(self.fMaterial, self.vertexList.name, len(self.vertexList.vertices)) + else: + return CData(), CData() - def save_binary(self, romfile, f3d, segments): - self.triList.save_binary(romfile, f3d, segments) - self.vertexList.save_binary(romfile) - - def to_c(self, f3d, gfxFormatter): - data = CData() - data.append(self.vertexList.to_c()) - data.append(self.triList.to_c(f3d)) - return data - def to_c_vertex_scroll(self, gfxFormatter: GfxFormatter): - if self.fMaterial.scrollData is not None: - return gfxFormatter.vertexScrollToC( - self.fMaterial, - self.vertexList.name, - len(self.vertexList.vertices) - ) - else: - return CData(), CData() - class FScrollDataField: - def __init__(self): - self.animType = "None" - self.speed = 0 + def __init__(self): + self.animType = "None" + self.speed = 0 - self.amplitude = 0 - self.frequency = 0 - self.offset = 0 + self.amplitude = 0 + self.frequency = 0 + self.offset = 0 + + self.noiseAmplitude = 0 - self.noiseAmplitude = 0 class FScrollData: - def __init__(self): - self.fields = [ - [FScrollDataField(), - FScrollDataField()], - - [FScrollDataField(), - FScrollDataField()] - ] - self.dimensions = [0, 0] - self.tile_scroll_tex0 = FSetTileSizeScrollField() - self.tile_scroll_tex1 = FSetTileSizeScrollField() - self.tile_scroll_exported = False + def __init__(self): + self.fields = [[FScrollDataField(), FScrollDataField()], [FScrollDataField(), FScrollDataField()]] + self.dimensions = [0, 0] + self.tile_scroll_tex0 = FSetTileSizeScrollField() + self.tile_scroll_tex1 = FSetTileSizeScrollField() + self.tile_scroll_exported = False + def get_f3d_mat_from_version(material: bpy.types.Material): - return material.f3d_mat if material.mat_ver > 3 else material + return material.f3d_mat if material.mat_ver > 3 else material + class FMaterial: - def __init__(self, name, DLFormat): - self.material = GfxList('mat_' + name, GfxListTag.Material, DLFormat) - self.revert = GfxList('mat_revert_' + name, GfxListTag.MaterialRevert, DLFormat.Static) - self.DLFormat = DLFormat - self.scrollData = FScrollData() + def __init__(self, name, DLFormat): + self.material = GfxList("mat_" + name, GfxListTag.Material, DLFormat) + self.revert = GfxList("mat_revert_" + name, GfxListTag.MaterialRevert, DLFormat.Static) + self.DLFormat = DLFormat + self.scrollData = FScrollData() - # Used for keeping track of shared resources in FModel hierarchy - self.usedImages = [] # array of (image, texFormat, paletteType) = imageKey - self.usedLights = [] # array of light names - # Used for tile scrolling - self.tileSizeCommands = {} # dict of {texIndex : DPSetTileSize} + # Used for keeping track of shared resources in FModel hierarchy + self.usedImages = [] # array of (image, texFormat, paletteType) = imageKey + self.usedLights = [] # array of light names + # Used for tile scrolling + self.tileSizeCommands = {} # dict of {texIndex : DPSetTileSize} - self.useLargeTextures = False - self.largeTextureIndex = None - self.texturesLoaded = [False, False] - self.saveLargeTextures = [True, True] + self.useLargeTextures = False + self.largeTextureIndex = None + self.texturesLoaded = [False, False] + self.saveLargeTextures = [True, True] - def getScrollData(self, material, dimensions): - self.getScrollDataField(material, 0, 0) - self.getScrollDataField(material, 0, 1) - self.getScrollDataField(material, 1, 0) - self.getScrollDataField(material, 1, 1) - self.scrollData.dimensions = dimensions - self.getSetTileSizeScrollData(material) + def getScrollData(self, material, dimensions): + self.getScrollDataField(material, 0, 0) + self.getScrollDataField(material, 0, 1) + self.getScrollDataField(material, 1, 0) + self.getScrollDataField(material, 1, 1) + self.scrollData.dimensions = dimensions + self.getSetTileSizeScrollData(material) - def getScrollDataField(self, material, texIndex, fieldIndex): - UVanim0 = material.f3d_mat.UVanim0 if material.mat_ver > 3 else material.UVanim - UVanim1 = material.f3d_mat.UVanim1 if material.mat_ver > 3 else material.UVanim_tex1 + def getScrollDataField(self, material, texIndex, fieldIndex): + UVanim0 = material.f3d_mat.UVanim0 if material.mat_ver > 3 else material.UVanim + UVanim1 = material.f3d_mat.UVanim1 if material.mat_ver > 3 else material.UVanim_tex1 - if texIndex == 0: - field = getattr(UVanim0, 'xyz'[fieldIndex]) - elif texIndex == 1: - field = getattr(UVanim1, 'xyz'[fieldIndex]) - else: - raise PluginError("Invalid texture index.") + if texIndex == 0: + field = getattr(UVanim0, "xyz"[fieldIndex]) + elif texIndex == 1: + field = getattr(UVanim1, "xyz"[fieldIndex]) + else: + raise PluginError("Invalid texture index.") - scrollField = self.scrollData.fields[texIndex][fieldIndex] + scrollField = self.scrollData.fields[texIndex][fieldIndex] - scrollField.animType = field.animType - scrollField.speed = field.speed - scrollField.amplitude = field.amplitude - scrollField.frequency = field.frequency - scrollField.offset = field.offset + scrollField.animType = field.animType + scrollField.speed = field.speed + scrollField.amplitude = field.amplitude + scrollField.frequency = field.frequency + scrollField.offset = field.offset - scrollField.noiseAmplitude = field.noiseAmplitude + scrollField.noiseAmplitude = field.noiseAmplitude - def getSetTileSizeScrollData(self, material): - tex0 = get_f3d_mat_from_version(material).tex0 - tex1 = get_f3d_mat_from_version(material).tex1 + def getSetTileSizeScrollData(self, material): + tex0 = get_f3d_mat_from_version(material).tex0 + tex1 = get_f3d_mat_from_version(material).tex1 - self.scrollData.tile_scroll_tex0.s = tex0.tile_scroll.s - self.scrollData.tile_scroll_tex0.t = tex0.tile_scroll.t - self.scrollData.tile_scroll_tex0.interval = tex0.tile_scroll.interval - self.scrollData.tile_scroll_tex1.s = tex1.tile_scroll.s - self.scrollData.tile_scroll_tex1.t = tex1.tile_scroll.t - self.scrollData.tile_scroll_tex1.interval = tex1.tile_scroll.interval + self.scrollData.tile_scroll_tex0.s = tex0.tile_scroll.s + self.scrollData.tile_scroll_tex0.t = tex0.tile_scroll.t + self.scrollData.tile_scroll_tex0.interval = tex0.tile_scroll.interval + self.scrollData.tile_scroll_tex1.s = tex1.tile_scroll.s + self.scrollData.tile_scroll_tex1.t = tex1.tile_scroll.t + self.scrollData.tile_scroll_tex1.interval = tex1.tile_scroll.interval - def sets_rendermode(self): - for command in self.material.commands: - if isinstance(command, DPSetRenderMode): - return True - return False + def sets_rendermode(self): + for command in self.material.commands: + if isinstance(command, DPSetRenderMode): + return True + return False - def get_ptr_addresses(self, f3d): - addresses = self.material.get_ptr_addresses(f3d) - if self.revert is not None: - addresses.extend(self.revert.get_ptr_addresses(f3d)) - return addresses - - def set_addr(self, startAddress, f3d): - addrRange = self.material.set_addr(startAddress, f3d) - startAddress = addrRange[0] - if self.revert is not None: - addrRange = self.revert.set_addr(addrRange[1], f3d) - return startAddress, addrRange[1] + def get_ptr_addresses(self, f3d): + addresses = self.material.get_ptr_addresses(f3d) + if self.revert is not None: + addresses.extend(self.revert.get_ptr_addresses(f3d)) + return addresses - def save_binary(self, romfile, f3d, segments): - self.material.save_binary(romfile, f3d, segments) - if self.revert is not None: - self.revert.save_binary(romfile, f3d, segments) + def set_addr(self, startAddress, f3d): + addrRange = self.material.set_addr(startAddress, f3d) + startAddress = addrRange[0] + if self.revert is not None: + addrRange = self.revert.set_addr(addrRange[1], f3d) + return startAddress, addrRange[1] + + def save_binary(self, romfile, f3d, segments): + self.material.save_binary(romfile, f3d, segments) + if self.revert is not None: + self.revert.save_binary(romfile, f3d, segments) + + def to_c(self, f3d): + data = CData() + data.append(self.material.to_c(f3d)) + if self.revert is not None: + data.append(self.revert.to_c(f3d)) + return data - def to_c(self, f3d): - data = CData() - data.append(self.material.to_c(f3d)) - if self.revert is not None: - data.append(self.revert.to_c(f3d)) - return data # viewport # NOTE: unfinished class Vp: - def __init__(self, scale, translation): - self.startAddress = 0 + def __init__(self, scale, translation): + self.startAddress = 0 + class Light: - def __init__(self, color, normal): - self.color = color - self.normal = normal + def __init__(self, color, normal): + self.color = color + self.normal = normal + + def to_binary(self): + return bytearray(self.color + [0x00] + self.color + [0x00] + self.normal + [0x00] + [0x00] * 4) + + def to_c(self): + return ( + "0x" + + format(self.color[0], "X") + + ", " + + "0x" + + format(self.color[1], "X") + + ", " + + "0x" + + format(self.color[2], "X") + + ", " + + "0x" + + format(self.normal[0], "X") + + ", " + + "0x" + + format(self.normal[1], "X") + + ", " + + "0x" + + format(self.normal[2], "X") + ) + + def to_sm64_decomp_s(self): + return ( + ".byte " + + "0x" + + format(self.color[0], "X") + + ", " + + "0x" + + format(self.color[1], "X") + + ", " + + "0x" + + format(self.color[2], "X") + + ", " + + "0x00, " + + "0x" + + format(self.color[0], "X") + + ", " + + "0x" + + format(self.color[1], "X") + + ", " + + "0x" + + format(self.color[2], "X") + + ", " + + "0x00 \n" + + ".byte " + + "0x" + + format(self.normal[0], "X") + + ", " + + "0x" + + format(self.normal[1], "X") + + ", " + + "0x" + + format(self.normal[2], "X") + + ", " + + "0x00, " + + "0x00, 0x00, 0x00, 0x00\n" + ) - def to_binary(self): - return bytearray(self.color + [0x00] + self.color + [0x00] + \ - self.normal + [0x00] + [0x00] * 4) - - def to_c(self): - return \ - '0x' + format(self.color[0], 'X') + ', ' +\ - '0x' + format(self.color[1], 'X') + ', ' +\ - '0x' + format(self.color[2], 'X') + ', ' +\ - '0x' + format(self.normal[0], 'X') + ', ' +\ - '0x' + format(self.normal[1], 'X') + ', ' +\ - '0x' + format(self.normal[2], 'X') - - def to_sm64_decomp_s(self): - return '.byte ' +\ - '0x' + format(self.color[0], 'X') + ', ' +\ - '0x' + format(self.color[1], 'X') + ', ' +\ - '0x' + format(self.color[2], 'X') + ', ' +\ - '0x00, ' + \ - '0x' + format(self.color[0], 'X') + ', ' +\ - '0x' + format(self.color[1], 'X') + ', ' +\ - '0x' + format(self.color[2], 'X') + ', ' +\ - '0x00 \n' +\ - '.byte ' + \ - '0x' + format(self.normal[0], 'X') + ', ' +\ - '0x' + format(self.normal[1], 'X') + ', ' +\ - '0x' + format(self.normal[2], 'X') + ', ' +\ - '0x00, ' + \ - '0x00, 0x00, 0x00, 0x00\n' class Ambient: - def __init__(self, color): - self.color = color - - def to_binary(self): - return bytearray(self.color + [0x00] + self.color + [0x00]) - - def to_c(self): - return \ - '0x' + format(self.color[0], 'X') + ', ' +\ - '0x' + format(self.color[1], 'X') + ', ' +\ - '0x' + format(self.color[2], 'X') - - def to_sm64_decomp_s(self): - return '.byte ' +\ - '0x' + format(self.color[0], 'X') + ', ' +\ - '0x' + format(self.color[1], 'X') + ', ' +\ - '0x' + format(self.color[2], 'X') + ', ' +\ - '0x00, ' + \ - '0x' + format(self.color[0], 'X') + ', ' +\ - '0x' + format(self.color[1], 'X') + ', ' +\ - '0x' + format(self.color[2], 'X') + ', ' +\ - '0x00\n' + def __init__(self, color): + self.color = color + + def to_binary(self): + return bytearray(self.color + [0x00] + self.color + [0x00]) + + def to_c(self): + return ( + "0x" + + format(self.color[0], "X") + + ", " + + "0x" + + format(self.color[1], "X") + + ", " + + "0x" + + format(self.color[2], "X") + ) + + def to_sm64_decomp_s(self): + return ( + ".byte " + + "0x" + + format(self.color[0], "X") + + ", " + + "0x" + + format(self.color[1], "X") + + ", " + + "0x" + + format(self.color[2], "X") + + ", " + + "0x00, " + + "0x" + + format(self.color[0], "X") + + ", " + + "0x" + + format(self.color[1], "X") + + ", " + + "0x" + + format(self.color[2], "X") + + ", " + + "0x00\n" + ) + class Hilite: - def __init__(self, name, x1, y1, x2, y2): - self.name = name - self.startAddress = 0 - self.x1 = x1 - self.y1 = y1 - self.x2 = x2 - self.y2 = y2 - - def to_binary(self): - return self.x1.to_bytes(4, 'big') +\ - self.y1.to_bytes(4, 'big') +\ - self.x2.to_bytes(4, 'big') +\ - self.y2.to_bytes(4, 'big') - - def to_c(self): - return 'Hilite ' + self.name + ' = {' + \ - str(self.x1) + ', ' +\ - str(self.y1) + ', ' +\ - str(self.x2) + ', ' +\ - str(self.y2) + '}' - - def to_sm64_decomp_s(self): - return self.name + ':\n' + '.word ' +\ - str(self.x1) + ', ' +\ - str(self.y1) + ', ' +\ - str(self.x2) + ', ' +\ - str(self.y2) + '\n' + def __init__(self, name, x1, y1, x2, y2): + self.name = name + self.startAddress = 0 + self.x1 = x1 + self.y1 = y1 + self.x2 = x2 + self.y2 = y2 + + def to_binary(self): + return ( + self.x1.to_bytes(4, "big") + + self.y1.to_bytes(4, "big") + + self.x2.to_bytes(4, "big") + + self.y2.to_bytes(4, "big") + ) + + def to_c(self): + return ( + "Hilite " + + self.name + + " = {" + + str(self.x1) + + ", " + + str(self.y1) + + ", " + + str(self.x2) + + ", " + + str(self.y2) + + "}" + ) + + def to_sm64_decomp_s(self): + return ( + self.name + + ":\n" + + ".word " + + str(self.x1) + + ", " + + str(self.y1) + + ", " + + str(self.x2) + + ", " + + str(self.y2) + + "\n" + ) + class Lights: - def __init__(self, name): - self.name = name - self.startAddress = 0 - self.a = None - self.l = [] - - def set_addr(self, startAddress): - startAddress = get64bitAlignedAddr(startAddress) - self.startAddress = startAddress - print('Lights ' + self.name + ': ' + str(startAddress) + ', ' + str(self.size())) - return (startAddress, startAddress + self.size()) - - def save_binary(self, romfile): - romfile.seek(self.startAddress) - romfile.write(self.to_binary()) - - def size(self): - return max(len(self.l), 1) * LIGHT_SIZE + AMBIENT_SIZE - - def getLightPointer(self, i): - return self.startAddress + AMBIENT_SIZE + i * LIGHT_SIZE + def __init__(self, name): + self.name = name + self.startAddress = 0 + self.a = None + self.l = [] - def getAmbientPointer(self): - return self.startAddress - - def to_binary(self): - data = self.a.to_binary() - if len(self.l) == 0: - data += Light([0,0,0],[0,0,0]).to_binary() - else: - for i in range(len(self.l)): - data += self.l[i].to_binary() - return data + def set_addr(self, startAddress): + startAddress = get64bitAlignedAddr(startAddress) + self.startAddress = startAddress + print("Lights " + self.name + ": " + str(startAddress) + ", " + str(self.size())) + return (startAddress, startAddress + self.size()) - def to_c(self): - data = CData() - data.header = "extern Lights" + str(len(self.l)) + " " + self.name + ";\n" - data.source = 'Lights' + str(len(self.l)) + " " + self.name + " = " +\ - 'gdSPDefLights' + str(len(self.l)) + '(\n' - data.source += '\t' + self.a.to_c() - for light in self.l: - data.source += ',\n\t' + light.to_c() - data.source += ');\n\n' - return data + def save_binary(self, romfile): + romfile.seek(self.startAddress) + romfile.write(self.to_binary()) + + def size(self): + return max(len(self.l), 1) * LIGHT_SIZE + AMBIENT_SIZE + + def getLightPointer(self, i): + return self.startAddress + AMBIENT_SIZE + i * LIGHT_SIZE + + def getAmbientPointer(self): + return self.startAddress + + def to_binary(self): + data = self.a.to_binary() + if len(self.l) == 0: + data += Light([0, 0, 0], [0, 0, 0]).to_binary() + else: + for i in range(len(self.l)): + data += self.l[i].to_binary() + return data + + def to_c(self): + data = CData() + data.header = "extern Lights" + str(len(self.l)) + " " + self.name + ";\n" + data.source = "Lights" + str(len(self.l)) + " " + self.name + " = " + "gdSPDefLights" + str(len(self.l)) + "(\n" + data.source += "\t" + self.a.to_c() + for light in self.l: + data.source += ",\n\t" + light.to_c() + data.source += ");\n\n" + return data + + def to_sm64_decomp_s(self): + data = ".balign 8\n" + self.name + ":\n" + data += self.name + "_a:\n" + self.a.to_sm64_decomp_s() + "\n" + if len(self.l) == 0: + data += self.name + "_l0:\n" + Light([0, 0, 0], [0, 0, 0]).to_sm64_decomp_s() + "\n" + else: + for i in range(len(self.l)): + data += self.name + "_l" + str(i) + ":\n" + self.l[i].to_sm64_decomp_s() + "\n" + return data - def to_sm64_decomp_s(self): - data = '.balign 8\n' + self.name + ':\n' - data += self.name + '_a:\n' + self.a.to_sm64_decomp_s() + '\n' - if len(self.l) == 0: - data += self.name + '_l0:\n' + \ - Light([0,0,0],[0,0,0]).to_sm64_decomp_s() + '\n' - else: - for i in range(len(self.l)): - data += self.name + '_l' + str(i) + ':\n' + \ - self.l[i].to_sm64_decomp_s() + '\n' - return data class LookAt: - def __init__(self, name): - self.name = name - self.startAddress = 0 - self.l = [] #2 lights + def __init__(self, name): + self.name = name + self.startAddress = 0 + self.l = [] # 2 lights + + def to_binary(self): + return self.l[0].to_binary() + self.l[1].to_binary() + + def to_c(self): + # {{}} => lookat, light array, + # {{}} => light, light_t + return ( + "LookAt " + + self.name + + " = {{" + + "{{" + + "{" + + str(self.l[0].color[0]) + + ", " + + str(self.l[0].color[1]) + + ", " + + str(self.l[0].color[2]) + + "}, 0, " + + "{" + + str(self.l[0].normal[0]) + + ", " + + str(self.l[0].normal[1]) + + ", " + + str(self.l[0].normal[2]) + + "}, 0" + + "}}" + + "{{" + + "{" + + str(self.l[1].color[0]) + + ", " + + str(self.l[1].color[1]) + + ", " + + str(self.l[1].color[2]) + + "}, 0, " + + "{" + + str(self.l[1].normal[0]) + + ", " + + str(self.l[1].normal[1]) + + ", " + + str(self.l[1].normal[2]) + + "}, 0" + + "}}" + + "}}\n" + ) + + def to_sm64_decomp_s(self): + data = ".balign 8\n" + self.name + ":\n" + data += self.name + ":\n" + data += self.l[0].to_sm64_decomp_s() + "\n" + data += self.l[1].to_sm64_decomp_s() + "\n" + return data - def to_binary(self): - return self.l[0].to_binary() + self.l[1].to_binary() - - def to_c(self): - # {{}} => lookat, light array, - # {{}} => light, light_t - return 'LookAt ' + self.name + ' = {{' + \ - '{{' + \ - "{" + \ - str(self.l[0].color[0]) + ', ' + \ - str(self.l[0].color[1]) + ', ' + \ - str(self.l[0].color[2]) + \ - '}, 0, ' +\ - "{" + \ - str(self.l[0].normal[0]) + ', ' + \ - str(self.l[0].normal[1]) + ', ' + \ - str(self.l[0].normal[2]) + \ - '}, 0' +\ - '}}' + \ - '{{' + \ - "{" + \ - str(self.l[1].color[0]) + ', ' + \ - str(self.l[1].color[1]) + ', ' + \ - str(self.l[1].color[2]) + \ - '}, 0, ' +\ - "{" + \ - str(self.l[1].normal[0]) + ', ' + \ - str(self.l[1].normal[1]) + ', ' + \ - str(self.l[1].normal[2]) + \ - '}, 0' +\ - '}}' + '}}\n' - - def to_sm64_decomp_s(self): - data = '.balign 8\n' + self.name + ':\n' - data += self.name + ':\n' - data += self.l[0].to_sm64_decomp_s() + '\n' - data += self.l[1].to_sm64_decomp_s() + '\n' - return data # A palette is just a RGBA16 texture with width = 1. class FImage: - def __init__(self, name, fmt, bitSize, width, height, filename, converted): - self.name = name - self.fmt = fmt - self.bitSize = bitSize - self.width = width - self.height = height - self.startAddress = 0 - self.data = bytearray(0) - self.filename = filename - self.converted = converted - self.isLargeTexture = False - self.paletteKey = None # another FImage reference - - def size(self): - return len(self.data) + def __init__(self, name, fmt, bitSize, width, height, filename, converted): + self.name = name + self.fmt = fmt + self.bitSize = bitSize + self.width = width + self.height = height + self.startAddress = 0 + self.data = bytearray(0) + self.filename = filename + self.converted = converted + self.isLargeTexture = False + self.paletteKey = None # another FImage reference - def to_binary(self): - return self.data - - def to_c(self, texArrayBitSize): - return self.to_c_helper(self.to_c_data(texArrayBitSize), texArrayBitSize) + def size(self): + return len(self.data) - def to_c_tex_separate(self, texPath, texArrayBitSize): - return self.to_c_helper('#include "' + texPath + self.filename + '"', texArrayBitSize) + def to_binary(self): + return self.data - def to_c_helper(self, texData, bitsPerValue): - code = CData() - code.header = 'extern u' + str(bitsPerValue) + ' ' + self.name + '[];\n' + def to_c(self, texArrayBitSize): + return self.to_c_helper(self.to_c_data(texArrayBitSize), texArrayBitSize) - # This is to force 8 byte alignment - if bitsPerValue != 64: - code.source = 'Gfx ' + self.name + '_aligner[] = {gsSPEndDisplayList()};\n' - code.source += 'u' + str(bitsPerValue) + ' ' + self.name + '[] = {\n\t' - code.source += texData - code.source += '\n};\n\n' - return code + def to_c_tex_separate(self, texPath, texArrayBitSize): + return self.to_c_helper('#include "' + texPath + self.filename + '"', texArrayBitSize) - def to_c_data(self, bitsPerValue): - if not self.converted: - raise PluginError("Error: Trying to write texture data to C, but haven't actually converted the image file to bytes yet.") + def to_c_helper(self, texData, bitsPerValue): + code = CData() + code.header = "extern u" + str(bitsPerValue) + " " + self.name + "[];\n" - bytesPerValue = int(bitsPerValue / 8) - numValues = int(len(self.data) / bytesPerValue) - remainderCount = len(self.data) - numValues * bytesPerValue - digits = 2 + 2 * bytesPerValue + # This is to force 8 byte alignment + if bitsPerValue != 64: + code.source = "Gfx " + self.name + "_aligner[] = {gsSPEndDisplayList()};\n" + code.source += "u" + str(bitsPerValue) + " " + self.name + "[] = {\n\t" + code.source += texData + code.source += "\n};\n\n" + return code - code = ''.join([ - format(int.from_bytes(self.data[ - i * bytesPerValue : (i+1) * bytesPerValue], 'big'), - '#0' + str(digits) + 'x') + ', ' +\ - ('\n\t' if i % 8 == 7 else '') - for i in range(numValues)]) + def to_c_data(self, bitsPerValue): + if not self.converted: + raise PluginError( + "Error: Trying to write texture data to C, but haven't actually converted the image file to bytes yet." + ) - if remainderCount > 0: - start = numValues * bytesPerValue - end = (numValues + 1) * bytesPerValue - code += format(int.from_bytes(self.data[start:end], 'big') << \ - (8 * (bytesPerValue - remainderCount)), '#0' + str(digits) + 'x') + bytesPerValue = int(bitsPerValue / 8) + numValues = int(len(self.data) / bytesPerValue) + remainderCount = len(self.data) - numValues * bytesPerValue + digits = 2 + 2 * bytesPerValue + + code = "".join( + [ + format( + int.from_bytes(self.data[i * bytesPerValue : (i + 1) * bytesPerValue], "big"), + "#0" + str(digits) + "x", + ) + + ", " + + ("\n\t" if i % 8 == 7 else "") + for i in range(numValues) + ] + ) + + if remainderCount > 0: + start = numValues * bytesPerValue + end = (numValues + 1) * bytesPerValue + code += format( + int.from_bytes(self.data[start:end], "big") << (8 * (bytesPerValue - remainderCount)), + "#0" + str(digits) + "x", + ) + + return code + + def set_addr(self, startAddress): + startAddress = get64bitAlignedAddr(startAddress) + self.startAddress = startAddress + print("Image " + self.name + ": " + str(startAddress) + ", " + str(self.size())) + return startAddress, startAddress + self.size() + + def save_binary(self, romfile): + romfile.seek(self.startAddress) + romfile.write(self.to_binary()) - return code - - def set_addr(self, startAddress): - startAddress = get64bitAlignedAddr(startAddress) - self.startAddress = startAddress - print('Image ' + self.name + ': ' + str(startAddress) + \ - ', ' + str(self.size())) - return startAddress, startAddress + self.size() - - def save_binary(self, romfile): - romfile.seek(self.startAddress) - romfile.write(self.to_binary()) # second arg of Dma is a pointer. def gsDma0p(c, s, l): - words = _SHIFTL(c, 24, 8) | _SHIFTL(l, 0, 24), int(s) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(c, 24, 8) | _SHIFTL(l, 0, 24), int(s) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def gsDma1p(c, s, l, p): - words = _SHIFTL(c, 24, 8) | _SHIFTL(p, 16, 8) | \ - _SHIFTL(l, 0, 16), int(s) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(c, 24, 8) | _SHIFTL(p, 16, 8) | _SHIFTL(l, 0, 16), int(s) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def gsDma2p(c, adrs, length, idx, ofs): - words = _SHIFTL(c,24,8) | _SHIFTL((length-1)/8,19,5) | \ - _SHIFTL(ofs/8,8,8) | _SHIFTL(idx,0,8), int(adrs) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - + words = _SHIFTL(c, 24, 8) | _SHIFTL((length - 1) / 8, 19, 5) | _SHIFTL(ofs / 8, 8, 8) | _SHIFTL(idx, 0, 8), int( + adrs + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def gsSPNoOp(f3d): - return gsDma0p(f3d.G_SPNOOP, 0, 0) + return gsDma0p(f3d.G_SPNOOP, 0, 0) + class SPMatrix: - def __init__(self, matrix, param): - self.matrix = matrix - self.param = param - - def get_ptr_offsets(self, f3d): - return [4] + def __init__(self, matrix, param): + self.matrix = matrix + self.param = param - def to_binary(self, f3d, segments): - matPtr = int(self.matrix, 16) - if f3d.F3DEX_GBI_2: - return gsDma2p(f3d.G_MTX, matPtr, MTX_SIZE, self.param ^ f3d.G_MTX_PUSH, 0) - else: - return gsDma1p(f3d.G_MTX, matPtr, MTX_SIZE, self.param) - - def to_c(self, static = True): - header = 'gsSPMatrix(' if static else 'gSPMatrix(glistp++, ' - if not static and bpy.context.scene.decomp_compatible: - header += 'segmented_to_virtual(' + str(self.matrix) + ')' - else: - header += str(self.matrix) - return header + ", " + \ - str(self.param) + ')' + def get_ptr_offsets(self, f3d): + return [4] - def to_sm64_decomp_s(self): - return 'gsSPMatrix ' + str(self.matrix) + ", " + str(self.param) + def to_binary(self, f3d, segments): + matPtr = int(self.matrix, 16) + if f3d.F3DEX_GBI_2: + return gsDma2p(f3d.G_MTX, matPtr, MTX_SIZE, self.param ^ f3d.G_MTX_PUSH, 0) + else: + return gsDma1p(f3d.G_MTX, matPtr, MTX_SIZE, self.param) + + def to_c(self, static=True): + header = "gsSPMatrix(" if static else "gSPMatrix(glistp++, " + if not static and bpy.context.scene.decomp_compatible: + header += "segmented_to_virtual(" + str(self.matrix) + ")" + else: + header += str(self.matrix) + return header + ", " + str(self.param) + ")" + + def to_sm64_decomp_s(self): + return "gsSPMatrix " + str(self.matrix) + ", " + str(self.param) + + def size(self, f3d): + return GFX_SIZE - def size(self, f3d): - return GFX_SIZE # TODO: Divide vertlist into sections # Divide mesh drawing by materials into separate gfx class SPVertex: - # v = seg pointer, n = count, v0 = ? - def __init__(self, vertList, offset, count, index): - self.vertList = vertList - self.offset = offset - self.count = count - self.index = index + # v = seg pointer, n = count, v0 = ? + def __init__(self, vertList, offset, count, index): + self.vertList = vertList + self.offset = offset + self.count = count + self.index = index - def get_ptr_offsets(self, f3d): - return [4] + def get_ptr_offsets(self, f3d): + return [4] - def to_binary(self, f3d, segments): - vertPtr = int.from_bytes(encodeSegmentedAddr( - self.vertList.startAddress + self.offset * VTX_SIZE, - segments), 'big') + def to_binary(self, f3d, segments): + vertPtr = int.from_bytes( + encodeSegmentedAddr(self.vertList.startAddress + self.offset * VTX_SIZE, segments), "big" + ) - if f3d.F3DEX_GBI_2: - words = _SHIFTL(f3d.G_VTX, 24, 8) | _SHIFTL(self.count, 12, 8) | \ - _SHIFTL(self.index + self.count, 1, 7), vertPtr - - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - - elif f3d.F3DEX_GBI or f3d.F3DLP_GBI: - return gsDma1p(f3d.G_VTX, vertPtr, \ - (self.count << 10) | (VTX_SIZE * self.count -1), \ - self.index * 2) + if f3d.F3DEX_GBI_2: + words = ( + _SHIFTL(f3d.G_VTX, 24, 8) | _SHIFTL(self.count, 12, 8) | _SHIFTL(self.index + self.count, 1, 7), + vertPtr, + ) - else: - return gsDma1p(f3d.G_VTX, vertPtr, \ - VTX_SIZE * self.count, (self.count - 1) << 4 | \ - self.index) - - def to_c(self, static = True): - header = 'gsSPVertex(' if static else 'gSPVertex(glistp++, ' - if not static and bpy.context.scene.decomp_compatible: - header += 'segmented_to_virtual(' + self.vertList.name + ' + ' + str(self.offset) + ')' - else: - header += self.vertList.name + ' + ' + str(self.offset) - return header + ", " + \ - str(self.count) + ', ' + str(self.index) + ')' + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + elif f3d.F3DEX_GBI or f3d.F3DLP_GBI: + return gsDma1p(f3d.G_VTX, vertPtr, (self.count << 10) | (VTX_SIZE * self.count - 1), self.index * 2) + + else: + return gsDma1p(f3d.G_VTX, vertPtr, VTX_SIZE * self.count, (self.count - 1) << 4 | self.index) + + def to_c(self, static=True): + header = "gsSPVertex(" if static else "gSPVertex(glistp++, " + if not static and bpy.context.scene.decomp_compatible: + header += "segmented_to_virtual(" + self.vertList.name + " + " + str(self.offset) + ")" + else: + header += self.vertList.name + " + " + str(self.offset) + return header + ", " + str(self.count) + ", " + str(self.index) + ")" + + def to_sm64_decomp_s(self): + return ( + "gsSPVertex " + + self.vertList.name + + ", " + + str(self.offset) + + ", " + + str(self.count) + + ", " + + str(self.index) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPVertex ' + self.vertList.name + ", " + str(self.offset) +\ - ', ' + str(self.count) + ', ' + str(self.index) - - def size(self, f3d): - return GFX_SIZE class SPViewport: - # v = seg pointer, n = count, v0 = ? - def __init__(self, viewport): - self.viewport = viewport - - def get_ptr_offsets(self, f3d): - return [4] + # v = seg pointer, n = count, v0 = ? + def __init__(self, viewport): + self.viewport = viewport - def to_binary(self, f3d, segments): - vpPtr = int.from_bytes(encodeSegmentedAddr( - self.viewport.startAddress, segments), 'big') + def get_ptr_offsets(self, f3d): + return [4] - if f3d.F3DEX_GBI_2: - return gsDma2p(f3d.G_MOVEMEM, vpPtr, VP_SIZE, f3d.G_MV_VIEWPORT, 0) - else: - return gsDma1p(f3d.G_MOVEMEM, vpPtr, VP_SIZE, f3d.G_MV_VIEWPORT) - - def to_c(self, static = True): - header = 'gsSPViewport(' if static else 'gSPViewport(glistp++, ' - return header + '&' + self.viewport.name + ')' + def to_binary(self, f3d, segments): + vpPtr = int.from_bytes(encodeSegmentedAddr(self.viewport.startAddress, segments), "big") + + if f3d.F3DEX_GBI_2: + return gsDma2p(f3d.G_MOVEMEM, vpPtr, VP_SIZE, f3d.G_MV_VIEWPORT, 0) + else: + return gsDma1p(f3d.G_MOVEMEM, vpPtr, VP_SIZE, f3d.G_MV_VIEWPORT) + + def to_c(self, static=True): + header = "gsSPViewport(" if static else "gSPViewport(glistp++, " + return header + "&" + self.viewport.name + ")" + + def to_sm64_decomp_s(self): + return "gsSPViewport " + self.viewport.name + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPViewport ' + self.viewport.name - - def size(self, f3d): - return GFX_SIZE class SPDisplayList: - def __init__(self, displayList): - self.displayList = displayList - - def get_ptr_offsets(self, f3d): - return [4] + def __init__(self, displayList): + self.displayList = displayList - def to_binary(self, f3d, segments): - dlPtr = int.from_bytes(encodeSegmentedAddr( - self.displayList.startAddress, segments), 'big') - return gsDma1p(f3d.G_DL, dlPtr, 0, f3d.G_DL_PUSH) - - def to_c(self, static = True): - if static: - return 'gsSPDisplayList(' + self.displayList.name + ')' - elif self.displayList.DLFormat == DLFormat.Static: - header = 'gSPDisplayList(glistp++, ' - if bpy.context.scene.decomp_compatible: - return header + 'segmented_to_virtual(' + self.displayList.name + '))' - else: - return header + self.displayList.name + ')' - else: - return 'glistp = ' + self.displayList.name + '(glistp)' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + dlPtr = int.from_bytes(encodeSegmentedAddr(self.displayList.startAddress, segments), "big") + return gsDma1p(f3d.G_DL, dlPtr, 0, f3d.G_DL_PUSH) + + def to_c(self, static=True): + if static: + return "gsSPDisplayList(" + self.displayList.name + ")" + elif self.displayList.DLFormat == DLFormat.Static: + header = "gSPDisplayList(glistp++, " + if bpy.context.scene.decomp_compatible: + return header + "segmented_to_virtual(" + self.displayList.name + "))" + else: + return header + self.displayList.name + ")" + else: + return "glistp = " + self.displayList.name + "(glistp)" + + def to_sm64_decomp_s(self): + return "gsSPDisplayList " + self.displayList.name + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPDisplayList ' + self.displayList.name - - def size(self, f3d): - return GFX_SIZE class SPBranchList: - def __init__(self, displayList): - self.displayList = displayList - - def get_ptr_offsets(self, f3d): - return [4] + def __init__(self, displayList): + self.displayList = displayList - def to_binary(self, f3d, segments): - dlPtr = int.from_bytes(encodeSegmentedAddr( - self.displayList.startAddress, segments), 'big') - return gsDma1p(f3d.G_DL, dlPtr, 0, f3d.G_DL_NOPUSH) - - def to_c(self, static = True): - header = 'gsSPBranchList(' if static else 'gSPBranchList(glistp++, ' - return header + '&' + self.displayList.name + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + dlPtr = int.from_bytes(encodeSegmentedAddr(self.displayList.startAddress, segments), "big") + return gsDma1p(f3d.G_DL, dlPtr, 0, f3d.G_DL_NOPUSH) + + def to_c(self, static=True): + header = "gsSPBranchList(" if static else "gSPBranchList(glistp++, " + return header + "&" + self.displayList.name + ")" + + def to_sm64_decomp_s(self): + return "gsSPBranchList " + self.displayList.name + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPBranchList ' + self.displayList.name - - def size(self, f3d): - return GFX_SIZE # SPSprite2DBase # RSP short command (no DMA required) macros def gsImmp0(c): - words = _SHIFTL((c), 24, 8), 0 - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL((c), 24, 8), 0 + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def gsImmp1(c, p0): - words = _SHIFTL((c), 24, 8), int(p0) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL((c), 24, 8), int(p0) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def gsImmp2(c, p0, p1): - words = _SHIFTL((c), 24, 8), _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL((c), 24, 8), _SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +def gsImmp3(c, p0, p1, p2): + words = _SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) | _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8)) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + -def gsImmp3(c, p0, p1, p2): - words = _SHIFTL((c), 24, 8), (_SHIFTL((p0), 16, 16) | \ - _SHIFTL((p1), 8, 8) | _SHIFTL((p2), 0, 8)) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - # last arg of Immp21 is a pointer. -def gsImmp21(c, p0, p1, dat): - words = _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8),\ - int(dat) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') +def gsImmp21(c, p0, p1, dat): + words = _SHIFTL((c), 24, 8) | _SHIFTL((p0), 8, 16) | _SHIFTL((p1), 0, 8), int(dat) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def gsMoveWd(index, offset, data, f3d): - if f3d.F3DEX_GBI_2: - return gsDma1p(f3d.G_MOVEWORD, data, offset, index) - else: - return gsImmp21(f3d.G_MOVEWORD, offset, index, data) + if f3d.F3DEX_GBI_2: + return gsDma1p(f3d.G_MOVEWORD, data, offset, index) + else: + return gsImmp21(f3d.G_MOVEWORD, offset, index, data) + # SPSprite2DScaleFlip # SPSprite2DDraw @@ -3083,318 +3595,345 @@ def gsMoveWd(index, offset, data, f3d): # Note: the SP1Triangle() and line macros multiply the vertex indices # by 10, this is an optimization for the microcode. + def _gsSP1Triangle_w1(v0, v1, v2): - return (_SHIFTL((v0)*2,16,8)|_SHIFTL((v1)*2,8,8)|_SHIFTL((v2)*2,0,8)) + return _SHIFTL((v0) * 2, 16, 8) | _SHIFTL((v1) * 2, 8, 8) | _SHIFTL((v2) * 2, 0, 8) + def _gsSP1Triangle_w1f(v0, v1, v2, flag, f3d): - if f3d.F3DLP_GBI or f3d.F3DEX_GBI: - if flag == 0: - return _gsSP1Triangle_w1(v0, v1, v2) - elif flag == 1: - return _gsSP1Triangle_w1(v1, v2, v0) - else: - return _gsSP1Triangle_w1(v2, v0, v1) - else: - return (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)|\ - _SHIFTL((v1)*10, 8,8)|_SHIFTL((v2)*10, 0,8)) + if f3d.F3DLP_GBI or f3d.F3DEX_GBI: + if flag == 0: + return _gsSP1Triangle_w1(v0, v1, v2) + elif flag == 1: + return _gsSP1Triangle_w1(v1, v2, v0) + else: + return _gsSP1Triangle_w1(v2, v0, v1) + else: + return _SHIFTL((flag), 24, 8) | _SHIFTL((v0) * 10, 16, 8) | _SHIFTL((v1) * 10, 8, 8) | _SHIFTL((v2) * 10, 0, 8) + def _gsSPLine3D_w1(v0, v1, wd): - return (_SHIFTL((v0)*2,16,8)|_SHIFTL((v1)*2,8,8)|_SHIFTL((wd),0,8)) + return _SHIFTL((v0) * 2, 16, 8) | _SHIFTL((v1) * 2, 8, 8) | _SHIFTL((wd), 0, 8) + def _gsSPLine3D_w1f(v0, v1, wd, flag, f3d): - if f3d.F3DLP_GBI or f3d.F3DEX_GBI: - if flag == 0: - return _gsSPLine3D_w1(v0, v1, wd) - else: - return _gsSPLine3D_w1(v1, v0, wd) - else: - return (_SHIFTL((flag), 24,8)|_SHIFTL((v0)*10,16,8)| \ - _SHIFTL((v1)*10, 8,8)|_SHIFTL((wd),0,8)) + if f3d.F3DLP_GBI or f3d.F3DEX_GBI: + if flag == 0: + return _gsSPLine3D_w1(v0, v1, wd) + else: + return _gsSPLine3D_w1(v1, v0, wd) + else: + return _SHIFTL((flag), 24, 8) | _SHIFTL((v0) * 10, 16, 8) | _SHIFTL((v1) * 10, 8, 8) | _SHIFTL((wd), 0, 8) + def _gsSP1Quadrangle_w1f(v0, v1, v2, v3, flag): - if flag == 0: - return _gsSP1Triangle_w1(v0, v1, v2) - elif flag == 1: - return _gsSP1Triangle_w1(v1, v2, v3) - elif flag == 2: - return _gsSP1Triangle_w1(v2, v3, v0) - else: - return _gsSP1Triangle_w1(v3, v0, v1) + if flag == 0: + return _gsSP1Triangle_w1(v0, v1, v2) + elif flag == 1: + return _gsSP1Triangle_w1(v1, v2, v3) + elif flag == 2: + return _gsSP1Triangle_w1(v2, v3, v0) + else: + return _gsSP1Triangle_w1(v3, v0, v1) + def _gsSP1Quadrangle_w2f(v0, v1, v2, v3, flag): - if flag == 0: - return _gsSP1Triangle_w1(v0, v2, v3) - elif flag == 1: - return _gsSP1Triangle_w1(v1, v3, v0) - elif flag == 1: - return _gsSP1Triangle_w1(v2, v0, v1) - else: - return _gsSP1Triangle_w1(v3, v1, v2) + if flag == 0: + return _gsSP1Triangle_w1(v0, v2, v3) + elif flag == 1: + return _gsSP1Triangle_w1(v1, v3, v0) + elif flag == 1: + return _gsSP1Triangle_w1(v2, v0, v1) + else: + return _gsSP1Triangle_w1(v3, v1, v2) + class SP1Triangle: - def __init__(self, v0, v1, v2, flag): - self.v0 = v0 - self.v1 = v1 - self.v2 = v2 - self.flag = flag + def __init__(self, v0, v1, v2, flag): + self.v0 = v0 + self.v1 = v1 + self.v2 = v2 + self.flag = flag - def to_binary(self, f3d, segments): - if f3d.F3DEX_GBI_2: - words = _SHIFTL(f3d.G_TRI1, 24, 8) | \ - _gsSP1Triangle_w1f(self.v0, self.v1, self.v2, - self.flag, f3d), 0 - else: - words = _SHIFTL(f3d.G_TRI1, 24, 8), _gsSP1Triangle_w1f( - self.v0, self.v1, self.v2, self.flag, f3d) - - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def to_binary(self, f3d, segments): + if f3d.F3DEX_GBI_2: + words = _SHIFTL(f3d.G_TRI1, 24, 8) | _gsSP1Triangle_w1f(self.v0, self.v1, self.v2, self.flag, f3d), 0 + else: + words = _SHIFTL(f3d.G_TRI1, 24, 8), _gsSP1Triangle_w1f(self.v0, self.v1, self.v2, self.flag, f3d) - - def to_c(self, static = True): - header = 'gsSP1Triangle(' if static else 'gSP1Triangle(glistp++, ' - return header + str(self.v0) + ', ' + str(self.v1) + ', ' + \ - str(self.v2) + ', ' + str(self.flag) + ')' + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSP1Triangle(" if static else "gSP1Triangle(glistp++, " + return header + str(self.v0) + ", " + str(self.v1) + ", " + str(self.v2) + ", " + str(self.flag) + ")" + + def to_sm64_decomp_s(self): + return "gsSP1Triangle " + str(self.v0) + ", " + str(self.v1) + ", " + str(self.v2) + ", " + str(self.flag) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSP1Triangle ' + str(self.v0) + ', ' + str(self.v1) + \ - ', ' + str(self.v2) + ', ' + str(self.flag) - - def size(self, f3d): - return GFX_SIZE class SPLine3D: - def __init__(self, v0, v1,flag): - self.v0 = v0 - self.v1 = v1 - self.flag = flag + def __init__(self, v0, v1, flag): + self.v0 = v0 + self.v1 = v1 + self.flag = flag - def to_binary(self, f3d, segments): - if f3d.F3DEX_GBI_2: - words = _SHIFTL(f3d.G_LINE3D, 24, 8)|_gsSPLine3D_w1f( - self.v0, self.v1, 0, self.flag, f3d), 0 - else: - words = _SHIFTL(f3d.G_LINE3D, 24, 8), _gsSPLine3D_w1f( - self.v0, self.v1, 0, self.flag, f3d) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - - def to_c(self, static = True): - header = 'gsSPLine3D(' if static else 'gSPLine3D(glistp++, ' - return header + str(self.v0) + ', ' + str(self.v1) + ', ' + \ - str(self.flag) + ')' + def to_binary(self, f3d, segments): + if f3d.F3DEX_GBI_2: + words = _SHIFTL(f3d.G_LINE3D, 24, 8) | _gsSPLine3D_w1f(self.v0, self.v1, 0, self.flag, f3d), 0 + else: + words = _SHIFTL(f3d.G_LINE3D, 24, 8), _gsSPLine3D_w1f(self.v0, self.v1, 0, self.flag, f3d) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSPLine3D(" if static else "gSPLine3D(glistp++, " + return header + str(self.v0) + ", " + str(self.v1) + ", " + str(self.flag) + ")" + + def to_sm64_decomp_s(self): + return "gsSPLine3D " + str(self.v0) + ", " + str(self.v1) + ", " + str(self.flag) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPLine3D ' + str(self.v0) + ', ' + str(self.v1) + \ - ', ' + str(self.flag) - - def size(self, f3d): - return GFX_SIZE class SPLineW3D: - def __init__(self, v0, v1, wd, flag): - self.v0 = v0 - self.v1 = v1 - self.wd = wd - self.flag = flag + def __init__(self, v0, v1, wd, flag): + self.v0 = v0 + self.v1 = v1 + self.wd = wd + self.flag = flag - def to_binary(self, f3d, segments): - if f3d.F3DEX_GBI_2: - words = _SHIFTL(f3d.G_LINE3D, 24, 8) | _gsSPLine3D_w1f( - self.v0, self.v1, self.wd, self.flag, f3d), 0 - else: - words = _SHIFTL(f3d.G_LINE3D, 24, 8), _gsSPLine3D_w1f( - self.v0, self.v1, self.wd, self.flag, f3d) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - - def to_c(self, static = True): - header = 'gsSPLineW3D(' if static else 'gSPLineW3D(glistp++, ' - return header + str(self.v0) + ', ' + str(self.v1) + ', ' + \ - str(self.wd) + ', ' + str(self.flag) + ')' + def to_binary(self, f3d, segments): + if f3d.F3DEX_GBI_2: + words = _SHIFTL(f3d.G_LINE3D, 24, 8) | _gsSPLine3D_w1f(self.v0, self.v1, self.wd, self.flag, f3d), 0 + else: + words = _SHIFTL(f3d.G_LINE3D, 24, 8), _gsSPLine3D_w1f(self.v0, self.v1, self.wd, self.flag, f3d) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSPLineW3D(" if static else "gSPLineW3D(glistp++, " + return header + str(self.v0) + ", " + str(self.v1) + ", " + str(self.wd) + ", " + str(self.flag) + ")" + + def to_sm64_decomp_s(self): + return "gsSPLineW3D " + str(self.v0) + ", " + str(self.v1) + ", " + str(self.wd) + ", " + str(self.flag) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPLineW3D ' + str(self.v0) + ', ' + str(self.v1) + ', ' + \ - str(self.wd) + ', ' + str(self.flag) - - def size(self, f3d): - return GFX_SIZE # SP1Quadrangle + class SP2Triangles: - def __init__(self, v00, v01, v02, flag0, v10, v11, v12, flag1): - self.v00 = v00 - self.v01 = v01 - self.v02 = v02 - self.flag0 = flag0 - self.v10 = v10 - self.v11 = v11 - self.v12 = v12 - self.flag1 = flag1 + def __init__(self, v00, v01, v02, flag0, v10, v11, v12, flag1): + self.v00 = v00 + self.v01 = v01 + self.v02 = v02 + self.flag0 = flag0 + self.v10 = v10 + self.v11 = v11 + self.v12 = v12 + self.flag1 = flag1 - def to_binary(self, f3d, segments): - if f3d.F3DLP_GBI or f3d.F3DEX_GBI: - words = (_SHIFTL(f3d.G_TRI2, 24, 8) | \ - _gsSP1Triangle_w1f( - self.v00, self.v01, self.v02, self.flag0, f3d)), \ - _gsSP1Triangle_w1f( - self.v10, self.v11, self.v12, self.flag1, f3d) - else: - raise PluginError("SP2Triangles not available in Fast3D.") - - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def to_binary(self, f3d, segments): + if f3d.F3DLP_GBI or f3d.F3DEX_GBI: + words = ( + _SHIFTL(f3d.G_TRI2, 24, 8) | _gsSP1Triangle_w1f(self.v00, self.v01, self.v02, self.flag0, f3d) + ), _gsSP1Triangle_w1f(self.v10, self.v11, self.v12, self.flag1, f3d) + else: + raise PluginError("SP2Triangles not available in Fast3D.") - - def to_c(self, static = True): - header = 'gsSP2Triangles(' if static else 'gSP2Triangles(glistp++, ' - return header + str(self.v00) + ', ' + str(self.v01) + ', ' + \ - str(self.v02) + ', ' + str(self.flag0) + ', ' + str(self.v10) + \ - ', ' + str(self.v11) + ', ' + str(self.v12) + ', ' + \ - str(self.flag1) + ')' + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSP2Triangles(" if static else "gSP2Triangles(glistp++, " + return ( + header + + str(self.v00) + + ", " + + str(self.v01) + + ", " + + str(self.v02) + + ", " + + str(self.flag0) + + ", " + + str(self.v10) + + ", " + + str(self.v11) + + ", " + + str(self.v12) + + ", " + + str(self.flag1) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsSP2Triangles " + + str(self.v00) + + ", " + + str(self.v01) + + ", " + + str(self.v02) + + ", " + + str(self.flag0) + + ", " + + str(self.v10) + + ", " + + str(self.v11) + + ", " + + str(self.v12) + + ", " + + str(self.flag1) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSP2Triangles ' + str(self.v00) + ', ' + str(self.v01) + \ - ', ' + str(self.v02) + ', ' + str(self.flag0) + ', ' + \ - str(self.v10) + ', ' + str(self.v11) + ', ' + str(self.v12) + \ - ', ' + str(self.flag1) - - def size(self, f3d): - return GFX_SIZE class SPCullDisplayList: - def __init__(self, vstart, vend): - self.vstart = vstart - self.vend = vend + def __init__(self, vstart, vend): + self.vstart = vstart + self.vend = vend - def to_binary(self, f3d, segments): - if f3d.F3DLP_GBI or f3d.F3DEX_GBI: - words = _SHIFTL(f3d.G_CULLDL, 24, 8) | \ - _SHIFTL((self.vstart)*2, 0, 16), _SHIFTL((self.vend)*2, 0, 16) - else: - words = _SHIFTL(f3d.G_CULLDL, 24, 8) | ((0x0f & (self.vstart))*40),\ - ((0x0f & ((self.vend)+1))*40) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - - def to_c(self, static = True): - header = 'gsSPCullDisplayList(' if static else \ - 'gSPCullDisplayList(glistp++, ' - return header + str(self.vstart) + ', ' + str(self.vend) + ')' + def to_binary(self, f3d, segments): + if f3d.F3DLP_GBI or f3d.F3DEX_GBI: + words = _SHIFTL(f3d.G_CULLDL, 24, 8) | _SHIFTL((self.vstart) * 2, 0, 16), _SHIFTL((self.vend) * 2, 0, 16) + else: + words = _SHIFTL(f3d.G_CULLDL, 24, 8) | ((0x0F & (self.vstart)) * 40), ((0x0F & ((self.vend) + 1)) * 40) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSPCullDisplayList(" if static else "gSPCullDisplayList(glistp++, " + return header + str(self.vstart) + ", " + str(self.vend) + ")" + + def to_sm64_decomp_s(self): + return "gsSPCullDisplayList " + str(self.vstart) + ", " + str(self.vend) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPCullDisplayList ' + str(self.vstart) + ', ' + str(self.vend) - - def size(self, f3d): - return GFX_SIZE class SPSegment: - def __init__(self, segment, base): - self.segment = segment - self.base = base + def __init__(self, segment, base): + self.segment = segment + self.base = base - def to_binary(self, f3d, segments): - return gsMoveWd(f3d.G_MW_SEGMENT, (self.segment)*4, self.base, f3d) - - def to_c(self, static = True): - header = 'gsSPSegment(' if static else 'gSPSegment(glistp++, ' - return header + str(self.segment) + ', ' + '0x' + \ - format(self.base, 'X') + ')' + def to_binary(self, f3d, segments): + return gsMoveWd(f3d.G_MW_SEGMENT, (self.segment) * 4, self.base, f3d) + + def to_c(self, static=True): + header = "gsSPSegment(" if static else "gSPSegment(glistp++, " + return header + str(self.segment) + ", " + "0x" + format(self.base, "X") + ")" + + def to_sm64_decomp_s(self): + return "gsSPSegment " + str(self.segment) + ", 0x" + format(self.base, "X") + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPSegment ' + str(self.segment) + ', 0x' + \ - format(self.base, 'X') - - def size(self, f3d): - return GFX_SIZE class SPClipRatio: - def __init__(self, ratio): - self.ratio = ratio + def __init__(self, ratio): + self.ratio = ratio - def to_binary(self, f3d, segments): + def to_binary(self, f3d, segments): - # These values are supposed to be flipped. - shortRatioPos = int.from_bytes((-self.ratio).to_bytes( - 2, 'big', signed = True), 'big', signed = False) - shortRatioNeg = int.from_bytes(self.ratio.to_bytes( - 2, 'big', signed = True), 'big', signed = False) + # These values are supposed to be flipped. + shortRatioPos = int.from_bytes((-self.ratio).to_bytes(2, "big", signed=True), "big", signed=False) + shortRatioNeg = int.from_bytes(self.ratio.to_bytes(2, "big", signed=True), "big", signed=False) - return \ - gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RNX, shortRatioNeg, f3d) +\ - gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RNY, shortRatioNeg, f3d) +\ - gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RPX, shortRatioPos, f3d) +\ - gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RPY, shortRatioPos, f3d) + return ( + gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RNX, shortRatioNeg, f3d) + + gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RNY, shortRatioNeg, f3d) + + gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RPX, shortRatioPos, f3d) + + gsMoveWd(f3d.G_MW_CLIP, f3d.G_MWO_CLIP_RPY, shortRatioPos, f3d) + ) - def to_c(self, static = True): - header = 'gsSPClipRatio(' if static else 'gSPClipRatio(glistp++, ' - return header + str(self.ratio) + ')' + def to_c(self, static=True): + header = "gsSPClipRatio(" if static else "gSPClipRatio(glistp++, " + return header + str(self.ratio) + ")" + + def to_sm64_decomp_s(self): + return "gsSPClipRatio " + str(self.ratio) + + def size(self, f3d): + return GFX_SIZE * 4 - def to_sm64_decomp_s(self): - return 'gsSPClipRatio ' + str(self.ratio) - - def size(self, f3d): - return GFX_SIZE * 4 # SPInsertMatrix # SPForceMatrix + class SPModifyVertex: - def __init__(self, vtx, where, val): - self.vtx = vtx - self.where = where - self.val = val + def __init__(self, vtx, where, val): + self.vtx = vtx + self.where = where + self.val = val - def to_binary(self, f3d, segments): - if f3d.F3DLP_GBI or f3d.F3DEX_GBI: - words = _SHIFTL(f3d.G_MODIFYVTX,24,8) | \ - _SHIFTL((self.where),16,8) | \ - _SHIFTL((self.vtx)*2,0,16), self.val - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') - else: - return gsMoveWd(f3d.G_MW_POINTS, (self.vtx)*40+(self.where), \ - self.val, f3d) - - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def to_binary(self, f3d, segments): + if f3d.F3DLP_GBI or f3d.F3DEX_GBI: + words = ( + _SHIFTL(f3d.G_MODIFYVTX, 24, 8) | _SHIFTL((self.where), 16, 8) | _SHIFTL((self.vtx) * 2, 0, 16), + self.val, + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + else: + return gsMoveWd(f3d.G_MW_POINTS, (self.vtx) * 40 + (self.where), self.val, f3d) - def to_c(self, static = True): - header = 'gsSPModifyVertex(' if static else 'gSPModifyVertex(glistp++, ' - return header + str(self.vtx) + ', ' + str(self.where) + ', ' + \ - str(self.val) + ')' + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSPModifyVertex(" if static else "gSPModifyVertex(glistp++, " + return header + str(self.vtx) + ", " + str(self.where) + ", " + str(self.val) + ")" + + def to_sm64_decomp_s(self): + return "gsSPModifyVertex " + str(self.vtx) + ", " + str(self.where) + ", " + str(self.val) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPModifyVertex ' + str(self.vtx) + ', ' + \ - str(self.where) + ', ' + str(self.val) - - def size(self, f3d): - return GFX_SIZE # LOD commands? # SPBranchLessZ + class SPBranchLessZraw: - def __init__(self, dl, vtx, zval): - self.dl = dl - self.vtx = vtx - self.zval = zval + def __init__(self, dl, vtx, zval): + self.dl = dl + self.vtx = vtx + self.zval = zval - def to_binary(self, f3d, segments): - dlPtr = int.from_bytes(encodeSegmentedAddr( - self.dl.startAddress, segments), 'big') + def to_binary(self, f3d, segments): + dlPtr = int.from_bytes(encodeSegmentedAddr(self.dl.startAddress, segments), "big") - words0 = _SHIFTL(f3d.G_RDPHALF_1, 24, 8), dlPtr - words1 = _SHIFTL(f3d.G_BRANCH_Z,24,8)|_SHIFTL((self.vtx)*5,12,12)|_SHIFTL((self.vtx)*2,0,12), self.zval - - return words0[0].to_bytes(4, 'big') + words0[1].to_bytes(4, 'big') +\ - words1[0].to_bytes(4, 'big') + words1[1].to_bytes(4, 'big') + words0 = _SHIFTL(f3d.G_RDPHALF_1, 24, 8), dlPtr + words1 = ( + _SHIFTL(f3d.G_BRANCH_Z, 24, 8) | _SHIFTL((self.vtx) * 5, 12, 12) | _SHIFTL((self.vtx) * 2, 0, 12), + self.zval, + ) - def to_c(self, static = True): - dlName = self.dl.name - header = 'gsSPBranchLessZraw(' if static else 'gSPBranchLessZraw(glistp++, ' - return header + dlName + ", " + str(self.vtx) + ", " + str(self.zval) + ")" + return ( + words0[0].to_bytes(4, "big") + + words0[1].to_bytes(4, "big") + + words1[0].to_bytes(4, "big") + + words1[1].to_bytes(4, "big") + ) + + def to_c(self, static=True): + dlName = self.dl.name + header = "gsSPBranchLessZraw(" if static else "gSPBranchLessZraw(glistp++, " + return header + dlName + ", " + str(self.vtx) + ", " + str(self.zval) + ")" + + def to_sm64_decomp_s(self): + dlName = self.dl.name + return "gsSPBranchLessZraw " + dlName + ", " + str(self.vtx) + ", " + str(self.zval) + + def size(self, f3d): + return GFX_SIZE * 2 - def to_sm64_decomp_s(self): - dlName = self.dl.name - return 'gsSPBranchLessZraw ' + dlName + ", " + str(self.vtx) + ", " + str(self.zval) - - def size(self, f3d): - return GFX_SIZE * 2 # SPLoadUcode (RSP) @@ -3404,914 +3943,1044 @@ class SPBranchLessZraw: # SPDmaWrite # SPDmaWrite + class SPNumLights: - # n is macro name (string) - def __init__(self, n): - self.n = n - - def to_binary(self, f3d, segments): - return gsMoveWd(f3d.G_MW_NUMLIGHT, f3d.G_MWO_NUMLIGHT, \ - f3d.NUML(self.n), f3d) + # n is macro name (string) + def __init__(self, n): + self.n = n - def to_c(self, static = True): - header = 'gsSPNumLights(' if static else 'gSPNumLights(glistp++, ' - return header + str(self.n) + ')' + def to_binary(self, f3d, segments): + return gsMoveWd(f3d.G_MW_NUMLIGHT, f3d.G_MWO_NUMLIGHT, f3d.NUML(self.n), f3d) + + def to_c(self, static=True): + header = "gsSPNumLights(" if static else "gSPNumLights(glistp++, " + return header + str(self.n) + ")" + + def to_sm64_decomp_s(self): + return "gsSPNumLights " + str(self.n) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPNumLights ' + str(self.n) - - def size(self, f3d): - return GFX_SIZE class SPLight: - # n is macro name (string) - def __init__(self, light, n): - self.light = light # start address of light - self.n = n - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - lightPtr = int.from_bytes(encodeSegmentedAddr( - self.light, segments), 'big') - if f3d.F3DEX_GBI_2: - data = gsDma2p(f3d.G_MOVEMEM, lightPtr, LIGHT_SIZE, \ - f3d.G_MV_LIGHT, lightIndex[self.n] * 24 + 24) - else: - data = gsDma1p(f3d.G_MOVEMEM, lightPtr, LIGHT_SIZE, \ - (lightIndex[self.n]-1) * 2 + f3d.G_MV_L0) - return data + # n is macro name (string) + def __init__(self, light, n): + self.light = light # start address of light + self.n = n - def to_c(self, static = True): - header = 'gsSPLight(' if static else 'gSPLight(glistp++, ' - if not static and bpy.context.scene.decomp_compatible: - header += 'segmented_to_virtual(' + self.light.name + ')' - else: - header += self.light.name - return header + ', ' + str(self.n) + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + lightPtr = int.from_bytes(encodeSegmentedAddr(self.light, segments), "big") + if f3d.F3DEX_GBI_2: + data = gsDma2p(f3d.G_MOVEMEM, lightPtr, LIGHT_SIZE, f3d.G_MV_LIGHT, lightIndex[self.n] * 24 + 24) + else: + data = gsDma1p(f3d.G_MOVEMEM, lightPtr, LIGHT_SIZE, (lightIndex[self.n] - 1) * 2 + f3d.G_MV_L0) + return data + + def to_c(self, static=True): + header = "gsSPLight(" if static else "gSPLight(glistp++, " + if not static and bpy.context.scene.decomp_compatible: + header += "segmented_to_virtual(" + self.light.name + ")" + else: + header += self.light.name + return header + ", " + str(self.n) + ")" + + def to_sm64_decomp_s(self): + return "gsSPLight " + self.light.name + ", " + str(self.n) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPLight ' + self.light.name + ', ' + str(self.n) - - def size(self, f3d): - return GFX_SIZE class SPLightColor: - # n is macro name (string) - def __init__(self, n, col): - self.n = n - self.col = col - - def to_binary(self, f3d, segments): - return \ - gsMoveWd(f3d.G_MW_LIGHTCOL, f3d.getLightMWO_a(self.n), - self.col, f3d), +\ - gsMoveWd(f3d.G_MW_LIGHTCOL, f3d.getLightMWO_b(self.n), - self.col, f3d) + # n is macro name (string) + def __init__(self, n, col): + self.n = n + self.col = col - def to_c(self, static = True): - header = 'gsSPLightColor(' if static else 'gSPLightColor(glistp++, ' - return header + str(self.n) + ', 0x' + format(self.col, '08X') + ')' + def to_binary(self, f3d, segments): + return gsMoveWd(f3d.G_MW_LIGHTCOL, f3d.getLightMWO_a(self.n), self.col, f3d), +gsMoveWd( + f3d.G_MW_LIGHTCOL, f3d.getLightMWO_b(self.n), self.col, f3d + ) - def to_sm64_decomp_s(self): - return 'gsSPLightColor ' + str(self.n) + ', 0x' + \ - format(self.col, '08X') + def to_c(self, static=True): + header = "gsSPLightColor(" if static else "gSPLightColor(glistp++, " + return header + str(self.n) + ", 0x" + format(self.col, "08X") + ")" + + def to_sm64_decomp_s(self): + return "gsSPLightColor " + str(self.n) + ", 0x" + format(self.col, "08X") + + def size(self, f3d): + return GFX_SIZE - def size(self, f3d): - return GFX_SIZE class SPSetLights: - def __init__(self, lights): - self.lights = lights - - def get_ptr_offsets(self, f3d): - offsets = [] - if len(self.lights.l) == 0: - offsets = [12, 20] - else: - lightNum = len(self.lights.l) - for i in range(lightNum): - offsets.append((i+1) * 8 + 4) - offsets.append((lightNum + 1) * 8 + 4) - return offsets - - def to_binary(self, f3d, segments): - data = SPNumLights('NUMLIGHTS_' + str(len(self.lights.l))).to_binary( - f3d, segments) - if len(self.lights.l) == 0: - # The light does not exist in python, but is added in - # when converted to binary, making this address valid. - data += SPLight(self.lights.getLightPointer(0), 'LIGHT_1' - ).to_binary(f3d, segments) - data += SPLight(self.lights.getAmbientPointer(), 'LIGHT_2' - ).to_binary(f3d, segments) - else: - for i in range(len(self.lights.l)): - data += SPLight(self.lights.getLightPointer(i), - 'LIGHT_' + str(i+1)).to_binary(f3d, segments) - data += SPLight(self.lights.getAmbientPointer(), - 'LIGHT_' + str(len(self.lights.l) + 1)).to_binary(f3d, segments) - return data + def __init__(self, lights): + self.lights = lights - def to_c(self, static = True): - header = 'gsSPSetLights' + str(len(self.lights.l)) + '(' if static \ - else 'gSPSetLights' + str(len(self.lights.l)) + '(glistp++, ' - if not static and bpy.context.scene.decomp_compatible: - header += '(*(Lights' + str(len(self.lights.l)) + '*) segmented_to_virtual(&' + self.lights.name + '))' - else: - header += self.lights.name - return header + ')' + def get_ptr_offsets(self, f3d): + offsets = [] + if len(self.lights.l) == 0: + offsets = [12, 20] + else: + lightNum = len(self.lights.l) + for i in range(lightNum): + offsets.append((i + 1) * 8 + 4) + offsets.append((lightNum + 1) * 8 + 4) + return offsets - def to_sm64_decomp_s(self): - return 'gsSPSetLights ' + self.lights.name + def to_binary(self, f3d, segments): + data = SPNumLights("NUMLIGHTS_" + str(len(self.lights.l))).to_binary(f3d, segments) + if len(self.lights.l) == 0: + # The light does not exist in python, but is added in + # when converted to binary, making this address valid. + data += SPLight(self.lights.getLightPointer(0), "LIGHT_1").to_binary(f3d, segments) + data += SPLight(self.lights.getAmbientPointer(), "LIGHT_2").to_binary(f3d, segments) + else: + for i in range(len(self.lights.l)): + data += SPLight(self.lights.getLightPointer(i), "LIGHT_" + str(i + 1)).to_binary(f3d, segments) + data += SPLight(self.lights.getAmbientPointer(), "LIGHT_" + str(len(self.lights.l) + 1)).to_binary( + f3d, segments + ) + return data + + def to_c(self, static=True): + header = ( + "gsSPSetLights" + str(len(self.lights.l)) + "(" + if static + else "gSPSetLights" + str(len(self.lights.l)) + "(glistp++, " + ) + if not static and bpy.context.scene.decomp_compatible: + header += "(*(Lights" + str(len(self.lights.l)) + "*) segmented_to_virtual(&" + self.lights.name + "))" + else: + header += self.lights.name + return header + ")" + + def to_sm64_decomp_s(self): + return "gsSPSetLights " + self.lights.name + + def size(self, f3d): + return GFX_SIZE * (2 + max(len(self.lights.l), 1)) - def size(self, f3d): - return GFX_SIZE * (2 + max(len(self.lights.l), 1)) # Reflection/Hiliting Macros + def gsSPLookAtX(l, f3d): - if f3d.F3DEX_GBI_2: - return gsDma2p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LIGHT, - f3d.G_MVO_LOOKATX) - else: - return gsDma1p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LOOKATX) + if f3d.F3DEX_GBI_2: + return gsDma2p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LIGHT, f3d.G_MVO_LOOKATX) + else: + return gsDma1p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LOOKATX) + def gsSPLookAtY(l, f3d): - if f3d.F3DEX_GBI_2: - return gsDma2p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LIGHT, - f3d.G_MVO_LOOKATY) - else: - return gsDma1p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LOOKATY) + if f3d.F3DEX_GBI_2: + return gsDma2p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LIGHT, f3d.G_MVO_LOOKATY) + else: + return gsDma1p(f3d.G_MOVEMEM, l, LIGHT_SIZE, f3d.G_MV_LOOKATY) + class SPLookAt: - def __init__(self, la): - self.la = la - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - light0Ptr = int.from_bytes(encodeSegmentedAddr( - self.la.startAddress, segments), 'big') - return gsSPLookAtX(light0Ptr, f3d) + gsSPLookAtY(light0Ptr + 16, f3d) + def __init__(self, la): + self.la = la - def to_c(self, static = True): - header = 'gsSPLookAt(' if static else 'gSPLookAt(glistp++, ' - return header + '&' + self.la.name + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + light0Ptr = int.from_bytes(encodeSegmentedAddr(self.la.startAddress, segments), "big") + return gsSPLookAtX(light0Ptr, f3d) + gsSPLookAtY(light0Ptr + 16, f3d) + + def to_c(self, static=True): + header = "gsSPLookAt(" if static else "gSPLookAt(glistp++, " + return header + "&" + self.la.name + ")" + + def to_sm64_decomp_s(self): + return "gsSPLookAt " + self.la.name + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPLookAt ' + self.la.name - - def size(self, f3d): - return GFX_SIZE class DPSetHilite1Tile: - def __init__(self, tile, hilite, width, height): - self.tile = tile - self.hilite = hilite - self.width = width - self.height = height - - def to_binary(self, f3d, segments): - return DPSetTileSize(self.tile, - self.hilite.x1 & 0xfff, self.hilite.y1 & 0xfff, - ((self.width - 1) * 4 + self.hilite.x1) & 0xfff, - ((self.height - 1) * 4 + self.hilite.y1) & 0xfff).to_binary( - f3d,segments) + def __init__(self, tile, hilite, width, height): + self.tile = tile + self.hilite = hilite + self.width = width + self.height = height - def to_c(self, static = True): - header = 'gsDPSetHilite1Tile(' if static else \ - 'gDPSetHilite1Tile(glistp++, ' - return header + str(self.tile) + ', ' + '&' + self.hilite.name + \ - ', ' + str(self.width) + ', ' + str(self.height) + ')' + def to_binary(self, f3d, segments): + return DPSetTileSize( + self.tile, + self.hilite.x1 & 0xFFF, + self.hilite.y1 & 0xFFF, + ((self.width - 1) * 4 + self.hilite.x1) & 0xFFF, + ((self.height - 1) * 4 + self.hilite.y1) & 0xFFF, + ).to_binary(f3d, segments) + + def to_c(self, static=True): + header = "gsDPSetHilite1Tile(" if static else "gDPSetHilite1Tile(glistp++, " + return ( + header + + str(self.tile) + + ", " + + "&" + + self.hilite.name + + ", " + + str(self.width) + + ", " + + str(self.height) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetHilite1Tile " + + str(self.tile) + + ", " + + self.hilite.name + + ", " + + str(self.width) + + ", " + + str(self.height) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetHilite1Tile ' + str(self.tile) + ', ' + \ - self.hilite.name + ', ' + str(self.width) + ', ' + str(self.height) - - def size(self, f3d): - return GFX_SIZE class DPSetHilite2Tile: - def __init__(self, tile, hilite, width, height): - self.tile = tile - self.hilite = hilite - self.width = width - self.height = height - - def to_binary(self, f3d, segments): - return DPSetTileSize(self.tile, - self.hilite.x2 & 0xfff, self.hilite.y2 & 0xfff, - ((self.width - 1) * 4 + self.hilite.x2) & 0xfff, - ((self.height - 1) * 4 + self.hilite.y2) & 0xfff).to_binary( - f3d,segments) + def __init__(self, tile, hilite, width, height): + self.tile = tile + self.hilite = hilite + self.width = width + self.height = height - def to_c(self, static = True): - header = 'gsDPSetHilite2Tile(' if static else \ - 'gDPSetHilite2Tile(glistp++, ' - return header + str(self.tile) + ', ' + '&' + self.hilite.name + \ - ', ' + str(self.width) + ', ' + str(self.height) + ')' + def to_binary(self, f3d, segments): + return DPSetTileSize( + self.tile, + self.hilite.x2 & 0xFFF, + self.hilite.y2 & 0xFFF, + ((self.width - 1) * 4 + self.hilite.x2) & 0xFFF, + ((self.height - 1) * 4 + self.hilite.y2) & 0xFFF, + ).to_binary(f3d, segments) - def to_sm64_decomp_s(self): - return 'gsDPSetHilite2Tile ' + str(self.tile) + ', ' + \ - self.hilite.name + ', ' + str(self.width) + ', ' + str(self.height) + def to_c(self, static=True): + header = "gsDPSetHilite2Tile(" if static else "gDPSetHilite2Tile(glistp++, " + return ( + header + + str(self.tile) + + ", " + + "&" + + self.hilite.name + + ", " + + str(self.width) + + ", " + + str(self.height) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetHilite2Tile " + + str(self.tile) + + ", " + + self.hilite.name + + ", " + + str(self.width) + + ", " + + str(self.height) + ) + + def size(self, f3d): + return GFX_SIZE - def size(self, f3d): - return GFX_SIZE class SPFogFactor: - def __init__(self, fm, fo): - self.fm = fm - self.fo = fo - - def to_binary(self, f3d, segments): - return gsMoveWd(f3d.G_MW_FOG, f3d.G_MWO_FOG, \ - (_SHIFTL(self.fm,16,16) | _SHIFTL(self.fo,0,16)), f3d) + def __init__(self, fm, fo): + self.fm = fm + self.fo = fo - def to_c(self, static = True): - header = 'gsSPFogFactor(' if static else 'gSPFogFactor(glistp++, ' - return header + str(self.fm) + ', ' + str(self.fo) + ')' + def to_binary(self, f3d, segments): + return gsMoveWd(f3d.G_MW_FOG, f3d.G_MWO_FOG, (_SHIFTL(self.fm, 16, 16) | _SHIFTL(self.fo, 0, 16)), f3d) + + def to_c(self, static=True): + header = "gsSPFogFactor(" if static else "gSPFogFactor(glistp++, " + return header + str(self.fm) + ", " + str(self.fo) + ")" + + def to_sm64_decomp_s(self): + return "gsSPFogFactor " + str(self.fm) + ", " + str(self.fo) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPFogFactor ' + str(self.fm) + ', ' + str(self.fo) - - def size(self, f3d): - return GFX_SIZE class SPFogPosition: - def __init__(self, minVal, maxVal): - self.minVal = int(round(minVal)) - self.maxVal = int(round(maxVal)) - - def to_binary(self, f3d, segments): - return gsMoveWd(f3d.G_MW_FOG, f3d.G_MWO_FOG,\ - (_SHIFTL((128000/((self.maxVal)-(self.minVal))),16,16) | \ - _SHIFTL(((500-(self.minVal))*256/((self.maxVal)-(self.minVal))), - 0,16)), f3d) + def __init__(self, minVal, maxVal): + self.minVal = int(round(minVal)) + self.maxVal = int(round(maxVal)) - def to_c(self, static = True): - header = 'gsSPFogPosition(' if static else 'gSPFogPosition(glistp++, ' - return header + str(self.minVal) + ', ' + str(self.maxVal) + ')' + def to_binary(self, f3d, segments): + return gsMoveWd( + f3d.G_MW_FOG, + f3d.G_MWO_FOG, + ( + _SHIFTL((128000 / ((self.maxVal) - (self.minVal))), 16, 16) + | _SHIFTL(((500 - (self.minVal)) * 256 / ((self.maxVal) - (self.minVal))), 0, 16) + ), + f3d, + ) + + def to_c(self, static=True): + header = "gsSPFogPosition(" if static else "gSPFogPosition(glistp++, " + return header + str(self.minVal) + ", " + str(self.maxVal) + ")" + + def to_sm64_decomp_s(self): + return "gsSPFogPosition " + str(self.minVal) + ", " + str(self.maxVal) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPFogPosition ' + str(self.minVal) + ', ' + str(self.maxVal) - - def size(self, f3d): - return GFX_SIZE class SPTexture: - def __init__(self, s, t, level, tile, on): - self.s = s - self.t = t - self.level = level - self.tile = tile - self.on = on - - def to_binary(self, f3d, segments): - if f3d.F3DEX_GBI_2: - words = (_SHIFTL(f3d.G_TEXTURE,24,8) | \ - _SHIFTL(f3d.BOWTIE_VAL,16,8) | \ - _SHIFTL((self.level),11,3) | _SHIFTL((self.tile),8,3) | \ - _SHIFTL((self.on),1,7)), (_SHIFTL((self.s),16,16) | \ - _SHIFTL((self.t),0,16)) - else: - words = (_SHIFTL(f3d.G_TEXTURE,24,8) | \ - _SHIFTL(f3d.BOWTIE_VAL,16,8) | \ - _SHIFTL((self.level),11,3)|_SHIFTL((self.tile),8,3) | \ - _SHIFTL((self.on),0,8)), (_SHIFTL((self.s),16,16) | \ - _SHIFTL((self.t),0,16)) + def __init__(self, s, t, level, tile, on): + self.s = s + self.t = t + self.level = level + self.tile = tile + self.on = on - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def to_binary(self, f3d, segments): + if f3d.F3DEX_GBI_2: + words = ( + _SHIFTL(f3d.G_TEXTURE, 24, 8) + | _SHIFTL(f3d.BOWTIE_VAL, 16, 8) + | _SHIFTL((self.level), 11, 3) + | _SHIFTL((self.tile), 8, 3) + | _SHIFTL((self.on), 1, 7) + ), (_SHIFTL((self.s), 16, 16) | _SHIFTL((self.t), 0, 16)) + else: + words = ( + _SHIFTL(f3d.G_TEXTURE, 24, 8) + | _SHIFTL(f3d.BOWTIE_VAL, 16, 8) + | _SHIFTL((self.level), 11, 3) + | _SHIFTL((self.tile), 8, 3) + | _SHIFTL((self.on), 0, 8) + ), (_SHIFTL((self.s), 16, 16) | _SHIFTL((self.t), 0, 16)) - def to_c(self, static = True): - header = 'gsSPTexture(' if static else 'gSPTexture(glistp++, ' - return header + str(self.s) + ', ' + str(self.t) + ', ' + \ - str(self.level) + ', ' + str(self.tile) + ', ' + str(self.on) + ')' + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsSPTexture(" if static else "gSPTexture(glistp++, " + return ( + header + + str(self.s) + + ", " + + str(self.t) + + ", " + + str(self.level) + + ", " + + str(self.tile) + + ", " + + str(self.on) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsSPTexture " + + str(self.s) + + ", " + + str(self.t) + + ", " + + str(self.level) + + ", " + + str(self.tile) + + ", " + + str(self.on) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPTexture ' + str(self.s) + ', ' + str(self.t) + ', ' + \ - str(self.level) + ', ' + str(self.tile) + ', ' + str(self.on) - - def size(self, f3d): - return GFX_SIZE # SPTextureL + class SPPerspNormalize: - def __init__(self, s): - self.s = s - - def to_binary(self, f3d, segments): - return gsMoveWd(f3d.G_MW_PERSPNORM, 0, (self.s), f3d) + def __init__(self, s): + self.s = s - def to_c(self, static = True): - header = 'gsSPPerspNormalize(' if static else \ - 'gSPPerspNormalize(glistp++, ' - return header + str(self.s) + ')' + def to_binary(self, f3d, segments): + return gsMoveWd(f3d.G_MW_PERSPNORM, 0, (self.s), f3d) + + def to_c(self, static=True): + header = "gsSPPerspNormalize(" if static else "gSPPerspNormalize(glistp++, " + return header + str(self.s) + ")" + + def to_sm64_decomp_s(self): + return "gsSPPerspNormalize " + str(self.s) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsSPPerspNormalize ' + str(self.s) - - def size(self, f3d): - return GFX_SIZE # SPPopMatrixN # SPPopMatrix + class SPEndDisplayList: - def __init__(self): - pass - - def to_binary(self, f3d, segments): - words = _SHIFTL(f3d.G_ENDDL, 24, 8), 0 - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self): + pass + + def to_binary(self, f3d, segments): + words = _SHIFTL(f3d.G_ENDDL, 24, 8), 0 + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + return "gsSPEndDisplayList()" if static else "gSPEndDisplayList(glistp++)" + + def to_sm64_decomp_s(self): + return "gsSPEndDisplayList" + + def size(self, f3d): + return GFX_SIZE - def to_c(self, static = True): - return 'gsSPEndDisplayList()' if static else \ - 'gSPEndDisplayList(glistp++)' +def gsSPGeometryMode_F3DEX_GBI_2(c, s, f3d): + words = (_SHIFTL(f3d.G_GEOMETRYMODE, 24, 8) | _SHIFTL(~c, 0, 24)), s + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") - def to_sm64_decomp_s(self): - return 'gsSPEndDisplayList' - - def size(self, f3d): - return GFX_SIZE - -def gsSPGeometryMode_F3DEX_GBI_2(c,s,f3d): - words = (_SHIFTL(f3d.G_GEOMETRYMODE,24,8) | \ - _SHIFTL(~c,0,24)), s - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') def gsSPGeometryMode_Non_F3DEX_GBI_2(word, f3d): - words = _SHIFTL(f3d.G_SETGEOMETRYMODE, 24, 8), word - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(f3d.G_SETGEOMETRYMODE, 24, 8), word + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def geoFlagListToWord(flagList, f3d): - word = 0 - for name in flagList: - if name == 'G_ZBUFFER': word += f3d.G_ZBUFFER - elif name == 'G_SHADE': word += f3d.G_SHADE - elif name == 'G_TEXTURE_ENABLE': word += f3d.G_TEXTURE_ENABLE - elif name == 'G_SHADING_SMOOTH': word += f3d.G_SHADING_SMOOTH - elif name == 'G_CULL_FRONT': word += f3d.G_CULL_FRONT - elif name == 'G_CULL_BACK': word += f3d.G_CULL_BACK - elif name == 'G_CULL_BOTH': word += f3d.G_CULL_BOTH - elif name == 'G_FOG': word += f3d.G_FOG - elif name == 'G_LIGHTING': word += f3d.G_LIGHTING - elif name == 'G_TEXTURE_GEN': word += f3d.G_TEXTURE_GEN - elif name == 'G_TEXTURE_GEN_LINEAR': word += f3d.G_TEXTURE_GEN_LINEAR - elif name == 'G_LOD': word += f3d.G_LOD - elif name == 'G_CLIPPING': word += f3d.G_CLIPPING - else: raise PluginError("Invalid geometry mode flag " + name) - - return word + word = 0 + for name in flagList: + if name == "G_ZBUFFER": + word += f3d.G_ZBUFFER + elif name == "G_SHADE": + word += f3d.G_SHADE + elif name == "G_TEXTURE_ENABLE": + word += f3d.G_TEXTURE_ENABLE + elif name == "G_SHADING_SMOOTH": + word += f3d.G_SHADING_SMOOTH + elif name == "G_CULL_FRONT": + word += f3d.G_CULL_FRONT + elif name == "G_CULL_BACK": + word += f3d.G_CULL_BACK + elif name == "G_CULL_BOTH": + word += f3d.G_CULL_BOTH + elif name == "G_FOG": + word += f3d.G_FOG + elif name == "G_LIGHTING": + word += f3d.G_LIGHTING + elif name == "G_TEXTURE_GEN": + word += f3d.G_TEXTURE_GEN + elif name == "G_TEXTURE_GEN_LINEAR": + word += f3d.G_TEXTURE_GEN_LINEAR + elif name == "G_LOD": + word += f3d.G_LOD + elif name == "G_CLIPPING": + word += f3d.G_CLIPPING + else: + raise PluginError("Invalid geometry mode flag " + name) + + return word + class SPGeometryMode: - def __init__(self, clearFlagList, setFlagList): - self.clearFlagList = clearFlagList - self.setFlagList = setFlagList - - def to_binary(self, f3d, segments): - if f3d.F3DEX_GBI_2: - wordClear = geoFlagListToWord(self.clearFlagList, f3d) - wordSet = geoFlagListToWord(self.setFlagList, f3d) + def __init__(self, clearFlagList, setFlagList): + self.clearFlagList = clearFlagList + self.setFlagList = setFlagList - return gsSPGeometryMode_F3DEX_GBI_2(wordClear, wordSet, f3d) - else: - raise PluginError("GeometryMode only available in F3DEX_GBI_2.") + def to_binary(self, f3d, segments): + if f3d.F3DEX_GBI_2: + wordClear = geoFlagListToWord(self.clearFlagList, f3d) + wordSet = geoFlagListToWord(self.setFlagList, f3d) - def to_c(self, static = True): - data = 'gsSPGeometryMode(' if static else \ - 'gSPGeometryMode(glistp++, ' - data += ((' | '.join(self.clearFlagList)) if len(self.clearFlagList) > 0 else '0') + ', ' - data += ((' | '.join(self.setFlagList)) if len(self.setFlagList) > 0 else '0') + ')' - return data + return gsSPGeometryMode_F3DEX_GBI_2(wordClear, wordSet, f3d) + else: + raise PluginError("GeometryMode only available in F3DEX_GBI_2.") + + def to_c(self, static=True): + data = "gsSPGeometryMode(" if static else "gSPGeometryMode(glistp++, " + data += ((" | ".join(self.clearFlagList)) if len(self.clearFlagList) > 0 else "0") + ", " + data += ((" | ".join(self.setFlagList)) if len(self.setFlagList) > 0 else "0") + ")" + return data + + def to_sm64_decomp_s(self): + data = "gsSPGeometryMode " + for flag in self.clearFlagList: + data += flag + " | " + data = data[:-3] + ", " + for flag in self.setFlagList: + data += flag + " | " + return data[:-3] + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - data = 'gsSPGeometryMode ' - for flag in self.clearFlagList: - data += flag + ' | ' - data = data[:-3] + ', ' - for flag in self.setFlagList: - data += flag + ' | ' - return data[:-3] - - def size(self, f3d): - return GFX_SIZE class SPSetGeometryMode: - def __init__(self, flagList): - self.flagList = flagList - - def to_binary(self, f3d, segments): - word = geoFlagListToWord(self.flagList, f3d) - if f3d.F3DEX_GBI_2: - return gsSPGeometryMode_F3DEX_GBI_2(0, word, f3d) - else: - words = _SHIFTL(f3d.G_SETGEOMETRYMODE, 24, 8), word - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, flagList): + self.flagList = flagList - def to_c(self, static = True): - data = 'gsSPSetGeometryMode(' if static else \ - 'gSPSetGeometryMode(glistp++, ' - for flag in self.flagList: - data += flag + ' | ' - return data[:-3] + ')' + def to_binary(self, f3d, segments): + word = geoFlagListToWord(self.flagList, f3d) + if f3d.F3DEX_GBI_2: + return gsSPGeometryMode_F3DEX_GBI_2(0, word, f3d) + else: + words = _SHIFTL(f3d.G_SETGEOMETRYMODE, 24, 8), word + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + data = "gsSPSetGeometryMode(" if static else "gSPSetGeometryMode(glistp++, " + for flag in self.flagList: + data += flag + " | " + return data[:-3] + ")" + + def to_sm64_decomp_s(self): + data = "gsSPSetGeometryMode " + for flag in self.flagList: + data += flag + " | " + return data[:-3] + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - data = 'gsSPSetGeometryMode ' - for flag in self.flagList: - data += flag + ' | ' - return data[:-3] - - def size(self, f3d): - return GFX_SIZE class SPClearGeometryMode: - def __init__(self, flagList): - self.flagList = flagList - - def to_binary(self, f3d, segments): - word = geoFlagListToWord(self.flagList, f3d) - if f3d.F3DEX_GBI_2: - return gsSPGeometryMode_F3DEX_GBI_2(word, 0, f3d) - else: - words = _SHIFTL(f3d.G_CLEARGEOMETRYMODE, 24, 8), word - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, flagList): + self.flagList = flagList - def to_c(self, static = True): - data = 'gsSPClearGeometryMode(' if static else \ - 'gSPClearGeometryMode(glistp++, ' - for flag in self.flagList: - data += flag + ' | ' - return data[:-3] + ')' + def to_binary(self, f3d, segments): + word = geoFlagListToWord(self.flagList, f3d) + if f3d.F3DEX_GBI_2: + return gsSPGeometryMode_F3DEX_GBI_2(word, 0, f3d) + else: + words = _SHIFTL(f3d.G_CLEARGEOMETRYMODE, 24, 8), word + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + data = "gsSPClearGeometryMode(" if static else "gSPClearGeometryMode(glistp++, " + for flag in self.flagList: + data += flag + " | " + return data[:-3] + ")" + + def to_sm64_decomp_s(self): + data = "gsSPClearGeometryMode " + for flag in self.flagList: + data += flag + " | " + return data[:-3] + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - data = 'gsSPClearGeometryMode ' - for flag in self.flagList: - data += flag + ' | ' - return data[:-3] - - def size(self, f3d): - return GFX_SIZE class SPLoadGeometryMode: - def __init__(self, flagList): - self.flagList = flagList - - def to_binary(self, f3d, segments): - word = geoFlagListToWord(self.flagList, f3d) - if f3d.F3DEX_GBI_2: - return gsSPGeometryMode_F3DEX_GBI_2(-1, word, f3d) - else: - raise PluginError("LoadGeometryMode only available in F3DEX_GBI_2.") + def __init__(self, flagList): + self.flagList = flagList - def to_c(self, static = True): - data = 'gsSPLoadGeometryMode(' if static else \ - 'gSPLoadGeometryMode(glistp++, ' - for flag in self.flagList: - data += flag + ' | ' - return data[:-3] + ')' + def to_binary(self, f3d, segments): + word = geoFlagListToWord(self.flagList, f3d) + if f3d.F3DEX_GBI_2: + return gsSPGeometryMode_F3DEX_GBI_2(-1, word, f3d) + else: + raise PluginError("LoadGeometryMode only available in F3DEX_GBI_2.") + + def to_c(self, static=True): + data = "gsSPLoadGeometryMode(" if static else "gSPLoadGeometryMode(glistp++, " + for flag in self.flagList: + data += flag + " | " + return data[:-3] + ")" + + def to_sm64_decomp_s(self): + data = "gsSPLoadGeometryMode " + for flag in self.flagList: + data += flag + " | " + return data[:-3] + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - data = 'gsSPLoadGeometryMode ' - for flag in self.flagList: - data += flag + ' | ' - return data[:-3] - - def size(self, f3d): - return GFX_SIZE def gsSPSetOtherMode(cmd, sft, length, data, f3d): - if f3d.F3DEX_GBI_2: - words = _SHIFTL(cmd,24,8) | _SHIFTL(32-(sft)-(length),8,8) | \ - _SHIFTL((length)-1,0,8), data - else: - words = _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | \ - _SHIFTL(length, 0, 8), (data) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + if f3d.F3DEX_GBI_2: + words = _SHIFTL(cmd, 24, 8) | _SHIFTL(32 - (sft) - (length), 8, 8) | _SHIFTL((length) - 1, 0, 8), data + else: + words = _SHIFTL(cmd, 24, 8) | _SHIFTL(sft, 8, 8) | _SHIFTL(length, 0, 8), (data) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + class SPSetOtherMode: - def __init__(self, cmd, sft, length, flagList): - self.cmd = cmd - self.sft = sft - self.length = length - self.flagList = [] + def __init__(self, cmd, sft, length, flagList): + self.cmd = cmd + self.sft = sft + self.length = length + self.flagList = [] - def to_binary(self, f3d, segments): - data = 0 - for flag in self.flagList: - data |= getattr(f3d, flag) if hasattr(f3d, str(flag)) else flag - cmd = getattr(f3d, self.cmd) if hasattr(f3d, str(self.cmd)) else self.cmd - sft = getattr(f3d, self.sft) if hasattr(f3d, str(self.sft)) else self.sft - return gsSPSetOtherMode(cmd, sft, self.length, data, f3d) + def to_binary(self, f3d, segments): + data = 0 + for flag in self.flagList: + data |= getattr(f3d, flag) if hasattr(f3d, str(flag)) else flag + cmd = getattr(f3d, self.cmd) if hasattr(f3d, str(self.cmd)) else self.cmd + sft = getattr(f3d, self.sft) if hasattr(f3d, str(self.sft)) else self.sft + return gsSPSetOtherMode(cmd, sft, self.length, data, f3d) - def to_c(self, static = True): - data = '' - for flag in self.flagList: - data += flag + ' | ' - data = data[:-3] - header = 'gsSPSetOtherMode(' if static else \ - 'gSPSetOtherMode(glistp++, ' - return header + str(self.cmd) + ", " + str(self.sft) + ", " + str(self.length) + ", " + data + ')' + def to_c(self, static=True): + data = "" + for flag in self.flagList: + data += flag + " | " + data = data[:-3] + header = "gsSPSetOtherMode(" if static else "gSPSetOtherMode(glistp++, " + return header + str(self.cmd) + ", " + str(self.sft) + ", " + str(self.length) + ", " + data + ")" + + def to_sm64_decomp_s(self): + data = "" + for flag in self.flagList: + data += flag + " | " + data = data[:-3] + return "gsSPSetOtherMode " + str(self.cmd) + ", " + str(self.sft) + ", " + str(self.length) + ", " + data + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - data = '' - for flag in self.flagList: - data += flag + ' | ' - data = data[:-3] - return 'gsSPSetOtherMode ' + str(self.cmd) + ", " + str(self.sft) + ", " + str(self.length) + ", " + data - - def size(self, f3d): - return GFX_SIZE class DPPipelineMode: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_PM_1PRIMITIVE': modeVal = f3d.G_PM_1PRIMITIVE - elif self.mode == 'G_PM_NPRIMITIVE': modeVal = f3d.G_PM_NPRIMITIVE - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_PIPELINE, 1, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPPipelineMode(' if static else \ - 'gDPPipelineMode(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_PM_1PRIMITIVE": + modeVal = f3d.G_PM_1PRIMITIVE + elif self.mode == "G_PM_NPRIMITIVE": + modeVal = f3d.G_PM_NPRIMITIVE + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_PIPELINE, 1, modeVal, f3d) + def to_c(self, static=True): + header = "gsDPPipelineMode(" if static else "gDPPipelineMode(glistp++, " + return header + self.mode + ")" - def to_sm64_decomp_s(self): - return 'gsDPPipelineMode ' + self.mode + def to_sm64_decomp_s(self): + return "gsDPPipelineMode " + self.mode + + def size(self, f3d): + return GFX_SIZE - def size(self, f3d): - return GFX_SIZE class DPSetCycleType: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_CYC_1CYCLE': modeVal = f3d.G_CYC_1CYCLE - elif self.mode == 'G_CYC_2CYCLE': modeVal = f3d.G_CYC_2CYCLE - elif self.mode == 'G_CYC_COPY': modeVal = f3d.G_CYC_COPY - elif self.mode == 'G_CYC_FILL': modeVal = f3d.G_CYC_FILL - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_CYCLETYPE, 2, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetCycleType(' if static else \ - 'gDPSetCycleType(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_CYC_1CYCLE": + modeVal = f3d.G_CYC_1CYCLE + elif self.mode == "G_CYC_2CYCLE": + modeVal = f3d.G_CYC_2CYCLE + elif self.mode == "G_CYC_COPY": + modeVal = f3d.G_CYC_COPY + elif self.mode == "G_CYC_FILL": + modeVal = f3d.G_CYC_FILL + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_CYCLETYPE, 2, modeVal, f3d) + def to_c(self, static=True): + header = "gsDPSetCycleType(" if static else "gDPSetCycleType(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetCycleType " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetCycleType ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetTexturePersp: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_TP_NONE': modeVal = f3d.G_TP_NONE - elif self.mode == 'G_TP_PERSP': modeVal = f3d.G_TP_PERSP - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_TEXTPERSP, 1, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetTexturePersp(' if static else \ - 'gDPSetTexturePersp(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_TP_NONE": + modeVal = f3d.G_TP_NONE + elif self.mode == "G_TP_PERSP": + modeVal = f3d.G_TP_PERSP + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTPERSP, 1, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetTexturePersp(" if static else "gDPSetTexturePersp(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetTexturePersp " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTexturePersp ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetTextureDetail: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_TD_CLAMP': modeVal = f3d.G_TD_CLAMP - elif self.mode == 'G_TD_SHARPEN': modeVal = f3d.G_TD_SHARPEN - elif self.mode == 'G_TD_DETAIL': modeVal = f3d.G_TD_DETAIL - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_TEXTDETAIL, 2, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetTextureDetail(' if static else \ - 'gDPSetTextureDetail(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_TD_CLAMP": + modeVal = f3d.G_TD_CLAMP + elif self.mode == "G_TD_SHARPEN": + modeVal = f3d.G_TD_SHARPEN + elif self.mode == "G_TD_DETAIL": + modeVal = f3d.G_TD_DETAIL + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTDETAIL, 2, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetTextureDetail(" if static else "gDPSetTextureDetail(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetTextureDetail " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTextureDetail ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetTextureLOD: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_TL_TILE': modeVal = f3d.G_TL_TILE - elif self.mode == 'G_TL_LOD': modeVal = f3d.G_TL_LOD - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_TEXTLOD, 1, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetTextureLOD(' if static else \ - 'gDPSetTextureLOD(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_TL_TILE": + modeVal = f3d.G_TL_TILE + elif self.mode == "G_TL_LOD": + modeVal = f3d.G_TL_LOD + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTLOD, 1, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetTextureLOD(" if static else "gDPSetTextureLOD(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetTextureLOD " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTextureLOD ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetTextureLUT: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_TT_NONE': modeVal = f3d.G_TT_NONE - elif self.mode == 'G_TT_RGBA16': modeVal = f3d.G_TT_RGBA16 - elif self.mode == 'G_TT_IA16': modeVal = f3d.G_TT_IA16 - else: print("Invalid LUT mode " + str(self.mode)) - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_TEXTLUT, 2, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetTextureLUT(' if static else \ - 'gDPSetTextureLUT(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_TT_NONE": + modeVal = f3d.G_TT_NONE + elif self.mode == "G_TT_RGBA16": + modeVal = f3d.G_TT_RGBA16 + elif self.mode == "G_TT_IA16": + modeVal = f3d.G_TT_IA16 + else: + print("Invalid LUT mode " + str(self.mode)) + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTLUT, 2, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetTextureLUT(" if static else "gDPSetTextureLUT(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetTextureLUT " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTextureLUT ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetTextureFilter: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_TF_POINT': modeVal = f3d.G_TF_POINT - elif self.mode == 'G_TF_AVERAGE': modeVal = f3d.G_TF_AVERAGE - elif self.mode == 'G_TF_BILERP': modeVal = f3d.G_TF_BILERP - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_TEXTFILT, 2, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetTextureFilter(' if static else \ - 'gDPSetTextureFilter(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_TF_POINT": + modeVal = f3d.G_TF_POINT + elif self.mode == "G_TF_AVERAGE": + modeVal = f3d.G_TF_AVERAGE + elif self.mode == "G_TF_BILERP": + modeVal = f3d.G_TF_BILERP + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTFILT, 2, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetTextureFilter(" if static else "gDPSetTextureFilter(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetTextureFilter " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTextureFilter ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetTextureConvert: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_TC_CONV': modeVal = f3d.G_TC_CONV - elif self.mode == 'G_TC_FILTCONV': modeVal = f3d.G_TC_FILTCONV - elif self.mode == 'G_TC_FILT': modeVal = f3d.G_TC_FILT - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_TEXTCONV, 3, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetTextureConvert(' if static else \ - 'gDPSetTextureConvert(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_TC_CONV": + modeVal = f3d.G_TC_CONV + elif self.mode == "G_TC_FILTCONV": + modeVal = f3d.G_TC_FILTCONV + elif self.mode == "G_TC_FILT": + modeVal = f3d.G_TC_FILT + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_TEXTCONV, 3, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetTextureConvert(" if static else "gDPSetTextureConvert(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetTextureConvert " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTextureConvert ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetCombineKey: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if self.mode == 'G_CK_NONE': modeVal = f3d.G_CK_NONE - elif self.mode == 'G_CK_KEY': modeVal = f3d.G_CK_KEY - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_COMBKEY, 1, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetCombineKey(' if static else \ - 'gDPSetCombineKey(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if self.mode == "G_CK_NONE": + modeVal = f3d.G_CK_NONE + elif self.mode == "G_CK_KEY": + modeVal = f3d.G_CK_KEY + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_COMBKEY, 1, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetCombineKey(" if static else "gDPSetCombineKey(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetCombineKey " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetCombineKey ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetColorDither: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if not f3d._HW_VERSION_1: - if self.mode == 'G_CD_MAGICSQ': modeVal = f3d.G_CD_MAGICSQ - elif self.mode == 'G_CD_BAYER': modeVal = f3d.G_CD_BAYER - elif self.mode == 'G_CD_NOISE': modeVal = f3d.G_CD_NOISE - elif self.mode == 'G_CD_DISABLE': modeVal = f3d.G_CD_DISABLE - elif self.mode == 'G_CD_ENABLE': modeVal = f3d.G_CD_ENABLE - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_RGBDITHER, 2, modeVal, f3d) - else: - if self.mode == 'G_CD_ENABLE': modeVal = f3d.G_CD_ENABLE - elif self.mode == 'G_CD_DISABLE': modeVal = f3d.G_CD_DISABLE - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_COLORDITHER, 1, modeVal, f3d) + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetColorDither(' if static else \ - 'gDPSetColorDither(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if not f3d._HW_VERSION_1: + if self.mode == "G_CD_MAGICSQ": + modeVal = f3d.G_CD_MAGICSQ + elif self.mode == "G_CD_BAYER": + modeVal = f3d.G_CD_BAYER + elif self.mode == "G_CD_NOISE": + modeVal = f3d.G_CD_NOISE + elif self.mode == "G_CD_DISABLE": + modeVal = f3d.G_CD_DISABLE + elif self.mode == "G_CD_ENABLE": + modeVal = f3d.G_CD_ENABLE + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_RGBDITHER, 2, modeVal, f3d) + else: + if self.mode == "G_CD_ENABLE": + modeVal = f3d.G_CD_ENABLE + elif self.mode == "G_CD_DISABLE": + modeVal = f3d.G_CD_DISABLE + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_COLORDITHER, 1, modeVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetColorDither(" if static else "gDPSetColorDither(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetColorDither " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetColorDither ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetAlphaDither: - # mode is a string - def __init__(self, mode): - self.mode = mode - - def to_binary(self, f3d, segments): - if not f3d._HW_VERSION_1: - if self.mode == 'G_AD_PATTERN': modeVal = f3d.G_AD_PATTERN - elif self.mode == 'G_AD_NOTPATTERN': modeVal = f3d.G_AD_NOTPATTERN - elif self.mode == 'G_AD_NOISE': modeVal = f3d.G_AD_NOISE - elif self.mode == 'G_AD_DISABLE': modeVal = f3d.G_AD_DISABLE - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, - f3d.G_MDSFT_ALPHADITHER, 2, modeVal, f3d) - else: - raise PluginError("SetAlphaDither not available in HW v1.") + # mode is a string + def __init__(self, mode): + self.mode = mode - def to_c(self, static = True): - header = 'gsDPSetAlphaDither(' if static else \ - 'gDPSetAlphaDither(glistp++, ' - return header + self.mode + ')' + def to_binary(self, f3d, segments): + if not f3d._HW_VERSION_1: + if self.mode == "G_AD_PATTERN": + modeVal = f3d.G_AD_PATTERN + elif self.mode == "G_AD_NOTPATTERN": + modeVal = f3d.G_AD_NOTPATTERN + elif self.mode == "G_AD_NOISE": + modeVal = f3d.G_AD_NOISE + elif self.mode == "G_AD_DISABLE": + modeVal = f3d.G_AD_DISABLE + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_H, f3d.G_MDSFT_ALPHADITHER, 2, modeVal, f3d) + else: + raise PluginError("SetAlphaDither not available in HW v1.") + + def to_c(self, static=True): + header = "gsDPSetAlphaDither(" if static else "gDPSetAlphaDither(glistp++, " + return header + self.mode + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetAlphaDither " + self.mode + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetAlphaDither ' + self.mode - - def size(self, f3d): - return GFX_SIZE class DPSetAlphaCompare: - # mask is a string - def __init__(self, mask): - self.mask = mask - - def to_binary(self, f3d, segments): - if self.mask == 'G_AC_NONE': maskVal = f3d.G_AC_NONE - elif self.mask == 'G_AC_THRESHOLD': maskVal = f3d.G_AC_THRESHOLD - elif self.mask == 'G_AC_DITHER': maskVal = f3d.G_AC_DITHER - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, - f3d.G_MDSFT_ALPHACOMPARE, 2, maskVal, f3d) + # mask is a string + def __init__(self, mask): + self.mask = mask - def to_c(self, static = True): - header = 'gsDPSetAlphaCompare(' if static else \ - 'gDPSetAlphaCompare(glistp++, ' - return header + self.mask + ')' + def to_binary(self, f3d, segments): + if self.mask == "G_AC_NONE": + maskVal = f3d.G_AC_NONE + elif self.mask == "G_AC_THRESHOLD": + maskVal = f3d.G_AC_THRESHOLD + elif self.mask == "G_AC_DITHER": + maskVal = f3d.G_AC_DITHER + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_ALPHACOMPARE, 2, maskVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetAlphaCompare(" if static else "gDPSetAlphaCompare(glistp++, " + return header + self.mask + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetAlphaCompare " + self.mask + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetAlphaCompare ' + self.mask - - def size(self, f3d): - return GFX_SIZE class DPSetDepthSource: - # src is a string - def __init__(self, src): - self.src = src - - def to_binary(self, f3d, segments): - if self.src == 'G_ZS_PIXEL': srcVal = f3d.G_ZS_PIXEL - elif self.src == 'G_ZS_PRIM': srcVal = f3d.G_ZS_PRIM - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, - f3d.G_MDSFT_ZSRCSEL, 1, srcVal, f3d) + # src is a string + def __init__(self, src): + self.src = src - def to_c(self, static = True): - header = 'gsDPSetDepthSource(' if static else \ - 'gDPSetDepthSource(glistp++, ' - return header + self.src + ')' + def to_binary(self, f3d, segments): + if self.src == "G_ZS_PIXEL": + srcVal = f3d.G_ZS_PIXEL + elif self.src == "G_ZS_PRIM": + srcVal = f3d.G_ZS_PRIM + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_ZSRCSEL, 1, srcVal, f3d) + + def to_c(self, static=True): + header = "gsDPSetDepthSource(" if static else "gDPSetDepthSource(glistp++, " + return header + self.src + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetDepthSource " + self.src + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetDepthSource ' + self.src - - def size(self, f3d): - return GFX_SIZE def renderFlagListToWord(flagList, f3d): - word = 0 - for name in flagList: - word += getattr(f3d, name) - - return word + word = 0 + for name in flagList: + word += getattr(f3d, name) + + return word + + +def GBL_c1(m1a, m1b, m2a, m2b): + return (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 + + +def GBL_c2(m1a, m1b, m2a, m2b): + return (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 -def GBL_c1(m1a, m1b, m2a, m2b): - return (m1a) << 30 | (m1b) << 26 | (m2a) << 22 | (m2b) << 18 -def GBL_c2(m1a, m1b, m2a, m2b): - return (m1a) << 28 | (m1b) << 24 | (m2a) << 20 | (m2b) << 16 class DPSetRenderMode: - # bl0-3 are string for each blender enum - def __init__(self, flagList, blendList): - self.flagList = flagList - self.use_preset = blendList is None - if not self.use_preset: - self.bl00 = blendList[0] - self.bl01 = blendList[1] - self.bl02 = blendList[2] - self.bl03 = blendList[3] - self.bl10 = blendList[4] - self.bl11 = blendList[5] - self.bl12 = blendList[6] - self.bl13 = blendList[7] - - def getGBL_c(self, f3d): - bl00 = getattr(f3d, self.bl00) - bl01 = getattr(f3d, self.bl01) - bl02 = getattr(f3d, self.bl02) - bl03 = getattr(f3d, self.bl03) - bl10 = getattr(f3d, self.bl10) - bl11 = getattr(f3d, self.bl11) - bl12 = getattr(f3d, self.bl12) - bl13 = getattr(f3d, self.bl13) - return GBL_c1(bl00, bl01, bl02, bl03) | \ - GBL_c2(bl10, bl11, bl12, bl13) - - def to_binary(self, f3d, segments): - flagWord = renderFlagListToWord(self.flagList, f3d) + # bl0-3 are string for each blender enum + def __init__(self, flagList, blendList): + self.flagList = flagList + self.use_preset = blendList is None + if not self.use_preset: + self.bl00 = blendList[0] + self.bl01 = blendList[1] + self.bl02 = blendList[2] + self.bl03 = blendList[3] + self.bl10 = blendList[4] + self.bl11 = blendList[5] + self.bl12 = blendList[6] + self.bl13 = blendList[7] - if not self.use_preset: - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, - f3d.G_MDSFT_RENDERMODE, 29, flagWord | self.getGBL_c(f3d), f3d) - else: - return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, - f3d.G_MDSFT_RENDERMODE, 29, flagWord, f3d) + def getGBL_c(self, f3d): + bl00 = getattr(f3d, self.bl00) + bl01 = getattr(f3d, self.bl01) + bl02 = getattr(f3d, self.bl02) + bl03 = getattr(f3d, self.bl03) + bl10 = getattr(f3d, self.bl10) + bl11 = getattr(f3d, self.bl11) + bl12 = getattr(f3d, self.bl12) + bl13 = getattr(f3d, self.bl13) + return GBL_c1(bl00, bl01, bl02, bl03) | GBL_c2(bl10, bl11, bl12, bl13) - def to_c(self, static = True): - data = 'gsDPSetRenderMode(' if static else \ - 'gDPSetRenderMode(glistp++, ' + def to_binary(self, f3d, segments): + flagWord = renderFlagListToWord(self.flagList, f3d) - if not self.use_preset: - data += 'GBL_c1(' + self.bl00 + ', ' + self.bl01 + ', ' + \ - self.bl02 + ', ' + self.bl03 + ') | GBL_c2(' + self.bl10 + \ - ', ' + self.bl11 + ', ' + self.bl12 + ', ' + self.bl13 + '), ' - for name in self.flagList: - data += name + ' | ' - return data[:-3] + ')' - else: - if len(self.flagList) != 2: - raise PluginError("For a rendermode preset, only two fields should be used.") - data += self.flagList[0] + ', ' + self.flagList[1] + ')' - return data + if not self.use_preset: + return gsSPSetOtherMode( + f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_RENDERMODE, 29, flagWord | self.getGBL_c(f3d), f3d + ) + else: + return gsSPSetOtherMode(f3d.G_SETOTHERMODE_L, f3d.G_MDSFT_RENDERMODE, 29, flagWord, f3d) - def to_sm64_decomp_s(self): - raise PluginError("Cannot use DPSetRenderMode with gbi.inc.") - flagWord = renderFlagListToWord(self.flagList, f3d) - data = 'gsDPSetRenderMode ' - data += '0x' + format(flagWord, 'X') + ', ' - data += '0x' + format(self.getGBL_c(f3d), 'X') - return data + def to_c(self, static=True): + data = "gsDPSetRenderMode(" if static else "gDPSetRenderMode(glistp++, " - ''' + if not self.use_preset: + data += ( + "GBL_c1(" + + self.bl00 + + ", " + + self.bl01 + + ", " + + self.bl02 + + ", " + + self.bl03 + + ") | GBL_c2(" + + self.bl10 + + ", " + + self.bl11 + + ", " + + self.bl12 + + ", " + + self.bl13 + + "), " + ) + for name in self.flagList: + data += name + " | " + return data[:-3] + ")" + else: + if len(self.flagList) != 2: + raise PluginError("For a rendermode preset, only two fields should be used.") + data += self.flagList[0] + ", " + self.flagList[1] + ")" + return data + + def to_sm64_decomp_s(self): + raise PluginError("Cannot use DPSetRenderMode with gbi.inc.") + flagWord = renderFlagListToWord(self.flagList, f3d) + data = "gsDPSetRenderMode " + data += "0x" + format(flagWord, "X") + ", " + data += "0x" + format(self.getGBL_c(f3d), "X") + return data + + """ # G_SETOTHERMODE_L gSetRenderMode self.AA_EN = AA_EN = 0x8 self.Z_CMP = Z_CMP = 0x10 @@ -4342,1299 +5011,2084 @@ class DPSetRenderMode: self.G_BL_A_SHADE = G_BL_A_SHADE = 2 self.G_BL_1 = G_BL_1 = 2 self.G_BL_0 = G_BL_0 = 3 - ''' - - def size(self, f3d): - return GFX_SIZE + """ + + def size(self, f3d): + return GFX_SIZE + def gsSetImage(cmd, fmt, siz, width, i): - words = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | \ - _SHIFTL(siz, 19, 2) | _SHIFTL((width)-1, 0, 12), i - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(cmd, 24, 8) | _SHIFTL(fmt, 21, 3) | _SHIFTL(siz, 19, 2) | _SHIFTL((width) - 1, 0, 12), i + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") -# DPSetColorImage + +# DPSetColorImage # DPSetDepthImage + class DPSetTextureImage: - def __init__(self, fmt, siz, width, img): - self.fmt = fmt # string - self.siz = siz # string - self.width = width - self.image = img - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - fmt = f3d.G_IM_FMT_VARS[self.fmt] - siz = f3d.G_IM_SIZ_VARS[self.siz] - imagePtr = int.from_bytes(encodeSegmentedAddr( - self.image.startAddress, segments), 'big') - return gsSetImage(f3d.G_SETTIMG, fmt, siz, self.width, imagePtr) + def __init__(self, fmt, siz, width, img): + self.fmt = fmt # string + self.siz = siz # string + self.width = width + self.image = img - def to_c(self, static = True): - header = 'gsDPSetTextureImage(' if static else \ - 'gDPSetTextureImage(glistp++, ' - header += self.fmt + ', ' + self.siz + ', ' + \ - str(self.width) + ', ' - if not static and bpy.context.scene.decomp_compatible: - header += 'segmented_to_virtual(' + self.image.name + '))' - else: - header += self.image.name + ')' - return header + def get_ptr_offsets(self, f3d): + return [4] - def to_sm64_decomp_s(self): - return 'gsDPSetTextureImage ' + self.fmt + ', ' + self.siz + \ - ', ' + str(self.width) + ', ' + self.image.name - - def size(self, f3d): - return GFX_SIZE + def to_binary(self, f3d, segments): + fmt = f3d.G_IM_FMT_VARS[self.fmt] + siz = f3d.G_IM_SIZ_VARS[self.siz] + imagePtr = int.from_bytes(encodeSegmentedAddr(self.image.startAddress, segments), "big") + return gsSetImage(f3d.G_SETTIMG, fmt, siz, self.width, imagePtr) -def gsDPSetCombine(muxs0, muxs1, f3d): - words = _SHIFTL(f3d.G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), muxs1 - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def to_c(self, static=True): + header = "gsDPSetTextureImage(" if static else "gDPSetTextureImage(glistp++, " + header += self.fmt + ", " + self.siz + ", " + str(self.width) + ", " + if not static and bpy.context.scene.decomp_compatible: + header += "segmented_to_virtual(" + self.image.name + "))" + else: + header += self.image.name + ")" + return header -def GCCc0w0(saRGB0, mRGB0, saA0, mA0): - return (_SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | \ - _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3)) + def to_sm64_decomp_s(self): + return "gsDPSetTextureImage " + self.fmt + ", " + self.siz + ", " + str(self.width) + ", " + self.image.name + + def size(self, f3d): + return GFX_SIZE + + +def gsDPSetCombine(muxs0, muxs1, f3d): + words = _SHIFTL(f3d.G_SETCOMBINE, 24, 8) | _SHIFTL(muxs0, 0, 24), muxs1 + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +def GCCc0w0(saRGB0, mRGB0, saA0, mA0): + return _SHIFTL((saRGB0), 20, 4) | _SHIFTL((mRGB0), 15, 5) | _SHIFTL((saA0), 12, 3) | _SHIFTL((mA0), 9, 3) + + +def GCCc1w0(saRGB1, mRGB1): + return _SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5) -def GCCc1w0(saRGB1, mRGB1): - return (_SHIFTL((saRGB1), 5, 4) | _SHIFTL((mRGB1), 0, 5)) def GCCc0w1(sbRGB0, aRGB0, sbA0, aA0): - return (_SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) |\ - _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3)) + return _SHIFTL((sbRGB0), 28, 4) | _SHIFTL((aRGB0), 15, 3) | _SHIFTL((sbA0), 12, 3) | _SHIFTL((aA0), 9, 3) + + +def GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1): + return ( + _SHIFTL((sbRGB1), 24, 4) + | _SHIFTL((saA1), 21, 3) + | _SHIFTL((mA1), 18, 3) + | _SHIFTL((aRGB1), 6, 3) + | _SHIFTL((sbA1), 3, 3) + | _SHIFTL((aA1), 0, 3) + ) -def GCCc1w1(sbRGB1, saA1, mA1, aRGB1, sbA1, aA1): - return (_SHIFTL((sbRGB1), 24, 4) | _SHIFTL((saA1), 21, 3) | \ - _SHIFTL((mA1), 18, 3) | _SHIFTL((aRGB1), 6, 3) | \ - _SHIFTL((sbA1), 3, 3) | _SHIFTL((aA1), 0, 3)) class DPSetCombineMode: - # all strings - def __init__(self, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, - a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1): - self.a0 = a0 - self.b0 = b0 - self.c0 = c0 - self.d0 = d0 - self.Aa0 = Aa0 - self.Ab0 = Ab0 - self.Ac0 = Ac0 - self.Ad0 = Ad0 - - self.a1 = a1 - self.b1 = b1 - self.c1 = c1 - self.d1 = d1 - self.Aa1 = Aa1 - self.Ab1 = Ab1 - self.Ac1 = Ac1 - self.Ad1 = Ad1 + # all strings + def __init__(self, a0, b0, c0, d0, Aa0, Ab0, Ac0, Ad0, a1, b1, c1, d1, Aa1, Ab1, Ac1, Ad1): + self.a0 = a0 + self.b0 = b0 + self.c0 = c0 + self.d0 = d0 + self.Aa0 = Aa0 + self.Ab0 = Ab0 + self.Ac0 = Ac0 + self.Ad0 = Ad0 - def to_binary(self, f3d, segments): - words = _SHIFTL(f3d.G_SETCOMBINE, 24, 8) | \ - _SHIFTL( - GCCc0w0( - f3d.CCMUXDict[self.a0], f3d.CCMUXDict[self.c0], \ - f3d.ACMUXDict[self.Aa0], f3d.ACMUXDict[self.Ac0]) | \ - GCCc1w0( - f3d.CCMUXDict[self.a1], f3d.CCMUXDict[self.c1]), \ - 0, 24),\ - GCCc0w1( - f3d.CCMUXDict[self.b0], f3d.CCMUXDict[self.d0], \ - f3d.ACMUXDict[self.Ab0], f3d.ACMUXDict[self.Ad0]) | \ - GCCc1w1( - f3d.CCMUXDict[self.b1], f3d.ACMUXDict[self.Aa1], \ - f3d.ACMUXDict[self.Ac1], f3d.CCMUXDict[self.d1], \ - f3d.ACMUXDict[self.Ab1], f3d.ACMUXDict[self.Ad1]) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + self.a1 = a1 + self.b1 = b1 + self.c1 = c1 + self.d1 = d1 + self.Aa1 = Aa1 + self.Ab1 = Ab1 + self.Ac1 = Ac1 + self.Ad1 = Ad1 - def to_c(self, static = True): - a0 = self.a0 # 'G_CCMUX_' + self.a0 - b0 = self.b0 # 'G_CCMUX_' + self.b0 - c0 = self.c0 # 'G_CCMUX_' + self.c0 - d0 = self.d0 # 'G_CCMUX_' + self.d0 + def to_binary(self, f3d, segments): + words = _SHIFTL(f3d.G_SETCOMBINE, 24, 8) | _SHIFTL( + GCCc0w0(f3d.CCMUXDict[self.a0], f3d.CCMUXDict[self.c0], f3d.ACMUXDict[self.Aa0], f3d.ACMUXDict[self.Ac0]) + | GCCc1w0(f3d.CCMUXDict[self.a1], f3d.CCMUXDict[self.c1]), + 0, + 24, + ), GCCc0w1( + f3d.CCMUXDict[self.b0], f3d.CCMUXDict[self.d0], f3d.ACMUXDict[self.Ab0], f3d.ACMUXDict[self.Ad0] + ) | GCCc1w1( + f3d.CCMUXDict[self.b1], + f3d.ACMUXDict[self.Aa1], + f3d.ACMUXDict[self.Ac1], + f3d.CCMUXDict[self.d1], + f3d.ACMUXDict[self.Ab1], + f3d.ACMUXDict[self.Ad1], + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") - Aa0 = self.Aa0 # 'G_ACMUX_' + self.Aa0 - Ab0 = self.Ab0 # 'G_ACMUX_' + self.Ab0 - Ac0 = self.Ac0 # 'G_ACMUX_' + self.Ac0 - Ad0 = self.Ad0 # 'G_ACMUX_' + self.Ad0 + def to_c(self, static=True): + a0 = self.a0 # 'G_CCMUX_' + self.a0 + b0 = self.b0 # 'G_CCMUX_' + self.b0 + c0 = self.c0 # 'G_CCMUX_' + self.c0 + d0 = self.d0 # 'G_CCMUX_' + self.d0 - a1 = self.a1 # 'G_CCMUX_' + self.a1 - b1 = self.b1 # 'G_CCMUX_' + self.b1 - c1 = self.c1 # 'G_CCMUX_' + self.c1 - d1 = self.d1 # 'G_CCMUX_' + self.d1 + Aa0 = self.Aa0 # 'G_ACMUX_' + self.Aa0 + Ab0 = self.Ab0 # 'G_ACMUX_' + self.Ab0 + Ac0 = self.Ac0 # 'G_ACMUX_' + self.Ac0 + Ad0 = self.Ad0 # 'G_ACMUX_' + self.Ad0 - Aa1 = self.Aa1 # 'G_ACMUX_' + self.Aa1 - Ab1 = self.Ab1 # 'G_ACMUX_' + self.Ab1 - Ac1 = self.Ac1 # 'G_ACMUX_' + self.Ac1 - Ad1 = self.Ad1 # 'G_ACMUX_' + self.Ad1 + a1 = self.a1 # 'G_CCMUX_' + self.a1 + b1 = self.b1 # 'G_CCMUX_' + self.b1 + c1 = self.c1 # 'G_CCMUX_' + self.c1 + d1 = self.d1 # 'G_CCMUX_' + self.d1 - # No tabs/line breaks, breaks macros - header = 'gsDPSetCombineLERP(' if static else \ - 'gDPSetCombineLERP(glistp++, ' - return header + a0 + ', ' + b0 + ', ' + c0 + ', ' + \ - d0 + ', ' + Aa0 + ', ' + Ab0 + ', ' + \ - Ac0 + ', ' + Ad0 + ', ' + a1 + ', ' + \ - b1 + ', ' + c1 + ', ' + d1 + ', ' + Aa1 + \ - ', ' + Ab1 + ', ' + Ac1 + ', ' + Ad1 + ')' + Aa1 = self.Aa1 # 'G_ACMUX_' + self.Aa1 + Ab1 = self.Ab1 # 'G_ACMUX_' + self.Ab1 + Ac1 = self.Ac1 # 'G_ACMUX_' + self.Ac1 + Ad1 = self.Ad1 # 'G_ACMUX_' + self.Ad1 + + # No tabs/line breaks, breaks macros + header = "gsDPSetCombineLERP(" if static else "gDPSetCombineLERP(glistp++, " + return ( + header + + a0 + + ", " + + b0 + + ", " + + c0 + + ", " + + d0 + + ", " + + Aa0 + + ", " + + Ab0 + + ", " + + Ac0 + + ", " + + Ad0 + + ", " + + a1 + + ", " + + b1 + + ", " + + c1 + + ", " + + d1 + + ", " + + Aa1 + + ", " + + Ab1 + + ", " + + Ac1 + + ", " + + Ad1 + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetCombineLERP " + + self.a0 + + ", " + + self.b0 + + ", " + + self.c0 + + ", " + + self.d0 + + ", " + + self.Aa0 + + ", " + + self.Ab0 + + ", " + + self.Ac0 + + ", " + + self.Ad0 + + ", " + + self.a1 + + ", " + + self.b1 + + ", " + + self.c1 + + ", " + + self.d1 + + ", " + + self.Aa1 + + ", " + + self.Ab1 + + ", " + + self.Ac1 + + ", " + + self.Ad1 + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetCombineLERP ' + self.a0 + ', ' + self.b0 + ', ' +\ - self.c0 + ', ' + self.d0 + ', ' + self.Aa0 + ', ' + \ - self.Ab0 + ', ' + self.Ac0 + ', ' + self.Ad0 + ', ' + \ - self.a1 + ', ' + self.b1 + ', ' + self.c1 + ', ' + self.d1 + \ - ', ' + self.Aa1 + ', ' + self.Ab1 + ', ' + self.Ac1 + \ - ', ' + self.Ad1 - - def size(self, f3d): - return GFX_SIZE def gsDPSetColor(c, d): - words = _SHIFTL(c, 24, 8), d - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(c, 24, 8), d + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + +def sDPRGBColor(cmd, r, g, b, a): + return gsDPSetColor(cmd, (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8))) -def sDPRGBColor(cmd, r, g, b, a): - return gsDPSetColor(cmd, \ - (_SHIFTL(r, 24, 8) | _SHIFTL(g, 16, 8) | \ - _SHIFTL(b, 8, 8) | _SHIFTL(a, 0, 8))) class DPSetEnvColor: - def __init__(self, r, g, b, a): - self.r = r - self.g = g - self.b = b - self.a = a - - def to_binary(self, f3d, segments): - return sDPRGBColor(f3d.G_SETENVCOLOR, self.r, self.g, self.b, self.a) + def __init__(self, r, g, b, a): + self.r = r + self.g = g + self.b = b + self.a = a - def to_c(self, static = True): - header = 'gsDPSetEnvColor(' if static else 'gDPSetEnvColor(glistp++, ' - return header + str(self.r) + ', ' + str(self.g) + ', ' + \ - str(self.b) + ', ' + str(self.a) + ')' + def to_binary(self, f3d, segments): + return sDPRGBColor(f3d.G_SETENVCOLOR, self.r, self.g, self.b, self.a) + + def to_c(self, static=True): + header = "gsDPSetEnvColor(" if static else "gDPSetEnvColor(glistp++, " + return header + str(self.r) + ", " + str(self.g) + ", " + str(self.b) + ", " + str(self.a) + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetEnvColor " + str(self.r) + ", " + str(self.g) + ", " + str(self.b) + ", " + str(self.a) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetEnvColor ' + str(self.r) + ', ' + str(self.g) + \ - ', ' + str(self.b) + ', ' + str(self.a) - - def size(self, f3d): - return GFX_SIZE class DPSetBlendColor: - def __init__(self, r, g, b, a): - self.r = r - self.g = g - self.b = b - self.a = a - - def to_binary(self, f3d, segments): - return sDPRGBColor(f3d.G_SETBLENDCOLOR, self.r, self.g, self.b, self.a) + def __init__(self, r, g, b, a): + self.r = r + self.g = g + self.b = b + self.a = a - def to_c(self, static = True): - header = 'gsDPSetBlendColor(' if static else \ - 'gDPSetBlendColor(glistp++, ' - return header + str(self.r) + ', ' + str(self.g) + ', ' + \ - str(self.b) + ', ' + str(self.a) + ')' + def to_binary(self, f3d, segments): + return sDPRGBColor(f3d.G_SETBLENDCOLOR, self.r, self.g, self.b, self.a) + + def to_c(self, static=True): + header = "gsDPSetBlendColor(" if static else "gDPSetBlendColor(glistp++, " + return header + str(self.r) + ", " + str(self.g) + ", " + str(self.b) + ", " + str(self.a) + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetBlendColor " + str(self.r) + ", " + str(self.g) + ", " + str(self.b) + ", " + str(self.a) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetBlendColor ' + str(self.r) + ', ' + str(self.g) + \ - ', ' + str(self.b) + ', ' + str(self.a) - - def size(self, f3d): - return GFX_SIZE class DPSetFogColor: - def __init__(self, r, g, b, a): - self.r = r - self.g = g - self.b = b - self.a = a - - def to_binary(self, f3d, segments): - return sDPRGBColor(f3d.G_SETFOGCOLOR, self.r, self.g, self.b, self.a) + def __init__(self, r, g, b, a): + self.r = r + self.g = g + self.b = b + self.a = a - def to_c(self, static = True): - header = 'gsDPSetFogColor(' if static else \ - 'gDPSetFogColor(glistp++, ' - return header + str(self.r) + ', ' + str(self.g) + ', ' + \ - str(self.b) + ', ' + str(self.a) + ')' + def to_binary(self, f3d, segments): + return sDPRGBColor(f3d.G_SETFOGCOLOR, self.r, self.g, self.b, self.a) + + def to_c(self, static=True): + header = "gsDPSetFogColor(" if static else "gDPSetFogColor(glistp++, " + return header + str(self.r) + ", " + str(self.g) + ", " + str(self.b) + ", " + str(self.a) + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetFogColor " + str(self.r) + ", " + str(self.g) + ", " + str(self.b) + ", " + str(self.a) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetFogColor ' + str(self.r) + ', ' + str(self.g) + \ - ', ' + str(self.b) + ', ' + str(self.a) - - def size(self, f3d): - return GFX_SIZE class DPSetFillColor: - def __init__(self, d): - self.d = d - - def to_binary(self, f3d, segments): - return gsDPSetColor(f3d.G_SETFILLCOLOR, self.d) + def __init__(self, d): + self.d = d - def to_c(self, static = True): - header = 'gsDPSetFillColor(' if static else \ - 'gDPSetFillColor(glistp++, ' - return header + str(self.d) + ')' + def to_binary(self, f3d, segments): + return gsDPSetColor(f3d.G_SETFILLCOLOR, self.d) + + def to_c(self, static=True): + header = "gsDPSetFillColor(" if static else "gDPSetFillColor(glistp++, " + return header + str(self.d) + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetFillColor " + str(self.d) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetFillColor ' + str(self.d) - - def size(self, f3d): - return GFX_SIZE class DPSetPrimDepth: - def __init__(self, z=0, dz=0): - self.z = z - self.dz = dz - - def to_binary(self, f3d, segments): - return gsDPSetColor(f3d.G_SETPRIMDEPTH, _SHIFTL(self.z, 16, 16) | \ - _SHIFTL(self.dz, 0, 16)) + def __init__(self, z=0, dz=0): + self.z = z + self.dz = dz - def to_c(self, static = True): - header = 'gsDPSetPrimDepth(' if static else \ - 'gDPSetPrimDepth(glistp++, ' - return header + str(self.z) + ', ' + str(self.dz) + ')' + def to_binary(self, f3d, segments): + return gsDPSetColor(f3d.G_SETPRIMDEPTH, _SHIFTL(self.z, 16, 16) | _SHIFTL(self.dz, 0, 16)) + + def to_c(self, static=True): + header = "gsDPSetPrimDepth(" if static else "gDPSetPrimDepth(glistp++, " + return header + str(self.z) + ", " + str(self.dz) + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetPrimDepth " + str(self.z) + ", " + str(self.dz) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetPrimDepth ' + str(self.z) + ', ' + str(self.dz) - - def size(self, f3d): - return GFX_SIZE class DPSetPrimColor: - def __init__(self, m, l, r, g, b, a): - self.m = m - self.l = l - self.r = r - self.g = g - self.b = b - self.a = a - - def to_binary(self, f3d, segments): - words = (_SHIFTL(f3d.G_SETPRIMCOLOR, 24, 8) | _SHIFTL(self.m, 8, 8) | \ - _SHIFTL(self.l, 0, 8)), (_SHIFTL(self.r, 24, 8) | \ - _SHIFTL(self.g, 16, 8) | _SHIFTL(self.b, 8, 8) | \ - _SHIFTL(self.a, 0, 8)) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, m, l, r, g, b, a): + self.m = m + self.l = l + self.r = r + self.g = g + self.b = b + self.a = a - def to_c(self, static = True): - header = 'gsDPSetPrimColor(' if static else \ - 'gDPSetPrimColor(glistp++, ' - return header + str(self.m) + ', ' + str(self.l) + ', ' + \ - str(self.r) + ', ' + str(self.g) + ', ' + \ - str(self.b) + ', ' + str(self.a) + ')' + def to_binary(self, f3d, segments): + words = (_SHIFTL(f3d.G_SETPRIMCOLOR, 24, 8) | _SHIFTL(self.m, 8, 8) | _SHIFTL(self.l, 0, 8)), ( + _SHIFTL(self.r, 24, 8) | _SHIFTL(self.g, 16, 8) | _SHIFTL(self.b, 8, 8) | _SHIFTL(self.a, 0, 8) + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsDPSetPrimColor(" if static else "gDPSetPrimColor(glistp++, " + return ( + header + + str(self.m) + + ", " + + str(self.l) + + ", " + + str(self.r) + + ", " + + str(self.g) + + ", " + + str(self.b) + + ", " + + str(self.a) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetPrimColor " + + str(self.m) + + ", " + + str(self.l) + + ", " + + str(self.r) + + ", " + + str(self.g) + + ", " + + str(self.b) + + ", " + + str(self.a) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetPrimColor ' + str(self.m) + ', ' + str(self.l) + \ - ', ' + str(self.r) + ', ' + str(self.g) + \ - ', ' + str(self.b) + ', ' + str(self.a) - - def size(self, f3d): - return GFX_SIZE class DPSetOtherMode: - def __init__(self, mode0, mode1): - self.mode0 = mode0 - self.mode1 = mode1 - - def to_binary(self, f3d, segments): - words = _SHIFTL(f3d.G_RDPSETOTHERMODE,24,8) | \ - _SHIFTL(self.mode0,0,24), self.mode1 - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, mode0, mode1): + self.mode0 = mode0 + self.mode1 = mode1 - def to_c(self, static = True): - header = 'gsDPSetOtherMode(' if static else \ - 'gDPSetOtherMode(glistp++, ' + def to_binary(self, f3d, segments): + words = _SHIFTL(f3d.G_RDPSETOTHERMODE, 24, 8) | _SHIFTL(self.mode0, 0, 24), self.mode1 + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") - mode0String = '' - for item in self.mode0: - mode0String += item + ' | ' - mode0String = mode0String[:-3] + def to_c(self, static=True): + header = "gsDPSetOtherMode(" if static else "gDPSetOtherMode(glistp++, " - mode1String = '' - for item in self.mode1: - mode1String += item + ' | ' - mode1String = mode1String[:-3] + mode0String = "" + for item in self.mode0: + mode0String += item + " | " + mode0String = mode0String[:-3] - return header + mode0String + ', ' + mode1String + ')' + mode1String = "" + for item in self.mode1: + mode1String += item + " | " + mode1String = mode1String[:-3] + + return header + mode0String + ", " + mode1String + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetOtherMode " + str(self.mode0) + ", " + str(self.mode1) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetOtherMode ' + str(self.mode0) + ', ' + str(self.mode1) - - def size(self, f3d): - return GFX_SIZE def gsDPLoadTileGeneric(c, tile, uls, ult, lrs, lrt): - words = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12), \ - _SHIFTL(tile, 24, 3) | _SHIFTL(lrs, 12, 12) | _SHIFTL(lrt, 0, 12) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(c, 24, 8) | _SHIFTL(uls, 12, 12) | _SHIFTL(ult, 0, 12), _SHIFTL(tile, 24, 3) | _SHIFTL( + lrs, 12, 12 + ) | _SHIFTL(lrt, 0, 12) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + class DPSetTileSize: - def __init__(self, t, uls, ult, lrs, lrt): - self.t = t - self.uls = uls - self.ult = ult - self.lrs = lrs - self.lrt = lrt - - def to_binary(self, f3d, segments): - return gsDPLoadTileGeneric(f3d.G_SETTILESIZE, self.t, - self.uls, self.ult, self.lrs, self.lrt) + def __init__(self, t, uls, ult, lrs, lrt): + self.t = t + self.uls = uls + self.ult = ult + self.lrs = lrs + self.lrt = lrt - def to_c(self, static = True): - header = 'gsDPSetTileSize(' if static else 'gDPSetTileSize(glistp++, ' - return header + str(self.t) + ', ' + str(self.uls) + ', ' + \ - str(self.ult) + ', ' + str(self.lrs) + ', ' + str(self.lrt) + ')' + def to_binary(self, f3d, segments): + return gsDPLoadTileGeneric(f3d.G_SETTILESIZE, self.t, self.uls, self.ult, self.lrs, self.lrt) + + def to_c(self, static=True): + header = "gsDPSetTileSize(" if static else "gDPSetTileSize(glistp++, " + return ( + header + + str(self.t) + + ", " + + str(self.uls) + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetTileSize " + + str(self.t) + + ", " + + str(self.uls) + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTileSize ' + str(self.t) + ', ' + str(self.uls) + ', ' + \ - str(self.ult) + ', ' + str(self.lrs) + ', ' + str(self.lrt) - - def size(self, f3d): - return GFX_SIZE class DPLoadTile: - def __init__(self, t, uls, ult, lrs, lrt): - self.t = t - self.uls = uls - self.ult = ult - self.lrs = lrs - self.lrt = lrt - - def to_binary(self, f3d, segments): - return gsDPLoadTileGeneric(f3d.G_LOADTILE, self.t, - self.uls, self.ult, self.lrs, self.lrt) + def __init__(self, t, uls, ult, lrs, lrt): + self.t = t + self.uls = uls + self.ult = ult + self.lrs = lrs + self.lrt = lrt - def to_c(self, static = True): - header = 'gsDPLoadTile(' if static else 'gDPLoadTile(glistp++, ' - return header + str(self.t) + ', ' + str(self.uls) + ', ' + \ - str(self.ult) + ', ' + str(self.lrs) + ', ' + str(self.lrt) + ')' + def to_binary(self, f3d, segments): + return gsDPLoadTileGeneric(f3d.G_LOADTILE, self.t, self.uls, self.ult, self.lrs, self.lrt) + + def to_c(self, static=True): + header = "gsDPLoadTile(" if static else "gDPLoadTile(glistp++, " + return ( + header + + str(self.t) + + ", " + + str(self.uls) + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadTile " + + str(self.t) + + ", " + + str(self.uls) + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPLoadTile ' + str(self.t) + ', ' + str(self.uls) + ', ' + \ - str(self.ult) + ', ' + str(self.lrs) + ', ' + str(self.lrt) - - def size(self, f3d): - return GFX_SIZE class DPSetTile: - def __init__(self, fmt, siz, line, tmem, tile, palette, cmt, \ - maskt, shiftt, cms, masks, shifts): - self.fmt = fmt # is a string - self.siz = siz # is a string - self.line = line - self.tmem = tmem - self.tile = tile - self.palette = palette - self.cmt = cmt # list of two strings - self.maskt = maskt - self.shiftt = shiftt - self.cms = cms # list of two strings - self.masks = masks - self.shifts = shifts + def __init__(self, fmt, siz, line, tmem, tile, palette, cmt, maskt, shiftt, cms, masks, shifts): + self.fmt = fmt # is a string + self.siz = siz # is a string + self.line = line + self.tmem = tmem + self.tile = tile + self.palette = palette + self.cmt = cmt # list of two strings + self.maskt = maskt + self.shiftt = shiftt + self.cms = cms # list of two strings + self.masks = masks + self.shifts = shifts - def to_binary(self, f3d, segments): - cms = f3d.G_TX_VARS[self.cms[0]] + f3d.G_TX_VARS[self.cms[1]] - cmt = f3d.G_TX_VARS[self.cmt[0]] + f3d.G_TX_VARS[self.cmt[1]] + def to_binary(self, f3d, segments): + cms = f3d.G_TX_VARS[self.cms[0]] + f3d.G_TX_VARS[self.cms[1]] + cmt = f3d.G_TX_VARS[self.cmt[0]] + f3d.G_TX_VARS[self.cmt[1]] - words = (_SHIFTL(f3d.G_SETTILE, 24, 8) | \ - _SHIFTL(f3d.G_IM_FMT_VARS[self.fmt], 21, 3) | \ - _SHIFTL(f3d.G_IM_SIZ_VARS[self.siz], 19, 2) | \ - _SHIFTL(self.line, 9, 9) | \ - _SHIFTL(self.tmem, 0, 9)), (_SHIFTL(self.tile, 24, 3) | \ - _SHIFTL(self.palette, 20, 4) | _SHIFTL(cmt, 18, 2) | \ - _SHIFTL(self.maskt, 14, 4) | _SHIFTL(self.shiftt, 10, 4) | \ - _SHIFTL(cms, 8, 2) | _SHIFTL(self.masks, 4, 4) | \ - _SHIFTL(self.shifts, 0, 4)) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = ( + _SHIFTL(f3d.G_SETTILE, 24, 8) + | _SHIFTL(f3d.G_IM_FMT_VARS[self.fmt], 21, 3) + | _SHIFTL(f3d.G_IM_SIZ_VARS[self.siz], 19, 2) + | _SHIFTL(self.line, 9, 9) + | _SHIFTL(self.tmem, 0, 9) + ), ( + _SHIFTL(self.tile, 24, 3) + | _SHIFTL(self.palette, 20, 4) + | _SHIFTL(cmt, 18, 2) + | _SHIFTL(self.maskt, 14, 4) + | _SHIFTL(self.shiftt, 10, 4) + | _SHIFTL(cms, 8, 2) + | _SHIFTL(self.masks, 4, 4) + | _SHIFTL(self.shifts, 0, 4) + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") - def to_c(self, static = True): - # no tabs/line breaks, breaks macros - header = 'gsDPSetTile(' if static else 'gDPSetTile(glistp++, ' - return header + self.fmt + ', ' + self.siz + ', ' + \ - str(self.line) + ', ' + str(self.tmem) + ', ' + \ - str(self.tile) + ', ' + str(self.palette) + ', ' + \ - self.cmt[0] + ' | ' + self.cmt[1] + ', ' + str(self.maskt) + \ - ', ' + str(self.shiftt) + ', ' + self.cms[0] + ' | ' + \ - self.cms[1] + ', ' + str(self.masks) + ', ' + str(self.shifts) + ')' + def to_c(self, static=True): + # no tabs/line breaks, breaks macros + header = "gsDPSetTile(" if static else "gDPSetTile(glistp++, " + return ( + header + + self.fmt + + ", " + + self.siz + + ", " + + str(self.line) + + ", " + + str(self.tmem) + + ", " + + str(self.tile) + + ", " + + str(self.palette) + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.maskt) + + ", " + + str(self.shiftt) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + str(self.masks) + + ", " + + str(self.shifts) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetTile " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.line) + + ", " + + str(self.tmem) + + ", " + + str(self.tile) + + ", " + + str(self.palette) + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.maskt) + + ", " + + str(self.shiftt) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + str(self.masks) + + ", " + + str(self.shifts) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetTile ' + self.fmt + ', ' + self.siz + ', ' + \ - str(self.line) + ', ' + str(self.tmem) + ', ' + \ - str(self.tile) + ', ' + str(self.palette) + ', ' + \ - self.cmt[0] + ' | ' + self.cmt[1] + ', ' + str(self.maskt) + \ - ', ' + str(self.shiftt) + ', ' + self.cms[0] + ' | ' + \ - self.cms[1] + ', ' + str(self.masks) + ', ' + str(self.shifts) - - def size(self, f3d): - return GFX_SIZE class DPLoadBlock: - def __init__(self, tile, uls, ult, lrs, dxt): - self.tile = tile - self.uls = uls - self.ult = ult - self.lrs = lrs - self.dxt = dxt - - def to_binary(self, f3d, segments): - words = (_SHIFTL(f3d.G_LOADBLOCK, 24, 8) | _SHIFTL(self.uls, 12, 12) | \ - _SHIFTL(self.ult, 0, 12)), (_SHIFTL(self.tile, 24, 3) | \ - _SHIFTL((min(self.lrs,f3d.G_TX_LDBLK_MAX_TXL)), 12, 12) | \ - _SHIFTL(self.dxt, 0, 12)) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, tile, uls, ult, lrs, dxt): + self.tile = tile + self.uls = uls + self.ult = ult + self.lrs = lrs + self.dxt = dxt - def to_c(self, static = True): - header = 'gsDPLoadBlock(' if static else 'gDPLoadBlock(glistp++, ' - return header + str(self.tile) + ', ' + str(self.uls) + ', ' + \ - str(self.ult) + ', ' + str(self.lrs) + ', ' + str(self.dxt) + ')' + def to_binary(self, f3d, segments): + words = (_SHIFTL(f3d.G_LOADBLOCK, 24, 8) | _SHIFTL(self.uls, 12, 12) | _SHIFTL(self.ult, 0, 12)), ( + _SHIFTL(self.tile, 24, 3) + | _SHIFTL((min(self.lrs, f3d.G_TX_LDBLK_MAX_TXL)), 12, 12) + | _SHIFTL(self.dxt, 0, 12) + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsDPLoadBlock(" if static else "gDPLoadBlock(glistp++, " + return ( + header + + str(self.tile) + + ", " + + str(self.uls) + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.dxt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadBlock " + + str(self.tile) + + ", " + + str(self.uls) + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.dxt) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPLoadBlock ' + str(self.tile) + ', ' + str(self.uls) + ', ' + \ - str(self.ult) + ', ' + str(self.lrs) + ', ' + str(self.dxt) - - def size(self, f3d): - return GFX_SIZE class DPLoadTLUTCmd: - def __init__(self, tile, count): - self.tile = tile - self.count = count - - def to_binary(self, f3d, segments): - words = _SHIFTL(f3d.G_LOADTLUT, 24, 8), \ - _SHIFTL((self.tile), 24, 3) | _SHIFTL((self.count), 14, 10) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, tile, count): + self.tile = tile + self.count = count - def to_c(self, static = True): - header = 'gsDPLoadTLUTCmd(' if static else 'gDPLoadTLUTCmd(glistp++, ' - return header + str(self.tile) + ', ' + str(self.count) + ')' + def to_binary(self, f3d, segments): + words = _SHIFTL(f3d.G_LOADTLUT, 24, 8), _SHIFTL((self.tile), 24, 3) | _SHIFTL((self.count), 14, 10) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsDPLoadTLUTCmd(" if static else "gDPLoadTLUTCmd(glistp++, " + return header + str(self.tile) + ", " + str(self.count) + ")" + + def to_sm64_decomp_s(self): + return "gsDPLoadTLUTCmd " + str(self.tile) + ", " + str(self.count) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPLoadTLUTCmd ' + str(self.tile) + ', ' + str(self.count) - - def size(self, f3d): - return GFX_SIZE class DPLoadTextureBlock: - def __init__(self, timg, fmt, siz, width, height, - pal, cms, cmt, masks, maskt, shifts, shiftt): - self.timg = timg # FImage object - self.fmt = fmt # string - self.siz = siz # string - self.width = width - self.height = height - self.pal = pal - self.cms = cms # list of two strings - self.cmt = cmt # list of two strings - self.masks = masks - self.maskt = maskt - self.shifts = shifts - self.shiftt = shiftt - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - return \ - DPSetTextureImage(self.fmt, self.siz + '_LOAD_BLOCK', \ - 1, self.timg).to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz + '_LOAD_BLOCK', - 0, 0, f3d.G_TX_LOADTILE, 0, self.cmt, self.maskt, self.shiftt, \ - self.cms, self.masks, self.shifts).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadBlock(f3d.G_TX_LOADTILE, 0, 0, \ - (((self.width)*(self.height) + \ - f3d.G_IM_SIZ_VARS[self.siz + '_INCR']) >> \ - f3d.G_IM_SIZ_VARS[self.siz + '_SHIFT'])-1, \ - f3d.CALC_DXT(self.width, f3d.G_IM_SIZ_VARS[self.siz + \ - '_BYTES'])).to_binary(f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz, ((((self.width) * \ - f3d.G_IM_SIZ_VARS[self.siz + '_LINE_BYTES'])+7)>>3), 0, \ - f3d.G_TX_RENDERTILE, self.pal, self.cmt, self.maskt, \ - self.shiftt, self.cms, self.masks, self.shifts).to_binary(\ - f3d, segments) + \ - DPSetTileSize(f3d.G_TX_RENDERTILE, 0, 0, \ - ((self.width)-1) << f3d.G_TEXTURE_IMAGE_FRAC, \ - ((self.height)-1) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary(\ - f3d, segments) + def __init__(self, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt): + self.timg = timg # FImage object + self.fmt = fmt # string + self.siz = siz # string + self.width = width + self.height = height + self.pal = pal + self.cms = cms # list of two strings + self.cmt = cmt # list of two strings + self.masks = masks + self.maskt = maskt + self.shifts = shifts + self.shiftt = shiftt - def to_c(self, static = True): - header = 'gsDPLoadTextureBlock(' if static else \ - 'gDPLoadTextureBlock(glistp++, ' - return header + '&' + self.timg.name + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - self.cms[0] + ' | ' + self.cms[1] + ', ' + self.cmt[0] + \ - ' | ' + self.cmt[1] + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + return ( + DPSetTextureImage(self.fmt, self.siz + "_LOAD_BLOCK", 1, self.timg).to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz + "_LOAD_BLOCK", + 0, + 0, + f3d.G_TX_LOADTILE, + 0, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadBlock( + f3d.G_TX_LOADTILE, + 0, + 0, + ( + ((self.width) * (self.height) + f3d.G_IM_SIZ_VARS[self.siz + "_INCR"]) + >> f3d.G_IM_SIZ_VARS[self.siz + "_SHIFT"] + ) + - 1, + f3d.CALC_DXT(self.width, f3d.G_IM_SIZ_VARS[self.siz + "_BYTES"]), + ).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz, + ((((self.width) * f3d.G_IM_SIZ_VARS[self.siz + "_LINE_BYTES"]) + 7) >> 3), + 0, + f3d.G_TX_RENDERTILE, + self.pal, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPSetTileSize( + f3d.G_TX_RENDERTILE, + 0, + 0, + ((self.width) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ((self.height) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + ) + + def to_c(self, static=True): + header = "gsDPLoadTextureBlock(" if static else "gDPLoadTextureBlock(glistp++, " + return ( + header + + "&" + + self.timg.name + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadTextureBlock " + + self.timg.name + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + str(self.cms) + + ", " + + str(self.cmt) + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + ) + + def size(self, f3d): + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTextureBlock ' + \ - self.timg.name + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - str(self.cms) + ', ' + str(self.cmt) + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) - - def size(self, f3d): - return GFX_SIZE * 7 class DPLoadTextureBlockYuv: - def __init__(self, timg, fmt, siz, width, height, - pal, cms, cmt, masks, maskt, shifts, shiftt): - self.timg = timg # FImage object - self.fmt = fmt # string - self.siz = siz # string - self.width = width - self.height = height - self.pal = pal - self.cms = cms - self.cmt = cmt - self.masks = masks - self.maskt = maskt - self.shifts = shifts - self.shiftt = shiftt - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - return \ - DPSetTextureImage(self.fmt, self.siz + '_LOAD_BLOCK', \ - 1, self.timg).to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz + '_LOAD_BLOCK', - 0, 0, f3d.G_TX_LOADTILE, 0, self.cmt, self.maskt, self.shiftt, \ - self.cms, self.masks, self.shifts).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadBlock(f3d.G_TX_LOADTILE, 0, 0, \ - (((self.width)*(self.height) + \ - f3d.G_IM_SIZ_VARS[self.siz + '_INCR']) >> \ - f3d.G_IM_SIZ_VARS[self.siz + '_SHIFT'])-1, \ - f3d.CALC_DXT(self.width, f3d.G_IM_SIZ_VARS[self.siz + \ - '_BYTES'])).to_binary(f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz, \ - ((((self.width) * 1)+7)>>3), 0, \ - f3d.G_TX_RENDERTILE, self.pal, self.cmt, self.maskt, \ - self.shiftt, self.cms, self.masks, self.shifts).to_binary(\ - f3d, segments) + \ - DPSetTileSize(f3d.G_TX_RENDERTILE, 0, 0, \ - ((self.width)-1) << f3d.G_TEXTURE_IMAGE_FRAC, \ - ((self.height)-1) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary(\ - f3d, segments) + def __init__(self, timg, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt): + self.timg = timg # FImage object + self.fmt = fmt # string + self.siz = siz # string + self.width = width + self.height = height + self.pal = pal + self.cms = cms + self.cmt = cmt + self.masks = masks + self.maskt = maskt + self.shifts = shifts + self.shiftt = shiftt - def to_c(self, static = True): - header = 'gsDPLoadTextureBlockYuv(' if static else \ - 'gDPLoadTextureBlockYuv(glistp++, ' - return header + '&' + self.timg.name + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - self.cms[0] + ' | ' + self.cms[1] + ', ' + self.cmt[0] + \ - ' | ' + self.cmt[1] + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + return ( + DPSetTextureImage(self.fmt, self.siz + "_LOAD_BLOCK", 1, self.timg).to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz + "_LOAD_BLOCK", + 0, + 0, + f3d.G_TX_LOADTILE, + 0, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadBlock( + f3d.G_TX_LOADTILE, + 0, + 0, + ( + ((self.width) * (self.height) + f3d.G_IM_SIZ_VARS[self.siz + "_INCR"]) + >> f3d.G_IM_SIZ_VARS[self.siz + "_SHIFT"] + ) + - 1, + f3d.CALC_DXT(self.width, f3d.G_IM_SIZ_VARS[self.siz + "_BYTES"]), + ).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz, + ((((self.width) * 1) + 7) >> 3), + 0, + f3d.G_TX_RENDERTILE, + self.pal, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPSetTileSize( + f3d.G_TX_RENDERTILE, + 0, + 0, + ((self.width) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ((self.height) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + ) + + def to_c(self, static=True): + header = "gsDPLoadTextureBlockYuv(" if static else "gDPLoadTextureBlockYuv(glistp++, " + return ( + header + + "&" + + self.timg.name + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadTextureBlockYuv " + + self.timg.name + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + str(self.cms) + + ", " + + str(self.cmt) + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + ) + + def size(self, f3d): + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTextureBlockYuv ' + \ - self.timg.name + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - str(self.cms) + ', ' + str(self.cmt) + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) - - def size(self, f3d): - return GFX_SIZE * 7 # gsDPLoadTextureBlockS # gsDPLoadMultiBlockS # gsDPLoadTextureBlockYuvS + class _DPLoadTextureBlock: - def __init__(self, timg, tmem, fmt, siz, width, height, - pal, cms, cmt, masks, maskt, shifts, shiftt): - self.timg = timg # FImage object - self.tmem = tmem - self.fmt = fmt # string - self.siz = siz # string - self.width = width - self.height = height - self.pal = pal - self.cms = cms - self.cmt = cmt - self.masks = masks - self.maskt = maskt - self.shifts = shifts - self.shiftt = shiftt + def __init__(self, timg, tmem, fmt, siz, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt): + self.timg = timg # FImage object + self.tmem = tmem + self.fmt = fmt # string + self.siz = siz # string + self.width = width + self.height = height + self.pal = pal + self.cms = cms + self.cmt = cmt + self.masks = masks + self.maskt = maskt + self.shifts = shifts + self.shiftt = shiftt - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - return \ - DPSetTextureImage(self.fmt, self.siz + '_LOAD_BLOCK', \ - 1, self.timg).to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz + '_LOAD_BLOCK', - 0, self.tmem, f3d.G_TX_LOADTILE, 0, self.cmt, self.maskt, - self.shiftt, self.cms, self.masks, self.shifts).to_binary(\ - f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadBlock(f3d.G_TX_LOADTILE, 0, 0, \ - (((self.width)*(self.height) + \ - f3d.G_IM_SIZ_VARS[self.siz + '_INCR']) >> \ - f3d.G_IM_SIZ_VARS[self.siz + '_SHIFT'])-1, \ - f3d.CALC_DXT(self.width, f3d.G_IM_SIZ_VARS[self.siz + \ - '_BYTES'])).to_binary(f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz, ((((self.width) * \ - f3d.G_IM_SIZ_VARS[self.siz + '_LINE_BYTES'])+7)>>3), \ - self.tmem, f3d.G_TX_RENDERTILE, self.pal, self.cmt, \ - self.maskt, self.shiftt, self.cms, self.masks, \ - self.shifts).to_binary(f3d, segments) + \ - DPSetTileSize(f3d.G_TX_RENDERTILE, 0, 0, \ - ((self.width)-1) << f3d.G_TEXTURE_IMAGE_FRAC, \ - ((self.height)-1) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary(\ - f3d, segments) + def get_ptr_offsets(self, f3d): + return [4] - def to_c(self, static = True): - header = '_gsDPLoadTextureBlock(' if static else \ - '_gDPLoadTextureBlock(glistp++, ' - return header + '&' + self.timg.name + ', ' + str(self.tmem) + ', ' +\ - self.fmt + ', ' + self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - self.cms[0] + ' | ' + self.cms[1] + ', ' + self.cmt[0] + \ - ' | ' + self.cmt[1] + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + ')' + def to_binary(self, f3d, segments): + return ( + DPSetTextureImage(self.fmt, self.siz + "_LOAD_BLOCK", 1, self.timg).to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz + "_LOAD_BLOCK", + 0, + self.tmem, + f3d.G_TX_LOADTILE, + 0, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadBlock( + f3d.G_TX_LOADTILE, + 0, + 0, + ( + ((self.width) * (self.height) + f3d.G_IM_SIZ_VARS[self.siz + "_INCR"]) + >> f3d.G_IM_SIZ_VARS[self.siz + "_SHIFT"] + ) + - 1, + f3d.CALC_DXT(self.width, f3d.G_IM_SIZ_VARS[self.siz + "_BYTES"]), + ).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz, + ((((self.width) * f3d.G_IM_SIZ_VARS[self.siz + "_LINE_BYTES"]) + 7) >> 3), + self.tmem, + f3d.G_TX_RENDERTILE, + self.pal, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPSetTileSize( + f3d.G_TX_RENDERTILE, + 0, + 0, + ((self.width) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ((self.height) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + ) + + def to_c(self, static=True): + header = "_gsDPLoadTextureBlock(" if static else "_gDPLoadTextureBlock(glistp++, " + return ( + header + + "&" + + self.timg.name + + ", " + + str(self.tmem) + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "_gsDPLoadTextureBlock " + + self.timg.name + + ", " + + str(self.tmem) + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + str(self.cms) + + ", " + + str(self.cmt) + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + ) + + def size(self, f3d): + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return '_gsDPLoadTextureBlock ' + \ - self.timg.name + ', ' + str(self.tmem) + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - str(self.cms) + ', ' + str(self.cmt) + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) - - def size(self, f3d): - return GFX_SIZE * 7 # _gsDPLoadTextureBlockTile # gsDPLoadMultiBlock # gsDPLoadMultiBlockS + class DPLoadTextureBlock_4b: - def __init__(self, timg, fmt, width, height, - pal, cms, cmt, masks, maskt, shifts, shiftt): - self.timg = timg # FImage object - self.fmt = fmt # string - self.width = width - self.height = height - self.pal = pal - self.cms = cms - self.cmt = cmt - self.masks = masks - self.maskt = maskt - self.shifts = shifts - self.shiftt = shiftt - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - return \ - DPSetTextureImage(self.fmt, 'G_IM_SIZ_16b', \ - 1, self.timg).to_binary(f3d, segments) + \ - DPSetTile(self.fmt, 'G_IM_SIZ_16b', - 0, 0, f3d.G_TX_LOADTILE, 0, self.cmt, self.maskt, self.shiftt, \ - self.cms, self.masks, self.shifts).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadBlock(f3d.G_TX_LOADTILE, 0, 0, \ - (((self.width)*(self.height) + 3) >> 2) - 1, \ - f3d.CALC_DXT_4b(self.width)).to_binary(f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) + \ - DPSetTile(self.fmt, 'G_IM_SIZ_4b', \ - (((self.width >> 1) + 7) >> 3), 0, \ - f3d.G_TX_RENDERTILE, self.pal, self.cmt, self.maskt, \ - self.shiftt, self.cms, self.masks, self.shifts).to_binary(\ - f3d, segments) + \ - DPSetTileSize(f3d.G_TX_RENDERTILE, 0, 0, \ - ((self.width)-1) << f3d.G_TEXTURE_IMAGE_FRAC, \ - ((self.height)-1) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary(\ - f3d, segments) + def __init__(self, timg, fmt, width, height, pal, cms, cmt, masks, maskt, shifts, shiftt): + self.timg = timg # FImage object + self.fmt = fmt # string + self.width = width + self.height = height + self.pal = pal + self.cms = cms + self.cmt = cmt + self.masks = masks + self.maskt = maskt + self.shifts = shifts + self.shiftt = shiftt - def to_c(self, static = True): - header = 'gsDPLoadTextureBlock_4b(' if static else \ - 'gDPLoadTextureBlock_4b(glistp++, ' - return header + '&' + self.timg.name + ', ' + self.fmt + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - self.cms[0] + ' | ' + self.cms[1] + ', ' + self.cmt[0] + \ - ' | ' + self.cmt[1] + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + return ( + DPSetTextureImage(self.fmt, "G_IM_SIZ_16b", 1, self.timg).to_binary(f3d, segments) + + DPSetTile( + self.fmt, + "G_IM_SIZ_16b", + 0, + 0, + f3d.G_TX_LOADTILE, + 0, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadBlock( + f3d.G_TX_LOADTILE, 0, 0, (((self.width) * (self.height) + 3) >> 2) - 1, f3d.CALC_DXT_4b(self.width) + ).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + + DPSetTile( + self.fmt, + "G_IM_SIZ_4b", + (((self.width >> 1) + 7) >> 3), + 0, + f3d.G_TX_RENDERTILE, + self.pal, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPSetTileSize( + f3d.G_TX_RENDERTILE, + 0, + 0, + ((self.width) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ((self.height) - 1) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + ) + + def to_c(self, static=True): + header = "gsDPLoadTextureBlock_4b(" if static else "gDPLoadTextureBlock_4b(glistp++, " + return ( + header + + "&" + + self.timg.name + + ", " + + self.fmt + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadTextureBlock_4b " + + self.timg.name + + ", " + + self.fmt + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + str(self.pal) + + ", " + + str(self.cms) + + ", " + + str(self.cmt) + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + ) + + def size(self, f3d): + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTextureBlock_4b ' + \ - self.timg.name + ', ' + self.fmt + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + str(self.pal) + ', ' + \ - str(self.cms) + ', ' + str(self.cmt) + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) - - def size(self, f3d): - return GFX_SIZE * 7 # gsDPLoadTextureBlock_4bS # gsDPLoadMultiBlock_4b # gsDPLoadMultiBlock_4bS # _gsDPLoadTextureBlock_4b + class DPLoadTextureTile: - def __init__(self, timg, fmt, siz, width, height, - uls, ult, lrs, lrt, - pal, cms, cmt, masks, maskt, shifts, shiftt): - self.timg = timg # FImage object - self.fmt = fmt # string - self.siz = siz # string - self.width = width - self.height = height - self.uls = uls - self.ult = ult - self.lrs = lrs - self.lrt = lrt - self.pal = pal - self.cms = cms - self.cmt = cmt - self.masks = masks - self.maskt = maskt - self.shifts = shifts - self.shiftt = shiftt - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - return \ - DPSetTextureImage(self.fmt, self.siz, \ - self.width, self.timg).to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz, \ - (((self.lrs-self.uls+1) * f3d.G_IM_SIZ_VARS[self.siz +\ - '_TILE_BYTES'] + 7)>>3), 0, f3d.G_TX_LOADTILE, 0, \ - self.cmt, self.maskt, self.shiftt, self.cms, self.masks,\ - self.shifts).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadTile(f3d.G_TX_LOADTILE, - (self.uls) << f3d.G_TEXTURE_IMAGE_FRAC, - (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, - (self.lrs) << f3d.G_TEXTURE_IMAGE_FRAC, - (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary( - f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) + \ - DPSetTile(self.fmt, self.siz, - ((((self.lrs-self.uls+1) * \ - f3d.G_IM_SIZ_VARS[self.siz + '_LINE_BYTES'])+7)>>3), 0, \ - f3d.G_TX_RENDERTILE, self.pal, self.cmt, self.maskt, \ - self.shiftt, self.cms, self.masks, self.shifts).to_binary(\ - f3d, segments) + \ - DPSetTileSize(f3d.G_TX_RENDERTILE, \ - (self.uls) << f3d.G_TEXTURE_IMAGE_FRAC, \ - (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, \ - (self.lrs) << f3d.G_TEXTURE_IMAGE_FRAC, \ - (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary(\ - f3d, segments) + def __init__(self, timg, fmt, siz, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, shiftt): + self.timg = timg # FImage object + self.fmt = fmt # string + self.siz = siz # string + self.width = width + self.height = height + self.uls = uls + self.ult = ult + self.lrs = lrs + self.lrt = lrt + self.pal = pal + self.cms = cms + self.cmt = cmt + self.masks = masks + self.maskt = maskt + self.shifts = shifts + self.shiftt = shiftt - def to_c(self, static = True): - header = 'gsDPLoadTextureTile(' if static else \ - 'gDPLoadTextureTile(glistp++, ' - return header + '&' + self.timg.name + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + self.uls + ', ' + str(self.ult) + \ - ', ' + str(self.lrs) + ', ' + str(self.lrt) + str(self.pal) + \ - ', ' + self.cms[0] + ' | ' + self.cms[1] + ', ' + self.cmt[0] + \ - ' | ' + self.cmt[1] + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + return ( + DPSetTextureImage(self.fmt, self.siz, self.width, self.timg).to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz, + (((self.lrs - self.uls + 1) * f3d.G_IM_SIZ_VARS[self.siz + "_TILE_BYTES"] + 7) >> 3), + 0, + f3d.G_TX_LOADTILE, + 0, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadTile( + f3d.G_TX_LOADTILE, + (self.uls) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrs) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + + DPSetTile( + self.fmt, + self.siz, + ((((self.lrs - self.uls + 1) * f3d.G_IM_SIZ_VARS[self.siz + "_LINE_BYTES"]) + 7) >> 3), + 0, + f3d.G_TX_RENDERTILE, + self.pal, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPSetTileSize( + f3d.G_TX_RENDERTILE, + (self.uls) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrs) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + ) + + def to_c(self, static=True): + header = "gsDPLoadTextureTile(" if static else "gDPLoadTextureTile(glistp++, " + return ( + header + + "&" + + self.timg.name + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + self.uls + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + + str(self.pal) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadTextureTile " + + self.timg.name + + ", " + + self.fmt + + ", " + + self.siz + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + self.uls + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + + ", " + + str(self.pal) + + ", " + + str(self.cms) + + ", " + + str(self.cmt) + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + ) + + def size(self, f3d): + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTextureTile ' + \ - self.timg.name + ', ' + self.fmt + ', ' + \ - self.siz + ', ' + str(self.width) + ', ' + \ - str(self.height) + ', ' + self.uls + ', ' + str(self.ult) + \ - ', ' + str(self.lrs) + ', ' + str(self.lrt)+ ', ' + \ - str(self.pal) + ', ' + \ - str(self.cms) + ', ' + str(self.cmt) + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) - - def size(self, f3d): - return GFX_SIZE * 7 # gsDPLoadMultiTile + class DPLoadTextureTile_4b: - def __init__(self, timg, fmt, width, height, - uls, ult, lrs, lrt, - pal, cms, cmt, masks, maskt, shifts, shiftt): - self.timg = timg # FImage object - self.fmt = fmt # string - self.width = width - self.height = height - self.uls = uls - self.ult = ult - self.lrs = lrs - self.lrt = lrt - self.pal = pal - self.cms = cms - self.cmt = cmt - self.masks = masks - self.maskt = maskt - self.shifts = shifts - self.shiftt = shiftt - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - return \ - DPSetTextureImage(self.fmt, 'G_IM_SIZ_8b', \ - self.width >> 1, self.timg).to_binary(f3d, segments) + \ - DPSetTile(self.fmt, 'G_IM_SIZ_8b', \ - ((((self.lrs-self.uls+1) >> 1) + 7)>>3), 0, f3d.G_TX_LOADTILE, \ - 0, self.cmt, self.maskt, self.shiftt, self.cms, self.masks,\ - self.shifts).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadTile(f3d.G_TX_LOADTILE, - (self.uls) << (f3d.G_TEXTURE_IMAGE_FRAC - 1), - (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, - (self.lrs) << (f3d.G_TEXTURE_IMAGE_FRAC - 1), - (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary( - f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) + \ - DPSetTile(self.fmt, 'G_IM_SIZ_4b', - ((((self.lrs-self.uls+1) >> 1)+7)>>3), 0, \ - f3d.G_TX_RENDERTILE, self.pal, self.cmt, self.maskt, \ - self.shiftt, self.cms, self.masks, self.shifts).to_binary(\ - f3d, segments) + \ - DPSetTileSize(f3d.G_TX_RENDERTILE, \ - (self.uls) << f3d.G_TEXTURE_IMAGE_FRAC, \ - (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, \ - (self.lrs) << f3d.G_TEXTURE_IMAGE_FRAC, \ - (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC).to_binary(\ - f3d, segments) + def __init__(self, timg, fmt, width, height, uls, ult, lrs, lrt, pal, cms, cmt, masks, maskt, shifts, shiftt): + self.timg = timg # FImage object + self.fmt = fmt # string + self.width = width + self.height = height + self.uls = uls + self.ult = ult + self.lrs = lrs + self.lrt = lrt + self.pal = pal + self.cms = cms + self.cmt = cmt + self.masks = masks + self.maskt = maskt + self.shifts = shifts + self.shiftt = shiftt - def to_c(self, static = True): - header = 'gsDPLoadTextureTile_4b(' if static else \ - 'gDPLoadTextureTile_4b(glistp++, ' - return header + '&' + self.timg.name + ', ' + self.fmt + ', ' + \ - str(self.width) + ', ' + \ - str(self.height) + ', ' + self.uls + ', ' + str(self.ult) + \ - ', ' + str(self.lrs) + ', ' + str(self.lrt) + str(self.pal) + \ - ', ' + self.cms[0] + ' | ' + self.cms[1] + ', ' + self.cmt[0] + \ - ' | ' + self.cmt[1] + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + ')' + def get_ptr_offsets(self, f3d): + return [4] - def to_sm64_decomp_s(self): - return 'gsDPLoadTextureTile_4b ' + \ - self.timg.name + ', ' + self.fmt + ', ' + \ - str(self.width) + ', ' + \ - str(self.height) + ', ' + self.uls + ', ' + str(self.ult) + \ - ', ' + str(self.lrs) + ', ' + str(self.lrt)+ ', ' + \ - str(self.pal) + ', ' + \ - str(self.cms) + ', ' + str(self.cmt) + ', ' + \ - str(self.masks) + ', ' + str(self.maskt) + ', ' + \ - str(self.shifts) + ', ' + str(self.shiftt) + def to_binary(self, f3d, segments): + return ( + DPSetTextureImage(self.fmt, "G_IM_SIZ_8b", self.width >> 1, self.timg).to_binary(f3d, segments) + + DPSetTile( + self.fmt, + "G_IM_SIZ_8b", + ((((self.lrs - self.uls + 1) >> 1) + 7) >> 3), + 0, + f3d.G_TX_LOADTILE, + 0, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadTile( + f3d.G_TX_LOADTILE, + (self.uls) << (f3d.G_TEXTURE_IMAGE_FRAC - 1), + (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrs) << (f3d.G_TEXTURE_IMAGE_FRAC - 1), + (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + + DPSetTile( + self.fmt, + "G_IM_SIZ_4b", + ((((self.lrs - self.uls + 1) >> 1) + 7) >> 3), + 0, + f3d.G_TX_RENDERTILE, + self.pal, + self.cmt, + self.maskt, + self.shiftt, + self.cms, + self.masks, + self.shifts, + ).to_binary(f3d, segments) + + DPSetTileSize( + f3d.G_TX_RENDERTILE, + (self.uls) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.ult) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrs) << f3d.G_TEXTURE_IMAGE_FRAC, + (self.lrt) << f3d.G_TEXTURE_IMAGE_FRAC, + ).to_binary(f3d, segments) + ) + + def to_c(self, static=True): + header = "gsDPLoadTextureTile_4b(" if static else "gDPLoadTextureTile_4b(glistp++, " + return ( + header + + "&" + + self.timg.name + + ", " + + self.fmt + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + self.uls + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + + str(self.pal) + + ", " + + self.cms[0] + + " | " + + self.cms[1] + + ", " + + self.cmt[0] + + " | " + + self.cmt[1] + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPLoadTextureTile_4b " + + self.timg.name + + ", " + + self.fmt + + ", " + + str(self.width) + + ", " + + str(self.height) + + ", " + + self.uls + + ", " + + str(self.ult) + + ", " + + str(self.lrs) + + ", " + + str(self.lrt) + + ", " + + str(self.pal) + + ", " + + str(self.cms) + + ", " + + str(self.cmt) + + ", " + + str(self.masks) + + ", " + + str(self.maskt) + + ", " + + str(self.shifts) + + ", " + + str(self.shiftt) + ) + + def size(self, f3d): + return GFX_SIZE * 7 - def size(self, f3d): - return GFX_SIZE * 7 # gsDPLoadMultiTile_4b + class DPLoadTLUT_pal16: - def __init__(self, pal, dram): - self.pal = pal - self.dram = dram # pallete object - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - if not f3d._HW_VERSION_1: - return \ - DPSetTextureImage('G_IM_FMT_RGBA', 'G_IM_SIZ_16b', 1, \ - self.dram).to_binary(f3d, segments) + \ - DPTileSync().to_binary(f3d, segments) + \ - DPSetTile('0', '0', 0, (256+(((self.pal)&0xf)*16)),\ - f3d.G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0).to_binary(\ - f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadTLUTCmd(f3d.G_TX_LOADTILE, 15).to_binary( - f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) - else: - return _DPLoadTextureBlock(self.dram, \ - (256+(((self.pal)&0xf)*16)), \ - f3d.G_IM_FMT_VARS['G_IM_FMT_RGBA'], \ - f3d.G_IM_SIZ_VARS['G_IM_SIZ_16b'], 4*16, 1, - self.pal, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + def __init__(self, pal, dram): + self.pal = pal + self.dram = dram # pallete object - def to_c(self, static = True): - header = 'gsDPLoadTLUT_pal16(' if static else \ - 'gDPLoadTLUT_pal16(glistp++, ' - return header + str(self.pal) + ', ' + '&' + self.dram.name + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + if not f3d._HW_VERSION_1: + return ( + DPSetTextureImage("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 1, self.dram).to_binary(f3d, segments) + + DPTileSync().to_binary(f3d, segments) + + DPSetTile( + "0", "0", 0, (256 + (((self.pal) & 0xF) * 16)), f3d.G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0 + ).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadTLUTCmd(f3d.G_TX_LOADTILE, 15).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + ) + else: + return _DPLoadTextureBlock( + self.dram, + (256 + (((self.pal) & 0xF) * 16)), + f3d.G_IM_FMT_VARS["G_IM_FMT_RGBA"], + f3d.G_IM_SIZ_VARS["G_IM_SIZ_16b"], + 4 * 16, + 1, + self.pal, + 0, + 0, + 0, + 0, + 0, + 0, + ).to_binary(f3d, segments) + + def to_c(self, static=True): + header = "gsDPLoadTLUT_pal16(" if static else "gDPLoadTLUT_pal16(glistp++, " + return header + str(self.pal) + ", " + "&" + self.dram.name + ")" + + def to_sm64_decomp_s(self): + return "gsDPLoadTLUT_pal16 " + str(self.pal) + ", " + self.dram.name + + def size(self, f3d): + if not f3d._HW_VERSION_1: + return GFX_SIZE * 6 + else: + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTLUT_pal16 ' + str(self.pal) + ', ' + self.dram.name - - def size(self, f3d): - if not f3d._HW_VERSION_1: - return GFX_SIZE * 6 - else: - return GFX_SIZE * 7 class DPLoadTLUT_pal256: - def __init__(self, dram): - self.dram = dram # pallete object - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - if not f3d._HW_VERSION_1: - return \ - DPSetTextureImage('G_IM_FMT_RGBA', 'G_IM_SIZ_16b', 1, \ - self.dram).to_binary(f3d, segments) + \ - DPTileSync().to_binary(f3d, segments) + \ - DPSetTile('0', '0', 0, 256, f3d.G_TX_LOADTILE, 0, 0, 0, 0, - 0, 0, 0).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadTLUTCmd(f3d.G_TX_LOADTILE, 255).to_binary( - f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) - else: - return _DPLoadTextureBlock(self.dram, 256, \ - f3d.G_IM_FMT_VARS['G_IM_FMT_RGBA'], \ - f3d.G_IM_SIZ_VARS['G_IM_SIZ_16b'], 4*256, 1, - 0, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + def __init__(self, dram): + self.dram = dram # pallete object - def to_c(self, static = True): - header = 'gsDPLoadTLUT_pal256(' if static else \ - 'gDPLoadTLUT_pal256(glistp++, ' - return header + '&' + self.dram.name + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + if not f3d._HW_VERSION_1: + return ( + DPSetTextureImage("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 1, self.dram).to_binary(f3d, segments) + + DPTileSync().to_binary(f3d, segments) + + DPSetTile("0", "0", 0, 256, f3d.G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadTLUTCmd(f3d.G_TX_LOADTILE, 255).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + ) + else: + return _DPLoadTextureBlock( + self.dram, + 256, + f3d.G_IM_FMT_VARS["G_IM_FMT_RGBA"], + f3d.G_IM_SIZ_VARS["G_IM_SIZ_16b"], + 4 * 256, + 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ).to_binary(f3d, segments) + + def to_c(self, static=True): + header = "gsDPLoadTLUT_pal256(" if static else "gDPLoadTLUT_pal256(glistp++, " + return header + "&" + self.dram.name + ")" + + def to_sm64_decomp_s(self): + return "gsDPLoadTLUT_pal256 " + self.dram.name + + def size(self, f3d): + if not f3d._HW_VERSION_1: + return GFX_SIZE * 6 + else: + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTLUT_pal256 ' + self.dram.name - - def size(self, f3d): - if not f3d._HW_VERSION_1: - return GFX_SIZE * 6 - else: - return GFX_SIZE * 7 class DPLoadTLUT: - def __init__(self, count, tmemaddr, dram): - self.count = count - self.tmemaddr = tmemaddr - self.dram = dram # pallete object - - def get_ptr_offsets(self, f3d): - return [4] - - def to_binary(self, f3d, segments): - if not f3d._HW_VERSION_1: - return \ - DPSetTextureImage('G_IM_FMT_RGBA', 'G_IM_SIZ_16b', 1, \ - self.dram).to_binary(f3d, segments) + \ - DPTileSync().to_binary(f3d, segments) + \ - DPSetTile('0', '0', 0, self.tmemaddr, f3d.G_TX_LOADTILE, \ - 0, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + \ - DPLoadSync().to_binary(f3d, segments) + \ - DPLoadTLUTCmd(f3d.G_TX_LOADTILE, self.count - 1).to_binary( - f3d, segments) + \ - DPPipeSync().to_binary(f3d, segments) - else: - return _DPLoadTextureBlock(self.dram, self.tmemaddr, \ - f3d.G_IM_FMT_VARS['G_IM_FMT_RGBA'], \ - f3d.G_IM_SIZ_VARS['G_IM_SIZ_16b'], 4, self.count, - 0, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + def __init__(self, count, tmemaddr, dram): + self.count = count + self.tmemaddr = tmemaddr + self.dram = dram # pallete object - def to_c(self, static = True): - header = 'gsDPLoadTLUT(' if static else \ - 'gDPLoadTLUT(glistp++, ' - return header + str(self.count) + ', ' + str(self.tmemaddr) + ', ' + \ - '&' + self.dram.name + ')' + def get_ptr_offsets(self, f3d): + return [4] + + def to_binary(self, f3d, segments): + if not f3d._HW_VERSION_1: + return ( + DPSetTextureImage("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 1, self.dram).to_binary(f3d, segments) + + DPTileSync().to_binary(f3d, segments) + + DPSetTile("0", "0", 0, self.tmemaddr, f3d.G_TX_LOADTILE, 0, 0, 0, 0, 0, 0, 0).to_binary(f3d, segments) + + DPLoadSync().to_binary(f3d, segments) + + DPLoadTLUTCmd(f3d.G_TX_LOADTILE, self.count - 1).to_binary(f3d, segments) + + DPPipeSync().to_binary(f3d, segments) + ) + else: + return _DPLoadTextureBlock( + self.dram, + self.tmemaddr, + f3d.G_IM_FMT_VARS["G_IM_FMT_RGBA"], + f3d.G_IM_SIZ_VARS["G_IM_SIZ_16b"], + 4, + self.count, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ).to_binary(f3d, segments) + + def to_c(self, static=True): + header = "gsDPLoadTLUT(" if static else "gDPLoadTLUT(glistp++, " + return header + str(self.count) + ", " + str(self.tmemaddr) + ", " + "&" + self.dram.name + ")" + + def to_sm64_decomp_s(self): + return "gsDPLoadTLUT " + str(self.count) + ", " + str(self.tmemaddr) + ", " + self.dram.name + + def size(self, f3d): + if not f3d._HW_VERSION_1: + return GFX_SIZE * 6 + else: + return GFX_SIZE * 7 - def to_sm64_decomp_s(self): - return 'gsDPLoadTLUT ' + str(self.count) + ', ' + \ - str(self.tmemaddr) + ', ' + self.dram.name - - def size(self, f3d): - if not f3d._HW_VERSION_1: - return GFX_SIZE * 6 - else: - return GFX_SIZE * 7 # gsDPSetScissor # gsDPSetScissorFrac # gsDPFillRectangle + class DPSetConvert: - def __init__(self, k0, k1, k2, k3, k4, k5): - self.k0 = k0 - self.k1 = k1 - self.k2 = k2 - self.k3 = k3 - self.k4 = k4 - self.k5 = k5 - - def to_binary(self, f3d, segments): - words = (_SHIFTL(f3d.G_SETCONVERT, 24, 8) | \ - _SHIFTL(self.k0, 13, 9) | _SHIFTL(self.k1, 4, 9) | \ - _SHIFTL(self.k2, 5, 4)), (_SHIFTL(self.k2, 27, 5) | \ - _SHIFTL(self.k3, 18, 9) | _SHIFTL(self.k4, 9, 9) | \ - _SHIFTL(self.k5, 0, 9)) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, k0, k1, k2, k3, k4, k5): + self.k0 = k0 + self.k1 = k1 + self.k2 = k2 + self.k3 = k3 + self.k4 = k4 + self.k5 = k5 - def to_c(self, static = True): - header = 'gsDPSetConvert(' if static else 'gDPSetConvert(glistp++, ' - return header + str(self.k0) + ', ' + str(self.k1) + ', ' + \ - str(self.k2) + ', ' + str(self.k3) + ', ' + str(self.k4) + \ - ', ' + str(self.k5) + ')' + def to_binary(self, f3d, segments): + words = ( + _SHIFTL(f3d.G_SETCONVERT, 24, 8) | _SHIFTL(self.k0, 13, 9) | _SHIFTL(self.k1, 4, 9) | _SHIFTL(self.k2, 5, 4) + ), (_SHIFTL(self.k2, 27, 5) | _SHIFTL(self.k3, 18, 9) | _SHIFTL(self.k4, 9, 9) | _SHIFTL(self.k5, 0, 9)) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsDPSetConvert(" if static else "gDPSetConvert(glistp++, " + return ( + header + + str(self.k0) + + ", " + + str(self.k1) + + ", " + + str(self.k2) + + ", " + + str(self.k3) + + ", " + + str(self.k4) + + ", " + + str(self.k5) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetConvert " + + str(self.k0) + + ", " + + str(self.k1) + + ", " + + str(self.k2) + + ", " + + str(self.k3) + + ", " + + str(self.k4) + + ", " + + str(self.k5) + ) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetConvert ' + str(self.k0) + ', ' + str(self.k1) + ', ' + \ - str(self.k2) + ', ' + str(self.k3) + ', ' + str(self.k4) + \ - ', ' + str(self.k5) - - def size(self, f3d): - return GFX_SIZE class DPSetKeyR: - def __init__(self, cR, sR, wR): - self.cR = cR - self.sR = sR - self.wR = wR - - def to_binary(self, f3d, segments): - words = _SHIFTL(f3d.G_SETKEYR, 24, 8), \ - _SHIFTL(self.wR, 16, 12) | _SHIFTL(self.cR, 8, 8) | \ - _SHIFTL(self.sR, 0, 8) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, cR, sR, wR): + self.cR = cR + self.sR = sR + self.wR = wR - def to_c(self, static = True): - header = 'gsDPSetKeyR(' if static else 'gDPSetKeyR(glistp++, ' - return header + str(self.cR) + ', ' + str(self.sR) + ', ' + \ - str(self.wR) + ')' + def to_binary(self, f3d, segments): + words = _SHIFTL(f3d.G_SETKEYR, 24, 8), _SHIFTL(self.wR, 16, 12) | _SHIFTL(self.cR, 8, 8) | _SHIFTL( + self.sR, 0, 8 + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + + def to_c(self, static=True): + header = "gsDPSetKeyR(" if static else "gDPSetKeyR(glistp++, " + return header + str(self.cR) + ", " + str(self.sR) + ", " + str(self.wR) + ")" + + def to_sm64_decomp_s(self): + return "gsDPSetKeyR " + str(self.cR) + ", " + str(self.sR) + ", " + str(self.wR) + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPSetKeyR ' + str(self.cR) + ', ' + str(self.sR) + ', ' + \ - str(self.wR) - - def size(self, f3d): - return GFX_SIZE class DPSetKeyGB: - def __init__(self, cG, sG, wG, cB, sB, wB): - self.cG = cG - self.sG = sG - self.wG = wG - self.cB = cB - self.sB = sB - self.wB = wB - - def to_binary(self, f3d, segments): - words = (_SHIFTL(f3d.G_SETKEYGB, 24, 8) | _SHIFTL(self.wG, 12, 12) |\ - _SHIFTL(self.wB, 0, 12)), (_SHIFTL(self.cG, 24, 8) | \ - _SHIFTL(self.sG, 16, 8) | _SHIFTL(self.cB, 8, 8) | \ - _SHIFTL(self.sB, 0, 8)) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + def __init__(self, cG, sG, wG, cB, sB, wB): + self.cG = cG + self.sG = sG + self.wG = wG + self.cB = cB + self.sB = sB + self.wB = wB - def to_c(self, static = True): - header = 'gsDPSetKeyGB(' if static else 'gDPSetKeyGB(glistp++, ' - return header + str(self.cG) + ', ' + str(self.sG) + ', ' + \ - str(self.wG) + ', ' + str(self.cB) + ', ' + str(self.sB) + \ - ', ' + str(self.wB) + ')' + def to_binary(self, f3d, segments): + words = (_SHIFTL(f3d.G_SETKEYGB, 24, 8) | _SHIFTL(self.wG, 12, 12) | _SHIFTL(self.wB, 0, 12)), ( + _SHIFTL(self.cG, 24, 8) | _SHIFTL(self.sG, 16, 8) | _SHIFTL(self.cB, 8, 8) | _SHIFTL(self.sB, 0, 8) + ) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") - def to_sm64_decomp_s(self): - return 'gsDPSetKeyGB ' + str(self.cG) + ', ' + str(self.sG) + ', ' + \ - str(self.wG) + ', ' + str(self.cB) + ', ' + str(self.sB) + \ - ', ' + str(self.wB) + def to_c(self, static=True): + header = "gsDPSetKeyGB(" if static else "gDPSetKeyGB(glistp++, " + return ( + header + + str(self.cG) + + ", " + + str(self.sG) + + ", " + + str(self.wG) + + ", " + + str(self.cB) + + ", " + + str(self.sB) + + ", " + + str(self.wB) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsDPSetKeyGB " + + str(self.cG) + + ", " + + str(self.sG) + + ", " + + str(self.wG) + + ", " + + str(self.cB) + + ", " + + str(self.sB) + + ", " + + str(self.wB) + ) + + def size(self, f3d): + return GFX_SIZE - def size(self, f3d): - return GFX_SIZE def gsDPNoParam(cmd): - words = _SHIFTL(cmd, 24, 8), 0 - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(cmd, 24, 8), 0 + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + def gsDPParam(cmd, param): - words = _SHIFTL(cmd, 24, 8), (param) - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') + words = _SHIFTL(cmd, 24, 8), (param) + return words[0].to_bytes(4, "big") + words[1].to_bytes(4, "big") + # gsDPTextureRectangle # gsDPTextureRectangleFlip + class SPTextureRectangle: - def __init__(self, xl, yl, xh, yh, tile, s, t, dsdx = 4 << 10, dtdy = 1 << 10): - self.xl = xl - self.yl = yl - self.xh = xh - self.yh = yh - self.tile = tile - self.s = s - self.t = t - self.dsdx = dsdx - self.dtdy = dtdy - - def to_binary(self, f3d, segments): - words = (_SHIFTL(f3d.G_TEXRECT, 24, 8) | _SHIFTL(self.xh, 12, 12) | \ - _SHIFTL(self.yh, 0, 12)), \ - (_SHIFTL(self.tile, 24, 3) | _SHIFTL(self.xl, 12, 12) | \ - _SHIFTL(self.yl, 0, 12)), \ - gsImmp1(f3d.G_RDPHALF_1, (_SHIFTL(self.s, 16, 16) | _SHIFTL(self.t, 0, 16))), \ - gsImmp1(f3d.G_RDPHALF_2, (_SHIFTL(self.dsdx, 16, 16) | _SHIFTL(self.dtdy, 0, 16))) + def __init__(self, xl, yl, xh, yh, tile, s, t, dsdx=4 << 10, dtdy=1 << 10): + self.xl = xl + self.yl = yl + self.xh = xh + self.yh = yh + self.tile = tile + self.s = s + self.t = t + self.dsdx = dsdx + self.dtdy = dtdy - return words[0].to_bytes(4, 'big') + words[1].to_bytes(4, 'big') +\ - words[2].to_bytes(4, 'big') + words[3].to_bytes(4, 'big') + def to_binary(self, f3d, segments): + words = ( + (_SHIFTL(f3d.G_TEXRECT, 24, 8) | _SHIFTL(self.xh, 12, 12) | _SHIFTL(self.yh, 0, 12)), + (_SHIFTL(self.tile, 24, 3) | _SHIFTL(self.xl, 12, 12) | _SHIFTL(self.yl, 0, 12)), + gsImmp1(f3d.G_RDPHALF_1, (_SHIFTL(self.s, 16, 16) | _SHIFTL(self.t, 0, 16))), + gsImmp1(f3d.G_RDPHALF_2, (_SHIFTL(self.dsdx, 16, 16) | _SHIFTL(self.dtdy, 0, 16))), + ) - def to_c(self, static = True): - header = 'gsSPTextureRectangle(' if static else 'gSPTextureRectangle(glistp++, ' - return header + str(self.xl) + ', ' + str(self.yl) + ', ' + \ - str(self.xh) + ', ' + str(self.yh) + ', ' + str(self.tile) + \ - ', ' + str(self.s) + ', ' + str(self.t) + ', ' + str(self.dsdx) + ', ' + str(self.dtdy) + ')' + return ( + words[0].to_bytes(4, "big") + + words[1].to_bytes(4, "big") + + words[2].to_bytes(4, "big") + + words[3].to_bytes(4, "big") + ) - def to_sm64_decomp_s(self): - return 'gsSPTextureRectangle ' + str(self.xl) + ', ' + str(self.yl) + ', ' + \ - str(self.xh) + ', ' + str(self.yh) + ', ' + str(self.tile) + \ - ', ' + str(self.s) + ', ' + str(self.t) + ', ' + str(self.dsdx) + ', ' + str(self.dtdy) + def to_c(self, static=True): + header = "gsSPTextureRectangle(" if static else "gSPTextureRectangle(glistp++, " + return ( + header + + str(self.xl) + + ", " + + str(self.yl) + + ", " + + str(self.xh) + + ", " + + str(self.yh) + + ", " + + str(self.tile) + + ", " + + str(self.s) + + ", " + + str(self.t) + + ", " + + str(self.dsdx) + + ", " + + str(self.dtdy) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsSPTextureRectangle " + + str(self.xl) + + ", " + + str(self.yl) + + ", " + + str(self.xh) + + ", " + + str(self.yh) + + ", " + + str(self.tile) + + ", " + + str(self.s) + + ", " + + str(self.t) + + ", " + + str(self.dsdx) + + ", " + + str(self.dtdy) + ) + + def size(self, f3d): + return GFX_SIZE * 2 - def size(self, f3d): - return GFX_SIZE * 2 class SPScisTextureRectangle: - def __init__(self, xl, yl, xh, yh, tile, s, t, dsdx = 4 << 10, dtdy = 1 << 10): - self.xl = xl - self.yl = yl - self.xh = xh - self.yh = yh - self.tile = tile - self.s = s - self.t = t - self.dsdx = dsdx - self.dtdy = dtdy - - def to_binary(self, f3d, segments): - raise PluginError("SPScisTextureRectangle not implemented for binary.") + def __init__(self, xl, yl, xh, yh, tile, s, t, dsdx=4 << 10, dtdy=1 << 10): + self.xl = xl + self.yl = yl + self.xh = xh + self.yh = yh + self.tile = tile + self.s = s + self.t = t + self.dsdx = dsdx + self.dtdy = dtdy - def to_c(self, static = True): - if static: - raise PluginError("SPScisTextureRectangle is dynamic only.") - header = 'gSPScisTextureRectangle(glistp++, ' - return header + str(self.xl) + ', ' + str(self.yl) + ', ' + \ - str(self.xh) + ', ' + str(self.yh) + ', ' + str(self.tile) + \ - ', ' + str(self.s) + ', ' + str(self.t) + ', ' + str(self.dsdx) + ', ' + str(self.dtdy) + ')' + def to_binary(self, f3d, segments): + raise PluginError("SPScisTextureRectangle not implemented for binary.") - def to_sm64_decomp_s(self): - return 'gsSPScisTextureRectangle ' + str(self.xl) + ', ' + str(self.yl) + ', ' + \ - str(self.xh) + ', ' + str(self.yh) + ', ' + str(self.tile) + \ - ', ' + str(self.s) + ', ' + str(self.t) + ', ' + str(self.dsdx) + ', ' + str(self.dtdy) + def to_c(self, static=True): + if static: + raise PluginError("SPScisTextureRectangle is dynamic only.") + header = "gSPScisTextureRectangle(glistp++, " + return ( + header + + str(self.xl) + + ", " + + str(self.yl) + + ", " + + str(self.xh) + + ", " + + str(self.yh) + + ", " + + str(self.tile) + + ", " + + str(self.s) + + ", " + + str(self.t) + + ", " + + str(self.dsdx) + + ", " + + str(self.dtdy) + + ")" + ) + + def to_sm64_decomp_s(self): + return ( + "gsSPScisTextureRectangle " + + str(self.xl) + + ", " + + str(self.yl) + + ", " + + str(self.xh) + + ", " + + str(self.yh) + + ", " + + str(self.tile) + + ", " + + str(self.s) + + ", " + + str(self.t) + + ", " + + str(self.dsdx) + + ", " + + str(self.dtdy) + ) + + def size(self, f3d): + return GFX_SIZE * 2 - def size(self, f3d): - return GFX_SIZE * 2 # gsSPTextureRectangleFlip # gsDPWord + class DPFullSync: - def __init__(self): - pass - - def to_binary(self, f3d, segments): - return gsDPNoParam(f3d.G_RDPFULLSYNC) + def __init__(self): + pass - def to_c(self, static = True): - return 'gsDPFullSync()' if static else 'gDPFullSync(glistp++)' + def to_binary(self, f3d, segments): + return gsDPNoParam(f3d.G_RDPFULLSYNC) + + def to_c(self, static=True): + return "gsDPFullSync()" if static else "gDPFullSync(glistp++)" + + def to_sm64_decomp_s(self): + return "gsDPFullSync" + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPFullSync' - - def size(self, f3d): - return GFX_SIZE class DPTileSync: - def __init__(self): - pass - - def to_binary(self, f3d, segments): - return gsDPNoParam(f3d.G_RDPTILESYNC) + def __init__(self): + pass + + def to_binary(self, f3d, segments): + return gsDPNoParam(f3d.G_RDPTILESYNC) + + def to_c(self, static=True): + return "gsDPTileSync()" if static else "gDPTileSync(glistp++)" + + def to_sm64_decomp_s(self): + return "gsDPTileSync" + + def size(self, f3d): + return GFX_SIZE - def to_c(self, static = True): - return 'gsDPTileSync()' if static else 'gDPTileSync(glistp++)' - def to_sm64_decomp_s(self): - return 'gsDPTileSync' - - def size(self, f3d): - return GFX_SIZE - class DPPipeSync: - def __init__(self): - pass - - def to_binary(self, f3d, segments): - return gsDPNoParam(f3d.G_RDPPIPESYNC) + def __init__(self): + pass - def to_c(self, static = True): - return 'gsDPPipeSync()' if static else 'gDPPipeSync(glistp++)' + def to_binary(self, f3d, segments): + return gsDPNoParam(f3d.G_RDPPIPESYNC) + + def to_c(self, static=True): + return "gsDPPipeSync()" if static else "gDPPipeSync(glistp++)" + + def to_sm64_decomp_s(self): + return "gsDPPipeSync" + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPPipeSync' - - def size(self, f3d): - return GFX_SIZE class DPLoadSync: - def __init__(self): - pass - - def to_binary(self, f3d, segments): - return gsDPNoParam(f3d.G_RDPLOADSYNC) + def __init__(self): + pass - def to_c(self, static = True): - return 'gsDPLoadSync()' if static else 'gDPLoadSync(glistp++)' + def to_binary(self, f3d, segments): + return gsDPNoParam(f3d.G_RDPLOADSYNC) + + def to_c(self, static=True): + return "gsDPLoadSync()" if static else "gDPLoadSync(glistp++)" + + def to_sm64_decomp_s(self): + return "gsDPLoadSync" + + def size(self, f3d): + return GFX_SIZE - def to_sm64_decomp_s(self): - return 'gsDPLoadSync' - - def size(self, f3d): - return GFX_SIZE F3DClassesWithPointers = [ - SPVertex, - SPDisplayList, - SPViewport, - SPBranchList, - SPLight, - SPSetLights, - SPLookAt, - DPSetTextureImage, - DPLoadTextureBlock, - DPLoadTextureBlockYuv, - _DPLoadTextureBlock, - DPLoadTextureBlock_4b, - DPLoadTextureTile, - DPLoadTextureTile_4b, - DPLoadTLUT_pal16, - DPLoadTLUT_pal256, - DPLoadTLUT, + SPVertex, + SPDisplayList, + SPViewport, + SPBranchList, + SPLight, + SPSetLights, + SPLookAt, + DPSetTextureImage, + DPLoadTextureBlock, + DPLoadTextureBlockYuv, + _DPLoadTextureBlock, + DPLoadTextureBlock_4b, + DPLoadTextureTile, + DPLoadTextureTile_4b, + DPLoadTLUT_pal16, + DPLoadTLUT_pal256, + DPLoadTLUT, ] diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index 9b41ac2..21c554e 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -18,2275 +18,2375 @@ from ..utility import * # env color bitSizeDict = { - 'G_IM_SIZ_4b' : 4, - 'G_IM_SIZ_8b' : 8, - 'G_IM_SIZ_16b' : 16, - 'G_IM_SIZ_32b' : 32, + "G_IM_SIZ_4b": 4, + "G_IM_SIZ_8b": 8, + "G_IM_SIZ_16b": 16, + "G_IM_SIZ_32b": 32, } texBitSizeOf = { - 'I4' : 'G_IM_SIZ_4b', - 'IA4' : 'G_IM_SIZ_4b', - 'CI4' : 'G_IM_SIZ_4b', - 'I8' : 'G_IM_SIZ_8b', - 'IA8' : 'G_IM_SIZ_8b', - 'CI8' : 'G_IM_SIZ_8b', - 'RGBA16' : 'G_IM_SIZ_16b', - 'IA16' : 'G_IM_SIZ_16b', - 'YUV16' : 'G_IM_SIZ_16b', - 'RGBA32' : 'G_IM_SIZ_32b', + "I4": "G_IM_SIZ_4b", + "IA4": "G_IM_SIZ_4b", + "CI4": "G_IM_SIZ_4b", + "I8": "G_IM_SIZ_8b", + "IA8": "G_IM_SIZ_8b", + "CI8": "G_IM_SIZ_8b", + "RGBA16": "G_IM_SIZ_16b", + "IA16": "G_IM_SIZ_16b", + "YUV16": "G_IM_SIZ_16b", + "RGBA32": "G_IM_SIZ_32b", } texFormatOf = { - 'I4' : 'G_IM_FMT_I', - 'IA4' : 'G_IM_FMT_IA', - 'CI4' : 'G_IM_FMT_CI', - 'I8' : 'G_IM_FMT_I', - 'IA8' : 'G_IM_FMT_IA', - 'CI8' : 'G_IM_FMT_CI', - 'RGBA16' : 'G_IM_FMT_RGBA', - 'IA16' : 'G_IM_FMT_IA', - 'YUV16' : 'G_IM_FMT_YUV', - 'RGBA32' : 'G_IM_FMT_RGBA', + "I4": "G_IM_FMT_I", + "IA4": "G_IM_FMT_IA", + "CI4": "G_IM_FMT_CI", + "I8": "G_IM_FMT_I", + "IA8": "G_IM_FMT_IA", + "CI8": "G_IM_FMT_CI", + "RGBA16": "G_IM_FMT_RGBA", + "IA16": "G_IM_FMT_IA", + "YUV16": "G_IM_FMT_YUV", + "RGBA32": "G_IM_FMT_RGBA", } sm64EnumDrawLayers = [ - ('0', 'Background (0x00)', 'Background'), - ('1', 'Opaque (0x01)', 'Opaque'), - ('2', 'Opaque Decal (0x02)', 'Opaque Decal'), - ('3', 'Opaque Intersecting (0x03)', 'Opaque Intersecting'), - ('4', 'Cutout (0x04)', 'Cutout'), - ('5', 'Transparent (0x05)', 'Transparent'), - ('6', 'Transparent Decal (0x06)', 'Transparent Decal'), - ('7', 'Transparent Intersecting (0x07)', 'Transparent Intersecting'), + ("0", "Background (0x00)", "Background"), + ("1", "Opaque (0x01)", "Opaque"), + ("2", "Opaque Decal (0x02)", "Opaque Decal"), + ("3", "Opaque Intersecting (0x03)", "Opaque Intersecting"), + ("4", "Cutout (0x04)", "Cutout"), + ("5", "Transparent (0x05)", "Transparent"), + ("6", "Transparent Decal (0x06)", "Transparent Decal"), + ("7", "Transparent Intersecting (0x07)", "Transparent Intersecting"), ] ootEnumDrawLayers = [ - ('Opaque', 'Opaque', 'Opaque'), - ('Transparent', 'Transparent', 'Transparent'), - ('Overlay', 'Overlay', 'Overlay'), + ("Opaque", "Opaque", "Opaque"), + ("Transparent", "Transparent", "Transparent"), + ("Overlay", "Overlay", "Overlay"), ] drawLayerSM64toOOT = { - '0' : "Opaque", - '1' : "Opaque", - '2' : "Opaque", - '3' : "Opaque", - '4' : "Opaque", - '5' : "Transparent", - '6' : "Transparent", - '7' : "Transparent", + "0": "Opaque", + "1": "Opaque", + "2": "Opaque", + "3": "Opaque", + "4": "Opaque", + "5": "Transparent", + "6": "Transparent", + "7": "Transparent", } drawLayerOOTtoSM64 = { - "Opaque" : '1', - "Transparent" : '5', - "Overlay" : '1', + "Opaque": "1", + "Transparent": "5", + "Overlay": "1", } -#drawLayerOOTAlpha = { -# "Opaque" : "OPAQUE", -# "Transparent" : "BLEND", -# "Overlay" : 'CLIP', -#} +# drawLayerOOTAlpha = { +# "Opaque" : "OPAQUE", +# "Transparent" : "BLEND", +# "Overlay" : 'CLIP', +# } drawLayerSM64Alpha = { - '0' : "CLIP", - '1' : "CLIP", - '2' : "CLIP", - '3' : "CLIP", - '4' : "CLIP", - '5' : "BLEND", - '6' : "BLEND", - '7' : "BLEND", + "0": "CLIP", + "1": "CLIP", + "2": "CLIP", + "3": "CLIP", + "4": "CLIP", + "5": "BLEND", + "6": "BLEND", + "7": "BLEND", } enumF3DMenu = [ - ("Combiner", "Combiner", "Combiner"), - ("Sources", "Sources", "Sources"), - ("Geo", "Geo", "Geo"), - ("Upper", "Upper", "Upper"), - ("Lower", "Lower", "Lower"), + ("Combiner", "Combiner", "Combiner"), + ("Sources", "Sources", "Sources"), + ("Geo", "Geo", "Geo"), + ("Upper", "Upper", "Upper"), + ("Lower", "Lower", "Lower"), ] enumF3DSource = [ - ("None", "None", "None"), - ('Texture', 'Texture', 'Texture'), - ('Tile Size', 'Tile Size', 'Tile Size'), - ('Primitive', 'Primitive', 'Primitive'), - ('Environment', 'Environment', 'Environment'), - ('Shade', 'Shade', 'Shade'), - ('Key', 'Key', 'Key'), - ('LOD Fraction', 'LOD Fraction', 'LOD Fraction'), - ('Convert', 'Convert', 'Convert'), + ("None", "None", "None"), + ("Texture", "Texture", "Texture"), + ("Tile Size", "Tile Size", "Tile Size"), + ("Primitive", "Primitive", "Primitive"), + ("Environment", "Environment", "Environment"), + ("Shade", "Shade", "Shade"), + ("Key", "Key", "Key"), + ("LOD Fraction", "LOD Fraction", "LOD Fraction"), + ("Convert", "Convert", "Convert"), ] defaultMaterialPresets = { - "Shaded Solid" : { - "SM64" : "Shaded Solid", - "OOT" : "oot_shaded_solid" - }, - "Shaded Texture" : { - "SM64" : "Shaded Texture", - "OOT" : "oot_shaded_texture" - } + "Shaded Solid": {"SM64": "Shaded Solid", "OOT": "oot_shaded_solid"}, + "Shaded Texture": {"SM64": "Shaded Texture", "OOT": "oot_shaded_texture"}, } + def getDefaultMaterialPreset(category): - game = bpy.context.scene.gameEditorMode - if game in defaultMaterialPresets[category]: - return defaultMaterialPresets[category][game] - else: - return "Shaded Solid" + game = bpy.context.scene.gameEditorMode + if game in defaultMaterialPresets[category]: + return defaultMaterialPresets[category][game] + else: + return "Shaded Solid" + def update_draw_layer(self, context): - if hasattr(context, 'material_slot') and context.material_slot is not None: - material = context.material_slot.material # Handles case of texture property groups - if not material.is_f3d or material.f3d_update_flag: - return + if hasattr(context, "material_slot") and context.material_slot is not None: + material = context.material_slot.material # Handles case of texture property groups + if not material.is_f3d or material.f3d_update_flag: + return + + material.f3d_update_flag = True + if material.mat_ver > 3: + drawLayer = material.f3d_mat.draw_layer + if context.scene.gameEditorMode == "SM64": + drawLayer.oot = drawLayerSM64toOOT[drawLayer.sm64] + elif context.scene.gameEditorMode == "OOT": + if material.f3d_mat.draw_layer.oot == "Opaque": + if int(material.f3d_mat.draw_layer.sm64) > 4: + material.f3d_mat.draw_layer.sm64 = "1" + elif material.f3d_mat.draw_layer.oot == "Transparent": + if int(material.f3d_mat.draw_layer.sm64) < 5: + material.f3d_mat.draw_layer.sm64 = "5" + material.f3d_mat.presetName = "Custom" + update_blend_method(material, context) + material.f3d_update_flag = False - material.f3d_update_flag = True - if material.mat_ver > 3: - drawLayer = material.f3d_mat.draw_layer - if context.scene.gameEditorMode == "SM64": - drawLayer.oot = drawLayerSM64toOOT[drawLayer.sm64] - elif context.scene.gameEditorMode == "OOT": - if material.f3d_mat.draw_layer.oot == "Opaque": - if int(material.f3d_mat.draw_layer.sm64) > 4: - material.f3d_mat.draw_layer.sm64 = '1' - elif material.f3d_mat.draw_layer.oot == "Transparent": - if int(material.f3d_mat.draw_layer.sm64) < 5: - material.f3d_mat.draw_layer.sm64 = '5' - material.f3d_mat.presetName = "Custom" - update_blend_method(material, context) - material.f3d_update_flag = False def update_blend_method(material, context): - if material.mat_ver > 3: - drawLayer = material.f3d_mat.draw_layer - if context.scene.gameEditorMode == "OOT": - if drawLayer.oot == "Opaque" or drawLayer.oot == "Overlay": - f3dMat = material.f3d_mat - if not f3dMat.rdp_settings.rendermode_advanced_enabled and\ - "TEX_EDGE" not in f3dMat.rdp_settings.rendermode_preset_cycle_1 and\ - ("TEX_EDGE" not in f3dMat.rdp_settings.rendermode_preset_cycle_2 or\ - f3dMat.rdp_settings.g_mdsft_cycletype != 'G_CYC_2CYCLE'): - material.blend_method = "OPAQUE" - else: - material.blend_method = "CLIP" - else: - material.blend_method = "BLEND" - elif context.scene.gameEditorMode == "SM64": - material.blend_method = drawLayerSM64Alpha[drawLayer.sm64] + if material.mat_ver > 3: + drawLayer = material.f3d_mat.draw_layer + if context.scene.gameEditorMode == "OOT": + if drawLayer.oot == "Opaque" or drawLayer.oot == "Overlay": + f3dMat = material.f3d_mat + if ( + not f3dMat.rdp_settings.rendermode_advanced_enabled + and "TEX_EDGE" not in f3dMat.rdp_settings.rendermode_preset_cycle_1 + and ( + "TEX_EDGE" not in f3dMat.rdp_settings.rendermode_preset_cycle_2 + or f3dMat.rdp_settings.g_mdsft_cycletype != "G_CYC_2CYCLE" + ) + ): + material.blend_method = "OPAQUE" + else: + material.blend_method = "CLIP" + else: + material.blend_method = "BLEND" + elif context.scene.gameEditorMode == "SM64": + material.blend_method = drawLayerSM64Alpha[drawLayer.sm64] + class DrawLayerProperty(bpy.types.PropertyGroup): - sm64 : bpy.props.EnumProperty(items = sm64EnumDrawLayers, default = "1", update = update_draw_layer) - oot : bpy.props.EnumProperty(items = ootEnumDrawLayers, default = "Opaque", update = update_draw_layer) + sm64: bpy.props.EnumProperty(items=sm64EnumDrawLayers, default="1", update=update_draw_layer) + oot: bpy.props.EnumProperty(items=ootEnumDrawLayers, default="Opaque", update=update_draw_layer) + def getTmemWordUsage(texFormat, width, height): - texelsPerLine = 64 / bitSizeDict[texBitSizeOf[texFormat]] - return math.ceil(width / texelsPerLine) * height + texelsPerLine = 64 / bitSizeDict[texBitSizeOf[texFormat]] + return math.ceil(width / texelsPerLine) * height + def getTmemMax(texFormat): - return 4096 if texFormat[:2] != 'CI' else 2048 + return 4096 if texFormat[:2] != "CI" else 2048 + def F3DOrganizeLights(self, context): - # Flag to prevent infinite recursion on update callback - if not hasattr(context, "material") or context.material.f3d_update_flag: - return - context.material.f3d_update_flag = True - lightList = [] - if self.f3d_light1 is not None: lightList.append(self.f3d_light1) - if self.f3d_light2 is not None: lightList.append(self.f3d_light2) - if self.f3d_light3 is not None: lightList.append(self.f3d_light3) - if self.f3d_light4 is not None: lightList.append(self.f3d_light4) - if self.f3d_light5 is not None: lightList.append(self.f3d_light5) - if self.f3d_light5 is not None: lightList.append(self.f3d_light6) - if self.f3d_light6 is not None: lightList.append(self.f3d_light7) + # Flag to prevent infinite recursion on update callback + if not hasattr(context, "material") or context.material.f3d_update_flag: + return + context.material.f3d_update_flag = True + lightList = [] + if self.f3d_light1 is not None: + lightList.append(self.f3d_light1) + if self.f3d_light2 is not None: + lightList.append(self.f3d_light2) + if self.f3d_light3 is not None: + lightList.append(self.f3d_light3) + if self.f3d_light4 is not None: + lightList.append(self.f3d_light4) + if self.f3d_light5 is not None: + lightList.append(self.f3d_light5) + if self.f3d_light5 is not None: + lightList.append(self.f3d_light6) + if self.f3d_light6 is not None: + lightList.append(self.f3d_light7) + + self.f3d_light1 = lightList[0] if len(lightList) > 0 else None + self.f3d_light2 = lightList[1] if len(lightList) > 1 else None + self.f3d_light3 = lightList[2] if len(lightList) > 2 else None + self.f3d_light4 = lightList[3] if len(lightList) > 3 else None + self.f3d_light5 = lightList[4] if len(lightList) > 4 else None + self.f3d_light6 = lightList[5] if len(lightList) > 5 else None + self.f3d_light7 = lightList[6] if len(lightList) > 6 else None + context.material.f3d_update_flag = False - self.f3d_light1 = lightList[0] if len(lightList) > 0 else None - self.f3d_light2 = lightList[1] if len(lightList) > 1 else None - self.f3d_light3 = lightList[2] if len(lightList) > 2 else None - self.f3d_light4 = lightList[3] if len(lightList) > 3 else None - self.f3d_light5 = lightList[4] if len(lightList) > 4 else None - self.f3d_light6 = lightList[5] if len(lightList) > 5 else None - self.f3d_light7 = lightList[6] if len(lightList) > 6 else None - context.material.f3d_update_flag = False def combiner_uses(material, checkList, is2Cycle): - display = False - for value in checkList: - if value[:5] == "TEXEL": - value1 = value - value2 = value.replace("0", "1") if "0" in value else value.replace("1", "0") - else: - value1 = value - value2 = value + display = False + for value in checkList: + if value[:5] == "TEXEL": + value1 = value + value2 = value.replace("0", "1") if "0" in value else value.replace("1", "0") + else: + value1 = value + value2 = value - display |= material.combiner1.A == value1 - if is2Cycle: - display |= material.combiner2.A == value2 + display |= material.combiner1.A == value1 + if is2Cycle: + display |= material.combiner2.A == value2 - display |= material.combiner1.B == value1 - if is2Cycle: - display |= material.combiner2.B == value2 + display |= material.combiner1.B == value1 + if is2Cycle: + display |= material.combiner2.B == value2 - display |= material.combiner1.C == value1 - if is2Cycle: - display |= material.combiner2.C == value2 + display |= material.combiner1.C == value1 + if is2Cycle: + display |= material.combiner2.C == value2 - display |= material.combiner1.D == value1 - if is2Cycle: - display |= material.combiner2.D == value2 + display |= material.combiner1.D == value1 + if is2Cycle: + display |= material.combiner2.D == value2 + display |= material.combiner1.A_alpha == value1 + if is2Cycle: + display |= material.combiner2.A_alpha == value2 - display |= material.combiner1.A_alpha == value1 - if is2Cycle: - display |= material.combiner2.A_alpha == value2 + display |= material.combiner1.B_alpha == value1 + if is2Cycle: + display |= material.combiner2.B_alpha == value2 - display |= material.combiner1.B_alpha == value1 - if is2Cycle: - display |= material.combiner2.B_alpha == value2 + display |= material.combiner1.C_alpha == value1 + if is2Cycle: + display |= material.combiner2.C_alpha == value2 - display |= material.combiner1.C_alpha == value1 - if is2Cycle: - display |= material.combiner2.C_alpha == value2 + display |= material.combiner1.D_alpha == value1 + if is2Cycle: + display |= material.combiner2.D_alpha == value2 - display |= material.combiner1.D_alpha == value1 - if is2Cycle: - display |= material.combiner2.D_alpha == value2 + return display - return display def combiner_uses_alpha(material, checkList, is2Cycle): - display = False - for value in checkList: - if value[:5] == "TEXEL": - value1 = value - value2 = value.replace("0", "1") if "0" in value else value.replace("1", "0") - else: - value1 = value - value2 = value + display = False + for value in checkList: + if value[:5] == "TEXEL": + value1 = value + value2 = value.replace("0", "1") if "0" in value else value.replace("1", "0") + else: + value1 = value + value2 = value - display |= material.combiner1.A_alpha == value1 - if is2Cycle: - display |= material.combiner2.A_alpha == value2 + display |= material.combiner1.A_alpha == value1 + if is2Cycle: + display |= material.combiner2.A_alpha == value2 - display |= material.combiner1.B_alpha == value1 - if is2Cycle: - display |= material.combiner2.B_alpha == value2 + display |= material.combiner1.B_alpha == value1 + if is2Cycle: + display |= material.combiner2.B_alpha == value2 - display |= material.combiner1.C_alpha == value1 - if is2Cycle: - display |= material.combiner2.C_alpha == value2 + display |= material.combiner1.C_alpha == value1 + if is2Cycle: + display |= material.combiner2.C_alpha == value2 - display |= material.combiner1.D_alpha == value1 - if is2Cycle: - display |= material.combiner2.D_alpha == value2 + display |= material.combiner1.D_alpha == value1 + if is2Cycle: + display |= material.combiner2.D_alpha == value2 + + return display - return display def all_combiner_uses(material): - useDict = { - 'Texture' : combiner_uses(material, - ['TEXEL0', 'TEXEL0_ALPHA', 'TEXEL1', 'TEXEL1_ALPHA'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), + useDict = { + "Texture": combiner_uses( + material, + ["TEXEL0", "TEXEL0_ALPHA", "TEXEL1", "TEXEL1_ALPHA"], + material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE", + ), + "Texture 0": combiner_uses( + material, ["TEXEL0", "TEXEL0_ALPHA"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ), + "Texture 1": combiner_uses( + material, ["TEXEL1", "TEXEL1_ALPHA"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ), + "Primitive": combiner_uses( + material, + ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], + material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE", + ), + "Environment": combiner_uses( + material, ["ENVIRONMENT", "ENV_ALPHA"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ), + "Shade": combiner_uses( + material, ["SHADE", "SHADE_ALPHA"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ), + "Shade Alpha": combiner_uses_alpha( + material, ["SHADE"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ), + "Key": combiner_uses(material, ["CENTER", "SCALE"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE"), + "LOD Fraction": combiner_uses( + material, ["LOD_FRACTION"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ), + "Convert": combiner_uses(material, ["K4", "K5"], material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE"), + } + return useDict - 'Texture 0' : combiner_uses(material, - ['TEXEL0', 'TEXEL0_ALPHA'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Texture 1' : combiner_uses(material, - ['TEXEL1', 'TEXEL1_ALPHA'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Primitive' : combiner_uses(material, - ['PRIMITIVE', 'PRIMITIVE_ALPHA', 'PRIM_LOD_FRAC'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Environment' : combiner_uses(material, - ['ENVIRONMENT', 'ENV_ALPHA'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Shade' : combiner_uses(material, - ['SHADE', 'SHADE_ALPHA'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Shade Alpha' : combiner_uses_alpha(material, - ['SHADE'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Key' : combiner_uses(material, ['CENTER', 'SCALE'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'LOD Fraction' : combiner_uses(material, ['LOD_FRACTION'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - - 'Convert' : combiner_uses(material, ['K4', 'K5'], - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'), - } - return useDict def ui_geo_mode(settings, dataHolder, layout, useDropdown): - inputGroup = layout.column() - if useDropdown: - inputGroup.prop(dataHolder, 'menu_geo', - text = 'Geometry Mode Settings', - icon = 'TRIA_DOWN' if dataHolder.menu_geo else 'TRIA_RIGHT') - if not useDropdown or dataHolder.menu_geo: - inputGroup.prop(settings, 'g_zbuffer', text = 'Z Buffer') - inputGroup.prop(settings, 'g_shade', text = 'Shading') - inputGroup.prop(settings, 'g_cull_front', text = 'Cull Front') - inputGroup.prop(settings, 'g_cull_back', text = 'Cull Back') - inputGroup.prop(settings, 'g_fog', text = 'Fog') - #if isinstance(dataHolder, bpy.types.Material) and \ - # settings.g_fog: - # material = dataHolder - # fogInfoBox = inputGroup.box() - # fogInfoBox.label(text = 'To enable fog, make sure to do these things:') - # fogInfoBox.label(text = '(Ignore this if you used the preset)') - # fogInfoBox.label(text = 'In Other Mode Upper Settings, set Cycle Type to "2 Cycle".') - # fogInfoBox.label(text = 'Use a combiner that has "Shade Color".') - # fogInfoBox.label(text = 'In Render Settings, check "Set Render Mode".') - # fogInfoBox.label(text = 'Set the first field to "Fog Shade".') - # fogInfoBox.label(text = 'Set the second to the material\'s draw layer, usually "Opaque".') + inputGroup = layout.column() + if useDropdown: + inputGroup.prop( + dataHolder, + "menu_geo", + text="Geometry Mode Settings", + icon="TRIA_DOWN" if dataHolder.menu_geo else "TRIA_RIGHT", + ) + if not useDropdown or dataHolder.menu_geo: + inputGroup.prop(settings, "g_zbuffer", text="Z Buffer") + inputGroup.prop(settings, "g_shade", text="Shading") + inputGroup.prop(settings, "g_cull_front", text="Cull Front") + inputGroup.prop(settings, "g_cull_back", text="Cull Back") + inputGroup.prop(settings, "g_fog", text="Fog") + # if isinstance(dataHolder, bpy.types.Material) and \ + # settings.g_fog: + # material = dataHolder + # fogInfoBox = inputGroup.box() + # fogInfoBox.label(text = 'To enable fog, make sure to do these things:') + # fogInfoBox.label(text = '(Ignore this if you used the preset)') + # fogInfoBox.label(text = 'In Other Mode Upper Settings, set Cycle Type to "2 Cycle".') + # fogInfoBox.label(text = 'Use a combiner that has "Shade Color".') + # fogInfoBox.label(text = 'In Render Settings, check "Set Render Mode".') + # fogInfoBox.label(text = 'Set the first field to "Fog Shade".') + # fogInfoBox.label(text = 'Set the second to the material\'s draw layer, usually "Opaque".') + + inputGroup.prop(settings, "g_lighting", text="Lighting") + inputGroup.prop(settings, "g_tex_gen", text="Texture UV Generate") + inputGroup.prop(settings, "g_tex_gen_linear", text="Texture UV Generate Linear") + inputGroup.prop(settings, "g_shade_smooth", text="Smooth Shading") + if bpy.context.scene.f3d_type == "F3DEX_GBI_2" or bpy.context.scene.f3d_type == "F3DEX_GBI": + inputGroup.prop(settings, "g_clipping", text="Clipping") - inputGroup.prop(settings, 'g_lighting', text = 'Lighting') - inputGroup.prop(settings, 'g_tex_gen', text = 'Texture UV Generate') - inputGroup.prop(settings, 'g_tex_gen_linear', - text = 'Texture UV Generate Linear') - inputGroup.prop(settings, 'g_shade_smooth', text = 'Smooth Shading') - if bpy.context.scene.f3d_type == 'F3DEX_GBI_2' or \ - bpy.context.scene.f3d_type == 'F3DEX_GBI': - inputGroup.prop(settings, 'g_clipping', text = 'Clipping') def ui_upper_mode(settings, dataHolder, layout, useDropdown): - inputGroup = layout.column() - if useDropdown: - inputGroup.prop(dataHolder, 'menu_upper', - text = 'Other Mode Upper Settings', - icon = 'TRIA_DOWN' if dataHolder.menu_upper else 'TRIA_RIGHT') - if not useDropdown or dataHolder.menu_upper: - if not bpy.context.scene.isHWv1: - prop_split(inputGroup, settings, 'g_mdsft_alpha_dither', - 'Alpha Dither') - prop_split(inputGroup, settings, 'g_mdsft_rgb_dither', - 'RGB Dither') - else: - prop_split(inputGroup, settings, 'g_mdsft_color_dither', - 'Color Dither') - prop_split(inputGroup, settings, 'g_mdsft_combkey', 'Chroma Key') - prop_split(inputGroup, settings, 'g_mdsft_textconv', 'Texture Convert') - prop_split(inputGroup, settings, 'g_mdsft_text_filt', 'Texture Filter') - #prop_split(inputGroup, settings, 'g_mdsft_textlut', 'Texture LUT') - prop_split(inputGroup, settings, 'g_mdsft_textlod', 'Texture LOD') - prop_split(inputGroup, settings, 'g_mdsft_textdetail', 'Texture Detail') - prop_split(inputGroup, settings, 'g_mdsft_textpersp', 'Texture Perspective Correction') - prop_split(inputGroup, settings, 'g_mdsft_cycletype', 'Cycle Type') + inputGroup = layout.column() + if useDropdown: + inputGroup.prop( + dataHolder, + "menu_upper", + text="Other Mode Upper Settings", + icon="TRIA_DOWN" if dataHolder.menu_upper else "TRIA_RIGHT", + ) + if not useDropdown or dataHolder.menu_upper: + if not bpy.context.scene.isHWv1: + prop_split(inputGroup, settings, "g_mdsft_alpha_dither", "Alpha Dither") + prop_split(inputGroup, settings, "g_mdsft_rgb_dither", "RGB Dither") + else: + prop_split(inputGroup, settings, "g_mdsft_color_dither", "Color Dither") + prop_split(inputGroup, settings, "g_mdsft_combkey", "Chroma Key") + prop_split(inputGroup, settings, "g_mdsft_textconv", "Texture Convert") + prop_split(inputGroup, settings, "g_mdsft_text_filt", "Texture Filter") + # prop_split(inputGroup, settings, 'g_mdsft_textlut', 'Texture LUT') + prop_split(inputGroup, settings, "g_mdsft_textlod", "Texture LOD") + prop_split(inputGroup, settings, "g_mdsft_textdetail", "Texture Detail") + prop_split(inputGroup, settings, "g_mdsft_textpersp", "Texture Perspective Correction") + prop_split(inputGroup, settings, "g_mdsft_cycletype", "Cycle Type") + + prop_split(inputGroup, settings, "g_mdsft_pipeline", "Pipeline Span Buffer Coherency") - prop_split(inputGroup, settings, 'g_mdsft_pipeline', 'Pipeline Span Buffer Coherency') def ui_lower_mode(settings, dataHolder, layout: bpy.types.UILayout, useDropdown): - inputGroup: bpy.types.UILayout = layout.column() - if useDropdown: - inputGroup.prop(dataHolder, 'menu_lower', - text = 'Other Mode Lower Settings', - icon = 'TRIA_DOWN' if dataHolder.menu_lower else 'TRIA_RIGHT') - if not useDropdown or dataHolder.menu_lower: - prop_split(inputGroup, settings, 'g_mdsft_alpha_compare', 'Alpha Compare') - if settings.g_mdsft_alpha_compare == 'G_AC_THRESHOLD' and settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - inputGroup.label(text = 'Compares blend alpha to *first cycle* combined (CC) alpha.') - prop_split(inputGroup, settings, 'g_mdsft_zsrcsel', 'Z Source Selection') - if settings.g_mdsft_zsrcsel == 'G_ZS_PRIM': - prim_box = inputGroup.box() - prop_split(prim_box, settings.prim_depth, 'z', 'Prim Depth: Z') - prop_split(prim_box, settings.prim_depth, 'dz', 'Prim Depth: Delta Z') - if settings.prim_depth.dz != 0 and settings.prim_depth.dz & (settings.prim_depth.dz - 1): - prim_box.label(text='Warning: DZ should ideally be a power of 2 up to 0x4000', icon='TEXTURE_DATA') + inputGroup: bpy.types.UILayout = layout.column() + if useDropdown: + inputGroup.prop( + dataHolder, + "menu_lower", + text="Other Mode Lower Settings", + icon="TRIA_DOWN" if dataHolder.menu_lower else "TRIA_RIGHT", + ) + if not useDropdown or dataHolder.menu_lower: + prop_split(inputGroup, settings, "g_mdsft_alpha_compare", "Alpha Compare") + if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + inputGroup.label(text="Compares blend alpha to *first cycle* combined (CC) alpha.") + prop_split(inputGroup, settings, "g_mdsft_zsrcsel", "Z Source Selection") + if settings.g_mdsft_zsrcsel == "G_ZS_PRIM": + prim_box = inputGroup.box() + prop_split(prim_box, settings.prim_depth, "z", "Prim Depth: Z") + prop_split(prim_box, settings.prim_depth, "dz", "Prim Depth: Delta Z") + if settings.prim_depth.dz != 0 and settings.prim_depth.dz & (settings.prim_depth.dz - 1): + prim_box.label(text="Warning: DZ should ideally be a power of 2 up to 0x4000", icon="TEXTURE_DATA") + def ui_other(settings, dataHolder, layout, useDropdown): - inputGroup = layout.column() - if useDropdown: - inputGroup.prop(dataHolder, 'menu_other', - text = 'Other Settings', - icon = 'TRIA_DOWN' if dataHolder.menu_other else 'TRIA_RIGHT') - if not useDropdown or dataHolder.menu_other: - clipRatioGroup = inputGroup.column() - prop_split(clipRatioGroup, settings, 'clip_ratio', "Clip Ratio") + inputGroup = layout.column() + if useDropdown: + inputGroup.prop( + dataHolder, "menu_other", text="Other Settings", icon="TRIA_DOWN" if dataHolder.menu_other else "TRIA_RIGHT" + ) + if not useDropdown or dataHolder.menu_other: + clipRatioGroup = inputGroup.column() + prop_split(clipRatioGroup, settings, "clip_ratio", "Clip Ratio") - if isinstance(dataHolder, bpy.types.Material) or isinstance(dataHolder, F3DMaterialProperty): - blend_color_group = layout.row() - prop_input_name = blend_color_group.column() - prop_input = blend_color_group.column() - prop_input_name.prop(dataHolder, 'set_blend', text = "Blend Color") - prop_input.prop(dataHolder, 'blend_color', text='') - prop_input.enabled = dataHolder.set_blend + if isinstance(dataHolder, bpy.types.Material) or isinstance(dataHolder, F3DMaterialProperty): + blend_color_group = layout.row() + prop_input_name = blend_color_group.column() + prop_input = blend_color_group.column() + prop_input_name.prop(dataHolder, "set_blend", text="Blend Color") + prop_input.prop(dataHolder, "blend_color", text="") + prop_input.enabled = dataHolder.set_blend def tmemUsageUI(layout, textureProp): - tex = textureProp.tex - if tex is not None and tex.size[0] > 0 and tex.size[1] > 0: - tmemUsage = getTmemWordUsage(textureProp.tex_format, tex.size[0], tex.size[1]) * 8 - tmemMax = getTmemMax(textureProp.tex_format) - layout.label(text = 'TMEM Usage: ' + str(tmemUsage) + ' / ' + str(tmemMax) + ' bytes') - if tmemUsage > tmemMax: - tmemSizeWarning = layout.box() - tmemSizeWarning.label(text = 'WARNING: Texture size is too large.') - tmemSizeWarning.label(text = 'Note that width will be internally padded to 64 bit boundaries.') + tex = textureProp.tex + if tex is not None and tex.size[0] > 0 and tex.size[1] > 0: + tmemUsage = getTmemWordUsage(textureProp.tex_format, tex.size[0], tex.size[1]) * 8 + tmemMax = getTmemMax(textureProp.tex_format) + layout.label(text="TMEM Usage: " + str(tmemUsage) + " / " + str(tmemMax) + " bytes") + if tmemUsage > tmemMax: + tmemSizeWarning = layout.box() + tmemSizeWarning.label(text="WARNING: Texture size is too large.") + tmemSizeWarning.label(text="Note that width will be internally padded to 64 bit boundaries.") + # UI Assumptions: # shading = 1 # lighting = 1 # cycle type = 1 cycle class F3DPanel(bpy.types.Panel): - bl_label = "F3D Material" - bl_idname = "MATERIAL_PT_F3D_Inspector" - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "material" - bl_options = {'HIDE_HEADER'} - - #def hasNecessaryNodes(self, nodes): - # result = True - # for name, nodeType in caseTemplateDict.items(): - # result &= (name in nodes) - # return result - - def ui_image(self, material, layout, textureProp, name, showCheckBox): - nodes = material.node_tree.nodes - inputGroup = layout.box().column() - - inputGroup.prop(textureProp, 'menu', text = name + ' Properties', - icon = 'TRIA_DOWN' if textureProp.menu else 'TRIA_RIGHT') - if textureProp.menu: - tex = textureProp.tex - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - - if showCheckBox: - prop_input_name.prop(textureProp, 'tex_set', text = "Set Texture") - else: - prop_input_name.label(text = name) - #prop_input.template_image(textureProp, 'tex', - # nodes[name].image_user) - texIndex = name[-1] - - prop_input.prop(textureProp, "use_tex_reference") - if textureProp.use_tex_reference: - prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") - prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") - if textureProp.tex_format[:2] == 'CI': - prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") - prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") - - else: - prop_input.template_ID(textureProp, 'tex', new='image.new', open='image.open', - unlink='image.tex' + texIndex + "_unlink") - prop_input.enabled = textureProp.tex_set - - if tex is not None: - prop_input.label(text = "Size: " + str(tex.size[0]) + " x " + str(tex.size[1])) - - if material.mat_ver > 3 and material.f3d_mat.use_large_textures: - prop_input.label(text = "Large texture mode enabled.") - prop_input.label(text = "Each triangle must fit in a single tile load.") - prop_input.label(text = "UVs must be in the [0, 1024] pixel range.") - prop_input.prop(textureProp, "save_large_texture") - if not textureProp.save_large_texture: - prop_input.label(text = "Most large textures will take forever to convert.", icon = 'PREVIEW_RANGE') - else: - tmemUsageUI(prop_input, textureProp) - - prop_split(prop_input, textureProp, 'tex_format', name = 'Format') - if textureProp.tex_format[:2] == 'CI': - prop_split(prop_input, textureProp, 'ci_format', name = 'CI Format') - - if not (material.mat_ver > 3 and material.f3d_mat.use_large_textures): - texFieldSettings = prop_input.column() - clampSettings = texFieldSettings.row() - clampSettings.prop(textureProp.S, "clamp", text = 'Clamp S') - clampSettings.prop(textureProp.T, "clamp", text = 'Clamp T') - - mirrorSettings = texFieldSettings.row() - mirrorSettings.prop(textureProp.S, "mirror", text = 'Mirror S') - mirrorSettings.prop(textureProp.T, "mirror", text = 'Mirror T') - - prop_input.prop(textureProp, 'autoprop', - text = 'Auto Set Other Properties') - - if not textureProp.autoprop: - mask = prop_input.row() - mask.prop(textureProp.S, "mask", text = 'Mask S') - mask.prop(textureProp.T, "mask", text = 'Mask T') - - shift = prop_input.row() - shift.prop(textureProp.S, "shift", text = 'Shift S') - shift.prop(textureProp.T, "shift", text = 'Shift T') - - low = prop_input.row() - low.prop(textureProp.S, "low", text = 'S Low') - low.prop(textureProp.T, "low", text = 'T Low') - - high = prop_input.row() - high.prop(textureProp.S, "high", text = 'S High') - high.prop(textureProp.T, "high", text = 'T High') - - if tex is not None and tex.size[0] > 0 and tex.size[1] > 0 and \ - (math.log(tex.size[0], 2) % 1 > 0.000001 or \ - math.log(tex.size[1], 2) % 1 > 0.000001): - warnBox = layout.box() - warnBox.label( - text = 'Warning: Texture dimensions are not power of 2.') - warnBox.label(text = 'Wrapping only occurs on power of 2 bounds.') - - def ui_prop(self, material, layout, name, setName, setProp, showCheckBox): - nodes = material.node_tree.nodes - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - if showCheckBox: - prop_input_name.prop(material, setName, text = name) - else: - prop_input_name.label(text = name) - prop_input.prop(nodes[name].outputs[0], 'default_value', text='') - prop_input.enabled = setProp - return inputGroup - - def ui_prop_non_node(self, material, layout, label, name, setName, setProp): - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - prop_input_name.prop(material, setName, text = name) - prop_input.prop(material, name, text='') - prop_input.enabled = setProp - return inputGroup - - def ui_scale(self, material, layout): - inputGroup = layout.row().split(factor = 0.5) - #prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - prop_input.prop(material, 'scale_autoprop', text='Texture Auto Scale') - prop_input_group = inputGroup.row() - prop_input_group.prop(material, 'tex_scale', text='') - prop_input_group.enabled = not material.scale_autoprop - return inputGroup - - def ui_prim(self, material, layout, setName, setProp, showCheckBox): - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - nodes = material.node_tree.nodes - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - if showCheckBox: - prop_input_name.prop(f3dMat, setName, text = 'Primitive Color') - else: - prop_input_name.label(text = 'Primitive Color') - - if material.mat_ver == 4: - prop_input.prop(material.f3d_mat, 'prim_color', text = '') - elif material.mat_ver == 3: - prop_input.prop(nodes['Primitive Color Output'].inputs[0], 'default_value', text='') - else: - prop_input.prop(nodes['Primitive Color'].outputs[0], 'default_value', text='') - - prop_input.prop(f3dMat, 'prim_lod_frac', text='Prim LOD Fraction') - prop_input.prop(f3dMat, 'prim_lod_min', text='Min LOD Ratio') - prop_input.enabled = setProp - return inputGroup - - def ui_env(self, material, layout, showCheckBox): - nodes = material.node_tree.nodes - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - - if material.mat_ver > 3: - if showCheckBox: - prop_input_name.prop(material.f3d_mat, 'set_env', text = 'Environment Color') - else: - prop_input_name.label(text = "Environment Color") - prop_input.prop(material.f3d_mat, 'env_color', text = '') - setProp = material.f3d_mat.set_env - else: - prop_input_name.prop(material, 'set_env', text = 'Environment Color') - prop_input.prop(nodes['Environment Color Output'].inputs[0], 'default_value', text='') - setProp = material.set_env - prop_input.enabled = setProp - return inputGroup - - def ui_chroma(self, material, layout, name, setName, setProp, showCheckBox): - nodes = material.node_tree.nodes - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - if showCheckBox: - prop_input_name.prop(material, setName, text = 'Chroma Key') - else: - prop_input_name.label(text = "Chroma Key") - if material.mat_ver == 4: - prop_input.prop(material.f3d_mat, 'key_center', text = 'Center') - else: - prop_input.prop(nodes['Chroma Key Center'].outputs[0], - 'default_value', text='Center') - prop_input.prop(material, 'key_scale', text = 'Scale') - prop_input.prop(material, 'key_width', text = 'Width') - if material.key_width[0] > 1 or material.key_width[1] > 1 or \ - material.key_width[2] > 1: - layout.box().label(text = \ - "NOTE: Keying is disabled for channels with width > 1.") - prop_input.enabled = setProp - return inputGroup - - def ui_lights(self, material, layout, name, showCheckBox): - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - if showCheckBox: - prop_input_name.prop(material, 'set_lights', text = name) - else: - prop_input_name.label(text = name) - prop_input_name.enabled = material.rdp_settings.g_lighting and \ - material.rdp_settings.g_shade - lightSettings = prop_input.column() - if material.rdp_settings.g_lighting: - if material.use_default_lighting: - lightSettings.prop(material, 'default_light_color', text = '') - else: - lightSettings.prop(material, 'ambient_light_color', text = 'Ambient Color') - - lightSettings.prop_search(material, 'f3d_light1', - bpy.data, 'lights', text = '') - if material.f3d_light1 is not None: - lightSettings.prop_search(material, 'f3d_light2', - bpy.data, 'lights', text = '') - if material.f3d_light2 is not None: - lightSettings.prop_search(material, 'f3d_light3', - bpy.data, 'lights', text = '') - if material.f3d_light3 is not None: - lightSettings.prop_search(material, 'f3d_light4', - bpy.data, 'lights', text = '') - if material.f3d_light4 is not None: - lightSettings.prop_search(material, 'f3d_light5', - bpy.data, 'lights', text = '') - if material.f3d_light5 is not None: - lightSettings.prop_search(material, 'f3d_light6', - bpy.data, 'lights', text = '') - if material.f3d_light6 is not None: - lightSettings.prop_search(material, 'f3d_light7', - bpy.data, 'lights', text = '') - prop_input.prop(material, 'use_default_lighting', text = 'Use Custom Lighting', invert_checkbox = True) - #layout.box().label(text = "Note: Lighting preview is not 100% accurate.") - #layout.box().label(text = "For vertex colors, clear 'Lighting'.") - prop_input.enabled = material.set_lights and \ - material.rdp_settings.g_lighting and \ - material.rdp_settings.g_shade - - return inputGroup - - def ui_convert(self, material, layout, showCheckBox): - inputGroup = layout.row() - prop_input_name = inputGroup.column() - prop_input = inputGroup.column() - if showCheckBox: - prop_input_name.prop(material, 'set_k0_5', text = 'YUV Convert') - else: - prop_input_name.label(text = 'YUV Convert') - - prop_k0 = prop_input.row() - prop_k0.prop(material, 'k0', text='K0') - prop_k0.label(text = str(int(material.k0 * 255))) - - prop_k1 = prop_input.row() - prop_k1.prop(material, 'k1', text='K1') - prop_k1.label(text = str(int(material.k1 * 255))) - - prop_k2 = prop_input.row() - prop_k2.prop(material, 'k2', text='K2') - prop_k2.label(text = str(int(material.k2 * 255))) - - prop_k3 = prop_input.row() - prop_k3.prop(material, 'k3', text='K3') - prop_k3.label(text = str(int(material.k3 * 255))) - - prop_k4 = prop_input.row() - prop_k4.prop(material, 'k4', text='K4') - prop_k4.label(text = str(int(material.k4 * 255))) - - prop_k5 = prop_input.row() - prop_k5.prop(material, 'k5', text='K5') - prop_k5.label(text = str(int(material.k5 * 255))) - - prop_input.enabled = material.set_k0_5 - return inputGroup - - def ui_lower_render_mode(self, material, layout, useDropdown): - # cycle independent - inputGroup = layout.column() - if useDropdown: - inputGroup.prop(material, 'menu_lower_render', - text = 'Render Settings', - icon = 'TRIA_DOWN' if material.menu_lower_render else 'TRIA_RIGHT') - if not useDropdown or material.menu_lower_render: - inputGroup.prop(material.rdp_settings, 'set_rendermode', - text ='Set Render Mode?') - - renderGroup = inputGroup.column() - renderGroup.prop(material.rdp_settings, 'rendermode_advanced_enabled', - text = 'Show Advanced Settings') - if not material.rdp_settings.rendermode_advanced_enabled: - prop_split(renderGroup, material.rdp_settings, - 'rendermode_preset_cycle_1', "Render Mode") - if material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - prop_split(renderGroup, material.rdp_settings, - 'rendermode_preset_cycle_2', "Render Mode Cycle 2") - else: - prop_split(renderGroup, material.rdp_settings, 'aa_en', 'Antialiasing') - prop_split(renderGroup, material.rdp_settings, 'z_cmp', 'Z Testing') - prop_split(renderGroup, material.rdp_settings, 'z_upd', 'Z Writing') - prop_split(renderGroup, material.rdp_settings, 'im_rd', 'IM_RD (?)') - prop_split(renderGroup, material.rdp_settings, 'clr_on_cvg', - 'Color On Coverage') - prop_split(renderGroup, material.rdp_settings, 'cvg_dst', - 'Coverage Destination') - prop_split(renderGroup, material.rdp_settings, 'zmode', 'Z Mode') - prop_split(renderGroup, material.rdp_settings, 'cvg_x_alpha', - 'Multiply Coverage And Alpha') - prop_split(renderGroup, material.rdp_settings, 'alpha_cvg_sel', - 'Use Coverage For Alpha') - prop_split(renderGroup, material.rdp_settings, 'force_bl', 'Force Blending') - - # cycle dependent - (P * A + M - B) / (A + B) - combinerBox = renderGroup.box() - combinerBox.label(text='Blender (Color = (P * A + M * B) / (A + B)') - combinerCol = combinerBox.row() - rowColor = combinerCol.column() - rowAlpha = combinerCol.column() - rowColor.prop(material.rdp_settings, 'blend_p1', text = 'P') - rowColor.prop(material.rdp_settings, 'blend_m1', text = 'M') - rowAlpha.prop(material.rdp_settings, 'blend_a1', text = 'A') - rowAlpha.prop(material.rdp_settings, 'blend_b1', text = 'B') - - if material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - combinerBox2 = renderGroup.box() - combinerBox2.label(text='Blender Cycle 2') - combinerCol2 = combinerBox2.row() - rowColor2 = combinerCol2.column() - rowAlpha2 = combinerCol2.column() - rowColor2.prop(material.rdp_settings, 'blend_p2', text = 'P') - rowColor2.prop(material.rdp_settings, 'blend_m2', text = 'M') - rowAlpha2.prop(material.rdp_settings, 'blend_a2', text = 'A') - rowAlpha2.prop(material.rdp_settings, 'blend_b2', text = 'B') - - renderGroup.enabled = material.rdp_settings.set_rendermode - - def ui_uvCheck(self, layout, context): - if hasattr(context, 'object') and context.object is not None and \ - isinstance(context.object.data, bpy.types.Mesh): - uv_layers = context.object.data.uv_layers - if uv_layers.active is None or uv_layers.active.name != 'UVMap': - uvErrorBox = layout.box() - uvErrorBox.label(text = 'Warning: This mesh\'s active UV layer is not named \"UVMap\".') - uvErrorBox.label(text = 'This will cause incorrect UVs to display.') - - def ui_draw_layer(self, material, layout, context): - if material.mat_ver > 3: - if context.scene.gameEditorMode == 'SM64': - prop_split(layout, material.f3d_mat.draw_layer, "sm64", "Draw Layer") - elif context.scene.gameEditorMode == 'OOT': - prop_split(layout, material.f3d_mat.draw_layer, "oot", "Draw Layer") - - def ui_fog(self, f3dMat, inputCol, showCheckBox): - if f3dMat.rdp_settings.g_fog: - inputGroup = inputCol.column() - if showCheckBox: - inputGroup.prop(f3dMat, 'set_fog', text = 'Set Fog') - if f3dMat.set_fog: - inputGroup.prop(f3dMat, 'use_global_fog', text = 'Use Global Fog (SM64)') - if f3dMat.use_global_fog: - inputGroup.label(text = 'Only applies to levels (area fog settings).', icon = 'INFO') - else: - fogColorGroup = inputGroup.row().split(factor = 0.5) - fogColorGroup.label(text = 'Fog Color') - fogColorGroup.prop(f3dMat, 'fog_color', text = '') - fogPositionGroup = inputGroup.row().split(factor = 0.5) - fogPositionGroup.label(text = 'Fog Range') - fogPositionGroup.prop(f3dMat, 'fog_position', text = '') - - - #inputGroup = inputCol.column() - #inputGroup.prop(f3dMat, 'set_fog', text = 'Set Fog') - #fogInputGroup = inputGroup.column() - #globalFogBox = fogInputGroup.box() - #globalFogBox.prop(f3dMat, 'use_global_fog', text = 'Use Global Fog') - #globalFogInfoBox = globalFogBox.box() - #globalFogInfoBox.label(text = 'Only applies to levels (area fog settings).') - #globalFogInfoBox.label(text = 'Disable this for non-level geolayout/dl exporting.') - #fogGroup = fogInputGroup.column() - #fogColorGroup = fogGroup.row().split(factor = 0.5) - #fogColorGroup.label(text = 'Fog Color') - #fogColorGroup.prop(f3dMat, 'fog_color', text = '') - #fogPositionGroup = fogGroup.row().split(factor = 0.5) - #fogPositionGroup.label(text = 'Fog Range') - #fogPositionGroup.prop(f3dMat, 'fog_position', text = '') - #fogInputGroup.enabled = f3dMat.set_fog - #fogGroup.enabled = not f3dMat.use_global_fog - #inputGroup.box().label(text = 'NOTE: Fog will break with draw layer overrides.') - - def drawVertexColorNotice(self, layout): - noticeBox = layout.box().column() - noticeBox.label( - text = 'There must be two vertex color layers.', icon = 'LINENUMBERS_ON') - noticeBox.label( - text = 'They should be called "Col" and "Alpha".') - - def drawShadeAlphaNotice(self, layout): - layout.box().column().label(text = "There must be a vertex color layer called \"Alpha\".", icon = 'IMAGE_ALPHA') - - def drawCIMultitextureNotice(self, layout): - layout.label(text = 'CI textures will break with multitexturing.', icon = 'LIBRARY_DATA_BROKEN') - - def draw_simple(self, f3dMat, material, layout, context): - self.ui_uvCheck(layout, context) - - inputCol = layout.column() - useDict = all_combiner_uses(f3dMat) - - if not f3dMat.rdp_settings.g_lighting: - self.drawVertexColorNotice(layout) - elif useDict["Shade Alpha"]: - self.drawShadeAlphaNotice(layout) - - useMultitexture = useDict['Texture 0'] and useDict['Texture 1'] and f3dMat.tex0.tex_set and f3dMat.tex1.tex_set - - if useMultitexture and f3dMat.tex0.tex_format[:2] == "CI" or f3dMat.tex1.tex_format[:2] == "CI": - self.drawCIMultitextureNotice(inputCol) - - if useDict['Texture 0'] and f3dMat.tex0.tex_set: - self.ui_image(material, inputCol, f3dMat.tex0, 'Texture 0', False) - - if useDict['Texture 1'] and f3dMat.tex1.tex_set: - self.ui_image(material, inputCol, f3dMat.tex1, 'Texture 1', False) - - if useMultitexture: - inputCol.prop(f3dMat, 'uv_basis', text = 'UV Basis') - - if useDict['Texture']: - if material.mat_ver > 3: - inputCol.prop(f3dMat, 'use_large_textures') - self.ui_scale(f3dMat, inputCol) - - if useDict['Primitive'] and f3dMat.set_prim: - self.ui_prim(material, inputCol, 'set_prim', f3dMat.set_prim, False) - - if useDict['Environment'] and f3dMat.set_env: - if material.mat_ver >= 3: - self.ui_env(material, inputCol, False) - else: - self.ui_prop(material, inputCol, 'Environment Color', 'set_env', material.set_env, False) - - showLightProperty = f3dMat.set_lights and \ - f3dMat.rdp_settings.g_lighting and \ - f3dMat.rdp_settings.g_shade - if useDict['Shade'] and showLightProperty: - self.ui_lights(f3dMat, inputCol, 'Shade Color', False) - - if useDict['Key'] and f3dMat.set_key: - self.ui_chroma(material, inputCol, 'Chroma Key Center', - 'set_key', f3dMat.set_key, False) - - if useDict['Convert'] and f3dMat.set_k0_5: - self.ui_convert(f3dMat, inputCol, False) - - if f3dMat.set_fog: - self.ui_fog(f3dMat, inputCol, False) - - def draw_full(self, f3dMat, material, layout, context): - - layout.row().prop(material, "menu_tab", expand = True) - menuTab = material.menu_tab - useDict = all_combiner_uses(f3dMat) - - if menuTab == "Combiner": - if material.mat_ver > 3: - self.ui_draw_layer(material, layout, context) - - if not f3dMat.rdp_settings.g_lighting: - self.drawVertexColorNotice(layout) - elif useDict["Shade Alpha"]: - self.drawShadeAlphaNotice(layout) - - combinerBox = layout.box() - combinerBox.prop(f3dMat, 'set_combiner', - text = 'Color Combiner (Color = (A - B) * C + D)') - combinerCol = combinerBox.row() - combinerCol.enabled = f3dMat.set_combiner - rowColor = combinerCol.column() - rowAlpha = combinerCol.column() - - rowColor.prop(f3dMat.combiner1, 'A') - rowColor.prop(f3dMat.combiner1, 'B') - rowColor.prop(f3dMat.combiner1, 'C') - rowColor.prop(f3dMat.combiner1, 'D') - rowAlpha.prop(f3dMat.combiner1, 'A_alpha') - rowAlpha.prop(f3dMat.combiner1, 'B_alpha') - rowAlpha.prop(f3dMat.combiner1, 'C_alpha') - rowAlpha.prop(f3dMat.combiner1, 'D_alpha') - if (f3dMat.rdp_settings.g_mdsft_alpha_compare == 'G_AC_THRESHOLD' - and f3dMat.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE'): - combinerBox.label(text = 'First cycle alpha out used for compare threshold.') - - if f3dMat.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - combinerBox2 = layout.box() - combinerBox2.label(text = 'Color Combiner Cycle 2') - combinerBox2.enabled = f3dMat.set_combiner - combinerCol2 = combinerBox2.row() - rowColor2 = combinerCol2.column() - rowAlpha2 = combinerCol2.column() - - rowColor2.prop(f3dMat.combiner2, 'A') - rowColor2.prop(f3dMat.combiner2, 'B') - rowColor2.prop(f3dMat.combiner2, 'C') - rowColor2.prop(f3dMat.combiner2, 'D') - rowAlpha2.prop(f3dMat.combiner2, 'A_alpha') - rowAlpha2.prop(f3dMat.combiner2, 'B_alpha') - rowAlpha2.prop(f3dMat.combiner2, 'C_alpha') - rowAlpha2.prop(f3dMat.combiner2, 'D_alpha') - - combinerBox2.label( - text = 'Note: In second cycle, texture 0 and texture 1 are flipped.') - - #layout.box().label( - # text = 'Note: Alpha preview is not 100% accurate.') - - if menuTab == "Sources": - self.ui_uvCheck(layout, context) - - inputCol = layout.column() - - useMultitexture = useDict['Texture 0'] and useDict['Texture 1'] - - if useMultitexture and f3dMat.tex0.tex_format[:2] == "CI" or f3dMat.tex1.tex_format[:2] == "CI": - self.drawCIMultitextureNotice(inputCol) - - if useDict['Texture 0']: - self.ui_image(material, inputCol, f3dMat.tex0, 'Texture 0', True) - - if useDict['Texture 1']: - self.ui_image(material, inputCol, f3dMat.tex1, 'Texture 1', True) - - if useMultitexture: - inputCol.prop(f3dMat, 'uv_basis', text = 'UV Basis') - - if useDict['Texture']: - if material.mat_ver > 3: - inputCol.prop(f3dMat, 'use_large_textures') - self.ui_scale(f3dMat, inputCol) - - if useDict['Primitive']: - self.ui_prim(material, inputCol, 'set_prim', f3dMat.set_prim, True) - - if useDict['Environment']: - if material.mat_ver >= 3: - self.ui_env(material, inputCol, True) - else: - self.ui_prop(material, inputCol, 'Environment Color', 'set_env', material.set_env, True) - - if useDict['Shade']: - self.ui_lights(f3dMat, inputCol, 'Shade Color', True) - - if useDict['Key']: - self.ui_chroma(material, inputCol, 'Chroma Key Center', - 'set_key', f3dMat.set_key, True) - - if useDict['Convert']: - self.ui_convert(f3dMat, inputCol, True) - - self.ui_fog(f3dMat, inputCol, True) - - if menuTab == "Geo": - ui_geo_mode(f3dMat.rdp_settings, f3dMat, layout, False) - if menuTab == "Upper": - ui_upper_mode(f3dMat.rdp_settings, f3dMat, layout, False) - if menuTab == "Lower": - ui_lower_mode(f3dMat.rdp_settings, f3dMat, layout, False) - #layout.box().label(text = \ - # 'WARNING: Render mode settings not reset after drawing.') - self.ui_lower_render_mode(f3dMat, layout, False) - ui_other(f3dMat.rdp_settings, f3dMat, layout, False) - - # texture convert/LUT controlled by texture settings - # add node support for geo mode settings - def draw(self, context): - layout = self.layout - - layout.operator(CreateFast3DMaterial.bl_idname) - material = context.material - if material is None: - return - elif not(material.use_nodes and material.is_f3d): - layout.label(text="This is not a Fast3D material.") - return - - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - #layout.box().label(text = 'Note: Do not copy paste materials.') - layout.prop(context.scene, 'f3d_simple', text = "Show Simplified UI") - layout = layout.box() - titleCol = layout.column() - titleCol.box().label(text = "F3D Material Inspector") - - if material.mat_ver > 3: - presetCol = layout.column() - split = presetCol.split(factor = 0.33) - split.label(text = 'Preset') - row = split.row(align=True) - row.menu(MATERIAL_MT_f3d_presets.__name__, text=f3dMat.presetName) - row.operator(AddPresetF3D.bl_idname, text="", icon='ZOOM_IN') - row.operator(AddPresetF3D.bl_idname, text="", icon='ZOOM_OUT').remove_active = True - else: - prop_split(layout, material, 'f3d_preset', 'Preset Material') - - if context.scene.f3d_simple and \ - ((material.mat_ver > 3 and f3dMat.presetName != "Custom") or \ - (material.mat_ver <= 3 and f3dMat.f3d_preset != "Custom")): - self.draw_simple(f3dMat, material, layout, context) - else: - if material.mat_ver > 3: - presetCol.prop(context.scene, 'f3dUserPresetsOnly') - self.draw_full(f3dMat, material, layout, context) - -#def ui_procAnimVec(self, procAnimVec, layout, name, vecType): -# layout.prop(procAnimVec, 'menu', text = name, -# icon = 'TRIA_DOWN' if procAnimVec.menu else 'TRIA_RIGHT') -# if procAnimVec.menu: -# box = layout.box() -# self.ui_procAnimField(procAnimVec.x, box, vecType[0]) -# self.ui_procAnimField(procAnimVec.y, box, vecType[1]) -# if len(vecType) > 2: -# self.ui_procAnimField(procAnimVec.z, box, vecType[2]) + bl_label = "F3D Material" + bl_idname = "MATERIAL_PT_F3D_Inspector" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "material" + bl_options = {"HIDE_HEADER"} + + # def hasNecessaryNodes(self, nodes): + # result = True + # for name, nodeType in caseTemplateDict.items(): + # result &= (name in nodes) + # return result + + def ui_image(self, material, layout, textureProp, name, showCheckBox): + nodes = material.node_tree.nodes + inputGroup = layout.box().column() + + inputGroup.prop( + textureProp, "menu", text=name + " Properties", icon="TRIA_DOWN" if textureProp.menu else "TRIA_RIGHT" + ) + if textureProp.menu: + tex = textureProp.tex + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + + if showCheckBox: + prop_input_name.prop(textureProp, "tex_set", text="Set Texture") + else: + prop_input_name.label(text=name) + # prop_input.template_image(textureProp, 'tex', + # nodes[name].image_user) + texIndex = name[-1] + + prop_input.prop(textureProp, "use_tex_reference") + if textureProp.use_tex_reference: + prop_split(prop_input, textureProp, "tex_reference", "Texture Reference") + prop_split(prop_input, textureProp, "tex_reference_size", "Texture Size") + if textureProp.tex_format[:2] == "CI": + prop_split(prop_input, textureProp, "pal_reference", "Palette Reference") + prop_split(prop_input, textureProp, "pal_reference_size", "Palette Size") + + else: + prop_input.template_ID( + textureProp, "tex", new="image.new", open="image.open", unlink="image.tex" + texIndex + "_unlink" + ) + prop_input.enabled = textureProp.tex_set + + if tex is not None: + prop_input.label(text="Size: " + str(tex.size[0]) + " x " + str(tex.size[1])) + + if material.mat_ver > 3 and material.f3d_mat.use_large_textures: + prop_input.label(text="Large texture mode enabled.") + prop_input.label(text="Each triangle must fit in a single tile load.") + prop_input.label(text="UVs must be in the [0, 1024] pixel range.") + prop_input.prop(textureProp, "save_large_texture") + if not textureProp.save_large_texture: + prop_input.label(text="Most large textures will take forever to convert.", icon="PREVIEW_RANGE") + else: + tmemUsageUI(prop_input, textureProp) + + prop_split(prop_input, textureProp, "tex_format", name="Format") + if textureProp.tex_format[:2] == "CI": + prop_split(prop_input, textureProp, "ci_format", name="CI Format") + + if not (material.mat_ver > 3 and material.f3d_mat.use_large_textures): + texFieldSettings = prop_input.column() + clampSettings = texFieldSettings.row() + clampSettings.prop(textureProp.S, "clamp", text="Clamp S") + clampSettings.prop(textureProp.T, "clamp", text="Clamp T") + + mirrorSettings = texFieldSettings.row() + mirrorSettings.prop(textureProp.S, "mirror", text="Mirror S") + mirrorSettings.prop(textureProp.T, "mirror", text="Mirror T") + + prop_input.prop(textureProp, "autoprop", text="Auto Set Other Properties") + + if not textureProp.autoprop: + mask = prop_input.row() + mask.prop(textureProp.S, "mask", text="Mask S") + mask.prop(textureProp.T, "mask", text="Mask T") + + shift = prop_input.row() + shift.prop(textureProp.S, "shift", text="Shift S") + shift.prop(textureProp.T, "shift", text="Shift T") + + low = prop_input.row() + low.prop(textureProp.S, "low", text="S Low") + low.prop(textureProp.T, "low", text="T Low") + + high = prop_input.row() + high.prop(textureProp.S, "high", text="S High") + high.prop(textureProp.T, "high", text="T High") + + if ( + tex is not None + and tex.size[0] > 0 + and tex.size[1] > 0 + and (math.log(tex.size[0], 2) % 1 > 0.000001 or math.log(tex.size[1], 2) % 1 > 0.000001) + ): + warnBox = layout.box() + warnBox.label(text="Warning: Texture dimensions are not power of 2.") + warnBox.label(text="Wrapping only occurs on power of 2 bounds.") + + def ui_prop(self, material, layout, name, setName, setProp, showCheckBox): + nodes = material.node_tree.nodes + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + if showCheckBox: + prop_input_name.prop(material, setName, text=name) + else: + prop_input_name.label(text=name) + prop_input.prop(nodes[name].outputs[0], "default_value", text="") + prop_input.enabled = setProp + return inputGroup + + def ui_prop_non_node(self, material, layout, label, name, setName, setProp): + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + prop_input_name.prop(material, setName, text=name) + prop_input.prop(material, name, text="") + prop_input.enabled = setProp + return inputGroup + + def ui_scale(self, material, layout): + inputGroup = layout.row().split(factor=0.5) + # prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + prop_input.prop(material, "scale_autoprop", text="Texture Auto Scale") + prop_input_group = inputGroup.row() + prop_input_group.prop(material, "tex_scale", text="") + prop_input_group.enabled = not material.scale_autoprop + return inputGroup + + def ui_prim(self, material, layout, setName, setProp, showCheckBox): + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + nodes = material.node_tree.nodes + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + if showCheckBox: + prop_input_name.prop(f3dMat, setName, text="Primitive Color") + else: + prop_input_name.label(text="Primitive Color") + + if material.mat_ver == 4: + prop_input.prop(material.f3d_mat, "prim_color", text="") + elif material.mat_ver == 3: + prop_input.prop(nodes["Primitive Color Output"].inputs[0], "default_value", text="") + else: + prop_input.prop(nodes["Primitive Color"].outputs[0], "default_value", text="") + + prop_input.prop(f3dMat, "prim_lod_frac", text="Prim LOD Fraction") + prop_input.prop(f3dMat, "prim_lod_min", text="Min LOD Ratio") + prop_input.enabled = setProp + return inputGroup + + def ui_env(self, material, layout, showCheckBox): + nodes = material.node_tree.nodes + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + + if material.mat_ver > 3: + if showCheckBox: + prop_input_name.prop(material.f3d_mat, "set_env", text="Environment Color") + else: + prop_input_name.label(text="Environment Color") + prop_input.prop(material.f3d_mat, "env_color", text="") + setProp = material.f3d_mat.set_env + else: + prop_input_name.prop(material, "set_env", text="Environment Color") + prop_input.prop(nodes["Environment Color Output"].inputs[0], "default_value", text="") + setProp = material.set_env + prop_input.enabled = setProp + return inputGroup + + def ui_chroma(self, material, layout, name, setName, setProp, showCheckBox): + nodes = material.node_tree.nodes + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + if showCheckBox: + prop_input_name.prop(material, setName, text="Chroma Key") + else: + prop_input_name.label(text="Chroma Key") + if material.mat_ver == 4: + prop_input.prop(material.f3d_mat, "key_center", text="Center") + else: + prop_input.prop(nodes["Chroma Key Center"].outputs[0], "default_value", text="Center") + prop_input.prop(material, "key_scale", text="Scale") + prop_input.prop(material, "key_width", text="Width") + if material.key_width[0] > 1 or material.key_width[1] > 1 or material.key_width[2] > 1: + layout.box().label(text="NOTE: Keying is disabled for channels with width > 1.") + prop_input.enabled = setProp + return inputGroup + + def ui_lights(self, material, layout, name, showCheckBox): + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + if showCheckBox: + prop_input_name.prop(material, "set_lights", text=name) + else: + prop_input_name.label(text=name) + prop_input_name.enabled = material.rdp_settings.g_lighting and material.rdp_settings.g_shade + lightSettings = prop_input.column() + if material.rdp_settings.g_lighting: + if material.use_default_lighting: + lightSettings.prop(material, "default_light_color", text="") + else: + lightSettings.prop(material, "ambient_light_color", text="Ambient Color") + + lightSettings.prop_search(material, "f3d_light1", bpy.data, "lights", text="") + if material.f3d_light1 is not None: + lightSettings.prop_search(material, "f3d_light2", bpy.data, "lights", text="") + if material.f3d_light2 is not None: + lightSettings.prop_search(material, "f3d_light3", bpy.data, "lights", text="") + if material.f3d_light3 is not None: + lightSettings.prop_search(material, "f3d_light4", bpy.data, "lights", text="") + if material.f3d_light4 is not None: + lightSettings.prop_search(material, "f3d_light5", bpy.data, "lights", text="") + if material.f3d_light5 is not None: + lightSettings.prop_search(material, "f3d_light6", bpy.data, "lights", text="") + if material.f3d_light6 is not None: + lightSettings.prop_search(material, "f3d_light7", bpy.data, "lights", text="") + prop_input.prop(material, "use_default_lighting", text="Use Custom Lighting", invert_checkbox=True) + # layout.box().label(text = "Note: Lighting preview is not 100% accurate.") + # layout.box().label(text = "For vertex colors, clear 'Lighting'.") + prop_input.enabled = ( + material.set_lights and material.rdp_settings.g_lighting and material.rdp_settings.g_shade + ) + + return inputGroup + + def ui_convert(self, material, layout, showCheckBox): + inputGroup = layout.row() + prop_input_name = inputGroup.column() + prop_input = inputGroup.column() + if showCheckBox: + prop_input_name.prop(material, "set_k0_5", text="YUV Convert") + else: + prop_input_name.label(text="YUV Convert") + + prop_k0 = prop_input.row() + prop_k0.prop(material, "k0", text="K0") + prop_k0.label(text=str(int(material.k0 * 255))) + + prop_k1 = prop_input.row() + prop_k1.prop(material, "k1", text="K1") + prop_k1.label(text=str(int(material.k1 * 255))) + + prop_k2 = prop_input.row() + prop_k2.prop(material, "k2", text="K2") + prop_k2.label(text=str(int(material.k2 * 255))) + + prop_k3 = prop_input.row() + prop_k3.prop(material, "k3", text="K3") + prop_k3.label(text=str(int(material.k3 * 255))) + + prop_k4 = prop_input.row() + prop_k4.prop(material, "k4", text="K4") + prop_k4.label(text=str(int(material.k4 * 255))) + + prop_k5 = prop_input.row() + prop_k5.prop(material, "k5", text="K5") + prop_k5.label(text=str(int(material.k5 * 255))) + + prop_input.enabled = material.set_k0_5 + return inputGroup + + def ui_lower_render_mode(self, material, layout, useDropdown): + # cycle independent + inputGroup = layout.column() + if useDropdown: + inputGroup.prop( + material, + "menu_lower_render", + text="Render Settings", + icon="TRIA_DOWN" if material.menu_lower_render else "TRIA_RIGHT", + ) + if not useDropdown or material.menu_lower_render: + inputGroup.prop(material.rdp_settings, "set_rendermode", text="Set Render Mode?") + + renderGroup = inputGroup.column() + renderGroup.prop(material.rdp_settings, "rendermode_advanced_enabled", text="Show Advanced Settings") + if not material.rdp_settings.rendermode_advanced_enabled: + prop_split(renderGroup, material.rdp_settings, "rendermode_preset_cycle_1", "Render Mode") + if material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + prop_split(renderGroup, material.rdp_settings, "rendermode_preset_cycle_2", "Render Mode Cycle 2") + else: + prop_split(renderGroup, material.rdp_settings, "aa_en", "Antialiasing") + prop_split(renderGroup, material.rdp_settings, "z_cmp", "Z Testing") + prop_split(renderGroup, material.rdp_settings, "z_upd", "Z Writing") + prop_split(renderGroup, material.rdp_settings, "im_rd", "IM_RD (?)") + prop_split(renderGroup, material.rdp_settings, "clr_on_cvg", "Color On Coverage") + prop_split(renderGroup, material.rdp_settings, "cvg_dst", "Coverage Destination") + prop_split(renderGroup, material.rdp_settings, "zmode", "Z Mode") + prop_split(renderGroup, material.rdp_settings, "cvg_x_alpha", "Multiply Coverage And Alpha") + prop_split(renderGroup, material.rdp_settings, "alpha_cvg_sel", "Use Coverage For Alpha") + prop_split(renderGroup, material.rdp_settings, "force_bl", "Force Blending") + + # cycle dependent - (P * A + M - B) / (A + B) + combinerBox = renderGroup.box() + combinerBox.label(text="Blender (Color = (P * A + M * B) / (A + B)") + combinerCol = combinerBox.row() + rowColor = combinerCol.column() + rowAlpha = combinerCol.column() + rowColor.prop(material.rdp_settings, "blend_p1", text="P") + rowColor.prop(material.rdp_settings, "blend_m1", text="M") + rowAlpha.prop(material.rdp_settings, "blend_a1", text="A") + rowAlpha.prop(material.rdp_settings, "blend_b1", text="B") + + if material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + combinerBox2 = renderGroup.box() + combinerBox2.label(text="Blender Cycle 2") + combinerCol2 = combinerBox2.row() + rowColor2 = combinerCol2.column() + rowAlpha2 = combinerCol2.column() + rowColor2.prop(material.rdp_settings, "blend_p2", text="P") + rowColor2.prop(material.rdp_settings, "blend_m2", text="M") + rowAlpha2.prop(material.rdp_settings, "blend_a2", text="A") + rowAlpha2.prop(material.rdp_settings, "blend_b2", text="B") + + renderGroup.enabled = material.rdp_settings.set_rendermode + + def ui_uvCheck(self, layout, context): + if ( + hasattr(context, "object") + and context.object is not None + and isinstance(context.object.data, bpy.types.Mesh) + ): + uv_layers = context.object.data.uv_layers + if uv_layers.active is None or uv_layers.active.name != "UVMap": + uvErrorBox = layout.box() + uvErrorBox.label(text='Warning: This mesh\'s active UV layer is not named "UVMap".') + uvErrorBox.label(text="This will cause incorrect UVs to display.") + + def ui_draw_layer(self, material, layout, context): + if material.mat_ver > 3: + if context.scene.gameEditorMode == "SM64": + prop_split(layout, material.f3d_mat.draw_layer, "sm64", "Draw Layer") + elif context.scene.gameEditorMode == "OOT": + prop_split(layout, material.f3d_mat.draw_layer, "oot", "Draw Layer") + + def ui_fog(self, f3dMat, inputCol, showCheckBox): + if f3dMat.rdp_settings.g_fog: + inputGroup = inputCol.column() + if showCheckBox: + inputGroup.prop(f3dMat, "set_fog", text="Set Fog") + if f3dMat.set_fog: + inputGroup.prop(f3dMat, "use_global_fog", text="Use Global Fog (SM64)") + if f3dMat.use_global_fog: + inputGroup.label(text="Only applies to levels (area fog settings).", icon="INFO") + else: + fogColorGroup = inputGroup.row().split(factor=0.5) + fogColorGroup.label(text="Fog Color") + fogColorGroup.prop(f3dMat, "fog_color", text="") + fogPositionGroup = inputGroup.row().split(factor=0.5) + fogPositionGroup.label(text="Fog Range") + fogPositionGroup.prop(f3dMat, "fog_position", text="") + + # inputGroup = inputCol.column() + # inputGroup.prop(f3dMat, 'set_fog', text = 'Set Fog') + # fogInputGroup = inputGroup.column() + # globalFogBox = fogInputGroup.box() + # globalFogBox.prop(f3dMat, 'use_global_fog', text = 'Use Global Fog') + # globalFogInfoBox = globalFogBox.box() + # globalFogInfoBox.label(text = 'Only applies to levels (area fog settings).') + # globalFogInfoBox.label(text = 'Disable this for non-level geolayout/dl exporting.') + # fogGroup = fogInputGroup.column() + # fogColorGroup = fogGroup.row().split(factor = 0.5) + # fogColorGroup.label(text = 'Fog Color') + # fogColorGroup.prop(f3dMat, 'fog_color', text = '') + # fogPositionGroup = fogGroup.row().split(factor = 0.5) + # fogPositionGroup.label(text = 'Fog Range') + # fogPositionGroup.prop(f3dMat, 'fog_position', text = '') + # fogInputGroup.enabled = f3dMat.set_fog + # fogGroup.enabled = not f3dMat.use_global_fog + # inputGroup.box().label(text = 'NOTE: Fog will break with draw layer overrides.') + + def drawVertexColorNotice(self, layout): + noticeBox = layout.box().column() + noticeBox.label(text="There must be two vertex color layers.", icon="LINENUMBERS_ON") + noticeBox.label(text='They should be called "Col" and "Alpha".') + + def drawShadeAlphaNotice(self, layout): + layout.box().column().label(text='There must be a vertex color layer called "Alpha".', icon="IMAGE_ALPHA") + + def drawCIMultitextureNotice(self, layout): + layout.label(text="CI textures will break with multitexturing.", icon="LIBRARY_DATA_BROKEN") + + def draw_simple(self, f3dMat, material, layout, context): + self.ui_uvCheck(layout, context) + + inputCol = layout.column() + useDict = all_combiner_uses(f3dMat) + + if not f3dMat.rdp_settings.g_lighting: + self.drawVertexColorNotice(layout) + elif useDict["Shade Alpha"]: + self.drawShadeAlphaNotice(layout) + + useMultitexture = useDict["Texture 0"] and useDict["Texture 1"] and f3dMat.tex0.tex_set and f3dMat.tex1.tex_set + + if useMultitexture and f3dMat.tex0.tex_format[:2] == "CI" or f3dMat.tex1.tex_format[:2] == "CI": + self.drawCIMultitextureNotice(inputCol) + + if useDict["Texture 0"] and f3dMat.tex0.tex_set: + self.ui_image(material, inputCol, f3dMat.tex0, "Texture 0", False) + + if useDict["Texture 1"] and f3dMat.tex1.tex_set: + self.ui_image(material, inputCol, f3dMat.tex1, "Texture 1", False) + + if useMultitexture: + inputCol.prop(f3dMat, "uv_basis", text="UV Basis") + + if useDict["Texture"]: + if material.mat_ver > 3: + inputCol.prop(f3dMat, "use_large_textures") + self.ui_scale(f3dMat, inputCol) + + if useDict["Primitive"] and f3dMat.set_prim: + self.ui_prim(material, inputCol, "set_prim", f3dMat.set_prim, False) + + if useDict["Environment"] and f3dMat.set_env: + if material.mat_ver >= 3: + self.ui_env(material, inputCol, False) + else: + self.ui_prop(material, inputCol, "Environment Color", "set_env", material.set_env, False) + + showLightProperty = f3dMat.set_lights and f3dMat.rdp_settings.g_lighting and f3dMat.rdp_settings.g_shade + if useDict["Shade"] and showLightProperty: + self.ui_lights(f3dMat, inputCol, "Shade Color", False) + + if useDict["Key"] and f3dMat.set_key: + self.ui_chroma(material, inputCol, "Chroma Key Center", "set_key", f3dMat.set_key, False) + + if useDict["Convert"] and f3dMat.set_k0_5: + self.ui_convert(f3dMat, inputCol, False) + + if f3dMat.set_fog: + self.ui_fog(f3dMat, inputCol, False) + + def draw_full(self, f3dMat, material, layout, context): + + layout.row().prop(material, "menu_tab", expand=True) + menuTab = material.menu_tab + useDict = all_combiner_uses(f3dMat) + + if menuTab == "Combiner": + if material.mat_ver > 3: + self.ui_draw_layer(material, layout, context) + + if not f3dMat.rdp_settings.g_lighting: + self.drawVertexColorNotice(layout) + elif useDict["Shade Alpha"]: + self.drawShadeAlphaNotice(layout) + + combinerBox = layout.box() + combinerBox.prop(f3dMat, "set_combiner", text="Color Combiner (Color = (A - B) * C + D)") + combinerCol = combinerBox.row() + combinerCol.enabled = f3dMat.set_combiner + rowColor = combinerCol.column() + rowAlpha = combinerCol.column() + + rowColor.prop(f3dMat.combiner1, "A") + rowColor.prop(f3dMat.combiner1, "B") + rowColor.prop(f3dMat.combiner1, "C") + rowColor.prop(f3dMat.combiner1, "D") + rowAlpha.prop(f3dMat.combiner1, "A_alpha") + rowAlpha.prop(f3dMat.combiner1, "B_alpha") + rowAlpha.prop(f3dMat.combiner1, "C_alpha") + rowAlpha.prop(f3dMat.combiner1, "D_alpha") + if ( + f3dMat.rdp_settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" + and f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" + ): + combinerBox.label(text="First cycle alpha out used for compare threshold.") + + if f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + combinerBox2 = layout.box() + combinerBox2.label(text="Color Combiner Cycle 2") + combinerBox2.enabled = f3dMat.set_combiner + combinerCol2 = combinerBox2.row() + rowColor2 = combinerCol2.column() + rowAlpha2 = combinerCol2.column() + + rowColor2.prop(f3dMat.combiner2, "A") + rowColor2.prop(f3dMat.combiner2, "B") + rowColor2.prop(f3dMat.combiner2, "C") + rowColor2.prop(f3dMat.combiner2, "D") + rowAlpha2.prop(f3dMat.combiner2, "A_alpha") + rowAlpha2.prop(f3dMat.combiner2, "B_alpha") + rowAlpha2.prop(f3dMat.combiner2, "C_alpha") + rowAlpha2.prop(f3dMat.combiner2, "D_alpha") + + combinerBox2.label(text="Note: In second cycle, texture 0 and texture 1 are flipped.") + + # layout.box().label( + # text = 'Note: Alpha preview is not 100% accurate.') + + if menuTab == "Sources": + self.ui_uvCheck(layout, context) + + inputCol = layout.column() + + useMultitexture = useDict["Texture 0"] and useDict["Texture 1"] + + if useMultitexture and f3dMat.tex0.tex_format[:2] == "CI" or f3dMat.tex1.tex_format[:2] == "CI": + self.drawCIMultitextureNotice(inputCol) + + if useDict["Texture 0"]: + self.ui_image(material, inputCol, f3dMat.tex0, "Texture 0", True) + + if useDict["Texture 1"]: + self.ui_image(material, inputCol, f3dMat.tex1, "Texture 1", True) + + if useMultitexture: + inputCol.prop(f3dMat, "uv_basis", text="UV Basis") + + if useDict["Texture"]: + if material.mat_ver > 3: + inputCol.prop(f3dMat, "use_large_textures") + self.ui_scale(f3dMat, inputCol) + + if useDict["Primitive"]: + self.ui_prim(material, inputCol, "set_prim", f3dMat.set_prim, True) + + if useDict["Environment"]: + if material.mat_ver >= 3: + self.ui_env(material, inputCol, True) + else: + self.ui_prop(material, inputCol, "Environment Color", "set_env", material.set_env, True) + + if useDict["Shade"]: + self.ui_lights(f3dMat, inputCol, "Shade Color", True) + + if useDict["Key"]: + self.ui_chroma(material, inputCol, "Chroma Key Center", "set_key", f3dMat.set_key, True) + + if useDict["Convert"]: + self.ui_convert(f3dMat, inputCol, True) + + self.ui_fog(f3dMat, inputCol, True) + + if menuTab == "Geo": + ui_geo_mode(f3dMat.rdp_settings, f3dMat, layout, False) + if menuTab == "Upper": + ui_upper_mode(f3dMat.rdp_settings, f3dMat, layout, False) + if menuTab == "Lower": + ui_lower_mode(f3dMat.rdp_settings, f3dMat, layout, False) + # layout.box().label(text = \ + # 'WARNING: Render mode settings not reset after drawing.') + self.ui_lower_render_mode(f3dMat, layout, False) + ui_other(f3dMat.rdp_settings, f3dMat, layout, False) + + # texture convert/LUT controlled by texture settings + # add node support for geo mode settings + def draw(self, context): + layout = self.layout + + layout.operator(CreateFast3DMaterial.bl_idname) + material = context.material + if material is None: + return + elif not (material.use_nodes and material.is_f3d): + layout.label(text="This is not a Fast3D material.") + return + + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + # layout.box().label(text = 'Note: Do not copy paste materials.') + layout.prop(context.scene, "f3d_simple", text="Show Simplified UI") + layout = layout.box() + titleCol = layout.column() + titleCol.box().label(text="F3D Material Inspector") + + if material.mat_ver > 3: + presetCol = layout.column() + split = presetCol.split(factor=0.33) + split.label(text="Preset") + row = split.row(align=True) + row.menu(MATERIAL_MT_f3d_presets.__name__, text=f3dMat.presetName) + row.operator(AddPresetF3D.bl_idname, text="", icon="ZOOM_IN") + row.operator(AddPresetF3D.bl_idname, text="", icon="ZOOM_OUT").remove_active = True + else: + prop_split(layout, material, "f3d_preset", "Preset Material") + + if context.scene.f3d_simple and ( + (material.mat_ver > 3 and f3dMat.presetName != "Custom") + or (material.mat_ver <= 3 and f3dMat.f3d_preset != "Custom") + ): + self.draw_simple(f3dMat, material, layout, context) + else: + if material.mat_ver > 3: + presetCol.prop(context.scene, "f3dUserPresetsOnly") + self.draw_full(f3dMat, material, layout, context) + + +# def ui_procAnimVec(self, procAnimVec, layout, name, vecType): +# layout.prop(procAnimVec, 'menu', text = name, +# icon = 'TRIA_DOWN' if procAnimVec.menu else 'TRIA_RIGHT') +# if procAnimVec.menu: +# box = layout.box() +# self.ui_procAnimField(procAnimVec.x, box, vecType[0]) +# self.ui_procAnimField(procAnimVec.y, box, vecType[1]) +# if len(vecType) > 2: +# self.ui_procAnimField(procAnimVec.z, box, vecType[2]) + def ui_tileScroll(tex, name, layout): - row = layout.row() - row.label(text = name) - row.prop(tex.tile_scroll, 's', text = 'S:') - row.prop(tex.tile_scroll, 't', text = 'T:') - row.prop(tex.tile_scroll, 'interval', text = 'Interval:') + row = layout.row() + row.label(text=name) + row.prop(tex.tile_scroll, "s", text="S:") + row.prop(tex.tile_scroll, "t", text="T:") + row.prop(tex.tile_scroll, "interval", text="Interval:") + def ui_procAnimVecEnum(material, procAnimVec, layout, name, vecType, useDropdown, useTex0, useTex1): - layout = layout.box() - box = layout.column() - if useDropdown: - layout.prop(procAnimVec, 'menu', text = name, - icon = 'TRIA_DOWN' if procAnimVec.menu else 'TRIA_RIGHT') - else: - layout.box().label(text = name) + layout = layout.box() + box = layout.column() + if useDropdown: + layout.prop(procAnimVec, "menu", text=name, icon="TRIA_DOWN" if procAnimVec.menu else "TRIA_RIGHT") + else: + layout.box().label(text=name) - if not useDropdown or procAnimVec.menu: - box = layout.column() - #box.box().label(text = 'Scrolling not visible in preview.') - #box.box().label(text = 'This is decomp only.') - combinedOption = None - xCombined = procAnimVec.x.animType == 'Rotation' - if xCombined: - combinedOption = procAnimVec.x.animType - yCombined = procAnimVec.y.animType == 'Rotation' - if yCombined: - combinedOption = procAnimVec.y.animType - if not yCombined: - ui_procAnimFieldEnum(procAnimVec.x, box, vecType[0], "UV" if xCombined else None) - if not xCombined: - ui_procAnimFieldEnum(procAnimVec.y, box, vecType[1], "UV" if yCombined else None) - if len(vecType) > 2: - ui_procAnimFieldEnum(procAnimVec.z, box, vecType[2]) - if xCombined or yCombined: - box.row().prop(procAnimVec, 'pivot') - box.row().prop(procAnimVec, 'angularSpeed') - if combinedOption == "Rotation": - pass + if not useDropdown or procAnimVec.menu: + box = layout.column() + # box.box().label(text = 'Scrolling not visible in preview.') + # box.box().label(text = 'This is decomp only.') + combinedOption = None + xCombined = procAnimVec.x.animType == "Rotation" + if xCombined: + combinedOption = procAnimVec.x.animType + yCombined = procAnimVec.y.animType == "Rotation" + if yCombined: + combinedOption = procAnimVec.y.animType + if not yCombined: + ui_procAnimFieldEnum(procAnimVec.x, box, vecType[0], "UV" if xCombined else None) + if not xCombined: + ui_procAnimFieldEnum(procAnimVec.y, box, vecType[1], "UV" if yCombined else None) + if len(vecType) > 2: + ui_procAnimFieldEnum(procAnimVec.z, box, vecType[2]) + if xCombined or yCombined: + box.row().prop(procAnimVec, "pivot") + box.row().prop(procAnimVec, "angularSpeed") + if combinedOption == "Rotation": + pass - if useTex0 or useTex1: - layout.box().label(text = 'SM64 SetTileSize Texture Scroll') + if useTex0 or useTex1: + layout.box().label(text="SM64 SetTileSize Texture Scroll") - if useTex0: - ui_tileScroll(material.tex0, 'Tex 0 Speed', layout) + if useTex0: + ui_tileScroll(material.tex0, "Tex 0 Speed", layout) + + if useTex1: + ui_tileScroll(material.tex1, "Tex 1 Speed", layout) - if useTex1: - ui_tileScroll(material.tex1, 'Tex 1 Speed', layout) def ui_procAnimFieldEnum(procAnimField, layout, name, overrideName): - box = layout - box.prop(procAnimField, 'animType', text = name if overrideName is None else overrideName) - if overrideName is None: - if procAnimField.animType == "Linear": - split0 = box.row().split(factor = 1) - split0.prop(procAnimField, 'speed') - elif procAnimField.animType == "Sine": - split1 = box.row().split(factor = 0.3333) - split1.prop(procAnimField, 'amplitude') - split1.prop(procAnimField, 'frequency') - #layout.row().prop(procAnimField, 'spaceFrequency') - #split2 = box.row().split(factor = 0.5) - split1.prop(procAnimField, 'offset') - elif procAnimField.animType == 'Noise': - box.row().prop(procAnimField, 'noiseAmplitude') + box = layout + box.prop(procAnimField, "animType", text=name if overrideName is None else overrideName) + if overrideName is None: + if procAnimField.animType == "Linear": + split0 = box.row().split(factor=1) + split0.prop(procAnimField, "speed") + elif procAnimField.animType == "Sine": + split1 = box.row().split(factor=0.3333) + split1.prop(procAnimField, "amplitude") + split1.prop(procAnimField, "frequency") + # layout.row().prop(procAnimField, 'spaceFrequency') + # split2 = box.row().split(factor = 0.5) + split1.prop(procAnimField, "offset") + elif procAnimField.animType == "Noise": + box.row().prop(procAnimField, "noiseAmplitude") + def ui_procAnimField(procAnimField, layout, name): - box = layout - box.prop(procAnimField, 'animate', text = name) - if procAnimField.animate: - if name not in 'XYZ': - split0 = box.row().split(factor = 1) - split0.prop(procAnimField, 'speed') - split1 = box.row().split(factor = 0.5) - split1.prop(procAnimField, 'amplitude') - split1.prop(procAnimField, 'frequency') - layout.row().prop(procAnimField, 'spaceFrequency') - split2 = box.row().split(factor = 0.5) - split2.prop(procAnimField, 'offset') - split2.prop(procAnimField, 'noiseAmplitude') + box = layout + box.prop(procAnimField, "animate", text=name) + if procAnimField.animate: + if name not in "XYZ": + split0 = box.row().split(factor=1) + split0.prop(procAnimField, "speed") + split1 = box.row().split(factor=0.5) + split1.prop(procAnimField, "amplitude") + split1.prop(procAnimField, "frequency") + layout.row().prop(procAnimField, "spaceFrequency") + split2 = box.row().split(factor=0.5) + split2.prop(procAnimField, "offset") + split2.prop(procAnimField, "noiseAmplitude") + def ui_procAnim(material, layout, useTex0, useTex1, title, useDropdown): - if material.mat_ver > 3: - ui_procAnimVecEnum(material.f3d_mat, material.f3d_mat.UVanim0, layout, title, 'UV', useDropdown, useTex0, useTex1) - else: - ui_procAnimVecEnum(material, material.UVanim, layout, title, 'UV', useDropdown, useTex0, useTex1) - #layout.prop(material, 'menu_procAnim', - # text = 'Procedural Animation', - # icon = 'TRIA_DOWN' if material.menu_procAnim else 'TRIA_RIGHT') - #if material.menu_procAnim: - # procAnimBox = layout.box() - # if useTex0: - # ui_procAnimVec(material.UVanim_tex0, procAnimBox, - # "UV Texture 0", 'UV') - # if useTex1: - # ui_procAnimVec(material.UVanim_tex1, procAnimBox, - # "UV Texture 1", 'UV') - # ui_procAnimVec(material.positionAnim, procAnimBox, - # "Position", 'XYZ') - # ui_procAnimVec(material.colorAnim, procAnimBox, "Color", - # 'RGB') + if material.mat_ver > 3: + ui_procAnimVecEnum( + material.f3d_mat, material.f3d_mat.UVanim0, layout, title, "UV", useDropdown, useTex0, useTex1 + ) + else: + ui_procAnimVecEnum(material, material.UVanim, layout, title, "UV", useDropdown, useTex0, useTex1) + # layout.prop(material, 'menu_procAnim', + # text = 'Procedural Animation', + # icon = 'TRIA_DOWN' if material.menu_procAnim else 'TRIA_RIGHT') + # if material.menu_procAnim: + # procAnimBox = layout.box() + # if useTex0: + # ui_procAnimVec(material.UVanim_tex0, procAnimBox, + # "UV Texture 0", 'UV') + # if useTex1: + # ui_procAnimVec(material.UVanim_tex1, procAnimBox, + # "UV Texture 1", 'UV') + # ui_procAnimVec(material.positionAnim, procAnimBox, + # "Position", 'XYZ') + # ui_procAnimVec(material.colorAnim, procAnimBox, "Color", + # 'RGB') def update_node_values(self, context): - if hasattr(context.scene, 'world') and \ - self == context.scene.world.rdp_defaults: - pass - elif hasattr(context, 'material_slot') and context.material_slot is not None: - material = context.material_slot.material # Handles case of texture property groups - if not material.is_f3d or material.f3d_update_flag: - return + if hasattr(context.scene, "world") and self == context.scene.world.rdp_defaults: + pass + elif hasattr(context, "material_slot") and context.material_slot is not None: + material = context.material_slot.material # Handles case of texture property groups + if not material.is_f3d or material.f3d_update_flag: + return + + material.f3d_update_flag = True + update_node_values_of_material(material, context) + if material.mat_ver > 3: + material.f3d_mat.presetName = "Custom" + else: + material.f3d_preset = "Custom" + material.f3d_update_flag = False - material.f3d_update_flag = True - update_node_values_of_material(material, context) - if material.mat_ver > 3: - material.f3d_mat.presetName = "Custom" - else: - material.f3d_preset = 'Custom' - material.f3d_update_flag = False def update_node_values_without_preset(self, context): - if hasattr(context.scene, 'world') and \ - self == context.scene.world.rdp_defaults: - pass - elif hasattr(context, 'material_slot') and context.material_slot is not None: - material = context.material_slot.material # Handles case of texture property groups - if not material.is_f3d or material.f3d_update_flag: - return + if hasattr(context.scene, "world") and self == context.scene.world.rdp_defaults: + pass + elif hasattr(context, "material_slot") and context.material_slot is not None: + material = context.material_slot.material # Handles case of texture property groups + if not material.is_f3d or material.f3d_update_flag: + return - material.f3d_update_flag = True - update_node_values_of_material(material, context) - material.f3d_update_flag = False - elif hasattr(context, 'material') and context.material is not None: - material = context.material - if not material.is_f3d or material.f3d_update_flag: - return + material.f3d_update_flag = True + update_node_values_of_material(material, context) + material.f3d_update_flag = False + elif hasattr(context, "material") and context.material is not None: + material = context.material + if not material.is_f3d or material.f3d_update_flag: + return + + material.f3d_update_flag = True + update_node_values_of_material(material, context) + material.f3d_update_flag = False + else: + # print('No material in context.') + pass - material.f3d_update_flag = True - update_node_values_of_material(material, context) - material.f3d_update_flag = False - else: - #print('No material in context.') - pass def update_node_values_directly(material, context): - if not material.is_f3d or material.f3d_update_flag: - return - material.f3d_update_flag = True - update_node_values_of_material(material, context) - material.f3d_preset = 'Custom' - material.f3d_update_flag = False + if not material.is_f3d or material.f3d_update_flag: + return + material.f3d_update_flag = True + update_node_values_of_material(material, context) + material.f3d_preset = "Custom" + material.f3d_update_flag = False + def getSocketFromCombinerToNodeDictColor(nodes, f3dVer, combinerInput): - nodeName, socketIndex = combinerToNodeDictColor[combinerInput] - return nodes[nodeName].outputs[socketIndex] if nodeName is not None else None + nodeName, socketIndex = combinerToNodeDictColor[combinerInput] + return nodes[nodeName].outputs[socketIndex] if nodeName is not None else None + def getSocketFromCombinerToNodeDictAlpha(nodes, f3dVer, combinerInput): - nodeName, socketIndex = combinerToNodeDictAlpha[combinerInput] - return nodes[nodeName].outputs[socketIndex] if nodeName is not None else None + nodeName, socketIndex = combinerToNodeDictAlpha[combinerInput] + return nodes[nodeName].outputs[socketIndex] if nodeName is not None else None + def update_node_combiner(material, combinerInputs, f3dVer, cycleIndex): - nodes = material.node_tree.nodes - combinerNode = nodes['Color Combiner Cycle ' + str(cycleIndex) + ' F3D v3'] - for i in range(8): - for link in combinerNode.inputs[i].links: - material.node_tree.links.remove(link) - if i in range(0,4): - if combinerInputs[i] == 'COMBINED' or combinerInputs[i] == 'COMBINED_ALPHA': - if cycleIndex == 2: - combiner1 = nodes['Color Combiner Cycle 1 F3D v3'] - combiner2 = nodes['Color Combiner Cycle 2 F3D v3'] - material.node_tree.links.new(combiner2.inputs[i], - combiner1.outputs[0 if combinerInputs[i] == 'COMBINED' else 1]) - else: - if cycleIndex == 2 and combinerInputs[i][:5] == "TEXEL": - value = combinerInputs[i] - combinerInput = value.replace("0", "1") if "0" in value else value.replace("1", "0") - else: - combinerInput = combinerInputs[i] - combinerSocket = getSocketFromCombinerToNodeDictColor(nodes, f3dVer, combinerInput) - material.node_tree.links.new(combinerNode.inputs[i], combinerSocket) - else: - if combinerInputs[i] == 'COMBINED': - if cycleIndex == 2: - combiner1 = nodes['Color Combiner Cycle 1 F3D v3'] - combiner2 = nodes['Color Combiner Cycle 2 F3D v3'] - material.node_tree.links.new(combiner2.inputs[i], combiner1.outputs[1]) - else: - combinerSocket = getSocketFromCombinerToNodeDictAlpha(nodes, f3dVer, combinerInputs[i]) - material.node_tree.links.new(combinerNode.inputs[i], combinerSocket) + nodes = material.node_tree.nodes + combinerNode = nodes["Color Combiner Cycle " + str(cycleIndex) + " F3D v3"] + for i in range(8): + for link in combinerNode.inputs[i].links: + material.node_tree.links.remove(link) + if i in range(0, 4): + if combinerInputs[i] == "COMBINED" or combinerInputs[i] == "COMBINED_ALPHA": + if cycleIndex == 2: + combiner1 = nodes["Color Combiner Cycle 1 F3D v3"] + combiner2 = nodes["Color Combiner Cycle 2 F3D v3"] + material.node_tree.links.new( + combiner2.inputs[i], combiner1.outputs[0 if combinerInputs[i] == "COMBINED" else 1] + ) + else: + if cycleIndex == 2 and combinerInputs[i][:5] == "TEXEL": + value = combinerInputs[i] + combinerInput = value.replace("0", "1") if "0" in value else value.replace("1", "0") + else: + combinerInput = combinerInputs[i] + combinerSocket = getSocketFromCombinerToNodeDictColor(nodes, f3dVer, combinerInput) + material.node_tree.links.new(combinerNode.inputs[i], combinerSocket) + else: + if combinerInputs[i] == "COMBINED": + if cycleIndex == 2: + combiner1 = nodes["Color Combiner Cycle 1 F3D v3"] + combiner2 = nodes["Color Combiner Cycle 2 F3D v3"] + material.node_tree.links.new(combiner2.inputs[i], combiner1.outputs[1]) + else: + combinerSocket = getSocketFromCombinerToNodeDictAlpha(nodes, f3dVer, combinerInputs[i]) + material.node_tree.links.new(combinerNode.inputs[i], combinerSocket) + def update_node_values_of_material(material, context): - nodes = material.node_tree.nodes + nodes = material.node_tree.nodes - # Case where f3d render engine is used instead of node graph - # Note that v4 doesn't change the node graph from v3, so we use that name - if material.mat_ver > 3: - update_blend_method(material, context) - if not hasNodeGraph(material): - return + # Case where f3d render engine is used instead of node graph + # Note that v4 doesn't change the node graph from v3, so we use that name + if material.mat_ver > 3: + update_blend_method(material, context) + if not hasNodeGraph(material): + return - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material - f3dVer = F3D('F3D', False) - if material.mat_ver == 1: - nodes['Case A 1'].inA = material.combiner1.A - nodes['Case B 1'].inB = material.combiner1.B - nodes['Case C 1'].inC = material.combiner1.C - nodes['Case D 1'].inD = material.combiner1.D - nodes['Case A Alpha 1'].inA_alpha = material.combiner1.A_alpha - nodes['Case B Alpha 1'].inB_alpha = material.combiner1.B_alpha - nodes['Case C Alpha 1'].inC_alpha = material.combiner1.C_alpha - nodes['Case D Alpha 1'].inD_alpha = material.combiner1.D_alpha - nodes['Case A 2'].inA = material.combiner2.A - nodes['Case B 2'].inB = material.combiner2.B - nodes['Case C 2'].inC = material.combiner2.C - nodes['Case D 2'].inD = material.combiner2.D - nodes['Case A Alpha 2'].inA_alpha = material.combiner2.A_alpha - nodes['Case B Alpha 2'].inB_alpha = material.combiner2.B_alpha - nodes['Case C Alpha 2'].inC_alpha = material.combiner2.C_alpha - nodes['Case D Alpha 2'].inD_alpha = material.combiner2.D_alpha - elif material.mat_ver == 2: - nodes['Case A 1'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.A] - nodes['Case B 1'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.B] - nodes['Case C 1'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.C] - nodes['Case D 1'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.D] - nodes['Case A Alpha 1'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.A_alpha] - nodes['Case B Alpha 1'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.B_alpha] - nodes['Case C Alpha 1'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.C_alpha] - nodes['Case D Alpha 1'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.D_alpha] - nodes['Case A 2'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.A] - nodes['Case B 2'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.B] - nodes['Case C 2'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.C] - nodes['Case D 2'].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.D] - nodes['Case A Alpha 2'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.A_alpha] - nodes['Case B Alpha 2'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.B_alpha] - nodes['Case C Alpha 2'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.C_alpha] - nodes['Case D Alpha 2'].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.D_alpha] - elif material.mat_ver >= 3: - combinerInputs1 = [ - f3dMat.combiner1.A, - f3dMat.combiner1.B, - f3dMat.combiner1.C, - f3dMat.combiner1.D, - f3dMat.combiner1.A_alpha, - f3dMat.combiner1.B_alpha, - f3dMat.combiner1.C_alpha, - f3dMat.combiner1.D_alpha, - ] + f3dVer = F3D("F3D", False) + if material.mat_ver == 1: + nodes["Case A 1"].inA = material.combiner1.A + nodes["Case B 1"].inB = material.combiner1.B + nodes["Case C 1"].inC = material.combiner1.C + nodes["Case D 1"].inD = material.combiner1.D + nodes["Case A Alpha 1"].inA_alpha = material.combiner1.A_alpha + nodes["Case B Alpha 1"].inB_alpha = material.combiner1.B_alpha + nodes["Case C Alpha 1"].inC_alpha = material.combiner1.C_alpha + nodes["Case D Alpha 1"].inD_alpha = material.combiner1.D_alpha + nodes["Case A 2"].inA = material.combiner2.A + nodes["Case B 2"].inB = material.combiner2.B + nodes["Case C 2"].inC = material.combiner2.C + nodes["Case D 2"].inD = material.combiner2.D + nodes["Case A Alpha 2"].inA_alpha = material.combiner2.A_alpha + nodes["Case B Alpha 2"].inB_alpha = material.combiner2.B_alpha + nodes["Case C Alpha 2"].inC_alpha = material.combiner2.C_alpha + nodes["Case D Alpha 2"].inD_alpha = material.combiner2.D_alpha + elif material.mat_ver == 2: + nodes["Case A 1"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.A] + nodes["Case B 1"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.B] + nodes["Case C 1"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.C] + nodes["Case D 1"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner1.D] + nodes["Case A Alpha 1"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.A_alpha] + nodes["Case B Alpha 1"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.B_alpha] + nodes["Case C Alpha 1"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.C_alpha] + nodes["Case D Alpha 1"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner1.D_alpha] + nodes["Case A 2"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.A] + nodes["Case B 2"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.B] + nodes["Case C 2"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.C] + nodes["Case D 2"].outputs[0].default_value = f3dVer.CCMUXDict[material.combiner2.D] + nodes["Case A Alpha 2"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.A_alpha] + nodes["Case B Alpha 2"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.B_alpha] + nodes["Case C Alpha 2"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.C_alpha] + nodes["Case D Alpha 2"].outputs[0].default_value = f3dVer.ACMUXDict[material.combiner2.D_alpha] + elif material.mat_ver >= 3: + combinerInputs1 = [ + f3dMat.combiner1.A, + f3dMat.combiner1.B, + f3dMat.combiner1.C, + f3dMat.combiner1.D, + f3dMat.combiner1.A_alpha, + f3dMat.combiner1.B_alpha, + f3dMat.combiner1.C_alpha, + f3dMat.combiner1.D_alpha, + ] - combinerInputs2 = [ - f3dMat.combiner2.A, - f3dMat.combiner2.B, - f3dMat.combiner2.C, - f3dMat.combiner2.D, - f3dMat.combiner2.A_alpha, - f3dMat.combiner2.B_alpha, - f3dMat.combiner2.C_alpha, - f3dMat.combiner2.D_alpha, - ] + combinerInputs2 = [ + f3dMat.combiner2.A, + f3dMat.combiner2.B, + f3dMat.combiner2.C, + f3dMat.combiner2.D, + f3dMat.combiner2.A_alpha, + f3dMat.combiner2.B_alpha, + f3dMat.combiner2.C_alpha, + f3dMat.combiner2.D_alpha, + ] - update_node_combiner(material, combinerInputs1, f3dVer, 1) - update_node_combiner(material, combinerInputs2, f3dVer, 2) + update_node_combiner(material, combinerInputs1, f3dVer, 1) + update_node_combiner(material, combinerInputs2, f3dVer, 2) - if material.mat_ver >= 3: - nodes['F3D v3'].inputs[4].default_value = 1 if \ - f3dMat.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE' else 0 - nodes['F3D v3'].inputs[5].default_value = \ - 0 if f3dMat.rdp_settings.g_cull_front else 1 - nodes['F3D v3'].inputs[6].default_value = \ - 0 if f3dMat.rdp_settings.g_cull_back else 1 + if material.mat_ver >= 3: + nodes["F3D v3"].inputs[4].default_value = 1 if f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" else 0 + nodes["F3D v3"].inputs[5].default_value = 0 if f3dMat.rdp_settings.g_cull_front else 1 + nodes["F3D v3"].inputs[6].default_value = 0 if f3dMat.rdp_settings.g_cull_back else 1 - nodes['Get UV 0 F3D v3'].inputs[0].default_value = 1 if \ - f3dMat.rdp_settings.g_tex_gen else 0 - nodes['Get UV 0 F3D v3'].inputs[1].default_value = 1 if \ - f3dMat.rdp_settings.g_tex_gen_linear else 0 - nodes['Get UV 1 F3D v3'].inputs[0].default_value = 1 if \ - f3dMat.rdp_settings.g_tex_gen else 0 - nodes['Get UV 1 F3D v3'].inputs[1].default_value = 1 if \ - f3dMat.rdp_settings.g_tex_gen_linear else 0 + nodes["Get UV 0 F3D v3"].inputs[0].default_value = 1 if f3dMat.rdp_settings.g_tex_gen else 0 + nodes["Get UV 0 F3D v3"].inputs[1].default_value = 1 if f3dMat.rdp_settings.g_tex_gen_linear else 0 + nodes["Get UV 1 F3D v3"].inputs[0].default_value = 1 if f3dMat.rdp_settings.g_tex_gen else 0 + nodes["Get UV 1 F3D v3"].inputs[1].default_value = 1 if f3dMat.rdp_settings.g_tex_gen_linear else 0 - nodes['Shade Color'].inputs[0].default_value = 0 if \ - not f3dMat.rdp_settings.g_shade else 1 - nodes['Shade Color'].inputs[1].default_value = 0 if \ - not f3dMat.rdp_settings.g_lighting else 1 + nodes["Shade Color"].inputs[0].default_value = 0 if not f3dMat.rdp_settings.g_shade else 1 + nodes["Shade Color"].inputs[1].default_value = 0 if not f3dMat.rdp_settings.g_lighting else 1 - if f3dMat.use_default_lighting: - nodes['Shade Color'].inputs[2].default_value = \ - (f3dMat.default_light_color[0], - f3dMat.default_light_color[1], - f3dMat.default_light_color[2], - f3dMat.default_light_color[3]) - else: - nodes['Shade Color'].inputs[2].default_value = \ - (f3dMat.ambient_light_color[0], - f3dMat.ambient_light_color[1], - f3dMat.ambient_light_color[2], - f3dMat.ambient_light_color[3]) + if f3dMat.use_default_lighting: + nodes["Shade Color"].inputs[2].default_value = ( + f3dMat.default_light_color[0], + f3dMat.default_light_color[1], + f3dMat.default_light_color[2], + f3dMat.default_light_color[3], + ) + else: + nodes["Shade Color"].inputs[2].default_value = ( + f3dMat.ambient_light_color[0], + f3dMat.ambient_light_color[1], + f3dMat.ambient_light_color[2], + f3dMat.ambient_light_color[3], + ) - if material.mat_ver > 3: - nodes['Primitive Color Output'].inputs[0].default_value = \ - (f3dMat.prim_color[0], - f3dMat.prim_color[1], - f3dMat.prim_color[2], - f3dMat.prim_color[3]) + if material.mat_ver > 3: + nodes["Primitive Color Output"].inputs[0].default_value = ( + f3dMat.prim_color[0], + f3dMat.prim_color[1], + f3dMat.prim_color[2], + f3dMat.prim_color[3], + ) - nodes['Environment Color Output'].inputs[0].default_value = \ - (f3dMat.env_color[0], - f3dMat.env_color[1], - f3dMat.env_color[2], - f3dMat.env_color[3]) + nodes["Environment Color Output"].inputs[0].default_value = ( + f3dMat.env_color[0], + f3dMat.env_color[1], + f3dMat.env_color[2], + f3dMat.env_color[3], + ) - nodes['Chroma Key Center'].outputs[0].default_value = \ - (f3dMat.key_center[0], - f3dMat.key_center[1], - f3dMat.key_center[2], - f3dMat.key_center[3]) + nodes["Chroma Key Center"].outputs[0].default_value = ( + f3dMat.key_center[0], + f3dMat.key_center[1], + f3dMat.key_center[2], + f3dMat.key_center[3], + ) - else: - nodes['Cycle Type'].outputs[0].default_value = 1 if \ - material.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE' else 0 - nodes['Cull Front'].outputs[0].default_value = \ - 0 if material.rdp_settings.g_cull_front else 1 - nodes['Cull Back'].outputs[0].default_value = \ - 0 if material.rdp_settings.g_cull_back else 1 - nodes['Texture Gen'].outputs[0].default_value = 1 if \ - material.rdp_settings.g_tex_gen else 0 - nodes['Texture Gen Linear'].outputs[0].default_value = 1 if \ - material.rdp_settings.g_tex_gen_linear else 0 - nodes['Shading'].outputs[0].default_value = 0 if \ - not material.rdp_settings.g_shade else 1 - nodes['Lighting'].outputs[0].default_value = 0 if \ - not material.rdp_settings.g_lighting else 1 + else: + nodes["Cycle Type"].outputs[0].default_value = ( + 1 if material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" else 0 + ) + nodes["Cull Front"].outputs[0].default_value = 0 if material.rdp_settings.g_cull_front else 1 + nodes["Cull Back"].outputs[0].default_value = 0 if material.rdp_settings.g_cull_back else 1 + nodes["Texture Gen"].outputs[0].default_value = 1 if material.rdp_settings.g_tex_gen else 0 + nodes["Texture Gen Linear"].outputs[0].default_value = 1 if material.rdp_settings.g_tex_gen_linear else 0 + nodes["Shading"].outputs[0].default_value = 0 if not material.rdp_settings.g_shade else 1 + nodes["Lighting"].outputs[0].default_value = 0 if not material.rdp_settings.g_lighting else 1 - if material.use_default_lighting: - nodes['Ambient Color'].outputs[0].default_value = \ - (material.default_light_color[0], - material.default_light_color[1], - material.default_light_color[2], - material.default_light_color[3]) - else: - nodes['Ambient Color'].outputs[0].default_value = \ - (material.ambient_light_color[0], - material.ambient_light_color[1], - material.ambient_light_color[2], - material.ambient_light_color[3]) + if material.use_default_lighting: + nodes["Ambient Color"].outputs[0].default_value = ( + material.default_light_color[0], + material.default_light_color[1], + material.default_light_color[2], + material.default_light_color[3], + ) + else: + nodes["Ambient Color"].outputs[0].default_value = ( + material.ambient_light_color[0], + material.ambient_light_color[1], + material.ambient_light_color[2], + material.ambient_light_color[3], + ) - material.show_transparent_back = f3dMat.rdp_settings.g_cull_front - nodes['Chroma Key Scale'].outputs[0].default_value = \ - [value for value in f3dMat.key_scale] + [1] - nodes['Primitive LOD Fraction'].outputs[0].default_value = \ - f3dMat.prim_lod_frac + material.show_transparent_back = f3dMat.rdp_settings.g_cull_front + nodes["Chroma Key Scale"].outputs[0].default_value = [value for value in f3dMat.key_scale] + [1] + nodes["Primitive LOD Fraction"].outputs[0].default_value = f3dMat.prim_lod_frac - # nodes['YUV Convert K0'].outputs[0].default_value = material.k0 - # nodes['YUV Convert K1'].outputs[0].default_value = material.k1 - # nodes['YUV Convert K2'].outputs[0].default_value = material.k2 - # nodes['YUV Convert K3'].outputs[0].default_value = material.k3 - nodes['YUV Convert K4'].outputs[0].default_value = f3dMat.k4 - nodes['YUV Convert K5'].outputs[0].default_value = f3dMat.k5 + # nodes['YUV Convert K0'].outputs[0].default_value = material.k0 + # nodes['YUV Convert K1'].outputs[0].default_value = material.k1 + # nodes['YUV Convert K2'].outputs[0].default_value = material.k2 + # nodes['YUV Convert K3'].outputs[0].default_value = material.k3 + nodes["YUV Convert K4"].outputs[0].default_value = f3dMat.k4 + nodes["YUV Convert K5"].outputs[0].default_value = f3dMat.k5 - update_tex_values_manual(material, context) + update_tex_values_manual(material, context) -def update_tex_values_field(self, fieldProperty, texCoordNode, pixelLength, - isTexGen, uvBasisScale, scale, autoprop, reverseValues, texIndex, field): - clamp = fieldProperty.clamp - mirror = fieldProperty.mirror - clampNode = texCoordNode['Clamp'] - mirrorNode = texCoordNode['Mirror'] - normHalfPixelNode = texCoordNode['Normalized Half Pixel'] - normLNode = texCoordNode["Normalized L"] - normHNode = texCoordNode["Normalized H"] - normMaskNode = texCoordNode["Normalized Mask"] - shiftNode = texCoordNode['Shift'] - scaleNode = texCoordNode['Scale'] +def update_tex_values_field( + self, + fieldProperty, + texCoordNode, + pixelLength, + isTexGen, + uvBasisScale, + scale, + autoprop, + reverseValues, + texIndex, + field, +): + clamp = fieldProperty.clamp + mirror = fieldProperty.mirror - clampNode.outputs[0].default_value = 1 if clamp else 0 - mirrorNode.outputs[0].default_value = 1 if mirror else 0 - normHalfPixelNode.outputs[0].default_value = \ - 1 / (2 * pixelLength) + clampNode = texCoordNode["Clamp"] + mirrorNode = texCoordNode["Mirror"] + normHalfPixelNode = texCoordNode["Normalized Half Pixel"] + normLNode = texCoordNode["Normalized L"] + normHNode = texCoordNode["Normalized H"] + normMaskNode = texCoordNode["Normalized Mask"] + shiftNode = texCoordNode["Shift"] + scaleNode = texCoordNode["Scale"] - if autoprop: - fieldProperty.low = 0 - fieldProperty.high = pixelLength - 1 - fieldProperty.mask = math.ceil(math.log(pixelLength, 2) - 0.001) - #fieldProperty.mask = 0 - fieldProperty.shift = 0 + clampNode.outputs[0].default_value = 1 if clamp else 0 + mirrorNode.outputs[0].default_value = 1 if mirror else 0 + normHalfPixelNode.outputs[0].default_value = 1 / (2 * pixelLength) - L = fieldProperty.low - H = fieldProperty.high - mask = fieldProperty.mask - shift = fieldProperty.shift + if autoprop: + fieldProperty.low = 0 + fieldProperty.high = pixelLength - 1 + fieldProperty.mask = math.ceil(math.log(pixelLength, 2) - 0.001) + # fieldProperty.mask = 0 + fieldProperty.shift = 0 - if reverseValues: - normLNode.outputs[0].default_value = -L / pixelLength - else: - normLNode.outputs[0].default_value = L / pixelLength - normHNode.outputs[0].default_value = (H + 1)/pixelLength - normMaskNode.outputs[0].default_value = \ - (2 ** mask) / pixelLength if mask > 0 else 0 + L = fieldProperty.low + H = fieldProperty.high + mask = fieldProperty.mask + shift = fieldProperty.shift + + if reverseValues: + normLNode.outputs[0].default_value = -L / pixelLength + else: + normLNode.outputs[0].default_value = L / pixelLength + normHNode.outputs[0].default_value = (H + 1) / pixelLength + normMaskNode.outputs[0].default_value = (2**mask) / pixelLength if mask > 0 else 0 + + shiftNode.outputs[0].default_value = shift + scaleNode.outputs[0].default_value = scale * uvBasisScale - shiftNode.outputs[0].default_value = shift - scaleNode.outputs[0].default_value = scale * uvBasisScale def setAutoProp(fieldProperty, pixelLength): - fieldProperty.low = 0 - fieldProperty.high = pixelLength - 1 - fieldProperty.mask = math.ceil(math.log(pixelLength, 2) - 0.001) - #fieldProperty.mask = 0 - fieldProperty.shift = 0 + fieldProperty.low = 0 + fieldProperty.high = pixelLength - 1 + fieldProperty.mask = math.ceil(math.log(pixelLength, 2) - 0.001) + # fieldProperty.mask = 0 + fieldProperty.shift = 0 -def update_tex_values_field_v2(self, fieldProperty, pixelLength, - uvBasisScale, scale, autoprop, texIndex, field): - fieldIndex = 0 if field == 'S' else 1 - pixelLengthAxis = pixelLength[fieldIndex] +def update_tex_values_field_v2(self, fieldProperty, pixelLength, uvBasisScale, scale, autoprop, texIndex, field): - nodes = self.node_tree.nodes - clampNode = nodes['Tex ' + str(texIndex) + ' Clamp'] - mirrorNode = nodes['Tex ' + str(texIndex) + ' Mirror'] - normHalfPixelNode = nodes['Tex ' + str(texIndex) + ' Normalized Half Pixel'] - normLNode = nodes['Tex ' + str(texIndex) + " Normalized L"] - normHNode = nodes['Tex ' + str(texIndex) + " Normalized H"] - normMaskNode = nodes["Tex " + str(texIndex) + " Normalized Mask"] - shiftNode = nodes['Tex ' + str(texIndex) + ' Shift'] - scaleNode = nodes['Tex ' + str(texIndex) + ' Scale'] + fieldIndex = 0 if field == "S" else 1 + pixelLengthAxis = pixelLength[fieldIndex] - clampNode.inputs[fieldIndex].default_value = 1 if fieldProperty.clamp else 0 - mirrorNode.inputs[fieldIndex].default_value = 1 if fieldProperty.mirror else 0 - normHalfPixelNode.inputs[fieldIndex].default_value = 1 / (2 * pixelLengthAxis) + nodes = self.node_tree.nodes + clampNode = nodes["Tex " + str(texIndex) + " Clamp"] + mirrorNode = nodes["Tex " + str(texIndex) + " Mirror"] + normHalfPixelNode = nodes["Tex " + str(texIndex) + " Normalized Half Pixel"] + normLNode = nodes["Tex " + str(texIndex) + " Normalized L"] + normHNode = nodes["Tex " + str(texIndex) + " Normalized H"] + normMaskNode = nodes["Tex " + str(texIndex) + " Normalized Mask"] + shiftNode = nodes["Tex " + str(texIndex) + " Shift"] + scaleNode = nodes["Tex " + str(texIndex) + " Scale"] - if autoprop: - setAutoProp(fieldProperty, pixelLengthAxis) + clampNode.inputs[fieldIndex].default_value = 1 if fieldProperty.clamp else 0 + mirrorNode.inputs[fieldIndex].default_value = 1 if fieldProperty.mirror else 0 + normHalfPixelNode.inputs[fieldIndex].default_value = 1 / (2 * pixelLengthAxis) - normLNode.inputs[fieldIndex].default_value = fieldProperty.low / pixelLengthAxis * (-1 if field == 'T' else 1) - normHNode.inputs[fieldIndex].default_value = (fieldProperty.high + 1)/pixelLengthAxis - normMaskNode.inputs[fieldIndex].default_value = (2 ** fieldProperty.mask) / pixelLengthAxis if fieldProperty.mask > 0 else 0 - shiftNode.inputs[fieldIndex].default_value = fieldProperty.shift - scaleNode.inputs[fieldIndex].default_value = scale[fieldIndex] * uvBasisScale[fieldIndex] + if autoprop: + setAutoProp(fieldProperty, pixelLengthAxis) -def update_tex_values_field_v3(self, texProperty, tex_size, - uvBasisScale, scale, texIndex): - nodes = self.node_tree.nodes - if texProperty.autoprop: - setAutoProp(texProperty.S, tex_size[0]) - setAutoProp(texProperty.T, tex_size[1]) + normLNode.inputs[fieldIndex].default_value = fieldProperty.low / pixelLengthAxis * (-1 if field == "T" else 1) + normHNode.inputs[fieldIndex].default_value = (fieldProperty.high + 1) / pixelLengthAxis + normMaskNode.inputs[fieldIndex].default_value = ( + (2**fieldProperty.mask) / pixelLengthAxis if fieldProperty.mask > 0 else 0 + ) + shiftNode.inputs[fieldIndex].default_value = fieldProperty.shift + scaleNode.inputs[fieldIndex].default_value = scale[fieldIndex] * uvBasisScale[fieldIndex] - # For input index, Tex Gen = 0, Tex Gen Linear = 1 - # Image Factor - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[2].default_value = ( - 1024 / tex_size[0], 1024 / tex_size[1], 0) +def update_tex_values_field_v3(self, texProperty, tex_size, uvBasisScale, scale, texIndex): + nodes = self.node_tree.nodes + if texProperty.autoprop: + setAutoProp(texProperty.S, tex_size[0]) + setAutoProp(texProperty.T, tex_size[1]) - # Normalized L - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[3].default_value = ( - texProperty.S.low / tex_size[0], - texProperty.T.low / tex_size[1], 0) + # For input index, Tex Gen = 0, Tex Gen Linear = 1 - # Normalized H - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[4].default_value = ( - (texProperty.S.high + 1) / tex_size[0], - (texProperty.T.high + 1) / tex_size[1], 0) + # Image Factor + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[2].default_value = (1024 / tex_size[0], 1024 / tex_size[1], 0) - # Clamp - isTexGen = self.f3d_mat.rdp_settings.g_tex_gen or self.f3d_mat.rdp_settings.g_tex_gen_linear - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[5].default_value = ( - 1 if texProperty.S.clamp and not isTexGen else 0, - 1 if texProperty.T.clamp and not isTexGen else 0, 0) + # Normalized L + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[3].default_value = ( + texProperty.S.low / tex_size[0], + texProperty.T.low / tex_size[1], + 0, + ) - # Normalized Mask - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[6].default_value = ( - (2 ** texProperty.S.mask) / tex_size[0] if texProperty.S.mask > 0 else 0, - (2 ** texProperty.T.mask) / tex_size[1] if texProperty.T.mask > 0 else 0, 0) + # Normalized H + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[4].default_value = ( + (texProperty.S.high + 1) / tex_size[0], + (texProperty.T.high + 1) / tex_size[1], + 0, + ) - # Mirror - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[7].default_value = ( - 1 if texProperty.S.mirror else 0, - 1 if texProperty.T.mirror else 0, 0) + # Clamp + isTexGen = self.f3d_mat.rdp_settings.g_tex_gen or self.f3d_mat.rdp_settings.g_tex_gen_linear + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[5].default_value = ( + 1 if texProperty.S.clamp and not isTexGen else 0, + 1 if texProperty.T.clamp and not isTexGen else 0, + 0, + ) - # Shift - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[8].default_value = ( - texProperty.S.shift, - texProperty.T.shift, 0) + # Normalized Mask + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[6].default_value = ( + (2**texProperty.S.mask) / tex_size[0] if texProperty.S.mask > 0 else 0, + (2**texProperty.T.mask) / tex_size[1] if texProperty.T.mask > 0 else 0, + 0, + ) - # Scale - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[9].default_value = ( - scale[0] * uvBasisScale[0], - scale[1] * uvBasisScale[1], 0) + # Mirror + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[7].default_value = ( + 1 if texProperty.S.mirror else 0, + 1 if texProperty.T.mirror else 0, + 0, + ) - # Normalized Half Pixel - nodes['Get UV ' + str(texIndex) + ' F3D v3'].inputs[10].default_value = ( - 1 / (2 * tex_size[0]), - 1 / (2 * tex_size[1]), 0) + # Shift + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[8].default_value = (texProperty.S.shift, texProperty.T.shift, 0) -def update_tex_values_index(self, context, texProperty, texNodeName, - uvNodeName, isTexGen, uvBasisScale, scale, texIndex): - nodes = self.node_tree.nodes + # Scale + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[9].default_value = ( + scale[0] * uvBasisScale[0], + scale[1] * uvBasisScale[1], + 0, + ) - nodes[texNodeName].image = texProperty.tex - if nodes[texNodeName].image is not None or texProperty.use_tex_reference: - if nodes[texNodeName].image is not None: - tex_size = nodes[texNodeName].image.size - else: - tex_size = texProperty.tex_reference_size - if tex_size[0] > 0 and tex_size[1] > 0: - if self.mat_ver == 1: - tex_x = nodes[uvNodeName].node_tree.nodes[\ - 'Create Tex Coord'].node_tree.nodes - tex_y = nodes[uvNodeName].node_tree.nodes[\ - 'Create Tex Coord.001'].node_tree.nodes - imageWidthNode = nodes[uvNodeName].node_tree.nodes['Image Width Factor'] - imageHeightNode = nodes[uvNodeName].node_tree.nodes['Image Height Factor'] - # 1024 == 2^16 / 2^6 (converting 0.16 to 10.5 fixed point) - imageWidthNode.outputs[0].default_value = 1024 / tex_size[0] - imageHeightNode.outputs[0].default_value = 1024 / tex_size[1] + # Normalized Half Pixel + nodes["Get UV " + str(texIndex) + " F3D v3"].inputs[10].default_value = ( + 1 / (2 * tex_size[0]), + 1 / (2 * tex_size[1]), + 0, + ) - update_tex_values_field(self, texProperty.S, tex_x, tex_size[0], - self.rdp_settings.g_tex_gen or self.rdp_settings.g_tex_gen_linear, - uvBasisScale[0], scale[0], texProperty.autoprop, False, texIndex, 'S') - update_tex_values_field(self, texProperty.T, tex_y, tex_size[1], - self.rdp_settings.g_tex_gen or self.rdp_settings.g_tex_gen_linear, - uvBasisScale[1], scale[1], texProperty.autoprop, True, texIndex, 'T') - elif self.mat_ver == 2: - tex_x = nodes - tex_y = nodes - imageFactorNode = nodes['Tex ' + str(texIndex) + ' Image Factor'] - imageFactorNode.inputs[0].default_value = 1024 / tex_size[0] - imageFactorNode.inputs[1].default_value = 1024 / tex_size[1] - update_tex_values_field_v2(self, texProperty.S, tex_size, - uvBasisScale, scale, texProperty.autoprop, texIndex, 'S') - update_tex_values_field_v2(self, texProperty.T, tex_size, - uvBasisScale, scale, texProperty.autoprop, texIndex, 'T') - elif self.mat_ver >= 3: - if self.mat_ver > 3: - f3dMat = self.f3d_mat - else: - f3dMat = self - if self.mat_ver == 3 or hasNodeGraph(self): - update_tex_values_field_v3(self, texProperty, tex_size, - uvBasisScale, scale, texIndex) - #nodes[texNodeName].interpolation = "Closest" - nodes[texNodeName].interpolation = "Closest" if \ - f3dMat.rdp_settings.g_mdsft_text_filt == 'G_TF_POINT' else "Linear" - else: - if texProperty.autoprop: - setAutoProp(texProperty.S, tex_size[0]) - setAutoProp(texProperty.T, tex_size[1]) - else: - print("Error: Unhandled material version " + str(self.mat_ver) + ' for texture properties.') +def update_tex_values_index( + self, context, texProperty, texNodeName, uvNodeName, isTexGen, uvBasisScale, scale, texIndex +): + nodes = self.node_tree.nodes - texFormat = texProperty.tex_format - ciFormat = texProperty.ci_format - if self.mat_ver >= 3: # No nodes, only sockets (0 = color, 1 = alpha) - if self.mat_ver == 3 or hasNodeGraph(self): - getTextureColorName = 'Get Texture Color' if texIndex == 0 else "Get Texture Color.001" - # Is Greyscale - nodes[getTextureColorName].inputs[2].default_value =\ - 1 if (texFormat[0] == 'I' or \ - (texFormat[:2] == 'CI' and ciFormat[0] == 'I')) else 0 + nodes[texNodeName].image = texProperty.tex + if nodes[texNodeName].image is not None or texProperty.use_tex_reference: + if nodes[texNodeName].image is not None: + tex_size = nodes[texNodeName].image.size + else: + tex_size = texProperty.tex_reference_size + if tex_size[0] > 0 and tex_size[1] > 0: + if self.mat_ver == 1: + tex_x = nodes[uvNodeName].node_tree.nodes["Create Tex Coord"].node_tree.nodes + tex_y = nodes[uvNodeName].node_tree.nodes["Create Tex Coord.001"].node_tree.nodes + imageWidthNode = nodes[uvNodeName].node_tree.nodes["Image Width Factor"] + imageHeightNode = nodes[uvNodeName].node_tree.nodes["Image Height Factor"] + # 1024 == 2^16 / 2^6 (converting 0.16 to 10.5 fixed point) + imageWidthNode.outputs[0].default_value = 1024 / tex_size[0] + imageHeightNode.outputs[0].default_value = 1024 / tex_size[1] - # Has Alpha - nodes[getTextureColorName].inputs[3].default_value = \ - 1 if ('A' in texFormat or \ - (texFormat[:2] == 'CI' and 'A' in ciFormat)) else 0 + update_tex_values_field( + self, + texProperty.S, + tex_x, + tex_size[0], + self.rdp_settings.g_tex_gen or self.rdp_settings.g_tex_gen_linear, + uvBasisScale[0], + scale[0], + texProperty.autoprop, + False, + texIndex, + "S", + ) + update_tex_values_field( + self, + texProperty.T, + tex_y, + tex_size[1], + self.rdp_settings.g_tex_gen or self.rdp_settings.g_tex_gen_linear, + uvBasisScale[1], + scale[1], + texProperty.autoprop, + True, + texIndex, + "T", + ) + elif self.mat_ver == 2: + tex_x = nodes + tex_y = nodes + imageFactorNode = nodes["Tex " + str(texIndex) + " Image Factor"] + imageFactorNode.inputs[0].default_value = 1024 / tex_size[0] + imageFactorNode.inputs[1].default_value = 1024 / tex_size[1] - # Is Intensity - nodes[getTextureColorName].inputs[4].default_value =\ - 1 if (texFormat == 'I4' or texFormat == 'I8') else 0 + update_tex_values_field_v2( + self, texProperty.S, tex_size, uvBasisScale, scale, texProperty.autoprop, texIndex, "S" + ) + update_tex_values_field_v2( + self, texProperty.T, tex_size, uvBasisScale, scale, texProperty.autoprop, texIndex, "T" + ) + elif self.mat_ver >= 3: + if self.mat_ver > 3: + f3dMat = self.f3d_mat + else: + f3dMat = self + if self.mat_ver == 3 or hasNodeGraph(self): + update_tex_values_field_v3(self, texProperty, tex_size, uvBasisScale, scale, texIndex) + # nodes[texNodeName].interpolation = "Closest" + nodes[texNodeName].interpolation = ( + "Closest" if f3dMat.rdp_settings.g_mdsft_text_filt == "G_TF_POINT" else "Linear" + ) + else: + if texProperty.autoprop: + setAutoProp(texProperty.S, tex_size[0]) + setAutoProp(texProperty.T, tex_size[1]) + else: + print("Error: Unhandled material version " + str(self.mat_ver) + " for texture properties.") - else: - nodes[texNodeName + ' Is Greyscale'].outputs[0].default_value = \ - 1 if (texFormat[0] == 'I' or \ - (texFormat[:2] == 'CI' and ciFormat[0] == 'I')) else 0 - nodes[texNodeName + ' Has Alpha'].outputs[0].default_value = \ - 1 if ('A' in texFormat or \ - (texFormat[:2] == 'CI' and 'A' in ciFormat))else 0 + texFormat = texProperty.tex_format + ciFormat = texProperty.ci_format + if self.mat_ver >= 3: # No nodes, only sockets (0 = color, 1 = alpha) + if self.mat_ver == 3 or hasNodeGraph(self): + getTextureColorName = "Get Texture Color" if texIndex == 0 else "Get Texture Color.001" + # Is Greyscale + nodes[getTextureColorName].inputs[2].default_value = ( + 1 if (texFormat[0] == "I" or (texFormat[:2] == "CI" and ciFormat[0] == "I")) else 0 + ) + + # Has Alpha + nodes[getTextureColorName].inputs[3].default_value = ( + 1 if ("A" in texFormat or (texFormat[:2] == "CI" and "A" in ciFormat)) else 0 + ) + + # Is Intensity + nodes[getTextureColorName].inputs[4].default_value = ( + 1 if (texFormat == "I4" or texFormat == "I8") else 0 + ) + + else: + nodes[texNodeName + " Is Greyscale"].outputs[0].default_value = ( + 1 if (texFormat[0] == "I" or (texFormat[:2] == "CI" and ciFormat[0] == "I")) else 0 + ) + nodes[texNodeName + " Has Alpha"].outputs[0].default_value = ( + 1 if ("A" in texFormat or (texFormat[:2] == "CI" and "A" in ciFormat)) else 0 + ) + + if texNodeName + " Is Intensity" in nodes: + nodes[texNodeName + " Is Intensity"].outputs[0].default_value = ( + 1 if (texFormat == "I4" or texFormat == "I8") else 0 + ) + else: + print("Using old node graph, cannot set intensity as alpha.") - if texNodeName + " Is Intensity" in nodes: - nodes[texNodeName + " Is Intensity"].outputs[0].default_value =\ - 1 if (texFormat == 'I4' or texFormat == 'I8') else 0 - else: - print("Using old node graph, cannot set intensity as alpha.") def update_tex_values_and_formats(self, context): - if hasattr(context, 'material') and context.material is not None: - if context.material.mat_ver > 3: - material = context.material.f3d_mat - useLargeTextures = material.use_large_textures - isMultiTexture = "multitexture" in material.presetName.lower() - else: - material = context.material - useLargeTextures = False - isMultiTexture = False + if hasattr(context, "material") and context.material is not None: + if context.material.mat_ver > 3: + material = context.material.f3d_mat + useLargeTextures = material.use_large_textures + isMultiTexture = "multitexture" in material.presetName.lower() + else: + material = context.material + useLargeTextures = False + isMultiTexture = False - if context.material.f3d_update_flag: - return - context.material.f3d_update_flag = True - if material.tex0 == self and material.tex0.tex is not None: - if isMultiTexture: - material.tex0.tex_format = 'RGBA16' - else: - material.tex0.tex_format = getOptimalFormat(material.tex0.tex, useLargeTextures) - if material.tex1 == self and material.tex1.tex is not None: - if isMultiTexture: - material.tex1.tex_format = 'RGBA16' - else: - material.tex1.tex_format = getOptimalFormat(material.tex1.tex, useLargeTextures) - context.material.f3d_update_flag = False + if context.material.f3d_update_flag: + return + context.material.f3d_update_flag = True + if material.tex0 == self and material.tex0.tex is not None: + if isMultiTexture: + material.tex0.tex_format = "RGBA16" + else: + material.tex0.tex_format = getOptimalFormat(material.tex0.tex, useLargeTextures) + if material.tex1 == self and material.tex1.tex is not None: + if isMultiTexture: + material.tex1.tex_format = "RGBA16" + else: + material.tex1.tex_format = getOptimalFormat(material.tex1.tex, useLargeTextures) + context.material.f3d_update_flag = False + + update_tex_values(context.material, context) + else: + if self.tex is not None: + self.tex_format = getOptimalFormat(self.tex, False) - update_tex_values(context.material, context) - else: - if self.tex is not None: - self.tex_format = getOptimalFormat(self.tex, False) def update_tex_values(self, context): - if hasattr(context, 'material') and context.material is not None: - material = context.material # Handles case of texture property groups - if material.f3d_update_flag: - return - material.f3d_update_flag = True - update_tex_values_manual(material, context) - material.f3d_update_flag = False + if hasattr(context, "material") and context.material is not None: + material = context.material # Handles case of texture property groups + if material.f3d_update_flag: + return + material.f3d_update_flag = True + update_tex_values_manual(material, context) + material.f3d_update_flag = False + def update_tex_values_manual(self, context): - if self.mat_ver > 3: - material = self.f3d_mat - else: - material = self - isTexGen = material.rdp_settings.g_tex_gen or material.rdp_settings.g_tex_gen_linear + if self.mat_ver > 3: + material = self.f3d_mat + else: + material = self + isTexGen = material.rdp_settings.g_tex_gen or material.rdp_settings.g_tex_gen_linear - if material.scale_autoprop: - tex_size = None - if material.tex0.tex is not None and material.tex1.tex is not None: - tex_size = material.tex0.tex.size if material.uv_basis == 'TEXEL0' else \ - material.tex1.tex.size - elif material.tex0.tex is not None: - tex_size = material.tex0.tex.size - elif material.tex1.tex is not None: - tex_size = material.tex1.tex.size + if material.scale_autoprop: + tex_size = None + if material.tex0.tex is not None and material.tex1.tex is not None: + tex_size = material.tex0.tex.size if material.uv_basis == "TEXEL0" else material.tex1.tex.size + elif material.tex0.tex is not None: + tex_size = material.tex0.tex.size + elif material.tex1.tex is not None: + tex_size = material.tex1.tex.size - if isTexGen and tex_size is not None: - material.tex_scale = ((tex_size[0] - 1) / 1024, - (tex_size[1] - 1) / 1024) - else: - material.tex_scale = (1,1) + if isTexGen and tex_size is not None: + material.tex_scale = ((tex_size[0] - 1) / 1024, (tex_size[1] - 1) / 1024) + else: + material.tex_scale = (1, 1) + useDict = all_combiner_uses(material) - useDict = all_combiner_uses(material) + if ( + useDict["Texture 0"] + and material.tex0.tex is not None + and useDict["Texture 1"] + and material.tex1.tex is not None + and material.tex0.tex.size[0] > 0 + and material.tex0.tex.size[1] > 0 + and material.tex1.tex.size[0] > 0 + and material.tex1.tex.size[1] > 0 + ): + if material.uv_basis == "TEXEL0": + uvBasisScale0 = (1, 1) + uvBasisScale1 = ( + material.tex0.tex.size[0] / material.tex1.tex.size[0], + material.tex0.tex.size[1] / material.tex1.tex.size[1], + ) + else: + uvBasisScale1 = (1, 1) + uvBasisScale0 = ( + material.tex1.tex.size[0] / material.tex0.tex.size[0], + material.tex1.tex.size[1] / material.tex0.tex.size[1], + ) + else: + uvBasisScale0 = (1, 1) + uvBasisScale1 = (1, 1) - if useDict['Texture 0'] and material.tex0.tex is not None and \ - useDict['Texture 1'] and material.tex1.tex is not None and\ - material.tex0.tex.size[0] > 0 and material.tex0.tex.size[1] > 0 and\ - material.tex1.tex.size[0] > 0 and material.tex1.tex.size[1] > 0: - if material.uv_basis == 'TEXEL0': - uvBasisScale0 = (1,1) - uvBasisScale1 = (material.tex0.tex.size[0] / material.tex1.tex.size[0], - material.tex0.tex.size[1] / material.tex1.tex.size[1]) - else: - uvBasisScale1 = (1,1) - uvBasisScale0 = (material.tex1.tex.size[0] / material.tex0.tex.size[0], - material.tex1.tex.size[1] / material.tex0.tex.size[1]) - else: - uvBasisScale0 = (1,1) - uvBasisScale1 = (1,1) + update_tex_values_index( + self, context, material.tex0, "Texture 0", "Get UV", isTexGen, uvBasisScale0, material.tex_scale, 0 + ) + update_tex_values_index( + self, context, material.tex1, "Texture 1", "Get UV.001", isTexGen, uvBasisScale1, material.tex_scale, 1 + ) - update_tex_values_index(self, context, material.tex0, 'Texture 0', - 'Get UV', isTexGen, uvBasisScale0, material.tex_scale, 0) - update_tex_values_index(self, context, material.tex1, 'Texture 1', - 'Get UV.001', isTexGen, uvBasisScale1, material.tex_scale, 1) def getMaterialScrollDimensions(material): - useDict = all_combiner_uses(material) + useDict = all_combiner_uses(material) + + if ( + useDict["Texture 0"] + and material.tex0.tex is not None + and useDict["Texture 1"] + and material.tex1.tex is not None + and material.tex0.tex.size[0] > 0 + and material.tex0.tex.size[1] > 0 + and material.tex1.tex.size[0] > 0 + and material.tex1.tex.size[1] > 0 + ): + if material.uv_basis == "TEXEL0": + return material.tex0.tex.size + else: + return material.tex1.tex.size + elif ( + useDict["Texture 1"] + and material.tex1.tex is not None + and material.tex1.tex.size[0] > 0 + and material.tex1.tex.size[1] > 0 + ): + return material.tex1.tex.size + elif ( + useDict["Texture 0"] + and material.tex0.tex is not None + and material.tex0.tex.size[0] > 0 + and material.tex0.tex.size[1] > 0 + ): + return material.tex0.tex.size + else: + return [32, 32] - if useDict['Texture 0'] and material.tex0.tex is not None and \ - useDict['Texture 1'] and material.tex1.tex is not None and\ - material.tex0.tex.size[0] > 0 and material.tex0.tex.size[1] > 0 and\ - material.tex1.tex.size[0] > 0 and material.tex1.tex.size[1] > 0: - if material.uv_basis == 'TEXEL0': - return material.tex0.tex.size - else: - return material.tex1.tex.size - elif useDict['Texture 1'] and material.tex1.tex is not None and\ - material.tex1.tex.size[0] > 0 and material.tex1.tex.size[1] > 0: - return material.tex1.tex.size - elif useDict['Texture 0'] and material.tex0.tex is not None and\ - material.tex0.tex.size[0] > 0 and material.tex0.tex.size[1] > 0: - return material.tex0.tex.size - else: - return [32, 32] def update_preset(self, context): - if hasattr(context, 'material_slot') and context.material_slot is not None: - material = context.material_slot.material - if material.mat_ver < 4 and material.f3d_preset != 'Custom': - materialSettings = materialPresetDict[material.f3d_preset] - materialSettings.applyToMaterial(material, False, update_node_values_of_material, bpy.context) + if hasattr(context, "material_slot") and context.material_slot is not None: + material = context.material_slot.material + if material.mat_ver < 4 and material.f3d_preset != "Custom": + materialSettings = materialPresetDict[material.f3d_preset] + materialSettings.applyToMaterial(material, False, update_node_values_of_material, bpy.context) + def update_preset_manual(material, context): - if material.mat_ver < 4 and material.f3d_preset != 'Custom': - materialSettings = materialPresetDict[material.f3d_preset] - materialSettings.applyToMaterial(material, False, update_node_values_of_material, bpy.context) + if material.mat_ver < 4 and material.f3d_preset != "Custom": + materialSettings = materialPresetDict[material.f3d_preset] + materialSettings.applyToMaterial(material, False, update_node_values_of_material, bpy.context) + + if material.mat_ver > 3: + if hasNodeGraph(material): + update_node_values_of_material(material, context) + update_tex_values_manual(material, context) - if material.mat_ver > 3: - if hasNodeGraph(material): - update_node_values_of_material(material, context) - update_tex_values_manual(material, context) def update_preset_manual_v4(material, preset): - override = bpy.context.copy() - override['material'] = material - if preset == 'Shaded Solid': - preset = 'sm64_shaded_solid' - if preset == 'Shaded Texture': - preset = "sm64_shaded_texture" - if preset.lower() != "custom": - material.f3d_update_flag = True - bpy.ops.script.execute_preset(override, - filepath=findF3DPresetPath(preset), - menu_idname='MATERIAL_MT_f3d_presets') - material.f3d_update_flag = False + override = bpy.context.copy() + override["material"] = material + if preset == "Shaded Solid": + preset = "sm64_shaded_solid" + if preset == "Shaded Texture": + preset = "sm64_shaded_texture" + if preset.lower() != "custom": + material.f3d_update_flag = True + bpy.ops.script.execute_preset( + override, filepath=findF3DPresetPath(preset), menu_idname="MATERIAL_MT_f3d_presets" + ) + material.f3d_update_flag = False + def hasNodeGraph(material): - return "F3D v3" in material.node_tree.nodes - -def createF3DMat(obj, preset = 'Shaded Solid', index = None): - material = bpy.data.materials.new('f3d_material') - if obj is not None: - if index is None: - obj.data.materials.append(material) - if bpy.context.object is not None: - bpy.context.object.active_material_index = len(obj.material_slots) - 1 - else: - obj.material_slots[index].material = material - if bpy.context.object is not None: - bpy.context.object.active_material_index = index - - material.is_f3d = True - material.mat_ver = 4 - - if material.mat_ver > 3 and not bpy.context.scene.generateF3DNodeGraph: - material.use_nodes = True - material.blend_method = 'BLEND' - material.show_transparent_back = False - - # Remove default shader - node_tree = material.node_tree - nodes = material.node_tree.nodes - links = material.node_tree.links - bsdf = nodes.get('Principled BSDF') - material_output = nodes.get('Material Output') - - tex0Node = node_tree.nodes.new("ShaderNodeTexImage") - tex0Node.name = "Texture 0" - tex0Node.label = "Texture 0" - tex0Node.location = [-300, 300] - tex1Node = node_tree.nodes.new("ShaderNodeTexImage") - tex1Node.name = "Texture 1" - tex1Node.label = "Texture 1" - tex1Node.location = [-300, 50] - - links.new(bsdf.inputs["Base Color"], tex0Node.outputs["Color"]) - links.new(bsdf.inputs["Subsurface Color"], tex1Node.outputs["Color"]) - bsdf.inputs['Specular'].default_value = 0 - - update_preset_manual_v4(material, preset) - - return material - - material.use_nodes = True - material.blend_method = 'HASHED' - material.show_transparent_back = False - - # Remove default shader - node_tree = material.node_tree - nodes = material.node_tree.nodes - links = material.node_tree.links - nodes.remove(nodes.get('Principled BSDF')) - material_output = nodes.get('Material Output') - - x = 0 - y = 0 - - uvDict = {} - #texGenNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', - # 'Texture Gen', x, y, 'Texture Gen', uvDict) - #texGenLinearNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', - # 'Texture Gen Linear', x, y, 'Texture Gen Linear', uvDict) - - # Create UV nodes - uvNode0, x, y = createUVInputsAndGroup(node_tree, 0, x, y) - uvNode1, x, y = createUVInputsAndGroup(node_tree, 1, x, y) - - x += 600 - y = 0 - x,y, primNode = addColorWithAlphaNode("Primitive Color", x, y, node_tree) - x,y, envNode = addColorWithAlphaNode("Environment Color", x, y, node_tree) - nodeDict, x, y = addNodeListAt(node_tree, { - 'Texture 0': 'ShaderNodeTexImage', - 'Texture 1': 'ShaderNodeTexImage', - #'Primitive Color': 'ShaderNodeRGB', - #'Shade Color': 'ShaderNodeBsdfDiffuse', - #'Environment Color': 'ShaderNodeRGB', - 'Chroma Key Center': 'ShaderNodeRGB', - 'Chroma Key Scale': 'ShaderNodeRGB', - #'Primitive Alpha': 'ShaderNodeValue', - #'Shade Alpha': 'ShaderNodeValue', - #'Environment Alpha' : 'ShaderNodeValue', - 'LOD Fraction' : 'ShaderNodeValue', - 'Primitive LOD Fraction' : 'ShaderNodeValue', - 'Noise' : 'ShaderNodeTexNoise', - 'YUV Convert K4' : 'ShaderNodeValue', - 'YUV Convert K5' : 'ShaderNodeValue', - '1' : 'ShaderNodeValue', - '0' : 'ShaderNodeValue', - }, x, y) - - # Set noise scale - nodeDict["Noise"].inputs[2].default_value = 10 - - createGroupLink(node_tree, nodeDict['Texture 0'].inputs[0], - uvNode0.outputs[0], 'NodeSocketVector', 'UV0Output') - createGroupLink(node_tree, nodeDict['Texture 1'].inputs[0], - uvNode1.outputs[0], 'NodeSocketVector', 'UV1Output') + return "F3D v3" in material.node_tree.nodes - # Note: Because of modulo operations on UVs, aliasing occurs - # due to mipmapping when 'Linear' filtering is used. - # When using 'Cubic', clamping doesn't work correctly either. - # Thus 'Closest' is used instead. - nodes['Texture 0'].interpolation = 'Linear' - nodes['Texture 1'].interpolation = 'Linear' +def createF3DMat(obj, preset="Shaded Solid", index=None): + material = bpy.data.materials.new("f3d_material") + if obj is not None: + if index is None: + obj.data.materials.append(material) + if bpy.context.object is not None: + bpy.context.object.active_material_index = len(obj.material_slots) - 1 + else: + obj.material_slots[index].material = material + if bpy.context.object is not None: + bpy.context.object.active_material_index = index - # Create texture format nodes - x += 300 - y = 0 - colorNode0, x, y = createTextureInputsAndGroup(node_tree, 0, x, y) - colorNode1, x, y = createTextureInputsAndGroup(node_tree, 1, x, y) - nodeDict["Texture 0"] = colorNode0 - nodeDict["Texture 1"] = colorNode1 + material.is_f3d = True + material.mat_ver = 4 - # Create cases A-D - #x += 300 - #y = 0 - #caseNodeDict1, x, y = addNodeListAt(node_tree, - # caseTemplateDict2, x, y, 1) - # - #caseNodeDict2, x, y = addNodeListAt(node_tree, - # caseTemplateDict2, x, y, 2) + if material.mat_ver > 3 and not bpy.context.scene.generateF3DNodeGraph: + material.use_nodes = True + material.blend_method = "BLEND" + material.show_transparent_back = False - # create shade node - x += 300 - y = 0 - #lightingNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', - # 'Lighting', x, y) - #shadingNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', - # 'Shading', x, y) - #ambientNode, x, y = addNodeAt(node_tree, 'ShaderNodeRGB', - # 'Ambient Color', x, y) - nodeDict['Shade Color'] = createShadeNode(node_tree, [x, y]) + # Remove default shader + node_tree = material.node_tree + nodes = material.node_tree.nodes + links = material.node_tree.links + bsdf = nodes.get("Principled BSDF") + material_output = nodes.get("Material Output") - #x += 300 - #y = 0 - #otherDict = {} - #cycleTypeNode, x, y = \ - # addNodeAt(node_tree, 'ShaderNodeValue', 'Cycle Type', x, y, 'Cycle Type', otherDict) - #cullFront, x, y = \ - # addNodeAt(node_tree, 'ShaderNodeValue', 'Cull Front', x, y, "Cull Front", otherDict) - #cullBack, x, y = \ - # addNodeAt(node_tree, 'ShaderNodeValue', 'Cull Back', x, y, 'Cull Back', otherDict) + tex0Node = node_tree.nodes.new("ShaderNodeTexImage") + tex0Node.name = "Texture 0" + tex0Node.label = "Texture 0" + tex0Node.location = [-300, 300] + tex1Node = node_tree.nodes.new("ShaderNodeTexImage") + tex1Node.name = "Texture 1" + tex1Node.label = "Texture 1" + tex1Node.location = [-300, 50] - x += 300 - y = 0 - # Create combiner nodes - # caseNodeDict is the A-D for color and alpha - # nodeDict is all sources - # otherDict is other shader inputs + links.new(bsdf.inputs["Base Color"], tex0Node.outputs["Color"]) + links.new(bsdf.inputs["Subsurface Color"], tex1Node.outputs["Color"]) + bsdf.inputs["Specular"].default_value = 0 - combiner1 = createNodeCombiner(node_tree, 1) - combiner1.location = [x, y] + update_preset_manual_v4(material, preset) - combiner2 = createNodeCombiner(node_tree, 2) - combiner2.location = [x, y-400] + return material - x += 300 - y = 0 - finalNode, x, y = createNodeF3D(node_tree, [x, y]) + material.use_nodes = True + material.blend_method = "HASHED" + material.show_transparent_back = False - links.new(finalNode.inputs[0], combiner1.outputs[0]) - links.new(finalNode.inputs[1], combiner1.outputs[1]) - links.new(finalNode.inputs[2], combiner2.outputs[0]) - links.new(finalNode.inputs[3], combiner2.outputs[1]) + # Remove default shader + node_tree = material.node_tree + nodes = material.node_tree.nodes + links = material.node_tree.links + nodes.remove(nodes.get("Principled BSDF")) + material_output = nodes.get("Material Output") - # link new node output to material_output input - links.new(material_output.inputs[0], finalNode.outputs[0]) + x = 0 + y = 0 - x += 300 - y = 0 - material_output.location = [x, y] + uvDict = {} + # texGenNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', + # 'Texture Gen', x, y, 'Texture Gen', uvDict) + # texGenLinearNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', + # 'Texture Gen Linear', x, y, 'Texture Gen Linear', uvDict) - #update_node_values_directly(material, bpy.context) - #update_tex_values(material, bpy.context) + # Create UV nodes + uvNode0, x, y = createUVInputsAndGroup(node_tree, 0, x, y) + uvNode1, x, y = createUVInputsAndGroup(node_tree, 1, x, y) - if material.mat_ver > 3: - update_preset_manual_v4(material, preset) - else: - # This won't update because material is not in context - if preset in [enumValue[0] for enumValue in enumMaterialPresets]: - material.f3d_preset = preset - else: - raise PluginError('Enum \'' + preset + '\' not found in material preset enum list.') - # That's why we force update - update_preset_manual(material, bpy.context) - #materialPresetDict['Shaded Texture'].applyToMaterial(material) + x += 600 + y = 0 + x, y, primNode = addColorWithAlphaNode("Primitive Color", x, y, node_tree) + x, y, envNode = addColorWithAlphaNode("Environment Color", x, y, node_tree) + nodeDict, x, y = addNodeListAt( + node_tree, + { + "Texture 0": "ShaderNodeTexImage", + "Texture 1": "ShaderNodeTexImage", + #'Primitive Color': 'ShaderNodeRGB', + #'Shade Color': 'ShaderNodeBsdfDiffuse', + #'Environment Color': 'ShaderNodeRGB', + "Chroma Key Center": "ShaderNodeRGB", + "Chroma Key Scale": "ShaderNodeRGB", + #'Primitive Alpha': 'ShaderNodeValue', + #'Shade Alpha': 'ShaderNodeValue', + #'Environment Alpha' : 'ShaderNodeValue', + "LOD Fraction": "ShaderNodeValue", + "Primitive LOD Fraction": "ShaderNodeValue", + "Noise": "ShaderNodeTexNoise", + "YUV Convert K4": "ShaderNodeValue", + "YUV Convert K5": "ShaderNodeValue", + "1": "ShaderNodeValue", + "0": "ShaderNodeValue", + }, + x, + y, + ) + + # Set noise scale + nodeDict["Noise"].inputs[2].default_value = 10 + + createGroupLink(node_tree, nodeDict["Texture 0"].inputs[0], uvNode0.outputs[0], "NodeSocketVector", "UV0Output") + createGroupLink(node_tree, nodeDict["Texture 1"].inputs[0], uvNode1.outputs[0], "NodeSocketVector", "UV1Output") + + # Note: Because of modulo operations on UVs, aliasing occurs + # due to mipmapping when 'Linear' filtering is used. + # When using 'Cubic', clamping doesn't work correctly either. + # Thus 'Closest' is used instead. + nodes["Texture 0"].interpolation = "Linear" + nodes["Texture 1"].interpolation = "Linear" + + # Create texture format nodes + x += 300 + y = 0 + colorNode0, x, y = createTextureInputsAndGroup(node_tree, 0, x, y) + colorNode1, x, y = createTextureInputsAndGroup(node_tree, 1, x, y) + nodeDict["Texture 0"] = colorNode0 + nodeDict["Texture 1"] = colorNode1 + + # Create cases A-D + # x += 300 + # y = 0 + # caseNodeDict1, x, y = addNodeListAt(node_tree, + # caseTemplateDict2, x, y, 1) + # + # caseNodeDict2, x, y = addNodeListAt(node_tree, + # caseTemplateDict2, x, y, 2) + + # create shade node + x += 300 + y = 0 + # lightingNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', + # 'Lighting', x, y) + # shadingNode, x, y = addNodeAt(node_tree, 'ShaderNodeValue', + # 'Shading', x, y) + # ambientNode, x, y = addNodeAt(node_tree, 'ShaderNodeRGB', + # 'Ambient Color', x, y) + nodeDict["Shade Color"] = createShadeNode(node_tree, [x, y]) + + # x += 300 + # y = 0 + # otherDict = {} + # cycleTypeNode, x, y = \ + # addNodeAt(node_tree, 'ShaderNodeValue', 'Cycle Type', x, y, 'Cycle Type', otherDict) + # cullFront, x, y = \ + # addNodeAt(node_tree, 'ShaderNodeValue', 'Cull Front', x, y, "Cull Front", otherDict) + # cullBack, x, y = \ + # addNodeAt(node_tree, 'ShaderNodeValue', 'Cull Back', x, y, 'Cull Back', otherDict) + + x += 300 + y = 0 + # Create combiner nodes + # caseNodeDict is the A-D for color and alpha + # nodeDict is all sources + # otherDict is other shader inputs + + combiner1 = createNodeCombiner(node_tree, 1) + combiner1.location = [x, y] + + combiner2 = createNodeCombiner(node_tree, 2) + combiner2.location = [x, y - 400] + + x += 300 + y = 0 + finalNode, x, y = createNodeF3D(node_tree, [x, y]) + + links.new(finalNode.inputs[0], combiner1.outputs[0]) + links.new(finalNode.inputs[1], combiner1.outputs[1]) + links.new(finalNode.inputs[2], combiner2.outputs[0]) + links.new(finalNode.inputs[3], combiner2.outputs[1]) + + # link new node output to material_output input + links.new(material_output.inputs[0], finalNode.outputs[0]) + + x += 300 + y = 0 + material_output.location = [x, y] + + # update_node_values_directly(material, bpy.context) + # update_tex_values(material, bpy.context) + + if material.mat_ver > 3: + update_preset_manual_v4(material, preset) + else: + # This won't update because material is not in context + if preset in [enumValue[0] for enumValue in enumMaterialPresets]: + material.f3d_preset = preset + else: + raise PluginError("Enum '" + preset + "' not found in material preset enum list.") + # That's why we force update + update_preset_manual(material, bpy.context) + # materialPresetDict['Shaded Texture'].applyToMaterial(material) + + return material - return material def reloadDefaultF3DPresets(): - presetNameToFilename = {} - for game, gamePresets in material_presets.items(): - for presetName, preset in gamePresets.items(): - presetNameToFilename[bpy.path.display_name(presetName)] = presetName - for material in bpy.data.materials: - if material.mat_ver > 3 and material.f3d_mat.presetName in presetNameToFilename: - update_preset_manual_v4(material, presetNameToFilename[material.f3d_mat.presetName]) + presetNameToFilename = {} + for game, gamePresets in material_presets.items(): + for presetName, preset in gamePresets.items(): + presetNameToFilename[bpy.path.display_name(presetName)] = presetName + for material in bpy.data.materials: + if material.mat_ver > 3 and material.f3d_mat.presetName in presetNameToFilename: + update_preset_manual_v4(material, presetNameToFilename[material.f3d_mat.presetName]) + class CreateFast3DMaterial(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.create_f3d_mat' - bl_label = "Create Fast3D Material" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.create_f3d_mat" + bl_label = "Create Fast3D Material" + bl_options = {"REGISTER", "UNDO", "PRESET"} + + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + obj = bpy.context.view_layer.objects.active + if obj is None: + self.report({"ERROR"}, "No active object selected.") + else: + preset = getDefaultMaterialPreset("Shaded Solid") + createF3DMat(obj, preset) + self.report({"INFO"}, "Created new Fast3D material.") + return {"FINISHED"} # must return a set - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - obj = bpy.context.view_layer.objects.active - if obj is None: - self.report({'ERROR'}, 'No active object selected.') - else: - preset = getDefaultMaterialPreset("Shaded Solid") - createF3DMat(obj, preset) - self.report({'INFO'}, 'Created new Fast3D material.') - return {'FINISHED'} # must return a set class ReloadDefaultF3DPresets(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.reload_f3d_presets' - bl_label = "Reload Default Fast3D Presets" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.reload_f3d_presets" + bl_label = "Reload Default Fast3D Presets" + bl_options = {"REGISTER", "UNDO", "PRESET"} + + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + reloadDefaultF3DPresets() + self.report({"INFO"}, "Success!") + return {"FINISHED"} # must return a set - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - reloadDefaultF3DPresets() - self.report({'INFO'}, 'Success!') - return {'FINISHED'} # must return a set class TextureFieldProperty(bpy.types.PropertyGroup): - clamp : bpy.props.BoolProperty(name = 'Clamp', - update = update_tex_values) - mirror : bpy.props.BoolProperty(name = 'Mirror', - update = update_tex_values) - low : bpy.props.FloatProperty(name = 'Low', min = 0, max = 1023.75, - update = update_tex_values) - high : bpy.props.FloatProperty(name = 'High', min = 0, max = 1023.75, - update = update_tex_values) - mask : bpy.props.IntProperty(min = 0, max = 15, - update = update_tex_values, default = 5) - shift : bpy.props.IntProperty(min = -5, max = 10, - update = update_tex_values) + clamp: bpy.props.BoolProperty(name="Clamp", update=update_tex_values) + mirror: bpy.props.BoolProperty(name="Mirror", update=update_tex_values) + low: bpy.props.FloatProperty(name="Low", min=0, max=1023.75, update=update_tex_values) + high: bpy.props.FloatProperty(name="High", min=0, max=1023.75, update=update_tex_values) + mask: bpy.props.IntProperty(min=0, max=15, update=update_tex_values, default=5) + shift: bpy.props.IntProperty(min=-5, max=10, update=update_tex_values) + class SetTileSizeScrollProperty(bpy.types.PropertyGroup): - s : bpy.props.IntProperty(min = -4095, max = 4095, default = 0) - t : bpy.props.IntProperty(min = -4095, max = 4095, default = 0) - interval : bpy.props.IntProperty(min = 1, soft_max = 1000, default = 1) + s: bpy.props.IntProperty(min=-4095, max=4095, default=0) + t: bpy.props.IntProperty(min=-4095, max=4095, default=0) + interval: bpy.props.IntProperty(min=1, soft_max=1000, default=1) + class TextureProperty(bpy.types.PropertyGroup): - tex : bpy.props.PointerProperty(type = bpy.types.Image, name = 'Texture', update = update_tex_values_and_formats) + tex: bpy.props.PointerProperty(type=bpy.types.Image, name="Texture", update=update_tex_values_and_formats) - tex_format : bpy.props.EnumProperty(name = 'Format', items = enumTexFormat, default = 'RGBA16', update = update_tex_values) - ci_format : bpy.props.EnumProperty(name = 'CI Format', items = enumCIFormat, default = 'RGBA16', update = update_tex_values) - S : bpy.props.PointerProperty(type = TextureFieldProperty) - T : bpy.props.PointerProperty(type = TextureFieldProperty) + tex_format: bpy.props.EnumProperty(name="Format", items=enumTexFormat, default="RGBA16", update=update_tex_values) + ci_format: bpy.props.EnumProperty(name="CI Format", items=enumCIFormat, default="RGBA16", update=update_tex_values) + S: bpy.props.PointerProperty(type=TextureFieldProperty) + T: bpy.props.PointerProperty(type=TextureFieldProperty) - use_tex_reference: bpy.props.BoolProperty(name = "Use Texture Reference", default = False, update = update_tex_values) - tex_reference: bpy.props.StringProperty(name = "Texture Reference", default = '0x08000000') - tex_reference_size: bpy.props.IntVectorProperty(name = "Texture Reference Size", min = 1, size = 2, default = (32,32), update = update_tex_values) - pal_reference: bpy.props.StringProperty(name = "Palette Reference", default = '0x08000000') - pal_reference_size : bpy.props.IntProperty(name = "Texture Reference Size", min = 1, default = 16) + use_tex_reference: bpy.props.BoolProperty(name="Use Texture Reference", default=False, update=update_tex_values) + tex_reference: bpy.props.StringProperty(name="Texture Reference", default="0x08000000") + tex_reference_size: bpy.props.IntVectorProperty( + name="Texture Reference Size", min=1, size=2, default=(32, 32), update=update_tex_values + ) + pal_reference: bpy.props.StringProperty(name="Palette Reference", default="0x08000000") + pal_reference_size: bpy.props.IntProperty(name="Texture Reference Size", min=1, default=16) + + menu: bpy.props.BoolProperty() + tex_set: bpy.props.BoolProperty(default=True, update=update_node_values) + autoprop: bpy.props.BoolProperty(name="Autoprop", update=update_tex_values, default=True) + save_large_texture: bpy.props.BoolProperty(name="Save Large Texture As PNG", default=True) + tile_scroll: bpy.props.PointerProperty(type=SetTileSizeScrollProperty) + # autoprop : bpy.props.BoolProperty(name = 'Autoprop', update = on_tex_autoprop, default = True) - menu : bpy.props.BoolProperty() - tex_set : bpy.props.BoolProperty(default = True, update = update_node_values) - autoprop : bpy.props.BoolProperty(name = 'Autoprop', update = update_tex_values, default = True) - save_large_texture : bpy.props.BoolProperty(name = "Save Large Texture As PNG", default = True) - tile_scroll : bpy.props.PointerProperty(type = SetTileSizeScrollProperty) - #autoprop : bpy.props.BoolProperty(name = 'Autoprop', update = on_tex_autoprop, default = True) def on_tex_autoprop(texProperty, context): - if texProperty.autoprop and texProperty.tex is not None: - tex_size = texProperty.tex.size - if tex_size[0] > 0 and tex_size[1] > 0: - setAutoProp(texProperty.S, tex_size[0]) - setAutoProp(texProperty.T, tex_size[1]) + if texProperty.autoprop and texProperty.tex is not None: + tex_size = texProperty.tex.size + if tex_size[0] > 0 and tex_size[1] > 0: + setAutoProp(texProperty.S, tex_size[0]) + setAutoProp(texProperty.T, tex_size[1]) + class CombinerProperty(bpy.types.PropertyGroup): - A : bpy.props.EnumProperty( - name = "A", description = "A", items = combiner_enums['Case A'], - default = 'TEXEL0', update = update_node_values) + A: bpy.props.EnumProperty( + name="A", description="A", items=combiner_enums["Case A"], default="TEXEL0", update=update_node_values + ) - B : bpy.props.EnumProperty( - name = "B", description = "B", items = combiner_enums['Case B'], - default = '0', update = update_node_values) + B: bpy.props.EnumProperty( + name="B", description="B", items=combiner_enums["Case B"], default="0", update=update_node_values + ) - C : bpy.props.EnumProperty( - name = "C", description = "C", items = combiner_enums['Case C'], - default = 'SHADE', update = update_node_values) + C: bpy.props.EnumProperty( + name="C", description="C", items=combiner_enums["Case C"], default="SHADE", update=update_node_values + ) - D : bpy.props.EnumProperty( - name = "D", description = "D", items = combiner_enums['Case D'], - default = '0', update = update_node_values) + D: bpy.props.EnumProperty( + name="D", description="D", items=combiner_enums["Case D"], default="0", update=update_node_values + ) - A_alpha : bpy.props.EnumProperty( - name = "A Alpha", description = "A Alpha", - items = combiner_enums['Case A Alpha'], - default = '0', update = update_node_values) + A_alpha: bpy.props.EnumProperty( + name="A Alpha", + description="A Alpha", + items=combiner_enums["Case A Alpha"], + default="0", + update=update_node_values, + ) - B_alpha : bpy.props.EnumProperty( - name = "B Alpha", description = "B Alpha", - items = combiner_enums['Case B Alpha'], - default = '0', update = update_node_values) + B_alpha: bpy.props.EnumProperty( + name="B Alpha", + description="B Alpha", + items=combiner_enums["Case B Alpha"], + default="0", + update=update_node_values, + ) - C_alpha : bpy.props.EnumProperty( - name = "C Alpha", description = "C Alpha", - items = combiner_enums['Case C Alpha'], - default = '0', update = update_node_values) + C_alpha: bpy.props.EnumProperty( + name="C Alpha", + description="C Alpha", + items=combiner_enums["Case C Alpha"], + default="0", + update=update_node_values, + ) + + D_alpha: bpy.props.EnumProperty( + name="D Alpha", + description="D Alpha", + items=combiner_enums["Case D Alpha"], + default="ENVIRONMENT", + update=update_node_values, + ) - D_alpha : bpy.props.EnumProperty( - name = "D Alpha", description = "D Alpha", - items = combiner_enums['Case D Alpha'], - default = 'ENVIRONMENT', update = update_node_values) class ProceduralAnimProperty(bpy.types.PropertyGroup): - speed : bpy.props.FloatProperty(name = 'Speed', default = 1) - amplitude : bpy.props.FloatProperty(name = 'Amplitude', default = 1) - frequency : bpy.props.FloatProperty(name = 'Frequency', default = 1) - #spaceFrequency : bpy.props.FloatVectorProperty(name = 'Space Frequency', - # size = 3, default = (0,0,0)) - spaceFrequency : bpy.props.FloatProperty(name = 'Space Frequency', - default = 0) - offset : bpy.props.FloatProperty(name = 'Offset', default = 0) - noiseAmplitude : bpy.props.FloatProperty(name = 'Amplitude', default = 1) - animate : bpy.props.BoolProperty() - animType : bpy.props.EnumProperty(name = 'Type', items = enumTexScroll) + speed: bpy.props.FloatProperty(name="Speed", default=1) + amplitude: bpy.props.FloatProperty(name="Amplitude", default=1) + frequency: bpy.props.FloatProperty(name="Frequency", default=1) + # spaceFrequency : bpy.props.FloatVectorProperty(name = 'Space Frequency', + # size = 3, default = (0,0,0)) + spaceFrequency: bpy.props.FloatProperty(name="Space Frequency", default=0) + offset: bpy.props.FloatProperty(name="Offset", default=0) + noiseAmplitude: bpy.props.FloatProperty(name="Amplitude", default=1) + animate: bpy.props.BoolProperty() + animType: bpy.props.EnumProperty(name="Type", items=enumTexScroll) + class ProcAnimVectorProperty(bpy.types.PropertyGroup): - x : bpy.props.PointerProperty(type = ProceduralAnimProperty) - y : bpy.props.PointerProperty(type = ProceduralAnimProperty) - z : bpy.props.PointerProperty(type = ProceduralAnimProperty) - pivot : bpy.props.FloatVectorProperty(size = 2, name = 'Pivot') - angularSpeed : bpy.props.FloatProperty(default = 1, name = 'Angular Speed') - menu : bpy.props.BoolProperty() + x: bpy.props.PointerProperty(type=ProceduralAnimProperty) + y: bpy.props.PointerProperty(type=ProceduralAnimProperty) + z: bpy.props.PointerProperty(type=ProceduralAnimProperty) + pivot: bpy.props.FloatVectorProperty(size=2, name="Pivot") + angularSpeed: bpy.props.FloatProperty(default=1, name="Angular Speed") + menu: bpy.props.BoolProperty() + class PrimDepthSettings(bpy.types.PropertyGroup): - z: bpy.props.IntProperty( - name="Prim Depth: Z", - default=0, - soft_min=-1, - soft_max=0x7fff, - description= - '''The value to use for z is the screen Z position of the object you are rendering. This is a value ranging from 0x0000 to 0x7fff, where 0x0000 usually corresponds to the near clipping plane and 0x7fff usually corresponds to the far clipping plane. You can use -1 to force Z to be at the far clipping plane.''' - ) - dz: bpy.props.IntProperty( - name="Prim Depth: Delta Z", - default=0, - soft_min=0, - soft_max=0x4000, - description= - '''The dz value should be set to 0. This value is used for antialiasing and objects drawn in decal render mode and must always be a power of 2 (0, 1, 2, 4, 8, ... 0x4000). If you are using decal mode and part of the decaled object is not being rendered correctly, try setting this to powers of 2. Otherwise use 0.''' - ) + z: bpy.props.IntProperty( + name="Prim Depth: Z", + default=0, + soft_min=-1, + soft_max=0x7FFF, + description="""The value to use for z is the screen Z position of the object you are rendering. This is a value ranging from 0x0000 to 0x7fff, where 0x0000 usually corresponds to the near clipping plane and 0x7fff usually corresponds to the far clipping plane. You can use -1 to force Z to be at the far clipping plane.""", + ) + dz: bpy.props.IntProperty( + name="Prim Depth: Delta Z", + default=0, + soft_min=0, + soft_max=0x4000, + description="""The dz value should be set to 0. This value is used for antialiasing and objects drawn in decal render mode and must always be a power of 2 (0, 1, 2, 4, 8, ... 0x4000). If you are using decal mode and part of the decaled object is not being rendered correctly, try setting this to powers of 2. Otherwise use 0.""", + ) + class RDPSettings(bpy.types.PropertyGroup): - g_zbuffer : bpy.props.BoolProperty(name = 'Z Buffer', default = True, - update = update_node_values) - g_shade : bpy.props.BoolProperty(name = 'Shading', default = True, - update = update_node_values) - #v1/2 difference - g_cull_front : bpy.props.BoolProperty(name = 'Cull Front', - update = update_node_values) - #v1/2 difference - g_cull_back : bpy.props.BoolProperty(name = 'Cull Back', default = True, - update = update_node_values) - g_fog : bpy.props.BoolProperty(name = 'Fog', - update = update_node_values) - g_lighting : bpy.props.BoolProperty(name = 'Lighting', default = True, - update = update_node_values) - g_tex_gen : bpy.props.BoolProperty(name = 'Texture UV Generate', - update = update_node_values) - g_tex_gen_linear : bpy.props.BoolProperty( - name = 'Texture UV Generate Linear', - update = update_node_values) - #v1/2 difference - g_shade_smooth : bpy.props.BoolProperty(name = 'Smooth Shading', - default = True, update = update_node_values) - # f3dlx2 only - g_clipping : bpy.props.BoolProperty(name = 'Clipping', - update = update_node_values) + g_zbuffer: bpy.props.BoolProperty(name="Z Buffer", default=True, update=update_node_values) + g_shade: bpy.props.BoolProperty(name="Shading", default=True, update=update_node_values) + # v1/2 difference + g_cull_front: bpy.props.BoolProperty(name="Cull Front", update=update_node_values) + # v1/2 difference + g_cull_back: bpy.props.BoolProperty(name="Cull Back", default=True, update=update_node_values) + g_fog: bpy.props.BoolProperty(name="Fog", update=update_node_values) + g_lighting: bpy.props.BoolProperty(name="Lighting", default=True, update=update_node_values) + g_tex_gen: bpy.props.BoolProperty(name="Texture UV Generate", update=update_node_values) + g_tex_gen_linear: bpy.props.BoolProperty(name="Texture UV Generate Linear", update=update_node_values) + # v1/2 difference + g_shade_smooth: bpy.props.BoolProperty(name="Smooth Shading", default=True, update=update_node_values) + # f3dlx2 only + g_clipping: bpy.props.BoolProperty(name="Clipping", update=update_node_values) - # upper half mode - # v2 only - g_mdsft_alpha_dither : bpy.props.EnumProperty( - name = 'Alpha Dither', items = enumAlphaDither, default = 'G_AD_NOISE', update = update_node_values) - # v2 only - g_mdsft_rgb_dither : bpy.props.EnumProperty( - name = 'RGB Dither', items = enumRGBDither, default = 'G_CD_MAGICSQ', update = update_node_values) - g_mdsft_combkey : bpy.props.EnumProperty( - name = 'Chroma Key', items = enumCombKey, default = 'G_CK_NONE', update = update_node_values) - g_mdsft_textconv : bpy.props.EnumProperty( - name = 'Texture Convert', items = enumTextConv, default = 'G_TC_FILT', update = update_node_values) - g_mdsft_text_filt : bpy.props.EnumProperty( - name = 'Texture Filter', items = enumTextFilt, default = 'G_TF_BILERP', - update = update_node_values_without_preset) - g_mdsft_textlut : bpy.props.EnumProperty( - name = 'Texture LUT', items = enumTextLUT, default = 'G_TT_NONE') - g_mdsft_textlod : bpy.props.EnumProperty( - name = 'Texture LOD', items = enumTextLOD, default = 'G_TL_TILE', update = update_node_values) - g_mdsft_textdetail : bpy.props.EnumProperty( - name = 'Texture Detail', items = enumTextDetail, default = 'G_TD_CLAMP', update = update_node_values) - g_mdsft_textpersp : bpy.props.EnumProperty( - name = 'Texture Perspective Correction', items = enumTextPersp, - default = 'G_TP_PERSP', update = update_node_values) - g_mdsft_cycletype : bpy.props.EnumProperty( - name = 'Cycle Type', items = enumCycleType, default = 'G_CYC_1CYCLE', - update = update_node_values) - # v1 only - g_mdsft_color_dither : bpy.props.EnumProperty( - name = 'Color Dither', items = enumColorDither, default = 'G_CD_ENABLE', update = update_node_values) - g_mdsft_pipeline : bpy.props.EnumProperty( - name = 'Pipeline Span Buffer Coherency', items = enumPipelineMode, - default = 'G_PM_1PRIMITIVE', update = update_node_values) + # upper half mode + # v2 only + g_mdsft_alpha_dither: bpy.props.EnumProperty( + name="Alpha Dither", items=enumAlphaDither, default="G_AD_NOISE", update=update_node_values + ) + # v2 only + g_mdsft_rgb_dither: bpy.props.EnumProperty( + name="RGB Dither", items=enumRGBDither, default="G_CD_MAGICSQ", update=update_node_values + ) + g_mdsft_combkey: bpy.props.EnumProperty( + name="Chroma Key", items=enumCombKey, default="G_CK_NONE", update=update_node_values + ) + g_mdsft_textconv: bpy.props.EnumProperty( + name="Texture Convert", items=enumTextConv, default="G_TC_FILT", update=update_node_values + ) + g_mdsft_text_filt: bpy.props.EnumProperty( + name="Texture Filter", items=enumTextFilt, default="G_TF_BILERP", update=update_node_values_without_preset + ) + g_mdsft_textlut: bpy.props.EnumProperty(name="Texture LUT", items=enumTextLUT, default="G_TT_NONE") + g_mdsft_textlod: bpy.props.EnumProperty( + name="Texture LOD", items=enumTextLOD, default="G_TL_TILE", update=update_node_values + ) + g_mdsft_textdetail: bpy.props.EnumProperty( + name="Texture Detail", items=enumTextDetail, default="G_TD_CLAMP", update=update_node_values + ) + g_mdsft_textpersp: bpy.props.EnumProperty( + name="Texture Perspective Correction", items=enumTextPersp, default="G_TP_PERSP", update=update_node_values + ) + g_mdsft_cycletype: bpy.props.EnumProperty( + name="Cycle Type", items=enumCycleType, default="G_CYC_1CYCLE", update=update_node_values + ) + # v1 only + g_mdsft_color_dither: bpy.props.EnumProperty( + name="Color Dither", items=enumColorDither, default="G_CD_ENABLE", update=update_node_values + ) + g_mdsft_pipeline: bpy.props.EnumProperty( + name="Pipeline Span Buffer Coherency", + items=enumPipelineMode, + default="G_PM_1PRIMITIVE", + update=update_node_values, + ) - # lower half mode - g_mdsft_alpha_compare : bpy.props.EnumProperty( - name = 'Alpha Compare', items = enumAlphaCompare, - default = 'G_AC_NONE', update = update_node_values) - g_mdsft_zsrcsel : bpy.props.EnumProperty( - name = 'Z Source Selection', items = enumDepthSource, - default = 'G_ZS_PIXEL', update = update_node_values) - - prim_depth : bpy.props.PointerProperty(type=PrimDepthSettings, name='Prim Depth Settings (gDPSetPrimDepth)', description='gDPSetPrimDepth') + # lower half mode + g_mdsft_alpha_compare: bpy.props.EnumProperty( + name="Alpha Compare", items=enumAlphaCompare, default="G_AC_NONE", update=update_node_values + ) + g_mdsft_zsrcsel: bpy.props.EnumProperty( + name="Z Source Selection", items=enumDepthSource, default="G_ZS_PIXEL", update=update_node_values + ) - clip_ratio : bpy.props.IntProperty(default = 1, - min = 1, max = 2**15 - 1, update = update_node_values) + prim_depth: bpy.props.PointerProperty( + type=PrimDepthSettings, name="Prim Depth Settings (gDPSetPrimDepth)", description="gDPSetPrimDepth" + ) - # cycle independent - set_rendermode : bpy.props.BoolProperty(default = False, update = update_node_values) - rendermode_advanced_enabled : bpy.props.BoolProperty(default = False, update = update_node_values) - rendermode_preset_cycle_1 : bpy.props.EnumProperty(items = enumRenderModesCycle1, - default = 'G_RM_AA_ZB_OPA_SURF', name = 'Render Mode Cycle 1', update = update_node_values) - rendermode_preset_cycle_2 : bpy.props.EnumProperty(items = enumRenderModesCycle2, - default = 'G_RM_AA_ZB_OPA_SURF2', name = 'Render Mode Cycle 2', update = update_node_values) - aa_en : bpy.props.BoolProperty(update = update_node_values) - z_cmp : bpy.props.BoolProperty(update = update_node_values) - z_upd : bpy.props.BoolProperty(update = update_node_values) - im_rd : bpy.props.BoolProperty(update = update_node_values) - clr_on_cvg : bpy.props.BoolProperty(update = update_node_values) - cvg_dst : bpy.props.EnumProperty( - name = 'Coverage Destination', items = enumCoverage, - update = update_node_values) - zmode : bpy.props.EnumProperty( - name = 'Z Mode', items = enumZMode, update = update_node_values) - cvg_x_alpha : bpy.props.BoolProperty(update = update_node_values) - alpha_cvg_sel : bpy.props.BoolProperty(update = update_node_values) - force_bl : bpy.props.BoolProperty(update = update_node_values) + clip_ratio: bpy.props.IntProperty(default=1, min=1, max=2**15 - 1, update=update_node_values) + + # cycle independent + set_rendermode: bpy.props.BoolProperty(default=False, update=update_node_values) + rendermode_advanced_enabled: bpy.props.BoolProperty(default=False, update=update_node_values) + rendermode_preset_cycle_1: bpy.props.EnumProperty( + items=enumRenderModesCycle1, + default="G_RM_AA_ZB_OPA_SURF", + name="Render Mode Cycle 1", + update=update_node_values, + ) + rendermode_preset_cycle_2: bpy.props.EnumProperty( + items=enumRenderModesCycle2, + default="G_RM_AA_ZB_OPA_SURF2", + name="Render Mode Cycle 2", + update=update_node_values, + ) + aa_en: bpy.props.BoolProperty(update=update_node_values) + z_cmp: bpy.props.BoolProperty(update=update_node_values) + z_upd: bpy.props.BoolProperty(update=update_node_values) + im_rd: bpy.props.BoolProperty(update=update_node_values) + clr_on_cvg: bpy.props.BoolProperty(update=update_node_values) + cvg_dst: bpy.props.EnumProperty(name="Coverage Destination", items=enumCoverage, update=update_node_values) + zmode: bpy.props.EnumProperty(name="Z Mode", items=enumZMode, update=update_node_values) + cvg_x_alpha: bpy.props.BoolProperty(update=update_node_values) + alpha_cvg_sel: bpy.props.BoolProperty(update=update_node_values) + force_bl: bpy.props.BoolProperty(update=update_node_values) + + # cycle dependent - (P * A + M - B) / (A + B) + blend_p1: bpy.props.EnumProperty(name="Color Source 1", items=enumBlendColor, update=update_node_values) + blend_p2: bpy.props.EnumProperty(name="Color Source 1", items=enumBlendColor, update=update_node_values) + blend_m1: bpy.props.EnumProperty(name="Color Source 2", items=enumBlendColor, update=update_node_values) + blend_m2: bpy.props.EnumProperty(name="Color Source 2", items=enumBlendColor, update=update_node_values) + blend_a1: bpy.props.EnumProperty(name="Alpha Source", items=enumBlendAlpha, update=update_node_values) + blend_a2: bpy.props.EnumProperty(name="Alpha Source", items=enumBlendAlpha, update=update_node_values) + blend_b1: bpy.props.EnumProperty(name="Alpha Mix", items=enumBlendMix, update=update_node_values) + blend_b2: bpy.props.EnumProperty(name="Alpha Mix", items=enumBlendMix, update=update_node_values) - # cycle dependent - (P * A + M - B) / (A + B) - blend_p1 : bpy.props.EnumProperty( - name = 'Color Source 1', items = enumBlendColor, update = update_node_values) - blend_p2 : bpy.props.EnumProperty( - name = 'Color Source 1', items = enumBlendColor, update = update_node_values) - blend_m1 : bpy.props.EnumProperty( - name = 'Color Source 2', items = enumBlendColor, update = update_node_values) - blend_m2 : bpy.props.EnumProperty( - name = 'Color Source 2', items = enumBlendColor, update = update_node_values) - blend_a1 : bpy.props.EnumProperty( - name = 'Alpha Source', items = enumBlendAlpha, update = update_node_values) - blend_a2 : bpy.props.EnumProperty( - name = 'Alpha Source', items = enumBlendAlpha, update = update_node_values) - blend_b1 : bpy.props.EnumProperty( - name = 'Alpha Mix', items = enumBlendMix, update = update_node_values) - blend_b2 : bpy.props.EnumProperty( - name = 'Alpha Mix', items = enumBlendMix, update = update_node_values) class DefaultRDPSettingsPanel(bpy.types.Panel): - bl_label = "RDP Default Settings" - bl_idname = "WORLD_PT_RDP_Default_Inspector" - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "world" - bl_options = {'HIDE_HEADER'} + bl_label = "RDP Default Settings" + bl_idname = "WORLD_PT_RDP_Default_Inspector" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "world" + bl_options = {"HIDE_HEADER"} - @classmethod - def poll(cls, context): - return context.scene.gameEditorMode == "SM64" + @classmethod + def poll(cls, context): + return context.scene.gameEditorMode == "SM64" + + def draw(self, context): + world = context.scene.world + layout = self.layout + layout.box().label(text="RDP Default Settings") + layout.label(text="If a material setting is a same as a default " + "setting, then it won't be set.") + ui_geo_mode(world.rdp_defaults, world, layout, True) + ui_upper_mode(world.rdp_defaults, world, layout, True) + ui_lower_mode(world.rdp_defaults, world, layout, True) + ui_other(world.rdp_defaults, world, layout, True) - def draw(self, context): - world = context.scene.world - layout = self.layout - layout.box().label(text = 'RDP Default Settings') - layout.label(text = "If a material setting is a same as a default " +\ - "setting, then it won't be set.") - ui_geo_mode(world.rdp_defaults, world, layout, True) - ui_upper_mode(world.rdp_defaults, world, layout, True) - ui_lower_mode(world.rdp_defaults, world, layout, True) - ui_other(world.rdp_defaults, world, layout, True) ### Node Categories ### # Node categories are a python system for automatically @@ -2295,24 +2395,31 @@ class DefaultRDPSettingsPanel(bpy.types.Panel): # all categories in a list node_categories = [ - # identifier, label, items list - F3DNodeCategory('CUSTOM', 'Custom', items = [ - NodeItem("GetAlphaFromColor",label="Get Alpha From Color", settings={}), - ]), - F3DNodeCategory('FAST3D', "Fast3D", items=[ - # the node item can have additional settings, - # which are applied to new nodes - # NB: settings values are stored as string expressions, - # for this reason they should be converted to strings using repr() - NodeItem("Fast3D_A", label="A"), - NodeItem("Fast3D_B", label="B"), - NodeItem("Fast3D_C", label="C"), - NodeItem("Fast3D_D", label="D"), - NodeItem("Fast3D_A_alpha", label="A Alpha"), - NodeItem("Fast3D_B_alpha", label="B Alpha"), - NodeItem("Fast3D_C_alpha", label="C Alpha"), - NodeItem("Fast3D_D_alpha", label="D Alpha"), - ''' + # identifier, label, items list + F3DNodeCategory( + "CUSTOM", + "Custom", + items=[ + NodeItem("GetAlphaFromColor", label="Get Alpha From Color", settings={}), + ], + ), + F3DNodeCategory( + "FAST3D", + "Fast3D", + items=[ + # the node item can have additional settings, + # which are applied to new nodes + # NB: settings values are stored as string expressions, + # for this reason they should be converted to strings using repr() + NodeItem("Fast3D_A", label="A"), + NodeItem("Fast3D_B", label="B"), + NodeItem("Fast3D_C", label="C"), + NodeItem("Fast3D_D", label="D"), + NodeItem("Fast3D_A_alpha", label="A Alpha"), + NodeItem("Fast3D_B_alpha", label="B Alpha"), + NodeItem("Fast3D_C_alpha", label="C Alpha"), + NodeItem("Fast3D_D_alpha", label="D Alpha"), + """ NodeItem("Test_NodeType", label="Full", settings={ "my_string_prop": repr("consectetur adipisicing elit"), "my_float_prop": repr(2.0), @@ -2324,941 +2431,965 @@ node_categories = [ }), NodeItem("Fast3DSplitter_NodeType", label="Splitter", settings={ }), - ''' - ]), + """, + ], + ), ] + def getOptimalFormat(tex, useLargeTextures): - texFormat = 'RGBA16' - if useLargeTextures: - return 'RGBA16' - if bpy.context.scene.ignoreTextureRestrictions or \ - tex.size[0] * tex.size[1] > 8192: # Image too big - return 'RGBA32' + texFormat = "RGBA16" + if useLargeTextures: + return "RGBA16" + if bpy.context.scene.ignoreTextureRestrictions or tex.size[0] * tex.size[1] > 8192: # Image too big + return "RGBA32" - isGreyscale = True - hasAlpha4bit = False - hasAlpha1bit = False - pixelValues = [] + isGreyscale = True + hasAlpha4bit = False + hasAlpha1bit = False + pixelValues = [] - # N64 is -Y, Blender is +Y - for j in reversed(range(tex.size[1])): - for i in range(tex.size[0]): - color = [1,1,1,1] - for field in range(tex.channels): - color[field] = tex.pixels[ - (j * tex.size[0] + i) * tex.channels + field] - if not (color[0] == color[1] and color[1] == color[2]): - isGreyscale = False - if color[3] < 0.9375: - hasAlpha4bit = True - if color[3] < 0.5: - hasAlpha1bit = True - pixelColor = getRGBA16Tuple(color) - if pixelColor not in pixelValues: - pixelValues.append(pixelColor) + # N64 is -Y, Blender is +Y + for j in reversed(range(tex.size[1])): + for i in range(tex.size[0]): + color = [1, 1, 1, 1] + for field in range(tex.channels): + color[field] = tex.pixels[(j * tex.size[0] + i) * tex.channels + field] + if not (color[0] == color[1] and color[1] == color[2]): + isGreyscale = False + if color[3] < 0.9375: + hasAlpha4bit = True + if color[3] < 0.5: + hasAlpha1bit = True + pixelColor = getRGBA16Tuple(color) + if pixelColor not in pixelValues: + pixelValues.append(pixelColor) - if isGreyscale: - if tex.size[0] * tex.size[1] > 4096: - if not hasAlpha1bit: - texFormat = 'I4' - else: - texFormat = 'IA4' - else: - if not hasAlpha4bit: - texFormat = 'I8' - else: - texFormat = 'IA8' - else: - if len(pixelValues) <= 16: - texFormat = 'CI4' - elif len(pixelValues) <= 256: - texFormat = 'CI8' - else: - texFormat = 'RGBA16' + if isGreyscale: + if tex.size[0] * tex.size[1] > 4096: + if not hasAlpha1bit: + texFormat = "I4" + else: + texFormat = "IA4" + else: + if not hasAlpha4bit: + texFormat = "I8" + else: + texFormat = "IA8" + else: + if len(pixelValues) <= 16: + texFormat = "CI4" + elif len(pixelValues) <= 256: + texFormat = "CI8" + else: + texFormat = "RGBA16" + + return texFormat - return texFormat def getCurrentPresetDir(): - return "f3d/" + bpy.context.scene.gameEditorMode.lower() + return "f3d/" + bpy.context.scene.gameEditorMode.lower() + # modules/bpy_types.py -> Menu class MATERIAL_MT_f3d_presets(Menu): - bl_label = "F3D Material Presets" - preset_operator = "script.execute_preset" + bl_label = "F3D Material Presets" + preset_operator = "script.execute_preset" - def draw(self, _context): - """ - Define these on the subclass: - - preset_operator (string) - - preset_subdir (string) + def draw(self, _context): + """ + Define these on the subclass: + - preset_operator (string) + - preset_subdir (string) + + Optionally: + - preset_add_operator (string) + - preset_extensions (set of strings) + - preset_operator_defaults (dict of keyword args) + """ + import bpy + + ext_valid = getattr(self, "preset_extensions", {".py", ".xml"}) + props_default = getattr(self, "preset_operator_defaults", None) + add_operator = getattr(self, "preset_add_operator", None) + presetDir = getCurrentPresetDir() + paths = ( + bpy.utils.preset_paths(presetDir) if not bpy.context.scene.f3dUserPresetsOnly else [] + ) + bpy.utils.preset_paths("f3d/user") + self.path_menu( + paths, + self.preset_operator, + props_default=props_default, + filter_ext=lambda ext: ext.lower() in ext_valid, + add_operator=add_operator, + ) - Optionally: - - preset_add_operator (string) - - preset_extensions (set of strings) - - preset_operator_defaults (dict of keyword args) - """ - import bpy - ext_valid = getattr(self, "preset_extensions", {".py", ".xml"}) - props_default = getattr(self, "preset_operator_defaults", None) - add_operator = getattr(self, "preset_add_operator", None) - presetDir = getCurrentPresetDir() - paths = (bpy.utils.preset_paths(presetDir) if \ - not bpy.context.scene.f3dUserPresetsOnly else []) + \ - bpy.utils.preset_paths("f3d/user") - self.path_menu( - paths, - self.preset_operator, - props_default=props_default, - filter_ext=lambda ext: ext.lower() in ext_valid, - add_operator=add_operator, - ) # https://docs.blender.org/api/current/bpy.ops.script.html -#class F3DExecutePreset(ExecutePreset): -# """Execute a preset""" -# bl_idname = "script.f3d_execute_preset" -# bl_label = "Execute an F3D Preset" +# class F3DExecutePreset(ExecutePreset): +# """Execute a preset""" +# bl_idname = "script.f3d_execute_preset" +# bl_label = "Execute an F3D Preset" # -# filepath: StringProperty( -# subtype='FILE_PATH', -# options={'SKIP_SAVE'}, -# ) -# menu_idname: StringProperty( -# name="Menu ID Name", -# description="ID name of the menu this was called from", -# options={'SKIP_SAVE'}, -# ) +# filepath: StringProperty( +# subtype='FILE_PATH', +# options={'SKIP_SAVE'}, +# ) +# menu_idname: StringProperty( +# name="Menu ID Name", +# description="ID name of the menu this was called from", +# options={'SKIP_SAVE'}, +# ) # -# def post_cb(self, context): -# presetName = bpy.path.display_name(basename(filepath)) -# for material in bpy.data.materials: -# if material.is_f3d and material.mat_ver > 3 and \ -# material.f3d_mat.preset_name == presetName: +# def post_cb(self, context): +# presetName = bpy.path.display_name(basename(filepath)) +# for material in bpy.data.materials: +# if material.is_f3d and material.mat_ver > 3 and \ +# material.f3d_mat.preset_name == presetName: class AddPresetF3D(AddPresetBase, Operator): - '''Add an F3D Material Preset''' - bl_idname = "material.f3d_preset_add" - bl_label = "Add F3D Material Preset" - preset_menu = "MATERIAL_MT_f3d_presets" + """Add an F3D Material Preset""" - # variable used for all preset values - # do NOT set "mat" in this operator, even in a for loop! it overrides this value - preset_defines = [ - "f3d_mat = bpy.context.material.f3d_mat" - ] + bl_idname = "material.f3d_preset_add" + bl_label = "Add F3D Material Preset" + preset_menu = "MATERIAL_MT_f3d_presets" - # properties to store in the preset - preset_values = [ - "f3d_mat", - ] + # variable used for all preset values + # do NOT set "mat" in this operator, even in a for loop! it overrides this value + preset_defines = ["f3d_mat = bpy.context.material.f3d_mat"] - # where to store the preset - preset_subdir = "f3d/user" + # properties to store in the preset + preset_values = [ + "f3d_mat", + ] - defaults = [ - "Custom", - #"Shaded Texture", - ] + # where to store the preset + preset_subdir = "f3d/user" - ignore_props = [ - "f3d_mat.tex0.tex", - "f3d_mat.tex0.tex_format", - "f3d_mat.tex0.ci_format", - "f3d_mat.tex0.use_tex_reference", - "f3d_mat.tex0.tex_reference", - "f3d_mat.tex0.tex_reference_size", - "f3d_mat.tex0.pal_reference", - "f3d_mat.tex0.pal_reference_size", - "f3d_mat.tex0.S", - "f3d_mat.tex0.T", - "f3d_mat.tex0.menu", - "f3d_mat.tex0.autoprop", - "f3d_mat.tex0.save_large_texture", - "f3d_mat.tex0.tile_scroll", - "f3d_mat.tex0.tile_scroll.s", - "f3d_mat.tex0.tile_scroll.t", - "f3d_mat.tex0.tile_scroll.interval", - "f3d_mat.tex1.tex", - "f3d_mat.tex1.tex_format", - "f3d_mat.tex1.ci_format", - "f3d_mat.tex1.use_tex_reference", - "f3d_mat.tex1.tex_reference", - "f3d_mat.tex1.tex_reference_size", - "f3d_mat.tex1.pal_reference", - "f3d_mat.tex1.pal_reference_size", - "f3d_mat.tex1.S", - "f3d_mat.tex1.T", - "f3d_mat.tex1.menu", - "f3d_mat.tex1.autoprop", - "f3d_mat.tex1.save_large_texture", - "f3d_mat.tex1.tile_scroll", - "f3d_mat.tex1.tile_scroll.s", - "f3d_mat.tex1.tile_scroll.t", - "f3d_mat.tex1.tile_scroll.interval", - "f3d_mat.tex_scale", - "f3d_mat.scale_autoprop", - "f3d_mat.uv_basis", - "f3d_mat.UVanim0", - "f3d_mat.UVanim1", - "f3d_mat.menu_procAnim", - "f3d_mat.menu_geo", - "f3d_mat.menu_upper", - "f3d_mat.menu_lower", - "f3d_mat.menu_other", - "f3d_mat.menu_lower_render", - "f3d_mat.f3d_update_flag", - "f3d_mat.name", - "f3d_mat.use_large_textures", - ] + defaults = [ + "Custom", + # "Shaded Texture", + ] - def execute(self, context): - import os - from bpy.utils import is_path_builtin + ignore_props = [ + "f3d_mat.tex0.tex", + "f3d_mat.tex0.tex_format", + "f3d_mat.tex0.ci_format", + "f3d_mat.tex0.use_tex_reference", + "f3d_mat.tex0.tex_reference", + "f3d_mat.tex0.tex_reference_size", + "f3d_mat.tex0.pal_reference", + "f3d_mat.tex0.pal_reference_size", + "f3d_mat.tex0.S", + "f3d_mat.tex0.T", + "f3d_mat.tex0.menu", + "f3d_mat.tex0.autoprop", + "f3d_mat.tex0.save_large_texture", + "f3d_mat.tex0.tile_scroll", + "f3d_mat.tex0.tile_scroll.s", + "f3d_mat.tex0.tile_scroll.t", + "f3d_mat.tex0.tile_scroll.interval", + "f3d_mat.tex1.tex", + "f3d_mat.tex1.tex_format", + "f3d_mat.tex1.ci_format", + "f3d_mat.tex1.use_tex_reference", + "f3d_mat.tex1.tex_reference", + "f3d_mat.tex1.tex_reference_size", + "f3d_mat.tex1.pal_reference", + "f3d_mat.tex1.pal_reference_size", + "f3d_mat.tex1.S", + "f3d_mat.tex1.T", + "f3d_mat.tex1.menu", + "f3d_mat.tex1.autoprop", + "f3d_mat.tex1.save_large_texture", + "f3d_mat.tex1.tile_scroll", + "f3d_mat.tex1.tile_scroll.s", + "f3d_mat.tex1.tile_scroll.t", + "f3d_mat.tex1.tile_scroll.interval", + "f3d_mat.tex_scale", + "f3d_mat.scale_autoprop", + "f3d_mat.uv_basis", + "f3d_mat.UVanim0", + "f3d_mat.UVanim1", + "f3d_mat.menu_procAnim", + "f3d_mat.menu_geo", + "f3d_mat.menu_upper", + "f3d_mat.menu_lower", + "f3d_mat.menu_other", + "f3d_mat.menu_lower_render", + "f3d_mat.f3d_update_flag", + "f3d_mat.name", + "f3d_mat.use_large_textures", + ] - if hasattr(self, "pre_cb"): - self.pre_cb(context) + def execute(self, context): + import os + from bpy.utils import is_path_builtin - preset_menu_class = getattr(bpy.types, self.preset_menu) + if hasattr(self, "pre_cb"): + self.pre_cb(context) - is_xml = getattr(preset_menu_class, "preset_type", None) == 'XML' - is_preset_add = not (self.remove_name or self.remove_active) + preset_menu_class = getattr(bpy.types, self.preset_menu) - if is_xml: - ext = ".xml" - else: - ext = ".py" + is_xml = getattr(preset_menu_class, "preset_type", None) == "XML" + is_preset_add = not (self.remove_name or self.remove_active) - name = self.name.strip() if is_preset_add else self.name + if is_xml: + ext = ".xml" + else: + ext = ".py" - if is_preset_add: - if not name: - return {'FINISHED'} + name = self.name.strip() if is_preset_add else self.name - filename = self.as_filename(name) - if filename in material_presets or filename == "custom": - self.report({'WARNING'}, "Unable to delete/overwrite default presets.") - return {'CANCELLED'} + if is_preset_add: + if not name: + return {"FINISHED"} - # Reset preset name - wm = bpy.data.window_managers[0] - if name == wm.preset_name: - wm.preset_name = 'New Preset' + filename = self.as_filename(name) + if filename in material_presets or filename == "custom": + self.report({"WARNING"}, "Unable to delete/overwrite default presets.") + return {"CANCELLED"} - filename = self.as_filename(name) - context.material.f3d_mat.presetName = bpy.path.display_name(filename) + # Reset preset name + wm = bpy.data.window_managers[0] + if name == wm.preset_name: + wm.preset_name = "New Preset" - target_path = os.path.join("presets", self.preset_subdir) - try: - target_path = bpy.utils.user_resource('SCRIPTS', - target_path, - create=True) - except: # 3.0 - target_path = bpy.utils.user_resource('SCRIPTS', - path=target_path, - create=True) + filename = self.as_filename(name) + context.material.f3d_mat.presetName = bpy.path.display_name(filename) - if not target_path: - self.report({'WARNING'}, "Failed to create presets path") - return {'CANCELLED'} + target_path = os.path.join("presets", self.preset_subdir) + try: + target_path = bpy.utils.user_resource("SCRIPTS", target_path, create=True) + except: # 3.0 + target_path = bpy.utils.user_resource("SCRIPTS", path=target_path, create=True) - filepath = os.path.join(target_path, filename) + ext + if not target_path: + self.report({"WARNING"}, "Failed to create presets path") + return {"CANCELLED"} - if hasattr(self, "add"): - self.add(context, filepath) - else: - print("Writing Preset: %r" % filepath) + filepath = os.path.join(target_path, filename) + ext - if is_xml: - import rna_xml - rna_xml.xml_file_write(context, - filepath, - preset_menu_class.preset_xml_map) - else: + if hasattr(self, "add"): + self.add(context, filepath) + else: + print("Writing Preset: %r" % filepath) - def rna_recursive_attr_expand(value, rna_path_step, level): - if rna_path_step in self.ignore_props: - #print("Ignoring: " + str(rna_path_step)) - return - #else: - # print("Processing: " + str(rna_path_step)) - if isinstance(value, bpy.types.PropertyGroup): - for sub_value_attr in value.bl_rna.properties.keys(): - if sub_value_attr == "rna_type": - continue - sub_value = getattr(value, sub_value_attr) - rna_recursive_attr_expand(sub_value, "%s.%s" % (rna_path_step, sub_value_attr), level) - elif type(value).__name__ == "bpy_prop_collection_idprop": # could use nicer method - file_preset.write("%s.clear()\n" % rna_path_step) - for sub_value in value: - file_preset.write("item_sub_%d = %s.add()\n" % (level, rna_path_step)) - rna_recursive_attr_expand(sub_value, "item_sub_%d" % level, level + 1) - else: - # convert thin wrapped sequences - # to simple lists to repr() - try: - value = value[:] - except: - pass + if is_xml: + import rna_xml - file_preset.write("%s = %r\n" % (rna_path_step, value)) + rna_xml.xml_file_write(context, filepath, preset_menu_class.preset_xml_map) + else: - file_preset = open(filepath, 'w', encoding="utf-8") - file_preset.write("import bpy\n") + def rna_recursive_attr_expand(value, rna_path_step, level): + if rna_path_step in self.ignore_props: + # print("Ignoring: " + str(rna_path_step)) + return + # else: + # print("Processing: " + str(rna_path_step)) + if isinstance(value, bpy.types.PropertyGroup): + for sub_value_attr in value.bl_rna.properties.keys(): + if sub_value_attr == "rna_type": + continue + sub_value = getattr(value, sub_value_attr) + rna_recursive_attr_expand(sub_value, "%s.%s" % (rna_path_step, sub_value_attr), level) + elif type(value).__name__ == "bpy_prop_collection_idprop": # could use nicer method + file_preset.write("%s.clear()\n" % rna_path_step) + for sub_value in value: + file_preset.write("item_sub_%d = %s.add()\n" % (level, rna_path_step)) + rna_recursive_attr_expand(sub_value, "item_sub_%d" % level, level + 1) + else: + # convert thin wrapped sequences + # to simple lists to repr() + try: + value = value[:] + except: + pass - if hasattr(self, "preset_defines"): - for rna_path in self.preset_defines: - exec(rna_path) - file_preset.write("%s\n" % rna_path) - file_preset.write("\n") - file_preset.write("bpy.context.material.f3d_update_flag = True\n") + file_preset.write("%s = %r\n" % (rna_path_step, value)) - for rna_path in self.preset_values: - value = eval(rna_path) - rna_recursive_attr_expand(value, rna_path, 1) + file_preset = open(filepath, "w", encoding="utf-8") + file_preset.write("import bpy\n") - file_preset.write("bpy.context.material.f3d_update_flag = False\n") - file_preset.write("f3d_mat.use_default_lighting = f3d_mat.use_default_lighting # Force nodes update\n") - file_preset.close() + if hasattr(self, "preset_defines"): + for rna_path in self.preset_defines: + exec(rna_path) + file_preset.write("%s\n" % rna_path) + file_preset.write("\n") + file_preset.write("bpy.context.material.f3d_update_flag = True\n") - presetName = bpy.path.display_name(filename) - preset_menu_class.bl_label = presetName + for rna_path in self.preset_values: + value = eval(rna_path) + rna_recursive_attr_expand(value, rna_path, 1) - for otherMat in bpy.data.materials: - if otherMat.f3d_mat.presetName == presetName and otherMat != context.material: - update_preset_manual_v4(otherMat, filename) - context.material.f3d_mat.presetName = bpy.path.display_name(filename) + file_preset.write("bpy.context.material.f3d_update_flag = False\n") + file_preset.write( + "f3d_mat.use_default_lighting = f3d_mat.use_default_lighting # Force nodes update\n" + ) + file_preset.close() - else: - if self.remove_active: - name = preset_menu_class.bl_label - filename = self.as_filename(name) - presetName = bpy.path.display_name(filename) + presetName = bpy.path.display_name(filename) + preset_menu_class.bl_label = presetName - if filename in material_presets or filename == "custom": - self.report({'WARNING'}, "Unable to delete/overwrite default presets.") - return {'CANCELLED'} + for otherMat in bpy.data.materials: + if otherMat.f3d_mat.presetName == presetName and otherMat != context.material: + update_preset_manual_v4(otherMat, filename) + context.material.f3d_mat.presetName = bpy.path.display_name(filename) - # fairly sloppy but convenient. - filepath = bpy.utils.preset_find(name, - self.preset_subdir, - ext=ext) + else: + if self.remove_active: + name = preset_menu_class.bl_label + filename = self.as_filename(name) + presetName = bpy.path.display_name(filename) - if not filepath: - filepath = bpy.utils.preset_find(name, - self.preset_subdir, - display_name=True, - ext=ext) + if filename in material_presets or filename == "custom": + self.report({"WARNING"}, "Unable to delete/overwrite default presets.") + return {"CANCELLED"} - if not filepath: - return {'CANCELLED'} + # fairly sloppy but convenient. + filepath = bpy.utils.preset_find(name, self.preset_subdir, ext=ext) - # Do not remove bundled presets - if is_path_builtin(filepath): - self.report({'WARNING'}, "Unable to remove default presets") - return {'CANCELLED'} + if not filepath: + filepath = bpy.utils.preset_find(name, self.preset_subdir, display_name=True, ext=ext) - try: - if hasattr(self, "remove"): - self.remove(context, filepath) - else: - os.remove(filepath) - except Exception as e: - self.report({'ERROR'}, "Unable to remove preset: %r" % e) - import traceback - traceback.print_exc() - return {'CANCELLED'} + if not filepath: + return {"CANCELLED"} - # XXX, stupid! - preset_menu_class.bl_label = "Presets" - for material in bpy.data.materials: - if material.f3d_mat.presetName == presetName: - material.f3d_mat.presetName = "Custom" - #context.material.f3d_mat.presetName = "Custom" + # Do not remove bundled presets + if is_path_builtin(filepath): + self.report({"WARNING"}, "Unable to remove default presets") + return {"CANCELLED"} - if hasattr(self, "post_cb"): - self.post_cb(context) + try: + if hasattr(self, "remove"): + self.remove(context, filepath) + else: + os.remove(filepath) + except Exception as e: + self.report({"ERROR"}, "Unable to remove preset: %r" % e) + import traceback + + traceback.print_exc() + return {"CANCELLED"} + + # XXX, stupid! + preset_menu_class.bl_label = "Presets" + for material in bpy.data.materials: + if material.f3d_mat.presetName == presetName: + material.f3d_mat.presetName = "Custom" + # context.material.f3d_mat.presetName = "Custom" + + if hasattr(self, "post_cb"): + self.post_cb(context) + + return {"FINISHED"} - return {'FINISHED'} def convertToNewMat(material, oldMat): - #mat_register_old() - material.f3d_mat.presetName = oldMat.presetName + # mat_register_old() + material.f3d_mat.presetName = oldMat.presetName - material.f3d_mat.scale_autoprop = oldMat.scale_autoprop - material.f3d_mat.uv_basis = oldMat.uv_basis + material.f3d_mat.scale_autoprop = oldMat.scale_autoprop + material.f3d_mat.uv_basis = oldMat.uv_basis - # Combiners - copyPropertyGroup(oldMat.combiner1, material.f3d_mat.combiner1) - copyPropertyGroup(oldMat.combiner2, material.f3d_mat.combiner2) - #material.f3d_mat.combiner1 = oldMat.combiner1 - #material.f3d_mat.combiner2 = oldMat.combiner2 + # Combiners + copyPropertyGroup(oldMat.combiner1, material.f3d_mat.combiner1) + copyPropertyGroup(oldMat.combiner2, material.f3d_mat.combiner2) + # material.f3d_mat.combiner1 = oldMat.combiner1 + # material.f3d_mat.combiner2 = oldMat.combiner2 - # Texture animation - material.f3d_mat.menu_procAnim = oldMat.menu_procAnim - copyPropertyGroup(oldMat.UVanim, material.f3d_mat.UVanim0) - copyPropertyGroup(oldMat.UVanim_tex1, material.f3d_mat.UVanim1) + # Texture animation + material.f3d_mat.menu_procAnim = oldMat.menu_procAnim + copyPropertyGroup(oldMat.UVanim, material.f3d_mat.UVanim0) + copyPropertyGroup(oldMat.UVanim_tex1, material.f3d_mat.UVanim1) - # material textures - material.f3d_mat.tex_scale = oldMat.tex_scale - copyPropertyGroup(oldMat.tex0, material.f3d_mat.tex0) - copyPropertyGroup(oldMat.tex1, material.f3d_mat.tex1) + # material textures + material.f3d_mat.tex_scale = oldMat.tex_scale + copyPropertyGroup(oldMat.tex0, material.f3d_mat.tex0) + copyPropertyGroup(oldMat.tex1, material.f3d_mat.tex1) - # Should Set? - material.f3d_mat.set_prim = oldMat.set_prim - material.f3d_mat.set_lights = oldMat.set_lights - material.f3d_mat.set_env = oldMat.set_env - material.f3d_mat.set_blend = oldMat.set_blend - material.f3d_mat.set_key = oldMat.set_key - material.f3d_mat.set_k0_5 = oldMat.set_k0_5 - material.f3d_mat.set_combiner = oldMat.set_combiner - material.f3d_mat.use_default_lighting = oldMat.use_default_lighting + # Should Set? + material.f3d_mat.set_prim = oldMat.set_prim + material.f3d_mat.set_lights = oldMat.set_lights + material.f3d_mat.set_env = oldMat.set_env + material.f3d_mat.set_blend = oldMat.set_blend + material.f3d_mat.set_key = oldMat.set_key + material.f3d_mat.set_k0_5 = oldMat.set_k0_5 + material.f3d_mat.set_combiner = oldMat.set_combiner + material.f3d_mat.use_default_lighting = oldMat.use_default_lighting - # Colors - nodes = oldMat.node_tree.nodes - material.f3d_mat.blend_color = oldMat.blend_color - if oldMat.mat_ver == 3: - prim = nodes['Primitive Color Output'].inputs[0].default_value - env = nodes['Environment Color Output'].inputs[0].default_value - else: - prim = nodes['Primitive Color'].outputs[0].default_value - env = nodes['Environment Color'].outputs[0].default_value + # Colors + nodes = oldMat.node_tree.nodes + material.f3d_mat.blend_color = oldMat.blend_color + if oldMat.mat_ver == 3: + prim = nodes["Primitive Color Output"].inputs[0].default_value + env = nodes["Environment Color Output"].inputs[0].default_value + else: + prim = nodes["Primitive Color"].outputs[0].default_value + env = nodes["Environment Color"].outputs[0].default_value - material.f3d_mat.blend_color = oldMat.blend_color - material.f3d_mat.prim_color = prim - material.f3d_mat.env_color = env - material.f3d_mat.key_center = nodes['Chroma Key Center'].outputs[0].default_value + material.f3d_mat.blend_color = oldMat.blend_color + material.f3d_mat.prim_color = prim + material.f3d_mat.env_color = env + material.f3d_mat.key_center = nodes["Chroma Key Center"].outputs[0].default_value - # Chroma - material.f3d_mat.key_scale = oldMat.key_scale - material.f3d_mat.key_width = oldMat.key_width + # Chroma + material.f3d_mat.key_scale = oldMat.key_scale + material.f3d_mat.key_width = oldMat.key_width - # Convert - material.f3d_mat.k0 = oldMat.k0 - material.f3d_mat.k1 = oldMat.k1 - material.f3d_mat.k2 = oldMat.k2 - material.f3d_mat.k3 = oldMat.k3 - material.f3d_mat.k4 = oldMat.k4 - material.f3d_mat.k5 = oldMat.k5 + # Convert + material.f3d_mat.k0 = oldMat.k0 + material.f3d_mat.k1 = oldMat.k1 + material.f3d_mat.k2 = oldMat.k2 + material.f3d_mat.k3 = oldMat.k3 + material.f3d_mat.k4 = oldMat.k4 + material.f3d_mat.k5 = oldMat.k5 - # Prim - material.f3d_mat.prim_lod_frac = oldMat.prim_lod_frac - material.f3d_mat.prim_lod_min = oldMat.prim_lod_min + # Prim + material.f3d_mat.prim_lod_frac = oldMat.prim_lod_frac + material.f3d_mat.prim_lod_min = oldMat.prim_lod_min - # lights - material.f3d_mat.default_light_color = oldMat.default_light_color - material.f3d_mat.ambient_light_color = oldMat.ambient_light_color - material.f3d_mat.f3d_light1 = oldMat.f3d_light1 - material.f3d_mat.f3d_light2 = oldMat.f3d_light2 - material.f3d_mat.f3d_light3 = oldMat.f3d_light3 - material.f3d_mat.f3d_light4 = oldMat.f3d_light4 - material.f3d_mat.f3d_light5 = oldMat.f3d_light5 - material.f3d_mat.f3d_light6 = oldMat.f3d_light6 - material.f3d_mat.f3d_light7 = oldMat.f3d_light7 + # lights + material.f3d_mat.default_light_color = oldMat.default_light_color + material.f3d_mat.ambient_light_color = oldMat.ambient_light_color + material.f3d_mat.f3d_light1 = oldMat.f3d_light1 + material.f3d_mat.f3d_light2 = oldMat.f3d_light2 + material.f3d_mat.f3d_light3 = oldMat.f3d_light3 + material.f3d_mat.f3d_light4 = oldMat.f3d_light4 + material.f3d_mat.f3d_light5 = oldMat.f3d_light5 + material.f3d_mat.f3d_light6 = oldMat.f3d_light6 + material.f3d_mat.f3d_light7 = oldMat.f3d_light7 - # Fog Properties - material.f3d_mat.fog_color = oldMat.fog_color - material.f3d_mat.fog_position = oldMat.fog_position - material.f3d_mat.set_fog = oldMat.set_fog - material.f3d_mat.use_global_fog = oldMat.use_global_fog + # Fog Properties + material.f3d_mat.fog_color = oldMat.fog_color + material.f3d_mat.fog_position = oldMat.fog_position + material.f3d_mat.set_fog = oldMat.set_fog + material.f3d_mat.use_global_fog = oldMat.use_global_fog - # geometry mode - material.f3d_mat.menu_geo = oldMat.menu_geo - material.f3d_mat.menu_upper = oldMat.menu_upper - material.f3d_mat.menu_lower = oldMat.menu_lower - material.f3d_mat.menu_other = oldMat.menu_other - material.f3d_mat.menu_lower_render = oldMat.menu_lower_render - copyPropertyGroup(oldMat.rdp_settings, material.f3d_mat.rdp_settings) + # geometry mode + material.f3d_mat.menu_geo = oldMat.menu_geo + material.f3d_mat.menu_upper = oldMat.menu_upper + material.f3d_mat.menu_lower = oldMat.menu_lower + material.f3d_mat.menu_other = oldMat.menu_other + material.f3d_mat.menu_lower_render = oldMat.menu_lower_render + copyPropertyGroup(oldMat.rdp_settings, material.f3d_mat.rdp_settings) + + # mat_unregister_old() - #mat_unregister_old() class F3DMaterialProperty(bpy.types.PropertyGroup): - presetName : bpy.props.StringProperty(name = "Preset Name", default = "Custom") + presetName: bpy.props.StringProperty(name="Preset Name", default="Custom") - scale_autoprop : bpy.props.BoolProperty(name = 'Auto Set Scale', default = True, update = update_tex_values) - uv_basis : bpy.props.EnumProperty(name = 'UV Basis', default = 'TEXEL0', items = enumTexUV, update = update_tex_values) + scale_autoprop: bpy.props.BoolProperty(name="Auto Set Scale", default=True, update=update_tex_values) + uv_basis: bpy.props.EnumProperty(name="UV Basis", default="TEXEL0", items=enumTexUV, update=update_tex_values) - # Combiners - combiner1 : bpy.props.PointerProperty(type = CombinerProperty) - combiner2 : bpy.props.PointerProperty(type = CombinerProperty) + # Combiners + combiner1: bpy.props.PointerProperty(type=CombinerProperty) + combiner2: bpy.props.PointerProperty(type=CombinerProperty) - # Texture animation - menu_procAnim : bpy.props.BoolProperty() - UVanim0 : bpy.props.PointerProperty(type = ProcAnimVectorProperty) - UVanim1 : bpy.props.PointerProperty(type = ProcAnimVectorProperty) + # Texture animation + menu_procAnim: bpy.props.BoolProperty() + UVanim0: bpy.props.PointerProperty(type=ProcAnimVectorProperty) + UVanim1: bpy.props.PointerProperty(type=ProcAnimVectorProperty) - # material textures - tex_scale : bpy.props.FloatVectorProperty(min = 0, max = 1, size = 2, default = (1,1), step = 1, update = update_tex_values) - tex0 : bpy.props.PointerProperty(type = TextureProperty) - tex1 : bpy.props.PointerProperty(type = TextureProperty) + # material textures + tex_scale: bpy.props.FloatVectorProperty(min=0, max=1, size=2, default=(1, 1), step=1, update=update_tex_values) + tex0: bpy.props.PointerProperty(type=TextureProperty) + tex1: bpy.props.PointerProperty(type=TextureProperty) - # Should Set? + # Should Set? - set_prim : bpy.props.BoolProperty(default = True, update = update_node_values) - set_lights : bpy.props.BoolProperty(default = True, update = update_node_values) - set_env : bpy.props.BoolProperty(default = False, update = update_node_values) - set_blend : bpy.props.BoolProperty(default = False, update = update_node_values) - set_key : bpy.props.BoolProperty(default = True, update = update_node_values) - set_k0_5 : bpy.props.BoolProperty(default = True, update = update_node_values) - set_combiner : bpy.props.BoolProperty(default = True, update = update_node_values) - use_default_lighting : bpy.props.BoolProperty(default = True, update = update_node_values_without_preset) + set_prim: bpy.props.BoolProperty(default=True, update=update_node_values) + set_lights: bpy.props.BoolProperty(default=True, update=update_node_values) + set_env: bpy.props.BoolProperty(default=False, update=update_node_values) + set_blend: bpy.props.BoolProperty(default=False, update=update_node_values) + set_key: bpy.props.BoolProperty(default=True, update=update_node_values) + set_k0_5: bpy.props.BoolProperty(default=True, update=update_node_values) + set_combiner: bpy.props.BoolProperty(default=True, update=update_node_values) + use_default_lighting: bpy.props.BoolProperty(default=True, update=update_node_values_without_preset) - # Blend Color - blend_color : bpy.props.FloatVectorProperty( - name = 'Blend Color', subtype='COLOR', size = 4, min = 0, max = 1, default = (0,0,0,1)) - prim_color : bpy.props.FloatVectorProperty( - name = 'Primitive Color', subtype='COLOR', size = 4, min = 0, max = 1, default = (1,1,1,1), - update = update_node_values_without_preset) - env_color : bpy.props.FloatVectorProperty( - name = 'Environment Color', subtype='COLOR', size = 4, min = 0, max = 1, default = (1,1,1,1), - update = update_node_values_without_preset) - key_center : bpy.props.FloatVectorProperty( - name = 'Key Center', subtype='COLOR', size = 4, min = 0, max = 1, default = (1,1,1,1), - update = update_node_values_without_preset) + # Blend Color + blend_color: bpy.props.FloatVectorProperty( + name="Blend Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) + prim_color: bpy.props.FloatVectorProperty( + name="Primitive Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=update_node_values_without_preset, + ) + env_color: bpy.props.FloatVectorProperty( + name="Environment Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=update_node_values_without_preset, + ) + key_center: bpy.props.FloatVectorProperty( + name="Key Center", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=update_node_values_without_preset, + ) - # Chroma - key_scale : bpy.props.FloatVectorProperty(name = 'Key Scale', min = 0, max = 1, step = 1, update = update_node_values) - key_width : bpy.props.FloatVectorProperty(name = 'Key Width', min = 0, max = 16, update = update_node_values) + # Chroma + key_scale: bpy.props.FloatVectorProperty(name="Key Scale", min=0, max=1, step=1, update=update_node_values) + key_width: bpy.props.FloatVectorProperty(name="Key Width", min=0, max=16, update=update_node_values) - # Convert - k0 : bpy.props.FloatProperty(min = -1, max = 1, default = 175/255, step = 1, update = update_node_values) - k1 : bpy.props.FloatProperty(min = -1, max = 1, default = -43/255, step = 1, update = update_node_values) - k2 : bpy.props.FloatProperty(min = -1, max = 1, default = -89/255, step = 1, update = update_node_values) - k3 : bpy.props.FloatProperty(min = -1, max = 1, default = 222/255, step = 1, update = update_node_values) - k4 : bpy.props.FloatProperty(min = -1, max = 1, default = 114/255, step = 1, update = update_node_values) - k5 : bpy.props.FloatProperty(min = -1, max = 1, default = 42/255, step = 1, update = update_node_values) + # Convert + k0: bpy.props.FloatProperty(min=-1, max=1, default=175 / 255, step=1, update=update_node_values) + k1: bpy.props.FloatProperty(min=-1, max=1, default=-43 / 255, step=1, update=update_node_values) + k2: bpy.props.FloatProperty(min=-1, max=1, default=-89 / 255, step=1, update=update_node_values) + k3: bpy.props.FloatProperty(min=-1, max=1, default=222 / 255, step=1, update=update_node_values) + k4: bpy.props.FloatProperty(min=-1, max=1, default=114 / 255, step=1, update=update_node_values) + k5: bpy.props.FloatProperty(min=-1, max=1, default=42 / 255, step=1, update=update_node_values) - # Prim - prim_lod_frac : bpy.props.FloatProperty(name = 'Prim LOD Frac', min = 0, max = 1, step = 1, update = update_node_values) - prim_lod_min : bpy.props.FloatProperty(name = 'Min LOD Ratio', min = 0, max = 1, step = 1, update = update_node_values) + # Prim + prim_lod_frac: bpy.props.FloatProperty(name="Prim LOD Frac", min=0, max=1, step=1, update=update_node_values) + prim_lod_min: bpy.props.FloatProperty(name="Min LOD Ratio", min=0, max=1, step=1, update=update_node_values) - # lights - default_light_color : bpy.props.FloatVectorProperty( - name = 'Default Light Color', subtype = 'COLOR', size = 4, min = 0, max = 1, default = (1,1,1,1), - update = update_node_values_without_preset) - ambient_light_color : bpy.props.FloatVectorProperty( - name = 'Ambient Light Color', subtype = 'COLOR', size = 4, min = 0, max = 1, default = (0.5,0.5,0.5,1), - update = update_node_values_without_preset) - f3d_light1 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) - f3d_light2 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) - f3d_light3 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) - f3d_light4 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) - f3d_light5 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) - f3d_light6 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) - f3d_light7 : bpy.props.PointerProperty(type = bpy.types.Light, update = F3DOrganizeLights) + # lights + default_light_color: bpy.props.FloatVectorProperty( + name="Default Light Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=update_node_values_without_preset, + ) + ambient_light_color: bpy.props.FloatVectorProperty( + name="Ambient Light Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(0.5, 0.5, 0.5, 1), + update=update_node_values_without_preset, + ) + f3d_light1: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + f3d_light2: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + f3d_light3: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + f3d_light4: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + f3d_light5: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + f3d_light6: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + f3d_light7: bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) - # Fog Properties - fog_color : bpy.props.FloatVectorProperty( - name = 'Fog Color', subtype='COLOR', size = 4, min = 0, max = 1, default = (0,0,0,1)) - fog_position : bpy.props.IntVectorProperty( - name = 'Fog Range', size = 2, min = 0, max = 1000, default = (970,1000)) - set_fog : bpy.props.BoolProperty() - use_global_fog : bpy.props.BoolProperty(default = False) + # Fog Properties + fog_color: bpy.props.FloatVectorProperty( + name="Fog Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) + fog_position: bpy.props.IntVectorProperty(name="Fog Range", size=2, min=0, max=1000, default=(970, 1000)) + set_fog: bpy.props.BoolProperty() + use_global_fog: bpy.props.BoolProperty(default=False) - # geometry mode - menu_geo : bpy.props.BoolProperty() - menu_upper : bpy.props.BoolProperty() - menu_lower : bpy.props.BoolProperty() - menu_other : bpy.props.BoolProperty() - menu_lower_render : bpy.props.BoolProperty() - rdp_settings : bpy.props.PointerProperty(type = RDPSettings) + # geometry mode + menu_geo: bpy.props.BoolProperty() + menu_upper: bpy.props.BoolProperty() + menu_lower: bpy.props.BoolProperty() + menu_other: bpy.props.BoolProperty() + menu_lower_render: bpy.props.BoolProperty() + rdp_settings: bpy.props.PointerProperty(type=RDPSettings) + + draw_layer: bpy.props.PointerProperty(type=DrawLayerProperty) + use_large_textures: bpy.props.BoolProperty(name="Large Texture Mode") - draw_layer : bpy.props.PointerProperty(type = DrawLayerProperty) - use_large_textures : bpy.props.BoolProperty(name = "Large Texture Mode") class UnlinkF3DImage0(bpy.types.Operator): - bl_idname = 'image.tex0_unlink' - bl_label = "Unlink F3D Image" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + bl_idname = "image.tex0_unlink" + bl_label = "Unlink F3D Image" + bl_options = {"REGISTER", "UNDO", "PRESET"} + + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + if context.material.mat_ver > 3: + context.material.f3d_mat.tex0.tex = None + else: + context.material.tex0.tex = None + return {"FINISHED"} # must return a set - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - if context.material.mat_ver > 3: - context.material.f3d_mat.tex0.tex = None - else: - context.material.tex0.tex = None - return {'FINISHED'} # must return a set class UnlinkF3DImage1(bpy.types.Operator): - bl_idname = 'image.tex1_unlink' - bl_label = "Unlink F3D Image" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + bl_idname = "image.tex1_unlink" + bl_label = "Unlink F3D Image" + bl_options = {"REGISTER", "UNDO", "PRESET"} + + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + if context.material.mat_ver > 3: + context.material.f3d_mat.tex1.tex = None + else: + context.material.tex1.tex = None + return {"FINISHED"} # must return a set - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - if context.material.mat_ver > 3: - context.material.f3d_mat.tex1.tex = None - else: - context.material.tex1.tex = None - return {'FINISHED'} # must return a set class UpdateF3DNodes(bpy.types.Operator): - bl_idname = 'material.update_f3d_nodes' - bl_label = "Update F3D Nodes" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + bl_idname = "material.update_f3d_nodes" + bl_label = "Update F3D Nodes" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - if context is None or not hasattr(context, "material") or context.material is None: - self.report({"ERROR"}, "Material not found in context.") - return {"CANCELLED"} - if not context.material.is_f3d: - self.report({"ERROR"}, "Material is not F3D.") - return {"CANCELLED"} - material = context.material + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + if context is None or not hasattr(context, "material") or context.material is None: + self.report({"ERROR"}, "Material not found in context.") + return {"CANCELLED"} + if not context.material.is_f3d: + self.report({"ERROR"}, "Material is not F3D.") + return {"CANCELLED"} + material = context.material + + material.f3d_update_flag = True + update_node_values_of_material(material, context) + if material.mat_ver > 3: + material.f3d_mat.presetName = "Custom" + else: + material.f3d_preset = "Custom" + material.f3d_update_flag = False + return {"FINISHED"} # must return a set - material.f3d_update_flag = True - update_node_values_of_material(material, context) - if material.mat_ver > 3: - material.f3d_mat.presetName = "Custom" - else: - material.f3d_preset = 'Custom' - material.f3d_update_flag = False - return {'FINISHED'} # must return a set mat_classes = ( - F3DNodeA, - F3DNodeB, - F3DNodeC, - F3DNodeD, - F3DNodeA_alpha, - F3DNodeB_alpha, - F3DNodeC_alpha, - F3DNodeD_alpha, - UnlinkF3DImage0, - UnlinkF3DImage1, - DrawLayerProperty, - MATERIAL_MT_f3d_presets, - AddPresetF3D, - F3DPanel, - CreateFast3DMaterial, - GetAlphaFromColor, - TextureFieldProperty, - SetTileSizeScrollProperty, - TextureProperty, - CombinerProperty, - ProceduralAnimProperty, - ProcAnimVectorProperty, - PrimDepthSettings, - RDPSettings, - DefaultRDPSettingsPanel, - F3DMaterialProperty, - ReloadDefaultF3DPresets, - UpdateF3DNodes, + F3DNodeA, + F3DNodeB, + F3DNodeC, + F3DNodeD, + F3DNodeA_alpha, + F3DNodeB_alpha, + F3DNodeC_alpha, + F3DNodeD_alpha, + UnlinkF3DImage0, + UnlinkF3DImage1, + DrawLayerProperty, + MATERIAL_MT_f3d_presets, + AddPresetF3D, + F3DPanel, + CreateFast3DMaterial, + GetAlphaFromColor, + TextureFieldProperty, + SetTileSizeScrollProperty, + TextureProperty, + CombinerProperty, + ProceduralAnimProperty, + ProcAnimVectorProperty, + PrimDepthSettings, + RDPSettings, + DefaultRDPSettingsPanel, + F3DMaterialProperty, + ReloadDefaultF3DPresets, + UpdateF3DNodes, ) + def mat_unregister_old(): - del bpy.types.Material.f3d_preset + del bpy.types.Material.f3d_preset - del bpy.types.Material.scale_autoprop - del bpy.types.Material.uv_basis + del bpy.types.Material.scale_autoprop + del bpy.types.Material.uv_basis - # Combiners - del bpy.types.Material.presetName + # Combiners + del bpy.types.Material.presetName - del bpy.types.Material.combiner1 - del bpy.types.Material.combiner2 + del bpy.types.Material.combiner1 + del bpy.types.Material.combiner2 - # Texture animation - del bpy.types.Material.menu_procAnim - del bpy.types.Material.UVanim_tex1 - del bpy.types.Material.UVanim + # Texture animation + del bpy.types.Material.menu_procAnim + del bpy.types.Material.UVanim_tex1 + del bpy.types.Material.UVanim - # material textures - del bpy.types.Material.tex_scale - del bpy.types.Material.tex0 - del bpy.types.Material.tex1 + # material textures + del bpy.types.Material.tex_scale + del bpy.types.Material.tex0 + del bpy.types.Material.tex1 - # Should Set? - del bpy.types.Material.set_prim - del bpy.types.Material.set_lights - del bpy.types.Material.set_env - del bpy.types.Material.set_blend - del bpy.types.Material.set_key - del bpy.types.Material.set_k0_5 - del bpy.types.Material.set_combiner - del bpy.types.Material.use_default_lighting + # Should Set? + del bpy.types.Material.set_prim + del bpy.types.Material.set_lights + del bpy.types.Material.set_env + del bpy.types.Material.set_blend + del bpy.types.Material.set_key + del bpy.types.Material.set_k0_5 + del bpy.types.Material.set_combiner + del bpy.types.Material.use_default_lighting - # Blend Color - del bpy.types.Material.blend_color + # Blend Color + del bpy.types.Material.blend_color - # Chroma - del bpy.types.Material.key_scale - del bpy.types.Material.key_width + # Chroma + del bpy.types.Material.key_scale + del bpy.types.Material.key_width - # Convert - del bpy.types.Material.k0 - del bpy.types.Material.k1 - del bpy.types.Material.k2 - del bpy.types.Material.k3 - del bpy.types.Material.k4 - del bpy.types.Material.k5 + # Convert + del bpy.types.Material.k0 + del bpy.types.Material.k1 + del bpy.types.Material.k2 + del bpy.types.Material.k3 + del bpy.types.Material.k4 + del bpy.types.Material.k5 - # Prim - del bpy.types.Material.prim_lod_frac - del bpy.types.Material.prim_lod_min + # Prim + del bpy.types.Material.prim_lod_frac + del bpy.types.Material.prim_lod_min - # lights - del bpy.types.Material.default_light_color - del bpy.types.Material.ambient_light_color - del bpy.types.Material.f3d_light1 - del bpy.types.Material.f3d_light2 - del bpy.types.Material.f3d_light3 - del bpy.types.Material.f3d_light4 - del bpy.types.Material.f3d_light5 - del bpy.types.Material.f3d_light6 - del bpy.types.Material.f3d_light7 + # lights + del bpy.types.Material.default_light_color + del bpy.types.Material.ambient_light_color + del bpy.types.Material.f3d_light1 + del bpy.types.Material.f3d_light2 + del bpy.types.Material.f3d_light3 + del bpy.types.Material.f3d_light4 + del bpy.types.Material.f3d_light5 + del bpy.types.Material.f3d_light6 + del bpy.types.Material.f3d_light7 - # Fog Properties - del bpy.types.Material.fog_color - del bpy.types.Material.fog_position - del bpy.types.Material.set_fog - del bpy.types.Material.use_global_fog + # Fog Properties + del bpy.types.Material.fog_color + del bpy.types.Material.fog_position + del bpy.types.Material.set_fog + del bpy.types.Material.use_global_fog + + # geometry mode + del bpy.types.Material.menu_geo + del bpy.types.Material.menu_upper + del bpy.types.Material.menu_lower + del bpy.types.Material.menu_other + del bpy.types.Material.menu_lower_render + del bpy.types.Material.rdp_settings - # geometry mode - del bpy.types.Material.menu_geo - del bpy.types.Material.menu_upper - del bpy.types.Material.menu_lower - del bpy.types.Material.menu_other - del bpy.types.Material.menu_lower_render - del bpy.types.Material.rdp_settings def mat_register_old(): - bpy.types.Material.f3d_preset = bpy.props.EnumProperty(name = 'F3D Preset', - items = enumMaterialPresets, default = 'Custom', - update = update_preset) + bpy.types.Material.f3d_preset = bpy.props.EnumProperty( + name="F3D Preset", items=enumMaterialPresets, default="Custom", update=update_preset + ) - bpy.types.Material.scale_autoprop = bpy.props.BoolProperty( - name = 'Auto Set Scale', default = True, - update = update_node_values_without_preset) - bpy.types.Material.uv_basis = bpy.props.EnumProperty( - name = 'UV Basis', default = 'TEXEL0', - update = update_tex_values, items = enumTexUV) + bpy.types.Material.scale_autoprop = bpy.props.BoolProperty( + name="Auto Set Scale", default=True, update=update_node_values_without_preset + ) + bpy.types.Material.uv_basis = bpy.props.EnumProperty( + name="UV Basis", default="TEXEL0", update=update_tex_values, items=enumTexUV + ) - # Combiners - bpy.types.Material.presetName = bpy.props.StringProperty(name = "Preset Name", default = "Custom") + # Combiners + bpy.types.Material.presetName = bpy.props.StringProperty(name="Preset Name", default="Custom") - bpy.types.Material.combiner1 = bpy.props.PointerProperty(type = \ - CombinerProperty) - bpy.types.Material.combiner2 = bpy.props.PointerProperty(type = \ - CombinerProperty) + bpy.types.Material.combiner1 = bpy.props.PointerProperty(type=CombinerProperty) + bpy.types.Material.combiner2 = bpy.props.PointerProperty(type=CombinerProperty) - # Texture animation - bpy.types.Material.menu_procAnim = bpy.props.BoolProperty() - #bpy.types.Material.positionAnim = bpy.props.PointerProperty( - # type = ProcAnimVectorProperty) - #bpy.types.Material.UVanim_tex0 = bpy.props.PointerProperty( - # type = ProcAnimVectorProperty) - bpy.types.Material.UVanim_tex1 = bpy.props.PointerProperty( - type = ProcAnimVectorProperty) - #bpy.types.Material.colorAnim = bpy.props.PointerProperty( - # type = ProcAnimVectorProperty) + # Texture animation + bpy.types.Material.menu_procAnim = bpy.props.BoolProperty() + # bpy.types.Material.positionAnim = bpy.props.PointerProperty( + # type = ProcAnimVectorProperty) + # bpy.types.Material.UVanim_tex0 = bpy.props.PointerProperty( + # type = ProcAnimVectorProperty) + bpy.types.Material.UVanim_tex1 = bpy.props.PointerProperty(type=ProcAnimVectorProperty) + # bpy.types.Material.colorAnim = bpy.props.PointerProperty( + # type = ProcAnimVectorProperty) - bpy.types.Material.UVanim = bpy.props.PointerProperty( - type = ProcAnimVectorProperty) + bpy.types.Material.UVanim = bpy.props.PointerProperty(type=ProcAnimVectorProperty) - # material textures - bpy.types.Material.tex_scale = bpy.props.FloatVectorProperty( - min = 0, max = 1, size = 2, default = (1,1), step = 1, - update = update_tex_values) - bpy.types.Material.tex0 = bpy.props.PointerProperty(type = TextureProperty) - bpy.types.Material.tex1 = bpy.props.PointerProperty(type = TextureProperty) + # material textures + bpy.types.Material.tex_scale = bpy.props.FloatVectorProperty( + min=0, max=1, size=2, default=(1, 1), step=1, update=update_tex_values + ) + bpy.types.Material.tex0 = bpy.props.PointerProperty(type=TextureProperty) + bpy.types.Material.tex1 = bpy.props.PointerProperty(type=TextureProperty) - # Should Set? - bpy.types.Material.set_prim = bpy.props.BoolProperty(default = True, - update = update_node_values) - bpy.types.Material.set_lights = bpy.props.BoolProperty(default = True, - update = update_node_values) - bpy.types.Material.set_env = bpy.props.BoolProperty(default = False, - update = update_node_values) - bpy.types.Material.set_blend = bpy.props.BoolProperty(default = False, - update = update_node_values) - bpy.types.Material.set_key = bpy.props.BoolProperty(default = True, - update = update_node_values) - bpy.types.Material.set_k0_5 = bpy.props.BoolProperty(default = True, - update = update_node_values) - bpy.types.Material.set_combiner = bpy.props.BoolProperty(default = True, - update = update_node_values) - bpy.types.Material.use_default_lighting = bpy.props.BoolProperty(default = True, - update = update_node_values_without_preset) + # Should Set? + bpy.types.Material.set_prim = bpy.props.BoolProperty(default=True, update=update_node_values) + bpy.types.Material.set_lights = bpy.props.BoolProperty(default=True, update=update_node_values) + bpy.types.Material.set_env = bpy.props.BoolProperty(default=False, update=update_node_values) + bpy.types.Material.set_blend = bpy.props.BoolProperty(default=False, update=update_node_values) + bpy.types.Material.set_key = bpy.props.BoolProperty(default=True, update=update_node_values) + bpy.types.Material.set_k0_5 = bpy.props.BoolProperty(default=True, update=update_node_values) + bpy.types.Material.set_combiner = bpy.props.BoolProperty(default=True, update=update_node_values) + bpy.types.Material.use_default_lighting = bpy.props.BoolProperty( + default=True, update=update_node_values_without_preset + ) - # Blend Color - bpy.types.Material.blend_color = bpy.props.FloatVectorProperty( - name = 'Blend Color', subtype='COLOR', size = 4, min = 0, max = 1, default = (0,0,0,1)) + # Blend Color + bpy.types.Material.blend_color = bpy.props.FloatVectorProperty( + name="Blend Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) - # Chroma - bpy.types.Material.key_scale = bpy.props.FloatVectorProperty( - name = 'Key Scale', min = 0, max = 1, step = 1, - update = update_node_values) - bpy.types.Material.key_width = bpy.props.FloatVectorProperty( - name = 'Key Width', min = 0, max = 16, - update = update_node_values) + # Chroma + bpy.types.Material.key_scale = bpy.props.FloatVectorProperty( + name="Key Scale", min=0, max=1, step=1, update=update_node_values + ) + bpy.types.Material.key_width = bpy.props.FloatVectorProperty( + name="Key Width", min=0, max=16, update=update_node_values + ) - # Convert - bpy.types.Material.k0 = bpy.props.FloatProperty(min = -1, max = 1, - default = 175/255, step = 1, update = update_node_values) - bpy.types.Material.k1 = bpy.props.FloatProperty(min = -1, max = 1, - default = -43/255, step = 1, update = update_node_values) - bpy.types.Material.k2 = bpy.props.FloatProperty(min = -1, max = 1, - default = -89/255, step = 1, update = update_node_values) - bpy.types.Material.k3 = bpy.props.FloatProperty(min = -1, max = 1, - default = 222/255, step = 1, update = update_node_values) - bpy.types.Material.k4 = bpy.props.FloatProperty(min = -1, max = 1, - default = 114/255, step = 1, update = update_node_values) - bpy.types.Material.k5 = bpy.props.FloatProperty(min = -1, max = 1, - default = 42/255, step = 1, update = update_node_values) + # Convert + bpy.types.Material.k0 = bpy.props.FloatProperty(min=-1, max=1, default=175 / 255, step=1, update=update_node_values) + bpy.types.Material.k1 = bpy.props.FloatProperty(min=-1, max=1, default=-43 / 255, step=1, update=update_node_values) + bpy.types.Material.k2 = bpy.props.FloatProperty(min=-1, max=1, default=-89 / 255, step=1, update=update_node_values) + bpy.types.Material.k3 = bpy.props.FloatProperty(min=-1, max=1, default=222 / 255, step=1, update=update_node_values) + bpy.types.Material.k4 = bpy.props.FloatProperty(min=-1, max=1, default=114 / 255, step=1, update=update_node_values) + bpy.types.Material.k5 = bpy.props.FloatProperty(min=-1, max=1, default=42 / 255, step=1, update=update_node_values) - # Prim - bpy.types.Material.prim_lod_frac = bpy.props.FloatProperty( - name = 'Prim LOD Frac', min = 0, max = 1, step = 1, - update = update_node_values) - bpy.types.Material.prim_lod_min = bpy.props.FloatProperty( - name = 'Min LOD Ratio', min = 0, max = 1, step = 1, - update = update_node_values) + # Prim + bpy.types.Material.prim_lod_frac = bpy.props.FloatProperty( + name="Prim LOD Frac", min=0, max=1, step=1, update=update_node_values + ) + bpy.types.Material.prim_lod_min = bpy.props.FloatProperty( + name="Min LOD Ratio", min=0, max=1, step=1, update=update_node_values + ) - # lights - bpy.types.Material.default_light_color = bpy.props.FloatVectorProperty( - name = 'Default Light Color', subtype = 'COLOR', size = 4, min = 0, max = 1, default = (1,1,1,1), - update = update_node_values_without_preset) - bpy.types.Material.ambient_light_color = bpy.props.FloatVectorProperty( - name = 'Ambient Light Color', subtype = 'COLOR', size = 4, min = 0, max = 1, default = (0.5,0.5,0.5,1), - update = update_node_values_without_preset) - bpy.types.Material.f3d_light1 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) - bpy.types.Material.f3d_light2 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) - bpy.types.Material.f3d_light3 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) - bpy.types.Material.f3d_light4 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) - bpy.types.Material.f3d_light5 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) - bpy.types.Material.f3d_light6 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) - bpy.types.Material.f3d_light7 = bpy.props.PointerProperty( - type = bpy.types.Light, update = F3DOrganizeLights) + # lights + bpy.types.Material.default_light_color = bpy.props.FloatVectorProperty( + name="Default Light Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=update_node_values_without_preset, + ) + bpy.types.Material.ambient_light_color = bpy.props.FloatVectorProperty( + name="Ambient Light Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(0.5, 0.5, 0.5, 1), + update=update_node_values_without_preset, + ) + bpy.types.Material.f3d_light1 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + bpy.types.Material.f3d_light2 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + bpy.types.Material.f3d_light3 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + bpy.types.Material.f3d_light4 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + bpy.types.Material.f3d_light5 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + bpy.types.Material.f3d_light6 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) + bpy.types.Material.f3d_light7 = bpy.props.PointerProperty(type=bpy.types.Light, update=F3DOrganizeLights) - # Fog Properties - bpy.types.Material.fog_color = bpy.props.FloatVectorProperty( - name = 'Fog Color', subtype='COLOR', size = 4, min = 0, max = 1, default = (0,0,0,1)) - bpy.types.Material.fog_position = bpy.props.IntVectorProperty( - name = 'Fog Range', size = 2, min = 0, max = 1000, default = (970,1000)) - bpy.types.Material.set_fog = bpy.props.BoolProperty() - bpy.types.Material.use_global_fog = bpy.props.BoolProperty(default = True) + # Fog Properties + bpy.types.Material.fog_color = bpy.props.FloatVectorProperty( + name="Fog Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) + bpy.types.Material.fog_position = bpy.props.IntVectorProperty( + name="Fog Range", size=2, min=0, max=1000, default=(970, 1000) + ) + bpy.types.Material.set_fog = bpy.props.BoolProperty() + bpy.types.Material.use_global_fog = bpy.props.BoolProperty(default=True) + + # geometry mode + bpy.types.Material.menu_geo = bpy.props.BoolProperty() + bpy.types.Material.menu_upper = bpy.props.BoolProperty() + bpy.types.Material.menu_lower = bpy.props.BoolProperty() + bpy.types.Material.menu_other = bpy.props.BoolProperty() + bpy.types.Material.menu_lower_render = bpy.props.BoolProperty() + bpy.types.Material.rdp_settings = bpy.props.PointerProperty(type=RDPSettings) - # geometry mode - bpy.types.Material.menu_geo = bpy.props.BoolProperty() - bpy.types.Material.menu_upper = bpy.props.BoolProperty() - bpy.types.Material.menu_lower = bpy.props.BoolProperty() - bpy.types.Material.menu_other = bpy.props.BoolProperty() - bpy.types.Material.menu_lower_render = bpy.props.BoolProperty() - bpy.types.Material.rdp_settings = bpy.props.PointerProperty( - type = RDPSettings) def findF3DPresetPath(filename): - try: - presetPath = bpy.utils.user_resource('SCRIPTS', - os.path.join("presets", "f3d"), create=True) - except: # 3.0 - presetPath = bpy.utils.user_resource('SCRIPTS', - path=os.path.join("presets", "f3d"), create=True) - for subdir in os.listdir(presetPath): - subPath = os.path.join(presetPath, subdir) - if os.path.isdir(subPath): - for preset in os.listdir(subPath): - if preset[:-3] == filename: - return os.path.join(subPath, filename) + ".py" - raise PluginError("Preset " + str(filename) + " not found.") + try: + presetPath = bpy.utils.user_resource("SCRIPTS", os.path.join("presets", "f3d"), create=True) + except: # 3.0 + presetPath = bpy.utils.user_resource("SCRIPTS", path=os.path.join("presets", "f3d"), create=True) + for subdir in os.listdir(presetPath): + subPath = os.path.join(presetPath, subdir) + if os.path.isdir(subPath): + for preset in os.listdir(subPath): + if preset[:-3] == filename: + return os.path.join(subPath, filename) + ".py" + raise PluginError("Preset " + str(filename) + " not found.") + def getF3DPresetPath(filename, subdir): - try: - presetPath = bpy.utils.user_resource('SCRIPTS', - os.path.join("presets", subdir), create=True) - except: # 3.0 - presetPath = bpy.utils.user_resource('SCRIPTS', - path=os.path.join("presets", subdir), create=True) - return os.path.join(presetPath, filename) + ".py" + try: + presetPath = bpy.utils.user_resource("SCRIPTS", os.path.join("presets", subdir), create=True) + except: # 3.0 + presetPath = bpy.utils.user_resource("SCRIPTS", path=os.path.join("presets", subdir), create=True) + return os.path.join(presetPath, filename) + ".py" + def savePresets(): - for subdir, presets in material_presets.items(): - for filename, preset in presets.items(): - filepath = getF3DPresetPath(filename, 'f3d/' + subdir) - file_preset = open(filepath, 'w', encoding="utf-8") - file_preset.write(preset) - file_preset.close() + for subdir, presets in material_presets.items(): + for filename, preset in presets.items(): + filepath = getF3DPresetPath(filename, "f3d/" + subdir) + file_preset = open(filepath, "w", encoding="utf-8") + file_preset.write(preset) + file_preset.close() + def mat_register(): - #bpy.app.handlers.load_post.append(loadTimer) - for cls in mat_classes: - try: - register_class(cls) - except: - print('failed to register:', cls) + # bpy.app.handlers.load_post.append(loadTimer) + for cls in mat_classes: + try: + register_class(cls) + except: + print("failed to register:", cls) - #presetDict = addMaterialPresets() - #for presetName, presetItem in presetDict.items(): - # enumMaterialPresets.append((presetName, presetName, presetName)) - # materialPresetDict[presetName] = presetItem + # presetDict = addMaterialPresets() + # for presetName, presetItem in presetDict.items(): + # enumMaterialPresets.append((presetName, presetName, presetName)) + # materialPresetDict[presetName] = presetItem - savePresets() + savePresets() - nodeitems_utils.register_node_categories('CUSTOM_NODES', node_categories) + nodeitems_utils.register_node_categories("CUSTOM_NODES", node_categories) - bpy.types.Scene.f3d_type = bpy.props.EnumProperty( - name = 'F3D Microcode', items = enumF3D, default = 'F3D') - bpy.types.Scene.isHWv1 = bpy.props.BoolProperty(name = 'Is Hardware v1?') + bpy.types.Scene.f3d_type = bpy.props.EnumProperty(name="F3D Microcode", items=enumF3D, default="F3D") + bpy.types.Scene.isHWv1 = bpy.props.BoolProperty(name="Is Hardware v1?") - # RDP Defaults - bpy.types.World.rdp_defaults = bpy.props.PointerProperty( - type = RDPSettings) - bpy.types.World.menu_geo = bpy.props.BoolProperty() - bpy.types.World.menu_upper = bpy.props.BoolProperty() - bpy.types.World.menu_lower = bpy.props.BoolProperty() - bpy.types.World.menu_other = bpy.props.BoolProperty() - bpy.types.World.menu_layers = bpy.props.BoolProperty() + # RDP Defaults + bpy.types.World.rdp_defaults = bpy.props.PointerProperty(type=RDPSettings) + bpy.types.World.menu_geo = bpy.props.BoolProperty() + bpy.types.World.menu_upper = bpy.props.BoolProperty() + bpy.types.World.menu_lower = bpy.props.BoolProperty() + bpy.types.World.menu_other = bpy.props.BoolProperty() + bpy.types.World.menu_layers = bpy.props.BoolProperty() - mat_register_old() - bpy.types.Material.is_f3d = bpy.props.BoolProperty() - bpy.types.Material.mat_ver = bpy.props.IntProperty(default = 1) - bpy.types.Material.f3d_update_flag = bpy.props.BoolProperty() - bpy.types.Material.f3d_mat = bpy.props.PointerProperty(type = F3DMaterialProperty) - bpy.types.Material.menu_tab = bpy.props.EnumProperty(items = enumF3DMenu) + mat_register_old() + bpy.types.Material.is_f3d = bpy.props.BoolProperty() + bpy.types.Material.mat_ver = bpy.props.IntProperty(default=1) + bpy.types.Material.f3d_update_flag = bpy.props.BoolProperty() + bpy.types.Material.f3d_mat = bpy.props.PointerProperty(type=F3DMaterialProperty) + bpy.types.Material.menu_tab = bpy.props.EnumProperty(items=enumF3DMenu) - bpy.types.Scene.f3dUserPresetsOnly = bpy.props.BoolProperty(name = "User Presets Only") - bpy.types.Scene.f3d_simple = bpy.props.BoolProperty(name = "Display Simple", default = True) + bpy.types.Scene.f3dUserPresetsOnly = bpy.props.BoolProperty(name="User Presets Only") + bpy.types.Scene.f3d_simple = bpy.props.BoolProperty(name="Display Simple", default=True) + + bpy.types.Object.use_f3d_culling = bpy.props.BoolProperty( + name="Enable Culling (Applies to F3DEX and up)", default=True + ) + bpy.types.Object.ignore_render = bpy.props.BoolProperty(name="Ignore Render") + bpy.types.Object.ignore_collision = bpy.props.BoolProperty(name="Ignore Collision") + bpy.types.Object.f3d_lod_z = bpy.props.IntProperty(name="F3D LOD Z", min=1, default=10) + bpy.types.Object.f3d_lod_always_render_farthest = bpy.props.BoolProperty(name="Always Render Farthest LOD") - bpy.types.Object.use_f3d_culling = bpy.props.BoolProperty( - name = 'Enable Culling (Applies to F3DEX and up)', default = True) - bpy.types.Object.ignore_render = bpy.props.BoolProperty( - name = 'Ignore Render') - bpy.types.Object.ignore_collision = bpy.props.BoolProperty( - name = 'Ignore Collision') - bpy.types.Object.f3d_lod_z = bpy.props.IntProperty( - name = "F3D LOD Z", min = 1, default = 10) - bpy.types.Object.f3d_lod_always_render_farthest = bpy.props.BoolProperty(name = "Always Render Farthest LOD") def mat_unregister(): - del bpy.types.Material.menu_tab - del bpy.types.Material.f3d_mat - del bpy.types.Material.is_f3d - del bpy.types.Material.mat_ver - del bpy.types.Material.f3d_update_flag - del bpy.types.Scene.f3d_simple - del bpy.types.Object.ignore_render - del bpy.types.Object.ignore_collision - del bpy.types.Object.use_f3d_culling - del bpy.types.Scene.f3dUserPresetsOnly - del bpy.types.Object.f3d_lod_z - del bpy.types.Object.f3d_lod_always_render_farthest - nodeitems_utils.unregister_node_categories('CUSTOM_NODES') - for cls in reversed(mat_classes): - unregister_class(cls) + del bpy.types.Material.menu_tab + del bpy.types.Material.f3d_mat + del bpy.types.Material.is_f3d + del bpy.types.Material.mat_ver + del bpy.types.Material.f3d_update_flag + del bpy.types.Scene.f3d_simple + del bpy.types.Object.ignore_render + del bpy.types.Object.ignore_collision + del bpy.types.Object.use_f3d_culling + del bpy.types.Scene.f3dUserPresetsOnly + del bpy.types.Object.f3d_lod_z + del bpy.types.Object.f3d_lod_always_render_farthest + nodeitems_utils.unregister_node_categories("CUSTOM_NODES") + for cls in reversed(mat_classes): + unregister_class(cls) -#from .f3d_material import * + +# from .f3d_material import * # Presets sm64_unlit_texture = F3DMaterialSettings() @@ -3325,61 +3456,71 @@ sm64_fog_shaded_texture.g_fog = True sm64_fog_shaded_texture.color_combiner = tuple(S_FOG_SHADED_TEX) sm64_fog_shaded_texture.set_env = False sm64_fog_shaded_texture.set_fog = True -sm64_fog_shaded_texture.g_mdsft_cycletype = 'G_CYC_2CYCLE' +sm64_fog_shaded_texture.g_mdsft_cycletype = "G_CYC_2CYCLE" sm64_fog_shaded_texture.set_rendermode = True sm64_fog_shaded_texture.rendermode_advanced_enabled = False -sm64_fog_shaded_texture.rendermode_preset_cycle_1 = 'G_RM_FOG_SHADE_A' -sm64_fog_shaded_texture.rendermode_preset_cycle_2 = 'G_RM_AA_ZB_OPA_SURF2' +sm64_fog_shaded_texture.rendermode_preset_cycle_1 = "G_RM_FOG_SHADE_A" +sm64_fog_shaded_texture.rendermode_preset_cycle_2 = "G_RM_AA_ZB_OPA_SURF2" sm64_fog_shaded_texture_cutout = copy.deepcopy(sm64_fog_shaded_texture) -sm64_fog_shaded_texture_cutout.color_combiner = \ - tuple(S_FOG_SHADED_TEX_CUTOUT) -sm64_fog_shaded_texture_cutout.rendermode_preset_cycle_2 = 'G_RM_AA_ZB_TEX_EDGE2' +sm64_fog_shaded_texture_cutout.color_combiner = tuple(S_FOG_SHADED_TEX_CUTOUT) +sm64_fog_shaded_texture_cutout.rendermode_preset_cycle_2 = "G_RM_AA_ZB_TEX_EDGE2" sm64_fog_shaded_texture_cutout.g_cull_back = False sm64_fog_shaded_texture_cutout.blend_method = "CLIP" sm64_fog_shaded_texture_transparent = copy.deepcopy(sm64_fog_shaded_texture) -sm64_fog_shaded_texture_transparent.color_combiner = \ - tuple(S_FOG_PRIM_TRANSPARENT_SHADE) -sm64_fog_shaded_texture_transparent.rendermode_preset_cycle_2 = 'G_RM_AA_ZB_XLU_SURF2' +sm64_fog_shaded_texture_transparent.color_combiner = tuple(S_FOG_PRIM_TRANSPARENT_SHADE) +sm64_fog_shaded_texture_transparent.rendermode_preset_cycle_2 = "G_RM_AA_ZB_XLU_SURF2" sm64_fog_shaded_texture_transparent.g_cull_back = False sm64_fog_shaded_texture_transparent.blend_method = "BLEND" # WARNING: Adding new presets will break any custom presets added afterward. enumMaterialPresets = [ - ('Custom', 'Custom', 'Custom'), - ('Unlit Texture', 'Unlit Texture', 'Unlit Texture'), - ('Unlit Texture Cutout', 'Unlit Texture Cutout', 'Unlit Texture Cutout'), - ('Shaded Solid', 'Shaded Solid', 'Shaded Solid'), - ('Decal On Shaded Solid', 'Decal On Shaded Solid', 'Decal On Shaded Solid'), - ('Shaded Texture', 'Shaded Texture', 'Shaded Texture'), - ('Shaded Texture Cutout', 'Shaded Texture Cutout', 'Shaded Texture Cutout'), - ('Shaded Texture Transparent', 'Shaded Texture Transparent (Prim Alpha)', 'Shaded Texture Transparent (Prim Alpha)'), - ('Vertex Colored Texture', 'Vertex Colored Texture', 'Vertex Colored Texture'), - ('Environment Mapped', 'Environment Mapped', 'Environment Mapped'), - ('Fog Shaded Texture', 'Fog Shaded Texture', 'Fog Shaded Texture'), - ('Fog Shaded Texture Cutout', 'Fog Shaded Texture Cutout', 'Fog Shaded Texture Cutout'), - ('Fog Shaded Texture Transparent', 'Fog Shaded Texture Transparent (Prim Alpha)', 'Fog Shaded Texture Transparent (Prim Alpha)'), - ('Vertex Colored Texture Transparent', 'Vertex Colored Texture Transparent', 'Vertex Colored Texture Transparent'), - ('Shaded Noise', 'Shaded Noise', 'Shaded Noise'), - ('Vertex Colored Texture (No Vertex Alpha)', 'Vertex Colored Texture (No Vertex Alpha)', 'Vertex Colored Texture (No Vertex Alpha)'), + ("Custom", "Custom", "Custom"), + ("Unlit Texture", "Unlit Texture", "Unlit Texture"), + ("Unlit Texture Cutout", "Unlit Texture Cutout", "Unlit Texture Cutout"), + ("Shaded Solid", "Shaded Solid", "Shaded Solid"), + ("Decal On Shaded Solid", "Decal On Shaded Solid", "Decal On Shaded Solid"), + ("Shaded Texture", "Shaded Texture", "Shaded Texture"), + ("Shaded Texture Cutout", "Shaded Texture Cutout", "Shaded Texture Cutout"), + ( + "Shaded Texture Transparent", + "Shaded Texture Transparent (Prim Alpha)", + "Shaded Texture Transparent (Prim Alpha)", + ), + ("Vertex Colored Texture", "Vertex Colored Texture", "Vertex Colored Texture"), + ("Environment Mapped", "Environment Mapped", "Environment Mapped"), + ("Fog Shaded Texture", "Fog Shaded Texture", "Fog Shaded Texture"), + ("Fog Shaded Texture Cutout", "Fog Shaded Texture Cutout", "Fog Shaded Texture Cutout"), + ( + "Fog Shaded Texture Transparent", + "Fog Shaded Texture Transparent (Prim Alpha)", + "Fog Shaded Texture Transparent (Prim Alpha)", + ), + ("Vertex Colored Texture Transparent", "Vertex Colored Texture Transparent", "Vertex Colored Texture Transparent"), + ("Shaded Noise", "Shaded Noise", "Shaded Noise"), + ( + "Vertex Colored Texture (No Vertex Alpha)", + "Vertex Colored Texture (No Vertex Alpha)", + "Vertex Colored Texture (No Vertex Alpha)", + ), ] materialPresetDict = { - 'Unlit Texture' : sm64_unlit_texture, - 'Unlit Texture Cutout' : sm64_unlit_texture_cutout, - 'Shaded Solid' : sm64_shaded_solid, - 'Shaded Texture' : sm64_shaded_texture, - 'Shaded Texture Cutout' : sm64_shaded_texture_cutout, - 'Shaded Texture Transparent' : sm64_prim_transparent_shade, - 'Environment Mapped' : sm64_unlit_env_map, - 'Decal On Shaded Solid' : sm64_decal, - 'Vertex Colored Texture' : sm64_vert_colored_tex, - 'Fog Shaded Texture' : sm64_fog_shaded_texture, - 'Fog Shaded Texture Cutout' : sm64_fog_shaded_texture_cutout, - 'Fog Shaded Texture Transparent' : sm64_fog_shaded_texture_transparent, - 'Vertex Colored Texture Transparent' : sm64_vert_colored_tex_transparent, - 'Shaded Noise' : sm64_shaded_noise, - 'Vertex Colored Texture (No Vertex Alpha)' : sm64_vert_colored_tex_no_vert_alpha, + "Unlit Texture": sm64_unlit_texture, + "Unlit Texture Cutout": sm64_unlit_texture_cutout, + "Shaded Solid": sm64_shaded_solid, + "Shaded Texture": sm64_shaded_texture, + "Shaded Texture Cutout": sm64_shaded_texture_cutout, + "Shaded Texture Transparent": sm64_prim_transparent_shade, + "Environment Mapped": sm64_unlit_env_map, + "Decal On Shaded Solid": sm64_decal, + "Vertex Colored Texture": sm64_vert_colored_tex, + "Fog Shaded Texture": sm64_fog_shaded_texture, + "Fog Shaded Texture Cutout": sm64_fog_shaded_texture_cutout, + "Fog Shaded Texture Transparent": sm64_fog_shaded_texture_transparent, + "Vertex Colored Texture Transparent": sm64_vert_colored_tex_transparent, + "Shaded Noise": sm64_shaded_noise, + "Vertex Colored Texture (No Vertex Alpha)": sm64_vert_colored_tex_no_vert_alpha, } diff --git a/fast64_internal/f3d/f3d_material_nodes.py b/fast64_internal/f3d/f3d_material_nodes.py index 7b552cb..89ae1ca 100644 --- a/fast64_internal/f3d/f3d_material_nodes.py +++ b/fast64_internal/f3d/f3d_material_nodes.py @@ -5,1123 +5,1122 @@ from .f3d_gbi import F3D from .f3d_enums import * from bpy.utils import register_class, unregister_class + def createGroupLink(node_tree, inputSocket, outputSocket, outputType, outputName): - if outputType is not None: - node_tree.outputs.new(outputType, outputName) - node_tree.links.new(inputSocket, outputSocket) + if outputType is not None: + node_tree.outputs.new(outputType, outputName) + node_tree.links.new(inputSocket, outputSocket) + def addColorWithAlphaNode(label, x, y, node_tree): - alphaSplitNode = node_tree.nodes.new('GetAlphaFromColor') - alphaSplitNode.location = (x-300, y) - alphaSplitNode.name = label + " Output" - - addNode = node_tree.nodes.new('ShaderNodeMath') - addNode.operation = 'ADD' - addNode.inputs[1].default_value = 0 - node_tree.links.new(addNode.inputs[0], alphaSplitNode.outputs[1]) - addNode.location = (x,y) - addNode.name = label + ' Alpha' + alphaSplitNode = node_tree.nodes.new("GetAlphaFromColor") + alphaSplitNode.location = (x - 300, y) + alphaSplitNode.name = label + " Output" - mixNode = node_tree.nodes.new('ShaderNodeMixRGB') - mixNode.inputs[0].default_value = 0 - node_tree.links.new(mixNode.inputs[1], alphaSplitNode.outputs[0]) - mixNode.location = (x,y - 100) - mixNode.name = label + ' RGB' + addNode = node_tree.nodes.new("ShaderNodeMath") + addNode.operation = "ADD" + addNode.inputs[1].default_value = 0 + node_tree.links.new(addNode.inputs[0], alphaSplitNode.outputs[1]) + addNode.location = (x, y) + addNode.name = label + " Alpha" - y -= 100 - return x, y, alphaSplitNode + mixNode = node_tree.nodes.new("ShaderNodeMixRGB") + mixNode.inputs[0].default_value = 0 + node_tree.links.new(mixNode.inputs[1], alphaSplitNode.outputs[0]) + mixNode.location = (x, y - 100) + mixNode.name = label + " RGB" -def addNodeAt(node_tree, name, label, x, y, nodeKey = None, nodeDict = None): - node = node_tree.nodes.new(name) - if label is not None: - node.label = label - node.name = label - node.location = (x,y) - if label == '1': - node.outputs[0].default_value = 1 - elif label == '0': - node.outputs[0].default_value = 0 - elif label == 'Shade Color': - node.label = 'Shade Shader' - colorNode = node_tree.nodes.new('ShaderNodeShaderToRGB') - node.inputs[0].default_value = (1,1,1,1) - if label is not None: - colorNode.label = label - node_tree.links.new(colorNode.inputs[0], node.outputs[0]) - colorNode.location = (x,y) - node.location = (x - 300, y) - node = colorNode - elif label == 'Noise': - node.inputs[1].default_value = 40 # scale - node.inputs[2].default_value = 0 # detail + y -= 100 + return x, y, alphaSplitNode - if nodeDict is not None: - if name in nodeDict: - raise ValueError(name + " already in the node dictionary.") - if nodeKey is not None: - nodeDict[nodeKey] = node - else: - nodeDict[name] = node - return (node, x, y - (node.height)) -def addNodeListAt(node_tree, nodeDict, x,y, cycleIndex = None): - newDict = {} - for label, typename in nodeDict.items(): - if cycleIndex is not None: - name = label + " " + str(cycleIndex) - else: - name = label - node, xDiscard, y = addNodeAt(node_tree, typename, name, x, y) - newDict[name] = node - return newDict, x, y +def addNodeAt(node_tree, name, label, x, y, nodeKey=None, nodeDict=None): + node = node_tree.nodes.new(name) + if label is not None: + node.label = label + node.name = label + node.location = (x, y) + if label == "1": + node.outputs[0].default_value = 1 + elif label == "0": + node.outputs[0].default_value = 0 + elif label == "Shade Color": + node.label = "Shade Shader" + colorNode = node_tree.nodes.new("ShaderNodeShaderToRGB") + node.inputs[0].default_value = (1, 1, 1, 1) + if label is not None: + colorNode.label = label + node_tree.links.new(colorNode.inputs[0], node.outputs[0]) + colorNode.location = (x, y) + node.location = (x - 300, y) + node = colorNode + elif label == "Noise": + node.inputs[1].default_value = 40 # scale + node.inputs[2].default_value = 0 # detail -def addSocketList(groupNode, groupInputNode, socketDict, cycleIndex = None): - newDict = {} - for label, typename in socketDict.items(): - if cycleIndex is not None: - name = label + " " + str(cycleIndex) - else: - name = label - #addNodeAt(node_tree, typename, name, x, y) - groupNode.inputs.new(typename, name) - groupInputNode.outputs.new(typename, name) + if nodeDict is not None: + if name in nodeDict: + raise ValueError(name + " already in the node dictionary.") + if nodeKey is not None: + nodeDict[nodeKey] = node + else: + nodeDict[name] = node + return (node, x, y - (node.height)) + + +def addNodeListAt(node_tree, nodeDict, x, y, cycleIndex=None): + newDict = {} + for label, typename in nodeDict.items(): + if cycleIndex is not None: + name = label + " " + str(cycleIndex) + else: + name = label + node, xDiscard, y = addNodeAt(node_tree, typename, name, x, y) + newDict[name] = node + return newDict, x, y + + +def addSocketList(groupNode, groupInputNode, socketDict, cycleIndex=None): + newDict = {} + for label, typename in socketDict.items(): + if cycleIndex is not None: + name = label + " " + str(cycleIndex) + else: + name = label + # addNodeAt(node_tree, typename, name, x, y) + groupNode.inputs.new(typename, name) + groupInputNode.outputs.new(typename, name) + + # We want to get the new output socket. + # new() doesn't actually return the socket, so we must index the collection. + # -1 is the index for the virtual socket at the end, so we want -2 instead. + outputSocket = groupInputNode.outputs[-2] + + newDict[name] = outputSocket + return newDict - # We want to get the new output socket. - # new() doesn't actually return the socket, so we must index the collection. - # -1 is the index for the virtual socket at the end, so we want -2 instead. - outputSocket = groupInputNode.outputs[-2] - - newDict[name] = outputSocket - return newDict # In 2.8 the Node.update function does not work. # We can bypass this by adding an update callback to a property in the node. # However, forcing an output socket update does NOT work when the output # is a group node input. Thus we must add an "add" bridge node in between to fix this. -def addNodeListAtWithZeroAddNode(node_tree, nodeDict, x,y, cycleIndex): - newDict = {} - for label, typename in nodeDict.items(): - name = label + " " + str(cycleIndex) - node, nextX, nextY = addNodeAt(node_tree, typename, name, x, y) - bridge, nextX, nextY = addNodeAt( - node_tree, 'ShaderNodeMath', name + ' Bridge', nextX, y) - bridge.operation = 'ADD' - bridge.inputs[1].default_value = 0 - node_tree.links.new(bridge.inputs[0], node.outputs[0]) - newDict[name] = bridge - y = nextY - return newDict +def addNodeListAtWithZeroAddNode(node_tree, nodeDict, x, y, cycleIndex): + newDict = {} + for label, typename in nodeDict.items(): + name = label + " " + str(cycleIndex) + node, nextX, nextY = addNodeAt(node_tree, typename, name, x, y) + bridge, nextX, nextY = addNodeAt(node_tree, "ShaderNodeMath", name + " Bridge", nextX, y) + bridge.operation = "ADD" + bridge.inputs[1].default_value = 0 + node_tree.links.new(bridge.inputs[0], node.outputs[0]) + newDict[name] = bridge + y = nextY + return newDict + # Assumes ascending order of cases. -def createNodeSwitch(node_tree, caseDict, caseSocket, caseName, - location, socketDict): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.location = location - location[1] = location[1] - (groupNode.height + 100) +def createNodeSwitch(node_tree, caseDict, caseSocket, caseName, location, socketDict): + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.location = location + location[1] = location[1] - (groupNode.height + 100) - createGroup = 'Switch ' + caseName + ' F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups["Switch " + caseName + " F3D v3"] - groupNode.node_tree = group_tree + createGroup = "Switch " + caseName + " F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Switch " + caseName + " F3D v3"] + groupNode.node_tree = group_tree - node_tree.links.new(groupNode.inputs[0], caseSocket) - internalSocketDict, nextSocketIndex = socketDictToInternalSocket(node_tree, - groupNode, None, socketDict, 1, False) - return groupNode + node_tree.links.new(groupNode.inputs[0], caseSocket) + internalSocketDict, nextSocketIndex = socketDictToInternalSocket( + node_tree, groupNode, None, socketDict, 1, False + ) + return groupNode - group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name = 'Switch ' + caseName + ' F3D v3') - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - output_node = group_tree.nodes.new("NodeGroupOutput") - input_node.location = (-300, 0) - output_node.location = (600, 0) + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Switch " + caseName + " F3D v3") + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + output_node = group_tree.nodes.new("NodeGroupOutput") + input_node.location = (-300, 0) + output_node.location = (600, 0) - # Add case node links - groupNode.inputs.new('NodeSocketInt', caseName) - node_tree.links.new(groupNode.inputs[0], caseSocket) - input_node.outputs.new('NodeSocketInt', caseName) - output_node.inputs.new('NodeSocketInt', caseName) - caseNodeInternal = input_node.outputs[0] + # Add case node links + groupNode.inputs.new("NodeSocketInt", caseName) + node_tree.links.new(groupNode.inputs[0], caseSocket) + input_node.outputs.new("NodeSocketInt", caseName) + output_node.inputs.new("NodeSocketInt", caseName) + caseNodeInternal = input_node.outputs[0] - internalSocketDict, nextSocketIndex = socketDictToInternalSocket(node_tree, - groupNode, input_node, socketDict, 1, True) + internalSocketDict, nextSocketIndex = socketDictToInternalSocket( + node_tree, groupNode, input_node, socketDict, 1, True + ) - nodePos = [0,0] - for case in reversed(range (len(caseDict))): - name = caseDict[case] - if case == len(caseDict) - 1: - prevSocket = internalSocketDict[name] - else: - greaterThanNode, mixNodeX, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, *nodePos) - greaterThanNode.operation = 'GREATER_THAN' - mixNode, x, nodePos[1] = addNodeAt(group_tree, - 'ShaderNodeMixRGB', None, mixNodeX, nodePos[1]) - - group_tree.links.new(greaterThanNode.inputs[0], caseNodeInternal) - group_tree.links.new(mixNode.inputs[0], - greaterThanNode.outputs[0]) - greaterThanNode.inputs[1].default_value = case - - # Connect group input to nodes - group_tree.links.new(mixNode.inputs[1], - internalSocketDict[name]) - group_tree.links.new(mixNode.inputs[2], - prevSocket) + nodePos = [0, 0] + for case in reversed(range(len(caseDict))): + name = caseDict[case] + if case == len(caseDict) - 1: + prevSocket = internalSocketDict[name] + else: + greaterThanNode, mixNodeX, y = addNodeAt(group_tree, "ShaderNodeMath", None, *nodePos) + greaterThanNode.operation = "GREATER_THAN" + mixNode, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMixRGB", None, mixNodeX, nodePos[1]) - prevSocket = mixNode.outputs[0] + group_tree.links.new(greaterThanNode.inputs[0], caseNodeInternal) + group_tree.links.new(mixNode.inputs[0], greaterThanNode.outputs[0]) + greaterThanNode.inputs[1].default_value = case + + # Connect group input to nodes + group_tree.links.new(mixNode.inputs[1], internalSocketDict[name]) + group_tree.links.new(mixNode.inputs[2], prevSocket) + + prevSocket = mixNode.outputs[0] + + group_tree.links.new(output_node.inputs[0], prevSocket) + + return groupNode - group_tree.links.new(output_node.inputs[0], prevSocket) - - return groupNode def createNodeCombinerMix(node_tree, nodeASocket, nodeBSocket, nodeCSocket, nodeDSocket, location, isAlpha): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.location = location - location[1] = location[1] - (groupNode.height + 100) + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.location = location + location[1] = location[1] - (groupNode.height + 100) - alphaText = 'Alpha ' if isAlpha else '' + alphaText = "Alpha " if isAlpha else "" - createGroup = 'Color Combiner ' + alphaText + 'Mix F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['Color Combiner ' + alphaText + 'Mix F3D v3'] - groupNode.node_tree = group_tree - - inputA = groupNode.inputs[0] - node_tree.links.new(inputA, nodeASocket) + createGroup = "Color Combiner " + alphaText + "Mix F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Color Combiner " + alphaText + "Mix F3D v3"] + groupNode.node_tree = group_tree - inputB = groupNode.inputs[1] - node_tree.links.new(inputB, nodeBSocket) + inputA = groupNode.inputs[0] + node_tree.links.new(inputA, nodeASocket) - inputC = groupNode.inputs[2] - node_tree.links.new(inputC, nodeCSocket) + inputB = groupNode.inputs[1] + node_tree.links.new(inputB, nodeBSocket) - inputD = groupNode.inputs[3] - node_tree.links.new(inputD, nodeDSocket) + inputC = groupNode.inputs[2] + node_tree.links.new(inputC, nodeCSocket) - return groupNode + inputD = groupNode.inputs[3] + node_tree.links.new(inputD, nodeDSocket) - # (A-B)*C + D - group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name = 'Color Combiner ' + alphaText + 'Mix F3D v3') - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - input_node.location = (-300, 0) - output_node = group_tree.nodes.new("NodeGroupOutput") - output_node.location = (600, 0) + return groupNode - # Add input source to group input - socketType = 'NodeSocketColor' if not isAlpha else 'NodeSocketFloat' - groupNode.inputs.new(socketType, 'A') - input_node.outputs.new(socketType, 'A') - inputA = groupNode.inputs[0] - node_tree.links.new(inputA, nodeASocket) + # (A-B)*C + D + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Color Combiner " + alphaText + "Mix F3D v3") + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + input_node.location = (-300, 0) + output_node = group_tree.nodes.new("NodeGroupOutput") + output_node.location = (600, 0) - groupNode.inputs.new(socketType, 'B') - input_node.outputs.new(socketType, 'B') - inputB = groupNode.inputs[1] - node_tree.links.new(inputB, nodeBSocket) + # Add input source to group input + socketType = "NodeSocketColor" if not isAlpha else "NodeSocketFloat" + groupNode.inputs.new(socketType, "A") + input_node.outputs.new(socketType, "A") + inputA = groupNode.inputs[0] + node_tree.links.new(inputA, nodeASocket) - groupNode.inputs.new(socketType, 'C') - input_node.outputs.new(socketType, 'C') - inputC = groupNode.inputs[2] - node_tree.links.new(inputC, nodeCSocket) + groupNode.inputs.new(socketType, "B") + input_node.outputs.new(socketType, "B") + inputB = groupNode.inputs[1] + node_tree.links.new(inputB, nodeBSocket) - groupNode.inputs.new(socketType, 'D') - input_node.outputs.new(socketType, 'D') - inputD = groupNode.inputs[3] - node_tree.links.new(inputD, nodeDSocket) + groupNode.inputs.new(socketType, "C") + input_node.outputs.new(socketType, "C") + inputC = groupNode.inputs[2] + node_tree.links.new(inputC, nodeCSocket) - nodePos = [0,0] - if not isAlpha: - nodeSubtract, x, nodePos[1] = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', 'Subtract', *nodePos) - nodeMultiply, x, nodePos[1] = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', 'Multiply', *nodePos) - nodeAdd, x, nodePos[1] = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', 'Add', *nodePos) + groupNode.inputs.new(socketType, "D") + input_node.outputs.new(socketType, "D") + inputD = groupNode.inputs[3] + node_tree.links.new(inputD, nodeDSocket) - nodeSubtract.blend_type = 'SUBTRACT' - nodeMultiply.blend_type = 'MULTIPLY' - nodeAdd.blend_type = 'ADD' + nodePos = [0, 0] + if not isAlpha: + nodeSubtract, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMixRGB", "Subtract", *nodePos) + nodeMultiply, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMixRGB", "Multiply", *nodePos) + nodeAdd, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMixRGB", "Add", *nodePos) - nodeSubtract.inputs['Fac'].default_value = 1 - nodeMultiply.inputs['Fac'].default_value = 1 - nodeAdd.inputs['Fac'].default_value = 1 - else: - nodeSubtract, x, nodePos[1] = \ - addNodeAt(group_tree, 'ShaderNodeMath', 'Subtract', *nodePos) - nodeMultiply, x, nodePos[1] = \ - addNodeAt(group_tree, 'ShaderNodeMath', 'Multiply', *nodePos) - nodeAdd, x, nodePos[1] = \ - addNodeAt(group_tree, 'ShaderNodeMath', 'Add', *nodePos) + nodeSubtract.blend_type = "SUBTRACT" + nodeMultiply.blend_type = "MULTIPLY" + nodeAdd.blend_type = "ADD" - nodeSubtract.operation = 'SUBTRACT' - nodeMultiply.operation = 'MULTIPLY' - nodeAdd.operation = 'ADD' + nodeSubtract.inputs["Fac"].default_value = 1 + nodeMultiply.inputs["Fac"].default_value = 1 + nodeAdd.inputs["Fac"].default_value = 1 + else: + nodeSubtract, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMath", "Subtract", *nodePos) + nodeMultiply, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMath", "Multiply", *nodePos) + nodeAdd, x, nodePos[1] = addNodeAt(group_tree, "ShaderNodeMath", "Add", *nodePos) - index1 = 1 if not isAlpha else 0 - index2 = 2 if not isAlpha else 1 - group_tree.links.new(nodeSubtract.inputs[index1], input_node.outputs[0]) - group_tree.links.new(nodeSubtract.inputs[index2], input_node.outputs[1]) - group_tree.links.new(nodeMultiply.inputs[index1], nodeSubtract.outputs[0]) - group_tree.links.new(nodeMultiply.inputs[index2], input_node.outputs[2]) - group_tree.links.new(nodeAdd.inputs[index1], nodeMultiply.outputs[0]) - group_tree.links.new(nodeAdd.inputs[index2], input_node.outputs[3]) + nodeSubtract.operation = "SUBTRACT" + nodeMultiply.operation = "MULTIPLY" + nodeAdd.operation = "ADD" + + index1 = 1 if not isAlpha else 0 + index2 = 2 if not isAlpha else 1 + group_tree.links.new(nodeSubtract.inputs[index1], input_node.outputs[0]) + group_tree.links.new(nodeSubtract.inputs[index2], input_node.outputs[1]) + group_tree.links.new(nodeMultiply.inputs[index1], nodeSubtract.outputs[0]) + group_tree.links.new(nodeMultiply.inputs[index2], input_node.outputs[2]) + group_tree.links.new(nodeAdd.inputs[index1], nodeMultiply.outputs[0]) + group_tree.links.new(nodeAdd.inputs[index2], input_node.outputs[3]) + + output_node.inputs.new(socketType, "Output") + groupNode.outputs.new(socketType, "Output") + group_tree.links.new(output_node.inputs[0], nodeAdd.outputs[0]) + + return groupNode - output_node.inputs.new(socketType, 'Output') - groupNode.outputs.new(socketType, 'Output') - group_tree.links.new(output_node.inputs[0], nodeAdd.outputs[0]) - - return groupNode # caseSocketDict is Case A-D for color and alpha # socketDict is all color sources def createNodeCombiner(node_tree, cycleIndex): - groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode = node_tree.nodes.new("ShaderNodeGroup") - createGroup = 'Color Combiner F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['Color Combiner F3D v3'] - groupNode.node_tree = group_tree - groupNode.name = 'Color Combiner Cycle ' + str(cycleIndex) + ' F3D v3' + createGroup = "Color Combiner F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Color Combiner F3D v3"] + groupNode.node_tree = group_tree + groupNode.name = "Color Combiner Cycle " + str(cycleIndex) + " F3D v3" - #caseSocketDict, nextIndex = \ - # socketDictToInternalSocket(node_tree, groupNode, None, caseSocketDict, 0, False) + # caseSocketDict, nextIndex = \ + # socketDictToInternalSocket(node_tree, groupNode, None, caseSocketDict, 0, False) - #socketDict, nextIndex = \ - # socketDictToInternalSocket(node_tree, groupNode, None, socketDict, nextIndex, False) + # socketDict, nextIndex = \ + # socketDictToInternalSocket(node_tree, groupNode, None, socketDict, nextIndex, False) - return groupNode + return groupNode - group_tree = bpy.data.node_groups.new( - type="ShaderNodeTree", name = 'Color Combiner F3D v3') - groupNode.node_tree = group_tree - groupNode.name = 'Color Combiner Cycle ' + str(cycleIndex) + ' F3D v3' - input_node = group_tree.nodes.new("NodeGroupInput") - input_node.location = (-300, 0) - output_node = group_tree.nodes.new("NodeGroupOutput") - output_node.location = (900, 0) + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Color Combiner F3D v3") + groupNode.node_tree = group_tree + groupNode.name = "Color Combiner Cycle " + str(cycleIndex) + " F3D v3" + input_node = group_tree.nodes.new("NodeGroupInput") + input_node.location = (-300, 0) + output_node = group_tree.nodes.new("NodeGroupOutput") + output_node.location = (900, 0) - caseSocketDict = addSocketList(groupNode, input_node, caseTemplateDict, cycleIndex) - #caseSocketDict, nextIndex = \ - # socketDictToInternalSocket(node_tree, groupNode, input_node, caseSocketDict, 0, True) + caseSocketDict = addSocketList(groupNode, input_node, caseTemplateDict, cycleIndex) + # caseSocketDict, nextIndex = \ + # socketDictToInternalSocket(node_tree, groupNode, input_node, caseSocketDict, 0, True) - #socketDict, nextIndex = \ - # socketDictToInternalSocket(node_tree, groupNode, input_node, socketDict, nextIndex, True) - - nodePos = [300, 0] + # socketDict, nextIndex = \ + # socketDictToInternalSocket(node_tree, groupNode, input_node, socketDict, nextIndex, True) - # Creating switch cascade - #caseNodes = {} - #for name, socket in caseSocketDict.items(): - # caseNodes[name] = createNodeSwitch(group_tree, - # [item[1] for item in combiner_enums[name[:-2]]], - # socket, name[:-2] , nodePos, socketDict) + nodePos = [300, 0] - nodePos = [600, 0] - out1 = createNodeCombinerMix( - group_tree, caseSocketDict['Case A ' + str(cycleIndex)], caseSocketDict['Case B ' + str(cycleIndex)], - caseSocketDict['Case C ' + str(cycleIndex)], caseSocketDict['Case D ' + str(cycleIndex)], nodePos, False) - out_alpha1 = createNodeCombinerMix(group_tree, caseSocketDict['Case A Alpha ' + str(cycleIndex)], - caseSocketDict['Case B Alpha ' + str(cycleIndex)], caseSocketDict['Case C Alpha ' + str(cycleIndex)], - caseSocketDict['Case D Alpha ' + str(cycleIndex)], nodePos, True) + # Creating switch cascade + # caseNodes = {} + # for name, socket in caseSocketDict.items(): + # caseNodes[name] = createNodeSwitch(group_tree, + # [item[1] for item in combiner_enums[name[:-2]]], + # socket, name[:-2] , nodePos, socketDict) - groupNode.outputs.new('NodeSocketColor', 'Color Combiner') - output_node.inputs.new('NodeSocketColor', 'Color Combiner') - groupNode.outputs.new('NodeSocketFloat', 'Color Combiner Alpha') - output_node.inputs.new('NodeSocketFloat', 'Color Combiner Alpha') - group_tree.links.new(output_node.inputs[0], out1.outputs[0]) - group_tree.links.new(output_node.inputs[1], out_alpha1.outputs[0]) + nodePos = [600, 0] + out1 = createNodeCombinerMix( + group_tree, + caseSocketDict["Case A " + str(cycleIndex)], + caseSocketDict["Case B " + str(cycleIndex)], + caseSocketDict["Case C " + str(cycleIndex)], + caseSocketDict["Case D " + str(cycleIndex)], + nodePos, + False, + ) + out_alpha1 = createNodeCombinerMix( + group_tree, + caseSocketDict["Case A Alpha " + str(cycleIndex)], + caseSocketDict["Case B Alpha " + str(cycleIndex)], + caseSocketDict["Case C Alpha " + str(cycleIndex)], + caseSocketDict["Case D Alpha " + str(cycleIndex)], + nodePos, + True, + ) + + groupNode.outputs.new("NodeSocketColor", "Color Combiner") + output_node.inputs.new("NodeSocketColor", "Color Combiner") + groupNode.outputs.new("NodeSocketFloat", "Color Combiner Alpha") + output_node.inputs.new("NodeSocketFloat", "Color Combiner Alpha") + group_tree.links.new(output_node.inputs[0], out1.outputs[0]) + group_tree.links.new(output_node.inputs[1], out_alpha1.outputs[0]) + + return groupNode - return groupNode # caseNodeDict is the A-D for color and alpha # nodeDict is all sources # otherDict is other shader inputs def createNodeF3D(node_tree, location): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.location = location - groupNode.name = 'F3D v3' - location[1] = location[1] - (groupNode.height + 100) + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.location = location + groupNode.name = "F3D v3" + location[1] = location[1] - (groupNode.height + 100) - createGroup = 'F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['F3D v3'] - groupNode.node_tree = group_tree + createGroup = "F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["F3D v3"] + groupNode.node_tree = group_tree - #caseSocketDict1, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, None, - # caseNodeDict1, [], [], 0, False) + # caseSocketDict1, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, None, + # caseNodeDict1, [], [], 0, False) - #caseSocketDict2, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, None, - # caseNodeDict2, [], [], nextIndex, False) + # caseSocketDict2, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, None, + # caseNodeDict2, [], [], nextIndex, False) - #socketDict, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, None, - # nodeDict, ['Combined Color', 'Shade Color', "Texture 0", "Texture 1"], - # ['Environment Color', 'Primitive Color'], nextIndex, False) + # socketDict, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, None, + # nodeDict, ['Combined Color', 'Shade Color', "Texture 0", "Texture 1"], + # ['Environment Color', 'Primitive Color'], nextIndex, False) - #otherSocketDict, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, None, - # otherDict, [], [], nextIndex, False) + # otherSocketDict, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, None, + # otherDict, [], [], nextIndex, False) - return groupNode, location[0], location[1] + return groupNode, location[0], location[1] - group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name = 'F3D v3') - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - output_node = group_tree.nodes.new("NodeGroupOutput") - input_node.location = (-300, 0) - output_node.location = (600, 0) - links = group_tree.links + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="F3D v3") + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + output_node = group_tree.nodes.new("NodeGroupOutput") + input_node.location = (-300, 0) + output_node.location = (600, 0) + links = group_tree.links - #caseSocketDict1, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, input_node, - # caseNodeDict1, [], [], 0, True) + # caseSocketDict1, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, input_node, + # caseNodeDict1, [], [], 0, True) - #caseSocketDict2, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, input_node, - # caseNodeDict2, [], [], nextIndex, True) + # caseSocketDict2, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, input_node, + # caseNodeDict2, [], [], nextIndex, True) - #socketDict, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, input_node, - # nodeDict, ['Combined Color', 'Shade Color', "Texture 0", "Texture 1"], - # ['Environment Color', 'Primitive Color'], nextIndex, True) - - #otherSocketDict, nextIndex = \ - # nodeDictToInternalSocket(node_tree, groupNode, input_node, - # otherDict, [], [], nextIndex, True) + # socketDict, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, input_node, + # nodeDict, ['Combined Color', 'Shade Color', "Texture 0", "Texture 1"], + # ['Environment Color', 'Primitive Color'], nextIndex, True) - #caseSocketDict1 = addSocketList(groupNode, input_node, caseTemplateDict, 1) - #caseSocketDict2 = addSocketList(groupNode, input_node, caseTemplateDict, 2) + # otherSocketDict, nextIndex = \ + # nodeDictToInternalSocket(node_tree, groupNode, input_node, + # otherDict, [], [], nextIndex, True) - #x = 0 - #y = 0 - #combiner1 = createNodeCombiner(group_tree, caseSocketDict1, 1) - #combiner1.location = [x, y] -# - #combiner2 = createNodeCombiner(group_tree, caseSocketDict2, 2) - #combiner2.location = [x, y-800] + # caseSocketDict1 = addSocketList(groupNode, input_node, caseTemplateDict, 1) + # caseSocketDict2 = addSocketList(groupNode, input_node, caseTemplateDict, 2) - addSocketList(groupNode, input_node, { - "Cycle 1 RGB" : "NodeSocketColor", - "Cycle 1 Alpha" : "NodeSocketFloat", - "Cycle 2 RGB" : "NodeSocketColor", - "Cycle 2 Alpha" : "NodeSocketFloat", - }) - - otherSocketDict = addSocketList(groupNode, input_node, otherTemplateDict) + # x = 0 + # y = 0 + # combiner1 = createNodeCombiner(group_tree, caseSocketDict1, 1) + # combiner1.location = [x, y] + # + # combiner2 = createNodeCombiner(group_tree, caseSocketDict2, 2) + # combiner2.location = [x, y-800] - x = 0 - y = 0 - mixCycleNodeRGB, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', 'Cycle Mix RGB', x, y) - mixCycleNodeAlpha, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', 'Cycle Mix Alpha', x, y) - - links.new(mixCycleNodeRGB.inputs[1], input_node.outputs[0]) - links.new(mixCycleNodeRGB.inputs[1], input_node.outputs[0]) - links.new(mixCycleNodeRGB.inputs[2], input_node.outputs[2]) - links.new(mixCycleNodeAlpha.inputs[1], input_node.outputs[1]) - links.new(mixCycleNodeAlpha.inputs[2], input_node.outputs[3]) - links.new(mixCycleNodeRGB.inputs[0], otherSocketDict['Cycle Type']) - links.new(mixCycleNodeAlpha.inputs[0], otherSocketDict['Cycle Type']) + addSocketList( + groupNode, + input_node, + { + "Cycle 1 RGB": "NodeSocketColor", + "Cycle 1 Alpha": "NodeSocketFloat", + "Cycle 2 RGB": "NodeSocketColor", + "Cycle 2 Alpha": "NodeSocketFloat", + }, + ) - x += 300 - y = 0 - - backFacing, x, y = \ - addNodeAt(group_tree, 'ShaderNodeNewGeometry', 'Is Backfacing', - x, y) - - x += 300 - y = 0 - multCullFront,x,y = \ - addNodeAt(group_tree, 'ShaderNodeMath','Multiply Cull Front', x, y) - multCullFront.operation = 'MULTIPLY' - multCullBack,x,y = \ - addNodeAt(group_tree, 'ShaderNodeMath','Multiply Cull Back', x, y) - multCullBack.operation = 'MULTIPLY' + otherSocketDict = addSocketList(groupNode, input_node, otherTemplateDict) - finalCullAlpha,x,y = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB','Cull Alpha', x, y) + x = 0 + y = 0 + mixCycleNodeRGB, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", "Cycle Mix RGB", x, y) + mixCycleNodeAlpha, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", "Cycle Mix Alpha", x, y) - links.new(multCullFront.inputs[0], otherSocketDict['Cull Front']) - links.new(multCullBack.inputs[0], otherSocketDict['Cull Back']) - links.new(multCullFront.inputs[1], mixCycleNodeAlpha.outputs[0]) - links.new(multCullBack.inputs[1], mixCycleNodeAlpha.outputs[0]) - links.new(finalCullAlpha.inputs[0], backFacing.outputs[6]) - links.new(finalCullAlpha.inputs[1], multCullFront.outputs[0]) - links.new(finalCullAlpha.inputs[2], multCullBack.outputs[0]) + links.new(mixCycleNodeRGB.inputs[1], input_node.outputs[0]) + links.new(mixCycleNodeRGB.inputs[1], input_node.outputs[0]) + links.new(mixCycleNodeRGB.inputs[2], input_node.outputs[2]) + links.new(mixCycleNodeAlpha.inputs[1], input_node.outputs[1]) + links.new(mixCycleNodeAlpha.inputs[2], input_node.outputs[3]) + links.new(mixCycleNodeRGB.inputs[0], otherSocketDict["Cycle Type"]) + links.new(mixCycleNodeAlpha.inputs[0], otherSocketDict["Cycle Type"]) - # Create mix shader to allow for alpha blending - # we cannot input alpha directly to material output, but we can mix between - # our final color and a completely transparent material based on alpha + x += 300 + y = 0 - x += 300 - y = 0 - output_node.location = [x,y] - mixShaderNode = group_tree.nodes.new('ShaderNodeMixShader') - mixShaderNode.location = [x, y - 300] - clearNode = group_tree.nodes.new('ShaderNodeEeveeSpecular') - clearNode.location = [x, y - 600] - clearNode.inputs[4].default_value = 1 # transparency - links.new(mixShaderNode.inputs[2], mixCycleNodeRGB.outputs[0]) - links.new(mixShaderNode.inputs[0], finalCullAlpha.outputs[0]) - links.new(mixShaderNode.inputs[1], clearNode.outputs[0]) + backFacing, x, y = addNodeAt(group_tree, "ShaderNodeNewGeometry", "Is Backfacing", x, y) - groupNode.outputs.new("NodeSocketShader", "Output") - output_node.inputs.new("NodeSocketShader", "Output") - links.new(output_node.inputs[0], mixShaderNode.outputs[0]) + x += 300 + y = 0 + multCullFront, x, y = addNodeAt(group_tree, "ShaderNodeMath", "Multiply Cull Front", x, y) + multCullFront.operation = "MULTIPLY" + multCullBack, x, y = addNodeAt(group_tree, "ShaderNodeMath", "Multiply Cull Back", x, y) + multCullBack.operation = "MULTIPLY" - return groupNode, location[0], location[1] + finalCullAlpha, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", "Cull Alpha", x, y) -def createNodeToGroupLink(node, outputIndex, groupNode, groupInputNode, - node_tree, nodeIndex, name, createSockets): - return createSocketToGroupLink(node.outputs[outputIndex], groupNode, - groupInputNode, node_tree, nodeIndex, name, createSockets) + links.new(multCullFront.inputs[0], otherSocketDict["Cull Front"]) + links.new(multCullBack.inputs[0], otherSocketDict["Cull Back"]) + links.new(multCullFront.inputs[1], mixCycleNodeAlpha.outputs[0]) + links.new(multCullBack.inputs[1], mixCycleNodeAlpha.outputs[0]) + links.new(finalCullAlpha.inputs[0], backFacing.outputs[6]) + links.new(finalCullAlpha.inputs[1], multCullFront.outputs[0]) + links.new(finalCullAlpha.inputs[2], multCullBack.outputs[0]) -def createSocketToGroupLink(socket, groupNode, groupInputNode, - node_tree, nodeIndex, name, createSockets): - if createSockets: - inputType = str(type(socket))[18:-2] # convert class to string - groupNode.inputs.new(inputType, name) - groupInputNode.outputs.new(inputType, name) - nodeExternal = groupNode.inputs[nodeIndex] - node_tree.links.new(nodeExternal, socket) + # Create mix shader to allow for alpha blending + # we cannot input alpha directly to material output, but we can mix between + # our final color and a completely transparent material based on alpha - if createSockets: - nodeInternal = groupInputNode.outputs[nodeIndex] - return nodeInternal - else: - return None + x += 300 + y = 0 + output_node.location = [x, y] + mixShaderNode = group_tree.nodes.new("ShaderNodeMixShader") + mixShaderNode.location = [x, y - 300] + clearNode = group_tree.nodes.new("ShaderNodeEeveeSpecular") + clearNode.location = [x, y - 600] + clearNode.inputs[4].default_value = 1 # transparency + links.new(mixShaderNode.inputs[2], mixCycleNodeRGB.outputs[0]) + links.new(mixShaderNode.inputs[0], finalCullAlpha.outputs[0]) + links.new(mixShaderNode.inputs[1], clearNode.outputs[0]) -def nodeDictToInternalSocket(node_tree, groupNode, groupInputNode, nodeDict, - texAlphaList, texAlphaWithBridgeList, startIndex, createSockets): - nodeIndex = startIndex - newDict = {} - for name, node in nodeDict.items(): - newDict[name] = createNodeToGroupLink(node, 0 if name != 'Noise' else 1, - groupNode, groupInputNode, node_tree, nodeIndex, name, createSockets) - nodeIndex += 1 - if name in texAlphaList: - newDict[name + " Alpha"] = createNodeToGroupLink(node, 1, groupNode, - groupInputNode, node_tree, nodeIndex, name + " Alpha", createSockets) - nodeIndex += 1 - elif name in texAlphaWithBridgeList: - alphaSplitNode = node.inputs[1].links[0].from_socket.node - bridgeNode = alphaSplitNode.outputs[1].links[0].to_socket.node - newDict[name + " Alpha"] = createNodeToGroupLink(bridgeNode, 0, - groupNode, groupInputNode, node_tree, nodeIndex, - name + " Alpha", createSockets) - nodeIndex += 1 + groupNode.outputs.new("NodeSocketShader", "Output") + output_node.inputs.new("NodeSocketShader", "Output") + links.new(output_node.inputs[0], mixShaderNode.outputs[0]) - return newDict, nodeIndex + return groupNode, location[0], location[1] + + +def createNodeToGroupLink(node, outputIndex, groupNode, groupInputNode, node_tree, nodeIndex, name, createSockets): + return createSocketToGroupLink( + node.outputs[outputIndex], groupNode, groupInputNode, node_tree, nodeIndex, name, createSockets + ) + + +def createSocketToGroupLink(socket, groupNode, groupInputNode, node_tree, nodeIndex, name, createSockets): + if createSockets: + inputType = str(type(socket))[18:-2] # convert class to string + groupNode.inputs.new(inputType, name) + groupInputNode.outputs.new(inputType, name) + nodeExternal = groupNode.inputs[nodeIndex] + node_tree.links.new(nodeExternal, socket) + + if createSockets: + nodeInternal = groupInputNode.outputs[nodeIndex] + return nodeInternal + else: + return None + + +def nodeDictToInternalSocket( + node_tree, groupNode, groupInputNode, nodeDict, texAlphaList, texAlphaWithBridgeList, startIndex, createSockets +): + nodeIndex = startIndex + newDict = {} + for name, node in nodeDict.items(): + newDict[name] = createNodeToGroupLink( + node, 0 if name != "Noise" else 1, groupNode, groupInputNode, node_tree, nodeIndex, name, createSockets + ) + nodeIndex += 1 + if name in texAlphaList: + newDict[name + " Alpha"] = createNodeToGroupLink( + node, 1, groupNode, groupInputNode, node_tree, nodeIndex, name + " Alpha", createSockets + ) + nodeIndex += 1 + elif name in texAlphaWithBridgeList: + alphaSplitNode = node.inputs[1].links[0].from_socket.node + bridgeNode = alphaSplitNode.outputs[1].links[0].to_socket.node + newDict[name + " Alpha"] = createNodeToGroupLink( + bridgeNode, 0, groupNode, groupInputNode, node_tree, nodeIndex, name + " Alpha", createSockets + ) + nodeIndex += 1 + + return newDict, nodeIndex + + +def socketDictToInternalSocket(node_tree, groupNode, groupInputNode, socketDict, startIndex, createSockets): + nodeIndex = startIndex + newDict = {} + for name, socket in socketDict.items(): + newDict[name] = createSocketToGroupLink( + socket, groupNode, groupInputNode, node_tree, nodeIndex, name, createSockets + ) + nodeIndex += 1 + return newDict, nodeIndex -def socketDictToInternalSocket(node_tree, groupNode, groupInputNode, socketDict, - startIndex, createSockets): - nodeIndex = startIndex - newDict = {} - for name, socket in socketDict.items(): - newDict[name] = createSocketToGroupLink(socket, groupNode, - groupInputNode, node_tree, nodeIndex, name, createSockets) - nodeIndex += 1 - return newDict, nodeIndex def createTexCoordNode(node_tree, location, uvSocket, socketDict, isV): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.name = 'Create Tex Coord' - groupNode.label = 'Create Tex Coord' - groupNode.location = location - location[1] = location[1] - (groupNode.height + 100) + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.name = "Create Tex Coord" + groupNode.label = "Create Tex Coord" + groupNode.location = location + location[1] = location[1] - (groupNode.height + 100) - verticalString = "U" if not isV else "V" - createGroup = 'Create Tex Coord ' + verticalString + ' F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['Create Tex Coord ' + verticalString + ' F3D v3'] - groupNode.node_tree = group_tree - socketDict, nextSocketIndex = socketDictToInternalSocket( - node_tree, groupNode, None, socketDict, 0, False) - return groupNode + verticalString = "U" if not isV else "V" + createGroup = "Create Tex Coord " + verticalString + " F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Create Tex Coord " + verticalString + " F3D v3"] + groupNode.node_tree = group_tree + socketDict, nextSocketIndex = socketDictToInternalSocket(node_tree, groupNode, None, socketDict, 0, False) + return groupNode - group_tree = bpy.data.node_groups.new( - type="ShaderNodeTree", name = 'Create Tex Coord ' + verticalString + ' F3D v3') - links = group_tree.links - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - output_node = group_tree.nodes.new("NodeGroupOutput") - input_node.location = (-800, 0) - output_node.location = (2800, 0) + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Create Tex Coord " + verticalString + " F3D v3") + links = group_tree.links + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + output_node = group_tree.nodes.new("NodeGroupOutput") + input_node.location = (-800, 0) + output_node.location = (2800, 0) - uvSocket = \ - createSocketToGroupLink(uvSocket, groupNode, - input_node, node_tree, 0, 'UV', True) - socketDict, nextSocketIndex = socketDictToInternalSocket( - node_tree, groupNode, input_node, socketDict, 1, True) + uvSocket = createSocketToGroupLink(uvSocket, groupNode, input_node, node_tree, 0, "UV", True) + socketDict, nextSocketIndex = socketDictToInternalSocket(node_tree, groupNode, input_node, socketDict, 1, True) - output_node_input_socket = output_node.inputs.new('NodeSocketVector', 'UV') + output_node_input_socket = output_node.inputs.new("NodeSocketVector", "UV") - x = 0 - y = 0 + x = 0 + y = 0 - # Change origin to top left corner - if isV: - toUpperOrigin, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, -400, 200) - toUpperOrigin.operation = "MULTIPLY_ADD" - toUpperOrigin.inputs[1].default_value = -1 - toUpperOrigin.inputs[2].default_value = 1 - links.new(toUpperOrigin.inputs[0], uvSocket) - prevSocket = toUpperOrigin.outputs[0] - else: - prevSocket = uvSocket + # Change origin to top left corner + if isV: + toUpperOrigin, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, -400, 200) + toUpperOrigin.operation = "MULTIPLY_ADD" + toUpperOrigin.inputs[1].default_value = -1 + toUpperOrigin.inputs[2].default_value = 1 + links.new(toUpperOrigin.inputs[0], uvSocket) + prevSocket = toUpperOrigin.outputs[0] + else: + prevSocket = uvSocket - # Apply shift - shiftPower, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, -400, 0) - shiftPower.operation = "POWER" - shiftPower.inputs[0].default_value = 0.5 - links.new(shiftPower.inputs[1], socketDict['Shift']) + # Apply shift + shiftPower, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, -400, 0) + shiftPower.operation = "POWER" + shiftPower.inputs[0].default_value = 0.5 + links.new(shiftPower.inputs[1], socketDict["Shift"]) - shiftMult, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, -400, -200) - shiftMult.operation = 'MULTIPLY' - links.new(shiftMult.inputs[0], prevSocket) - links.new(shiftMult.inputs[1], shiftPower.outputs[0]) + shiftMult, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, -400, -200) + shiftMult.operation = "MULTIPLY" + links.new(shiftMult.inputs[0], prevSocket) + links.new(shiftMult.inputs[1], shiftPower.outputs[0]) - # Apply scale - scaleMult, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, -200,-200) - scaleMult.operation = 'MULTIPLY' - links.new(scaleMult.inputs[0], shiftMult.outputs[0]) - links.new(scaleMult.inputs[1], socketDict['Scale']) + # Apply scale + scaleMult, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, -200, -200) + scaleMult.operation = "MULTIPLY" + links.new(scaleMult.inputs[0], shiftMult.outputs[0]) + links.new(scaleMult.inputs[1], socketDict["Scale"]) - # Revert origin to lower left corner - if isV: - toLowerOrigin, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, -200, -400) - toLowerOrigin.operation = "MULTIPLY_ADD" - toLowerOrigin.inputs[1].default_value = -1 - toLowerOrigin.inputs[2].default_value = 1 - links.new(toLowerOrigin.inputs[0], scaleMult.outputs[0]) - prevNode2 = toLowerOrigin - else: - prevNode2 = scaleMult - - # Add L - # offsetting by L means subtracting L from UV - addL, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 0, 0) - addL.operation = 'SUBTRACT' - links.new(addL.inputs[0], prevNode2.outputs[0]) - links.new(addL.inputs[1], socketDict["Normalized L"]) + # Revert origin to lower left corner + if isV: + toLowerOrigin, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, -200, -400) + toLowerOrigin.operation = "MULTIPLY_ADD" + toLowerOrigin.inputs[1].default_value = -1 + toLowerOrigin.inputs[2].default_value = 1 + links.new(toLowerOrigin.inputs[0], scaleMult.outputs[0]) + prevNode2 = toLowerOrigin + else: + prevNode2 = scaleMult - # Clamp using H - clampLow, x, y = addNodeAt(group_tree, 'ShaderNodeMath', - 'Max of NOT zero', 200, 0) - clampLow.operation = 'MAXIMUM' - clampLow.inputs[0].default_value = 0.0000001 # so negative clamping works - links.new(clampLow.inputs[0], socketDict["Normalized Half Pixel"]) - links.new(clampLow.inputs[1], addL.outputs[0]) + # Add L + # offsetting by L means subtracting L from UV + addL, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 0, 0) + addL.operation = "SUBTRACT" + links.new(addL.inputs[0], prevNode2.outputs[0]) + links.new(addL.inputs[1], socketDict["Normalized L"]) - clampHighHalfPixelOffset, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, 400, 200) - clampHighHalfPixelOffset.operation = 'SUBTRACT' - links.new(clampHighHalfPixelOffset.inputs[0], socketDict["Normalized H"]) - links.new(clampHighHalfPixelOffset.inputs[1], socketDict["Normalized Half Pixel"]) + # Clamp using H + clampLow, x, y = addNodeAt(group_tree, "ShaderNodeMath", "Max of NOT zero", 200, 0) + clampLow.operation = "MAXIMUM" + clampLow.inputs[0].default_value = 0.0000001 # so negative clamping works + links.new(clampLow.inputs[0], socketDict["Normalized Half Pixel"]) + links.new(clampLow.inputs[1], addL.outputs[0]) - clampHigh, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 400, 0) - clampHigh.operation = 'MINIMUM' - links.new(clampHigh.inputs[0], clampHighHalfPixelOffset.outputs[0]) - links.new(clampHigh.inputs[1], clampLow.outputs[0]) + clampHighHalfPixelOffset, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 400, 200) + clampHighHalfPixelOffset.operation = "SUBTRACT" + links.new(clampHighHalfPixelOffset.inputs[0], socketDict["Normalized H"]) + links.new(clampHighHalfPixelOffset.inputs[1], socketDict["Normalized Half Pixel"]) - clampMix, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 600, 0) - links.new(clampMix.inputs[0], socketDict["Clamp"]) - links.new(clampMix.inputs[1], addL.outputs[0]) - links.new(clampMix.inputs[2], clampHigh.outputs[0]) + clampHigh, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 400, 0) + clampHigh.operation = "MINIMUM" + links.new(clampHigh.inputs[0], clampHighHalfPixelOffset.outputs[0]) + links.new(clampHigh.inputs[1], clampLow.outputs[0]) - # Apply mask - maskPositive, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 800,-400) - maskPositive.operation = "MODULO" - links.new(maskPositive.inputs[0], clampMix.outputs[0]) - links.new(maskPositive.inputs[1], socketDict["Normalized Mask"]) + clampMix, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 600, 0) + links.new(clampMix.inputs[0], socketDict["Clamp"]) + links.new(clampMix.inputs[1], addL.outputs[0]) + links.new(clampMix.inputs[2], clampHigh.outputs[0]) - ifNegative, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 800, 0) - ifNegative.operation = 'LESS_THAN' - links.new(ifNegative.inputs[0], clampMix.outputs[0]) - ifNegative.inputs[1].default_value = 0 + # Apply mask + maskPositive, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 800, -400) + maskPositive.operation = "MODULO" + links.new(maskPositive.inputs[0], clampMix.outputs[0]) + links.new(maskPositive.inputs[1], socketDict["Normalized Mask"]) - maskNegative, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 800,-200) - links.new(maskNegative.inputs[0], socketDict["Normalized Mask"]) - links.new(maskNegative.inputs[1], maskPositive.outputs[0]) + ifNegative, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 800, 0) + ifNegative.operation = "LESS_THAN" + links.new(ifNegative.inputs[0], clampMix.outputs[0]) + ifNegative.inputs[1].default_value = 0 - maskSignMix, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB',None,1000,-200) - links.new(maskSignMix.inputs[0], ifNegative.outputs[0]) - links.new(maskSignMix.inputs[1], maskPositive.outputs[0]) - links.new(maskSignMix.inputs[2], maskNegative.outputs[0]) + maskNegative, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 800, -200) + links.new(maskNegative.inputs[0], socketDict["Normalized Mask"]) + links.new(maskNegative.inputs[1], maskPositive.outputs[0]) - # Apply mirror - mirrorAbs, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 1000,-600) - mirrorAbs.operation = "ABSOLUTE" - links.new(mirrorAbs.inputs[0], clampMix.outputs[0]) - mirrorAbs.inputs[1].default_value = 0 + maskSignMix, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 1000, -200) + links.new(maskSignMix.inputs[0], ifNegative.outputs[0]) + links.new(maskSignMix.inputs[1], maskPositive.outputs[0]) + links.new(maskSignMix.inputs[2], maskNegative.outputs[0]) - mirrorMaskDiv, x, y = addNodeAt(group_tree, 'ShaderNodeMath',None,1200,-600) - mirrorMaskDiv.operation = 'DIVIDE' - links.new(mirrorMaskDiv.inputs[0], mirrorAbs.outputs[0]) - links.new(mirrorMaskDiv.inputs[1], socketDict["Normalized Mask"]) + # Apply mirror + mirrorAbs, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 1000, -600) + mirrorAbs.operation = "ABSOLUTE" + links.new(mirrorAbs.inputs[0], clampMix.outputs[0]) + mirrorAbs.inputs[1].default_value = 0 - mirrorFloor, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 1400,-600) - mirrorFloor.operation = 'FLOOR' - links.new(mirrorFloor.inputs[0], mirrorMaskDiv.outputs[0]) - mirrorFloor.inputs[1].default_value = 0 + mirrorMaskDiv, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 1200, -600) + mirrorMaskDiv.operation = "DIVIDE" + links.new(mirrorMaskDiv.inputs[0], mirrorAbs.outputs[0]) + links.new(mirrorMaskDiv.inputs[1], socketDict["Normalized Mask"]) - mirrorMod, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 1600,-600) - mirrorMod.operation = 'MODULO' - links.new(mirrorMod.inputs[0], mirrorFloor.outputs[0]) - mirrorMod.inputs[1].default_value = 2 + mirrorFloor, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 1400, -600) + mirrorFloor.operation = "FLOOR" + links.new(mirrorFloor.inputs[0], mirrorMaskDiv.outputs[0]) + mirrorFloor.inputs[1].default_value = 0 - mirrorSub, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 1600,-800) - mirrorSub.operation = "SUBTRACT" - mirrorSub.inputs[0].default_value = 1 - links.new(mirrorSub.inputs[1], mirrorMod.outputs[0]) + mirrorMod, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 1600, -600) + mirrorMod.operation = "MODULO" + links.new(mirrorMod.inputs[0], mirrorFloor.outputs[0]) + mirrorMod.inputs[1].default_value = 2 - mirrorToggleMix, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', - None, 1800, -600) - links.new(mirrorToggleMix.inputs[0], ifNegative.outputs[0]) - links.new(mirrorToggleMix.inputs[1], mirrorMod.outputs[0]) - links.new(mirrorToggleMix.inputs[2], mirrorSub.outputs[0]) + mirrorSub, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 1600, -800) + mirrorSub.operation = "SUBTRACT" + mirrorSub.inputs[0].default_value = 1 + links.new(mirrorSub.inputs[1], mirrorMod.outputs[0]) - mirrorCheck, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 2000,-400) - mirrorCheck.operation = 'MULTIPLY' - links.new(mirrorCheck.inputs[0], mirrorToggleMix.outputs[0]) - links.new(mirrorCheck.inputs[1], socketDict["Mirror"]) + mirrorToggleMix, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 1800, -600) + links.new(mirrorToggleMix.inputs[0], ifNegative.outputs[0]) + links.new(mirrorToggleMix.inputs[1], mirrorMod.outputs[0]) + links.new(mirrorToggleMix.inputs[2], mirrorSub.outputs[0]) - mirrored, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 2000,-200) - mirrored.operation = 'SUBTRACT' - links.new(mirrored.inputs[0], socketDict["Normalized Mask"]) - links.new(mirrored.inputs[1], maskSignMix.outputs[0]) + mirrorCheck, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 2000, -400) + mirrorCheck.operation = "MULTIPLY" + links.new(mirrorCheck.inputs[0], mirrorToggleMix.outputs[0]) + links.new(mirrorCheck.inputs[1], socketDict["Mirror"]) - mirrorMix, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 2200,-200) - links.new(mirrorMix.inputs[0], mirrorCheck.outputs[0]) - links.new(mirrorMix.inputs[1], maskSignMix.outputs[0]) - links.new(mirrorMix.inputs[2], mirrored.outputs[0]) + mirrored, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 2000, -200) + mirrored.operation = "SUBTRACT" + links.new(mirrored.inputs[0], socketDict["Normalized Mask"]) + links.new(mirrored.inputs[1], maskSignMix.outputs[0]) - # Handle 0 Mask - check0Mask, x, y = addNodeAt(group_tree, 'ShaderNodeMath', None, 800,-1000) - check0Mask.operation = 'GREATER_THAN' - links.new(check0Mask.inputs[0], socketDict["Normalized Mask"]) - check0Mask.inputs[1].default_value = 0 + mirrorMix, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 2200, -200) + links.new(mirrorMix.inputs[0], mirrorCheck.outputs[0]) + links.new(mirrorMix.inputs[1], maskSignMix.outputs[0]) + links.new(mirrorMix.inputs[2], mirrored.outputs[0]) - mix0Mask, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 2400,-200) - links.new(mix0Mask.inputs[0], check0Mask.outputs[0]) - links.new(mix0Mask.inputs[1], clampHigh.outputs[0]) - links.new(mix0Mask.inputs[2], mirrorMix.outputs[0]) + # Handle 0 Mask + check0Mask, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 800, -1000) + check0Mask.operation = "GREATER_THAN" + links.new(check0Mask.inputs[0], socketDict["Normalized Mask"]) + check0Mask.inputs[1].default_value = 0 - # Output + mix0Mask, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 2400, -200) + links.new(mix0Mask.inputs[0], check0Mask.outputs[0]) + links.new(mix0Mask.inputs[1], clampHigh.outputs[0]) + links.new(mix0Mask.inputs[2], mirrorMix.outputs[0]) - # In Blender 3.1, for some reason output_node.inputs[0] is some junk socket, - # and the socket we want to use is actually output_node.inputs[1]. - # So just use the socket as returned on creation above, output_node_input_socket. - # - # But in earlier Blender versions, like Blender 2.93, output_node_input_socket as - # returned above is some junk socket that is not the actual input socket. (bug?) - # - # So we check the Blender version here, lack of a better option. - # - # Also note inputs[0] needs to be accessed here for some reason, it can't be accessed - # above right after new(), at least in Blender 2.93 it doesn't work. (bug?) - if bpy.app.version < (3, 1, 0): - links.new(mix0Mask.outputs[0], output_node.inputs[0]) - else: - links.new(mix0Mask.outputs[0], output_node_input_socket) + # Output + + # In Blender 3.1, for some reason output_node.inputs[0] is some junk socket, + # and the socket we want to use is actually output_node.inputs[1]. + # So just use the socket as returned on creation above, output_node_input_socket. + # + # But in earlier Blender versions, like Blender 2.93, output_node_input_socket as + # returned above is some junk socket that is not the actual input socket. (bug?) + # + # So we check the Blender version here, lack of a better option. + # + # Also note inputs[0] needs to be accessed here for some reason, it can't be accessed + # above right after new(), at least in Blender 2.93 it doesn't work. (bug?) + if bpy.app.version < (3, 1, 0): + links.new(mix0Mask.outputs[0], output_node.inputs[0]) + else: + links.new(mix0Mask.outputs[0], output_node_input_socket) + + return groupNode - return groupNode def splitTextureVectorInputs(node_tree, socketDict, x, y): - horizontalDict = {} - verticalDict = {} - for name, socket in socketDict.items(): - splitNode, x, y = addNodeAt(node_tree, "ShaderNodeSeparateXYZ", "Split Texture Vector", x, y) - node_tree.links.new(splitNode.inputs[0], socket) - horizontalDict[name] = splitNode.outputs[0] - verticalDict[name] = splitNode.outputs[1] + horizontalDict = {} + verticalDict = {} + for name, socket in socketDict.items(): + splitNode, x, y = addNodeAt(node_tree, "ShaderNodeSeparateXYZ", "Split Texture Vector", x, y) + node_tree.links.new(splitNode.inputs[0], socket) + horizontalDict[name] = splitNode.outputs[0] + verticalDict[name] = splitNode.outputs[1] + + return horizontalDict, verticalDict, x, y - return horizontalDict, verticalDict, x, y def createUVGroup(node_tree, location, textureIndex): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.name = 'Get UV' - groupNode.label = 'Get UV' - groupNode.location = location - groupNode.name = 'Get UV ' + str(textureIndex) + ' F3D v3' - location[1] = location[1] - (groupNode.height + 100) + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.name = "Get UV" + groupNode.label = "Get UV" + groupNode.location = location + groupNode.name = "Get UV " + str(textureIndex) + " F3D v3" + location[1] = location[1] - (groupNode.height + 100) - createGroup = 'Get UV F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['Get UV F3D v3'] - groupNode.node_tree = group_tree - #texGenSocketDict, nodeIndex = nodeDictToInternalSocket(node_tree, - # groupNode, None, texGenDict, [], [], 0, False) - #socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, - # groupNode, None, nodeDict, [], [], nodeIndex, False) - - return groupNode, location[0], location[1] + createGroup = "Get UV F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Get UV F3D v3"] + groupNode.node_tree = group_tree + # texGenSocketDict, nodeIndex = nodeDictToInternalSocket(node_tree, + # groupNode, None, texGenDict, [], [], 0, False) + # socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, + # groupNode, None, nodeDict, [], [], nodeIndex, False) - group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name = 'Get UV F3D v3') - links = group_tree.links - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - output_node = group_tree.nodes.new("NodeGroupOutput") - input_node.location = (-300, 0) - output_node.location = (2400, 0) + return groupNode, location[0], location[1] - output_node.inputs.new('NodeSocketVector', 'UV') + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Get UV F3D v3") + links = group_tree.links + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + output_node = group_tree.nodes.new("NodeGroupOutput") + input_node.location = (-300, 0) + output_node.location = (2400, 0) - #texGenSocketDict, nodeIndex = nodeDictToInternalSocket(node_tree, - # groupNode, input_node, texGenDict, [], [], 0, True) - #socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, - # groupNode, input_node, nodeDict, [], [], nodeIndex, True) + output_node.inputs.new("NodeSocketVector", "UV") - texGenSocketDict = addSocketList(groupNode, input_node, { - "Texture Gen" : "NodeSocketFloat", - "Texture Gen Linear" : "NodeSocketFloat", - }) + # texGenSocketDict, nodeIndex = nodeDictToInternalSocket(node_tree, + # groupNode, input_node, texGenDict, [], [], 0, True) + # socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, + # groupNode, input_node, nodeDict, [], [], nodeIndex, True) - socketDict = addSocketList(groupNode, input_node, { - "Image Factor" : "NodeSocketVector", - 'Normalized L' : "NodeSocketVector", - 'Normalized H' : "NodeSocketVector", - 'Clamp' : "NodeSocketVector", - 'Normalized Mask' : "NodeSocketVector", - 'Mirror' : "NodeSocketVector", - 'Shift' : "NodeSocketVector", - 'Scale' : "NodeSocketVector", - 'Normalized Half Pixel' : "NodeSocketVector", - }) - - x = 0 - y = 0 - horizontalDict, verticalDict, x, y = \ - splitTextureVectorInputs(group_tree, socketDict, x, y) + texGenSocketDict = addSocketList( + groupNode, + input_node, + { + "Texture Gen": "NodeSocketFloat", + "Texture Gen Linear": "NodeSocketFloat", + }, + ) - # Regular UVs - x += 300 - y = 0 - UVMapNode, x, y = addNodeAt(group_tree, 'ShaderNodeUVMap', None, x, y) - UVMapNode.uv_map = 'UVMap' - - # Get normal - geometryNode, x, y = \ - addNodeAt(group_tree, "ShaderNodeNewGeometry", None, x, y) + socketDict = addSocketList( + groupNode, + input_node, + { + "Image Factor": "NodeSocketVector", + "Normalized L": "NodeSocketVector", + "Normalized H": "NodeSocketVector", + "Clamp": "NodeSocketVector", + "Normalized Mask": "NodeSocketVector", + "Mirror": "NodeSocketVector", + "Shift": "NodeSocketVector", + "Scale": "NodeSocketVector", + "Normalized Half Pixel": "NodeSocketVector", + }, + ) - # Convert to screen space normal - transformNode, x, y = \ - addNodeAt(group_tree, "ShaderNodeVectorTransform", None, x, y) - transformNode.convert_from = 'WORLD' - transformNode.convert_to = 'CAMERA' - transformNode.vector_type = 'NORMAL' - links.new(transformNode.inputs[0], geometryNode.outputs[1]) + x = 0 + y = 0 + horizontalDict, verticalDict, x, y = splitTextureVectorInputs(group_tree, socketDict, x, y) - # Convert [-1,1] to [0,1] - x += 300 - y = 0 - addOneNode, x, y = \ - addNodeAt(group_tree, "ShaderNodeVectorMath", None, x, y) - addOneNode.inputs[1].default_value = (1,1,1) - links.new(addOneNode.inputs[0], transformNode.outputs[0]) + # Regular UVs + x += 300 + y = 0 + UVMapNode, x, y = addNodeAt(group_tree, "ShaderNodeUVMap", None, x, y) + UVMapNode.uv_map = "UVMap" - separateNode, x, y = \ - addNodeAt(group_tree, "ShaderNodeSeparateXYZ", None, x, y) - links.new(separateNode.inputs[0], addOneNode.outputs[0]) + # Get normal + geometryNode, x, y = addNodeAt(group_tree, "ShaderNodeNewGeometry", None, x, y) - divideTwoX, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, x, y) - divideTwoY, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, x, y) - divideTwoX.operation = 'DIVIDE' - divideTwoY.operation = 'DIVIDE' - divideTwoX.inputs[1].default_value = -2 # Must be negative (env, not sphere) - divideTwoY.inputs[1].default_value = -2 - links.new(divideTwoX.inputs[0], separateNode.outputs[0]) - links.new(divideTwoY.inputs[0], separateNode.outputs[1]) + # Convert to screen space normal + transformNode, x, y = addNodeAt(group_tree, "ShaderNodeVectorTransform", None, x, y) + transformNode.convert_from = "WORLD" + transformNode.convert_to = "CAMERA" + transformNode.vector_type = "NORMAL" + links.new(transformNode.inputs[0], geometryNode.outputs[1]) - # Normalize values based on tex size. - x += 300 - y = 0 - normalizeX, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, x, y) - normalizeY, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, x, y) - normalizeX.operation = 'MULTIPLY' - normalizeY.operation = 'MULTIPLY' - links.new(normalizeX.inputs[0], divideTwoX.outputs[0]) - links.new(normalizeY.inputs[0], divideTwoY.outputs[0]) - links.new(normalizeX.inputs[1], horizontalDict["Image Factor"]) - links.new(normalizeY.inputs[1], verticalDict["Image Factor"]) + # Convert [-1,1] to [0,1] + x += 300 + y = 0 + addOneNode, x, y = addNodeAt(group_tree, "ShaderNodeVectorMath", None, x, y) + addOneNode.inputs[1].default_value = (1, 1, 1) + links.new(addOneNode.inputs[0], transformNode.outputs[0]) - # Get UVs for tex gen, scaled by texture scale. + separateNode, x, y = addNodeAt(group_tree, "ShaderNodeSeparateXYZ", None, x, y) + links.new(separateNode.inputs[0], addOneNode.outputs[0]) - texGenCombine, x, y = \ - addNodeAt(group_tree, 'ShaderNodeCombineXYZ', None, 1200, -300) - links.new(texGenCombine.inputs[0], normalizeX.outputs[0]) - links.new(texGenCombine.inputs[1], normalizeY.outputs[0]) + divideTwoX, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, x, y) + divideTwoY, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, x, y) + divideTwoX.operation = "DIVIDE" + divideTwoY.operation = "DIVIDE" + divideTwoX.inputs[1].default_value = -2 # Must be negative (env, not sphere) + divideTwoY.inputs[1].default_value = -2 + links.new(divideTwoX.inputs[0], separateNode.outputs[0]) + links.new(divideTwoY.inputs[0], separateNode.outputs[1]) - # Get UVs for tex gen linear, scaled by texture scale. - texGenLinearAcosX, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, 600, -600) - texGenLinearAcosY, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, 600, y) - texGenLinearAcosX.operation = 'ARCCOSINE' - texGenLinearAcosY.operation = 'ARCCOSINE' - links.new(texGenLinearAcosX.inputs[0], divideTwoX.outputs[0]) - links.new(texGenLinearAcosY.inputs[0], divideTwoY.outputs[0]) - texGenLinearAcosX.inputs[1].default_value = 0 - texGenLinearAcosY.inputs[1].default_value = 0 + # Normalize values based on tex size. + x += 300 + y = 0 + normalizeX, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, x, y) + normalizeY, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, x, y) + normalizeX.operation = "MULTIPLY" + normalizeY.operation = "MULTIPLY" + links.new(normalizeX.inputs[0], divideTwoX.outputs[0]) + links.new(normalizeY.inputs[0], divideTwoY.outputs[0]) + links.new(normalizeX.inputs[1], horizontalDict["Image Factor"]) + links.new(normalizeY.inputs[1], verticalDict["Image Factor"]) - # Normalize values based on tex size. - normalizeLinearX, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, 600, y) - normalizeLinearY, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMath', None, 600, y) - normalizeLinearX.operation = 'MULTIPLY' - normalizeLinearY.operation = 'MULTIPLY' - links.new(normalizeLinearX.inputs[0], texGenLinearAcosX.outputs[0]) - links.new(normalizeLinearY.inputs[0], texGenLinearAcosY.outputs[0]) - links.new(normalizeLinearX.inputs[1], horizontalDict["Image Factor"]) - links.new(normalizeLinearY.inputs[1], verticalDict["Image Factor"]) + # Get UVs for tex gen, scaled by texture scale. - texGenLinearCombine, x, y = \ - addNodeAt(group_tree, 'ShaderNodeCombineXYZ', None, 1200, -600) - links.new(texGenLinearCombine.inputs[0], normalizeLinearX.outputs[0]) - links.new(texGenLinearCombine.inputs[1], normalizeLinearY.outputs[0]) + texGenCombine, x, y = addNodeAt(group_tree, "ShaderNodeCombineXYZ", None, 1200, -300) + links.new(texGenCombine.inputs[0], normalizeX.outputs[0]) + links.new(texGenCombine.inputs[1], normalizeY.outputs[0]) - # Mix UV based on flags - mixTexGen, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 1500, 0) - links.new(mixTexGen.inputs[0], texGenSocketDict["Texture Gen"]) - links.new(mixTexGen.inputs[1], UVMapNode.outputs[0]) - links.new(mixTexGen.inputs[2], texGenCombine.outputs[0]) - - mixTexGenLinear, x, y = \ - addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 1500, y) - links.new(mixTexGenLinear.inputs[0], texGenSocketDict["Texture Gen Linear"]) - links.new(mixTexGenLinear.inputs[1], mixTexGen.outputs[0]) - links.new(mixTexGenLinear.inputs[2], texGenLinearCombine.outputs[0]) + # Get UVs for tex gen linear, scaled by texture scale. + texGenLinearAcosX, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 600, -600) + texGenLinearAcosY, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 600, y) + texGenLinearAcosX.operation = "ARCCOSINE" + texGenLinearAcosY.operation = "ARCCOSINE" + links.new(texGenLinearAcosX.inputs[0], divideTwoX.outputs[0]) + links.new(texGenLinearAcosY.inputs[0], divideTwoY.outputs[0]) + texGenLinearAcosX.inputs[1].default_value = 0 + texGenLinearAcosY.inputs[1].default_value = 0 - # Apply tile attributes - uvSplit, x, y = \ - addNodeAt(group_tree, 'ShaderNodeSeparateXYZ', None, 1800, 500) - links.new(uvSplit.inputs[0], mixTexGenLinear.outputs[0]) - - uv_xNode = createTexCoordNode(group_tree, [2000, 500], uvSplit.outputs[0], horizontalDict, False) - uv_yNode = createTexCoordNode(group_tree, [2000, 300], uvSplit.outputs[1], verticalDict, True) + # Normalize values based on tex size. + normalizeLinearX, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 600, y) + normalizeLinearY, x, y = addNodeAt(group_tree, "ShaderNodeMath", None, 600, y) + normalizeLinearX.operation = "MULTIPLY" + normalizeLinearY.operation = "MULTIPLY" + links.new(normalizeLinearX.inputs[0], texGenLinearAcosX.outputs[0]) + links.new(normalizeLinearY.inputs[0], texGenLinearAcosY.outputs[0]) + links.new(normalizeLinearX.inputs[1], horizontalDict["Image Factor"]) + links.new(normalizeLinearY.inputs[1], verticalDict["Image Factor"]) - links.new(uv_xNode.inputs[0], uvSplit.outputs[0]) - links.new(uv_yNode.inputs[0], uvSplit.outputs[1]) + texGenLinearCombine, x, y = addNodeAt(group_tree, "ShaderNodeCombineXYZ", None, 1200, -600) + links.new(texGenLinearCombine.inputs[0], normalizeLinearX.outputs[0]) + links.new(texGenLinearCombine.inputs[1], normalizeLinearY.outputs[0]) - uvCombine, x, y = \ - addNodeAt(group_tree, 'ShaderNodeCombineXYZ', None, 2200, 500) + # Mix UV based on flags + mixTexGen, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 1500, 0) + links.new(mixTexGen.inputs[0], texGenSocketDict["Texture Gen"]) + links.new(mixTexGen.inputs[1], UVMapNode.outputs[0]) + links.new(mixTexGen.inputs[2], texGenCombine.outputs[0]) - links.new(uvCombine.inputs[0], uv_xNode.outputs[0]) - links.new(uvCombine.inputs[1], uv_yNode.outputs[0]) + mixTexGenLinear, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 1500, y) + links.new(mixTexGenLinear.inputs[0], texGenSocketDict["Texture Gen Linear"]) + links.new(mixTexGenLinear.inputs[1], mixTexGen.outputs[0]) + links.new(mixTexGenLinear.inputs[2], texGenLinearCombine.outputs[0]) + + # Apply tile attributes + uvSplit, x, y = addNodeAt(group_tree, "ShaderNodeSeparateXYZ", None, 1800, 500) + links.new(uvSplit.inputs[0], mixTexGenLinear.outputs[0]) + + uv_xNode = createTexCoordNode(group_tree, [2000, 500], uvSplit.outputs[0], horizontalDict, False) + uv_yNode = createTexCoordNode(group_tree, [2000, 300], uvSplit.outputs[1], verticalDict, True) + + links.new(uv_xNode.inputs[0], uvSplit.outputs[0]) + links.new(uv_yNode.inputs[0], uvSplit.outputs[1]) + + uvCombine, x, y = addNodeAt(group_tree, "ShaderNodeCombineXYZ", None, 2200, 500) + + links.new(uvCombine.inputs[0], uv_xNode.outputs[0]) + links.new(uvCombine.inputs[1], uv_yNode.outputs[0]) + + links.new(output_node.inputs[0], uvCombine.outputs[0]) + return groupNode, location[0], location[1] - links.new(output_node.inputs[0], uvCombine.outputs[0]) - return groupNode, location[0], location[1] def createShadeNode(node_tree, location): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.name = 'Shade Color' - groupNode.label = 'Shade Color' - groupNode.location = location - location[1] = location[1] - (groupNode.height + 100) + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.name = "Shade Color" + groupNode.label = "Shade Color" + groupNode.location = location + location[1] = location[1] - (groupNode.height + 100) - createGroup = 'Get Shade Color F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['Get Shade Color F3D v3'] - groupNode.node_tree = group_tree - #shadingNodeInternal = createSocketToGroupLink(shadingNode.outputs[0], - # groupNode, None, node_tree, 0, 'Shading', False) - #lightingNodeInternal = createSocketToGroupLink(lightingNode.outputs[0], - # groupNode, None, node_tree, 1, 'Lighting', False) - #ambientInternal = createSocketToGroupLink(ambientNode.outputs[0], - # groupNode, None, node_tree, 2, 'Ambient Color', False) + createGroup = "Get Shade Color F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Get Shade Color F3D v3"] + groupNode.node_tree = group_tree + # shadingNodeInternal = createSocketToGroupLink(shadingNode.outputs[0], + # groupNode, None, node_tree, 0, 'Shading', False) + # lightingNodeInternal = createSocketToGroupLink(lightingNode.outputs[0], + # groupNode, None, node_tree, 1, 'Lighting', False) + # ambientInternal = createSocketToGroupLink(ambientNode.outputs[0], + # groupNode, None, node_tree, 2, 'Ambient Color', False) - # Handle case so that shade alpha is visible even when using lighting. - nodes = group_tree.nodes - links = group_tree.links - if "Mix.002" in nodes: - outputNode = nodes["Group Output"] - alphaNode = nodes["Attribute.001"] - alphaMixNode = nodes["Mix.002"] - #if outputNode.inputs[1].links[0].from_node == alphaMixNode: - - # Link alpha node to alpha output. - links.new(alphaNode.outputs[2], outputNode.inputs[1]) - nodes.remove(alphaMixNode) - - return groupNode + # Handle case so that shade alpha is visible even when using lighting. + nodes = group_tree.nodes + links = group_tree.links + if "Mix.002" in nodes: + outputNode = nodes["Group Output"] + alphaNode = nodes["Attribute.001"] + alphaMixNode = nodes["Mix.002"] + # if outputNode.inputs[1].links[0].from_node == alphaMixNode: - group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", - name = 'Get Shade Color F3D v3') - links = group_tree.links - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - output_node = group_tree.nodes.new("NodeGroupOutput") - input_node.location = (-300, 0) - output_node.location = (600, 0) + # Link alpha node to alpha output. + links.new(alphaNode.outputs[2], outputNode.inputs[1]) + nodes.remove(alphaMixNode) - socketDict = addSocketList(groupNode, input_node, { - "Shading" : "NodeSocketFloat", - 'Lighting' : "NodeSocketFloat", - 'Ambient Color' : "NodeSocketColor" - }) + return groupNode - #shadingNodeInternal = createSocketToGroupLink(shadingNode.outputs[0], - # groupNode, input_node, node_tree, 0, 'Shading', createGroup) - #lightingNodeInternal = createSocketToGroupLink(lightingNode.outputs[0], - # groupNode, input_node, node_tree, 1, 'Lighting', createGroup) - #ambientInternal = createSocketToGroupLink(ambientNode.outputs[0], - # groupNode, input_node, node_tree, 2, 'Ambient Color', createGroup) - groupNode.outputs.new('NodeSocketColor', 'Color') - output_node.inputs.new('NodeSocketColor', 'Color') - groupNode.outputs.new('NodeSocketFloat', 'Alpha') - output_node.inputs.new('NodeSocketFloat', 'Alpha') + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Get Shade Color F3D v3") + links = group_tree.links + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + output_node = group_tree.nodes.new("NodeGroupOutput") + input_node.location = (-300, 0) + output_node.location = (600, 0) - diffuseNode, x, y = addNodeAt(group_tree, 'ShaderNodeBsdfDiffuse', None, 0, 0) - colorNode, x, y = addNodeAt(group_tree, 'ShaderNodeRGB', None, 0, y) - toRGBNode, x, y = addNodeAt(group_tree, 'ShaderNodeShaderToRGB', None, 200, 0) - vertColorNode, x, y = addNodeAt(group_tree,'ShaderNodeAttribute',None, 200, y) - vertAlphaNode, x, y = addNodeAt(group_tree,'ShaderNodeAttribute',None, 200, y) + socketDict = addSocketList( + groupNode, + input_node, + {"Shading": "NodeSocketFloat", "Lighting": "NodeSocketFloat", "Ambient Color": "NodeSocketColor"}, + ) - addAmbient, x, y = \ - addNodeAt(group_tree, 'ShaderNodeVectorMath', None, 400, 0) + # shadingNodeInternal = createSocketToGroupLink(shadingNode.outputs[0], + # groupNode, input_node, node_tree, 0, 'Shading', createGroup) + # lightingNodeInternal = createSocketToGroupLink(lightingNode.outputs[0], + # groupNode, input_node, node_tree, 1, 'Lighting', createGroup) + # ambientInternal = createSocketToGroupLink(ambientNode.outputs[0], + # groupNode, input_node, node_tree, 2, 'Ambient Color', createGroup) + groupNode.outputs.new("NodeSocketColor", "Color") + output_node.inputs.new("NodeSocketColor", "Color") + groupNode.outputs.new("NodeSocketFloat", "Alpha") + output_node.inputs.new("NodeSocketFloat", "Alpha") - mixRGB, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 600, 0) - mixRGBShadeless, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', None,600, y) - mixAlpha, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', None, 600, y) + diffuseNode, x, y = addNodeAt(group_tree, "ShaderNodeBsdfDiffuse", None, 0, 0) + colorNode, x, y = addNodeAt(group_tree, "ShaderNodeRGB", None, 0, y) + toRGBNode, x, y = addNodeAt(group_tree, "ShaderNodeShaderToRGB", None, 200, 0) + vertColorNode, x, y = addNodeAt(group_tree, "ShaderNodeAttribute", None, 200, y) + vertAlphaNode, x, y = addNodeAt(group_tree, "ShaderNodeAttribute", None, 200, y) - colorNode.outputs[0].default_value = (1,1,1,1) - vertColorNode.attribute_name = 'Col' - vertAlphaNode.attribute_name = 'Alpha' + addAmbient, x, y = addNodeAt(group_tree, "ShaderNodeVectorMath", None, 400, 0) - #links.new(diffuseNode.inputs[0], ambientInternal) - links.new(toRGBNode.inputs[0], diffuseNode.outputs[0]) - links.new(addAmbient.inputs[0], socketDict['Ambient Color']) - links.new(addAmbient.inputs[1], toRGBNode.outputs[0]) - links.new(mixRGB.inputs[0], socketDict['Lighting']) - links.new(mixRGB.inputs[1], vertColorNode.outputs[0]) - links.new(mixRGB.inputs[2], addAmbient.outputs[0]) + mixRGB, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 600, 0) + mixRGBShadeless, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 600, y) + mixAlpha, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, 600, y) - links.new(mixRGBShadeless.inputs[0], socketDict['Shading']) - links.new(mixRGBShadeless.inputs[1], colorNode.outputs[0]) - links.new(mixRGBShadeless.inputs[2], mixRGB.outputs[0]) + colorNode.outputs[0].default_value = (1, 1, 1, 1) + vertColorNode.attribute_name = "Col" + vertAlphaNode.attribute_name = "Alpha" - links.new(mixAlpha.inputs[0], socketDict['Lighting']) - links.new(mixAlpha.inputs[1], vertAlphaNode.outputs[2]) - mixAlpha.inputs[2].default_value = (1,1,1,1) + # links.new(diffuseNode.inputs[0], ambientInternal) + links.new(toRGBNode.inputs[0], diffuseNode.outputs[0]) + links.new(addAmbient.inputs[0], socketDict["Ambient Color"]) + links.new(addAmbient.inputs[1], toRGBNode.outputs[0]) + links.new(mixRGB.inputs[0], socketDict["Lighting"]) + links.new(mixRGB.inputs[1], vertColorNode.outputs[0]) + links.new(mixRGB.inputs[2], addAmbient.outputs[0]) - links.new(output_node.inputs[0], mixRGBShadeless.outputs[0]) - links.new(output_node.inputs[1], mixAlpha.outputs[0]) + links.new(mixRGBShadeless.inputs[0], socketDict["Shading"]) + links.new(mixRGBShadeless.inputs[1], colorNode.outputs[0]) + links.new(mixRGBShadeless.inputs[2], mixRGB.outputs[0]) + + links.new(mixAlpha.inputs[0], socketDict["Lighting"]) + links.new(mixAlpha.inputs[1], vertAlphaNode.outputs[2]) + mixAlpha.inputs[2].default_value = (1, 1, 1, 1) + + links.new(output_node.inputs[0], mixRGBShadeless.outputs[0]) + links.new(output_node.inputs[1], mixAlpha.outputs[0]) + + return groupNode - return groupNode def createTexFormatNodes(node_tree, location, externalColorSocket, externalAlphaSocket): - groupNode = node_tree.nodes.new("ShaderNodeGroup") - groupNode.location = location - groupNode.name = 'Get Texture Color' - location[1] = location[1] - (groupNode.height + 100) + groupNode = node_tree.nodes.new("ShaderNodeGroup") + groupNode.location = location + groupNode.name = "Get Texture Color" + location[1] = location[1] - (groupNode.height + 100) - createGroup = 'Get Texture Color F3D v3' not in bpy.data.node_groups - if not createGroup: - group_tree = bpy.data.node_groups['Get Texture Color F3D v3'] - groupNode.node_tree = group_tree + createGroup = "Get Texture Color F3D v3" not in bpy.data.node_groups + if not createGroup: + group_tree = bpy.data.node_groups["Get Texture Color F3D v3"] + groupNode.node_tree = group_tree - nodeIndex = 0 - colorSocket = createSocketToGroupLink(externalColorSocket, groupNode, None, - node_tree, nodeIndex, "Color", createGroup) - nodeIndex += 1 - alphaSocket = createSocketToGroupLink(externalAlphaSocket, groupNode, None, - node_tree, nodeIndex, "Alpha", createGroup) - nodeIndex += 1 + nodeIndex = 0 + colorSocket = createSocketToGroupLink( + externalColorSocket, groupNode, None, node_tree, nodeIndex, "Color", createGroup + ) + nodeIndex += 1 + alphaSocket = createSocketToGroupLink( + externalAlphaSocket, groupNode, None, node_tree, nodeIndex, "Alpha", createGroup + ) + nodeIndex += 1 - #socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, - # groupNode, None, nodeDict, [], [], nodeIndex, createGroup) - - return groupNode, location[0], location[1] - - group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name = 'Get Texture Color F3D v3') - links = group_tree.links - groupNode.node_tree = group_tree - input_node = group_tree.nodes.new("NodeGroupInput") - output_node = group_tree.nodes.new("NodeGroupOutput") + # socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, + # groupNode, None, nodeDict, [], [], nodeIndex, createGroup) - x = 0 - y = 0 - input_node.location = (x,y) + return groupNode, location[0], location[1] - output_node.inputs.new('NodeSocketColor', 'Color') - groupNode.outputs.new("NodeSocketColor", "Color") - output_node.inputs.new('NodeSocketFloat', 'Alpha') - groupNode.outputs.new("NodeSocketFloat", "Alpha") + group_tree = bpy.data.node_groups.new(type="ShaderNodeTree", name="Get Texture Color F3D v3") + links = group_tree.links + groupNode.node_tree = group_tree + input_node = group_tree.nodes.new("NodeGroupInput") + output_node = group_tree.nodes.new("NodeGroupOutput") - nodeIndex = 0 - colorSocket = createSocketToGroupLink(externalColorSocket, groupNode, input_node, - node_tree, nodeIndex, "Color", createGroup) - nodeIndex += 1 - alphaSocket = createSocketToGroupLink(externalAlphaSocket, groupNode, input_node, - node_tree, nodeIndex, "Alpha", createGroup) - nodeIndex += 1 + x = 0 + y = 0 + input_node.location = (x, y) - socketDict = addSocketList(groupNode, input_node, { - "Is Greyscale" : "NodeSocketFloat", - "Has Alpha" : "NodeSocketFloat", - 'Is Intensity' : "NodeSocketFloat" - }) + output_node.inputs.new("NodeSocketColor", "Color") + groupNode.outputs.new("NodeSocketColor", "Color") + output_node.inputs.new("NodeSocketFloat", "Alpha") + groupNode.outputs.new("NodeSocketFloat", "Alpha") - #socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, - # groupNode, input_node, nodeDict, [], [], nodeIndex, createGroup) + nodeIndex = 0 + colorSocket = createSocketToGroupLink( + externalColorSocket, groupNode, input_node, node_tree, nodeIndex, "Color", createGroup + ) + nodeIndex += 1 + alphaSocket = createSocketToGroupLink( + externalAlphaSocket, groupNode, input_node, node_tree, nodeIndex, "Alpha", createGroup + ) + nodeIndex += 1 - # Add texture format mixes - x += 300 - greyNode, x, y = addNodeAt(group_tree, 'ShaderNodeSeparateHSV', - None, x, y) - links.new(greyNode.inputs[0], colorSocket) + socketDict = addSocketList( + groupNode, + input_node, + {"Is Greyscale": "NodeSocketFloat", "Has Alpha": "NodeSocketFloat", "Is Intensity": "NodeSocketFloat"}, + ) - greyMix, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', - None, x, y) - links.new(greyMix.inputs[0], socketDict["Is Greyscale"]) - links.new(greyMix.inputs[1], colorSocket) - links.new(greyMix.inputs[2], greyNode.outputs[2]) - links.new(output_node.inputs[0], greyMix.outputs[0]) + # socketDict, nodeIndex = nodeDictToInternalSocket(node_tree, + # groupNode, input_node, nodeDict, [], [], nodeIndex, createGroup) - alphaMix, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', - None, x, y) - links.new(alphaMix.inputs[0], socketDict["Has Alpha"]) - links.new(alphaMix.inputs[2], alphaSocket) - alphaMix.inputs[1].default_value = (1,1,1,1) + # Add texture format mixes + x += 300 + greyNode, x, y = addNodeAt(group_tree, "ShaderNodeSeparateHSV", None, x, y) + links.new(greyNode.inputs[0], colorSocket) - alphaMixIntensity, x, y = addNodeAt(group_tree, 'ShaderNodeMixRGB', - None, x, y) - links.new(alphaMixIntensity.inputs[0], socketDict["Is Intensity"]) - links.new(alphaMixIntensity.inputs[1], alphaMix.outputs[0]) - links.new(alphaMixIntensity.inputs[2], greyNode.outputs[2]) - links.new(output_node.inputs[1], alphaMixIntensity.outputs[0]) - - x += 300 - output_node.location = (x, 0) + greyMix, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, x, y) + links.new(greyMix.inputs[0], socketDict["Is Greyscale"]) + links.new(greyMix.inputs[1], colorSocket) + links.new(greyMix.inputs[2], greyNode.outputs[2]) + links.new(output_node.inputs[0], greyMix.outputs[0]) + + alphaMix, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, x, y) + links.new(alphaMix.inputs[0], socketDict["Has Alpha"]) + links.new(alphaMix.inputs[2], alphaSocket) + alphaMix.inputs[1].default_value = (1, 1, 1, 1) + + alphaMixIntensity, x, y = addNodeAt(group_tree, "ShaderNodeMixRGB", None, x, y) + links.new(alphaMixIntensity.inputs[0], socketDict["Is Intensity"]) + links.new(alphaMixIntensity.inputs[1], alphaMix.outputs[0]) + links.new(alphaMixIntensity.inputs[2], greyNode.outputs[2]) + links.new(output_node.inputs[1], alphaMixIntensity.outputs[0]) + + x += 300 + output_node.location = (x, 0) + + return groupNode, location[0], location[1] - return groupNode, location[0], location[1] def createUVInputsAndGroup(node_tree, texIndex, x, y): - uvNode, x, y = createUVGroup(node_tree, [x,y], texIndex) + uvNode, x, y = createUVGroup(node_tree, [x, y], texIndex) + + return uvNode, x + 300, 0 - return uvNode, x + 300, 0 def createTextureInputsAndGroup(node_tree, texIndex, x, y): - colorSocket = node_tree.nodes["Texture " + str(texIndex)].outputs[0] - alphaSocket = node_tree.nodes["Texture " + str(texIndex)].outputs[1] + colorSocket = node_tree.nodes["Texture " + str(texIndex)].outputs[0] + alphaSocket = node_tree.nodes["Texture " + str(texIndex)].outputs[1] - colorNode, x, y = createTexFormatNodes(node_tree, [x,y], colorSocket, alphaSocket) - return colorNode, x, y + colorNode, x, y = createTexFormatNodes(node_tree, [x, y], colorSocket, alphaSocket) + return colorNode, x, y -''' +""" class F3DLightCollectionProperty(bpy.types.PropertyGroup): light1 : bpy.props.PointerProperty(type = bpy.types.Light) light2 : bpy.props.PointerProperty(type = bpy.types.Light) @@ -1130,107 +1129,106 @@ class F3DLightCollectionProperty(bpy.types.PropertyGroup): light5 : bpy.props.PointerProperty(type = bpy.types.Light) light6 : bpy.props.PointerProperty(type = bpy.types.Light) light7 : bpy.props.PointerProperty(type = bpy.types.Light) -''' - +""" + + class GetAlphaFromColor(ShaderNode): - bl_idname = 'GetAlphaFromColor' - # Label for nice name display - bl_label = "Get Alpha From Color" - # Icon identifier - bl_icon = 'NODE' + bl_idname = "GetAlphaFromColor" + # Label for nice name display + bl_label = "Get Alpha From Color" + # Icon identifier + bl_icon = "NODE" - def update_GetAlphaFromColor(self, context): - inputSocket = self.inputs[0] - if inputSocket.is_linked: - for link in inputSocket.links: - if link.is_valid: - self.inputs[0].default_value = \ - link.from_socket.default_value - - if len(self.outputs) >= 2: - out = self.outputs[0] - if out.is_linked: - for link in out.links: - if link.is_valid: - link.to_socket.default_value = self.inputs[0].default_value + def update_GetAlphaFromColor(self, context): + inputSocket = self.inputs[0] + if inputSocket.is_linked: + for link in inputSocket.links: + if link.is_valid: + self.inputs[0].default_value = link.from_socket.default_value - outAlpha = self.outputs[1] - if outAlpha.is_linked: - for link in outAlpha.links: - if link.is_valid: - link.to_socket.default_value = self.inputs[0].default_value[3] + if len(self.outputs) >= 2: + out = self.outputs[0] + if out.is_linked: + for link in out.links: + if link.is_valid: + link.to_socket.default_value = self.inputs[0].default_value - inColor : bpy.props.FloatVectorProperty( - name = 'Input Color', subtype='COLOR', size = 4, - update = update_GetAlphaFromColor) + outAlpha = self.outputs[1] + if outAlpha.is_linked: + for link in outAlpha.links: + if link.is_valid: + link.to_socket.default_value = self.inputs[0].default_value[3] - def init(self, context): - self.inputs.new("NodeSocketColor", "Input Color") - self.outputs.new("NodeSocketColor", "Output Color") - self.outputs.new("NodeSocketFloat", "Output Alpha") + inColor: bpy.props.FloatVectorProperty(name="Input Color", subtype="COLOR", size=4, update=update_GetAlphaFromColor) - # Copy function to initialize a copied node from an existing one. - def copy(self, node): - pass #print("Copying from node ", node) + def init(self, context): + self.inputs.new("NodeSocketColor", "Input Color") + self.outputs.new("NodeSocketColor", "Output Color") + self.outputs.new("NodeSocketFloat", "Output Alpha") - # Free function to clean up on removal. - def free(self): - print("Removing node ", self, ", Goodbye!") + # Copy function to initialize a copied node from an existing one. + def copy(self, node): + pass # print("Copying from node ", node) - # Additional buttons displayed on the node. - def draw_buttons(self, context, layout): - pass - #layout.prop(self, 'inA') + # Free function to clean up on removal. + def free(self): + print("Removing node ", self, ", Goodbye!") - def draw_label(self): - return "Get Alpha From Color" - - def update(self): - inputSocket = self.inputs[0] - if inputSocket.is_linked: - for link in inputSocket.links: - if link.is_valid: - self.inputs[0].default_value = \ - link.from_socket.default_value + # Additional buttons displayed on the node. + def draw_buttons(self, context, layout): + pass + # layout.prop(self, 'inA') - if len(self.outputs) >= 2: - out = self.outputs[0] - if out.is_linked: - for link in out.links: - if link.is_valid: - link.to_socket.default_value = self.inputs[0].default_value + def draw_label(self): + return "Get Alpha From Color" + + def update(self): + inputSocket = self.inputs[0] + if inputSocket.is_linked: + for link in inputSocket.links: + if link.is_valid: + self.inputs[0].default_value = link.from_socket.default_value + + if len(self.outputs) >= 2: + out = self.outputs[0] + if out.is_linked: + for link in out.links: + if link.is_valid: + link.to_socket.default_value = self.inputs[0].default_value + + outAlpha = self.outputs[1] + if outAlpha.is_linked: + for link in outAlpha.links: + if link.is_valid: + link.to_socket.default_value = self.inputs[0].default_value[3] - outAlpha = self.outputs[1] - if outAlpha.is_linked: - for link in outAlpha.links: - if link.is_valid: - link.to_socket.default_value = self.inputs[0].default_value[3] class F3DNodeA(ShaderNode): - bl_idname = 'Fast3D_A' + bl_idname = "Fast3D_A" # Label for nice name display bl_label = "Case A" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeA(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inA] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inA] - inA : bpy.props.EnumProperty(name = "A", description = "A", - items = combiner_enums['Case A'], default = 'TEXEL0', update = update_F3DNodeA) + inA: bpy.props.EnumProperty( + name="A", description="A", items=combiner_enums["Case A"], default="TEXEL0", update=update_F3DNodeA + ) def init(self, context): self.outputs.new("NodeSocketInt", "A") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1238,42 +1236,44 @@ class F3DNodeA(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inA') + layout.prop(self, "inA") def draw_label(self): return "Fast3D Node A" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inA] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inA] + class F3DNodeB(ShaderNode): - bl_idname = 'Fast3D_B' + bl_idname = "Fast3D_B" # Label for nice name display bl_label = "Case B" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeB(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inB] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inB] - inB : bpy.props.EnumProperty(name = "B", description = "B", - items = combiner_enums['Case B'], default = '0', update = update_F3DNodeB) + inB: bpy.props.EnumProperty( + name="B", description="B", items=combiner_enums["Case B"], default="0", update=update_F3DNodeB + ) def init(self, context): self.outputs.new("NodeSocketInt", "B") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1281,42 +1281,44 @@ class F3DNodeB(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inB') + layout.prop(self, "inB") def draw_label(self): return "Fast3D Node B" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inB] - + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inB] + + class F3DNodeC(ShaderNode): - bl_idname = 'Fast3D_C' + bl_idname = "Fast3D_C" # Label for nice name display bl_label = "Case C" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeC(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inC] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inC] - inC : bpy.props.EnumProperty(name = "C", description = "C", - items = combiner_enums['Case C'], default = 'SHADE', update = update_F3DNodeC) + inC: bpy.props.EnumProperty( + name="C", description="C", items=combiner_enums["Case C"], default="SHADE", update=update_F3DNodeC + ) def init(self, context): self.outputs.new("NodeSocketInt", "C") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1324,42 +1326,44 @@ class F3DNodeC(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inC') + layout.prop(self, "inC") def draw_label(self): return "Fast3D Node C" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inC] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inC] + class F3DNodeD(ShaderNode): - bl_idname = 'Fast3D_D' + bl_idname = "Fast3D_D" # Label for nice name display bl_label = "Case D" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeD(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inD] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inD] - inD : bpy.props.EnumProperty(name = "D", description = "D", - items = combiner_enums['Case D'], default = '0', update = update_F3DNodeD) + inD: bpy.props.EnumProperty( + name="D", description="D", items=combiner_enums["Case D"], default="0", update=update_F3DNodeD + ) def init(self, context): self.outputs.new("NodeSocketInt", "D") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1367,43 +1371,48 @@ class F3DNodeD(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inD') + layout.prop(self, "inD") def draw_label(self): return "Fast3D Node D" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).CCMUXDict[self.inD] + link.to_socket.default_value = F3D("F3D", False).CCMUXDict[self.inD] + class F3DNodeA_alpha(ShaderNode): - bl_idname = 'Fast3D_A_alpha' + bl_idname = "Fast3D_A_alpha" # Label for nice name display bl_label = "Case A Alpha" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeA_alpha(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inA_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inA_alpha] - inA_alpha : bpy.props.EnumProperty(name = "A Alpha", - description = "A Alpha", items = combiner_enums['Case A Alpha'], - default = '0', update = update_F3DNodeA_alpha) + inA_alpha: bpy.props.EnumProperty( + name="A Alpha", + description="A Alpha", + items=combiner_enums["Case A Alpha"], + default="0", + update=update_F3DNodeA_alpha, + ) def init(self, context): self.outputs.new("NodeSocketInt", "A Alpha") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1411,42 +1420,48 @@ class F3DNodeA_alpha(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inA_alpha') + layout.prop(self, "inA_alpha") def draw_label(self): return "Fast3D Node A Alpha" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inA_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inA_alpha] + class F3DNodeB_alpha(ShaderNode): - bl_idname = 'Fast3D_B_alpha' + bl_idname = "Fast3D_B_alpha" # Label for nice name display bl_label = "Case B Alpha" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeB_alpha(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inB_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inB_alpha] - inB_alpha : bpy.props.EnumProperty(name = "B Alpha", description = "B Alpha", - items = combiner_enums['Case B Alpha'], default = '0', update = update_F3DNodeB_alpha) + inB_alpha: bpy.props.EnumProperty( + name="B Alpha", + description="B Alpha", + items=combiner_enums["Case B Alpha"], + default="0", + update=update_F3DNodeB_alpha, + ) def init(self, context): self.outputs.new("NodeSocketInt", "B Alpha") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1454,42 +1469,48 @@ class F3DNodeB_alpha(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inB_alpha') + layout.prop(self, "inB_alpha") def draw_label(self): return "Fast3D Node B Alpha" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inB_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inB_alpha] + class F3DNodeC_alpha(ShaderNode): - bl_idname = 'Fast3D_C_alpha' + bl_idname = "Fast3D_C_alpha" # Label for nice name display bl_label = "Case C Alpha" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeC_alpha(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inC_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inC_alpha] - inC_alpha : bpy.props.EnumProperty(name = "C Alpha", description = "C Alpha", - items = combiner_enums['Case C Alpha'], default = '0', update = update_F3DNodeC_alpha) + inC_alpha: bpy.props.EnumProperty( + name="C Alpha", + description="C Alpha", + items=combiner_enums["Case C Alpha"], + default="0", + update=update_F3DNodeC_alpha, + ) def init(self, context): self.outputs.new("NodeSocketInt", "C Alpha") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1497,42 +1518,48 @@ class F3DNodeC_alpha(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inC_alpha') + layout.prop(self, "inC_alpha") def draw_label(self): return "Fast3D Node C Alpha" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inC_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inC_alpha] + class F3DNodeD_alpha(ShaderNode): - bl_idname = 'Fast3D_D_alpha' + bl_idname = "Fast3D_D_alpha" # Label for nice name display bl_label = "Case D Alpha" # Icon identifier - bl_icon = 'NODE' + bl_icon = "NODE" def update_F3DNodeD_alpha(self, context): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = F3D('F3D', False).ACMUXDict[self.inD_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inD_alpha] - inD_alpha : bpy.props.EnumProperty(name = "D Alpha", description = "D Alpha", - items = combiner_enums['Case D Alpha'], default = 'ENVIRONMENT', update = update_F3DNodeD_alpha) + inD_alpha: bpy.props.EnumProperty( + name="D Alpha", + description="D Alpha", + items=combiner_enums["Case D Alpha"], + default="ENVIRONMENT", + update=update_F3DNodeD_alpha, + ) def init(self, context): self.outputs.new("NodeSocketInt", "D Alpha") # Copy function to initialize a copied node from an existing one. def copy(self, node): - pass #print("Copying from node ", node) + pass # print("Copying from node ", node) # Free function to clean up on removal. def free(self): @@ -1540,21 +1567,20 @@ class F3DNodeD_alpha(ShaderNode): # Additional buttons displayed on the node. def draw_buttons(self, context, layout): - layout.prop(self, 'inD_alpha') + layout.prop(self, "inD_alpha") def draw_label(self): return "Fast3D Node D Alpha" - + def update(self): out = self.outputs[0] if out.is_linked: for link in out.links: if link.is_valid: - link.to_socket.default_value = \ - F3D('F3D', False).ACMUXDict[self.inD_alpha] + link.to_socket.default_value = F3D("F3D", False).ACMUXDict[self.inD_alpha] class F3DNodeCategory(NodeCategory): @classmethod def poll(cls, context): - return context.space_data.tree_type == 'CustomTreeType' + return context.space_data.tree_type == "CustomTreeType" diff --git a/fast64_internal/f3d/f3d_parser.py b/fast64_internal/f3d/f3d_parser.py index 9ef813a..9a97584 100644 --- a/fast64_internal/f3d/f3d_parser.py +++ b/fast64_internal/f3d/f3d_parser.py @@ -1,1570 +1,1694 @@ import bmesh, bpy, mathutils, pprint, re, math, traceback from bpy.utils import register_class, unregister_class from .f3d_gbi import * -from .f3d_material import createF3DMat, update_preset_manual, update_node_values_directly, all_combiner_uses, ootEnumDrawLayers +from .f3d_material import ( + createF3DMat, + update_preset_manual, + update_node_values_directly, + all_combiner_uses, + ootEnumDrawLayers, +) from .f3d_writer import BufferVertex from ..utility import * import ast, operator colorCombinationCommands = [ - 0x03, #load lighting data - 0xB6, #clear geometry params - 0xB7, #set geometry params - 0xBB, #set texture scaling factor - 0xF3, #set texture size - 0xF5, #set texture properties - 0xF7, #set fill color - 0xF8, #set fog color - 0xFB, #set env color - 0xFC, #set color combination - 0xFD #load texture + 0x03, # load lighting data + 0xB6, # clear geometry params + 0xB7, # set geometry params + 0xBB, # set texture scaling factor + 0xF3, # set texture size + 0xF5, # set texture properties + 0xF7, # set fill color + 0xF8, # set fog color + 0xFB, # set env color + 0xFC, # set color combination + 0xFD, # load texture ] -drawCommands = [ - 0x04, #load vertex data - 0xBF #draw triangle -] +drawCommands = [0x04, 0xBF] # load vertex data # draw triangle + def getAxisVector(enumValue): - sign = -1 if enumValue[0] == '-' else 1 - axis = enumValue[0] if sign == 1 else enumValue[1] - return ( - sign if axis == 'X' else 0, - sign if axis == 'Y' else 0, - sign if axis == 'Z' else 0 - ) + sign = -1 if enumValue[0] == "-" else 1 + axis = enumValue[0] if sign == 1 else enumValue[1] + return (sign if axis == "X" else 0, sign if axis == "Y" else 0, sign if axis == "Z" else 0) + def getExportRotation(forwardAxisEnum, convertTransformMatrix): - if 'Z' in forwardAxisEnum: - print("Z axis reserved for verticals.") - return None - elif forwardAxisEnum == 'X': - rightAxisEnum = '-Y' - elif forwardAxisEnum == '-Y': - rightAxisEnum = '-X' - elif forwardAxisEnum == '-X': - rightAxisEnum = 'Y' - else: - rightAxisEnum = 'X' + if "Z" in forwardAxisEnum: + print("Z axis reserved for verticals.") + return None + elif forwardAxisEnum == "X": + rightAxisEnum = "-Y" + elif forwardAxisEnum == "-Y": + rightAxisEnum = "-X" + elif forwardAxisEnum == "-X": + rightAxisEnum = "Y" + else: + rightAxisEnum = "X" - forwardAxis = getAxisVector(forwardAxisEnum) - rightAxis = getAxisVector(rightAxisEnum) + forwardAxis = getAxisVector(forwardAxisEnum) + rightAxis = getAxisVector(rightAxisEnum) - upAxis = (0, 0, 1) + upAxis = (0, 0, 1) - # Z assumed to be up - columns = [rightAxis, forwardAxis, upAxis] - localToBlenderRotation = mathutils.Matrix([ - [col[0] for col in columns], - [col[1] for col in columns], - [col[2] for col in columns] - ]).to_quaternion() + # Z assumed to be up + columns = [rightAxis, forwardAxis, upAxis] + localToBlenderRotation = mathutils.Matrix( + [[col[0] for col in columns], [col[1] for col in columns], [col[2] for col in columns]] + ).to_quaternion() - return convertTransformMatrix.to_quaternion() @ localToBlenderRotation + return convertTransformMatrix.to_quaternion() @ localToBlenderRotation -def F3DtoBlenderObject(romfile, startAddress, scene, - newname, transformMatrix, - segmentData, shadeSmooth): - - mesh = bpy.data.meshes.new(newname + '-mesh') - obj = bpy.data.objects.new(newname, mesh) - scene.collection.objects.link(obj) - createBlankMaterial(obj) - bMesh = bmesh.new() - bMesh.from_mesh(mesh) - - parseF3DBinary(romfile, startAddress, scene, bMesh, obj, \ - transformMatrix, newname, segmentData, \ - [None] * 16 * 16) +def F3DtoBlenderObject(romfile, startAddress, scene, newname, transformMatrix, segmentData, shadeSmooth): - #bmesh.ops.rotate(bMesh, cent = [0,0,0], - # matrix = blenderToSM64Rotation, - # verts = bMesh.verts) - bMesh.to_mesh(mesh) - bMesh.free() - mesh.update() + mesh = bpy.data.meshes.new(newname + "-mesh") + obj = bpy.data.objects.new(newname, mesh) + scene.collection.objects.link(obj) + createBlankMaterial(obj) - if shadeSmooth: - bpy.ops.object.select_all(action = 'DESELECT') - obj.select_set(True) - bpy.ops.object.shade_smooth() + bMesh = bmesh.new() + bMesh.from_mesh(mesh) - return obj + parseF3DBinary(romfile, startAddress, scene, bMesh, obj, transformMatrix, newname, segmentData, [None] * 16 * 16) + + # bmesh.ops.rotate(bMesh, cent = [0,0,0], + # matrix = blenderToSM64Rotation, + # verts = bMesh.verts) + bMesh.to_mesh(mesh) + bMesh.free() + mesh.update() + + if shadeSmooth: + bpy.ops.object.select_all(action="DESELECT") + obj.select_set(True) + bpy.ops.object.shade_smooth() + + return obj def cmdToPositiveInt(cmd): - return cmd if cmd >= 0 else 256 + cmd + return cmd if cmd >= 0 else 256 + cmd -def parseF3DBinary(romfile, startAddress, scene, - bMesh, obj, transformMatrix, groupName, segmentData, vertexBuffer): - f3d = F3D('F3D', False) - currentAddress = startAddress - romfile.seek(currentAddress) - command = romfile.read(8) - - faceSeq = bMesh.faces - vertSeq = bMesh.verts - uv_layer = bMesh.loops.layers.uv.verify() - deform_layer = bMesh.verts.layers.deform.verify() - vertexGroup = getOrMakeVertexGroup(obj, groupName) - groupIndex = vertexGroup.index - textureSize = [32, 32] +def parseF3DBinary(romfile, startAddress, scene, bMesh, obj, transformMatrix, groupName, segmentData, vertexBuffer): + f3d = F3D("F3D", False) + currentAddress = startAddress + romfile.seek(currentAddress) + command = romfile.read(8) - currentTextureAddr = -1 - jumps = [startAddress] + faceSeq = bMesh.faces + vertSeq = bMesh.verts + uv_layer = bMesh.loops.layers.uv.verify() + deform_layer = bMesh.verts.layers.deform.verify() + vertexGroup = getOrMakeVertexGroup(obj, groupName) + groupIndex = vertexGroup.index - # Used for remove_double op at end - vertList = [] + textureSize = [32, 32] - while len(jumps) > 0: - # FD, FC, B7 (tex, shader, geomode) - #print(format(command[0], '#04x') + ' at ' + hex(currentAddress)) - if command[0] == cmdToPositiveInt(f3d.G_TRI1): - try: - newVerts = interpretDrawTriangle(command, vertexBuffer, - faceSeq, vertSeq, uv_layer, deform_layer, groupIndex) - vertList.extend(newVerts) - except TypeError: - print("Ignoring triangle from unloaded vertices.") + currentTextureAddr = -1 + jumps = [startAddress] - elif command[0] == cmdToPositiveInt(f3d.G_VTX): - interpretLoadVertices(romfile, vertexBuffer, transformMatrix, - command, segmentData) + # Used for remove_double op at end + vertList = [] - # Note: size can usually be indicated in LoadTile / LoadBlock. - elif command[0] == cmdToPositiveInt(f3d.G_SETTILESIZE): - textureSize = interpretSetTileSize( - int.from_bytes(command[4:8], 'big')) + while len(jumps) > 0: + # FD, FC, B7 (tex, shader, geomode) + # print(format(command[0], '#04x') + ' at ' + hex(currentAddress)) + if command[0] == cmdToPositiveInt(f3d.G_TRI1): + try: + newVerts = interpretDrawTriangle( + command, vertexBuffer, faceSeq, vertSeq, uv_layer, deform_layer, groupIndex + ) + vertList.extend(newVerts) + except TypeError: + print("Ignoring triangle from unloaded vertices.") - elif command[0] == cmdToPositiveInt(f3d.G_DL): - if command[1] == 0: - jumps.append(currentAddress) - currentAddress = decodeSegmentedAddr(command[4:8], - segmentData = segmentData) - romfile.seek(currentAddress) - command = romfile.read(8) - continue + elif command[0] == cmdToPositiveInt(f3d.G_VTX): + interpretLoadVertices(romfile, vertexBuffer, transformMatrix, command, segmentData) - elif command[0] == cmdToPositiveInt(f3d.G_ENDDL): - currentAddress = jumps.pop() + # Note: size can usually be indicated in LoadTile / LoadBlock. + elif command[0] == cmdToPositiveInt(f3d.G_SETTILESIZE): + textureSize = interpretSetTileSize(int.from_bytes(command[4:8], "big")) - elif command[0] == cmdToPositiveInt(f3d.G_SETGEOMETRYMODE): - pass - elif command[0] == cmdToPositiveInt(f3d.G_SETCOMBINE): - pass + elif command[0] == cmdToPositiveInt(f3d.G_DL): + if command[1] == 0: + jumps.append(currentAddress) + currentAddress = decodeSegmentedAddr(command[4:8], segmentData=segmentData) + romfile.seek(currentAddress) + command = romfile.read(8) + continue - elif command[0] == cmdToPositiveInt(f3d.G_SETTIMG): - currentTextureAddr =\ - interpretSetTImage(command, segmentData) + elif command[0] == cmdToPositiveInt(f3d.G_ENDDL): + currentAddress = jumps.pop() - elif command[0] == cmdToPositiveInt(f3d.G_LOADBLOCK): - # for now only 16bit RGBA is supported. - interpretLoadBlock(command, romfile, currentTextureAddr, textureSize, - 'RGBA', 16) + elif command[0] == cmdToPositiveInt(f3d.G_SETGEOMETRYMODE): + pass + elif command[0] == cmdToPositiveInt(f3d.G_SETCOMBINE): + pass - elif command[0] == cmdToPositiveInt(f3d.G_SETTILE): - interpretSetTile(int.from_bytes(command[4:8], 'big'), None) + elif command[0] == cmdToPositiveInt(f3d.G_SETTIMG): + currentTextureAddr = interpretSetTImage(command, segmentData) - else: - pass - #print(format(command[0], '#04x') + ' at ' + hex(currentAddress)) + elif command[0] == cmdToPositiveInt(f3d.G_LOADBLOCK): + # for now only 16bit RGBA is supported. + interpretLoadBlock(command, romfile, currentTextureAddr, textureSize, "RGBA", 16) + + elif command[0] == cmdToPositiveInt(f3d.G_SETTILE): + interpretSetTile(int.from_bytes(command[4:8], "big"), None) + + else: + pass + # print(format(command[0], '#04x') + ' at ' + hex(currentAddress)) + + currentAddress += 8 + romfile.seek(currentAddress) + command = romfile.read(8) + + bmesh.ops.remove_doubles(bMesh, verts=vertList, dist=0.0001) + return vertexBuffer - currentAddress += 8 - romfile.seek(currentAddress) - command = romfile.read(8) - - bmesh.ops.remove_doubles(bMesh, verts = vertList, dist = 0.0001) - return vertexBuffer def getPosition(vertexBuffer, index): - xStart = index * 16 + 0 - yStart = index * 16 + 2 - zStart = index * 16 + 4 + xStart = index * 16 + 0 + yStart = index * 16 + 2 + zStart = index * 16 + 4 - xBytes = vertexBuffer[xStart : xStart + 2] - yBytes = vertexBuffer[yStart : yStart + 2] - zBytes = vertexBuffer[zStart : zStart + 2] + xBytes = vertexBuffer[xStart : xStart + 2] + yBytes = vertexBuffer[yStart : yStart + 2] + zBytes = vertexBuffer[zStart : zStart + 2] - x = int.from_bytes(xBytes, 'big', signed=True) / bpy.context.scene.blenderToSM64Scale - y = int.from_bytes(yBytes, 'big', signed=True) / bpy.context.scene.blenderToSM64Scale - z = int.from_bytes(zBytes, 'big', signed=True) / bpy.context.scene.blenderToSM64Scale + x = int.from_bytes(xBytes, "big", signed=True) / bpy.context.scene.blenderToSM64Scale + y = int.from_bytes(yBytes, "big", signed=True) / bpy.context.scene.blenderToSM64Scale + z = int.from_bytes(zBytes, "big", signed=True) / bpy.context.scene.blenderToSM64Scale - return (x, y, z) + return (x, y, z) -def getNormalorColor(vertexBuffer, index, isNormal = True): - xByte = bytes([vertexBuffer[index * 16 + 12]]) - yByte = bytes([vertexBuffer[index * 16 + 13]]) - zByte = bytes([vertexBuffer[index * 16 + 14]]) - wByte = bytes([vertexBuffer[index * 16 + 15]]) - if isNormal: - x = int.from_bytes(xByte, 'big', signed=True) - y = int.from_bytes(yByte, 'big', signed=True) - z = int.from_bytes(zByte, 'big', signed=True) - return (x,y,z) +def getNormalorColor(vertexBuffer, index, isNormal=True): + xByte = bytes([vertexBuffer[index * 16 + 12]]) + yByte = bytes([vertexBuffer[index * 16 + 13]]) + zByte = bytes([vertexBuffer[index * 16 + 14]]) + wByte = bytes([vertexBuffer[index * 16 + 15]]) - else: # vertex color - r = int.from_bytes(xByte, 'big') / 255 - g = int.from_bytes(yByte, 'big') / 255 - b = int.from_bytes(zByte, 'big') / 255 - a = int.from_bytes(wByte, 'big') / 255 - return (r,g,b,a) + if isNormal: + x = int.from_bytes(xByte, "big", signed=True) + y = int.from_bytes(yByte, "big", signed=True) + z = int.from_bytes(zByte, "big", signed=True) + return (x, y, z) -def getUV(vertexBuffer, index, textureDimensions = [32,32]): - uStart = index * 16 + 8 - vStart = index * 16 + 10 + else: # vertex color + r = int.from_bytes(xByte, "big") / 255 + g = int.from_bytes(yByte, "big") / 255 + b = int.from_bytes(zByte, "big") / 255 + a = int.from_bytes(wByte, "big") / 255 + return (r, g, b, a) - uBytes = vertexBuffer[uStart : uStart + 2] - vBytes = vertexBuffer[vStart : vStart + 2] - u = int.from_bytes(uBytes, 'big', signed = True) / 32 - v = int.from_bytes(vBytes, 'big', signed = True) / 32 +def getUV(vertexBuffer, index, textureDimensions=[32, 32]): + uStart = index * 16 + 8 + vStart = index * 16 + 10 - # We don't know texture size, so assume 32x32. - u /= textureDimensions[0] - v /= textureDimensions[1] - v = 1 - v + uBytes = vertexBuffer[uStart : uStart + 2] + vBytes = vertexBuffer[vStart : vStart + 2] + + u = int.from_bytes(uBytes, "big", signed=True) / 32 + v = int.from_bytes(vBytes, "big", signed=True) / 32 + + # We don't know texture size, so assume 32x32. + u /= textureDimensions[0] + v /= textureDimensions[1] + v = 1 - v + + return (u, v) - return (u,v) def interpretSetTile(data, texture): - clampMirrorFlags = bitMask(data, 18, 2) + clampMirrorFlags = bitMask(data, 18, 2) + def interpretSetTileSize(data): - hVal = bitMask(data, 0, 12) - wVal = bitMask(data, 12, 12) + hVal = bitMask(data, 0, 12) + wVal = bitMask(data, 12, 12) - height = hVal >> 2 + 1 - width = wVal >> 2 + 1 + height = hVal >> 2 + 1 + width = wVal >> 2 + 1 - return (width, height) + return (width, height) -def interpretLoadVertices(romfile, vertexBuffer, transformMatrix, command, - segmentData = None): - command = int.from_bytes(command, 'big', signed=True) - numVerts = bitMask(command, 52, 4) + 1 - startIndex = bitMask(command, 48, 4) - dataLength = bitMask(command, 32, 16) - segmentedAddr = bitMask(command, 0, 32) +def interpretLoadVertices(romfile, vertexBuffer, transformMatrix, command, segmentData=None): + command = int.from_bytes(command, "big", signed=True) - dataStartAddr = decodeSegmentedAddr(segmentedAddr.to_bytes(4, 'big'), - segmentData = segmentData) + numVerts = bitMask(command, 52, 4) + 1 + startIndex = bitMask(command, 48, 4) + dataLength = bitMask(command, 32, 16) + segmentedAddr = bitMask(command, 0, 32) - romfile.seek(dataStartAddr) - data = romfile.read(dataLength) + dataStartAddr = decodeSegmentedAddr(segmentedAddr.to_bytes(4, "big"), segmentData=segmentData) - for i in range(numVerts): - vert = mathutils.Vector(readVectorFromShorts(data, i * 16)) - vert = transformMatrix @ vert - transformedVert = bytearray(6) - writeVectorToShorts(transformedVert, 0, vert) - - start = (startIndex + i) * 16 - vertexBuffer[start: start + 6] = transformedVert - vertexBuffer[start + 6: start + 16] = data[i * 16 + 6: i * 16 + 16] + romfile.seek(dataStartAddr) + data = romfile.read(dataLength) + + for i in range(numVerts): + vert = mathutils.Vector(readVectorFromShorts(data, i * 16)) + vert = transformMatrix @ vert + transformedVert = bytearray(6) + writeVectorToShorts(transformedVert, 0, vert) + + start = (startIndex + i) * 16 + vertexBuffer[start : start + 6] = transformedVert + vertexBuffer[start + 6 : start + 16] = data[i * 16 + 6 : i * 16 + 16] # Note the divided by 0x0A, which is due to the way BF command stores indices. # Without this the triangles are drawn incorrectly. -def interpretDrawTriangle(command, vertexBuffer, - faceSeq, vertSeq, uv_layer, deform_layer, groupIndex): +def interpretDrawTriangle(command, vertexBuffer, faceSeq, vertSeq, uv_layer, deform_layer, groupIndex): - verts = [None, None, None] + verts = [None, None, None] - index0 = int(command[5] / 0x0A) - index1 = int(command[6] / 0x0A) - index2 = int(command[7] / 0x0A) + index0 = int(command[5] / 0x0A) + index1 = int(command[6] / 0x0A) + index2 = int(command[7] / 0x0A) - vert0 = mathutils.Vector(getPosition(vertexBuffer, index0)) - vert1 = mathutils.Vector(getPosition(vertexBuffer, index1)) - vert2 = mathutils.Vector(getPosition(vertexBuffer, index2)) + vert0 = mathutils.Vector(getPosition(vertexBuffer, index0)) + vert1 = mathutils.Vector(getPosition(vertexBuffer, index1)) + vert2 = mathutils.Vector(getPosition(vertexBuffer, index2)) - verts[0] = vertSeq.new(vert0) - verts[1] = vertSeq.new(vert1) - verts[2] = vertSeq.new(vert2) + verts[0] = vertSeq.new(vert0) + verts[1] = vertSeq.new(vert1) + verts[2] = vertSeq.new(vert2) - tri = faceSeq.new(verts) + tri = faceSeq.new(verts) - # Assign vertex group - for vert in tri.verts: - vert[deform_layer][groupIndex] = 1 + # Assign vertex group + for vert in tri.verts: + vert[deform_layer][groupIndex] = 1 + + loopIndex = 0 + for loop in tri.loops: + loop[uv_layer].uv = mathutils.Vector(getUV(vertexBuffer, int(command[5 + loopIndex] / 0x0A))) + loopIndex += 1 + + return verts - loopIndex = 0 - for loop in tri.loops: - loop[uv_layer].uv = mathutils.Vector( - getUV(vertexBuffer, int(command[5 + loopIndex] / 0x0A))) - loopIndex += 1 - - return verts def interpretSetTImage(command, levelData): - segmentedAddr = command[4:8] - return decodeSegmentedAddr(segmentedAddr, levelData) + segmentedAddr = command[4:8] + return decodeSegmentedAddr(segmentedAddr, levelData) + def interpretLoadBlock(command, romfile, textureStart, textureSize, colorFormat, colorDepth): - numTexels = ((int.from_bytes(command[6:8], 'big')) >> 12) + 1 + numTexels = ((int.from_bytes(command[6:8], "big")) >> 12) + 1 + + # This is currently broken. + # createNewTextureMaterial(romfile, textureStart, textureSize, numTexels, colorFormat, colorDepth, obj) - # This is currently broken. - #createNewTextureMaterial(romfile, textureStart, textureSize, numTexels, colorFormat, colorDepth, obj) def printvbuf(vertexBuffer): - for i in range(0, int(len(vertexBuffer) / 16)): - print(getPosition(vertexBuffer, i)) - print(getNormalorColor(vertexBuffer, i)) - print(getUV(vertexBuffer, i)) + for i in range(0, int(len(vertexBuffer) / 16)): + print(getPosition(vertexBuffer, i)) + print(getNormalorColor(vertexBuffer, i)) + print(getUV(vertexBuffer, i)) def createBlankMaterial(obj): - material = createF3DMat(obj) - material.f3d_preset = 'Shaded Solid' - update_preset_manual(material, bpy.context) + material = createF3DMat(obj) + material.f3d_preset = "Shaded Solid" + update_preset_manual(material, bpy.context) + def createNewTextureMaterial(romfile, textureStart, textureSize, texelCount, colorFormat, colorDepth, obj): - newMat = bpy.data.materials.new('f3d_material') - newTex = bpy.data.textures.new('f3d_texture', 'IMAGE') - newImg = bpy.data.images.new('f3d_texture', *textureSize, True, True) - - newTex.image = newImg - newSlot = newMat.texture_slots.add() - newSlot.texture = newTex - - obj.data.materials.append(newMat) - - romfile.seek(textureStart) - texelSize = int(colorDepth / 8) - dataLength = texelCount * texelSize - textureData = romfile.read(dataLength) + newMat = bpy.data.materials.new("f3d_material") + newTex = bpy.data.textures.new("f3d_texture", "IMAGE") + newImg = bpy.data.images.new("f3d_texture", *textureSize, True, True) + + newTex.image = newImg + newSlot = newMat.texture_slots.add() + newSlot.texture = newTex + + obj.data.materials.append(newMat) + + romfile.seek(textureStart) + texelSize = int(colorDepth / 8) + dataLength = texelCount * texelSize + textureData = romfile.read(dataLength) + + if colorDepth != 16: + print("Warning: Only 16bit RGBA supported, input was " + str(colorDepth) + "bit " + colorFormat) + else: + print(str(texelSize) + " " + str(colorDepth)) + for n in range(0, dataLength, texelSize): + oldPixel = textureData[n : n + texelSize] + newImg.pixels[n : n + 4] = read16bitRGBA(int.from_bytes(oldPixel, "big")) - if colorDepth != 16: - print("Warning: Only 16bit RGBA supported, input was " + \ - str(colorDepth) + 'bit ' + colorFormat) - else: - print(str(texelSize) + " " + str(colorDepth)) - for n in range(0, dataLength, texelSize): - oldPixel = textureData[n : n + texelSize] - newImg.pixels[n : n+4] = read16bitRGBA( - int.from_bytes(oldPixel, 'big')) binOps = { - ast.Add: operator.add, - ast.Sub: operator.sub, - ast.Mult: operator.mul, - ast.Div: operator.truediv, - ast.Mod: operator.mod, - ast.LShift: operator.lshift, - ast.RShift: operator.rshift, - ast.RShift: operator.rshift, - ast.BitOr: operator.or_, - ast.BitAnd: operator.and_, - ast.BitXor: operator.xor, + ast.Add: operator.add, + ast.Sub: operator.sub, + ast.Mult: operator.mul, + ast.Div: operator.truediv, + ast.Mod: operator.mod, + ast.LShift: operator.lshift, + ast.RShift: operator.rshift, + ast.RShift: operator.rshift, + ast.BitOr: operator.or_, + ast.BitAnd: operator.and_, + ast.BitXor: operator.xor, } -def math_eval (s, f3d): - if isinstance(s, int): - return s - s = s.strip() - node = ast.parse(s, mode='eval') +def math_eval(s, f3d): + if isinstance(s, int): + return s - def _eval(node): - if isinstance(node, ast.Expression): - return _eval(node.body) - elif isinstance(node, ast.Str): - return node.s - elif isinstance(node, ast.Name): - if hasattr(f3d, node.id): - return getattr(f3d, node.id) - else: - return node.id - elif isinstance(node, ast.Num): - return node.n - elif isinstance(node, ast.UnaryOp): - if isinstance(node.op, ast.USub): - return -1 * _eval(node.operand) - elif isinstance(node.op, ast.Invert): - return ~ _eval(node.operand) - else: - raise Exception('Unsupported type {}'.format(node.op)) - elif isinstance(node, ast.BinOp): - return binOps[type(node.op)](_eval(node.left), _eval(node.right)) - elif isinstance(node, ast.Call): - args = list(map(_eval, node.args)) - funcName = _eval(node.func) - return funcName(*args) - else: - raise Exception('Unsupported type {}'.format(node)) + s = s.strip() + node = ast.parse(s, mode="eval") + + def _eval(node): + if isinstance(node, ast.Expression): + return _eval(node.body) + elif isinstance(node, ast.Str): + return node.s + elif isinstance(node, ast.Name): + if hasattr(f3d, node.id): + return getattr(f3d, node.id) + else: + return node.id + elif isinstance(node, ast.Num): + return node.n + elif isinstance(node, ast.UnaryOp): + if isinstance(node.op, ast.USub): + return -1 * _eval(node.operand) + elif isinstance(node.op, ast.Invert): + return ~_eval(node.operand) + else: + raise Exception("Unsupported type {}".format(node.op)) + elif isinstance(node, ast.BinOp): + return binOps[type(node.op)](_eval(node.left), _eval(node.right)) + elif isinstance(node, ast.Call): + args = list(map(_eval, node.args)) + funcName = _eval(node.func) + return funcName(*args) + else: + raise Exception("Unsupported type {}".format(node)) + + return _eval(node.body) - return _eval(node.body) def bytesToNormal(normal): - return [int.from_bytes([value], 'big', signed = True) / 128 if value > 0 else - value / 128 for value in normal] + return [int.from_bytes([value], "big", signed=True) / 128 if value > 0 else value / 128 for value in normal] + def getTileFormat(value, f3d): - data = math_eval(value, f3d) - return ["G_IM_FMT_RGBA", "G_IM_FMT_YUV", "G_IM_FMT_CI", "G_IM_FMT_IA", "G_IM_FMT_I"][data] + data = math_eval(value, f3d) + return ["G_IM_FMT_RGBA", "G_IM_FMT_YUV", "G_IM_FMT_CI", "G_IM_FMT_IA", "G_IM_FMT_I"][data] + def getTileSize(value, f3d): - data = math_eval(value, f3d) - return ["G_IM_SIZ_4b", "G_IM_SIZ_8b", "G_IM_SIZ_16b", "G_IM_SIZ_32b", "G_IM_SIZ_32b", "G_IM_SIZ_DD"][data] + data = math_eval(value, f3d) + return ["G_IM_SIZ_4b", "G_IM_SIZ_8b", "G_IM_SIZ_16b", "G_IM_SIZ_32b", "G_IM_SIZ_32b", "G_IM_SIZ_DD"][data] + def getTileClampMirror(value, f3d): - data = math_eval(value, f3d) - return [(data & f3d.G_TX_CLAMP) != 0, (data & f3d.G_TX_MIRROR) != 0] + data = math_eval(value, f3d) + return [(data & f3d.G_TX_CLAMP) != 0, (data & f3d.G_TX_MIRROR) != 0] + def getTileMask(value, f3d): - data = math_eval(value, f3d) - return data + data = math_eval(value, f3d) + return data + def getTileShift(value, f3d): - data = math_eval(value, f3d) - return data + data = math_eval(value, f3d) + return data + def renderModeMask(rendermode, cycle, blendOnly): - nonBlend = (((1 << 13) - 1) << 3) if not blendOnly else 0 - if cycle == 1: - return rendermode & (3 << 30 | 3 << 26 | 3 << 22 | 3 << 18 | nonBlend) - else: - return rendermode & (3 << 28 | 3 << 24 | 3 << 20 | 3 << 16 | nonBlend) + nonBlend = (((1 << 13) - 1) << 3) if not blendOnly else 0 + if cycle == 1: + return rendermode & (3 << 30 | 3 << 26 | 3 << 22 | 3 << 18 | nonBlend) + else: + return rendermode & (3 << 28 | 3 << 24 | 3 << 20 | 3 << 16 | nonBlend) + def convertF3DUV(value, maxSize): - try: - valueBytes = int.to_bytes(value, 2, 'big', signed = True) - except OverflowError: - valueBytes = int.to_bytes(value, 2, 'big', signed = False) - - return ((int.from_bytes(valueBytes, 'big', signed = True) / 32) + 0.5) / (maxSize if maxSize > 0 else 1) + try: + valueBytes = int.to_bytes(value, 2, "big", signed=True) + except OverflowError: + valueBytes = int.to_bytes(value, 2, "big", signed=False) + + return ((int.from_bytes(valueBytes, "big", signed=True) / 32) + 0.5) / (maxSize if maxSize > 0 else 1) + class F3DParsedCommands: - def __init__(self, name, commands, index): - self.name = name - self.commands = commands - self.index = index + def __init__(self, name, commands, index): + self.name = name + self.commands = commands + self.index = index + + def currentCommand(self): + return self.commands[self.index] - def currentCommand(self): - return self.commands[self.index] class F3DContext: - def __init__(self, f3d, basePath, materialContext): - self.f3d = f3d - self.vertexBuffer = [None] * f3d.vert_load_size - self.basePath = basePath - self.materialContext = materialContext - - self.clearMaterial() - mat = self.mat() - mat.set_combiner = False - - self.materials = [] # saved materials - self.triMatIndices = [] # material indices per triangle - self.materialChanged = True - self.lastMaterialIndex = None - - self.vertexData = {} # c name : parsed data - self.textureData = {} # c name : blender texture - - self.tlutAppliedTextures = [] # c name - self.currentTextureName = None - - # This macro has all the tile setting properties, so we reuse it - self.tileSettings = [DPSetTile( - "G_IM_FMT_RGBA", "G_IM_SIZ_16b", 5, 0, i, 0, - [False, False], 0, 0, - [False, False], 0, 0) for i in range(8)] - self.tileSizes = [DPSetTileSize(i, 0, 0, 32, 32) for i in range(8)] - - # When a tile is loaded, store dict of tmem : texture - self.tmemDict = {} - - # This should be modified before parsing f3d - self.matrixData = {} # bone name : matrix - self.currentTransformName = None - self.limbToBoneName = {} # limb name (c variable) : bone name (blender vertex group) - - # data for Mesh.from_pydata, list of BufferVertex tuples - # use BufferVertex to also form uvs / normals / colors - self.verts = [] - self.limbGroups = {} # dict of groupName : vertex indices - - self.lights = Lights("lights_context") - self.lights.l = [ - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]),] - self.lights.a = Ambient([0,0,0]) - self.numLights = 0 - self.lightData = {} # (color, normal) : list of blender light objects - - # MAKE SURE TO CALL THIS BETWEEN parseF3D() CALLS - def clearMaterial(self): - mat = self.mat() - - mat.rdp_settings.sets_rendermode = False - mat.set_prim = False - mat.set_lights = False - mat.set_env = False - mat.set_blend = False - mat.set_key = False - mat.set_k0_5 = False - - mat.prim_color = [1,1,1,1] - mat.env_color = [1,1,1,1] - mat.blend_color = [1,1,1,1] - for i in range(1, 8): - setattr(mat, "f3d_light" + str(i), None) - mat.tex0.tex = None - mat.tex1.tex = None - mat.tex0.tex_set = False - mat.tex1.tex_set = False - - mat.tex0.tex_format = "RGBA16" - mat.tex1.tex_format = "RGBA16" - - self.tmemDict = {} - - self.tileSettings = [DPSetTile( - "G_IM_FMT_RGBA", "G_IM_SIZ_16b", 5, 0, i, 0, - [False, False], 0, 0, - [False, False], 0, 0) for i in range(8)] - - self.tileSizes = [DPSetTileSize(i, 0, 0, 32, 32) for i in range(8)] - - self.lights = Lights("lights_context") - self.lights.l = [ - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]), - Light([0,0,0],[0x28, 0x28, 0x28]),] - self.lights.a = Ambient([0,0,0]) - self.numLights = 0 - - mat.presetName = "Custom" - - def mat(self): - return self.materialContext.f3d_mat - - def vertexFormatPatterns(self, data): - # position, uv, color/normal - return [ - # decomp format - "\{\s*\{\s*" +\ - "\{([^,\}]*),([^,\}]*),([^,\}]*)\}\s*," + "[^,\}]*,\s*" +\ - "\{([^,\}]*),([^,\}]*)\}\s*,\s*" +\ - "\{([^,\}]*),([^,\}]*),([^,\}]*),([^,\}]*)\}\s*" +\ - "\}\s*\}", - - # nusys format - "\{\s*" +\ - "([^,\}]*),([^,\}]*),([^,\}]*)," + "[^,\}]*," +\ - "([^,\}]*),([^,\}]*)," +\ - "([^,\}]*),([^,\}]*),([^,\}]*),([^,\}]*)\s*" +\ - "\}", - ] - - # For game specific instance, override this to be able to identify which verts belong to which bone. - def setCurrentTransform(self, name): - self.currentTransformName = name - - def getTransformedVertex(self, index): - bufferVert = self.vertexBuffer[index] - - # NOTE: The groupIndex here does NOT correspond to a vertex group, but to the name of the limb (c variable) - matrixName = bufferVert.groupIndex - if matrixName in self.matrixData: - transform = self.matrixData[matrixName] - else: - print(self.matrixData) - raise PluginError("Transform matrix not specified for " + matrixName) - - mat = self.mat() - f3dVert = bufferVert.f3dVert - position = transform @ mathutils.Vector(f3dVert[0]) - if mat.tex0.tex is not None: - uv = [convertF3DUV(f3dVert[1][i], mat.tex0.tex.size[i]) for i in range(2)] - #uv = [1 - (f3dVert[1][i] / (self.materialContext.f3d_mat.tex0.tex.size[i] * 32)) for i in range(2)] - #uv = [((f3dVert[1][i] / 32) + 0.5) / mat.tex0.tex.size[i] for i in range(2)] - else: - uv = [convertF3DUV(f3dVert[1][i], 32) for i in range(2)] - #uv = [1 - (f3dVert[1][i] / (32 * 32)) for i in range(2)] - #uv = [((f3dVert[1][i] / 32) + 0.5) / 32 for i in range(2)] - uv[1] = 1 - uv[1] - - color = [value / 256 if value > 0 else - int.from_bytes(value.to_bytes(1, 'big', signed = True), 'big', signed = False) / 256 - for value in f3dVert[2]] - - normal = bytesToNormal(f3dVert[2][:3]) + [0] - normal = (transform.inverted().transposed() @ mathutils.Vector(normal)).normalized()[:3] - - # This is not usual format of f3dVert, but we need separate color/normal data. - # NOTE: The groupIndex here does NOT correspond to a vertex group, but to the name of the limb (c variable) - return BufferVertex([position, uv, color, normal], bufferVert.groupIndex, bufferVert.materialIndex) - - def addVertices(self, num, start, vertexDataName, vertexDataOffset): - vertexData = self.vertexData[vertexDataName] - - # TODO: material index not important? - count = math_eval(num, self.f3d) - start = math_eval(start, self.f3d) - - if start + count > len (self.vertexBuffer): - raise PluginError("Vertex buffer of size " + len(self.vertexBuffer) + " too small, attempting load into " +\ - str(start) + ", " + str(start + count)) - for i in range(count): - self.vertexBuffer[start + i] = \ - BufferVertex(vertexData[vertexDataOffset + i], self.currentTransformName, 0) - - def addTriangle(self, indices, dlData): - if self.materialChanged: - mat = self.mat() - region = None - - tileSettings = self.tileSettings[0] - tileSizeSettings = self.tileSizes[0] - if tileSettings.tmem in self.tmemDict: - textureName = self.tmemDict[tileSettings.tmem] - self.loadTexture(dlData, textureName, region, tileSettings, False) - self.applyTileToMaterial(0, tileSettings, tileSizeSettings) - - tileSettings = self.tileSettings[1] - tileSizeSettings = self.tileSizes[1] - if tileSettings.tmem in self.tmemDict: - textureName = self.tmemDict[tileSettings.tmem] - self.loadTexture(dlData, textureName, region, tileSettings, False) - self.applyTileToMaterial(1, tileSettings, tileSizeSettings) - - self.applyLights() - - self.lastMaterialIndex = self.getMaterialIndex() - self.materialChanged = False - - verts = [self.getTransformedVertex(math_eval(index, self.f3d)) for index in indices] - #if verts[0].groupIndex != verts[1].groupIndex or\ - # verts[0].groupIndex != verts[2].groupIndex or\ - # verts[2].groupIndex != verts[1].groupIndex: - # return - for i in range(len(verts)): - vert = verts[i] - - # NOTE: The groupIndex here does NOT correspond to a vertex group, but to the name of the limb (c variable) - if vert.groupIndex not in self.limbGroups: - self.limbGroups[vert.groupIndex] = [] - self.limbGroups[vert.groupIndex].append(len(self.verts) + i) - self.verts.extend([vert.f3dVert for vert in verts]) - - for i in range(int(len(indices) / 3)): - self.triMatIndices.append(self.lastMaterialIndex) - - def getMaterialIndex(self): - # We do this for now to update tile settings for S and T. - # Right now we don't handle those, so we need the auto-calculator to set it correctly. - overrideContext = bpy.context.copy() - overrideContext["material"] = self.materialContext - bpy.ops.material.update_f3d_nodes(overrideContext) - - for material in self.materials: - if propertyGroupEquals(self.materialContext.f3d_mat, material.f3d_mat): - return self.materials.index(material) - - self.addMaterial() - return len(self.materials) - 1 - - def getImageName(self, image): - for name, otherImage in self.textureData.items(): - if image == otherImage: - return name - return None - - def applyTLUTToIndex(self, index): - mat = self.mat() - texProp = getattr(mat, "tex" + str(index)) - combinerUses = all_combiner_uses(mat) - if combinerUses["Texture " + str(index)] and \ - (texProp.tex is not None or texProp.use_tex_reference) and \ - texProp.tex_set and texProp.tex_format[:2] == "CI" and\ - (texProp.tex not in self.tlutAppliedTextures or texProp.use_tex_reference): - - # Only handles TLUT at 256 - tlutName = self.tmemDict[256] - if 256 in self.tmemDict and tlutName is not None: - tlut = self.textureData[tlutName] - if isinstance(tlut, F3DTextureReference) or texProp.use_tex_reference: - if not texProp.use_tex_reference: - texProp.use_tex_reference = True - imageName = self.getImageName(texProp.tex) - if imageName is not None: - texProp.tex_reference = imageName - else: - print("Cannot find name of texture " + str(texProp.tex)) - - if isinstance(tlut, F3DTextureReference): - texProp.pal_reference = tlut.name - texProp.pal_reference_size = tlut.width - else: - texProp.pal_reference = tlutName - texProp.pal_reference_size = min(tlut.size[0] * tlut.size[1], 256) - - else: - self.applyTLUT(texProp.tex, tlut) - self.tlutAppliedTextures.append(texProp.tex) - else: - print("Ignoring TLUT.") - - def postMaterialChanged(self): - return - - def addMaterial(self): - mat = self.mat() - combinerUses = all_combiner_uses(self.mat()) - self.applyTLUTToIndex(0) - self.applyTLUTToIndex(1) - - material = self.materialContext.copy() - overrideContext = bpy.context.copy() - overrideContext["material"] = material - bpy.ops.material.update_f3d_nodes(overrideContext) - self.materials.append(material) - self.materialChanged = False - - self.postMaterialChanged() - - def getSizeMacro(self, size, suffix): - if hasattr(self.f3d, size): - return getattr(self.f3d, size + suffix) - else: - return getattr(self.f3d, self.f3d.IM_SIZ[size] + suffix) - - def getImagePathFromInclude(self, path): - if self.basePath is None: - raise PluginError("Cannot load texture from " + path + " without any provided base path.") - - imagePath = path[:-5] + 'png' - return os.path.join(self.basePath, imagePath) - - def getVTXPathFromInclude(self, path): - if self.basePath is None: - raise PluginError("Cannot load VTX from " + path + " without any provided base path.") - return os.path.join(self.basePath, path) - - def setGeoFlags(self, command, value): - mat = self.mat() - bitFlags = math_eval(command.params[0], self.f3d) - - if bitFlags & self.f3d.G_ZBUFFER: - mat.rdp_settings.g_zbuffer = value - if bitFlags & self.f3d.G_SHADE: - mat.rdp_settings.g_shade = value - if bitFlags & self.f3d.G_CULL_FRONT: - mat.rdp_settings.g_cull_front = value - if bitFlags & self.f3d.G_CULL_BACK: - mat.rdp_settings.g_cull_back = value - if bitFlags & self.f3d.G_FOG: - mat.rdp_settings.g_fog = value - if bitFlags & self.f3d.G_LIGHTING: - mat.rdp_settings.g_lighting = value - if bitFlags & self.f3d.G_TEXTURE_GEN: - mat.rdp_settings.g_tex_gen = value - if bitFlags & self.f3d.G_TEXTURE_GEN_LINEAR: - mat.rdp_settings.g_tex_gen_linear = value - if bitFlags & self.f3d.G_SHADING_SMOOTH: - mat.rdp_settings.g_shade_smooth = value - if bitFlags & self.f3d.G_CLIPPING: - mat.rdp_settings.g_clipping = value - - def loadGeoFlags(self, command): - mat = self.mat() - - bitFlags = math_eval(command.params[0], self.f3d) - - mat.rdp_settings.g_zbuffer = bitFlags & self.f3d.G_ZBUFFER != 0 - mat.rdp_settings.g_shade = bitFlags & self.f3d.G_SHADE != 0 - mat.rdp_settings.g_cull_front = bitFlags & self.f3d.G_CULL_FRONT != 0 - mat.rdp_settings.g_cull_back = bitFlags & self.f3d.G_CULL_BACK != 0 - mat.rdp_settings.g_fog = bitFlags & self.f3d.G_FOG != 0 - mat.rdp_settings.g_lighting = bitFlags & self.f3d.G_LIGHTING != 0 - mat.rdp_settings.g_tex_gen = bitFlags & self.f3d.G_TEXTURE_GEN != 0 - mat.rdp_settings.g_tex_gen_linear = bitFlags & self.f3d.G_TEXTURE_GEN_LINEAR != 0 - mat.rdp_settings.g_shade_smooth = bitFlags & self.f3d.G_SHADING_SMOOTH != 0 - mat.rdp_settings.g_clipping = bitFlags & self.f3d.G_CLIPPING != 0 - - def setCombineLerp(self, lerp0, lerp1): - mat = self.mat() - - if len(lerp0) < 8 or len(lerp1) < 8: - print("Incorrect combiner param count: " + str(lerp0) + " " + str(lerp1)) - return - - lerp0 = [value.strip() for value in lerp0] - lerp1 = [value.strip() for value in lerp1] - - # Padding since index can go up to 31 - combinerAList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', '1', 'NOISE'] + ['0'] * 24 - combinerBList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', 'CENTER', 'K4'] + ['0'] * 24 - combinerCList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', 'SCALE', - 'COMBINED_ALPHA', 'TEXEL0_ALPHA', 'TEXEL1_ALPHA', 'PRIMITIVE_ALPHA', 'SHADE_ALPHA', 'ENV_ALPHA', - 'LOD_FRACTION', 'PRIM_LOD_FRAC', 'K5'] + ['0'] * 16 - combinerDList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', '1', '0'] + ['0'] * 24 - - combinerAAlphaList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', '1', '0'] - combinerBAlphaList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', '1', '0'] - combinerCAlphaList = ['LOD_FRACTION', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', 'PRIM_LOD_FRAC', '0'] - combinerDAlphaList = ['COMBINED', 'TEXEL0', 'TEXEL1', 'PRIMITIVE', 'SHADE', 'ENVIRONMENT', '1', '0'] - - for i in range(0,4): - lerp0[i] = math_eval("G_CCMUX_" + lerp0[i], self.f3d) - lerp1[i] = math_eval("G_CCMUX_" + lerp1[i], self.f3d) - - for i in range(4,8): - lerp0[i] = math_eval("G_ACMUX_" + lerp0[i], self.f3d) - lerp1[i] = math_eval("G_ACMUX_" + lerp1[i], self.f3d) - - - mat.set_combiner = True - mat.combiner1.A = combinerAList[lerp0[0]] - mat.combiner1.B = combinerBList[lerp0[1]] - mat.combiner1.C = combinerCList[lerp0[2]] - mat.combiner1.D = combinerDList[lerp0[3]] - mat.combiner1.A_alpha = combinerAAlphaList[lerp0[4]] - mat.combiner1.B_alpha = combinerBAlphaList[lerp0[5]] - mat.combiner1.C_alpha = combinerCAlphaList[lerp0[6]] - mat.combiner1.D_alpha = combinerDAlphaList[lerp0[7]] - - mat.combiner2.A = combinerAList[lerp1[0]] - mat.combiner2.B = combinerBList[lerp1[1]] - mat.combiner2.C = combinerCList[lerp1[2]] - mat.combiner2.D = combinerDList[lerp1[3]] - mat.combiner2.A_alpha = combinerAAlphaList[lerp1[4]] - mat.combiner2.B_alpha = combinerBAlphaList[lerp1[5]] - mat.combiner2.C_alpha = combinerCAlphaList[lerp1[6]] - mat.combiner2.D_alpha = combinerDAlphaList[lerp1[7]] - - def setCombineMode(self, command): - if not hasattr(self.f3d, command.params[0]) or\ - not hasattr(self.f3d, command.params[1]): - print("Unhandled combiner mode: " + command.params[0] + ", " + command.params[1]) - return - lerp0 = getattr(self.f3d, command.params[0]) - lerp1 = getattr(self.f3d, command.params[1]) - - self.setCombineLerp(lerp0, lerp1) - - def setTLUTMode(self, index, value): - mat = self.mat() - texProp = getattr(mat, "tex" + str(index)) - bitData = math_eval(value, self.f3d) - if value == self.f3d.G_TT_NONE: - if texProp.tex_format[:2] == 'CI': - texProp.tex_format = 'RGBA16' - elif value == self.f3d.G_TT_IA16: - texProp.ci_format = "IA16" - else: - texProp.ci_format = "RGBA16" - - def setOtherModeFlags(self, command): - mat = self.mat() - mode = math_eval(command.params[0], self.f3d) - if mode == self.f3d.G_SETOTHERMODE_H: - self.setOtherModeFlagsH(command) - else: - self.setOtherModeFlagsL(command) - - def setOtherModeFlagsH(self, command): - - otherModeH = { - "G_MDSFT_ALPHADITHER" : ["G_AD_PATTERN", "G_AD_NOTPATTERN", "G_AD_NOISE", "G_AD_DISABLE"], - "G_MDSFT_RGBDITHER" : ["G_CD_MAGICSQ", "G_CD_BAYER", "NOISE"], - "G_MDSFT_COMBKEY" : ["G_CK_NONE", "G_CK_KEY"], - "G_MDSFT_TEXTCONV" : ["G_TC_CONV", "G_TC_CONV", "G_TC_CONV", "G_TC_CONV", "G_TC_CONV", "G_TC_FILTCONV", "G_TC_FILT"], - "G_MDSFT_TEXTFILT" : ["G_TF_POINT", "G_TF_POINT", "G_TF_BILERP", "G_TF_AVERAGE"], - "G_MDSFT_TEXTLOD" : ["G_TL_TILE", "G_TL_LOD"], - "G_MDSFT_TEXTDETAIL" : ["G_TD_CLAMP", "G_TD_SHARPEN", "G_TD_DETAIL"], - "G_MDSFT_TEXTPERSP" : ["G_TP_NONE", "G_TP_PERSP"], - "G_MDSFT_CYCLETYPE" : ["G_CYC_1CYCLE", "G_CYC_2CYCLE", "G_CYC_COPY", "G_CYC_FILL"], - "G_MDSFT_COLORDITHER" : ["G_CD_MAGICSQ", "G_CD_BAYER", "G_CD_NOISE"], - "G_MDSFT_PIPELINE" : ["G_PM_NPRIMITIVE", "G_PM_1PRIMITIVE"], - } - mat = self.mat() - flags = math_eval(command.params[3], self.f3d) - shift = math_eval(command.params[1], self.f3d) - mask = math_eval(command.params[2], self.f3d) - - for field, fieldData in otherModeH.items(): - fieldShift = getattr(self.f3d, field) - if fieldShift >= shift and fieldShift < shift + mask: - setattr(mat.rdp_settings, field.lower(), fieldData[(flags >> fieldShift) & \ - ((1 << int(ceil(math.log(len(fieldData), 2)))) - 1)]) - - - # This only handles commonly used render mode presets (with macros), - # and no render modes at all with raw bit data. - def setOtherModeFlagsL(self, command): - otherModeL = { - "G_MDSFT_ALPHACOMPARE" : ["G_AC_NONE", "G_AC_THRESHOLD", "G_AC_THRESHOLD", "G_AC_DITHER"], - "G_MDSFT_ZSRCSEL" : ["G_ZS_PIXEL", "G_ZS_PRIM"], - } - - mat = self.mat() - flags = math_eval(command.params[3], self.f3d) - shift = math_eval(command.params[1], self.f3d) - mask = math_eval(command.params[2], self.f3d) - - for field, fieldData in otherModeL.items(): - fieldShift = getattr(self.f3d, field) - if fieldShift >= shift and fieldShift < shift + mask: - setattr(mat.rdp_settings, field.lower(), fieldData[(flags >> fieldShift) & \ - ((1 << int(ceil(math.log(len(fieldData), 2)))) - 1)]) - - if self.f3d.G_MDSFT_RENDERMODE >= shift and self.f3d.G_MDSFT_RENDERMODE < shift + mask: - self.setRenderMode(flags) - - def setRenderMode(self, flags): - mat = self.mat() - rendermode1 = renderModeMask(flags, 1, False) - rendermode2 = renderModeMask(flags, 2, False) - - blend1 = renderModeMask(flags, 1, True) - - rendermodeName1 = None - rendermodeName2 = None - - #print("Render mode: " + hex(rendermode1) + ", " + hex(rendermode2)) - for name, value in vars(self.f3d).items(): - if name[:5] == "G_RM_": - #print(name + " " + hex(value)) - - if name in ["G_RM_FOG_SHADE_A", "G_RM_FOG_PRIM_A", "G_RM_PASS"]: - if blend1 == value: - rendermodeName1 = name - else: - if rendermode1 == value: - rendermodeName1 = name - if rendermode2 == value: - rendermodeName2 = name - if rendermodeName1 is not None and rendermodeName2 is not None: - break - - mat.rdp_settings.sets_rendermode = True - if rendermodeName1 is not None and rendermodeName2 is not None: - mat.rdp_settings.rendermode_advanced_enabled = False - mat.rdp_settings.rendermode_preset_cycle_1 = rendermodeName1 - mat.rdp_settings.rendermode_preset_cycle_2 = rendermodeName2 - else: - mat.rdp_settings.rendermode_advanced_enabled = True - - mat.rdp_settings.aa_en = rendermode1 & self.f3d.AA_EN != 0 - mat.rdp_settings.z_cmp = rendermode1 & self.f3d.Z_CMP != 0 - mat.rdp_settings.z_upd = rendermode1 & self.f3d.Z_UPD != 0 - mat.rdp_settings.im_rd = rendermode1 & self.f3d.IM_RD != 0 - mat.rdp_settings.clr_on_cvg = rendermode1 & self.f3d.CLR_ON_CVG != 0 - mat.rdp_settings.cvg_dst = self.f3d.cvgDstDict[rendermode1 & self.f3d.CVG_DST_SAVE] - mat.rdp_settings.zmode = self.f3d.zmodeDict[rendermode1 & self.f3d.ZMODE_DEC] - mat.rdp_settings.cvg_x_alpha = rendermode1 & self.f3d.CVG_X_ALPHA != 0 - mat.rdp_settings.alpha_cvg_sel = rendermode1 & self.f3d.ALPHA_CVG_SEL != 0 - mat.rdp_settings.force_bl = rendermode1 & self.f3d.FORCE_BL != 0 - - mat.rdp_settings.blend_p1 = self.f3d.blendColorDict[rendermode1 >> 30 & 3] - mat.rdp_settings.blend_a1 = self.f3d.blendAlphaDict[rendermode1 >> 26 & 3] - mat.rdp_settings.blend_m1 = self.f3d.blendColorDict[rendermode1 >> 22 & 3] - mat.rdp_settings.blend_b1 = self.f3d.blendMixDict[rendermode1 >> 18 & 3] - - mat.rdp_settings.blend_p2 = self.f3d.blendColorDict[rendermode2 >> 28 & 3] - mat.rdp_settings.blend_a2 = self.f3d.blendAlphaDict[rendermode2 >> 24 & 3] - mat.rdp_settings.blend_m2 = self.f3d.blendColorDict[rendermode2 >> 20 & 3] - mat.rdp_settings.blend_b2 = self.f3d.blendMixDict[rendermode2 >> 16 & 3] - - def gammaInverseParam(self, color): - return [gammaInverseValue(math_eval(value, self.f3d) / 255) for value in color[:3]] + [math_eval(color[3], self.f3d) / 255] - - def getLightIndex(self, lightIndexString): - return math_eval(lightIndexString, self.f3d) if "LIGHT_" not in lightIndexString else int(lightIndexString[-1:]) - - def getLightCount(self, lightCountString): - return math_eval(lightCountString, self.f3d) if "NUMLIGHTS_" not in lightCountString else int(lightCountString[-1:]) - - def getLightObj(self, light): - lightKey = (tuple(light.color), tuple(light.normal)) - if lightKey not in self.lightData: - lightName = "Light" - bLight = bpy.data.lights.new(lightName, "SUN") - lightObj = bpy.data.objects.new(lightName, bLight) - - lightObj.rotation_euler = (mathutils.Euler((0, 0, math.pi)).to_quaternion() @ \ - (mathutils.Euler((math.pi / 2, 0, 0)).to_quaternion() @ \ - mathutils.Vector(light.normal)).rotation_difference(mathutils.Vector((0,0,1)))).to_euler() - #lightObj.rotation_euler[0] *= 1 - bLight.color = light.color - - bpy.context.scene.collection.objects.link(lightObj) - self.lightData[lightKey] = lightObj - return self.lightData[lightKey] - - def applyLights(self): - mat = self.mat() - allCombinerUses = all_combiner_uses(mat) - if allCombinerUses["Shade"] and mat.rdp_settings.g_lighting and mat.set_lights: - mat.use_default_lighting = False - mat.ambient_light_color = self.lights.a.color + ([1] if len(self.lights.a.color) == 3 else []) - - for i in range(self.numLights): - lightObj = self.getLightObj(self.lights.l[i]) - setattr(mat, "f3d_light" + str(i + 1), lightObj.data) - - def setLightColor(self, data, command): - self.mat().set_lights = True - lightIndex = self.getLightIndex(command.params[0]) - colorData = math_eval(command.params[1], self.f3d) - color = [((colorData >> 24) & 0xFF) / 0xFF, ((colorData >> 16) & 0xFF) / 0xFF, ((colorData >> 8) & 0xFF) / 0xFF] - - if lightIndex != self.numLights + 1: - self.lights.l[lightIndex - 1].color = color - else: - self.lights.a.color = color - - # This is an assumption. - if self.numLights < lightIndex - 1: - self.numLights = lightIndex - 1 - - # Assumes that any SPLight references a Lights0-9n struct instead of specific Light structs. - def setLight(self, data, command): - mat = self.mat() - mat.set_lights = True - - lightReference = command.params[0] - lightIndex = self.getLightIndex(command.params[1]) - - match = re.search("([A-Za-z0-9\_]*)\.(l(\[([0-9])\])?)?(a)?", lightReference) - if match is None: - print("Could not handle parsing of light reference: " + lightReference + ". Currently only handling Lights0-9n structs (not Light)") - return - - lightsName = match.group(1) - lights = self.createLights(data, lightsName) - - if match.group(2) is not None: - if match.group(3) is not None: - lightIndex = math_eval(match.group(4), self.f3d) - else: - lightIndex = 0 - - # This is done as an assumption, to handle models that have numLights set beforehand - if self.numLights < lightIndex + 1: - self.numLights = lightIndex + 1 - self.lights.l[lightIndex] = lights.l[lightIndex] - else: - self.lights.a = lights.a - - def setLights(self, data, command): - mat = self.mat() - self.mat().set_lights = True - - numLights = self.getLightCount(command.name[13]) - self.numLights = numLights - - lightsName = command.params[0] - self.lights = self.createLights(data, lightsName) - - def createLights(self, data, lightsName): - numLights, lightValues = parseLightsData(data, lightsName, self) - ambientColor = gammaInverse([value / 255 for value in lightValues[0:3]]) - - lightList = [] - - for i in range(numLights): - color = gammaInverse([value / 255 for value in lightValues[3 + 6*i : 3 + 6*i + 3]]) - direction = bytesToNormal(lightValues[3 + 6*i + 3 : 3 + 6*i + 6]) - lightList.append(Light(color, direction)) - - while len(lightList) < 7: - lightList.append(Light([0,0,0],[0x28, 0x28, 0x28])) - - # normally a and l are Ambient and Light objects, - # but here they will be a color and blender light object array. - lights = Lights(lightsName) - lights.a = Ambient(ambientColor) - lights.l = lightList - - return lights - - def getTileIndex(self, value): - if value == "G_TX_RENDERTILE": - return self.f3d.G_TX_RENDERTILE - elif value == "G_TX_LOADTILE": - return self.f3d.G_TX_LOADTILE - else: - return math_eval(value, self.f3d) - - def getTileSettings(self, value): - return self.tileSettings[self.getTileIndex(value)] - - def getTileSizeSettings(self, value): - return self.tileSizes[self.getTileIndex(value)] - - def setTileSize(self, params): - mat = self.mat() - tileSizeSettings = self.getTileSizeSettings(params[0]) - tileSettings = self.getTileSettings(params[0]) - - dimensions = [0,0,0,0] - for i in range(1,5): - #match = None - #if not isinstance(params[i], int): - # match = re.search("\(([0-9]+)\s*\-\s*1\s*\)\s*<<\s*G\_TEXTURE\_IMAGE\_FRAC", params[i]) - #if match is not None: - # dimensions[i - 1] = (math_eval(match.group(1), self.f3d) - 1) << self.f3d.G_TEXTURE_IMAGE_FRAC - #else: - # dimensions[i - 1] = math_eval(params[i], self.f3d) - dimensions[i - 1] = math_eval(params[i], self.f3d) - - tileSizeSettings.uls = dimensions[0] - tileSizeSettings.ult = dimensions[1] - tileSizeSettings.lrs = dimensions[2] - tileSizeSettings.lrt = dimensions[3] - - def setTile(self, params, dlData): - tileIndex = self.getTileIndex(params[4]) - tileSettings = self.getTileSettings(params[4]) - tileSettings.fmt = getTileFormat(params[0], self.f3d) - tileSettings.siz = getTileSize(params[1], self.f3d) - tileSettings.line = math_eval(params[2], self.f3d) - tileSettings.tmem = math_eval(params[3], self.f3d) - tileSettings.palette = math_eval(params[5], self.f3d) - tileSettings.cmt = getTileClampMirror(params[6], self.f3d) - tileSettings.maskt = getTileMask(params[7], self.f3d) - tileSettings.shifts = getTileShift(params[8], self.f3d) - tileSettings.cms = getTileClampMirror(params[9], self.f3d) - tileSettings.masks = getTileMask(params[10], self.f3d) - tileSettings.shifts = getTileShift(params[11], self.f3d) - - tileSizeSettings = self.getTileSizeSettings(params[4]) - - def loadTile(self, params): - tileSettings = self.getTileSettings(params[0]) - # TODO: Region parsing too hard? - #region = [ - # math_eval(params[1], self.f3d) / 4, - # math_eval(params[2], self.f3d) / 4, - # math_eval(params[3], self.f3d) / 4, - # math_eval(params[4], self.f3d) / 4 - #] - region = None - - # Defer texture parsing until next set tile. - self.tmemDict[tileSettings.tmem] = self.currentTextureName - self.materialChanged = True - - def loadMultiBlock(self, params, dlData, is4bit): - width = math_eval(params[5], self.f3d) - height = math_eval(params[6], self.f3d) - siz = params[4] - line = ((width * self.getSizeMacro(siz, "_LINE_BYTES")) + 7) >> 3 if not is4bit else\ - ((width >> 1) + 7) >> 3 - tmem = params[1] - tile = params[2] - loadBlockSiz = self.getSizeMacro(siz, "_LOAD_BLOCK") if not is4bit else self.f3d.G_IM_SIZ_16b - self.currentTextureName = params[0] - self.setTile([params[3], loadBlockSiz, 0, tmem, "G_TX_LOADTILE", 0, - params[9], params[11], params[13], params[8], params[10], params[12], - ], dlData) - # TODO: Region is ignored for now - self.loadTile(["G_TX_LOADTILE", 0, 0, 0, 0]) - self.setTile([params[3], params[4], line, tmem, tile, 0, - params[9], params[11], params[13], params[8], params[10], params[12], - ], dlData) - self.setTileSize([tile, 0, 0, - (width - 1) << self.f3d.G_TEXTURE_IMAGE_FRAC, - (height - 1) << self.f3d.G_TEXTURE_IMAGE_FRAC]) - - def loadTLUTPal(self, name, dlData, count): - # TODO: Doesn't handle loading palettes into not tmem 256 - self.currentTextureName = name - self.setTile([0,0,0, 256, "G_TX_LOADTILE", 0,0,0,0,0,0,0], dlData) - self.loadTLUT(["G_TX_LOADTILE", count], dlData) - - def applyTileToMaterial(self, index, tileSettings, tileSizeSettings): - mat = self.mat() - - texProp = getattr(mat, "tex" + str(index)) - - name = self.tmemDict[tileSettings.tmem] - image = self.textureData[name] - if isinstance(image, F3DTextureReference): - texProp.tex = None - texProp.use_tex_reference = True - texProp.tex_reference = name - size = texProp.tex_reference_size - else: - texProp.tex = image - texProp.use_tex_reference = False - size = texProp.tex.size - texProp.tex_set = True - - # TODO: Handle low/high for image files? - if texProp.use_tex_reference: - #texProp.autoprop = False - #texProp.S.low = round(tileSizeSettings.uls / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) - #texProp.T.low = round(tileSizeSettings.ult / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) - #texProp.S.high = round(tileSizeSettings.lrs / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) - #texProp.T.high = round(tileSizeSettings.lrt / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) - - # WARNING: Inferring texture size from tile size. - texProp.tex_reference_size = [ - int(round(tileSizeSettings.lrs / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC) + 1)), - int(round(tileSizeSettings.lrt / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC) + 1))] - - #if texProp.S.low == 0 and texProp.T.low == 0 and \ - # texProp.S.high == size[0] - 1 and \ - # (texProp.use_tex_reference or texProp.T.high == size[1] - 1): - # texProp.autoProp = True - #else: - # print(str(texProp.S.low) + " " + str(texProp.T.low) + " " + str(texProp.S.high) + " " + str(texProp.T.high)) - # print(str(size[0]-1) + " " + str(size[1]-1)) - - texProp.tex_format = tileSettings.fmt[8:].replace("_", "") + tileSettings.siz[8:-1].replace("_", "") - - texProp.S.clamp = tileSettings.cms[0] - texProp.S.mirror = tileSettings.cms[1] - - texProp.T.clamp = tileSettings.cmt[0] - texProp.T.mirror = tileSettings.cmt[1] - - # TODO: Handle S and T properties - - # Override this to handle game specific references. - def handleTextureName(self, textureName): - return textureName - - def loadTexture(self, data, name, region, tileSettings, isLUT): - textureName = self.handleTextureName(name) - - if textureName in self.textureData: - return self.textureData[textureName] - - # region ignored? - if isLUT: - siz = "G_IM_SIZ_16b" - width = 16 - else: - siz = tileSettings.siz - if siz == "G_IM_SIZ_4b": - width = (tileSettings.line * 8) * 2 - else: - width = int(ceil((tileSettings.line * 8) / self.f3d.G_IM_SIZ_VARS[siz + '_LINE_BYTES'])) - - # TODO: Textures are sometimes loaded in with different dimensions than for rendering. - # This means width is incorrect? - image = parseTextureData(data, textureName, self, tileSettings.fmt, siz, width, self.basePath, isLUT, self.f3d) - - self.textureData[textureName] = image - return self.textureData[textureName] - - def loadTLUT(self, params, dlData): - tileSettings = self.getTileSettings(params[0]) - name = self.currentTextureName - textureName = self.handleTextureName(name) - self.tmemDict[tileSettings.tmem] = textureName - - tlut = self.loadTexture(dlData, textureName, [0,0, 16, 16], tileSettings, True) - self.materialChanged = True - - def applyTLUT(self, image, tlut): - for i in range(int(len(image.pixels) / 4)): - lutIndex = int(round(image.pixels[4*i] * 255)) - newValues = tlut.pixels[4 * lutIndex : 4 * (lutIndex + 1)] - if len(newValues) < 4: - print("Invalid lutIndex " + str(lutIndex)) - else: - image.pixels[4*i : 4*(i+1)] = newValues - - def processCommands(self, dlData, dlName, dlCommands): - callStack = [F3DParsedCommands(dlName, dlCommands, 0)] - while len(callStack) > 0: - currentCommandList = callStack[-1] - command = currentCommandList.currentCommand() - - if currentCommandList.index >= len(currentCommandList.commands): - raise PluginError("Cannot handle unterminated static display lists: " + currentCommandList.name) - elif len(callStack) > 2**16: - raise PluginError("DL call stack larger than 2**16, assuming infinite loop: " + currentCommandList.name) - - #print(command.name + " " + str(command.params)) - if command.name == 'gsSPVertex': - vertexDataName, vertexDataOffset = getVertexDataStart(command.params[0], self.f3d) - parseVertexData(dlData, vertexDataName, self) - self.addVertices(command.params[1], command.params[2], vertexDataName, vertexDataOffset) - elif command.name == 'gsSPMatrix': - self.setCurrentTransform(command.params[0]) - elif command.name == 'gsSPPopMatrix': - print("gsSPPopMatrix not handled.") - elif command.name == 'gsSP1Triangle': - self.addTriangle(command.params[0:3], dlData) - elif command.name == 'gsSP2Triangles': - self.addTriangle(command.params[0:3] + command.params[4:7], dlData) - elif command.name == 'gsSPDisplayList' or command.name[:10] == 'gsSPBranch': - newDLName = self.processDLName(command.params[0]) - if newDLName is not None: - newDLCommands = parseDLData(dlData, newDLName) - # Use -1 index so that it will be incremented to 0 at end of loop - parsedCommands = F3DParsedCommands(newDLName, newDLCommands, -1) - if command.name == 'gsSPDisplayList': - callStack.append(parsedCommands) - elif command.name[:10] == 'gsSPBranch': # TODO: Handle BranchZ? - callStack = callStack[:-1] - callStack.append(parsedCommands) - elif command.name == 'gsSPEndDisplayList': - callStack = callStack[:-1] - - # Material Specific Commands - prevMaterialChangedStatus = self.materialChanged - self.materialChanged = True - - # Should we parse commands into f3d_gbi classes? - # No, because some parsing involves reading C files, which is separate. - - # Assumes macros use variable names instead of values - mat = self.mat() - try: - if command.name == 'gsSPClipRatio': - mat.clip_ratio = math_eval(command.params[0], self.f3d) - elif command.name == 'gsSPNumLights': - self.numLights = self.getLightCount(command.name[1]) - elif command.name == 'gsSPLight': - self.setLight(dlData, command) - elif command.name == 'gsSPLightColor': - self.setLightColor(dlData, command) - elif command.name[:13] == 'gsSPSetLights': - self.setLights(dlData, command) - elif command.name == 'gsSPFogFactor': - pass - elif command.name == 'gsSPFogPosition': - mat.fog_position = [math_eval(command.params[0], self.f3d), math_eval(command.params[1], self.f3d)] - mat.set_fog = True - elif command.name == 'gsSPTexture' or command.name == 'gsSPTextureL': - mat.tex_scale = [math_eval(command.params[0], self.f3d) / (2**16), math_eval(command.params[1], self.f3d) / (2**16)] - elif command.name == 'gsSPSetGeometryMode': - self.setGeoFlags(command, True) - elif command.name == 'gsSPClearGeometryMode': - self.setGeoFlags(command, False) - elif command.name == 'gsSPLoadGeometryMode': - self.loadGeoFlags(command) - elif command.name == 'gsSPSetOtherMode': - self.setOtherModeFlags(command) - elif command.name == 'gsDPPipelineMode': - mat.rdp_settings.g_mdsft_pipeline = command.params[0] - elif command.name == 'gsDPSetCycleType': - mat.rdp_settings.g_mdsft_cycletype = command.params[0] - elif command.name == 'gsDPSetTexturePersp': - mat.rdp_settings.g_mdsft_textpersp = command.params[0] - elif command.name == 'gsDPSetTextureDetail': - mat.rdp_settings.g_mdsft_textdetail = command.params[0] - elif command.name == 'gsDPSetTextureLOD': - mat.rdp_settings.g_mdsft_textlod = command.params[0] - elif command.name == 'gsDPSetTextureLUT': - self.setTLUTMode(0, command.params[0]) - self.setTLUTMode(1, command.params[0]) - elif command.name == 'gsDPSetTextureFilter': - mat.rdp_settings.g_mdsft_text_filt = command.params[0] - elif command.name == 'gsDPSetTextureConvert': - mat.rdp_settings.g_mdsft_textconv = command.params[0] - elif command.name == 'gsDPSetCombineKey': - mat.rdp_settings.g_mdsft_combkey = command.params[0] - elif command.name == 'gsDPSetColorDither': - mat.rdp_settings.g_mdsft_color_dither = command.params[0] - elif command.name == 'gsDPSetAlphaDither': - mat.rdp_settings.g_mdsft_alpha_dither = command.params[0] - elif command.name == 'gsDPSetAlphaCompare': - mat.rdp_settings.g_mdsft_alpha_compare = command.params[0] - elif command.name == 'gsDPSetDepthSource': - mat.rdp_settings.g_mdsft_zsrcsel = command.params[0] - elif command.name == 'gsDPSetRenderMode': - flags = math_eval(command.params[0] + " | " + command.params[1], self.f3d) - self.setRenderMode(flags) - elif command.name == 'gsDPSetTextureImage': - # Are other params necessary? - # The params are set in SetTile commands. - self.currentTextureName = command.params[3] - elif command.name == 'gsDPSetCombineMode': - self.setCombineMode(command) - elif command.name == 'gsDPSetCombineLERP': - self.setCombineLerp(command.params[0:8], command.params[8:16]) - elif command.name == 'gsDPSetEnvColor': - mat.env_color = self.gammaInverseParam(command.params) - mat.set_env = True - elif command.name == 'gsDPSetBlendColor': - mat.blend_color = self.gammaInverseParam(command.params) - mat.set_blend = True - elif command.name == 'gsDPSetFogColor': - mat.fog_color = self.gammaInverseParam(command.params) - mat.set_fog = True - elif command.name == 'gsDPSetFillColor': - pass - elif command.name == 'gsDPSetPrimDepth': - pass - elif command.name == 'gsDPSetPrimColor': - mat.prim_lod_min = math_eval(command.params[0], self.f3d) / 255 - mat.prim_lod_frac = math_eval(command.params[1], self.f3d) / 255 - mat.prim_color = self.gammaInverseParam(command.params[2:6]) - mat.set_prim = True - elif command.name == 'gsDPSetOtherMode': - print("gsDPSetOtherMode not handled.") - elif command.name == 'DPSetConvert': - mat.set_k0_5 = True - for i in range(6): - setattr(mat, 'k' + str(i), gammaInverseValue(math_eval(command.params[i], self.f3d) / 255)) - elif command.name == 'DPSetKeyR': - mat.set_key = True - elif command.name == 'DPSetKeyGB': - mat.set_key = True - else: - self.materialChanged = prevMaterialChangedStatus - - # Texture Commands - # Assume file texture load - # SetTextureImage -> Load command -> Set Tile (0 or 1) - - if command.name == 'gsDPSetTileSize': - self.setTileSize(command.params) - elif command.name == 'gsDPLoadTile': - self.loadTile(command.params) - elif command.name == 'gsDPSetTile': - self.setTile(command.params, dlData) - elif command.name == 'gsDPLoadBlock': - self.loadTile(command.params) - elif command.name == 'gsDPLoadTLUTCmd': - self.loadTLUT(command.params, dlData) - - # This all ignores S/T high/low values - # This is pretty bad/confusing - elif command.name[:len("gsDPLoadTextureBlock")] == 'gsDPLoadTextureBlock': - is4bit = '4b' in command.name - if is4bit: - self.loadMultiBlock([command.params[0]] + [0, "G_TX_RENDERTILE"] + \ - [command.params[1], "G_IM_SIZ_4b"] + command.params[2:], dlData, True) - else: - self.loadMultiBlock([command.params[0]] + [0, "G_TX_RENDERTILE"] + \ - command.params[1:], dlData, False) - elif command.name[:len("gsDPLoadMultiBlock")] == 'gsDPLoadMultiBlock': - is4bit = '4b' in command.name - if is4bit: - self.loadMultiBlock(command.params[:4] + ["G_IM_SIZ_4b"] + command.params[4:], dlData, True) - else: - self.loadMultiBlock(command.params, dlData, False) - elif command.name[:len("gsDPLoadTextureTile")] == 'gsDPLoadTextureTile': - is4bit = '4b' in command.name - if is4bit: - self.loadMultiBlock([command.params[0]] + [0, "G_TX_RENDERTILE"] +\ - [command.params[1], "G_IM_SIZ_4b"] + command.params[2:4] + \ - command.params[9:], '4b', dlData, True) - else: - self.loadMultiBlock([command.params[0]] + [0, "G_TX_RENDERTILE"] +\ - command.params[1:5] + command.params[9:], '4b', dlData, False) - elif command.name[:len("gsDPLoadMultiTile")] == 'gsDPLoadMultiTile': - is4bit = '4b' in command.name - if is4bit: - self.loadMultiBlock(command.params[:4] + ["G_IM_SIZ_4b"] + command.params[4:6] +\ - command.params[10:], dlData, True) - else: - self.loadMultiBlock(command.params[:7] + command.params[11:], dlData, False) - - # TODO: Only handles palettes at tmem = 256 - elif command.name == "gsDPLoadTLUT_pal16": - self.loadTLUTPal(command.params[1], dlData, 15) - elif command.name == "gsDPLoadTLUT_pal256": - self.loadTLUTPal(command.params[0], dlData, 255) - else: - pass - - except TypeError as e: - print(traceback.format_exc()) - #raise Exception(e) - #print(e) - - # Don't use currentCommandList because some commands may change that - if len(callStack) > 0: - callStack[-1].index += 1 - - # override this to handle game specific DL calls. - # return None to indicate DL call should be skipped. - def processDLName(self, name): - return name - - def createMesh(self, obj, removeDoubles, importNormals): - mesh = obj.data - if len(self.verts) % 3 != 0: - print(len(self.verts)) - raise PluginError("Number of verts in mesh not divisible by 3, currently " + str(len(self.verts))) - - triangleCount = int(len(self.verts) / 3) - verts = [f3dVert[0] for f3dVert in self.verts] - faces = [[3 * i + j for j in range(3)] for i in range(triangleCount)] - print("Vertices: " + str(len(self.verts)) + ", Triangles: " + str(triangleCount)) - - mesh.from_pydata(vertices = verts, edges = [], faces = faces) - uv_layer = mesh.uv_layers.new().data - #if self.materialContext.f3d_mat.rdp_settings.g_lighting: - color_layer = mesh.vertex_colors.new(name = "Col").data - alpha_layer = mesh.vertex_colors.new(name = "Alpha").data - #else: - - if importNormals: - mesh.use_auto_smooth = True - mesh.normals_split_custom_set([f3dVert[3] for f3dVert in self.verts]) - - for groupName, indices in self.limbGroups.items(): - group = obj.vertex_groups.new(name = self.limbToBoneName[groupName]) - group.add(indices, 1, "REPLACE") - - for i in range(len(mesh.polygons)): - mesh.polygons[i].material_index = self.triMatIndices[i] - - for i in range(len(mesh.loops)): - # This should be okay, since we aren't trying to optimize vertices - # There will be one loop for every vertex - uv_layer[i].uv = self.verts[i][1] - - #if self.materialContext.f3d_mat.rdp_settings.g_lighting: - color_layer[i].color = self.verts[i][2] - alpha_layer[i].color = [self.verts[i][2][3]] * 3 + [1] - - if bpy.context.mode != "OBJECT": - bpy.ops.object.mode_set(mode = "OBJECT") - bpy.ops.object.select_all(action = "DESELECT") - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - - for material in self.materials: - obj.data.materials.append(material) - if not importNormals: - bpy.ops.object.shade_smooth() - if removeDoubles: - bpy.ops.object.mode_set(mode = "EDIT") - bpy.ops.mesh.select_all(action = "SELECT") - bpy.ops.mesh.remove_doubles() - bpy.ops.object.mode_set(mode = "OBJECT") - - bpy.data.materials.remove(self.materialContext) - - obj.location = bpy.context.scene.cursor.location - - i = 0 - for key, lightObj in self.lightData.items(): - lightObj.location = bpy.context.scene.cursor.location + mathutils.Vector((i,0,0)) - i += 1 + def __init__(self, f3d, basePath, materialContext): + self.f3d = f3d + self.vertexBuffer = [None] * f3d.vert_load_size + self.basePath = basePath + self.materialContext = materialContext + + self.clearMaterial() + mat = self.mat() + mat.set_combiner = False + + self.materials = [] # saved materials + self.triMatIndices = [] # material indices per triangle + self.materialChanged = True + self.lastMaterialIndex = None + + self.vertexData = {} # c name : parsed data + self.textureData = {} # c name : blender texture + + self.tlutAppliedTextures = [] # c name + self.currentTextureName = None + + # This macro has all the tile setting properties, so we reuse it + self.tileSettings = [ + DPSetTile("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 5, 0, i, 0, [False, False], 0, 0, [False, False], 0, 0) + for i in range(8) + ] + self.tileSizes = [DPSetTileSize(i, 0, 0, 32, 32) for i in range(8)] + + # When a tile is loaded, store dict of tmem : texture + self.tmemDict = {} + + # This should be modified before parsing f3d + self.matrixData = {} # bone name : matrix + self.currentTransformName = None + self.limbToBoneName = {} # limb name (c variable) : bone name (blender vertex group) + + # data for Mesh.from_pydata, list of BufferVertex tuples + # use BufferVertex to also form uvs / normals / colors + self.verts = [] + self.limbGroups = {} # dict of groupName : vertex indices + + self.lights = Lights("lights_context") + self.lights.l = [ + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + ] + self.lights.a = Ambient([0, 0, 0]) + self.numLights = 0 + self.lightData = {} # (color, normal) : list of blender light objects + + # MAKE SURE TO CALL THIS BETWEEN parseF3D() CALLS + def clearMaterial(self): + mat = self.mat() + + mat.rdp_settings.sets_rendermode = False + mat.set_prim = False + mat.set_lights = False + mat.set_env = False + mat.set_blend = False + mat.set_key = False + mat.set_k0_5 = False + + mat.prim_color = [1, 1, 1, 1] + mat.env_color = [1, 1, 1, 1] + mat.blend_color = [1, 1, 1, 1] + for i in range(1, 8): + setattr(mat, "f3d_light" + str(i), None) + mat.tex0.tex = None + mat.tex1.tex = None + mat.tex0.tex_set = False + mat.tex1.tex_set = False + + mat.tex0.tex_format = "RGBA16" + mat.tex1.tex_format = "RGBA16" + + self.tmemDict = {} + + self.tileSettings = [ + DPSetTile("G_IM_FMT_RGBA", "G_IM_SIZ_16b", 5, 0, i, 0, [False, False], 0, 0, [False, False], 0, 0) + for i in range(8) + ] + + self.tileSizes = [DPSetTileSize(i, 0, 0, 32, 32) for i in range(8)] + + self.lights = Lights("lights_context") + self.lights.l = [ + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + Light([0, 0, 0], [0x28, 0x28, 0x28]), + ] + self.lights.a = Ambient([0, 0, 0]) + self.numLights = 0 + + mat.presetName = "Custom" + + def mat(self): + return self.materialContext.f3d_mat + + def vertexFormatPatterns(self, data): + # position, uv, color/normal + return [ + # decomp format + "\{\s*\{\s*" + + "\{([^,\}]*),([^,\}]*),([^,\}]*)\}\s*," + + "[^,\}]*,\s*" + + "\{([^,\}]*),([^,\}]*)\}\s*,\s*" + + "\{([^,\}]*),([^,\}]*),([^,\}]*),([^,\}]*)\}\s*" + + "\}\s*\}", + # nusys format + "\{\s*" + + "([^,\}]*),([^,\}]*),([^,\}]*)," + + "[^,\}]*," + + "([^,\}]*),([^,\}]*)," + + "([^,\}]*),([^,\}]*),([^,\}]*),([^,\}]*)\s*" + + "\}", + ] + + # For game specific instance, override this to be able to identify which verts belong to which bone. + def setCurrentTransform(self, name): + self.currentTransformName = name + + def getTransformedVertex(self, index): + bufferVert = self.vertexBuffer[index] + + # NOTE: The groupIndex here does NOT correspond to a vertex group, but to the name of the limb (c variable) + matrixName = bufferVert.groupIndex + if matrixName in self.matrixData: + transform = self.matrixData[matrixName] + else: + print(self.matrixData) + raise PluginError("Transform matrix not specified for " + matrixName) + + mat = self.mat() + f3dVert = bufferVert.f3dVert + position = transform @ mathutils.Vector(f3dVert[0]) + if mat.tex0.tex is not None: + uv = [convertF3DUV(f3dVert[1][i], mat.tex0.tex.size[i]) for i in range(2)] + # uv = [1 - (f3dVert[1][i] / (self.materialContext.f3d_mat.tex0.tex.size[i] * 32)) for i in range(2)] + # uv = [((f3dVert[1][i] / 32) + 0.5) / mat.tex0.tex.size[i] for i in range(2)] + else: + uv = [convertF3DUV(f3dVert[1][i], 32) for i in range(2)] + # uv = [1 - (f3dVert[1][i] / (32 * 32)) for i in range(2)] + # uv = [((f3dVert[1][i] / 32) + 0.5) / 32 for i in range(2)] + uv[1] = 1 - uv[1] + + color = [ + value / 256 + if value > 0 + else int.from_bytes(value.to_bytes(1, "big", signed=True), "big", signed=False) / 256 + for value in f3dVert[2] + ] + + normal = bytesToNormal(f3dVert[2][:3]) + [0] + normal = (transform.inverted().transposed() @ mathutils.Vector(normal)).normalized()[:3] + + # This is not usual format of f3dVert, but we need separate color/normal data. + # NOTE: The groupIndex here does NOT correspond to a vertex group, but to the name of the limb (c variable) + return BufferVertex([position, uv, color, normal], bufferVert.groupIndex, bufferVert.materialIndex) + + def addVertices(self, num, start, vertexDataName, vertexDataOffset): + vertexData = self.vertexData[vertexDataName] + + # TODO: material index not important? + count = math_eval(num, self.f3d) + start = math_eval(start, self.f3d) + + if start + count > len(self.vertexBuffer): + raise PluginError( + "Vertex buffer of size " + + len(self.vertexBuffer) + + " too small, attempting load into " + + str(start) + + ", " + + str(start + count) + ) + for i in range(count): + self.vertexBuffer[start + i] = BufferVertex(vertexData[vertexDataOffset + i], self.currentTransformName, 0) + + def addTriangle(self, indices, dlData): + if self.materialChanged: + mat = self.mat() + region = None + + tileSettings = self.tileSettings[0] + tileSizeSettings = self.tileSizes[0] + if tileSettings.tmem in self.tmemDict: + textureName = self.tmemDict[tileSettings.tmem] + self.loadTexture(dlData, textureName, region, tileSettings, False) + self.applyTileToMaterial(0, tileSettings, tileSizeSettings) + + tileSettings = self.tileSettings[1] + tileSizeSettings = self.tileSizes[1] + if tileSettings.tmem in self.tmemDict: + textureName = self.tmemDict[tileSettings.tmem] + self.loadTexture(dlData, textureName, region, tileSettings, False) + self.applyTileToMaterial(1, tileSettings, tileSizeSettings) + + self.applyLights() + + self.lastMaterialIndex = self.getMaterialIndex() + self.materialChanged = False + + verts = [self.getTransformedVertex(math_eval(index, self.f3d)) for index in indices] + # if verts[0].groupIndex != verts[1].groupIndex or\ + # verts[0].groupIndex != verts[2].groupIndex or\ + # verts[2].groupIndex != verts[1].groupIndex: + # return + for i in range(len(verts)): + vert = verts[i] + + # NOTE: The groupIndex here does NOT correspond to a vertex group, but to the name of the limb (c variable) + if vert.groupIndex not in self.limbGroups: + self.limbGroups[vert.groupIndex] = [] + self.limbGroups[vert.groupIndex].append(len(self.verts) + i) + self.verts.extend([vert.f3dVert for vert in verts]) + + for i in range(int(len(indices) / 3)): + self.triMatIndices.append(self.lastMaterialIndex) + + def getMaterialIndex(self): + # We do this for now to update tile settings for S and T. + # Right now we don't handle those, so we need the auto-calculator to set it correctly. + overrideContext = bpy.context.copy() + overrideContext["material"] = self.materialContext + bpy.ops.material.update_f3d_nodes(overrideContext) + + for material in self.materials: + if propertyGroupEquals(self.materialContext.f3d_mat, material.f3d_mat): + return self.materials.index(material) + + self.addMaterial() + return len(self.materials) - 1 + + def getImageName(self, image): + for name, otherImage in self.textureData.items(): + if image == otherImage: + return name + return None + + def applyTLUTToIndex(self, index): + mat = self.mat() + texProp = getattr(mat, "tex" + str(index)) + combinerUses = all_combiner_uses(mat) + if ( + combinerUses["Texture " + str(index)] + and (texProp.tex is not None or texProp.use_tex_reference) + and texProp.tex_set + and texProp.tex_format[:2] == "CI" + and (texProp.tex not in self.tlutAppliedTextures or texProp.use_tex_reference) + ): + + # Only handles TLUT at 256 + tlutName = self.tmemDict[256] + if 256 in self.tmemDict and tlutName is not None: + tlut = self.textureData[tlutName] + if isinstance(tlut, F3DTextureReference) or texProp.use_tex_reference: + if not texProp.use_tex_reference: + texProp.use_tex_reference = True + imageName = self.getImageName(texProp.tex) + if imageName is not None: + texProp.tex_reference = imageName + else: + print("Cannot find name of texture " + str(texProp.tex)) + + if isinstance(tlut, F3DTextureReference): + texProp.pal_reference = tlut.name + texProp.pal_reference_size = tlut.width + else: + texProp.pal_reference = tlutName + texProp.pal_reference_size = min(tlut.size[0] * tlut.size[1], 256) + + else: + self.applyTLUT(texProp.tex, tlut) + self.tlutAppliedTextures.append(texProp.tex) + else: + print("Ignoring TLUT.") + + def postMaterialChanged(self): + return + + def addMaterial(self): + mat = self.mat() + combinerUses = all_combiner_uses(self.mat()) + self.applyTLUTToIndex(0) + self.applyTLUTToIndex(1) + + material = self.materialContext.copy() + overrideContext = bpy.context.copy() + overrideContext["material"] = material + bpy.ops.material.update_f3d_nodes(overrideContext) + self.materials.append(material) + self.materialChanged = False + + self.postMaterialChanged() + + def getSizeMacro(self, size, suffix): + if hasattr(self.f3d, size): + return getattr(self.f3d, size + suffix) + else: + return getattr(self.f3d, self.f3d.IM_SIZ[size] + suffix) + + def getImagePathFromInclude(self, path): + if self.basePath is None: + raise PluginError("Cannot load texture from " + path + " without any provided base path.") + + imagePath = path[:-5] + "png" + return os.path.join(self.basePath, imagePath) + + def getVTXPathFromInclude(self, path): + if self.basePath is None: + raise PluginError("Cannot load VTX from " + path + " without any provided base path.") + return os.path.join(self.basePath, path) + + def setGeoFlags(self, command, value): + mat = self.mat() + bitFlags = math_eval(command.params[0], self.f3d) + + if bitFlags & self.f3d.G_ZBUFFER: + mat.rdp_settings.g_zbuffer = value + if bitFlags & self.f3d.G_SHADE: + mat.rdp_settings.g_shade = value + if bitFlags & self.f3d.G_CULL_FRONT: + mat.rdp_settings.g_cull_front = value + if bitFlags & self.f3d.G_CULL_BACK: + mat.rdp_settings.g_cull_back = value + if bitFlags & self.f3d.G_FOG: + mat.rdp_settings.g_fog = value + if bitFlags & self.f3d.G_LIGHTING: + mat.rdp_settings.g_lighting = value + if bitFlags & self.f3d.G_TEXTURE_GEN: + mat.rdp_settings.g_tex_gen = value + if bitFlags & self.f3d.G_TEXTURE_GEN_LINEAR: + mat.rdp_settings.g_tex_gen_linear = value + if bitFlags & self.f3d.G_SHADING_SMOOTH: + mat.rdp_settings.g_shade_smooth = value + if bitFlags & self.f3d.G_CLIPPING: + mat.rdp_settings.g_clipping = value + + def loadGeoFlags(self, command): + mat = self.mat() + + bitFlags = math_eval(command.params[0], self.f3d) + + mat.rdp_settings.g_zbuffer = bitFlags & self.f3d.G_ZBUFFER != 0 + mat.rdp_settings.g_shade = bitFlags & self.f3d.G_SHADE != 0 + mat.rdp_settings.g_cull_front = bitFlags & self.f3d.G_CULL_FRONT != 0 + mat.rdp_settings.g_cull_back = bitFlags & self.f3d.G_CULL_BACK != 0 + mat.rdp_settings.g_fog = bitFlags & self.f3d.G_FOG != 0 + mat.rdp_settings.g_lighting = bitFlags & self.f3d.G_LIGHTING != 0 + mat.rdp_settings.g_tex_gen = bitFlags & self.f3d.G_TEXTURE_GEN != 0 + mat.rdp_settings.g_tex_gen_linear = bitFlags & self.f3d.G_TEXTURE_GEN_LINEAR != 0 + mat.rdp_settings.g_shade_smooth = bitFlags & self.f3d.G_SHADING_SMOOTH != 0 + mat.rdp_settings.g_clipping = bitFlags & self.f3d.G_CLIPPING != 0 + + def setCombineLerp(self, lerp0, lerp1): + mat = self.mat() + + if len(lerp0) < 8 or len(lerp1) < 8: + print("Incorrect combiner param count: " + str(lerp0) + " " + str(lerp1)) + return + + lerp0 = [value.strip() for value in lerp0] + lerp1 = [value.strip() for value in lerp1] + + # Padding since index can go up to 31 + combinerAList = ["COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", "1", "NOISE"] + ["0"] * 24 + combinerBList = ["COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", "CENTER", "K4"] + [ + "0" + ] * 24 + combinerCList = [ + "COMBINED", + "TEXEL0", + "TEXEL1", + "PRIMITIVE", + "SHADE", + "ENVIRONMENT", + "SCALE", + "COMBINED_ALPHA", + "TEXEL0_ALPHA", + "TEXEL1_ALPHA", + "PRIMITIVE_ALPHA", + "SHADE_ALPHA", + "ENV_ALPHA", + "LOD_FRACTION", + "PRIM_LOD_FRAC", + "K5", + ] + ["0"] * 16 + combinerDList = ["COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", "1", "0"] + ["0"] * 24 + + combinerAAlphaList = ["COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", "1", "0"] + combinerBAlphaList = ["COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", "1", "0"] + combinerCAlphaList = [ + "LOD_FRACTION", + "TEXEL0", + "TEXEL1", + "PRIMITIVE", + "SHADE", + "ENVIRONMENT", + "PRIM_LOD_FRAC", + "0", + ] + combinerDAlphaList = ["COMBINED", "TEXEL0", "TEXEL1", "PRIMITIVE", "SHADE", "ENVIRONMENT", "1", "0"] + + for i in range(0, 4): + lerp0[i] = math_eval("G_CCMUX_" + lerp0[i], self.f3d) + lerp1[i] = math_eval("G_CCMUX_" + lerp1[i], self.f3d) + + for i in range(4, 8): + lerp0[i] = math_eval("G_ACMUX_" + lerp0[i], self.f3d) + lerp1[i] = math_eval("G_ACMUX_" + lerp1[i], self.f3d) + + mat.set_combiner = True + mat.combiner1.A = combinerAList[lerp0[0]] + mat.combiner1.B = combinerBList[lerp0[1]] + mat.combiner1.C = combinerCList[lerp0[2]] + mat.combiner1.D = combinerDList[lerp0[3]] + mat.combiner1.A_alpha = combinerAAlphaList[lerp0[4]] + mat.combiner1.B_alpha = combinerBAlphaList[lerp0[5]] + mat.combiner1.C_alpha = combinerCAlphaList[lerp0[6]] + mat.combiner1.D_alpha = combinerDAlphaList[lerp0[7]] + + mat.combiner2.A = combinerAList[lerp1[0]] + mat.combiner2.B = combinerBList[lerp1[1]] + mat.combiner2.C = combinerCList[lerp1[2]] + mat.combiner2.D = combinerDList[lerp1[3]] + mat.combiner2.A_alpha = combinerAAlphaList[lerp1[4]] + mat.combiner2.B_alpha = combinerBAlphaList[lerp1[5]] + mat.combiner2.C_alpha = combinerCAlphaList[lerp1[6]] + mat.combiner2.D_alpha = combinerDAlphaList[lerp1[7]] + + def setCombineMode(self, command): + if not hasattr(self.f3d, command.params[0]) or not hasattr(self.f3d, command.params[1]): + print("Unhandled combiner mode: " + command.params[0] + ", " + command.params[1]) + return + lerp0 = getattr(self.f3d, command.params[0]) + lerp1 = getattr(self.f3d, command.params[1]) + + self.setCombineLerp(lerp0, lerp1) + + def setTLUTMode(self, index, value): + mat = self.mat() + texProp = getattr(mat, "tex" + str(index)) + bitData = math_eval(value, self.f3d) + if value == self.f3d.G_TT_NONE: + if texProp.tex_format[:2] == "CI": + texProp.tex_format = "RGBA16" + elif value == self.f3d.G_TT_IA16: + texProp.ci_format = "IA16" + else: + texProp.ci_format = "RGBA16" + + def setOtherModeFlags(self, command): + mat = self.mat() + mode = math_eval(command.params[0], self.f3d) + if mode == self.f3d.G_SETOTHERMODE_H: + self.setOtherModeFlagsH(command) + else: + self.setOtherModeFlagsL(command) + + def setOtherModeFlagsH(self, command): + + otherModeH = { + "G_MDSFT_ALPHADITHER": ["G_AD_PATTERN", "G_AD_NOTPATTERN", "G_AD_NOISE", "G_AD_DISABLE"], + "G_MDSFT_RGBDITHER": ["G_CD_MAGICSQ", "G_CD_BAYER", "NOISE"], + "G_MDSFT_COMBKEY": ["G_CK_NONE", "G_CK_KEY"], + "G_MDSFT_TEXTCONV": [ + "G_TC_CONV", + "G_TC_CONV", + "G_TC_CONV", + "G_TC_CONV", + "G_TC_CONV", + "G_TC_FILTCONV", + "G_TC_FILT", + ], + "G_MDSFT_TEXTFILT": ["G_TF_POINT", "G_TF_POINT", "G_TF_BILERP", "G_TF_AVERAGE"], + "G_MDSFT_TEXTLOD": ["G_TL_TILE", "G_TL_LOD"], + "G_MDSFT_TEXTDETAIL": ["G_TD_CLAMP", "G_TD_SHARPEN", "G_TD_DETAIL"], + "G_MDSFT_TEXTPERSP": ["G_TP_NONE", "G_TP_PERSP"], + "G_MDSFT_CYCLETYPE": ["G_CYC_1CYCLE", "G_CYC_2CYCLE", "G_CYC_COPY", "G_CYC_FILL"], + "G_MDSFT_COLORDITHER": ["G_CD_MAGICSQ", "G_CD_BAYER", "G_CD_NOISE"], + "G_MDSFT_PIPELINE": ["G_PM_NPRIMITIVE", "G_PM_1PRIMITIVE"], + } + mat = self.mat() + flags = math_eval(command.params[3], self.f3d) + shift = math_eval(command.params[1], self.f3d) + mask = math_eval(command.params[2], self.f3d) + + for field, fieldData in otherModeH.items(): + fieldShift = getattr(self.f3d, field) + if fieldShift >= shift and fieldShift < shift + mask: + setattr( + mat.rdp_settings, + field.lower(), + fieldData[(flags >> fieldShift) & ((1 << int(ceil(math.log(len(fieldData), 2)))) - 1)], + ) + + # This only handles commonly used render mode presets (with macros), + # and no render modes at all with raw bit data. + def setOtherModeFlagsL(self, command): + otherModeL = { + "G_MDSFT_ALPHACOMPARE": ["G_AC_NONE", "G_AC_THRESHOLD", "G_AC_THRESHOLD", "G_AC_DITHER"], + "G_MDSFT_ZSRCSEL": ["G_ZS_PIXEL", "G_ZS_PRIM"], + } + + mat = self.mat() + flags = math_eval(command.params[3], self.f3d) + shift = math_eval(command.params[1], self.f3d) + mask = math_eval(command.params[2], self.f3d) + + for field, fieldData in otherModeL.items(): + fieldShift = getattr(self.f3d, field) + if fieldShift >= shift and fieldShift < shift + mask: + setattr( + mat.rdp_settings, + field.lower(), + fieldData[(flags >> fieldShift) & ((1 << int(ceil(math.log(len(fieldData), 2)))) - 1)], + ) + + if self.f3d.G_MDSFT_RENDERMODE >= shift and self.f3d.G_MDSFT_RENDERMODE < shift + mask: + self.setRenderMode(flags) + + def setRenderMode(self, flags): + mat = self.mat() + rendermode1 = renderModeMask(flags, 1, False) + rendermode2 = renderModeMask(flags, 2, False) + + blend1 = renderModeMask(flags, 1, True) + + rendermodeName1 = None + rendermodeName2 = None + + # print("Render mode: " + hex(rendermode1) + ", " + hex(rendermode2)) + for name, value in vars(self.f3d).items(): + if name[:5] == "G_RM_": + # print(name + " " + hex(value)) + + if name in ["G_RM_FOG_SHADE_A", "G_RM_FOG_PRIM_A", "G_RM_PASS"]: + if blend1 == value: + rendermodeName1 = name + else: + if rendermode1 == value: + rendermodeName1 = name + if rendermode2 == value: + rendermodeName2 = name + if rendermodeName1 is not None and rendermodeName2 is not None: + break + + mat.rdp_settings.sets_rendermode = True + if rendermodeName1 is not None and rendermodeName2 is not None: + mat.rdp_settings.rendermode_advanced_enabled = False + mat.rdp_settings.rendermode_preset_cycle_1 = rendermodeName1 + mat.rdp_settings.rendermode_preset_cycle_2 = rendermodeName2 + else: + mat.rdp_settings.rendermode_advanced_enabled = True + + mat.rdp_settings.aa_en = rendermode1 & self.f3d.AA_EN != 0 + mat.rdp_settings.z_cmp = rendermode1 & self.f3d.Z_CMP != 0 + mat.rdp_settings.z_upd = rendermode1 & self.f3d.Z_UPD != 0 + mat.rdp_settings.im_rd = rendermode1 & self.f3d.IM_RD != 0 + mat.rdp_settings.clr_on_cvg = rendermode1 & self.f3d.CLR_ON_CVG != 0 + mat.rdp_settings.cvg_dst = self.f3d.cvgDstDict[rendermode1 & self.f3d.CVG_DST_SAVE] + mat.rdp_settings.zmode = self.f3d.zmodeDict[rendermode1 & self.f3d.ZMODE_DEC] + mat.rdp_settings.cvg_x_alpha = rendermode1 & self.f3d.CVG_X_ALPHA != 0 + mat.rdp_settings.alpha_cvg_sel = rendermode1 & self.f3d.ALPHA_CVG_SEL != 0 + mat.rdp_settings.force_bl = rendermode1 & self.f3d.FORCE_BL != 0 + + mat.rdp_settings.blend_p1 = self.f3d.blendColorDict[rendermode1 >> 30 & 3] + mat.rdp_settings.blend_a1 = self.f3d.blendAlphaDict[rendermode1 >> 26 & 3] + mat.rdp_settings.blend_m1 = self.f3d.blendColorDict[rendermode1 >> 22 & 3] + mat.rdp_settings.blend_b1 = self.f3d.blendMixDict[rendermode1 >> 18 & 3] + + mat.rdp_settings.blend_p2 = self.f3d.blendColorDict[rendermode2 >> 28 & 3] + mat.rdp_settings.blend_a2 = self.f3d.blendAlphaDict[rendermode2 >> 24 & 3] + mat.rdp_settings.blend_m2 = self.f3d.blendColorDict[rendermode2 >> 20 & 3] + mat.rdp_settings.blend_b2 = self.f3d.blendMixDict[rendermode2 >> 16 & 3] + + def gammaInverseParam(self, color): + return [gammaInverseValue(math_eval(value, self.f3d) / 255) for value in color[:3]] + [ + math_eval(color[3], self.f3d) / 255 + ] + + def getLightIndex(self, lightIndexString): + return math_eval(lightIndexString, self.f3d) if "LIGHT_" not in lightIndexString else int(lightIndexString[-1:]) + + def getLightCount(self, lightCountString): + return ( + math_eval(lightCountString, self.f3d) + if "NUMLIGHTS_" not in lightCountString + else int(lightCountString[-1:]) + ) + + def getLightObj(self, light): + lightKey = (tuple(light.color), tuple(light.normal)) + if lightKey not in self.lightData: + lightName = "Light" + bLight = bpy.data.lights.new(lightName, "SUN") + lightObj = bpy.data.objects.new(lightName, bLight) + + lightObj.rotation_euler = ( + mathutils.Euler((0, 0, math.pi)).to_quaternion() + @ ( + mathutils.Euler((math.pi / 2, 0, 0)).to_quaternion() @ mathutils.Vector(light.normal) + ).rotation_difference(mathutils.Vector((0, 0, 1))) + ).to_euler() + # lightObj.rotation_euler[0] *= 1 + bLight.color = light.color + + bpy.context.scene.collection.objects.link(lightObj) + self.lightData[lightKey] = lightObj + return self.lightData[lightKey] + + def applyLights(self): + mat = self.mat() + allCombinerUses = all_combiner_uses(mat) + if allCombinerUses["Shade"] and mat.rdp_settings.g_lighting and mat.set_lights: + mat.use_default_lighting = False + mat.ambient_light_color = self.lights.a.color + ([1] if len(self.lights.a.color) == 3 else []) + + for i in range(self.numLights): + lightObj = self.getLightObj(self.lights.l[i]) + setattr(mat, "f3d_light" + str(i + 1), lightObj.data) + + def setLightColor(self, data, command): + self.mat().set_lights = True + lightIndex = self.getLightIndex(command.params[0]) + colorData = math_eval(command.params[1], self.f3d) + color = [((colorData >> 24) & 0xFF) / 0xFF, ((colorData >> 16) & 0xFF) / 0xFF, ((colorData >> 8) & 0xFF) / 0xFF] + + if lightIndex != self.numLights + 1: + self.lights.l[lightIndex - 1].color = color + else: + self.lights.a.color = color + + # This is an assumption. + if self.numLights < lightIndex - 1: + self.numLights = lightIndex - 1 + + # Assumes that any SPLight references a Lights0-9n struct instead of specific Light structs. + def setLight(self, data, command): + mat = self.mat() + mat.set_lights = True + + lightReference = command.params[0] + lightIndex = self.getLightIndex(command.params[1]) + + match = re.search("([A-Za-z0-9\_]*)\.(l(\[([0-9])\])?)?(a)?", lightReference) + if match is None: + print( + "Could not handle parsing of light reference: " + + lightReference + + ". Currently only handling Lights0-9n structs (not Light)" + ) + return + + lightsName = match.group(1) + lights = self.createLights(data, lightsName) + + if match.group(2) is not None: + if match.group(3) is not None: + lightIndex = math_eval(match.group(4), self.f3d) + else: + lightIndex = 0 + + # This is done as an assumption, to handle models that have numLights set beforehand + if self.numLights < lightIndex + 1: + self.numLights = lightIndex + 1 + self.lights.l[lightIndex] = lights.l[lightIndex] + else: + self.lights.a = lights.a + + def setLights(self, data, command): + mat = self.mat() + self.mat().set_lights = True + + numLights = self.getLightCount(command.name[13]) + self.numLights = numLights + + lightsName = command.params[0] + self.lights = self.createLights(data, lightsName) + + def createLights(self, data, lightsName): + numLights, lightValues = parseLightsData(data, lightsName, self) + ambientColor = gammaInverse([value / 255 for value in lightValues[0:3]]) + + lightList = [] + + for i in range(numLights): + color = gammaInverse([value / 255 for value in lightValues[3 + 6 * i : 3 + 6 * i + 3]]) + direction = bytesToNormal(lightValues[3 + 6 * i + 3 : 3 + 6 * i + 6]) + lightList.append(Light(color, direction)) + + while len(lightList) < 7: + lightList.append(Light([0, 0, 0], [0x28, 0x28, 0x28])) + + # normally a and l are Ambient and Light objects, + # but here they will be a color and blender light object array. + lights = Lights(lightsName) + lights.a = Ambient(ambientColor) + lights.l = lightList + + return lights + + def getTileIndex(self, value): + if value == "G_TX_RENDERTILE": + return self.f3d.G_TX_RENDERTILE + elif value == "G_TX_LOADTILE": + return self.f3d.G_TX_LOADTILE + else: + return math_eval(value, self.f3d) + + def getTileSettings(self, value): + return self.tileSettings[self.getTileIndex(value)] + + def getTileSizeSettings(self, value): + return self.tileSizes[self.getTileIndex(value)] + + def setTileSize(self, params): + mat = self.mat() + tileSizeSettings = self.getTileSizeSettings(params[0]) + tileSettings = self.getTileSettings(params[0]) + + dimensions = [0, 0, 0, 0] + for i in range(1, 5): + # match = None + # if not isinstance(params[i], int): + # match = re.search("\(([0-9]+)\s*\-\s*1\s*\)\s*<<\s*G\_TEXTURE\_IMAGE\_FRAC", params[i]) + # if match is not None: + # dimensions[i - 1] = (math_eval(match.group(1), self.f3d) - 1) << self.f3d.G_TEXTURE_IMAGE_FRAC + # else: + # dimensions[i - 1] = math_eval(params[i], self.f3d) + dimensions[i - 1] = math_eval(params[i], self.f3d) + + tileSizeSettings.uls = dimensions[0] + tileSizeSettings.ult = dimensions[1] + tileSizeSettings.lrs = dimensions[2] + tileSizeSettings.lrt = dimensions[3] + + def setTile(self, params, dlData): + tileIndex = self.getTileIndex(params[4]) + tileSettings = self.getTileSettings(params[4]) + tileSettings.fmt = getTileFormat(params[0], self.f3d) + tileSettings.siz = getTileSize(params[1], self.f3d) + tileSettings.line = math_eval(params[2], self.f3d) + tileSettings.tmem = math_eval(params[3], self.f3d) + tileSettings.palette = math_eval(params[5], self.f3d) + tileSettings.cmt = getTileClampMirror(params[6], self.f3d) + tileSettings.maskt = getTileMask(params[7], self.f3d) + tileSettings.shifts = getTileShift(params[8], self.f3d) + tileSettings.cms = getTileClampMirror(params[9], self.f3d) + tileSettings.masks = getTileMask(params[10], self.f3d) + tileSettings.shifts = getTileShift(params[11], self.f3d) + + tileSizeSettings = self.getTileSizeSettings(params[4]) + + def loadTile(self, params): + tileSettings = self.getTileSettings(params[0]) + # TODO: Region parsing too hard? + # region = [ + # math_eval(params[1], self.f3d) / 4, + # math_eval(params[2], self.f3d) / 4, + # math_eval(params[3], self.f3d) / 4, + # math_eval(params[4], self.f3d) / 4 + # ] + region = None + + # Defer texture parsing until next set tile. + self.tmemDict[tileSettings.tmem] = self.currentTextureName + self.materialChanged = True + + def loadMultiBlock(self, params, dlData, is4bit): + width = math_eval(params[5], self.f3d) + height = math_eval(params[6], self.f3d) + siz = params[4] + line = ((width * self.getSizeMacro(siz, "_LINE_BYTES")) + 7) >> 3 if not is4bit else ((width >> 1) + 7) >> 3 + tmem = params[1] + tile = params[2] + loadBlockSiz = self.getSizeMacro(siz, "_LOAD_BLOCK") if not is4bit else self.f3d.G_IM_SIZ_16b + self.currentTextureName = params[0] + self.setTile( + [ + params[3], + loadBlockSiz, + 0, + tmem, + "G_TX_LOADTILE", + 0, + params[9], + params[11], + params[13], + params[8], + params[10], + params[12], + ], + dlData, + ) + # TODO: Region is ignored for now + self.loadTile(["G_TX_LOADTILE", 0, 0, 0, 0]) + self.setTile( + [ + params[3], + params[4], + line, + tmem, + tile, + 0, + params[9], + params[11], + params[13], + params[8], + params[10], + params[12], + ], + dlData, + ) + self.setTileSize( + [tile, 0, 0, (width - 1) << self.f3d.G_TEXTURE_IMAGE_FRAC, (height - 1) << self.f3d.G_TEXTURE_IMAGE_FRAC] + ) + + def loadTLUTPal(self, name, dlData, count): + # TODO: Doesn't handle loading palettes into not tmem 256 + self.currentTextureName = name + self.setTile([0, 0, 0, 256, "G_TX_LOADTILE", 0, 0, 0, 0, 0, 0, 0], dlData) + self.loadTLUT(["G_TX_LOADTILE", count], dlData) + + def applyTileToMaterial(self, index, tileSettings, tileSizeSettings): + mat = self.mat() + + texProp = getattr(mat, "tex" + str(index)) + + name = self.tmemDict[tileSettings.tmem] + image = self.textureData[name] + if isinstance(image, F3DTextureReference): + texProp.tex = None + texProp.use_tex_reference = True + texProp.tex_reference = name + size = texProp.tex_reference_size + else: + texProp.tex = image + texProp.use_tex_reference = False + size = texProp.tex.size + texProp.tex_set = True + + # TODO: Handle low/high for image files? + if texProp.use_tex_reference: + # texProp.autoprop = False + # texProp.S.low = round(tileSizeSettings.uls / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) + # texProp.T.low = round(tileSizeSettings.ult / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) + # texProp.S.high = round(tileSizeSettings.lrs / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) + # texProp.T.high = round(tileSizeSettings.lrt / (2 ** self.f3d.G_TEXTURE_IMAGE_FRAC), 3) + + # WARNING: Inferring texture size from tile size. + texProp.tex_reference_size = [ + int(round(tileSizeSettings.lrs / (2**self.f3d.G_TEXTURE_IMAGE_FRAC) + 1)), + int(round(tileSizeSettings.lrt / (2**self.f3d.G_TEXTURE_IMAGE_FRAC) + 1)), + ] + + # if texProp.S.low == 0 and texProp.T.low == 0 and \ + # texProp.S.high == size[0] - 1 and \ + # (texProp.use_tex_reference or texProp.T.high == size[1] - 1): + # texProp.autoProp = True + # else: + # print(str(texProp.S.low) + " " + str(texProp.T.low) + " " + str(texProp.S.high) + " " + str(texProp.T.high)) + # print(str(size[0]-1) + " " + str(size[1]-1)) + + texProp.tex_format = tileSettings.fmt[8:].replace("_", "") + tileSettings.siz[8:-1].replace("_", "") + + texProp.S.clamp = tileSettings.cms[0] + texProp.S.mirror = tileSettings.cms[1] + + texProp.T.clamp = tileSettings.cmt[0] + texProp.T.mirror = tileSettings.cmt[1] + + # TODO: Handle S and T properties + + # Override this to handle game specific references. + def handleTextureName(self, textureName): + return textureName + + def loadTexture(self, data, name, region, tileSettings, isLUT): + textureName = self.handleTextureName(name) + + if textureName in self.textureData: + return self.textureData[textureName] + + # region ignored? + if isLUT: + siz = "G_IM_SIZ_16b" + width = 16 + else: + siz = tileSettings.siz + if siz == "G_IM_SIZ_4b": + width = (tileSettings.line * 8) * 2 + else: + width = int(ceil((tileSettings.line * 8) / self.f3d.G_IM_SIZ_VARS[siz + "_LINE_BYTES"])) + + # TODO: Textures are sometimes loaded in with different dimensions than for rendering. + # This means width is incorrect? + image = parseTextureData(data, textureName, self, tileSettings.fmt, siz, width, self.basePath, isLUT, self.f3d) + + self.textureData[textureName] = image + return self.textureData[textureName] + + def loadTLUT(self, params, dlData): + tileSettings = self.getTileSettings(params[0]) + name = self.currentTextureName + textureName = self.handleTextureName(name) + self.tmemDict[tileSettings.tmem] = textureName + + tlut = self.loadTexture(dlData, textureName, [0, 0, 16, 16], tileSettings, True) + self.materialChanged = True + + def applyTLUT(self, image, tlut): + for i in range(int(len(image.pixels) / 4)): + lutIndex = int(round(image.pixels[4 * i] * 255)) + newValues = tlut.pixels[4 * lutIndex : 4 * (lutIndex + 1)] + if len(newValues) < 4: + print("Invalid lutIndex " + str(lutIndex)) + else: + image.pixels[4 * i : 4 * (i + 1)] = newValues + + def processCommands(self, dlData, dlName, dlCommands): + callStack = [F3DParsedCommands(dlName, dlCommands, 0)] + while len(callStack) > 0: + currentCommandList = callStack[-1] + command = currentCommandList.currentCommand() + + if currentCommandList.index >= len(currentCommandList.commands): + raise PluginError("Cannot handle unterminated static display lists: " + currentCommandList.name) + elif len(callStack) > 2**16: + raise PluginError("DL call stack larger than 2**16, assuming infinite loop: " + currentCommandList.name) + + # print(command.name + " " + str(command.params)) + if command.name == "gsSPVertex": + vertexDataName, vertexDataOffset = getVertexDataStart(command.params[0], self.f3d) + parseVertexData(dlData, vertexDataName, self) + self.addVertices(command.params[1], command.params[2], vertexDataName, vertexDataOffset) + elif command.name == "gsSPMatrix": + self.setCurrentTransform(command.params[0]) + elif command.name == "gsSPPopMatrix": + print("gsSPPopMatrix not handled.") + elif command.name == "gsSP1Triangle": + self.addTriangle(command.params[0:3], dlData) + elif command.name == "gsSP2Triangles": + self.addTriangle(command.params[0:3] + command.params[4:7], dlData) + elif command.name == "gsSPDisplayList" or command.name[:10] == "gsSPBranch": + newDLName = self.processDLName(command.params[0]) + if newDLName is not None: + newDLCommands = parseDLData(dlData, newDLName) + # Use -1 index so that it will be incremented to 0 at end of loop + parsedCommands = F3DParsedCommands(newDLName, newDLCommands, -1) + if command.name == "gsSPDisplayList": + callStack.append(parsedCommands) + elif command.name[:10] == "gsSPBranch": # TODO: Handle BranchZ? + callStack = callStack[:-1] + callStack.append(parsedCommands) + elif command.name == "gsSPEndDisplayList": + callStack = callStack[:-1] + + # Material Specific Commands + prevMaterialChangedStatus = self.materialChanged + self.materialChanged = True + + # Should we parse commands into f3d_gbi classes? + # No, because some parsing involves reading C files, which is separate. + + # Assumes macros use variable names instead of values + mat = self.mat() + try: + if command.name == "gsSPClipRatio": + mat.clip_ratio = math_eval(command.params[0], self.f3d) + elif command.name == "gsSPNumLights": + self.numLights = self.getLightCount(command.name[1]) + elif command.name == "gsSPLight": + self.setLight(dlData, command) + elif command.name == "gsSPLightColor": + self.setLightColor(dlData, command) + elif command.name[:13] == "gsSPSetLights": + self.setLights(dlData, command) + elif command.name == "gsSPFogFactor": + pass + elif command.name == "gsSPFogPosition": + mat.fog_position = [math_eval(command.params[0], self.f3d), math_eval(command.params[1], self.f3d)] + mat.set_fog = True + elif command.name == "gsSPTexture" or command.name == "gsSPTextureL": + mat.tex_scale = [ + math_eval(command.params[0], self.f3d) / (2**16), + math_eval(command.params[1], self.f3d) / (2**16), + ] + elif command.name == "gsSPSetGeometryMode": + self.setGeoFlags(command, True) + elif command.name == "gsSPClearGeometryMode": + self.setGeoFlags(command, False) + elif command.name == "gsSPLoadGeometryMode": + self.loadGeoFlags(command) + elif command.name == "gsSPSetOtherMode": + self.setOtherModeFlags(command) + elif command.name == "gsDPPipelineMode": + mat.rdp_settings.g_mdsft_pipeline = command.params[0] + elif command.name == "gsDPSetCycleType": + mat.rdp_settings.g_mdsft_cycletype = command.params[0] + elif command.name == "gsDPSetTexturePersp": + mat.rdp_settings.g_mdsft_textpersp = command.params[0] + elif command.name == "gsDPSetTextureDetail": + mat.rdp_settings.g_mdsft_textdetail = command.params[0] + elif command.name == "gsDPSetTextureLOD": + mat.rdp_settings.g_mdsft_textlod = command.params[0] + elif command.name == "gsDPSetTextureLUT": + self.setTLUTMode(0, command.params[0]) + self.setTLUTMode(1, command.params[0]) + elif command.name == "gsDPSetTextureFilter": + mat.rdp_settings.g_mdsft_text_filt = command.params[0] + elif command.name == "gsDPSetTextureConvert": + mat.rdp_settings.g_mdsft_textconv = command.params[0] + elif command.name == "gsDPSetCombineKey": + mat.rdp_settings.g_mdsft_combkey = command.params[0] + elif command.name == "gsDPSetColorDither": + mat.rdp_settings.g_mdsft_color_dither = command.params[0] + elif command.name == "gsDPSetAlphaDither": + mat.rdp_settings.g_mdsft_alpha_dither = command.params[0] + elif command.name == "gsDPSetAlphaCompare": + mat.rdp_settings.g_mdsft_alpha_compare = command.params[0] + elif command.name == "gsDPSetDepthSource": + mat.rdp_settings.g_mdsft_zsrcsel = command.params[0] + elif command.name == "gsDPSetRenderMode": + flags = math_eval(command.params[0] + " | " + command.params[1], self.f3d) + self.setRenderMode(flags) + elif command.name == "gsDPSetTextureImage": + # Are other params necessary? + # The params are set in SetTile commands. + self.currentTextureName = command.params[3] + elif command.name == "gsDPSetCombineMode": + self.setCombineMode(command) + elif command.name == "gsDPSetCombineLERP": + self.setCombineLerp(command.params[0:8], command.params[8:16]) + elif command.name == "gsDPSetEnvColor": + mat.env_color = self.gammaInverseParam(command.params) + mat.set_env = True + elif command.name == "gsDPSetBlendColor": + mat.blend_color = self.gammaInverseParam(command.params) + mat.set_blend = True + elif command.name == "gsDPSetFogColor": + mat.fog_color = self.gammaInverseParam(command.params) + mat.set_fog = True + elif command.name == "gsDPSetFillColor": + pass + elif command.name == "gsDPSetPrimDepth": + pass + elif command.name == "gsDPSetPrimColor": + mat.prim_lod_min = math_eval(command.params[0], self.f3d) / 255 + mat.prim_lod_frac = math_eval(command.params[1], self.f3d) / 255 + mat.prim_color = self.gammaInverseParam(command.params[2:6]) + mat.set_prim = True + elif command.name == "gsDPSetOtherMode": + print("gsDPSetOtherMode not handled.") + elif command.name == "DPSetConvert": + mat.set_k0_5 = True + for i in range(6): + setattr(mat, "k" + str(i), gammaInverseValue(math_eval(command.params[i], self.f3d) / 255)) + elif command.name == "DPSetKeyR": + mat.set_key = True + elif command.name == "DPSetKeyGB": + mat.set_key = True + else: + self.materialChanged = prevMaterialChangedStatus + + # Texture Commands + # Assume file texture load + # SetTextureImage -> Load command -> Set Tile (0 or 1) + + if command.name == "gsDPSetTileSize": + self.setTileSize(command.params) + elif command.name == "gsDPLoadTile": + self.loadTile(command.params) + elif command.name == "gsDPSetTile": + self.setTile(command.params, dlData) + elif command.name == "gsDPLoadBlock": + self.loadTile(command.params) + elif command.name == "gsDPLoadTLUTCmd": + self.loadTLUT(command.params, dlData) + + # This all ignores S/T high/low values + # This is pretty bad/confusing + elif command.name[: len("gsDPLoadTextureBlock")] == "gsDPLoadTextureBlock": + is4bit = "4b" in command.name + if is4bit: + self.loadMultiBlock( + [command.params[0]] + + [0, "G_TX_RENDERTILE"] + + [command.params[1], "G_IM_SIZ_4b"] + + command.params[2:], + dlData, + True, + ) + else: + self.loadMultiBlock( + [command.params[0]] + [0, "G_TX_RENDERTILE"] + command.params[1:], dlData, False + ) + elif command.name[: len("gsDPLoadMultiBlock")] == "gsDPLoadMultiBlock": + is4bit = "4b" in command.name + if is4bit: + self.loadMultiBlock(command.params[:4] + ["G_IM_SIZ_4b"] + command.params[4:], dlData, True) + else: + self.loadMultiBlock(command.params, dlData, False) + elif command.name[: len("gsDPLoadTextureTile")] == "gsDPLoadTextureTile": + is4bit = "4b" in command.name + if is4bit: + self.loadMultiBlock( + [command.params[0]] + + [0, "G_TX_RENDERTILE"] + + [command.params[1], "G_IM_SIZ_4b"] + + command.params[2:4] + + command.params[9:], + "4b", + dlData, + True, + ) + else: + self.loadMultiBlock( + [command.params[0]] + [0, "G_TX_RENDERTILE"] + command.params[1:5] + command.params[9:], + "4b", + dlData, + False, + ) + elif command.name[: len("gsDPLoadMultiTile")] == "gsDPLoadMultiTile": + is4bit = "4b" in command.name + if is4bit: + self.loadMultiBlock( + command.params[:4] + ["G_IM_SIZ_4b"] + command.params[4:6] + command.params[10:], + dlData, + True, + ) + else: + self.loadMultiBlock(command.params[:7] + command.params[11:], dlData, False) + + # TODO: Only handles palettes at tmem = 256 + elif command.name == "gsDPLoadTLUT_pal16": + self.loadTLUTPal(command.params[1], dlData, 15) + elif command.name == "gsDPLoadTLUT_pal256": + self.loadTLUTPal(command.params[0], dlData, 255) + else: + pass + + except TypeError as e: + print(traceback.format_exc()) + # raise Exception(e) + # print(e) + + # Don't use currentCommandList because some commands may change that + if len(callStack) > 0: + callStack[-1].index += 1 + + # override this to handle game specific DL calls. + # return None to indicate DL call should be skipped. + def processDLName(self, name): + return name + + def createMesh(self, obj, removeDoubles, importNormals): + mesh = obj.data + if len(self.verts) % 3 != 0: + print(len(self.verts)) + raise PluginError("Number of verts in mesh not divisible by 3, currently " + str(len(self.verts))) + + triangleCount = int(len(self.verts) / 3) + verts = [f3dVert[0] for f3dVert in self.verts] + faces = [[3 * i + j for j in range(3)] for i in range(triangleCount)] + print("Vertices: " + str(len(self.verts)) + ", Triangles: " + str(triangleCount)) + + mesh.from_pydata(vertices=verts, edges=[], faces=faces) + uv_layer = mesh.uv_layers.new().data + # if self.materialContext.f3d_mat.rdp_settings.g_lighting: + color_layer = mesh.vertex_colors.new(name="Col").data + alpha_layer = mesh.vertex_colors.new(name="Alpha").data + # else: + + if importNormals: + mesh.use_auto_smooth = True + mesh.normals_split_custom_set([f3dVert[3] for f3dVert in self.verts]) + + for groupName, indices in self.limbGroups.items(): + group = obj.vertex_groups.new(name=self.limbToBoneName[groupName]) + group.add(indices, 1, "REPLACE") + + for i in range(len(mesh.polygons)): + mesh.polygons[i].material_index = self.triMatIndices[i] + + for i in range(len(mesh.loops)): + # This should be okay, since we aren't trying to optimize vertices + # There will be one loop for every vertex + uv_layer[i].uv = self.verts[i][1] + + # if self.materialContext.f3d_mat.rdp_settings.g_lighting: + color_layer[i].color = self.verts[i][2] + alpha_layer[i].color = [self.verts[i][2][3]] * 3 + [1] + + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + bpy.ops.object.select_all(action="DESELECT") + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + + for material in self.materials: + obj.data.materials.append(material) + if not importNormals: + bpy.ops.object.shade_smooth() + if removeDoubles: + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_all(action="SELECT") + bpy.ops.mesh.remove_doubles() + bpy.ops.object.mode_set(mode="OBJECT") + + bpy.data.materials.remove(self.materialContext) + + obj.location = bpy.context.scene.cursor.location + + i = 0 + for key, lightObj in self.lightData.items(): + lightObj.location = bpy.context.scene.cursor.location + mathutils.Vector((i, 0, 0)) + i += 1 class ParsedMacro: - def __init__(self, name, params): - self.name = name - self.params = params + def __init__(self, name, params): + self.name = name + self.params = params + # Static DLs only @@ -1575,421 +1699,474 @@ class ParsedMacro: # This means changing the c variable names. def parseF3D(dlData, dlName, obj, transformMatrix, limbName, boneName, drawLayerPropName, drawLayer, f3dContext): - f3dContext.matrixData[limbName] = transformMatrix - f3dContext.setCurrentTransform(limbName) - f3dContext.limbToBoneName[limbName] = boneName - setattr(f3dContext.mat().draw_layer, drawLayerPropName, drawLayer) - - #vertexGroup = getOrMakeVertexGroup(obj, boneName) - #groupIndex = vertexGroup.index + f3dContext.matrixData[limbName] = transformMatrix + f3dContext.setCurrentTransform(limbName) + f3dContext.limbToBoneName[limbName] = boneName + setattr(f3dContext.mat().draw_layer, drawLayerPropName, drawLayer) + + # vertexGroup = getOrMakeVertexGroup(obj, boneName) + # groupIndex = vertexGroup.index + + dlCommands = parseDLData(dlData, dlName) + f3dContext.processCommands(dlData, dlName, dlCommands) - dlCommands = parseDLData(dlData, dlName) - f3dContext.processCommands(dlData, dlName, dlCommands) def parseDLData(dlData, dlName): - matchResult = re.search("Gfx\s*" + re.escape(dlName) + "\s*\[\s*\w*\s*\]\s*=\s*\{([^\}]*)\}", dlData) - if matchResult is None: - raise PluginError("Cannot find display list named " + dlName) + matchResult = re.search("Gfx\s*" + re.escape(dlName) + "\s*\[\s*\w*\s*\]\s*=\s*\{([^\}]*)\}", dlData) + if matchResult is None: + raise PluginError("Cannot find display list named " + dlName) - dlCommandData = matchResult.group(1) + dlCommandData = matchResult.group(1) - # recursive regex not available in re - #dlCommands = [(match.group(1), [param.strip() for param in match.group(2).split(",")]) for match in \ - # re.findall('(gs[A-Za-z0-9\_]*)\(((?>[^()]|(?R))*)\)', dlCommandData, re.DOTALL)] + # recursive regex not available in re + # dlCommands = [(match.group(1), [param.strip() for param in match.group(2).split(",")]) for match in \ + # re.findall('(gs[A-Za-z0-9\_]*)\(((?>[^()]|(?R))*)\)', dlCommandData, re.DOTALL)] + + dlCommands = parseMacroList(dlCommandData) + return dlCommands - dlCommands = parseMacroList(dlCommandData) - return dlCommands - def getVertexDataStart(vertexDataParam, f3d): - matchResult = re.search("\&?([A-Za-z0-9\_]*)\s*(\[([^\]]*)\])?\s*(\+(.*))?", vertexDataParam) - if matchResult is None: - raise PluginError("SPVertex param " + vertexDataParam + " is malformed.") + matchResult = re.search("\&?([A-Za-z0-9\_]*)\s*(\[([^\]]*)\])?\s*(\+(.*))?", vertexDataParam) + if matchResult is None: + raise PluginError("SPVertex param " + vertexDataParam + " is malformed.") - offset = 0 - if matchResult.group(3): - offset += math_eval(matchResult.group(3), f3d) - if matchResult.group(5): - offset += math_eval(matchResult.group(5), f3d) + offset = 0 + if matchResult.group(3): + offset += math_eval(matchResult.group(3), f3d) + if matchResult.group(5): + offset += math_eval(matchResult.group(5), f3d) + + return matchResult.group(1), offset - return matchResult.group(1), offset def parseVertexData(dlData, vertexDataName, f3dContext): - if vertexDataName in f3dContext.vertexData: - return f3dContext.vertexData[vertexDataName] + if vertexDataName in f3dContext.vertexData: + return f3dContext.vertexData[vertexDataName] - matchResult = re.search("Vtx\s*" + re.escape(vertexDataName) + "\s*\[\s*[0-9x]*\s*\]\s*=\s*\{([^;]*);", dlData, re.DOTALL) - if matchResult is None: - raise PluginError("Cannot find vertex list named " + vertexDataName) - data = matchResult.group(1) + matchResult = re.search( + "Vtx\s*" + re.escape(vertexDataName) + "\s*\[\s*[0-9x]*\s*\]\s*=\s*\{([^;]*);", dlData, re.DOTALL + ) + if matchResult is None: + raise PluginError("Cannot find vertex list named " + vertexDataName) + data = matchResult.group(1) - pathMatch = re.search(r'\#include\s*"([^"]*)"', data) - if pathMatch is not None: - path = pathMatch.group(1) - data = readFile(f3dContext.getVTXPathFromInclude(path)) + pathMatch = re.search(r'\#include\s*"([^"]*)"', data) + if pathMatch is not None: + path = pathMatch.group(1) + data = readFile(f3dContext.getVTXPathFromInclude(path)) - f3d = f3dContext.f3d - patterns = f3dContext.vertexFormatPatterns(data) - vertexData = [] - for pattern in patterns: - vertexData = [( - [math_eval(match.group(1), f3d), math_eval(match.group(2), f3d), math_eval(match.group(3), f3d)], - [math_eval(match.group(4), f3d), math_eval(match.group(5), f3d)], - [math_eval(match.group(6), f3d), math_eval(match.group(7), f3d), math_eval(match.group(8), f3d), math_eval(match.group(9), f3d)]) - for match in re.finditer(pattern, data, re.DOTALL)] - if len(vertexData) > 0: - break - f3dContext.vertexData[vertexDataName] = vertexData + f3d = f3dContext.f3d + patterns = f3dContext.vertexFormatPatterns(data) + vertexData = [] + for pattern in patterns: + vertexData = [ + ( + [math_eval(match.group(1), f3d), math_eval(match.group(2), f3d), math_eval(match.group(3), f3d)], + [math_eval(match.group(4), f3d), math_eval(match.group(5), f3d)], + [ + math_eval(match.group(6), f3d), + math_eval(match.group(7), f3d), + math_eval(match.group(8), f3d), + math_eval(match.group(9), f3d), + ], + ) + for match in re.finditer(pattern, data, re.DOTALL) + ] + if len(vertexData) > 0: + break + f3dContext.vertexData[vertexDataName] = vertexData + + return f3dContext.vertexData[vertexDataName] - return f3dContext.vertexData[vertexDataName] def parseLightsData(lightsData, lightsName, f3dContext): - #if lightsName in f3dContext.lightData: - # return f3dContext.lightData[lightsName] + # if lightsName in f3dContext.lightData: + # return f3dContext.lightData[lightsName] - matchResult = re.search("Lights([0-9n])\s*" + re.escape(lightsName) + "\s*=\s*gdSPDefLights[0-9]\s*\(([^\)]*)\)\s*;\s*", lightsData, re.DOTALL) - if matchResult is None: - raise PluginError("Cannot find lights data named " + lightsName) - data = matchResult.group(2) + matchResult = re.search( + "Lights([0-9n])\s*" + re.escape(lightsName) + "\s*=\s*gdSPDefLights[0-9]\s*\(([^\)]*)\)\s*;\s*", + lightsData, + re.DOTALL, + ) + if matchResult is None: + raise PluginError("Cannot find lights data named " + lightsName) + data = matchResult.group(2) - values = [math_eval(value.strip(), f3dContext.f3d) for value in data.split(',')] - if values[-1] == "": - values = values[:-1] + values = [math_eval(value.strip(), f3dContext.f3d) for value in data.split(",")] + if values[-1] == "": + values = values[:-1] - lightCount = matchResult.group(1) - if lightCount == "n": - lightCount = "7" - return int(lightCount), values + lightCount = matchResult.group(1) + if lightCount == "n": + lightCount = "7" + return int(lightCount), values + + # return f3dContext.lightData[lightsName] - #return f3dContext.lightData[lightsName] def RGBA16toRGBA32(value): - return [((value >> 11) & 31) / 31, ((value >> 6) & 31) / 31, ((value >> 1) & 31) / 31, value & 1] + return [((value >> 11) & 31) / 31, ((value >> 6) & 31) / 31, ((value >> 1) & 31) / 31, value & 1] + def IA16toRGBA32(value): - return [((value >> 8) & 255) / 255, ((value >> 8) & 255) / 255, ((value >> 8) & 255) / 255, (value & 255) / 255] + return [((value >> 8) & 255) / 255, ((value >> 8) & 255) / 255, ((value >> 8) & 255) / 255, (value & 255) / 255] + def IA8toRGBA32(value): - return [((value >> 4) & 15) / 15, ((value >> 4) & 15) / 15, ((value >> 4) & 15) / 15, (value & 15) / 15] + return [((value >> 4) & 15) / 15, ((value >> 4) & 15) / 15, ((value >> 4) & 15) / 15, (value & 15) / 15] + def IA4toRGBA32(value): - return [((value >> 1) & 7) / 7, ((value >> 1) & 7) / 7, ((value >> 1) & 7) / 7, value & 1] + return [((value >> 1) & 7) / 7, ((value >> 1) & 7) / 7, ((value >> 1) & 7) / 7, value & 1] + def I8toRGBA32(value): - return [value / 255, value / 255, value / 255, 1] + return [value / 255, value / 255, value / 255, 1] + def I4toRGBA32(value): - return [value / 15, value / 15, value / 15, 1] + return [value / 15, value / 15, value / 15, 1] + def CI8toRGBA32(value): - return [value / 255, value / 255, value / 255, 1] + return [value / 255, value / 255, value / 255, 1] + def CI4toRGBA32(value): - return [value / 255, value / 255, value / 255, 1] + return [value / 255, value / 255, value / 255, 1] + class F3DTextureReference: - def __init__(self, name, width): - self.name = name - self.width = width + def __init__(self, name, width): + self.name = name + self.width = width + def parseTextureData(dlData, textureName, f3dContext, imageFormat, imageSize, width, basePath, isLUT, f3d): - matchResult = re.search("([A-Za-z0-9\_]+)\s*" + re.escape(textureName) + "\s*\[\s*[0-9x]*\s*\]\s*=\s*\{([^\}]*)\s\}\s*;\s*", dlData, re.DOTALL) - if matchResult is None: - print("Cannot find texture named " + textureName) - return F3DTextureReference(textureName, width) - data = matchResult.group(2) - valueSize = matchResult.group(1) + matchResult = re.search( + "([A-Za-z0-9\_]+)\s*" + re.escape(textureName) + "\s*\[\s*[0-9x]*\s*\]\s*=\s*\{([^\}]*)\s\}\s*;\s*", + dlData, + re.DOTALL, + ) + if matchResult is None: + print("Cannot find texture named " + textureName) + return F3DTextureReference(textureName, width) + data = matchResult.group(2) + valueSize = matchResult.group(1) - pathMatch = re.search("\#include\s*\"([^\"]*)\"", data, re.DOTALL) - if pathMatch is not None: - path = pathMatch.group(1) - originalImage = bpy.data.images.load(f3dContext.getImagePathFromInclude(path)) - image = originalImage.copy() - image.pack() - image.filepath = "" - bpy.data.images.remove(originalImage) + pathMatch = re.search('\#include\s*"([^"]*)"', data, re.DOTALL) + if pathMatch is not None: + path = pathMatch.group(1) + originalImage = bpy.data.images.load(f3dContext.getImagePathFromInclude(path)) + image = originalImage.copy() + image.pack() + image.filepath = "" + bpy.data.images.remove(originalImage) - # Blender UV origin is bottom right, while N64 is top right, so we must flip LUT since we read it as data - if isLUT: - flippedValues = image.pixels[:] - width, height = image.size - for j in range(height): - image.pixels[width * j * 4 : width * (j+1) * 4] = flippedValues[width * (height - (j+1)) * 4 : width * (height - j) * 4] - else: - values = [value.strip() for value in data.split(',') if value.strip() != ""] - newValues = [] - for value in values: - intValue = math_eval(value, f3d) - if valueSize == 'u8' or valueSize == 's8' or valueSize == 'char' or valueSize == "Texture": - size = 1 - elif valueSize == 'u16' or valueSize == "s16" or valueSize == "short": - size = 2 - elif valueSize == 'u32' or valueSize == 's32' or valueSize == 'int': - size = 4 - else: - size = 8 - newValues.extend(int.to_bytes(intValue, size, 'big')[:]) - values = newValues + # Blender UV origin is bottom right, while N64 is top right, so we must flip LUT since we read it as data + if isLUT: + flippedValues = image.pixels[:] + width, height = image.size + for j in range(height): + image.pixels[width * j * 4 : width * (j + 1) * 4] = flippedValues[ + width * (height - (j + 1)) * 4 : width * (height - j) * 4 + ] + else: + values = [value.strip() for value in data.split(",") if value.strip() != ""] + newValues = [] + for value in values: + intValue = math_eval(value, f3d) + if valueSize == "u8" or valueSize == "s8" or valueSize == "char" or valueSize == "Texture": + size = 1 + elif valueSize == "u16" or valueSize == "s16" or valueSize == "short": + size = 2 + elif valueSize == "u32" or valueSize == "s32" or valueSize == "int": + size = 4 + else: + size = 8 + newValues.extend(int.to_bytes(intValue, size, "big")[:]) + values = newValues - if width == 0: - width = 16 - height = int(ceil(len(values) / (width * int(imageSize[9:-1]) / 8))) - #print("Texture: " + str(len(values)) + ", width = " + str(width) + ", height = " + str(height)) - image = bpy.data.images.new(textureName, width, height, alpha = True) - if imageFormat == "G_IM_FMT_RGBA": - if imageSize == 'G_IM_SIZ_16b': - for i in range(int(len(values) / 2)): - image.pixels[4*i:4 * (i+1)] = RGBA16toRGBA32(int.from_bytes(values[2*i:2*(i+1)], 'big')) - elif imageSize == 'G_IM_SIZ_32b': - image.pixels[:] = values - else: - print("Unhandled size for RGBA: " + str(imageSize)) - elif imageFormat == "G_IM_FMT_IA": - if imageSize == 'G_IM_SIZ_4b': - for i in range(len(values)): - image.pixels[8*i : 8*i+4] = IA4toRGBA32((values[i] >> 4) & 15) - image.pixels[8*i+4 : 8*i+8] = IA4toRGBA32(values[i] & 15) - elif imageSize == "G_IM_SIZ_8b": - for i in range(len(values)): - image.pixels[4*i:4 * (i+1)] = IA8toRGBA32(values[i]) - elif imageSize == "G_IM_SIZ_16b": - for i in range(int(len(values) / 2)): - image.pixels[4*i:4 * (i+1)] = IA16toRGBA32(int.from_bytes(values[2*i:2*(i+1)], 'big')) - else: - print("Unhandled size for IA: " + str(imageSize)) - elif imageFormat == "G_IM_FMT_I": - if imageSize == 'G_IM_SIZ_4b': - for i in range(len(values)): - image.pixels[8*i : 8*i+4] = I4toRGBA32((values[i] >> 4) & 15) - image.pixels[8*i+4 : 8*i+8] = I4toRGBA32(values[i] & 15) - elif imageSize == "G_IM_SIZ_8b": - for i in range(len(values)): - image.pixels[4*i:4 * (i+1)] = I8toRGBA32(values[i]) - else: - print("Unhandled size for I: " + str(imageSize)) - elif imageFormat == "G_IM_FMT_CI": - if imageSize == 'G_IM_SIZ_4b': - for i in range(len(values)): - image.pixels[8*i : 8*i+4] = CI4toRGBA32((values[i] >> 4) & 15) - image.pixels[8*i+4 : 8*i+8] = CI4toRGBA32(values[i] & 15) - elif imageSize == "G_IM_SIZ_8b": - for i in range(len(values)): - image.pixels[4*i:4 * (i+1)] = CI8toRGBA32(values[i]) - else: - print("Unhandled size for CI: " + str(imageSize)) + if width == 0: + width = 16 + height = int(ceil(len(values) / (width * int(imageSize[9:-1]) / 8))) + # print("Texture: " + str(len(values)) + ", width = " + str(width) + ", height = " + str(height)) + image = bpy.data.images.new(textureName, width, height, alpha=True) + if imageFormat == "G_IM_FMT_RGBA": + if imageSize == "G_IM_SIZ_16b": + for i in range(int(len(values) / 2)): + image.pixels[4 * i : 4 * (i + 1)] = RGBA16toRGBA32( + int.from_bytes(values[2 * i : 2 * (i + 1)], "big") + ) + elif imageSize == "G_IM_SIZ_32b": + image.pixels[:] = values + else: + print("Unhandled size for RGBA: " + str(imageSize)) + elif imageFormat == "G_IM_FMT_IA": + if imageSize == "G_IM_SIZ_4b": + for i in range(len(values)): + image.pixels[8 * i : 8 * i + 4] = IA4toRGBA32((values[i] >> 4) & 15) + image.pixels[8 * i + 4 : 8 * i + 8] = IA4toRGBA32(values[i] & 15) + elif imageSize == "G_IM_SIZ_8b": + for i in range(len(values)): + image.pixels[4 * i : 4 * (i + 1)] = IA8toRGBA32(values[i]) + elif imageSize == "G_IM_SIZ_16b": + for i in range(int(len(values) / 2)): + image.pixels[4 * i : 4 * (i + 1)] = IA16toRGBA32(int.from_bytes(values[2 * i : 2 * (i + 1)], "big")) + else: + print("Unhandled size for IA: " + str(imageSize)) + elif imageFormat == "G_IM_FMT_I": + if imageSize == "G_IM_SIZ_4b": + for i in range(len(values)): + image.pixels[8 * i : 8 * i + 4] = I4toRGBA32((values[i] >> 4) & 15) + image.pixels[8 * i + 4 : 8 * i + 8] = I4toRGBA32(values[i] & 15) + elif imageSize == "G_IM_SIZ_8b": + for i in range(len(values)): + image.pixels[4 * i : 4 * (i + 1)] = I8toRGBA32(values[i]) + else: + print("Unhandled size for I: " + str(imageSize)) + elif imageFormat == "G_IM_FMT_CI": + if imageSize == "G_IM_SIZ_4b": + for i in range(len(values)): + image.pixels[8 * i : 8 * i + 4] = CI4toRGBA32((values[i] >> 4) & 15) + image.pixels[8 * i + 4 : 8 * i + 8] = CI4toRGBA32(values[i] & 15) + elif imageSize == "G_IM_SIZ_8b": + for i in range(len(values)): + image.pixels[4 * i : 4 * (i + 1)] = CI8toRGBA32(values[i]) + else: + print("Unhandled size for CI: " + str(imageSize)) - # Blender UV origin is bottom right, while N64 is top right, so we must flip non LUT - if not isLUT: - flippedValues = image.pixels[:] - for j in range(height): - image.pixels[width * j * 4 : width * (j+1) * 4] = flippedValues[width * (height - (j+1)) * 4 : width * (height - j) * 4] + # Blender UV origin is bottom right, while N64 is top right, so we must flip non LUT + if not isLUT: + flippedValues = image.pixels[:] + for j in range(height): + image.pixels[width * j * 4 : width * (j + 1) * 4] = flippedValues[ + width * (height - (j + 1)) * 4 : width * (height - j) * 4 + ] + + return image - return image def parseMacroList(data): - end = 0 - start = 0 - isCommand = True - commands = [] - parenthesesCount = 0 + end = 0 + start = 0 + isCommand = True + commands = [] + parenthesesCount = 0 - command = None - params = None - while end < len(data) - 1: - end += 1 - if data[end] == '(': - parenthesesCount += 1 - elif data[end] == ')': - parenthesesCount -= 1 + command = None + params = None + while end < len(data) - 1: + end += 1 + if data[end] == "(": + parenthesesCount += 1 + elif data[end] == ")": + parenthesesCount -= 1 - if isCommand and parenthesesCount > 0: - command = data[start:end].strip() - if command[0] == ',': - command = command[1:].strip() - isCommand = False - start = end + 1 - - elif not isCommand and parenthesesCount == 0: - params = parseMacroArgs(data[start:end]) - commands.append(ParsedMacro(command, params)) - isCommand = True - start = end + 1 + if isCommand and parenthesesCount > 0: + command = data[start:end].strip() + if command[0] == ",": + command = command[1:].strip() + isCommand = False + start = end + 1 + + elif not isCommand and parenthesesCount == 0: + params = parseMacroArgs(data[start:end]) + commands.append(ParsedMacro(command, params)) + isCommand = True + start = end + 1 + + return commands - return commands def parseMacroArgs(data): - end = 0 - start = 0 - params = [] - parenthesesCount = 0 + end = 0 + start = 0 + params = [] + parenthesesCount = 0 - while end < len(data) - 1: - end += 1 - if data[end] == '(': - parenthesesCount += 1 - elif data[end] == ')': - parenthesesCount -= 1 + while end < len(data) - 1: + end += 1 + if data[end] == "(": + parenthesesCount += 1 + elif data[end] == ")": + parenthesesCount -= 1 - if (data[end] == ',' or end == len(data) -1) and parenthesesCount == 0: - if end == len(data)-1: - end += 1 - param = "".join(data[start:end].split()) - params.append(param) - start = end + 1 + if (data[end] == "," or end == len(data) - 1) and parenthesesCount == 0: + if end == len(data) - 1: + end += 1 + param = "".join(data[start:end].split()) + params.append(param) + start = end + 1 + + return params - return params def getImportData(filepaths): - data = '' - for path in filepaths: - if os.path.exists(path): - data += readFile(path) + data = "" + for path in filepaths: + if os.path.exists(path): + data += readFile(path) + + return data - return data def importMeshC(filepaths, name, scale, removeDoubles, importNormals, drawLayer, f3dContext): - data = getImportData(filepaths) + data = getImportData(filepaths) - # Create new skinned mesh - mesh = bpy.data.meshes.new(name + '_mesh') - obj = bpy.data.objects.new(name + '_mesh', mesh) - bpy.context.scene.collection.objects.link(obj) + # Create new skinned mesh + mesh = bpy.data.meshes.new(name + "_mesh") + obj = bpy.data.objects.new(name + "_mesh", mesh) + bpy.context.scene.collection.objects.link(obj) - f3dContext.mat().draw_layer.oot = drawLayer - transformMatrix = mathutils.Matrix.Scale(1 / scale, 4) + f3dContext.mat().draw_layer.oot = drawLayer + transformMatrix = mathutils.Matrix.Scale(1 / scale, 4) - parseF3D(data, name, obj, transformMatrix, - name, name, "oot", drawLayer, f3dContext) - - f3dContext.clearMaterial() - f3dContext.createMesh(obj, removeDoubles, importNormals) + parseF3D(data, name, obj, transformMatrix, name, name, "oot", drawLayer, f3dContext) + + f3dContext.clearMaterial() + f3dContext.createMesh(obj, removeDoubles, importNormals) + + applyRotation([obj], math.radians(-90), "X") - applyRotation([obj], math.radians(-90), 'X') class F3D_ImportDL(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.f3d_import_dl' - bl_label = "Import DL" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.f3d_import_dl" + bl_label = "Import DL" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - obj = None - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + obj = None + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") - try: - name = context.scene.DLImportName - importPath = bpy.path.abspath(context.scene.DLImportPath) - basePath = bpy.path.abspath(context.scene.DLImportBasePath) - scaleValue = bpy.context.scene.blenderF3DScale - - removeDoubles = context.scene.DLRemoveDoubles - importNormals = context.scene.DLImportNormals - drawLayer = context.scene.DLImportDrawLayer - f3dType = context.scene.f3d_type - isHWv1 = context.scene.isHWv1 + try: + name = context.scene.DLImportName + importPath = bpy.path.abspath(context.scene.DLImportPath) + basePath = bpy.path.abspath(context.scene.DLImportBasePath) + scaleValue = bpy.context.scene.blenderF3DScale - importPaths = [importPath] + removeDoubles = context.scene.DLRemoveDoubles + importNormals = context.scene.DLImportNormals + drawLayer = context.scene.DLImportDrawLayer + f3dType = context.scene.f3d_type + isHWv1 = context.scene.isHWv1 - importMeshC(importPaths, name, scaleValue, removeDoubles, importNormals, drawLayer, - F3DContext(F3D(f3dType, isHWv1), basePath, createF3DMat(None))) + importPaths = [importPath] - self.report({'INFO'}, 'Success!') - return {'FINISHED'} + importMeshC( + importPaths, + name, + scaleValue, + removeDoubles, + importNormals, + drawLayer, + F3DContext(F3D(f3dType, isHWv1), basePath, createF3DMat(None)), + ) - except Exception as e: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') - raisePluginError(self, e) - return {'CANCELLED'} # must return a set + self.report({"INFO"}, "Success!") + return {"FINISHED"} + + except Exception as e: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + raisePluginError(self, e) + return {"CANCELLED"} # must return a set class F3D_UL_ImportDLPathList(bpy.types.UIList): - def draw_item(self, context, layout, data, item, icon, active_data, active_propname): - scene = data - fileProperty = item - # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. - if self.layout_type in {'DEFAULT', 'COMPACT'}: - # You should always start your row layout by a label (icon + text), or a non-embossed text field, - # this will also make the row easily selectable in the list! The later also enables ctrl-click rename. - # We use icon_value of label, as our given icon is an integer value, not an enum ID. - # Note "data" names should never be translated! - if ma: - layout.prop(fileProperty, "Path", text="", emboss=False, icon_value=icon) - else: - layout.label(text="", translate=False, icon_value=icon) - # 'GRID' layout type should be as compact as possible (typically a single icon!). - elif self.layout_type in {'GRID'}: - layout.alignment = 'CENTER' - layout.label(text="", icon_value=icon) + def draw_item(self, context, layout, data, item, icon, active_data, active_propname): + scene = data + fileProperty = item + # draw_item must handle the three layout types... Usually 'DEFAULT' and 'COMPACT' can share the same code. + if self.layout_type in {"DEFAULT", "COMPACT"}: + # You should always start your row layout by a label (icon + text), or a non-embossed text field, + # this will also make the row easily selectable in the list! The later also enables ctrl-click rename. + # We use icon_value of label, as our given icon is an integer value, not an enum ID. + # Note "data" names should never be translated! + if ma: + layout.prop(fileProperty, "Path", text="", emboss=False, icon_value=icon) + else: + layout.label(text="", translate=False, icon_value=icon) + # 'GRID' layout type should be as compact as possible (typically a single icon!). + elif self.layout_type in {"GRID"}: + layout.alignment = "CENTER" + layout.label(text="", icon_value=icon) + class F3D_ImportDLPanel(bpy.types.Panel): - bl_idname = "F3D_PT_import_dl" - bl_label = "F3D Importer" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'Fast64' - bl_options = {'DEFAULT_CLOSED'} + bl_idname = "F3D_PT_import_dl" + bl_label = "F3D Importer" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Fast64" + bl_options = {"DEFAULT_CLOSED"} - @classmethod - def poll(cls, context): - return True + @classmethod + def poll(cls, context): + return True - # called every frame - def draw(self, context): - col = self.layout.column() - - col.operator(F3D_ImportDL.bl_idname) - prop_split(col, context.scene, "DLImportName", "Name") - prop_split(col, context.scene, "DLImportPath", "File") - prop_split(col, context.scene, "DLImportBasePath", "Base Path") - prop_split(col, context.scene, "blenderF3DScale", "Scale") - prop_split(col, context.scene, "DLImportDrawLayer", "Draw Layer") - col.prop(context.scene, "DLRemoveDoubles") - col.prop(context.scene, "DLImportNormals") + # called every frame + def draw(self, context): + col = self.layout.column() - box = col.box().column() - box.label(text = "All data must be contained within file.") - box.label(text = "The only exception are pngs converted to inc.c.") + col.operator(F3D_ImportDL.bl_idname) + prop_split(col, context.scene, "DLImportName", "Name") + prop_split(col, context.scene, "DLImportPath", "File") + prop_split(col, context.scene, "DLImportBasePath", "Base Path") + prop_split(col, context.scene, "blenderF3DScale", "Scale") + prop_split(col, context.scene, "DLImportDrawLayer", "Draw Layer") + col.prop(context.scene, "DLRemoveDoubles") + col.prop(context.scene, "DLImportNormals") - #col.template_list('F3D_UL_ImportDLPathList', '', context.scene, - # 'DLImportOtherFiles', context.scene, 'DLImportOtherFilesIndex') + box = col.box().column() + box.label(text="All data must be contained within file.") + box.label(text="The only exception are pngs converted to inc.c.") + + # col.template_list('F3D_UL_ImportDLPathList', '', context.scene, + # 'DLImportOtherFiles', context.scene, 'DLImportOtherFilesIndex') + + +class ImportFileProperty(bpy.types.PropertyGroup): + path: bpy.props.StringProperty(name="Path", subtype="FILE_PATH") -class ImportFileProperty (bpy.types.PropertyGroup): - path : bpy.props.StringProperty(name = "Path", subtype = "FILE_PATH") f3d_parser_classes = ( - F3D_ImportDL, - F3D_ImportDLPanel, - ImportFileProperty, - F3D_UL_ImportDLPathList, + F3D_ImportDL, + F3D_ImportDLPanel, + ImportFileProperty, + F3D_UL_ImportDLPathList, ) -def f3d_parser_register(): - for cls in f3d_parser_classes: - register_class(cls) - bpy.types.Scene.DLImportName = bpy.props.StringProperty(name = "Name") - bpy.types.Scene.DLImportPath = bpy.props.StringProperty(name = 'Directory', subtype = 'FILE_PATH') - bpy.types.Scene.DLImportBasePath = bpy.props.StringProperty(name = 'Directory', subtype = 'FILE_PATH') - bpy.types.Scene.DLRemoveDoubles = bpy.props.BoolProperty(name = "Remove Doubles", default = True) - bpy.types.Scene.DLImportNormals = bpy.props.BoolProperty(name = "Import Normals", default = True) - bpy.types.Scene.DLImportDrawLayer = bpy.props.EnumProperty(name = "Draw Layer", items = ootEnumDrawLayers) - bpy.types.Scene.DLImportOtherFiles = bpy.props.CollectionProperty(type = ImportFileProperty) - bpy.types.Scene.DLImportOtherFilesIndex = bpy.props.IntProperty() +def f3d_parser_register(): + for cls in f3d_parser_classes: + register_class(cls) + + bpy.types.Scene.DLImportName = bpy.props.StringProperty(name="Name") + bpy.types.Scene.DLImportPath = bpy.props.StringProperty(name="Directory", subtype="FILE_PATH") + bpy.types.Scene.DLImportBasePath = bpy.props.StringProperty(name="Directory", subtype="FILE_PATH") + bpy.types.Scene.DLRemoveDoubles = bpy.props.BoolProperty(name="Remove Doubles", default=True) + bpy.types.Scene.DLImportNormals = bpy.props.BoolProperty(name="Import Normals", default=True) + bpy.types.Scene.DLImportDrawLayer = bpy.props.EnumProperty(name="Draw Layer", items=ootEnumDrawLayers) + bpy.types.Scene.DLImportOtherFiles = bpy.props.CollectionProperty(type=ImportFileProperty) + bpy.types.Scene.DLImportOtherFilesIndex = bpy.props.IntProperty() + def f3d_parser_unregister(): - for cls in reversed(f3d_parser_classes): - unregister_class(cls) + for cls in reversed(f3d_parser_classes): + unregister_class(cls) - del bpy.types.Scene.DLImportName - del bpy.types.Scene.DLImportPath - del bpy.types.Scene.DLRemoveDoubles - del bpy.types.Scene.DLImportNormals - del bpy.types.Scene.DLImportDrawLayer - del bpy.types.Scene.DLImportBasePath - del bpy.types.Scene.DLImportOtherFiles - del bpy.types.Scene.DLImportOtherFilesIndex + del bpy.types.Scene.DLImportName + del bpy.types.Scene.DLImportPath + del bpy.types.Scene.DLRemoveDoubles + del bpy.types.Scene.DLImportNormals + del bpy.types.Scene.DLImportDrawLayer + del bpy.types.Scene.DLImportBasePath + del bpy.types.Scene.DLImportOtherFiles + del bpy.types.Scene.DLImportOtherFilesIndex diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index 93e5d43..295fa5f 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -5,896 +5,1065 @@ from bpy.utils import register_class, unregister_class from .f3d_enums import * from .f3d_constants import * -from .f3d_material import all_combiner_uses, getMaterialScrollDimensions, getTmemWordUsage, getTmemMax, bitSizeDict, texBitSizeOf, texFormatOf +from .f3d_material import ( + all_combiner_uses, + getMaterialScrollDimensions, + getTmemWordUsage, + getTmemMax, + bitSizeDict, + texBitSizeOf, + texFormatOf, +) from .f3d_gbi import * from .f3d_gbi import _DPLoadTextureBlock from ..utility import * + def getEdgeToFaceDict(mesh): - edgeDict = {} - for face in mesh.loop_triangles: - for edgeKey in face.edge_keys: - if edgeKey not in edgeDict: - edgeDict[edgeKey] = [] - if face not in edgeDict[edgeKey]: - edgeDict[edgeKey].append(face) - return edgeDict + edgeDict = {} + for face in mesh.loop_triangles: + for edgeKey in face.edge_keys: + if edgeKey not in edgeDict: + edgeDict[edgeKey] = [] + if face not in edgeDict[edgeKey]: + edgeDict[edgeKey].append(face) + return edgeDict + def getVertToFaceDict(mesh): - vertDict = {} - for face in mesh.loop_triangles: - for vertIndex in face.vertices: - if vertIndex not in vertDict: - vertDict[vertIndex] = [] - if face not in vertDict[vertIndex]: - vertDict[vertIndex].append(face) - return vertDict + vertDict = {} + for face in mesh.loop_triangles: + for vertIndex in face.vertices: + if vertIndex not in vertDict: + vertDict[vertIndex] = [] + if face not in vertDict[vertIndex]: + vertDict[vertIndex].append(face) + return vertDict + def getLoopFromVert(inputIndex, face): - for i in range(len(face.vertices)): - if face.vertices[i] == inputIndex: - return face.loops[i] + for i in range(len(face.vertices)): + if face.vertices[i] == inputIndex: + return face.loops[i] + class VertexGroupInfo: - def __init__(self): - self.vertexGroups = {} # vertex index : vertex group - self.vertexGroupToLimb = {} + def __init__(self): + self.vertexGroups = {} # vertex index : vertex group + self.vertexGroupToLimb = {} + class MeshInfo: - def __init__(self): - self.vert = {} # all faces connected to a vert - self.edge = {} # all faces connected to an edge - self.f3dVert = {} # f3d vertex of a given loop - self.edgeValid = {} # bool given two faces - self.validNeighbors = {} # all neighbors of a face with a valid connecting edge - self.texDimensions = {} # texture dimensions for each material + def __init__(self): + self.vert = {} # all faces connected to a vert + self.edge = {} # all faces connected to an edge + self.f3dVert = {} # f3d vertex of a given loop + self.edgeValid = {} # bool given two faces + self.validNeighbors = {} # all neighbors of a face with a valid connecting edge + self.texDimensions = {} # texture dimensions for each material + + self.vertexGroupInfo = None - self.vertexGroupInfo = None def getInfoDict(obj): - fixLargeUVs(obj) - obj.data.calc_loop_triangles() - obj.data.calc_normals_split() - if len(obj.data.materials) == 0: - raise PluginError("Mesh does not have any Fast3D materials.") + fixLargeUVs(obj) + obj.data.calc_loop_triangles() + obj.data.calc_normals_split() + if len(obj.data.materials) == 0: + raise PluginError("Mesh does not have any Fast3D materials.") - infoDict = MeshInfo() + infoDict = MeshInfo() - vertDict = infoDict.vert - edgeDict = infoDict.edge - f3dVertDict = infoDict.f3dVert - edgeValidDict = infoDict.edgeValid - validNeighborDict = infoDict.validNeighbors + vertDict = infoDict.vert + edgeDict = infoDict.edge + f3dVertDict = infoDict.f3dVert + edgeValidDict = infoDict.edgeValid + validNeighborDict = infoDict.validNeighbors - mesh = obj.data - if len(obj.data.uv_layers) == 0: - uv_data = obj.data.uv_layers.new().data - else: - uv_data = None - for uv_layer in obj.data.uv_layers: - if uv_layer.name == 'UVMap': - uv_data = uv_layer.data - if uv_data is None: - raise PluginError("Object \'" + obj.name + "\' does not have a UV layer named \'UVMap.\'") - for face in mesh.loop_triangles: - validNeighborDict[face] = [] - material = obj.material_slots[face.material_index].material - if material is None: - raise PluginError("There are some faces on your mesh that are assigned to an empty material slot.") - for vertIndex in face.vertices: - if vertIndex not in vertDict: - vertDict[vertIndex] = [] - if face not in vertDict[vertIndex]: - vertDict[vertIndex].append(face) - for edgeKey in face.edge_keys: - if edgeKey not in edgeDict: - edgeDict[edgeKey] = [] - if face not in edgeDict[edgeKey]: - edgeDict[edgeKey].append(face) + mesh = obj.data + if len(obj.data.uv_layers) == 0: + uv_data = obj.data.uv_layers.new().data + else: + uv_data = None + for uv_layer in obj.data.uv_layers: + if uv_layer.name == "UVMap": + uv_data = uv_layer.data + if uv_data is None: + raise PluginError("Object '" + obj.name + "' does not have a UV layer named 'UVMap.'") + for face in mesh.loop_triangles: + validNeighborDict[face] = [] + material = obj.material_slots[face.material_index].material + if material is None: + raise PluginError("There are some faces on your mesh that are assigned to an empty material slot.") + for vertIndex in face.vertices: + if vertIndex not in vertDict: + vertDict[vertIndex] = [] + if face not in vertDict[vertIndex]: + vertDict[vertIndex].append(face) + for edgeKey in face.edge_keys: + if edgeKey not in edgeDict: + edgeDict[edgeKey] = [] + if face not in edgeDict[edgeKey]: + edgeDict[edgeKey].append(face) + + for loopIndex in face.loops: + convertInfo = LoopConvertInfo( + uv_data, obj, isLightingDisabled(obj.material_slots[face.material_index].material) + ) + f3dVertDict[loopIndex] = getF3DVert(mesh.loops[loopIndex], face, convertInfo, mesh) + for face in mesh.loop_triangles: + for edgeKey in face.edge_keys: + for otherFace in edgeDict[edgeKey]: + if otherFace == face: + continue + if (otherFace, face) not in edgeValidDict and (face, otherFace) not in edgeValidDict: + edgeValid = ( + f3dVertDict[getLoopFromVert(edgeKey[0], face)] + == f3dVertDict[getLoopFromVert(edgeKey[0], otherFace)] + and f3dVertDict[getLoopFromVert(edgeKey[1], face)] + == f3dVertDict[getLoopFromVert(edgeKey[1], otherFace)] + ) + edgeValidDict[(otherFace, face)] = edgeValid + if edgeValid: + validNeighborDict[face].append(otherFace) + validNeighborDict[otherFace].append(face) + return infoDict - for loopIndex in face.loops: - convertInfo = LoopConvertInfo(uv_data, obj, - isLightingDisabled(obj.material_slots[face.material_index].material)) - f3dVertDict[loopIndex] = getF3DVert(mesh.loops[loopIndex], face, convertInfo, mesh) - for face in mesh.loop_triangles: - for edgeKey in face.edge_keys: - for otherFace in edgeDict[edgeKey]: - if otherFace == face: - continue - if (otherFace, face) not in edgeValidDict and \ - (face, otherFace) not in edgeValidDict: - edgeValid = \ - f3dVertDict[getLoopFromVert(edgeKey[0], face)] == \ - f3dVertDict[getLoopFromVert(edgeKey[0], otherFace)] and \ - f3dVertDict[getLoopFromVert(edgeKey[1], face)] == \ - f3dVertDict[getLoopFromVert(edgeKey[1], otherFace)] - edgeValidDict[(otherFace, face)] = edgeValid - if edgeValid: - validNeighborDict[face].append(otherFace) - validNeighborDict[otherFace].append(face) - return infoDict def fixLargeUVs(obj): - mesh = obj.data - if len(obj.data.uv_layers) == 0: - uv_data = obj.data.uv_layers.new().data - else: - uv_data = None - for uv_layer in obj.data.uv_layers: - if uv_layer.name == 'UVMap': - uv_data = uv_layer.data - if uv_data is None: - raise PluginError("Object \'" + obj.name + "\' does not have a UV layer named \'UVMap.\'") + mesh = obj.data + if len(obj.data.uv_layers) == 0: + uv_data = obj.data.uv_layers.new().data + else: + uv_data = None + for uv_layer in obj.data.uv_layers: + if uv_layer.name == "UVMap": + uv_data = uv_layer.data + if uv_data is None: + raise PluginError("Object '" + obj.name + "' does not have a UV layer named 'UVMap.'") - texSizeDict = {} - if len(obj.data.materials) == 0: - raise PluginError(f"{obj.name}: This object needs an f3d material on it.") + texSizeDict = {} + if len(obj.data.materials) == 0: + raise PluginError(f"{obj.name}: This object needs an f3d material on it.") - # Don't get tex dimensions here, as it also processes unused materials. - #texSizeDict[material] = getTexDimensions(material) + # Don't get tex dimensions here, as it also processes unused materials. + # texSizeDict[material] = getTexDimensions(material) - for polygon in mesh.polygons: - material = obj.material_slots[polygon.material_index].material - if material is None: - raise PluginError("There are some faces on your mesh that are assigned to an empty material slot.") + for polygon in mesh.polygons: + material = obj.material_slots[polygon.material_index].material + if material is None: + raise PluginError("There are some faces on your mesh that are assigned to an empty material slot.") - if material not in texSizeDict: - texSizeDict[material] = getTexDimensions(material) - if material.mat_ver > 3 and material.f3d_mat.use_large_textures: - continue + if material not in texSizeDict: + texSizeDict[material] = getTexDimensions(material) + if material.mat_ver > 3 and material.f3d_mat.use_large_textures: + continue - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material - UVinterval = [ - 2 if f3dMat.tex0.S.mirror or f3dMat.tex1.S.mirror else 1, - 2 if f3dMat.tex0.T.mirror or f3dMat.tex1.T.mirror else 1] + UVinterval = [ + 2 if f3dMat.tex0.S.mirror or f3dMat.tex1.S.mirror else 1, + 2 if f3dMat.tex0.T.mirror or f3dMat.tex1.T.mirror else 1, + ] - size = texSizeDict[material] - if size[0] == 0 or size[1] == 0: - continue - cellSize = [1024 / size[0], 1024 / size[1]] - minUV, maxUV = findUVBounds(polygon, uv_data) - uvOffset = [0,0] + size = texSizeDict[material] + if size[0] == 0 or size[1] == 0: + continue + cellSize = [1024 / size[0], 1024 / size[1]] + minUV, maxUV = findUVBounds(polygon, uv_data) + uvOffset = [0, 0] - for i in range(2): + for i in range(2): - # Move any UVs close to or straddling edge - minDiff = (-cellSize[i]+2) - minUV[i] - if minDiff > 0: - applyOffset(minUV, maxUV, uvOffset, ceil(minDiff / UVinterval[i]) * UVinterval[i], i) + # Move any UVs close to or straddling edge + minDiff = (-cellSize[i] + 2) - minUV[i] + if minDiff > 0: + applyOffset(minUV, maxUV, uvOffset, ceil(minDiff / UVinterval[i]) * UVinterval[i], i) - maxDiff = maxUV[i] - (cellSize[i] - 1) - if maxDiff > 0: - applyOffset(minUV, maxUV, uvOffset, -ceil(maxDiff / UVinterval[i]) * UVinterval[i], i) + maxDiff = maxUV[i] - (cellSize[i] - 1) + if maxDiff > 0: + applyOffset(minUV, maxUV, uvOffset, -ceil(maxDiff / UVinterval[i]) * UVinterval[i], i) - for loopIndex in polygon.loop_indices: - newUV = (uv_data[loopIndex].uv[0] + uvOffset[0], - uv_data[loopIndex].uv[1] + uvOffset[1]) - uv_data[loopIndex].uv = newUV + for loopIndex in polygon.loop_indices: + newUV = (uv_data[loopIndex].uv[0] + uvOffset[0], uv_data[loopIndex].uv[1] + uvOffset[1]) + uv_data[loopIndex].uv = newUV + + # if newUV[0] > cellSize[0] or \ + # newUV[1] > cellSize[1] or \ + # newUV[0] < -cellSize[0] or \ + # newUV[1] < -cellSize[1]: + # print("TOO BIG: " + str(newUV)) - #if newUV[0] > cellSize[0] or \ - # newUV[1] > cellSize[1] or \ - # newUV[0] < -cellSize[0] or \ - # newUV[1] < -cellSize[1]: - # print("TOO BIG: " + str(newUV)) def applyOffset(minUV, maxUV, uvOffset, offset, i): - minUV[i] += offset - maxUV[i] += offset - uvOffset[i] += offset + minUV[i] += offset + maxUV[i] += offset + uvOffset[i] += offset + def findUVBounds(polygon, uv_data): - minUV = [None, None] - maxUV = [None, None] - for loopIndex in polygon.loop_indices: - uv = uv_data[loopIndex].uv - for i in range(2): - minUV[i] = uv[i] if minUV[i] is None else min(minUV[i], uv[i]) - maxUV[i] = uv[i] if maxUV[i] is None else max(maxUV[i], uv[i]) - return minUV, maxUV + minUV = [None, None] + maxUV = [None, None] + for loopIndex in polygon.loop_indices: + uv = uv_data[loopIndex].uv + for i in range(2): + minUV[i] = uv[i] if minUV[i] is None else min(minUV[i], uv[i]) + maxUV[i] = uv[i] if maxUV[i] is None else max(maxUV[i], uv[i]) + return minUV, maxUV + class TileLoad: - def __init__(self, texFormat, twoTextures, texDimensions): - self.sl = None - self.sh = None - self.tl = None - self.th = None + def __init__(self, texFormat, twoTextures, texDimensions): + self.sl = None + self.sh = None + self.tl = None + self.th = None - self.texFormat = texFormat - self.twoTextures = twoTextures - self.texDimensions = texDimensions - self.tmemMax = getTmemMax(texFormat) + self.texFormat = texFormat + self.twoTextures = twoTextures + self.texDimensions = texDimensions + self.tmemMax = getTmemMax(texFormat) - # offset by 1 pixel for filtering purposes - def getLow(self, value): - return int(max(math.floor(value - 1), 0)) + # offset by 1 pixel for filtering purposes + def getLow(self, value): + return int(max(math.floor(value - 1), 0)) - def getHigh(self, value, field): - # 1024 wraps around to 0 - # -1 is because the high value is (max value - 1) - # ex. 32 pixel width -> high = 31 - return int(min(math.ceil(value + 1), min(self.texDimensions[field], 1024)) - 1) + def getHigh(self, value, field): + # 1024 wraps around to 0 + # -1 is because the high value is (max value - 1) + # ex. 32 pixel width -> high = 31 + return int(min(math.ceil(value + 1), min(self.texDimensions[field], 1024)) - 1) - def tryAppend(self, other): - return self.appendTile(other.sl, other.sh, other.tl, other.th) + def tryAppend(self, other): + return self.appendTile(other.sl, other.sh, other.tl, other.th) - def appendTile(self, sl, sh, tl, th): - new_sl = min(sl, self.sl) - new_sh = max(sh, self.sh) - new_tl = min(tl, self.tl) - new_th = max(th, self.th) - newWidth = abs(new_sl - new_sh) + 1 - newHeight = abs(new_tl - new_th) + 1 + def appendTile(self, sl, sh, tl, th): + new_sl = min(sl, self.sl) + new_sh = max(sh, self.sh) + new_tl = min(tl, self.tl) + new_th = max(th, self.th) + newWidth = abs(new_sl - new_sh) + 1 + newHeight = abs(new_tl - new_th) + 1 - tmemUsage = getTmemWordUsage(self.texFormat, newWidth, newHeight) * 8 *\ - (2 if self.twoTextures else 1) + tmemUsage = getTmemWordUsage(self.texFormat, newWidth, newHeight) * 8 * (2 if self.twoTextures else 1) - if tmemUsage > self.tmemMax: - return False - else: - self.sl = new_sl - self.sh = new_sh - self.tl = new_tl - self.th = new_th - return True + if tmemUsage > self.tmemMax: + return False + else: + self.sl = new_sl + self.sh = new_sh + self.tl = new_tl + self.th = new_th + return True - def tryAdd(self, points): - if len(points) == 0: - return True + def tryAdd(self, points): + if len(points) == 0: + return True - sl = self.getLow(points[0][0]) - sh = self.getHigh(points[0][0], 0) - tl = self.getLow(points[0][1]) - th = self.getHigh(points[0][1], 1) + sl = self.getLow(points[0][0]) + sh = self.getHigh(points[0][0], 0) + tl = self.getLow(points[0][1]) + th = self.getHigh(points[0][1], 1) - if self.sl is None: - self.sl = sl - self.sh = sh - self.tl = tl - self.th = th + if self.sl is None: + self.sl = sl + self.sh = sh + self.tl = tl + self.th = th - for point in points: - sl = min(self.getLow(point[0]), sl) - sh = max(self.getHigh(point[0], 0), sh) - tl = min(self.getLow(point[1]), tl) - th = max(self.getHigh(point[1], 1), th) + for point in points: + sl = min(self.getLow(point[0]), sl) + sh = max(self.getHigh(point[0], 0), sh) + tl = min(self.getLow(point[1]), tl) + th = max(self.getHigh(point[1], 1), th) - return self.appendTile(sl, sh, tl, th) + return self.appendTile(sl, sh, tl, th) - def getDimensions(self): - return [abs(self.sl - self.sh) + 1, - abs(self.tl - self.th) + 1] + def getDimensions(self): + return [abs(self.sl - self.sh) + 1, abs(self.tl - self.th) + 1] -def saveMeshWithLargeTexturesByFaces(material, faces, fModel, fMesh, obj, drawLayer, - convertTextureData, currentGroupIndex, triConverterInfo, existingVertData, matRegionDict, - lastMaterialName): - ''' - lastMaterialName is for optimization; set it to None to disable optimization. - ''' - if len(faces) == 0: - print('0 Faces Provided.') - return +def saveMeshWithLargeTexturesByFaces( + material, + faces, + fModel, + fMesh, + obj, + drawLayer, + convertTextureData, + currentGroupIndex, + triConverterInfo, + existingVertData, + matRegionDict, + lastMaterialName, +): + """ + lastMaterialName is for optimization; set it to None to disable optimization. + """ - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material + if len(faces) == 0: + print("0 Faces Provided.") + return - fMaterial, texDimensions = \ - saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData) - isPointSampled = isTexturePointSampled(material) - exportVertexColors = isLightingDisabled(material) - uv_data = obj.data.uv_layers['UVMap'].data - convertInfo = LoopConvertInfo(uv_data, obj, exportVertexColors) + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material - if fMaterial.largeTextureIndex == 0: - texFormat = f3dMat.tex0.tex_format - otherTex = f3dMat.tex1 - otherTextureIndex = 1 - else: - texFormat = f3dMat.tex1.tex_format - otherTex = f3dMat.tex0 - otherTextureIndex = 0 + fMaterial, texDimensions = saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData) + isPointSampled = isTexturePointSampled(material) + exportVertexColors = isLightingDisabled(material) + uv_data = obj.data.uv_layers["UVMap"].data + convertInfo = LoopConvertInfo(uv_data, obj, exportVertexColors) - twoTextures = fMaterial.texturesLoaded[0] and fMaterial.texturesLoaded[1] - tileLoads = {} - faceTileLoads = {} - for face in faces: - uvs = [UVtoST(obj, loopIndex, uv_data, texDimensions, isPointSampled) for loopIndex in face.loops] - faceTileLoad = TileLoad(texFormat, twoTextures, texDimensions) - faceTileLoads[face] = faceTileLoad - if not faceTileLoad.tryAdd(uvs): - raise PluginError("Large texture material " + str(material.name) + " has a triangle that is too large to fit in a single tile load.") + if fMaterial.largeTextureIndex == 0: + texFormat = f3dMat.tex0.tex_format + otherTex = f3dMat.tex1 + otherTextureIndex = 1 + else: + texFormat = f3dMat.tex1.tex_format + otherTex = f3dMat.tex0 + otherTextureIndex = 0 - added = False - for tileLoad, sortedFaces in tileLoads.items(): - if tileLoad.tryAppend(faceTileLoad): - sortedFaces.append(face) - added = True - break - if not added: - tileLoads[faceTileLoad] = [face] + twoTextures = fMaterial.texturesLoaded[0] and fMaterial.texturesLoaded[1] + tileLoads = {} + faceTileLoads = {} + for face in faces: + uvs = [UVtoST(obj, loopIndex, uv_data, texDimensions, isPointSampled) for loopIndex in face.loops] + faceTileLoad = TileLoad(texFormat, twoTextures, texDimensions) + faceTileLoads[face] = faceTileLoad + if not faceTileLoad.tryAdd(uvs): + raise PluginError( + "Large texture material " + + str(material.name) + + " has a triangle that is too large to fit in a single tile load." + ) - tileLoads = list(tileLoads.items()) + added = False + for tileLoad, sortedFaces in tileLoads.items(): + if tileLoad.tryAppend(faceTileLoad): + sortedFaces.append(face) + added = True + break + if not added: + tileLoads[faceTileLoad] = [face] - if material.name != lastMaterialName: - fMesh.add_material_call(fMaterial) - triGroup = fMesh.tri_group_new(fMaterial) - fMesh.draw.commands.append(SPDisplayList(triGroup.triList)) + tileLoads = list(tileLoads.items()) - # For materials with tex0 and tex1, if the other texture can fit into a single tile load, - # we load it once at the beginning only. - otherTexSingleLoad = False - if fMaterial.texturesLoaded[otherTextureIndex]: - tmem = getTmemWordUsage(otherTex.tex_format, otherTex.tex.size[0], otherTex.tex.size[1]) * 8 - if tmem <= getTmemMax(otherTex.tex_format): - otherTexSingleLoad = True - #nextTmem = 0 - #revertCommands = GfxList("temp", GfxListTag.Draw, fModel.DLFormat) # Unhandled? - #texDimensions, nextTmem = \ - # saveTextureIndex(material.name, fModel, fMaterial, triGroup.triList, revertCommands, otherTex, 0, nextTmem, - # None, False, None, True, True) + if material.name != lastMaterialName: + fMesh.add_material_call(fMaterial) + triGroup = fMesh.tri_group_new(fMaterial) + fMesh.draw.commands.append(SPDisplayList(triGroup.triList)) - #saveGeometry(obj, triList, fMesh.vertexList, bFaces, - # bMesh, texDimensions, transformMatrix, isPointSampled, isFlatShaded, - # exportVertexColors, fModel.f3d) - currentGroupIndex = None - for tileLoad, tileFaces in tileLoads: - revertCommands = GfxList("temp", GfxListTag.Draw, fModel.DLFormat) - nextTmem = 0 - triGroup.triList.commands.append(DPPipeSync()) - if fMaterial.texturesLoaded[0] and not (otherTextureIndex == 0 and otherTexSingleLoad): - texDimensions0, nextTmem = \ - saveTextureIndex(material.name, fModel, fMaterial, triGroup.triList, revertCommands, f3dMat.tex0, 0, nextTmem, - None, False, [tileLoad, None], True, False) - if fMaterial.texturesLoaded[1] and not (otherTextureIndex == 1 and otherTexSingleLoad): - texDimensions1, nextTmem = saveTextureIndex(material.name, fModel, - fMaterial, triGroup.triList, revertCommands, f3dMat.tex1, 1, nextTmem, None, False, - [None, tileLoad], True, False) + # For materials with tex0 and tex1, if the other texture can fit into a single tile load, + # we load it once at the beginning only. + otherTexSingleLoad = False + if fMaterial.texturesLoaded[otherTextureIndex]: + tmem = getTmemWordUsage(otherTex.tex_format, otherTex.tex.size[0], otherTex.tex.size[1]) * 8 + if tmem <= getTmemMax(otherTex.tex_format): + otherTexSingleLoad = True + # nextTmem = 0 + # revertCommands = GfxList("temp", GfxListTag.Draw, fModel.DLFormat) # Unhandled? + # texDimensions, nextTmem = \ + # saveTextureIndex(material.name, fModel, fMaterial, triGroup.triList, revertCommands, otherTex, 0, nextTmem, + # None, False, None, True, True) - triConverter = TriangleConverter(triConverterInfo, texDimensions, material, currentGroupIndex, - triGroup.triList, triGroup.vertexList, - copy.deepcopy(existingVertData), copy.deepcopy(matRegionDict)) + # saveGeometry(obj, triList, fMesh.vertexList, bFaces, + # bMesh, texDimensions, transformMatrix, isPointSampled, isFlatShaded, + # exportVertexColors, fModel.f3d) + currentGroupIndex = None + for tileLoad, tileFaces in tileLoads: + revertCommands = GfxList("temp", GfxListTag.Draw, fModel.DLFormat) + nextTmem = 0 + triGroup.triList.commands.append(DPPipeSync()) + if fMaterial.texturesLoaded[0] and not (otherTextureIndex == 0 and otherTexSingleLoad): + texDimensions0, nextTmem = saveTextureIndex( + material.name, + fModel, + fMaterial, + triGroup.triList, + revertCommands, + f3dMat.tex0, + 0, + nextTmem, + None, + False, + [tileLoad, None], + True, + False, + ) + if fMaterial.texturesLoaded[1] and not (otherTextureIndex == 1 and otherTexSingleLoad): + texDimensions1, nextTmem = saveTextureIndex( + material.name, + fModel, + fMaterial, + triGroup.triList, + revertCommands, + f3dMat.tex1, + 1, + nextTmem, + None, + False, + [None, tileLoad], + True, + False, + ) - currentGroupIndex = saveTriangleStrip(triConverter, tileFaces, obj.data, False) + triConverter = TriangleConverter( + triConverterInfo, + texDimensions, + material, + currentGroupIndex, + triGroup.triList, + triGroup.vertexList, + copy.deepcopy(existingVertData), + copy.deepcopy(matRegionDict), + ) - if len(revertCommands.commands) > 0: - fMesh.draw.commands.extend(revertCommands.commands) + currentGroupIndex = saveTriangleStrip(triConverter, tileFaces, obj.data, False) - triGroup.triList.commands.append(SPEndDisplayList()) + if len(revertCommands.commands) > 0: + fMesh.draw.commands.extend(revertCommands.commands) - if fMaterial.revert is not None: - fMesh.draw.commands.append(SPDisplayList(fMaterial.revert)) + triGroup.triList.commands.append(SPEndDisplayList()) + + if fMaterial.revert is not None: + fMesh.draw.commands.append(SPDisplayList(fMaterial.revert)) + + return currentGroupIndex - return currentGroupIndex # Make sure to set original_name before calling this # used when duplicating an object -def saveStaticModel(triConverterInfo, fModel, obj, transformMatrix, ownerName, convertTextureData, revertMatAtEnd, drawLayerField): - if len(obj.data.polygons) == 0: - return None +def saveStaticModel( + triConverterInfo, fModel, obj, transformMatrix, ownerName, convertTextureData, revertMatAtEnd, drawLayerField +): + if len(obj.data.polygons) == 0: + return None - #checkForF3DMaterial(obj) + # checkForF3DMaterial(obj) - facesByMat = {} - for face in obj.data.loop_triangles: - if face.material_index not in facesByMat: - facesByMat[face.material_index] = [] - facesByMat[face.material_index].append(face) + facesByMat = {} + for face in obj.data.loop_triangles: + if face.material_index not in facesByMat: + facesByMat[face.material_index] = [] + facesByMat[face.material_index].append(face) - fMeshes = {} - for material_index, faces in facesByMat.items(): - material = obj.material_slots[material_index].material + fMeshes = {} + for material_index, faces in facesByMat.items(): + material = obj.material_slots[material_index].material - if drawLayerField is not None and material.mat_ver > 3: - drawLayer = getattr(material.f3d_mat.draw_layer, drawLayerField) - drawLayerName = drawLayer - else: - drawLayer = fModel.getDrawLayerV3(obj) - drawLayerName = None + if drawLayerField is not None and material.mat_ver > 3: + drawLayer = getattr(material.f3d_mat.draw_layer, drawLayerField) + drawLayerName = drawLayer + else: + drawLayer = fModel.getDrawLayerV3(obj) + drawLayerName = None - if drawLayer not in fMeshes: - fMesh = fModel.addMesh(obj.original_name, ownerName, drawLayerName, False, obj) - fMeshes[drawLayer] = fMesh + if drawLayer not in fMeshes: + fMesh = fModel.addMesh(obj.original_name, ownerName, drawLayerName, False, obj) + fMeshes[drawLayer] = fMesh - if obj.use_f3d_culling and (fModel.f3d.F3DEX_GBI or fModel.f3d.F3DEX_GBI_2): - addCullCommand(obj, fMesh, transformMatrix, fModel.matWriteMethod) - else: - fMesh = fMeshes[drawLayer] + if obj.use_f3d_culling and (fModel.f3d.F3DEX_GBI or fModel.f3d.F3DEX_GBI_2): + addCullCommand(obj, fMesh, transformMatrix, fModel.matWriteMethod) + else: + fMesh = fMeshes[drawLayer] - checkForF3dMaterialInFaces(obj, material) - fMaterial, texDimensions = \ - saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData) + checkForF3dMaterialInFaces(obj, material) + fMaterial, texDimensions = saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData) - if fMaterial.useLargeTextures: - saveMeshWithLargeTexturesByFaces(material, faces, fModel, fMesh, obj, drawLayer, convertTextureData, None, - triConverterInfo, None, None, None) - else: - saveMeshByFaces(material, faces, - fModel, fMesh, obj, drawLayer, convertTextureData, None, triConverterInfo, None, None, None) + if fMaterial.useLargeTextures: + saveMeshWithLargeTexturesByFaces( + material, + faces, + fModel, + fMesh, + obj, + drawLayer, + convertTextureData, + None, + triConverterInfo, + None, + None, + None, + ) + else: + saveMeshByFaces( + material, + faces, + fModel, + fMesh, + obj, + drawLayer, + convertTextureData, + None, + triConverterInfo, + None, + None, + None, + ) + + for drawLayer, fMesh in fMeshes.items(): + if revertMatAtEnd: + fModel.onEndDraw(fMesh, obj) + revertMatAndEndDraw(fMesh.draw, []) + else: + fModel.endDraw(fMesh, obj) + return fMeshes - for drawLayer, fMesh in fMeshes.items(): - if revertMatAtEnd: - fModel.onEndDraw(fMesh, obj) - revertMatAndEndDraw(fMesh.draw, []) - else: - fModel.endDraw(fMesh, obj) - return fMeshes def addCullCommand(obj, fMesh, transformMatrix, matWriteMethod): - fMesh.add_cull_vtx() - # if the object has a specifically set culling bounds, use that instead - for vertexPos in obj.get('culling_bounds', obj.bound_box): - # Most other fields of convertVertexData are unnecessary for bounding box verts - fMesh.cullVertexList.vertices.append( - convertVertexData(obj.data, - mathutils.Vector(vertexPos), [0,0], - mathutils.Vector([0,0,0,0]), [32, 32], - transformMatrix, False, False)) + fMesh.add_cull_vtx() + # if the object has a specifically set culling bounds, use that instead + for vertexPos in obj.get("culling_bounds", obj.bound_box): + # Most other fields of convertVertexData are unnecessary for bounding box verts + fMesh.cullVertexList.vertices.append( + convertVertexData( + obj.data, + mathutils.Vector(vertexPos), + [0, 0], + mathutils.Vector([0, 0, 0, 0]), + [32, 32], + transformMatrix, + False, + False, + ) + ) + + if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: + defaults = bpy.context.scene.world.rdp_defaults + if defaults.g_lighting: + cullCommands = [ + SPClearGeometryMode(["G_LIGHTING"]), + SPVertex(fMesh.cullVertexList, 0, 8, 0), + SPSetGeometryMode(["G_LIGHTING"]), + SPCullDisplayList(0, 7), + ] + else: + cullCommands = [SPVertex(fMesh.cullVertexList, 0, 8, 0), SPCullDisplayList(0, 7)] + elif matWriteMethod == GfxMatWriteMethod.WriteAll: + cullCommands = [ + SPClearGeometryMode(["G_LIGHTING"]), + SPVertex(fMesh.cullVertexList, 0, 8, 0), + SPCullDisplayList(0, 7), + ] + else: + raise PluginError("Unhandled material write method for f3d culling: " + str(matWriteMethod)) + fMesh.draw.commands = cullCommands + fMesh.draw.commands - if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - defaults = bpy.context.scene.world.rdp_defaults - if defaults.g_lighting: - cullCommands = [ - SPClearGeometryMode(['G_LIGHTING']), - SPVertex(fMesh.cullVertexList, 0, 8, 0), - SPSetGeometryMode(['G_LIGHTING']), - SPCullDisplayList(0, 7) - ] - else: - cullCommands = [ - SPVertex(fMesh.cullVertexList, 0, 8, 0), - SPCullDisplayList(0, 7) - ] - elif matWriteMethod == GfxMatWriteMethod.WriteAll: - cullCommands = [ - SPClearGeometryMode(['G_LIGHTING']), - SPVertex(fMesh.cullVertexList, 0, 8, 0), - SPCullDisplayList(0, 7) - ] - else: - raise PluginError("Unhandled material write method for f3d culling: " + str(matWriteMethod)) - fMesh.draw.commands = cullCommands + fMesh.draw.commands def exportF3DCommon(obj, fModel, transformMatrix, includeChildren, name, DLFormat, convertTextureData): - tempObj, meshList = combineObjects(obj, includeChildren, None, None) - try: - drawLayer = fModel.getDrawLayerV3(tempObj) - infoDict = getInfoDict(tempObj) - triConverterInfo = TriangleConverterInfo(tempObj, None, fModel.f3d, transformMatrix, infoDict) - fMesh = saveStaticModel(triConverterInfo, fModel, tempObj, - transformMatrix, name, convertTextureData, True, None)[drawLayer] - cleanupCombineObj(tempObj, meshList) - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - except Exception as e: - cleanupCombineObj(tempObj, meshList) - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - raise Exception(str(e)) + tempObj, meshList = combineObjects(obj, includeChildren, None, None) + try: + drawLayer = fModel.getDrawLayerV3(tempObj) + infoDict = getInfoDict(tempObj) + triConverterInfo = TriangleConverterInfo(tempObj, None, fModel.f3d, transformMatrix, infoDict) + fMesh = saveStaticModel( + triConverterInfo, fModel, tempObj, transformMatrix, name, convertTextureData, True, None + )[drawLayer] + cleanupCombineObj(tempObj, meshList) + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + except Exception as e: + cleanupCombineObj(tempObj, meshList) + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + raise Exception(str(e)) - return fMesh + return fMesh def checkForF3dMaterialInFaces(obj, material): - if not material.is_f3d: - raise PluginError("Material '" + material.name + "' on object '" + obj.name +\ - "' is not a Fast3D material. Replace it with a Fast3D material.") + if not material.is_f3d: + raise PluginError( + "Material '" + + material.name + + "' on object '" + + obj.name + + "' is not a Fast3D material. Replace it with a Fast3D material." + ) + def checkForF3DMaterial(obj): - if len(obj.material_slots) == 0: - raise PluginError(obj.name + " has no Fast3D material. Make sure to add a Fast3D material to it.") - for materialSlot in obj.material_slots: - if materialSlot.material is None or \ - not materialSlot.material.is_f3d: - raise PluginError(obj.name + " has either empty material slots " +\ - 'or non-Fast3D materials. Remove any regular blender materials / empty slots.') + if len(obj.material_slots) == 0: + raise PluginError(obj.name + " has no Fast3D material. Make sure to add a Fast3D material to it.") + for materialSlot in obj.material_slots: + if materialSlot.material is None or not materialSlot.material.is_f3d: + raise PluginError( + obj.name + + " has either empty material slots " + + "or non-Fast3D materials. Remove any regular blender materials / empty slots." + ) + def revertMatAndEndDraw(gfxList, otherCommands): - gfxList.commands.extend([ - DPPipeSync(), - SPSetGeometryMode(['G_LIGHTING']), - SPClearGeometryMode(['G_TEXTURE_GEN']), - DPSetCombineMode(*S_SHADED_SOLID), - SPTexture(0xFFFF, 0xFFFF, 0, 0, 0)] +\ - otherCommands) + gfxList.commands.extend( + [ + DPPipeSync(), + SPSetGeometryMode(["G_LIGHTING"]), + SPClearGeometryMode(["G_TEXTURE_GEN"]), + DPSetCombineMode(*S_SHADED_SOLID), + SPTexture(0xFFFF, 0xFFFF, 0, 0, 0), + ] + + otherCommands + ) + + if gfxList.DLFormat != DLFormat.Dynamic: + gfxList.commands.append(SPEndDisplayList()) - if gfxList.DLFormat != DLFormat.Dynamic: - gfxList.commands.append(SPEndDisplayList()) def getCommonEdge(face1, face2, mesh): - for edgeKey1 in face1.edge_keys: - for edgeKey2 in face2.edge_keys: - if edgeKey1 == edgeKey2: - return edgeKey1 - raise PluginError("No common edge between faces " + str(face1.index) + \ - ' and ' + str(face2.index)) + for edgeKey1 in face1.edge_keys: + for edgeKey2 in face2.edge_keys: + if edgeKey1 == edgeKey2: + return edgeKey1 + raise PluginError("No common edge between faces " + str(face1.index) + " and " + str(face2.index)) + def edgeValid(edgeValidDict, face, otherFace): - if (face, otherFace) in edgeValidDict: - return edgeValidDict[(face, otherFace)] - else: - return edgeValidDict[(otherFace, face)] + if (face, otherFace) in edgeValidDict: + return edgeValidDict[(face, otherFace)] + else: + return edgeValidDict[(otherFace, face)] + def getLowestUnvisitedNeighborCountFace(unvisitedFaces, infoDict): - lowestNeighborFace = unvisitedFaces[0] - lowestNeighborCount = len(infoDict.validNeighbors[lowestNeighborFace]) - for face in unvisitedFaces: - neighborCount = len(infoDict.validNeighbors[face]) - if neighborCount < lowestNeighborCount: - lowestNeighborFace = face - lowestNeighborCount = neighborCount - return lowestNeighborFace + lowestNeighborFace = unvisitedFaces[0] + lowestNeighborCount = len(infoDict.validNeighbors[lowestNeighborFace]) + for face in unvisitedFaces: + neighborCount = len(infoDict.validNeighbors[face]) + if neighborCount < lowestNeighborCount: + lowestNeighborFace = face + lowestNeighborCount = neighborCount + return lowestNeighborFace -def getNextNeighborFace(faces, face, lastEdgeKey, visitedFaces, possibleFaces, - infoDict): - if lastEdgeKey is not None: - handledEdgeKeys = [lastEdgeKey] - nextEdgeKey = face.edge_keys[ - (face.edge_keys.index(lastEdgeKey) + 1) % 3] - else: - handledEdgeKeys = [] - nextEdgeKey = face.edge_keys[0] +def getNextNeighborFace(faces, face, lastEdgeKey, visitedFaces, possibleFaces, infoDict): + + if lastEdgeKey is not None: + handledEdgeKeys = [lastEdgeKey] + nextEdgeKey = face.edge_keys[(face.edge_keys.index(lastEdgeKey) + 1) % 3] + else: + handledEdgeKeys = [] + nextEdgeKey = face.edge_keys[0] + + nextFaceAndEdge = (None, None) + while nextEdgeKey not in handledEdgeKeys: + for linkedFace in infoDict.edge[nextEdgeKey]: + if linkedFace == face or linkedFace not in faces: + continue + elif edgeValid(infoDict.edgeValid, linkedFace, face) and linkedFace not in visitedFaces: + if nextFaceAndEdge[0] is None: + # print(nextLoop.face) + nextFaceAndEdge = (linkedFace, nextEdgeKey) + else: + # Move face to front of queue + if linkedFace in possibleFaces: + possibleFaces.remove(linkedFace) + possibleFaces.insert(0, linkedFace) + handledEdgeKeys.append(nextEdgeKey) + nextEdgeKey = face.edge_keys[(face.edge_keys.index(nextEdgeKey) + 1) % 3] + return nextFaceAndEdge - nextFaceAndEdge = (None, None) - while nextEdgeKey not in handledEdgeKeys: - for linkedFace in infoDict.edge[nextEdgeKey]: - if linkedFace == face or linkedFace not in faces: - continue - elif edgeValid(infoDict.edgeValid, linkedFace, face) and \ - linkedFace not in visitedFaces: - if nextFaceAndEdge[0] is None: - #print(nextLoop.face) - nextFaceAndEdge = (linkedFace, nextEdgeKey) - else: - # Move face to front of queue - if linkedFace in possibleFaces: - possibleFaces.remove(linkedFace) - possibleFaces.insert(0, linkedFace) - handledEdgeKeys.append(nextEdgeKey) - nextEdgeKey = face.edge_keys[ - (face.edge_keys.index(nextEdgeKey) + 1) % 3] - return nextFaceAndEdge def saveTriangleStrip(triConverter, faces, mesh, terminateDL): - visitedFaces = [] - unvisitedFaces = copy.copy(faces) - possibleFaces = [] - lastEdgeKey = None - infoDict = triConverter.triConverterInfo.infoDict - neighborFace = getLowestUnvisitedNeighborCountFace(unvisitedFaces, infoDict) + visitedFaces = [] + unvisitedFaces = copy.copy(faces) + possibleFaces = [] + lastEdgeKey = None + infoDict = triConverter.triConverterInfo.infoDict + neighborFace = getLowestUnvisitedNeighborCountFace(unvisitedFaces, infoDict) - while len(visitedFaces) < len(faces): - #print(str(len(visitedFaces)) + " " + str(len(bFaces))) - if neighborFace is None: - if len(possibleFaces) > 0: - #print("get neighbor from queue") - neighborFace = possibleFaces[0] - lastEdgeKey = None - possibleFaces = [] - else: - #print('get new neighbor') - neighborFace = getLowestUnvisitedNeighborCountFace( - unvisitedFaces, infoDict) - lastEdgeKey = None + while len(visitedFaces) < len(faces): + # print(str(len(visitedFaces)) + " " + str(len(bFaces))) + if neighborFace is None: + if len(possibleFaces) > 0: + # print("get neighbor from queue") + neighborFace = possibleFaces[0] + lastEdgeKey = None + possibleFaces = [] + else: + # print('get new neighbor') + neighborFace = getLowestUnvisitedNeighborCountFace(unvisitedFaces, infoDict) + lastEdgeKey = None - triConverter.addFace(neighborFace) - if neighborFace in visitedFaces: - raise PluginError("Repeated face") - visitedFaces.append(neighborFace) - unvisitedFaces.remove(neighborFace) - if neighborFace in possibleFaces: - possibleFaces.remove(neighborFace) - for otherFace in infoDict.validNeighbors[neighborFace]: - infoDict.validNeighbors[otherFace].remove(neighborFace) + triConverter.addFace(neighborFace) + if neighborFace in visitedFaces: + raise PluginError("Repeated face") + visitedFaces.append(neighborFace) + unvisitedFaces.remove(neighborFace) + if neighborFace in possibleFaces: + possibleFaces.remove(neighborFace) + for otherFace in infoDict.validNeighbors[neighborFace]: + infoDict.validNeighbors[otherFace].remove(neighborFace) - neighborFace, lastEdgeKey = getNextNeighborFace(faces, - neighborFace, lastEdgeKey, visitedFaces, possibleFaces, infoDict) + neighborFace, lastEdgeKey = getNextNeighborFace( + faces, neighborFace, lastEdgeKey, visitedFaces, possibleFaces, infoDict + ) + + triConverter.finish(terminateDL) + return triConverter.currentGroupIndex - triConverter.finish(terminateDL) - return triConverter.currentGroupIndex # Necessary for UV half pixel offset (see 13.7.5.3) def isTexturePointSampled(material): - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - return f3dMat.rdp_settings.g_mdsft_text_filt == 'G_TF_POINT' + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + return f3dMat.rdp_settings.g_mdsft_text_filt == "G_TF_POINT" + def isLightingDisabled(material): - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - return not f3dMat.rdp_settings.g_lighting + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + return not f3dMat.rdp_settings.g_lighting + # Necessary as G_SHADE_SMOOTH actually does nothing def checkIfFlatShaded(material): - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - return not f3dMat.rdp_settings.g_shade_smooth + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + return not f3dMat.rdp_settings.g_shade_smooth -def saveMeshByFaces(material, faces, fModel, fMesh, obj, drawLayer, - convertTextureData, currentGroupIndex, triConverterInfo, - existingVertData, matRegionDict, lastMaterialName): - ''' - lastMaterialName is for optimization; set it to None to disable optimization. - ''' - if len(faces) == 0: - print('0 Faces Provided.') - return - fMaterial, texDimensions = \ - saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData) - isPointSampled = isTexturePointSampled(material) - exportVertexColors = isLightingDisabled(material) - uv_data = obj.data.uv_layers['UVMap'].data - convertInfo = LoopConvertInfo(uv_data, obj, exportVertexColors) +def saveMeshByFaces( + material, + faces, + fModel, + fMesh, + obj, + drawLayer, + convertTextureData, + currentGroupIndex, + triConverterInfo, + existingVertData, + matRegionDict, + lastMaterialName, +): + """ + lastMaterialName is for optimization; set it to None to disable optimization. + """ - if material.name != lastMaterialName: - fMesh.add_material_call(fMaterial) - triGroup = fMesh.tri_group_new(fMaterial) - fMesh.draw.commands.append(SPDisplayList(triGroup.triList)) + if len(faces) == 0: + print("0 Faces Provided.") + return + fMaterial, texDimensions = saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData) + isPointSampled = isTexturePointSampled(material) + exportVertexColors = isLightingDisabled(material) + uv_data = obj.data.uv_layers["UVMap"].data + convertInfo = LoopConvertInfo(uv_data, obj, exportVertexColors) - triConverter = TriangleConverter(triConverterInfo, texDimensions, material, - currentGroupIndex, triGroup.triList, triGroup.vertexList, - copy.deepcopy(existingVertData), copy.deepcopy(matRegionDict)) + if material.name != lastMaterialName: + fMesh.add_material_call(fMaterial) + triGroup = fMesh.tri_group_new(fMaterial) + fMesh.draw.commands.append(SPDisplayList(triGroup.triList)) - currentGroupIndex = saveTriangleStrip(triConverter, faces, obj.data, True) + triConverter = TriangleConverter( + triConverterInfo, + texDimensions, + material, + currentGroupIndex, + triGroup.triList, + triGroup.vertexList, + copy.deepcopy(existingVertData), + copy.deepcopy(matRegionDict), + ) - if fMaterial.revert is not None: - fMesh.draw.commands.append(SPDisplayList(fMaterial.revert)) + currentGroupIndex = saveTriangleStrip(triConverter, faces, obj.data, True) + + if fMaterial.revert is not None: + fMesh.draw.commands.append(SPDisplayList(fMaterial.revert)) + + return currentGroupIndex - return currentGroupIndex def get8bitRoundedNormal(loop, mesh): - alpha_layer = mesh.vertex_colors['Alpha'].data if 'Alpha' in \ - mesh.vertex_colors else None + alpha_layer = mesh.vertex_colors["Alpha"].data if "Alpha" in mesh.vertex_colors else None - if alpha_layer is not None: - normalizedAColor = alpha_layer[loop.index].color - normalizedA = mathutils.Color(normalizedAColor[0:3]).v - else: - normalizedA = 1 + if alpha_layer is not None: + normalizedAColor = alpha_layer[loop.index].color + normalizedA = mathutils.Color(normalizedAColor[0:3]).v + else: + normalizedA = 1 + + # Don't round, as this may move UV toward UV bounds. + return mathutils.Vector( + (int(loop.normal[0] * 128) / 128, int(loop.normal[1] * 128) / 128, int(loop.normal[2] * 128) / 128, normalizedA) + ) - # Don't round, as this may move UV toward UV bounds. - return mathutils.Vector( - (int(loop.normal[0] * 128) / 128, - int(loop.normal[1] * 128) / 128, - int(loop.normal[2] * 128) / 128, - normalizedA) - ) class LoopConvertInfo: - def __init__(self, uv_data, obj, exportVertexColors): - self.uv_data = uv_data - self.obj = obj - self.exportVertexColors = exportVertexColors + def __init__(self, uv_data, obj, exportVertexColors): + self.uv_data = uv_data + self.obj = obj + self.exportVertexColors = exportVertexColors + def getNewIndices(existingIndices, bufferStart): - n = bufferStart - newIndices = [] - for index in existingIndices: - if index is None: - newIndices.append(n) - n += 1 - else: - newIndices.append(index) - return newIndices + n = bufferStart + newIndices = [] + for index in existingIndices: + if index is None: + newIndices.append(n) + n += 1 + else: + newIndices.append(index) + return newIndices + class BufferVertex: - def __init__(self, f3dVert, groupIndex, materialIndex): - self.f3dVert = f3dVert - self.groupIndex = groupIndex - self.materialIndex = materialIndex + def __init__(self, f3dVert, groupIndex, materialIndex): + self.f3dVert = f3dVert + self.groupIndex = groupIndex + self.materialIndex = materialIndex - def __eq__(self, other): - return self.f3dVert == other.f3dVert and \ - self.groupIndex == other.groupIndex and \ - self.materialIndex == other.materialIndex + def __eq__(self, other): + return ( + self.f3dVert == other.f3dVert + and self.groupIndex == other.groupIndex + and self.materialIndex == other.materialIndex + ) class TriangleConverterInfo: - def __init__(self, obj, armature, f3d, transformMatrix, infoDict): - self.infoDict = infoDict - self.vertexGroupInfo = self.infoDict.vertexGroupInfo - self.armature = armature - self.obj = obj - self.mesh = obj.data - self.f3d = f3d - self.transformMatrix = transformMatrix + def __init__(self, obj, armature, f3d, transformMatrix, infoDict): + self.infoDict = infoDict + self.vertexGroupInfo = self.infoDict.vertexGroupInfo + self.armature = armature + self.obj = obj + self.mesh = obj.data + self.f3d = f3d + self.transformMatrix = transformMatrix - # Caching names - self.groupNames = {} + # Caching names + self.groupNames = {} - def getMatrixAddrFromGroup(self, groupIndex): - raise PluginError("TriangleConverterInfo must be extended with getMatrixAddrFromGroup implemented for game specific uses.") + def getMatrixAddrFromGroup(self, groupIndex): + raise PluginError( + "TriangleConverterInfo must be extended with getMatrixAddrFromGroup implemented for game specific uses." + ) + + def getTransformMatrix(self, groupIndex): + if self.armature is None or groupIndex is None: + groupMatrix = mathutils.Matrix.Identity(4) + else: + if groupIndex not in self.groupNames: + self.groupNames[groupIndex] = getGroupNameFromIndex(self.obj, groupIndex) + name = self.groupNames[groupIndex] + if name not in self.armature.bones: + print("Vertex group " + name + " not found in bones.") + groupMatrix = mathutils.Matrix.Identity(4) + else: + groupMatrix = self.armature.bones[name].matrix_local.inverted() + return self.transformMatrix @ groupMatrix - def getTransformMatrix(self, groupIndex): - if self.armature is None or groupIndex is None: - groupMatrix = mathutils.Matrix.Identity(4) - else: - if groupIndex not in self.groupNames: - self.groupNames[groupIndex] = getGroupNameFromIndex(self.obj, groupIndex) - name = self.groupNames[groupIndex] - if name not in self.armature.bones: - print("Vertex group " + name + " not found in bones.") - groupMatrix = mathutils.Matrix.Identity(4) - else: - groupMatrix = self.armature.bones[name].matrix_local.inverted() - return self.transformMatrix @ groupMatrix # existingVertexData is used for cases where we want to assume the presence of vertex data # loaded in from a previous matrix transform (ex. sm64 skinning) class TriangleConverter: - def __init__(self, triConverterInfo, texDimensions, material, currentGroupIndex, - triList, vtxList, existingVertexData, existingVertexMaterialRegions): - self.triConverterInfo = triConverterInfo - self.currentGroupIndex = currentGroupIndex - self.originalGroupIndex = currentGroupIndex + def __init__( + self, + triConverterInfo, + texDimensions, + material, + currentGroupIndex, + triList, + vtxList, + existingVertexData, + existingVertexMaterialRegions, + ): + self.triConverterInfo = triConverterInfo + self.currentGroupIndex = currentGroupIndex + self.originalGroupIndex = currentGroupIndex - # Existing data assumed to be already loaded in. - if existingVertexData is not None: - # [(position, uv, colorOrNormal)] - self.vertBuffer = existingVertexData - else: - self.vertBuffer = [] - self.existingVertexMaterialRegions = existingVertexMaterialRegions - self.bufferStart = len(self.vertBuffer) - self.vertexBufferTriangles = [] # [(index0, index1, index2)] + # Existing data assumed to be already loaded in. + if existingVertexData is not None: + # [(position, uv, colorOrNormal)] + self.vertBuffer = existingVertexData + else: + self.vertBuffer = [] + self.existingVertexMaterialRegions = existingVertexMaterialRegions + self.bufferStart = len(self.vertBuffer) + self.vertexBufferTriangles = [] # [(index0, index1, index2)] - self.triList = triList - self.vtxList = vtxList + self.triList = triList + self.vtxList = vtxList - isPointSampled = isTexturePointSampled(material) - exportVertexColors = isLightingDisabled(material) - uv_data = triConverterInfo.obj.data.uv_layers['UVMap'].data - self.convertInfo = LoopConvertInfo(uv_data, triConverterInfo.obj, exportVertexColors) - self.texDimensions = texDimensions - self.isPointSampled = isPointSampled - self.exportVertexColors = exportVertexColors + isPointSampled = isTexturePointSampled(material) + exportVertexColors = isLightingDisabled(material) + uv_data = triConverterInfo.obj.data.uv_layers["UVMap"].data + self.convertInfo = LoopConvertInfo(uv_data, triConverterInfo.obj, exportVertexColors) + self.texDimensions = texDimensions + self.isPointSampled = isPointSampled + self.exportVertexColors = exportVertexColors + def vertInBuffer(self, bufferVert, material_index): + if self.existingVertexMaterialRegions is None: + return bufferVert in self.vertBuffer + else: + if material_index in self.existingVertexMaterialRegions: + matRegion = self.existingVertexMaterialRegions[material_index] + if bufferVert in self.vertBuffer[matRegion[0] : matRegion[1]]: + return True + return bufferVert in self.vertBuffer[self.bufferStart :] - def vertInBuffer(self, bufferVert, material_index): - if self.existingVertexMaterialRegions is None: - return bufferVert in self.vertBuffer - else: - if material_index in self.existingVertexMaterialRegions: - matRegion = self.existingVertexMaterialRegions[material_index] - if bufferVert in self.vertBuffer[matRegion[0] : matRegion[1]]: - return True + def getSortedBuffer(self): + limbVerts = {} + for bufferVert in self.vertBuffer[self.bufferStart :]: + if bufferVert.groupIndex not in limbVerts: + limbVerts[bufferVert.groupIndex] = [] + limbVerts[bufferVert.groupIndex].append(bufferVert) - return bufferVert in self.vertBuffer[self.bufferStart : ] + return limbVerts - def getSortedBuffer(self): - limbVerts = {} - for bufferVert in self.vertBuffer[self.bufferStart:]: - if bufferVert.groupIndex not in limbVerts: - limbVerts[bufferVert.groupIndex] = [] - limbVerts[bufferVert.groupIndex].append(bufferVert) + def processGeometry(self): + # Sort verts by limb index, then load current limb verts + bufferStart = self.bufferStart + bufferEnd = self.bufferStart + limbVerts = self.getSortedBuffer() - return limbVerts + if self.currentGroupIndex in limbVerts: + currentLimbVerts = limbVerts[self.currentGroupIndex] + self.vertBuffer = self.vertBuffer[: self.bufferStart] + currentLimbVerts + self.triList.commands.append( + SPVertex(self.vtxList, len(self.vtxList.vertices), len(currentLimbVerts), self.bufferStart) + ) + bufferEnd += len(currentLimbVerts) + del limbVerts[self.currentGroupIndex] - def processGeometry(self): - # Sort verts by limb index, then load current limb verts - bufferStart = self.bufferStart - bufferEnd = self.bufferStart - limbVerts = self.getSortedBuffer() + # Save vertices + for bufferVert in self.vertBuffer[bufferStart:bufferEnd]: + self.vtxList.vertices.append( + convertVertexData( + self.triConverterInfo.mesh, + bufferVert.f3dVert[0], + bufferVert.f3dVert[1], + bufferVert.f3dVert[2], + self.texDimensions, + self.triConverterInfo.getTransformMatrix(bufferVert.groupIndex), + self.isPointSampled, + self.exportVertexColors, + ) + ) - if self.currentGroupIndex in limbVerts: - currentLimbVerts = limbVerts[self.currentGroupIndex] - self.vertBuffer = self.vertBuffer[:self.bufferStart] + currentLimbVerts - self.triList.commands.append( - SPVertex(self.vtxList, len(self.vtxList.vertices), - len(currentLimbVerts), self.bufferStart)) - bufferEnd += len(currentLimbVerts) - del limbVerts[self.currentGroupIndex] + bufferStart = bufferEnd + else: + self.vertBuffer = self.vertBuffer[: self.bufferStart] - # Save vertices - for bufferVert in self.vertBuffer[bufferStart : bufferEnd]: - self.vtxList.vertices.append(convertVertexData(self.triConverterInfo.mesh, - bufferVert.f3dVert[0], bufferVert.f3dVert[1], bufferVert.f3dVert[2], self.texDimensions, - self.triConverterInfo.getTransformMatrix(bufferVert.groupIndex), self.isPointSampled, - self.exportVertexColors)) + # Load other limb verts + for groupIndex, bufferVerts in limbVerts.items(): + if groupIndex != self.currentGroupIndex: + self.triList.commands.append( + SPMatrix(self.triConverterInfo.getMatrixAddrFromGroup(groupIndex), "G_MTX_LOAD") + ) + self.currentGroupIndex = groupIndex + self.triList.commands.append( + SPVertex(self.vtxList, len(self.vtxList.vertices), len(bufferVerts), bufferStart) + ) - bufferStart = bufferEnd - else: - self.vertBuffer = self.vertBuffer[:self.bufferStart] + self.vertBuffer += bufferVerts + bufferEnd += len(bufferVerts) - # Load other limb verts - for groupIndex, bufferVerts in limbVerts.items(): - if groupIndex != self.currentGroupIndex: - self.triList.commands.append(SPMatrix(self.triConverterInfo.getMatrixAddrFromGroup(groupIndex), "G_MTX_LOAD")) - self.currentGroupIndex = groupIndex - self.triList.commands.append( - SPVertex(self.vtxList, len(self.vtxList.vertices), - len(bufferVerts), bufferStart)) + # Save vertices + for bufferVert in self.vertBuffer[bufferStart:bufferEnd]: + self.vtxList.vertices.append( + convertVertexData( + self.triConverterInfo.mesh, + bufferVert.f3dVert[0], + bufferVert.f3dVert[1], + bufferVert.f3dVert[2], + self.texDimensions, + self.triConverterInfo.getTransformMatrix(bufferVert.groupIndex), + self.isPointSampled, + self.exportVertexColors, + ) + ) - self.vertBuffer += bufferVerts - bufferEnd += len(bufferVerts) + bufferStart = bufferEnd - # Save vertices - for bufferVert in self.vertBuffer[bufferStart : bufferEnd]: - self.vtxList.vertices.append(convertVertexData(self.triConverterInfo.mesh, - bufferVert.f3dVert[0], bufferVert.f3dVert[1], bufferVert.f3dVert[2], self.texDimensions, - self.triConverterInfo.getTransformMatrix(bufferVert.groupIndex), self.isPointSampled, - self.exportVertexColors)) + # Load triangles + self.triList.commands.extend( + createTriangleCommands(self.vertexBufferTriangles, self.vertBuffer, self.triConverterInfo.f3d.F3DEX_GBI) + ) - bufferStart = bufferEnd + def addFace(self, face): + triIndices = [] + addedVerts = [] # verts added to existing vertexBuffer + allVerts = [] # all verts not in 'untouched' buffer region - # Load triangles - self.triList.commands.extend(createTriangleCommands( - self.vertexBufferTriangles, self.vertBuffer, self.triConverterInfo.f3d.F3DEX_GBI)) + for loopIndex in face.loops: + loop = self.triConverterInfo.mesh.loops[loopIndex] + vertexGroup = ( + self.triConverterInfo.vertexGroupInfo.vertexGroups[loop.vertex_index] + if self.triConverterInfo.vertexGroupInfo is not None + else None + ) + bufferVert = BufferVertex( + getF3DVert(loop, face, self.convertInfo, self.triConverterInfo.mesh), vertexGroup, face.material_index + ) + triIndices.append(bufferVert) + if not self.vertInBuffer(bufferVert, face.material_index): + addedVerts.append(bufferVert) - def addFace(self, face): - triIndices = [] - addedVerts = [] # verts added to existing vertexBuffer - allVerts = [] # all verts not in 'untouched' buffer region + if bufferVert not in self.vertBuffer[: self.bufferStart]: + allVerts.append(bufferVert) - for loopIndex in face.loops: - loop = self.triConverterInfo.mesh.loops[loopIndex] - vertexGroup = self.triConverterInfo.vertexGroupInfo.vertexGroups[loop.vertex_index] if self.triConverterInfo.vertexGroupInfo is not None else None - bufferVert = BufferVertex(getF3DVert(loop, face, self.convertInfo, self.triConverterInfo.mesh), - vertexGroup, face.material_index) - triIndices.append(bufferVert) - if not self.vertInBuffer(bufferVert, face.material_index): - addedVerts.append(bufferVert) + # We care only about load size, since loading is what takes up time. + # Even if vert_buffer is larger, its still another load to fill it. + if len(self.vertBuffer) + len(addedVerts) > self.triConverterInfo.f3d.vert_load_size: + self.processGeometry() + self.vertBuffer = self.vertBuffer[: self.bufferStart] + allVerts + self.vertexBufferTriangles = [triIndices] + else: + self.vertBuffer.extend(addedVerts) + self.vertexBufferTriangles.append(triIndices) - if bufferVert not in self.vertBuffer[:self.bufferStart]: - allVerts.append(bufferVert) + def finish(self, terminateDL): + if len(self.vertexBufferTriangles) > 0: + self.processGeometry() - # We care only about load size, since loading is what takes up time. - # Even if vert_buffer is larger, its still another load to fill it. - if len(self.vertBuffer) + len(addedVerts) > self.triConverterInfo.f3d.vert_load_size: - self.processGeometry() - self.vertBuffer = self.vertBuffer[:self.bufferStart] + allVerts - self.vertexBufferTriangles = [triIndices] - else: - self.vertBuffer.extend(addedVerts) - self.vertexBufferTriangles.append(triIndices) + # if self.originalGroupIndex != self.currentGroupIndex: + # self.triList.commands.append(SPMatrix(getMatrixAddrFromGroup(self.originalGroupIndex), "G_MTX_LOAD")) + if terminateDL: + self.triList.commands.append(SPEndDisplayList()) - def finish(self, terminateDL): - if len(self.vertexBufferTriangles) > 0: - self.processGeometry() - - #if self.originalGroupIndex != self.currentGroupIndex: - # self.triList.commands.append(SPMatrix(getMatrixAddrFromGroup(self.originalGroupIndex), "G_MTX_LOAD")) - if terminateDL: - self.triList.commands.append(SPEndDisplayList()) def getF3DVert(loop, face, convertInfo, mesh): - position = mesh.vertices[loop.vertex_index].co.copy().freeze() - # N64 is -Y, Blender is +Y - uv = convertInfo.uv_data[loop.index].uv.copy() - uv[:] = [field if not math.isnan(field) else 0 for field in uv] - uv[1] = 1 - uv[1] - uv = uv.freeze() - colorOrNormal = getLoopColorOrNormal(loop, face, - convertInfo.obj.data, convertInfo.obj, convertInfo.exportVertexColors) + position = mesh.vertices[loop.vertex_index].co.copy().freeze() + # N64 is -Y, Blender is +Y + uv = convertInfo.uv_data[loop.index].uv.copy() + uv[:] = [field if not math.isnan(field) else 0 for field in uv] + uv[1] = 1 - uv[1] + uv = uv.freeze() + colorOrNormal = getLoopColorOrNormal( + loop, face, convertInfo.obj.data, convertInfo.obj, convertInfo.exportVertexColors + ) + + return (position, uv, colorOrNormal) - return (position, uv, colorOrNormal) def getLoopNormal(loop, face, mesh, isFlatShaded): - # This is a workaround for flat shading not working well. - # Since we support custom blender normals we can now ignore this. - #if isFlatShaded: - # normal = -face.normal #??? - #else: - # normal = -loop.normal #??? - #return get8bitRoundedNormal(normal).freeze() - return get8bitRoundedNormal(loop, mesh).freeze() + # This is a workaround for flat shading not working well. + # Since we support custom blender normals we can now ignore this. + # if isFlatShaded: + # normal = -face.normal #??? + # else: + # normal = -loop.normal #??? + # return get8bitRoundedNormal(normal).freeze() + return get8bitRoundedNormal(loop, mesh).freeze() -''' + +""" def getLoopNormalCreased(bLoop, obj): edges = obj.data.edges centerVert = bLoop.vert @@ -994,1498 +1163,1855 @@ def getHighestFaceWeight(faceWeights): if faceWeight.weight > highestFaceWeight.weight: highestFaceWeight = faceWeight return highestFaceWeight -''' +""" + def UVtoST(obj, loopIndex, uv_data, texDimensions, isPointSampled): - uv = uv_data[loopIndex].uv.copy() - uv[1] = 1 - uv[1] - loopUV = uv.freeze() + uv = uv_data[loopIndex].uv.copy() + uv[1] = 1 - uv[1] + loopUV = uv.freeze() - pixelOffset = 0 if isPointSampled else 0.5 - return [ - convertFloatToFixed16(loopUV[0] * texDimensions[0] - pixelOffset) / 32, - convertFloatToFixed16(loopUV[1] * texDimensions[1] - pixelOffset) / 32 - ] + pixelOffset = 0 if isPointSampled else 0.5 + return [ + convertFloatToFixed16(loopUV[0] * texDimensions[0] - pixelOffset) / 32, + convertFloatToFixed16(loopUV[1] * texDimensions[1] - pixelOffset) / 32, + ] -def convertVertexData(mesh, loopPos, loopUV, loopColorOrNormal, - texDimensions, transformMatrix, isPointSampled, exportVertexColors): - #uv_layer = mesh.uv_layers.active - #color_layer = mesh.vertex_colors['Col'] - #alpha_layer = mesh.vertex_colors['Alpha'] +def convertVertexData( + mesh, loopPos, loopUV, loopColorOrNormal, texDimensions, transformMatrix, isPointSampled, exportVertexColors +): + # uv_layer = mesh.uv_layers.active + # color_layer = mesh.vertex_colors['Col'] + # alpha_layer = mesh.vertex_colors['Alpha'] - # Position (8 bytes) - position = [int(round(floatValue)) for \ - floatValue in (transformMatrix @ loopPos)] + # Position (8 bytes) + position = [int(round(floatValue)) for floatValue in (transformMatrix @ loopPos)] - # UV (4 bytes) - # For F3D, Bilinear samples the point from the center of the pixel. - # However, Point samples from the corner. - # Thus we add 0.5 to the UV only if bilinear filtering. - # see section 13.7.5.3 in programming manual. - pixelOffset = 0 if isPointSampled else 0.5 - uv = [ - convertFloatToFixed16(loopUV[0] * texDimensions[0] - pixelOffset), - convertFloatToFixed16(loopUV[1] * texDimensions[1] - pixelOffset) - ] + # UV (4 bytes) + # For F3D, Bilinear samples the point from the center of the pixel. + # However, Point samples from the corner. + # Thus we add 0.5 to the UV only if bilinear filtering. + # see section 13.7.5.3 in programming manual. + pixelOffset = 0 if isPointSampled else 0.5 + uv = [ + convertFloatToFixed16(loopUV[0] * texDimensions[0] - pixelOffset), + convertFloatToFixed16(loopUV[1] * texDimensions[1] - pixelOffset), + ] - # Color/Normal (4 bytes) - if exportVertexColors: - colorOrNormal = [ - int(round(loopColorOrNormal[0] * 255)).to_bytes(1, 'big')[0], - int(round(loopColorOrNormal[1] * 255)).to_bytes(1, 'big')[0], - int(round(loopColorOrNormal[2] * 255)).to_bytes(1, 'big')[0], - int(round(loopColorOrNormal[3] * 255)).to_bytes(1, 'big')[0] - ] - else: - # normal transformed correctly. - normal = (transformMatrix.inverted().transposed() @ \ - loopColorOrNormal).normalized() - colorOrNormal = [ - int(round(normal[0] * 127)).to_bytes(1, 'big', signed = True)[0], - int(round(normal[1] * 127)).to_bytes(1, 'big', signed = True)[0], - int(round(normal[2] * 127)).to_bytes(1, 'big', signed = True)[0], - int(round(loopColorOrNormal[3] * 255)).to_bytes(1, 'big')[0], - ] + # Color/Normal (4 bytes) + if exportVertexColors: + colorOrNormal = [ + int(round(loopColorOrNormal[0] * 255)).to_bytes(1, "big")[0], + int(round(loopColorOrNormal[1] * 255)).to_bytes(1, "big")[0], + int(round(loopColorOrNormal[2] * 255)).to_bytes(1, "big")[0], + int(round(loopColorOrNormal[3] * 255)).to_bytes(1, "big")[0], + ] + else: + # normal transformed correctly. + normal = (transformMatrix.inverted().transposed() @ loopColorOrNormal).normalized() + colorOrNormal = [ + int(round(normal[0] * 127)).to_bytes(1, "big", signed=True)[0], + int(round(normal[1] * 127)).to_bytes(1, "big", signed=True)[0], + int(round(normal[2] * 127)).to_bytes(1, "big", signed=True)[0], + int(round(loopColorOrNormal[3] * 255)).to_bytes(1, "big")[0], + ] + + return Vtx(position, uv, colorOrNormal) - return Vtx(position, uv, colorOrNormal) def getLoopColor(loop, mesh, mat_ver): - color_layer = mesh.vertex_colors['Col'].data if 'Col' in \ - mesh.vertex_colors else None - alpha_layer = mesh.vertex_colors['Alpha'].data if 'Alpha' in \ - mesh.vertex_colors else None + color_layer = mesh.vertex_colors["Col"].data if "Col" in mesh.vertex_colors else None + alpha_layer = mesh.vertex_colors["Alpha"].data if "Alpha" in mesh.vertex_colors else None - if color_layer is not None: - normalizedRGB = color_layer[loop.index].color - else: - normalizedRGB = [1,1,1] - if alpha_layer is not None: - normalizedAColor = alpha_layer[loop.index].color - normalizedA = mathutils.Color(normalizedAColor[0:3]).v - else: - normalizedA = 1 + if color_layer is not None: + normalizedRGB = color_layer[loop.index].color + else: + normalizedRGB = [1, 1, 1] + if alpha_layer is not None: + normalizedAColor = alpha_layer[loop.index].color + normalizedA = mathutils.Color(normalizedAColor[0:3]).v + else: + normalizedA = 1 + + return (normalizedRGB[0], normalizedRGB[1], normalizedRGB[2], normalizedA) - return (normalizedRGB[0], normalizedRGB[1], normalizedRGB[2], normalizedA) def getLoopColorOrNormal(loop, face, mesh, obj, exportVertexColors): - material = obj.material_slots[face.material_index].material - isFlatShaded = checkIfFlatShaded(material) - if exportVertexColors: - return getLoopColor(loop, mesh, material.mat_ver) - else: - return getLoopNormal(loop, face, mesh, isFlatShaded) + material = obj.material_slots[face.material_index].material + isFlatShaded = checkIfFlatShaded(material) + if exportVertexColors: + return getLoopColor(loop, mesh, material.mat_ver) + else: + return getLoopNormal(loop, face, mesh, isFlatShaded) + def createTriangleCommands(triangles, vertexBuffer, useSP2Triangle): - triangles = copy.deepcopy(triangles) - commands = [] - if useSP2Triangle: - while len(triangles) > 0: - if len(triangles) >= 2: - commands.append(SP2Triangles( - vertexBuffer.index(triangles[0][0]), - vertexBuffer.index(triangles[0][1]), - vertexBuffer.index(triangles[0][2]), 0, - vertexBuffer.index(triangles[1][0]), - vertexBuffer.index(triangles[1][1]), - vertexBuffer.index(triangles[1][2]), 0)) - triangles = triangles[2:] - else: - commands.append(SP1Triangle( - vertexBuffer.index(triangles[0][0]), - vertexBuffer.index(triangles[0][1]), - vertexBuffer.index(triangles[0][2]), 0)) - triangles = [] - else: - while len(triangles) > 0: - commands.append(SP1Triangle( - vertexBuffer.index(triangles[0][0]), - vertexBuffer.index(triangles[0][1]), - vertexBuffer.index(triangles[0][2]), 0)) - triangles = triangles[1:] + triangles = copy.deepcopy(triangles) + commands = [] + if useSP2Triangle: + while len(triangles) > 0: + if len(triangles) >= 2: + commands.append( + SP2Triangles( + vertexBuffer.index(triangles[0][0]), + vertexBuffer.index(triangles[0][1]), + vertexBuffer.index(triangles[0][2]), + 0, + vertexBuffer.index(triangles[1][0]), + vertexBuffer.index(triangles[1][1]), + vertexBuffer.index(triangles[1][2]), + 0, + ) + ) + triangles = triangles[2:] + else: + commands.append( + SP1Triangle( + vertexBuffer.index(triangles[0][0]), + vertexBuffer.index(triangles[0][1]), + vertexBuffer.index(triangles[0][2]), + 0, + ) + ) + triangles = [] + else: + while len(triangles) > 0: + commands.append( + SP1Triangle( + vertexBuffer.index(triangles[0][0]), + vertexBuffer.index(triangles[0][1]), + vertexBuffer.index(triangles[0][2]), + 0, + ) + ) + triangles = triangles[1:] + + return commands - return commands # white diffuse, grey ambient, normal = (1,1,1) defaultLighting = [ - (mathutils.Vector((1,1,1)), mathutils.Vector((1, 1, 1)).normalized()), - (mathutils.Vector((0.5, 0.5, 0.5)), mathutils.Vector((1, 1, 1)).normalized())] + (mathutils.Vector((1, 1, 1)), mathutils.Vector((1, 1, 1)).normalized()), + (mathutils.Vector((0.5, 0.5, 0.5)), mathutils.Vector((1, 1, 1)).normalized()), +] + def getTexDimensions(material): - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - texDimensions0 = None - texDimensions1 = None - useDict = all_combiner_uses(f3dMat) - if useDict['Texture 0'] and f3dMat.tex0.tex_set: - if f3dMat.tex0.use_tex_reference: - texDimensions0 = f3dMat.tex0.tex_reference_size - else: - if f3dMat.tex0.tex is None: - raise PluginError('In material \"' + material.name + '\", a texture has not been set.') - texDimensions0 = f3dMat.tex0.tex.size[0], f3dMat.tex0.tex.size[1] - if useDict['Texture 1'] and f3dMat.tex1.tex_set: - if f3dMat.tex1.use_tex_reference: - texDimensions1 = f3dMat.tex1.tex_reference_size - else: - if f3dMat.tex1.tex is None: - raise PluginError('In material \"' + material.name + '\", a texture has not been set.') - texDimensions1 = f3dMat.tex1.tex.size[0], f3dMat.tex1.tex.size[1] + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + texDimensions0 = None + texDimensions1 = None + useDict = all_combiner_uses(f3dMat) + if useDict["Texture 0"] and f3dMat.tex0.tex_set: + if f3dMat.tex0.use_tex_reference: + texDimensions0 = f3dMat.tex0.tex_reference_size + else: + if f3dMat.tex0.tex is None: + raise PluginError('In material "' + material.name + '", a texture has not been set.') + texDimensions0 = f3dMat.tex0.tex.size[0], f3dMat.tex0.tex.size[1] + if useDict["Texture 1"] and f3dMat.tex1.tex_set: + if f3dMat.tex1.use_tex_reference: + texDimensions1 = f3dMat.tex1.tex_reference_size + else: + if f3dMat.tex1.tex is None: + raise PluginError('In material "' + material.name + '", a texture has not been set.') + texDimensions1 = f3dMat.tex1.tex.size[0], f3dMat.tex1.tex.size[1] + + if texDimensions0 is not None and texDimensions1 is not None: + texDimensions = texDimensions0 if f3dMat.uv_basis == "TEXEL0" else texDimensions1 + elif texDimensions0 is not None: + texDimensions = texDimensions0 + elif texDimensions1 is not None: + texDimensions = texDimensions1 + else: + texDimensions = [32, 32] + return texDimensions - if texDimensions0 is not None and texDimensions1 is not None: - texDimensions = texDimensions0 if f3dMat.uv_basis == 'TEXEL0' \ - else texDimensions1 - elif texDimensions0 is not None: - texDimensions = texDimensions0 - elif texDimensions1 is not None: - texDimensions = texDimensions1 - else: - texDimensions = [32, 32] - return texDimensions def saveOrGetF3DMaterial(material, fModel, obj, drawLayer, convertTextureData): - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material - areaKey = fModel.global_data.getCurrentAreaKey(f3dMat) - areaIndex = fModel.global_data.current_area_index + areaKey = fModel.global_data.getCurrentAreaKey(f3dMat) + areaIndex = fModel.global_data.current_area_index - if f3dMat.rdp_settings.set_rendermode: - materialKey = (material, drawLayer, areaKey) - else: - materialKey = (material, None, areaKey) + if f3dMat.rdp_settings.set_rendermode: + materialKey = (material, drawLayer, areaKey) + else: + materialKey = (material, None, areaKey) - materialItem = fModel.getMaterialAndHandleShared(materialKey) - if materialItem is not None: - return materialItem + materialItem = fModel.getMaterialAndHandleShared(materialKey) + if materialItem is not None: + return materialItem - if len(obj.data.materials) == 0: - raise PluginError("Mesh must have at least one material.") - materialName = fModel.name + "_" + toAlnum(material.name) + (('_layer' + str(drawLayer)) \ - if f3dMat.rdp_settings.set_rendermode and drawLayer is not None else '') +\ - (('_area' + str(areaIndex)) if \ - f3dMat.set_fog and f3dMat.use_global_fog and areaKey is not None else '') - fMaterial = FMaterial(materialName, fModel.DLFormat) - fMaterial.material.commands.append(DPPipeSync()) - fMaterial.revert.commands.append(DPPipeSync()) + if len(obj.data.materials) == 0: + raise PluginError("Mesh must have at least one material.") + materialName = ( + fModel.name + + "_" + + toAlnum(material.name) + + (("_layer" + str(drawLayer)) if f3dMat.rdp_settings.set_rendermode and drawLayer is not None else "") + + (("_area" + str(areaIndex)) if f3dMat.set_fog and f3dMat.use_global_fog and areaKey is not None else "") + ) + fMaterial = FMaterial(materialName, fModel.DLFormat) + fMaterial.material.commands.append(DPPipeSync()) + fMaterial.revert.commands.append(DPPipeSync()) - if not material.is_f3d: - raise PluginError("Material named " + material.name + \ - ' is not an F3D material.') + if not material.is_f3d: + raise PluginError("Material named " + material.name + " is not an F3D material.") - fMaterial.getScrollData(material, getMaterialScrollDimensions(f3dMat)) + fMaterial.getScrollData(material, getMaterialScrollDimensions(f3dMat)) - if f3dMat.set_combiner: - if f3dMat.rdp_settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - fMaterial.material.commands.append( - DPSetCombineMode( - f3dMat.combiner1.A, - f3dMat.combiner1.B, - f3dMat.combiner1.C, - f3dMat.combiner1.D, - f3dMat.combiner1.A_alpha, - f3dMat.combiner1.B_alpha, - f3dMat.combiner1.C_alpha, - f3dMat.combiner1.D_alpha, - f3dMat.combiner2.A, - f3dMat.combiner2.B, - f3dMat.combiner2.C, - f3dMat.combiner2.D, - f3dMat.combiner2.A_alpha, - f3dMat.combiner2.B_alpha, - f3dMat.combiner2.C_alpha, - f3dMat.combiner2.D_alpha - )) - else: - fMaterial.material.commands.append( - DPSetCombineMode( - f3dMat.combiner1.A, - f3dMat.combiner1.B, - f3dMat.combiner1.C, - f3dMat.combiner1.D, - f3dMat.combiner1.A_alpha, - f3dMat.combiner1.B_alpha, - f3dMat.combiner1.C_alpha, - f3dMat.combiner1.D_alpha, - f3dMat.combiner1.A, - f3dMat.combiner1.B, - f3dMat.combiner1.C, - f3dMat.combiner1.D, - f3dMat.combiner1.A_alpha, - f3dMat.combiner1.B_alpha, - f3dMat.combiner1.C_alpha, - f3dMat.combiner1.D_alpha - )) + if f3dMat.set_combiner: + if f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + fMaterial.material.commands.append( + DPSetCombineMode( + f3dMat.combiner1.A, + f3dMat.combiner1.B, + f3dMat.combiner1.C, + f3dMat.combiner1.D, + f3dMat.combiner1.A_alpha, + f3dMat.combiner1.B_alpha, + f3dMat.combiner1.C_alpha, + f3dMat.combiner1.D_alpha, + f3dMat.combiner2.A, + f3dMat.combiner2.B, + f3dMat.combiner2.C, + f3dMat.combiner2.D, + f3dMat.combiner2.A_alpha, + f3dMat.combiner2.B_alpha, + f3dMat.combiner2.C_alpha, + f3dMat.combiner2.D_alpha, + ) + ) + else: + fMaterial.material.commands.append( + DPSetCombineMode( + f3dMat.combiner1.A, + f3dMat.combiner1.B, + f3dMat.combiner1.C, + f3dMat.combiner1.D, + f3dMat.combiner1.A_alpha, + f3dMat.combiner1.B_alpha, + f3dMat.combiner1.C_alpha, + f3dMat.combiner1.D_alpha, + f3dMat.combiner1.A, + f3dMat.combiner1.B, + f3dMat.combiner1.C, + f3dMat.combiner1.D, + f3dMat.combiner1.A_alpha, + f3dMat.combiner1.B_alpha, + f3dMat.combiner1.C_alpha, + f3dMat.combiner1.D_alpha, + ) + ) - if f3dMat.set_fog: - if f3dMat.use_global_fog and fModel.global_data.getCurrentAreaData() is not None: - fogData = fModel.global_data.getCurrentAreaData().fog_data - fog_position = fogData.position - fog_color = fogData.color - else: - fog_position = f3dMat.fog_position - fog_color = f3dMat.fog_color - fMaterial.material.commands.extend([ - DPSetFogColor( - int(round(fog_color[0] * 255)), - int(round(fog_color[1] * 255)), - int(round(fog_color[2] * 255)), - int(round(fog_color[3] * 255))), - SPFogPosition(fog_position[0], fog_position[1]) - ]) + if f3dMat.set_fog: + if f3dMat.use_global_fog and fModel.global_data.getCurrentAreaData() is not None: + fogData = fModel.global_data.getCurrentAreaData().fog_data + fog_position = fogData.position + fog_color = fogData.color + else: + fog_position = f3dMat.fog_position + fog_color = f3dMat.fog_color + fMaterial.material.commands.extend( + [ + DPSetFogColor( + int(round(fog_color[0] * 255)), + int(round(fog_color[1] * 255)), + int(round(fog_color[2] * 255)), + int(round(fog_color[3] * 255)), + ), + SPFogPosition(fog_position[0], fog_position[1]), + ] + ) - useDict = all_combiner_uses(f3dMat) + useDict = all_combiner_uses(f3dMat) - if drawLayer is not None: - defaultRM = fModel.getRenderMode(drawLayer) - else: - defaultRM = None + if drawLayer is not None: + defaultRM = fModel.getRenderMode(drawLayer) + else: + defaultRM = None - defaults = bpy.context.scene.world.rdp_defaults - if fModel.f3d.F3DEX_GBI_2: - saveGeoModeDefinitionF3DEX2(fMaterial, f3dMat.rdp_settings, defaults, fModel.matWriteMethod) - else: - saveGeoModeDefinition(fMaterial, f3dMat.rdp_settings, defaults, fModel.matWriteMethod) - saveOtherModeHDefinition(fMaterial, f3dMat.rdp_settings, defaults, fModel.f3d._HW_VERSION_1, fModel.matWriteMethod) - saveOtherModeLDefinition(fMaterial, f3dMat.rdp_settings, defaults, defaultRM, fModel.matWriteMethod) - saveOtherDefinition(fMaterial, f3dMat, defaults) + defaults = bpy.context.scene.world.rdp_defaults + if fModel.f3d.F3DEX_GBI_2: + saveGeoModeDefinitionF3DEX2(fMaterial, f3dMat.rdp_settings, defaults, fModel.matWriteMethod) + else: + saveGeoModeDefinition(fMaterial, f3dMat.rdp_settings, defaults, fModel.matWriteMethod) + saveOtherModeHDefinition(fMaterial, f3dMat.rdp_settings, defaults, fModel.f3d._HW_VERSION_1, fModel.matWriteMethod) + saveOtherModeLDefinition(fMaterial, f3dMat.rdp_settings, defaults, defaultRM, fModel.matWriteMethod) + saveOtherDefinition(fMaterial, f3dMat, defaults) - # Set scale - s = int(f3dMat.tex_scale[0] * 0xFFFF) - t = int(f3dMat.tex_scale[1] * 0xFFFF) - fMaterial.material.commands.append( - SPTexture(s, t, 0, fModel.f3d.G_TX_RENDERTILE, 1)) + # Set scale + s = int(f3dMat.tex_scale[0] * 0xFFFF) + t = int(f3dMat.tex_scale[1] * 0xFFFF) + fMaterial.material.commands.append(SPTexture(s, t, 0, fModel.f3d.G_TX_RENDERTILE, 1)) - # Save textures - texDimensions0 = None - texDimensions1 = None - nextTmem = 0 - loadTextures = not (material.mat_ver > 3 and f3dMat.use_large_textures) - if useDict['Texture 0'] and f3dMat.tex0.tex_set: - if f3dMat.tex0.tex is None and not f3dMat.tex0.use_tex_reference: - raise PluginError('In material \"' + material.name + '\", a texture has not been set.') + # Save textures + texDimensions0 = None + texDimensions1 = None + nextTmem = 0 + loadTextures = not (material.mat_ver > 3 and f3dMat.use_large_textures) + if useDict["Texture 0"] and f3dMat.tex0.tex_set: + if f3dMat.tex0.tex is None and not f3dMat.tex0.use_tex_reference: + raise PluginError('In material "' + material.name + '", a texture has not been set.') - fMaterial.useLargeTextures = not loadTextures - fMaterial.texturesLoaded[0] = True - fMaterial.saveLargeTextures[0] = f3dMat.tex0.save_large_texture - texDimensions0, nextTmem = saveTextureIndex(material.name, fModel, - fMaterial, fMaterial.material, fMaterial.revert, f3dMat.tex0, 0, nextTmem, None, convertTextureData, - None, loadTextures, True) + fMaterial.useLargeTextures = not loadTextures + fMaterial.texturesLoaded[0] = True + fMaterial.saveLargeTextures[0] = f3dMat.tex0.save_large_texture + texDimensions0, nextTmem = saveTextureIndex( + material.name, + fModel, + fMaterial, + fMaterial.material, + fMaterial.revert, + f3dMat.tex0, + 0, + nextTmem, + None, + convertTextureData, + None, + loadTextures, + True, + ) - # If the texture in both texels is the same then it can be rewritten to the same location in tmem - # This allows for a texture that fills tmem to still be used for both texel0 and texel1 - if f3dMat.tex0.tex == f3dMat.tex1.tex: - if nextTmem >= (512 if f3dMat.tex0.tex_format[:2] != 'CI' else 256): - nextTmem = 0 + # If the texture in both texels is the same then it can be rewritten to the same location in tmem + # This allows for a texture that fills tmem to still be used for both texel0 and texel1 + if f3dMat.tex0.tex == f3dMat.tex1.tex: + if nextTmem >= (512 if f3dMat.tex0.tex_format[:2] != "CI" else 256): + nextTmem = 0 - if useDict['Texture 1'] and f3dMat.tex1.tex_set: - if f3dMat.tex1.tex is None and not f3dMat.tex1.use_tex_reference: - raise PluginError('In material \"' + material.name + '\", a texture has not been set.') + if useDict["Texture 1"] and f3dMat.tex1.tex_set: + if f3dMat.tex1.tex is None and not f3dMat.tex1.use_tex_reference: + raise PluginError('In material "' + material.name + '", a texture has not been set.') - fMaterial.useLargeTextures = not loadTextures - fMaterial.texturesLoaded[1] = True - fMaterial.saveLargeTextures[1] = f3dMat.tex1.save_large_texture - texDimensions1, nextTmem = saveTextureIndex(material.name, fModel, - fMaterial, fMaterial.material, fMaterial.revert, f3dMat.tex1, 1, nextTmem, None, convertTextureData, - None, loadTextures, True) + fMaterial.useLargeTextures = not loadTextures + fMaterial.texturesLoaded[1] = True + fMaterial.saveLargeTextures[1] = f3dMat.tex1.save_large_texture + texDimensions1, nextTmem = saveTextureIndex( + material.name, + fModel, + fMaterial, + fMaterial.material, + fMaterial.revert, + f3dMat.tex1, + 1, + nextTmem, + None, + convertTextureData, + None, + loadTextures, + True, + ) - # Used so we know how to convert normalized UVs when saving verts. - if texDimensions0 is not None and texDimensions1 is not None: - if f3dMat.uv_basis == 'TEXEL0': - texDimensions = texDimensions0 - fMaterial.largeTextureIndex = 0 - else: - texDimensions = texDimensions1 - fMaterial.largeTextureIndex = 1 + # Used so we know how to convert normalized UVs when saving verts. + if texDimensions0 is not None and texDimensions1 is not None: + if f3dMat.uv_basis == "TEXEL0": + texDimensions = texDimensions0 + fMaterial.largeTextureIndex = 0 + else: + texDimensions = texDimensions1 + fMaterial.largeTextureIndex = 1 - elif texDimensions0 is not None: - texDimensions = texDimensions0 - fMaterial.largeTextureIndex = 0 - elif texDimensions1 is not None: - texDimensions = texDimensions1 - fMaterial.largeTextureIndex = 1 - else: - texDimensions = [32, 32] + elif texDimensions0 is not None: + texDimensions = texDimensions0 + fMaterial.largeTextureIndex = 0 + elif texDimensions1 is not None: + texDimensions = texDimensions1 + fMaterial.largeTextureIndex = 1 + else: + texDimensions = [32, 32] - nodes = material.node_tree.nodes - if useDict['Primitive'] and f3dMat.set_prim: - if material.mat_ver > 3: - color = f3dMat.prim_color - elif material.mat_ver == 3: - color = nodes['Primitive Color Output'].inputs[0].default_value - else: - color = nodes['Primitive Color'].outputs[0].default_value - color = gammaCorrect(color[0:3]) + [color[3]] - fMaterial.material.commands.append( - DPSetPrimColor( - int(f3dMat.prim_lod_min * 255), - int(f3dMat.prim_lod_frac * 255), - int(color[0] * 255), - int(color[1] * 255), - int(color[2] * 255), - int(color[3] * 255))) + nodes = material.node_tree.nodes + if useDict["Primitive"] and f3dMat.set_prim: + if material.mat_ver > 3: + color = f3dMat.prim_color + elif material.mat_ver == 3: + color = nodes["Primitive Color Output"].inputs[0].default_value + else: + color = nodes["Primitive Color"].outputs[0].default_value + color = gammaCorrect(color[0:3]) + [color[3]] + fMaterial.material.commands.append( + DPSetPrimColor( + int(f3dMat.prim_lod_min * 255), + int(f3dMat.prim_lod_frac * 255), + int(color[0] * 255), + int(color[1] * 255), + int(color[2] * 255), + int(color[3] * 255), + ) + ) - if useDict['Environment'] and f3dMat.set_env: - if material.mat_ver > 3: - color = f3dMat.env_color - elif material.mat_ver == 3: - color = nodes['Environment Color Output'].inputs[0].default_value - else: - color = nodes['Environment Color'].outputs[0].default_value - color = gammaCorrect(color[0:3]) + [color[3]] - fMaterial.material.commands.append( - DPSetEnvColor( - int(color[0] * 255), - int(color[1] * 255), - int(color[2] * 255), - int(color[3] * 255))) + if useDict["Environment"] and f3dMat.set_env: + if material.mat_ver > 3: + color = f3dMat.env_color + elif material.mat_ver == 3: + color = nodes["Environment Color Output"].inputs[0].default_value + else: + color = nodes["Environment Color"].outputs[0].default_value + color = gammaCorrect(color[0:3]) + [color[3]] + fMaterial.material.commands.append( + DPSetEnvColor(int(color[0] * 255), int(color[1] * 255), int(color[2] * 255), int(color[3] * 255)) + ) - if useDict['Shade'] and f3dMat.set_lights: - fLights = saveLightsDefinition(fModel, fMaterial, f3dMat, - materialName + '_lights') - fMaterial.material.commands.extend([ - SPSetLights(fLights) # TODO: handle synching: NO NEED? - ]) + if useDict["Shade"] and f3dMat.set_lights: + fLights = saveLightsDefinition(fModel, fMaterial, f3dMat, materialName + "_lights") + fMaterial.material.commands.extend([SPSetLights(fLights)]) # TODO: handle synching: NO NEED? - if useDict['Key'] and f3dMat.set_key: - if material.mat_ver == 4: - center = f3dMat.key_center - else: - center = nodes['Chroma Key Center'].outputs[0].default_value - scale = f3dMat.key_scale - width = f3dMat.key_width - fMaterial.material.commands.extend([ - DPSetCombineKey('G_CK_KEY'), - # TODO: Add UI handling width - DPSetKeyR(int(center[0] * 255), int(scale[0] * 255), - int(width[0] * 2**8)), - DPSetKeyGB(int(center[1] * 255), int(scale[1] * 255), - int(width[1] * 2**8), - int(center[2] * 255), int(scale[2] * 255), - int(width[2] * 2**8)) - ]) + if useDict["Key"] and f3dMat.set_key: + if material.mat_ver == 4: + center = f3dMat.key_center + else: + center = nodes["Chroma Key Center"].outputs[0].default_value + scale = f3dMat.key_scale + width = f3dMat.key_width + fMaterial.material.commands.extend( + [ + DPSetCombineKey("G_CK_KEY"), + # TODO: Add UI handling width + DPSetKeyR(int(center[0] * 255), int(scale[0] * 255), int(width[0] * 2**8)), + DPSetKeyGB( + int(center[1] * 255), + int(scale[1] * 255), + int(width[1] * 2**8), + int(center[2] * 255), + int(scale[2] * 255), + int(width[2] * 2**8), + ), + ] + ) - # all k0-5 set at once - # make sure to handle this in node shader - # or don't, who cares - if useDict['Convert'] and f3dMat.set_k0_5: - fMaterial.material.commands.extend([ - DPSetTextureConvert('G_TC_FILTCONV'), # TODO: allow filter option - DPSetConvert( - int(f3dMat.k0 * 255), - int(f3dMat.k1 * 255), - int(f3dMat.k2 * 255), - int(f3dMat.k3 * 255), - int(f3dMat.k4 * 255), - int(f3dMat.k5 * 255)) - ]) + # all k0-5 set at once + # make sure to handle this in node shader + # or don't, who cares + if useDict["Convert"] and f3dMat.set_k0_5: + fMaterial.material.commands.extend( + [ + DPSetTextureConvert("G_TC_FILTCONV"), # TODO: allow filter option + DPSetConvert( + int(f3dMat.k0 * 255), + int(f3dMat.k1 * 255), + int(f3dMat.k2 * 255), + int(f3dMat.k3 * 255), + int(f3dMat.k4 * 255), + int(f3dMat.k5 * 255), + ), + ] + ) - fModel.onMaterialCommandsBuilt(fMaterial.material, fMaterial.revert, material, drawLayer) + fModel.onMaterialCommandsBuilt(fMaterial.material, fMaterial.revert, material, drawLayer) - # End Display List - # For dynamic calls, materials will be called as functions and should not end the DL. - if fModel.DLFormat == DLFormat.Static: - fMaterial.material.commands.append(SPEndDisplayList()) + # End Display List + # For dynamic calls, materials will be called as functions and should not end the DL. + if fModel.DLFormat == DLFormat.Static: + fMaterial.material.commands.append(SPEndDisplayList()) - #revertMatAndEndDraw(fMaterial.revert) - if len(fMaterial.revert.commands) > 1: # 1 being the pipe sync - if fMaterial.DLFormat == DLFormat.Static: - fMaterial.revert.commands.append(SPEndDisplayList()) - else: - fMaterial.revert = None + # revertMatAndEndDraw(fMaterial.revert) + if len(fMaterial.revert.commands) > 1: # 1 being the pipe sync + if fMaterial.DLFormat == DLFormat.Static: + fMaterial.revert.commands.append(SPEndDisplayList()) + else: + fMaterial.revert = None - materialKey = material, (drawLayer if f3dMat.rdp_settings.set_rendermode else None), \ - fModel.global_data.getCurrentAreaKey(f3dMat) - fModel.materials[materialKey] = (fMaterial, texDimensions) + materialKey = ( + material, + (drawLayer if f3dMat.rdp_settings.set_rendermode else None), + fModel.global_data.getCurrentAreaKey(f3dMat), + ) + fModel.materials[materialKey] = (fMaterial, texDimensions) - return fMaterial, texDimensions - -def saveTextureIndex(propName, fModel, fMaterial, loadTexGfx, revertTexGfx, texProp, index, tmem, - overrideName, convertTextureData, tileSettingsOverride, loadTextures, loadPalettes): - tex = texProp.tex - - if tex is not None and (tex.size[0] == 0 or tex.size[1] == 0): - raise PluginError("Image " + tex.name + " has either a 0 width or height; image may have been removed from original location.") - - if not texProp.use_tex_reference: - if tex is None: - raise PluginError('In ' + propName + ", no texture is selected.") - elif len(tex.pixels) == 0: - raise PluginError("Could not load missing texture: " + tex.name + ". Make sure this texture has not been deleted or moved on disk.") - - texFormat = texProp.tex_format - isCITexture = texFormat[:2] == 'CI' - palFormat = texProp.ci_format if isCITexture else '' - - if not texProp.use_tex_reference: - if tex.filepath == "": - name = tex.name - else: - name = tex.filepath - else: - name = texProp.tex_reference - texName = fModel.name + '_' + \ - (getNameFromPath(name, True) + '_' + texFormat.lower() if overrideName is None else overrideName) + return fMaterial, texDimensions - if tileSettingsOverride is not None: - tileSettings = tileSettingsOverride[index] - width, height = tileSettings.getDimensions() - setTLUTMode = False - else: - tileSettings = None - if texProp.use_tex_reference: - width, height = texProp.tex_reference_size - else: - width, height = tex.size - setTLUTMode = fModel.matWriteMethod == GfxMatWriteMethod.WriteAll +def saveTextureIndex( + propName, + fModel, + fMaterial, + loadTexGfx, + revertTexGfx, + texProp, + index, + tmem, + overrideName, + convertTextureData, + tileSettingsOverride, + loadTextures, + loadPalettes, +): + tex = texProp.tex - nextTmem = tmem + getTmemWordUsage(texFormat, width, height) + if tex is not None and (tex.size[0] == 0 or tex.size[1] == 0): + raise PluginError( + "Image " + tex.name + " has either a 0 width or height; image may have been removed from original location." + ) - if not bpy.context.scene.ignoreTextureRestrictions and loadTextures: - if nextTmem > (512 if texFormat[:2] != 'CI' else 256): - raise PluginError("Error in \"" + propName + "\": Textures are too big. Max TMEM size is 4k " + \ - "bytes, ex. 2 32x32 RGBA 16 bit textures.\nNote that texture width will be internally padded to 64 bit boundaries.") - if width > 1024 or height > 1024: - raise PluginError("Error in \"" + propName + "\": Any side of an image cannot be greater " +\ - "than 1024.") + if not texProp.use_tex_reference: + if tex is None: + raise PluginError("In " + propName + ", no texture is selected.") + elif len(tex.pixels) == 0: + raise PluginError( + "Could not load missing texture: " + + tex.name + + ". Make sure this texture has not been deleted or moved on disk." + ) - if tileSettings is None: - clamp_S = texProp.S.clamp - mirror_S = texProp.S.mirror - tex_SL = texProp.S.low - tex_SH = texProp.S.high - mask_S = texProp.S.mask - shift_S = texProp.S.shift + texFormat = texProp.tex_format + isCITexture = texFormat[:2] == "CI" + palFormat = texProp.ci_format if isCITexture else "" - clamp_T = texProp.T.clamp - mirror_T = texProp.T.mirror - tex_TL = texProp.T.low - tex_TH = texProp.T.high - mask_T = texProp.T.mask - shift_T = texProp.T.shift + if not texProp.use_tex_reference: + if tex.filepath == "": + name = tex.name + else: + name = tex.filepath + else: + name = texProp.tex_reference + texName = ( + fModel.name + + "_" + + (getNameFromPath(name, True) + "_" + texFormat.lower() if overrideName is None else overrideName) + ) - else: - clamp_S = True - mirror_S = False - tex_SL = tileSettings.sl - tex_SH = tileSettings.sh - mask_S = 0 - shift_S = 0 + if tileSettingsOverride is not None: + tileSettings = tileSettingsOverride[index] + width, height = tileSettings.getDimensions() + setTLUTMode = False + else: + tileSettings = None + if texProp.use_tex_reference: + width, height = texProp.tex_reference_size + else: + width, height = tex.size + setTLUTMode = fModel.matWriteMethod == GfxMatWriteMethod.WriteAll - clamp_T = True - mirror_T = False - tex_TL = tileSettings.tl - tex_TH = tileSettings.th - mask_T = 0 - shift_T = 0 + nextTmem = tmem + getTmemWordUsage(texFormat, width, height) - convertTextureData = convertTextureData and not (fMaterial.useLargeTextures and fMaterial.saveLargeTextures[index]) - if isCITexture: - if texProp.use_tex_reference: - fImage = FImage(texProp.tex_reference, None, None, width, height, None, False) - fPalette = FImage(texProp.pal_reference, None, None, 1, texProp.pal_reference_size, None, False) - else: - fImage, fPalette = saveOrGetPaletteDefinition( - fMaterial, fModel, tex, texName, texFormat, palFormat, convertTextureData) + if not bpy.context.scene.ignoreTextureRestrictions and loadTextures: + if nextTmem > (512 if texFormat[:2] != "CI" else 256): + raise PluginError( + 'Error in "' + + propName + + '": Textures are too big. Max TMEM size is 4k ' + + "bytes, ex. 2 32x32 RGBA 16 bit textures.\nNote that texture width will be internally padded to 64 bit boundaries." + ) + if width > 1024 or height > 1024: + raise PluginError('Error in "' + propName + '": Any side of an image cannot be greater ' + "than 1024.") - if loadPalettes: - savePaletteLoading(loadTexGfx, revertTexGfx, fPalette, - palFormat, 0, fPalette.height, fModel.f3d, fModel.matWriteMethod) - else: - if texProp.use_tex_reference: - fImage = FImage(texProp.tex_reference, None, None, width, height, None, False) - else: - fImage = saveOrGetTextureDefinition(fMaterial, fModel, tex, texName, - texFormat, convertTextureData) + if tileSettings is None: + clamp_S = texProp.S.clamp + mirror_S = texProp.S.mirror + tex_SL = texProp.S.low + tex_SH = texProp.S.high + mask_S = texProp.S.mask + shift_S = texProp.S.shift - if setTLUTMode and not isCITexture: - loadTexGfx.commands.append(DPSetTextureLUT('G_TT_NONE')) - if loadTextures: - saveTextureLoading(fMaterial, fImage, loadTexGfx, clamp_S, - mirror_S, clamp_T, mirror_T, - mask_S, mask_T, shift_S, - shift_T, tex_SL, tex_TL, tex_SH, - tex_TH, texFormat, index, fModel.f3d, tmem) - texDimensions = fImage.width, fImage.height - #fImage = saveTextureDefinition(fModel, tex, texName, - # texFormatOf[texFormat], texBitSizeOf[texFormat]) - #fModel.textures[texName] = fImage + clamp_T = texProp.T.clamp + mirror_T = texProp.T.mirror + tex_TL = texProp.T.low + tex_TH = texProp.T.high + mask_T = texProp.T.mask + shift_T = texProp.T.shift + + else: + clamp_S = True + mirror_S = False + tex_SL = tileSettings.sl + tex_SH = tileSettings.sh + mask_S = 0 + shift_S = 0 + + clamp_T = True + mirror_T = False + tex_TL = tileSettings.tl + tex_TH = tileSettings.th + mask_T = 0 + shift_T = 0 + + convertTextureData = convertTextureData and not (fMaterial.useLargeTextures and fMaterial.saveLargeTextures[index]) + if isCITexture: + if texProp.use_tex_reference: + fImage = FImage(texProp.tex_reference, None, None, width, height, None, False) + fPalette = FImage(texProp.pal_reference, None, None, 1, texProp.pal_reference_size, None, False) + else: + fImage, fPalette = saveOrGetPaletteDefinition( + fMaterial, fModel, tex, texName, texFormat, palFormat, convertTextureData + ) + + if loadPalettes: + savePaletteLoading( + loadTexGfx, revertTexGfx, fPalette, palFormat, 0, fPalette.height, fModel.f3d, fModel.matWriteMethod + ) + else: + if texProp.use_tex_reference: + fImage = FImage(texProp.tex_reference, None, None, width, height, None, False) + else: + fImage = saveOrGetTextureDefinition(fMaterial, fModel, tex, texName, texFormat, convertTextureData) + + if setTLUTMode and not isCITexture: + loadTexGfx.commands.append(DPSetTextureLUT("G_TT_NONE")) + if loadTextures: + saveTextureLoading( + fMaterial, + fImage, + loadTexGfx, + clamp_S, + mirror_S, + clamp_T, + mirror_T, + mask_S, + mask_T, + shift_S, + shift_T, + tex_SL, + tex_TL, + tex_SH, + tex_TH, + texFormat, + index, + fModel.f3d, + tmem, + ) + texDimensions = fImage.width, fImage.height + # fImage = saveTextureDefinition(fModel, tex, texName, + # texFormatOf[texFormat], texBitSizeOf[texFormat]) + # fModel.textures[texName] = fImage + + return texDimensions, nextTmem - return texDimensions, nextTmem # texIndex: 0 for texture0, 1 for texture1 -def saveTextureLoading(fMaterial, fImage, loadTexGfx, clamp_S, mirror_S, clamp_T, - mirror_T, mask_S, mask_T, shift_S, shift_T, - SL, TL, SH, TH, tex_format, texIndex, f3d, tmem): - cms = [('G_TX_CLAMP' if clamp_S else 'G_TX_WRAP'), - ('G_TX_MIRROR' if mirror_S else 'G_TX_NOMIRROR')] - cmt = [('G_TX_CLAMP' if clamp_T else 'G_TX_WRAP'), - ('G_TX_MIRROR' if mirror_T else 'G_TX_NOMIRROR')] - masks = mask_S - maskt = mask_T - shifts = shift_S if shift_S >= 0 else (shift_S + 16) - shiftt = shift_T if shift_T >= 0 else (shift_T + 16) +def saveTextureLoading( + fMaterial, + fImage, + loadTexGfx, + clamp_S, + mirror_S, + clamp_T, + mirror_T, + mask_S, + mask_T, + shift_S, + shift_T, + SL, + TL, + SH, + TH, + tex_format, + texIndex, + f3d, + tmem, +): + cms = [("G_TX_CLAMP" if clamp_S else "G_TX_WRAP"), ("G_TX_MIRROR" if mirror_S else "G_TX_NOMIRROR")] + cmt = [("G_TX_CLAMP" if clamp_T else "G_TX_WRAP"), ("G_TX_MIRROR" if mirror_T else "G_TX_NOMIRROR")] + masks = mask_S + maskt = mask_T + shifts = shift_S if shift_S >= 0 else (shift_S + 16) + shiftt = shift_T if shift_T >= 0 else (shift_T + 16) - #print('Low ' + str(SL) + ' ' + str(TL)) - sl = int(SL * (2 ** f3d.G_TEXTURE_IMAGE_FRAC)) - tl = int(TL * (2 ** f3d.G_TEXTURE_IMAGE_FRAC)) - sh = int(SH * (2 ** f3d.G_TEXTURE_IMAGE_FRAC)) - th = int(TH * (2 ** f3d.G_TEXTURE_IMAGE_FRAC)) + # print('Low ' + str(SL) + ' ' + str(TL)) + sl = int(SL * (2**f3d.G_TEXTURE_IMAGE_FRAC)) + tl = int(TL * (2**f3d.G_TEXTURE_IMAGE_FRAC)) + sh = int(SH * (2**f3d.G_TEXTURE_IMAGE_FRAC)) + th = int(TH * (2**f3d.G_TEXTURE_IMAGE_FRAC)) - fmt = texFormatOf[tex_format] - siz = texBitSizeOf[tex_format] - pal = 0 if fmt[:2] != 'CI' else 0 # handle palettes + fmt = texFormatOf[tex_format] + siz = texBitSizeOf[tex_format] + pal = 0 if fmt[:2] != "CI" else 0 # handle palettes - #texelsPerWord = int(round(64 / bitSizeDict[siz])) - useLoadBlock = not fImage.isLargeTexture and \ - isPowerOf2(fImage.width) and isPowerOf2(fImage.height) + # texelsPerWord = int(round(64 / bitSizeDict[siz])) + useLoadBlock = not fImage.isLargeTexture and isPowerOf2(fImage.width) and isPowerOf2(fImage.height) - # LoadTile will pad rows to 64 bit word alignment, while - # LoadBlock assumes this is already done. + # LoadTile will pad rows to 64 bit word alignment, while + # LoadBlock assumes this is already done. - # These commands are basically DPLoadMultiBlock/Tile, - # except for the load tile index which will be 6 instead of 7 for render tile = 1. - # This may be unnecessary, but at this point DPLoadMultiBlock/Tile is not implemented yet - # so it would be extra work for the same outcome. - base_width = int(fImage.width) - if fImage.isLargeTexture: - # TODO: Use width of block to load - base_width = int(SH - SL) + # These commands are basically DPLoadMultiBlock/Tile, + # except for the load tile index which will be 6 instead of 7 for render tile = 1. + # This may be unnecessary, but at this point DPLoadMultiBlock/Tile is not implemented yet + # so it would be extra work for the same outcome. + base_width = int(fImage.width) + if fImage.isLargeTexture: + # TODO: Use width of block to load + base_width = int(SH - SL) - if siz == 'G_IM_SIZ_4b': - sl2 = int(SL * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) - sh2 = int(SH * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) + if siz == "G_IM_SIZ_4b": + sl2 = int(SL * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) + sh2 = int(SH * (2 ** (f3d.G_TEXTURE_IMAGE_FRAC - 1))) - dxt = f3d.CALC_DXT_4b(fImage.width) - line = (((base_width + 1) >> 1) + 7) >> 3 + dxt = f3d.CALC_DXT_4b(fImage.width) + line = (((base_width + 1) >> 1) + 7) >> 3 - if useLoadBlock: - loadTexGfx.commands.extend([ - DPTileSync(), # added in - DPSetTextureImage(fmt, 'G_IM_SIZ_16b', 1, fImage), - DPSetTile(fmt, 'G_IM_SIZ_16b', 0, tmem, f3d.G_TX_LOADTILE - texIndex, 0, - cmt, maskt, shiftt, cms, masks, shifts), - DPLoadSync(), - DPLoadBlock(f3d.G_TX_LOADTILE - texIndex, 0, 0, (((fImage.width)*(fImage.height)+3)>>2)-1, dxt)]) - else: - loadTexGfx.commands.extend([ - DPTileSync(), # added in - DPSetTextureImage(fmt, 'G_IM_SIZ_8b', fImage.width >> 1, fImage), - DPSetTile(fmt, 'G_IM_SIZ_8b', line, tmem, - f3d.G_TX_LOADTILE - texIndex, 0, cmt, maskt, shiftt, - cms, masks, shifts), - DPLoadSync(), - DPLoadTile(f3d.G_TX_LOADTILE - texIndex, sl2, tl, sh2, th),]) + if useLoadBlock: + loadTexGfx.commands.extend( + [ + DPTileSync(), # added in + DPSetTextureImage(fmt, "G_IM_SIZ_16b", 1, fImage), + DPSetTile( + fmt, + "G_IM_SIZ_16b", + 0, + tmem, + f3d.G_TX_LOADTILE - texIndex, + 0, + cmt, + maskt, + shiftt, + cms, + masks, + shifts, + ), + DPLoadSync(), + DPLoadBlock( + f3d.G_TX_LOADTILE - texIndex, 0, 0, (((fImage.width) * (fImage.height) + 3) >> 2) - 1, dxt + ), + ] + ) + else: + loadTexGfx.commands.extend( + [ + DPTileSync(), # added in + DPSetTextureImage(fmt, "G_IM_SIZ_8b", fImage.width >> 1, fImage), + DPSetTile( + fmt, + "G_IM_SIZ_8b", + line, + tmem, + f3d.G_TX_LOADTILE - texIndex, + 0, + cmt, + maskt, + shiftt, + cms, + masks, + shifts, + ), + DPLoadSync(), + DPLoadTile(f3d.G_TX_LOADTILE - texIndex, sl2, tl, sh2, th), + ] + ) - else: - dxt = f3d.CALC_DXT(fImage.width, f3d.G_IM_SIZ_VARS[siz + '_BYTES']) - # Note that _LINE_BYTES and _TILE_BYTES variables are the same. - line = int((base_width * f3d.G_IM_SIZ_VARS[siz + "_LINE_BYTES"]) + 7) >> 3 + else: + dxt = f3d.CALC_DXT(fImage.width, f3d.G_IM_SIZ_VARS[siz + "_BYTES"]) + # Note that _LINE_BYTES and _TILE_BYTES variables are the same. + line = int((base_width * f3d.G_IM_SIZ_VARS[siz + "_LINE_BYTES"]) + 7) >> 3 - if useLoadBlock: - loadTexGfx.commands.extend([ - DPTileSync(), # added in + if useLoadBlock: + loadTexGfx.commands.extend( + [ + DPTileSync(), # added in + # Load Block version + DPSetTextureImage(fmt, siz + "_LOAD_BLOCK", 1, fImage), + DPSetTile( + fmt, + siz + "_LOAD_BLOCK", + 0, + tmem, + f3d.G_TX_LOADTILE - texIndex, + 0, + cmt, + maskt, + shiftt, + cms, + masks, + shifts, + ), + DPLoadSync(), + DPLoadBlock( + f3d.G_TX_LOADTILE - texIndex, + 0, + 0, + ( + ((fImage.width) * (fImage.height) + f3d.G_IM_SIZ_VARS[siz + "_INCR"]) + >> f3d.G_IM_SIZ_VARS[siz + "_SHIFT"] + ) + - 1, + dxt, + ), + ] + ) + else: + loadTexGfx.commands.extend( + [ + DPTileSync(), # added in + # Load Tile version + DPSetTextureImage(fmt, siz, fImage.width, fImage), + DPSetTile( + fmt, siz, line, tmem, f3d.G_TX_LOADTILE - texIndex, 0, cmt, maskt, shiftt, cms, masks, shifts + ), + DPLoadSync(), + DPLoadTile(f3d.G_TX_LOADTILE - texIndex, sl, tl, sh, th), + ] + ) # added in - # Load Block version - DPSetTextureImage(fmt, siz + '_LOAD_BLOCK', 1, fImage), - DPSetTile(fmt, siz + '_LOAD_BLOCK', 0, tmem, - f3d.G_TX_LOADTILE - texIndex, 0, cmt, maskt, shiftt, - cms, masks, shifts), - DPLoadSync(), - DPLoadBlock(f3d.G_TX_LOADTILE - texIndex, 0, 0, \ - (((fImage.width)*(fImage.height) + \ - f3d.G_IM_SIZ_VARS[siz + '_INCR']) >> \ - f3d.G_IM_SIZ_VARS[siz + '_SHIFT'])-1, \ - dxt),]) - else: - loadTexGfx.commands.extend([ - DPTileSync(), # added in + tileSizeCommand = DPSetTileSize(f3d.G_TX_RENDERTILE + texIndex, sl, tl, sh, th) + loadTexGfx.commands.extend( + [ + DPPipeSync(), + DPSetTile( + fmt, siz, line, tmem, f3d.G_TX_RENDERTILE + texIndex, pal, cmt, maskt, shiftt, cms, masks, shifts + ), + tileSizeCommand, + ] + ) # added in) - # Load Tile version - DPSetTextureImage(fmt, siz, fImage.width, fImage), - DPSetTile(fmt, siz, line, tmem, - f3d.G_TX_LOADTILE - texIndex, 0, cmt, maskt, shiftt, - cms, masks, shifts), - DPLoadSync(), - DPLoadTile(f3d.G_TX_LOADTILE - texIndex, sl, tl, sh, th),]) # added in + # hasattr check for FTexRect + if hasattr(fMaterial, "tileSizeCommands"): + fMaterial.tileSizeCommands[f3d.G_TX_RENDERTILE + texIndex] = tileSizeCommand - tileSizeCommand = DPSetTileSize(f3d.G_TX_RENDERTILE + texIndex, sl, tl, sh, th) - loadTexGfx.commands.extend([ - DPPipeSync(), - DPSetTile(fmt, siz, line, tmem, \ - f3d.G_TX_RENDERTILE + texIndex, pal, cmt, maskt, \ - shiftt, cms, masks, shifts), - tileSizeCommand, - ]) # added in) - - # hasattr check for FTexRect - if hasattr(fMaterial, 'tileSizeCommands'): - fMaterial.tileSizeCommands[f3d.G_TX_RENDERTILE + texIndex] = tileSizeCommand # palette stored in upper half of TMEM (words 256-511) # pal is palette number (0-16), for CI8 always set to 0 -def savePaletteLoading(loadTexGfx, revertTexGfx, fPalette, palFormat, pal, - colorCount, f3d, matWriteMethod): - palFmt = texFormatOf[palFormat] - cms = ['G_TX_WRAP', 'G_TX_NOMIRROR'] - cmt = ['G_TX_WRAP', 'G_TX_NOMIRROR'] +def savePaletteLoading(loadTexGfx, revertTexGfx, fPalette, palFormat, pal, colorCount, f3d, matWriteMethod): + palFmt = texFormatOf[palFormat] + cms = ["G_TX_WRAP", "G_TX_NOMIRROR"] + cmt = ["G_TX_WRAP", "G_TX_NOMIRROR"] - loadTexGfx.commands.append(DPSetTextureLUT( - 'G_TT_RGBA16' if palFmt == 'G_IM_FMT_RGBA' else 'G_TT_IA16')) - if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - revertTexGfx.commands.append(DPSetTextureLUT('G_TT_NONE')) + loadTexGfx.commands.append(DPSetTextureLUT("G_TT_RGBA16" if palFmt == "G_IM_FMT_RGBA" else "G_TT_IA16")) + if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: + revertTexGfx.commands.append(DPSetTextureLUT("G_TT_NONE")) + + if not f3d._HW_VERSION_1: + loadTexGfx.commands.extend( + [ + DPSetTextureImage(palFmt, "G_IM_SIZ_16b", 1, fPalette), + DPTileSync(), + DPSetTile("0", "0", 0, (256 + (((pal) & 0xF) * 16)), f3d.G_TX_LOADTILE, 0, cmt, 0, 0, cms, 0, 0), + DPLoadSync(), + DPLoadTLUTCmd(f3d.G_TX_LOADTILE, colorCount - 1), + DPPipeSync(), + ] + ) + else: + loadTexGfx.commands.extend( + [ + _DPLoadTextureBlock( + fPalette, + (256 + (((pal) & 0xF) * 16)), + palFmt, + "G_IM_SIZ_16b", + 4 * colorCount, + 1, + pal, + cms, + cmt, + 0, + 0, + 0, + 0, + ) + ] + ) - if not f3d._HW_VERSION_1: - loadTexGfx.commands.extend([ - DPSetTextureImage(palFmt, 'G_IM_SIZ_16b', 1, fPalette), - DPTileSync(), - DPSetTile('0', '0', 0, (256+(((pal)&0xf)*16)),\ - f3d.G_TX_LOADTILE, 0, cmt, 0, 0, cms, 0, 0), - DPLoadSync(), - DPLoadTLUTCmd(f3d.G_TX_LOADTILE, colorCount - 1), - DPPipeSync()]) - else: - loadTexGfx.commands.extend([ - _DPLoadTextureBlock(fPalette, \ - (256+(((pal)&0xf)*16)), \ - palFmt, 'G_IM_SIZ_16b', 4*colorCount, 1, - pal, cms, cmt, 0, 0, 0, 0)]) def saveOrGetPaletteDefinition(fMaterial, fModelOrTexRect, image, imageName, texFmt, palFmt, convertTextureData): - texFormat = texFormatOf[texFmt] - palFormat = texFormatOf[palFmt] - bitSize = texBitSizeOf[texFmt] - # If image already loaded, return that data. - paletteName = toAlnum(imageName) + '_pal_' + palFmt.lower() - imageKey = (image, (texFmt, palFmt)) - paletteKey = (image, (palFmt, 'PAL')) - fImage, fPalette = fModelOrTexRect.getTextureAndHandleShared(imageKey) - if fImage is not None: - return fImage, fPalette + texFormat = texFormatOf[texFmt] + palFormat = texFormatOf[palFmt] + bitSize = texBitSizeOf[texFmt] + # If image already loaded, return that data. + paletteName = toAlnum(imageName) + "_pal_" + palFmt.lower() + imageKey = (image, (texFmt, palFmt)) + paletteKey = (image, (palFmt, "PAL")) + fImage, fPalette = fModelOrTexRect.getTextureAndHandleShared(imageKey) + if fImage is not None: + return fImage, fPalette - palette = [] - texture = [] - maxColors = 16 if bitSize == 'G_IM_SIZ_4b' else 256 - if convertTextureData: - # N64 is -Y, Blender is +Y - for j in reversed(range(image.size[1])): - for i in range(image.size[0]): - color = [1,1,1,1] - for field in range(image.channels): - color[field] = image.pixels[ - (j * image.size[0] + i) * image.channels + field] - if palFormat == 'G_IM_FMT_RGBA': - pixelColor = getRGBA16Tuple(color) - elif palFormat == 'G_IM_FMT_IA': - pixelColor = getIA16Tuple(color) - else: - raise PluginError("Invalid combo: " + palFormat + ', ' + bitSize) + palette = [] + texture = [] + maxColors = 16 if bitSize == "G_IM_SIZ_4b" else 256 + if convertTextureData: + # N64 is -Y, Blender is +Y + for j in reversed(range(image.size[1])): + for i in range(image.size[0]): + color = [1, 1, 1, 1] + for field in range(image.channels): + color[field] = image.pixels[(j * image.size[0] + i) * image.channels + field] + if palFormat == "G_IM_FMT_RGBA": + pixelColor = getRGBA16Tuple(color) + elif palFormat == "G_IM_FMT_IA": + pixelColor = getIA16Tuple(color) + else: + raise PluginError("Invalid combo: " + palFormat + ", " + bitSize) - if pixelColor not in palette: - palette.append(pixelColor) - if len(palette) > maxColors: - raise PluginError('Texture ' + imageName + ' has more than ' + \ - str(maxColors) + ' colors.') - texture.append(palette.index(pixelColor)) + if pixelColor not in palette: + palette.append(pixelColor) + if len(palette) > maxColors: + raise PluginError("Texture " + imageName + " has more than " + str(maxColors) + " colors.") + texture.append(palette.index(pixelColor)) - if image.filepath == "": - name = image.name - else: - name = image.filepath - filename = getNameFromPath(name, True) + '.' + \ - fModelOrTexRect.getTextureSuffixFromFormat(texFmt) + '.inc.c' - paletteFilename = getNameFromPath(name, True) + '.' + \ - fModelOrTexRect.getTextureSuffixFromFormat(texFmt) + '.pal' - #paletteFilename = getNameFromPath(name, True) + '.' + \ - # fModelOrTexRect.getTextureSuffixFromFormat(palFmt) + '.inc.c' - fImage = FImage(checkDuplicateTextureName(fModelOrTexRect, toAlnum(imageName)), texFormat, bitSize, - image.size[0], image.size[1], filename, convertTextureData) + if image.filepath == "": + name = image.name + else: + name = image.filepath + filename = getNameFromPath(name, True) + "." + fModelOrTexRect.getTextureSuffixFromFormat(texFmt) + ".inc.c" + paletteFilename = getNameFromPath(name, True) + "." + fModelOrTexRect.getTextureSuffixFromFormat(texFmt) + ".pal" + # paletteFilename = getNameFromPath(name, True) + '.' + \ + # fModelOrTexRect.getTextureSuffixFromFormat(palFmt) + '.inc.c' + fImage = FImage( + checkDuplicateTextureName(fModelOrTexRect, toAlnum(imageName)), + texFormat, + bitSize, + image.size[0], + image.size[1], + filename, + convertTextureData, + ) - fPalette = FImage(checkDuplicateTextureName(fModelOrTexRect, paletteName), palFormat, 'G_IM_SIZ_16b', 1, - len(palette), paletteFilename, convertTextureData) - if fMaterial.useLargeTextures: - fImage.isLargeTexture = True - fPalette.isLargeTexture = True - fImage.paletteKey = paletteKey + fPalette = FImage( + checkDuplicateTextureName(fModelOrTexRect, paletteName), + palFormat, + "G_IM_SIZ_16b", + 1, + len(palette), + paletteFilename, + convertTextureData, + ) + if fMaterial.useLargeTextures: + fImage.isLargeTexture = True + fPalette.isLargeTexture = True + fImage.paletteKey = paletteKey - #paletteImage = bpy.data.images.new(paletteName, 1, len(palette)) - #paletteImage.pixels = palette - #paletteImage.filepath = paletteFilename + # paletteImage = bpy.data.images.new(paletteName, 1, len(palette)) + # paletteImage.pixels = palette + # paletteImage.filepath = paletteFilename - if convertTextureData: - for color in palette: - fPalette.data.extend(color.to_bytes(2, 'big')) + if convertTextureData: + for color in palette: + fPalette.data.extend(color.to_bytes(2, "big")) - if bitSize == 'G_IM_SIZ_4b': - fImage.data = compactNibbleArray(texture, image.size[0], image.size[1]) - else: - fImage.data = bytearray(texture) + if bitSize == "G_IM_SIZ_4b": + fImage.data = compactNibbleArray(texture, image.size[0], image.size[1]) + else: + fImage.data = bytearray(texture) - fModelOrTexRect.addTexture((image, (texFmt, palFmt)), fImage, fMaterial) - fModelOrTexRect.addTexture((image, (palFmt, 'PAL')), fPalette, fMaterial) + fModelOrTexRect.addTexture((image, (texFmt, palFmt)), fImage, fMaterial) + fModelOrTexRect.addTexture((image, (palFmt, "PAL")), fPalette, fMaterial) + + return fImage, fPalette # , paletteImage - return fImage, fPalette #, paletteImage def compactNibbleArray(texture, width, height): - nibbleData = bytearray(0) - dataSize = int(width * height / 2) + nibbleData = bytearray(0) + dataSize = int(width * height / 2) - nibbleData = [ - ((texture[i * 2] & 0xF) << 4) |\ - (texture[i * 2 + 1] & 0xF) for i in range(dataSize) - ] + nibbleData = [((texture[i * 2] & 0xF) << 4) | (texture[i * 2 + 1] & 0xF) for i in range(dataSize)] - if (width * height) % 2 == 1: - nibbleData.append((texture[-1] & 0xF) << 4) + if (width * height) % 2 == 1: + nibbleData.append((texture[-1] & 0xF) << 4) + + return bytearray(nibbleData) - return bytearray(nibbleData) def checkDuplicateTextureName(fModelOrTexRect, name): - names = [] - for info, texture in fModelOrTexRect.textures.items(): - names.append(texture.name) - while name in names: - name = name + '_copy' - return name + names = [] + for info, texture in fModelOrTexRect.textures.items(): + names.append(texture.name) + while name in names: + name = name + "_copy" + return name + def saveOrGetTextureDefinition(fMaterial, fModel, image, imageName, texFormat, convertTextureData): - fmt = texFormatOf[texFormat] - bitSize = texBitSizeOf[texFormat] + fmt = texFormatOf[texFormat] + bitSize = texBitSizeOf[texFormat] - # If image already loaded, return that data. - imageKey = (image, (texFormat, 'NONE')) - fImage, fPalette = fModel.getTextureAndHandleShared(imageKey) - if fImage is not None: - return fImage + # If image already loaded, return that data. + imageKey = (image, (texFormat, "NONE")) + fImage, fPalette = fModel.getTextureAndHandleShared(imageKey) + if fImage is not None: + return fImage - if image.filepath == "": - name = image.name - else: - name = image.filepath - filename = getNameFromPath(name, True) + '.' + \ - fModel.getTextureSuffixFromFormat(texFormat) + '.inc.c' + if image.filepath == "": + name = image.name + else: + name = image.filepath + filename = getNameFromPath(name, True) + "." + fModel.getTextureSuffixFromFormat(texFormat) + ".inc.c" - fImage = FImage(checkDuplicateTextureName(fModel, toAlnum(imageName)), fmt, bitSize, - image.size[0], image.size[1], filename, convertTextureData) - if fMaterial.useLargeTextures: - fImage.isLargeTexture = True + fImage = FImage( + checkDuplicateTextureName(fModel, toAlnum(imageName)), + fmt, + bitSize, + image.size[0], + image.size[1], + filename, + convertTextureData, + ) + if fMaterial.useLargeTextures: + fImage.isLargeTexture = True - if convertTextureData: - print("Converting texture data.") - if fmt == 'G_IM_FMT_RGBA': - if bitSize == 'G_IM_SIZ_16b': - #fImage.data = bytearray([byteVal for doubleByte in [ - # (((int(image.pixels[(j * image.size[0] + i) * image.channels + 0] * 0x1F) & 0x1F) << 11) | \ - # ((int(image.pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F) & 0x1F) << 6) | \ - # ((int(image.pixels[(j * image.size[0] + i) * image.channels + 2] * 0x1F) & 0x1F) << 1) | \ - # (1 if image.pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) - # ).to_bytes(2, 'big') - # for j in reversed(range(image.size[1])) for i in range(image.size[0])] for byteVal in doubleByte]) + if convertTextureData: + print("Converting texture data.") + if fmt == "G_IM_FMT_RGBA": + if bitSize == "G_IM_SIZ_16b": + # fImage.data = bytearray([byteVal for doubleByte in [ + # (((int(image.pixels[(j * image.size[0] + i) * image.channels + 0] * 0x1F) & 0x1F) << 11) | \ + # ((int(image.pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F) & 0x1F) << 6) | \ + # ((int(image.pixels[(j * image.size[0] + i) * image.channels + 2] * 0x1F) & 0x1F) << 1) | \ + # (1 if image.pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) + # ).to_bytes(2, 'big') + # for j in reversed(range(image.size[1])) for i in range(image.size[0])] for byteVal in doubleByte]) - fImage.data = bytearray([byteVal for doubleByte in [ - ((((int(round(image.pixels[(j * image.size[0] + i) * image.channels + 0] * 0x1F)) & 0x1F) << 3) | - ((int(round(image.pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F)) & 0x1F) >> 2)), + fImage.data = bytearray( + [ + byteVal + for doubleByte in [ + ( + ( + ( + ( + int( + round(image.pixels[(j * image.size[0] + i) * image.channels + 0] * 0x1F) + ) + & 0x1F + ) + << 3 + ) + | ( + ( + int( + round(image.pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F) + ) + & 0x1F + ) + >> 2 + ) + ), + ( + ( + ( + int( + round(image.pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F) + ) + & 0x03 + ) + << 6 + ) + | ( + ( + int( + round(image.pixels[(j * image.size[0] + i) * image.channels + 2] * 0x1F) + ) + & 0x1F + ) + << 1 + ) + | (1 if image.pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) + ), + ) + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + ] + for byteVal in doubleByte + ] + ) + elif bitSize == "G_IM_SIZ_32b": + fImage.data = bytearray( + [ + int(round(image.pixels[(j * image.size[0] + i) * image.channels + field] * 0xFF)) & 0xFF + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + for field in range(image.channels) + ] + ) + else: + raise PluginError("Invalid combo: " + fmt + ", " + bitSize) - (((int(round(image.pixels[(j * image.size[0] + i) * image.channels + 1] * 0x1F)) & 0x03) << 6) | \ - ((int(round(image.pixels[(j * image.size[0] + i) * image.channels + 2] * 0x1F)) & 0x1F) << 1) | \ - (1 if image.pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0))) + elif fmt == "G_IM_FMT_YUV": + raise PluginError("YUV not yet implemented.") + if bitSize == "G_IM_SIZ_16b": + pass + else: + raise PluginError("Invalid combo: " + fmt + ", " + bitSize) - for j in reversed(range(image.size[1])) for i in range(image.size[0])] for byteVal in doubleByte]) - elif bitSize == 'G_IM_SIZ_32b': - fImage.data = bytearray([ - int(round(image.pixels[(j * image.size[0] + i) * image.channels + field] * 0xFF)) & 0xFF - for j in reversed(range(image.size[1])) for i in range(image.size[0]) for field in range(image.channels)]) - else: - raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) + elif fmt == "G_IM_FMT_CI": + raise PluginError("CI not yet implemented.") - elif fmt == 'G_IM_FMT_YUV': - raise PluginError("YUV not yet implemented.") - if bitSize == 'G_IM_SIZ_16b': - pass - else: - raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) + elif fmt == "G_IM_FMT_IA": + if bitSize == "G_IM_SIZ_4b": + fImage.data = bytearray( + [ + ( + ( + int( + round( + mathutils.Color( + image.pixels[ + (j * image.size[0] + i) + * image.channels : (j * image.size[0] + i) + * image.channels + + 3 + ] + ).v + * 0x7 + ) + ) + & 0x7 + ) + << 1 + ) + | (1 if image.pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + ] + ) + elif bitSize == "G_IM_SIZ_8b": + fImage.data = bytearray( + [ + ( + ( + int( + round( + mathutils.Color( + image.pixels[ + (j * image.size[0] + i) + * image.channels : (j * image.size[0] + i) + * image.channels + + 3 + ] + ).v + * 0xF + ) + ) + & 0xF + ) + << 4 + ) + | (int(round(image.pixels[(j * image.size[0] + i) * image.channels + 3] * 0xF)) & 0xF) + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + ] + ) + elif bitSize == "G_IM_SIZ_16b": + fImage.data = bytearray( + [ + byteVal + for doubleByte in [ + ( + int( + round( + mathutils.Color( + image.pixels[ + (j * image.size[0] + i) + * image.channels : (j * image.size[0] + i) + * image.channels + + 3 + ] + ).v + * 0xFF + ) + ) + & 0xFF, + int(round(image.pixels[(j * image.size[0] + i) * image.channels + 3] * 0xFF)) & 0xFF, + ) + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + ] + for byteVal in doubleByte + ] + ) + else: + raise PluginError("Invalid combo: " + fmt + ", " + bitSize) + elif fmt == "G_IM_FMT_I": + if bitSize == "G_IM_SIZ_4b": + fImage.data = bytearray( + [ + int( + round( + mathutils.Color( + image.pixels[ + (j * image.size[0] + i) + * image.channels : (j * image.size[0] + i) + * image.channels + + 3 + ] + ).v + * 0xF + ) + ) + & 0xF + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + ] + ) + elif bitSize == "G_IM_SIZ_8b": + fImage.data = bytearray( + [ + int( + round( + mathutils.Color( + image.pixels[ + (j * image.size[0] + i) + * image.channels : (j * image.size[0] + i) + * image.channels + + 3 + ] + ).v + * 0xFF + ) + ) + & 0xFF + for j in reversed(range(image.size[1])) + for i in range(image.size[0]) + ] + ) + else: + raise PluginError("Invalid combo: " + fmt + ", " + bitSize) + else: + raise PluginError("Invalid image format " + fmt) - elif fmt == 'G_IM_FMT_CI': - raise PluginError("CI not yet implemented.") + # We stored 4bit values in byte arrays, now to convert + if bitSize == "G_IM_SIZ_4b": + fImage.data = compactNibbleArray(fImage.data, image.size[0], image.size[1]) - elif fmt == 'G_IM_FMT_IA': - if bitSize == 'G_IM_SIZ_4b': - fImage.data = bytearray([ - ((int(round(mathutils.Color( - image.pixels[ - (j * image.size[0] + i) * image.channels : - (j * image.size[0] + i) * image.channels + 3 - ]).v * 0x7)) & 0x7) << 1) | \ - (1 if image.pixels[(j * image.size[0] + i) * image.channels + 3] > 0.5 else 0) - for j in reversed(range(image.size[1])) for i in range(image.size[0])]) - elif bitSize == 'G_IM_SIZ_8b': - fImage.data = bytearray([ - ((int(round(mathutils.Color( - image.pixels[ - (j * image.size[0] + i) * image.channels : - (j * image.size[0] + i) * image.channels + 3 - ]).v * 0xF)) & 0xF) << 4) | \ - (int(round(image.pixels[(j * image.size[0] + i) * image.channels + 3] * 0xF)) & 0xF) - for j in reversed(range(image.size[1])) for i in range(image.size[0])]) - elif bitSize == 'G_IM_SIZ_16b': - fImage.data = bytearray([byteVal for doubleByte in [ - (int(round(mathutils.Color( - image.pixels[ - (j * image.size[0] + i) * image.channels : - (j * image.size[0] + i) * image.channels + 3 - ]).v * 0xFF)) & 0xFF, - int(round(image.pixels[(j * image.size[0] + i) * image.channels + 3] * 0xFF)) & 0xFF) - for j in reversed(range(image.size[1])) for i in range(image.size[0])] for byteVal in doubleByte]) - else: - raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) - elif fmt == 'G_IM_FMT_I': - if bitSize == 'G_IM_SIZ_4b': - fImage.data = bytearray([ - int(round(mathutils.Color( - image.pixels[ - (j * image.size[0] + i) * image.channels : - (j * image.size[0] + i) * image.channels + 3 - ]).v * 0xF)) & 0xF - for j in reversed(range(image.size[1])) for i in range(image.size[0])]) - elif bitSize == 'G_IM_SIZ_8b': - fImage.data = bytearray([ - int(round(mathutils.Color( - image.pixels[ - (j * image.size[0] + i) * image.channels : - (j * image.size[0] + i) * image.channels + 3 - ]).v * 0xFF)) & 0xFF - for j in reversed(range(image.size[1])) for i in range(image.size[0])]) - else: - raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) - else: - raise PluginError("Invalid image format " + fmt) + print("Finished converting.") + fModel.addTexture((image, (texFormat, "NONE")), fImage, fMaterial) - # We stored 4bit values in byte arrays, now to convert - if bitSize == 'G_IM_SIZ_4b': - fImage.data = \ - compactNibbleArray(fImage.data, image.size[0], image.size[1]) + return fImage - print("Finished converting.") - fModel.addTexture((image, (texFormat, 'NONE')), fImage, fMaterial) + # Ignore, old version not using list comprehension + # Warning, ints not rounded + # if convertTextureData: + # # N64 is -Y, Blender is +Y + # for j in reversed(range(image.size[1])): + # for i in range(image.size[0]): + # color = [1,1,1,1] + # for field in range(image.channels): + # color[field] = image.pixels[ + # (j * image.size[0] + i) * image.channels + field] + # if fmt == 'G_IM_FMT_RGBA': + # if bitSize == 'G_IM_SIZ_16b': + # words = \ + # ((int(color[0] * 0x1F) & 0x1F) << 11) | \ + # ((int(color[1] * 0x1F) & 0x1F) << 6) | \ + # ((int(color[2] * 0x1F) & 0x1F) << 1) | \ + # (1 if color[3] > 0.5 else 0) + # fImage.data.extend(bytearray(words.to_bytes(2, 'big'))) + # elif bitSize == 'G_IM_SIZ_32b': + # fImage.data.extend(bytearray([ + # int(value * 0xFF) & 0xFF for value in color])) + # else: + # raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) - return fImage - # Ignore, old version not using list comprehension - # Warning, ints not rounded - #if convertTextureData: - # # N64 is -Y, Blender is +Y - # for j in reversed(range(image.size[1])): - # for i in range(image.size[0]): - # color = [1,1,1,1] - # for field in range(image.channels): - # color[field] = image.pixels[ - # (j * image.size[0] + i) * image.channels + field] - # if fmt == 'G_IM_FMT_RGBA': - # if bitSize == 'G_IM_SIZ_16b': - # words = \ - # ((int(color[0] * 0x1F) & 0x1F) << 11) | \ - # ((int(color[1] * 0x1F) & 0x1F) << 6) | \ - # ((int(color[2] * 0x1F) & 0x1F) << 1) | \ - # (1 if color[3] > 0.5 else 0) - # fImage.data.extend(bytearray(words.to_bytes(2, 'big'))) - # elif bitSize == 'G_IM_SIZ_32b': - # fImage.data.extend(bytearray([ - # int(value * 0xFF) & 0xFF for value in color])) - # else: - # raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) # - # elif fmt == 'G_IM_FMT_YUV': - # raise PluginError("YUV not yet implemented.") - # if bitSize == 'G_IM_SIZ_16b': - # pass - # else: - # raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) +# elif fmt == 'G_IM_FMT_YUV': +# raise PluginError("YUV not yet implemented.") +# if bitSize == 'G_IM_SIZ_16b': +# pass +# else: +# raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) # - # elif fmt == 'G_IM_FMT_CI': - # raise PluginError("CI not yet implemented.") +# elif fmt == 'G_IM_FMT_CI': +# raise PluginError("CI not yet implemented.") # - # elif fmt == 'G_IM_FMT_IA': - # intensity = mathutils.Color(color[0:3]).v - # alpha = color[3] - # if bitSize == 'G_IM_SIZ_4b': - # fImage.data.append( - # ((int(intensity * 0x7) & 0x7) << 1) | \ - # (1 if alpha > 0.5 else 0)) - # elif bitSize == 'G_IM_SIZ_8b': - # fImage.data.append( - # ((int(intensity * 0xF) & 0xF) << 4) | \ - # (int(alpha * 0xF) & 0xF)) - # elif bitSize == 'G_IM_SIZ_16b': - # fImage.data.extend(bytearray( - # [int(intensity * 0xFF), int(alpha * 0xFF)])) - # else: - # raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) - # elif fmt == 'G_IM_FMT_I': - # intensity = mathutils.Color(color[0:3]).v - # if bitSize == 'G_IM_SIZ_4b': - # fImage.data.append(int(intensity * 0xF)) - # elif bitSize == 'G_IM_SIZ_8b': - # fImage.data.append(int(intensity * 0xFF)) - # else: - # raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) - # else: - # raise PluginError("Invalid image format " + fmt) - # - # # We stored 4bit values in byte arrays, now to convert - # if bitSize == 'G_IM_SIZ_4b': - # fImage.data = \ - # compactNibbleArray(fImage.data, image.size[0], image.size[1]) - # - #fModel.addTexture((image, (texFormat, 'NONE')), fImage, fMaterial) +# elif fmt == 'G_IM_FMT_IA': +# intensity = mathutils.Color(color[0:3]).v +# alpha = color[3] +# if bitSize == 'G_IM_SIZ_4b': +# fImage.data.append( +# ((int(intensity * 0x7) & 0x7) << 1) | \ +# (1 if alpha > 0.5 else 0)) +# elif bitSize == 'G_IM_SIZ_8b': +# fImage.data.append( +# ((int(intensity * 0xF) & 0xF) << 4) | \ +# (int(alpha * 0xF) & 0xF)) +# elif bitSize == 'G_IM_SIZ_16b': +# fImage.data.extend(bytearray( +# [int(intensity * 0xFF), int(alpha * 0xFF)])) +# else: +# raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) +# elif fmt == 'G_IM_FMT_I': +# intensity = mathutils.Color(color[0:3]).v +# if bitSize == 'G_IM_SIZ_4b': +# fImage.data.append(int(intensity * 0xF)) +# elif bitSize == 'G_IM_SIZ_8b': +# fImage.data.append(int(intensity * 0xFF)) +# else: +# raise PluginError("Invalid combo: " + fmt + ', ' + bitSize) +# else: +# raise PluginError("Invalid image format " + fmt) # - #return fImage +# # We stored 4bit values in byte arrays, now to convert +# if bitSize == 'G_IM_SIZ_4b': +# fImage.data = \ +# compactNibbleArray(fImage.data, image.size[0], image.size[1]) +# +# fModel.addTexture((image, (texFormat, 'NONE')), fImage, fMaterial) +# +# return fImage + def saveLightsDefinition(fModel, fMaterial, material, lightsName): - lights = fModel.getLightAndHandleShared(lightsName) - if lights is not None: - return lights + lights = fModel.getLightAndHandleShared(lightsName) + if lights is not None: + return lights - lights = Lights(toAlnum(lightsName)) + lights = Lights(toAlnum(lightsName)) - if material.use_default_lighting: - color = gammaCorrect(material.default_light_color) - lights.a = Ambient( - [int(color[0] * 255 / 2), - int(color[1] * 255 / 2), - int(color[2] * 255 / 2)]) - lights.l.append(Light( - [int(color[0] * 255), - int(color[1] * 255), - int(color[2] * 255)], - [0x28, 0x28, 0x28])) - else: - ambientColor = gammaCorrect(material.ambient_light_color) + if material.use_default_lighting: + color = gammaCorrect(material.default_light_color) + lights.a = Ambient([int(color[0] * 255 / 2), int(color[1] * 255 / 2), int(color[2] * 255 / 2)]) + lights.l.append(Light([int(color[0] * 255), int(color[1] * 255), int(color[2] * 255)], [0x28, 0x28, 0x28])) + else: + ambientColor = gammaCorrect(material.ambient_light_color) - lights.a = Ambient( - [int(ambientColor[0] * 255), - int(ambientColor[1] * 255), - int(ambientColor[2] * 255)]) + lights.a = Ambient([int(ambientColor[0] * 255), int(ambientColor[1] * 255), int(ambientColor[2] * 255)]) - if material.f3d_light1 is not None: - addLightDefinition(material, material.f3d_light1, lights) - if material.f3d_light2 is not None: - addLightDefinition(material, material.f3d_light2, lights) - if material.f3d_light3 is not None: - addLightDefinition(material, material.f3d_light3, lights) - if material.f3d_light4 is not None: - addLightDefinition(material, material.f3d_light4, lights) - if material.f3d_light5 is not None: - addLightDefinition(material, material.f3d_light5, lights) - if material.f3d_light6 is not None: - addLightDefinition(material, material.f3d_light6, lights) - if material.f3d_light7 is not None: - addLightDefinition(material, material.f3d_light7, lights) + if material.f3d_light1 is not None: + addLightDefinition(material, material.f3d_light1, lights) + if material.f3d_light2 is not None: + addLightDefinition(material, material.f3d_light2, lights) + if material.f3d_light3 is not None: + addLightDefinition(material, material.f3d_light3, lights) + if material.f3d_light4 is not None: + addLightDefinition(material, material.f3d_light4, lights) + if material.f3d_light5 is not None: + addLightDefinition(material, material.f3d_light5, lights) + if material.f3d_light6 is not None: + addLightDefinition(material, material.f3d_light6, lights) + if material.f3d_light7 is not None: + addLightDefinition(material, material.f3d_light7, lights) + + if lightsName in fModel.lights: + raise PluginError("Duplicate light name.") + fModel.addLight(lightsName, lights, fMaterial) + return lights - if lightsName in fModel.lights: - raise PluginError("Duplicate light name.") - fModel.addLight(lightsName, lights, fMaterial) - return lights def addLightDefinition(mat, f3d_light, fLights): - #lightObj = None - #for obj in bpy.context.scene.objects: - # if obj.data == f3d_light: - # lightObj = obj - # break - #if lightObj is None: - # raise PluginError( - # "The material \"" + mat.name + "\" is referencing a light that is no longer in the scene (i.e. has been deleted).") + # lightObj = None + # for obj in bpy.context.scene.objects: + # if obj.data == f3d_light: + # lightObj = obj + # break + # if lightObj is None: + # raise PluginError( + # "The material \"" + mat.name + "\" is referencing a light that is no longer in the scene (i.e. has been deleted).") + + fLights.l.append( + Light( + getLightColor(f3d_light.color), + getLightRotation(f3d_light), + ) + ) - fLights.l.append(Light( - getLightColor(f3d_light.color), - getLightRotation(f3d_light), - )) def getLightColor(lightColor): - return [int(round(value * 0xFF)) for value in gammaCorrect(lightColor)] + return [int(round(value * 0xFF)) for value in gammaCorrect(lightColor)] + def getLightRotation(lightData): - lightObj = None - for obj in bpy.context.scene.objects: - if obj.data == lightData: - lightObj = obj - break - if lightObj is None: - raise PluginError("A material is referencing a light that is no longer in the scene (i.e. has been deleted).") + lightObj = None + for obj in bpy.context.scene.objects: + if obj.data == lightData: + lightObj = obj + break + if lightObj is None: + raise PluginError("A material is referencing a light that is no longer in the scene (i.e. has been deleted).") + + return getObjDirection(lightObj) - return getObjDirection(lightObj) def getObjDirection(obj): - spaceRot = mathutils.Euler((-pi / 2, 0, 0)).to_quaternion() - rotation = spaceRot @ getObjectQuaternion(obj) - normal = (rotation @ mathutils.Vector((0,0,1))).normalized() - return normToSigned8Vector(normal) + spaceRot = mathutils.Euler((-pi / 2, 0, 0)).to_quaternion() + rotation = spaceRot @ getObjectQuaternion(obj) + normal = (rotation @ mathutils.Vector((0, 0, 1))).normalized() + return normToSigned8Vector(normal) + def normToSigned8Vector(normal): - return [int.from_bytes(int(value * 127).to_bytes(1, 'big', - signed = True), 'big') for value in normal] + return [int.from_bytes(int(value * 127).to_bytes(1, "big", signed=True), "big") for value in normal] + def saveBitGeoF3DEX2(value, defaultValue, flagName, geo, matWriteMethod): - if value != defaultValue or matWriteMethod == GfxMatWriteMethod.WriteAll: - if value: - geo.setFlagList.append(flagName) - else: - geo.clearFlagList.append(flagName) + if value != defaultValue or matWriteMethod == GfxMatWriteMethod.WriteAll: + if value: + geo.setFlagList.append(flagName) + else: + geo.clearFlagList.append(flagName) + def saveGeoModeDefinitionF3DEX2(fMaterial, settings, defaults, matWriteMethod): - geo = SPGeometryMode([],[]) + geo = SPGeometryMode([], []) - saveBitGeoF3DEX2(settings.g_zbuffer, defaults.g_zbuffer, 'G_ZBUFFER', - geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_shade, defaults.g_shade, 'G_SHADE', - geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_cull_front, defaults.g_cull_front, 'G_CULL_FRONT', - geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_cull_back, defaults.g_cull_back, 'G_CULL_BACK', - geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_fog, defaults.g_fog, 'G_FOG', geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_lighting, defaults.g_lighting, 'G_LIGHTING', - geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_zbuffer, defaults.g_zbuffer, "G_ZBUFFER", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_shade, defaults.g_shade, "G_SHADE", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_cull_front, defaults.g_cull_front, "G_CULL_FRONT", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_cull_back, defaults.g_cull_back, "G_CULL_BACK", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_fog, defaults.g_fog, "G_FOG", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_lighting, defaults.g_lighting, "G_LIGHTING", geo, matWriteMethod) - # make sure normals are saved correctly. - saveBitGeoF3DEX2(settings.g_tex_gen, defaults.g_tex_gen, 'G_TEXTURE_GEN', - geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_tex_gen_linear, defaults.g_tex_gen_linear, - 'G_TEXTURE_GEN_LINEAR', geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_shade_smooth, defaults.g_shade_smooth, - 'G_SHADING_SMOOTH', geo, matWriteMethod) - saveBitGeoF3DEX2(settings.g_clipping, defaults.g_clipping, 'G_CLIPPING', - geo, matWriteMethod) + # make sure normals are saved correctly. + saveBitGeoF3DEX2(settings.g_tex_gen, defaults.g_tex_gen, "G_TEXTURE_GEN", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_tex_gen_linear, defaults.g_tex_gen_linear, "G_TEXTURE_GEN_LINEAR", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_shade_smooth, defaults.g_shade_smooth, "G_SHADING_SMOOTH", geo, matWriteMethod) + saveBitGeoF3DEX2(settings.g_clipping, defaults.g_clipping, "G_CLIPPING", geo, matWriteMethod) - if len(geo.clearFlagList) != 0 or len(geo.setFlagList) != 0: - if len(geo.clearFlagList) == 0: - geo.clearFlagList.append('0') - elif len(geo.setFlagList) == 0: - geo.setFlagList.append('0') + if len(geo.clearFlagList) != 0 or len(geo.setFlagList) != 0: + if len(geo.clearFlagList) == 0: + geo.clearFlagList.append("0") + elif len(geo.setFlagList) == 0: + geo.setFlagList.append("0") + + if matWriteMethod == GfxMatWriteMethod.WriteAll: + fMaterial.material.commands.append(SPLoadGeometryMode(geo.setFlagList)) + else: + fMaterial.material.commands.append(geo) + fMaterial.revert.commands.append(SPGeometryMode(geo.setFlagList, geo.clearFlagList)) - if matWriteMethod == GfxMatWriteMethod.WriteAll: - fMaterial.material.commands.append(SPLoadGeometryMode(geo.setFlagList)) - else: - fMaterial.material.commands.append(geo) - fMaterial.revert.commands.append(SPGeometryMode(geo.setFlagList, geo.clearFlagList)) def saveBitGeo(value, defaultValue, flagName, setGeo, clearGeo, matWriteMethod): - if value != defaultValue or matWriteMethod == GfxMatWriteMethod.WriteAll: - if value: - setGeo.flagList.append(flagName) - else: - clearGeo.flagList.append(flagName) + if value != defaultValue or matWriteMethod == GfxMatWriteMethod.WriteAll: + if value: + setGeo.flagList.append(flagName) + else: + clearGeo.flagList.append(flagName) + def saveGeoModeDefinition(fMaterial, settings, defaults, matWriteMethod): - setGeo = SPSetGeometryMode([]) - clearGeo = SPClearGeometryMode([]) + setGeo = SPSetGeometryMode([]) + clearGeo = SPClearGeometryMode([]) - saveBitGeo(settings.g_zbuffer, defaults.g_zbuffer, 'G_ZBUFFER', - setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_shade, defaults.g_shade, 'G_SHADE', - setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_cull_front, defaults.g_cull_front, 'G_CULL_FRONT', - setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_cull_back, defaults.g_cull_back, 'G_CULL_BACK', - setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_fog, defaults.g_fog, 'G_FOG', setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_lighting, defaults.g_lighting, 'G_LIGHTING', - setGeo, clearGeo, matWriteMethod) + saveBitGeo(settings.g_zbuffer, defaults.g_zbuffer, "G_ZBUFFER", setGeo, clearGeo, matWriteMethod) + saveBitGeo(settings.g_shade, defaults.g_shade, "G_SHADE", setGeo, clearGeo, matWriteMethod) + saveBitGeo(settings.g_cull_front, defaults.g_cull_front, "G_CULL_FRONT", setGeo, clearGeo, matWriteMethod) + saveBitGeo(settings.g_cull_back, defaults.g_cull_back, "G_CULL_BACK", setGeo, clearGeo, matWriteMethod) + saveBitGeo(settings.g_fog, defaults.g_fog, "G_FOG", setGeo, clearGeo, matWriteMethod) + saveBitGeo(settings.g_lighting, defaults.g_lighting, "G_LIGHTING", setGeo, clearGeo, matWriteMethod) - # make sure normals are saved correctly. - saveBitGeo(settings.g_tex_gen, defaults.g_tex_gen, 'G_TEXTURE_GEN', - setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_tex_gen_linear, defaults.g_tex_gen_linear, - 'G_TEXTURE_GEN_LINEAR', setGeo, clearGeo, matWriteMethod) - saveBitGeo(settings.g_shade_smooth, defaults.g_shade_smooth, - 'G_SHADING_SMOOTH', setGeo, clearGeo, matWriteMethod) - if bpy.context.scene.f3d_type == 'F3DEX_GBI_2' or \ - bpy.context.scene.f3d_type == 'F3DEX_GBI': - saveBitGeo(settings.g_clipping, defaults.g_clipping, 'G_CLIPPING', - setGeo, clearGeo, matWriteMethod) + # make sure normals are saved correctly. + saveBitGeo(settings.g_tex_gen, defaults.g_tex_gen, "G_TEXTURE_GEN", setGeo, clearGeo, matWriteMethod) + saveBitGeo( + settings.g_tex_gen_linear, defaults.g_tex_gen_linear, "G_TEXTURE_GEN_LINEAR", setGeo, clearGeo, matWriteMethod + ) + saveBitGeo(settings.g_shade_smooth, defaults.g_shade_smooth, "G_SHADING_SMOOTH", setGeo, clearGeo, matWriteMethod) + if bpy.context.scene.f3d_type == "F3DEX_GBI_2" or bpy.context.scene.f3d_type == "F3DEX_GBI": + saveBitGeo(settings.g_clipping, defaults.g_clipping, "G_CLIPPING", setGeo, clearGeo, matWriteMethod) + + if len(setGeo.flagList) > 0: + fMaterial.material.commands.append(setGeo) + if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: + fMaterial.revert.commands.append(SPClearGeometryMode(setGeo.flagList)) + if len(clearGeo.flagList) > 0: + fMaterial.material.commands.append(clearGeo) + if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: + fMaterial.revert.commands.append(SPSetGeometryMode(clearGeo.flagList)) - if len(setGeo.flagList) > 0: - fMaterial.material.commands.append(setGeo) - if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - fMaterial.revert.commands.append(SPClearGeometryMode(setGeo.flagList)) - if len(clearGeo.flagList) > 0: - fMaterial.material.commands.append(clearGeo) - if matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - fMaterial.revert.commands.append(SPSetGeometryMode(clearGeo.flagList)) def saveModeSetting(fMaterial, value, defaultValue, cmdClass): - if value != defaultValue: - fMaterial.material.commands.append(cmdClass(value)) - fMaterial.revert.commands.append(cmdClass(defaultValue)) + if value != defaultValue: + fMaterial.material.commands.append(cmdClass(value)) + fMaterial.revert.commands.append(cmdClass(defaultValue)) + def saveOtherModeHDefinition(fMaterial, settings, defaults, isHWv1, matWriteMethod): - if matWriteMethod == GfxMatWriteMethod.WriteAll: - saveOtherModeHDefinitionAll(fMaterial, settings, defaults, isHWv1) - elif matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - saveOtherModeHDefinitionIndividual(fMaterial, settings, defaults, isHWv1) - else: - raise PluginError("Unhandled material write method: " + str(matWriteMethod)) + if matWriteMethod == GfxMatWriteMethod.WriteAll: + saveOtherModeHDefinitionAll(fMaterial, settings, defaults, isHWv1) + elif matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: + saveOtherModeHDefinitionIndividual(fMaterial, settings, defaults, isHWv1) + else: + raise PluginError("Unhandled material write method: " + str(matWriteMethod)) + def saveOtherModeHDefinitionAll(fMaterial, settings, defaults, isHWv1): - cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20, []) - cmd.flagList.append(settings.g_mdsft_alpha_dither) - if not isHWv1: - cmd.flagList.append(settings.g_mdsft_rgb_dither) - cmd.flagList.append(settings.g_mdsft_combkey) - cmd.flagList.append(settings.g_mdsft_textconv) - cmd.flagList.append(settings.g_mdsft_text_filt) - cmd.flagList.append(settings.g_mdsft_textlod) - cmd.flagList.append(settings.g_mdsft_textdetail) - cmd.flagList.append(settings.g_mdsft_textpersp) - cmd.flagList.append(settings.g_mdsft_cycletype) - if isHWv1: - cmd.flagList.append(settings.g_mdsft_color_dither) - cmd.flagList.append(settings.g_mdsft_pipeline) + cmd = SPSetOtherMode("G_SETOTHERMODE_H", 4, 20, []) + cmd.flagList.append(settings.g_mdsft_alpha_dither) + if not isHWv1: + cmd.flagList.append(settings.g_mdsft_rgb_dither) + cmd.flagList.append(settings.g_mdsft_combkey) + cmd.flagList.append(settings.g_mdsft_textconv) + cmd.flagList.append(settings.g_mdsft_text_filt) + cmd.flagList.append(settings.g_mdsft_textlod) + cmd.flagList.append(settings.g_mdsft_textdetail) + cmd.flagList.append(settings.g_mdsft_textpersp) + cmd.flagList.append(settings.g_mdsft_cycletype) + if isHWv1: + cmd.flagList.append(settings.g_mdsft_color_dither) + cmd.flagList.append(settings.g_mdsft_pipeline) + + fMaterial.material.commands.append(cmd) - fMaterial.material.commands.append(cmd) def saveOtherModeHDefinitionIndividual(fMaterial, settings, defaults, isHWv1): - saveModeSetting(fMaterial, settings.g_mdsft_alpha_dither, - defaults.g_mdsft_alpha_dither, DPSetAlphaDither) + saveModeSetting(fMaterial, settings.g_mdsft_alpha_dither, defaults.g_mdsft_alpha_dither, DPSetAlphaDither) - if not isHWv1: - saveModeSetting(fMaterial, settings.g_mdsft_rgb_dither, - defaults.g_mdsft_rgb_dither, DPSetColorDither) + if not isHWv1: + saveModeSetting(fMaterial, settings.g_mdsft_rgb_dither, defaults.g_mdsft_rgb_dither, DPSetColorDither) - saveModeSetting(fMaterial, settings.g_mdsft_combkey, - defaults.g_mdsft_combkey, DPSetCombineKey) + saveModeSetting(fMaterial, settings.g_mdsft_combkey, defaults.g_mdsft_combkey, DPSetCombineKey) - saveModeSetting(fMaterial, settings.g_mdsft_textconv, - defaults.g_mdsft_textconv, DPSetTextureConvert) + saveModeSetting(fMaterial, settings.g_mdsft_textconv, defaults.g_mdsft_textconv, DPSetTextureConvert) - saveModeSetting(fMaterial, settings.g_mdsft_text_filt, - defaults.g_mdsft_text_filt, DPSetTextureFilter) + saveModeSetting(fMaterial, settings.g_mdsft_text_filt, defaults.g_mdsft_text_filt, DPSetTextureFilter) - #saveModeSetting(fMaterial, settings.g_mdsft_textlut, - # defaults.g_mdsft_textlut, DPSetTextureLUT) + # saveModeSetting(fMaterial, settings.g_mdsft_textlut, + # defaults.g_mdsft_textlut, DPSetTextureLUT) - saveModeSetting(fMaterial, settings.g_mdsft_textlod, - defaults.g_mdsft_textlod, DPSetTextureLOD) + saveModeSetting(fMaterial, settings.g_mdsft_textlod, defaults.g_mdsft_textlod, DPSetTextureLOD) - saveModeSetting(fMaterial, settings.g_mdsft_textdetail, - defaults.g_mdsft_textdetail, DPSetTextureDetail) + saveModeSetting(fMaterial, settings.g_mdsft_textdetail, defaults.g_mdsft_textdetail, DPSetTextureDetail) - saveModeSetting(fMaterial, settings.g_mdsft_textpersp, - defaults.g_mdsft_textpersp, DPSetTexturePersp) + saveModeSetting(fMaterial, settings.g_mdsft_textpersp, defaults.g_mdsft_textpersp, DPSetTexturePersp) - saveModeSetting(fMaterial, settings.g_mdsft_cycletype, - defaults.g_mdsft_cycletype, DPSetCycleType) + saveModeSetting(fMaterial, settings.g_mdsft_cycletype, defaults.g_mdsft_cycletype, DPSetCycleType) - if isHWv1: - saveModeSetting(fMaterial, settings.g_mdsft_color_dither, - defaults.g_mdsft_color_dither, DPSetColorDither) + if isHWv1: + saveModeSetting(fMaterial, settings.g_mdsft_color_dither, defaults.g_mdsft_color_dither, DPSetColorDither) + + saveModeSetting(fMaterial, settings.g_mdsft_pipeline, defaults.g_mdsft_pipeline, DPPipelineMode) - saveModeSetting(fMaterial, settings.g_mdsft_pipeline, - defaults.g_mdsft_pipeline, DPPipelineMode) def saveOtherModeLDefinition(fMaterial, settings, defaults, defaultRenderMode, matWriteMethod): - if matWriteMethod == GfxMatWriteMethod.WriteAll: - saveOtherModeLDefinitionAll(fMaterial, settings, defaults, defaultRenderMode) - elif matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: - saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRenderMode) - else: - raise PluginError("Unhandled material write method: " + str(matWriteMethod)) + if matWriteMethod == GfxMatWriteMethod.WriteAll: + saveOtherModeLDefinitionAll(fMaterial, settings, defaults, defaultRenderMode) + elif matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert: + saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRenderMode) + else: + raise PluginError("Unhandled material write method: " + str(matWriteMethod)) + def saveOtherModeLDefinitionAll(fMaterial: FMaterial, settings, defaults, defaultRenderMode): - if not settings.set_rendermode and defaultRenderMode is None: - cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, 3, []) - cmd.flagList.append(settings.g_mdsft_alpha_compare) - cmd.flagList.append(settings.g_mdsft_zsrcsel) + if not settings.set_rendermode and defaultRenderMode is None: + cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, 3, []) + cmd.flagList.append(settings.g_mdsft_alpha_compare) + cmd.flagList.append(settings.g_mdsft_zsrcsel) - else: - cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, 32, []) - cmd.flagList.append(settings.g_mdsft_alpha_compare) - cmd.flagList.append(settings.g_mdsft_zsrcsel) + else: + cmd = SPSetOtherMode("G_SETOTHERMODE_L", 0, 32, []) + cmd.flagList.append(settings.g_mdsft_alpha_compare) + cmd.flagList.append(settings.g_mdsft_zsrcsel) - if settings.set_rendermode: - flagList, blendList = getRenderModeFlagList(settings, fMaterial) - cmd.flagList.extend(flagList) - if blendList is not None: - cmd.flagList.extend([ - "GBL_c1(" + blendList[0] + ", " + blendList[1] + ", " + blendList[2] + ", " + blendList[3] + ")", - "GBL_c2(" + blendList[4] + ", " + blendList[5] + ", " + blendList[6] + ", " + blendList[7] + ")", - ]) - else: - cmd.flagList.extend(defaultRenderMode) + if settings.set_rendermode: + flagList, blendList = getRenderModeFlagList(settings, fMaterial) + cmd.flagList.extend(flagList) + if blendList is not None: + cmd.flagList.extend( + [ + "GBL_c1(" + + blendList[0] + + ", " + + blendList[1] + + ", " + + blendList[2] + + ", " + + blendList[3] + + ")", + "GBL_c2(" + + blendList[4] + + ", " + + blendList[5] + + ", " + + blendList[6] + + ", " + + blendList[7] + + ")", + ] + ) + else: + cmd.flagList.extend(defaultRenderMode) - fMaterial.material.commands.append(cmd) + fMaterial.material.commands.append(cmd) + + if settings.g_mdsft_zsrcsel == "G_ZS_PRIM": + fMaterial.material.commands.append(DPSetPrimDepth(z=settings.prim_depth.z, dz=settings.prim_depth.dz)) + fMaterial.revert.commands.append(DPSetPrimDepth()) - if settings.g_mdsft_zsrcsel == 'G_ZS_PRIM': - fMaterial.material.commands.append(DPSetPrimDepth(z=settings.prim_depth.z, dz=settings.prim_depth.dz)) - fMaterial.revert.commands.append(DPSetPrimDepth()) def saveOtherModeLDefinitionIndividual(fMaterial, settings, defaults, defaultRenderMode): - saveModeSetting(fMaterial, settings.g_mdsft_alpha_compare, - defaults.g_mdsft_alpha_compare, DPSetAlphaCompare) + saveModeSetting(fMaterial, settings.g_mdsft_alpha_compare, defaults.g_mdsft_alpha_compare, DPSetAlphaCompare) - saveModeSetting(fMaterial, settings.g_mdsft_zsrcsel, - defaults.g_mdsft_zsrcsel, DPSetDepthSource) + saveModeSetting(fMaterial, settings.g_mdsft_zsrcsel, defaults.g_mdsft_zsrcsel, DPSetDepthSource) - if settings.g_mdsft_zsrcsel == 'G_ZS_PRIM': - fMaterial.material.commands.append(DPSetPrimDepth(z=settings.prim_depth.z, dz=settings.prim_depth.dz)) - fMaterial.revert.commands.append(DPSetPrimDepth()) + if settings.g_mdsft_zsrcsel == "G_ZS_PRIM": + fMaterial.material.commands.append(DPSetPrimDepth(z=settings.prim_depth.z, dz=settings.prim_depth.dz)) + fMaterial.revert.commands.append(DPSetPrimDepth()) - if settings.set_rendermode: - flagList, blendList = getRenderModeFlagList(settings, fMaterial) - renderModeSet = DPSetRenderMode(flagList, blendList) + if settings.set_rendermode: + flagList, blendList = getRenderModeFlagList(settings, fMaterial) + renderModeSet = DPSetRenderMode(flagList, blendList) + + fMaterial.material.commands.append(renderModeSet) + if defaultRenderMode is not None: + fMaterial.revert.commands.append(DPSetRenderMode(defaultRenderMode, None)) - fMaterial.material.commands.append(renderModeSet) - if defaultRenderMode is not None: - fMaterial.revert.commands.append(DPSetRenderMode(defaultRenderMode, None)) def getRenderModeFlagList(settings, fMaterial): - flagList = [] - blendList = None - # cycle independent + flagList = [] + blendList = None + # cycle independent - if not settings.rendermode_advanced_enabled: - fMaterial.renderModeUseDrawLayer = [ - settings.rendermode_preset_cycle_1 == 'Use Draw Layer', - settings.rendermode_preset_cycle_2 == 'Use Draw Layer'] + if not settings.rendermode_advanced_enabled: + fMaterial.renderModeUseDrawLayer = [ + settings.rendermode_preset_cycle_1 == "Use Draw Layer", + settings.rendermode_preset_cycle_2 == "Use Draw Layer", + ] - if settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - flagList = [ - settings.rendermode_preset_cycle_1, - settings.rendermode_preset_cycle_2] - else: - cycle2 = settings.rendermode_preset_cycle_1 + '2' - if cycle2 not in [value[0] for value in enumRenderModesCycle2]: - cycle2 = "G_RM_NOOP" - flagList = [ - settings.rendermode_preset_cycle_1, cycle2] - else: - if settings.g_mdsft_cycletype == 'G_CYC_2CYCLE': - blendList = \ - [settings.blend_p1, settings.blend_a1, - settings.blend_m1, settings.blend_b1, - settings.blend_p2, settings.blend_a2, - settings.blend_m2, settings.blend_b2] - else: - blendList = \ - [settings.blend_p1, settings.blend_a1, - settings.blend_m1, settings.blend_b1, - settings.blend_p1, settings.blend_a1, - settings.blend_m1, settings.blend_b1] + if settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + flagList = [settings.rendermode_preset_cycle_1, settings.rendermode_preset_cycle_2] + else: + cycle2 = settings.rendermode_preset_cycle_1 + "2" + if cycle2 not in [value[0] for value in enumRenderModesCycle2]: + cycle2 = "G_RM_NOOP" + flagList = [settings.rendermode_preset_cycle_1, cycle2] + else: + if settings.g_mdsft_cycletype == "G_CYC_2CYCLE": + blendList = [ + settings.blend_p1, + settings.blend_a1, + settings.blend_m1, + settings.blend_b1, + settings.blend_p2, + settings.blend_a2, + settings.blend_m2, + settings.blend_b2, + ] + else: + blendList = [ + settings.blend_p1, + settings.blend_a1, + settings.blend_m1, + settings.blend_b1, + settings.blend_p1, + settings.blend_a1, + settings.blend_m1, + settings.blend_b1, + ] - if settings.aa_en: - flagList.append("AA_EN") - if settings.z_cmp: - flagList.append("Z_CMP") - if settings.z_upd: - flagList.append("Z_UPD") - if settings.im_rd: - flagList.append("IM_RD") - if settings.clr_on_cvg: - flagList.append("CLR_ON_CVG") + if settings.aa_en: + flagList.append("AA_EN") + if settings.z_cmp: + flagList.append("Z_CMP") + if settings.z_upd: + flagList.append("Z_UPD") + if settings.im_rd: + flagList.append("IM_RD") + if settings.clr_on_cvg: + flagList.append("CLR_ON_CVG") - flagList.append(settings.cvg_dst) - flagList.append(settings.zmode) + flagList.append(settings.cvg_dst) + flagList.append(settings.zmode) - if settings.cvg_x_alpha: - flagList.append("CVG_X_ALPHA") - if settings.alpha_cvg_sel: - flagList.append("ALPHA_CVG_SEL") - if settings.force_bl: - flagList.append("FORCE_BL") + if settings.cvg_x_alpha: + flagList.append("CVG_X_ALPHA") + if settings.alpha_cvg_sel: + flagList.append("ALPHA_CVG_SEL") + if settings.force_bl: + flagList.append("FORCE_BL") + + return flagList, blendList - return flagList, blendList def saveOtherDefinition(fMaterial, material, defaults): - settings = material.rdp_settings - if settings.clip_ratio != defaults.clip_ratio: - fMaterial.material.commands.append(SPClipRatio(settings.clip_ratio)) - fMaterial.revert.commands.append(SPClipRatio(defaults.clip_ratio)) + settings = material.rdp_settings + if settings.clip_ratio != defaults.clip_ratio: + fMaterial.material.commands.append(SPClipRatio(settings.clip_ratio)) + fMaterial.revert.commands.append(SPClipRatio(defaults.clip_ratio)) - if material.set_blend: - fMaterial.material.commands.append( - DPSetBlendColor( - int(material.blend_color[0] * 255), - int(material.blend_color[1] * 255), - int(material.blend_color[2] * 255), - int(material.blend_color[3] * 255))) + if material.set_blend: + fMaterial.material.commands.append( + DPSetBlendColor( + int(material.blend_color[0] * 255), + int(material.blend_color[1] * 255), + int(material.blend_color[2] * 255), + int(material.blend_color[3] * 255), + ) + ) enumMatWriteMethod = [ - ("Differing", "Write Differing And Revert", "Write Differing And Revert"), - ("All", "Write All", "Write All") + ("Differing", "Write Differing And Revert", "Write Differing And Revert"), + ("All", "Write All", "Write All"), ] -matWriteMethodEnumDict = { - "Differing" : GfxMatWriteMethod.WriteDifferingAndRevert, - "All" : GfxMatWriteMethod.WriteAll -} +matWriteMethodEnumDict = {"Differing": GfxMatWriteMethod.WriteDifferingAndRevert, "All": GfxMatWriteMethod.WriteAll} + def getWriteMethodFromEnum(enumVal): - if enumVal not in matWriteMethodEnumDict: - raise PluginError("Enum value " + str(enumVal) + " not found in material write method dict.") - else: - return matWriteMethodEnumDict[enumVal] + if enumVal not in matWriteMethodEnumDict: + raise PluginError("Enum value " + str(enumVal) + " not found in material write method dict.") + else: + return matWriteMethodEnumDict[enumVal] -def exportF3DtoC(dirPath, obj, DLFormat, transformMatrix, - f3dType, isHWv1, texDir, savePNG, texSeparate, name, matWriteMethod): - fModel = FModel(f3dType, isHWv1, name, DLFormat, matWriteMethod) - fMesh = exportF3DCommon(obj, fModel, transformMatrix, - True, name, DLFormat, not savePNG) +def exportF3DtoC( + dirPath, obj, DLFormat, transformMatrix, f3dType, isHWv1, texDir, savePNG, texSeparate, name, matWriteMethod +): - modelDirPath = os.path.join(dirPath, toAlnum(name)) + fModel = FModel(f3dType, isHWv1, name, DLFormat, matWriteMethod) + fMesh = exportF3DCommon(obj, fModel, transformMatrix, True, name, DLFormat, not savePNG) - if not os.path.exists(modelDirPath): - os.makedirs(modelDirPath) + modelDirPath = os.path.join(dirPath, toAlnum(name)) - gfxFormatter = GfxFormatter(ScrollMethod.Vertex, 64) - exportData = fModel.to_c(TextureExportSettings(texSeparate, savePNG, texDir, modelDirPath), gfxFormatter) - staticData = exportData.staticData - dynamicData = exportData.dynamicData - texC = exportData.textureData + if not os.path.exists(modelDirPath): + os.makedirs(modelDirPath) - if DLFormat == DLFormat.Static: - staticData.append(dynamicData) - else: - geoString = writeMaterialFiles(dirPath, modelDirPath, - '#include "actors/' + toAlnum(name) + '/header.h"', - '#include "actors/' + toAlnum(name) + '/material.inc.h"', - dynamicData.header, dynamicData.source, '', True) + gfxFormatter = GfxFormatter(ScrollMethod.Vertex, 64) + exportData = fModel.to_c(TextureExportSettings(texSeparate, savePNG, texDir, modelDirPath), gfxFormatter) + staticData = exportData.staticData + dynamicData = exportData.dynamicData + texC = exportData.textureData - if texSeparate: - texCFile = open(os.path.join(modelDirPath, 'texture.inc.c'), 'w', newline='\n') - texCFile.write(texC.source) - texCFile.close() + if DLFormat == DLFormat.Static: + staticData.append(dynamicData) + else: + geoString = writeMaterialFiles( + dirPath, + modelDirPath, + '#include "actors/' + toAlnum(name) + '/header.h"', + '#include "actors/' + toAlnum(name) + '/material.inc.h"', + dynamicData.header, + dynamicData.source, + "", + True, + ) + + if texSeparate: + texCFile = open(os.path.join(modelDirPath, "texture.inc.c"), "w", newline="\n") + texCFile.write(texC.source) + texCFile.close() + + writeCData(staticData, os.path.join(modelDirPath, "header.h"), os.path.join(modelDirPath, "model.inc.c")) - writeCData(staticData, os.path.join(modelDirPath, 'header.h'), - os.path.join(modelDirPath, 'model.inc.c')) def removeDL(sourcePath, headerPath, DLName): - DLDataC = readFile(sourcePath) - originalDataC = DLDataC + DLDataC = readFile(sourcePath) + originalDataC = DLDataC - DLDataH = readFile(headerPath) - originalDataH = DLDataH + DLDataH = readFile(headerPath) + originalDataH = DLDataH - matchResult = re.search("Gfx\s*" + re.escape(DLName) + "\s*\[\s*[0-9x]*\s*\]\s*=\s*\{([^}]*)}\s*;\s*", DLDataC, re.DOTALL) - if matchResult is not None: - DLDataC = DLDataC[:matchResult.start(0)] + DLDataC[matchResult.end(0):] + matchResult = re.search( + "Gfx\s*" + re.escape(DLName) + "\s*\[\s*[0-9x]*\s*\]\s*=\s*\{([^}]*)}\s*;\s*", DLDataC, re.DOTALL + ) + if matchResult is not None: + DLDataC = DLDataC[: matchResult.start(0)] + DLDataC[matchResult.end(0) :] - headerMatch = getDeclaration(DLDataH, DLName) - if headerMatch is not None: - DLDataH = DLDataH[:headerMatch.start(0)] + DLDataH[headerMatch.end(0):] + headerMatch = getDeclaration(DLDataH, DLName) + if headerMatch is not None: + DLDataH = DLDataH[: headerMatch.start(0)] + DLDataH[headerMatch.end(0) :] - if DLDataC != originalDataC: - writeFile(sourcePath, DLDataC) + if DLDataC != originalDataC: + writeFile(sourcePath, DLDataC) + + if DLDataH != originalDataH: + writeFile(headerPath, DLDataH) - if DLDataH != originalDataH: - writeFile(headerPath, DLDataH) class F3D_ExportDL(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.f3d_export_dl' - bl_label = "Export Display List" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.f3d_export_dl" + bl_label = "Export Display List" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") - try: - allObjs = context.selected_objects - if len(allObjs) == 0: - raise PluginError("No objects selected.") - obj = context.selected_objects[0] - if not isinstance(obj.data, bpy.types.Mesh): - raise PluginError("Object is not a mesh.") + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + try: + allObjs = context.selected_objects + if len(allObjs) == 0: + raise PluginError("No objects selected.") + obj = context.selected_objects[0] + if not isinstance(obj.data, bpy.types.Mesh): + raise PluginError("Object is not a mesh.") - scaleValue = bpy.context.scene.blenderF3DScale - finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector(( - scaleValue, scaleValue, scaleValue))).to_4x4() + scaleValue = bpy.context.scene.blenderF3DScale + finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector((scaleValue, scaleValue, scaleValue))).to_4x4() - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} - try: - applyRotation([obj], math.radians(90), 'X') + try: + applyRotation([obj], math.radians(90), "X") - exportPath = bpy.path.abspath(context.scene.DLExportPath) - dlFormat = DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic - f3dType = context.scene.f3d_type - isHWv1 = context.scene.isHWv1 - texDir = bpy.context.scene.DLTexDir - savePNG = bpy.context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions - separateTexDef = bpy.context.scene.DLSeparateTextureDef - DLName = bpy.context.scene.DLName - matWriteMethod = getWriteMethodFromEnum(context.scene.matWriteMethod) + exportPath = bpy.path.abspath(context.scene.DLExportPath) + dlFormat = DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic + f3dType = context.scene.f3d_type + isHWv1 = context.scene.isHWv1 + texDir = bpy.context.scene.DLTexDir + savePNG = bpy.context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions + separateTexDef = bpy.context.scene.DLSeparateTextureDef + DLName = bpy.context.scene.DLName + matWriteMethod = getWriteMethodFromEnum(context.scene.matWriteMethod) - exportF3DtoC(exportPath, obj, dlFormat, finalTransform, - f3dType, isHWv1, texDir, savePNG, separateTexDef, DLName, matWriteMethod) + exportF3DtoC( + exportPath, + obj, + dlFormat, + finalTransform, + f3dType, + isHWv1, + texDir, + savePNG, + separateTexDef, + DLName, + matWriteMethod, + ) - self.report({'INFO'}, 'Success!') + self.report({"INFO"}, "Success!") - applyRotation([obj], math.radians(-90), 'X') - return {'FINISHED'} # must return a set + applyRotation([obj], math.radians(-90), "X") + return {"FINISHED"} # must return a set - except Exception as e: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') - applyRotation([obj], math.radians(-90), 'X') + except Exception as e: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + applyRotation([obj], math.radians(-90), "X") + + raisePluginError(self, e) + return {"CANCELLED"} # must return a set - raisePluginError(self, e) - return {'CANCELLED'} # must return a set class F3D_ExportDLPanel(bpy.types.Panel): - bl_idname = "F3D_PT_export_dl" - bl_label = "F3D Exporter" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'Fast64' - bl_options = {'DEFAULT_CLOSED'} + bl_idname = "F3D_PT_export_dl" + bl_label = "F3D Exporter" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Fast64" + bl_options = {"DEFAULT_CLOSED"} - @classmethod - def poll(cls, context): - return True + @classmethod + def poll(cls, context): + return True - # called every frame - def draw(self, context): - col = self.layout.column() - col.operator(F3D_ExportDL.bl_idname) + # called every frame + def draw(self, context): + col = self.layout.column() + col.operator(F3D_ExportDL.bl_idname) - prop_split(col, context.scene, 'DLName', 'Name') - prop_split(col, context.scene, 'DLExportPath', "Export Path") - prop_split(col, context.scene, "blenderF3DScale", "Scale") - prop_split(col, context.scene, 'matWriteMethod', "Material Write Method") - col.prop(context.scene, 'DLExportisStatic') + prop_split(col, context.scene, "DLName", "Name") + prop_split(col, context.scene, "DLExportPath", "Export Path") + prop_split(col, context.scene, "blenderF3DScale", "Scale") + prop_split(col, context.scene, "matWriteMethod", "Material Write Method") + col.prop(context.scene, "DLExportisStatic") + + if not bpy.context.scene.ignoreTextureRestrictions: + if context.scene.saveTextures: + prop_split(col, context.scene, "DLTexDir", "Texture Include Path") + col.prop(context.scene, "DLSeparateTextureDef") - if not bpy.context.scene.ignoreTextureRestrictions: - if context.scene.saveTextures: - prop_split(col, context.scene, 'DLTexDir', - 'Texture Include Path') - col.prop(context.scene, 'DLSeparateTextureDef') f3d_writer_classes = ( - F3D_ExportDL, - F3D_ExportDLPanel, + F3D_ExportDL, + F3D_ExportDLPanel, ) def f3d_writer_register(): - for cls in f3d_writer_classes: - register_class(cls) + for cls in f3d_writer_classes: + register_class(cls) + + bpy.types.Scene.matWriteMethod = bpy.props.EnumProperty(items=enumMatWriteMethod) - bpy.types.Scene.matWriteMethod = bpy.props.EnumProperty(items = enumMatWriteMethod) def f3d_writer_unregister(): - for cls in reversed(f3d_writer_classes): - unregister_class(cls) + for cls in reversed(f3d_writer_classes): + unregister_class(cls) - del bpy.types.Scene.matWriteMethod + del bpy.types.Scene.matWriteMethod diff --git a/fast64_internal/f3d_material_converter.py b/fast64_internal/f3d_material_converter.py index e045ad4..f2ab6aa 100644 --- a/fast64_internal/f3d_material_converter.py +++ b/fast64_internal/f3d_material_converter.py @@ -7,292 +7,310 @@ from .sm64.sm64_collision import CollisionSettings from .utility import * from bl_operators.presets import AddPresetBase -def upgradeF3DVersionAll(objs, armatures, version): - # Remove original v2 node groups so that they can be recreated. - deleteGroups = [] - for node_tree in bpy.data.node_groups: - if node_tree.name[-6:] == 'F3D v' + str(version): - deleteGroups.append(node_tree) - for deleteGroup in deleteGroups: - bpy.data.node_groups.remove(deleteGroup) - # Dict of non-f3d materials : converted f3d materials - # handles cases where materials are used in multiple objects - materialDict = {} - for obj in objs: - upgradeF3DVersionOneObject(obj, materialDict, version) - - for armature in armatures: - for bone in armature.bones: - if bone.geo_cmd == "Switch": - for switchOption in bone.switch_options: - if switchOption.switchType == "Material": - if switchOption.materialOverride in materialDict: - switchOption.materialOverride = materialDict[switchOption.materialOverride] - for i in range(len(switchOption.specificOverrideArray)): - material = switchOption.specificOverrideArray[i].material - if material in materialDict: - switchOption.specificOverrideArray[i].material = materialDict[material] - for i in range(len(switchOption.specificIgnoreArray)): - material = switchOption.specificIgnoreArray[i].material - if material in materialDict: - switchOption.specificIgnoreArray[i].material = materialDict[material] +def upgradeF3DVersionAll(objs, armatures, version): + # Remove original v2 node groups so that they can be recreated. + deleteGroups = [] + for node_tree in bpy.data.node_groups: + if node_tree.name[-6:] == "F3D v" + str(version): + deleteGroups.append(node_tree) + for deleteGroup in deleteGroups: + bpy.data.node_groups.remove(deleteGroup) + + # Dict of non-f3d materials : converted f3d materials + # handles cases where materials are used in multiple objects + materialDict = {} + for obj in objs: + upgradeF3DVersionOneObject(obj, materialDict, version) + + for armature in armatures: + for bone in armature.bones: + if bone.geo_cmd == "Switch": + for switchOption in bone.switch_options: + if switchOption.switchType == "Material": + if switchOption.materialOverride in materialDict: + switchOption.materialOverride = materialDict[switchOption.materialOverride] + for i in range(len(switchOption.specificOverrideArray)): + material = switchOption.specificOverrideArray[i].material + if material in materialDict: + switchOption.specificOverrideArray[i].material = materialDict[material] + for i in range(len(switchOption.specificIgnoreArray)): + material = switchOption.specificIgnoreArray[i].material + if material in materialDict: + switchOption.specificIgnoreArray[i].material = materialDict[material] def upgradeF3DVersionOneObject(obj, materialDict, version): - for index in range(len(obj.material_slots)): - material = obj.material_slots[index].material - if material is not None and material.is_f3d: - if material in materialDict: - obj.material_slots[index].material = materialDict[material] - else: - convertF3DtoNewVersion(obj, index, material, materialDict, version) + for index in range(len(obj.material_slots)): + material = obj.material_slots[index].material + if material is not None and material.is_f3d: + if material in materialDict: + obj.material_slots[index].material = materialDict[material] + else: + convertF3DtoNewVersion(obj, index, material, materialDict, version) + V4PresetName = { - 'Unlit Texture' : "sm64_unlit_texture", - 'Unlit Texture Cutout' : "sm64_unlit_texture_cutout", - 'Shaded Solid' : "sm64_shaded_solid", - 'Shaded Texture' : "sm64_shaded_texture", - 'Shaded Texture Cutout' : "sm64_shaded_texture_cutout", - 'Shaded Texture Transparent' : "sm64_shaded_texture_transparent", - 'Environment Mapped' : "sm64_environment_map", - 'Decal On Shaded Solid' : "sm64_decal", - 'Vertex Colored Texture' : "sm64_vertex_colored_texture", - 'Fog Shaded Texture' : "sm64_fog_shaded_texture", - 'Fog Shaded Texture Cutout' : "sm64_fog_shaded_texture_cutout", - 'Fog Shaded Texture Transparent' : "sm64_fog_shaded_texture_transparent", - 'Vertex Colored Texture Transparent' : "sm64_vertex_colored_texture_transparent", - 'Shaded Noise' : "sm64_shaded_noise", + "Unlit Texture": "sm64_unlit_texture", + "Unlit Texture Cutout": "sm64_unlit_texture_cutout", + "Shaded Solid": "sm64_shaded_solid", + "Shaded Texture": "sm64_shaded_texture", + "Shaded Texture Cutout": "sm64_shaded_texture_cutout", + "Shaded Texture Transparent": "sm64_shaded_texture_transparent", + "Environment Mapped": "sm64_environment_map", + "Decal On Shaded Solid": "sm64_decal", + "Vertex Colored Texture": "sm64_vertex_colored_texture", + "Fog Shaded Texture": "sm64_fog_shaded_texture", + "Fog Shaded Texture Cutout": "sm64_fog_shaded_texture_cutout", + "Fog Shaded Texture Transparent": "sm64_fog_shaded_texture_transparent", + "Vertex Colored Texture Transparent": "sm64_vertex_colored_texture_transparent", + "Shaded Noise": "sm64_shaded_noise", } + def getV4PresetName(name): - newName = None - if name in V4PresetName: - newName = V4PresetName[name] - else: - newName = "Custom" - return newName + newName = None + if name in V4PresetName: + newName = V4PresetName[name] + else: + newName = "Custom" + return newName + def convertF3DtoNewVersion(obj, index, material, materialDict, version): - - if material.mat_ver > 3: - oldPreset = AddPresetBase.as_filename(material.f3d_mat.presetName) - else: - oldPreset = material.f3d_preset - if version > 3: - newMat = createF3DMat(obj, preset = getV4PresetName(oldPreset), index = index) - if material.mat_ver > 3: - copyPropertyGroup(material.f3d_mat, newMat.f3d_mat) - else: - convertToNewMat(newMat, material) - if newMat.f3d_mat.draw_layer.sm64 != obj.draw_layer_static: - newMat.f3d_mat.draw_layer.sm64 = obj.draw_layer_static - else: - newMat = createF3DMat(obj, preset = oldPreset, index = index) - matSettings = F3DMaterialSettings() - matSettings.loadFromMaterial(material, True) - matSettings.applyToMaterial(newMat, True, update_node_values_of_material, bpy.context) + if material.mat_ver > 3: + oldPreset = AddPresetBase.as_filename(material.f3d_mat.presetName) + else: + oldPreset = material.f3d_preset - copyPropertyGroup(material.ootMaterial, newMat.ootMaterial) - copyPropertyGroup(material.ootCollisionProperty, newMat.ootCollisionProperty) + if version > 3: + newMat = createF3DMat(obj, preset=getV4PresetName(oldPreset), index=index) + if material.mat_ver > 3: + copyPropertyGroup(material.f3d_mat, newMat.f3d_mat) + else: + convertToNewMat(newMat, material) + if newMat.f3d_mat.draw_layer.sm64 != obj.draw_layer_static: + newMat.f3d_mat.draw_layer.sm64 = obj.draw_layer_static + else: + newMat = createF3DMat(obj, preset=oldPreset, index=index) + matSettings = F3DMaterialSettings() + matSettings.loadFromMaterial(material, True) + matSettings.applyToMaterial(newMat, True, update_node_values_of_material, bpy.context) - colSettings = CollisionSettings() - colSettings.load(material) - colSettings.apply(newMat) + copyPropertyGroup(material.ootMaterial, newMat.ootMaterial) + copyPropertyGroup(material.ootCollisionProperty, newMat.ootCollisionProperty) + + colSettings = CollisionSettings() + colSettings.load(material) + colSettings.apply(newMat) + + updateMatWithNewVersionName(newMat, material, materialDict, version) - updateMatWithNewVersionName(newMat, material, materialDict, version) def convertAllBSDFtoF3D(objs, renameUV): - # Dict of non-f3d materials : converted f3d materials - # handles cases where materials are used in multiple objects - materialDict = {} - for obj in objs: - if renameUV: - for uv_layer in obj.data.uv_layers: - uv_layer.name = "UVMap" - for index in range(len(obj.material_slots)): - material = obj.material_slots[index].material - if material is not None and not material.is_f3d: - if material in materialDict: - print("Existing material") - obj.material_slots[index].material = materialDict[material] - else: - print("New material") - convertBSDFtoF3D(obj, index, material, materialDict) + # Dict of non-f3d materials : converted f3d materials + # handles cases where materials are used in multiple objects + materialDict = {} + for obj in objs: + if renameUV: + for uv_layer in obj.data.uv_layers: + uv_layer.name = "UVMap" + for index in range(len(obj.material_slots)): + material = obj.material_slots[index].material + if material is not None and not material.is_f3d: + if material in materialDict: + print("Existing material") + obj.material_slots[index].material = materialDict[material] + else: + print("New material") + convertBSDFtoF3D(obj, index, material, materialDict) + def convertBSDFtoF3D(obj, index, material, materialDict): - if not material.use_nodes: - newMaterial = createF3DMat(obj, preset = 'Shaded Solid', index = index) - f3dMat = newMaterial.f3d_mat if newMaterial.mat_ver > 3 else newMaterial - f3dMat.default_light_color = material.diffuse_color - updateMatWithName(newMaterial, material, materialDict) + if not material.use_nodes: + newMaterial = createF3DMat(obj, preset="Shaded Solid", index=index) + f3dMat = newMaterial.f3d_mat if newMaterial.mat_ver > 3 else newMaterial + f3dMat.default_light_color = material.diffuse_color + updateMatWithName(newMaterial, material, materialDict) + + elif "Principled BSDF" in material.node_tree.nodes: + tex0Node = material.node_tree.nodes["Principled BSDF"].inputs["Base Color"] + tex1Node = material.node_tree.nodes["Principled BSDF"].inputs["Subsurface Color"] + if len(tex0Node.links) == 0: + newMaterial = createF3DMat(obj, preset=getDefaultMaterialPreset("Shaded Solid"), index=index) + f3dMat = newMaterial.f3d_mat if newMaterial.mat_ver > 3 else newMaterial + f3dMat.default_light_color = tex0Node.default_value + updateMatWithName(newMaterial, material, materialDict) + else: + if isinstance(tex0Node.links[0].from_node, bpy.types.ShaderNodeTexImage): + if "convert_preset" in material: + presetName = material["convert_preset"] + if presetName not in [enumValue[0] for enumValue in enumMaterialPresets]: + raise PluginError( + "During BSDF to F3D conversion, for material '" + + material.name + + "'," + + " enum '" + + presetName + + "' was not found in material preset enum list." + ) + else: + presetName = getDefaultMaterialPreset("Shaded Texture") + newMaterial = createF3DMat(obj, preset=presetName, index=index) + f3dMat = newMaterial.f3d_mat if newMaterial.mat_ver > 3 else newMaterial + f3dMat.tex0.tex = tex0Node.links[0].from_node.image + if len(tex1Node.links) > 0 and isinstance(tex1Node.links[0].from_node, bpy.types.ShaderNodeTexImage): + f3dMat.tex1.tex = tex1Node.links[0].from_node.image + updateMatWithName(newMaterial, material, materialDict) + else: + print("Principled BSDF material does not have an Image Node attached to its Base Color.") + else: + print("Material is not a Principled BSDF or non-node material.") - elif "Principled BSDF" in material.node_tree.nodes: - tex0Node = material.node_tree.nodes['Principled BSDF'].inputs['Base Color'] - tex1Node = material.node_tree.nodes['Principled BSDF'].inputs['Subsurface Color'] - if len(tex0Node.links) == 0: - newMaterial = createF3DMat(obj, preset = getDefaultMaterialPreset("Shaded Solid"), index = index) - f3dMat = newMaterial.f3d_mat if newMaterial.mat_ver > 3 else newMaterial - f3dMat.default_light_color = tex0Node.default_value - updateMatWithName(newMaterial, material, materialDict) - else: - if isinstance(tex0Node.links[0].from_node, bpy.types.ShaderNodeTexImage): - if 'convert_preset' in material: - presetName = material['convert_preset'] - if presetName not in [enumValue[0] for enumValue in enumMaterialPresets]: - raise PluginError('During BSDF to F3D conversion, for material \'' + material.name + '\',' + \ - ' enum \'' + presetName + '\' was not found in material preset enum list.') - else: - presetName = getDefaultMaterialPreset('Shaded Texture') - newMaterial = createF3DMat(obj, preset = presetName, index = index) - f3dMat = newMaterial.f3d_mat if newMaterial.mat_ver > 3 else newMaterial - f3dMat.tex0.tex = tex0Node.links[0].from_node.image - if len(tex1Node.links) > 0 and \ - isinstance(tex1Node.links[0].from_node, bpy.types.ShaderNodeTexImage): - f3dMat.tex1.tex = tex1Node.links[0].from_node.image - updateMatWithName(newMaterial, material, materialDict) - else: - print("Principled BSDF material does not have an Image Node attached to its Base Color.") - else: - print("Material is not a Principled BSDF or non-node material.") def updateMatWithName(f3dMat, oldMat, materialDict): - f3dMat.name = oldMat.name + "_f3d" - update_preset_manual(f3dMat, bpy.context) - materialDict[oldMat] = f3dMat + f3dMat.name = oldMat.name + "_f3d" + update_preset_manual(f3dMat, bpy.context) + materialDict[oldMat] = f3dMat + def updateMatWithNewVersionName(f3dMat, oldMat, materialDict, version): - name = oldMat.name - if oldMat.name[-3:-1] == '_v': - name = oldMat.name[:-3] - f3dMat.name = name + "_v" + str(version) - update_preset_manual(f3dMat, bpy.context) - materialDict[oldMat] = f3dMat + name = oldMat.name + if oldMat.name[-3:-1] == "_v": + name = oldMat.name[:-3] + f3dMat.name = name + "_v" + str(version) + update_preset_manual(f3dMat, bpy.context) + materialDict[oldMat] = f3dMat + class BSDFConvert(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.convert_bsdf' - bl_label = "Principled BSDF to F3D Converter" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.convert_bsdf" + bl_label = "Principled BSDF to F3D Converter" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - try: - if context.mode != 'OBJECT': - raise PluginError("Operator can only be used in object mode.") - - if context.scene.bsdf_conv_all: - convertAllBSDFtoF3D([obj for obj in bpy.data.objects if isinstance(obj.data, bpy.types.Mesh)], - context.scene.rename_uv_maps) - else: - if len(context.selected_objects) == 0: - raise PluginError("Mesh not selected.") - elif type(context.selected_objects[0].data) is not\ - bpy.types.Mesh: - raise PluginError("Mesh not selected.") - - obj = context.selected_objects[0] - convertAllBSDFtoF3D([obj], context.scene.rename_uv_maps) - - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + try: + if context.mode != "OBJECT": + raise PluginError("Operator can only be used in object mode.") + + if context.scene.bsdf_conv_all: + convertAllBSDFtoF3D( + [obj for obj in bpy.data.objects if isinstance(obj.data, bpy.types.Mesh)], + context.scene.rename_uv_maps, + ) + else: + if len(context.selected_objects) == 0: + raise PluginError("Mesh not selected.") + elif type(context.selected_objects[0].data) is not bpy.types.Mesh: + raise PluginError("Mesh not selected.") + + obj = context.selected_objects[0] + convertAllBSDFtoF3D([obj], context.scene.rename_uv_maps) + + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + + self.report({"INFO"}, "Created F3D material.") + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Created F3D material.') - return {'FINISHED'} # must return a set class MatUpdateConvert(bpy.types.Operator): - # set bl_ properties - version = 4 - bl_idname = 'object.convert_f3d_update' - bl_label = "Recreate F3D Materials As v" + str(version) - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + version = 4 + bl_idname = "object.convert_f3d_update" + bl_label = "Recreate F3D Materials As v" + str(version) + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - try: - if context.mode != 'OBJECT': - raise PluginError("Operator can only be used in object mode.") - - if context.scene.update_conv_all: - upgradeF3DVersionAll([obj for obj in bpy.data.objects if isinstance(obj.data, bpy.types.Mesh)], - bpy.data.armatures, self.version) - else: - if len(context.selected_objects) == 0: - raise PluginError("Mesh not selected.") - elif type(context.selected_objects[0].data) is not\ - bpy.types.Mesh: - raise PluginError("Mesh not selected.") - - obj = context.selected_objects[0] - upgradeF3DVersionOneObject(obj, {}, self.version) - - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + try: + if context.mode != "OBJECT": + raise PluginError("Operator can only be used in object mode.") + + if context.scene.update_conv_all: + upgradeF3DVersionAll( + [obj for obj in bpy.data.objects if isinstance(obj.data, bpy.types.Mesh)], + bpy.data.armatures, + self.version, + ) + else: + if len(context.selected_objects) == 0: + raise PluginError("Mesh not selected.") + elif type(context.selected_objects[0].data) is not bpy.types.Mesh: + raise PluginError("Mesh not selected.") + + obj = context.selected_objects[0] + upgradeF3DVersionOneObject(obj, {}, self.version) + + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + + self.report({"INFO"}, "Created F3D material.") + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Created F3D material.') - return {'FINISHED'} # must return a set class F3DMaterialConverterPanel(bpy.types.Panel): - bl_label = "F3D Material Converter" - bl_idname = "MATERIAL_PT_F3D_Material_Converter" - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'Fast64' + bl_label = "F3D Material Converter" + bl_idname = "MATERIAL_PT_F3D_Material_Converter" + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "Fast64" - @classmethod - def poll(cls, context): - return True - #return hasattr(context, 'object') and context.object is not None and \ - # isinstance(context.object.data, bpy.types.Mesh) + @classmethod + def poll(cls, context): + return True + # return hasattr(context, 'object') and context.object is not None and \ + # isinstance(context.object.data, bpy.types.Mesh) - def draw(self, context): - #mesh = context.object.data - self.layout.operator(BSDFConvert.bl_idname) - self.layout.prop(context.scene, 'bsdf_conv_all') - self.layout.prop(context.scene, 'rename_uv_maps') - self.layout.operator(MatUpdateConvert.bl_idname) - self.layout.prop(context.scene, 'update_conv_all') - self.layout.operator(ReloadDefaultF3DPresets.bl_idname) + def draw(self, context): + # mesh = context.object.data + self.layout.operator(BSDFConvert.bl_idname) + self.layout.prop(context.scene, "bsdf_conv_all") + self.layout.prop(context.scene, "rename_uv_maps") + self.layout.operator(MatUpdateConvert.bl_idname) + self.layout.prop(context.scene, "update_conv_all") + self.layout.operator(ReloadDefaultF3DPresets.bl_idname) bsdf_conv_classes = ( - BSDFConvert, - MatUpdateConvert, + BSDFConvert, + MatUpdateConvert, ) -bsdf_conv_panel_classes = ( - F3DMaterialConverterPanel, -) +bsdf_conv_panel_classes = (F3DMaterialConverterPanel,) + def bsdf_conv_panel_regsiter(): - for cls in bsdf_conv_panel_classes: - register_class(cls) + for cls in bsdf_conv_panel_classes: + register_class(cls) + def bsdf_conv_panel_unregsiter(): - for cls in bsdf_conv_panel_classes: - unregister_class(cls) + for cls in bsdf_conv_panel_classes: + unregister_class(cls) + def bsdf_conv_register(): - for cls in bsdf_conv_classes: - register_class(cls) + for cls in bsdf_conv_classes: + register_class(cls) + + # Moved to Level Root + bpy.types.Scene.bsdf_conv_all = bpy.props.BoolProperty(name="Convert all objects", default=True) + bpy.types.Scene.update_conv_all = bpy.props.BoolProperty(name="Convert all objects", default=True) + bpy.types.Scene.rename_uv_maps = bpy.props.BoolProperty(name="Rename UV maps", default=True) - # Moved to Level Root - bpy.types.Scene.bsdf_conv_all = bpy.props.BoolProperty( - name = 'Convert all objects', default = True) - bpy.types.Scene.update_conv_all = bpy.props.BoolProperty( - name = 'Convert all objects', default = True) - bpy.types.Scene.rename_uv_maps = bpy.props.BoolProperty( - name = 'Rename UV maps', default = True) def bsdf_conv_unregister(): - for cls in bsdf_conv_classes: - unregister_class(cls) + for cls in bsdf_conv_classes: + unregister_class(cls) - del bpy.types.Scene.bsdf_conv_all - del bpy.types.Scene.update_conv_all - del bpy.types.Scene.rename_uv_maps \ No newline at end of file + del bpy.types.Scene.bsdf_conv_all + del bpy.types.Scene.update_conv_all + del bpy.types.Scene.rename_uv_maps diff --git a/fast64_internal/oot/oot_constants.py b/fast64_internal/oot/oot_constants.py index e3bfba7..fdde62f 100644 --- a/fast64_internal/oot/oot_constants.py +++ b/fast64_internal/oot/oot_constants.py @@ -1,1553 +1,1555 @@ ootEnumMeshType = [ - #("Custom", "Custom", "Custom"), - ("0", "Type 0 (Simple)", "Type 0 (Simple)"), - ("1", "Type 1 (Prerendered)", "Type 1 (Prerendered)"), - ("2", "Type 2 (Distance Culling)", "Type 2 (Distance Culling)"), + # ("Custom", "Custom", "Custom"), + ("0", "Type 0 (Simple)", "Type 0 (Simple)"), + ("1", "Type 1 (Prerendered)", "Type 1 (Prerendered)"), + ("2", "Type 2 (Distance Culling)", "Type 2 (Distance Culling)"), ] ootEnumSceneMenu = [ - ("General", "General", "General"), - ("Lighting", "Lighting", "Lighting"), - ("Cutscene", "Cutscene", "Cutscene"), - ("Exits", "Exits", "Exits"), - ("Alternate", "Alternate", "Alternate"), + ("General", "General", "General"), + ("Lighting", "Lighting", "Lighting"), + ("Cutscene", "Cutscene", "Cutscene"), + ("Exits", "Exits", "Exits"), + ("Alternate", "Alternate", "Alternate"), ] ootEnumSceneMenuAlternate = [ - ("General", "General", "General"), - ("Lighting", "Lighting", "Lighting"), - ("Cutscene", "Cutscene", "Cutscene") + ("General", "General", "General"), + ("Lighting", "Lighting", "Lighting"), + ("Cutscene", "Cutscene", "Cutscene"), ] ootEnumRoomMenu = [ - ("General", "General", "General"), - ("Objects", "Objects", "Objects"), - ("Alternate", "Alternate", "Alternate"), + ("General", "General", "General"), + ("Objects", "Objects", "Objects"), + ("Alternate", "Alternate", "Alternate"), ] ootEnumRoomMenuAlternate = [ - ("General", "General", "General"), - ("Objects", "Objects", "Objects"), + ("General", "General", "General"), + ("Objects", "Objects", "Objects"), ] ootEnumHeaderMenu = [ - ("Child Night", "Child Night", "Child Night"), - ("Adult Day", "Adult Day", "Adult Day"), - ("Adult Night", "Adult Night", "Adult Night"), - ("Cutscene", "Cutscene", "Cutscene") + ("Child Night", "Child Night", "Child Night"), + ("Adult Day", "Adult Day", "Adult Day"), + ("Adult Night", "Adult Night", "Adult Night"), + ("Cutscene", "Cutscene", "Cutscene"), ] ootEnumLightGroupMenu = [ - ("Dawn", "Dawn", "Dawn"), - ("Day", "Day", "Day"), - ("Dusk", "Dusk", "Dusk"), - ("Night", "Night", "Night") + ("Dawn", "Dawn", "Dawn"), + ("Day", "Day", "Day"), + ("Dusk", "Dusk", "Dusk"), + ("Night", "Night", "Night"), ] ootEnumTransitionActorID = [ - ("Custom", "Custom", "Custom"), - ("ACTOR_EN_DOOR", "EN_DOOR", "EN_DOOR"), - ("ACTOR_DOOR_SHUTTER", "DOOR_SHUTTER", "DOOR_SHUTTER"), - ("ACTOR_DOOR_WARP1", "DOOR_WARP1", "DOOR_WARP1"), - ("ACTOR_DOOR_TOKI", "DOOR_TOKI", "DOOR_TOKI"), - ("ACTOR_DOOR_ANA", "DOOR_ANA", "DOOR_ANA"), - ("ACTOR_DOOR_GERUDO", "DOOR_GERUDO", "DOOR_GERUDO"), - ("ACTOR_DOOR_KILLER", "DOOR_KILLER", "DOOR_KILLER"), + ("Custom", "Custom", "Custom"), + ("ACTOR_EN_DOOR", "EN_DOOR", "EN_DOOR"), + ("ACTOR_DOOR_SHUTTER", "DOOR_SHUTTER", "DOOR_SHUTTER"), + ("ACTOR_DOOR_WARP1", "DOOR_WARP1", "DOOR_WARP1"), + ("ACTOR_DOOR_TOKI", "DOOR_TOKI", "DOOR_TOKI"), + ("ACTOR_DOOR_ANA", "DOOR_ANA", "DOOR_ANA"), + ("ACTOR_DOOR_GERUDO", "DOOR_GERUDO", "DOOR_GERUDO"), + ("ACTOR_DOOR_KILLER", "DOOR_KILLER", "DOOR_KILLER"), ] ootEnumActorID = [ - ("Custom", "Custom", "Custom"), - ("ACTOR_PLAYER", "PLAYER", "PLAYER"), - ("ACTOR_EN_TEST", "EN_TEST", "EN_TEST"), - ("ACTOR_EN_GIRLA", "EN_GIRLA", "EN_GIRLA"), - ("ACTOR_EN_PART", "EN_PART", "EN_PART"), - ("ACTOR_EN_LIGHT", "EN_LIGHT", "EN_LIGHT"), - ("ACTOR_EN_DOOR", "EN_DOOR", "EN_DOOR"), - ("ACTOR_EN_BOX", "EN_BOX", "EN_BOX"), - ("ACTOR_BG_DY_YOSEIZO", "BG_DY_YOSEIZO", "BG_DY_YOSEIZO"), - ("ACTOR_BG_HIDAN_FIREWALL", "BG_HIDAN_FIREWALL", "BG_HIDAN_FIREWALL"), - ("ACTOR_EN_POH", "EN_POH", "EN_POH"), - ("ACTOR_EN_OKUTA", "EN_OKUTA", "EN_OKUTA"), - ("ACTOR_BG_YDAN_SP", "BG_YDAN_SP", "BG_YDAN_SP"), - ("ACTOR_EN_BOM", "EN_BOM", "EN_BOM"), - ("ACTOR_EN_WALLMAS", "EN_WALLMAS", "EN_WALLMAS"), - ("ACTOR_EN_DODONGO", "EN_DODONGO", "EN_DODONGO"), - ("ACTOR_EN_FIREFLY", "EN_FIREFLY", "EN_FIREFLY"), - ("ACTOR_EN_HORSE", "EN_HORSE", "EN_HORSE"), - ("ACTOR_EN_ITEM00", "EN_ITEM00", "EN_ITEM00"), - ("ACTOR_EN_ARROW", "EN_ARROW", "EN_ARROW"), - ("ACTOR_EN_ELF", "EN_ELF", "EN_ELF"), - ("ACTOR_EN_NIW", "EN_NIW", "EN_NIW"), - ("ACTOR_EN_TITE", "EN_TITE", "EN_TITE"), - ("ACTOR_EN_REEBA", "EN_REEBA", "EN_REEBA"), - ("ACTOR_EN_PEEHAT", "EN_PEEHAT", "EN_PEEHAT"), - ("ACTOR_EN_BUTTE", "EN_BUTTE", "EN_BUTTE"), - ("ACTOR_EN_INSECT", "EN_INSECT", "EN_INSECT"), - ("ACTOR_EN_FISH", "EN_FISH", "EN_FISH"), - ("ACTOR_EN_HOLL", "EN_HOLL", "EN_HOLL"), - ("ACTOR_EN_SCENE_CHANGE", "EN_SCENE_CHANGE", "EN_SCENE_CHANGE"), - ("ACTOR_EN_ZF", "EN_ZF", "EN_ZF"), - ("ACTOR_EN_HATA", "EN_HATA", "EN_HATA"), - ("ACTOR_BOSS_DODONGO", "BOSS_DODONGO", "BOSS_DODONGO"), - ("ACTOR_BOSS_GOMA", "BOSS_GOMA", "BOSS_GOMA"), - ("ACTOR_EN_ZL1", "EN_ZL1", "EN_ZL1"), - ("ACTOR_EN_VIEWER", "EN_VIEWER", "EN_VIEWER"), - ("ACTOR_EN_GOMA", "EN_GOMA", "EN_GOMA"), - ("ACTOR_BG_PUSHBOX", "BG_PUSHBOX", "BG_PUSHBOX"), - ("ACTOR_EN_BUBBLE", "EN_BUBBLE", "EN_BUBBLE"), - ("ACTOR_DOOR_SHUTTER", "DOOR_SHUTTER", "DOOR_SHUTTER"), - ("ACTOR_EN_DODOJR", "EN_DODOJR", "EN_DODOJR"), - ("ACTOR_EN_BDFIRE", "EN_BDFIRE", "EN_BDFIRE"), - ("ACTOR_EN_BOOM", "EN_BOOM", "EN_BOOM"), - ("ACTOR_EN_TORCH2", "EN_TORCH2", "EN_TORCH2"), - ("ACTOR_EN_BILI", "EN_BILI", "EN_BILI"), - ("ACTOR_EN_TP", "EN_TP", "EN_TP"), - ("ACTOR_EN_ST", "EN_ST", "EN_ST"), - ("ACTOR_EN_BW", "EN_BW", "EN_BW"), - ("ACTOR_EN_A_OBJ", "EN_A_OBJ", "EN_A_OBJ"), - ("ACTOR_EN_EIYER", "EN_EIYER", "EN_EIYER"), - ("ACTOR_EN_RIVER_SOUND", "EN_RIVER_SOUND", "EN_RIVER_SOUND"), - ("ACTOR_EN_HORSE_NORMAL", "EN_HORSE_NORMAL", "EN_HORSE_NORMAL"), - ("ACTOR_EN_OSSAN", "EN_OSSAN", "EN_OSSAN"), - ("ACTOR_BG_TREEMOUTH", "BG_TREEMOUTH", "BG_TREEMOUTH"), - ("ACTOR_BG_DODOAGO", "BG_DODOAGO", "BG_DODOAGO"), - ("ACTOR_BG_HIDAN_DALM", "BG_HIDAN_DALM", "BG_HIDAN_DALM"), - ("ACTOR_BG_HIDAN_HROCK", "BG_HIDAN_HROCK", "BG_HIDAN_HROCK"), - ("ACTOR_EN_HORSE_GANON", "EN_HORSE_GANON", "EN_HORSE_GANON"), - ("ACTOR_BG_HIDAN_ROCK", "BG_HIDAN_ROCK", "BG_HIDAN_ROCK"), - ("ACTOR_BG_HIDAN_RSEKIZOU", "BG_HIDAN_RSEKIZOU", "BG_HIDAN_RSEKIZOU"), - ("ACTOR_BG_HIDAN_SEKIZOU", "BG_HIDAN_SEKIZOU", "BG_HIDAN_SEKIZOU"), - ("ACTOR_BG_HIDAN_SIMA", "BG_HIDAN_SIMA", "BG_HIDAN_SIMA"), - ("ACTOR_BG_HIDAN_SYOKU", "BG_HIDAN_SYOKU", "BG_HIDAN_SYOKU"), - ("ACTOR_EN_XC", "EN_XC", "EN_XC"), - ("ACTOR_BG_HIDAN_CURTAIN", "BG_HIDAN_CURTAIN", "BG_HIDAN_CURTAIN"), - ("ACTOR_BG_SPOT00_HANEBASI", "BG_SPOT00_HANEBASI", "BG_SPOT00_HANEBASI"), - ("ACTOR_EN_MB", "EN_MB", "EN_MB"), - ("ACTOR_EN_BOMBF", "EN_BOMBF", "EN_BOMBF"), - ("ACTOR_EN_ZL2", "EN_ZL2", "EN_ZL2"), - ("ACTOR_BG_HIDAN_FSLIFT", "BG_HIDAN_FSLIFT", "BG_HIDAN_FSLIFT"), - ("ACTOR_EN_OE2", "EN_OE2", "EN_OE2"), - ("ACTOR_BG_YDAN_HASI", "BG_YDAN_HASI", "BG_YDAN_HASI"), - ("ACTOR_BG_YDAN_MARUTA", "BG_YDAN_MARUTA", "BG_YDAN_MARUTA"), - ("ACTOR_BOSS_GANONDROF", "BOSS_GANONDROF", "BOSS_GANONDROF"), - ("ACTOR_EN_AM", "EN_AM", "EN_AM"), - ("ACTOR_EN_DEKUBABA", "EN_DEKUBABA", "EN_DEKUBABA"), - ("ACTOR_EN_M_FIRE1", "EN_M_FIRE1", "EN_M_FIRE1"), - ("ACTOR_EN_M_THUNDER", "EN_M_THUNDER", "EN_M_THUNDER"), - ("ACTOR_BG_DDAN_JD", "BG_DDAN_JD", "BG_DDAN_JD"), - ("ACTOR_BG_BREAKWALL", "BG_BREAKWALL", "BG_BREAKWALL"), - ("ACTOR_EN_JJ", "EN_JJ", "EN_JJ"), - ("ACTOR_EN_HORSE_ZELDA", "EN_HORSE_ZELDA", "EN_HORSE_ZELDA"), - ("ACTOR_BG_DDAN_KD", "BG_DDAN_KD", "BG_DDAN_KD"), - ("ACTOR_DOOR_WARP1", "DOOR_WARP1", "DOOR_WARP1"), - ("ACTOR_OBJ_SYOKUDAI", "OBJ_SYOKUDAI", "OBJ_SYOKUDAI"), - ("ACTOR_ITEM_B_HEART", "ITEM_B_HEART", "ITEM_B_HEART"), - ("ACTOR_EN_DEKUNUTS", "EN_DEKUNUTS", "EN_DEKUNUTS"), - ("ACTOR_BG_MENKURI_KAITEN", "BG_MENKURI_KAITEN", "BG_MENKURI_KAITEN"), - ("ACTOR_BG_MENKURI_EYE", "BG_MENKURI_EYE", "BG_MENKURI_EYE"), - ("ACTOR_EN_VALI", "EN_VALI", "EN_VALI"), - ("ACTOR_BG_MIZU_MOVEBG", "BG_MIZU_MOVEBG", "BG_MIZU_MOVEBG"), - ("ACTOR_BG_MIZU_WATER", "BG_MIZU_WATER", "BG_MIZU_WATER"), - ("ACTOR_ARMS_HOOK", "ARMS_HOOK", "ARMS_HOOK"), - ("ACTOR_EN_FHG", "EN_FHG", "EN_FHG"), - ("ACTOR_BG_MORI_HINERI", "BG_MORI_HINERI", "BG_MORI_HINERI"), - ("ACTOR_EN_BB", "EN_BB", "EN_BB"), - ("ACTOR_BG_TOKI_HIKARI", "BG_TOKI_HIKARI", "BG_TOKI_HIKARI"), - ("ACTOR_EN_YUKABYUN", "EN_YUKABYUN", "EN_YUKABYUN"), - ("ACTOR_BG_TOKI_SWD", "BG_TOKI_SWD", "BG_TOKI_SWD"), - ("ACTOR_EN_FHG_FIRE", "EN_FHG_FIRE", "EN_FHG_FIRE"), - ("ACTOR_BG_MJIN", "BG_MJIN", "BG_MJIN"), - ("ACTOR_BG_HIDAN_KOUSI", "BG_HIDAN_KOUSI", "BG_HIDAN_KOUSI"), - ("ACTOR_DOOR_TOKI", "DOOR_TOKI", "DOOR_TOKI"), - ("ACTOR_BG_HIDAN_HAMSTEP", "BG_HIDAN_HAMSTEP", "BG_HIDAN_HAMSTEP"), - ("ACTOR_EN_BIRD", "EN_BIRD", "EN_BIRD"), - ("ACTOR_EN_WOOD02", "EN_WOOD02", "EN_WOOD02"), - ("ACTOR_EN_LIGHTBOX", "EN_LIGHTBOX", "EN_LIGHTBOX"), - ("ACTOR_EN_PU_BOX", "EN_PU_BOX", "EN_PU_BOX"), - ("ACTOR_EN_TRAP", "EN_TRAP", "EN_TRAP"), - ("ACTOR_EN_AROW_TRAP", "EN_AROW_TRAP", "EN_AROW_TRAP"), - ("ACTOR_EN_VASE", "EN_VASE", "EN_VASE"), - ("ACTOR_EN_TA", "EN_TA", "EN_TA"), - ("ACTOR_EN_TK", "EN_TK", "EN_TK"), - ("ACTOR_BG_MORI_BIGST", "BG_MORI_BIGST", "BG_MORI_BIGST"), - ("ACTOR_BG_MORI_ELEVATOR", "BG_MORI_ELEVATOR", "BG_MORI_ELEVATOR"), - ("ACTOR_BG_MORI_KAITENKABE", "BG_MORI_KAITENKABE", "BG_MORI_KAITENKABE"), - ("ACTOR_BG_MORI_RAKKATENJO", "BG_MORI_RAKKATENJO", "BG_MORI_RAKKATENJO"), - ("ACTOR_EN_VM", "EN_VM", "EN_VM"), - ("ACTOR_DEMO_EFFECT", "DEMO_EFFECT", "DEMO_EFFECT"), - ("ACTOR_DEMO_KANKYO", "DEMO_KANKYO", "DEMO_KANKYO"), - ("ACTOR_BG_HIDAN_FWBIG", "BG_HIDAN_FWBIG", "BG_HIDAN_FWBIG"), - ("ACTOR_EN_FLOORMAS", "EN_FLOORMAS", "EN_FLOORMAS"), - ("ACTOR_EN_HEISHI1", "EN_HEISHI1", "EN_HEISHI1"), - ("ACTOR_EN_RD", "EN_RD", "EN_RD"), - ("ACTOR_EN_PO_SISTERS", "EN_PO_SISTERS", "EN_PO_SISTERS"), - ("ACTOR_BG_HEAVY_BLOCK", "BG_HEAVY_BLOCK", "BG_HEAVY_BLOCK"), - ("ACTOR_BG_PO_EVENT", "BG_PO_EVENT", "BG_PO_EVENT"), - ("ACTOR_OBJ_MURE", "OBJ_MURE", "OBJ_MURE"), - ("ACTOR_EN_SW", "EN_SW", "EN_SW"), - ("ACTOR_BOSS_FD", "BOSS_FD", "BOSS_FD"), - ("ACTOR_OBJECT_KANKYO", "OBJECT_KANKYO", "OBJECT_KANKYO"), - ("ACTOR_EN_DU", "EN_DU", "EN_DU"), - ("ACTOR_EN_FD", "EN_FD", "EN_FD"), - ("ACTOR_EN_HORSE_LINK_CHILD", "EN_HORSE_LINK_CHILD", "EN_HORSE_LINK_CHILD"), - ("ACTOR_DOOR_ANA", "DOOR_ANA", "DOOR_ANA"), - ("ACTOR_BG_SPOT02_OBJECTS", "BG_SPOT02_OBJECTS", "BG_SPOT02_OBJECTS"), - ("ACTOR_BG_HAKA", "BG_HAKA", "BG_HAKA"), - ("ACTOR_MAGIC_WIND", "MAGIC_WIND", "MAGIC_WIND"), - ("ACTOR_MAGIC_FIRE", "MAGIC_FIRE", "MAGIC_FIRE"), - ("ACTOR_EN_RU1", "EN_RU1", "EN_RU1"), - ("ACTOR_BOSS_FD2", "BOSS_FD2", "BOSS_FD2"), - ("ACTOR_EN_FD_FIRE", "EN_FD_FIRE", "EN_FD_FIRE"), - ("ACTOR_EN_DH", "EN_DH", "EN_DH"), - ("ACTOR_EN_DHA", "EN_DHA", "EN_DHA"), - ("ACTOR_EN_RL", "EN_RL", "EN_RL"), - ("ACTOR_EN_ENCOUNT1", "EN_ENCOUNT1", "EN_ENCOUNT1"), - ("ACTOR_DEMO_DU", "DEMO_DU", "DEMO_DU"), - ("ACTOR_DEMO_IM", "DEMO_IM", "DEMO_IM"), - ("ACTOR_DEMO_TRE_LGT", "DEMO_TRE_LGT", "DEMO_TRE_LGT"), - ("ACTOR_EN_FW", "EN_FW", "EN_FW"), - ("ACTOR_BG_VB_SIMA", "BG_VB_SIMA", "BG_VB_SIMA"), - ("ACTOR_EN_VB_BALL", "EN_VB_BALL", "EN_VB_BALL"), - ("ACTOR_BG_HAKA_MEGANE", "BG_HAKA_MEGANE", "BG_HAKA_MEGANE"), - ("ACTOR_BG_HAKA_MEGANEBG", "BG_HAKA_MEGANEBG", "BG_HAKA_MEGANEBG"), - ("ACTOR_BG_HAKA_SHIP", "BG_HAKA_SHIP", "BG_HAKA_SHIP"), - ("ACTOR_BG_HAKA_SGAMI", "BG_HAKA_SGAMI", "BG_HAKA_SGAMI"), - ("ACTOR_EN_HEISHI2", "EN_HEISHI2", "EN_HEISHI2"), - ("ACTOR_EN_ENCOUNT2", "EN_ENCOUNT2", "EN_ENCOUNT2"), - ("ACTOR_EN_FIRE_ROCK", "EN_FIRE_ROCK", "EN_FIRE_ROCK"), - ("ACTOR_EN_BROB", "EN_BROB", "EN_BROB"), - ("ACTOR_MIR_RAY", "MIR_RAY", "MIR_RAY"), - ("ACTOR_BG_SPOT09_OBJ", "BG_SPOT09_OBJ", "BG_SPOT09_OBJ"), - ("ACTOR_BG_SPOT18_OBJ", "BG_SPOT18_OBJ", "BG_SPOT18_OBJ"), - ("ACTOR_BOSS_VA", "BOSS_VA", "BOSS_VA"), - ("ACTOR_BG_HAKA_TUBO", "BG_HAKA_TUBO", "BG_HAKA_TUBO"), - ("ACTOR_BG_HAKA_TRAP", "BG_HAKA_TRAP", "BG_HAKA_TRAP"), - ("ACTOR_BG_HAKA_HUTA", "BG_HAKA_HUTA", "BG_HAKA_HUTA"), - ("ACTOR_BG_HAKA_ZOU", "BG_HAKA_ZOU", "BG_HAKA_ZOU"), - ("ACTOR_BG_SPOT17_FUNEN", "BG_SPOT17_FUNEN", "BG_SPOT17_FUNEN"), - ("ACTOR_EN_SYATEKI_ITM", "EN_SYATEKI_ITM", "EN_SYATEKI_ITM"), - ("ACTOR_EN_SYATEKI_MAN", "EN_SYATEKI_MAN", "EN_SYATEKI_MAN"), - ("ACTOR_EN_TANA", "EN_TANA", "EN_TANA"), - ("ACTOR_EN_NB", "EN_NB", "EN_NB"), - ("ACTOR_BOSS_MO", "BOSS_MO", "BOSS_MO"), - ("ACTOR_EN_SB", "EN_SB", "EN_SB"), - ("ACTOR_EN_BIGOKUTA", "EN_BIGOKUTA", "EN_BIGOKUTA"), - ("ACTOR_EN_KAREBABA", "EN_KAREBABA", "EN_KAREBABA"), - ("ACTOR_BG_BDAN_OBJECTS", "BG_BDAN_OBJECTS", "BG_BDAN_OBJECTS"), - ("ACTOR_DEMO_SA", "DEMO_SA", "DEMO_SA"), - ("ACTOR_DEMO_GO", "DEMO_GO", "DEMO_GO"), - ("ACTOR_EN_IN", "EN_IN", "EN_IN"), - ("ACTOR_EN_TR", "EN_TR", "EN_TR"), - ("ACTOR_BG_SPOT16_BOMBSTONE", "BG_SPOT16_BOMBSTONE", "BG_SPOT16_BOMBSTONE"), - ("ACTOR_BG_HIDAN_KOWARERUKABE", "BG_HIDAN_KOWARERUKABE", "BG_HIDAN_KOWARERUKABE"), - ("ACTOR_BG_BOMBWALL", "BG_BOMBWALL", "BG_BOMBWALL"), - ("ACTOR_BG_SPOT08_ICEBLOCK", "BG_SPOT08_ICEBLOCK", "BG_SPOT08_ICEBLOCK"), - ("ACTOR_EN_RU2", "EN_RU2", "EN_RU2"), - ("ACTOR_OBJ_DEKUJR", "OBJ_DEKUJR", "OBJ_DEKUJR"), - ("ACTOR_BG_MIZU_UZU", "BG_MIZU_UZU", "BG_MIZU_UZU"), - ("ACTOR_BG_SPOT06_OBJECTS", "BG_SPOT06_OBJECTS", "BG_SPOT06_OBJECTS"), - ("ACTOR_BG_ICE_OBJECTS", "BG_ICE_OBJECTS", "BG_ICE_OBJECTS"), - ("ACTOR_BG_HAKA_WATER", "BG_HAKA_WATER", "BG_HAKA_WATER"), - ("ACTOR_EN_MA2", "EN_MA2", "EN_MA2"), - ("ACTOR_EN_BOM_CHU", "EN_BOM_CHU", "EN_BOM_CHU"), - ("ACTOR_EN_HORSE_GAME_CHECK", "EN_HORSE_GAME_CHECK", "EN_HORSE_GAME_CHECK"), - ("ACTOR_BOSS_TW", "BOSS_TW", "BOSS_TW"), - ("ACTOR_EN_RR", "EN_RR", "EN_RR"), - ("ACTOR_EN_BA", "EN_BA", "EN_BA"), - ("ACTOR_EN_BX", "EN_BX", "EN_BX"), - ("ACTOR_EN_ANUBICE", "EN_ANUBICE", "EN_ANUBICE"), - ("ACTOR_EN_ANUBICE_FIRE", "EN_ANUBICE_FIRE", "EN_ANUBICE_FIRE"), - ("ACTOR_BG_MORI_HASHIGO", "BG_MORI_HASHIGO", "BG_MORI_HASHIGO"), - ("ACTOR_BG_MORI_HASHIRA4", "BG_MORI_HASHIRA4", "BG_MORI_HASHIRA4"), - ("ACTOR_BG_MORI_IDOMIZU", "BG_MORI_IDOMIZU", "BG_MORI_IDOMIZU"), - ("ACTOR_BG_SPOT16_DOUGHNUT", "BG_SPOT16_DOUGHNUT", "BG_SPOT16_DOUGHNUT"), - ("ACTOR_BG_BDAN_SWITCH", "BG_BDAN_SWITCH", "BG_BDAN_SWITCH"), - ("ACTOR_EN_MA1", "EN_MA1", "EN_MA1"), - ("ACTOR_BOSS_GANON", "BOSS_GANON", "BOSS_GANON"), - ("ACTOR_BOSS_SST", "BOSS_SST", "BOSS_SST"), - ("ACTOR_EN_NY", "EN_NY", "EN_NY"), - ("ACTOR_EN_FR", "EN_FR", "EN_FR"), - ("ACTOR_ITEM_SHIELD", "ITEM_SHIELD", "ITEM_SHIELD"), - ("ACTOR_BG_ICE_SHELTER", "BG_ICE_SHELTER", "BG_ICE_SHELTER"), - ("ACTOR_EN_ICE_HONO", "EN_ICE_HONO", "EN_ICE_HONO"), - ("ACTOR_ITEM_OCARINA", "ITEM_OCARINA", "ITEM_OCARINA"), - ("ACTOR_MAGIC_DARK", "MAGIC_DARK", "MAGIC_DARK"), - ("ACTOR_DEMO_6K", "DEMO_6K", "DEMO_6K"), - ("ACTOR_EN_ANUBICE_TAG", "EN_ANUBICE_TAG", "EN_ANUBICE_TAG"), - ("ACTOR_BG_HAKA_GATE", "BG_HAKA_GATE", "BG_HAKA_GATE"), - ("ACTOR_BG_SPOT15_SAKU", "BG_SPOT15_SAKU", "BG_SPOT15_SAKU"), - ("ACTOR_BG_JYA_GOROIWA", "BG_JYA_GOROIWA", "BG_JYA_GOROIWA"), - ("ACTOR_BG_JYA_ZURERUKABE", "BG_JYA_ZURERUKABE", "BG_JYA_ZURERUKABE"), - ("ACTOR_BG_JYA_COBRA", "BG_JYA_COBRA", "BG_JYA_COBRA"), - ("ACTOR_BG_JYA_KANAAMI", "BG_JYA_KANAAMI", "BG_JYA_KANAAMI"), - ("ACTOR_FISHING", "FISHING", "FISHING"), - ("ACTOR_OBJ_OSHIHIKI", "OBJ_OSHIHIKI", "OBJ_OSHIHIKI"), - ("ACTOR_BG_GATE_SHUTTER", "BG_GATE_SHUTTER", "BG_GATE_SHUTTER"), - ("ACTOR_EFF_DUST", "EFF_DUST", "EFF_DUST"), - ("ACTOR_BG_SPOT01_FUSYA", "BG_SPOT01_FUSYA", "BG_SPOT01_FUSYA"), - ("ACTOR_BG_SPOT01_IDOHASHIRA", "BG_SPOT01_IDOHASHIRA", "BG_SPOT01_IDOHASHIRA"), - ("ACTOR_BG_SPOT01_IDOMIZU", "BG_SPOT01_IDOMIZU", "BG_SPOT01_IDOMIZU"), - ("ACTOR_BG_PO_SYOKUDAI", "BG_PO_SYOKUDAI", "BG_PO_SYOKUDAI"), - ("ACTOR_BG_GANON_OTYUKA", "BG_GANON_OTYUKA", "BG_GANON_OTYUKA"), - ("ACTOR_BG_SPOT15_RRBOX", "BG_SPOT15_RRBOX", "BG_SPOT15_RRBOX"), - ("ACTOR_BG_UMAJUMP", "BG_UMAJUMP", "BG_UMAJUMP"), - ("ACTOR_ARROW_FIRE", "ARROW_FIRE", "ARROW_FIRE"), - ("ACTOR_ARROW_ICE", "ARROW_ICE", "ARROW_ICE"), - ("ACTOR_ARROW_LIGHT", "ARROW_LIGHT", "ARROW_LIGHT"), - ("ACTOR_ITEM_ETCETERA", "ITEM_ETCETERA", "ITEM_ETCETERA"), - ("ACTOR_OBJ_KIBAKO", "OBJ_KIBAKO", "OBJ_KIBAKO"), - ("ACTOR_OBJ_TSUBO", "OBJ_TSUBO", "OBJ_TSUBO"), - ("ACTOR_EN_WONDER_ITEM", "EN_WONDER_ITEM", "EN_WONDER_ITEM"), - ("ACTOR_EN_IK", "EN_IK", "EN_IK"), - ("ACTOR_DEMO_IK", "DEMO_IK", "DEMO_IK"), - ("ACTOR_EN_SKJ", "EN_SKJ", "EN_SKJ"), - ("ACTOR_EN_SKJNEEDLE", "EN_SKJNEEDLE", "EN_SKJNEEDLE"), - ("ACTOR_EN_G_SWITCH", "EN_G_SWITCH", "EN_G_SWITCH"), - ("ACTOR_DEMO_EXT", "DEMO_EXT", "DEMO_EXT"), - ("ACTOR_DEMO_SHD", "DEMO_SHD", "DEMO_SHD"), - ("ACTOR_EN_DNS", "EN_DNS", "EN_DNS"), - ("ACTOR_ELF_MSG", "ELF_MSG", "ELF_MSG"), - ("ACTOR_EN_HONOTRAP", "EN_HONOTRAP", "EN_HONOTRAP"), - ("ACTOR_EN_TUBO_TRAP", "EN_TUBO_TRAP", "EN_TUBO_TRAP"), - ("ACTOR_OBJ_ICE_POLY", "OBJ_ICE_POLY", "OBJ_ICE_POLY"), - ("ACTOR_BG_SPOT03_TAKI", "BG_SPOT03_TAKI", "BG_SPOT03_TAKI"), - ("ACTOR_BG_SPOT07_TAKI", "BG_SPOT07_TAKI", "BG_SPOT07_TAKI"), - ("ACTOR_EN_FZ", "EN_FZ", "EN_FZ"), - ("ACTOR_EN_PO_RELAY", "EN_PO_RELAY", "EN_PO_RELAY"), - ("ACTOR_BG_RELAY_OBJECTS", "BG_RELAY_OBJECTS", "BG_RELAY_OBJECTS"), - ("ACTOR_EN_DIVING_GAME", "EN_DIVING_GAME", "EN_DIVING_GAME"), - ("ACTOR_EN_KUSA", "EN_KUSA", "EN_KUSA"), - ("ACTOR_OBJ_BEAN", "OBJ_BEAN", "OBJ_BEAN"), - ("ACTOR_OBJ_BOMBIWA", "OBJ_BOMBIWA", "OBJ_BOMBIWA"), - ("ACTOR_OBJ_SWITCH", "OBJ_SWITCH", "OBJ_SWITCH"), - ("ACTOR_OBJ_ELEVATOR", "OBJ_ELEVATOR", "OBJ_ELEVATOR"), - ("ACTOR_OBJ_LIFT", "OBJ_LIFT", "OBJ_LIFT"), - ("ACTOR_OBJ_HSBLOCK", "OBJ_HSBLOCK", "OBJ_HSBLOCK"), - ("ACTOR_EN_OKARINA_TAG", "EN_OKARINA_TAG", "EN_OKARINA_TAG"), - ("ACTOR_EN_YABUSAME_MARK", "EN_YABUSAME_MARK", "EN_YABUSAME_MARK"), - ("ACTOR_EN_GOROIWA", "EN_GOROIWA", "EN_GOROIWA"), - ("ACTOR_EN_EX_RUPPY", "EN_EX_RUPPY", "EN_EX_RUPPY"), - ("ACTOR_EN_TORYO", "EN_TORYO", "EN_TORYO"), - ("ACTOR_EN_DAIKU", "EN_DAIKU", "EN_DAIKU"), - ("ACTOR_EN_NWC", "EN_NWC", "EN_NWC"), - ("ACTOR_EN_BLKOBJ", "EN_BLKOBJ", "EN_BLKOBJ"), - ("ACTOR_ITEM_INBOX", "ITEM_INBOX", "ITEM_INBOX"), - ("ACTOR_EN_GE1", "EN_GE1", "EN_GE1"), - ("ACTOR_OBJ_BLOCKSTOP", "OBJ_BLOCKSTOP", "OBJ_BLOCKSTOP"), - ("ACTOR_EN_SDA", "EN_SDA", "EN_SDA"), - ("ACTOR_EN_CLEAR_TAG", "EN_CLEAR_TAG", "EN_CLEAR_TAG"), - ("ACTOR_EN_NIW_LADY", "EN_NIW_LADY", "EN_NIW_LADY"), - ("ACTOR_EN_GM", "EN_GM", "EN_GM"), - ("ACTOR_EN_MS", "EN_MS", "EN_MS"), - ("ACTOR_EN_HS", "EN_HS", "EN_HS"), - ("ACTOR_BG_INGATE", "BG_INGATE", "BG_INGATE"), - ("ACTOR_EN_KANBAN", "EN_KANBAN", "EN_KANBAN"), - ("ACTOR_EN_HEISHI3", "EN_HEISHI3", "EN_HEISHI3"), - ("ACTOR_EN_SYATEKI_NIW", "EN_SYATEKI_NIW", "EN_SYATEKI_NIW"), - ("ACTOR_EN_ATTACK_NIW", "EN_ATTACK_NIW", "EN_ATTACK_NIW"), - ("ACTOR_BG_SPOT01_IDOSOKO", "BG_SPOT01_IDOSOKO", "BG_SPOT01_IDOSOKO"), - ("ACTOR_EN_SA", "EN_SA", "EN_SA"), - ("ACTOR_EN_WONDER_TALK", "EN_WONDER_TALK", "EN_WONDER_TALK"), - ("ACTOR_BG_GJYO_BRIDGE", "BG_GJYO_BRIDGE", "BG_GJYO_BRIDGE"), - ("ACTOR_EN_DS", "EN_DS", "EN_DS"), - ("ACTOR_EN_MK", "EN_MK", "EN_MK"), - ("ACTOR_EN_BOM_BOWL_MAN", "EN_BOM_BOWL_MAN", "EN_BOM_BOWL_MAN"), - ("ACTOR_EN_BOM_BOWL_PIT", "EN_BOM_BOWL_PIT", "EN_BOM_BOWL_PIT"), - ("ACTOR_EN_OWL", "EN_OWL", "EN_OWL"), - ("ACTOR_EN_ISHI", "EN_ISHI", "EN_ISHI"), - ("ACTOR_OBJ_HANA", "OBJ_HANA", "OBJ_HANA"), - ("ACTOR_OBJ_LIGHTSWITCH", "OBJ_LIGHTSWITCH", "OBJ_LIGHTSWITCH"), - ("ACTOR_OBJ_MURE2", "OBJ_MURE2", "OBJ_MURE2"), - ("ACTOR_EN_GO", "EN_GO", "EN_GO"), - ("ACTOR_EN_FU", "EN_FU", "EN_FU"), - ("ACTOR_EN_CHANGER", "EN_CHANGER", "EN_CHANGER"), - ("ACTOR_BG_JYA_MEGAMI", "BG_JYA_MEGAMI", "BG_JYA_MEGAMI"), - ("ACTOR_BG_JYA_LIFT", "BG_JYA_LIFT", "BG_JYA_LIFT"), - ("ACTOR_BG_JYA_BIGMIRROR", "BG_JYA_BIGMIRROR", "BG_JYA_BIGMIRROR"), - ("ACTOR_BG_JYA_BOMBCHUIWA", "BG_JYA_BOMBCHUIWA", "BG_JYA_BOMBCHUIWA"), - ("ACTOR_BG_JYA_AMISHUTTER", "BG_JYA_AMISHUTTER", "BG_JYA_AMISHUTTER"), - ("ACTOR_BG_JYA_BOMBIWA", "BG_JYA_BOMBIWA", "BG_JYA_BOMBIWA"), - ("ACTOR_BG_SPOT18_BASKET", "BG_SPOT18_BASKET", "BG_SPOT18_BASKET"), - ("ACTOR_EN_GANON_ORGAN", "EN_GANON_ORGAN", "EN_GANON_ORGAN"), - ("ACTOR_EN_SIOFUKI", "EN_SIOFUKI", "EN_SIOFUKI"), - ("ACTOR_EN_STREAM", "EN_STREAM", "EN_STREAM"), - ("ACTOR_EN_MM", "EN_MM", "EN_MM"), - ("ACTOR_EN_KO", "EN_KO", "EN_KO"), - ("ACTOR_EN_KZ", "EN_KZ", "EN_KZ"), - ("ACTOR_EN_WEATHER_TAG", "EN_WEATHER_TAG", "EN_WEATHER_TAG"), - ("ACTOR_BG_SST_FLOOR", "BG_SST_FLOOR", "BG_SST_FLOOR"), - ("ACTOR_EN_ANI", "EN_ANI", "EN_ANI"), - ("ACTOR_EN_EX_ITEM", "EN_EX_ITEM", "EN_EX_ITEM"), - ("ACTOR_BG_JYA_IRONOBJ", "BG_JYA_IRONOBJ", "BG_JYA_IRONOBJ"), - ("ACTOR_EN_JS", "EN_JS", "EN_JS"), - ("ACTOR_EN_JSJUTAN", "EN_JSJUTAN", "EN_JSJUTAN"), - ("ACTOR_EN_CS", "EN_CS", "EN_CS"), - ("ACTOR_EN_MD", "EN_MD", "EN_MD"), - ("ACTOR_EN_HY", "EN_HY", "EN_HY"), - ("ACTOR_EN_GANON_MANT", "EN_GANON_MANT", "EN_GANON_MANT"), - ("ACTOR_EN_OKARINA_EFFECT", "EN_OKARINA_EFFECT", "EN_OKARINA_EFFECT"), - ("ACTOR_EN_MAG", "EN_MAG", "EN_MAG"), - ("ACTOR_DOOR_GERUDO", "DOOR_GERUDO", "DOOR_GERUDO"), - ("ACTOR_ELF_MSG2", "ELF_MSG2", "ELF_MSG2"), - ("ACTOR_DEMO_GT", "DEMO_GT", "DEMO_GT"), - ("ACTOR_EN_PO_FIELD", "EN_PO_FIELD", "EN_PO_FIELD"), - ("ACTOR_EFC_ERUPC", "EFC_ERUPC", "EFC_ERUPC"), - ("ACTOR_BG_ZG", "BG_ZG", "BG_ZG"), - ("ACTOR_EN_HEISHI4", "EN_HEISHI4", "EN_HEISHI4"), - ("ACTOR_EN_ZL3", "EN_ZL3", "EN_ZL3"), - ("ACTOR_BOSS_GANON2", "BOSS_GANON2", "BOSS_GANON2"), - ("ACTOR_EN_KAKASI", "EN_KAKASI", "EN_KAKASI"), - ("ACTOR_EN_TAKARA_MAN", "EN_TAKARA_MAN", "EN_TAKARA_MAN"), - ("ACTOR_OBJ_MAKEOSHIHIKI", "OBJ_MAKEOSHIHIKI", "OBJ_MAKEOSHIHIKI"), - ("ACTOR_OCEFF_SPOT", "OCEFF_SPOT", "OCEFF_SPOT"), - ("ACTOR_END_TITLE", "END_TITLE", "END_TITLE"), - ("ACTOR_EN_TORCH", "EN_TORCH", "EN_TORCH"), - ("ACTOR_DEMO_EC", "DEMO_EC", "DEMO_EC"), - ("ACTOR_SHOT_SUN", "SHOT_SUN", "SHOT_SUN"), - ("ACTOR_EN_DY_EXTRA", "EN_DY_EXTRA", "EN_DY_EXTRA"), - ("ACTOR_EN_WONDER_TALK2", "EN_WONDER_TALK2", "EN_WONDER_TALK2"), - ("ACTOR_EN_GE2", "EN_GE2", "EN_GE2"), - ("ACTOR_OBJ_ROOMTIMER", "OBJ_ROOMTIMER", "OBJ_ROOMTIMER"), - ("ACTOR_EN_SSH", "EN_SSH", "EN_SSH"), - ("ACTOR_EN_STH", "EN_STH", "EN_STH"), - ("ACTOR_OCEFF_WIPE", "OCEFF_WIPE", "OCEFF_WIPE"), - ("ACTOR_OCEFF_STORM", "OCEFF_STORM", "OCEFF_STORM"), - ("ACTOR_EN_WEIYER", "EN_WEIYER", "EN_WEIYER"), - ("ACTOR_BG_SPOT05_SOKO", "BG_SPOT05_SOKO", "BG_SPOT05_SOKO"), - ("ACTOR_BG_JYA_1FLIFT", "BG_JYA_1FLIFT", "BG_JYA_1FLIFT"), - ("ACTOR_BG_JYA_HAHENIRON", "BG_JYA_HAHENIRON", "BG_JYA_HAHENIRON"), - ("ACTOR_BG_SPOT12_GATE", "BG_SPOT12_GATE", "BG_SPOT12_GATE"), - ("ACTOR_BG_SPOT12_SAKU", "BG_SPOT12_SAKU", "BG_SPOT12_SAKU"), - ("ACTOR_EN_HINTNUTS", "EN_HINTNUTS", "EN_HINTNUTS"), - ("ACTOR_EN_NUTSBALL", "EN_NUTSBALL", "EN_NUTSBALL"), - ("ACTOR_BG_SPOT00_BREAK", "BG_SPOT00_BREAK", "BG_SPOT00_BREAK"), - ("ACTOR_EN_SHOPNUTS", "EN_SHOPNUTS", "EN_SHOPNUTS"), - ("ACTOR_EN_IT", "EN_IT", "EN_IT"), - ("ACTOR_EN_GELDB", "EN_GELDB", "EN_GELDB"), - ("ACTOR_OCEFF_WIPE2", "OCEFF_WIPE2", "OCEFF_WIPE2"), - ("ACTOR_OCEFF_WIPE3", "OCEFF_WIPE3", "OCEFF_WIPE3"), - ("ACTOR_EN_NIW_GIRL", "EN_NIW_GIRL", "EN_NIW_GIRL"), - ("ACTOR_EN_DOG", "EN_DOG", "EN_DOG"), - ("ACTOR_EN_SI", "EN_SI", "EN_SI"), - ("ACTOR_BG_SPOT01_OBJECTS2", "BG_SPOT01_OBJECTS2", "BG_SPOT01_OBJECTS2"), - ("ACTOR_OBJ_COMB", "OBJ_COMB", "OBJ_COMB"), - ("ACTOR_BG_SPOT11_BAKUDANKABE", "BG_SPOT11_BAKUDANKABE", "BG_SPOT11_BAKUDANKABE"), - ("ACTOR_OBJ_KIBAKO2", "OBJ_KIBAKO2", "OBJ_KIBAKO2"), - ("ACTOR_EN_DNT_DEMO", "EN_DNT_DEMO", "EN_DNT_DEMO"), - ("ACTOR_EN_DNT_JIJI", "EN_DNT_JIJI", "EN_DNT_JIJI"), - ("ACTOR_EN_DNT_NOMAL", "EN_DNT_NOMAL", "EN_DNT_NOMAL"), - ("ACTOR_EN_GUEST", "EN_GUEST", "EN_GUEST"), - ("ACTOR_BG_BOM_GUARD", "BG_BOM_GUARD", "BG_BOM_GUARD"), - ("ACTOR_EN_HS2", "EN_HS2", "EN_HS2"), - ("ACTOR_DEMO_KEKKAI", "DEMO_KEKKAI", "DEMO_KEKKAI"), - ("ACTOR_BG_SPOT08_BAKUDANKABE", "BG_SPOT08_BAKUDANKABE", "BG_SPOT08_BAKUDANKABE"), - ("ACTOR_BG_SPOT17_BAKUDANKABE", "BG_SPOT17_BAKUDANKABE", "BG_SPOT17_BAKUDANKABE"), - ("ACTOR_OBJ_MURE3", "OBJ_MURE3", "OBJ_MURE3"), - ("ACTOR_EN_TG", "EN_TG", "EN_TG"), - ("ACTOR_EN_MU", "EN_MU", "EN_MU"), - ("ACTOR_EN_GO2", "EN_GO2", "EN_GO2"), - ("ACTOR_EN_WF", "EN_WF", "EN_WF"), - ("ACTOR_EN_SKB", "EN_SKB", "EN_SKB"), - ("ACTOR_DEMO_GJ", "DEMO_GJ", "DEMO_GJ"), - ("ACTOR_DEMO_GEFF", "DEMO_GEFF", "DEMO_GEFF"), - ("ACTOR_BG_GND_FIREMEIRO", "BG_GND_FIREMEIRO", "BG_GND_FIREMEIRO"), - ("ACTOR_BG_GND_DARKMEIRO", "BG_GND_DARKMEIRO", "BG_GND_DARKMEIRO"), - ("ACTOR_BG_GND_SOULMEIRO", "BG_GND_SOULMEIRO", "BG_GND_SOULMEIRO"), - ("ACTOR_BG_GND_NISEKABE", "BG_GND_NISEKABE", "BG_GND_NISEKABE"), - ("ACTOR_BG_GND_ICEBLOCK", "BG_GND_ICEBLOCK", "BG_GND_ICEBLOCK"), - ("ACTOR_EN_GB", "EN_GB", "EN_GB"), - ("ACTOR_EN_GS", "EN_GS", "EN_GS"), - ("ACTOR_BG_MIZU_BWALL", "BG_MIZU_BWALL", "BG_MIZU_BWALL"), - ("ACTOR_BG_MIZU_SHUTTER", "BG_MIZU_SHUTTER", "BG_MIZU_SHUTTER"), - ("ACTOR_EN_DAIKU_KAKARIKO", "EN_DAIKU_KAKARIKO", "EN_DAIKU_KAKARIKO"), - ("ACTOR_BG_BOWL_WALL", "BG_BOWL_WALL", "BG_BOWL_WALL"), - ("ACTOR_EN_WALL_TUBO", "EN_WALL_TUBO", "EN_WALL_TUBO"), - ("ACTOR_EN_PO_DESERT", "EN_PO_DESERT", "EN_PO_DESERT"), - ("ACTOR_EN_CROW", "EN_CROW", "EN_CROW"), - ("ACTOR_DOOR_KILLER", "DOOR_KILLER", "DOOR_KILLER"), - ("ACTOR_BG_SPOT11_OASIS", "BG_SPOT11_OASIS", "BG_SPOT11_OASIS"), - ("ACTOR_BG_SPOT18_FUTA", "BG_SPOT18_FUTA", "BG_SPOT18_FUTA"), - ("ACTOR_BG_SPOT18_SHUTTER", "BG_SPOT18_SHUTTER", "BG_SPOT18_SHUTTER"), - ("ACTOR_EN_MA3", "EN_MA3", "EN_MA3"), - ("ACTOR_EN_COW", "EN_COW", "EN_COW"), - ("ACTOR_BG_ICE_TURARA", "BG_ICE_TURARA", "BG_ICE_TURARA"), - ("ACTOR_BG_ICE_SHUTTER", "BG_ICE_SHUTTER", "BG_ICE_SHUTTER"), - ("ACTOR_EN_KAKASI2", "EN_KAKASI2", "EN_KAKASI2"), - ("ACTOR_EN_KAKASI3", "EN_KAKASI3", "EN_KAKASI3"), - ("ACTOR_OCEFF_WIPE4", "OCEFF_WIPE4", "OCEFF_WIPE4"), - ("ACTOR_EN_EG", "EN_EG", "EN_EG"), - ("ACTOR_BG_MENKURI_NISEKABE", "BG_MENKURI_NISEKABE", "BG_MENKURI_NISEKABE"), - ("ACTOR_EN_ZO", "EN_ZO", "EN_ZO"), - ("ACTOR_OBJ_MAKEKINSUTA", "OBJ_MAKEKINSUTA", "OBJ_MAKEKINSUTA"), - ("ACTOR_EN_GE3", "EN_GE3", "EN_GE3"), - ("ACTOR_OBJ_TIMEBLOCK", "OBJ_TIMEBLOCK", "OBJ_TIMEBLOCK"), - ("ACTOR_OBJ_HAMISHI", "OBJ_HAMISHI", "OBJ_HAMISHI"), - ("ACTOR_EN_ZL4", "EN_ZL4", "EN_ZL4"), - ("ACTOR_EN_MM2", "EN_MM2", "EN_MM2"), - ("ACTOR_BG_JYA_BLOCK", "BG_JYA_BLOCK", "BG_JYA_BLOCK"), - ("ACTOR_OBJ_WARP2BLOCK", "OBJ_WARP2BLOCK", "OBJ_WARP2BLOCK"), + ("Custom", "Custom", "Custom"), + ("ACTOR_PLAYER", "PLAYER", "PLAYER"), + ("ACTOR_EN_TEST", "EN_TEST", "EN_TEST"), + ("ACTOR_EN_GIRLA", "EN_GIRLA", "EN_GIRLA"), + ("ACTOR_EN_PART", "EN_PART", "EN_PART"), + ("ACTOR_EN_LIGHT", "EN_LIGHT", "EN_LIGHT"), + ("ACTOR_EN_DOOR", "EN_DOOR", "EN_DOOR"), + ("ACTOR_EN_BOX", "EN_BOX", "EN_BOX"), + ("ACTOR_BG_DY_YOSEIZO", "BG_DY_YOSEIZO", "BG_DY_YOSEIZO"), + ("ACTOR_BG_HIDAN_FIREWALL", "BG_HIDAN_FIREWALL", "BG_HIDAN_FIREWALL"), + ("ACTOR_EN_POH", "EN_POH", "EN_POH"), + ("ACTOR_EN_OKUTA", "EN_OKUTA", "EN_OKUTA"), + ("ACTOR_BG_YDAN_SP", "BG_YDAN_SP", "BG_YDAN_SP"), + ("ACTOR_EN_BOM", "EN_BOM", "EN_BOM"), + ("ACTOR_EN_WALLMAS", "EN_WALLMAS", "EN_WALLMAS"), + ("ACTOR_EN_DODONGO", "EN_DODONGO", "EN_DODONGO"), + ("ACTOR_EN_FIREFLY", "EN_FIREFLY", "EN_FIREFLY"), + ("ACTOR_EN_HORSE", "EN_HORSE", "EN_HORSE"), + ("ACTOR_EN_ITEM00", "EN_ITEM00", "EN_ITEM00"), + ("ACTOR_EN_ARROW", "EN_ARROW", "EN_ARROW"), + ("ACTOR_EN_ELF", "EN_ELF", "EN_ELF"), + ("ACTOR_EN_NIW", "EN_NIW", "EN_NIW"), + ("ACTOR_EN_TITE", "EN_TITE", "EN_TITE"), + ("ACTOR_EN_REEBA", "EN_REEBA", "EN_REEBA"), + ("ACTOR_EN_PEEHAT", "EN_PEEHAT", "EN_PEEHAT"), + ("ACTOR_EN_BUTTE", "EN_BUTTE", "EN_BUTTE"), + ("ACTOR_EN_INSECT", "EN_INSECT", "EN_INSECT"), + ("ACTOR_EN_FISH", "EN_FISH", "EN_FISH"), + ("ACTOR_EN_HOLL", "EN_HOLL", "EN_HOLL"), + ("ACTOR_EN_SCENE_CHANGE", "EN_SCENE_CHANGE", "EN_SCENE_CHANGE"), + ("ACTOR_EN_ZF", "EN_ZF", "EN_ZF"), + ("ACTOR_EN_HATA", "EN_HATA", "EN_HATA"), + ("ACTOR_BOSS_DODONGO", "BOSS_DODONGO", "BOSS_DODONGO"), + ("ACTOR_BOSS_GOMA", "BOSS_GOMA", "BOSS_GOMA"), + ("ACTOR_EN_ZL1", "EN_ZL1", "EN_ZL1"), + ("ACTOR_EN_VIEWER", "EN_VIEWER", "EN_VIEWER"), + ("ACTOR_EN_GOMA", "EN_GOMA", "EN_GOMA"), + ("ACTOR_BG_PUSHBOX", "BG_PUSHBOX", "BG_PUSHBOX"), + ("ACTOR_EN_BUBBLE", "EN_BUBBLE", "EN_BUBBLE"), + ("ACTOR_DOOR_SHUTTER", "DOOR_SHUTTER", "DOOR_SHUTTER"), + ("ACTOR_EN_DODOJR", "EN_DODOJR", "EN_DODOJR"), + ("ACTOR_EN_BDFIRE", "EN_BDFIRE", "EN_BDFIRE"), + ("ACTOR_EN_BOOM", "EN_BOOM", "EN_BOOM"), + ("ACTOR_EN_TORCH2", "EN_TORCH2", "EN_TORCH2"), + ("ACTOR_EN_BILI", "EN_BILI", "EN_BILI"), + ("ACTOR_EN_TP", "EN_TP", "EN_TP"), + ("ACTOR_EN_ST", "EN_ST", "EN_ST"), + ("ACTOR_EN_BW", "EN_BW", "EN_BW"), + ("ACTOR_EN_A_OBJ", "EN_A_OBJ", "EN_A_OBJ"), + ("ACTOR_EN_EIYER", "EN_EIYER", "EN_EIYER"), + ("ACTOR_EN_RIVER_SOUND", "EN_RIVER_SOUND", "EN_RIVER_SOUND"), + ("ACTOR_EN_HORSE_NORMAL", "EN_HORSE_NORMAL", "EN_HORSE_NORMAL"), + ("ACTOR_EN_OSSAN", "EN_OSSAN", "EN_OSSAN"), + ("ACTOR_BG_TREEMOUTH", "BG_TREEMOUTH", "BG_TREEMOUTH"), + ("ACTOR_BG_DODOAGO", "BG_DODOAGO", "BG_DODOAGO"), + ("ACTOR_BG_HIDAN_DALM", "BG_HIDAN_DALM", "BG_HIDAN_DALM"), + ("ACTOR_BG_HIDAN_HROCK", "BG_HIDAN_HROCK", "BG_HIDAN_HROCK"), + ("ACTOR_EN_HORSE_GANON", "EN_HORSE_GANON", "EN_HORSE_GANON"), + ("ACTOR_BG_HIDAN_ROCK", "BG_HIDAN_ROCK", "BG_HIDAN_ROCK"), + ("ACTOR_BG_HIDAN_RSEKIZOU", "BG_HIDAN_RSEKIZOU", "BG_HIDAN_RSEKIZOU"), + ("ACTOR_BG_HIDAN_SEKIZOU", "BG_HIDAN_SEKIZOU", "BG_HIDAN_SEKIZOU"), + ("ACTOR_BG_HIDAN_SIMA", "BG_HIDAN_SIMA", "BG_HIDAN_SIMA"), + ("ACTOR_BG_HIDAN_SYOKU", "BG_HIDAN_SYOKU", "BG_HIDAN_SYOKU"), + ("ACTOR_EN_XC", "EN_XC", "EN_XC"), + ("ACTOR_BG_HIDAN_CURTAIN", "BG_HIDAN_CURTAIN", "BG_HIDAN_CURTAIN"), + ("ACTOR_BG_SPOT00_HANEBASI", "BG_SPOT00_HANEBASI", "BG_SPOT00_HANEBASI"), + ("ACTOR_EN_MB", "EN_MB", "EN_MB"), + ("ACTOR_EN_BOMBF", "EN_BOMBF", "EN_BOMBF"), + ("ACTOR_EN_ZL2", "EN_ZL2", "EN_ZL2"), + ("ACTOR_BG_HIDAN_FSLIFT", "BG_HIDAN_FSLIFT", "BG_HIDAN_FSLIFT"), + ("ACTOR_EN_OE2", "EN_OE2", "EN_OE2"), + ("ACTOR_BG_YDAN_HASI", "BG_YDAN_HASI", "BG_YDAN_HASI"), + ("ACTOR_BG_YDAN_MARUTA", "BG_YDAN_MARUTA", "BG_YDAN_MARUTA"), + ("ACTOR_BOSS_GANONDROF", "BOSS_GANONDROF", "BOSS_GANONDROF"), + ("ACTOR_EN_AM", "EN_AM", "EN_AM"), + ("ACTOR_EN_DEKUBABA", "EN_DEKUBABA", "EN_DEKUBABA"), + ("ACTOR_EN_M_FIRE1", "EN_M_FIRE1", "EN_M_FIRE1"), + ("ACTOR_EN_M_THUNDER", "EN_M_THUNDER", "EN_M_THUNDER"), + ("ACTOR_BG_DDAN_JD", "BG_DDAN_JD", "BG_DDAN_JD"), + ("ACTOR_BG_BREAKWALL", "BG_BREAKWALL", "BG_BREAKWALL"), + ("ACTOR_EN_JJ", "EN_JJ", "EN_JJ"), + ("ACTOR_EN_HORSE_ZELDA", "EN_HORSE_ZELDA", "EN_HORSE_ZELDA"), + ("ACTOR_BG_DDAN_KD", "BG_DDAN_KD", "BG_DDAN_KD"), + ("ACTOR_DOOR_WARP1", "DOOR_WARP1", "DOOR_WARP1"), + ("ACTOR_OBJ_SYOKUDAI", "OBJ_SYOKUDAI", "OBJ_SYOKUDAI"), + ("ACTOR_ITEM_B_HEART", "ITEM_B_HEART", "ITEM_B_HEART"), + ("ACTOR_EN_DEKUNUTS", "EN_DEKUNUTS", "EN_DEKUNUTS"), + ("ACTOR_BG_MENKURI_KAITEN", "BG_MENKURI_KAITEN", "BG_MENKURI_KAITEN"), + ("ACTOR_BG_MENKURI_EYE", "BG_MENKURI_EYE", "BG_MENKURI_EYE"), + ("ACTOR_EN_VALI", "EN_VALI", "EN_VALI"), + ("ACTOR_BG_MIZU_MOVEBG", "BG_MIZU_MOVEBG", "BG_MIZU_MOVEBG"), + ("ACTOR_BG_MIZU_WATER", "BG_MIZU_WATER", "BG_MIZU_WATER"), + ("ACTOR_ARMS_HOOK", "ARMS_HOOK", "ARMS_HOOK"), + ("ACTOR_EN_FHG", "EN_FHG", "EN_FHG"), + ("ACTOR_BG_MORI_HINERI", "BG_MORI_HINERI", "BG_MORI_HINERI"), + ("ACTOR_EN_BB", "EN_BB", "EN_BB"), + ("ACTOR_BG_TOKI_HIKARI", "BG_TOKI_HIKARI", "BG_TOKI_HIKARI"), + ("ACTOR_EN_YUKABYUN", "EN_YUKABYUN", "EN_YUKABYUN"), + ("ACTOR_BG_TOKI_SWD", "BG_TOKI_SWD", "BG_TOKI_SWD"), + ("ACTOR_EN_FHG_FIRE", "EN_FHG_FIRE", "EN_FHG_FIRE"), + ("ACTOR_BG_MJIN", "BG_MJIN", "BG_MJIN"), + ("ACTOR_BG_HIDAN_KOUSI", "BG_HIDAN_KOUSI", "BG_HIDAN_KOUSI"), + ("ACTOR_DOOR_TOKI", "DOOR_TOKI", "DOOR_TOKI"), + ("ACTOR_BG_HIDAN_HAMSTEP", "BG_HIDAN_HAMSTEP", "BG_HIDAN_HAMSTEP"), + ("ACTOR_EN_BIRD", "EN_BIRD", "EN_BIRD"), + ("ACTOR_EN_WOOD02", "EN_WOOD02", "EN_WOOD02"), + ("ACTOR_EN_LIGHTBOX", "EN_LIGHTBOX", "EN_LIGHTBOX"), + ("ACTOR_EN_PU_BOX", "EN_PU_BOX", "EN_PU_BOX"), + ("ACTOR_EN_TRAP", "EN_TRAP", "EN_TRAP"), + ("ACTOR_EN_AROW_TRAP", "EN_AROW_TRAP", "EN_AROW_TRAP"), + ("ACTOR_EN_VASE", "EN_VASE", "EN_VASE"), + ("ACTOR_EN_TA", "EN_TA", "EN_TA"), + ("ACTOR_EN_TK", "EN_TK", "EN_TK"), + ("ACTOR_BG_MORI_BIGST", "BG_MORI_BIGST", "BG_MORI_BIGST"), + ("ACTOR_BG_MORI_ELEVATOR", "BG_MORI_ELEVATOR", "BG_MORI_ELEVATOR"), + ("ACTOR_BG_MORI_KAITENKABE", "BG_MORI_KAITENKABE", "BG_MORI_KAITENKABE"), + ("ACTOR_BG_MORI_RAKKATENJO", "BG_MORI_RAKKATENJO", "BG_MORI_RAKKATENJO"), + ("ACTOR_EN_VM", "EN_VM", "EN_VM"), + ("ACTOR_DEMO_EFFECT", "DEMO_EFFECT", "DEMO_EFFECT"), + ("ACTOR_DEMO_KANKYO", "DEMO_KANKYO", "DEMO_KANKYO"), + ("ACTOR_BG_HIDAN_FWBIG", "BG_HIDAN_FWBIG", "BG_HIDAN_FWBIG"), + ("ACTOR_EN_FLOORMAS", "EN_FLOORMAS", "EN_FLOORMAS"), + ("ACTOR_EN_HEISHI1", "EN_HEISHI1", "EN_HEISHI1"), + ("ACTOR_EN_RD", "EN_RD", "EN_RD"), + ("ACTOR_EN_PO_SISTERS", "EN_PO_SISTERS", "EN_PO_SISTERS"), + ("ACTOR_BG_HEAVY_BLOCK", "BG_HEAVY_BLOCK", "BG_HEAVY_BLOCK"), + ("ACTOR_BG_PO_EVENT", "BG_PO_EVENT", "BG_PO_EVENT"), + ("ACTOR_OBJ_MURE", "OBJ_MURE", "OBJ_MURE"), + ("ACTOR_EN_SW", "EN_SW", "EN_SW"), + ("ACTOR_BOSS_FD", "BOSS_FD", "BOSS_FD"), + ("ACTOR_OBJECT_KANKYO", "OBJECT_KANKYO", "OBJECT_KANKYO"), + ("ACTOR_EN_DU", "EN_DU", "EN_DU"), + ("ACTOR_EN_FD", "EN_FD", "EN_FD"), + ("ACTOR_EN_HORSE_LINK_CHILD", "EN_HORSE_LINK_CHILD", "EN_HORSE_LINK_CHILD"), + ("ACTOR_DOOR_ANA", "DOOR_ANA", "DOOR_ANA"), + ("ACTOR_BG_SPOT02_OBJECTS", "BG_SPOT02_OBJECTS", "BG_SPOT02_OBJECTS"), + ("ACTOR_BG_HAKA", "BG_HAKA", "BG_HAKA"), + ("ACTOR_MAGIC_WIND", "MAGIC_WIND", "MAGIC_WIND"), + ("ACTOR_MAGIC_FIRE", "MAGIC_FIRE", "MAGIC_FIRE"), + ("ACTOR_EN_RU1", "EN_RU1", "EN_RU1"), + ("ACTOR_BOSS_FD2", "BOSS_FD2", "BOSS_FD2"), + ("ACTOR_EN_FD_FIRE", "EN_FD_FIRE", "EN_FD_FIRE"), + ("ACTOR_EN_DH", "EN_DH", "EN_DH"), + ("ACTOR_EN_DHA", "EN_DHA", "EN_DHA"), + ("ACTOR_EN_RL", "EN_RL", "EN_RL"), + ("ACTOR_EN_ENCOUNT1", "EN_ENCOUNT1", "EN_ENCOUNT1"), + ("ACTOR_DEMO_DU", "DEMO_DU", "DEMO_DU"), + ("ACTOR_DEMO_IM", "DEMO_IM", "DEMO_IM"), + ("ACTOR_DEMO_TRE_LGT", "DEMO_TRE_LGT", "DEMO_TRE_LGT"), + ("ACTOR_EN_FW", "EN_FW", "EN_FW"), + ("ACTOR_BG_VB_SIMA", "BG_VB_SIMA", "BG_VB_SIMA"), + ("ACTOR_EN_VB_BALL", "EN_VB_BALL", "EN_VB_BALL"), + ("ACTOR_BG_HAKA_MEGANE", "BG_HAKA_MEGANE", "BG_HAKA_MEGANE"), + ("ACTOR_BG_HAKA_MEGANEBG", "BG_HAKA_MEGANEBG", "BG_HAKA_MEGANEBG"), + ("ACTOR_BG_HAKA_SHIP", "BG_HAKA_SHIP", "BG_HAKA_SHIP"), + ("ACTOR_BG_HAKA_SGAMI", "BG_HAKA_SGAMI", "BG_HAKA_SGAMI"), + ("ACTOR_EN_HEISHI2", "EN_HEISHI2", "EN_HEISHI2"), + ("ACTOR_EN_ENCOUNT2", "EN_ENCOUNT2", "EN_ENCOUNT2"), + ("ACTOR_EN_FIRE_ROCK", "EN_FIRE_ROCK", "EN_FIRE_ROCK"), + ("ACTOR_EN_BROB", "EN_BROB", "EN_BROB"), + ("ACTOR_MIR_RAY", "MIR_RAY", "MIR_RAY"), + ("ACTOR_BG_SPOT09_OBJ", "BG_SPOT09_OBJ", "BG_SPOT09_OBJ"), + ("ACTOR_BG_SPOT18_OBJ", "BG_SPOT18_OBJ", "BG_SPOT18_OBJ"), + ("ACTOR_BOSS_VA", "BOSS_VA", "BOSS_VA"), + ("ACTOR_BG_HAKA_TUBO", "BG_HAKA_TUBO", "BG_HAKA_TUBO"), + ("ACTOR_BG_HAKA_TRAP", "BG_HAKA_TRAP", "BG_HAKA_TRAP"), + ("ACTOR_BG_HAKA_HUTA", "BG_HAKA_HUTA", "BG_HAKA_HUTA"), + ("ACTOR_BG_HAKA_ZOU", "BG_HAKA_ZOU", "BG_HAKA_ZOU"), + ("ACTOR_BG_SPOT17_FUNEN", "BG_SPOT17_FUNEN", "BG_SPOT17_FUNEN"), + ("ACTOR_EN_SYATEKI_ITM", "EN_SYATEKI_ITM", "EN_SYATEKI_ITM"), + ("ACTOR_EN_SYATEKI_MAN", "EN_SYATEKI_MAN", "EN_SYATEKI_MAN"), + ("ACTOR_EN_TANA", "EN_TANA", "EN_TANA"), + ("ACTOR_EN_NB", "EN_NB", "EN_NB"), + ("ACTOR_BOSS_MO", "BOSS_MO", "BOSS_MO"), + ("ACTOR_EN_SB", "EN_SB", "EN_SB"), + ("ACTOR_EN_BIGOKUTA", "EN_BIGOKUTA", "EN_BIGOKUTA"), + ("ACTOR_EN_KAREBABA", "EN_KAREBABA", "EN_KAREBABA"), + ("ACTOR_BG_BDAN_OBJECTS", "BG_BDAN_OBJECTS", "BG_BDAN_OBJECTS"), + ("ACTOR_DEMO_SA", "DEMO_SA", "DEMO_SA"), + ("ACTOR_DEMO_GO", "DEMO_GO", "DEMO_GO"), + ("ACTOR_EN_IN", "EN_IN", "EN_IN"), + ("ACTOR_EN_TR", "EN_TR", "EN_TR"), + ("ACTOR_BG_SPOT16_BOMBSTONE", "BG_SPOT16_BOMBSTONE", "BG_SPOT16_BOMBSTONE"), + ("ACTOR_BG_HIDAN_KOWARERUKABE", "BG_HIDAN_KOWARERUKABE", "BG_HIDAN_KOWARERUKABE"), + ("ACTOR_BG_BOMBWALL", "BG_BOMBWALL", "BG_BOMBWALL"), + ("ACTOR_BG_SPOT08_ICEBLOCK", "BG_SPOT08_ICEBLOCK", "BG_SPOT08_ICEBLOCK"), + ("ACTOR_EN_RU2", "EN_RU2", "EN_RU2"), + ("ACTOR_OBJ_DEKUJR", "OBJ_DEKUJR", "OBJ_DEKUJR"), + ("ACTOR_BG_MIZU_UZU", "BG_MIZU_UZU", "BG_MIZU_UZU"), + ("ACTOR_BG_SPOT06_OBJECTS", "BG_SPOT06_OBJECTS", "BG_SPOT06_OBJECTS"), + ("ACTOR_BG_ICE_OBJECTS", "BG_ICE_OBJECTS", "BG_ICE_OBJECTS"), + ("ACTOR_BG_HAKA_WATER", "BG_HAKA_WATER", "BG_HAKA_WATER"), + ("ACTOR_EN_MA2", "EN_MA2", "EN_MA2"), + ("ACTOR_EN_BOM_CHU", "EN_BOM_CHU", "EN_BOM_CHU"), + ("ACTOR_EN_HORSE_GAME_CHECK", "EN_HORSE_GAME_CHECK", "EN_HORSE_GAME_CHECK"), + ("ACTOR_BOSS_TW", "BOSS_TW", "BOSS_TW"), + ("ACTOR_EN_RR", "EN_RR", "EN_RR"), + ("ACTOR_EN_BA", "EN_BA", "EN_BA"), + ("ACTOR_EN_BX", "EN_BX", "EN_BX"), + ("ACTOR_EN_ANUBICE", "EN_ANUBICE", "EN_ANUBICE"), + ("ACTOR_EN_ANUBICE_FIRE", "EN_ANUBICE_FIRE", "EN_ANUBICE_FIRE"), + ("ACTOR_BG_MORI_HASHIGO", "BG_MORI_HASHIGO", "BG_MORI_HASHIGO"), + ("ACTOR_BG_MORI_HASHIRA4", "BG_MORI_HASHIRA4", "BG_MORI_HASHIRA4"), + ("ACTOR_BG_MORI_IDOMIZU", "BG_MORI_IDOMIZU", "BG_MORI_IDOMIZU"), + ("ACTOR_BG_SPOT16_DOUGHNUT", "BG_SPOT16_DOUGHNUT", "BG_SPOT16_DOUGHNUT"), + ("ACTOR_BG_BDAN_SWITCH", "BG_BDAN_SWITCH", "BG_BDAN_SWITCH"), + ("ACTOR_EN_MA1", "EN_MA1", "EN_MA1"), + ("ACTOR_BOSS_GANON", "BOSS_GANON", "BOSS_GANON"), + ("ACTOR_BOSS_SST", "BOSS_SST", "BOSS_SST"), + ("ACTOR_EN_NY", "EN_NY", "EN_NY"), + ("ACTOR_EN_FR", "EN_FR", "EN_FR"), + ("ACTOR_ITEM_SHIELD", "ITEM_SHIELD", "ITEM_SHIELD"), + ("ACTOR_BG_ICE_SHELTER", "BG_ICE_SHELTER", "BG_ICE_SHELTER"), + ("ACTOR_EN_ICE_HONO", "EN_ICE_HONO", "EN_ICE_HONO"), + ("ACTOR_ITEM_OCARINA", "ITEM_OCARINA", "ITEM_OCARINA"), + ("ACTOR_MAGIC_DARK", "MAGIC_DARK", "MAGIC_DARK"), + ("ACTOR_DEMO_6K", "DEMO_6K", "DEMO_6K"), + ("ACTOR_EN_ANUBICE_TAG", "EN_ANUBICE_TAG", "EN_ANUBICE_TAG"), + ("ACTOR_BG_HAKA_GATE", "BG_HAKA_GATE", "BG_HAKA_GATE"), + ("ACTOR_BG_SPOT15_SAKU", "BG_SPOT15_SAKU", "BG_SPOT15_SAKU"), + ("ACTOR_BG_JYA_GOROIWA", "BG_JYA_GOROIWA", "BG_JYA_GOROIWA"), + ("ACTOR_BG_JYA_ZURERUKABE", "BG_JYA_ZURERUKABE", "BG_JYA_ZURERUKABE"), + ("ACTOR_BG_JYA_COBRA", "BG_JYA_COBRA", "BG_JYA_COBRA"), + ("ACTOR_BG_JYA_KANAAMI", "BG_JYA_KANAAMI", "BG_JYA_KANAAMI"), + ("ACTOR_FISHING", "FISHING", "FISHING"), + ("ACTOR_OBJ_OSHIHIKI", "OBJ_OSHIHIKI", "OBJ_OSHIHIKI"), + ("ACTOR_BG_GATE_SHUTTER", "BG_GATE_SHUTTER", "BG_GATE_SHUTTER"), + ("ACTOR_EFF_DUST", "EFF_DUST", "EFF_DUST"), + ("ACTOR_BG_SPOT01_FUSYA", "BG_SPOT01_FUSYA", "BG_SPOT01_FUSYA"), + ("ACTOR_BG_SPOT01_IDOHASHIRA", "BG_SPOT01_IDOHASHIRA", "BG_SPOT01_IDOHASHIRA"), + ("ACTOR_BG_SPOT01_IDOMIZU", "BG_SPOT01_IDOMIZU", "BG_SPOT01_IDOMIZU"), + ("ACTOR_BG_PO_SYOKUDAI", "BG_PO_SYOKUDAI", "BG_PO_SYOKUDAI"), + ("ACTOR_BG_GANON_OTYUKA", "BG_GANON_OTYUKA", "BG_GANON_OTYUKA"), + ("ACTOR_BG_SPOT15_RRBOX", "BG_SPOT15_RRBOX", "BG_SPOT15_RRBOX"), + ("ACTOR_BG_UMAJUMP", "BG_UMAJUMP", "BG_UMAJUMP"), + ("ACTOR_ARROW_FIRE", "ARROW_FIRE", "ARROW_FIRE"), + ("ACTOR_ARROW_ICE", "ARROW_ICE", "ARROW_ICE"), + ("ACTOR_ARROW_LIGHT", "ARROW_LIGHT", "ARROW_LIGHT"), + ("ACTOR_ITEM_ETCETERA", "ITEM_ETCETERA", "ITEM_ETCETERA"), + ("ACTOR_OBJ_KIBAKO", "OBJ_KIBAKO", "OBJ_KIBAKO"), + ("ACTOR_OBJ_TSUBO", "OBJ_TSUBO", "OBJ_TSUBO"), + ("ACTOR_EN_WONDER_ITEM", "EN_WONDER_ITEM", "EN_WONDER_ITEM"), + ("ACTOR_EN_IK", "EN_IK", "EN_IK"), + ("ACTOR_DEMO_IK", "DEMO_IK", "DEMO_IK"), + ("ACTOR_EN_SKJ", "EN_SKJ", "EN_SKJ"), + ("ACTOR_EN_SKJNEEDLE", "EN_SKJNEEDLE", "EN_SKJNEEDLE"), + ("ACTOR_EN_G_SWITCH", "EN_G_SWITCH", "EN_G_SWITCH"), + ("ACTOR_DEMO_EXT", "DEMO_EXT", "DEMO_EXT"), + ("ACTOR_DEMO_SHD", "DEMO_SHD", "DEMO_SHD"), + ("ACTOR_EN_DNS", "EN_DNS", "EN_DNS"), + ("ACTOR_ELF_MSG", "ELF_MSG", "ELF_MSG"), + ("ACTOR_EN_HONOTRAP", "EN_HONOTRAP", "EN_HONOTRAP"), + ("ACTOR_EN_TUBO_TRAP", "EN_TUBO_TRAP", "EN_TUBO_TRAP"), + ("ACTOR_OBJ_ICE_POLY", "OBJ_ICE_POLY", "OBJ_ICE_POLY"), + ("ACTOR_BG_SPOT03_TAKI", "BG_SPOT03_TAKI", "BG_SPOT03_TAKI"), + ("ACTOR_BG_SPOT07_TAKI", "BG_SPOT07_TAKI", "BG_SPOT07_TAKI"), + ("ACTOR_EN_FZ", "EN_FZ", "EN_FZ"), + ("ACTOR_EN_PO_RELAY", "EN_PO_RELAY", "EN_PO_RELAY"), + ("ACTOR_BG_RELAY_OBJECTS", "BG_RELAY_OBJECTS", "BG_RELAY_OBJECTS"), + ("ACTOR_EN_DIVING_GAME", "EN_DIVING_GAME", "EN_DIVING_GAME"), + ("ACTOR_EN_KUSA", "EN_KUSA", "EN_KUSA"), + ("ACTOR_OBJ_BEAN", "OBJ_BEAN", "OBJ_BEAN"), + ("ACTOR_OBJ_BOMBIWA", "OBJ_BOMBIWA", "OBJ_BOMBIWA"), + ("ACTOR_OBJ_SWITCH", "OBJ_SWITCH", "OBJ_SWITCH"), + ("ACTOR_OBJ_ELEVATOR", "OBJ_ELEVATOR", "OBJ_ELEVATOR"), + ("ACTOR_OBJ_LIFT", "OBJ_LIFT", "OBJ_LIFT"), + ("ACTOR_OBJ_HSBLOCK", "OBJ_HSBLOCK", "OBJ_HSBLOCK"), + ("ACTOR_EN_OKARINA_TAG", "EN_OKARINA_TAG", "EN_OKARINA_TAG"), + ("ACTOR_EN_YABUSAME_MARK", "EN_YABUSAME_MARK", "EN_YABUSAME_MARK"), + ("ACTOR_EN_GOROIWA", "EN_GOROIWA", "EN_GOROIWA"), + ("ACTOR_EN_EX_RUPPY", "EN_EX_RUPPY", "EN_EX_RUPPY"), + ("ACTOR_EN_TORYO", "EN_TORYO", "EN_TORYO"), + ("ACTOR_EN_DAIKU", "EN_DAIKU", "EN_DAIKU"), + ("ACTOR_EN_NWC", "EN_NWC", "EN_NWC"), + ("ACTOR_EN_BLKOBJ", "EN_BLKOBJ", "EN_BLKOBJ"), + ("ACTOR_ITEM_INBOX", "ITEM_INBOX", "ITEM_INBOX"), + ("ACTOR_EN_GE1", "EN_GE1", "EN_GE1"), + ("ACTOR_OBJ_BLOCKSTOP", "OBJ_BLOCKSTOP", "OBJ_BLOCKSTOP"), + ("ACTOR_EN_SDA", "EN_SDA", "EN_SDA"), + ("ACTOR_EN_CLEAR_TAG", "EN_CLEAR_TAG", "EN_CLEAR_TAG"), + ("ACTOR_EN_NIW_LADY", "EN_NIW_LADY", "EN_NIW_LADY"), + ("ACTOR_EN_GM", "EN_GM", "EN_GM"), + ("ACTOR_EN_MS", "EN_MS", "EN_MS"), + ("ACTOR_EN_HS", "EN_HS", "EN_HS"), + ("ACTOR_BG_INGATE", "BG_INGATE", "BG_INGATE"), + ("ACTOR_EN_KANBAN", "EN_KANBAN", "EN_KANBAN"), + ("ACTOR_EN_HEISHI3", "EN_HEISHI3", "EN_HEISHI3"), + ("ACTOR_EN_SYATEKI_NIW", "EN_SYATEKI_NIW", "EN_SYATEKI_NIW"), + ("ACTOR_EN_ATTACK_NIW", "EN_ATTACK_NIW", "EN_ATTACK_NIW"), + ("ACTOR_BG_SPOT01_IDOSOKO", "BG_SPOT01_IDOSOKO", "BG_SPOT01_IDOSOKO"), + ("ACTOR_EN_SA", "EN_SA", "EN_SA"), + ("ACTOR_EN_WONDER_TALK", "EN_WONDER_TALK", "EN_WONDER_TALK"), + ("ACTOR_BG_GJYO_BRIDGE", "BG_GJYO_BRIDGE", "BG_GJYO_BRIDGE"), + ("ACTOR_EN_DS", "EN_DS", "EN_DS"), + ("ACTOR_EN_MK", "EN_MK", "EN_MK"), + ("ACTOR_EN_BOM_BOWL_MAN", "EN_BOM_BOWL_MAN", "EN_BOM_BOWL_MAN"), + ("ACTOR_EN_BOM_BOWL_PIT", "EN_BOM_BOWL_PIT", "EN_BOM_BOWL_PIT"), + ("ACTOR_EN_OWL", "EN_OWL", "EN_OWL"), + ("ACTOR_EN_ISHI", "EN_ISHI", "EN_ISHI"), + ("ACTOR_OBJ_HANA", "OBJ_HANA", "OBJ_HANA"), + ("ACTOR_OBJ_LIGHTSWITCH", "OBJ_LIGHTSWITCH", "OBJ_LIGHTSWITCH"), + ("ACTOR_OBJ_MURE2", "OBJ_MURE2", "OBJ_MURE2"), + ("ACTOR_EN_GO", "EN_GO", "EN_GO"), + ("ACTOR_EN_FU", "EN_FU", "EN_FU"), + ("ACTOR_EN_CHANGER", "EN_CHANGER", "EN_CHANGER"), + ("ACTOR_BG_JYA_MEGAMI", "BG_JYA_MEGAMI", "BG_JYA_MEGAMI"), + ("ACTOR_BG_JYA_LIFT", "BG_JYA_LIFT", "BG_JYA_LIFT"), + ("ACTOR_BG_JYA_BIGMIRROR", "BG_JYA_BIGMIRROR", "BG_JYA_BIGMIRROR"), + ("ACTOR_BG_JYA_BOMBCHUIWA", "BG_JYA_BOMBCHUIWA", "BG_JYA_BOMBCHUIWA"), + ("ACTOR_BG_JYA_AMISHUTTER", "BG_JYA_AMISHUTTER", "BG_JYA_AMISHUTTER"), + ("ACTOR_BG_JYA_BOMBIWA", "BG_JYA_BOMBIWA", "BG_JYA_BOMBIWA"), + ("ACTOR_BG_SPOT18_BASKET", "BG_SPOT18_BASKET", "BG_SPOT18_BASKET"), + ("ACTOR_EN_GANON_ORGAN", "EN_GANON_ORGAN", "EN_GANON_ORGAN"), + ("ACTOR_EN_SIOFUKI", "EN_SIOFUKI", "EN_SIOFUKI"), + ("ACTOR_EN_STREAM", "EN_STREAM", "EN_STREAM"), + ("ACTOR_EN_MM", "EN_MM", "EN_MM"), + ("ACTOR_EN_KO", "EN_KO", "EN_KO"), + ("ACTOR_EN_KZ", "EN_KZ", "EN_KZ"), + ("ACTOR_EN_WEATHER_TAG", "EN_WEATHER_TAG", "EN_WEATHER_TAG"), + ("ACTOR_BG_SST_FLOOR", "BG_SST_FLOOR", "BG_SST_FLOOR"), + ("ACTOR_EN_ANI", "EN_ANI", "EN_ANI"), + ("ACTOR_EN_EX_ITEM", "EN_EX_ITEM", "EN_EX_ITEM"), + ("ACTOR_BG_JYA_IRONOBJ", "BG_JYA_IRONOBJ", "BG_JYA_IRONOBJ"), + ("ACTOR_EN_JS", "EN_JS", "EN_JS"), + ("ACTOR_EN_JSJUTAN", "EN_JSJUTAN", "EN_JSJUTAN"), + ("ACTOR_EN_CS", "EN_CS", "EN_CS"), + ("ACTOR_EN_MD", "EN_MD", "EN_MD"), + ("ACTOR_EN_HY", "EN_HY", "EN_HY"), + ("ACTOR_EN_GANON_MANT", "EN_GANON_MANT", "EN_GANON_MANT"), + ("ACTOR_EN_OKARINA_EFFECT", "EN_OKARINA_EFFECT", "EN_OKARINA_EFFECT"), + ("ACTOR_EN_MAG", "EN_MAG", "EN_MAG"), + ("ACTOR_DOOR_GERUDO", "DOOR_GERUDO", "DOOR_GERUDO"), + ("ACTOR_ELF_MSG2", "ELF_MSG2", "ELF_MSG2"), + ("ACTOR_DEMO_GT", "DEMO_GT", "DEMO_GT"), + ("ACTOR_EN_PO_FIELD", "EN_PO_FIELD", "EN_PO_FIELD"), + ("ACTOR_EFC_ERUPC", "EFC_ERUPC", "EFC_ERUPC"), + ("ACTOR_BG_ZG", "BG_ZG", "BG_ZG"), + ("ACTOR_EN_HEISHI4", "EN_HEISHI4", "EN_HEISHI4"), + ("ACTOR_EN_ZL3", "EN_ZL3", "EN_ZL3"), + ("ACTOR_BOSS_GANON2", "BOSS_GANON2", "BOSS_GANON2"), + ("ACTOR_EN_KAKASI", "EN_KAKASI", "EN_KAKASI"), + ("ACTOR_EN_TAKARA_MAN", "EN_TAKARA_MAN", "EN_TAKARA_MAN"), + ("ACTOR_OBJ_MAKEOSHIHIKI", "OBJ_MAKEOSHIHIKI", "OBJ_MAKEOSHIHIKI"), + ("ACTOR_OCEFF_SPOT", "OCEFF_SPOT", "OCEFF_SPOT"), + ("ACTOR_END_TITLE", "END_TITLE", "END_TITLE"), + ("ACTOR_EN_TORCH", "EN_TORCH", "EN_TORCH"), + ("ACTOR_DEMO_EC", "DEMO_EC", "DEMO_EC"), + ("ACTOR_SHOT_SUN", "SHOT_SUN", "SHOT_SUN"), + ("ACTOR_EN_DY_EXTRA", "EN_DY_EXTRA", "EN_DY_EXTRA"), + ("ACTOR_EN_WONDER_TALK2", "EN_WONDER_TALK2", "EN_WONDER_TALK2"), + ("ACTOR_EN_GE2", "EN_GE2", "EN_GE2"), + ("ACTOR_OBJ_ROOMTIMER", "OBJ_ROOMTIMER", "OBJ_ROOMTIMER"), + ("ACTOR_EN_SSH", "EN_SSH", "EN_SSH"), + ("ACTOR_EN_STH", "EN_STH", "EN_STH"), + ("ACTOR_OCEFF_WIPE", "OCEFF_WIPE", "OCEFF_WIPE"), + ("ACTOR_OCEFF_STORM", "OCEFF_STORM", "OCEFF_STORM"), + ("ACTOR_EN_WEIYER", "EN_WEIYER", "EN_WEIYER"), + ("ACTOR_BG_SPOT05_SOKO", "BG_SPOT05_SOKO", "BG_SPOT05_SOKO"), + ("ACTOR_BG_JYA_1FLIFT", "BG_JYA_1FLIFT", "BG_JYA_1FLIFT"), + ("ACTOR_BG_JYA_HAHENIRON", "BG_JYA_HAHENIRON", "BG_JYA_HAHENIRON"), + ("ACTOR_BG_SPOT12_GATE", "BG_SPOT12_GATE", "BG_SPOT12_GATE"), + ("ACTOR_BG_SPOT12_SAKU", "BG_SPOT12_SAKU", "BG_SPOT12_SAKU"), + ("ACTOR_EN_HINTNUTS", "EN_HINTNUTS", "EN_HINTNUTS"), + ("ACTOR_EN_NUTSBALL", "EN_NUTSBALL", "EN_NUTSBALL"), + ("ACTOR_BG_SPOT00_BREAK", "BG_SPOT00_BREAK", "BG_SPOT00_BREAK"), + ("ACTOR_EN_SHOPNUTS", "EN_SHOPNUTS", "EN_SHOPNUTS"), + ("ACTOR_EN_IT", "EN_IT", "EN_IT"), + ("ACTOR_EN_GELDB", "EN_GELDB", "EN_GELDB"), + ("ACTOR_OCEFF_WIPE2", "OCEFF_WIPE2", "OCEFF_WIPE2"), + ("ACTOR_OCEFF_WIPE3", "OCEFF_WIPE3", "OCEFF_WIPE3"), + ("ACTOR_EN_NIW_GIRL", "EN_NIW_GIRL", "EN_NIW_GIRL"), + ("ACTOR_EN_DOG", "EN_DOG", "EN_DOG"), + ("ACTOR_EN_SI", "EN_SI", "EN_SI"), + ("ACTOR_BG_SPOT01_OBJECTS2", "BG_SPOT01_OBJECTS2", "BG_SPOT01_OBJECTS2"), + ("ACTOR_OBJ_COMB", "OBJ_COMB", "OBJ_COMB"), + ("ACTOR_BG_SPOT11_BAKUDANKABE", "BG_SPOT11_BAKUDANKABE", "BG_SPOT11_BAKUDANKABE"), + ("ACTOR_OBJ_KIBAKO2", "OBJ_KIBAKO2", "OBJ_KIBAKO2"), + ("ACTOR_EN_DNT_DEMO", "EN_DNT_DEMO", "EN_DNT_DEMO"), + ("ACTOR_EN_DNT_JIJI", "EN_DNT_JIJI", "EN_DNT_JIJI"), + ("ACTOR_EN_DNT_NOMAL", "EN_DNT_NOMAL", "EN_DNT_NOMAL"), + ("ACTOR_EN_GUEST", "EN_GUEST", "EN_GUEST"), + ("ACTOR_BG_BOM_GUARD", "BG_BOM_GUARD", "BG_BOM_GUARD"), + ("ACTOR_EN_HS2", "EN_HS2", "EN_HS2"), + ("ACTOR_DEMO_KEKKAI", "DEMO_KEKKAI", "DEMO_KEKKAI"), + ("ACTOR_BG_SPOT08_BAKUDANKABE", "BG_SPOT08_BAKUDANKABE", "BG_SPOT08_BAKUDANKABE"), + ("ACTOR_BG_SPOT17_BAKUDANKABE", "BG_SPOT17_BAKUDANKABE", "BG_SPOT17_BAKUDANKABE"), + ("ACTOR_OBJ_MURE3", "OBJ_MURE3", "OBJ_MURE3"), + ("ACTOR_EN_TG", "EN_TG", "EN_TG"), + ("ACTOR_EN_MU", "EN_MU", "EN_MU"), + ("ACTOR_EN_GO2", "EN_GO2", "EN_GO2"), + ("ACTOR_EN_WF", "EN_WF", "EN_WF"), + ("ACTOR_EN_SKB", "EN_SKB", "EN_SKB"), + ("ACTOR_DEMO_GJ", "DEMO_GJ", "DEMO_GJ"), + ("ACTOR_DEMO_GEFF", "DEMO_GEFF", "DEMO_GEFF"), + ("ACTOR_BG_GND_FIREMEIRO", "BG_GND_FIREMEIRO", "BG_GND_FIREMEIRO"), + ("ACTOR_BG_GND_DARKMEIRO", "BG_GND_DARKMEIRO", "BG_GND_DARKMEIRO"), + ("ACTOR_BG_GND_SOULMEIRO", "BG_GND_SOULMEIRO", "BG_GND_SOULMEIRO"), + ("ACTOR_BG_GND_NISEKABE", "BG_GND_NISEKABE", "BG_GND_NISEKABE"), + ("ACTOR_BG_GND_ICEBLOCK", "BG_GND_ICEBLOCK", "BG_GND_ICEBLOCK"), + ("ACTOR_EN_GB", "EN_GB", "EN_GB"), + ("ACTOR_EN_GS", "EN_GS", "EN_GS"), + ("ACTOR_BG_MIZU_BWALL", "BG_MIZU_BWALL", "BG_MIZU_BWALL"), + ("ACTOR_BG_MIZU_SHUTTER", "BG_MIZU_SHUTTER", "BG_MIZU_SHUTTER"), + ("ACTOR_EN_DAIKU_KAKARIKO", "EN_DAIKU_KAKARIKO", "EN_DAIKU_KAKARIKO"), + ("ACTOR_BG_BOWL_WALL", "BG_BOWL_WALL", "BG_BOWL_WALL"), + ("ACTOR_EN_WALL_TUBO", "EN_WALL_TUBO", "EN_WALL_TUBO"), + ("ACTOR_EN_PO_DESERT", "EN_PO_DESERT", "EN_PO_DESERT"), + ("ACTOR_EN_CROW", "EN_CROW", "EN_CROW"), + ("ACTOR_DOOR_KILLER", "DOOR_KILLER", "DOOR_KILLER"), + ("ACTOR_BG_SPOT11_OASIS", "BG_SPOT11_OASIS", "BG_SPOT11_OASIS"), + ("ACTOR_BG_SPOT18_FUTA", "BG_SPOT18_FUTA", "BG_SPOT18_FUTA"), + ("ACTOR_BG_SPOT18_SHUTTER", "BG_SPOT18_SHUTTER", "BG_SPOT18_SHUTTER"), + ("ACTOR_EN_MA3", "EN_MA3", "EN_MA3"), + ("ACTOR_EN_COW", "EN_COW", "EN_COW"), + ("ACTOR_BG_ICE_TURARA", "BG_ICE_TURARA", "BG_ICE_TURARA"), + ("ACTOR_BG_ICE_SHUTTER", "BG_ICE_SHUTTER", "BG_ICE_SHUTTER"), + ("ACTOR_EN_KAKASI2", "EN_KAKASI2", "EN_KAKASI2"), + ("ACTOR_EN_KAKASI3", "EN_KAKASI3", "EN_KAKASI3"), + ("ACTOR_OCEFF_WIPE4", "OCEFF_WIPE4", "OCEFF_WIPE4"), + ("ACTOR_EN_EG", "EN_EG", "EN_EG"), + ("ACTOR_BG_MENKURI_NISEKABE", "BG_MENKURI_NISEKABE", "BG_MENKURI_NISEKABE"), + ("ACTOR_EN_ZO", "EN_ZO", "EN_ZO"), + ("ACTOR_OBJ_MAKEKINSUTA", "OBJ_MAKEKINSUTA", "OBJ_MAKEKINSUTA"), + ("ACTOR_EN_GE3", "EN_GE3", "EN_GE3"), + ("ACTOR_OBJ_TIMEBLOCK", "OBJ_TIMEBLOCK", "OBJ_TIMEBLOCK"), + ("ACTOR_OBJ_HAMISHI", "OBJ_HAMISHI", "OBJ_HAMISHI"), + ("ACTOR_EN_ZL4", "EN_ZL4", "EN_ZL4"), + ("ACTOR_EN_MM2", "EN_MM2", "EN_MM2"), + ("ACTOR_BG_JYA_BLOCK", "BG_JYA_BLOCK", "BG_JYA_BLOCK"), + ("ACTOR_OBJ_WARP2BLOCK", "OBJ_WARP2BLOCK", "OBJ_WARP2BLOCK"), ] ootEnumLinkIdle = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Default", "Default"), - ("0x01", "Sneezing", "Sneezing"), - ("0x02", "Wiping Forehead", "Wiping Forehead"), - ("0x03", "Too Hot", "Too Hot (Triggers Heat Timer)"), - ("0x04", "Yawning", "Yawning"), - ("0x07", "Gasping For Breath", "Gasping For Breath"), - ("0x09", "Brandish Sword", "Brandish Sword"), - ("0x0A", "Adjust Tunic", "Adjust Tunic"), - ("0xFF", "Hops On Epona", "Hops On Epona"), + ("Custom", "Custom", "Custom"), + ("0x00", "Default", "Default"), + ("0x01", "Sneezing", "Sneezing"), + ("0x02", "Wiping Forehead", "Wiping Forehead"), + ("0x03", "Too Hot", "Too Hot (Triggers Heat Timer)"), + ("0x04", "Yawning", "Yawning"), + ("0x07", "Gasping For Breath", "Gasping For Breath"), + ("0x09", "Brandish Sword", "Brandish Sword"), + ("0x0A", "Adjust Tunic", "Adjust Tunic"), + ("0xFF", "Hops On Epona", "Hops On Epona"), ] # Make sure to add exceptions in utility.py - selectMeshChildrenOnly ootEnumEmptyType = [ - ('None', 'None', 'None'), - ('Scene', 'Scene', 'Scene'), - ('Room', 'Room', 'Room'), - ('Actor', 'Actor', 'Actor'), - ('Transition Actor', 'Transition Actor', 'Transition Actor'), - ('Entrance', 'Entrance', 'Entrance'), - ('Water Box', 'Water Box', 'Water Box'), - ('Cull Group', 'Cull Group', 'Cull Group'), - ('LOD', 'LOD Group', 'LOD Group'), - ('Cutscene', 'Cutscene', 'Cutscene'), - #('Camera Volume', 'Camera Volume', 'Camera Volume'), + ("None", "None", "None"), + ("Scene", "Scene", "Scene"), + ("Room", "Room", "Room"), + ("Actor", "Actor", "Actor"), + ("Transition Actor", "Transition Actor", "Transition Actor"), + ("Entrance", "Entrance", "Entrance"), + ("Water Box", "Water Box", "Water Box"), + ("Cull Group", "Cull Group", "Cull Group"), + ("LOD", "LOD Group", "LOD Group"), + ("Cutscene", "Cutscene", "Cutscene"), + # ('Camera Volume', 'Camera Volume', 'Camera Volume'), ] ootEnumCloudiness = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Sunny", "Sunny"), - ("0x01", "Cloudy", "Cloudy"), + ("Custom", "Custom", "Custom"), + ("0x00", "Sunny", "Sunny"), + ("0x01", "Cloudy", "Cloudy"), ] ootEnumCameraMode = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Default", "Default"), - ("0x10", "Two Views, No C-Up", "Two Views, No C-Up"), - ("0x20", "Rotating Background, Bird's Eye C-Up", "Rotating Background, Bird's Eye C-Up"), - ("0x30", "Fixed Background, No C-Up", "Fixed Background, No C-Up"), - ("0x40", "Rotating Background, No C-Up", "Rotating Background, No C-Up"), - ("0x50", "Shooting Gallery", "Shooting Gallery"), + ("Custom", "Custom", "Custom"), + ("0x00", "Default", "Default"), + ("0x10", "Two Views, No C-Up", "Two Views, No C-Up"), + ("0x20", "Rotating Background, Bird's Eye C-Up", "Rotating Background, Bird's Eye C-Up"), + ("0x30", "Fixed Background, No C-Up", "Fixed Background, No C-Up"), + ("0x40", "Rotating Background, No C-Up", "Rotating Background, No C-Up"), + ("0x50", "Shooting Gallery", "Shooting Gallery"), ] ootEnumMapLocation = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Hyrule Field", "Hyrule Field"), - ("0x01", "Kakariko Village", "Kakariko Village"), - ("0x02", "Graveyard", "Graveyard"), - ("0x03", "Zora's River", "Zora's River"), - ("0x04", "Kokiri Forest", "Kokiri Forest"), - ("0x05", "Sacred Forest Meadow", "Sacred Forest Meadow"), - ("0x06", "Lake Hylia", "Lake Hylia"), - ("0x07", "Zora's Domain", "Zora's Domain"), - ("0x08", "Zora's Fountain", "Zora's Fountain"), - ("0x09", "Gerudo Valley", "Gerudo Valley"), - ("0x0A", "Lost Woods", "Lost Woods"), - ("0x0B", "Desert Colossus", "Desert Colossus"), - ("0x0C", "Gerudo's Fortress", "Gerudo's Fortress"), - ("0x0D", "Haunted Wasteland", "Haunted Wasteland"), - ("0x0E", "Market", "Market"), - ("0x0F", "Hyrule Castle", "Hyrule Castle"), - ("0x10", "Death Mountain Trail", "Death Mountain Trail"), - ("0x11", "Death Mountain Crater", "Death Mountain Crater"), - ("0x12", "Goron City", "Goron City"), - ("0x13", "Lon Lon Ranch", "Lon Lon Ranch"), - ("0x14", "Dampe's Grave & Windmill", "Dampe's Grave & Windmill"), - ("0x15", "Ganon's Castle", "Ganon's Castle"), - ("0x16", "Grottos & Fairy Fountains", "Grottos & Fairy Fountains"), + ("Custom", "Custom", "Custom"), + ("0x00", "Hyrule Field", "Hyrule Field"), + ("0x01", "Kakariko Village", "Kakariko Village"), + ("0x02", "Graveyard", "Graveyard"), + ("0x03", "Zora's River", "Zora's River"), + ("0x04", "Kokiri Forest", "Kokiri Forest"), + ("0x05", "Sacred Forest Meadow", "Sacred Forest Meadow"), + ("0x06", "Lake Hylia", "Lake Hylia"), + ("0x07", "Zora's Domain", "Zora's Domain"), + ("0x08", "Zora's Fountain", "Zora's Fountain"), + ("0x09", "Gerudo Valley", "Gerudo Valley"), + ("0x0A", "Lost Woods", "Lost Woods"), + ("0x0B", "Desert Colossus", "Desert Colossus"), + ("0x0C", "Gerudo's Fortress", "Gerudo's Fortress"), + ("0x0D", "Haunted Wasteland", "Haunted Wasteland"), + ("0x0E", "Market", "Market"), + ("0x0F", "Hyrule Castle", "Hyrule Castle"), + ("0x10", "Death Mountain Trail", "Death Mountain Trail"), + ("0x11", "Death Mountain Crater", "Death Mountain Crater"), + ("0x12", "Goron City", "Goron City"), + ("0x13", "Lon Lon Ranch", "Lon Lon Ranch"), + ("0x14", "Dampe's Grave & Windmill", "Dampe's Grave & Windmill"), + ("0x15", "Ganon's Castle", "Ganon's Castle"), + ("0x16", "Grottos & Fairy Fountains", "Grottos & Fairy Fountains"), ] ootEnumSkybox = [ - ("Custom", "Custom", "Custom"), - ("0x00", "None", "None"), - ("0x01", "Standard Sky", "Standard Sky"), - ("0x02", "Hylian Bazaar", "Hylian Bazaar"), - ("0x03", "Brown Cloudy Sky", "Brown Cloudy Sky"), - ("0x04", "Market Ruins", "Market Ruins"), - ("0x05", "Black Cloudy Night", "Black Cloudy Night"), - ("0x07", "Link's House", "Link's House"), - ("0x09", "Market (Main Square, Day)", "Market (Main Square, Day)"), - ("0x0A", "Market (Main Square, Night)", "Market (Main Square, Night)"), - ("0x0B", "Happy Mask Shop", "Happy Mask Shop"), - ("0x0C", "Know-It-All Brothers' House", "Know-It-All Brothers' House"), - ("0x0E", "Kokiri Twins' House", "Kokiri Twins' House"), - ("0x0F", "Stable", "Stable"), - ("0x10", "Stew Lady's House", "Stew Lady's House"), - ("0x11", "Kokiri Shop", "Kokiri Shop"), - ("0x13", "Goron Shop", "Goron Shop"), - ("0x14", "Zora Shop", "Zora Shop"), - ("0x16", "Kakariko Potions Shop", "Kakariko Potions Shop"), - ("0x17", "Hylian Potions Shop", "Hylian Potions Shop"), - ("0x18", "Bomb Shop", "Bomb Shop"), - ("0x1A", "Dog Lady's House", "Dog Lady's House"), - ("0x1B", "Impa's House", "Impa's House"), - ("0x1C", "Gerudo Tent", "Gerudo Tent"), - ("0x1D", "Environment Color", "Environment Color"), - ("0x20", "Mido's House", "Mido's House"), - ("0x21", "Saria's House", "Saria's House"), - ("0x22", "Dog Guy's House", "Dog Guy's House"), + ("Custom", "Custom", "Custom"), + ("0x00", "None", "None"), + ("0x01", "Standard Sky", "Standard Sky"), + ("0x02", "Hylian Bazaar", "Hylian Bazaar"), + ("0x03", "Brown Cloudy Sky", "Brown Cloudy Sky"), + ("0x04", "Market Ruins", "Market Ruins"), + ("0x05", "Black Cloudy Night", "Black Cloudy Night"), + ("0x07", "Link's House", "Link's House"), + ("0x09", "Market (Main Square, Day)", "Market (Main Square, Day)"), + ("0x0A", "Market (Main Square, Night)", "Market (Main Square, Night)"), + ("0x0B", "Happy Mask Shop", "Happy Mask Shop"), + ("0x0C", "Know-It-All Brothers' House", "Know-It-All Brothers' House"), + ("0x0E", "Kokiri Twins' House", "Kokiri Twins' House"), + ("0x0F", "Stable", "Stable"), + ("0x10", "Stew Lady's House", "Stew Lady's House"), + ("0x11", "Kokiri Shop", "Kokiri Shop"), + ("0x13", "Goron Shop", "Goron Shop"), + ("0x14", "Zora Shop", "Zora Shop"), + ("0x16", "Kakariko Potions Shop", "Kakariko Potions Shop"), + ("0x17", "Hylian Potions Shop", "Hylian Potions Shop"), + ("0x18", "Bomb Shop", "Bomb Shop"), + ("0x1A", "Dog Lady's House", "Dog Lady's House"), + ("0x1B", "Impa's House", "Impa's House"), + ("0x1C", "Gerudo Tent", "Gerudo Tent"), + ("0x1D", "Environment Color", "Environment Color"), + ("0x20", "Mido's House", "Mido's House"), + ("0x21", "Saria's House", "Saria's House"), + ("0x22", "Dog Guy's House", "Dog Guy's House"), ] ootEnumSkyboxLighting = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Time Of Day", "Time Of Day"), - ("0x01", "Indoor", "Indoor"), + ("Custom", "Custom", "Custom"), + ("0x00", "Time Of Day", "Time Of Day"), + ("0x01", "Indoor", "Indoor"), ] ootEnumAudioSessionPreset = [ - ("Custom", "Custom", "Custom"), - ("0x00", "0x00", "0x00"), + ("Custom", "Custom", "Custom"), + ("0x00", "0x00", "0x00"), ] -ootEnumMusicSeq = [ - ("Custom", "Custom", "Custom"), - ("0x02", "Hyrule Field", "Hyrule Field"), - ("0x03", "Hyrule Field (Initial Segment From Loading Area)", "Hyrule Field (Initial Segment From Loading Area)"), - ("0x04", "Hyrule Field (Moving Segment 1)", "Hyrule Field (Moving Segment 1)"), - ("0x05", "Hyrule Field (Moving Segment 2)", "Hyrule Field (Moving Segment 2)"), - ("0x06", "Hyrule Field (Moving Segment 3)", "Hyrule Field (Moving Segment 3)"), - ("0x07", "Hyrule Field (Moving Segment 4)", "Hyrule Field (Moving Segment 4)"), - ("0x08", "Hyrule Field (Moving Segment 5)", "Hyrule Field (Moving Segment 5)"), - ("0x09", "Hyrule Field (Moving Segment 6)", "Hyrule Field (Moving Segment 6)"), - ("0x0A", "Hyrule Field (Moving Segment 7)", "Hyrule Field (Moving Segment 7)"), - ("0x0B", "Hyrule Field (Moving Segment 8)", "Hyrule Field (Moving Segment 8)"), - ("0x0C", "Hyrule Field (Moving Segment 9)", "Hyrule Field (Moving Segment 9)"), - ("0x0D", "Hyrule Field (Moving Segment 10)", "Hyrule Field (Moving Segment 10)"), - ("0x0E", "Hyrule Field (Moving Segment 11)", "Hyrule Field (Moving Segment 11)"), - ("0x0F", "Hyrule Field (Enemy Approaches)", "Hyrule Field (Enemy Approaches)"), - ("0x10", "Hyrule Field (Enemy Near Segment 1)", "Hyrule Field (Enemy Near Segment 1)"), - ("0x11", "Hyrule Field (Enemy Near Segment 2)", "Hyrule Field (Enemy Near Segment 2)"), - ("0x12", "Hyrule Field (Enemy Near Segment 3)", "Hyrule Field (Enemy Near Segment 3)"), - ("0x13", "Hyrule Field (Enemy Near Segment 4)", "Hyrule Field (Enemy Near Segment 4)"), - ("0x14", "Hyrule Field (Standing Still Segment 1)", "Hyrule Field (Standing Still Segment 1)"), - ("0x15", "Hyrule Field (Standing Still Segment 2)", "Hyrule Field (Standing Still Segment 2)"), - ("0x16", "Hyrule Field (Standing Still Segment 3)", "Hyrule Field (Standing Still Segment 3)"), - ("0x17", "Hyrule Field (Standing Still Segment 4)", "Hyrule Field (Standing Still Segment 4)"), - ("0x18", "Dodongo's Cavern", "Dodongo's Cavern"), - ("0x19", "Kakariko Village (Adult)", "Kakariko Village (Adult)"), - ("0x1A", "Enemy Battle", "Enemy Battle"), - ("0x1B", "Boss Battle 00", "Boss Battle 00"), - ("0x1C", "Inside the Deku Tree", "Inside the Deku Tree"), - ("0x1D", "Market", "Market"), - ("0x1E", "Title Theme", "Title Theme"), - ("0x1F", "Link's House", "Link's House"), - ("0x20", "Game Over", "Game Over"), - ("0x21", "Boss Clear", "Boss Clear"), - ("0x22", "Item Get", "Item Get"), - ("0x23", "Opening Ganon", "Opening Ganon"), - ("0x24", "Heart Get", "Heart Get"), - ("0x25", "Prelude Of Light", "Prelude Of Light"), - ("0x26", "Inside Jabu-Jabu's Belly", "Inside Jabu-Jabu's Belly"), - ("0x27", "Kakariko Village (Child)", "Kakariko Village (Child)"), - ("0x28", "Great Fairy's Fountain", "Great Fairy's Fountain"), - ("0x29", "Zelda's Theme", "Zelda's Theme"), - ("0x2A", "Fire Temple", "Fire Temple"), - ("0x2B", "Open Treasure Chest", "Open Treasure Chest"), - ("0x2C", "Forest Temple", "Forest Temple"), - ("0x2D", "Hyrule Castle Courtyard", "Hyrule Castle Courtyard"), - ("0x2E", "Ganondorf's Theme", "Ganondorf's Theme"), - ("0x2F", "Lon Lon Ranch", "Lon Lon Ranch"), - ("0x30", "Goron City", "Goron City "), - ("0x31", "Hyrule Field Morning Theme", "Hyrule Field Morning Theme"), - ("0x32", "Spiritual Stone Get", "Spiritual Stone Get"), - ("0x33", "Bolero of Fire", "Bolero of Fire"), - ("0x34", "Minuet of Woods", "Minuet of Woods"), - ("0x35", "Serenade of Water", "Serenade of Water"), - ("0x36", "Requiem of Spirit", "Requiem of Spirit"), - ("0x37", "Nocturne of Shadow", "Nocturne of Shadow"), - ("0x38", "Mini-Boss Battle", "Mini-Boss Battle"), - ("0x39", "Obtain Small Item", "Obtain Small Item"), - ("0x3A", "Temple of Time", "Temple of Time"), - ("0x3B", "Escape from Lon Lon Ranch", "Escape from Lon Lon Ranch"), - ("0x3C", "Kokiri Forest", "Kokiri Forest"), - ("0x3D", "Obtain Fairy Ocarina", "Obtain Fairy Ocarina"), - ("0x3E", "Lost Woods", "Lost Woods"), - ("0x3F", "Spirit Temple", "Spirit Temple"), - ("0x40", "Horse Race", "Horse Race"), - ("0x41", "Horse Race Goal", "Horse Race Goal"), - ("0x42", "Ingo's Theme", "Ingo's Theme"), - ("0x43", "Obtain Medallion", "Obtain Medallion"), - ("0x44", "Ocarina Saria's Song", "Ocarina Saria's Song"), - ("0x45", "Ocarina Epona's Song", "Ocarina Epona's Song"), - ("0x46", "Ocarina Zelda's Lullaby", "Ocarina Zelda's Lullaby"), - ("0x47", "Sun's Song", "Sun's Song"), - ("0x48", "Song of Time", "Song of Time"), - ("0x49", "Song of Storms", "Song of Storms"), - ("0x4A", "Fairy Flying", "Fairy Flying"), - ("0x4B", "Deku Tree", "Deku Tree"), - ("0x4C", "Windmill Hut", "Windmill Hut"), - ("0x4D", "Legend of Hyrule", "Legend of Hyrule"), - ("0x4E", "Shooting Gallery", "Shooting Gallery"), - ("0x4F", "Sheik's Theme", "Sheik's Theme"), - ("0x50", "Zora's Domain", "Zora's Domain"), - ("0x51", "Enter Zelda", "Enter Zelda"), - ("0x52", "Goodbye to Zelda", "Goodbye to Zelda"), - ("0x53", "Master Sword", "Master Sword"), - ("0x54", "Ganon Intro", "Ganon Intro"), - ("0x55", "Shop", "Shop"), - ("0x56", "Chamber of the Sages", "Chamber of the Sages"), - ("0x57", "File Select", "File Select"), - ("0x58", "Ice Cavern", "Ice Cavern"), - ("0x59", "Open Door of Temple of Time", "Open Door of Temple of Time"), - ("0x5A", "Kaepora Gaebora's Theme", "Kaepora Gaebora's Theme"), - ("0x5B", "Shadow Temple", "Shadow Temple"), - ("0x5C", "Water Temple", "Water Temple"), - ("0x5D", "Ganon's Castle Bridge", "Ganon's Castle Bridge"), - ("0x5E", "Ocarina of Time", "Ocarina of Time"), - ("0x5F", "Gerudo Valley", "Gerudo Valley"), - ("0x60", "Potion Shop", "Potion Shop"), - ("0x61", "Kotake & Koume's Theme", "Kotake & Koume's Theme"), - ("0x62", "Escape from Ganon's Castle", "Escape from Ganon's Castle"), - ("0x63", "Ganon's Castle Under Ground", "Ganon's Castle Under Ground"), - ("0x64", "Ganondorf Battle", "Ganondorf Battle"), - ("0x65", "Ganon Battle", "Ganon Battle"), - ("0x66", "Seal of Six Sages", "Seal of Six Sages"), - ("0x67", "End Credits I", "End Credits I"), - ("0x68", "End Credits II", "End Credits II"), - ("0x69", "End Credits III", "End Credits III"), - ("0x6A", "End Credits IV", "End Credits IV"), - ("0x6B", "King Dodongo & Volvagia Boss Battle", "King Dodongo & Volvagia Boss Battle"), - ("0x6C", "Mini-Game", "Mini-Game"), +ootEnumMusicSeq = [ + ("Custom", "Custom", "Custom"), + ("0x02", "Hyrule Field", "Hyrule Field"), + ("0x03", "Hyrule Field (Initial Segment From Loading Area)", "Hyrule Field (Initial Segment From Loading Area)"), + ("0x04", "Hyrule Field (Moving Segment 1)", "Hyrule Field (Moving Segment 1)"), + ("0x05", "Hyrule Field (Moving Segment 2)", "Hyrule Field (Moving Segment 2)"), + ("0x06", "Hyrule Field (Moving Segment 3)", "Hyrule Field (Moving Segment 3)"), + ("0x07", "Hyrule Field (Moving Segment 4)", "Hyrule Field (Moving Segment 4)"), + ("0x08", "Hyrule Field (Moving Segment 5)", "Hyrule Field (Moving Segment 5)"), + ("0x09", "Hyrule Field (Moving Segment 6)", "Hyrule Field (Moving Segment 6)"), + ("0x0A", "Hyrule Field (Moving Segment 7)", "Hyrule Field (Moving Segment 7)"), + ("0x0B", "Hyrule Field (Moving Segment 8)", "Hyrule Field (Moving Segment 8)"), + ("0x0C", "Hyrule Field (Moving Segment 9)", "Hyrule Field (Moving Segment 9)"), + ("0x0D", "Hyrule Field (Moving Segment 10)", "Hyrule Field (Moving Segment 10)"), + ("0x0E", "Hyrule Field (Moving Segment 11)", "Hyrule Field (Moving Segment 11)"), + ("0x0F", "Hyrule Field (Enemy Approaches)", "Hyrule Field (Enemy Approaches)"), + ("0x10", "Hyrule Field (Enemy Near Segment 1)", "Hyrule Field (Enemy Near Segment 1)"), + ("0x11", "Hyrule Field (Enemy Near Segment 2)", "Hyrule Field (Enemy Near Segment 2)"), + ("0x12", "Hyrule Field (Enemy Near Segment 3)", "Hyrule Field (Enemy Near Segment 3)"), + ("0x13", "Hyrule Field (Enemy Near Segment 4)", "Hyrule Field (Enemy Near Segment 4)"), + ("0x14", "Hyrule Field (Standing Still Segment 1)", "Hyrule Field (Standing Still Segment 1)"), + ("0x15", "Hyrule Field (Standing Still Segment 2)", "Hyrule Field (Standing Still Segment 2)"), + ("0x16", "Hyrule Field (Standing Still Segment 3)", "Hyrule Field (Standing Still Segment 3)"), + ("0x17", "Hyrule Field (Standing Still Segment 4)", "Hyrule Field (Standing Still Segment 4)"), + ("0x18", "Dodongo's Cavern", "Dodongo's Cavern"), + ("0x19", "Kakariko Village (Adult)", "Kakariko Village (Adult)"), + ("0x1A", "Enemy Battle", "Enemy Battle"), + ("0x1B", "Boss Battle 00", "Boss Battle 00"), + ("0x1C", "Inside the Deku Tree", "Inside the Deku Tree"), + ("0x1D", "Market", "Market"), + ("0x1E", "Title Theme", "Title Theme"), + ("0x1F", "Link's House", "Link's House"), + ("0x20", "Game Over", "Game Over"), + ("0x21", "Boss Clear", "Boss Clear"), + ("0x22", "Item Get", "Item Get"), + ("0x23", "Opening Ganon", "Opening Ganon"), + ("0x24", "Heart Get", "Heart Get"), + ("0x25", "Prelude Of Light", "Prelude Of Light"), + ("0x26", "Inside Jabu-Jabu's Belly", "Inside Jabu-Jabu's Belly"), + ("0x27", "Kakariko Village (Child)", "Kakariko Village (Child)"), + ("0x28", "Great Fairy's Fountain", "Great Fairy's Fountain"), + ("0x29", "Zelda's Theme", "Zelda's Theme"), + ("0x2A", "Fire Temple", "Fire Temple"), + ("0x2B", "Open Treasure Chest", "Open Treasure Chest"), + ("0x2C", "Forest Temple", "Forest Temple"), + ("0x2D", "Hyrule Castle Courtyard", "Hyrule Castle Courtyard"), + ("0x2E", "Ganondorf's Theme", "Ganondorf's Theme"), + ("0x2F", "Lon Lon Ranch", "Lon Lon Ranch"), + ("0x30", "Goron City", "Goron City "), + ("0x31", "Hyrule Field Morning Theme", "Hyrule Field Morning Theme"), + ("0x32", "Spiritual Stone Get", "Spiritual Stone Get"), + ("0x33", "Bolero of Fire", "Bolero of Fire"), + ("0x34", "Minuet of Woods", "Minuet of Woods"), + ("0x35", "Serenade of Water", "Serenade of Water"), + ("0x36", "Requiem of Spirit", "Requiem of Spirit"), + ("0x37", "Nocturne of Shadow", "Nocturne of Shadow"), + ("0x38", "Mini-Boss Battle", "Mini-Boss Battle"), + ("0x39", "Obtain Small Item", "Obtain Small Item"), + ("0x3A", "Temple of Time", "Temple of Time"), + ("0x3B", "Escape from Lon Lon Ranch", "Escape from Lon Lon Ranch"), + ("0x3C", "Kokiri Forest", "Kokiri Forest"), + ("0x3D", "Obtain Fairy Ocarina", "Obtain Fairy Ocarina"), + ("0x3E", "Lost Woods", "Lost Woods"), + ("0x3F", "Spirit Temple", "Spirit Temple"), + ("0x40", "Horse Race", "Horse Race"), + ("0x41", "Horse Race Goal", "Horse Race Goal"), + ("0x42", "Ingo's Theme", "Ingo's Theme"), + ("0x43", "Obtain Medallion", "Obtain Medallion"), + ("0x44", "Ocarina Saria's Song", "Ocarina Saria's Song"), + ("0x45", "Ocarina Epona's Song", "Ocarina Epona's Song"), + ("0x46", "Ocarina Zelda's Lullaby", "Ocarina Zelda's Lullaby"), + ("0x47", "Sun's Song", "Sun's Song"), + ("0x48", "Song of Time", "Song of Time"), + ("0x49", "Song of Storms", "Song of Storms"), + ("0x4A", "Fairy Flying", "Fairy Flying"), + ("0x4B", "Deku Tree", "Deku Tree"), + ("0x4C", "Windmill Hut", "Windmill Hut"), + ("0x4D", "Legend of Hyrule", "Legend of Hyrule"), + ("0x4E", "Shooting Gallery", "Shooting Gallery"), + ("0x4F", "Sheik's Theme", "Sheik's Theme"), + ("0x50", "Zora's Domain", "Zora's Domain"), + ("0x51", "Enter Zelda", "Enter Zelda"), + ("0x52", "Goodbye to Zelda", "Goodbye to Zelda"), + ("0x53", "Master Sword", "Master Sword"), + ("0x54", "Ganon Intro", "Ganon Intro"), + ("0x55", "Shop", "Shop"), + ("0x56", "Chamber of the Sages", "Chamber of the Sages"), + ("0x57", "File Select", "File Select"), + ("0x58", "Ice Cavern", "Ice Cavern"), + ("0x59", "Open Door of Temple of Time", "Open Door of Temple of Time"), + ("0x5A", "Kaepora Gaebora's Theme", "Kaepora Gaebora's Theme"), + ("0x5B", "Shadow Temple", "Shadow Temple"), + ("0x5C", "Water Temple", "Water Temple"), + ("0x5D", "Ganon's Castle Bridge", "Ganon's Castle Bridge"), + ("0x5E", "Ocarina of Time", "Ocarina of Time"), + ("0x5F", "Gerudo Valley", "Gerudo Valley"), + ("0x60", "Potion Shop", "Potion Shop"), + ("0x61", "Kotake & Koume's Theme", "Kotake & Koume's Theme"), + ("0x62", "Escape from Ganon's Castle", "Escape from Ganon's Castle"), + ("0x63", "Ganon's Castle Under Ground", "Ganon's Castle Under Ground"), + ("0x64", "Ganondorf Battle", "Ganondorf Battle"), + ("0x65", "Ganon Battle", "Ganon Battle"), + ("0x66", "Seal of Six Sages", "Seal of Six Sages"), + ("0x67", "End Credits I", "End Credits I"), + ("0x68", "End Credits II", "End Credits II"), + ("0x69", "End Credits III", "End Credits III"), + ("0x6A", "End Credits IV", "End Credits IV"), + ("0x6B", "King Dodongo & Volvagia Boss Battle", "King Dodongo & Volvagia Boss Battle"), + ("0x6C", "Mini-Game", "Mini-Game"), ] ootEnumNightSeq = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Standard night [day and night cycle]", "0x00"), - ("0x01", "Standard night [Kakariko]", "0x01"), - ("0x02", "Distant storm [Graveyard]", "0x02"), - ("0x03", "Howling wind and cawing [Ganon's Castle]", "0x03"), - ("0x04", "Wind + night birds [Kokiri]", "0x04"), - ("0x05", "Wind + crickets", "0x05"), - ("0x06", "Wind", "0x06"), - ("0x07", "Howling wind", "0x07"), - ("0x08", "Wind + crickets", "0x08"), - ("0x09", "Wind + crickets", "0x09"), - ("0x0A", "Tubed howling wind [Wasteland]", "0x0A"), - ("0x0B", "Tubed howling wind [Colossus]", "0x0B"), - ("0x0C", "Wind", "0x0C"), - ("0x0D", "Wind + crickets", "0x0D"), - ("0x0E", "Wind + crickets", "0x0E"), - ("0x0F", "Wind + birds", "0x0F"), - ("0x10", "Wind + crickets", "0x10"), - ("0x11", "?", "0x11"), - ("0x12", "Wind + crickets", "0x12"), - ("0x13", "Day music always playing", "0x13"), - ("0x14", "Silence", "0x14"), - ("0x16", "Silence", "0x16"), - ("0x17", "High tubed wind + rain", "0x17"), - ("0x18", "Silence", "0x18"), - ("0x19", "Silence", "0x19"), - ("0x1A", "High tubed wind + rain", "0x1A"), - ("0x1B", "Silence", "0x1B"), - ("0x1C", "Rain", "0x1C"), - ("0x1D", "High tubed wind + rain", "0x1D"), - ("0x1E", "Silence", "0x1E"), - ("0x1F", "High tubed wind + rain ", "0x1F"), + ("Custom", "Custom", "Custom"), + ("0x00", "Standard night [day and night cycle]", "0x00"), + ("0x01", "Standard night [Kakariko]", "0x01"), + ("0x02", "Distant storm [Graveyard]", "0x02"), + ("0x03", "Howling wind and cawing [Ganon's Castle]", "0x03"), + ("0x04", "Wind + night birds [Kokiri]", "0x04"), + ("0x05", "Wind + crickets", "0x05"), + ("0x06", "Wind", "0x06"), + ("0x07", "Howling wind", "0x07"), + ("0x08", "Wind + crickets", "0x08"), + ("0x09", "Wind + crickets", "0x09"), + ("0x0A", "Tubed howling wind [Wasteland]", "0x0A"), + ("0x0B", "Tubed howling wind [Colossus]", "0x0B"), + ("0x0C", "Wind", "0x0C"), + ("0x0D", "Wind + crickets", "0x0D"), + ("0x0E", "Wind + crickets", "0x0E"), + ("0x0F", "Wind + birds", "0x0F"), + ("0x10", "Wind + crickets", "0x10"), + ("0x11", "?", "0x11"), + ("0x12", "Wind + crickets", "0x12"), + ("0x13", "Day music always playing", "0x13"), + ("0x14", "Silence", "0x14"), + ("0x16", "Silence", "0x16"), + ("0x17", "High tubed wind + rain", "0x17"), + ("0x18", "Silence", "0x18"), + ("0x19", "Silence", "0x19"), + ("0x1A", "High tubed wind + rain", "0x1A"), + ("0x1B", "Silence", "0x1B"), + ("0x1C", "Rain", "0x1C"), + ("0x1D", "High tubed wind + rain", "0x1D"), + ("0x1E", "Silence", "0x1E"), + ("0x1F", "High tubed wind + rain ", "0x1F"), ] ootEnumObjectID = [ - ("Custom", "Custom", "Custom"), - ("OBJECT_HUMAN", "Human", "Human"), - ("OBJECT_OKUTA", "Okuta", "Okuta"), - ("OBJECT_CROW", "Crow", "Crow"), - ("OBJECT_POH", "Poh", "Poh"), - ("OBJECT_DY_OBJ", "Dy Obj", "Dy Obj"), - ("OBJECT_WALLMASTER", "Wallmaster", "Wallmaster"), - ("OBJECT_DODONGO", "Dodongo", "Dodongo"), - ("OBJECT_FIREFLY", "Firefly", "Firefly"), - ("OBJECT_BOX", "Box", "Box"), - ("OBJECT_FIRE", "Fire", "Fire"), - ("OBJECT_BUBBLE", "Bubble", "Bubble"), - ("OBJECT_NIW", "Niw", "Niw"), - ("OBJECT_TITE", "Tite", "Tite"), - ("OBJECT_REEBA", "Reeba", "Reeba"), - ("OBJECT_PEEHAT", "Peehat", "Peehat"), - ("OBJECT_KINGDODONGO", "Kingdodongo", "Kingdodongo"), - ("OBJECT_HORSE", "Horse", "Horse"), - ("OBJECT_ZF", "Zf", "Zf"), - ("OBJECT_GOMA", "Goma", "Goma"), - ("OBJECT_ZL1", "Zl1", "Zl1"), - ("OBJECT_GOL", "Gol", "Gol"), - ("OBJECT_DODOJR", "Dodojr", "Dodojr"), - ("OBJECT_TORCH2", "Torch2", "Torch2"), - ("OBJECT_BL", "Bl", "Bl"), - ("OBJECT_TP", "Tp", "Tp"), - ("OBJECT_OA1", "Oa1", "Oa1"), - ("OBJECT_ST", "St", "St"), - ("OBJECT_BW", "Bw", "Bw"), - ("OBJECT_EI", "Ei", "Ei"), - ("OBJECT_HORSE_NORMAL", "Horse Normal", "Horse Normal"), - ("OBJECT_OB1", "Ob1", "Ob1"), - ("OBJECT_O_ANIME", "O Anime", "O Anime"), - ("OBJECT_SPOT04_OBJECTS", "Spot04 Objects", "Spot04 Objects"), - ("OBJECT_DDAN_OBJECTS", "Ddan Objects", "Ddan Objects"), - ("OBJECT_HIDAN_OBJECTS", "Hidan Objects", "Hidan Objects"), - ("OBJECT_HORSE_GANON", "Horse Ganon", "Horse Ganon"), - ("OBJECT_OA2", "Oa2", "Oa2"), - ("OBJECT_SPOT00_OBJECTS", "Spot00 Objects", "Spot00 Objects"), - ("OBJECT_MB", "Mb", "Mb"), - ("OBJECT_BOMBF", "Bombf", "Bombf"), - ("OBJECT_SK2", "Sk2", "Sk2"), - ("OBJECT_OE1", "Oe1", "Oe1"), - ("OBJECT_OE_ANIME", "Oe Anime", "Oe Anime"), - ("OBJECT_OE2", "Oe2", "Oe2"), - ("OBJECT_YDAN_OBJECTS", "Ydan Objects", "Ydan Objects"), - ("OBJECT_GND", "Gnd", "Gnd"), - ("OBJECT_AM", "Am", "Am"), - ("OBJECT_DEKUBABA", "Dekubaba", "Dekubaba"), - ("OBJECT_OA3", "Oa3", "Oa3"), - ("OBJECT_OA4", "Oa4", "Oa4"), - ("OBJECT_OA5", "Oa5", "Oa5"), - ("OBJECT_OA6", "Oa6", "Oa6"), - ("OBJECT_OA7", "Oa7", "Oa7"), - ("OBJECT_JJ", "Jj", "Jj"), - ("OBJECT_OA8", "Oa8", "Oa8"), - ("OBJECT_OA9", "Oa9", "Oa9"), - ("OBJECT_OB2", "Ob2", "Ob2"), - ("OBJECT_OB3", "Ob3", "Ob3"), - ("OBJECT_OB4", "Ob4", "Ob4"), - ("OBJECT_HORSE_ZELDA", "Horse Zelda", "Horse Zelda"), - ("OBJECT_OPENING_DEMO1", "Opening Demo1", "Opening Demo1"), - ("OBJECT_WARP1", "Warp1", "Warp1"), - ("OBJECT_B_HEART", "B Heart", "B Heart"), - ("OBJECT_DEKUNUTS", "Dekunuts", "Dekunuts"), - ("OBJECT_OE3", "Oe3", "Oe3"), - ("OBJECT_OE4", "Oe4", "Oe4"), - ("OBJECT_MENKURI_OBJECTS", "Menkuri Objects", "Menkuri Objects"), - ("OBJECT_OE5", "Oe5", "Oe5"), - ("OBJECT_OE6", "Oe6", "Oe6"), - ("OBJECT_OE7", "Oe7", "Oe7"), - ("OBJECT_OE8", "Oe8", "Oe8"), - ("OBJECT_OE9", "Oe9", "Oe9"), - ("OBJECT_OE10", "Oe10", "Oe10"), - ("OBJECT_OE11", "Oe11", "Oe11"), - ("OBJECT_OE12", "Oe12", "Oe12"), - ("OBJECT_VALI", "Vali", "Vali"), - ("OBJECT_OA10", "Oa10", "Oa10"), - ("OBJECT_OA11", "Oa11", "Oa11"), - ("OBJECT_MIZU_OBJECTS", "Mizu Objects", "Mizu Objects"), - ("OBJECT_FHG", "Fhg", "Fhg"), - ("OBJECT_OSSAN", "Ossan", "Ossan"), - ("OBJECT_MORI_HINERI1", "Mori Hineri1", "Mori Hineri1"), - ("OBJECT_BB", "Bb", "Bb"), - ("OBJECT_TOKI_OBJECTS", "Toki Objects", "Toki Objects"), - ("OBJECT_YUKABYUN", "Yukabyun", "Yukabyun"), - ("OBJECT_ZL2", "Zl2", "Zl2"), - ("OBJECT_MJIN", "Mjin", "Mjin"), - ("OBJECT_MJIN_FLASH", "Mjin Flash", "Mjin Flash"), - ("OBJECT_MJIN_DARK", "Mjin Dark", "Mjin Dark"), - ("OBJECT_MJIN_FLAME", "Mjin Flame", "Mjin Flame"), - ("OBJECT_MJIN_ICE", "Mjin Ice", "Mjin Ice"), - ("OBJECT_MJIN_SOUL", "Mjin Soul", "Mjin Soul"), - ("OBJECT_MJIN_WIND", "Mjin Wind", "Mjin Wind"), - ("OBJECT_MJIN_OKA", "Mjin Oka", "Mjin Oka"), - ("OBJECT_HAKA_OBJECTS", "Haka Objects", "Haka Objects"), - ("OBJECT_SPOT06_OBJECTS", "Spot06 Objects", "Spot06 Objects"), - ("OBJECT_ICE_OBJECTS", "Ice Objects", "Ice Objects"), - ("OBJECT_RELAY_OBJECTS", "Relay Objects", "Relay Objects"), - ("OBJECT_PO_FIELD", "Po Field", "Po Field"), - ("OBJECT_PO_COMPOSER", "Po Composer", "Po Composer"), - ("OBJECT_MORI_HINERI1A", "Mori Hineri1a", "Mori Hineri1a"), - ("OBJECT_MORI_HINERI2", "Mori Hineri2", "Mori Hineri2"), - ("OBJECT_MORI_HINERI2A", "Mori Hineri2a", "Mori Hineri2a"), - ("OBJECT_MORI_OBJECTS", "Mori Objects", "Mori Objects"), - ("OBJECT_MORI_TEX", "Mori Tex", "Mori Tex"), - ("OBJECT_SPOT08_OBJ", "Spot08 Obj", "Spot08 Obj"), - ("OBJECT_WARP2", "Warp2", "Warp2"), - ("OBJECT_HATA", "Hata", "Hata"), - ("OBJECT_BIRD", "Bird", "Bird"), - ("OBJECT_WOOD02", "Wood02", "Wood02"), - ("OBJECT_LIGHTBOX", "Lightbox", "Lightbox"), - ("OBJECT_PU_BOX", "Pu Box", "Pu Box"), - ("OBJECT_TRAP", "Trap", "Trap"), - ("OBJECT_VASE", "Vase", "Vase"), - ("OBJECT_IM", "Im", "Im"), - ("OBJECT_TA", "Ta", "Ta"), - ("OBJECT_TK", "Tk", "Tk"), - ("OBJECT_XC", "Xc", "Xc"), - ("OBJECT_VM", "Vm", "Vm"), - ("OBJECT_BV", "Bv", "Bv"), - ("OBJECT_HAKACH_OBJECTS", "Hakach Objects", "Hakach Objects"), - ("OBJECT_EFC_CRYSTAL_LIGHT", "Efc Crystal Light", "Efc Crystal Light"), - ("OBJECT_EFC_FIRE_BALL", "Efc Fire Ball", "Efc Fire Ball"), - ("OBJECT_EFC_FLASH", "Efc Flash", "Efc Flash"), - ("OBJECT_EFC_LGT_SHOWER", "Efc Lgt Shower", "Efc Lgt Shower"), - ("OBJECT_EFC_STAR_FIELD", "Efc Star Field", "Efc Star Field"), - ("OBJECT_GOD_LGT", "God Lgt", "God Lgt"), - ("OBJECT_LIGHT_RING", "Light Ring", "Light Ring"), - ("OBJECT_TRIFORCE_SPOT", "Triforce Spot", "Triforce Spot"), - ("OBJECT_BDAN_OBJECTS", "Bdan Objects", "Bdan Objects"), - ("OBJECT_SD", "Sd", "Sd"), - ("OBJECT_RD", "Rd", "Rd"), - ("OBJECT_PO_SISTERS", "Po Sisters", "Po Sisters"), - ("OBJECT_HEAVY_OBJECT", "Heavy Object", "Heavy Object"), - ("OBJECT_GNDD", "Gndd", "Gndd"), - ("OBJECT_FD", "Fd", "Fd"), - ("OBJECT_DU", "Du", "Du"), - ("OBJECT_FW", "Fw", "Fw"), - ("OBJECT_MEDAL", "Medal", "Medal"), - ("OBJECT_HORSE_LINK_CHILD", "Horse Link Child", "Horse Link Child"), - ("OBJECT_SPOT02_OBJECTS", "Spot02 Objects", "Spot02 Objects"), - ("OBJECT_HAKA", "Haka", "Haka"), - ("OBJECT_RU1", "Ru1", "Ru1"), - ("OBJECT_SYOKUDAI", "Syokudai", "Syokudai"), - ("OBJECT_FD2", "Fd2", "Fd2"), - ("OBJECT_DH", "Dh", "Dh"), - ("OBJECT_RL", "Rl", "Rl"), - ("OBJECT_EFC_TW", "Efc Tw", "Efc Tw"), - ("OBJECT_DEMO_TRE_LGT", "Demo Tre Lgt", "Demo Tre Lgt"), - ("OBJECT_GI_KEY", "Gi Key", "Gi Key"), - ("OBJECT_MIR_RAY", "Mir Ray", "Mir Ray"), - ("OBJECT_BROB", "Brob", "Brob"), - ("OBJECT_GI_JEWEL", "Gi Jewel", "Gi Jewel"), - ("OBJECT_SPOT09_OBJ", "Spot09 Obj", "Spot09 Obj"), - ("OBJECT_SPOT18_OBJ", "Spot18 Obj", "Spot18 Obj"), - ("OBJECT_BDOOR", "Bdoor", "Bdoor"), - ("OBJECT_SPOT17_OBJ", "Spot17 Obj", "Spot17 Obj"), - ("OBJECT_SHOP_DUNGEN", "Shop Dungen", "Shop Dungen"), - ("OBJECT_NB", "Nb", "Nb"), - ("OBJECT_MO", "Mo", "Mo"), - ("OBJECT_SB", "Sb", "Sb"), - ("OBJECT_GI_MELODY", "Gi Melody", "Gi Melody"), - ("OBJECT_GI_HEART", "Gi Heart", "Gi Heart"), - ("OBJECT_GI_COMPASS", "Gi Compass", "Gi Compass"), - ("OBJECT_GI_BOSSKEY", "Gi Bosskey", "Gi Bosskey"), - ("OBJECT_GI_MEDAL", "Gi Medal", "Gi Medal"), - ("OBJECT_GI_NUTS", "Gi Nuts", "Gi Nuts"), - ("OBJECT_SA", "Sa", "Sa"), - ("OBJECT_GI_HEARTS", "Gi Hearts", "Gi Hearts"), - ("OBJECT_GI_ARROWCASE", "Gi Arrowcase", "Gi Arrowcase"), - ("OBJECT_GI_BOMBPOUCH", "Gi Bombpouch", "Gi Bombpouch"), - ("OBJECT_IN", "In", "In"), - ("OBJECT_TR", "Tr", "Tr"), - ("OBJECT_SPOT16_OBJ", "Spot16 Obj", "Spot16 Obj"), - ("OBJECT_OE1S", "Oe1s", "Oe1s"), - ("OBJECT_OE4S", "Oe4s", "Oe4s"), - ("OBJECT_OS_ANIME", "Os Anime", "Os Anime"), - ("OBJECT_GI_BOTTLE", "Gi Bottle", "Gi Bottle"), - ("OBJECT_GI_STICK", "Gi Stick", "Gi Stick"), - ("OBJECT_GI_MAP", "Gi Map", "Gi Map"), - ("OBJECT_OF1D_MAP", "Of1d Map", "Of1d Map"), - ("OBJECT_RU2", "Ru2", "Ru2"), - ("OBJECT_GI_SHIELD_1", "Gi Shield 1", "Gi Shield 1"), - ("OBJECT_DEKUJR", "Dekujr", "Dekujr"), - ("OBJECT_GI_MAGICPOT", "Gi Magicpot", "Gi Magicpot"), - ("OBJECT_GI_BOMB_1", "Gi Bomb 1", "Gi Bomb 1"), - ("OBJECT_OF1S", "Of1s", "Of1s"), - ("OBJECT_MA2", "Ma2", "Ma2"), - ("OBJECT_GI_PURSE", "Gi Purse", "Gi Purse"), - ("OBJECT_HNI", "Hni", "Hni"), - ("OBJECT_TW", "Tw", "Tw"), - ("OBJECT_RR", "Rr", "Rr"), - ("OBJECT_BXA", "Bxa", "Bxa"), - ("OBJECT_ANUBICE", "Anubice", "Anubice"), - ("OBJECT_GI_GERUDO", "Gi Gerudo", "Gi Gerudo"), - ("OBJECT_GI_ARROW", "Gi Arrow", "Gi Arrow"), - ("OBJECT_GI_BOMB_2", "Gi Bomb 2", "Gi Bomb 2"), - ("OBJECT_GI_EGG", "Gi Egg", "Gi Egg"), - ("OBJECT_GI_SCALE", "Gi Scale", "Gi Scale"), - ("OBJECT_GI_SHIELD_2", "Gi Shield 2", "Gi Shield 2"), - ("OBJECT_GI_HOOKSHOT", "Gi Hookshot", "Gi Hookshot"), - ("OBJECT_GI_OCARINA", "Gi Ocarina", "Gi Ocarina"), - ("OBJECT_GI_MILK", "Gi Milk", "Gi Milk"), - ("OBJECT_MA1", "Ma1", "Ma1"), - ("OBJECT_GANON", "Ganon", "Ganon"), - ("OBJECT_SST", "Sst", "Sst"), - ("OBJECT_NY_UNUSED", "Ny Unused", "Ny Unused"), - ("OBJECT_NY", "Ny", "Ny"), - ("OBJECT_FR", "Fr", "Fr"), - ("OBJECT_GI_PACHINKO", "Gi Pachinko", "Gi Pachinko"), - ("OBJECT_GI_BOOMERANG", "Gi Boomerang", "Gi Boomerang"), - ("OBJECT_GI_BOW", "Gi Bow", "Gi Bow"), - ("OBJECT_GI_GLASSES", "Gi Glasses", "Gi Glasses"), - ("OBJECT_GI_LIQUID", "Gi Liquid", "Gi Liquid"), - ("OBJECT_ANI", "Ani", "Ani"), - ("OBJECT_DEMO_6K", "Demo 6k", "Demo 6k"), - ("OBJECT_GI_SHIELD_3", "Gi Shield 3", "Gi Shield 3"), - ("OBJECT_GI_LETTER", "Gi Letter", "Gi Letter"), - ("OBJECT_SPOT15_OBJ", "Spot15 Obj", "Spot15 Obj"), - ("OBJECT_JYA_OBJ", "Jya Obj", "Jya Obj"), - ("OBJECT_GI_CLOTHES", "Gi Clothes", "Gi Clothes"), - ("OBJECT_GI_BEAN", "Gi Bean", "Gi Bean"), - ("OBJECT_GI_FISH", "Gi Fish", "Gi Fish"), - ("OBJECT_GI_SAW", "Gi Saw", "Gi Saw"), - ("OBJECT_GI_HAMMER", "Gi Hammer", "Gi Hammer"), - ("OBJECT_GI_GRASS", "Gi Grass", "Gi Grass"), - ("OBJECT_GI_LONGSWORD", "Gi Longsword", "Gi Longsword"), - ("OBJECT_SPOT01_OBJECTS", "Spot01 Objects", "Spot01 Objects"), - ("OBJECT_MD_UNUSED", "Md Unused", "Md Unused"), - ("OBJECT_MD", "Md", "Md"), - ("OBJECT_KM1", "Km1", "Km1"), - ("OBJECT_KW1", "Kw1", "Kw1"), - ("OBJECT_ZO", "Zo", "Zo"), - ("OBJECT_KZ", "Kz", "Kz"), - ("OBJECT_UMAJUMP", "Umajump", "Umajump"), - ("OBJECT_MASTERKOKIRI", "Masterkokiri", "Masterkokiri"), - ("OBJECT_MASTERKOKIRIHEAD", "Masterkokirihead", "Masterkokirihead"), - ("OBJECT_MASTERGOLON", "Mastergolon", "Mastergolon"), - ("OBJECT_MASTERZOORA", "Masterzoora", "Masterzoora"), - ("OBJECT_AOB", "Aob", "Aob"), - ("OBJECT_IK", "Ik", "Ik"), - ("OBJECT_AHG", "Ahg", "Ahg"), - ("OBJECT_CNE", "Cne", "Cne"), - ("OBJECT_GI_NIWATORI", "Gi Niwatori", "Gi Niwatori"), - ("OBJECT_SKJ", "Skj", "Skj"), - ("OBJECT_GI_BOTTLE_LETTER", "Gi Bottle Letter", "Gi Bottle Letter"), - ("OBJECT_BJI", "Bji", "Bji"), - ("OBJECT_BBA", "Bba", "Bba"), - ("OBJECT_GI_OCARINA_0", "Gi Ocarina 0", "Gi Ocarina 0"), - ("OBJECT_DS", "Ds", "Ds"), - ("OBJECT_ANE", "Ane", "Ane"), - ("OBJECT_BOJ", "Boj", "Boj"), - ("OBJECT_SPOT03_OBJECT", "Spot03 Object", "Spot03 Object"), - ("OBJECT_SPOT07_OBJECT", "Spot07 Object", "Spot07 Object"), - ("OBJECT_FZ", "Fz", "Fz"), - ("OBJECT_BOB", "Bob", "Bob"), - ("OBJECT_GE1", "Ge1", "Ge1"), - ("OBJECT_YABUSAME_POINT", "Yabusame Point", "Yabusame Point"), - ("OBJECT_GI_BOOTS_2", "Gi Boots 2", "Gi Boots 2"), - ("OBJECT_GI_SEED", "Gi Seed", "Gi Seed"), - ("OBJECT_GND_MAGIC", "Gnd Magic", "Gnd Magic"), - ("OBJECT_D_ELEVATOR", "D Elevator", "D Elevator"), - ("OBJECT_D_HSBLOCK", "D Hsblock", "D Hsblock"), - ("OBJECT_D_LIFT", "D Lift", "D Lift"), - ("OBJECT_MAMENOKI", "Mamenoki", "Mamenoki"), - ("OBJECT_GOROIWA", "Goroiwa", "Goroiwa"), - ("OBJECT_TORYO", "Toryo", "Toryo"), - ("OBJECT_DAIKU", "Daiku", "Daiku"), - ("OBJECT_NWC", "Nwc", "Nwc"), - ("OBJECT_BLKOBJ", "Blkobj", "Blkobj"), - ("OBJECT_GM", "Gm", "Gm"), - ("OBJECT_MS", "Ms", "Ms"), - ("OBJECT_HS", "Hs", "Hs"), - ("OBJECT_INGATE", "Ingate", "Ingate"), - ("OBJECT_LIGHTSWITCH", "Lightswitch", "Lightswitch"), - ("OBJECT_KUSA", "Kusa", "Kusa"), - ("OBJECT_TSUBO", "Tsubo", "Tsubo"), - ("OBJECT_GI_GLOVES", "Gi Gloves", "Gi Gloves"), - ("OBJECT_GI_COIN", "Gi Coin", "Gi Coin"), - ("OBJECT_KANBAN", "Kanban", "Kanban"), - ("OBJECT_GJYO_OBJECTS", "Gjyo Objects", "Gjyo Objects"), - ("OBJECT_OWL", "Owl", "Owl"), - ("OBJECT_MK", "Mk", "Mk"), - ("OBJECT_FU", "Fu", "Fu"), - ("OBJECT_GI_KI_TAN_MASK", "Gi Ki Tan Mask", "Gi Ki Tan Mask"), - ("OBJECT_GI_REDEAD_MASK", "Gi Redead Mask", "Gi Redead Mask"), - ("OBJECT_GI_SKJ_MASK", "Gi Skj Mask", "Gi Skj Mask"), - ("OBJECT_GI_RABIT_MASK", "Gi Rabit Mask", "Gi Rabit Mask"), - ("OBJECT_GI_TRUTH_MASK", "Gi Truth Mask", "Gi Truth Mask"), - ("OBJECT_GANON_OBJECTS", "Ganon Objects", "Ganon Objects"), - ("OBJECT_SIOFUKI", "Siofuki", "Siofuki"), - ("OBJECT_STREAM", "Stream", "Stream"), - ("OBJECT_MM", "Mm", "Mm"), - ("OBJECT_FA", "Fa", "Fa"), - ("OBJECT_OS", "Os", "Os"), - ("OBJECT_GI_EYE_LOTION", "Gi Eye Lotion", "Gi Eye Lotion"), - ("OBJECT_GI_POWDER", "Gi Powder", "Gi Powder"), - ("OBJECT_GI_MUSHROOM", "Gi Mushroom", "Gi Mushroom"), - ("OBJECT_GI_TICKETSTONE", "Gi Ticketstone", "Gi Ticketstone"), - ("OBJECT_GI_BROKENSWORD", "Gi Brokensword", "Gi Brokensword"), - ("OBJECT_JS", "Js", "Js"), - ("OBJECT_CS", "Cs", "Cs"), - ("OBJECT_GI_PRESCRIPTION", "Gi Prescription", "Gi Prescription"), - ("OBJECT_GI_BRACELET", "Gi Bracelet", "Gi Bracelet"), - ("OBJECT_GI_SOLDOUT", "Gi Soldout", "Gi Soldout"), - ("OBJECT_GI_FROG", "Gi Frog", "Gi Frog"), - ("OBJECT_MAG", "Mag", "Mag"), - ("OBJECT_DOOR_GERUDO", "Door Gerudo", "Door Gerudo"), - ("OBJECT_GT", "Gt", "Gt"), - ("OBJECT_EFC_ERUPC", "Efc Erupc", "Efc Erupc"), - ("OBJECT_ZL2_ANIME1", "Zl2 Anime1", "Zl2 Anime1"), - ("OBJECT_ZL2_ANIME2", "Zl2 Anime2", "Zl2 Anime2"), - ("OBJECT_GI_GOLONMASK", "Gi Golonmask", "Gi Golonmask"), - ("OBJECT_GI_ZORAMASK", "Gi Zoramask", "Gi Zoramask"), - ("OBJECT_GI_GERUDOMASK", "Gi Gerudomask", "Gi Gerudomask"), - ("OBJECT_GANON2", "Ganon2", "Ganon2"), - ("OBJECT_KA", "Ka", "Ka"), - ("OBJECT_TS", "Ts", "Ts"), - ("OBJECT_ZG", "Zg", "Zg"), - ("OBJECT_GI_HOVERBOOTS", "Gi Hoverboots", "Gi Hoverboots"), - ("OBJECT_GI_M_ARROW", "Gi M Arrow", "Gi M Arrow"), - ("OBJECT_DS2", "Ds2", "Ds2"), - ("OBJECT_EC", "Ec", "Ec"), - ("OBJECT_FISH", "Fish", "Fish"), - ("OBJECT_GI_SUTARU", "Gi Sutaru", "Gi Sutaru"), - ("OBJECT_GI_GODDESS", "Gi Goddess", "Gi Goddess"), - ("OBJECT_SSH", "Ssh", "Ssh"), - ("OBJECT_BIGOKUTA", "Bigokuta", "Bigokuta"), - ("OBJECT_BG", "Bg", "Bg"), - ("OBJECT_SPOT05_OBJECTS", "Spot05 Objects", "Spot05 Objects"), - ("OBJECT_SPOT12_OBJ", "Spot12 Obj", "Spot12 Obj"), - ("OBJECT_BOMBIWA", "Bombiwa", "Bombiwa"), - ("OBJECT_HINTNUTS", "Hintnuts", "Hintnuts"), - ("OBJECT_RS", "Rs", "Rs"), - ("OBJECT_SPOT00_BREAK", "Spot00 Break", "Spot00 Break"), - ("OBJECT_GLA", "Gla", "Gla"), - ("OBJECT_SHOPNUTS", "Shopnuts", "Shopnuts"), - ("OBJECT_GELDB", "Geldb", "Geldb"), - ("OBJECT_GR", "Gr", "Gr"), - ("OBJECT_DOG", "Dog", "Dog"), - ("OBJECT_JYA_IRON", "Jya Iron", "Jya Iron"), - ("OBJECT_JYA_DOOR", "Jya Door", "Jya Door"), - ("OBJECT_SPOT11_OBJ", "Spot11 Obj", "Spot11 Obj"), - ("OBJECT_KIBAKO2", "Kibako2", "Kibako2"), - ("OBJECT_DNS", "Dns", "Dns"), - ("OBJECT_DNK", "Dnk", "Dnk"), - ("OBJECT_GI_FIRE", "Gi Fire", "Gi Fire"), - ("OBJECT_GI_INSECT", "Gi Insect", "Gi Insect"), - ("OBJECT_GI_BUTTERFLY", "Gi Butterfly", "Gi Butterfly"), - ("OBJECT_GI_GHOST", "Gi Ghost", "Gi Ghost"), - ("OBJECT_GI_SOUL", "Gi Soul", "Gi Soul"), - ("OBJECT_BOWL", "Bowl", "Bowl"), - ("OBJECT_DEMO_KEKKAI", "Demo Kekkai", "Demo Kekkai"), - ("OBJECT_EFC_DOUGHNUT", "Efc Doughnut", "Efc Doughnut"), - ("OBJECT_GI_DEKUPOUCH", "Gi Dekupouch", "Gi Dekupouch"), - ("OBJECT_GANON_ANIME1", "Ganon Anime1", "Ganon Anime1"), - ("OBJECT_GANON_ANIME2", "Ganon Anime2", "Ganon Anime2"), - ("OBJECT_GANON_ANIME3", "Ganon Anime3", "Ganon Anime3"), - ("OBJECT_GI_RUPY", "Gi Rupy", "Gi Rupy"), - ("OBJECT_SPOT01_MATOYA", "Spot01 Matoya", "Spot01 Matoya"), - ("OBJECT_SPOT01_MATOYAB", "Spot01 Matoyab", "Spot01 Matoyab"), - ("OBJECT_MU", "Mu", "Mu"), - ("OBJECT_WF", "Wf", "Wf"), - ("OBJECT_SKB", "Skb", "Skb"), - ("OBJECT_GJ", "Gj", "Gj"), - ("OBJECT_GEFF", "Geff", "Geff"), - ("OBJECT_HAKA_DOOR", "Haka Door", "Haka Door"), - ("OBJECT_GS", "Gs", "Gs"), - ("OBJECT_PS", "Ps", "Ps"), - ("OBJECT_BWALL", "Bwall", "Bwall"), - ("OBJECT_COW", "Cow", "Cow"), - ("OBJECT_COB", "Cob", "Cob"), - ("OBJECT_GI_SWORD_1", "Gi Sword 1", "Gi Sword 1"), - ("OBJECT_DOOR_KILLER", "Door Killer", "Door Killer"), - ("OBJECT_OUKE_HAKA", "Ouke Haka", "Ouke Haka"), - ("OBJECT_TIMEBLOCK", "Timeblock", "Timeblock"), + ("Custom", "Custom", "Custom"), + ("OBJECT_HUMAN", "Human", "Human"), + ("OBJECT_OKUTA", "Okuta", "Okuta"), + ("OBJECT_CROW", "Crow", "Crow"), + ("OBJECT_POH", "Poh", "Poh"), + ("OBJECT_DY_OBJ", "Dy Obj", "Dy Obj"), + ("OBJECT_WALLMASTER", "Wallmaster", "Wallmaster"), + ("OBJECT_DODONGO", "Dodongo", "Dodongo"), + ("OBJECT_FIREFLY", "Firefly", "Firefly"), + ("OBJECT_BOX", "Box", "Box"), + ("OBJECT_FIRE", "Fire", "Fire"), + ("OBJECT_BUBBLE", "Bubble", "Bubble"), + ("OBJECT_NIW", "Niw", "Niw"), + ("OBJECT_TITE", "Tite", "Tite"), + ("OBJECT_REEBA", "Reeba", "Reeba"), + ("OBJECT_PEEHAT", "Peehat", "Peehat"), + ("OBJECT_KINGDODONGO", "Kingdodongo", "Kingdodongo"), + ("OBJECT_HORSE", "Horse", "Horse"), + ("OBJECT_ZF", "Zf", "Zf"), + ("OBJECT_GOMA", "Goma", "Goma"), + ("OBJECT_ZL1", "Zl1", "Zl1"), + ("OBJECT_GOL", "Gol", "Gol"), + ("OBJECT_DODOJR", "Dodojr", "Dodojr"), + ("OBJECT_TORCH2", "Torch2", "Torch2"), + ("OBJECT_BL", "Bl", "Bl"), + ("OBJECT_TP", "Tp", "Tp"), + ("OBJECT_OA1", "Oa1", "Oa1"), + ("OBJECT_ST", "St", "St"), + ("OBJECT_BW", "Bw", "Bw"), + ("OBJECT_EI", "Ei", "Ei"), + ("OBJECT_HORSE_NORMAL", "Horse Normal", "Horse Normal"), + ("OBJECT_OB1", "Ob1", "Ob1"), + ("OBJECT_O_ANIME", "O Anime", "O Anime"), + ("OBJECT_SPOT04_OBJECTS", "Spot04 Objects", "Spot04 Objects"), + ("OBJECT_DDAN_OBJECTS", "Ddan Objects", "Ddan Objects"), + ("OBJECT_HIDAN_OBJECTS", "Hidan Objects", "Hidan Objects"), + ("OBJECT_HORSE_GANON", "Horse Ganon", "Horse Ganon"), + ("OBJECT_OA2", "Oa2", "Oa2"), + ("OBJECT_SPOT00_OBJECTS", "Spot00 Objects", "Spot00 Objects"), + ("OBJECT_MB", "Mb", "Mb"), + ("OBJECT_BOMBF", "Bombf", "Bombf"), + ("OBJECT_SK2", "Sk2", "Sk2"), + ("OBJECT_OE1", "Oe1", "Oe1"), + ("OBJECT_OE_ANIME", "Oe Anime", "Oe Anime"), + ("OBJECT_OE2", "Oe2", "Oe2"), + ("OBJECT_YDAN_OBJECTS", "Ydan Objects", "Ydan Objects"), + ("OBJECT_GND", "Gnd", "Gnd"), + ("OBJECT_AM", "Am", "Am"), + ("OBJECT_DEKUBABA", "Dekubaba", "Dekubaba"), + ("OBJECT_OA3", "Oa3", "Oa3"), + ("OBJECT_OA4", "Oa4", "Oa4"), + ("OBJECT_OA5", "Oa5", "Oa5"), + ("OBJECT_OA6", "Oa6", "Oa6"), + ("OBJECT_OA7", "Oa7", "Oa7"), + ("OBJECT_JJ", "Jj", "Jj"), + ("OBJECT_OA8", "Oa8", "Oa8"), + ("OBJECT_OA9", "Oa9", "Oa9"), + ("OBJECT_OB2", "Ob2", "Ob2"), + ("OBJECT_OB3", "Ob3", "Ob3"), + ("OBJECT_OB4", "Ob4", "Ob4"), + ("OBJECT_HORSE_ZELDA", "Horse Zelda", "Horse Zelda"), + ("OBJECT_OPENING_DEMO1", "Opening Demo1", "Opening Demo1"), + ("OBJECT_WARP1", "Warp1", "Warp1"), + ("OBJECT_B_HEART", "B Heart", "B Heart"), + ("OBJECT_DEKUNUTS", "Dekunuts", "Dekunuts"), + ("OBJECT_OE3", "Oe3", "Oe3"), + ("OBJECT_OE4", "Oe4", "Oe4"), + ("OBJECT_MENKURI_OBJECTS", "Menkuri Objects", "Menkuri Objects"), + ("OBJECT_OE5", "Oe5", "Oe5"), + ("OBJECT_OE6", "Oe6", "Oe6"), + ("OBJECT_OE7", "Oe7", "Oe7"), + ("OBJECT_OE8", "Oe8", "Oe8"), + ("OBJECT_OE9", "Oe9", "Oe9"), + ("OBJECT_OE10", "Oe10", "Oe10"), + ("OBJECT_OE11", "Oe11", "Oe11"), + ("OBJECT_OE12", "Oe12", "Oe12"), + ("OBJECT_VALI", "Vali", "Vali"), + ("OBJECT_OA10", "Oa10", "Oa10"), + ("OBJECT_OA11", "Oa11", "Oa11"), + ("OBJECT_MIZU_OBJECTS", "Mizu Objects", "Mizu Objects"), + ("OBJECT_FHG", "Fhg", "Fhg"), + ("OBJECT_OSSAN", "Ossan", "Ossan"), + ("OBJECT_MORI_HINERI1", "Mori Hineri1", "Mori Hineri1"), + ("OBJECT_BB", "Bb", "Bb"), + ("OBJECT_TOKI_OBJECTS", "Toki Objects", "Toki Objects"), + ("OBJECT_YUKABYUN", "Yukabyun", "Yukabyun"), + ("OBJECT_ZL2", "Zl2", "Zl2"), + ("OBJECT_MJIN", "Mjin", "Mjin"), + ("OBJECT_MJIN_FLASH", "Mjin Flash", "Mjin Flash"), + ("OBJECT_MJIN_DARK", "Mjin Dark", "Mjin Dark"), + ("OBJECT_MJIN_FLAME", "Mjin Flame", "Mjin Flame"), + ("OBJECT_MJIN_ICE", "Mjin Ice", "Mjin Ice"), + ("OBJECT_MJIN_SOUL", "Mjin Soul", "Mjin Soul"), + ("OBJECT_MJIN_WIND", "Mjin Wind", "Mjin Wind"), + ("OBJECT_MJIN_OKA", "Mjin Oka", "Mjin Oka"), + ("OBJECT_HAKA_OBJECTS", "Haka Objects", "Haka Objects"), + ("OBJECT_SPOT06_OBJECTS", "Spot06 Objects", "Spot06 Objects"), + ("OBJECT_ICE_OBJECTS", "Ice Objects", "Ice Objects"), + ("OBJECT_RELAY_OBJECTS", "Relay Objects", "Relay Objects"), + ("OBJECT_PO_FIELD", "Po Field", "Po Field"), + ("OBJECT_PO_COMPOSER", "Po Composer", "Po Composer"), + ("OBJECT_MORI_HINERI1A", "Mori Hineri1a", "Mori Hineri1a"), + ("OBJECT_MORI_HINERI2", "Mori Hineri2", "Mori Hineri2"), + ("OBJECT_MORI_HINERI2A", "Mori Hineri2a", "Mori Hineri2a"), + ("OBJECT_MORI_OBJECTS", "Mori Objects", "Mori Objects"), + ("OBJECT_MORI_TEX", "Mori Tex", "Mori Tex"), + ("OBJECT_SPOT08_OBJ", "Spot08 Obj", "Spot08 Obj"), + ("OBJECT_WARP2", "Warp2", "Warp2"), + ("OBJECT_HATA", "Hata", "Hata"), + ("OBJECT_BIRD", "Bird", "Bird"), + ("OBJECT_WOOD02", "Wood02", "Wood02"), + ("OBJECT_LIGHTBOX", "Lightbox", "Lightbox"), + ("OBJECT_PU_BOX", "Pu Box", "Pu Box"), + ("OBJECT_TRAP", "Trap", "Trap"), + ("OBJECT_VASE", "Vase", "Vase"), + ("OBJECT_IM", "Im", "Im"), + ("OBJECT_TA", "Ta", "Ta"), + ("OBJECT_TK", "Tk", "Tk"), + ("OBJECT_XC", "Xc", "Xc"), + ("OBJECT_VM", "Vm", "Vm"), + ("OBJECT_BV", "Bv", "Bv"), + ("OBJECT_HAKACH_OBJECTS", "Hakach Objects", "Hakach Objects"), + ("OBJECT_EFC_CRYSTAL_LIGHT", "Efc Crystal Light", "Efc Crystal Light"), + ("OBJECT_EFC_FIRE_BALL", "Efc Fire Ball", "Efc Fire Ball"), + ("OBJECT_EFC_FLASH", "Efc Flash", "Efc Flash"), + ("OBJECT_EFC_LGT_SHOWER", "Efc Lgt Shower", "Efc Lgt Shower"), + ("OBJECT_EFC_STAR_FIELD", "Efc Star Field", "Efc Star Field"), + ("OBJECT_GOD_LGT", "God Lgt", "God Lgt"), + ("OBJECT_LIGHT_RING", "Light Ring", "Light Ring"), + ("OBJECT_TRIFORCE_SPOT", "Triforce Spot", "Triforce Spot"), + ("OBJECT_BDAN_OBJECTS", "Bdan Objects", "Bdan Objects"), + ("OBJECT_SD", "Sd", "Sd"), + ("OBJECT_RD", "Rd", "Rd"), + ("OBJECT_PO_SISTERS", "Po Sisters", "Po Sisters"), + ("OBJECT_HEAVY_OBJECT", "Heavy Object", "Heavy Object"), + ("OBJECT_GNDD", "Gndd", "Gndd"), + ("OBJECT_FD", "Fd", "Fd"), + ("OBJECT_DU", "Du", "Du"), + ("OBJECT_FW", "Fw", "Fw"), + ("OBJECT_MEDAL", "Medal", "Medal"), + ("OBJECT_HORSE_LINK_CHILD", "Horse Link Child", "Horse Link Child"), + ("OBJECT_SPOT02_OBJECTS", "Spot02 Objects", "Spot02 Objects"), + ("OBJECT_HAKA", "Haka", "Haka"), + ("OBJECT_RU1", "Ru1", "Ru1"), + ("OBJECT_SYOKUDAI", "Syokudai", "Syokudai"), + ("OBJECT_FD2", "Fd2", "Fd2"), + ("OBJECT_DH", "Dh", "Dh"), + ("OBJECT_RL", "Rl", "Rl"), + ("OBJECT_EFC_TW", "Efc Tw", "Efc Tw"), + ("OBJECT_DEMO_TRE_LGT", "Demo Tre Lgt", "Demo Tre Lgt"), + ("OBJECT_GI_KEY", "Gi Key", "Gi Key"), + ("OBJECT_MIR_RAY", "Mir Ray", "Mir Ray"), + ("OBJECT_BROB", "Brob", "Brob"), + ("OBJECT_GI_JEWEL", "Gi Jewel", "Gi Jewel"), + ("OBJECT_SPOT09_OBJ", "Spot09 Obj", "Spot09 Obj"), + ("OBJECT_SPOT18_OBJ", "Spot18 Obj", "Spot18 Obj"), + ("OBJECT_BDOOR", "Bdoor", "Bdoor"), + ("OBJECT_SPOT17_OBJ", "Spot17 Obj", "Spot17 Obj"), + ("OBJECT_SHOP_DUNGEN", "Shop Dungen", "Shop Dungen"), + ("OBJECT_NB", "Nb", "Nb"), + ("OBJECT_MO", "Mo", "Mo"), + ("OBJECT_SB", "Sb", "Sb"), + ("OBJECT_GI_MELODY", "Gi Melody", "Gi Melody"), + ("OBJECT_GI_HEART", "Gi Heart", "Gi Heart"), + ("OBJECT_GI_COMPASS", "Gi Compass", "Gi Compass"), + ("OBJECT_GI_BOSSKEY", "Gi Bosskey", "Gi Bosskey"), + ("OBJECT_GI_MEDAL", "Gi Medal", "Gi Medal"), + ("OBJECT_GI_NUTS", "Gi Nuts", "Gi Nuts"), + ("OBJECT_SA", "Sa", "Sa"), + ("OBJECT_GI_HEARTS", "Gi Hearts", "Gi Hearts"), + ("OBJECT_GI_ARROWCASE", "Gi Arrowcase", "Gi Arrowcase"), + ("OBJECT_GI_BOMBPOUCH", "Gi Bombpouch", "Gi Bombpouch"), + ("OBJECT_IN", "In", "In"), + ("OBJECT_TR", "Tr", "Tr"), + ("OBJECT_SPOT16_OBJ", "Spot16 Obj", "Spot16 Obj"), + ("OBJECT_OE1S", "Oe1s", "Oe1s"), + ("OBJECT_OE4S", "Oe4s", "Oe4s"), + ("OBJECT_OS_ANIME", "Os Anime", "Os Anime"), + ("OBJECT_GI_BOTTLE", "Gi Bottle", "Gi Bottle"), + ("OBJECT_GI_STICK", "Gi Stick", "Gi Stick"), + ("OBJECT_GI_MAP", "Gi Map", "Gi Map"), + ("OBJECT_OF1D_MAP", "Of1d Map", "Of1d Map"), + ("OBJECT_RU2", "Ru2", "Ru2"), + ("OBJECT_GI_SHIELD_1", "Gi Shield 1", "Gi Shield 1"), + ("OBJECT_DEKUJR", "Dekujr", "Dekujr"), + ("OBJECT_GI_MAGICPOT", "Gi Magicpot", "Gi Magicpot"), + ("OBJECT_GI_BOMB_1", "Gi Bomb 1", "Gi Bomb 1"), + ("OBJECT_OF1S", "Of1s", "Of1s"), + ("OBJECT_MA2", "Ma2", "Ma2"), + ("OBJECT_GI_PURSE", "Gi Purse", "Gi Purse"), + ("OBJECT_HNI", "Hni", "Hni"), + ("OBJECT_TW", "Tw", "Tw"), + ("OBJECT_RR", "Rr", "Rr"), + ("OBJECT_BXA", "Bxa", "Bxa"), + ("OBJECT_ANUBICE", "Anubice", "Anubice"), + ("OBJECT_GI_GERUDO", "Gi Gerudo", "Gi Gerudo"), + ("OBJECT_GI_ARROW", "Gi Arrow", "Gi Arrow"), + ("OBJECT_GI_BOMB_2", "Gi Bomb 2", "Gi Bomb 2"), + ("OBJECT_GI_EGG", "Gi Egg", "Gi Egg"), + ("OBJECT_GI_SCALE", "Gi Scale", "Gi Scale"), + ("OBJECT_GI_SHIELD_2", "Gi Shield 2", "Gi Shield 2"), + ("OBJECT_GI_HOOKSHOT", "Gi Hookshot", "Gi Hookshot"), + ("OBJECT_GI_OCARINA", "Gi Ocarina", "Gi Ocarina"), + ("OBJECT_GI_MILK", "Gi Milk", "Gi Milk"), + ("OBJECT_MA1", "Ma1", "Ma1"), + ("OBJECT_GANON", "Ganon", "Ganon"), + ("OBJECT_SST", "Sst", "Sst"), + ("OBJECT_NY_UNUSED", "Ny Unused", "Ny Unused"), + ("OBJECT_NY", "Ny", "Ny"), + ("OBJECT_FR", "Fr", "Fr"), + ("OBJECT_GI_PACHINKO", "Gi Pachinko", "Gi Pachinko"), + ("OBJECT_GI_BOOMERANG", "Gi Boomerang", "Gi Boomerang"), + ("OBJECT_GI_BOW", "Gi Bow", "Gi Bow"), + ("OBJECT_GI_GLASSES", "Gi Glasses", "Gi Glasses"), + ("OBJECT_GI_LIQUID", "Gi Liquid", "Gi Liquid"), + ("OBJECT_ANI", "Ani", "Ani"), + ("OBJECT_DEMO_6K", "Demo 6k", "Demo 6k"), + ("OBJECT_GI_SHIELD_3", "Gi Shield 3", "Gi Shield 3"), + ("OBJECT_GI_LETTER", "Gi Letter", "Gi Letter"), + ("OBJECT_SPOT15_OBJ", "Spot15 Obj", "Spot15 Obj"), + ("OBJECT_JYA_OBJ", "Jya Obj", "Jya Obj"), + ("OBJECT_GI_CLOTHES", "Gi Clothes", "Gi Clothes"), + ("OBJECT_GI_BEAN", "Gi Bean", "Gi Bean"), + ("OBJECT_GI_FISH", "Gi Fish", "Gi Fish"), + ("OBJECT_GI_SAW", "Gi Saw", "Gi Saw"), + ("OBJECT_GI_HAMMER", "Gi Hammer", "Gi Hammer"), + ("OBJECT_GI_GRASS", "Gi Grass", "Gi Grass"), + ("OBJECT_GI_LONGSWORD", "Gi Longsword", "Gi Longsword"), + ("OBJECT_SPOT01_OBJECTS", "Spot01 Objects", "Spot01 Objects"), + ("OBJECT_MD_UNUSED", "Md Unused", "Md Unused"), + ("OBJECT_MD", "Md", "Md"), + ("OBJECT_KM1", "Km1", "Km1"), + ("OBJECT_KW1", "Kw1", "Kw1"), + ("OBJECT_ZO", "Zo", "Zo"), + ("OBJECT_KZ", "Kz", "Kz"), + ("OBJECT_UMAJUMP", "Umajump", "Umajump"), + ("OBJECT_MASTERKOKIRI", "Masterkokiri", "Masterkokiri"), + ("OBJECT_MASTERKOKIRIHEAD", "Masterkokirihead", "Masterkokirihead"), + ("OBJECT_MASTERGOLON", "Mastergolon", "Mastergolon"), + ("OBJECT_MASTERZOORA", "Masterzoora", "Masterzoora"), + ("OBJECT_AOB", "Aob", "Aob"), + ("OBJECT_IK", "Ik", "Ik"), + ("OBJECT_AHG", "Ahg", "Ahg"), + ("OBJECT_CNE", "Cne", "Cne"), + ("OBJECT_GI_NIWATORI", "Gi Niwatori", "Gi Niwatori"), + ("OBJECT_SKJ", "Skj", "Skj"), + ("OBJECT_GI_BOTTLE_LETTER", "Gi Bottle Letter", "Gi Bottle Letter"), + ("OBJECT_BJI", "Bji", "Bji"), + ("OBJECT_BBA", "Bba", "Bba"), + ("OBJECT_GI_OCARINA_0", "Gi Ocarina 0", "Gi Ocarina 0"), + ("OBJECT_DS", "Ds", "Ds"), + ("OBJECT_ANE", "Ane", "Ane"), + ("OBJECT_BOJ", "Boj", "Boj"), + ("OBJECT_SPOT03_OBJECT", "Spot03 Object", "Spot03 Object"), + ("OBJECT_SPOT07_OBJECT", "Spot07 Object", "Spot07 Object"), + ("OBJECT_FZ", "Fz", "Fz"), + ("OBJECT_BOB", "Bob", "Bob"), + ("OBJECT_GE1", "Ge1", "Ge1"), + ("OBJECT_YABUSAME_POINT", "Yabusame Point", "Yabusame Point"), + ("OBJECT_GI_BOOTS_2", "Gi Boots 2", "Gi Boots 2"), + ("OBJECT_GI_SEED", "Gi Seed", "Gi Seed"), + ("OBJECT_GND_MAGIC", "Gnd Magic", "Gnd Magic"), + ("OBJECT_D_ELEVATOR", "D Elevator", "D Elevator"), + ("OBJECT_D_HSBLOCK", "D Hsblock", "D Hsblock"), + ("OBJECT_D_LIFT", "D Lift", "D Lift"), + ("OBJECT_MAMENOKI", "Mamenoki", "Mamenoki"), + ("OBJECT_GOROIWA", "Goroiwa", "Goroiwa"), + ("OBJECT_TORYO", "Toryo", "Toryo"), + ("OBJECT_DAIKU", "Daiku", "Daiku"), + ("OBJECT_NWC", "Nwc", "Nwc"), + ("OBJECT_BLKOBJ", "Blkobj", "Blkobj"), + ("OBJECT_GM", "Gm", "Gm"), + ("OBJECT_MS", "Ms", "Ms"), + ("OBJECT_HS", "Hs", "Hs"), + ("OBJECT_INGATE", "Ingate", "Ingate"), + ("OBJECT_LIGHTSWITCH", "Lightswitch", "Lightswitch"), + ("OBJECT_KUSA", "Kusa", "Kusa"), + ("OBJECT_TSUBO", "Tsubo", "Tsubo"), + ("OBJECT_GI_GLOVES", "Gi Gloves", "Gi Gloves"), + ("OBJECT_GI_COIN", "Gi Coin", "Gi Coin"), + ("OBJECT_KANBAN", "Kanban", "Kanban"), + ("OBJECT_GJYO_OBJECTS", "Gjyo Objects", "Gjyo Objects"), + ("OBJECT_OWL", "Owl", "Owl"), + ("OBJECT_MK", "Mk", "Mk"), + ("OBJECT_FU", "Fu", "Fu"), + ("OBJECT_GI_KI_TAN_MASK", "Gi Ki Tan Mask", "Gi Ki Tan Mask"), + ("OBJECT_GI_REDEAD_MASK", "Gi Redead Mask", "Gi Redead Mask"), + ("OBJECT_GI_SKJ_MASK", "Gi Skj Mask", "Gi Skj Mask"), + ("OBJECT_GI_RABIT_MASK", "Gi Rabit Mask", "Gi Rabit Mask"), + ("OBJECT_GI_TRUTH_MASK", "Gi Truth Mask", "Gi Truth Mask"), + ("OBJECT_GANON_OBJECTS", "Ganon Objects", "Ganon Objects"), + ("OBJECT_SIOFUKI", "Siofuki", "Siofuki"), + ("OBJECT_STREAM", "Stream", "Stream"), + ("OBJECT_MM", "Mm", "Mm"), + ("OBJECT_FA", "Fa", "Fa"), + ("OBJECT_OS", "Os", "Os"), + ("OBJECT_GI_EYE_LOTION", "Gi Eye Lotion", "Gi Eye Lotion"), + ("OBJECT_GI_POWDER", "Gi Powder", "Gi Powder"), + ("OBJECT_GI_MUSHROOM", "Gi Mushroom", "Gi Mushroom"), + ("OBJECT_GI_TICKETSTONE", "Gi Ticketstone", "Gi Ticketstone"), + ("OBJECT_GI_BROKENSWORD", "Gi Brokensword", "Gi Brokensword"), + ("OBJECT_JS", "Js", "Js"), + ("OBJECT_CS", "Cs", "Cs"), + ("OBJECT_GI_PRESCRIPTION", "Gi Prescription", "Gi Prescription"), + ("OBJECT_GI_BRACELET", "Gi Bracelet", "Gi Bracelet"), + ("OBJECT_GI_SOLDOUT", "Gi Soldout", "Gi Soldout"), + ("OBJECT_GI_FROG", "Gi Frog", "Gi Frog"), + ("OBJECT_MAG", "Mag", "Mag"), + ("OBJECT_DOOR_GERUDO", "Door Gerudo", "Door Gerudo"), + ("OBJECT_GT", "Gt", "Gt"), + ("OBJECT_EFC_ERUPC", "Efc Erupc", "Efc Erupc"), + ("OBJECT_ZL2_ANIME1", "Zl2 Anime1", "Zl2 Anime1"), + ("OBJECT_ZL2_ANIME2", "Zl2 Anime2", "Zl2 Anime2"), + ("OBJECT_GI_GOLONMASK", "Gi Golonmask", "Gi Golonmask"), + ("OBJECT_GI_ZORAMASK", "Gi Zoramask", "Gi Zoramask"), + ("OBJECT_GI_GERUDOMASK", "Gi Gerudomask", "Gi Gerudomask"), + ("OBJECT_GANON2", "Ganon2", "Ganon2"), + ("OBJECT_KA", "Ka", "Ka"), + ("OBJECT_TS", "Ts", "Ts"), + ("OBJECT_ZG", "Zg", "Zg"), + ("OBJECT_GI_HOVERBOOTS", "Gi Hoverboots", "Gi Hoverboots"), + ("OBJECT_GI_M_ARROW", "Gi M Arrow", "Gi M Arrow"), + ("OBJECT_DS2", "Ds2", "Ds2"), + ("OBJECT_EC", "Ec", "Ec"), + ("OBJECT_FISH", "Fish", "Fish"), + ("OBJECT_GI_SUTARU", "Gi Sutaru", "Gi Sutaru"), + ("OBJECT_GI_GODDESS", "Gi Goddess", "Gi Goddess"), + ("OBJECT_SSH", "Ssh", "Ssh"), + ("OBJECT_BIGOKUTA", "Bigokuta", "Bigokuta"), + ("OBJECT_BG", "Bg", "Bg"), + ("OBJECT_SPOT05_OBJECTS", "Spot05 Objects", "Spot05 Objects"), + ("OBJECT_SPOT12_OBJ", "Spot12 Obj", "Spot12 Obj"), + ("OBJECT_BOMBIWA", "Bombiwa", "Bombiwa"), + ("OBJECT_HINTNUTS", "Hintnuts", "Hintnuts"), + ("OBJECT_RS", "Rs", "Rs"), + ("OBJECT_SPOT00_BREAK", "Spot00 Break", "Spot00 Break"), + ("OBJECT_GLA", "Gla", "Gla"), + ("OBJECT_SHOPNUTS", "Shopnuts", "Shopnuts"), + ("OBJECT_GELDB", "Geldb", "Geldb"), + ("OBJECT_GR", "Gr", "Gr"), + ("OBJECT_DOG", "Dog", "Dog"), + ("OBJECT_JYA_IRON", "Jya Iron", "Jya Iron"), + ("OBJECT_JYA_DOOR", "Jya Door", "Jya Door"), + ("OBJECT_SPOT11_OBJ", "Spot11 Obj", "Spot11 Obj"), + ("OBJECT_KIBAKO2", "Kibako2", "Kibako2"), + ("OBJECT_DNS", "Dns", "Dns"), + ("OBJECT_DNK", "Dnk", "Dnk"), + ("OBJECT_GI_FIRE", "Gi Fire", "Gi Fire"), + ("OBJECT_GI_INSECT", "Gi Insect", "Gi Insect"), + ("OBJECT_GI_BUTTERFLY", "Gi Butterfly", "Gi Butterfly"), + ("OBJECT_GI_GHOST", "Gi Ghost", "Gi Ghost"), + ("OBJECT_GI_SOUL", "Gi Soul", "Gi Soul"), + ("OBJECT_BOWL", "Bowl", "Bowl"), + ("OBJECT_DEMO_KEKKAI", "Demo Kekkai", "Demo Kekkai"), + ("OBJECT_EFC_DOUGHNUT", "Efc Doughnut", "Efc Doughnut"), + ("OBJECT_GI_DEKUPOUCH", "Gi Dekupouch", "Gi Dekupouch"), + ("OBJECT_GANON_ANIME1", "Ganon Anime1", "Ganon Anime1"), + ("OBJECT_GANON_ANIME2", "Ganon Anime2", "Ganon Anime2"), + ("OBJECT_GANON_ANIME3", "Ganon Anime3", "Ganon Anime3"), + ("OBJECT_GI_RUPY", "Gi Rupy", "Gi Rupy"), + ("OBJECT_SPOT01_MATOYA", "Spot01 Matoya", "Spot01 Matoya"), + ("OBJECT_SPOT01_MATOYAB", "Spot01 Matoyab", "Spot01 Matoyab"), + ("OBJECT_MU", "Mu", "Mu"), + ("OBJECT_WF", "Wf", "Wf"), + ("OBJECT_SKB", "Skb", "Skb"), + ("OBJECT_GJ", "Gj", "Gj"), + ("OBJECT_GEFF", "Geff", "Geff"), + ("OBJECT_HAKA_DOOR", "Haka Door", "Haka Door"), + ("OBJECT_GS", "Gs", "Gs"), + ("OBJECT_PS", "Ps", "Ps"), + ("OBJECT_BWALL", "Bwall", "Bwall"), + ("OBJECT_COW", "Cow", "Cow"), + ("OBJECT_COB", "Cob", "Cob"), + ("OBJECT_GI_SWORD_1", "Gi Sword 1", "Gi Sword 1"), + ("OBJECT_DOOR_KILLER", "Door Killer", "Door Killer"), + ("OBJECT_OUKE_HAKA", "Ouke Haka", "Ouke Haka"), + ("OBJECT_TIMEBLOCK", "Timeblock", "Timeblock"), ] ootEnumGlobalObject = [ - ("Custom", "Custom", "Custom"), - ("0x0000", "None", "None"), - ("0x0002", "Overworld", "gameplay_field_keep"), - ("0x0003", "Dungeon", "gameplay_dangeon_keep"), + ("Custom", "Custom", "Custom"), + ("0x0000", "None", "None"), + ("0x0002", "Overworld", "gameplay_field_keep"), + ("0x0003", "Dungeon", "gameplay_dangeon_keep"), ] ootEnumNaviHints = [ - ("Custom", "Custom", "Custom"), - ("0x00", "None", "None"), - ("0x01", "Overworld", "elf_message_field"), - ("0x02", "Dungeon", "elf_message_ydan"), + ("Custom", "Custom", "Custom"), + ("0x00", "None", "None"), + ("0x01", "Overworld", "elf_message_field"), + ("0x02", "Dungeon", "elf_message_ydan"), ] ootEnumTransitionAnims = [ - ("Custom", "Custom", "Custom"), - ("0x00", "Spiky", "Spiky"), - ("0x01", "Triforce", "Triforce"), - ("0x02", "Slow Black Fade", "Slow Black Fade"), - ("0x03", "Slow Day/White, Slow Night/Black Fade", "Slow Day/White, Slow Night/Black Fade"), - ("0x04", "Fast Day/Black, Slow Night/Black Fade", "Fast Day/Black, Slow Night/Black Fade"), - ("0x05", "Fast Day/White, Slow Night/Black Fade", "Fast Day/White, Slow Night/Black Fade"), - ("0x06", "Very Slow Day/White, Slow Night/Black Fade", "Very Slow Day/White, Slow Night/Black Fade"), - ("0x07", "Very Slow Day/White, Slow Night/Black Fade", "Very Slow Day/White, Slow Night/Black Fade"), - ("0x0E", "Slow Sandstorm Fade", "Slow Sandstorm Fade"), - ("0x0F", "Fast Sandstorm Fade", "Fast Sandstorm Fade"), - ("0x20", "Iris Fade", "Iris Fade"), - ("0x2C", "Shortcut Transition", "Shortcut Transition"), + ("Custom", "Custom", "Custom"), + ("0x00", "Spiky", "Spiky"), + ("0x01", "Triforce", "Triforce"), + ("0x02", "Slow Black Fade", "Slow Black Fade"), + ("0x03", "Slow Day/White, Slow Night/Black Fade", "Slow Day/White, Slow Night/Black Fade"), + ("0x04", "Fast Day/Black, Slow Night/Black Fade", "Fast Day/Black, Slow Night/Black Fade"), + ("0x05", "Fast Day/White, Slow Night/Black Fade", "Fast Day/White, Slow Night/Black Fade"), + ("0x06", "Very Slow Day/White, Slow Night/Black Fade", "Very Slow Day/White, Slow Night/Black Fade"), + ("0x07", "Very Slow Day/White, Slow Night/Black Fade", "Very Slow Day/White, Slow Night/Black Fade"), + ("0x0E", "Slow Sandstorm Fade", "Slow Sandstorm Fade"), + ("0x0F", "Fast Sandstorm Fade", "Fast Sandstorm Fade"), + ("0x20", "Iris Fade", "Iris Fade"), + ("0x2C", "Shortcut Transition", "Shortcut Transition"), ] # The order of this list matters (normal OoT scene order as defined by ``scene_table.h``) ootEnumSceneID = [ - ("Custom", "Custom", "Custom"), - ("SCENE_YDAN", "Inside the Deku Tree (Ydan)", "Ydan"), - ("SCENE_DDAN", "Dodongo's Cavern (Ddan)", "Ddan"), - ("SCENE_BDAN", "Inside Jabu Jabu's Belly (Bdan)", "Bdan"), - ("SCENE_BMORI1", "Forest Temple (Bmori1)", "Bmori1"), - ("SCENE_HIDAN", "Fire Temple (Hidan)", "Hidan"), - ("SCENE_MIZUSIN", "Water Temple (Mizusin)", "Mizusin"), - ("SCENE_JYASINZOU", "Spirit Temple (Jyasinzou)", "Jyasinzou"), - ("SCENE_HAKADAN", "Shadow Temple (Hakadan)", "Hakadan"), - ("SCENE_HAKADANCH", "Bottom of the Well (Hakadanch)", "Hakadanch"), - ("SCENE_ICE_DOUKUTO", "Ice Cavern (Ice Doukuto)", "Ice Doukuto"), - ("SCENE_GANON", "Ganon's Tower (Ganon)", "Ganon"), - ("SCENE_MEN", "Gerudo Training Ground (Men)", "Men"), - ("SCENE_GERUDOWAY", "Thieves' Hideout (Gerudoway)", "Gerudoway"), - ("SCENE_GANONTIKA", "Inside Ganon's Castle (Ganontika)", "Ganontika"), - ("SCENE_GANON_SONOGO", "Ganon's Tower (Collapsing) (Ganon Sonogo)", "Ganon Sonogo"), - ("SCENE_GANONTIKA_SONOGO", "Inside Ganon's Castle (Collapsing) (Ganontika Sonogo)", "Ganontika Sonogo"), - ("SCENE_TAKARAYA", "Treasure Chest Shop (Takaraya)", "Takaraya"), - ("SCENE_YDAN_BOSS", "Gohma's Lair (Ydan Boss)", "Ydan Boss"), - ("SCENE_DDAN_BOSS", "King Dodongo's Lair (Ddan Boss)", "Ddan Boss"), - ("SCENE_BDAN_BOSS", "Barinade's Lair (Bdan Boss)", "Bdan Boss"), - ("SCENE_MORIBOSSROOM", "Phantom Ganon's Lair (Moribossroom)", "Moribossroom"), - ("SCENE_FIRE_BS", "Volvagia's Lair (Fire Bs)", "Fire Bs"), - ("SCENE_MIZUSIN_BS", "Morpha's Lair (Mizusin Bs)", "Mizusin Bs"), - ("SCENE_JYASINBOSS", "Twinrova's Lair & Iron Knuckle Mini-Boss Room (Jyasinboss)", "Jyasinboss"), - ("SCENE_HAKADAN_BS", "Bongo Bongo's Lair (Hakadan Bs)", "Hakadan Bs"), - ("SCENE_GANON_BOSS", "Ganondorf's Lair (Ganon Boss)", "Ganon Boss"), - ("SCENE_GANON_FINAL", "Ganondorf's Death Scene (Tower Escape Exterior) (Ganon Final)", "Ganon Final"), - ("SCENE_ENTRA", "Market Entrance (Child - Day) (Entra)", "Entra"), - ("SCENE_ENTRA_N", "Market Entrance (Child - Night) (Entra N)", "Entra N"), - ("SCENE_ENRUI", "Market Entrance (Ruins) (Enrui)", "Enrui"), - ("SCENE_MARKET_ALLEY", "Back Alley (Day) (Market Alley)", "Market Alley"), - ("SCENE_MARKET_ALLEY_N", "Back Alley (Night) (Market Alley N)", "Market Alley N"), - ("SCENE_MARKET_DAY", "Market (Child - Day) (Market Day)", "Market Day"), - ("SCENE_MARKET_NIGHT", "Market (Child - Night) (Market Night)", "Market Night"), - ("SCENE_MARKET_RUINS", "Market (Ruins) (Market Ruins)", "Market Ruins"), - ("SCENE_SHRINE", "Temple of Time Exterior (Day) (Shrine)", "Shrine"), - ("SCENE_SHRINE_N", "Temple of Time Exterior (Night) (Shrine N)", "Shrine N"), - ("SCENE_SHRINE_R", "Temple of Time Exterior (Ruins) (Shrine R)", "Shrine R"), - ("SCENE_KOKIRI_HOME", "Know-It-All Brothers' House (Kokiri Home)", "Kokiri Home"), - ("SCENE_KOKIRI_HOME3", "Twins' House (Kokiri Home3)", "Kokiri Home3"), - ("SCENE_KOKIRI_HOME4", "Mido's House (Kokiri Home4)", "Kokiri Home4"), - ("SCENE_KOKIRI_HOME5", "Saria's House (Kokiri Home5)", "Kokiri Home5"), - ("SCENE_KAKARIKO", "Carpenter Boss's House (Kakariko)", "Kakariko"), - ("SCENE_KAKARIKO3", "Back Alley House (Man in Green) (Kakariko3)", "Kakariko3"), - ("SCENE_SHOP1", "Bazaar (Shop1)", "Shop1"), - ("SCENE_KOKIRI_SHOP", "Kokiri Shop (Kokiri Shop)", "Kokiri Shop"), - ("SCENE_GOLON", "Goron Shop (Golon)", "Golon"), - ("SCENE_ZOORA", "Zora Shop (Zoora)", "Zoora"), - ("SCENE_DRAG", "Kakariko Potion Shop (Drag)", "Drag"), - ("SCENE_ALLEY_SHOP", "Market Potion Shop (Alley Shop)", "Alley Shop"), - ("SCENE_NIGHT_SHOP", "Bombchu Shop (Night Shop)", "Night Shop"), - ("SCENE_FACE_SHOP", "Happy Mask Shop (Face Shop)", "Face Shop"), - ("SCENE_LINK_HOME", "Link's House (Link Home)", "Link Home"), - ("SCENE_IMPA", "Back Alley House (Dog Lady) (Impa)", "Impa"), - ("SCENE_MALON_STABLE", "Stable (Malon Stable)", "Malon Stable"), - ("SCENE_LABO", "Impa's House (Labo)", "Labo"), - ("SCENE_HYLIA_LABO", "Lakeside Laboratory (Hylia Labo)", "Hylia Labo"), - ("SCENE_TENT", "Carpenters' Tent (Tent)", "Tent"), - ("SCENE_HUT", "Gravekeeper's Hut (Hut)", "Hut"), - ("SCENE_DAIYOUSEI_IZUMI", "Great Fairy's Fountain (Upgrades) (Daiyousei Izumi)", "Daiyousei Izumi"), - ("SCENE_YOUSEI_IZUMI_TATE", "Fairy's Fountain (Healing Fairies) (Yousei Izumi Tate)", "Yousei Izumi Tate"), - ("SCENE_YOUSEI_IZUMI_YOKO", "Great Fairy's Fountain (Spells) (Yousei Izumi Yoko)", "Yousei Izumi Yoko"), - ("SCENE_KAKUSIANA", "Grottos (Kakusiana)", "Kakusiana"), - ("SCENE_HAKAANA", "Grave (Redead) (Hakaana)", "Hakaana"), - ("SCENE_HAKAANA2", "Grave (Fairy's Fountain) (Hakaana2)", "Hakaana2"), - ("SCENE_HAKAANA_OUKE", "Royal Family's Tomb (Hakaana Ouke)", "Hakaana Ouke"), - ("SCENE_SYATEKIJYOU", "Shooting Gallery (Syatekijyou)", "Syatekijyou"), - ("SCENE_TOKINOMA", "Temple of Time (Tokinoma)", "Tokinoma"), - ("SCENE_KENJYANOMA", "Chamber of the Sages (Kenjyanoma)", "Kenjyanoma"), - ("SCENE_HAIRAL_NIWA", "Castle Hedge Maze (Day) (Hairal Niwa)", "Hairal Niwa"), - ("SCENE_HAIRAL_NIWA_N", "Castle Hedge Maze (Night) (Hairal Niwa N)", "Hairal Niwa N"), - ("SCENE_HIRAL_DEMO", "Cutscene Map (Hiral Demo)", "Hiral Demo"), - ("SCENE_HAKASITARELAY", "Dampé's Grave & Windmill (Hakasitarelay)", "Hakasitarelay"), - ("SCENE_TURIBORI", "Fishing Pond (Turibori)", "Turibori"), - ("SCENE_NAKANIWA", "Castle Courtyard (Nakaniwa)", "Nakaniwa"), - ("SCENE_BOWLING", "Bombchu Bowling Alley (Bowling)", "Bowling"), - ("SCENE_SOUKO", "Lon Lon Ranch House & Tower (Souko)", "Souko"), - ("SCENE_MIHARIGOYA", "Guard House (Miharigoya)", "Miharigoya"), - ("SCENE_MAHOUYA", "Granny's Potion Shop (Mahouya)", "Mahouya"), - ("SCENE_GANON_DEMO", "Ganon's Tower Collapse & Battle Arena (Ganon Demo)", "Ganon Demo"), - ("SCENE_KINSUTA", "House of Skulltula (Kinsuta)", "Kinsuta"), - ("SCENE_SPOT00", "Hyrule Field (Spot00)", "Spot00"), - ("SCENE_SPOT01", "Kakariko Village (Spot01)", "Spot01"), - ("SCENE_SPOT02", "Graveyard (Spot02)", "Spot02"), - ("SCENE_SPOT03", "Zora's River (Spot03)", "Spot03"), - ("SCENE_SPOT04", "Kokiri Forest (Spot04)", "Spot04"), - ("SCENE_SPOT05", "Sacred Forest Meadow (Spot05)", "Spot05"), - ("SCENE_SPOT06", "Lake Hylia (Spot06)", "Spot06"), - ("SCENE_SPOT07", "Zora's Domain (Spot07)", "Spot07"), - ("SCENE_SPOT08", "Zora's Fountain (Spot08)", "Spot08"), - ("SCENE_SPOT09", "Gerudo Valley (Spot09)", "Spot09"), - ("SCENE_SPOT10", "Lost Woods (Spot10)", "Spot10"), - ("SCENE_SPOT11", "Desert Colossus (Spot11)", "Spot11"), - ("SCENE_SPOT12", "Gerudo's Fortress (Spot12)", "Spot12"), - ("SCENE_SPOT13", "Haunted Wasteland (Spot13)", "Spot13"), - ("SCENE_SPOT15", "Hyrule Castle (Spot15)", "Spot15"), - ("SCENE_SPOT16", "Death Mountain Trail (Spot16)", "Spot16"), - ("SCENE_SPOT17", "Death Mountain Crater (Spot17)", "Spot17"), - ("SCENE_SPOT18", "Goron City (Spot18)", "Spot18"), - ("SCENE_SPOT20", "Lon Lon Ranch (Spot20)", "Spot20"), - ("SCENE_GANON_TOU", "Ganon's Castle Exterior (Ganon Tou)", "Ganon Tou"), - ("SCENE_TEST01", "Jungle Gym (Test01)", "Test01"), - ("SCENE_BESITU", "Ganondorf Test Room (Besitu)", "Besitu"), - ("SCENE_DEPTH_TEST", "Depth Test (Depth Test)", "Depth Test"), - ("SCENE_SYOTES", "Stalfos Mini-Boss Room (Syotes)", "Syotes"), - ("SCENE_SYOTES2", "Stalfos Boss ROom (Syotes2)", "Syotes2"), - ("SCENE_SUTARU", "Sutaru (Sutaru)", "Sutaru"), - ("SCENE_HAIRAL_NIWA2", "Castle Hedge Maze (Early) (Hairal Niwa2)", "Hairal Niwa2"), - ("SCENE_SASATEST", "Sasatest (Sasatest)", "Sasatest"), - ("SCENE_TESTROOM", "Treasure Chest Room (Testroom)", "Testroom"), + ("Custom", "Custom", "Custom"), + ("SCENE_YDAN", "Inside the Deku Tree (Ydan)", "Ydan"), + ("SCENE_DDAN", "Dodongo's Cavern (Ddan)", "Ddan"), + ("SCENE_BDAN", "Inside Jabu Jabu's Belly (Bdan)", "Bdan"), + ("SCENE_BMORI1", "Forest Temple (Bmori1)", "Bmori1"), + ("SCENE_HIDAN", "Fire Temple (Hidan)", "Hidan"), + ("SCENE_MIZUSIN", "Water Temple (Mizusin)", "Mizusin"), + ("SCENE_JYASINZOU", "Spirit Temple (Jyasinzou)", "Jyasinzou"), + ("SCENE_HAKADAN", "Shadow Temple (Hakadan)", "Hakadan"), + ("SCENE_HAKADANCH", "Bottom of the Well (Hakadanch)", "Hakadanch"), + ("SCENE_ICE_DOUKUTO", "Ice Cavern (Ice Doukuto)", "Ice Doukuto"), + ("SCENE_GANON", "Ganon's Tower (Ganon)", "Ganon"), + ("SCENE_MEN", "Gerudo Training Ground (Men)", "Men"), + ("SCENE_GERUDOWAY", "Thieves' Hideout (Gerudoway)", "Gerudoway"), + ("SCENE_GANONTIKA", "Inside Ganon's Castle (Ganontika)", "Ganontika"), + ("SCENE_GANON_SONOGO", "Ganon's Tower (Collapsing) (Ganon Sonogo)", "Ganon Sonogo"), + ("SCENE_GANONTIKA_SONOGO", "Inside Ganon's Castle (Collapsing) (Ganontika Sonogo)", "Ganontika Sonogo"), + ("SCENE_TAKARAYA", "Treasure Chest Shop (Takaraya)", "Takaraya"), + ("SCENE_YDAN_BOSS", "Gohma's Lair (Ydan Boss)", "Ydan Boss"), + ("SCENE_DDAN_BOSS", "King Dodongo's Lair (Ddan Boss)", "Ddan Boss"), + ("SCENE_BDAN_BOSS", "Barinade's Lair (Bdan Boss)", "Bdan Boss"), + ("SCENE_MORIBOSSROOM", "Phantom Ganon's Lair (Moribossroom)", "Moribossroom"), + ("SCENE_FIRE_BS", "Volvagia's Lair (Fire Bs)", "Fire Bs"), + ("SCENE_MIZUSIN_BS", "Morpha's Lair (Mizusin Bs)", "Mizusin Bs"), + ("SCENE_JYASINBOSS", "Twinrova's Lair & Iron Knuckle Mini-Boss Room (Jyasinboss)", "Jyasinboss"), + ("SCENE_HAKADAN_BS", "Bongo Bongo's Lair (Hakadan Bs)", "Hakadan Bs"), + ("SCENE_GANON_BOSS", "Ganondorf's Lair (Ganon Boss)", "Ganon Boss"), + ("SCENE_GANON_FINAL", "Ganondorf's Death Scene (Tower Escape Exterior) (Ganon Final)", "Ganon Final"), + ("SCENE_ENTRA", "Market Entrance (Child - Day) (Entra)", "Entra"), + ("SCENE_ENTRA_N", "Market Entrance (Child - Night) (Entra N)", "Entra N"), + ("SCENE_ENRUI", "Market Entrance (Ruins) (Enrui)", "Enrui"), + ("SCENE_MARKET_ALLEY", "Back Alley (Day) (Market Alley)", "Market Alley"), + ("SCENE_MARKET_ALLEY_N", "Back Alley (Night) (Market Alley N)", "Market Alley N"), + ("SCENE_MARKET_DAY", "Market (Child - Day) (Market Day)", "Market Day"), + ("SCENE_MARKET_NIGHT", "Market (Child - Night) (Market Night)", "Market Night"), + ("SCENE_MARKET_RUINS", "Market (Ruins) (Market Ruins)", "Market Ruins"), + ("SCENE_SHRINE", "Temple of Time Exterior (Day) (Shrine)", "Shrine"), + ("SCENE_SHRINE_N", "Temple of Time Exterior (Night) (Shrine N)", "Shrine N"), + ("SCENE_SHRINE_R", "Temple of Time Exterior (Ruins) (Shrine R)", "Shrine R"), + ("SCENE_KOKIRI_HOME", "Know-It-All Brothers' House (Kokiri Home)", "Kokiri Home"), + ("SCENE_KOKIRI_HOME3", "Twins' House (Kokiri Home3)", "Kokiri Home3"), + ("SCENE_KOKIRI_HOME4", "Mido's House (Kokiri Home4)", "Kokiri Home4"), + ("SCENE_KOKIRI_HOME5", "Saria's House (Kokiri Home5)", "Kokiri Home5"), + ("SCENE_KAKARIKO", "Carpenter Boss's House (Kakariko)", "Kakariko"), + ("SCENE_KAKARIKO3", "Back Alley House (Man in Green) (Kakariko3)", "Kakariko3"), + ("SCENE_SHOP1", "Bazaar (Shop1)", "Shop1"), + ("SCENE_KOKIRI_SHOP", "Kokiri Shop (Kokiri Shop)", "Kokiri Shop"), + ("SCENE_GOLON", "Goron Shop (Golon)", "Golon"), + ("SCENE_ZOORA", "Zora Shop (Zoora)", "Zoora"), + ("SCENE_DRAG", "Kakariko Potion Shop (Drag)", "Drag"), + ("SCENE_ALLEY_SHOP", "Market Potion Shop (Alley Shop)", "Alley Shop"), + ("SCENE_NIGHT_SHOP", "Bombchu Shop (Night Shop)", "Night Shop"), + ("SCENE_FACE_SHOP", "Happy Mask Shop (Face Shop)", "Face Shop"), + ("SCENE_LINK_HOME", "Link's House (Link Home)", "Link Home"), + ("SCENE_IMPA", "Back Alley House (Dog Lady) (Impa)", "Impa"), + ("SCENE_MALON_STABLE", "Stable (Malon Stable)", "Malon Stable"), + ("SCENE_LABO", "Impa's House (Labo)", "Labo"), + ("SCENE_HYLIA_LABO", "Lakeside Laboratory (Hylia Labo)", "Hylia Labo"), + ("SCENE_TENT", "Carpenters' Tent (Tent)", "Tent"), + ("SCENE_HUT", "Gravekeeper's Hut (Hut)", "Hut"), + ("SCENE_DAIYOUSEI_IZUMI", "Great Fairy's Fountain (Upgrades) (Daiyousei Izumi)", "Daiyousei Izumi"), + ("SCENE_YOUSEI_IZUMI_TATE", "Fairy's Fountain (Healing Fairies) (Yousei Izumi Tate)", "Yousei Izumi Tate"), + ("SCENE_YOUSEI_IZUMI_YOKO", "Great Fairy's Fountain (Spells) (Yousei Izumi Yoko)", "Yousei Izumi Yoko"), + ("SCENE_KAKUSIANA", "Grottos (Kakusiana)", "Kakusiana"), + ("SCENE_HAKAANA", "Grave (Redead) (Hakaana)", "Hakaana"), + ("SCENE_HAKAANA2", "Grave (Fairy's Fountain) (Hakaana2)", "Hakaana2"), + ("SCENE_HAKAANA_OUKE", "Royal Family's Tomb (Hakaana Ouke)", "Hakaana Ouke"), + ("SCENE_SYATEKIJYOU", "Shooting Gallery (Syatekijyou)", "Syatekijyou"), + ("SCENE_TOKINOMA", "Temple of Time (Tokinoma)", "Tokinoma"), + ("SCENE_KENJYANOMA", "Chamber of the Sages (Kenjyanoma)", "Kenjyanoma"), + ("SCENE_HAIRAL_NIWA", "Castle Hedge Maze (Day) (Hairal Niwa)", "Hairal Niwa"), + ("SCENE_HAIRAL_NIWA_N", "Castle Hedge Maze (Night) (Hairal Niwa N)", "Hairal Niwa N"), + ("SCENE_HIRAL_DEMO", "Cutscene Map (Hiral Demo)", "Hiral Demo"), + ("SCENE_HAKASITARELAY", "Dampé's Grave & Windmill (Hakasitarelay)", "Hakasitarelay"), + ("SCENE_TURIBORI", "Fishing Pond (Turibori)", "Turibori"), + ("SCENE_NAKANIWA", "Castle Courtyard (Nakaniwa)", "Nakaniwa"), + ("SCENE_BOWLING", "Bombchu Bowling Alley (Bowling)", "Bowling"), + ("SCENE_SOUKO", "Lon Lon Ranch House & Tower (Souko)", "Souko"), + ("SCENE_MIHARIGOYA", "Guard House (Miharigoya)", "Miharigoya"), + ("SCENE_MAHOUYA", "Granny's Potion Shop (Mahouya)", "Mahouya"), + ("SCENE_GANON_DEMO", "Ganon's Tower Collapse & Battle Arena (Ganon Demo)", "Ganon Demo"), + ("SCENE_KINSUTA", "House of Skulltula (Kinsuta)", "Kinsuta"), + ("SCENE_SPOT00", "Hyrule Field (Spot00)", "Spot00"), + ("SCENE_SPOT01", "Kakariko Village (Spot01)", "Spot01"), + ("SCENE_SPOT02", "Graveyard (Spot02)", "Spot02"), + ("SCENE_SPOT03", "Zora's River (Spot03)", "Spot03"), + ("SCENE_SPOT04", "Kokiri Forest (Spot04)", "Spot04"), + ("SCENE_SPOT05", "Sacred Forest Meadow (Spot05)", "Spot05"), + ("SCENE_SPOT06", "Lake Hylia (Spot06)", "Spot06"), + ("SCENE_SPOT07", "Zora's Domain (Spot07)", "Spot07"), + ("SCENE_SPOT08", "Zora's Fountain (Spot08)", "Spot08"), + ("SCENE_SPOT09", "Gerudo Valley (Spot09)", "Spot09"), + ("SCENE_SPOT10", "Lost Woods (Spot10)", "Spot10"), + ("SCENE_SPOT11", "Desert Colossus (Spot11)", "Spot11"), + ("SCENE_SPOT12", "Gerudo's Fortress (Spot12)", "Spot12"), + ("SCENE_SPOT13", "Haunted Wasteland (Spot13)", "Spot13"), + ("SCENE_SPOT15", "Hyrule Castle (Spot15)", "Spot15"), + ("SCENE_SPOT16", "Death Mountain Trail (Spot16)", "Spot16"), + ("SCENE_SPOT17", "Death Mountain Crater (Spot17)", "Spot17"), + ("SCENE_SPOT18", "Goron City (Spot18)", "Spot18"), + ("SCENE_SPOT20", "Lon Lon Ranch (Spot20)", "Spot20"), + ("SCENE_GANON_TOU", "Ganon's Castle Exterior (Ganon Tou)", "Ganon Tou"), + ("SCENE_TEST01", "Jungle Gym (Test01)", "Test01"), + ("SCENE_BESITU", "Ganondorf Test Room (Besitu)", "Besitu"), + ("SCENE_DEPTH_TEST", "Depth Test (Depth Test)", "Depth Test"), + ("SCENE_SYOTES", "Stalfos Mini-Boss Room (Syotes)", "Syotes"), + ("SCENE_SYOTES2", "Stalfos Boss ROom (Syotes2)", "Syotes2"), + ("SCENE_SUTARU", "Sutaru (Sutaru)", "Sutaru"), + ("SCENE_HAIRAL_NIWA2", "Castle Hedge Maze (Early) (Hairal Niwa2)", "Hairal Niwa2"), + ("SCENE_SASATEST", "Sasatest (Sasatest)", "Sasatest"), + ("SCENE_TESTROOM", "Treasure Chest Room (Testroom)", "Testroom"), ] ootSceneIDToName = { - "SCENE_YDAN" : "ydan", - "SCENE_DDAN" : "ddan", - "SCENE_BDAN" : "bdan", - "SCENE_BMORI1" : "Bmori1", - "SCENE_HIDAN" : "HIDAN", - "SCENE_MIZUSIN" : "MIZUsin", - "SCENE_JYASINZOU" : "jyasinzou", - "SCENE_HAKADAN" : "HAKAdan", - "SCENE_HAKADANCH" : "HAKAdanCH", - "SCENE_ICE_DOUKUTO" : "ice_doukutu", - "SCENE_GANON" : "ganon", - "SCENE_MEN" : "men", - "SCENE_GERUDOWAY" : "gerudoway", - "SCENE_GANONTIKA" : "ganontika", - "SCENE_GANON_SONOGO" : "ganon_sonogo", - "SCENE_GANONTIKA_SONOGO" : "ganontikasonogo", - "SCENE_TAKARAYA" : "takaraya", - "SCENE_YDAN_BOSS" : "ydan_boss", - "SCENE_DDAN_BOSS" : "ddan_boss", - "SCENE_BDAN_BOSS" : "bdan_boss", - "SCENE_MORIBOSSROOM" : "moribossroom", - "SCENE_FIRE_BS" : "FIRE_bs", - "SCENE_MIZUSIN_BS" : "MIZUsin_bs", - "SCENE_JYASINBOSS" : "jyasinboss", - "SCENE_HAKADAN_BS" : "HAKAdan_bs", - "SCENE_GANON_BOSS" : "ganon_boss", - "SCENE_GANON_FINAL" : "ganon_final", - "SCENE_ENTRA" : "entra", - "SCENE_ENTRA_N" : "entra_n", - "SCENE_ENRUI" : "enrui", - "SCENE_MARKET_ALLEY" : "market_alley", - "SCENE_MARKET_ALLEY_N" : "market_alley_n", - "SCENE_MARKET_DAY" : "market_day", - "SCENE_MARKET_NIGHT" : "market_night", - "SCENE_MARKET_RUINS" : "market_ruins", - "SCENE_SHRINE" : "shrine", - "SCENE_SHRINE_N" : "shrine_n", - "SCENE_SHRINE_R" : "shrine_r", - "SCENE_KOKIRI_HOME" : "kokiri_home", - "SCENE_KOKIRI_HOME3" : "kokiri_home3", - "SCENE_KOKIRI_HOME4" : "kokiri_home4", - "SCENE_KOKIRI_HOME5" : "kokiri_home5", - "SCENE_KAKARIKO" : "kakariko", - "SCENE_KAKARIKO3" : "kakariko3", - "SCENE_SHOP1" : "shop1", - "SCENE_KOKIRI_SHOP" : "kokiri_shop", - "SCENE_GOLON" : "golon", - "SCENE_ZOORA" : "zoora", - "SCENE_DRAG" : "drag", - "SCENE_ALLEY_SHOP" : "alley_shop", - "SCENE_NIGHT_SHOP" : "night_shop", - "SCENE_FACE_SHOP" : "face_shop", - "SCENE_LINK_HOME" : "link_home", - "SCENE_IMPA" : "impa", - "SCENE_MALON_STABLE" : "malon_stable", - "SCENE_LABO" : "labo", - "SCENE_HYLIA_LABO" : "hylia_labo", - "SCENE_TENT" : "tent", - "SCENE_HUT" : "hut", - "SCENE_DAIYOUSEI_IZUMI" : "daiyousei_izumi", - "SCENE_YOUSEI_IZUMI_TATE" : "yousei_izumi_tate", - "SCENE_YOUSEI_IZUMI_YOKO" : "yousei_izumi_yoko", - "SCENE_KAKUSIANA" : "kakusiana", - "SCENE_HAKAANA" : "hakaana", - "SCENE_HAKAANA2" : "hakaana2", - "SCENE_HAKAANA_OUKE" : "hakaana_ouke", - "SCENE_SYATEKIJYOU" : "syatekijyou", - "SCENE_TOKINOMA" : "tokinoma", - "SCENE_KENJYANOMA" : "kenjyanoma", - "SCENE_HAIRAL_NIWA" : "hairal_niwa", - "SCENE_HAIRAL_NIWA_N" : "hairal_niwa_n", - "SCENE_HIRAL_DEMO" : "hiral_demo", - "SCENE_HAKASITARELAY" : "hakasitarelay", - "SCENE_TURIBORI" : "turibori", - "SCENE_NAKANIWA" : "nakaniwa", - "SCENE_BOWLING" : "bowling", - "SCENE_SOUKO" : "souko", - "SCENE_MIHARIGOYA" : "miharigoya", - "SCENE_MAHOUYA" : "mahouya", - "SCENE_GANON_DEMO" : "ganon_demo", - "SCENE_KINSUTA" : "kinsuta", - "SCENE_SPOT00" : "spot00", - "SCENE_SPOT01" : "spot01", - "SCENE_SPOT02" : "spot02", - "SCENE_SPOT03" : "spot03", - "SCENE_SPOT04" : "spot04", - "SCENE_SPOT05" : "spot05", - "SCENE_SPOT06" : "spot06", - "SCENE_SPOT07" : "spot07", - "SCENE_SPOT08" : "spot08", - "SCENE_SPOT09" : "spot09", - "SCENE_SPOT10" : "spot10", - "SCENE_SPOT11" : "spot11", - "SCENE_SPOT12" : "spot12", - "SCENE_SPOT13" : "spot13", - "SCENE_SPOT15" : "spot15", - "SCENE_SPOT16" : "spot16", - "SCENE_SPOT17" : "spot17", - "SCENE_SPOT18" : "spot18", - "SCENE_SPOT20" : "spot20", - "SCENE_GANON_TOU" : "ganon_tou", - "SCENE_TEST01" : "test01", - "SCENE_BESITU" : "besitu", - "SCENE_DEPTH_TEST" : "depth_test", - "SCENE_SYOTES" : "syotes", - "SCENE_SYOTES2" : "syotes2", - "SCENE_SUTARU" : "sutaru", - "SCENE_HAIRAL_NIWA2" : "hairal_niwa2", - "SCENE_SASATEST" : "sasatest", - "SCENE_TESTROOM" : "testroom", + "SCENE_YDAN": "ydan", + "SCENE_DDAN": "ddan", + "SCENE_BDAN": "bdan", + "SCENE_BMORI1": "Bmori1", + "SCENE_HIDAN": "HIDAN", + "SCENE_MIZUSIN": "MIZUsin", + "SCENE_JYASINZOU": "jyasinzou", + "SCENE_HAKADAN": "HAKAdan", + "SCENE_HAKADANCH": "HAKAdanCH", + "SCENE_ICE_DOUKUTO": "ice_doukutu", + "SCENE_GANON": "ganon", + "SCENE_MEN": "men", + "SCENE_GERUDOWAY": "gerudoway", + "SCENE_GANONTIKA": "ganontika", + "SCENE_GANON_SONOGO": "ganon_sonogo", + "SCENE_GANONTIKA_SONOGO": "ganontikasonogo", + "SCENE_TAKARAYA": "takaraya", + "SCENE_YDAN_BOSS": "ydan_boss", + "SCENE_DDAN_BOSS": "ddan_boss", + "SCENE_BDAN_BOSS": "bdan_boss", + "SCENE_MORIBOSSROOM": "moribossroom", + "SCENE_FIRE_BS": "FIRE_bs", + "SCENE_MIZUSIN_BS": "MIZUsin_bs", + "SCENE_JYASINBOSS": "jyasinboss", + "SCENE_HAKADAN_BS": "HAKAdan_bs", + "SCENE_GANON_BOSS": "ganon_boss", + "SCENE_GANON_FINAL": "ganon_final", + "SCENE_ENTRA": "entra", + "SCENE_ENTRA_N": "entra_n", + "SCENE_ENRUI": "enrui", + "SCENE_MARKET_ALLEY": "market_alley", + "SCENE_MARKET_ALLEY_N": "market_alley_n", + "SCENE_MARKET_DAY": "market_day", + "SCENE_MARKET_NIGHT": "market_night", + "SCENE_MARKET_RUINS": "market_ruins", + "SCENE_SHRINE": "shrine", + "SCENE_SHRINE_N": "shrine_n", + "SCENE_SHRINE_R": "shrine_r", + "SCENE_KOKIRI_HOME": "kokiri_home", + "SCENE_KOKIRI_HOME3": "kokiri_home3", + "SCENE_KOKIRI_HOME4": "kokiri_home4", + "SCENE_KOKIRI_HOME5": "kokiri_home5", + "SCENE_KAKARIKO": "kakariko", + "SCENE_KAKARIKO3": "kakariko3", + "SCENE_SHOP1": "shop1", + "SCENE_KOKIRI_SHOP": "kokiri_shop", + "SCENE_GOLON": "golon", + "SCENE_ZOORA": "zoora", + "SCENE_DRAG": "drag", + "SCENE_ALLEY_SHOP": "alley_shop", + "SCENE_NIGHT_SHOP": "night_shop", + "SCENE_FACE_SHOP": "face_shop", + "SCENE_LINK_HOME": "link_home", + "SCENE_IMPA": "impa", + "SCENE_MALON_STABLE": "malon_stable", + "SCENE_LABO": "labo", + "SCENE_HYLIA_LABO": "hylia_labo", + "SCENE_TENT": "tent", + "SCENE_HUT": "hut", + "SCENE_DAIYOUSEI_IZUMI": "daiyousei_izumi", + "SCENE_YOUSEI_IZUMI_TATE": "yousei_izumi_tate", + "SCENE_YOUSEI_IZUMI_YOKO": "yousei_izumi_yoko", + "SCENE_KAKUSIANA": "kakusiana", + "SCENE_HAKAANA": "hakaana", + "SCENE_HAKAANA2": "hakaana2", + "SCENE_HAKAANA_OUKE": "hakaana_ouke", + "SCENE_SYATEKIJYOU": "syatekijyou", + "SCENE_TOKINOMA": "tokinoma", + "SCENE_KENJYANOMA": "kenjyanoma", + "SCENE_HAIRAL_NIWA": "hairal_niwa", + "SCENE_HAIRAL_NIWA_N": "hairal_niwa_n", + "SCENE_HIRAL_DEMO": "hiral_demo", + "SCENE_HAKASITARELAY": "hakasitarelay", + "SCENE_TURIBORI": "turibori", + "SCENE_NAKANIWA": "nakaniwa", + "SCENE_BOWLING": "bowling", + "SCENE_SOUKO": "souko", + "SCENE_MIHARIGOYA": "miharigoya", + "SCENE_MAHOUYA": "mahouya", + "SCENE_GANON_DEMO": "ganon_demo", + "SCENE_KINSUTA": "kinsuta", + "SCENE_SPOT00": "spot00", + "SCENE_SPOT01": "spot01", + "SCENE_SPOT02": "spot02", + "SCENE_SPOT03": "spot03", + "SCENE_SPOT04": "spot04", + "SCENE_SPOT05": "spot05", + "SCENE_SPOT06": "spot06", + "SCENE_SPOT07": "spot07", + "SCENE_SPOT08": "spot08", + "SCENE_SPOT09": "spot09", + "SCENE_SPOT10": "spot10", + "SCENE_SPOT11": "spot11", + "SCENE_SPOT12": "spot12", + "SCENE_SPOT13": "spot13", + "SCENE_SPOT15": "spot15", + "SCENE_SPOT16": "spot16", + "SCENE_SPOT17": "spot17", + "SCENE_SPOT18": "spot18", + "SCENE_SPOT20": "spot20", + "SCENE_GANON_TOU": "ganon_tou", + "SCENE_TEST01": "test01", + "SCENE_BESITU": "besitu", + "SCENE_DEPTH_TEST": "depth_test", + "SCENE_SYOTES": "syotes", + "SCENE_SYOTES2": "syotes2", + "SCENE_SUTARU": "sutaru", + "SCENE_HAIRAL_NIWA2": "hairal_niwa2", + "SCENE_SASATEST": "sasatest", + "SCENE_TESTROOM": "testroom", } ootEnumCamTransition = [ - ("Custom", "Custom", "Custom"), - ("0x00", "0x00", "0x00"), - #("0x0F", "0x0F", "0x0F"), - #("0xFF", "0xFF", "0xFF"), + ("Custom", "Custom", "Custom"), + ("0x00", "0x00", "0x00"), + # ("0x0F", "0x0F", "0x0F"), + # ("0xFF", "0xFF", "0xFF"), ] # see curRoom.unk_03 ootEnumRoomBehaviour = [ - ("Custom", "Custom", "Custom"), - ("0x00", "None", "None"), - ("0x01", "Disable Sun Song Effect", "Disable Sun Song Effect"), - ("0x02", "Disable Action Button Jumping", "Disable Action Button Jumping"), - ("0x03", "(?) Disable Color Dither", "(?) Disable Color Dither"), - ("0x04", "(?) Horse Camera Related", "(?) Horse Camera Related"), - ("0x05", "(?) Nayru's Love Light Dim", "(?) Nayru's Love Light Dim"), + ("Custom", "Custom", "Custom"), + ("0x00", "None", "None"), + ("0x01", "Disable Sun Song Effect", "Disable Sun Song Effect"), + ("0x02", "Disable Action Button Jumping", "Disable Action Button Jumping"), + ("0x03", "(?) Disable Color Dither", "(?) Disable Color Dither"), + ("0x04", "(?) Horse Camera Related", "(?) Horse Camera Related"), + ("0x05", "(?) Nayru's Love Light Dim", "(?) Nayru's Love Light Dim"), ] ootEnumExitIndex = [ - ("Custom", "Custom", "Custom"), - ("Default", "Default", "Default"), + ("Custom", "Custom", "Custom"), + ("Default", "Default", "Default"), ] ootEnumSceneSetupPreset = [ - ("Custom", "Custom", "Custom"), - ("All Scene Setups", "All Scene Setups", "All Scene Setups"), - ("All Non-Cutscene Scene Setups", "All Non-Cutscene Scene Setups", "All Non-Cutscene Scene Setups"), + ("Custom", "Custom", "Custom"), + ("All Scene Setups", "All Scene Setups", "All Scene Setups"), + ("All Non-Cutscene Scene Setups", "All Non-Cutscene Scene Setups", "All Non-Cutscene Scene Setups"), ] ootEnumCSWriteType = [ - ("Custom", "Custom", "Provide the name of a cutscene header variable"), - ("Embedded", "Embedded", "Cutscene data is within scene header (deprecated)"), - ("Object", "Object", "Reference to Blender object representing cutscene") + ("Custom", "Custom", "Provide the name of a cutscene header variable"), + ("Embedded", "Embedded", "Cutscene data is within scene header (deprecated)"), + ("Object", "Object", "Reference to Blender object representing cutscene"), ] ootEnumCSListType = [ - ("Textbox", "Textbox", "Textbox"), - ("FX", "Scene Trans FX", "Scene Trans FX"), - ("Lighting", "Lighting", "Lighting"), - ("Time", "Time", "Time"), - ("PlayBGM", "Play BGM", "Play BGM"), - ("StopBGM", "Stop BGM", "Stop BGM"), - ("FadeBGM", "Fade BGM", "Fade BGM"), - ("Misc", "Misc", "Misc"), - ("0x09", "Cmd 09", "Cmd 09"), - ("Unk", "Unknown Data", "Unknown Data") + ("Textbox", "Textbox", "Textbox"), + ("FX", "Scene Trans FX", "Scene Trans FX"), + ("Lighting", "Lighting", "Lighting"), + ("Time", "Time", "Time"), + ("PlayBGM", "Play BGM", "Play BGM"), + ("StopBGM", "Stop BGM", "Stop BGM"), + ("FadeBGM", "Fade BGM", "Fade BGM"), + ("Misc", "Misc", "Misc"), + ("0x09", "Cmd 09", "Cmd 09"), + ("Unk", "Unknown Data", "Unknown Data"), ] ootEnumCSListTypeIcons = [ - 'ALIGN_BOTTOM', 'COLORSET_10_VEC', 'LIGHT_SUN', 'TIME', 'PLAY', 'SNAP_FACE', 'IPO_EASE_IN_OUT', - 'OPTIONS', 'EVENT_F9', 'QUESTION' + "ALIGN_BOTTOM", + "COLORSET_10_VEC", + "LIGHT_SUN", + "TIME", + "PLAY", + "SNAP_FACE", + "IPO_EASE_IN_OUT", + "OPTIONS", + "EVENT_F9", + "QUESTION", ] ootEnumCSListTypeListC = { - "Textbox": 'CS_TEXT_LIST', - "FX": 'CS_SCENE_TRANS_FX', - "Lighting": 'CS_LIGHTING_LIST', - "Time": 'CS_TIME_LIST', - "PlayBGM": 'CS_PLAY_BGM_LIST', - "StopBGM": 'CS_STOP_BGM_LIST', - "FadeBGM": 'CS_FADE_BGM_LIST', - "Misc": 'CS_MISC_LIST', - "0x09": 'CS_CMD_09_LIST', - "Unk": 'CS_UNK_DATA_LIST' + "Textbox": "CS_TEXT_LIST", + "FX": "CS_SCENE_TRANS_FX", + "Lighting": "CS_LIGHTING_LIST", + "Time": "CS_TIME_LIST", + "PlayBGM": "CS_PLAY_BGM_LIST", + "StopBGM": "CS_STOP_BGM_LIST", + "FadeBGM": "CS_FADE_BGM_LIST", + "Misc": "CS_MISC_LIST", + "0x09": "CS_CMD_09_LIST", + "Unk": "CS_UNK_DATA_LIST", } ootEnumCSListTypeEntryC = { - "Textbox": None, # special case - "FX": None, # no list entries - "Lighting": 'CS_LIGHTING', - "Time": 'CS_TIME', - "PlayBGM": 'CS_PLAY_BGM', - "StopBGM": 'CS_STOP_BGM', - "FadeBGM": 'CS_FADE_BGM', - "Misc": 'CS_MISC', - "0x09": 'CS_CMD_09', - "Unk": 'CS_UNK_DATA' + "Textbox": None, # special case + "FX": None, # no list entries + "Lighting": "CS_LIGHTING", + "Time": "CS_TIME", + "PlayBGM": "CS_PLAY_BGM", + "StopBGM": "CS_STOP_BGM", + "FadeBGM": "CS_FADE_BGM", + "Misc": "CS_MISC", + "0x09": "CS_CMD_09", + "Unk": "CS_UNK_DATA", } -ootEnumCSTextboxType = [ - ("Text", "Text", "Text"), - ("None", "None", "None"), - ("LearnSong", "Learn Song", "Learn Song") -] +ootEnumCSTextboxType = [("Text", "Text", "Text"), ("None", "None", "None"), ("LearnSong", "Learn Song", "Learn Song")] -ootEnumCSTextboxTypeIcons = [ - 'FILE_TEXT', 'HIDE_ON', 'FILE_SOUND' -] +ootEnumCSTextboxTypeIcons = ["FILE_TEXT", "HIDE_ON", "FILE_SOUND"] ootEnumCSTextboxTypeEntryC = { - "Text": 'CS_TEXT_DISPLAY_TEXTBOX', - "None": 'CS_TEXT_NONE', - "LearnSong": 'CS_TEXT_LEARN_SONG', + "Text": "CS_TEXT_DISPLAY_TEXTBOX", + "None": "CS_TEXT_NONE", + "LearnSong": "CS_TEXT_LEARN_SONG", } ootEnumCSTransitionType = [ - ('1', 'To White +', 'Also plays whiteout sound for certain scenes/entrances'), - ('2', 'To Blue', 'To Blue'), - ('3', 'From Red', 'From Red'), - ('4', 'From Green', 'From Green'), - ('5', 'From White', 'From White'), - ('6', 'From Blue', 'From Blue'), - ('7', 'To Red', 'To Red'), - ('8', 'To Green', 'To Green'), - ('9', 'Set Unk', 'gSaveContext.unk_1410 = 1, works with scene xn 11/17'), - ('10', 'From Black', 'From Black'), - ('11', 'To Black', 'To Black'), - ('12', 'To Dim Unk', 'Fade gSaveContext.unk_1410 255>100, works with scene xn 11/17'), - ('13', 'From Dim', 'Alpha 100>255') + ("1", "To White +", "Also plays whiteout sound for certain scenes/entrances"), + ("2", "To Blue", "To Blue"), + ("3", "From Red", "From Red"), + ("4", "From Green", "From Green"), + ("5", "From White", "From White"), + ("6", "From Blue", "From Blue"), + ("7", "To Red", "To Red"), + ("8", "To Green", "To Green"), + ("9", "Set Unk", "gSaveContext.unk_1410 = 1, works with scene xn 11/17"), + ("10", "From Black", "From Black"), + ("11", "To Black", "To Black"), + ("12", "To Dim Unk", "Fade gSaveContext.unk_1410 255>100, works with scene xn 11/17"), + ("13", "From Dim", "Alpha 100>255"), ] ootDrawConfigNames = [ - "SDC_DEFAULT", - "SDC_SPOT00", - "SDC_SPOT01", - "SDC_SPOT03", - "SDC_SPOT04", - "SDC_SPOT06", - "SDC_SPOT07", - "SDC_SPOT08", - "SDC_SPOT09", - "SDC_SPOT10", - "SDC_SPOT11", - "SDC_SPOT12", - "SDC_SPOT13", - "SDC_SPOT15", - "SDC_SPOT16", - "SDC_SPOT17", - "SDC_SPOT18", - "SDC_SPOT20", - "SDC_HIDAN", - "SDC_YDAN", - "SDC_DDAN", - "SDC_BDAN", - "SDC_BMORI1", - "SDC_MIZUSIN", - "SDC_HAKADAN", - "SDC_JYASINZOU", - "SDC_GANONTIKA", - "SDC_MEN", - "SDC_YDAN_BOSS", - "SDC_MIZUSIN_BS", - "SDC_TOKINOMA", - "SDC_KAKUSIANA", - "SDC_KENJYANOMA", - "SDC_GREAT_FAIRY_FOUNTAIN", - "SDC_SYATEKIJYOU", - "SDC_HAIRAL_NIWA", - "SDC_GANON_CASTLE_EXTERIOR", - "SDC_ICE_DOUKUTO", - "SDC_GANON_FINAL", - "SDC_FAIRY_FOUNTAIN", - "SDC_GERUDOWAY", - "SDC_BOWLING", - "SDC_HAKAANA_OUKE", - "SDC_HYLIA_LABO", - "SDC_SOUKO", - "SDC_MIHARIGOYA", - "SDC_MAHOUYA", - "SDC_CALM_WATER", - "SDC_GRAVE_EXIT_LIGHT_SHINING", - "SDC_BESITU", - "SDC_TURIBORI", - "SDC_GANON_SONOGO", - "SDC_GANONTIKA_SONOGO", + "SDC_DEFAULT", + "SDC_SPOT00", + "SDC_SPOT01", + "SDC_SPOT03", + "SDC_SPOT04", + "SDC_SPOT06", + "SDC_SPOT07", + "SDC_SPOT08", + "SDC_SPOT09", + "SDC_SPOT10", + "SDC_SPOT11", + "SDC_SPOT12", + "SDC_SPOT13", + "SDC_SPOT15", + "SDC_SPOT16", + "SDC_SPOT17", + "SDC_SPOT18", + "SDC_SPOT20", + "SDC_HIDAN", + "SDC_YDAN", + "SDC_DDAN", + "SDC_BDAN", + "SDC_BMORI1", + "SDC_MIZUSIN", + "SDC_HAKADAN", + "SDC_JYASINZOU", + "SDC_GANONTIKA", + "SDC_MEN", + "SDC_YDAN_BOSS", + "SDC_MIZUSIN_BS", + "SDC_TOKINOMA", + "SDC_KAKUSIANA", + "SDC_KENJYANOMA", + "SDC_GREAT_FAIRY_FOUNTAIN", + "SDC_SYATEKIJYOU", + "SDC_HAIRAL_NIWA", + "SDC_GANON_CASTLE_EXTERIOR", + "SDC_ICE_DOUKUTO", + "SDC_GANON_FINAL", + "SDC_FAIRY_FOUNTAIN", + "SDC_GERUDOWAY", + "SDC_BOWLING", + "SDC_HAKAANA_OUKE", + "SDC_HYLIA_LABO", + "SDC_SOUKO", + "SDC_MIHARIGOYA", + "SDC_MAHOUYA", + "SDC_CALM_WATER", + "SDC_GRAVE_EXIT_LIGHT_SHINING", + "SDC_BESITU", + "SDC_TURIBORI", + "SDC_GANON_SONOGO", + "SDC_GANONTIKA_SONOGO", ] diff --git a/fast64_internal/oot/oot_level_writer.py b/fast64_internal/oot/oot_level_writer.py index 6ad8ab9..3b9c03d 100644 --- a/fast64_internal/oot/oot_level_writer.py +++ b/fast64_internal/oot/oot_level_writer.py @@ -18,670 +18,775 @@ from .oot_spline import * from .oot_cutscene import * from .c_writer import * + def sceneNameFromID(sceneID): - if sceneID in ootSceneIDToName: - return ootSceneIDToName[sceneID] - else: - raise PluginError("Cannot find scene ID " + str(sceneID)) + if sceneID in ootSceneIDToName: + return ootSceneIDToName[sceneID] + else: + raise PluginError("Cannot find scene ID " + str(sceneID)) + def ootPreprendSceneIncludes(scene, file): - exportFile = ootSceneIncludes(scene) - exportFile.append(file) - return exportFile + exportFile = ootSceneIncludes(scene) + exportFile.append(file) + return exportFile + def ootCreateSceneHeader(levelC): - sceneHeader = CData() + sceneHeader = CData() - sceneHeader.append(levelC.sceneMainC) - if levelC.sceneTexturesIsUsed(): - sceneHeader.append(levelC.sceneTexturesC) - sceneHeader.append(levelC.sceneCollisionC) - if levelC.sceneCutscenesIsUsed(): - for i in range(len(levelC.sceneCutscenesC)): - sceneHeader.append(levelC.sceneCutscenesC[i]) - for roomName, roomMainC in levelC.roomMainC.items(): - sceneHeader.append(roomMainC) - for roomName, roomMeshInfoC in levelC.roomMeshInfoC.items(): - sceneHeader.append(roomMeshInfoC) - for roomName, roomMeshC in levelC.roomMeshC.items(): - sceneHeader.append(roomMeshC) + sceneHeader.append(levelC.sceneMainC) + if levelC.sceneTexturesIsUsed(): + sceneHeader.append(levelC.sceneTexturesC) + sceneHeader.append(levelC.sceneCollisionC) + if levelC.sceneCutscenesIsUsed(): + for i in range(len(levelC.sceneCutscenesC)): + sceneHeader.append(levelC.sceneCutscenesC[i]) + for roomName, roomMainC in levelC.roomMainC.items(): + sceneHeader.append(roomMainC) + for roomName, roomMeshInfoC in levelC.roomMeshInfoC.items(): + sceneHeader.append(roomMeshInfoC) + for roomName, roomMeshC in levelC.roomMeshC.items(): + sceneHeader.append(roomMeshC) + + return sceneHeader - return sceneHeader def ootCombineSceneFiles(levelC): - sceneC = CData() + sceneC = CData() - sceneC.append(levelC.sceneMainC) - if levelC.sceneTexturesIsUsed(): - sceneC.append(levelC.sceneTexturesC) - sceneC.append(levelC.sceneCollisionC) - if levelC.sceneCutscenesIsUsed(): - for i in range(len(levelC.sceneCutscenesC)): - sceneC.append(levelC.sceneCutscenesC[i]) - return sceneC + sceneC.append(levelC.sceneMainC) + if levelC.sceneTexturesIsUsed(): + sceneC.append(levelC.sceneTexturesC) + sceneC.append(levelC.sceneCollisionC) + if levelC.sceneCutscenesIsUsed(): + for i in range(len(levelC.sceneCutscenesC)): + sceneC.append(levelC.sceneCutscenesC[i]) + return sceneC -def ootExportSceneToC(originalSceneObj, transformMatrix, - f3dType, isHWv1, sceneName, DLFormat, savePNG, exportInfo): - checkObjectReference(originalSceneObj, "Scene object") - isCustomExport = exportInfo.isCustomExportPath - exportPath = exportInfo.exportPath +def ootExportSceneToC(originalSceneObj, transformMatrix, f3dType, isHWv1, sceneName, DLFormat, savePNG, exportInfo): - scene = ootConvertScene(originalSceneObj, transformMatrix, - f3dType, isHWv1, sceneName, DLFormat, not savePNG) - - exportSubdir = '' - if exportInfo.customSubPath is not None: - exportSubdir = exportInfo.customSubPath - if not isCustomExport and exportInfo.customSubPath is None: - for sceneSubdir, sceneNames in ootSceneDirs.items(): - if sceneName in sceneNames: - exportSubdir = sceneSubdir - break - if exportSubdir == "": - raise PluginError("Scene folder " + sceneName + " cannot be found in the ootSceneDirs list.") + checkObjectReference(originalSceneObj, "Scene object") + isCustomExport = exportInfo.isCustomExportPath + exportPath = exportInfo.exportPath - levelPath = ootGetPath(exportPath, isCustomExport, exportSubdir, sceneName, True, True) - levelC = ootLevelToC(scene, TextureExportSettings(False, savePNG, exportSubdir + sceneName, levelPath)) + scene = ootConvertScene(originalSceneObj, transformMatrix, f3dType, isHWv1, sceneName, DLFormat, not savePNG) + + exportSubdir = "" + if exportInfo.customSubPath is not None: + exportSubdir = exportInfo.customSubPath + if not isCustomExport and exportInfo.customSubPath is None: + for sceneSubdir, sceneNames in ootSceneDirs.items(): + if sceneName in sceneNames: + exportSubdir = sceneSubdir + break + if exportSubdir == "": + raise PluginError("Scene folder " + sceneName + " cannot be found in the ootSceneDirs list.") + + levelPath = ootGetPath(exportPath, isCustomExport, exportSubdir, sceneName, True, True) + levelC = ootLevelToC(scene, TextureExportSettings(False, savePNG, exportSubdir + sceneName, levelPath)) + + if bpy.context.scene.ootSceneSingleFile: + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, ootCombineSceneFiles(levelC)), + os.path.join(levelPath, scene.sceneName() + ".c"), + ) + for i in range(len(scene.rooms)): + roomC = CData() + roomC.append(levelC.roomMainC[scene.rooms[i].roomName()]) + roomC.append(levelC.roomMeshInfoC[scene.rooms[i].roomName()]) + roomC.append(levelC.roomMeshC[scene.rooms[i].roomName()]) + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, roomC), os.path.join(levelPath, scene.rooms[i].roomName() + ".c") + ) + else: + # Export the scene segment .c files + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, levelC.sceneMainC), os.path.join(levelPath, scene.sceneName() + "_main.c") + ) + if levelC.sceneTexturesIsUsed(): + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, levelC.sceneTexturesC), + os.path.join(levelPath, scene.sceneName() + "_tex.c"), + ) + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, levelC.sceneCollisionC), + os.path.join(levelPath, scene.sceneName() + "_col.c"), + ) + if levelC.sceneCutscenesIsUsed(): + for i in range(len(levelC.sceneCutscenesC)): + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, levelC.sceneCutscenesC[i]), + os.path.join(levelPath, scene.sceneName() + "_cs_" + str(i) + ".c"), + ) + + # Export the room segment .c files + for roomName, roomMainC in levelC.roomMainC.items(): + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, roomMainC), os.path.join(levelPath, roomName + "_main.c") + ) + for roomName, roomMeshInfoC in levelC.roomMeshInfoC.items(): + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, roomMeshInfoC), os.path.join(levelPath, roomName + "_model_info.c") + ) + for roomName, roomMeshC in levelC.roomMeshC.items(): + writeCDataSourceOnly( + ootPreprendSceneIncludes(scene, roomMeshC), os.path.join(levelPath, roomName + "_model.c") + ) + + # Export the scene .h file + writeCDataHeaderOnly(ootCreateSceneHeader(levelC), os.path.join(levelPath, scene.sceneName() + ".h")) + + if not isCustomExport: + writeOtherSceneProperties(scene, exportInfo, levelC) - if bpy.context.scene.ootSceneSingleFile: - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, ootCombineSceneFiles(levelC)), - os.path.join(levelPath, scene.sceneName() + '.c')) - for i in range(len(scene.rooms)): - roomC = CData() - roomC.append(levelC.roomMainC[scene.rooms[i].roomName()]) - roomC.append(levelC.roomMeshInfoC[scene.rooms[i].roomName()]) - roomC.append(levelC.roomMeshC[scene.rooms[i].roomName()]) - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, roomC), - os.path.join(levelPath, scene.rooms[i].roomName() + '.c')) - else: - # Export the scene segment .c files - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, levelC.sceneMainC), - os.path.join(levelPath, scene.sceneName() + '_main.c')) - if levelC.sceneTexturesIsUsed(): - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, levelC.sceneTexturesC), - os.path.join(levelPath, scene.sceneName() + '_tex.c')) - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, levelC.sceneCollisionC), - os.path.join(levelPath, scene.sceneName() + '_col.c')) - if levelC.sceneCutscenesIsUsed(): - for i in range(len(levelC.sceneCutscenesC)): - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, levelC.sceneCutscenesC[i]), - os.path.join(levelPath, scene.sceneName() + '_cs_' + str(i) + '.c')) - - # Export the room segment .c files - for roomName, roomMainC in levelC.roomMainC.items(): - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, roomMainC), - os.path.join(levelPath, roomName + '_main.c')) - for roomName, roomMeshInfoC in levelC.roomMeshInfoC.items(): - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, roomMeshInfoC), - os.path.join(levelPath, roomName + '_model_info.c')) - for roomName, roomMeshC in levelC.roomMeshC.items(): - writeCDataSourceOnly(ootPreprendSceneIncludes(scene, roomMeshC), - os.path.join(levelPath, roomName + '_model.c')) - - # Export the scene .h file - writeCDataHeaderOnly(ootCreateSceneHeader(levelC), - os.path.join(levelPath, scene.sceneName() + '.h')) - - if not isCustomExport: - writeOtherSceneProperties(scene, exportInfo, levelC) def writeOtherSceneProperties(scene, exportInfo, levelC): - modifySceneTable(scene, exportInfo) - modifySegmentDefinition(scene, exportInfo, levelC) - modifySceneFiles(scene, exportInfo) + modifySceneTable(scene, exportInfo) + modifySegmentDefinition(scene, exportInfo, levelC) + modifySceneFiles(scene, exportInfo) + def readSceneData(scene, scene_properties, sceneHeader, alternateSceneHeaders): - scene.write_dummy_room_list = scene_properties.write_dummy_room_list - scene.sceneTableEntry.drawConfig = sceneHeader.sceneTableEntry.drawConfig - scene.globalObject = getCustomProperty(sceneHeader, "globalObject") - scene.naviCup = getCustomProperty(sceneHeader, "naviCup") - scene.skyboxID = getCustomProperty(sceneHeader, "skyboxID") - scene.skyboxCloudiness = getCustomProperty(sceneHeader, "skyboxCloudiness") - scene.skyboxLighting = getCustomProperty(sceneHeader, "skyboxLighting") - scene.mapLocation = getCustomProperty(sceneHeader, "mapLocation") - scene.cameraMode = getCustomProperty(sceneHeader, "cameraMode") - scene.musicSeq = getCustomProperty(sceneHeader, "musicSeq") - scene.nightSeq = getCustomProperty(sceneHeader, "nightSeq") - scene.audioSessionPreset = getCustomProperty(sceneHeader, "audioSessionPreset") + scene.write_dummy_room_list = scene_properties.write_dummy_room_list + scene.sceneTableEntry.drawConfig = sceneHeader.sceneTableEntry.drawConfig + scene.globalObject = getCustomProperty(sceneHeader, "globalObject") + scene.naviCup = getCustomProperty(sceneHeader, "naviCup") + scene.skyboxID = getCustomProperty(sceneHeader, "skyboxID") + scene.skyboxCloudiness = getCustomProperty(sceneHeader, "skyboxCloudiness") + scene.skyboxLighting = getCustomProperty(sceneHeader, "skyboxLighting") + scene.mapLocation = getCustomProperty(sceneHeader, "mapLocation") + scene.cameraMode = getCustomProperty(sceneHeader, "cameraMode") + scene.musicSeq = getCustomProperty(sceneHeader, "musicSeq") + scene.nightSeq = getCustomProperty(sceneHeader, "nightSeq") + scene.audioSessionPreset = getCustomProperty(sceneHeader, "audioSessionPreset") - if sceneHeader.skyboxLighting == '0x00': # Time of Day - scene.lights.append(getLightData(sceneHeader.timeOfDayLights.dawn)) - scene.lights.append(getLightData(sceneHeader.timeOfDayLights.day)) - scene.lights.append(getLightData(sceneHeader.timeOfDayLights.dusk)) - scene.lights.append(getLightData(sceneHeader.timeOfDayLights.night)) - else: - for lightProp in sceneHeader.lightList: - scene.lights.append(getLightData(lightProp)) + if sceneHeader.skyboxLighting == "0x00": # Time of Day + scene.lights.append(getLightData(sceneHeader.timeOfDayLights.dawn)) + scene.lights.append(getLightData(sceneHeader.timeOfDayLights.day)) + scene.lights.append(getLightData(sceneHeader.timeOfDayLights.dusk)) + scene.lights.append(getLightData(sceneHeader.timeOfDayLights.night)) + else: + for lightProp in sceneHeader.lightList: + scene.lights.append(getLightData(lightProp)) - for exitProp in sceneHeader.exitList: - scene.exitList.append(getExitData(exitProp)) + for exitProp in sceneHeader.exitList: + scene.exitList.append(getExitData(exitProp)) - scene.writeCutscene = getCustomProperty(sceneHeader, "writeCutscene") - if scene.writeCutscene: - scene.csWriteType = getattr(sceneHeader, "csWriteType") - if scene.csWriteType == "Embedded": - scene.csEndFrame = getCustomProperty(sceneHeader, "csEndFrame") - scene.csWriteTerminator = getCustomProperty(sceneHeader, "csWriteTerminator") - scene.csTermIdx = getCustomProperty(sceneHeader, "csTermIdx") - scene.csTermStart = getCustomProperty(sceneHeader, "csTermStart") - scene.csTermEnd = getCustomProperty(sceneHeader, "csTermEnd") - readCutsceneData(scene, sceneHeader) - elif scene.csWriteType == "Custom": - scene.csWriteCustom = getCustomProperty(sceneHeader, "csWriteCustom") - elif scene.csWriteType == "Object": - if sceneHeader.csWriteObject is None: - raise PluginError('No object selected for cutscene reference') - elif sceneHeader.csWriteObject.ootEmptyType != 'Cutscene': - raise PluginError('Object selected as cutscene is wrong type, must be empty with Cutscene type') - elif sceneHeader.csWriteObject.parent is not None: - raise PluginError('Cutscene empty object should not be parented to anything') - else: - scene.csWriteObject = convertCutsceneObject(sceneHeader.csWriteObject) - - if alternateSceneHeaders is not None: - for ec in sceneHeader.extraCutscenes: - scene.extraCutscenes.append(convertCutsceneObject(ec.csObject)) - - scene.collision.cameraData = OOTCameraData(scene.name) + scene.writeCutscene = getCustomProperty(sceneHeader, "writeCutscene") + if scene.writeCutscene: + scene.csWriteType = getattr(sceneHeader, "csWriteType") + if scene.csWriteType == "Embedded": + scene.csEndFrame = getCustomProperty(sceneHeader, "csEndFrame") + scene.csWriteTerminator = getCustomProperty(sceneHeader, "csWriteTerminator") + scene.csTermIdx = getCustomProperty(sceneHeader, "csTermIdx") + scene.csTermStart = getCustomProperty(sceneHeader, "csTermStart") + scene.csTermEnd = getCustomProperty(sceneHeader, "csTermEnd") + readCutsceneData(scene, sceneHeader) + elif scene.csWriteType == "Custom": + scene.csWriteCustom = getCustomProperty(sceneHeader, "csWriteCustom") + elif scene.csWriteType == "Object": + if sceneHeader.csWriteObject is None: + raise PluginError("No object selected for cutscene reference") + elif sceneHeader.csWriteObject.ootEmptyType != "Cutscene": + raise PluginError("Object selected as cutscene is wrong type, must be empty with Cutscene type") + elif sceneHeader.csWriteObject.parent is not None: + raise PluginError("Cutscene empty object should not be parented to anything") + else: + scene.csWriteObject = convertCutsceneObject(sceneHeader.csWriteObject) - if not alternateSceneHeaders.childNightHeader.usePreviousHeader: - scene.childNightHeader = scene.getAlternateHeaderScene(scene.name) - readSceneData(scene.childNightHeader, scene_properties, alternateSceneHeaders.childNightHeader, None) + if alternateSceneHeaders is not None: + for ec in sceneHeader.extraCutscenes: + scene.extraCutscenes.append(convertCutsceneObject(ec.csObject)) - if not alternateSceneHeaders.adultDayHeader.usePreviousHeader: - scene.adultDayHeader = scene.getAlternateHeaderScene(scene.name) - readSceneData(scene.adultDayHeader, scene_properties, alternateSceneHeaders.adultDayHeader, None) + scene.collision.cameraData = OOTCameraData(scene.name) - if not alternateSceneHeaders.adultNightHeader.usePreviousHeader: - scene.adultNightHeader = scene.getAlternateHeaderScene(scene.name) - readSceneData(scene.adultNightHeader, scene_properties, alternateSceneHeaders.adultNightHeader, None) + if not alternateSceneHeaders.childNightHeader.usePreviousHeader: + scene.childNightHeader = scene.getAlternateHeaderScene(scene.name) + readSceneData(scene.childNightHeader, scene_properties, alternateSceneHeaders.childNightHeader, None) + + if not alternateSceneHeaders.adultDayHeader.usePreviousHeader: + scene.adultDayHeader = scene.getAlternateHeaderScene(scene.name) + readSceneData(scene.adultDayHeader, scene_properties, alternateSceneHeaders.adultDayHeader, None) + + if not alternateSceneHeaders.adultNightHeader.usePreviousHeader: + scene.adultNightHeader = scene.getAlternateHeaderScene(scene.name) + readSceneData(scene.adultNightHeader, scene_properties, alternateSceneHeaders.adultNightHeader, None) + + for i in range(len(alternateSceneHeaders.cutsceneHeaders)): + cutsceneHeaderProp = alternateSceneHeaders.cutsceneHeaders[i] + cutsceneHeader = scene.getAlternateHeaderScene(scene.name) + readSceneData(cutsceneHeader, scene_properties, cutsceneHeaderProp, None) + scene.cutsceneHeaders.append(cutsceneHeader) + else: + if len(sceneHeader.extraCutscenes) > 0: + raise PluginError( + "Extra cutscenes (not in any header) only belong in the main scene, not alternate headers" + ) - for i in range(len(alternateSceneHeaders.cutsceneHeaders)): - cutsceneHeaderProp = alternateSceneHeaders.cutsceneHeaders[i] - cutsceneHeader = scene.getAlternateHeaderScene(scene.name) - readSceneData(cutsceneHeader, scene_properties, cutsceneHeaderProp, None) - scene.cutsceneHeaders.append(cutsceneHeader) - else: - if len(sceneHeader.extraCutscenes) > 0: - raise PluginError("Extra cutscenes (not in any header) only belong in the main scene, not alternate headers") def getConvertedTransform(transformMatrix, sceneObj, obj, handleOrientation): - - # Hacky solution to handle Z-up to Y-up conversion - # We cannot apply rotation to empty, as that modifies scale - if handleOrientation: - orientation = mathutils.Quaternion((1, 0, 0), math.radians(90.0)) - else: - orientation = mathutils.Matrix.Identity(4) - return getConvertedTransformWithOrientation(transformMatrix, sceneObj, obj, orientation) + + # Hacky solution to handle Z-up to Y-up conversion + # We cannot apply rotation to empty, as that modifies scale + if handleOrientation: + orientation = mathutils.Quaternion((1, 0, 0), math.radians(90.0)) + else: + orientation = mathutils.Matrix.Identity(4) + return getConvertedTransformWithOrientation(transformMatrix, sceneObj, obj, orientation) + def getConvertedTransformWithOrientation(transformMatrix, sceneObj, obj, orientation): - relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world - blenderTranslation, blenderRotation, scale = relativeTransform.decompose() - rotation = blenderRotation @ orientation - convertedTranslation = ootConvertTranslation(blenderTranslation) - convertedRotation = ootConvertRotation(rotation) - - return convertedTranslation, convertedRotation, scale, rotation - + relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world + blenderTranslation, blenderRotation, scale = relativeTransform.decompose() + rotation = blenderRotation @ orientation + convertedTranslation = ootConvertTranslation(blenderTranslation) + convertedRotation = ootConvertRotation(rotation) + + return convertedTranslation, convertedRotation, scale, rotation + + def getExitData(exitProp): - if exitProp.exitIndex != "Custom": - raise PluginError("Exit index enums not implemented yet.") - return OOTExit(exitProp.exitIndexCustom) + if exitProp.exitIndex != "Custom": + raise PluginError("Exit index enums not implemented yet.") + return OOTExit(exitProp.exitIndexCustom) + def getLightData(lightProp): - light = OOTLight() - light.ambient = getLightColor(lightProp.ambient) - if lightProp.useCustomDiffuse0: - if lightProp.diffuse0Custom is None: - raise PluginError("Error: Diffuse 0 light object not set in a scene lighting property.") - light.diffuse0 = getLightColor(lightProp.diffuse0Custom.color) - light.diffuseDir0 = getLightRotation(lightProp.diffuse0Custom) - else: - light.diffuse0 = getLightColor(lightProp.diffuse0) - light.diffuseDir0 = [0x49, 0x49, 0x49] + light = OOTLight() + light.ambient = getLightColor(lightProp.ambient) + if lightProp.useCustomDiffuse0: + if lightProp.diffuse0Custom is None: + raise PluginError("Error: Diffuse 0 light object not set in a scene lighting property.") + light.diffuse0 = getLightColor(lightProp.diffuse0Custom.color) + light.diffuseDir0 = getLightRotation(lightProp.diffuse0Custom) + else: + light.diffuse0 = getLightColor(lightProp.diffuse0) + light.diffuseDir0 = [0x49, 0x49, 0x49] - if lightProp.useCustomDiffuse1: - if lightProp.diffuse1Custom is None: - raise PluginError("Error: Diffuse 1 light object not set in a scene lighting property.") - light.diffuse1 = getLightColor(lightProp.diffuse1Custom.color) - light.diffuseDir1 = getLightRotation(lightProp.diffuse1Custom) - else: - light.diffuse1 = getLightColor(lightProp.diffuse1) - light.diffuseDir1 = [0xB7, 0xB7, 0xB7] + if lightProp.useCustomDiffuse1: + if lightProp.diffuse1Custom is None: + raise PluginError("Error: Diffuse 1 light object not set in a scene lighting property.") + light.diffuse1 = getLightColor(lightProp.diffuse1Custom.color) + light.diffuseDir1 = getLightRotation(lightProp.diffuse1Custom) + else: + light.diffuse1 = getLightColor(lightProp.diffuse1) + light.diffuseDir1 = [0xB7, 0xB7, 0xB7] + + light.fogColor = getLightColor(lightProp.fogColor) + light.fogNear = lightProp.fogNear + light.transitionSpeed = lightProp.transitionSpeed + light.fogFar = lightProp.fogFar + return light - light.fogColor = getLightColor(lightProp.fogColor) - light.fogNear = lightProp.fogNear - light.transitionSpeed = lightProp.transitionSpeed - light.fogFar = lightProp.fogFar - return light def readRoomData(room, roomHeader, alternateRoomHeaders): - room.roomIndex = roomHeader.roomIndex - room.roomBehaviour = getCustomProperty(roomHeader, "roomBehaviour") - room.disableWarpSongs = roomHeader.disableWarpSongs - room.showInvisibleActors = roomHeader.showInvisibleActors - room.linkIdleMode = getCustomProperty(roomHeader, "linkIdleMode") - room.linkIdleModeCustom = roomHeader.linkIdleModeCustom - room.setWind = roomHeader.setWind - room.windVector = normToSigned8Vector(mathutils.Vector(roomHeader.windVector).normalized()) - room.windStrength = int(0xFF * max(mathutils.Vector(roomHeader.windVector).length, 1)) - if roomHeader.leaveTimeUnchanged: - room.timeHours = "0xFF" - room.timeMinutes = "0xFF" - else: - room.timeHours = roomHeader.timeHours - room.timeMinutes = roomHeader.timeMinutes - room.timeSpeed = max(-128, min(127, int(round(roomHeader.timeSpeed * 0xA)))) - room.disableSkybox = roomHeader.disableSkybox - room.disableSunMoon = roomHeader.disableSunMoon - room.echo = roomHeader.echo - room.objectList.extend([getCustomProperty(item, "objectID") for item in roomHeader.objectList]) - if len(room.objectList) > 15: - raise PluginError("Error: A scene can only have a maximum of 15 objects (OOT, not blender objects).") + room.roomIndex = roomHeader.roomIndex + room.roomBehaviour = getCustomProperty(roomHeader, "roomBehaviour") + room.disableWarpSongs = roomHeader.disableWarpSongs + room.showInvisibleActors = roomHeader.showInvisibleActors + room.linkIdleMode = getCustomProperty(roomHeader, "linkIdleMode") + room.linkIdleModeCustom = roomHeader.linkIdleModeCustom + room.setWind = roomHeader.setWind + room.windVector = normToSigned8Vector(mathutils.Vector(roomHeader.windVector).normalized()) + room.windStrength = int(0xFF * max(mathutils.Vector(roomHeader.windVector).length, 1)) + if roomHeader.leaveTimeUnchanged: + room.timeHours = "0xFF" + room.timeMinutes = "0xFF" + else: + room.timeHours = roomHeader.timeHours + room.timeMinutes = roomHeader.timeMinutes + room.timeSpeed = max(-128, min(127, int(round(roomHeader.timeSpeed * 0xA)))) + room.disableSkybox = roomHeader.disableSkybox + room.disableSunMoon = roomHeader.disableSunMoon + room.echo = roomHeader.echo + room.objectList.extend([getCustomProperty(item, "objectID") for item in roomHeader.objectList]) + if len(room.objectList) > 15: + raise PluginError("Error: A scene can only have a maximum of 15 objects (OOT, not blender objects).") - if alternateRoomHeaders is not None: - if not alternateRoomHeaders.childNightHeader.usePreviousHeader: - room.childNightHeader = room.getAlternateHeaderRoom(room.ownerName) - readRoomData(room.childNightHeader, alternateRoomHeaders.childNightHeader, None) + if alternateRoomHeaders is not None: + if not alternateRoomHeaders.childNightHeader.usePreviousHeader: + room.childNightHeader = room.getAlternateHeaderRoom(room.ownerName) + readRoomData(room.childNightHeader, alternateRoomHeaders.childNightHeader, None) - if not alternateRoomHeaders.adultDayHeader.usePreviousHeader: - room.adultDayHeader = room.getAlternateHeaderRoom(room.ownerName) - readRoomData(room.adultDayHeader, alternateRoomHeaders.adultDayHeader, None) + if not alternateRoomHeaders.adultDayHeader.usePreviousHeader: + room.adultDayHeader = room.getAlternateHeaderRoom(room.ownerName) + readRoomData(room.adultDayHeader, alternateRoomHeaders.adultDayHeader, None) - if not alternateRoomHeaders.adultNightHeader.usePreviousHeader: - room.adultNightHeader = room.getAlternateHeaderRoom(room.ownerName) - readRoomData(room.adultNightHeader, alternateRoomHeaders.adultNightHeader, None) + if not alternateRoomHeaders.adultNightHeader.usePreviousHeader: + room.adultNightHeader = room.getAlternateHeaderRoom(room.ownerName) + readRoomData(room.adultNightHeader, alternateRoomHeaders.adultNightHeader, None) + + for i in range(len(alternateRoomHeaders.cutsceneHeaders)): + cutsceneHeaderProp = alternateRoomHeaders.cutsceneHeaders[i] + cutsceneHeader = room.getAlternateHeaderRoom(room.ownerName) + readRoomData(cutsceneHeader, cutsceneHeaderProp, None) + room.cutsceneHeaders.append(cutsceneHeader) - for i in range(len(alternateRoomHeaders.cutsceneHeaders)): - cutsceneHeaderProp = alternateRoomHeaders.cutsceneHeaders[i] - cutsceneHeader = room.getAlternateHeaderRoom(room.ownerName) - readRoomData(cutsceneHeader, cutsceneHeaderProp, None) - room.cutsceneHeaders.append(cutsceneHeader) def readCamPos(camPosProp, obj, scene, sceneObj, transformMatrix): - # Camera faces opposite direction - orientation = mathutils.Quaternion((0, 1, 0), math.radians(180.0)) - translation, rotation, scale, orientedRotation = \ - getConvertedTransformWithOrientation(transformMatrix, sceneObj, obj, orientation) - camPosProp = obj.ootCameraPositionProperty - index = camPosProp.index - # TODO: FOV conversion? - if index in scene.collision.cameraData.camPosDict: - raise PluginError("Error: Repeated camera position index: " + str(index)) - if camPosProp.camSType == "Custom": - camSType = camPosProp.camSTypeCustom - else: - camSType = decomp_compat_map_CameraSType.get(camPosProp.camSType, camPosProp.camSType) - scene.collision.cameraData.camPosDict[index] = OOTCameraPosData( - camSType, camPosProp.hasPositionData, - translation, rotation, int(round(math.degrees(obj.data.angle))), camPosProp.jfifID) + # Camera faces opposite direction + orientation = mathutils.Quaternion((0, 1, 0), math.radians(180.0)) + translation, rotation, scale, orientedRotation = getConvertedTransformWithOrientation( + transformMatrix, sceneObj, obj, orientation + ) + camPosProp = obj.ootCameraPositionProperty + index = camPosProp.index + # TODO: FOV conversion? + if index in scene.collision.cameraData.camPosDict: + raise PluginError("Error: Repeated camera position index: " + str(index)) + if camPosProp.camSType == "Custom": + camSType = camPosProp.camSTypeCustom + else: + camSType = decomp_compat_map_CameraSType.get(camPosProp.camSType, camPosProp.camSType) + scene.collision.cameraData.camPosDict[index] = OOTCameraPosData( + camSType, + camPosProp.hasPositionData, + translation, + rotation, + int(round(math.degrees(obj.data.angle))), + camPosProp.jfifID, + ) + def readPathProp(pathProp, obj, scene, sceneObj, sceneName, transformMatrix): - relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world - index = obj.ootSplineProperty.index - if index in scene.pathList: - raise PluginError("Error: " + obj.name + "has a repeated spline index: " + str(index)) - scene.pathList[index] = ootConvertPath(sceneName, index, obj, relativeTransform) + relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world + index = obj.ootSplineProperty.index + if index in scene.pathList: + raise PluginError("Error: " + obj.name + "has a repeated spline index: " + str(index)) + scene.pathList[index] = ootConvertPath(sceneName, index, obj, relativeTransform) -def ootConvertScene(originalSceneObj, transformMatrix, - f3dType, isHWv1, sceneName, DLFormat, convertTextureData): - if originalSceneObj.data is not None or originalSceneObj.ootEmptyType != "Scene": - raise PluginError(originalSceneObj.name + " is not an empty with the \"Scene\" empty type.") - - if bpy.context.scene.exportHiddenGeometry: - hiddenObjs = unhideAllAndGetHiddenList(bpy.context.scene) +def ootConvertScene(originalSceneObj, transformMatrix, f3dType, isHWv1, sceneName, DLFormat, convertTextureData): - # Don't remove ignore_render, as we want to reuse this for collision - sceneObj, allObjs = \ - ootDuplicateHierarchy(originalSceneObj, None, True, OOTObjectCategorizer()) + if originalSceneObj.data is not None or originalSceneObj.ootEmptyType != "Scene": + raise PluginError(originalSceneObj.name + ' is not an empty with the "Scene" empty type.') - if bpy.context.scene.exportHiddenGeometry: - hideObjsInList(hiddenObjs) - - roomObjs = [child for child in sceneObj.children if child.data is None and child.ootEmptyType == 'Room'] - if len(roomObjs) == 0: - raise PluginError("The scene has no child empties with the 'Room' empty type.") + if bpy.context.scene.exportHiddenGeometry: + hiddenObjs = unhideAllAndGetHiddenList(bpy.context.scene) - try: - scene = OOTScene(sceneName, OOTModel(f3dType, isHWv1, sceneName + '_dl', DLFormat, None)) - readSceneData(scene, sceneObj.fast64.oot.scene, sceneObj.ootSceneHeader, sceneObj.ootAlternateSceneHeaders) - processedRooms = set() + # Don't remove ignore_render, as we want to reuse this for collision + sceneObj, allObjs = ootDuplicateHierarchy(originalSceneObj, None, True, OOTObjectCategorizer()) - for obj in sceneObj.children: - translation, rotation, scale, orientedRotation = \ - getConvertedTransform(transformMatrix, sceneObj, obj, True) + if bpy.context.scene.exportHiddenGeometry: + hideObjsInList(hiddenObjs) - if obj.data is None and obj.ootEmptyType == 'Room': - roomObj = obj - roomIndex = roomObj.ootRoomHeader.roomIndex - if roomIndex in processedRooms: - raise PluginError("Error: room index " + str(roomIndex) + " is used more than once.") - processedRooms.add(roomIndex) - room = scene.addRoom(roomIndex, sceneName, roomObj.ootRoomHeader.meshType) - readRoomData(room, roomObj.ootRoomHeader, roomObj.ootAlternateRoomHeaders) + roomObjs = [child for child in sceneObj.children if child.data is None and child.ootEmptyType == "Room"] + if len(roomObjs) == 0: + raise PluginError("The scene has no child empties with the 'Room' empty type.") - DLGroup = room.mesh.addMeshGroup(CullGroup( - translation, scale, obj.ootRoomHeader.defaultCullDistance)).DLGroup - ootProcessMesh(room.mesh, DLGroup, sceneObj, roomObj, transformMatrix, convertTextureData, None) - room.mesh.terminateDLs() - room.mesh.removeUnusedEntries() - ootProcessEmpties(scene, room, sceneObj, roomObj, transformMatrix) - elif obj.data is None and obj.ootEmptyType == "Water Box": - ootProcessWaterBox(sceneObj, obj, transformMatrix, scene, 0x3F) - elif isinstance(obj.data, bpy.types.Camera): - camPosProp = obj.ootCameraPositionProperty - readCamPos(camPosProp, obj, scene, sceneObj, transformMatrix) - elif isinstance(obj.data, bpy.types.Curve) and assertCurveValid(obj): - readPathProp(obj.ootSplineProperty, obj, scene, sceneObj, sceneName, transformMatrix) - - scene.validateIndices() - scene.entranceList = sorted(scene.entranceList, key=lambda x: x.startPositionIndex) - exportCollisionCommon(scene.collision, sceneObj, transformMatrix, True, sceneName) + try: + scene = OOTScene(sceneName, OOTModel(f3dType, isHWv1, sceneName + "_dl", DLFormat, None)) + readSceneData(scene, sceneObj.fast64.oot.scene, sceneObj.ootSceneHeader, sceneObj.ootAlternateSceneHeaders) + processedRooms = set() - ootCleanupScene(originalSceneObj, allObjs) + for obj in sceneObj.children: + translation, rotation, scale, orientedRotation = getConvertedTransform(transformMatrix, sceneObj, obj, True) - except Exception as e: - ootCleanupScene(originalSceneObj, allObjs) - raise Exception(str(e)) + if obj.data is None and obj.ootEmptyType == "Room": + roomObj = obj + roomIndex = roomObj.ootRoomHeader.roomIndex + if roomIndex in processedRooms: + raise PluginError("Error: room index " + str(roomIndex) + " is used more than once.") + processedRooms.add(roomIndex) + room = scene.addRoom(roomIndex, sceneName, roomObj.ootRoomHeader.meshType) + readRoomData(room, roomObj.ootRoomHeader, roomObj.ootAlternateRoomHeaders) + + DLGroup = room.mesh.addMeshGroup( + CullGroup(translation, scale, obj.ootRoomHeader.defaultCullDistance) + ).DLGroup + ootProcessMesh(room.mesh, DLGroup, sceneObj, roomObj, transformMatrix, convertTextureData, None) + room.mesh.terminateDLs() + room.mesh.removeUnusedEntries() + ootProcessEmpties(scene, room, sceneObj, roomObj, transformMatrix) + elif obj.data is None and obj.ootEmptyType == "Water Box": + ootProcessWaterBox(sceneObj, obj, transformMatrix, scene, 0x3F) + elif isinstance(obj.data, bpy.types.Camera): + camPosProp = obj.ootCameraPositionProperty + readCamPos(camPosProp, obj, scene, sceneObj, transformMatrix) + elif isinstance(obj.data, bpy.types.Curve) and assertCurveValid(obj): + readPathProp(obj.ootSplineProperty, obj, scene, sceneObj, sceneName, transformMatrix) + + scene.validateIndices() + scene.entranceList = sorted(scene.entranceList, key=lambda x: x.startPositionIndex) + exportCollisionCommon(scene.collision, sceneObj, transformMatrix, True, sceneName) + + ootCleanupScene(originalSceneObj, allObjs) + + except Exception as e: + ootCleanupScene(originalSceneObj, allObjs) + raise Exception(str(e)) + + return scene - return scene # This function should be called on a copy of an object # The copy will have modifiers / scale applied and will be made single user # When we duplicated obj hierarchy we stripped all ignore_renders from hierarchy. def ootProcessMesh(roomMesh, DLGroup, sceneObj, obj, transformMatrix, convertTextureData, LODHierarchyObject): - relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world - translation, rotation, scale = relativeTransform.decompose() + relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world + translation, rotation, scale = relativeTransform.decompose() - if obj.data is None and obj.ootEmptyType == "Cull Group": - if LODHierarchyObject is not None: - raise PluginError(obj.name + " cannot be used as a cull group because it is " +\ - "in the sub-hierarchy of the LOD group empty " + LODHierarchyObject.name) + if obj.data is None and obj.ootEmptyType == "Cull Group": + if LODHierarchyObject is not None: + raise PluginError( + obj.name + + " cannot be used as a cull group because it is " + + "in the sub-hierarchy of the LOD group empty " + + LODHierarchyObject.name + ) - checkUniformScale(scale, obj) - DLGroup = roomMesh.addMeshGroup(CullGroup( - ootConvertTranslation(translation), scale, obj.empty_display_size)).DLGroup + checkUniformScale(scale, obj) + DLGroup = roomMesh.addMeshGroup( + CullGroup(ootConvertTranslation(translation), scale, obj.empty_display_size) + ).DLGroup - elif isinstance(obj.data, bpy.types.Mesh) and not obj.ignore_render: - triConverterInfo = TriangleConverterInfo(obj, None, roomMesh.model.f3d, relativeTransform, getInfoDict(obj)) - fMeshes = saveStaticModel(triConverterInfo, roomMesh.model, obj, relativeTransform, roomMesh.model.name, - convertTextureData, False, 'oot') - if fMeshes is not None: - for drawLayer, fMesh in fMeshes.items(): - DLGroup.addDLCall(fMesh.draw, drawLayer) + elif isinstance(obj.data, bpy.types.Mesh) and not obj.ignore_render: + triConverterInfo = TriangleConverterInfo(obj, None, roomMesh.model.f3d, relativeTransform, getInfoDict(obj)) + fMeshes = saveStaticModel( + triConverterInfo, + roomMesh.model, + obj, + relativeTransform, + roomMesh.model.name, + convertTextureData, + False, + "oot", + ) + if fMeshes is not None: + for drawLayer, fMesh in fMeshes.items(): + DLGroup.addDLCall(fMesh.draw, drawLayer) + + alphabeticalChildren = sorted(obj.children, key=lambda childObj: childObj.original_name.lower()) + for childObj in alphabeticalChildren: + if childObj.data is None and childObj.ootEmptyType == "LOD": + ootProcessLOD( + roomMesh, DLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject + ) + else: + ootProcessMesh( + roomMesh, DLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject + ) - alphabeticalChildren = sorted(obj.children, key = lambda childObj: childObj.original_name.lower()) - for childObj in alphabeticalChildren: - if childObj.data is None and childObj.ootEmptyType == "LOD": - ootProcessLOD(roomMesh, DLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject) - else: - ootProcessMesh(roomMesh, DLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject) def ootProcessLOD(roomMesh, DLGroup, sceneObj, obj, transformMatrix, convertTextureData, LODHierarchyObject): - relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world - translation, rotation, scale = relativeTransform.decompose() - ootTranslation = ootConvertTranslation(translation) + relativeTransform = transformMatrix @ sceneObj.matrix_world.inverted() @ obj.matrix_world + translation, rotation, scale = relativeTransform.decompose() + ootTranslation = ootConvertTranslation(translation) - LODHierarchyObject = obj - name = toAlnum(roomMesh.model.name + "_" + obj.name + "_lod") - opaqueLOD = roomMesh.model.addLODGroup(name + "_opaque", ootTranslation, obj.f3d_lod_always_render_farthest) - transparentLOD = roomMesh.model.addLODGroup(name + "_transparent", ootTranslation, obj.f3d_lod_always_render_farthest) + LODHierarchyObject = obj + name = toAlnum(roomMesh.model.name + "_" + obj.name + "_lod") + opaqueLOD = roomMesh.model.addLODGroup(name + "_opaque", ootTranslation, obj.f3d_lod_always_render_farthest) + transparentLOD = roomMesh.model.addLODGroup( + name + "_transparent", ootTranslation, obj.f3d_lod_always_render_farthest + ) - index = 0 - for childObj in obj.children: - # This group will not be converted to C directly, but its display lists will be converted through the FLODGroup. - childDLGroup = OOTDLGroup(name + str(index), roomMesh.model.DLFormat) - index += 1 - - if childObj.data is None and childObj.ootEmptyType == "LOD": - ootProcessLOD(roomMesh, childDLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject) - else: - ootProcessMesh(roomMesh, childDLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject) + index = 0 + for childObj in obj.children: + # This group will not be converted to C directly, but its display lists will be converted through the FLODGroup. + childDLGroup = OOTDLGroup(name + str(index), roomMesh.model.DLFormat) + index += 1 - # We handle case with no geometry, for the cases where we have "gaps" in the LOD hierarchy. - # This can happen if a LOD does not use transparency while the levels above and below it does. - childDLGroup.createDLs() - childDLGroup.terminateDLs() + if childObj.data is None and childObj.ootEmptyType == "LOD": + ootProcessLOD( + roomMesh, childDLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject + ) + else: + ootProcessMesh( + roomMesh, childDLGroup, sceneObj, childObj, transformMatrix, convertTextureData, LODHierarchyObject + ) - # Add lod AFTER processing hierarchy, so that DLs will be built by then - opaqueLOD.add_lod(childDLGroup.opaque, childObj.f3d_lod_z * bpy.context.scene.ootBlenderScale) - transparentLOD.add_lod(childDLGroup.transparent, childObj.f3d_lod_z * bpy.context.scene.ootBlenderScale) + # We handle case with no geometry, for the cases where we have "gaps" in the LOD hierarchy. + # This can happen if a LOD does not use transparency while the levels above and below it does. + childDLGroup.createDLs() + childDLGroup.terminateDLs() - opaqueLOD.create_data() - transparentLOD.create_data() + # Add lod AFTER processing hierarchy, so that DLs will be built by then + opaqueLOD.add_lod(childDLGroup.opaque, childObj.f3d_lod_z * bpy.context.scene.ootBlenderScale) + transparentLOD.add_lod(childDLGroup.transparent, childObj.f3d_lod_z * bpy.context.scene.ootBlenderScale) + + opaqueLOD.create_data() + transparentLOD.create_data() + + DLGroup.addDLCall(opaqueLOD.draw, "Opaque") + DLGroup.addDLCall(transparentLOD.draw, "Transparent") - DLGroup.addDLCall(opaqueLOD.draw, "Opaque") - DLGroup.addDLCall(transparentLOD.draw, "Transparent") def ootProcessEmpties(scene, room, sceneObj, obj, transformMatrix): - translation, rotation, scale, orientedRotation = getConvertedTransform(transformMatrix, sceneObj, obj, True) + translation, rotation, scale, orientedRotation = getConvertedTransform(transformMatrix, sceneObj, obj, True) + + if obj.data is None: + if obj.ootEmptyType == "Actor": + actorProp = obj.ootActorProperty + addActor( + room, + OOTActor( + getCustomProperty(actorProp, "actorID"), + translation, + rotation, + actorProp.actorParam, + None + if not actorProp.rotOverride + else (actorProp.rotOverrideX, actorProp.rotOverrideY, actorProp.rotOverrideZ), + ), + actorProp, + "actorList", + obj.name, + ) + elif obj.ootEmptyType == "Transition Actor": + transActorProp = obj.ootTransitionActorProperty + addActor( + scene, + OOTTransitionActor( + getCustomProperty(transActorProp.actor, "actorID"), + room.roomIndex, + transActorProp.roomIndex, + getCustomProperty(transActorProp, "cameraTransitionFront"), + getCustomProperty(transActorProp, "cameraTransitionBack"), + translation, + rotation[1], # TODO: Correct axis? + transActorProp.actor.actorParam, + ), + transActorProp.actor, + "transitionActorList", + obj.name, + ) + # scene.transitionActorList.append(OOTTransitionActor( + # getCustomProperty(transActorProp.actor, "actorID"), + # room.roomIndex, transActorProp.roomIndex, + # getCustomProperty(transActorProp, "cameraTransitionFront"), + # getCustomProperty(transActorProp, "cameraTransitionBack"), + # translation, rotation[1], # TODO: Correct axis? + # transActorProp.actor.actorParam)) + elif obj.ootEmptyType == "Entrance": + entranceProp = obj.ootEntranceProperty + spawnIndex = obj.ootEntranceProperty.spawnIndex + addActor(scene, OOTEntrance(room.roomIndex, spawnIndex), entranceProp.actor, "entranceList", obj.name) + # scene.entranceList.append(OOTEntrance(room.roomIndex, spawnIndex)) + addStartPosition( + scene, + spawnIndex, + OOTActor( + "ACTOR_PLAYER" if not entranceProp.customActor else entranceProp.actor.actorIDCustom, + translation, + rotation, + entranceProp.actor.actorParam, + None, + ), + entranceProp.actor, + obj.name, + ) + elif obj.ootEmptyType == "Water Box": + ootProcessWaterBox(sceneObj, obj, transformMatrix, scene, room.roomIndex) + elif isinstance(obj.data, bpy.types.Camera): + camPosProp = obj.ootCameraPositionProperty + readCamPos(camPosProp, obj, scene, sceneObj, transformMatrix) + elif isinstance(obj.data, bpy.types.Curve) and assertCurveValid(obj): + readPathProp(obj.ootSplineProperty, obj, scene, sceneObj, scene.name, transformMatrix) + + for childObj in obj.children: + ootProcessEmpties(scene, room, sceneObj, childObj, transformMatrix) + - if obj.data is None: - if obj.ootEmptyType == "Actor": - actorProp = obj.ootActorProperty - addActor(room, OOTActor(getCustomProperty(actorProp, 'actorID'), - translation, rotation, actorProp.actorParam, - None if not actorProp.rotOverride else (actorProp.rotOverrideX, actorProp.rotOverrideY, actorProp.rotOverrideZ)), - actorProp, "actorList", obj.name) - elif obj.ootEmptyType == "Transition Actor": - transActorProp = obj.ootTransitionActorProperty - addActor(scene, OOTTransitionActor( - getCustomProperty(transActorProp.actor, "actorID"), - room.roomIndex, transActorProp.roomIndex, - getCustomProperty(transActorProp, "cameraTransitionFront"), - getCustomProperty(transActorProp, "cameraTransitionBack"), - translation, rotation[1], # TODO: Correct axis? - transActorProp.actor.actorParam), transActorProp.actor, "transitionActorList", obj.name) - #scene.transitionActorList.append(OOTTransitionActor( - # getCustomProperty(transActorProp.actor, "actorID"), - # room.roomIndex, transActorProp.roomIndex, - # getCustomProperty(transActorProp, "cameraTransitionFront"), - # getCustomProperty(transActorProp, "cameraTransitionBack"), - # translation, rotation[1], # TODO: Correct axis? - # transActorProp.actor.actorParam)) - elif obj.ootEmptyType == "Entrance": - entranceProp = obj.ootEntranceProperty - spawnIndex = obj.ootEntranceProperty.spawnIndex - addActor(scene, OOTEntrance(room.roomIndex, spawnIndex), entranceProp.actor, "entranceList", obj.name) - #scene.entranceList.append(OOTEntrance(room.roomIndex, spawnIndex)) - addStartPosition(scene, spawnIndex, OOTActor( - "ACTOR_PLAYER" if not entranceProp.customActor else entranceProp.actor.actorIDCustom, - translation, rotation, entranceProp.actor.actorParam, None), entranceProp.actor, obj.name) - elif obj.ootEmptyType == "Water Box": - ootProcessWaterBox(sceneObj, obj, transformMatrix, scene, room.roomIndex) - elif isinstance(obj.data, bpy.types.Camera): - camPosProp = obj.ootCameraPositionProperty - readCamPos(camPosProp, obj, scene, sceneObj, transformMatrix) - elif isinstance(obj.data, bpy.types.Curve) and assertCurveValid(obj): - readPathProp(obj.ootSplineProperty, obj, scene, sceneObj, scene.name, transformMatrix) - - for childObj in obj.children: - ootProcessEmpties(scene, room, sceneObj, childObj, transformMatrix) - def ootProcessWaterBox(sceneObj, obj, transformMatrix, scene, roomIndex): - translation, rotation, scale, orientedRotation = getConvertedTransform(transformMatrix, sceneObj, obj, True) + translation, rotation, scale, orientedRotation = getConvertedTransform(transformMatrix, sceneObj, obj, True) + + checkIdentityRotation(obj, orientedRotation, False) + waterBoxProp = obj.ootWaterBoxProperty + scene.collision.waterBoxes.append( + OOTWaterBox( + roomIndex, + getCustomProperty(waterBoxProp, "lighting"), + getCustomProperty(waterBoxProp, "camera"), + translation, + scale, + obj.empty_display_size, + ) + ) - checkIdentityRotation(obj, orientedRotation, False) - waterBoxProp = obj.ootWaterBoxProperty - scene.collision.waterBoxes.append(OOTWaterBox( - roomIndex, - getCustomProperty(waterBoxProp, "lighting"), - getCustomProperty(waterBoxProp, "camera"), - translation, scale, obj.empty_display_size)) class OOT_ExportScene(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.oot_export_level' - bl_label = "Export Scene" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.oot_export_level" + bl_label = "Export Scene" + bl_options = {"REGISTER", "UNDO", "PRESET"} - def execute(self, context): - activeObj = None - try: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") - activeObj = context.view_layer.objects.active - - obj = context.scene.ootSceneExportObj - if obj is None: - raise PluginError("Scene object input not set.") - elif obj.data is not None or obj.ootEmptyType != 'Scene': - raise PluginError("The input object is not an empty with the Scene type.") + def execute(self, context): + activeObj = None + try: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + activeObj = context.view_layer.objects.active - #obj = context.active_object + obj = context.scene.ootSceneExportObj + if obj is None: + raise PluginError("Scene object input not set.") + elif obj.data is not None or obj.ootEmptyType != "Scene": + raise PluginError("The input object is not an empty with the Scene type.") - scaleValue = bpy.context.scene.ootBlenderScale - finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector(( - scaleValue, scaleValue, scaleValue))).to_4x4() - - except Exception as e: - raisePluginError(self, e) - return {'CANCELLED'} # must return a set - try: - levelName = context.scene.ootSceneName - if context.scene.ootSceneCustomExport: - exportInfo = ExportInfo(True, bpy.path.abspath(context.scene.ootSceneExportPath), None, levelName) - else: - if context.scene.ootSceneOption == 'Custom': - subfolder = 'assets/scenes/' + context.scene.ootSceneSubFolder + '/' - else: - levelName = sceneNameFromID(context.scene.ootSceneOption) - subfolder = None - exportInfo = ExportInfo(False, bpy.path.abspath(context.scene.ootDecompPath), subfolder, levelName) - #if not context.scene.ootSceneCustomExport: - # applyBasicTweaks(exportPath) + # obj = context.active_object - ootExportSceneToC(obj, finalTransform, - context.scene.f3d_type, context.scene.isHWv1, levelName, DLFormat.Static, - context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, exportInfo) - - #ootExportScene(obj, finalTransform, - # context.scene.f3d_type, context.scene.isHWv1, levelName, exportPath, - # context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, - # context.scene.ootSceneCustomExport, DLFormat.Dynamic) - self.report({'INFO'}, 'Success!') + scaleValue = bpy.context.scene.ootBlenderScale + finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector((scaleValue, scaleValue, scaleValue))).to_4x4() - context.view_layer.objects.active = activeObj - if activeObj is not None: - activeObj.select_set(True) + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} # must return a set + try: + levelName = context.scene.ootSceneName + if context.scene.ootSceneCustomExport: + exportInfo = ExportInfo(True, bpy.path.abspath(context.scene.ootSceneExportPath), None, levelName) + else: + if context.scene.ootSceneOption == "Custom": + subfolder = "assets/scenes/" + context.scene.ootSceneSubFolder + "/" + else: + levelName = sceneNameFromID(context.scene.ootSceneOption) + subfolder = None + exportInfo = ExportInfo(False, bpy.path.abspath(context.scene.ootDecompPath), subfolder, levelName) + # if not context.scene.ootSceneCustomExport: + # applyBasicTweaks(exportPath) - #applyRotation(obj.children, math.radians(0), 'X') - return {'FINISHED'} # must return a set + ootExportSceneToC( + obj, + finalTransform, + context.scene.f3d_type, + context.scene.isHWv1, + levelName, + DLFormat.Static, + context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, + exportInfo, + ) + + # ootExportScene(obj, finalTransform, + # context.scene.f3d_type, context.scene.isHWv1, levelName, exportPath, + # context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, + # context.scene.ootSceneCustomExport, DLFormat.Dynamic) + self.report({"INFO"}, "Success!") + + context.view_layer.objects.active = activeObj + if activeObj is not None: + activeObj.select_set(True) + + # applyRotation(obj.children, math.radians(0), 'X') + return {"FINISHED"} # must return a set + + except Exception as e: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + context.view_layer.objects.active = activeObj + if activeObj is not None: + activeObj.select_set(True) + raisePluginError(self, e) + return {"CANCELLED"} # must return a set - except Exception as e: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') - context.view_layer.objects.active = activeObj - if activeObj is not None: - activeObj.select_set(True) - raisePluginError(self, e) - return {'CANCELLED'} # must return a set def ootRemoveSceneC(exportInfo): - modifySceneTable(None, exportInfo) - modifySegmentDefinition(None, exportInfo, None) - deleteSceneFiles(exportInfo) + modifySceneTable(None, exportInfo) + modifySegmentDefinition(None, exportInfo, None) + deleteSceneFiles(exportInfo) + class OOT_RemoveScene(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.oot_remove_level' - bl_label = "Remove Scene" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.oot_remove_level" + bl_label = "Remove Scene" + bl_options = {"REGISTER", "UNDO", "PRESET"} - def execute(self, context): - levelName = context.scene.ootSceneName - if context.scene.ootSceneCustomExport: - operator.report({'ERROR'}, "You can only remove scenes from your decomp path.") - return {"FINISHED"} - - if context.scene.ootSceneOption == 'Custom': - subfolder = 'assets/scenes/' + context.scene.ootSceneSubFolder + '/' - else: - levelName = sceneNameFromID(context.scene.ootSceneOption) - subfolder = None - exportInfo = ExportInfo(False, bpy.path.abspath(context.scene.ootDecompPath), subfolder, levelName) - - ootRemoveSceneC(exportInfo) + def execute(self, context): + levelName = context.scene.ootSceneName + if context.scene.ootSceneCustomExport: + operator.report({"ERROR"}, "You can only remove scenes from your decomp path.") + return {"FINISHED"} + + if context.scene.ootSceneOption == "Custom": + subfolder = "assets/scenes/" + context.scene.ootSceneSubFolder + "/" + else: + levelName = sceneNameFromID(context.scene.ootSceneOption) + subfolder = None + exportInfo = ExportInfo(False, bpy.path.abspath(context.scene.ootDecompPath), subfolder, levelName) + + ootRemoveSceneC(exportInfo) + + self.report({"INFO"}, "Success!") + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Success!') - return {'FINISHED'} # must return a set class OOT_ExportScenePanel(OOT_Panel): - bl_idname = "OOT_PT_export_level" - bl_label = "OOT Scene Exporter" + bl_idname = "OOT_PT_export_level" + bl_label = "OOT Scene Exporter" + + # called every frame + def draw(self, context): + col = self.layout.column() + col.operator(OOT_ExportScene.bl_idname) + # if not bpy.context.scene.ignoreTextureRestrictions: + # col.prop(context.scene, 'saveTextures') + prop_split(col, context.scene, "ootSceneExportObj", "Scene Object") + col.prop(context.scene, "ootSceneSingleFile") + col.prop(context.scene, "ootSceneCustomExport") + if context.scene.ootSceneCustomExport: + prop_split(col, context.scene, "ootSceneExportPath", "Directory") + prop_split(col, context.scene, "ootSceneName", "Name") + customExportWarning(col) + else: + col.operator(OOT_SearchSceneEnumOperator.bl_idname, icon="VIEWZOOM") + col.box().column().label(text=getEnumName(ootEnumSceneID, context.scene.ootSceneOption)) + # col.prop(context.scene, 'ootSceneOption') + if context.scene.ootSceneOption == "Custom": + prop_split(col, context.scene, "ootSceneSubFolder", "Subfolder") + prop_split(col, context.scene, "ootSceneName", "Name") + col.operator(OOT_RemoveScene.bl_idname) - # called every frame - def draw(self, context): - col = self.layout.column() - col.operator(OOT_ExportScene.bl_idname) - #if not bpy.context.scene.ignoreTextureRestrictions: - # col.prop(context.scene, 'saveTextures') - prop_split(col, context.scene, 'ootSceneExportObj', "Scene Object") - col.prop(context.scene, 'ootSceneSingleFile') - col.prop(context.scene, 'ootSceneCustomExport') - if context.scene.ootSceneCustomExport: - prop_split(col, context.scene, 'ootSceneExportPath', 'Directory') - prop_split(col, context.scene, 'ootSceneName', 'Name') - customExportWarning(col) - else: - col.operator(OOT_SearchSceneEnumOperator.bl_idname, icon = 'VIEWZOOM') - col.box().column().label(text = getEnumName(ootEnumSceneID, context.scene.ootSceneOption)) - #col.prop(context.scene, 'ootSceneOption') - if context.scene.ootSceneOption == 'Custom': - prop_split(col, context.scene, 'ootSceneSubFolder', 'Subfolder') - prop_split(col, context.scene, 'ootSceneName', 'Name') - col.operator(OOT_RemoveScene.bl_idname) def isSceneObj(self, obj): - return obj.data is None and obj.ootEmptyType == "Scene" + return obj.data is None and obj.ootEmptyType == "Scene" + oot_level_classes = ( - OOT_ExportScene, - OOT_RemoveScene, + OOT_ExportScene, + OOT_RemoveScene, ) -oot_level_panel_classes = ( - OOT_ExportScenePanel, -) +oot_level_panel_classes = (OOT_ExportScenePanel,) + def oot_level_panel_register(): - for cls in oot_level_panel_classes: - register_class(cls) + for cls in oot_level_panel_classes: + register_class(cls) + def oot_level_panel_unregister(): - for cls in oot_level_panel_classes: - unregister_class(cls) + for cls in oot_level_panel_classes: + unregister_class(cls) + def oot_level_register(): - for cls in oot_level_classes: - register_class(cls) - - bpy.types.Scene.ootSceneName = bpy.props.StringProperty(name = 'Name', default = 'spot03') - bpy.types.Scene.ootSceneSubFolder = bpy.props.StringProperty(name = "Subfolder", default = 'overworld') - bpy.types.Scene.ootSceneOption = bpy.props.EnumProperty(name = "Scene", items = ootEnumSceneID, default = 'SCENE_YDAN') - bpy.types.Scene.ootSceneExportPath = bpy.props.StringProperty( - name = 'Directory', subtype = 'FILE_PATH') - bpy.types.Scene.ootSceneCustomExport = bpy.props.BoolProperty( - name = 'Custom Export Path') - bpy.types.Scene.ootSceneExportObj = bpy.props.PointerProperty(type = bpy.types.Object, poll = isSceneObj) - bpy.types.Scene.ootSceneSingleFile = bpy.props.BoolProperty( - name = "Export as Single File", - default = False, - description = "Does not split the scene and rooms into multiple files.") + for cls in oot_level_classes: + register_class(cls) + + bpy.types.Scene.ootSceneName = bpy.props.StringProperty(name="Name", default="spot03") + bpy.types.Scene.ootSceneSubFolder = bpy.props.StringProperty(name="Subfolder", default="overworld") + bpy.types.Scene.ootSceneOption = bpy.props.EnumProperty(name="Scene", items=ootEnumSceneID, default="SCENE_YDAN") + bpy.types.Scene.ootSceneExportPath = bpy.props.StringProperty(name="Directory", subtype="FILE_PATH") + bpy.types.Scene.ootSceneCustomExport = bpy.props.BoolProperty(name="Custom Export Path") + bpy.types.Scene.ootSceneExportObj = bpy.props.PointerProperty(type=bpy.types.Object, poll=isSceneObj) + bpy.types.Scene.ootSceneSingleFile = bpy.props.BoolProperty( + name="Export as Single File", + default=False, + description="Does not split the scene and rooms into multiple files.", + ) def oot_level_unregister(): - for cls in reversed(oot_level_classes): - unregister_class(cls) + for cls in reversed(oot_level_classes): + unregister_class(cls) - del bpy.types.Scene.ootSceneName - del bpy.types.Scene.ootSceneExportPath - del bpy.types.Scene.ootSceneCustomExport - del bpy.types.Scene.ootSceneOption - del bpy.types.Scene.ootSceneSubFolder - del bpy.types.Scene.ootSceneSingleFile + del bpy.types.Scene.ootSceneName + del bpy.types.Scene.ootSceneExportPath + del bpy.types.Scene.ootSceneCustomExport + del bpy.types.Scene.ootSceneOption + del bpy.types.Scene.ootSceneSubFolder + del bpy.types.Scene.ootSceneSingleFile diff --git a/fast64_internal/sm64/__init__.py b/fast64_internal/sm64/__init__.py index 1b04ade..ee2ed47 100644 --- a/fast64_internal/sm64/__init__.py +++ b/fast64_internal/sm64/__init__.py @@ -18,277 +18,277 @@ import bpy from bpy.utils import register_class, unregister_class enumRefreshVer = [ - ("Refresh 3", "Refresh 3", "Refresh 3"), - ("Refresh 4", "Refresh 4", "Refresh 4"), - ("Refresh 5", "Refresh 5", "Refresh 5"), - ("Refresh 6", "Refresh 6", "Refresh 6"), - ("Refresh 7", "Refresh 7", "Refresh 7"), - ("Refresh 8", "Refresh 8", "Refresh 8"), - ("Refresh 10", "Refresh 10", "Refresh 10"), - ("Refresh 11", "Refresh 11", "Refresh 11"), - ("Refresh 12", "Refresh 12", "Refresh 12"), - ("Refresh 13", "Refresh 13", "Refresh 13"), + ("Refresh 3", "Refresh 3", "Refresh 3"), + ("Refresh 4", "Refresh 4", "Refresh 4"), + ("Refresh 5", "Refresh 5", "Refresh 5"), + ("Refresh 6", "Refresh 6", "Refresh 6"), + ("Refresh 7", "Refresh 7", "Refresh 7"), + ("Refresh 8", "Refresh 8", "Refresh 8"), + ("Refresh 10", "Refresh 10", "Refresh 10"), + ("Refresh 11", "Refresh 11", "Refresh 11"), + ("Refresh 12", "Refresh 12", "Refresh 12"), + ("Refresh 13", "Refresh 13", "Refresh 13"), ] + class SM64_AddrConv(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.addr_conv' - bl_label = "Convert Address" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.addr_conv" + bl_label = "Convert Address" + bl_options = {"REGISTER", "UNDO", "PRESET"} - segToVirt : bpy.props.BoolProperty() + segToVirt: bpy.props.BoolProperty() + + def execute(self, context): + romfileSrc = None + try: + address = int(context.scene.convertibleAddr, 16) + importRom = context.scene.importRom + romfileSrc = open(bpy.path.abspath(importRom), "rb") + checkExpanded(bpy.path.abspath(importRom)) + levelParsed = parseLevelAtPointer(romfileSrc, level_pointers[context.scene.levelConvert]) + segmentData = levelParsed.segmentData + if self.segToVirt: + ptr = decodeSegmentedAddr(address.to_bytes(4, "big"), segmentData) + self.report({"INFO"}, "Virtual pointer is 0x" + format(ptr, "08X")) + else: + ptr = int.from_bytes(encodeSegmentedAddr(address, segmentData), "big") + self.report({"INFO"}, "Segmented pointer is 0x" + format(ptr, "08X")) + romfileSrc.close() + return {"FINISHED"} + except Exception as e: + if romfileSrc is not None: + romfileSrc.close() + raisePluginError(self, e) + return {"CANCELLED"} # must return a set - def execute(self, context): - romfileSrc = None - try: - address = int(context.scene.convertibleAddr, 16) - importRom = context.scene.importRom - romfileSrc = open(bpy.path.abspath(importRom), 'rb') - checkExpanded(bpy.path.abspath(importRom)) - levelParsed = parseLevelAtPointer(romfileSrc, - level_pointers[context.scene.levelConvert]) - segmentData = levelParsed.segmentData - if self.segToVirt: - ptr = decodeSegmentedAddr( - address.to_bytes(4, 'big'), segmentData) - self.report({'INFO'}, - 'Virtual pointer is 0x' + format(ptr, '08X')) - else: - ptr = int.from_bytes( - encodeSegmentedAddr(address, segmentData), 'big') - self.report({'INFO'}, - 'Segmented pointer is 0x' + format(ptr, '08X')) - romfileSrc.close() - return {'FINISHED'} - except Exception as e: - if romfileSrc is not None: - romfileSrc.close() - raisePluginError(self, e) - return {'CANCELLED'} # must return a set class SM64_MenuVisibilityPanel(SM64_Panel): - bl_idname = "SM64_PT_menu_visibility_settings" - bl_label = "SM64 Menu Visibility Settings" - bl_options = set() # default to open - bl_order = 0 # force to front + bl_idname = "SM64_PT_menu_visibility_settings" + bl_label = "SM64 Menu Visibility Settings" + bl_options = set() # default to open + bl_order = 0 # force to front - def draw(self, context): - col = self.layout.column() - col.scale_y = 1.1 # extra padding - sm64Props: SM64_Properties = context.scene.fast64.sm64 + def draw(self, context): + col = self.layout.column() + col.scale_y = 1.1 # extra padding + sm64Props: SM64_Properties = context.scene.fast64.sm64 + + prop_split(col, sm64Props, "goal", "Export goal") + prop_split(col, sm64Props, "showImportingMenus", "Show Importing Options") - prop_split(col, sm64Props, 'goal', 'Export goal') - prop_split(col, sm64Props, 'showImportingMenus', 'Show Importing Options') class SM64_FileSettingsPanel(SM64_Panel): - bl_idname = "SM64_PT_file_settings" - bl_label = "SM64 File Settings" - bl_options = set() + bl_idname = "SM64_PT_file_settings" + bl_label = "SM64 File Settings" + bl_options = set() - def draw(self, context): - col = self.layout.column() - col.scale_y = 1.1 # extra padding - sm64Props: SM64_Properties = context.scene.fast64.sm64 + def draw(self, context): + col = self.layout.column() + col.scale_y = 1.1 # extra padding + sm64Props: SM64_Properties = context.scene.fast64.sm64 - prop_split(col, sm64Props, 'exportType', 'Export type') - prop_split(col, context.scene, 'blenderToSM64Scale', 'Blender To SM64 Scale') + prop_split(col, sm64Props, "exportType", "Export type") + prop_split(col, context.scene, "blenderToSM64Scale", "Blender To SM64 Scale") - if sm64Props.showImportingMenus: - col.prop(context.scene, 'importRom') + if sm64Props.showImportingMenus: + col.prop(context.scene, "importRom") + + if sm64Props.exportType == "Binary": + col.prop(context.scene, "exportRom") + col.prop(context.scene, "outputRom") + col.prop(context.scene, "extendBank4") + elif sm64Props.exportType == "C": + col.prop(context.scene, "disableScroll") + col.prop(context.scene, "decompPath") + prop_split(col, context.scene, "refreshVer", "Decomp Func Map") + prop_split(col, context.scene, "compressionFormat", "Compression Format") - if sm64Props.exportType == 'Binary': - col.prop(context.scene, 'exportRom') - col.prop(context.scene, 'outputRom') - col.prop(context.scene, 'extendBank4') - elif sm64Props.exportType == 'C': - col.prop(context.scene, 'disableScroll') - col.prop(context.scene, 'decompPath') - prop_split(col, context.scene, 'refreshVer', 'Decomp Func Map') - prop_split(col, context.scene, 'compressionFormat', 'Compression Format') class SM64_AddressConvertPanel(SM64_Panel): - bl_idname = "SM64_PT_addr_conv" - bl_label = "SM64 Address Converter" - goal = sm64GoalImport + bl_idname = "SM64_PT_addr_conv" + bl_label = "SM64 Address Converter" + goal = sm64GoalImport + + def draw(self, context): + col = self.layout.column() + segToVirtOp = col.operator(SM64_AddrConv.bl_idname, text="Convert Segmented To Virtual") + segToVirtOp.segToVirt = True + virtToSegOp = col.operator(SM64_AddrConv.bl_idname, text="Convert Virtual To Segmented") + virtToSegOp.segToVirt = False + prop_split(col, context.scene, "convertibleAddr", "Address") + col.prop(context.scene, "levelConvert") - def draw(self, context): - col = self.layout.column() - segToVirtOp = col.operator(SM64_AddrConv.bl_idname, - text = "Convert Segmented To Virtual") - segToVirtOp.segToVirt = True - virtToSegOp = col.operator(SM64_AddrConv.bl_idname, - text = "Convert Virtual To Segmented") - virtToSegOp.segToVirt = False - prop_split(col, context.scene, 'convertibleAddr', 'Address') - col.prop(context.scene, 'levelConvert') def get_legacy_export_type(): - legacy_export_types = ('C', 'Binary', 'Insertable Binary') - scene = bpy.context.scene + legacy_export_types = ("C", "Binary", "Insertable Binary") + scene = bpy.context.scene - for exportKey in ['animExportType', 'colExportType', 'DLExportType', 'geoExportType']: - eType = scene.pop(exportKey, None) - if eType is not None and legacy_export_types[eType] != 'C': - return legacy_export_types[eType] + for exportKey in ["animExportType", "colExportType", "DLExportType", "geoExportType"]: + eType = scene.pop(exportKey, None) + if eType is not None and legacy_export_types[eType] != "C": + return legacy_export_types[eType] + + return "C" - return 'C' class SM64_Properties(bpy.types.PropertyGroup): - '''Global SM64 Scene Properties found under scene.fast64.sm64''' - version: bpy.props.IntProperty(name="SM64_Properties Version", default=0) - cur_version = 1 # version after property migration + """Global SM64 Scene Properties found under scene.fast64.sm64""" - # UI Selection - showImportingMenus: bpy.props.BoolProperty(name='Show Importing Menus', default=False) - exportType: bpy.props.EnumProperty(items = enumExportType, name = 'Export Type', default = 'C') - goal: bpy.props.EnumProperty(items=sm64GoalTypeEnum, name = 'Export Goal', default = 'All') - - # TODO: Utilize these across all exports - # C exporting - # useCustomExportLocation = bpy.props.BoolProperty(name = 'Use Custom Export Path') - # customExportPath: bpy.props.StringProperty(name = 'Custom Export Path', subtype = 'FILE_PATH') - # exportLocation: bpy.props.EnumProperty(items = enumExportHeaderType, name = 'Export Location', default = 'Actor') - # useSelectedObjectName = bpy.props.BoolProperty(name = 'Use Name From Selected Object', default=False) - # exportName: bpy.props.StringProperty(name='Name', default='mario') - # exportGeolayoutName: bpy.props.StringProperty(name='Name', default='mario_geo') + version: bpy.props.IntProperty(name="SM64_Properties Version", default=0) + cur_version = 1 # version after property migration - # Actor exports - # exportGroup: bpy.props.StringProperty(name='Group', default='group0') + # UI Selection + showImportingMenus: bpy.props.BoolProperty(name="Show Importing Menus", default=False) + exportType: bpy.props.EnumProperty(items=enumExportType, name="Export Type", default="C") + goal: bpy.props.EnumProperty(items=sm64GoalTypeEnum, name="Export Goal", default="All") - # Level exports - # exportLevelName: bpy.props.StringProperty(name = 'Level', default = 'bob') - # exportLevelOption: bpy.props.EnumProperty(items = enumLevelNames, name = 'Level', default = 'bob') + # TODO: Utilize these across all exports + # C exporting + # useCustomExportLocation = bpy.props.BoolProperty(name = 'Use Custom Export Path') + # customExportPath: bpy.props.StringProperty(name = 'Custom Export Path', subtype = 'FILE_PATH') + # exportLocation: bpy.props.EnumProperty(items = enumExportHeaderType, name = 'Export Location', default = 'Actor') + # useSelectedObjectName = bpy.props.BoolProperty(name = 'Use Name From Selected Object', default=False) + # exportName: bpy.props.StringProperty(name='Name', default='mario') + # exportGeolayoutName: bpy.props.StringProperty(name='Name', default='mario_geo') - # Insertable Binary - # exportInsertableBinaryPath: bpy.props.StringProperty(name = 'Filepath', subtype = 'FILE_PATH') + # Actor exports + # exportGroup: bpy.props.StringProperty(name='Group', default='group0') - @staticmethod - def upgrade_changed_props(): - if bpy.context.scene.fast64.sm64.version != SM64_Properties.cur_version: - bpy.context.scene.fast64.sm64.exportType = get_legacy_export_type() - bpy.context.scene.fast64.sm64.version = SM64_Properties.cur_version + # Level exports + # exportLevelName: bpy.props.StringProperty(name = 'Level', default = 'bob') + # exportLevelOption: bpy.props.EnumProperty(items = enumLevelNames, name = 'Level', default = 'bob') + + # Insertable Binary + # exportInsertableBinaryPath: bpy.props.StringProperty(name = 'Filepath', subtype = 'FILE_PATH') + + @staticmethod + def upgrade_changed_props(): + if bpy.context.scene.fast64.sm64.version != SM64_Properties.cur_version: + bpy.context.scene.fast64.sm64.exportType = get_legacy_export_type() + bpy.context.scene.fast64.sm64.version = SM64_Properties.cur_version sm64_classes = ( - SM64_AddrConv, - SM64_Properties, + SM64_AddrConv, + SM64_Properties, ) sm64_panel_classes = ( - SM64_MenuVisibilityPanel, - SM64_FileSettingsPanel, - SM64_AddressConvertPanel, + SM64_MenuVisibilityPanel, + SM64_FileSettingsPanel, + SM64_AddressConvertPanel, ) -def sm64_panel_register(): - for cls in sm64_panel_classes: - register_class(cls) - sm64_col_panel_register() - sm64_bone_panel_register() - sm64_cam_panel_register() - sm64_obj_panel_register() - sm64_geo_parser_panel_register() - sm64_geo_writer_panel_register() - sm64_level_panel_register() - sm64_spline_panel_register() - sm64_dl_writer_panel_register() - sm64_dl_parser_panel_register() - sm64_anim_panel_register() +def sm64_panel_register(): + for cls in sm64_panel_classes: + register_class(cls) + + sm64_col_panel_register() + sm64_bone_panel_register() + sm64_cam_panel_register() + sm64_obj_panel_register() + sm64_geo_parser_panel_register() + sm64_geo_writer_panel_register() + sm64_level_panel_register() + sm64_spline_panel_register() + sm64_dl_writer_panel_register() + sm64_dl_parser_panel_register() + sm64_anim_panel_register() + def sm64_panel_unregister(): - for cls in sm64_panel_classes: - unregister_class(cls) + for cls in sm64_panel_classes: + unregister_class(cls) + + sm64_col_panel_unregister() + sm64_bone_panel_unregister() + sm64_cam_panel_unregister() + sm64_obj_panel_unregister() + sm64_geo_parser_panel_unregister() + sm64_geo_writer_panel_unregister() + sm64_level_panel_unregister() + sm64_spline_panel_unregister() + sm64_dl_writer_panel_unregister() + sm64_dl_parser_panel_unregister() + sm64_anim_panel_unregister() - sm64_col_panel_unregister() - sm64_bone_panel_unregister() - sm64_cam_panel_unregister() - sm64_obj_panel_unregister() - sm64_geo_parser_panel_unregister() - sm64_geo_writer_panel_unregister() - sm64_level_panel_unregister() - sm64_spline_panel_unregister() - sm64_dl_writer_panel_unregister() - sm64_dl_parser_panel_unregister() - sm64_anim_panel_unregister() def sm64_register(registerPanels): - for cls in sm64_classes: - register_class(cls) + for cls in sm64_classes: + register_class(cls) - sm64_col_register() # register first, so panel goes above mat panel - sm64_bone_register() - sm64_cam_register() - sm64_obj_register() - sm64_geo_parser_register() - sm64_geo_writer_register() - sm64_level_register() - sm64_spline_register() - sm64_dl_writer_register() - sm64_dl_parser_register() - sm64_anim_register() + sm64_col_register() # register first, so panel goes above mat panel + sm64_bone_register() + sm64_cam_register() + sm64_obj_register() + sm64_geo_parser_register() + sm64_geo_writer_register() + sm64_level_register() + sm64_spline_register() + sm64_dl_writer_register() + sm64_dl_parser_register() + sm64_anim_register() - if registerPanels: - sm64_panel_register() + if registerPanels: + sm64_panel_register() - bpy.types.Scene.importRom = bpy.props.StringProperty( - name ='Import ROM', subtype = 'FILE_PATH') - bpy.types.Scene.exportRom = bpy.props.StringProperty( - name ='Export ROM', subtype = 'FILE_PATH') - bpy.types.Scene.outputRom = bpy.props.StringProperty( - name ='Output ROM', subtype = 'FILE_PATH') - bpy.types.Scene.extendBank4 = bpy.props.BoolProperty( - name = 'Extend Bank 4 on Export?', default = True, - description = 'Sets bank 4 range to (' +\ - hex(defaultExtendSegment4[0]) + ', ' + \ - hex(defaultExtendSegment4[1]) + ') and copies data from old bank') - bpy.types.Scene.convertibleAddr = bpy.props.StringProperty( - name = 'Address') - bpy.types.Scene.levelConvert = bpy.props.EnumProperty( - items = level_enums, name = 'Level', default = 'IC') - bpy.types.Scene.refreshVer = bpy.props.EnumProperty( - items = enumRefreshVer, name = 'Refresh', default = 'Refresh 13') - bpy.types.Scene.disableScroll = bpy.props.BoolProperty( - name = 'Disable Scrolling Textures') + bpy.types.Scene.importRom = bpy.props.StringProperty(name="Import ROM", subtype="FILE_PATH") + bpy.types.Scene.exportRom = bpy.props.StringProperty(name="Export ROM", subtype="FILE_PATH") + bpy.types.Scene.outputRom = bpy.props.StringProperty(name="Output ROM", subtype="FILE_PATH") + bpy.types.Scene.extendBank4 = bpy.props.BoolProperty( + name="Extend Bank 4 on Export?", + default=True, + description="Sets bank 4 range to (" + + hex(defaultExtendSegment4[0]) + + ", " + + hex(defaultExtendSegment4[1]) + + ") and copies data from old bank", + ) + bpy.types.Scene.convertibleAddr = bpy.props.StringProperty(name="Address") + bpy.types.Scene.levelConvert = bpy.props.EnumProperty(items=level_enums, name="Level", default="IC") + bpy.types.Scene.refreshVer = bpy.props.EnumProperty(items=enumRefreshVer, name="Refresh", default="Refresh 13") + bpy.types.Scene.disableScroll = bpy.props.BoolProperty(name="Disable Scrolling Textures") + + bpy.types.Scene.blenderToSM64Scale = bpy.props.FloatProperty(name="Blender To SM64 Scale", default=100) # 212.766 + bpy.types.Scene.decompPath = bpy.props.StringProperty(name="Decomp Folder", subtype="FILE_PATH") + + bpy.types.Scene.compressionFormat = bpy.props.EnumProperty( + items=enumCompressionFormat, name="Compression", default="mio0" + ) - bpy.types.Scene.blenderToSM64Scale = bpy.props.FloatProperty( - name = 'Blender To SM64 Scale', default = 100) # 212.766 - bpy.types.Scene.decompPath = bpy.props.StringProperty( - name ='Decomp Folder', subtype = 'FILE_PATH') - - bpy.types.Scene.compressionFormat = bpy.props.EnumProperty( - items = enumCompressionFormat, name = 'Compression', default = 'mio0') def sm64_unregister(unregisterPanels): - for cls in reversed(sm64_classes): - unregister_class(cls) + for cls in reversed(sm64_classes): + unregister_class(cls) - sm64_col_unregister() # register first, so panel goes above mat panel - sm64_bone_unregister() - sm64_cam_unregister() - sm64_obj_unregister() - sm64_geo_parser_unregister() - sm64_geo_writer_unregister() - sm64_level_unregister() - sm64_spline_unregister() - sm64_dl_writer_unregister() - sm64_dl_parser_unregister() - sm64_anim_unregister() + sm64_col_unregister() # register first, so panel goes above mat panel + sm64_bone_unregister() + sm64_cam_unregister() + sm64_obj_unregister() + sm64_geo_parser_unregister() + sm64_geo_writer_unregister() + sm64_level_unregister() + sm64_spline_unregister() + sm64_dl_writer_unregister() + sm64_dl_parser_unregister() + sm64_anim_unregister() - if unregisterPanels: - sm64_panel_unregister() + if unregisterPanels: + sm64_panel_unregister() - del bpy.types.Scene.importRom - del bpy.types.Scene.exportRom - del bpy.types.Scene.outputRom - del bpy.types.Scene.extendBank4 - - del bpy.types.Scene.convertibleAddr - del bpy.types.Scene.levelConvert - del bpy.types.Scene.refreshVer + del bpy.types.Scene.importRom + del bpy.types.Scene.exportRom + del bpy.types.Scene.outputRom + del bpy.types.Scene.extendBank4 - del bpy.types.Scene.disableScroll - - del bpy.types.Scene.blenderToSM64Scale - del bpy.types.Scene.decompPath - del bpy.types.Scene.compressionFormat + del bpy.types.Scene.convertibleAddr + del bpy.types.Scene.levelConvert + del bpy.types.Scene.refreshVer + + del bpy.types.Scene.disableScroll + + del bpy.types.Scene.blenderToSM64Scale + del bpy.types.Scene.decompPath + del bpy.types.Scene.compressionFormat diff --git a/fast64_internal/sm64/sm64_f3d_writer.py b/fast64_internal/sm64/sm64_f3d_writer.py index c11f2b2..3e59bbb 100644 --- a/fast64_internal/sm64/sm64_f3d_writer.py +++ b/fast64_internal/sm64/sm64_f3d_writer.py @@ -7,935 +7,1043 @@ from ..f3d.f3d_gbi import FMaterial from .sm64_texscroll import * from .sm64_utility import * from bpy.utils import register_class, unregister_class -from .sm64_constants import level_enums, enumLevelNames, level_pointers, defaultExtendSegment4, bank0Segment, insertableBinaryTypes +from .sm64_constants import ( + level_enums, + enumLevelNames, + level_pointers, + defaultExtendSegment4, + bank0Segment, + insertableBinaryTypes, +) from .sm64_level_parser import parseLevelAtPointer from .sm64_rom_tweaks import ExtendBank0x04 enumHUDExportLocation = [ - ('HUD', 'HUD', 'Exports to src/game/hud.c'), - ('Menu', 'Menu', 'Exports to src/game/ingame_menu.c') + ("HUD", "HUD", "Exports to src/game/hud.c"), + ("Menu", "Menu", "Exports to src/game/ingame_menu.c"), ] # filepath, function to insert before enumHUDPaths = { - "HUD" : ('src/game/hud.c', 'void render_hud(void)'), - 'Menu' : ('src/game/ingame_menu.c', 's16 render_menus_and_dialogs()'), + "HUD": ("src/game/hud.c", "void render_hud(void)"), + "Menu": ("src/game/ingame_menu.c", "s16 render_menus_and_dialogs()"), } + class SM64Model(FModel): - def __init__(self, f3dType, isHWv1, name, DLFormat): - FModel.__init__(self, f3dType, isHWv1, name, DLFormat, GfxMatWriteMethod.WriteDifferingAndRevert) + def __init__(self, f3dType, isHWv1, name, DLFormat): + FModel.__init__(self, f3dType, isHWv1, name, DLFormat, GfxMatWriteMethod.WriteDifferingAndRevert) - def getDrawLayerV3(self, obj): - return int(obj.draw_layer_static) + def getDrawLayerV3(self, obj): + return int(obj.draw_layer_static) + + def getRenderMode(self, drawLayer): + cycle1 = getattr(bpy.context.scene.world, "draw_layer_" + str(drawLayer) + "_cycle_1") + cycle2 = getattr(bpy.context.scene.world, "draw_layer_" + str(drawLayer) + "_cycle_2") + return [cycle1, cycle2] - def getRenderMode(self, drawLayer): - cycle1 = getattr(bpy.context.scene.world, 'draw_layer_' + str(drawLayer) + '_cycle_1') - cycle2 = getattr(bpy.context.scene.world, 'draw_layer_' + str(drawLayer) + '_cycle_2') - return [cycle1, cycle2] class SM64GfxFormatter(GfxFormatter): - def __init__(self, scrollMethod: ScrollMethod): - self.functionNodeDraw = False - GfxFormatter.__init__(self, scrollMethod, 8) + def __init__(self, scrollMethod: ScrollMethod): + self.functionNodeDraw = False + GfxFormatter.__init__(self, scrollMethod, 8) - def vertexScrollToC(self, fMaterial: FMaterial, name: str, count: int): - fScrollData = fMaterial.scrollData - data = CData() - sts_data = CData() + def vertexScrollToC(self, fMaterial: FMaterial, name: str, count: int): + fScrollData = fMaterial.scrollData + data = CData() + sts_data = CData() - data.source = self.vertexScrollTemplate( - fScrollData, name, count, - 'absi', 'signum_positive', 'coss', 'random_float', 'random_sign', 'segmented_to_virtual' - ) - sts_data.source = self.tileScrollStaticMaterialToC(fMaterial) + data.source = self.vertexScrollTemplate( + fScrollData, + name, + count, + "absi", + "signum_positive", + "coss", + "random_float", + "random_sign", + "segmented_to_virtual", + ) + sts_data.source = self.tileScrollStaticMaterialToC(fMaterial) - scrollDataFields = fScrollData.fields[0] - if not((scrollDataFields[0].animType == "None") and\ - (scrollDataFields[1].animType == "None")): - data.header = 'extern void scroll_' + name + "();\n" + scrollDataFields = fScrollData.fields[0] + if not ((scrollDataFields[0].animType == "None") and (scrollDataFields[1].animType == "None")): + data.header = "extern void scroll_" + name + "();\n" - # self.tileScrollFunc is set in GfxFormatter.tileScrollStaticMaterialToC - if self.tileScrollFunc is not None: - sts_data.header = f'{self.tileScrollFunc}\n' - else: - sts_data = None + # self.tileScrollFunc is set in GfxFormatter.tileScrollStaticMaterialToC + if self.tileScrollFunc is not None: + sts_data.header = f"{self.tileScrollFunc}\n" + else: + sts_data = None - return data, sts_data + return data, sts_data - # This code is not functional, only used for an example - def drawToC(self, f3d, gfxList): - data = CData() - if self.functionNodeDraw: - data.header = 'Gfx* ' + self.name + '(s32 renderContext, struct GraphNode* node, struct AllocOnlyPool *a2);\n' - data.source = 'Gfx* ' + self.name + '(s32 renderContext, struct GraphNode* node, struct AllocOnlyPool *a2) {\n' +\ - '\tGfx* startCmd = NULL;\n' +\ - '\tGfx* glistp = NULL;\n' +\ - '\tstruct GraphNodeGenerated *generatedNode;\n' +\ - '\tif(renderContext == GEO_CONTEXT_RENDER) {\n' +\ - '\t\tgeneratedNode = (struct GraphNodeGenerated *) node;\n' +\ - '\t\tgeneratedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | (generatedNode->parameter << 8);\n' +\ - '\t\tstartCmd = glistp = alloc_display_list(sizeof(Gfx) * ' + \ - str(int(round(self.size_total(f3d) / GFX_SIZE))) + ');\n' +\ - '\t\tif(startCmd == NULL) return NULL;\n' + # This code is not functional, only used for an example + def drawToC(self, f3d, gfxList): + data = CData() + if self.functionNodeDraw: + data.header = ( + "Gfx* " + self.name + "(s32 renderContext, struct GraphNode* node, struct AllocOnlyPool *a2);\n" + ) + data.source = ( + "Gfx* " + + self.name + + "(s32 renderContext, struct GraphNode* node, struct AllocOnlyPool *a2) {\n" + + "\tGfx* startCmd = NULL;\n" + + "\tGfx* glistp = NULL;\n" + + "\tstruct GraphNodeGenerated *generatedNode;\n" + + "\tif(renderContext == GEO_CONTEXT_RENDER) {\n" + + "\t\tgeneratedNode = (struct GraphNodeGenerated *) node;\n" + + "\t\tgeneratedNode->fnNode.node.flags = (generatedNode->fnNode.node.flags & 0xFF) | (generatedNode->parameter << 8);\n" + + "\t\tstartCmd = glistp = alloc_display_list(sizeof(Gfx) * " + + str(int(round(self.size_total(f3d) / GFX_SIZE))) + + ");\n" + + "\t\tif(startCmd == NULL) return NULL;\n" + ) - for command in self.commands: - if isinstance(command, SPDisplayList) and command.displayList.tag == GfxListTag.Material: - data.source += '\t' + 'glistp = ' + command.displayList.name + '(glistp, gAreaUpdateCounter, gAreaUpdateCounter);\n' - else: - data.source += '\t' + command.to_c(False) + ';\n' + for command in self.commands: + if isinstance(command, SPDisplayList) and command.displayList.tag == GfxListTag.Material: + data.source += ( + "\t" + + "glistp = " + + command.displayList.name + + "(glistp, gAreaUpdateCounter, gAreaUpdateCounter);\n" + ) + else: + data.source += "\t" + command.to_c(False) + ";\n" - data.source += '\t}\n\treturn startCmd;\n}' - return data - else: - return gfxList.to_c(f3d) + data.source += "\t}\n\treturn startCmd;\n}" + return data + else: + return gfxList.to_c(f3d) - # This code is not functional, only used for an example - def tileScrollMaterialToC(self, f3d, fMaterial: FMaterial): - data = CData() + # This code is not functional, only used for an example + def tileScrollMaterialToC(self, f3d, fMaterial: FMaterial): + data = CData() - materialGfx = fMaterial.material - scrollDataFields = fMaterial.scrollData.fields + materialGfx = fMaterial.material + scrollDataFields = fMaterial.scrollData.fields - data.header = 'Gfx* ' + fMaterial.material.name + '(Gfx* glistp, int s, int t);\n' + data.header = "Gfx* " + fMaterial.material.name + "(Gfx* glistp, int s, int t);\n" - # Set tile scrolling - for texIndex in range(2): # for each texture - for axisIndex in range(2): # for each axis - scrollField = scrollDataFields[texIndex][axisIndex] - if scrollField.animType != "None": - if scrollField.animType == "Linear": - if axisIndex == 0: - fMaterial.tileSizeCommands[texIndex].uls = str(fMaterial.tileSizeCommands[0].uls) + \ - " + s * " + str(scrollField.speed) - else: - fMaterial.tileSizeCommands[texIndex].ult = str(fMaterial.tileSizeCommands[0].ult) + \ - " + s * " + str(scrollField.speed) + # Set tile scrolling + for texIndex in range(2): # for each texture + for axisIndex in range(2): # for each axis + scrollField = scrollDataFields[texIndex][axisIndex] + if scrollField.animType != "None": + if scrollField.animType == "Linear": + if axisIndex == 0: + fMaterial.tileSizeCommands[texIndex].uls = ( + str(fMaterial.tileSizeCommands[0].uls) + " + s * " + str(scrollField.speed) + ) + else: + fMaterial.tileSizeCommands[texIndex].ult = ( + str(fMaterial.tileSizeCommands[0].ult) + " + s * " + str(scrollField.speed) + ) - # Build commands - data.source = 'Gfx* ' + materialGfx.name + '(Gfx* glistp, int s, int t) {\n' - for command in materialGfx.commands: - data.source += '\t' + command.to_c(False) + ';\n' - data.source += '\treturn glistp;\n}' + '\n\n' + # Build commands + data.source = "Gfx* " + materialGfx.name + "(Gfx* glistp, int s, int t) {\n" + for command in materialGfx.commands: + data.source += "\t" + command.to_c(False) + ";\n" + data.source += "\treturn glistp;\n}" + "\n\n" - if fMaterial.revert is not None: - data.append(fMaterial.revert.to_c(f3d)) - return data + if fMaterial.revert is not None: + data.append(fMaterial.revert.to_c(f3d)) + return data -def exportTexRectToC(dirPath, texProp, f3dType, isHWv1, texDir, - savePNG, name, exportToProject, projectExportData): - fTexRect = exportTexRectCommon(texProp, f3dType, isHWv1, name, not savePNG) - if name is None or name == '': - raise PluginError("Name cannot be empty.") +def exportTexRectToC(dirPath, texProp, f3dType, isHWv1, texDir, savePNG, name, exportToProject, projectExportData): + fTexRect = exportTexRectCommon(texProp, f3dType, isHWv1, name, not savePNG) - exportData = fTexRect.to_c(savePNG, texDir, SM64GfxFormatter(ScrollMethod.Vertex)) - staticData = exportData.staticData - dynamicData = exportData.dynamicData + if name is None or name == "": + raise PluginError("Name cannot be empty.") - declaration = staticData.header - code = modifyDLForHUD(dynamicData.source) - data = staticData.source + exportData = fTexRect.to_c(savePNG, texDir, SM64GfxFormatter(ScrollMethod.Vertex)) + staticData = exportData.staticData + dynamicData = exportData.dynamicData - if exportToProject: - seg2CPath = os.path.join(dirPath, "bin/segment2.c") - seg2HPath = os.path.join(dirPath, "src/game/segment2.h") - seg2TexDir = os.path.join(dirPath, "textures/segment2") - hudPath = os.path.join(dirPath, projectExportData[0]) + declaration = staticData.header + code = modifyDLForHUD(dynamicData.source) + data = staticData.source - checkIfPathExists(seg2CPath) - checkIfPathExists(seg2HPath) - checkIfPathExists(seg2TexDir) - checkIfPathExists(hudPath) - - fTexRect.save_textures(seg2TexDir, not savePNG) + if exportToProject: + seg2CPath = os.path.join(dirPath, "bin/segment2.c") + seg2HPath = os.path.join(dirPath, "src/game/segment2.h") + seg2TexDir = os.path.join(dirPath, "textures/segment2") + hudPath = os.path.join(dirPath, projectExportData[0]) - textures = [] - for info, texture in fTexRect.textures.items(): - textures.append(texture) + checkIfPathExists(seg2CPath) + checkIfPathExists(seg2HPath) + checkIfPathExists(seg2TexDir) + checkIfPathExists(hudPath) - # Append/Overwrite texture definition to segment2.c - overwriteData('const\s*u8\s*', textures[0].name, data, seg2CPath, None, False) - - # Append texture declaration to segment2.h - writeIfNotFound(seg2HPath, declaration, '#endif') + fTexRect.save_textures(seg2TexDir, not savePNG) - # Write/Overwrite function to hud.c - overwriteData('void\s*', fTexRect.name, code, hudPath, projectExportData[1], True) + textures = [] + for info, texture in fTexRect.textures.items(): + textures.append(texture) - else: - singleFileData = '' - singleFileData += '// Copy this function to src/game/hud.c or src/game/ingame_menu.c.\n' - singleFileData += '// Call the function in render_hud() or render_menus_and_dialogs() respectively.\n' - singleFileData += code - singleFileData += '// Copy this declaration to src/game/segment2.h.\n' - singleFileData += declaration - singleFileData += '// Copy this texture data to bin/segment2.c\n' - singleFileData += '// If texture data is being included from an inc.c, make sure to copy the png to textures/segment2.\n' - singleFileData += data - singleFilePath = os.path.join(dirPath, fTexRect.name + '.c') - singleFile = open(singleFilePath, 'w', newline='\n') - singleFile.write(singleFileData) - singleFile.close() + # Append/Overwrite texture definition to segment2.c + overwriteData("const\s*u8\s*", textures[0].name, data, seg2CPath, None, False) + + # Append texture declaration to segment2.h + writeIfNotFound(seg2HPath, declaration, "#endif") + + # Write/Overwrite function to hud.c + overwriteData("void\s*", fTexRect.name, code, hudPath, projectExportData[1], True) + + else: + singleFileData = "" + singleFileData += "// Copy this function to src/game/hud.c or src/game/ingame_menu.c.\n" + singleFileData += "// Call the function in render_hud() or render_menus_and_dialogs() respectively.\n" + singleFileData += code + singleFileData += "// Copy this declaration to src/game/segment2.h.\n" + singleFileData += declaration + singleFileData += "// Copy this texture data to bin/segment2.c\n" + singleFileData += ( + "// If texture data is being included from an inc.c, make sure to copy the png to textures/segment2.\n" + ) + singleFileData += data + singleFilePath = os.path.join(dirPath, fTexRect.name + ".c") + singleFile = open(singleFilePath, "w", newline="\n") + singleFile.write(singleFileData) + singleFile.close() + + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") - if bpy.context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') def modifyDLForHUD(data): - # Use sm64 master dl pointer - data = re.sub('glistp', 'gDisplayListHead', data) + # Use sm64 master dl pointer + data = re.sub("glistp", "gDisplayListHead", data) - # Add positional arguments to drawing, along with negative pos handling - negativePosHandling = \ - '\ts32 xl = MAX(0, x);\n' +\ - '\ts32 yl = MAX(0, y);\n' +\ - '\ts32 xh = MAX(0, x + width - 1);\n' +\ - '\ts32 yh = MAX(0, y + height - 1);\n' +\ - '\ts = (x < 0) ? s - x : s;\n' +\ - '\tt = (y < 0) ? t - y : t;\n' - - data = re.sub('Gfx\* gDisplayListHead\) \{\n', - 's32 x, s32 y, s32 width, s32 height, s32 s, s32 t) {\n' + \ - negativePosHandling, data) + # Add positional arguments to drawing, along with negative pos handling + negativePosHandling = ( + "\ts32 xl = MAX(0, x);\n" + + "\ts32 yl = MAX(0, y);\n" + + "\ts32 xh = MAX(0, x + width - 1);\n" + + "\ts32 yh = MAX(0, y + height - 1);\n" + + "\ts = (x < 0) ? s - x : s;\n" + + "\tt = (y < 0) ? t - y : t;\n" + ) - # Remove display list end command and return value - data = re.sub('\tgSPEndDisplayList\(gDisplayListHead\+\+\)\;\n\treturn gDisplayListHead;\n', '', data) - data = 'void' + data[4:] + data = re.sub( + "Gfx\* gDisplayListHead\) \{\n", + "s32 x, s32 y, s32 width, s32 height, s32 s, s32 t) {\n" + negativePosHandling, + data, + ) - # Apply positional arguments to SPScisTextureRectangle - matchResult = re.search('gSPScisTextureRectangle\(gDisplayListHead\+\+\,' + \ - ' (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\,', data) - if matchResult: - #data = data[:matchResult.start(0)] + \ - # 'gSPScisTextureRectangle(gDisplayListHead++, (x << 2) + ' + \ - # matchResult.group(1) + ', (y << 2) + ' + \ - # matchResult.group(3) + ', (x << 2) + ' + \ - # matchResult.group(5) + ', (y << 2) + ' + \ - # matchResult.group(7) + ',' + data[matchResult.end(0):] - data = data[:matchResult.start(0)] + \ - 'gSPScisTextureRectangle(gDisplayListHead++, ' +\ - 'xl << 2, yl << 2, xh << 2, yh << 2, ' +\ - matchResult.group(11) + ', s << 5, t << 5, ' + data[matchResult.end(0):] + # Remove display list end command and return value + data = re.sub("\tgSPEndDisplayList\(gDisplayListHead\+\+\)\;\n\treturn gDisplayListHead;\n", "", data) + data = "void" + data[4:] + + # Apply positional arguments to SPScisTextureRectangle + matchResult = re.search( + "gSPScisTextureRectangle\(gDisplayListHead\+\+\," + + " (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\,", + data, + ) + if matchResult: + # data = data[:matchResult.start(0)] + \ + # 'gSPScisTextureRectangle(gDisplayListHead++, (x << 2) + ' + \ + # matchResult.group(1) + ', (y << 2) + ' + \ + # matchResult.group(3) + ', (x << 2) + ' + \ + # matchResult.group(5) + ', (y << 2) + ' + \ + # matchResult.group(7) + ',' + data[matchResult.end(0):] + data = ( + data[: matchResult.start(0)] + + "gSPScisTextureRectangle(gDisplayListHead++, " + + "xl << 2, yl << 2, xh << 2, yh << 2, " + + matchResult.group(11) + + ", s << 5, t << 5, " + + data[matchResult.end(0) :] + ) + + # Make sure to convert segmented texture pointer to virtual + # matchResult = re.search('gDPSetTextureImage\(gDisplayListHead\+\+\,' +\ + # '(((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\)', data) + # if matchResult: + # data = data[:matchResult.start(7)] + 'segmented_to_virtual(&' + \ + # matchResult.group(7) + ")" +data[matchResult.end(7):] + + return data - # Make sure to convert segmented texture pointer to virtual - #matchResult = re.search('gDPSetTextureImage\(gDisplayListHead\+\+\,' +\ - # '(((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\, (((?!\,).)*)\)', data) - #if matchResult: - # data = data[:matchResult.start(7)] + 'segmented_to_virtual(&' + \ - # matchResult.group(7) + ")" +data[matchResult.end(7):] - - return data def exportTexRectCommon(texProp, f3dType, isHWv1, name, convertTextureData): - tex = texProp.tex - if tex is None: - raise PluginError('No texture is selected.') - - texProp.S.low = 0 - texProp.S.high = texProp.tex.size[0] - 1 - texProp.S.mask = math.ceil(math.log(texProp.tex.size[0], 2) - 0.001) - texProp.S.shift = 0 + tex = texProp.tex + if tex is None: + raise PluginError("No texture is selected.") - texProp.T.low = 0 - texProp.T.high = texProp.tex.size[1] - 1 - texProp.T.mask = math.ceil(math.log(texProp.tex.size[1], 2) - 0.001) - texProp.T.shift = 0 + texProp.S.low = 0 + texProp.S.high = texProp.tex.size[0] - 1 + texProp.S.mask = math.ceil(math.log(texProp.tex.size[0], 2) - 0.001) + texProp.S.shift = 0 - fTexRect = FTexRect(f3dType, isHWv1, toAlnum(name), GfxMatWriteMethod.WriteDifferingAndRevert) - fMaterial = FMaterial(toAlnum(name) + "_mat", DLFormat.Dynamic) + texProp.T.low = 0 + texProp.T.high = texProp.tex.size[1] - 1 + texProp.T.mask = math.ceil(math.log(texProp.tex.size[1], 2) - 0.001) + texProp.T.shift = 0 - # dl_hud_img_begin - fTexRect.draw.commands.extend([ - DPPipeSync(), - DPSetCycleType('G_CYC_COPY'), - DPSetTexturePersp('G_TP_NONE'), - DPSetAlphaCompare('G_AC_THRESHOLD'), - DPSetBlendColor(0xFF, 0xFF, 0xFF, 0xFF), - DPSetRenderMode(['G_RM_AA_XLU_SURF', 'G_RM_AA_XLU_SURF2'], None) - ]) + fTexRect = FTexRect(f3dType, isHWv1, toAlnum(name), GfxMatWriteMethod.WriteDifferingAndRevert) + fMaterial = FMaterial(toAlnum(name) + "_mat", DLFormat.Dynamic) - drawEndCommands = GfxList("temp", GfxListTag.Draw, DLFormat.Dynamic) + # dl_hud_img_begin + fTexRect.draw.commands.extend( + [ + DPPipeSync(), + DPSetCycleType("G_CYC_COPY"), + DPSetTexturePersp("G_TP_NONE"), + DPSetAlphaCompare("G_AC_THRESHOLD"), + DPSetBlendColor(0xFF, 0xFF, 0xFF, 0xFF), + DPSetRenderMode(["G_RM_AA_XLU_SURF", "G_RM_AA_XLU_SURF2"], None), + ] + ) - texDimensions, nextTmem = saveTextureIndex(texProp.tex.name, fTexRect, - fMaterial, fTexRect.draw, drawEndCommands, texProp, 0, 0, 'texture', convertTextureData, - None, True, True) + drawEndCommands = GfxList("temp", GfxListTag.Draw, DLFormat.Dynamic) - fTexRect.draw.commands.append( - SPScisTextureRectangle(0, 0, - (texDimensions[0] - 1) << 2, (texDimensions[1] - 1) << 2, - 0, 0, 0) - ) + texDimensions, nextTmem = saveTextureIndex( + texProp.tex.name, + fTexRect, + fMaterial, + fTexRect.draw, + drawEndCommands, + texProp, + 0, + 0, + "texture", + convertTextureData, + None, + True, + True, + ) - fTexRect.draw.commands.extend(drawEndCommands.commands) + fTexRect.draw.commands.append( + SPScisTextureRectangle(0, 0, (texDimensions[0] - 1) << 2, (texDimensions[1] - 1) << 2, 0, 0, 0) + ) - # dl_hud_img_end - fTexRect.draw.commands.extend([ - DPPipeSync(), - DPSetCycleType('G_CYC_1CYCLE'), - SPTexture(0xFFFF, 0xFFFF, 0, 'G_TX_RENDERTILE', 'G_OFF'), - DPSetTexturePersp('G_TP_PERSP'), - DPSetAlphaCompare('G_AC_NONE'), - DPSetRenderMode(['G_RM_AA_ZB_OPA_SURF', 'G_RM_AA_ZB_OPA_SURF2'], None), - SPEndDisplayList() - ]) - - return fTexRect + fTexRect.draw.commands.extend(drawEndCommands.commands) -def sm64ExportF3DtoC(basePath, obj, DLFormat, transformMatrix, - f3dType, isHWv1, texDir, savePNG, texSeparate, includeChildren, name, levelName, groupName, customExport, headerType): - dirPath, texDir = getExportDir(customExport, basePath, headerType, - levelName, texDir, name) + # dl_hud_img_end + fTexRect.draw.commands.extend( + [ + DPPipeSync(), + DPSetCycleType("G_CYC_1CYCLE"), + SPTexture(0xFFFF, 0xFFFF, 0, "G_TX_RENDERTILE", "G_OFF"), + DPSetTexturePersp("G_TP_PERSP"), + DPSetAlphaCompare("G_AC_NONE"), + DPSetRenderMode(["G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"], None), + SPEndDisplayList(), + ] + ) - fModel = SM64Model(f3dType, isHWv1, name, DLFormat) - fMesh = exportF3DCommon(obj, fModel, transformMatrix, - includeChildren, name, DLFormat, not savePNG) + return fTexRect - modelDirPath = os.path.join(dirPath, toAlnum(name)) - if not os.path.exists(modelDirPath): - os.mkdir(modelDirPath) +def sm64ExportF3DtoC( + basePath, + obj, + DLFormat, + transformMatrix, + f3dType, + isHWv1, + texDir, + savePNG, + texSeparate, + includeChildren, + name, + levelName, + groupName, + customExport, + headerType, +): + dirPath, texDir = getExportDir(customExport, basePath, headerType, levelName, texDir, name) - if headerType == 'Actor': - scrollName = 'actor_dl_' + name - elif headerType == 'Level': - scrollName = levelName + '_level_dl_' + name + fModel = SM64Model(f3dType, isHWv1, name, DLFormat) + fMesh = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, name, DLFormat, not savePNG) - gfxFormatter = SM64GfxFormatter(ScrollMethod.Vertex) - exportData = fModel.to_c(TextureExportSettings(texSeparate, savePNG, texDir, modelDirPath), gfxFormatter) - staticData = exportData.staticData - dynamicData = exportData.dynamicData - texC = exportData.textureData + modelDirPath = os.path.join(dirPath, toAlnum(name)) - scrollData, hasScrolling = fModel.to_c_vertex_scroll(scrollName, gfxFormatter) + if not os.path.exists(modelDirPath): + os.mkdir(modelDirPath) - scroll_data = scrollData.source - cDefineScroll = scrollData.header + if headerType == "Actor": + scrollName = "actor_dl_" + name + elif headerType == "Level": + scrollName = levelName + "_level_dl_" + name - modifyTexScrollFiles(basePath, modelDirPath, cDefineScroll, scroll_data, hasScrolling) - - if DLFormat == DLFormat.Static: - staticData.append(dynamicData) - else: - geoString = writeMaterialFiles(basePath, modelDirPath, - '#include "actors/' + toAlnum(name) + '/header.h"', - '#include "actors/' + toAlnum(name) + '/material.inc.h"', - dynamicData.header, dynamicData.source, '', customExport) + gfxFormatter = SM64GfxFormatter(ScrollMethod.Vertex) + exportData = fModel.to_c(TextureExportSettings(texSeparate, savePNG, texDir, modelDirPath), gfxFormatter) + staticData = exportData.staticData + dynamicData = exportData.dynamicData + texC = exportData.textureData - if texSeparate: - texCFile = open(os.path.join(modelDirPath, 'texture.inc.c'), 'w', newline='\n') - texCFile.write(texC.source) - texCFile.close() + scrollData, hasScrolling = fModel.to_c_vertex_scroll(scrollName, gfxFormatter) - modelPath = os.path.join(modelDirPath, 'model.inc.c') - outFile = open(modelPath, 'w', newline='\n') - outFile.write(staticData.source) - outFile.close() - - headerPath = os.path.join(modelDirPath, 'header.h') - cDefFile = open(headerPath, 'w', newline='\n') - cDefFile.write(staticData.header) - cDefFile.close() - - fileStatus = None - if not customExport: - if headerType == 'Actor': - # Write to group files - if groupName == '' or groupName is None: - raise PluginError("Actor header type chosen but group name not provided.") + scroll_data = scrollData.source + cDefineScroll = scrollData.header - groupPathC = os.path.join(dirPath, groupName + ".c") - groupPathH = os.path.join(dirPath, groupName + ".h") + modifyTexScrollFiles(basePath, modelDirPath, cDefineScroll, scroll_data, hasScrolling) - writeIfNotFound(groupPathC, '\n#include "' + toAlnum(name) + '/model.inc.c"', '') - writeIfNotFound(groupPathH, '\n#include "' + toAlnum(name) + '/header.h"', '\n#endif') + if DLFormat == DLFormat.Static: + staticData.append(dynamicData) + else: + geoString = writeMaterialFiles( + basePath, + modelDirPath, + '#include "actors/' + toAlnum(name) + '/header.h"', + '#include "actors/' + toAlnum(name) + '/material.inc.h"', + dynamicData.header, + dynamicData.source, + "", + customExport, + ) - if DLFormat != DLFormat.Static: # Change this - writeMaterialHeaders(basePath, - '#include "actors/' + toAlnum(name) + '/material.inc.c"', - '#include "actors/' + toAlnum(name) + '/material.inc.h"') + if texSeparate: + texCFile = open(os.path.join(modelDirPath, "texture.inc.c"), "w", newline="\n") + texCFile.write(texC.source) + texCFile.close() - texscrollIncludeC = '#include "actors/' + name + '/texscroll.inc.c"' - texscrollIncludeH = '#include "actors/' + name + '/texscroll.inc.h"' - texscrollGroup = groupName - texscrollGroupInclude = '#include "actors/' + groupName + '.h"' - - elif headerType == 'Level': - groupPathC = os.path.join(dirPath, "leveldata.c") - groupPathH = os.path.join(dirPath, "header.h") + modelPath = os.path.join(modelDirPath, "model.inc.c") + outFile = open(modelPath, "w", newline="\n") + outFile.write(staticData.source) + outFile.close() - writeIfNotFound(groupPathC, '\n#include "levels/' + levelName + '/' + \ - toAlnum(name) + '/model.inc.c"', '') - writeIfNotFound(groupPathH, '\n#include "levels/' + levelName + '/' + \ - toAlnum(name) + '/header.h"', '\n#endif') + headerPath = os.path.join(modelDirPath, "header.h") + cDefFile = open(headerPath, "w", newline="\n") + cDefFile.write(staticData.header) + cDefFile.close() - if DLFormat != DLFormat.Static: # Change this - writeMaterialHeaders(basePath, - '#include "levels/' + levelName + '/' + toAlnum(name) + '/material.inc.c"', - '#include "levels/' + levelName + '/' + toAlnum(name) + '/material.inc.h"') - - texscrollIncludeC = '#include "levels/' + levelName + '/' + name + '/texscroll.inc.c"' - texscrollIncludeH = '#include "levels/' + levelName + '/' + name + '/texscroll.inc.h"' - texscrollGroup = levelName - texscrollGroupInclude = '#include "levels/' + levelName + '/header.h"' + fileStatus = None + if not customExport: + if headerType == "Actor": + # Write to group files + if groupName == "" or groupName is None: + raise PluginError("Actor header type chosen but group name not provided.") - fileStatus = modifyTexScrollHeadersGroup(basePath, texscrollIncludeC, texscrollIncludeH, - texscrollGroup, cDefineScroll, texscrollGroupInclude, hasScrolling) + groupPathC = os.path.join(dirPath, groupName + ".c") + groupPathH = os.path.join(dirPath, groupName + ".h") - if bpy.context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') + writeIfNotFound(groupPathC, '\n#include "' + toAlnum(name) + '/model.inc.c"', "") + writeIfNotFound(groupPathH, '\n#include "' + toAlnum(name) + '/header.h"', "\n#endif") - return fileStatus + if DLFormat != DLFormat.Static: # Change this + writeMaterialHeaders( + basePath, + '#include "actors/' + toAlnum(name) + '/material.inc.c"', + '#include "actors/' + toAlnum(name) + '/material.inc.h"', + ) -def exportF3DtoBinary(romfile, exportRange, transformMatrix, - obj, f3dType, isHWv1, segmentData, includeChildren): - - fModel = SM64Model(f3dType, isHWv1, obj.name, DLFormat) - fMesh = exportF3DCommon(obj, fModel, - transformMatrix, includeChildren, obj.name, DLFormat.Static, True) - fModel.freePalettes() + texscrollIncludeC = '#include "actors/' + name + '/texscroll.inc.c"' + texscrollIncludeH = '#include "actors/' + name + '/texscroll.inc.h"' + texscrollGroup = groupName + texscrollGroupInclude = '#include "actors/' + groupName + '.h"' - addrRange = fModel.set_addr(exportRange[0]) - if addrRange[1] > exportRange[1]: - raise PluginError('Size too big: Data ends at ' + hex(addrRange[1]) +\ - ', which is larger than the specified range.') - fModel.save_binary(romfile, segmentData) - if bpy.context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') + elif headerType == "Level": + groupPathC = os.path.join(dirPath, "leveldata.c") + groupPathH = os.path.join(dirPath, "header.h") - segPointerData = encodeSegmentedAddr( - fMesh.draw.startAddress, segmentData) + writeIfNotFound(groupPathC, '\n#include "levels/' + levelName + "/" + toAlnum(name) + '/model.inc.c"', "") + writeIfNotFound( + groupPathH, '\n#include "levels/' + levelName + "/" + toAlnum(name) + '/header.h"', "\n#endif" + ) - return fMesh.draw.startAddress, addrRange, segPointerData + if DLFormat != DLFormat.Static: # Change this + writeMaterialHeaders( + basePath, + '#include "levels/' + levelName + "/" + toAlnum(name) + '/material.inc.c"', + '#include "levels/' + levelName + "/" + toAlnum(name) + '/material.inc.h"', + ) -def exportF3DtoBinaryBank0(romfile, exportRange, transformMatrix, - obj, f3dType, isHWv1, RAMAddr, includeChildren): + texscrollIncludeC = '#include "levels/' + levelName + "/" + name + '/texscroll.inc.c"' + texscrollIncludeH = '#include "levels/' + levelName + "/" + name + '/texscroll.inc.h"' + texscrollGroup = levelName + texscrollGroupInclude = '#include "levels/' + levelName + '/header.h"' - fModel = SM64Model(f3dType, isHWv1, obj.name, DLFormat) - fMesh = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, - obj.name, DLFormat.Static, True) - segmentData = copy.copy(bank0Segment) + fileStatus = modifyTexScrollHeadersGroup( + basePath, + texscrollIncludeC, + texscrollIncludeH, + texscrollGroup, + cDefineScroll, + texscrollGroupInclude, + hasScrolling, + ) - data, startRAM = getBinaryBank0F3DData(fModel, RAMAddr, exportRange) + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") - startAddress = get64bitAlignedAddr(exportRange[0]) - romfile.seek(startAddress) - romfile.write(data) + return fileStatus - if bpy.context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') - segPointerData = encodeSegmentedAddr( - fMesh.draw.startAddress, segmentData) +def exportF3DtoBinary(romfile, exportRange, transformMatrix, obj, f3dType, isHWv1, segmentData, includeChildren): - return (fMesh.draw.startAddress, \ - (startAddress, startAddress + len(data)), segPointerData) + fModel = SM64Model(f3dType, isHWv1, obj.name, DLFormat) + fMesh = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, obj.name, DLFormat.Static, True) + fModel.freePalettes() -def exportF3DtoInsertableBinary(filepath, transformMatrix, - obj, f3dType, isHWv1, includeChildren): + addrRange = fModel.set_addr(exportRange[0]) + if addrRange[1] > exportRange[1]: + raise PluginError( + "Size too big: Data ends at " + hex(addrRange[1]) + ", which is larger than the specified range." + ) + fModel.save_binary(romfile, segmentData) + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") - fModel = SM64Model(f3dType, isHWv1, obj.name, DLFormat) - fMesh = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, - obj.name, DLFormat.Static, True) - - data, startRAM = getBinaryBank0F3DData(fModel, 0, [0, 0xFFFFFF]) - # must happen after getBinaryBank0F3DData - address_ptrs = fModel.get_ptr_addresses(f3dType) + segPointerData = encodeSegmentedAddr(fMesh.draw.startAddress, segmentData) + + return fMesh.draw.startAddress, addrRange, segPointerData + + +def exportF3DtoBinaryBank0(romfile, exportRange, transformMatrix, obj, f3dType, isHWv1, RAMAddr, includeChildren): + + fModel = SM64Model(f3dType, isHWv1, obj.name, DLFormat) + fMesh = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, obj.name, DLFormat.Static, True) + segmentData = copy.copy(bank0Segment) + + data, startRAM = getBinaryBank0F3DData(fModel, RAMAddr, exportRange) + + startAddress = get64bitAlignedAddr(exportRange[0]) + romfile.seek(startAddress) + romfile.write(data) + + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + + segPointerData = encodeSegmentedAddr(fMesh.draw.startAddress, segmentData) + + return (fMesh.draw.startAddress, (startAddress, startAddress + len(data)), segPointerData) + + +def exportF3DtoInsertableBinary(filepath, transformMatrix, obj, f3dType, isHWv1, includeChildren): + + fModel = SM64Model(f3dType, isHWv1, obj.name, DLFormat) + fMesh = exportF3DCommon(obj, fModel, transformMatrix, includeChildren, obj.name, DLFormat.Static, True) + + data, startRAM = getBinaryBank0F3DData(fModel, 0, [0, 0xFFFFFF]) + # must happen after getBinaryBank0F3DData + address_ptrs = fModel.get_ptr_addresses(f3dType) + + writeInsertableFile(filepath, insertableBinaryTypes["Display List"], address_ptrs, fMesh.draw.startAddress, data) - writeInsertableFile(filepath, insertableBinaryTypes['Display List'], - address_ptrs, fMesh.draw.startAddress, data) def getBinaryBank0F3DData(fModel, RAMAddr, exportRange): - fModel.freePalettes() - segmentData = copy.copy(bank0Segment) + fModel.freePalettes() + segmentData = copy.copy(bank0Segment) - addrRange = fModel.set_addr(RAMAddr) - if addrRange[1] - RAMAddr > exportRange[1] - exportRange[0]: - raise PluginError('Size too big: Data ends at ' + hex(addrRange[1]) +\ - ', which is larger than the specified range.') + addrRange = fModel.set_addr(RAMAddr) + if addrRange[1] - RAMAddr > exportRange[1] - exportRange[0]: + raise PluginError( + "Size too big: Data ends at " + hex(addrRange[1]) + ", which is larger than the specified range." + ) + + bytesIO = BytesIO() + # actualRAMAddr = get64bitAlignedAddr(RAMAddr) + bytesIO.seek(RAMAddr) + fModel.save_binary(bytesIO, segmentData) + data = bytesIO.getvalue()[RAMAddr:] + bytesIO.close() + return data, RAMAddr - bytesIO = BytesIO() - #actualRAMAddr = get64bitAlignedAddr(RAMAddr) - bytesIO.seek(RAMAddr) - fModel.save_binary(bytesIO, segmentData) - data = bytesIO.getvalue()[RAMAddr:] - bytesIO.close() - return data, RAMAddr class SM64_ExportDL(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.sm64_export_dl' - bl_label = "Export Display List" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.sm64_export_dl" + bl_label = "Export Display List" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - romfileOutput = None - tempROM = None - try: - if context.mode != 'OBJECT': - raise PluginError("Operator can only be used in object mode.") - allObjs = context.selected_objects - if len(allObjs) == 0: - raise PluginError("No objects selected.") - obj = context.selected_objects[0] - if not isinstance(obj.data, bpy.types.Mesh): - raise PluginError("Object is not a mesh.") + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + romfileOutput = None + tempROM = None + try: + if context.mode != "OBJECT": + raise PluginError("Operator can only be used in object mode.") + allObjs = context.selected_objects + if len(allObjs) == 0: + raise PluginError("No objects selected.") + obj = context.selected_objects[0] + if not isinstance(obj.data, bpy.types.Mesh): + raise PluginError("Object is not a mesh.") - #T, R, S = obj.matrix_world.decompose() - #objTransform = R.to_matrix().to_4x4() @ \ - # mathutils.Matrix.Diagonal(S).to_4x4() + # T, R, S = obj.matrix_world.decompose() + # objTransform = R.to_matrix().to_4x4() @ \ + # mathutils.Matrix.Diagonal(S).to_4x4() - #finalTransform = (blenderToSM64Rotation * \ - # (bpy.context.scene.blenderToSM64Scale)).to_4x4() - #finalTransform = mathutils.Matrix.Identity(4) - scaleValue = bpy.context.scene.blenderToSM64Scale - finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector(( - scaleValue, scaleValue, scaleValue))).to_4x4() + # finalTransform = (blenderToSM64Rotation * \ + # (bpy.context.scene.blenderToSM64Scale)).to_4x4() + # finalTransform = mathutils.Matrix.Identity(4) + scaleValue = bpy.context.scene.blenderToSM64Scale + finalTransform = mathutils.Matrix.Diagonal(mathutils.Vector((scaleValue, scaleValue, scaleValue))).to_4x4() - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} - - try: - applyRotation([obj], math.radians(90), 'X') - if context.scene.fast64.sm64.exportType == 'C': - exportPath, levelName = getPathAndLevel(context.scene.DLCustomExport, - context.scene.DLExportPath, context.scene.DLLevelName, - context.scene.DLLevelOption) - if not context.scene.DLCustomExport: - applyBasicTweaks(exportPath) - fileStatus = sm64ExportF3DtoC(exportPath, obj, - DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic, finalTransform, - context.scene.f3d_type, context.scene.isHWv1, - bpy.context.scene.DLTexDir, - bpy.context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, - bpy.context.scene.DLSeparateTextureDef, - bpy.context.scene.DLincludeChildren, bpy.context.scene.DLName, levelName, context.scene.DLGroupName, - context.scene.DLCustomExport, - context.scene.DLExportHeaderType) + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} - starSelectWarning(self, fileStatus) - #cProfile.runctx('sm64ExportF3DtoC(exportPath, obj,' +\ - # 'DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic, finalTransform,' +\ - # 'context.scene.f3d_type, context.scene.isHWv1,' +\ - # 'bpy.context.scene.DLTexDir,' +\ - # 'bpy.context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions,' +\ - # 'bpy.context.scene.DLSeparateTextureDef,' +\ - # 'bpy.context.scene.DLincludeChildren, bpy.context.scene.DLName, levelName, context.scene.DLGroupName,' +\ - # 'context.scene.DLCustomExport,' +\ - # 'context.scene.DLExportHeaderType)', - # globals(), locals(), "E:/blender.prof") - #p = pstats.Stats("E:/blender.prof") - #p.sort_stats("cumulative").print_stats(2000) - self.report({'INFO'}, 'Success!') - - elif context.scene.fast64.sm64.exportType == 'Insertable Binary': - exportF3DtoInsertableBinary( - bpy.path.abspath(context.scene.DLInsertableBinaryPath), - finalTransform, obj, context.scene.f3d_type, - context.scene.isHWv1, bpy.context.scene.DLincludeChildren) - self.report({'INFO'}, 'Success! DL at ' + \ - context.scene.DLInsertableBinaryPath + '.') - else: - checkExpanded(bpy.path.abspath(context.scene.exportRom)) - tempROM = tempName(context.scene.outputRom) - romfileExport = \ - open(bpy.path.abspath(context.scene.exportRom), 'rb') - shutil.copy(bpy.path.abspath(context.scene.exportRom), - bpy.path.abspath(tempROM)) - romfileExport.close() - romfileOutput = open(bpy.path.abspath(tempROM), 'rb+') + try: + applyRotation([obj], math.radians(90), "X") + if context.scene.fast64.sm64.exportType == "C": + exportPath, levelName = getPathAndLevel( + context.scene.DLCustomExport, + context.scene.DLExportPath, + context.scene.DLLevelName, + context.scene.DLLevelOption, + ) + if not context.scene.DLCustomExport: + applyBasicTweaks(exportPath) + fileStatus = sm64ExportF3DtoC( + exportPath, + obj, + DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic, + finalTransform, + context.scene.f3d_type, + context.scene.isHWv1, + bpy.context.scene.DLTexDir, + bpy.context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, + bpy.context.scene.DLSeparateTextureDef, + bpy.context.scene.DLincludeChildren, + bpy.context.scene.DLName, + levelName, + context.scene.DLGroupName, + context.scene.DLCustomExport, + context.scene.DLExportHeaderType, + ) - levelParsed = parseLevelAtPointer(romfileOutput, - level_pointers[context.scene.levelDLExport]) - segmentData = levelParsed.segmentData - if context.scene.extendBank4: - ExtendBank0x04(romfileOutput, segmentData, - defaultExtendSegment4) + starSelectWarning(self, fileStatus) + # cProfile.runctx('sm64ExportF3DtoC(exportPath, obj,' +\ + # 'DLFormat.Static if context.scene.DLExportisStatic else DLFormat.Dynamic, finalTransform,' +\ + # 'context.scene.f3d_type, context.scene.isHWv1,' +\ + # 'bpy.context.scene.DLTexDir,' +\ + # 'bpy.context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions,' +\ + # 'bpy.context.scene.DLSeparateTextureDef,' +\ + # 'bpy.context.scene.DLincludeChildren, bpy.context.scene.DLName, levelName, context.scene.DLGroupName,' +\ + # 'context.scene.DLCustomExport,' +\ + # 'context.scene.DLExportHeaderType)', + # globals(), locals(), "E:/blender.prof") + # p = pstats.Stats("E:/blender.prof") + # p.sort_stats("cumulative").print_stats(2000) + self.report({"INFO"}, "Success!") - if context.scene.DLUseBank0: - startAddress, addrRange, segPointerData = \ - exportF3DtoBinaryBank0(romfileOutput, - [int(context.scene.DLExportStart, 16), - int(context.scene.DLExportEnd, 16)], - finalTransform, obj, context.scene.f3d_type, - context.scene.isHWv1, getAddressFromRAMAddress( - int(context.scene.DLRAMAddr, 16)), - bpy.context.scene.DLincludeChildren) - else: - startAddress, addrRange, segPointerData = \ - exportF3DtoBinary(romfileOutput, - [int(context.scene.DLExportStart, 16), - int(context.scene.DLExportEnd, 16)], - finalTransform, obj, context.scene.f3d_type, - context.scene.isHWv1, segmentData, - bpy.context.scene.DLincludeChildren) - - if context.scene.overwriteGeoPtr: - romfileOutput.seek(int(context.scene.DLExportGeoPtr, 16)) - romfileOutput.write(segPointerData) - - romfileOutput.close() - if os.path.exists(bpy.path.abspath(context.scene.outputRom)): - os.remove(bpy.path.abspath(context.scene.outputRom)) - os.rename(bpy.path.abspath(tempROM), - bpy.path.abspath(context.scene.outputRom)) - - if context.scene.DLUseBank0: - self.report({'INFO'}, 'Success! DL at (' + \ - hex(addrRange[0]) + ', ' + hex(addrRange[1]) + \ - '), ' +\ - 'to write to RAM address ' + \ - hex(startAddress + 0x80000000)) - else: - - self.report({'INFO'}, 'Success! DL at (' + \ - hex(addrRange[0]) + ', ' + hex(addrRange[1]) + \ - ') (Seg. ' + bytesToHex(segPointerData) + ').') + elif context.scene.fast64.sm64.exportType == "Insertable Binary": + exportF3DtoInsertableBinary( + bpy.path.abspath(context.scene.DLInsertableBinaryPath), + finalTransform, + obj, + context.scene.f3d_type, + context.scene.isHWv1, + bpy.context.scene.DLincludeChildren, + ) + self.report({"INFO"}, "Success! DL at " + context.scene.DLInsertableBinaryPath + ".") + else: + checkExpanded(bpy.path.abspath(context.scene.exportRom)) + tempROM = tempName(context.scene.outputRom) + romfileExport = open(bpy.path.abspath(context.scene.exportRom), "rb") + shutil.copy(bpy.path.abspath(context.scene.exportRom), bpy.path.abspath(tempROM)) + romfileExport.close() + romfileOutput = open(bpy.path.abspath(tempROM), "rb+") - applyRotation([obj], math.radians(-90), 'X') - return {'FINISHED'} # must return a set + levelParsed = parseLevelAtPointer(romfileOutput, level_pointers[context.scene.levelDLExport]) + segmentData = levelParsed.segmentData + if context.scene.extendBank4: + ExtendBank0x04(romfileOutput, segmentData, defaultExtendSegment4) + + if context.scene.DLUseBank0: + startAddress, addrRange, segPointerData = exportF3DtoBinaryBank0( + romfileOutput, + [int(context.scene.DLExportStart, 16), int(context.scene.DLExportEnd, 16)], + finalTransform, + obj, + context.scene.f3d_type, + context.scene.isHWv1, + getAddressFromRAMAddress(int(context.scene.DLRAMAddr, 16)), + bpy.context.scene.DLincludeChildren, + ) + else: + startAddress, addrRange, segPointerData = exportF3DtoBinary( + romfileOutput, + [int(context.scene.DLExportStart, 16), int(context.scene.DLExportEnd, 16)], + finalTransform, + obj, + context.scene.f3d_type, + context.scene.isHWv1, + segmentData, + bpy.context.scene.DLincludeChildren, + ) + + if context.scene.overwriteGeoPtr: + romfileOutput.seek(int(context.scene.DLExportGeoPtr, 16)) + romfileOutput.write(segPointerData) + + romfileOutput.close() + if os.path.exists(bpy.path.abspath(context.scene.outputRom)): + os.remove(bpy.path.abspath(context.scene.outputRom)) + os.rename(bpy.path.abspath(tempROM), bpy.path.abspath(context.scene.outputRom)) + + if context.scene.DLUseBank0: + self.report( + {"INFO"}, + "Success! DL at (" + + hex(addrRange[0]) + + ", " + + hex(addrRange[1]) + + "), " + + "to write to RAM address " + + hex(startAddress + 0x80000000), + ) + else: + + self.report( + {"INFO"}, + "Success! DL at (" + + hex(addrRange[0]) + + ", " + + hex(addrRange[1]) + + ") (Seg. " + + bytesToHex(segPointerData) + + ").", + ) + + applyRotation([obj], math.radians(-90), "X") + return {"FINISHED"} # must return a set + + except Exception as e: + if context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + applyRotation([obj], math.radians(-90), "X") + if context.scene.fast64.sm64.exportType == "Binary": + if romfileOutput is not None: + romfileOutput.close() + if tempROM is not None and os.path.exists(bpy.path.abspath(tempROM)): + os.remove(bpy.path.abspath(tempROM)) + raisePluginError(self, e) + return {"CANCELLED"} # must return a set - except Exception as e: - if context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') - applyRotation([obj], math.radians(-90), 'X') - if context.scene.fast64.sm64.exportType == 'Binary': - if romfileOutput is not None: - romfileOutput.close() - if tempROM is not None and os.path.exists(bpy.path.abspath(tempROM)): - os.remove(bpy.path.abspath(tempROM)) - raisePluginError(self, e) - return {'CANCELLED'} # must return a set class SM64_ExportDLPanel(SM64_Panel): - bl_idname = "SM64_PT_export_dl" - bl_label = "SM64 DL Exporter" - goal = 'Export Displaylist' + bl_idname = "SM64_PT_export_dl" + bl_label = "SM64 DL Exporter" + goal = "Export Displaylist" - # called every frame - def draw(self, context): - col = self.layout.column() - propsDLE = col.operator(SM64_ExportDL.bl_idname) + # called every frame + def draw(self, context): + col = self.layout.column() + propsDLE = col.operator(SM64_ExportDL.bl_idname) + + if context.scene.fast64.sm64.exportType == "C": + col.prop(context.scene, "DLExportisStatic") + + col.prop(context.scene, "DLCustomExport") + if context.scene.DLCustomExport: + col.prop(context.scene, "DLExportPath") + prop_split(col, context.scene, "DLName", "Name") + if not bpy.context.scene.ignoreTextureRestrictions and context.scene.saveTextures: + prop_split(col, context.scene, "DLTexDir", "Texture Include Path") + col.prop(context.scene, "DLSeparateTextureDef") + customExportWarning(col) + else: + prop_split(col, context.scene, "DLExportHeaderType", "Export Type") + prop_split(col, context.scene, "DLName", "Name") + if context.scene.DLExportHeaderType == "Actor": + prop_split(col, context.scene, "DLGroupName", "Group Name") + elif context.scene.DLExportHeaderType == "Level": + prop_split(col, context.scene, "DLLevelOption", "Level") + if context.scene.DLLevelOption == "custom": + prop_split(col, context.scene, "DLLevelName", "Level Name") + if not bpy.context.scene.ignoreTextureRestrictions and context.scene.saveTextures: + col.prop(context.scene, "DLSeparateTextureDef") + + decompFolderMessage(col) + writeBox = makeWriteInfoBox(col) + writeBoxExportType( + writeBox, + context.scene.DLExportHeaderType, + context.scene.DLName, + context.scene.DLLevelName, + context.scene.DLLevelOption, + ) + + elif context.scene.fast64.sm64.exportType == "Insertable Binary": + col.prop(context.scene, "DLInsertableBinaryPath") + else: + prop_split(col, context.scene, "DLExportStart", "Start Address") + prop_split(col, context.scene, "DLExportEnd", "End Address") + col.prop(context.scene, "DLUseBank0") + if context.scene.DLUseBank0: + prop_split(col, context.scene, "DLRAMAddr", "RAM Address") + else: + col.prop(context.scene, "levelDLExport") + col.prop(context.scene, "overwriteGeoPtr") + if context.scene.overwriteGeoPtr: + prop_split(col, context.scene, "DLExportGeoPtr", "Geolayout Pointer") + col.prop(context.scene, "DLincludeChildren") - if context.scene.fast64.sm64.exportType == 'C': - col.prop(context.scene, 'DLExportisStatic') - - - col.prop(context.scene, 'DLCustomExport') - if context.scene.DLCustomExport: - col.prop(context.scene, 'DLExportPath') - prop_split(col, context.scene, 'DLName', 'Name') - if not bpy.context.scene.ignoreTextureRestrictions and context.scene.saveTextures: - prop_split(col, context.scene, 'DLTexDir', - 'Texture Include Path') - col.prop(context.scene, 'DLSeparateTextureDef') - customExportWarning(col) - else: - prop_split(col, context.scene, 'DLExportHeaderType', 'Export Type') - prop_split(col, context.scene, 'DLName', 'Name') - if context.scene.DLExportHeaderType == 'Actor': - prop_split(col, context.scene, 'DLGroupName', 'Group Name') - elif context.scene.DLExportHeaderType == 'Level': - prop_split(col, context.scene, 'DLLevelOption', 'Level') - if context.scene.DLLevelOption == 'custom': - prop_split(col, context.scene, 'DLLevelName', 'Level Name') - if not bpy.context.scene.ignoreTextureRestrictions and context.scene.saveTextures: - col.prop(context.scene, 'DLSeparateTextureDef') - - decompFolderMessage(col) - writeBox = makeWriteInfoBox(col) - writeBoxExportType(writeBox, context.scene.DLExportHeaderType, - context.scene.DLName, context.scene.DLLevelName, context.scene.DLLevelOption) - - elif context.scene.fast64.sm64.exportType == 'Insertable Binary': - col.prop(context.scene, 'DLInsertableBinaryPath') - else: - prop_split(col, context.scene, 'DLExportStart', 'Start Address') - prop_split(col, context.scene, 'DLExportEnd', 'End Address') - col.prop(context.scene, 'DLUseBank0') - if context.scene.DLUseBank0: - prop_split(col, context.scene, 'DLRAMAddr', 'RAM Address') - else: - col.prop(context.scene, 'levelDLExport') - col.prop(context.scene, 'overwriteGeoPtr') - if context.scene.overwriteGeoPtr: - prop_split(col, context.scene, 'DLExportGeoPtr', - 'Geolayout Pointer') - col.prop(context.scene, 'DLincludeChildren') class ExportTexRectDraw(bpy.types.Operator): - # set bl_ properties - bl_idname = 'object.f3d_texrect_draw' - bl_label = "Export F3D Texture Rectangle" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + # set bl_ properties + bl_idname = "object.f3d_texrect_draw" + bl_label = "Export F3D Texture Rectangle" + bl_options = {"REGISTER", "UNDO", "PRESET"} - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - try: - if context.scene.texrect.tex is None: - raise PluginError("No texture selected.") - else: - if context.scene.TexRectCustomExport: - exportPath = context.scene.TexRectExportPath - else: - if context.scene.decompPath == "": - raise PluginError("Decomp path has not been set in File Settings.") - exportPath = context.scene.decompPath - if not context.scene.TexRectCustomExport: - applyBasicTweaks(exportPath) - exportTexRectToC(bpy.path.abspath(exportPath), - context.scene.texrect, - context.scene.f3d_type, context.scene.isHWv1, - 'textures/segment2', - context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, - context.scene.TexRectName, - not context.scene.TexRectCustomExport, - enumHUDPaths[context.scene.TexRectExportType]) + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + try: + if context.scene.texrect.tex is None: + raise PluginError("No texture selected.") + else: + if context.scene.TexRectCustomExport: + exportPath = context.scene.TexRectExportPath + else: + if context.scene.decompPath == "": + raise PluginError("Decomp path has not been set in File Settings.") + exportPath = context.scene.decompPath + if not context.scene.TexRectCustomExport: + applyBasicTweaks(exportPath) + exportTexRectToC( + bpy.path.abspath(exportPath), + context.scene.texrect, + context.scene.f3d_type, + context.scene.isHWv1, + "textures/segment2", + context.scene.saveTextures or bpy.context.scene.ignoreTextureRestrictions, + context.scene.TexRectName, + not context.scene.TexRectCustomExport, + enumHUDPaths[context.scene.TexRectExportType], + ) + + self.report({"INFO"}, "Success!") + except Exception as e: + raisePluginError(self, e) + return {"CANCELLED"} + return {"FINISHED"} # must return a set - self.report({'INFO'}, 'Success!') - except Exception as e: - raisePluginError(self, e) - return {"CANCELLED"} - return {'FINISHED'} # must return a set class UnlinkTexRect(bpy.types.Operator): - bl_idname = 'image.texrect_unlink' - bl_label = "Unlink TexRect Image" - bl_options = {'REGISTER', 'UNDO', 'PRESET'} + bl_idname = "image.texrect_unlink" + bl_label = "Unlink TexRect Image" + bl_options = {"REGISTER", "UNDO", "PRESET"} + + # Called on demand (i.e. button press, menu item) + # Can also be called from operator search menu (Spacebar) + def execute(self, context): + context.scene.texrect.tex = None + return {"FINISHED"} # must return a set - # Called on demand (i.e. button press, menu item) - # Can also be called from operator search menu (Spacebar) - def execute(self, context): - context.scene.texrect.tex = None - return {'FINISHED'} # must return a set class ExportTexRectDrawPanel(SM64_Panel): - bl_idname = "TEXTURE_PT_export_texrect" - bl_label = "SM64 UI Image Exporter" - goal = 'Export UI Image' - decomp_only = True + bl_idname = "TEXTURE_PT_export_texrect" + bl_label = "SM64 UI Image Exporter" + goal = "Export UI Image" + decomp_only = True - # called every frame - def draw(self, context): - col = self.layout.column() - propsTexRectE = col.operator(ExportTexRectDraw.bl_idname) + # called every frame + def draw(self, context): + col = self.layout.column() + propsTexRectE = col.operator(ExportTexRectDraw.bl_idname) - textureProp = context.scene.texrect - tex = textureProp.tex - col.label(text = 'This is for decomp only.') - col.template_ID(textureProp, 'tex', new="image.new", open="image.open", unlink="image.texrect_unlink") - #col.prop(textureProp, 'tex') + textureProp = context.scene.texrect + tex = textureProp.tex + col.label(text="This is for decomp only.") + col.template_ID(textureProp, "tex", new="image.new", open="image.open", unlink="image.texrect_unlink") + # col.prop(textureProp, 'tex') + + tmemUsageUI(col, textureProp) + if tex is not None and tex.size[0] > 0 and tex.size[1] > 0: + col.prop(textureProp, "tex_format", text="Format") + if textureProp.tex_format[:2] == "CI": + col.prop(textureProp, "ci_format", text="CI Format") + col.prop(textureProp.S, "clamp", text="Clamp S") + col.prop(textureProp.T, "clamp", text="Clamp T") + col.prop(textureProp.S, "mirror", text="Mirror S") + col.prop(textureProp.T, "mirror", text="Mirror T") + + prop_split(col, context.scene, "TexRectName", "Name") + col.prop(context.scene, "TexRectCustomExport") + if context.scene.TexRectCustomExport: + col.prop(context.scene, "TexRectExportPath") + customExportWarning(col) + else: + prop_split(col, context.scene, "TexRectExportType", "Export Type") + if not context.scene.TexRectCustomExport: + decompFolderMessage(col) + writeBox = makeWriteInfoBox(col) + writeBox.label(text="bin/segment2.c") + writeBox.label(text="src/game/segment2.h") + writeBox.label(text="textures/segment2") + infoBox = col.box() + infoBox.label(text="After export, call your hud's draw function in ") + infoBox.label(text=enumHUDPaths[context.scene.TexRectExportType][0] + ": ") + infoBox.label(text=enumHUDPaths[context.scene.TexRectExportType][1] + ".") - tmemUsageUI(col, textureProp) - if tex is not None and tex.size[0] > 0 and tex.size[1] > 0: - col.prop(textureProp, 'tex_format', text = 'Format') - if textureProp.tex_format[:2] == 'CI': - col.prop(textureProp, 'ci_format', text = 'CI Format') - col.prop(textureProp.S, 'clamp', text = 'Clamp S') - col.prop(textureProp.T, 'clamp', text = 'Clamp T') - col.prop(textureProp.S, 'mirror', text = 'Mirror S') - col.prop(textureProp.T, 'mirror', text = 'Mirror T') - - prop_split(col, context.scene, 'TexRectName', 'Name') - col.prop(context.scene, 'TexRectCustomExport') - if context.scene.TexRectCustomExport: - col.prop(context.scene, 'TexRectExportPath') - customExportWarning(col) - else: - prop_split(col, context.scene, 'TexRectExportType', 'Export Type') - if not context.scene.TexRectCustomExport: - decompFolderMessage(col) - writeBox = makeWriteInfoBox(col) - writeBox.label(text = 'bin/segment2.c') - writeBox.label(text = 'src/game/segment2.h') - writeBox.label(text = 'textures/segment2') - infoBox = col.box() - infoBox.label(text = 'After export, call your hud\'s draw function in ') - infoBox.label(text = enumHUDPaths[context.scene.TexRectExportType][0] + ': ') - infoBox.label(text = enumHUDPaths[context.scene.TexRectExportType][1] + '.') class SM64_DrawLayersPanel(bpy.types.Panel): - bl_label = "SM64 Draw Layers" - bl_idname = "WORLD_PT_SM64_Draw_Layers_Panel" - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "world" - bl_options = {'HIDE_HEADER'} + bl_label = "SM64 Draw Layers" + bl_idname = "WORLD_PT_SM64_Draw_Layers_Panel" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "world" + bl_options = {"HIDE_HEADER"} - @classmethod - def poll(cls, context): - return context.scene.gameEditorMode == "SM64" + @classmethod + def poll(cls, context): + return context.scene.gameEditorMode == "SM64" - def draw(self, context): - world = context.scene.world - layout = self.layout + def draw(self, context): + world = context.scene.world + layout = self.layout + + inputGroup = layout.column() + inputGroup.prop( + world, "menu_layers", text="Draw Layers", icon="TRIA_DOWN" if world.menu_layers else "TRIA_RIGHT" + ) + if world.menu_layers: + for i in range(8): + drawLayerUI(inputGroup, i, world) - inputGroup = layout.column() - inputGroup.prop(world, 'menu_layers', - text = 'Draw Layers', - icon = 'TRIA_DOWN' if world.menu_layers else 'TRIA_RIGHT') - if world.menu_layers: - for i in range(8): - drawLayerUI(inputGroup, i, world) def drawLayerUI(layout, drawLayer, world): - box = layout.box() - box.label(text = 'Layer ' + str(drawLayer)) - row = box.row() - row.prop(world, 'draw_layer_' + str(drawLayer) + '_cycle_1', text = '') - row.prop(world, 'draw_layer_' + str(drawLayer) + '_cycle_2', text = '') + box = layout.box() + box.label(text="Layer " + str(drawLayer)) + row = box.row() + row.prop(world, "draw_layer_" + str(drawLayer) + "_cycle_1", text="") + row.prop(world, "draw_layer_" + str(drawLayer) + "_cycle_2", text="") + class SM64_MaterialPanel(bpy.types.Panel): - bl_label = "SM64 Material" - bl_idname = "MATERIAL_PT_SM64_Material_Inspector" - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "material" - bl_options = {'HIDE_HEADER'} + bl_label = "SM64 Material" + bl_idname = "MATERIAL_PT_SM64_Material_Inspector" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "material" + bl_options = {"HIDE_HEADER"} - @classmethod - def poll(cls, context): - return context.material is not None and context.scene.gameEditorMode == "SM64" + @classmethod + def poll(cls, context): + return context.material is not None and context.scene.gameEditorMode == "SM64" - def draw(self, context): - layout = self.layout - material = context.material - col = layout.column() + def draw(self, context): + layout = self.layout + material = context.material + col = layout.column() - if material.mat_ver > 3: - f3dMat = material.f3d_mat - else: - f3dMat = material - useDict = all_combiner_uses(f3dMat) + if material.mat_ver > 3: + f3dMat = material.f3d_mat + else: + f3dMat = material + useDict = all_combiner_uses(f3dMat) - if useDict['Texture']: - ui_procAnim(material, col, useDict['Texture 0'], useDict['Texture 1'], - "SM64 UV Texture Scroll", False) + if useDict["Texture"]: + ui_procAnim(material, col, useDict["Texture 0"], useDict["Texture 1"], "SM64 UV Texture Scroll", False) sm64_dl_writer_classes = ( - SM64_ExportDL, - ExportTexRectDraw, - UnlinkTexRect, + SM64_ExportDL, + ExportTexRectDraw, + UnlinkTexRect, ) sm64_dl_writer_panel_classes = ( - SM64_MaterialPanel, - SM64_DrawLayersPanel, - SM64_ExportDLPanel, - ExportTexRectDrawPanel, + SM64_MaterialPanel, + SM64_DrawLayersPanel, + SM64_ExportDLPanel, + ExportTexRectDrawPanel, ) + def sm64_dl_writer_panel_register(): - for cls in sm64_dl_writer_panel_classes: - register_class(cls) + for cls in sm64_dl_writer_panel_classes: + register_class(cls) + def sm64_dl_writer_panel_unregister(): - for cls in sm64_dl_writer_panel_classes: - unregister_class(cls) + for cls in sm64_dl_writer_panel_classes: + unregister_class(cls) + def sm64_dl_writer_register(): - for cls in sm64_dl_writer_classes: - register_class(cls) + for cls in sm64_dl_writer_classes: + register_class(cls) - bpy.types.World.draw_layer_0_cycle_1 = bpy.props.StringProperty(default = 'G_RM_ZB_OPA_SURF') - bpy.types.World.draw_layer_0_cycle_2 = bpy.props.StringProperty(default = 'G_RM_ZB_OPA_SURF2') - bpy.types.World.draw_layer_1_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_OPA_SURF') - bpy.types.World.draw_layer_1_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_OPA_SURF2') - bpy.types.World.draw_layer_2_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_OPA_DECAL') - bpy.types.World.draw_layer_2_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_OPA_DECAL2') - bpy.types.World.draw_layer_3_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_OPA_INTER') - bpy.types.World.draw_layer_3_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_OPA_INTER2') - bpy.types.World.draw_layer_4_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_TEX_EDGE') - bpy.types.World.draw_layer_4_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_TEX_EDGE2') - bpy.types.World.draw_layer_5_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_XLU_SURF') - bpy.types.World.draw_layer_5_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_XLU_SURF2') - bpy.types.World.draw_layer_6_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_XLU_DECAL') - bpy.types.World.draw_layer_6_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_XLU_DECAL2') - bpy.types.World.draw_layer_7_cycle_1 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_XLU_INTER') - bpy.types.World.draw_layer_7_cycle_2 = bpy.props.StringProperty(default = 'G_RM_AA_ZB_XLU_INTER2') + bpy.types.World.draw_layer_0_cycle_1 = bpy.props.StringProperty(default="G_RM_ZB_OPA_SURF") + bpy.types.World.draw_layer_0_cycle_2 = bpy.props.StringProperty(default="G_RM_ZB_OPA_SURF2") + bpy.types.World.draw_layer_1_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_SURF") + bpy.types.World.draw_layer_1_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_SURF2") + bpy.types.World.draw_layer_2_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_DECAL") + bpy.types.World.draw_layer_2_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_DECAL2") + bpy.types.World.draw_layer_3_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_INTER") + bpy.types.World.draw_layer_3_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_INTER2") + bpy.types.World.draw_layer_4_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_TEX_EDGE") + bpy.types.World.draw_layer_4_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_TEX_EDGE2") + bpy.types.World.draw_layer_5_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_SURF") + bpy.types.World.draw_layer_5_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_SURF2") + bpy.types.World.draw_layer_6_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_DECAL") + bpy.types.World.draw_layer_6_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_DECAL2") + bpy.types.World.draw_layer_7_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_INTER") + bpy.types.World.draw_layer_7_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_INTER2") - bpy.types.Scene.DLExportStart = bpy.props.StringProperty( - name = 'Start', default = '11D8930') - bpy.types.Scene.DLExportEnd = bpy.props.StringProperty( - name = 'End', default = '11FFF00') - bpy.types.Scene.levelDLExport = bpy.props.EnumProperty(items = level_enums, - name = 'Level', default = 'WF') - bpy.types.Scene.DLExportGeoPtr = bpy.props.StringProperty( - name ='Geolayout Pointer', default = '132AA8') - bpy.types.Scene.overwriteGeoPtr = bpy.props.BoolProperty( - name = "Overwrite geolayout pointer", default = False) - bpy.types.Scene.DLExportPath = bpy.props.StringProperty( - name = 'Directory', subtype = 'FILE_PATH') - bpy.types.Scene.DLExportisStatic = bpy.props.BoolProperty( - name = 'Static DL', default = True) - bpy.types.Scene.DLDefinePath = bpy.props.StringProperty( - name = 'Definitions Filepath', subtype = 'FILE_PATH') - bpy.types.Scene.DLUseBank0 = bpy.props.BoolProperty(name = 'Use Bank 0') - bpy.types.Scene.DLRAMAddr = bpy.props.StringProperty(name = 'RAM Address', - default = '80000000') - bpy.types.Scene.DLTexDir = bpy.props.StringProperty( - name ='Include Path', default = 'levels/bob') - bpy.types.Scene.DLSeparateTextureDef = bpy.props.BoolProperty( - name = 'Save texture.inc.c separately') - bpy.types.Scene.DLincludeChildren = bpy.props.BoolProperty( - name = 'Include Children') - bpy.types.Scene.DLInsertableBinaryPath = bpy.props.StringProperty( - name = 'Filepath', subtype = 'FILE_PATH') - bpy.types.Scene.DLName = bpy.props.StringProperty( - name = 'Name', default = 'mario') - bpy.types.Scene.DLCustomExport = bpy.props.BoolProperty( - name = 'Custom Export Path') - bpy.types.Scene.DLExportHeaderType = bpy.props.EnumProperty( - items = enumExportHeaderType, name = 'Header Export', default = 'Actor') - bpy.types.Scene.DLGroupName = bpy.props.StringProperty(name = 'Group Name', - default = 'group0') - bpy.types.Scene.DLLevelName = bpy.props.StringProperty(name = 'Level', - default = 'bob') - bpy.types.Scene.DLLevelOption = bpy.props.EnumProperty( - items = enumLevelNames, name = 'Level', default = 'bob') + bpy.types.Scene.DLExportStart = bpy.props.StringProperty(name="Start", default="11D8930") + bpy.types.Scene.DLExportEnd = bpy.props.StringProperty(name="End", default="11FFF00") + bpy.types.Scene.levelDLExport = bpy.props.EnumProperty(items=level_enums, name="Level", default="WF") + bpy.types.Scene.DLExportGeoPtr = bpy.props.StringProperty(name="Geolayout Pointer", default="132AA8") + bpy.types.Scene.overwriteGeoPtr = bpy.props.BoolProperty(name="Overwrite geolayout pointer", default=False) + bpy.types.Scene.DLExportPath = bpy.props.StringProperty(name="Directory", subtype="FILE_PATH") + bpy.types.Scene.DLExportisStatic = bpy.props.BoolProperty(name="Static DL", default=True) + bpy.types.Scene.DLDefinePath = bpy.props.StringProperty(name="Definitions Filepath", subtype="FILE_PATH") + bpy.types.Scene.DLUseBank0 = bpy.props.BoolProperty(name="Use Bank 0") + bpy.types.Scene.DLRAMAddr = bpy.props.StringProperty(name="RAM Address", default="80000000") + bpy.types.Scene.DLTexDir = bpy.props.StringProperty(name="Include Path", default="levels/bob") + bpy.types.Scene.DLSeparateTextureDef = bpy.props.BoolProperty(name="Save texture.inc.c separately") + bpy.types.Scene.DLincludeChildren = bpy.props.BoolProperty(name="Include Children") + bpy.types.Scene.DLInsertableBinaryPath = bpy.props.StringProperty(name="Filepath", subtype="FILE_PATH") + bpy.types.Scene.DLName = bpy.props.StringProperty(name="Name", default="mario") + bpy.types.Scene.DLCustomExport = bpy.props.BoolProperty(name="Custom Export Path") + bpy.types.Scene.DLExportHeaderType = bpy.props.EnumProperty( + items=enumExportHeaderType, name="Header Export", default="Actor" + ) + bpy.types.Scene.DLGroupName = bpy.props.StringProperty(name="Group Name", default="group0") + bpy.types.Scene.DLLevelName = bpy.props.StringProperty(name="Level", default="bob") + bpy.types.Scene.DLLevelOption = bpy.props.EnumProperty(items=enumLevelNames, name="Level", default="bob") + + bpy.types.Scene.texrect = bpy.props.PointerProperty(type=TextureProperty) + bpy.types.Scene.texrectImageTexture = bpy.props.PointerProperty(type=bpy.types.ImageTexture) + bpy.types.Scene.TexRectExportPath = bpy.props.StringProperty(name="Export Path", subtype="FILE_PATH") + bpy.types.Scene.TexRectTexDir = bpy.props.StringProperty(name="Include Path", default="textures/segment2") + bpy.types.Scene.TexRectName = bpy.props.StringProperty(name="Name", default="render_hud_image") + bpy.types.Scene.TexRectCustomExport = bpy.props.BoolProperty(name="Custom Export Path") + bpy.types.Scene.TexRectExportType = bpy.props.EnumProperty(name="Export Type", items=enumHUDExportLocation) - bpy.types.Scene.texrect = bpy.props.PointerProperty(type = TextureProperty) - bpy.types.Scene.texrectImageTexture = bpy.props.PointerProperty(type = bpy.types.ImageTexture) - bpy.types.Scene.TexRectExportPath = bpy.props.StringProperty(name = 'Export Path', subtype='FILE_PATH') - bpy.types.Scene.TexRectTexDir = bpy.props.StringProperty(name = 'Include Path', default = 'textures/segment2') - bpy.types.Scene.TexRectName = bpy.props.StringProperty(name = 'Name', default = 'render_hud_image') - bpy.types.Scene.TexRectCustomExport = bpy.props.BoolProperty(name = 'Custom Export Path') - bpy.types.Scene.TexRectExportType = bpy.props.EnumProperty(name = 'Export Type', items = enumHUDExportLocation) def sm64_dl_writer_unregister(): - for cls in reversed(sm64_dl_writer_classes): - unregister_class(cls) + for cls in reversed(sm64_dl_writer_classes): + unregister_class(cls) - del bpy.types.Scene.levelDLExport - del bpy.types.Scene.DLExportStart - del bpy.types.Scene.DLExportEnd - del bpy.types.Scene.DLExportGeoPtr - del bpy.types.Scene.overwriteGeoPtr - del bpy.types.Scene.DLExportPath - del bpy.types.Scene.DLExportisStatic - del bpy.types.Scene.DLDefinePath - del bpy.types.Scene.DLUseBank0 - del bpy.types.Scene.DLRAMAddr - del bpy.types.Scene.DLTexDir - del bpy.types.Scene.DLSeparateTextureDef - del bpy.types.Scene.DLincludeChildren - del bpy.types.Scene.DLInsertableBinaryPath - del bpy.types.Scene.DLName - del bpy.types.Scene.DLCustomExport - del bpy.types.Scene.DLExportHeaderType - del bpy.types.Scene.DLGroupName - del bpy.types.Scene.DLLevelName - del bpy.types.Scene.DLLevelOption - - del bpy.types.Scene.texrect - del bpy.types.Scene.TexRectExportPath - del bpy.types.Scene.TexRectTexDir - del bpy.types.Scene.TexRectName - del bpy.types.Scene.texrectImageTexture - del bpy.types.Scene.TexRectCustomExport - del bpy.types.Scene.TexRectExportType + del bpy.types.Scene.levelDLExport + del bpy.types.Scene.DLExportStart + del bpy.types.Scene.DLExportEnd + del bpy.types.Scene.DLExportGeoPtr + del bpy.types.Scene.overwriteGeoPtr + del bpy.types.Scene.DLExportPath + del bpy.types.Scene.DLExportisStatic + del bpy.types.Scene.DLDefinePath + del bpy.types.Scene.DLUseBank0 + del bpy.types.Scene.DLRAMAddr + del bpy.types.Scene.DLTexDir + del bpy.types.Scene.DLSeparateTextureDef + del bpy.types.Scene.DLincludeChildren + del bpy.types.Scene.DLInsertableBinaryPath + del bpy.types.Scene.DLName + del bpy.types.Scene.DLCustomExport + del bpy.types.Scene.DLExportHeaderType + del bpy.types.Scene.DLGroupName + del bpy.types.Scene.DLLevelName + del bpy.types.Scene.DLLevelOption + + del bpy.types.Scene.texrect + del bpy.types.Scene.TexRectExportPath + del bpy.types.Scene.TexRectTexDir + del bpy.types.Scene.TexRectName + del bpy.types.Scene.texrectImageTexture + del bpy.types.Scene.TexRectCustomExport + del bpy.types.Scene.TexRectExportType diff --git a/fast64_internal/sm64/sm64_objects.py b/fast64_internal/sm64/sm64_objects.py index 0c66e41..1770d6a 100644 --- a/fast64_internal/sm64/sm64_objects.py +++ b/fast64_internal/sm64/sm64_objects.py @@ -11,1848 +11,2079 @@ from ..utility import * from ..f3d.f3d_material import sm64EnumDrawLayers enumTerrain = [ - ('Custom', 'Custom', 'Custom'), - ('TERRAIN_GRASS', 'Grass', 'Grass'), - ('TERRAIN_STONE', 'Stone', 'Stone'), - ('TERRAIN_SNOW', 'Snow', 'Snow'), - ('TERRAIN_SAND', 'Sand', 'Sand'), - ('TERRAIN_SPOOKY', 'Spooky', 'Spooky'), - ('TERRAIN_WATER', 'Water', 'Water'), - ('TERRAIN_SLIDE', 'Slide', 'Slide'), + ("Custom", "Custom", "Custom"), + ("TERRAIN_GRASS", "Grass", "Grass"), + ("TERRAIN_STONE", "Stone", "Stone"), + ("TERRAIN_SNOW", "Snow", "Snow"), + ("TERRAIN_SAND", "Sand", "Sand"), + ("TERRAIN_SPOOKY", "Spooky", "Spooky"), + ("TERRAIN_WATER", "Water", "Water"), + ("TERRAIN_SLIDE", "Slide", "Slide"), ] enumMusicSeq = [ - ('Custom', 'Custom', 'Custom'), - ('SEQ_LEVEL_BOSS_KOOPA', 'Boss Koopa', 'Boss Koopa'), - ('SEQ_LEVEL_BOSS_KOOPA_FINAL', 'Boss Koopa Final', 'Boss Koopa Final'), - ('SEQ_LEVEL_GRASS', 'Grass Level', 'Grass Level'), - ('SEQ_LEVEL_HOT', 'Hot Level', 'Hot Level'), - ('SEQ_LEVEL_INSIDE_CASTLE', 'Inside Castle', 'Inside Castle'), - ('SEQ_LEVEL_KOOPA_ROAD', 'Koopa Road', 'Koopa Road'), - ('SEQ_LEVEL_SLIDE', 'Slide Level', 'Slide Level'), - ('SEQ_LEVEL_SNOW', 'Snow Level', 'Snow Level'), - ('SEQ_LEVEL_SPOOKY', 'Spooky Level', 'Spooky Level'), - ('SEQ_LEVEL_UNDERGROUND', 'Underground Level', 'Underground Level'), - ('SEQ_LEVEL_WATER', 'Water Level', 'Water Level'), - ('SEQ_MENU_FILE_SELECT', 'File Select', 'File Select'), - ('SEQ_MENU_STAR_SELECT', 'Star Select Menu', 'Star Select Menu'), - ('SEQ_MENU_TITLE_SCREEN', 'Title Screen', 'Title Screen'), - ('SEQ_EVENT_BOSS', 'Boss', 'Boss'), - ('SEQ_EVENT_CUTSCENE_COLLECT_KEY', 'Collect Key', 'Collect Key'), - ('SEQ_EVENT_CUTSCENE_COLLECT_STAR', 'Collect Star', 'Collect Star'), - ('SEQ_EVENT_CUTSCENE_CREDITS', 'Credits', 'Credits'), - ('SEQ_EVENT_CUTSCENE_ENDING', 'Ending Cutscene', 'Ending Cutscene'), - ('SEQ_EVENT_CUTSCENE_INTRO', 'Intro Cutscene', 'Intro Cutscene'), - ('SEQ_EVENT_CUTSCENE_LAKITU', 'Lakitu Cutscene', 'Lakitu Cutscene'), - ('SEQ_EVENT_CUTSCENE_STAR_SPAWN', 'Star Spawn', 'Star Spawn'), - ('SEQ_EVENT_CUTSCENE_VICTORY', 'Victory Cutscene', 'Victory Cutscene'), - ('SEQ_EVENT_ENDLESS_STAIRS', 'Endless Stairs', 'Endless Stairs'), - ('SEQ_EVENT_HIGH_SCORE', 'High Score', 'High Score'), - ('SEQ_EVENT_KOOPA_MESSAGE', 'Koopa Message', 'Koopa Message'), - ('SEQ_EVENT_MERRY_GO_ROUND', 'Merry Go Round', 'Merry Go Round'), - ('SEQ_EVENT_METAL_CAP', 'Metal Cap', 'Metal Cap'), - ('SEQ_EVENT_PEACH_MESSAGE', 'Peach Message', 'Peach Message'), - ('SEQ_EVENT_PIRANHA_PLANT', 'Piranha Lullaby', 'Piranha Lullaby'), - ('SEQ_EVENT_POWERUP', 'Powerup', 'Powerup'), - ('SEQ_EVENT_RACE', 'Race', 'Race'), - ('SEQ_EVENT_SOLVE_PUZZLE', 'Solve Puzzle', 'Solve Puzzle'), - ('SEQ_SOUND_PLAYER', 'Sound Player', 'Sound Player'), - ('SEQ_EVENT_TOAD_MESSAGE', 'Toad Message', 'Toad Message'), + ("Custom", "Custom", "Custom"), + ("SEQ_LEVEL_BOSS_KOOPA", "Boss Koopa", "Boss Koopa"), + ("SEQ_LEVEL_BOSS_KOOPA_FINAL", "Boss Koopa Final", "Boss Koopa Final"), + ("SEQ_LEVEL_GRASS", "Grass Level", "Grass Level"), + ("SEQ_LEVEL_HOT", "Hot Level", "Hot Level"), + ("SEQ_LEVEL_INSIDE_CASTLE", "Inside Castle", "Inside Castle"), + ("SEQ_LEVEL_KOOPA_ROAD", "Koopa Road", "Koopa Road"), + ("SEQ_LEVEL_SLIDE", "Slide Level", "Slide Level"), + ("SEQ_LEVEL_SNOW", "Snow Level", "Snow Level"), + ("SEQ_LEVEL_SPOOKY", "Spooky Level", "Spooky Level"), + ("SEQ_LEVEL_UNDERGROUND", "Underground Level", "Underground Level"), + ("SEQ_LEVEL_WATER", "Water Level", "Water Level"), + ("SEQ_MENU_FILE_SELECT", "File Select", "File Select"), + ("SEQ_MENU_STAR_SELECT", "Star Select Menu", "Star Select Menu"), + ("SEQ_MENU_TITLE_SCREEN", "Title Screen", "Title Screen"), + ("SEQ_EVENT_BOSS", "Boss", "Boss"), + ("SEQ_EVENT_CUTSCENE_COLLECT_KEY", "Collect Key", "Collect Key"), + ("SEQ_EVENT_CUTSCENE_COLLECT_STAR", "Collect Star", "Collect Star"), + ("SEQ_EVENT_CUTSCENE_CREDITS", "Credits", "Credits"), + ("SEQ_EVENT_CUTSCENE_ENDING", "Ending Cutscene", "Ending Cutscene"), + ("SEQ_EVENT_CUTSCENE_INTRO", "Intro Cutscene", "Intro Cutscene"), + ("SEQ_EVENT_CUTSCENE_LAKITU", "Lakitu Cutscene", "Lakitu Cutscene"), + ("SEQ_EVENT_CUTSCENE_STAR_SPAWN", "Star Spawn", "Star Spawn"), + ("SEQ_EVENT_CUTSCENE_VICTORY", "Victory Cutscene", "Victory Cutscene"), + ("SEQ_EVENT_ENDLESS_STAIRS", "Endless Stairs", "Endless Stairs"), + ("SEQ_EVENT_HIGH_SCORE", "High Score", "High Score"), + ("SEQ_EVENT_KOOPA_MESSAGE", "Koopa Message", "Koopa Message"), + ("SEQ_EVENT_MERRY_GO_ROUND", "Merry Go Round", "Merry Go Round"), + ("SEQ_EVENT_METAL_CAP", "Metal Cap", "Metal Cap"), + ("SEQ_EVENT_PEACH_MESSAGE", "Peach Message", "Peach Message"), + ("SEQ_EVENT_PIRANHA_PLANT", "Piranha Lullaby", "Piranha Lullaby"), + ("SEQ_EVENT_POWERUP", "Powerup", "Powerup"), + ("SEQ_EVENT_RACE", "Race", "Race"), + ("SEQ_EVENT_SOLVE_PUZZLE", "Solve Puzzle", "Solve Puzzle"), + ("SEQ_SOUND_PLAYER", "Sound Player", "Sound Player"), + ("SEQ_EVENT_TOAD_MESSAGE", "Toad Message", "Toad Message"), ] enumWarpType = [ - ("Warp", "Warp", "Warp"), - ("Painting", "Painting", "Painting"), - ("Instant", "Instant", "Instant"), + ("Warp", "Warp", "Warp"), + ("Painting", "Painting", "Painting"), + ("Instant", "Instant", "Instant"), ] enumWarpFlag = [ - ("Custom", "Custom", "Custom"), - ("WARP_NO_CHECKPOINT", 'No Checkpoint', 'No Checkpoint'), - ("WARP_CHECKPOINT", 'Checkpoint', 'Checkpoint'), + ("Custom", "Custom", "Custom"), + ("WARP_NO_CHECKPOINT", "No Checkpoint", "No Checkpoint"), + ("WARP_CHECKPOINT", "Checkpoint", "Checkpoint"), ] enumEnvFX = [ - ('Custom', 'Custom', 'Custom'), - ('ENVFX_MODE_NONE', 'None', 'None'), - ('ENVFX_SNOW_NORMAL', 'Snow', 'Used in CCM, SL'), - ('ENVFX_SNOW_WATER', 'Water Bubbles', 'Used in Secret Aquarium, Sunken Ships'), - ('ENVFX_SNOW_BLIZZARD', 'Blizzard', 'Unused'), - ('ENVFX_FLOWERS', 'Flowers', 'Unused'), - ('ENVFX_LAVA_BUBBLES', 'Lava Bubbles', 'Used in LLL, BitFS, Bowser 2'), - ('ENVFX_WHIRLPOOL_BUBBLES', 'Whirpool Bubbles', 'Used in DDD where whirpool is'), - ('ENVFX_JETSTREAM_BUBBLES', 'Jetstream Bubbles', 'Used in JRB, DDD where jetstream is'), + ("Custom", "Custom", "Custom"), + ("ENVFX_MODE_NONE", "None", "None"), + ("ENVFX_SNOW_NORMAL", "Snow", "Used in CCM, SL"), + ("ENVFX_SNOW_WATER", "Water Bubbles", "Used in Secret Aquarium, Sunken Ships"), + ("ENVFX_SNOW_BLIZZARD", "Blizzard", "Unused"), + ("ENVFX_FLOWERS", "Flowers", "Unused"), + ("ENVFX_LAVA_BUBBLES", "Lava Bubbles", "Used in LLL, BitFS, Bowser 2"), + ("ENVFX_WHIRLPOOL_BUBBLES", "Whirpool Bubbles", "Used in DDD where whirpool is"), + ("ENVFX_JETSTREAM_BUBBLES", "Jetstream Bubbles", "Used in JRB, DDD where jetstream is"), ] enumCameraMode = [ - ('Custom', 'Custom', 'Custom'), - ('CAMERA_MODE_NONE', 'None', 'None'), - ('CAMERA_MODE_RADIAL', 'Radial', 'Radial'), - ('CAMERA_MODE_OUTWARD_RADIAL', 'Outward Radial', 'Outward Radial'), - ('CAMERA_MODE_BEHIND_MARIO', 'Behind Mario', 'Behind Mario'), - ('CAMERA_MODE_CLOSE', 'Close', 'Close'), - ('CAMERA_MODE_C_UP', 'C Up', 'C Up'), - ('CAMERA_MODE_WATER_SURFACE', 'Water Surface', 'Water Surface'), - ('CAMERA_MODE_SLIDE_HOOT', 'Slide/Hoot', 'Slide/Hoot'), - ('CAMERA_MODE_INSIDE_CANNON', 'Inside Cannon', 'Inside Cannon'), - ('CAMERA_MODE_BOSS_FIGHT', 'Boss Fight', 'Boss Fight'), - ('CAMERA_MODE_PARALLEL_TRACKING', 'Parallel Tracking', 'Parallel Tracking'), - ('CAMERA_MODE_FIXED', 'Fixed', 'Fixed'), - ('CAMERA_MODE_8_DIRECTIONS', '8 Directions', '8 Directions'), - ('CAMERA_MODE_FREE_ROAM', 'Free Roam', 'Free Roam'), - ('CAMERA_MODE_SPIRAL_STAIRS', 'Spiral Stairs', 'Spiral Stairs'), + ("Custom", "Custom", "Custom"), + ("CAMERA_MODE_NONE", "None", "None"), + ("CAMERA_MODE_RADIAL", "Radial", "Radial"), + ("CAMERA_MODE_OUTWARD_RADIAL", "Outward Radial", "Outward Radial"), + ("CAMERA_MODE_BEHIND_MARIO", "Behind Mario", "Behind Mario"), + ("CAMERA_MODE_CLOSE", "Close", "Close"), + ("CAMERA_MODE_C_UP", "C Up", "C Up"), + ("CAMERA_MODE_WATER_SURFACE", "Water Surface", "Water Surface"), + ("CAMERA_MODE_SLIDE_HOOT", "Slide/Hoot", "Slide/Hoot"), + ("CAMERA_MODE_INSIDE_CANNON", "Inside Cannon", "Inside Cannon"), + ("CAMERA_MODE_BOSS_FIGHT", "Boss Fight", "Boss Fight"), + ("CAMERA_MODE_PARALLEL_TRACKING", "Parallel Tracking", "Parallel Tracking"), + ("CAMERA_MODE_FIXED", "Fixed", "Fixed"), + ("CAMERA_MODE_8_DIRECTIONS", "8 Directions", "8 Directions"), + ("CAMERA_MODE_FREE_ROAM", "Free Roam", "Free Roam"), + ("CAMERA_MODE_SPIRAL_STAIRS", "Spiral Stairs", "Spiral Stairs"), ] enumBackground = [ - ('OCEAN_SKY', 'Ocean Sky', 'Ocean Sky'), - ('FLAMING_SKY', 'Flaming Sky', 'Flaming Sky'), - ('UNDERWATER_CITY', 'Underwater City', 'Underwater City'), - ('BELOW_CLOUDS', 'Below Clouds', 'Below Clouds'), - ('SNOW_MOUNTAINS', 'Snow Mountains', 'Snow Mountains'), - ('DESERT', 'Desert', 'Desert'), - ('HAUNTED', 'Haunted', 'Haunted'), - ('GREEN_SKY', 'Green Sky', 'Green Sky'), - ('ABOVE_CLOUDS', 'Above Clouds', 'Above Clouds'), - ('PURPLE_SKY', 'Purple Sky', 'Purple Sky'), - ('CUSTOM', 'Custom', 'Custom'), + ("OCEAN_SKY", "Ocean Sky", "Ocean Sky"), + ("FLAMING_SKY", "Flaming Sky", "Flaming Sky"), + ("UNDERWATER_CITY", "Underwater City", "Underwater City"), + ("BELOW_CLOUDS", "Below Clouds", "Below Clouds"), + ("SNOW_MOUNTAINS", "Snow Mountains", "Snow Mountains"), + ("DESERT", "Desert", "Desert"), + ("HAUNTED", "Haunted", "Haunted"), + ("GREEN_SKY", "Green Sky", "Green Sky"), + ("ABOVE_CLOUDS", "Above Clouds", "Above Clouds"), + ("PURPLE_SKY", "Purple Sky", "Purple Sky"), + ("CUSTOM", "Custom", "Custom"), ] backgroundSegments = { - 'OCEAN_SKY' : 'water', - 'FLAMING_SKY' : 'bitfs', - 'UNDERWATER_CITY' : 'wdw', - 'BELOW_CLOUDS' : 'cloud_floor', - 'SNOW_MOUNTAINS' : 'ccm', - 'DESERT' : 'ssl', - 'HAUNTED' : 'bbh', - 'GREEN_SKY' : 'bidw', - 'ABOVE_CLOUDS' : 'clouds', - 'PURPLE_SKY' : 'bits', + "OCEAN_SKY": "water", + "FLAMING_SKY": "bitfs", + "UNDERWATER_CITY": "wdw", + "BELOW_CLOUDS": "cloud_floor", + "SNOW_MOUNTAINS": "ccm", + "DESERT": "ssl", + "HAUNTED": "bbh", + "GREEN_SKY": "bidw", + "ABOVE_CLOUDS": "clouds", + "PURPLE_SKY": "bits", } -enumWaterBoxType = [ - ("Water", 'Water', "Water"), - ('Toxic Haze', 'Toxic Haze', 'Toxic Haze') -] +enumWaterBoxType = [("Water", "Water", "Water"), ("Toxic Haze", "Toxic Haze", "Toxic Haze")] + class InlineGeolayoutObjConfig: - def __init__( - self, name, geo_node, - can_have_dl=False, - must_have_dl=False, - must_have_geo=False, - uses_location=False, - uses_rotation=False, - uses_scale=False - ): - self.name = name - self.geo_node = geo_node - self.can_have_dl = can_have_dl or must_have_dl - self.must_have_dl = must_have_dl - self.must_have_geo = must_have_geo - self.uses_location = uses_location - self.uses_rotation = uses_rotation - self.uses_scale = uses_scale + def __init__( + self, + name, + geo_node, + can_have_dl=False, + must_have_dl=False, + must_have_geo=False, + uses_location=False, + uses_rotation=False, + uses_scale=False, + ): + self.name = name + self.geo_node = geo_node + self.can_have_dl = can_have_dl or must_have_dl + self.must_have_dl = must_have_dl + self.must_have_geo = must_have_geo + self.uses_location = uses_location + self.uses_rotation = uses_rotation + self.uses_scale = uses_scale + inlineGeoLayoutObjects = { - 'Geo ASM' : InlineGeolayoutObjConfig('Geo ASM', FunctionNode), - 'Geo Branch' : InlineGeolayoutObjConfig('Geo Branch', JumpNode, - must_have_geo=True), - 'Geo Translate/Rotate' : InlineGeolayoutObjConfig('Geo Translate/Rotate', TranslateRotateNode, - can_have_dl=True, uses_location=True, uses_rotation=True), - 'Geo Translate Node' : InlineGeolayoutObjConfig('Geo Translate Node', TranslateNode, - can_have_dl=True, uses_location=True), - 'Geo Rotation Node' : InlineGeolayoutObjConfig('Geo Rotation Node', RotateNode, - can_have_dl=True, uses_rotation=True), - 'Geo Billboard' : InlineGeolayoutObjConfig('Geo Billboard', BillboardNode, - can_have_dl=True, uses_location=True), - 'Geo Scale' : InlineGeolayoutObjConfig('Geo Scale', ScaleNode, - can_have_dl=True, uses_scale=True), - 'Geo Displaylist' : InlineGeolayoutObjConfig('Geo Displaylist', DisplayListNode, - must_have_dl=True), - 'Custom Geo Command' : InlineGeolayoutObjConfig('Custom Geo Command', CustomNode), + "Geo ASM": InlineGeolayoutObjConfig("Geo ASM", FunctionNode), + "Geo Branch": InlineGeolayoutObjConfig("Geo Branch", JumpNode, must_have_geo=True), + "Geo Translate/Rotate": InlineGeolayoutObjConfig( + "Geo Translate/Rotate", TranslateRotateNode, can_have_dl=True, uses_location=True, uses_rotation=True + ), + "Geo Translate Node": InlineGeolayoutObjConfig( + "Geo Translate Node", TranslateNode, can_have_dl=True, uses_location=True + ), + "Geo Rotation Node": InlineGeolayoutObjConfig( + "Geo Rotation Node", RotateNode, can_have_dl=True, uses_rotation=True + ), + "Geo Billboard": InlineGeolayoutObjConfig("Geo Billboard", BillboardNode, can_have_dl=True, uses_location=True), + "Geo Scale": InlineGeolayoutObjConfig("Geo Scale", ScaleNode, can_have_dl=True, uses_scale=True), + "Geo Displaylist": InlineGeolayoutObjConfig("Geo Displaylist", DisplayListNode, must_have_dl=True), + "Custom Geo Command": InlineGeolayoutObjConfig("Custom Geo Command", CustomNode), } # When adding new types related to geolayout, # Make sure to add exceptions to enumSM64EmptyWithGeolayout enumObjectType = [ - ('None', 'None', 'None'), - ('Level Root', 'Level Root', 'Level Root'), - ('Area Root', 'Area Root', 'Area Root'), - ('Object', 'Object', 'Object'), - ('Macro', 'Macro', 'Macro'), - ('Special', 'Special', 'Special'), - ('Mario Start', 'Mario Start', 'Mario Start'), - ('Whirlpool', 'Whirlpool', 'Whirlpool'), - ('Water Box', 'Water Box', 'Water Box'), - ('Camera Volume', 'Camera Volume', 'Camera Volume'), - ('Switch', 'Switch Node', 'Switch Node'), - ('Puppycam Volume', 'Puppycam Volume', 'Puppycam Volume'), - ('', 'Inline Geolayout Commands', ''), # This displays as a column header for the next set of options - *[(key, key, key) for key in inlineGeoLayoutObjects.keys()] + ("None", "None", "None"), + ("Level Root", "Level Root", "Level Root"), + ("Area Root", "Area Root", "Area Root"), + ("Object", "Object", "Object"), + ("Macro", "Macro", "Macro"), + ("Special", "Special", "Special"), + ("Mario Start", "Mario Start", "Mario Start"), + ("Whirlpool", "Whirlpool", "Whirlpool"), + ("Water Box", "Water Box", "Water Box"), + ("Camera Volume", "Camera Volume", "Camera Volume"), + ("Switch", "Switch Node", "Switch Node"), + ("Puppycam Volume", "Puppycam Volume", "Puppycam Volume"), + ("", "Inline Geolayout Commands", ""), # This displays as a column header for the next set of options + *[(key, key, key) for key in inlineGeoLayoutObjects.keys()], ] enumPuppycamMode = [ - ('Custom', 'Custom', 'Custom'), - ('NC_MODE_NORMAL', 'Normal', 'Normal'), - ('NC_MODE_SLIDE', 'Slide', 'Slide'), - ('NC_MODE_FIXED', 'Fixed Position', 'Fixed Position'), - ('NC_MODE_2D', 'Two Dimensional', 'Two Dimensional'), - ('NC_MODE_8D', '8 Directions', '8 Directions'), - ('NC_MODE_FIXED_NOMOVE', 'Fixed, No Move', 'Fixed, No Move'), - ('NC_MODE_NOTURN', 'No Turning', 'No Turning'), - ('NC_MODE_NOROTATE', 'No Rotation', 'No Rotation'), + ("Custom", "Custom", "Custom"), + ("NC_MODE_NORMAL", "Normal", "Normal"), + ("NC_MODE_SLIDE", "Slide", "Slide"), + ("NC_MODE_FIXED", "Fixed Position", "Fixed Position"), + ("NC_MODE_2D", "Two Dimensional", "Two Dimensional"), + ("NC_MODE_8D", "8 Directions", "8 Directions"), + ("NC_MODE_FIXED_NOMOVE", "Fixed, No Move", "Fixed, No Move"), + ("NC_MODE_NOTURN", "No Turning", "No Turning"), + ("NC_MODE_NOROTATE", "No Rotation", "No Rotation"), ] enumPuppycamFlags = [ - ('NC_FLAG_XTURN', 'X Turn', 'the camera\'s yaw can be moved by the player.'), - ('NC_FLAG_YTURN', 'Y Turn', 'the camera\'s pitch can be moved by the player.'), - ('NC_FLAG_ZOOM', 'Zoom', 'the camera\'s distance can be set by the player.'), - ('NC_FLAG_8D', '8 Directions', 'the camera will snap to an 8 directional axis'), - ('NC_FLAG_4D', '4 Directions', 'the camera will snap to a 4 directional axis'), - ('NC_FLAG_2D', '2D', 'the camera will stick to 2D.'), - ('NC_FLAG_FOCUSX', 'Use X Focus', 'the camera will point towards its focus on the X axis.'), - ('NC_FLAG_FOCUSY', 'Use Y Focus', 'the camera will point towards its focus on the Y axis.'), - ('NC_FLAG_FOCUSZ', 'Use Z Focus', 'the camera will point towards its focus on the Z axis.'), - ('NC_FLAG_POSX', 'Move on X axis', 'the camera will move along the X axis.'), - ('NC_FLAG_POSY', 'Move on Y axis', 'the camera will move along the Y axis.'), - ('NC_FLAG_POSZ', 'Move on Z axis', 'the camera will move along the Z axis.'), - ('NC_FLAG_COLLISION', 'Collision', 'the camera will collide and correct itself with terrain.'), - ('NC_FLAG_SLIDECORRECT', 'Slide Correction', 'the camera will attempt to centre itself behind Mario whenever he\'s sliding.'), + ("NC_FLAG_XTURN", "X Turn", "the camera's yaw can be moved by the player."), + ("NC_FLAG_YTURN", "Y Turn", "the camera's pitch can be moved by the player."), + ("NC_FLAG_ZOOM", "Zoom", "the camera's distance can be set by the player."), + ("NC_FLAG_8D", "8 Directions", "the camera will snap to an 8 directional axis"), + ("NC_FLAG_4D", "4 Directions", "the camera will snap to a 4 directional axis"), + ("NC_FLAG_2D", "2D", "the camera will stick to 2D."), + ("NC_FLAG_FOCUSX", "Use X Focus", "the camera will point towards its focus on the X axis."), + ("NC_FLAG_FOCUSY", "Use Y Focus", "the camera will point towards its focus on the Y axis."), + ("NC_FLAG_FOCUSZ", "Use Z Focus", "the camera will point towards its focus on the Z axis."), + ("NC_FLAG_POSX", "Move on X axis", "the camera will move along the X axis."), + ("NC_FLAG_POSY", "Move on Y axis", "the camera will move along the Y axis."), + ("NC_FLAG_POSZ", "Move on Z axis", "the camera will move along the Z axis."), + ("NC_FLAG_COLLISION", "Collision", "the camera will collide and correct itself with terrain."), + ( + "NC_FLAG_SLIDECORRECT", + "Slide Correction", + "the camera will attempt to centre itself behind Mario whenever he's sliding.", + ), ] -class SM64_Object: - def __init__(self, model, position, rotation, behaviour, bparam, acts): - self.model = model - self.behaviour = behaviour - self.bparam = bparam - self.acts = acts - self.position = position - self.rotation = rotation - def to_c(self): - if self.acts == 0x1F: - return 'OBJECT(' + str(self.model) + ', ' + \ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(int(round(math.degrees(self.rotation[0])))) + ', ' + \ - str(int(round(math.degrees(self.rotation[1])))) + ', ' + \ - str(int(round(math.degrees(self.rotation[2])))) + ', ' + \ - str(self.bparam) + ', ' + str(self.behaviour) + ')' - else: - return 'OBJECT_WITH_ACTS(' + str(self.model) + ', ' + \ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(int(round(math.degrees(self.rotation[0])))) + ', ' + \ - str(int(round(math.degrees(self.rotation[1])))) + ', ' + \ - str(int(round(math.degrees(self.rotation[2])))) + ', ' + \ - str(self.bparam) + ', ' + str(self.behaviour) + ', ' + str(self.acts) + ')' +class SM64_Object: + def __init__(self, model, position, rotation, behaviour, bparam, acts): + self.model = model + self.behaviour = behaviour + self.bparam = bparam + self.acts = acts + self.position = position + self.rotation = rotation + + def to_c(self): + if self.acts == 0x1F: + return ( + "OBJECT(" + + str(self.model) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(int(round(math.degrees(self.rotation[0])))) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + ", " + + str(int(round(math.degrees(self.rotation[2])))) + + ", " + + str(self.bparam) + + ", " + + str(self.behaviour) + + ")" + ) + else: + return ( + "OBJECT_WITH_ACTS(" + + str(self.model) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(int(round(math.degrees(self.rotation[0])))) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + ", " + + str(int(round(math.degrees(self.rotation[2])))) + + ", " + + str(self.bparam) + + ", " + + str(self.behaviour) + + ", " + + str(self.acts) + + ")" + ) + class SM64_Whirpool: - def __init__(self, index, condition, strength, position): - self.index = index - self.condition = condition - self.strength = strength - self.position = position + def __init__(self, index, condition, strength, position): + self.index = index + self.condition = condition + self.strength = strength + self.position = position + + def to_c(self): + return ( + "WHIRPOOL(" + + str(self.index) + + ", " + + str(self.condition) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(self.strength) + + ")" + ) - def to_c(self): - return 'WHIRPOOL(' + str(self.index) + ', ' + str(self.condition) + ', ' +\ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(self.strength) + ')' class SM64_Macro_Object: - def __init__(self, preset, position, rotation, bparam): - self.preset = preset - self.bparam = bparam - self.position = position - self.rotation = rotation + def __init__(self, preset, position, rotation, bparam): + self.preset = preset + self.bparam = bparam + self.position = position + self.rotation = rotation + + def to_c(self): + if self.bparam is None: + return ( + "MACRO_OBJECT(" + + str(self.preset) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ")" + ) + else: + return ( + "MACRO_OBJECT_WITH_BEH_PARAM(" + + str(self.preset) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(self.bparam) + + ")" + ) - def to_c(self): - if self.bparam is None: - return 'MACRO_OBJECT(' + str(self.preset) + ', ' + \ - str(int(round(math.degrees(self.rotation[1])))) + ', ' + \ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ')' - else: - return 'MACRO_OBJECT_WITH_BEH_PARAM(' + str(self.preset) + ', ' + \ - str(int(round(math.degrees(self.rotation[1])))) + ', ' + \ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(self.bparam) + ')' class SM64_Special_Object: - def __init__(self, preset, position, rotation, bparam): - self.preset = preset - self.bparam = bparam - self.position = position - self.rotation = rotation + def __init__(self, preset, position, rotation, bparam): + self.preset = preset + self.bparam = bparam + self.position = position + self.rotation = rotation - def to_binary(self): - data = int(self.preset).to_bytes(2, 'big') - if len(self.position) > 3: - raise PluginError("Object position should not be " + \ - str(len(self.position) + ' fields long.')) - for index in self.position: - data.extend(int(round(index)).to_bytes(2, 'big', signed = False)) - if self.rotation is not None: - data.extend(int(round(math.degrees(self.rotation[1]))).to_bytes(2, 'big')) - if self.bparam is not None: - data.extend(int(self.bparam).to_bytes(2, 'big')) - return data + def to_binary(self): + data = int(self.preset).to_bytes(2, "big") + if len(self.position) > 3: + raise PluginError("Object position should not be " + str(len(self.position) + " fields long.")) + for index in self.position: + data.extend(int(round(index)).to_bytes(2, "big", signed=False)) + if self.rotation is not None: + data.extend(int(round(math.degrees(self.rotation[1]))).to_bytes(2, "big")) + if self.bparam is not None: + data.extend(int(self.bparam).to_bytes(2, "big")) + return data + + def to_c(self): + if self.rotation is None: + return ( + "SPECIAL_OBJECT(" + + str(self.preset) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + "),\n" + ) + elif self.bparam is None: + return ( + "SPECIAL_OBJECT_WITH_YAW(" + + str(self.preset) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + "),\n" + ) + else: + return ( + "SPECIAL_OBJECT_WITH_YAW_AND_PARAM(" + + str(self.preset) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + ", " + + str(self.bparam) + + "),\n" + ) - def to_c(self): - if self.rotation is None: - return 'SPECIAL_OBJECT(' + str(self.preset) + ', ' +\ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + '),\n' - elif self.bparam is None: - return 'SPECIAL_OBJECT_WITH_YAW(' + str(self.preset) + ', ' +\ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(int(round(math.degrees(self.rotation[1])))) + '),\n' - else: - return 'SPECIAL_OBJECT_WITH_YAW_AND_PARAM(' + str(self.preset) + ', ' +\ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(int(round(math.degrees(self.rotation[1])))) + ', ' + \ - str(self.bparam) + '),\n' class SM64_Mario_Start: - def __init__(self, area, position, rotation): - self.area = area - self.position = position - self.rotation = rotation + def __init__(self, area, position, rotation): + self.area = area + self.position = position + self.rotation = rotation + + def to_c(self): + return ( + "MARIO_POS(" + + str(self.area) + + ", " + + str(int(round(math.degrees(self.rotation[1])))) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ")" + ) - def to_c(self): - return 'MARIO_POS(' + str(self.area) + ', ' + str(int(round(math.degrees(self.rotation[1])))) + ', ' +\ - str(int(round(self.position[0]))) + ', ' + str(int(round(self.position[1]))) + ', ' + str(int(round(self.position[2]))) + ')' class SM64_Area: - def __init__(self, index, music_seq, music_preset, - terrain_type, geolayout, collision, warpNodes, name, startDialog): - self.cameraVolumes = [] - self.puppycamVolumes = [] - self.name = toAlnum(name) - self.geolayout = geolayout - self.collision = collision - self.index = index - self.objects = [] - self.macros = [] - self.specials = [] - self.water_boxes = [] - self.music_preset = music_preset - self.music_seq = music_seq - self.terrain_type = terrain_type - self.warpNodes = warpNodes - self.mario_start = None - self.splines = [] - self.startDialog = startDialog + def __init__( + self, index, music_seq, music_preset, terrain_type, geolayout, collision, warpNodes, name, startDialog + ): + self.cameraVolumes = [] + self.puppycamVolumes = [] + self.name = toAlnum(name) + self.geolayout = geolayout + self.collision = collision + self.index = index + self.objects = [] + self.macros = [] + self.specials = [] + self.water_boxes = [] + self.music_preset = music_preset + self.music_seq = music_seq + self.terrain_type = terrain_type + self.warpNodes = warpNodes + self.mario_start = None + self.splines = [] + self.startDialog = startDialog - def macros_name(self): - return self.name + '_macro_objs' + def macros_name(self): + return self.name + "_macro_objs" - def to_c_script(self, includeRooms, persistentBlockString: str = ''): - data = '' - data += '\tAREA(' + str(self.index) + ', ' + self.geolayout.name + '),\n' - for warpNode in self.warpNodes: - data += '\t\t' + warpNode + ',\n' - for obj in self.objects: - data += '\t\t' + obj.to_c() + ',\n' - data += '\t\tTERRAIN(' + self.collision.name + '),\n' - if includeRooms: - data += '\t\tROOMS(' + self.collision.rooms_name() + '),\n' - data += '\t\tMACRO_OBJECTS(' + self.macros_name() + '),\n' - if self.music_seq is None: - data += '\t\tSTOP_MUSIC(0),\n' - else: - data += '\t\tSET_BACKGROUND_MUSIC(' + self.music_preset + ', ' + self.music_seq + '),\n' - if self.startDialog is not None: - data += '\t\tSHOW_DIALOG(0x00, ' + self.startDialog + '),\n' - data += '\t\tTERRAIN_TYPE(' + self.terrain_type + '),\n' - data += f'{persistentBlockString}\n' - data += '\tEND_AREA(),\n\n' - return data + def to_c_script(self, includeRooms, persistentBlockString: str = ""): + data = "" + data += "\tAREA(" + str(self.index) + ", " + self.geolayout.name + "),\n" + for warpNode in self.warpNodes: + data += "\t\t" + warpNode + ",\n" + for obj in self.objects: + data += "\t\t" + obj.to_c() + ",\n" + data += "\t\tTERRAIN(" + self.collision.name + "),\n" + if includeRooms: + data += "\t\tROOMS(" + self.collision.rooms_name() + "),\n" + data += "\t\tMACRO_OBJECTS(" + self.macros_name() + "),\n" + if self.music_seq is None: + data += "\t\tSTOP_MUSIC(0),\n" + else: + data += "\t\tSET_BACKGROUND_MUSIC(" + self.music_preset + ", " + self.music_seq + "),\n" + if self.startDialog is not None: + data += "\t\tSHOW_DIALOG(0x00, " + self.startDialog + "),\n" + data += "\t\tTERRAIN_TYPE(" + self.terrain_type + "),\n" + data += f"{persistentBlockString}\n" + data += "\tEND_AREA(),\n\n" + return data - def to_c_macros(self): - data = CData() - data.header = 'extern const MacroObject ' + self.macros_name() + '[];\n' - data.source += 'const MacroObject ' + self.macros_name() + '[] = {\n' - for macro in self.macros: - data.source += '\t' + macro.to_c() + ',\n' - data.source += '\tMACRO_OBJECT_END(),\n};\n\n' + def to_c_macros(self): + data = CData() + data.header = "extern const MacroObject " + self.macros_name() + "[];\n" + data.source += "const MacroObject " + self.macros_name() + "[] = {\n" + for macro in self.macros: + data.source += "\t" + macro.to_c() + ",\n" + data.source += "\tMACRO_OBJECT_END(),\n};\n\n" - return data + return data - def to_c_camera_volumes(self): - data = '' - for camVolume in self.cameraVolumes: - data += '\t' + camVolume.to_c() + '\n' - return data + def to_c_camera_volumes(self): + data = "" + for camVolume in self.cameraVolumes: + data += "\t" + camVolume.to_c() + "\n" + return data - def to_c_puppycam_volumes(self): - data = '' - for puppycamVolume in self.puppycamVolumes: - data += '\t' + puppycamVolume.to_c() + '\n' - return data + def to_c_puppycam_volumes(self): + data = "" + for puppycamVolume in self.puppycamVolumes: + data += "\t" + puppycamVolume.to_c() + "\n" + return data - def hasCutsceneSpline(self): - for spline in self.splines: - if spline.splineType == 'Cutscene': - return True - return False + def hasCutsceneSpline(self): + for spline in self.splines: + if spline.splineType == "Cutscene": + return True + return False + + def to_c_splines(self): + data = CData() + for spline in self.splines: + data.append(spline.to_c()) + if self.hasCutsceneSpline(): + data.source = '#include "src/game/camera.h"\n\n' + data.source + data.header = '#include "src/game/camera.h"\n\n' + data.header + return data - def to_c_splines(self): - data = CData() - for spline in self.splines: - data.append(spline.to_c()) - if self.hasCutsceneSpline(): - data.source = '#include "src/game/camera.h"\n\n' + data.source - data.header = '#include "src/game/camera.h"\n\n' + data.header - return data class CollisionWaterBox: - def __init__(self, waterBoxType, position, scale, emptyScale): - # The scale ordering is due to the fact that scaling happens AFTER rotation. - # Thus the translation uses Y-up, while the scale uses Z-up. - self.waterBoxType = waterBoxType - self.low = (position[0] - scale[0] * emptyScale, position[2] - scale[1] * emptyScale) - self.high = (position[0] + scale[0] * emptyScale, position[2] + scale[1] * emptyScale) - self.height = position[1] + scale[2] * emptyScale + def __init__(self, waterBoxType, position, scale, emptyScale): + # The scale ordering is due to the fact that scaling happens AFTER rotation. + # Thus the translation uses Y-up, while the scale uses Z-up. + self.waterBoxType = waterBoxType + self.low = (position[0] - scale[0] * emptyScale, position[2] - scale[1] * emptyScale) + self.high = (position[0] + scale[0] * emptyScale, position[2] + scale[1] * emptyScale) + self.height = position[1] + scale[2] * emptyScale - def to_binary(self): - data = bytearray([0x00, 0x00 if self.waterBoxType == 'Water' else 0x32]) - data.extend(int(round(self.low[0])).to_bytes(2, 'big', signed=True)) - data.extend(int(round(self.low[1])).to_bytes(2, 'big', signed=True)) - data.extend(int(round(self.high[0])).to_bytes(2, 'big', signed=True)) - data.extend(int(round(self.high[1])).to_bytes(2, 'big', signed=True)) - data.extend(int(round(self.height)).to_bytes(2, 'big', signed=True)) - return data + def to_binary(self): + data = bytearray([0x00, 0x00 if self.waterBoxType == "Water" else 0x32]) + data.extend(int(round(self.low[0])).to_bytes(2, "big", signed=True)) + data.extend(int(round(self.low[1])).to_bytes(2, "big", signed=True)) + data.extend(int(round(self.high[0])).to_bytes(2, "big", signed=True)) + data.extend(int(round(self.high[1])).to_bytes(2, "big", signed=True)) + data.extend(int(round(self.height)).to_bytes(2, "big", signed=True)) + return data + + def to_c(self): + data = ( + "COL_WATER_BOX(" + + ("0x00" if self.waterBoxType == "Water" else "0x32") + + ", " + + str(int(round(self.low[0]))) + + ", " + + str(int(round(self.low[1]))) + + ", " + + str(int(round(self.high[0]))) + + ", " + + str(int(round(self.high[1]))) + + ", " + + str(int(round(self.height))) + + "),\n" + ) + return data - def to_c(self): - data = 'COL_WATER_BOX(' + \ - ('0x00' if self.waterBoxType == 'Water' else '0x32') + ', ' + \ - str(int(round(self.low[0]))) + ', ' + \ - str(int(round(self.low[1]))) + ', ' + \ - str(int(round(self.high[0]))) + ', ' + \ - str(int(round(self.high[1]))) + ', ' + \ - str(int(round(self.height))) + '),\n' - return data class CameraVolume: - def __init__(self, area, functionName, position, rotation, scale, emptyScale): - # The scale ordering is due to the fact that scaling happens AFTER rotation. - # Thus the translation uses Y-up, while the scale uses Z-up. - self.area = area - self.functionName = functionName - self.position = position - self.scale = mathutils.Vector((scale[0], scale[2], scale[1])) * emptyScale - self.rotation = rotation + def __init__(self, area, functionName, position, rotation, scale, emptyScale): + # The scale ordering is due to the fact that scaling happens AFTER rotation. + # Thus the translation uses Y-up, while the scale uses Z-up. + self.area = area + self.functionName = functionName + self.position = position + self.scale = mathutils.Vector((scale[0], scale[2], scale[1])) * emptyScale + self.rotation = rotation - def to_binary(self): - raise PluginError("Binary exporting not implemented for camera volumens.") + def to_binary(self): + raise PluginError("Binary exporting not implemented for camera volumens.") + + def to_c(self): + data = ( + "{" + + str(self.area) + + ", " + + str(self.functionName) + + ", " + + str(int(round(self.position[0]))) + + ", " + + str(int(round(self.position[1]))) + + ", " + + str(int(round(self.position[2]))) + + ", " + + str(int(round(self.scale[0]))) + + ", " + + str(int(round(self.scale[1]))) + + ", " + + str(int(round(self.scale[2]))) + + ", " + + str(convertRadiansToS16(self.rotation[1])) + + "}," + ) + return data - def to_c(self): - data = '{' + \ - str(self.area) + ', ' + str(self.functionName) + ', ' + \ - str(int(round(self.position[0]))) + ', ' + \ - str(int(round(self.position[1]))) + ', ' + \ - str(int(round(self.position[2]))) + ', ' + \ - str(int(round(self.scale[0]))) + ', ' + \ - str(int(round(self.scale[1]))) + ', ' + \ - str(int(round(self.scale[2]))) + ', ' + \ - str(convertRadiansToS16(self.rotation[1])) + '},' - return data class PuppycamVolume: + def __init__(self, area, level, permaswap, functionName, position, scale, emptyScale, camPos, camFocus, mode): + self.level = level + self.area = area + self.functionName = functionName + self.permaswap = permaswap + self.mode = mode - def __init__(self, area, level, permaswap, functionName, position, scale, emptyScale, camPos, camFocus, mode): - self.level = level - self.area = area - self.functionName = functionName - self.permaswap = permaswap - self.mode = mode + # camPos and camFocus are in blender scale, z-up + # xyz, beginning and end + self.begin = (position[0] - scale[0], position[1] - scale[2], position[2] - scale[1]) + self.end = (position[0] + scale[0], position[1] + scale[2], position[2] + scale[1]) + camScaleValue = bpy.context.scene.blenderToSM64Scale - #camPos and camFocus are in blender scale, z-up - # xyz, beginning and end - self.begin = (position[0] - scale[0], position[1] - scale[2], position[2] - scale[1]) - self.end = (position[0] + scale[0], position[1] + scale[2], position[2] + scale[1]) - camScaleValue = bpy.context.scene.blenderToSM64Scale + # xyz for pos and focus obtained from chosen empties or from selected camera (32767 is ignore flag) + if camPos != (32767, 32767, 32767): + self.camPos = (camPos[0] * camScaleValue, camPos[2] * camScaleValue, camPos[1] * camScaleValue * -1) + else: + self.camPos = camPos - # xyz for pos and focus obtained from chosen empties or from selected camera (32767 is ignore flag) - if camPos != (32767, 32767, 32767): - self.camPos = (camPos[0] * camScaleValue, camPos[2] * camScaleValue, camPos[1] * camScaleValue * -1) - else: - self.camPos = camPos + if camFocus != (32767, 32767, 32767): + self.camFocus = (camFocus[0] * camScaleValue, camFocus[2] * camScaleValue, camFocus[1] * camScaleValue * -1) + else: + self.camFocus = camFocus - if camFocus != (32767, 32767, 32767): - self.camFocus = (camFocus[0] * camScaleValue, camFocus[2] * camScaleValue, camFocus[1] * camScaleValue * -1) - else: - self.camFocus = camFocus + def to_binary(self): + raise PluginError("Binary exporting not implemented for puppycam volumes.") - def to_binary(self): - raise PluginError("Binary exporting not implemented for puppycam volumes.") + def to_c(self): + data = ( + "{" + + str(self.level) + + ", " + + str(self.area) + + ", " + + ("1" if self.permaswap else "0") + + ", " + + str(self.mode) + + (", &" if str(self.functionName) != "0" else ", ") + + str(self.functionName) + + ", " + + str(int(round(self.begin[0]))) + + ", " + + str(int(round(self.begin[1]))) + + ", " + + str(int(round(self.begin[2]))) + + ", " + + str(int(round(self.end[0]))) + + ", " + + str(int(round(self.end[1]))) + + ", " + + str(int(round(self.end[2]))) + + ", " + + str(int(round(self.camPos[0]))) + + ", " + + str(int(round(self.camPos[1]))) + + ", " + + str(int(round(self.camPos[2]))) + + ", " + + str(int(round(self.camFocus[0]))) + + ", " + + str(int(round(self.camFocus[1]))) + + ", " + + str(int(round(self.camFocus[2]))) + + "}," + ) + return data - def to_c(self): - data = '{' + \ - str(self.level) + ', ' + str(self.area) + ', ' + ('1' if self.permaswap else '0') + ', ' + \ - str(self.mode) + (', &' if str(self.functionName) != '0' else ', ') + str(self.functionName) + ', ' + \ - str(int(round(self.begin[0]))) + ', ' + \ - str(int(round(self.begin[1]))) + ', ' + \ - str(int(round(self.begin[2]))) + ', ' + \ - str(int(round(self.end[0]))) + ', ' + \ - str(int(round(self.end[1]))) + ', ' + \ - str(int(round(self.end[2]))) + ', ' + \ - str(int(round(self.camPos[0]))) + ', ' + \ - str(int(round(self.camPos[1]))) + ', ' + \ - str(int(round(self.camPos[2]))) + ', ' + \ - str(int(round(self.camFocus[0]))) + ', ' + \ - str(int(round(self.camFocus[1]))) + ', ' + \ - str(int(round(self.camFocus[2]))) + '},' - return data def exportAreaCommon(areaObj, transformMatrix, geolayout, collision, name): - bpy.ops.object.select_all(action = 'DESELECT') - areaObj.select_set(True) + bpy.ops.object.select_all(action="DESELECT") + areaObj.select_set(True) - if not areaObj.noMusic: - if areaObj.musicSeqEnum != 'Custom': - musicSeq = areaObj.musicSeqEnum - else: - musicSeq = areaObj.music_seq - else: - musicSeq = None + if not areaObj.noMusic: + if areaObj.musicSeqEnum != "Custom": + musicSeq = areaObj.musicSeqEnum + else: + musicSeq = areaObj.music_seq + else: + musicSeq = None - if areaObj.terrainEnum != 'Custom': - terrainType = areaObj.terrainEnum - else: - terrainType = areaObj.terrain_type + if areaObj.terrainEnum != "Custom": + terrainType = areaObj.terrainEnum + else: + terrainType = areaObj.terrain_type - area = SM64_Area(areaObj.areaIndex, musicSeq, areaObj.music_preset, - terrainType, geolayout, collision, - [areaObj.warpNodes[i].to_c() for i in range(len(areaObj.warpNodes))], - name, areaObj.startDialog if areaObj.showStartDialog else None) + area = SM64_Area( + areaObj.areaIndex, + musicSeq, + areaObj.music_preset, + terrainType, + geolayout, + collision, + [areaObj.warpNodes[i].to_c() for i in range(len(areaObj.warpNodes))], + name, + areaObj.startDialog if areaObj.showStartDialog else None, + ) - start_process_sm64_objects(areaObj, area, transformMatrix, False) + start_process_sm64_objects(areaObj, area, transformMatrix, False) + + return area - return area # These are all done in reference to refresh 8 def handleRefreshDiffModelIDs(modelID): - if bpy.context.scene.refreshVer == 'Refresh 8' or \ - bpy.context.scene.refreshVer == 'Refresh 7': - pass - elif bpy.context.scene.refreshVer == 'Refresh 6': - if modelID == 'MODEL_TWEESTER': - modelID = 'MODEL_TORNADO' - elif bpy.context.scene.refreshVer == 'Refresh 5' or \ - bpy.context.scene.refreshVer == 'Refresh 4' or \ - bpy.context.scene.refreshVer == 'Refresh 3': - if modelID == 'MODEL_TWEESTER': - modelID = 'MODEL_TORNADO' - elif modelID == 'MODEL_WAVE_TRAIL': - modelID = "MODEL_WATER_WAVES" - elif modelID == 'MODEL_IDLE_WATER_WAVE': - modelID = 'MODEL_WATER_WAVES_SURF' - elif modelID == 'MODEL_SMALL_WATER_SPLASH': - modelID = 'MODEL_SPOT_ON_GROUND' + if bpy.context.scene.refreshVer == "Refresh 8" or bpy.context.scene.refreshVer == "Refresh 7": + pass + elif bpy.context.scene.refreshVer == "Refresh 6": + if modelID == "MODEL_TWEESTER": + modelID = "MODEL_TORNADO" + elif ( + bpy.context.scene.refreshVer == "Refresh 5" + or bpy.context.scene.refreshVer == "Refresh 4" + or bpy.context.scene.refreshVer == "Refresh 3" + ): + if modelID == "MODEL_TWEESTER": + modelID = "MODEL_TORNADO" + elif modelID == "MODEL_WAVE_TRAIL": + modelID = "MODEL_WATER_WAVES" + elif modelID == "MODEL_IDLE_WATER_WAVE": + modelID = "MODEL_WATER_WAVES_SURF" + elif modelID == "MODEL_SMALL_WATER_SPLASH": + modelID = "MODEL_SPOT_ON_GROUND" + + return modelID - return modelID def handleRefreshDiffSpecials(preset): - if bpy.context.scene.refreshVer == 'Refresh 8' or \ - bpy.context.scene.refreshVer == 'Refresh 7' or \ - bpy.context.scene.refreshVer == 'Refresh 6' or \ - bpy.context.scene.refreshVer == 'Refresh 5' or \ - bpy.context.scene.refreshVer == 'Refresh 4' or \ - bpy.context.scene.refreshVer == 'Refresh 3': - pass - return preset + if ( + bpy.context.scene.refreshVer == "Refresh 8" + or bpy.context.scene.refreshVer == "Refresh 7" + or bpy.context.scene.refreshVer == "Refresh 6" + or bpy.context.scene.refreshVer == "Refresh 5" + or bpy.context.scene.refreshVer == "Refresh 4" + or bpy.context.scene.refreshVer == "Refresh 3" + ): + pass + return preset + def handleRefreshDiffMacros(preset): - if bpy.context.scene.refreshVer == 'Refresh 8' or \ - bpy.context.scene.refreshVer == 'Refresh 7' or \ - bpy.context.scene.refreshVer == 'Refresh 6' or \ - bpy.context.scene.refreshVer == 'Refresh 5' or \ - bpy.context.scene.refreshVer == 'Refresh 4' or \ - bpy.context.scene.refreshVer == 'Refresh 3': - pass - return preset + if ( + bpy.context.scene.refreshVer == "Refresh 8" + or bpy.context.scene.refreshVer == "Refresh 7" + or bpy.context.scene.refreshVer == "Refresh 6" + or bpy.context.scene.refreshVer == "Refresh 5" + or bpy.context.scene.refreshVer == "Refresh 4" + or bpy.context.scene.refreshVer == "Refresh 3" + ): + pass + return preset + def start_process_sm64_objects(obj, area, transformMatrix, specialsOnly): - #spaceRotation = mathutils.Quaternion((1, 0, 0), math.radians(90.0)).to_matrix().to_4x4() + # spaceRotation = mathutils.Quaternion((1, 0, 0), math.radians(90.0)).to_matrix().to_4x4() + + # We want translations to be relative to area obj, but rotation/scale to be world space + translation, rotation, scale = obj.matrix_world.decompose() + process_sm64_objects(obj, area, mathutils.Matrix.Translation(translation), transformMatrix, specialsOnly) - # We want translations to be relative to area obj, but rotation/scale to be world space - translation, rotation, scale = obj.matrix_world.decompose() - process_sm64_objects(obj, area, - mathutils.Matrix.Translation(translation), transformMatrix, specialsOnly) def process_sm64_objects(obj, area, rootMatrix, transformMatrix, specialsOnly): - translation, originalRotation, scale = \ - (transformMatrix @ rootMatrix.inverted() @ obj.matrix_world).decompose() + translation, originalRotation, scale = (transformMatrix @ rootMatrix.inverted() @ obj.matrix_world).decompose() - finalTransform = mathutils.Matrix.Translation(translation) @ \ - originalRotation.to_matrix().to_4x4() @ \ - mathutils.Matrix.Diagonal(scale).to_4x4() + finalTransform = ( + mathutils.Matrix.Translation(translation) + @ originalRotation.to_matrix().to_4x4() + @ mathutils.Matrix.Diagonal(scale).to_4x4() + ) - # Hacky solution to handle Z-up to Y-up conversion - rotation = originalRotation @ mathutils.Quaternion((1, 0, 0), math.radians(90.0)) + # Hacky solution to handle Z-up to Y-up conversion + rotation = originalRotation @ mathutils.Quaternion((1, 0, 0), math.radians(90.0)) - if obj.data is None: - if obj.sm64_obj_type == 'Area Root' and obj.areaIndex != area.index: - return - if specialsOnly: - if obj.sm64_obj_type == 'Special': - preset = obj.sm64_special_enum if obj.sm64_special_enum != 'Custom' else obj.sm64_obj_preset - preset = handleRefreshDiffSpecials(preset) - area.specials.append(SM64_Special_Object(preset, translation, - rotation.to_euler() if obj.sm64_obj_set_yaw else None, - obj.fast64.sm64.game_object.get_behavior_params() if (obj.sm64_obj_set_yaw and obj.sm64_obj_set_bparam) else None)) - elif obj.sm64_obj_type == 'Water Box': - checkIdentityRotation(obj, rotation, False) - area.water_boxes.append(CollisionWaterBox(obj.waterBoxType, - translation, scale, obj.empty_display_size)) - else: - if obj.sm64_obj_type == 'Object': - modelID = obj.sm64_model_enum if obj.sm64_model_enum != 'Custom' else obj.sm64_obj_model - modelID = handleRefreshDiffModelIDs(modelID) - behaviour = func_map[bpy.context.scene.refreshVer][obj.sm64_behaviour_enum] if \ - obj.sm64_behaviour_enum != 'Custom' else obj.sm64_obj_behaviour - area.objects.append(SM64_Object(modelID, translation, rotation.to_euler(), - behaviour, obj.fast64.sm64.game_object.get_behavior_params(), get_act_string(obj))) - elif obj.sm64_obj_type == 'Macro': - macro = obj.sm64_macro_enum if obj.sm64_macro_enum != 'Custom' else obj.sm64_obj_preset - area.macros.append(SM64_Macro_Object(macro, translation, rotation.to_euler(), - obj.fast64.sm64.game_object.get_behavior_params() if obj.sm64_obj_set_bparam else None)) - elif obj.sm64_obj_type == 'Mario Start': - mario_start = SM64_Mario_Start(obj.sm64_obj_mario_start_area, translation, rotation.to_euler()) - area.objects.append(mario_start) - area.mario_start = mario_start - elif obj.sm64_obj_type == 'Trajectory': - pass - elif obj.sm64_obj_type == 'Whirpool': - area.objects.append(SM64_Whirpool(obj.whirlpool_index, - obj.whirpool_condition, obj.whirpool_strength, translation)) - elif obj.sm64_obj_type == 'Camera Volume': - checkIdentityRotation(obj, rotation, True) - if obj.cameraVolumeGlobal: - triggerIndex = -1 - else: - triggerIndex = area.index - area.cameraVolumes.append(CameraVolume(triggerIndex, obj.cameraVolumeFunction, - translation, rotation.to_euler(), scale, obj.empty_display_size)) + if obj.data is None: + if obj.sm64_obj_type == "Area Root" and obj.areaIndex != area.index: + return + if specialsOnly: + if obj.sm64_obj_type == "Special": + preset = obj.sm64_special_enum if obj.sm64_special_enum != "Custom" else obj.sm64_obj_preset + preset = handleRefreshDiffSpecials(preset) + area.specials.append( + SM64_Special_Object( + preset, + translation, + rotation.to_euler() if obj.sm64_obj_set_yaw else None, + obj.fast64.sm64.game_object.get_behavior_params() + if (obj.sm64_obj_set_yaw and obj.sm64_obj_set_bparam) + else None, + ) + ) + elif obj.sm64_obj_type == "Water Box": + checkIdentityRotation(obj, rotation, False) + area.water_boxes.append(CollisionWaterBox(obj.waterBoxType, translation, scale, obj.empty_display_size)) + else: + if obj.sm64_obj_type == "Object": + modelID = obj.sm64_model_enum if obj.sm64_model_enum != "Custom" else obj.sm64_obj_model + modelID = handleRefreshDiffModelIDs(modelID) + behaviour = ( + func_map[bpy.context.scene.refreshVer][obj.sm64_behaviour_enum] + if obj.sm64_behaviour_enum != "Custom" + else obj.sm64_obj_behaviour + ) + area.objects.append( + SM64_Object( + modelID, + translation, + rotation.to_euler(), + behaviour, + obj.fast64.sm64.game_object.get_behavior_params(), + get_act_string(obj), + ) + ) + elif obj.sm64_obj_type == "Macro": + macro = obj.sm64_macro_enum if obj.sm64_macro_enum != "Custom" else obj.sm64_obj_preset + area.macros.append( + SM64_Macro_Object( + macro, + translation, + rotation.to_euler(), + obj.fast64.sm64.game_object.get_behavior_params() if obj.sm64_obj_set_bparam else None, + ) + ) + elif obj.sm64_obj_type == "Mario Start": + mario_start = SM64_Mario_Start(obj.sm64_obj_mario_start_area, translation, rotation.to_euler()) + area.objects.append(mario_start) + area.mario_start = mario_start + elif obj.sm64_obj_type == "Trajectory": + pass + elif obj.sm64_obj_type == "Whirpool": + area.objects.append( + SM64_Whirpool(obj.whirlpool_index, obj.whirpool_condition, obj.whirpool_strength, translation) + ) + elif obj.sm64_obj_type == "Camera Volume": + checkIdentityRotation(obj, rotation, True) + if obj.cameraVolumeGlobal: + triggerIndex = -1 + else: + triggerIndex = area.index + area.cameraVolumes.append( + CameraVolume( + triggerIndex, + obj.cameraVolumeFunction, + translation, + rotation.to_euler(), + scale, + obj.empty_display_size, + ) + ) - elif obj.sm64_obj_type == 'Puppycam Volume': - checkIdentityRotation(obj, rotation, False) + elif obj.sm64_obj_type == "Puppycam Volume": + checkIdentityRotation(obj, rotation, False) - triggerIndex = area.index - puppycamProp = obj.puppycamProp - if(puppycamProp.puppycamUseFlags): - puppycamModeString = '0' - if puppycamProp.NC_FLAG_XTURN: - puppycamModeString += " | NC_FLAG_XTURN" - if puppycamProp.NC_FLAG_YTURN: - puppycamModeString += " | NC_FLAG_YTURN" - if puppycamProp.NC_FLAG_ZOOM: - puppycamModeString += " | NC_FLAG_ZOOM" - if puppycamProp.NC_FLAG_8D: - puppycamModeString += " | NC_FLAG_8D" - if puppycamProp.NC_FLAG_4D: - puppycamModeString += " | NC_FLAG_4D" - if puppycamProp.NC_FLAG_2D: - puppycamModeString += " | NC_FLAG_2D" - if puppycamProp.NC_FLAG_FOCUSX: - puppycamModeString += " | NC_FLAG_FOCUSX" - if puppycamProp.NC_FLAG_FOCUSY: - puppycamModeString += " | NC_FLAG_FOCUSY" - if puppycamProp.NC_FLAG_FOCUSZ: - puppycamModeString += " | NC_FLAG_FOCUSZ" - if puppycamProp.NC_FLAG_POSX: - puppycamModeString += " | NC_FLAG_POSX" - if puppycamProp.NC_FLAG_POSY: - puppycamModeString += " | NC_FLAG_POSY" - if puppycamProp.NC_FLAG_POSZ: - puppycamModeString += " | NC_FLAG_POSZ" - if puppycamProp.NC_FLAG_COLLISION: - puppycamModeString += " | NC_FLAG_COLLISION" - if puppycamProp.NC_FLAG_SLIDECORRECT: - puppycamModeString += " | NC_FLAG_SLIDECORRECT" - else: - puppycamModeString = (puppycamProp.puppycamMode if puppycamProp.puppycamMode != 'Custom' else puppycamProp.puppycamType) + triggerIndex = area.index + puppycamProp = obj.puppycamProp + if puppycamProp.puppycamUseFlags: + puppycamModeString = "0" + if puppycamProp.NC_FLAG_XTURN: + puppycamModeString += " | NC_FLAG_XTURN" + if puppycamProp.NC_FLAG_YTURN: + puppycamModeString += " | NC_FLAG_YTURN" + if puppycamProp.NC_FLAG_ZOOM: + puppycamModeString += " | NC_FLAG_ZOOM" + if puppycamProp.NC_FLAG_8D: + puppycamModeString += " | NC_FLAG_8D" + if puppycamProp.NC_FLAG_4D: + puppycamModeString += " | NC_FLAG_4D" + if puppycamProp.NC_FLAG_2D: + puppycamModeString += " | NC_FLAG_2D" + if puppycamProp.NC_FLAG_FOCUSX: + puppycamModeString += " | NC_FLAG_FOCUSX" + if puppycamProp.NC_FLAG_FOCUSY: + puppycamModeString += " | NC_FLAG_FOCUSY" + if puppycamProp.NC_FLAG_FOCUSZ: + puppycamModeString += " | NC_FLAG_FOCUSZ" + if puppycamProp.NC_FLAG_POSX: + puppycamModeString += " | NC_FLAG_POSX" + if puppycamProp.NC_FLAG_POSY: + puppycamModeString += " | NC_FLAG_POSY" + if puppycamProp.NC_FLAG_POSZ: + puppycamModeString += " | NC_FLAG_POSZ" + if puppycamProp.NC_FLAG_COLLISION: + puppycamModeString += " | NC_FLAG_COLLISION" + if puppycamProp.NC_FLAG_SLIDECORRECT: + puppycamModeString += " | NC_FLAG_SLIDECORRECT" + else: + puppycamModeString = ( + puppycamProp.puppycamMode + if puppycamProp.puppycamMode != "Custom" + else puppycamProp.puppycamType + ) + if (not puppycamProp.puppycamUseEmptiesForPos) and puppycamProp.puppycamCamera is not None: + puppycamCamPosCoords = puppycamProp.puppycamCamera.location + elif puppycamProp.puppycamUseEmptiesForPos and puppycamProp.puppycamCamPos != "": + puppycamPosObject = bpy.context.scene.objects[puppycamProp.puppycamCamPos] + puppycamCamPosCoords = puppycamPosObject.location + else: + puppycamCamPosCoords = (32767, 32767, 32767) - if (not puppycamProp.puppycamUseEmptiesForPos) and puppycamProp.puppycamCamera is not None: - puppycamCamPosCoords = puppycamProp.puppycamCamera.location - elif puppycamProp.puppycamUseEmptiesForPos and puppycamProp.puppycamCamPos != "": - puppycamPosObject = bpy.context.scene.objects[puppycamProp.puppycamCamPos] - puppycamCamPosCoords = puppycamPosObject.location - else: - puppycamCamPosCoords = (32767, 32767, 32767) + if (not puppycamProp.puppycamUseEmptiesForPos) and puppycamProp.puppycamCamera is not None: + puppycamCamFocusCoords = (puppycamProp.puppycamCamera.matrix_local @ mathutils.Vector((0, 0, -1)))[ + : + ] + elif puppycamProp.puppycamUseEmptiesForPos and puppycamProp.puppycamCamFocus != "": + puppycamFocObject = bpy.context.scene.objects[puppycamProp.puppycamCamFocus] + puppycamCamFocusCoords = puppycamFocObject.location + else: + puppycamCamFocusCoords = (32767, 32767, 32767) - if (not puppycamProp.puppycamUseEmptiesForPos) and puppycamProp.puppycamCamera is not None: - puppycamCamFocusCoords = (puppycamProp.puppycamCamera.matrix_local @ mathutils.Vector((0, 0, -1)))[:] - elif puppycamProp.puppycamUseEmptiesForPos and puppycamProp.puppycamCamFocus != "": - puppycamFocObject = bpy.context.scene.objects[puppycamProp.puppycamCamFocus] - puppycamCamFocusCoords = puppycamFocObject.location - else: - puppycamCamFocusCoords = (32767, 32767, 32767) + area.puppycamVolumes.append( + PuppycamVolume( + triggerIndex, + levelIDNames[bpy.data.scenes["Scene"].levelOption], + puppycamProp.puppycamVolumePermaswap, + puppycamProp.puppycamVolumeFunction, + translation, + scale, + obj.empty_display_size, + puppycamCamPosCoords, + puppycamCamFocusCoords, + puppycamModeString, + ) + ) - area.puppycamVolumes.append(PuppycamVolume(triggerIndex, levelIDNames[bpy.data.scenes["Scene"].levelOption], - puppycamProp.puppycamVolumePermaswap, puppycamProp.puppycamVolumeFunction, translation, scale, obj.empty_display_size, puppycamCamPosCoords, puppycamCamFocusCoords, puppycamModeString)) + elif not specialsOnly and assertCurveValid(obj): + area.splines.append(convertSplineObject(area.name + "_spline_" + obj.name, obj, finalTransform)) + for child in obj.children: + process_sm64_objects(child, area, rootMatrix, transformMatrix, specialsOnly) - elif not specialsOnly and assertCurveValid(obj): - area.splines.append(convertSplineObject(area.name + '_spline_' + obj.name , obj, finalTransform)) - - - for child in obj.children: - process_sm64_objects(child, area, rootMatrix, transformMatrix, specialsOnly) def get_act_string(obj): - if obj.sm64_obj_use_act1 and obj.sm64_obj_use_act2 and obj.sm64_obj_use_act3 and \ - obj.sm64_obj_use_act4 and obj.sm64_obj_use_act5 and obj.sm64_obj_use_act6: - return 0x1F - elif not obj.sm64_obj_use_act1 and not obj.sm64_obj_use_act2 and not obj.sm64_obj_use_act3 and \ - not obj.sm64_obj_use_act4 and not obj.sm64_obj_use_act5 and not obj.sm64_obj_use_act6: - return 0 - else: - data = '' - if obj.sm64_obj_use_act1: - data += (" | " if len(data) > 0 else '') + 'ACT_1' - if obj.sm64_obj_use_act2: - data += (" | " if len(data) > 0 else '') + 'ACT_2' - if obj.sm64_obj_use_act3: - data += (" | " if len(data) > 0 else '') + 'ACT_3' - if obj.sm64_obj_use_act4: - data += (" | " if len(data) > 0 else '') + 'ACT_4' - if obj.sm64_obj_use_act5: - data += (" | " if len(data) > 0 else '') + 'ACT_5' - if obj.sm64_obj_use_act6: - data += (" | " if len(data) > 0 else '') + 'ACT_6' - return data + if ( + obj.sm64_obj_use_act1 + and obj.sm64_obj_use_act2 + and obj.sm64_obj_use_act3 + and obj.sm64_obj_use_act4 + and obj.sm64_obj_use_act5 + and obj.sm64_obj_use_act6 + ): + return 0x1F + elif ( + not obj.sm64_obj_use_act1 + and not obj.sm64_obj_use_act2 + and not obj.sm64_obj_use_act3 + and not obj.sm64_obj_use_act4 + and not obj.sm64_obj_use_act5 + and not obj.sm64_obj_use_act6 + ): + return 0 + else: + data = "" + if obj.sm64_obj_use_act1: + data += (" | " if len(data) > 0 else "") + "ACT_1" + if obj.sm64_obj_use_act2: + data += (" | " if len(data) > 0 else "") + "ACT_2" + if obj.sm64_obj_use_act3: + data += (" | " if len(data) > 0 else "") + "ACT_3" + if obj.sm64_obj_use_act4: + data += (" | " if len(data) > 0 else "") + "ACT_4" + if obj.sm64_obj_use_act5: + data += (" | " if len(data) > 0 else "") + "ACT_5" + if obj.sm64_obj_use_act6: + data += (" | " if len(data) > 0 else "") + "ACT_6" + return data + class SearchModelIDEnumOperator(bpy.types.Operator): - bl_idname = "object.search_model_id_enum_operator" - bl_label = "Search Model IDs" - bl_property = "sm64_model_enum" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "object.search_model_id_enum_operator" + bl_label = "Search Model IDs" + bl_property = "sm64_model_enum" + bl_options = {"REGISTER", "UNDO"} - sm64_model_enum : bpy.props.EnumProperty(items = enumModelIDs) + sm64_model_enum: bpy.props.EnumProperty(items=enumModelIDs) - def execute(self, context): - context.object.sm64_model_enum = self.sm64_model_enum - bpy.context.region.tag_redraw() - self.report({'INFO'}, "Selected: " + self.sm64_model_enum) - return {'FINISHED'} + def execute(self, context): + context.object.sm64_model_enum = self.sm64_model_enum + bpy.context.region.tag_redraw() + self.report({"INFO"}, "Selected: " + self.sm64_model_enum) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {"RUNNING_MODAL"} - def invoke(self, context, event): - context.window_manager.invoke_search_popup(self) - return {'RUNNING_MODAL'} class SearchBehaviourEnumOperator(bpy.types.Operator): - bl_idname = "object.search_behaviour_enum_operator" - bl_label = "Search Behaviours" - bl_property = "sm64_behaviour_enum" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "object.search_behaviour_enum_operator" + bl_label = "Search Behaviours" + bl_property = "sm64_behaviour_enum" + bl_options = {"REGISTER", "UNDO"} - sm64_behaviour_enum : bpy.props.EnumProperty(items = enumBehaviourPresets) + sm64_behaviour_enum: bpy.props.EnumProperty(items=enumBehaviourPresets) - def execute(self, context): - context.object.sm64_behaviour_enum = self.sm64_behaviour_enum - bpy.context.region.tag_redraw() - name = func_map[context.scene.refreshVer][self.sm64_behaviour_enum] if \ - self.sm64_behaviour_enum != 'Custom' else 'Custom' - self.report({'INFO'}, "Selected: " + name) - return {'FINISHED'} + def execute(self, context): + context.object.sm64_behaviour_enum = self.sm64_behaviour_enum + bpy.context.region.tag_redraw() + name = ( + func_map[context.scene.refreshVer][self.sm64_behaviour_enum] + if self.sm64_behaviour_enum != "Custom" + else "Custom" + ) + self.report({"INFO"}, "Selected: " + name) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {"RUNNING_MODAL"} - def invoke(self, context, event): - context.window_manager.invoke_search_popup(self) - return {'RUNNING_MODAL'} class SearchMacroEnumOperator(bpy.types.Operator): - bl_idname = "object.search_macro_enum_operator" - bl_label = "Search Macros" - bl_property = "sm64_macro_enum" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "object.search_macro_enum_operator" + bl_label = "Search Macros" + bl_property = "sm64_macro_enum" + bl_options = {"REGISTER", "UNDO"} - sm64_macro_enum : bpy.props.EnumProperty(items = enumMacrosNames) + sm64_macro_enum: bpy.props.EnumProperty(items=enumMacrosNames) - def execute(self, context): - context.object.sm64_macro_enum = self.sm64_macro_enum - bpy.context.region.tag_redraw() - self.report({'INFO'}, "Selected: " + self.sm64_macro_enum) - return {'FINISHED'} + def execute(self, context): + context.object.sm64_macro_enum = self.sm64_macro_enum + bpy.context.region.tag_redraw() + self.report({"INFO"}, "Selected: " + self.sm64_macro_enum) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {"RUNNING_MODAL"} - def invoke(self, context, event): - context.window_manager.invoke_search_popup(self) - return {'RUNNING_MODAL'} class SearchSpecialEnumOperator(bpy.types.Operator): - bl_idname = "object.search_special_enum_operator" - bl_label = "Search Specials" - bl_property = "sm64_special_enum" - bl_options = {'REGISTER', 'UNDO'} + bl_idname = "object.search_special_enum_operator" + bl_label = "Search Specials" + bl_property = "sm64_special_enum" + bl_options = {"REGISTER", "UNDO"} - sm64_special_enum : bpy.props.EnumProperty(items = enumSpecialsNames) + sm64_special_enum: bpy.props.EnumProperty(items=enumSpecialsNames) - def execute(self, context): - context.object.sm64_special_enum = self.sm64_special_enum - bpy.context.region.tag_redraw() - self.report({'INFO'}, "Selected: " + self.sm64_special_enum) - return {'FINISHED'} + def execute(self, context): + context.object.sm64_special_enum = self.sm64_special_enum + bpy.context.region.tag_redraw() + self.report({"INFO"}, "Selected: " + self.sm64_special_enum) + return {"FINISHED"} + + def invoke(self, context, event): + context.window_manager.invoke_search_popup(self) + return {"RUNNING_MODAL"} - def invoke(self, context, event): - context.window_manager.invoke_search_popup(self) - return {'RUNNING_MODAL'} class SM64ObjectPanel(bpy.types.Panel): - bl_label = "Object Inspector" - bl_idname = "OBJECT_PT_SM64_Object_Inspector" - bl_space_type = 'PROPERTIES' - bl_region_type = 'WINDOW' - bl_context = "object" - bl_options = {'HIDE_HEADER'} + bl_label = "Object Inspector" + bl_idname = "OBJECT_PT_SM64_Object_Inspector" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "object" + bl_options = {"HIDE_HEADER"} - @classmethod - def poll(cls, context): - return context.scene.gameEditorMode == "SM64" and (context.object is not None and context.object.data is None) + @classmethod + def poll(cls, context): + return context.scene.gameEditorMode == "SM64" and (context.object is not None and context.object.data is None) - def draw_inline_obj(self, box: bpy.types.UILayout, obj: bpy.types.Object): - obj_details: InlineGeolayoutObjConfig = inlineGeoLayoutObjects.get(obj.sm64_obj_type) + def draw_inline_obj(self, box: bpy.types.UILayout, obj: bpy.types.Object): + obj_details: InlineGeolayoutObjConfig = inlineGeoLayoutObjects.get(obj.sm64_obj_type) - # display transformation warnings - warnings = set() - if obj_details.uses_scale and not obj_scale_is_unified(obj): - warnings.add("Object's scale must all be the same exact value (e.g. 2, 2, 2)") + # display transformation warnings + warnings = set() + if obj_details.uses_scale and not obj_scale_is_unified(obj): + warnings.add("Object's scale must all be the same exact value (e.g. 2, 2, 2)") - if not obj_details.uses_scale and not all_values_equal_x(obj.scale, 1): - warnings.add("Object's scale values must all be set to 1") + if not obj_details.uses_scale and not all_values_equal_x(obj.scale, 1): + warnings.add("Object's scale values must all be set to 1") - loc = obj.matrix_local.decompose()[0] - if not obj_details.uses_location and not all_values_equal_x(loc, 0): - warnings.add("Object's relative location must be set to 0") + loc = obj.matrix_local.decompose()[0] + if not obj_details.uses_location and not all_values_equal_x(loc, 0): + warnings.add("Object's relative location must be set to 0") - if not obj_details.uses_rotation and not all_values_equal_x(obj.rotation_euler, 0): - warnings.add("Object's rotations must be set to 0") + if not obj_details.uses_rotation and not all_values_equal_x(obj.rotation_euler, 0): + warnings.add("Object's rotations must be set to 0") - if len(warnings): - warning_box = box.box() - warning_box.alert = True - warning_box.label(text = "Warning: Unexpected export results from these issues:", icon = 'ERROR') - for warning in warnings: - warning_box.label(text = warning, icon = 'ERROR') - warning_box.label(text = f'Relative location: {", ".join([str(l) for l in loc])}') + if len(warnings): + warning_box = box.box() + warning_box.alert = True + warning_box.label(text="Warning: Unexpected export results from these issues:", icon="ERROR") + for warning in warnings: + warning_box.label(text=warning, icon="ERROR") + warning_box.label(text=f'Relative location: {", ".join([str(l) for l in loc])}') - if obj.sm64_obj_type == 'Geo ASM': - prop_split(box, obj.fast64.sm64.geo_asm, 'func', 'Function') - prop_split(box, obj.fast64.sm64.geo_asm, 'param', 'Parameter') - return + if obj.sm64_obj_type == "Geo ASM": + prop_split(box, obj.fast64.sm64.geo_asm, "func", "Function") + prop_split(box, obj.fast64.sm64.geo_asm, "param", "Parameter") + return - elif obj.sm64_obj_type == 'Custom Geo Command': - prop_split(box, obj, 'customGeoCommand', 'Geo Macro') - prop_split(box, obj, 'customGeoCommandArgs', 'Parameters') - return + elif obj.sm64_obj_type == "Custom Geo Command": + prop_split(box, obj, "customGeoCommand", "Geo Macro") + prop_split(box, obj, "customGeoCommandArgs", "Parameters") + return - if obj_details.can_have_dl: - prop_split(box, obj, 'draw_layer_static', 'Draw Layer') + if obj_details.can_have_dl: + prop_split(box, obj, "draw_layer_static", "Draw Layer") - if not obj_details.must_have_dl: - prop_split(box, obj, 'useDLReference', 'Use DL Reference') + if not obj_details.must_have_dl: + prop_split(box, obj, "useDLReference", "Use DL Reference") - if obj_details.must_have_dl or obj.useDLReference: - # option to specify a mesh instead of string reference - prop_split(box, obj, 'dlReference', 'Displaylist variable or hex address') + if obj_details.must_have_dl or obj.useDLReference: + # option to specify a mesh instead of string reference + prop_split(box, obj, "dlReference", "Displaylist variable or hex address") - if obj_details.must_have_geo: - prop_split(box, obj, 'geoReference', 'Geolayout variable or hex address') + if obj_details.must_have_geo: + prop_split(box, obj, "geoReference", "Geolayout variable or hex address") - if obj_details.uses_rotation or obj_details.uses_location or obj_details.uses_scale: - info_box = box.box() - info_box.label(text = "Note: uses empty object's:") - if obj_details.uses_location: - info_box.label(text = 'Location', icon = 'DOT') - if obj_details.uses_rotation: - info_box.label(text = 'Rotation', icon = 'DOT') - if obj_details.uses_scale: - info_box.label(text = 'Scale', icon = 'DOT') + if obj_details.uses_rotation or obj_details.uses_location or obj_details.uses_scale: + info_box = box.box() + info_box.label(text="Note: uses empty object's:") + if obj_details.uses_location: + info_box.label(text="Location", icon="DOT") + if obj_details.uses_rotation: + info_box.label(text="Rotation", icon="DOT") + if obj_details.uses_scale: + info_box.label(text="Scale", icon="DOT") - if len(obj.children): - if checkIsSM64PreInlineGeoLayout(obj.sm64_obj_type): - box.box().label(text = 'Children of this object will just be the following geo commands.') - else: - box.box().label(text = 'Children of this object will be wrapped in GEO_OPEN_NODE and GEO_CLOSE_NODE.') + if len(obj.children): + if checkIsSM64PreInlineGeoLayout(obj.sm64_obj_type): + box.box().label(text="Children of this object will just be the following geo commands.") + else: + box.box().label(text="Children of this object will be wrapped in GEO_OPEN_NODE and GEO_CLOSE_NODE.") - def draw_behavior_params(self, obj: bpy.types.Object, parent_box: bpy.types.UILayout): - game_object = obj.fast64.sm64.game_object # .bparams - parent_box.separator() - box = parent_box.box() - box.label(text = "Behavior Parameters") + def draw_behavior_params(self, obj: bpy.types.Object, parent_box: bpy.types.UILayout): + game_object = obj.fast64.sm64.game_object # .bparams + parent_box.separator() + box = parent_box.box() + box.label(text="Behavior Parameters") - box.prop(game_object, 'use_individual_params', text = "Use Individual Behavior Params") + box.prop(game_object, "use_individual_params", text="Use Individual Behavior Params") - if game_object.use_individual_params: - individuals = box.box() - individuals.label(text = "Individual Behavior Parameters") - row = individuals.row() - for i in range(1, 5): - column = row.column() - column.label(text = f"Param {i}") - column.prop(game_object, f'bparam{i}', text="") - individuals.separator() - individuals.label(text = f"Result: {game_object.get_combined_bparams()}") - else: - box.separator() - box.label(text = "All Behavior Parameters") - box.prop(game_object, 'bparams', text="") - parent_box.separator() + if game_object.use_individual_params: + individuals = box.box() + individuals.label(text="Individual Behavior Parameters") + row = individuals.row() + for i in range(1, 5): + column = row.column() + column.label(text=f"Param {i}") + column.prop(game_object, f"bparam{i}", text="") + individuals.separator() + individuals.label(text=f"Result: {game_object.get_combined_bparams()}") + else: + box.separator() + box.label(text="All Behavior Parameters") + box.prop(game_object, "bparams", text="") + parent_box.separator() - def draw(self, context): - prop_split(self.layout, context.scene, "gameEditorMode", "Game") - box = self.layout.box().column() - column = self.layout.box().column() # added just for puppycam trigger importing - box.box().label(text = 'SM64 Object Inspector') - obj = context.object - prop_split(box, obj, 'sm64_obj_type', 'Object Type') - if obj.sm64_obj_type == 'Object': - prop_split(box, obj, 'sm64_model_enum', 'Model') - if obj.sm64_model_enum == 'Custom': - prop_split(box, obj, 'sm64_obj_model', 'Model ID') - box.operator(SearchModelIDEnumOperator.bl_idname, icon = 'VIEWZOOM') - box.box().label(text = 'Model IDs defined in include/model_ids.h.') - prop_split(box, obj, 'sm64_behaviour_enum', 'Behaviour') - if obj.sm64_behaviour_enum == 'Custom': - prop_split(box, obj, 'sm64_obj_behaviour', 'Behaviour Name') - box.operator(SearchBehaviourEnumOperator.bl_idname, icon = 'VIEWZOOM') - behaviourLabel = box.box() - behaviourLabel.label(text = 'Behaviours defined in include/behaviour_data.h.') - behaviourLabel.label(text = 'Actual contents in data/behaviour_data.c.') - self.draw_behavior_params(obj, box) - self.draw_acts(obj, box) + def draw(self, context): + prop_split(self.layout, context.scene, "gameEditorMode", "Game") + box = self.layout.box().column() + column = self.layout.box().column() # added just for puppycam trigger importing + box.box().label(text="SM64 Object Inspector") + obj = context.object + prop_split(box, obj, "sm64_obj_type", "Object Type") + if obj.sm64_obj_type == "Object": + prop_split(box, obj, "sm64_model_enum", "Model") + if obj.sm64_model_enum == "Custom": + prop_split(box, obj, "sm64_obj_model", "Model ID") + box.operator(SearchModelIDEnumOperator.bl_idname, icon="VIEWZOOM") + box.box().label(text="Model IDs defined in include/model_ids.h.") + prop_split(box, obj, "sm64_behaviour_enum", "Behaviour") + if obj.sm64_behaviour_enum == "Custom": + prop_split(box, obj, "sm64_obj_behaviour", "Behaviour Name") + box.operator(SearchBehaviourEnumOperator.bl_idname, icon="VIEWZOOM") + behaviourLabel = box.box() + behaviourLabel.label(text="Behaviours defined in include/behaviour_data.h.") + behaviourLabel.label(text="Actual contents in data/behaviour_data.c.") + self.draw_behavior_params(obj, box) + self.draw_acts(obj, box) - elif obj.sm64_obj_type == 'Macro': - prop_split(box, obj, 'sm64_macro_enum', 'Preset') - if obj.sm64_macro_enum == 'Custom': - prop_split(box, obj, 'sm64_obj_preset', 'Preset Name') - box.operator(SearchMacroEnumOperator.bl_idname, icon = 'VIEWZOOM') - box.box().label(text = 'Macro presets defined in include/macro_preset_names.h.') - box.prop(obj, 'sm64_obj_set_bparam', text = 'Set Behaviour Parameter') - if obj.sm64_obj_set_bparam: - self.draw_behavior_params(obj, box) + elif obj.sm64_obj_type == "Macro": + prop_split(box, obj, "sm64_macro_enum", "Preset") + if obj.sm64_macro_enum == "Custom": + prop_split(box, obj, "sm64_obj_preset", "Preset Name") + box.operator(SearchMacroEnumOperator.bl_idname, icon="VIEWZOOM") + box.box().label(text="Macro presets defined in include/macro_preset_names.h.") + box.prop(obj, "sm64_obj_set_bparam", text="Set Behaviour Parameter") + if obj.sm64_obj_set_bparam: + self.draw_behavior_params(obj, box) - elif obj.sm64_obj_type == 'Special': - prop_split(box, obj, 'sm64_special_enum', 'Preset') - if obj.sm64_special_enum == 'Custom': - prop_split(box, obj, 'sm64_obj_preset', 'Preset Name') - box.operator(SearchSpecialEnumOperator.bl_idname, icon = 'VIEWZOOM') - box.box().label(text = 'Special presets defined in include/special_preset_names.h.') - box.prop(obj, 'sm64_obj_set_yaw', text = 'Set Yaw') - if obj.sm64_obj_set_yaw: - box.prop(obj, 'sm64_obj_set_bparam', text = 'Set Behaviour Parameter') - if obj.sm64_obj_set_bparam: - self.draw_behavior_params(obj, box) + elif obj.sm64_obj_type == "Special": + prop_split(box, obj, "sm64_special_enum", "Preset") + if obj.sm64_special_enum == "Custom": + prop_split(box, obj, "sm64_obj_preset", "Preset Name") + box.operator(SearchSpecialEnumOperator.bl_idname, icon="VIEWZOOM") + box.box().label(text="Special presets defined in include/special_preset_names.h.") + box.prop(obj, "sm64_obj_set_yaw", text="Set Yaw") + if obj.sm64_obj_set_yaw: + box.prop(obj, "sm64_obj_set_bparam", text="Set Behaviour Parameter") + if obj.sm64_obj_set_bparam: + self.draw_behavior_params(obj, box) - elif obj.sm64_obj_type == 'Mario Start': - prop_split(box, obj, 'sm64_obj_mario_start_area', 'Area') + elif obj.sm64_obj_type == "Mario Start": + prop_split(box, obj, "sm64_obj_mario_start_area", "Area") - elif obj.sm64_obj_type == 'Trajectory': - pass + elif obj.sm64_obj_type == "Trajectory": + pass - elif obj.sm64_obj_type == 'Whirlpool': - prop_split(box, obj, 'whirpool_index', 'Index') - prop_split(box, obj, 'whirpool_condition', 'Condition') - prop_split(box, obj, 'whirpool_strength', 'Strength') - pass + elif obj.sm64_obj_type == "Whirlpool": + prop_split(box, obj, "whirpool_index", "Index") + prop_split(box, obj, "whirpool_condition", "Condition") + prop_split(box, obj, "whirpool_strength", "Strength") + pass - elif obj.sm64_obj_type == 'Water Box': - prop_split(box, obj, 'waterBoxType', 'Water Box Type') - box.box().label(text = "Water box area defined by top face of box shaped empty.") - box.box().label(text = "No rotation allowed.") + elif obj.sm64_obj_type == "Water Box": + prop_split(box, obj, "waterBoxType", "Water Box Type") + box.box().label(text="Water box area defined by top face of box shaped empty.") + box.box().label(text="No rotation allowed.") - elif obj.sm64_obj_type == 'Level Root': - levelObj = obj.fast64.sm64.level - if obj.useBackgroundColor: - prop_split(box, obj, 'backgroundColor', 'Background Color') - box.prop(obj, 'useBackgroundColor') - else: - #prop_split(box, obj, 'backgroundID', 'Background ID') - prop_split(box, obj, 'background', 'Background') - if obj.background == 'CUSTOM': - prop_split(box, levelObj, 'backgroundID', 'Custom ID') - prop_split(box, levelObj, 'backgroundSegment', 'Custom Background Segment') - segmentExportBox = box.box() - segmentExportBox.label(text = f'Exported Segment: _{levelObj.backgroundSegment}_{context.scene.compressionFormat}SegmentRomStart') - box.prop(obj, 'useBackgroundColor') - #box.box().label(text = 'Background IDs defined in include/geo_commands.h.') - box.prop(obj, 'actSelectorIgnore') - box.prop(obj, 'setAsStartLevel') - prop_split(box, obj, 'acousticReach', 'Acoustic Reach') - obj.starGetCutscenes.draw(box) + elif obj.sm64_obj_type == "Level Root": + levelObj = obj.fast64.sm64.level + if obj.useBackgroundColor: + prop_split(box, obj, "backgroundColor", "Background Color") + box.prop(obj, "useBackgroundColor") + else: + # prop_split(box, obj, 'backgroundID', 'Background ID') + prop_split(box, obj, "background", "Background") + if obj.background == "CUSTOM": + prop_split(box, levelObj, "backgroundID", "Custom ID") + prop_split(box, levelObj, "backgroundSegment", "Custom Background Segment") + segmentExportBox = box.box() + segmentExportBox.label( + text=f"Exported Segment: _{levelObj.backgroundSegment}_{context.scene.compressionFormat}SegmentRomStart" + ) + box.prop(obj, "useBackgroundColor") + # box.box().label(text = 'Background IDs defined in include/geo_commands.h.') + box.prop(obj, "actSelectorIgnore") + box.prop(obj, "setAsStartLevel") + prop_split(box, obj, "acousticReach", "Acoustic Reach") + obj.starGetCutscenes.draw(box) - elif obj.sm64_obj_type == 'Area Root': - # Code that used to be in area inspector - prop_split(box, obj, 'areaIndex', 'Area Index') - box.prop(obj, 'noMusic', text = 'Disable Music') - if not obj.noMusic: - prop_split(box, obj, 'music_preset', 'Music Preset') - prop_split(box, obj, 'musicSeqEnum', 'Music Sequence') - if obj.musicSeqEnum == 'Custom': - prop_split(box, obj, 'music_seq', '') + elif obj.sm64_obj_type == "Area Root": + # Code that used to be in area inspector + prop_split(box, obj, "areaIndex", "Area Index") + box.prop(obj, "noMusic", text="Disable Music") + if not obj.noMusic: + prop_split(box, obj, "music_preset", "Music Preset") + prop_split(box, obj, "musicSeqEnum", "Music Sequence") + if obj.musicSeqEnum == "Custom": + prop_split(box, obj, "music_seq", "") - prop_split(box, obj, 'terrainEnum', 'Terrain') - if obj.terrainEnum == 'Custom': - prop_split(box, obj, 'terrain_type', '') - prop_split(box, obj, 'envOption', 'Environment Type') - if obj.envOption == 'Custom': - prop_split(box, obj, 'envType', "") - prop_split(box, obj, 'camOption', 'Camera Type') - if obj.camOption == 'Custom': - prop_split(box, obj, 'camType', '') - camBox = box.box() - camBox.label(text = 'Warning: Camera modes can be overriden by area specific camera code.') - camBox.label(text = 'Check the switch statment in camera_course_processing() in src/game/camera.c.') + prop_split(box, obj, "terrainEnum", "Terrain") + if obj.terrainEnum == "Custom": + prop_split(box, obj, "terrain_type", "") + prop_split(box, obj, "envOption", "Environment Type") + if obj.envOption == "Custom": + prop_split(box, obj, "envType", "") + prop_split(box, obj, "camOption", "Camera Type") + if obj.camOption == "Custom": + prop_split(box, obj, "camType", "") + camBox = box.box() + camBox.label(text="Warning: Camera modes can be overriden by area specific camera code.") + camBox.label(text="Check the switch statment in camera_course_processing() in src/game/camera.c.") - fogBox = box.box() - fogInfoBox = fogBox.box() - fogInfoBox.label(text = 'Warning: Fog only applies to materials that:') - fogInfoBox.label(text = '- use fog') - fogInfoBox.label(text = '- have global fog enabled.') - prop_split(fogBox, obj, 'area_fog_color', 'Area Fog Color') - prop_split(fogBox, obj, 'area_fog_position', 'Area Fog Position') + fogBox = box.box() + fogInfoBox = fogBox.box() + fogInfoBox.label(text="Warning: Fog only applies to materials that:") + fogInfoBox.label(text="- use fog") + fogInfoBox.label(text="- have global fog enabled.") + prop_split(fogBox, obj, "area_fog_color", "Area Fog Color") + prop_split(fogBox, obj, "area_fog_position", "Area Fog Position") - if obj.areaIndex == 1 or obj.areaIndex == 2 or obj.areaIndex == 3: - prop_split(box, obj, 'echoLevel', 'Echo Level') + if obj.areaIndex == 1 or obj.areaIndex == 2 or obj.areaIndex == 3: + prop_split(box, obj, "echoLevel", "Echo Level") - if obj.areaIndex == 1 or obj.areaIndex == 2 or obj.areaIndex == 3 or obj.areaIndex == 4: - box.prop(obj, 'zoomOutOnPause') + if obj.areaIndex == 1 or obj.areaIndex == 2 or obj.areaIndex == 3 or obj.areaIndex == 4: + box.prop(obj, "zoomOutOnPause") - box.prop(obj.fast64.sm64.area, 'disable_background') + box.prop(obj.fast64.sm64.area, "disable_background") - areaLayout = box.box() - areaLayout.enabled = not obj.fast64.sm64.area.disable_background - areaLayout.prop(obj, 'areaOverrideBG') - if obj.areaOverrideBG: - prop_split(areaLayout, obj, 'areaBGColor', 'Background Color') + areaLayout = box.box() + areaLayout.enabled = not obj.fast64.sm64.area.disable_background + areaLayout.prop(obj, "areaOverrideBG") + if obj.areaOverrideBG: + prop_split(areaLayout, obj, "areaBGColor", "Background Color") - box.prop(obj, 'showStartDialog') - if obj.showStartDialog: - prop_split(box, obj, 'startDialog', "Start Dialog") - dialogBox = box.box() - dialogBox.label(text = 'See text/us/dialogs.h for values.') - dialogBox.label(text = 'See load_level_init_text() in src/game/level_update.c for conditions.') - box.prop(obj, 'enableRoomSwitch') - if obj.enableRoomSwitch: - infoBox = box.box() - infoBox.label(text = 'Every child hierarchy of the area root will be treated as its own room (except for the first one.)') - infoBox.label(text = 'You can use empties with the "None" type as empty geolayout nodes to group related geometry under.') - infoBox.label(text = 'Children will ordered alphabetically, with the first child being always visible.') - box.prop(obj, 'useDefaultScreenRect') - if not obj.useDefaultScreenRect: - prop_split(box, obj, 'screenPos', 'Screen Position') - prop_split(box, obj, 'screenSize', 'Screen Size') + box.prop(obj, "showStartDialog") + if obj.showStartDialog: + prop_split(box, obj, "startDialog", "Start Dialog") + dialogBox = box.box() + dialogBox.label(text="See text/us/dialogs.h for values.") + dialogBox.label(text="See load_level_init_text() in src/game/level_update.c for conditions.") + box.prop(obj, "enableRoomSwitch") + if obj.enableRoomSwitch: + infoBox = box.box() + infoBox.label( + text="Every child hierarchy of the area root will be treated as its own room (except for the first one.)" + ) + infoBox.label( + text='You can use empties with the "None" type as empty geolayout nodes to group related geometry under.' + ) + infoBox.label(text="Children will ordered alphabetically, with the first child being always visible.") + box.prop(obj, "useDefaultScreenRect") + if not obj.useDefaultScreenRect: + prop_split(box, obj, "screenPos", "Screen Position") + prop_split(box, obj, "screenSize", "Screen Size") - prop_split(box, obj, 'clipPlanes', 'Clip Planes') + prop_split(box, obj, "clipPlanes", "Clip Planes") - box.label(text = "Warp Nodes") - box.operator(AddWarpNode.bl_idname).option = len(obj.warpNodes) - for i in range(len(obj.warpNodes)): - drawWarpNodeProperty(box, obj.warpNodes[i], i) + box.label(text="Warp Nodes") + box.operator(AddWarpNode.bl_idname).option = len(obj.warpNodes) + for i in range(len(obj.warpNodes)): + drawWarpNodeProperty(box, obj.warpNodes[i], i) - elif obj.sm64_obj_type == 'Camera Volume': - prop_split(box, obj, 'cameraVolumeFunction', 'Camera Function') - box.prop(obj, 'cameraVolumeGlobal') - box.box().label(text = "Only vertical axis rotation allowed.") + elif obj.sm64_obj_type == "Camera Volume": + prop_split(box, obj, "cameraVolumeFunction", "Camera Function") + box.prop(obj, "cameraVolumeGlobal") + box.box().label(text="Only vertical axis rotation allowed.") - elif obj.sm64_obj_type == 'Puppycam Volume': - puppycamProp = obj.puppycamProp - prop_split(column, puppycamProp, 'puppycamVolumeFunction', 'Puppycam Function') - column.prop(puppycamProp, 'puppycamVolumePermaswap') - column.prop(puppycamProp, 'puppycamUseFlags') + elif obj.sm64_obj_type == "Puppycam Volume": + puppycamProp = obj.puppycamProp + prop_split(column, puppycamProp, "puppycamVolumeFunction", "Puppycam Function") + column.prop(puppycamProp, "puppycamVolumePermaswap") + column.prop(puppycamProp, "puppycamUseFlags") - column.prop(puppycamProp, 'puppycamUseEmptiesForPos') + column.prop(puppycamProp, "puppycamUseEmptiesForPos") - if puppycamProp.puppycamUseEmptiesForPos: - column.label(text = "Fixed Camera Position (Optional)") - column.prop_search(puppycamProp, "puppycamCamPos", bpy.data, "objects", text = '') + if puppycamProp.puppycamUseEmptiesForPos: + column.label(text="Fixed Camera Position (Optional)") + column.prop_search(puppycamProp, "puppycamCamPos", bpy.data, "objects", text="") - column.label(text = "Fixed Camera Focus (Optional)") - column.prop_search(puppycamProp, "puppycamCamFocus", bpy.data, "objects", text = '') - else: - column.label(text = "Fixed Camera Position (Optional)") - column.prop(puppycamProp, "puppycamCamera") - if puppycamProp.puppycamCamera is not None: - column.box().label(text = "FOV not exported, only for preview camera.") - prop_split(column, puppycamProp, 'puppycamFOV', 'Camera FOV') - column.operator("mesh.puppycam_setup_camera", text = 'Setup Camera', icon = 'VIEW_CAMERA') + column.label(text="Fixed Camera Focus (Optional)") + column.prop_search(puppycamProp, "puppycamCamFocus", bpy.data, "objects", text="") + else: + column.label(text="Fixed Camera Position (Optional)") + column.prop(puppycamProp, "puppycamCamera") + if puppycamProp.puppycamCamera is not None: + column.box().label(text="FOV not exported, only for preview camera.") + prop_split(column, puppycamProp, "puppycamFOV", "Camera FOV") + column.operator("mesh.puppycam_setup_camera", text="Setup Camera", icon="VIEW_CAMERA") - if puppycamProp.puppycamUseFlags: - for i, flagSet in enumerate(enumPuppycamFlags): - column.prop(puppycamProp, flagSet[0]) - else: - prop_split(column, puppycamProp, 'puppycamMode', 'Camera Mode') - if puppycamProp.puppycamMode == 'Custom': - prop_split(column, puppycamProp, 'puppycamType', '') + if puppycamProp.puppycamUseFlags: + for i, flagSet in enumerate(enumPuppycamFlags): + column.prop(puppycamProp, flagSet[0]) + else: + prop_split(column, puppycamProp, "puppycamMode", "Camera Mode") + if puppycamProp.puppycamMode == "Custom": + prop_split(column, puppycamProp, "puppycamType", "") - column.box().label(text = "No rotation allowed.") + column.box().label(text="No rotation allowed.") - elif obj.sm64_obj_type == 'Switch': - prop_split(box, obj, 'switchFunc', 'Function') - prop_split(box, obj, 'switchParam', 'Parameter') - box.box().label(text = 'Children will ordered alphabetically.') + elif obj.sm64_obj_type == "Switch": + prop_split(box, obj, "switchFunc", "Function") + prop_split(box, obj, "switchParam", "Parameter") + box.box().label(text="Children will ordered alphabetically.") - elif obj.sm64_obj_type in inlineGeoLayoutObjects: - self.draw_inline_obj(box, obj) + elif obj.sm64_obj_type in inlineGeoLayoutObjects: + self.draw_inline_obj(box, obj) - elif obj.sm64_obj_type == 'None': - box.box().label(text = 'This can be used as an empty transform node in a geolayout hierarchy.') + elif obj.sm64_obj_type == "None": + box.box().label(text="This can be used as an empty transform node in a geolayout hierarchy.") - def draw_acts(self, obj, layout): - layout.label(text = 'Acts') - acts = layout.row() - self.draw_act(obj, acts, 1) - self.draw_act(obj, acts, 2) - self.draw_act(obj, acts, 3) - self.draw_act(obj, acts, 4) - self.draw_act(obj, acts, 5) - self.draw_act(obj, acts, 6) + def draw_acts(self, obj, layout): + layout.label(text="Acts") + acts = layout.row() + self.draw_act(obj, acts, 1) + self.draw_act(obj, acts, 2) + self.draw_act(obj, acts, 3) + self.draw_act(obj, acts, 4) + self.draw_act(obj, acts, 5) + self.draw_act(obj, acts, 6) + + def draw_act(self, obj, layout, value): + layout = layout.column() + layout.label(text=str(value)) + layout.prop(obj, "sm64_obj_use_act" + str(value), text="") - def draw_act(self, obj, layout, value): - layout = layout.column() - layout.label(text = str(value)) - layout.prop(obj, 'sm64_obj_use_act' + str(value), text = '') enumStarGetCutscene = [ - ('Custom', 'Custom', 'Custom'), - ('0', 'Lakitu Flies Away', 'Lakitu Flies Away'), - ('1', 'Rotate Around Mario', 'Rotate Around Mario'), - ('2', 'Closeup Of Mario', 'Closeup Of Mario'), - ('3', 'Bowser Keys', 'Bowser Keys'), - ('4', '100 Coin Star', '100 Coin Star'), + ("Custom", "Custom", "Custom"), + ("0", "Lakitu Flies Away", "Lakitu Flies Away"), + ("1", "Rotate Around Mario", "Rotate Around Mario"), + ("2", "Closeup Of Mario", "Closeup Of Mario"), + ("3", "Bowser Keys", "Bowser Keys"), + ("4", "100 Coin Star", "100 Coin Star"), ] + class WarpNodeProperty(bpy.types.PropertyGroup): - warpType : bpy.props.EnumProperty(name = 'Warp Type', items = enumWarpType, default = 'Warp') - warpID : bpy.props.StringProperty(name = 'Warp ID', default = '0x0A') - destLevelEnum : bpy.props.EnumProperty(name = 'Destination Level', default = 'bob', items = enumLevelNames) - destLevel : bpy.props.StringProperty(name = 'Destination Level Value', default = 'LEVEL_BOB') - destArea : bpy.props.StringProperty(name = 'Destination Area', default = '0x01') - destNode : bpy.props.StringProperty(name = 'Destination Node', default = '0x0A') - warpFlags : bpy.props.StringProperty(name = 'Warp Flags', default = 'WARP_NO_CHECKPOINT') - warpFlagEnum : bpy.props.EnumProperty(name = 'Warp Flags Value', default = 'WARP_NO_CHECKPOINT', items = enumWarpFlag) - instantOffset : bpy.props.IntVectorProperty(name = 'Offset', - size = 3, default = (0,0,0)) - instantWarpObject1 : bpy.props.PointerProperty(name = 'Object 1', type = bpy.types.Object) - instantWarpObject2 : bpy.props.PointerProperty(name = 'Object 2', type = bpy.types.Object) - useOffsetObjects : bpy.props.BoolProperty(name = 'Use Offset Objects', default = False) + warpType: bpy.props.EnumProperty(name="Warp Type", items=enumWarpType, default="Warp") + warpID: bpy.props.StringProperty(name="Warp ID", default="0x0A") + destLevelEnum: bpy.props.EnumProperty(name="Destination Level", default="bob", items=enumLevelNames) + destLevel: bpy.props.StringProperty(name="Destination Level Value", default="LEVEL_BOB") + destArea: bpy.props.StringProperty(name="Destination Area", default="0x01") + destNode: bpy.props.StringProperty(name="Destination Node", default="0x0A") + warpFlags: bpy.props.StringProperty(name="Warp Flags", default="WARP_NO_CHECKPOINT") + warpFlagEnum: bpy.props.EnumProperty(name="Warp Flags Value", default="WARP_NO_CHECKPOINT", items=enumWarpFlag) + instantOffset: bpy.props.IntVectorProperty(name="Offset", size=3, default=(0, 0, 0)) + instantWarpObject1: bpy.props.PointerProperty(name="Object 1", type=bpy.types.Object) + instantWarpObject2: bpy.props.PointerProperty(name="Object 2", type=bpy.types.Object) + useOffsetObjects: bpy.props.BoolProperty(name="Use Offset Objects", default=False) - expand : bpy.props.BoolProperty() + expand: bpy.props.BoolProperty() - def uses_area_nodes(self): - return self.instantWarpObject1.sm64_obj_type == 'Area Root' and self.instantWarpObject2.sm64_obj_type == 'Area Root' + def uses_area_nodes(self): + return ( + self.instantWarpObject1.sm64_obj_type == "Area Root" + and self.instantWarpObject2.sm64_obj_type == "Area Root" + ) - def calc_offsets_from_objects(self, reverse = False): - if self.instantWarpObject1 is None or self.instantWarpObject2 is None: - raise PluginError(f'Warp Start and Warp End in Warp Node {self.warpID} must have objects selected.') + def calc_offsets_from_objects(self, reverse=False): + if self.instantWarpObject1 is None or self.instantWarpObject2 is None: + raise PluginError(f"Warp Start and Warp End in Warp Node {self.warpID} must have objects selected.") - difference = self.instantWarpObject2.location - self.instantWarpObject1.location + difference = self.instantWarpObject2.location - self.instantWarpObject1.location - if reverse: - difference *= -1 + if reverse: + difference *= -1 - # Convert from Blender space to SM64 space - ret = Vector() - ret.x = int(round(difference.x * bpy.context.scene.blenderF3DScale)) - ret.y = int(round(difference.z * bpy.context.scene.blenderF3DScale)) - ret.z = int(round(-difference.y * bpy.context.scene.blenderF3DScale)) - return ret + # Convert from Blender space to SM64 space + ret = Vector() + ret.x = int(round(difference.x * bpy.context.scene.blenderF3DScale)) + ret.y = int(round(difference.z * bpy.context.scene.blenderF3DScale)) + ret.z = int(round(-difference.y * bpy.context.scene.blenderF3DScale)) + return ret - def to_c(self): - if self.warpType == 'Instant': - offset = Vector() + def to_c(self): + if self.warpType == "Instant": + offset = Vector() - if self.useOffsetObjects: - offset = self.calc_offsets_from_objects(self.uses_area_nodes()) - else: - offset.x = self.instantOffset[0] - offset.y = self.instantOffset[1] - offset.z = self.instantOffset[2] + if self.useOffsetObjects: + offset = self.calc_offsets_from_objects(self.uses_area_nodes()) + else: + offset.x = self.instantOffset[0] + offset.y = self.instantOffset[1] + offset.z = self.instantOffset[2] - return 'INSTANT_WARP(' + str(self.warpID) + ', ' + str(self.destArea) +\ - ', ' + str(int(offset.x)) + ', ' + str(int(offset.y)) + \ - ', ' + str(int(offset.z)) + ')' - else: - if self.warpType == 'Warp': - cmd = 'WARP_NODE' - elif self.warpType == 'Painting': - cmd = 'PAINTING_WARP_NODE' + return ( + "INSTANT_WARP(" + + str(self.warpID) + + ", " + + str(self.destArea) + + ", " + + str(int(offset.x)) + + ", " + + str(int(offset.y)) + + ", " + + str(int(offset.z)) + + ")" + ) + else: + if self.warpType == "Warp": + cmd = "WARP_NODE" + elif self.warpType == "Painting": + cmd = "PAINTING_WARP_NODE" - if self.destLevelEnum == 'custom': - destLevel = self.destLevel - else: - destLevel = levelIDNames[self.destLevelEnum] + if self.destLevelEnum == "custom": + destLevel = self.destLevel + else: + destLevel = levelIDNames[self.destLevelEnum] + + if self.warpFlagEnum == "Custom": + warpFlags = self.warpFlags + else: + warpFlags = self.warpFlagEnum + return ( + cmd + + "(" + + str(self.warpID) + + ", " + + str(destLevel) + + ", " + + str(self.destArea) + + ", " + + str(self.destNode) + + ", " + + str(warpFlags) + + ")" + ) - if self.warpFlagEnum == 'Custom': - warpFlags = self.warpFlags - else: - warpFlags = self.warpFlagEnum - return cmd + '(' + str(self.warpID) + ', ' + str(destLevel) + ', ' +\ - str(self.destArea) + ', ' + str(self.destNode) + ', ' + str(warpFlags) + ')' class AddWarpNode(bpy.types.Operator): - bl_idname = 'bone.add_warp_node' - bl_label = 'Add Warp Node' - bl_options = {'REGISTER', 'UNDO'} - option : bpy.props.IntProperty() - def execute(self, context): - obj = context.object - obj.warpNodes.add() - obj.warpNodes.move(len(obj.warpNodes)-1, self.option) - self.report({'INFO'}, 'Success!') - return {'FINISHED'} + bl_idname = "bone.add_warp_node" + bl_label = "Add Warp Node" + bl_options = {"REGISTER", "UNDO"} + option: bpy.props.IntProperty() + + def execute(self, context): + obj = context.object + obj.warpNodes.add() + obj.warpNodes.move(len(obj.warpNodes) - 1, self.option) + self.report({"INFO"}, "Success!") + return {"FINISHED"} + class RemoveWarpNode(bpy.types.Operator): - bl_idname = 'bone.remove_warp_node' - bl_label = 'Remove Warp Node' - bl_options = {'REGISTER', 'UNDO'} - option : bpy.props.IntProperty() - def execute(self, context): - context.object.warpNodes.remove(self.option) - self.report({'INFO'}, 'Success!') - return {'FINISHED'} + bl_idname = "bone.remove_warp_node" + bl_label = "Remove Warp Node" + bl_options = {"REGISTER", "UNDO"} + option: bpy.props.IntProperty() + + def execute(self, context): + context.object.warpNodes.remove(self.option) + self.report({"INFO"}, "Success!") + return {"FINISHED"} + def drawWarpNodeProperty(layout, warpNode, index): - box = layout.box().column() - #box.box().label(text = 'Switch Option ' + str(index + 1)) - box.prop(warpNode, 'expand', text = 'Warp Node ' + \ - str(warpNode.warpID), icon = 'TRIA_DOWN' if warpNode.expand else \ - 'TRIA_RIGHT') - if warpNode.expand: - prop_split(box, warpNode, 'warpType', 'Warp Type') - if warpNode.warpType == 'Instant': - prop_split(box, warpNode, 'warpID', 'Warp ID') - prop_split(box, warpNode, 'destArea', 'Destination Area') - prop_split(box, warpNode, 'useOffsetObjects', 'Use Offset Objects?') - if warpNode.useOffsetObjects: - prop_split(box, warpNode, 'instantWarpObject1', 'Warp Start') - prop_split(box, warpNode, 'instantWarpObject2', 'Warp End') - writeBox = box.box() - if warpNode.instantWarpObject1 is None or warpNode.instantWarpObject2 is None: - writeBox.label(text='Both Objects must be selected for offset') - else: - usesAreaNodes = warpNode.uses_area_nodes() - difference = warpNode.calc_offsets_from_objects(usesAreaNodes) - writeBox.label(text='Current Offset: ') - - writeBox.label(text=f'X: {difference.x}') - writeBox.label(text=f'Y: {difference.y}') - writeBox.label(text=f'Z: {difference.z}') + box = layout.box().column() + # box.box().label(text = 'Switch Option ' + str(index + 1)) + box.prop( + warpNode, + "expand", + text="Warp Node " + str(warpNode.warpID), + icon="TRIA_DOWN" if warpNode.expand else "TRIA_RIGHT", + ) + if warpNode.expand: + prop_split(box, warpNode, "warpType", "Warp Type") + if warpNode.warpType == "Instant": + prop_split(box, warpNode, "warpID", "Warp ID") + prop_split(box, warpNode, "destArea", "Destination Area") + prop_split(box, warpNode, "useOffsetObjects", "Use Offset Objects?") + if warpNode.useOffsetObjects: + prop_split(box, warpNode, "instantWarpObject1", "Warp Start") + prop_split(box, warpNode, "instantWarpObject2", "Warp End") + writeBox = box.box() + if warpNode.instantWarpObject1 is None or warpNode.instantWarpObject2 is None: + writeBox.label(text="Both Objects must be selected for offset") + else: + usesAreaNodes = warpNode.uses_area_nodes() + difference = warpNode.calc_offsets_from_objects(usesAreaNodes) + writeBox.label(text="Current Offset: ") - if usesAreaNodes: - writeBox.label(text='(When using two area nodes, the calculation is reversed)') - else: - prop_split(box, warpNode, 'instantOffset', 'Offset') - else: - prop_split(box, warpNode, 'warpID', 'Warp ID') - prop_split(box, warpNode, 'destLevelEnum', 'Destination Level') - if warpNode.destLevelEnum == 'custom': - prop_split(box, warpNode, 'destLevel', '') - prop_split(box, warpNode, 'destArea', 'Destination Area') - prop_split(box, warpNode, 'destNode', 'Destination Node') - prop_split(box, warpNode, 'warpFlagEnum', 'Warp Flags') - if warpNode.warpFlagEnum == 'Custom': - prop_split(box, warpNode, 'warpFlags', 'Warp Flags Value') + writeBox.label(text=f"X: {difference.x}") + writeBox.label(text=f"Y: {difference.y}") + writeBox.label(text=f"Z: {difference.z}") - buttons = box.row(align = True) - buttons.operator(RemoveWarpNode.bl_idname, - text = 'Remove Option').option = index - buttons.operator(AddWarpNode.bl_idname, - text = 'Add Option').option = index + 1 + if usesAreaNodes: + writeBox.label(text="(When using two area nodes, the calculation is reversed)") + else: + prop_split(box, warpNode, "instantOffset", "Offset") + else: + prop_split(box, warpNode, "warpID", "Warp ID") + prop_split(box, warpNode, "destLevelEnum", "Destination Level") + if warpNode.destLevelEnum == "custom": + prop_split(box, warpNode, "destLevel", "") + prop_split(box, warpNode, "destArea", "Destination Area") + prop_split(box, warpNode, "destNode", "Destination Node") + prop_split(box, warpNode, "warpFlagEnum", "Warp Flags") + if warpNode.warpFlagEnum == "Custom": + prop_split(box, warpNode, "warpFlags", "Warp Flags Value") + + buttons = box.row(align=True) + buttons.operator(RemoveWarpNode.bl_idname, text="Remove Option").option = index + buttons.operator(AddWarpNode.bl_idname, text="Add Option").option = index + 1 class StarGetCutscenesProperty(bpy.types.PropertyGroup): - star1_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '1') - star2_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '2') - star3_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '3') - star4_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '4') - star5_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '5') - star6_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '6') - star7_option : bpy.props.EnumProperty(items = enumStarGetCutscene, default = '4', name = '7') + star1_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="1") + star2_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="2") + star3_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="3") + star4_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="4") + star5_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="5") + star6_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="6") + star7_option: bpy.props.EnumProperty(items=enumStarGetCutscene, default="4", name="7") - star1_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') - star2_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') - star3_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') - star4_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') - star5_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') - star6_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') - star7_value : bpy.props.IntProperty(default = 0, min = 0, max = 15, name = 'Value') + star1_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") + star2_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") + star3_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") + star4_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") + star5_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") + star6_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") + star7_value: bpy.props.IntProperty(default=0, min=0, max=15, name="Value") - def value(self): - value = '0x' - value += self.star1_option if self.star1_option != 'Custom' else format(self.star1_value, 'X') - value += self.star2_option if self.star2_option != 'Custom' else format(self.star2_value, 'X') - value += self.star3_option if self.star3_option != 'Custom' else format(self.star3_value, 'X') - value += self.star4_option if self.star4_option != 'Custom' else format(self.star4_value, 'X') - value += self.star5_option if self.star5_option != 'Custom' else format(self.star5_value, 'X') - value += self.star6_option if self.star6_option != 'Custom' else format(self.star6_value, 'X') - value += self.star7_option if self.star7_option != 'Custom' else format(self.star7_value, 'X') - value += '0' - return value + def value(self): + value = "0x" + value += self.star1_option if self.star1_option != "Custom" else format(self.star1_value, "X") + value += self.star2_option if self.star2_option != "Custom" else format(self.star2_value, "X") + value += self.star3_option if self.star3_option != "Custom" else format(self.star3_value, "X") + value += self.star4_option if self.star4_option != "Custom" else format(self.star4_value, "X") + value += self.star5_option if self.star5_option != "Custom" else format(self.star5_value, "X") + value += self.star6_option if self.star6_option != "Custom" else format(self.star6_value, "X") + value += self.star7_option if self.star7_option != "Custom" else format(self.star7_value, "X") + value += "0" + return value + + def draw(self, layout): + layout.label(text="Star Get Cutscenes") + layout.prop(self, "star1_option") + if self.star1_option == "Custom": + prop_split(layout, self, "star1_value", "") + layout.prop(self, "star2_option") + if self.star2_option == "Custom": + prop_split(layout, self, "star2_value", "") + layout.prop(self, "star3_option") + if self.star3_option == "Custom": + prop_split(layout, self, "star3_value", "") + layout.prop(self, "star4_option") + if self.star4_option == "Custom": + prop_split(layout, self, "star4_value", "") + layout.prop(self, "star5_option") + if self.star5_option == "Custom": + prop_split(layout, self, "star5_value", "") + layout.prop(self, "star6_option") + if self.star6_option == "Custom": + prop_split(layout, self, "star6_value", "") + layout.prop(self, "star7_option") + if self.star7_option == "Custom": + prop_split(layout, self, "star7_value", "") - def draw(self, layout): - layout.label(text = 'Star Get Cutscenes') - layout.prop(self, 'star1_option') - if self.star1_option == 'Custom': - prop_split(layout, self, 'star1_value', '') - layout.prop(self, 'star2_option') - if self.star2_option == 'Custom': - prop_split(layout, self, 'star2_value', '') - layout.prop(self, 'star3_option') - if self.star3_option == 'Custom': - prop_split(layout, self, 'star3_value', '') - layout.prop(self, 'star4_option') - if self.star4_option == 'Custom': - prop_split(layout, self, 'star4_value', '') - layout.prop(self, 'star5_option') - if self.star5_option == 'Custom': - prop_split(layout, self, 'star5_value', '') - layout.prop(self, 'star6_option') - if self.star6_option == 'Custom': - prop_split(layout, self, 'star6_value', '') - layout.prop(self, 'star7_option') - if self.star7_option == 'Custom': - prop_split(layout, self, 'star7_value', '') def onUpdateObjectType(self, context): - isNoneEmpty = self.sm64_obj_type == "None" - isBoxEmpty = self.sm64_obj_type == 'Water Box' or self.sm64_obj_type == 'Camera Volume' - self.show_name = not (isBoxEmpty or isNoneEmpty) - self.show_axis = not (isBoxEmpty or isNoneEmpty) + isNoneEmpty = self.sm64_obj_type == "None" + isBoxEmpty = self.sm64_obj_type == "Water Box" or self.sm64_obj_type == "Camera Volume" + self.show_name = not (isBoxEmpty or isNoneEmpty) + self.show_axis = not (isBoxEmpty or isNoneEmpty) + + if isBoxEmpty: + self.empty_display_type = "CUBE" - if isBoxEmpty: - self.empty_display_type = "CUBE" class PuppycamSetupCamera(bpy.types.Operator): - """Setup Camera""" - bl_idname = "mesh.puppycam_setup_camera" - bl_label = "Set up Camera" - bl_options = {'REGISTER'} + """Setup Camera""" - def execute(self, context): - scene = context.scene - cameraObject = bpy.context.active_object.puppycamProp.puppycamCamera.data.name + bl_idname = "mesh.puppycam_setup_camera" + bl_label = "Set up Camera" + bl_options = {"REGISTER"} - scene.camera = bpy.context.active_object.puppycamProp.puppycamCamera - bpy.data.cameras[cameraObject].show_name = True - bpy.data.cameras[cameraObject].show_safe_areas = True + def execute(self, context): + scene = context.scene + cameraObject = bpy.context.active_object.puppycamProp.puppycamCamera.data.name - scene.safe_areas.title[0] = 0 - scene.safe_areas.title[1] = 8/240 # Use the safe areas to denote where default 8 pixel black bars will be - scene.safe_areas.action = (0, 0) + scene.camera = bpy.context.active_object.puppycamProp.puppycamCamera + bpy.data.cameras[cameraObject].show_name = True + bpy.data.cameras[cameraObject].show_safe_areas = True - # If you could set resolution on a per-camera basis, I'd do that instead. Oh well. - scene.render.resolution_x = 320 - scene.render.resolution_y = 240 + scene.safe_areas.title[0] = 0 + scene.safe_areas.title[1] = 8 / 240 # Use the safe areas to denote where default 8 pixel black bars will be + scene.safe_areas.action = (0, 0) - bpy.data.cameras[cameraObject].angle = math.radians(bpy.context.active_object.puppycamProp.puppycamFOV * (4/3)) + # If you could set resolution on a per-camera basis, I'd do that instead. Oh well. + scene.render.resolution_x = 320 + scene.render.resolution_y = 240 - return {'FINISHED'} + bpy.data.cameras[cameraObject].angle = math.radians( + bpy.context.active_object.puppycamProp.puppycamFOV * (4 / 3) + ) + + return {"FINISHED"} def sm64_is_camera_poll(self, object): - return object.type == 'CAMERA' + return object.type == "CAMERA" + class PuppycamProperty(bpy.types.PropertyGroup): - puppycamVolumeFunction : bpy.props.StringProperty( - name = 'Puppycam Function', default = '0') + puppycamVolumeFunction: bpy.props.StringProperty(name="Puppycam Function", default="0") - puppycamVolumePermaswap : bpy.props.BoolProperty( - name = 'Permaswap') + puppycamVolumePermaswap: bpy.props.BoolProperty(name="Permaswap") - puppycamUseEmptiesForPos : bpy.props.BoolProperty( - name = 'Use Empty Objects for positions') + puppycamUseEmptiesForPos: bpy.props.BoolProperty(name="Use Empty Objects for positions") - puppycamCamera : bpy.props.PointerProperty( - type=bpy.types.Object, - poll=sm64_is_camera_poll - ) + puppycamCamera: bpy.props.PointerProperty(type=bpy.types.Object, poll=sm64_is_camera_poll) - puppycamFOV : bpy.props.FloatProperty( - name = 'Field Of View', min = 0, max = 180, default = 45 - ) + puppycamFOV: bpy.props.FloatProperty(name="Field Of View", min=0, max=180, default=45) - puppycamMode : bpy.props.EnumProperty( - items = enumPuppycamMode, default = 'NC_MODE_NORMAL') + puppycamMode: bpy.props.EnumProperty(items=enumPuppycamMode, default="NC_MODE_NORMAL") - puppycamType : bpy.props.StringProperty( - name = 'Custom Mode', default = 'NC_MODE_NORMAL') + puppycamType: bpy.props.StringProperty(name="Custom Mode", default="NC_MODE_NORMAL") - puppycamCamPos : bpy.props.StringProperty( - name = 'Fixed Camera Position') + puppycamCamPos: bpy.props.StringProperty(name="Fixed Camera Position") - puppycamCamFocus : bpy.props.StringProperty( - name = 'Fixed Camera Focus') + puppycamCamFocus: bpy.props.StringProperty(name="Fixed Camera Focus") - puppycamUseFlags : bpy.props.BoolProperty( - name = 'Use Flags') + puppycamUseFlags: bpy.props.BoolProperty(name="Use Flags") - NC_FLAG_XTURN : bpy.props.BoolProperty( - name = 'X Turn') + NC_FLAG_XTURN: bpy.props.BoolProperty(name="X Turn") - NC_FLAG_YTURN : bpy.props.BoolProperty( - name = 'Y Turn') + NC_FLAG_YTURN: bpy.props.BoolProperty(name="Y Turn") - NC_FLAG_ZOOM : bpy.props.BoolProperty( - name = 'Y Turn') + NC_FLAG_ZOOM: bpy.props.BoolProperty(name="Y Turn") - NC_FLAG_8D : bpy.props.BoolProperty( - name = '8 Directions') + NC_FLAG_8D: bpy.props.BoolProperty(name="8 Directions") - NC_FLAG_4D : bpy.props.BoolProperty( - name = '4 Directions') + NC_FLAG_4D: bpy.props.BoolProperty(name="4 Directions") - NC_FLAG_2D : bpy.props.BoolProperty( - name = '2D') + NC_FLAG_2D: bpy.props.BoolProperty(name="2D") - NC_FLAG_FOCUSX : bpy.props.BoolProperty( - name = 'Use X Focus') + NC_FLAG_FOCUSX: bpy.props.BoolProperty(name="Use X Focus") - NC_FLAG_FOCUSY : bpy.props.BoolProperty( - name = 'Use Y Focus') + NC_FLAG_FOCUSY: bpy.props.BoolProperty(name="Use Y Focus") - NC_FLAG_FOCUSZ : bpy.props.BoolProperty( - name = 'Use Z Focus') + NC_FLAG_FOCUSZ: bpy.props.BoolProperty(name="Use Z Focus") - NC_FLAG_POSX : bpy.props.BoolProperty( - name = 'Move on X axis') + NC_FLAG_POSX: bpy.props.BoolProperty(name="Move on X axis") - NC_FLAG_POSY : bpy.props.BoolProperty( - name = 'Move on Y axis') + NC_FLAG_POSY: bpy.props.BoolProperty(name="Move on Y axis") - NC_FLAG_POSZ : bpy.props.BoolProperty( - name = 'Move on Z axis') + NC_FLAG_POSZ: bpy.props.BoolProperty(name="Move on Z axis") - NC_FLAG_COLLISION : bpy.props.BoolProperty( - name = 'Camera Collision') + NC_FLAG_COLLISION: bpy.props.BoolProperty(name="Camera Collision") + + NC_FLAG_SLIDECORRECT: bpy.props.BoolProperty(name="Slide Correction") - NC_FLAG_SLIDECORRECT : bpy.props.BoolProperty( - name = 'Slide Correction') class SM64_GeoASMProperties(bpy.types.PropertyGroup): - name = "Geo ASM Properties" - func: bpy.props.StringProperty(name = "Geo ASM Func", default="", description="Name of function for C, hex address for binary.") - param: bpy.props.StringProperty(name = "Geo ASM Param", default="0", description="Function parameter. (Binary exporting will cast to int)") + name = "Geo ASM Properties" + func: bpy.props.StringProperty( + name="Geo ASM Func", default="", description="Name of function for C, hex address for binary." + ) + param: bpy.props.StringProperty( + name="Geo ASM Param", default="0", description="Function parameter. (Binary exporting will cast to int)" + ) - @staticmethod - def upgrade_object(obj: bpy.types.Object): - geo_asm = obj.fast64.sm64.geo_asm + @staticmethod + def upgrade_object(obj: bpy.types.Object): + geo_asm = obj.fast64.sm64.geo_asm - func = obj.get("geoASMFunc") or obj.get("geo_func") or geo_asm.func - geo_asm.func = func + func = obj.get("geoASMFunc") or obj.get("geo_func") or geo_asm.func + geo_asm.func = func + + param = obj.get("geoASMParam") or obj.get("func_param") or geo_asm.param + geo_asm.param = str(param) - param = obj.get("geoASMParam") or obj.get("func_param") or geo_asm.param - geo_asm.param = str(param) class SM64_AreaProperties(bpy.types.PropertyGroup): - name = "Area Properties" - disable_background: bpy.props.BoolProperty(name = "Disable Background", default=False, description="Disable rendering background. Ideal for interiors or areas that should never see a background.") + name = "Area Properties" + disable_background: bpy.props.BoolProperty( + name="Disable Background", + default=False, + description="Disable rendering background. Ideal for interiors or areas that should never see a background.", + ) + class SM64_LevelProperties(bpy.types.PropertyGroup): - name = "SM64 Level Properties" - backgroundID: bpy.props.StringProperty( - name = 'Background Define', default = 'BACKGROUND_CUSTOM', - description = - 'The background define that is passed into GEO_BACKGROUND\n' - '(ex. BACKGROUND_OCEAN_SKY, BACKGROUND_GREEN_SKY)') + name = "SM64 Level Properties" + backgroundID: bpy.props.StringProperty( + name="Background Define", + default="BACKGROUND_CUSTOM", + description="The background define that is passed into GEO_BACKGROUND\n" + "(ex. BACKGROUND_OCEAN_SKY, BACKGROUND_GREEN_SKY)", + ) + + backgroundSegment: bpy.props.StringProperty( + name="Background Segment", + default="water_skybox", + description="Segment that will be loaded.\n" + "This will be suffixed with _yay0SegmentRomStart or _mio0SegmentRomStart\n" + "(ex. water_skybox, bidw_skybox)", + ) - backgroundSegment: bpy.props.StringProperty( - name = 'Background Segment', default = "water_skybox", - description = - 'Segment that will be loaded.\n' - 'This will be suffixed with _yay0SegmentRomStart or _mio0SegmentRomStart\n' - '(ex. water_skybox, bidw_skybox)') DEFAULT_BEHAVIOR_PARAMS = "0x00000000" + class SM64_GameObjectProperties(bpy.types.PropertyGroup): - name = "Game Object Properties" - bparams: bpy.props.StringProperty(name = "Behavior Parameters", description="All Behavior Parameters", default=DEFAULT_BEHAVIOR_PARAMS) + name = "Game Object Properties" + bparams: bpy.props.StringProperty( + name="Behavior Parameters", description="All Behavior Parameters", default=DEFAULT_BEHAVIOR_PARAMS + ) - use_individual_params: bpy.props.BoolProperty(name="Use Individual Behavior Params", description="Use Individual Behavior Params", default=True) - bparam1: bpy.props.StringProperty(name = "Behavior Param 1", description="First Behavior Param", default="") - bparam2: bpy.props.StringProperty(name = "Behavior Param 2", description="Second Behavior Param", default="") - bparam3: bpy.props.StringProperty(name = "Behavior Param 3", description="Third Behavior Param", default="") - bparam4: bpy.props.StringProperty(name = "Behavior Param 4", description="Fourth Behavior Param", default="") + use_individual_params: bpy.props.BoolProperty( + name="Use Individual Behavior Params", description="Use Individual Behavior Params", default=True + ) + bparam1: bpy.props.StringProperty(name="Behavior Param 1", description="First Behavior Param", default="") + bparam2: bpy.props.StringProperty(name="Behavior Param 2", description="Second Behavior Param", default="") + bparam3: bpy.props.StringProperty(name="Behavior Param 3", description="Third Behavior Param", default="") + bparam4: bpy.props.StringProperty(name="Behavior Param 4", description="Fourth Behavior Param", default="") - @staticmethod - def upgrade_object(obj): - game_object: SM64_GameObjectProperties = obj.fast64.sm64.game_object + @staticmethod + def upgrade_object(obj): + game_object: SM64_GameObjectProperties = obj.fast64.sm64.game_object - game_object.bparams = obj.get("sm64_obj_bparam", game_object.bparams) + game_object.bparams = obj.get("sm64_obj_bparam", game_object.bparams) - # delete legacy property - if "sm64_obj_bparam" in obj: - del obj["sm64_obj_bparam"] + # delete legacy property + if "sm64_obj_bparam" in obj: + del obj["sm64_obj_bparam"] - # get combined bparams, if they arent the default value then return because they have been set - combined_bparams = game_object.get_combined_bparams() - if combined_bparams != DEFAULT_BEHAVIOR_PARAMS: - return + # get combined bparams, if they arent the default value then return because they have been set + combined_bparams = game_object.get_combined_bparams() + if combined_bparams != DEFAULT_BEHAVIOR_PARAMS: + return - # If bparams arent the default bparams, disable `use_individual_params` - if (game_object.bparams != DEFAULT_BEHAVIOR_PARAMS): - game_object.use_individual_params = False + # If bparams arent the default bparams, disable `use_individual_params` + if game_object.bparams != DEFAULT_BEHAVIOR_PARAMS: + game_object.use_individual_params = False - def get_combined_bparams(self): - params = [self.bparam1, self.bparam2, self.bparam3, self.bparam4] - fmt_params = [] - for i, p in enumerate(params): - if len(p) == 0: - continue - shift = 8 * (3 - i) - fmt_params.append(f"({p} << {shift})" if shift > 0 else f"({p})") + def get_combined_bparams(self): + params = [self.bparam1, self.bparam2, self.bparam3, self.bparam4] + fmt_params = [] + for i, p in enumerate(params): + if len(p) == 0: + continue + shift = 8 * (3 - i) + fmt_params.append(f"({p} << {shift})" if shift > 0 else f"({p})") - if len(fmt_params) == 0: - return DEFAULT_BEHAVIOR_PARAMS - else: - return ' | '.join(fmt_params) + if len(fmt_params) == 0: + return DEFAULT_BEHAVIOR_PARAMS + else: + return " | ".join(fmt_params) + + def get_behavior_params(self): + if self.use_individual_params: + return self.get_combined_bparams() + return self.bparams - def get_behavior_params(self): - if self.use_individual_params: - return self.get_combined_bparams() - return self.bparams class SM64_ObjectProperties(bpy.types.PropertyGroup): - version: bpy.props.IntProperty(name="SM64_ObjectProperties Version", default=0) - cur_version = 3 # version after property migration + version: bpy.props.IntProperty(name="SM64_ObjectProperties Version", default=0) + cur_version = 3 # version after property migration - geo_asm: bpy.props.PointerProperty(type=SM64_GeoASMProperties) - level: bpy.props.PointerProperty(type=SM64_LevelProperties) - area: bpy.props.PointerProperty(type=SM64_AreaProperties) - game_object: bpy.props.PointerProperty(type=SM64_GameObjectProperties) + geo_asm: bpy.props.PointerProperty(type=SM64_GeoASMProperties) + level: bpy.props.PointerProperty(type=SM64_LevelProperties) + area: bpy.props.PointerProperty(type=SM64_AreaProperties) + game_object: bpy.props.PointerProperty(type=SM64_GameObjectProperties) + + @staticmethod + def upgrade_changed_props(): + for obj in bpy.data.objects: + if obj.fast64.sm64.version == 0: + SM64_GeoASMProperties.upgrade_object(obj) + if obj.fast64.sm64.version < 3: + SM64_GameObjectProperties.upgrade_object(obj) + obj.fast64.sm64.version = SM64_ObjectProperties.cur_version - @staticmethod - def upgrade_changed_props(): - for obj in bpy.data.objects: - if obj.fast64.sm64.version == 0: - SM64_GeoASMProperties.upgrade_object(obj) - if obj.fast64.sm64.version < 3: - SM64_GameObjectProperties.upgrade_object(obj) - obj.fast64.sm64.version = SM64_ObjectProperties.cur_version sm64_obj_classes = ( - WarpNodeProperty, - AddWarpNode, - RemoveWarpNode, - - SearchModelIDEnumOperator, - SearchBehaviourEnumOperator, - SearchSpecialEnumOperator, - SearchMacroEnumOperator, - - StarGetCutscenesProperty, - - PuppycamProperty, - PuppycamSetupCamera, - - SM64_GeoASMProperties, - SM64_LevelProperties, - SM64_AreaProperties, - SM64_GameObjectProperties, - SM64_ObjectProperties, + WarpNodeProperty, + AddWarpNode, + RemoveWarpNode, + SearchModelIDEnumOperator, + SearchBehaviourEnumOperator, + SearchSpecialEnumOperator, + SearchMacroEnumOperator, + StarGetCutscenesProperty, + PuppycamProperty, + PuppycamSetupCamera, + SM64_GeoASMProperties, + SM64_LevelProperties, + SM64_AreaProperties, + SM64_GameObjectProperties, + SM64_ObjectProperties, ) -sm64_obj_panel_classes = ( - SM64ObjectPanel, -) +sm64_obj_panel_classes = (SM64ObjectPanel,) + def sm64_obj_panel_register(): - for cls in sm64_obj_panel_classes: - register_class(cls) + for cls in sm64_obj_panel_classes: + register_class(cls) + def sm64_obj_panel_unregister(): - for cls in sm64_obj_panel_classes: - unregister_class(cls) + for cls in sm64_obj_panel_classes: + unregister_class(cls) + def sm64_obj_register(): - for cls in sm64_obj_classes: - register_class(cls) + for cls in sm64_obj_classes: + register_class(cls) - bpy.types.Object.puppycamProp = bpy.props.PointerProperty(type = PuppycamProperty) + bpy.types.Object.puppycamProp = bpy.props.PointerProperty(type=PuppycamProperty) - bpy.types.Object.sm64_model_enum = bpy.props.EnumProperty( - name = 'Model', items = enumModelIDs) + bpy.types.Object.sm64_model_enum = bpy.props.EnumProperty(name="Model", items=enumModelIDs) - bpy.types.Object.sm64_macro_enum = bpy.props.EnumProperty( - name = 'Macro', items = enumMacrosNames) + bpy.types.Object.sm64_macro_enum = bpy.props.EnumProperty(name="Macro", items=enumMacrosNames) - bpy.types.Object.sm64_special_enum = bpy.props.EnumProperty( - name = 'Special', items = enumSpecialsNames) + bpy.types.Object.sm64_special_enum = bpy.props.EnumProperty(name="Special", items=enumSpecialsNames) - bpy.types.Object.sm64_behaviour_enum = bpy.props.EnumProperty( - name = 'Behaviour', items = enumBehaviourPresets) + bpy.types.Object.sm64_behaviour_enum = bpy.props.EnumProperty(name="Behaviour", items=enumBehaviourPresets) - #bpy.types.Object.sm64_model = bpy.props.StringProperty( - # name = 'Model Name') - #bpy.types.Object.sm64_macro = bpy.props.StringProperty( - # name = 'Macro Name') - #bpy.types.Object.sm64_special = bpy.props.StringProperty( - # name = 'Special Name') - #bpy.types.Object.sm64_behaviour = bpy.props.StringProperty( - # name = 'Behaviour Name') + # bpy.types.Object.sm64_model = bpy.props.StringProperty( + # name = 'Model Name') + # bpy.types.Object.sm64_macro = bpy.props.StringProperty( + # name = 'Macro Name') + # bpy.types.Object.sm64_special = bpy.props.StringProperty( + # name = 'Special Name') + # bpy.types.Object.sm64_behaviour = bpy.props.StringProperty( + # name = 'Behaviour Name') - bpy.types.Object.sm64_obj_type = bpy.props.EnumProperty( - name = 'SM64 Object Type', items = enumObjectType, default = 'None', update = onUpdateObjectType) + bpy.types.Object.sm64_obj_type = bpy.props.EnumProperty( + name="SM64 Object Type", items=enumObjectType, default="None", update=onUpdateObjectType + ) - bpy.types.Object.sm64_obj_model = bpy.props.StringProperty( - name = 'Model', default = 'MODEL_NONE') + bpy.types.Object.sm64_obj_model = bpy.props.StringProperty(name="Model", default="MODEL_NONE") - bpy.types.Object.sm64_obj_preset = bpy.props.StringProperty( - name = 'Preset') + bpy.types.Object.sm64_obj_preset = bpy.props.StringProperty(name="Preset") - bpy.types.Object.sm64_obj_behaviour = bpy.props.StringProperty( - name = 'Behaviour') + bpy.types.Object.sm64_obj_behaviour = bpy.props.StringProperty(name="Behaviour") - bpy.types.Object.sm64_obj_mario_start_area = bpy.props.StringProperty( - name = 'Area', default = '0x01') + bpy.types.Object.sm64_obj_mario_start_area = bpy.props.StringProperty(name="Area", default="0x01") - bpy.types.Object.whirpool_index = bpy.props.StringProperty( - name = 'Index', default = '0') - bpy.types.Object.whirpool_condition = bpy.props.StringProperty( - name = 'Condition', default = '3') - bpy.types.Object.whirpool_strength = bpy.props.StringProperty( - name = 'Strength', default = '-30') - bpy.types.Object.waterBoxType = bpy.props.EnumProperty( - name = 'Water Box Type', items = enumWaterBoxType, default = 'Water') + bpy.types.Object.whirpool_index = bpy.props.StringProperty(name="Index", default="0") + bpy.types.Object.whirpool_condition = bpy.props.StringProperty(name="Condition", default="3") + bpy.types.Object.whirpool_strength = bpy.props.StringProperty(name="Strength", default="-30") + bpy.types.Object.waterBoxType = bpy.props.EnumProperty( + name="Water Box Type", items=enumWaterBoxType, default="Water" + ) - bpy.types.Object.sm64_obj_use_act1 = bpy.props.BoolProperty( - name = 'Act 1', default = True) - bpy.types.Object.sm64_obj_use_act2 = bpy.props.BoolProperty( - name = 'Act 2', default = True) - bpy.types.Object.sm64_obj_use_act3 = bpy.props.BoolProperty( - name = 'Act 3', default = True) - bpy.types.Object.sm64_obj_use_act4 = bpy.props.BoolProperty( - name = 'Act 4', default = True) - bpy.types.Object.sm64_obj_use_act5 = bpy.props.BoolProperty( - name = 'Act 5', default = True) - bpy.types.Object.sm64_obj_use_act6 = bpy.props.BoolProperty( - name = 'Act 6', default = True) + bpy.types.Object.sm64_obj_use_act1 = bpy.props.BoolProperty(name="Act 1", default=True) + bpy.types.Object.sm64_obj_use_act2 = bpy.props.BoolProperty(name="Act 2", default=True) + bpy.types.Object.sm64_obj_use_act3 = bpy.props.BoolProperty(name="Act 3", default=True) + bpy.types.Object.sm64_obj_use_act4 = bpy.props.BoolProperty(name="Act 4", default=True) + bpy.types.Object.sm64_obj_use_act5 = bpy.props.BoolProperty(name="Act 5", default=True) + bpy.types.Object.sm64_obj_use_act6 = bpy.props.BoolProperty(name="Act 6", default=True) - bpy.types.Object.sm64_obj_set_bparam = bpy.props.BoolProperty( - name = 'Set Behaviour Parameter', default = True) + bpy.types.Object.sm64_obj_set_bparam = bpy.props.BoolProperty(name="Set Behaviour Parameter", default=True) - bpy.types.Object.sm64_obj_set_yaw = bpy.props.BoolProperty( - name = 'Set Yaw', default = False) + bpy.types.Object.sm64_obj_set_yaw = bpy.props.BoolProperty(name="Set Yaw", default=False) - bpy.types.Object.useBackgroundColor = bpy.props.BoolProperty( - name = 'Use Solid Color For Background', default = False) + bpy.types.Object.useBackgroundColor = bpy.props.BoolProperty(name="Use Solid Color For Background", default=False) - #bpy.types.Object.backgroundID = bpy.props.StringProperty( - # name = 'Background ID', default = 'BACKGROUND_OCEAN_SKY') + # bpy.types.Object.backgroundID = bpy.props.StringProperty( + # name = 'Background ID', default = 'BACKGROUND_OCEAN_SKY') - bpy.types.Object.background = bpy.props.EnumProperty( - name = 'Background', items = enumBackground, default = 'OCEAN_SKY') + bpy.types.Object.background = bpy.props.EnumProperty(name="Background", items=enumBackground, default="OCEAN_SKY") - bpy.types.Object.backgroundColor = bpy.props.FloatVectorProperty( - name = 'Background Color', subtype='COLOR', size = 4, - min = 0, max = 1, default = (0,0,0,1)) + bpy.types.Object.backgroundColor = bpy.props.FloatVectorProperty( + name="Background Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) - bpy.types.Object.screenPos = bpy.props.IntVectorProperty( - name = 'Screen Position', size = 2, default = (160, 120), - min = -2**15, max = 2**15 - 1) + bpy.types.Object.screenPos = bpy.props.IntVectorProperty( + name="Screen Position", size=2, default=(160, 120), min=-(2**15), max=2**15 - 1 + ) - bpy.types.Object.screenSize = bpy.props.IntVectorProperty( - name = 'Screen Size', size = 2, default = (160, 120), - min = -2**15, max = 2**15 - 1) + bpy.types.Object.screenSize = bpy.props.IntVectorProperty( + name="Screen Size", size=2, default=(160, 120), min=-(2**15), max=2**15 - 1 + ) - bpy.types.Object.useDefaultScreenRect = bpy.props.BoolProperty( - name = 'Use Default Screen Rect', default = True) + bpy.types.Object.useDefaultScreenRect = bpy.props.BoolProperty(name="Use Default Screen Rect", default=True) - bpy.types.Object.clipPlanes = bpy.props.IntVectorProperty( - name = 'Clip Planes', size = 2, min = 0, default = (100, 30000) - ) + bpy.types.Object.clipPlanes = bpy.props.IntVectorProperty(name="Clip Planes", size=2, min=0, default=(100, 30000)) - bpy.types.Object.area_fog_color = bpy.props.FloatVectorProperty( - name = 'Area Fog Color', subtype='COLOR', size = 4, - min = 0, max = 1, default = (0,0,0,1)) + bpy.types.Object.area_fog_color = bpy.props.FloatVectorProperty( + name="Area Fog Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) - bpy.types.Object.area_fog_position = bpy.props.FloatVectorProperty( - name = 'Area Fog Position', size = 2, default = (970, 1000)) + bpy.types.Object.area_fog_position = bpy.props.FloatVectorProperty( + name="Area Fog Position", size=2, default=(970, 1000) + ) - bpy.types.Object.areaOverrideBG = bpy.props.BoolProperty( - name = 'Override Background') + bpy.types.Object.areaOverrideBG = bpy.props.BoolProperty(name="Override Background") - bpy.types.Object.areaBGColor = bpy.props.FloatVectorProperty( - name = 'Background Color', subtype='COLOR', size = 4, - min = 0, max = 1, default = (0,0,0,1)) + bpy.types.Object.areaBGColor = bpy.props.FloatVectorProperty( + name="Background Color", subtype="COLOR", size=4, min=0, max=1, default=(0, 0, 0, 1) + ) - bpy.types.Object.camOption = bpy.props.EnumProperty( - items = enumCameraMode, default = 'CAMERA_MODE_8_DIRECTIONS') + bpy.types.Object.camOption = bpy.props.EnumProperty(items=enumCameraMode, default="CAMERA_MODE_8_DIRECTIONS") - bpy.types.Object.camType = bpy.props.StringProperty( - name = 'Camera Type', default = 'CAMERA_MODE_8_DIRECTIONS') + bpy.types.Object.camType = bpy.props.StringProperty(name="Camera Type", default="CAMERA_MODE_8_DIRECTIONS") - bpy.types.Object.envOption = bpy.props.EnumProperty( - items = enumEnvFX, default = 'ENVFX_MODE_NONE') + bpy.types.Object.envOption = bpy.props.EnumProperty(items=enumEnvFX, default="ENVFX_MODE_NONE") - bpy.types.Object.envType = bpy.props.StringProperty( - name = 'Environment Type', default = 'ENVFX_MODE_NONE') + bpy.types.Object.envType = bpy.props.StringProperty(name="Environment Type", default="ENVFX_MODE_NONE") - bpy.types.Object.fov = bpy.props.FloatProperty( - name = 'Field Of View', min = 0, max = 180, default = 45 - ) + bpy.types.Object.fov = bpy.props.FloatProperty(name="Field Of View", min=0, max=180, default=45) - bpy.types.Object.dynamicFOV = bpy.props.BoolProperty( - name = 'Dynamic FOV', default = True) + bpy.types.Object.dynamicFOV = bpy.props.BoolProperty(name="Dynamic FOV", default=True) - bpy.types.Object.cameraVolumeFunction = bpy.props.StringProperty( - name = 'Camera Function', default = 'cam_castle_hmc_start_pool_cutscene') - bpy.types.Object.cameraVolumeGlobal = bpy.props.BoolProperty( - name = 'Is Global') + bpy.types.Object.cameraVolumeFunction = bpy.props.StringProperty( + name="Camera Function", default="cam_castle_hmc_start_pool_cutscene" + ) + bpy.types.Object.cameraVolumeGlobal = bpy.props.BoolProperty(name="Is Global") - bpy.types.Object.starGetCutscenes = bpy.props.PointerProperty( - name = "Star Get Cutscenes", type = StarGetCutscenesProperty) + bpy.types.Object.starGetCutscenes = bpy.props.PointerProperty( + name="Star Get Cutscenes", type=StarGetCutscenesProperty + ) - bpy.types.Object.acousticReach = bpy.props.StringProperty( - name = 'Acoustic Reach', default = '20000') + bpy.types.Object.acousticReach = bpy.props.StringProperty(name="Acoustic Reach", default="20000") - bpy.types.Object.echoLevel = bpy.props.StringProperty( - name = 'Echo Level', default = '0x00') + bpy.types.Object.echoLevel = bpy.props.StringProperty(name="Echo Level", default="0x00") - bpy.types.Object.zoomOutOnPause = bpy.props.BoolProperty( - name = 'Zoom Out On Pause', default = True) + bpy.types.Object.zoomOutOnPause = bpy.props.BoolProperty(name="Zoom Out On Pause", default=True) - bpy.types.Object.areaIndex = bpy.props.IntProperty(name = 'Index', - min = 0, default = 1) + bpy.types.Object.areaIndex = bpy.props.IntProperty(name="Index", min=0, default=1) - bpy.types.Object.music_preset = bpy.props.StringProperty( - name = "Music Preset", default = '0x00') - bpy.types.Object.music_seq = bpy.props.StringProperty( - name = "Music Sequence Value", default = 'SEQ_LEVEL_GRASS') - bpy.types.Object.noMusic = bpy.props.BoolProperty( - name = 'No Music', default = False) - bpy.types.Object.terrain_type = bpy.props.StringProperty( - name = "Terrain Type", default = 'TERRAIN_GRASS') - bpy.types.Object.terrainEnum = bpy.props.EnumProperty( - name = 'Terrain', items = enumTerrain, default = "TERRAIN_GRASS") - bpy.types.Object.musicSeqEnum = bpy.props.EnumProperty( - name = 'Music Sequence', items = enumMusicSeq, default = "SEQ_LEVEL_GRASS") + bpy.types.Object.music_preset = bpy.props.StringProperty(name="Music Preset", default="0x00") + bpy.types.Object.music_seq = bpy.props.StringProperty(name="Music Sequence Value", default="SEQ_LEVEL_GRASS") + bpy.types.Object.noMusic = bpy.props.BoolProperty(name="No Music", default=False) + bpy.types.Object.terrain_type = bpy.props.StringProperty(name="Terrain Type", default="TERRAIN_GRASS") + bpy.types.Object.terrainEnum = bpy.props.EnumProperty(name="Terrain", items=enumTerrain, default="TERRAIN_GRASS") + bpy.types.Object.musicSeqEnum = bpy.props.EnumProperty( + name="Music Sequence", items=enumMusicSeq, default="SEQ_LEVEL_GRASS" + ) - bpy.types.Object.areaCamera = bpy.props.PointerProperty(type = bpy.types.Camera) - bpy.types.Object.warpNodes = bpy.props.CollectionProperty( - type = WarpNodeProperty) + bpy.types.Object.areaCamera = bpy.props.PointerProperty(type=bpy.types.Camera) + bpy.types.Object.warpNodes = bpy.props.CollectionProperty(type=WarpNodeProperty) - bpy.types.Object.showStartDialog = bpy.props.BoolProperty(name = "Show Start Dialog") - bpy.types.Object.startDialog = bpy.props.StringProperty(name = 'Start Dialog', default = 'DIALOG_000') - bpy.types.Object.actSelectorIgnore = bpy.props.BoolProperty(name = 'Skip Act Selector') - bpy.types.Object.setAsStartLevel = bpy.props.BoolProperty(name = 'Set As Start Level') + bpy.types.Object.showStartDialog = bpy.props.BoolProperty(name="Show Start Dialog") + bpy.types.Object.startDialog = bpy.props.StringProperty(name="Start Dialog", default="DIALOG_000") + bpy.types.Object.actSelectorIgnore = bpy.props.BoolProperty(name="Skip Act Selector") + bpy.types.Object.setAsStartLevel = bpy.props.BoolProperty(name="Set As Start Level") - bpy.types.Object.switchFunc = bpy.props.StringProperty( - name = 'Function', default = '', - description = 'Name of function for C, hex address for binary.') + bpy.types.Object.switchFunc = bpy.props.StringProperty( + name="Function", default="", description="Name of function for C, hex address for binary." + ) - bpy.types.Object.switchParam = bpy.props.IntProperty( - name = 'Function Parameter', min = -2**(15), max = 2**(15) - 1, default = 0) + bpy.types.Object.switchParam = bpy.props.IntProperty( + name="Function Parameter", min=-(2 ** (15)), max=2 ** (15) - 1, default=0 + ) - bpy.types.Object.useDLReference = bpy.props.BoolProperty(name = 'Use displaylist reference') - bpy.types.Object.dlReference = bpy.props.StringProperty(name = 'Displaylist variable name or hex address for binary.') + bpy.types.Object.useDLReference = bpy.props.BoolProperty(name="Use displaylist reference") + bpy.types.Object.dlReference = bpy.props.StringProperty(name="Displaylist variable name or hex address for binary.") - bpy.types.Object.geoReference = bpy.props.StringProperty(name = 'Geolayout variable name or hex address for binary') + bpy.types.Object.geoReference = bpy.props.StringProperty(name="Geolayout variable name or hex address for binary") - bpy.types.Object.customGeoCommand = bpy.props.StringProperty(name = 'Geolayout macro command', default = '') - bpy.types.Object.customGeoCommandArgs = bpy.props.StringProperty(name = 'Geolayout macro arguments', default = '') + bpy.types.Object.customGeoCommand = bpy.props.StringProperty(name="Geolayout macro command", default="") + bpy.types.Object.customGeoCommandArgs = bpy.props.StringProperty(name="Geolayout macro arguments", default="") + + bpy.types.Object.enableRoomSwitch = bpy.props.BoolProperty(name="Enable Room System") - bpy.types.Object.enableRoomSwitch = bpy.props.BoolProperty(name = 'Enable Room System') def sm64_obj_unregister(): - del bpy.types.Object.sm64_model_enum - del bpy.types.Object.sm64_macro_enum - del bpy.types.Object.sm64_special_enum - del bpy.types.Object.sm64_behaviour_enum + del bpy.types.Object.sm64_model_enum + del bpy.types.Object.sm64_macro_enum + del bpy.types.Object.sm64_special_enum + del bpy.types.Object.sm64_behaviour_enum - #del bpy.types.Object.sm64_model - #del bpy.types.Object.sm64_macro - #del bpy.types.Object.sm64_special - #del bpy.types.Object.sm64_behaviour + # del bpy.types.Object.sm64_model + # del bpy.types.Object.sm64_macro + # del bpy.types.Object.sm64_special + # del bpy.types.Object.sm64_behaviour - del bpy.types.Object.sm64_obj_type - del bpy.types.Object.sm64_obj_model - del bpy.types.Object.sm64_obj_preset - del bpy.types.Object.sm64_obj_behaviour + del bpy.types.Object.sm64_obj_type + del bpy.types.Object.sm64_obj_model + del bpy.types.Object.sm64_obj_preset + del bpy.types.Object.sm64_obj_behaviour - del bpy.types.Object.whirpool_index - del bpy.types.Object.whirpool_condition - del bpy.types.Object.whirpool_strength + del bpy.types.Object.whirpool_index + del bpy.types.Object.whirpool_condition + del bpy.types.Object.whirpool_strength - del bpy.types.Object.waterBoxType + del bpy.types.Object.waterBoxType - del bpy.types.Object.sm64_obj_use_act1 - del bpy.types.Object.sm64_obj_use_act2 - del bpy.types.Object.sm64_obj_use_act3 - del bpy.types.Object.sm64_obj_use_act4 - del bpy.types.Object.sm64_obj_use_act5 - del bpy.types.Object.sm64_obj_use_act6 + del bpy.types.Object.sm64_obj_use_act1 + del bpy.types.Object.sm64_obj_use_act2 + del bpy.types.Object.sm64_obj_use_act3 + del bpy.types.Object.sm64_obj_use_act4 + del bpy.types.Object.sm64_obj_use_act5 + del bpy.types.Object.sm64_obj_use_act6 - del bpy.types.Object.sm64_obj_set_bparam - del bpy.types.Object.sm64_obj_set_yaw + del bpy.types.Object.sm64_obj_set_bparam + del bpy.types.Object.sm64_obj_set_yaw - del bpy.types.Object.useBackgroundColor - #del bpy.types.Object.backgroundID - del bpy.types.Object.background - del bpy.types.Object.backgroundColor + del bpy.types.Object.useBackgroundColor + # del bpy.types.Object.backgroundID + del bpy.types.Object.background + del bpy.types.Object.backgroundColor - del bpy.types.Object.screenPos - del bpy.types.Object.screenSize - del bpy.types.Object.useDefaultScreenRect - del bpy.types.Object.clipPlanes - del bpy.types.Object.area_fog_color - del bpy.types.Object.area_fog_position - del bpy.types.Object.areaOverrideBG - del bpy.types.Object.areaBGColor - del bpy.types.Object.camOption - del bpy.types.Object.camType - del bpy.types.Object.envOption - del bpy.types.Object.envType - del bpy.types.Object.fov - del bpy.types.Object.dynamicFOV + del bpy.types.Object.screenPos + del bpy.types.Object.screenSize + del bpy.types.Object.useDefaultScreenRect + del bpy.types.Object.clipPlanes + del bpy.types.Object.area_fog_color + del bpy.types.Object.area_fog_position + del bpy.types.Object.areaOverrideBG + del bpy.types.Object.areaBGColor + del bpy.types.Object.camOption + del bpy.types.Object.camType + del bpy.types.Object.envOption + del bpy.types.Object.envType + del bpy.types.Object.fov + del bpy.types.Object.dynamicFOV - del bpy.types.Object.cameraVolumeFunction - del bpy.types.Object.cameraVolumeGlobal + del bpy.types.Object.cameraVolumeFunction + del bpy.types.Object.cameraVolumeGlobal - del bpy.types.Object.starGetCutscenes + del bpy.types.Object.starGetCutscenes - del bpy.types.Object.acousticReach - del bpy.types.Object.echoLevel - del bpy.types.Object.zoomOutOnPause + del bpy.types.Object.acousticReach + del bpy.types.Object.echoLevel + del bpy.types.Object.zoomOutOnPause - del bpy.types.Object.areaIndex - del bpy.types.Object.music_preset - del bpy.types.Object.music_seq - del bpy.types.Object.terrain_type - del bpy.types.Object.areaCamera - del bpy.types.Object.noMusic + del bpy.types.Object.areaIndex + del bpy.types.Object.music_preset + del bpy.types.Object.music_seq + del bpy.types.Object.terrain_type + del bpy.types.Object.areaCamera + del bpy.types.Object.noMusic - del bpy.types.Object.showStartDialog - del bpy.types.Object.startDialog - del bpy.types.Object.actSelectorIgnore - del bpy.types.Object.setAsStartLevel - del bpy.types.Object.switchFunc - del bpy.types.Object.switchParam - del bpy.types.Object.enableRoomSwitch + del bpy.types.Object.showStartDialog + del bpy.types.Object.startDialog + del bpy.types.Object.actSelectorIgnore + del bpy.types.Object.setAsStartLevel + del bpy.types.Object.switchFunc + del bpy.types.Object.switchParam + del bpy.types.Object.enableRoomSwitch - for cls in reversed(sm64_obj_classes): - unregister_class(cls) + for cls in reversed(sm64_obj_classes): + unregister_class(cls) -''' + +""" object: model, bparam, behaviour, acts macro: preset, [bparam] special: preset, [yaw, [bparam]] trajectory: id -''' +""" diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index 3393d29..6161f98 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -4,1080 +4,1192 @@ from mathutils import * from .utility_anim import * from typing import Callable, Iterable + class PluginError(Exception): - pass + pass + class VertexWeightError(PluginError): - pass + pass -geoNodeRotateOrder = 'ZXY' -sm64BoneUp = Vector([1,0,0]) -transform_mtx_blender_to_n64 = lambda: Matrix(( - (1, 0, 0, 0), - (0, 0, 1, 0), - (0, -1, 0, 0), - (0, 0, 0, 1))) +geoNodeRotateOrder = "ZXY" +sm64BoneUp = Vector([1, 0, 0]) + +transform_mtx_blender_to_n64 = lambda: Matrix(((1, 0, 0, 0), (0, 0, 1, 0), (0, -1, 0, 0), (0, 0, 0, 1))) axis_enums = [ - ('X', 'X', 'X'), - ('Y', 'Y', 'Y'), - ('-X', '-X', '-X'), - ('-Y', '-Y', '-Y'), + ("X", "X", "X"), + ("Y", "Y", "Y"), + ("-X", "-X", "-X"), + ("-Y", "-Y", "-Y"), ] enumExportType = [ - ('C', 'C', 'C'), - ('Binary', 'Binary', 'Binary'), - ('Insertable Binary', 'Insertable Binary', 'Insertable Binary') + ("C", "C", "C"), + ("Binary", "Binary", "Binary"), + ("Insertable Binary", "Insertable Binary", "Insertable Binary"), ] enumExportHeaderType = [ - #('None', 'None', 'Headers are not written'), - ('Actor', 'Actor Data', 'Headers are written to a group in actors/'), - ('Level', 'Level Data', 'Headers are written to a specific level in levels/') + # ('None', 'None', 'Headers are not written'), + ("Actor", "Actor Data", "Headers are written to a group in actors/"), + ("Level", "Level Data", "Headers are written to a specific level in levels/"), ] enumCompressionFormat = [ - ('mio0', 'MIO0', 'MIO0'), - ('yay0', 'YAY0', 'YAY0'), + ("mio0", "MIO0", "MIO0"), + ("yay0", "YAY0", "YAY0"), ] def isPowerOf2(n): - return (n & (n-1) == 0) and n != 0 + return (n & (n - 1) == 0) and n != 0 + def getDeclaration(data, name): - matchResult = re.search("extern\s*[A-Za-z0-9\_]*\s*" + re.escape(name) + \ - "\s*(\[[^;\]]*\])?;\s*", data, re.DOTALL) - return matchResult + matchResult = re.search("extern\s*[A-Za-z0-9\_]*\s*" + re.escape(name) + "\s*(\[[^;\]]*\])?;\s*", data, re.DOTALL) + return matchResult + def hexOrDecInt(value): - if isinstance(value, int): - return value - elif "<<" in value: - i = value.index("<<") - return hexOrDecInt(value[:i]) << hexOrDecInt(value[i + 2:]) - elif ">>" in value: - i = value.index(">>") - return hexOrDecInt(value[:i]) >> hexOrDecInt(value[i + 2:]) - elif 'x' in value: - return int(value, 16) - else: - return int(value) + if isinstance(value, int): + return value + elif "<<" in value: + i = value.index("<<") + return hexOrDecInt(value[:i]) << hexOrDecInt(value[i + 2 :]) + elif ">>" in value: + i = value.index(">>") + return hexOrDecInt(value[:i]) >> hexOrDecInt(value[i + 2 :]) + elif "x" in value: + return int(value, 16) + else: + return int(value) + def getOrMakeVertexGroup(obj, groupName): - for group in obj.vertex_groups: - if group.name == groupName: - return group - return obj.vertex_groups.new(name = groupName) + for group in obj.vertex_groups: + if group.name == groupName: + return group + return obj.vertex_groups.new(name=groupName) + def unhideAllAndGetHiddenList(scene): - hiddenObjs = [] - for obj in scene.objects: - if obj.hide_get(): - hiddenObjs.append(obj) + hiddenObjs = [] + for obj in scene.objects: + if obj.hide_get(): + hiddenObjs.append(obj) + + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + bpy.ops.object.hide_view_clear() + return hiddenObjs - if bpy.context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = "OBJECT") - bpy.ops.object.hide_view_clear() - return hiddenObjs def hideObjsInList(hiddenObjs): - for obj in hiddenObjs: - obj.hide_set(True) + for obj in hiddenObjs: + obj.hide_set(True) def readFile(filepath): - datafile = open(filepath, 'r', newline = '\n', encoding = 'utf-8') - data = datafile.read() - datafile.close() - return data + datafile = open(filepath, "r", newline="\n", encoding="utf-8") + data = datafile.read() + datafile.close() + return data + def writeFile(filepath, data): - datafile = open(filepath, 'w', newline = '\n', encoding = 'utf-8') - datafile.write(data) - datafile.close() + datafile = open(filepath, "w", newline="\n", encoding="utf-8") + datafile.write(data) + datafile.close() + def checkObjectReference(obj, title): - if obj.name not in bpy.context.view_layer.objects: - raise PluginError(title + " not in current view layer.\n The object is either in a different view layer or is deleted.") + if obj.name not in bpy.context.view_layer.objects: + raise PluginError( + title + " not in current view layer.\n The object is either in a different view layer or is deleted." + ) + def parentObject(parent, child): - bpy.ops.object.select_all(action = "DESELECT") + bpy.ops.object.select_all(action="DESELECT") + + child.select_set(True) + parent.select_set(True) + bpy.context.view_layer.objects.active = parent + bpy.ops.object.parent_set(type="OBJECT", keep_transform=True) - child.select_set(True) - parent.select_set(True) - bpy.context.view_layer.objects.active = parent - bpy.ops.object.parent_set(type='OBJECT', keep_transform=True) def attemptModifierApply(modifier): - try: - bpy.ops.object.modifier_apply(modifier=modifier.name) - except Exception as e: - print("Skipping modifier " + str(modifier.name)) + try: + bpy.ops.object.modifier_apply(modifier=modifier.name) + except Exception as e: + print("Skipping modifier " + str(modifier.name)) + def getFMeshName(vertexGroup, namePrefix, drawLayer, isSkinned): - fMeshName = toAlnum(namePrefix + ('_' if namePrefix != '' else '') + vertexGroup) - if isSkinned: - fMeshName += '_skinned' - fMeshName += '_mesh' - if drawLayer is not None: - fMeshName += '_layer_' + str(drawLayer) - return fMeshName + fMeshName = toAlnum(namePrefix + ("_" if namePrefix != "" else "") + vertexGroup) + if isSkinned: + fMeshName += "_skinned" + fMeshName += "_mesh" + if drawLayer is not None: + fMeshName += "_layer_" + str(drawLayer) + return fMeshName + def checkUniqueBoneNames(fModel, name, vertexGroup): - if name in fModel.meshes: - raise PluginError(vertexGroup + " has already been processed. Make " +\ - "sure this bone name is unique, even across all switch option " +\ - "armatures, and that any integer keys are not strings.") + if name in fModel.meshes: + raise PluginError( + vertexGroup + + " has already been processed. Make " + + "sure this bone name is unique, even across all switch option " + + "armatures, and that any integer keys are not strings." + ) + def getGroupIndexFromname(obj, name): - for group in obj.vertex_groups: - if group.name == name: - return group.index - return None + for group in obj.vertex_groups: + if group.name == name: + return group.index + return None + def getGroupNameFromIndex(obj, index): - for group in obj.vertex_groups: - if group.index == index: - return group.name - return None + for group in obj.vertex_groups: + if group.index == index: + return group.name + return None def copyPropertyCollection(oldProp, newProp): - newProp.clear() - for item in oldProp: - newItem = newProp.add() - if isinstance(item, bpy.types.PropertyGroup): - copyPropertyGroup(item, newItem) - elif type(item).__name__ == "bpy_prop_collection_idprop": - copyPropertyCollection(item, newItem) - else: - newItem = item + newProp.clear() + for item in oldProp: + newItem = newProp.add() + if isinstance(item, bpy.types.PropertyGroup): + copyPropertyGroup(item, newItem) + elif type(item).__name__ == "bpy_prop_collection_idprop": + copyPropertyCollection(item, newItem) + else: + newItem = item + def copyPropertyGroup(oldProp, newProp): - for sub_value_attr in oldProp.bl_rna.properties.keys(): - if sub_value_attr == "rna_type": - continue - sub_value = getattr(oldProp, sub_value_attr) - if isinstance(sub_value, bpy.types.PropertyGroup): - copyPropertyGroup(sub_value, getattr(newProp, sub_value_attr)) - elif type(sub_value).__name__ == "bpy_prop_collection_idprop": - newCollection = getattr(newProp, sub_value_attr) - copyPropertyCollection(sub_value, newCollection) - else: - setattr(newProp, sub_value_attr, sub_value) + for sub_value_attr in oldProp.bl_rna.properties.keys(): + if sub_value_attr == "rna_type": + continue + sub_value = getattr(oldProp, sub_value_attr) + if isinstance(sub_value, bpy.types.PropertyGroup): + copyPropertyGroup(sub_value, getattr(newProp, sub_value_attr)) + elif type(sub_value).__name__ == "bpy_prop_collection_idprop": + newCollection = getattr(newProp, sub_value_attr) + copyPropertyCollection(sub_value, newCollection) + else: + setattr(newProp, sub_value_attr, sub_value) + def propertyCollectionEquals(oldProp, newProp): - if len(oldProp) != len(newProp): - print("Unequal size: " + str(oldProp) + " " + str(len(oldProp)) + ", " + str(newProp) + str(len(newProp))) - return False + if len(oldProp) != len(newProp): + print("Unequal size: " + str(oldProp) + " " + str(len(oldProp)) + ", " + str(newProp) + str(len(newProp))) + return False - equivalent = True - for i in range(len(oldProp)): - item = oldProp[i] - newItem = newProp[i] - if isinstance(item, bpy.types.PropertyGroup): - equivalent &= propertyGroupEquals(item, newItem) - elif type(item).__name__ == "bpy_prop_collection_idprop": - equivalent &= propertyCollectionEquals(item, newItem) - else: - try: - iterator = iter(item) - except TypeError: - isEquivalent = newItem == item - else: - isEquivalent = tuple([i for i in newItem]) == tuple([ i for i in item]) - if not isEquivalent: - pass #print("Not equivalent: " + str(item) + " " + str(newItem)) - equivalent &= isEquivalent + equivalent = True + for i in range(len(oldProp)): + item = oldProp[i] + newItem = newProp[i] + if isinstance(item, bpy.types.PropertyGroup): + equivalent &= propertyGroupEquals(item, newItem) + elif type(item).__name__ == "bpy_prop_collection_idprop": + equivalent &= propertyCollectionEquals(item, newItem) + else: + try: + iterator = iter(item) + except TypeError: + isEquivalent = newItem == item + else: + isEquivalent = tuple([i for i in newItem]) == tuple([i for i in item]) + if not isEquivalent: + pass # print("Not equivalent: " + str(item) + " " + str(newItem)) + equivalent &= isEquivalent + + return equivalent - return equivalent def propertyGroupEquals(oldProp, newProp): - equivalent = True - for sub_value_attr in oldProp.bl_rna.properties.keys(): - if sub_value_attr == "rna_type": - continue - sub_value = getattr(oldProp, sub_value_attr) - if isinstance(sub_value, bpy.types.PropertyGroup): - equivalent &= propertyGroupEquals(sub_value, getattr(newProp, sub_value_attr)) - elif type(sub_value).__name__ == "bpy_prop_collection_idprop": - newCollection = getattr(newProp, sub_value_attr) - copyPropertyCollection(sub_value, newCollection) - else: - newValue = getattr(newProp, sub_value_attr) - try: - iterator = iter(newValue) - except TypeError: - isEquivalent = newValue == sub_value - else: - isEquivalent = tuple([i for i in newValue]) == tuple([i for i in sub_value]) + equivalent = True + for sub_value_attr in oldProp.bl_rna.properties.keys(): + if sub_value_attr == "rna_type": + continue + sub_value = getattr(oldProp, sub_value_attr) + if isinstance(sub_value, bpy.types.PropertyGroup): + equivalent &= propertyGroupEquals(sub_value, getattr(newProp, sub_value_attr)) + elif type(sub_value).__name__ == "bpy_prop_collection_idprop": + newCollection = getattr(newProp, sub_value_attr) + copyPropertyCollection(sub_value, newCollection) + else: + newValue = getattr(newProp, sub_value_attr) + try: + iterator = iter(newValue) + except TypeError: + isEquivalent = newValue == sub_value + else: + isEquivalent = tuple([i for i in newValue]) == tuple([i for i in sub_value]) - if not isEquivalent: - pass #print("Not equivalent: " + str(sub_value) + " " + str(newValue) + " " + str(sub_value_attr)) - equivalent &= isEquivalent + if not isEquivalent: + pass # print("Not equivalent: " + str(sub_value) + " " + str(newValue) + " " + str(sub_value_attr)) + equivalent &= isEquivalent + + return equivalent - return equivalent def writeCData(data, headerPath, sourcePath): - sourceFile = open(sourcePath, 'w', newline = '\n', encoding = 'utf-8') - sourceFile.write(data.source) - sourceFile.close() + sourceFile = open(sourcePath, "w", newline="\n", encoding="utf-8") + sourceFile.write(data.source) + sourceFile.close() + + headerFile = open(headerPath, "w", newline="\n", encoding="utf-8") + headerFile.write(data.header) + headerFile.close() - headerFile = open(headerPath, 'w', newline = '\n', encoding = 'utf-8') - headerFile.write(data.header) - headerFile.close() def writeCDataSourceOnly(data, sourcePath): - sourceFile = open(sourcePath, 'w', newline = '\n', encoding = 'utf-8') - sourceFile.write(data.source) - sourceFile.close() + sourceFile = open(sourcePath, "w", newline="\n", encoding="utf-8") + sourceFile.write(data.source) + sourceFile.close() + def writeCDataHeaderOnly(data, headerPath): - headerFile = open(headerPath, 'w', newline = '\n', encoding = 'utf-8') - headerFile.write(data.header) - headerFile.close() + headerFile = open(headerPath, "w", newline="\n", encoding="utf-8") + headerFile.write(data.header) + headerFile.close() + class CData: - def __init__(self): - self.source = "" - self.header = "" + def __init__(self): + self.source = "" + self.header = "" + + def append(self, other): + self.source += other.source + self.header += other.header - def append(self, other): - self.source += other.source - self.header += other.header def getObjectFromData(data): - for obj in bpy.data.objects: - if obj.data == data: - return obj - return None + for obj in bpy.data.objects: + if obj.data == data: + return obj + return None + def getTabbedText(text, tabCount): - return text.replace('\n', '\n' + '\t' * tabCount) + return text.replace("\n", "\n" + "\t" * tabCount) + def extendedRAMLabel(layout): - return - infoBox = layout.box() - infoBox.label(text = 'Be sure to add: ') - infoBox.label(text = '"#define USE_EXT_RAM"') - infoBox.label(text = 'to include/segments.h.') - infoBox.label(text = 'Extended RAM prevents crashes.') + return + infoBox = layout.box() + infoBox.label(text="Be sure to add: ") + infoBox.label(text='"#define USE_EXT_RAM"') + infoBox.label(text="to include/segments.h.") + infoBox.label(text="Extended RAM prevents crashes.") + def checkExpanded(filepath): - size = os.path.getsize(filepath) - if size < 9000000: # check if 8MB - raise PluginError("ROM at " + filepath + " is too small. You may be using an unexpanded ROM. You can expand a ROM by opening it in SM64 Editor or ROM Manager.") + size = os.path.getsize(filepath) + if size < 9000000: # check if 8MB + raise PluginError( + "ROM at " + + filepath + + " is too small. You may be using an unexpanded ROM. You can expand a ROM by opening it in SM64 Editor or ROM Manager." + ) + def getPathAndLevel(customExport, exportPath, levelName, levelOption): - if customExport: - exportPath = bpy.path.abspath(exportPath) - levelName = levelName - else: - exportPath = bpy.path.abspath(bpy.context.scene.decompPath) - if levelOption == 'custom': - levelName = levelName - else: - levelName = levelOption - return exportPath, levelName + if customExport: + exportPath = bpy.path.abspath(exportPath) + levelName = levelName + else: + exportPath = bpy.path.abspath(bpy.context.scene.decompPath) + if levelOption == "custom": + levelName = levelName + else: + levelName = levelOption + return exportPath, levelName + def findStartBones(armatureObj): - noParentBones = sorted([bone.name for bone in armatureObj.data.bones if \ - bone.parent is None and (bone.geo_cmd != 'SwitchOption' and bone.geo_cmd != 'Ignore')]) + noParentBones = sorted( + [ + bone.name + for bone in armatureObj.data.bones + if bone.parent is None and (bone.geo_cmd != "SwitchOption" and bone.geo_cmd != "Ignore") + ] + ) - if len(noParentBones) == 0: - raise PluginError("No non switch option start bone could be found " +\ - 'in ' + armatureObj.name + '. Is this the root armature?') - else: - return noParentBones + if len(noParentBones) == 0: + raise PluginError( + "No non switch option start bone could be found " + + "in " + + armatureObj.name + + ". Is this the root armature?" + ) + else: + return noParentBones + + if len(noParentBones) == 1: + return noParentBones[0] + elif len(noParentBones) == 0: + raise PluginError( + "No non switch option start bone could be found " + + "in " + + armatureObj.name + + ". Is this the root armature?" + ) + else: + raise PluginError( + "Too many parentless bones found. Make sure your bone hierarchy starts from a single bone, " + + 'and that any bones not related to a hierarchy have their geolayout command set to "Ignore".' + ) - if len(noParentBones) == 1: - return noParentBones[0] - elif len(noParentBones) == 0: - raise PluginError("No non switch option start bone could be found " +\ - 'in ' + armatureObj.name + '. Is this the root armature?') - else: - raise PluginError("Too many parentless bones found. Make sure your bone hierarchy starts from a single bone, " +\ - "and that any bones not related to a hierarchy have their geolayout command set to \"Ignore\".") def getDataFromFile(filepath): - if not os.path.exists(filepath): - raise PluginError("Path \"" + filepath + '" does not exist.') - dataFile = open(filepath, 'r', newline = '\n') - data = dataFile.read() - dataFile.close() - return data + if not os.path.exists(filepath): + raise PluginError('Path "' + filepath + '" does not exist.') + dataFile = open(filepath, "r", newline="\n") + data = dataFile.read() + dataFile.close() + return data + def saveDataToFile(filepath, data): - dataFile = open(filepath, 'w', newline = '\n') - dataFile.write(data) - dataFile.close() + dataFile = open(filepath, "w", newline="\n") + dataFile.write(data) + dataFile.close() + def applyBasicTweaks(baseDir): - enableExtendedRAM(baseDir) - return + enableExtendedRAM(baseDir) + return + def enableExtendedRAM(baseDir): - segmentPath = os.path.join(baseDir, 'include/segments.h') + segmentPath = os.path.join(baseDir, "include/segments.h") - segmentFile = open(segmentPath, 'r', newline = '\n') - segmentData = segmentFile.read() - segmentFile.close() + segmentFile = open(segmentPath, "r", newline="\n") + segmentData = segmentFile.read() + segmentFile.close() - matchResult = re.search('#define\s*USE\_EXT\_RAM', segmentData) + matchResult = re.search("#define\s*USE\_EXT\_RAM", segmentData) - if not matchResult: - matchResult = re.search('#ifndef\s*USE\_EXT\_RAM', segmentData) - if matchResult is None: - raise PluginError("When trying to enable extended RAM, " +\ - "could not find '#ifndef USE_EXT_RAM' in include/segments.h.") - segmentData = segmentData[:matchResult.start(0)] + \ - '#define USE_EXT_RAM\n' + \ - segmentData[matchResult.start(0):] + if not matchResult: + matchResult = re.search("#ifndef\s*USE\_EXT\_RAM", segmentData) + if matchResult is None: + raise PluginError( + "When trying to enable extended RAM, " + "could not find '#ifndef USE_EXT_RAM' in include/segments.h." + ) + segmentData = ( + segmentData[: matchResult.start(0)] + "#define USE_EXT_RAM\n" + segmentData[matchResult.start(0) :] + ) + + segmentFile = open(segmentPath, "w", newline="\n") + segmentFile.write(segmentData) + segmentFile.close() - segmentFile = open(segmentPath, 'w', newline = '\n') - segmentFile.write(segmentData) - segmentFile.close() def writeMaterialHeaders(exportDir, matCInclude, matHInclude): - writeIfNotFound(os.path.join(exportDir, 'src/game/materials.c'), - '\n' + matCInclude, '') - writeIfNotFound(os.path.join(exportDir, 'src/game/materials.h'), - '\n' + matHInclude, '#endif') + writeIfNotFound(os.path.join(exportDir, "src/game/materials.c"), "\n" + matCInclude, "") + writeIfNotFound(os.path.join(exportDir, "src/game/materials.h"), "\n" + matHInclude, "#endif") -def writeMaterialFiles(exportDir, assetDir, headerInclude, matHInclude, - headerDynamic, dynamic_data, geoString, customExport): - if not customExport: - writeMaterialBase(exportDir) - levelMatCPath = os.path.join(assetDir, 'material.inc.c') - levelMatHPath = os.path.join(assetDir, 'material.inc.h') - levelMatCFile = open(levelMatCPath, 'w', newline = '\n') - levelMatCFile.write(dynamic_data) - levelMatCFile.close() +def writeMaterialFiles( + exportDir, assetDir, headerInclude, matHInclude, headerDynamic, dynamic_data, geoString, customExport +): + if not customExport: + writeMaterialBase(exportDir) + levelMatCPath = os.path.join(assetDir, "material.inc.c") + levelMatHPath = os.path.join(assetDir, "material.inc.h") - headerDynamic = headerInclude + '\n\n' + headerDynamic - levelMatHFile = open(levelMatHPath, 'w', newline = '\n') - levelMatHFile.write(headerDynamic) - levelMatHFile.close() + levelMatCFile = open(levelMatCPath, "w", newline="\n") + levelMatCFile.write(dynamic_data) + levelMatCFile.close() + + headerDynamic = headerInclude + "\n\n" + headerDynamic + levelMatHFile = open(levelMatHPath, "w", newline="\n") + levelMatHFile.write(headerDynamic) + levelMatHFile.close() + + return matHInclude + "\n\n" + geoString - return matHInclude + '\n\n' + geoString def writeMaterialBase(baseDir): - matHPath = os.path.join(baseDir, 'src/game/materials.h') - if not os.path.exists(matHPath): - matHFile = open(matHPath, 'w', newline = '\n') + matHPath = os.path.join(baseDir, "src/game/materials.h") + if not os.path.exists(matHPath): + matHFile = open(matHPath, "w", newline="\n") - # Write material.inc.h - matHFile.write( - '#ifndef MATERIALS_H\n' +\ - '#define MATERIALS_H\n\n' + \ - '#endif') + # Write material.inc.h + matHFile.write("#ifndef MATERIALS_H\n" + "#define MATERIALS_H\n\n" + "#endif") - matHFile.close() + matHFile.close() - matCPath = os.path.join(baseDir, 'src/game/materials.c') - if not os.path.exists(matCPath): - matCFile = open(matCPath, 'w', newline = '\n') - matCFile.write( - '#include "types.h"\n' +\ - '#include "rendering_graph_node.h"\n' +\ - '#include "object_fields.h"\n' +\ - '#include "materials.h"') + matCPath = os.path.join(baseDir, "src/game/materials.c") + if not os.path.exists(matCPath): + matCFile = open(matCPath, "w", newline="\n") + matCFile.write( + '#include "types.h"\n' + + '#include "rendering_graph_node.h"\n' + + '#include "object_fields.h"\n' + + '#include "materials.h"' + ) - # Write global texture load function here - # Write material.inc.c - # Write update_materials + # Write global texture load function here + # Write material.inc.c + # Write update_materials + + matCFile.close() - matCFile.close() def getRGBA16Tuple(color): - return ((int(round(color[0] * 0x1F)) & 0x1F) << 11) | \ - ((int(round(color[1] * 0x1F)) & 0x1F) << 6) | \ - ((int(round(color[2] * 0x1F)) & 0x1F) << 1) | \ - (1 if color[3] > 0.5 else 0) + return ( + ((int(round(color[0] * 0x1F)) & 0x1F) << 11) + | ((int(round(color[1] * 0x1F)) & 0x1F) << 6) + | ((int(round(color[2] * 0x1F)) & 0x1F) << 1) + | (1 if color[3] > 0.5 else 0) + ) + def getIA16Tuple(color): - intensity = mathutils.Color(color[0:3]).v - alpha = color[3] - return (int(round(intensity * 0xFF)) << 8) | int(alpha * 0xFF) + intensity = mathutils.Color(color[0:3]).v + alpha = color[3] + return (int(round(intensity * 0xFF)) << 8) | int(alpha * 0xFF) + def convertRadiansToS16(value): - value = math.degrees(value) - # ??? Why is this negative? - # TODO: Figure out why this has to be this way - value = 360 - (value % 360) - return hex(round(value / 360 * 0xFFFF)) + value = math.degrees(value) + # ??? Why is this negative? + # TODO: Figure out why this has to be this way + value = 360 - (value % 360) + return hex(round(value / 360 * 0xFFFF)) + def cast_integer(value: int, bits: int, signed: bool): wrap = 1 << bits value %= wrap return value - wrap if signed and value & (1 << (bits - 1)) else value + to_s16 = lambda x: cast_integer(round(x), 16, True) radians_to_s16 = lambda d: to_s16(d * 0x10000 / (2 * math.pi)) + def decompFolderMessage(layout): - layout.box().label(text = 'This will export to your decomp folder.') + layout.box().label(text="This will export to your decomp folder.") + def customExportWarning(layout): - layout.box().label(text = 'This will not write any headers/dependencies.') + layout.box().label(text="This will not write any headers/dependencies.") + def raisePluginError(operator, exception): - print(traceback.format_exc()) - if bpy.context.scene.fullTraceback: - operator.report({'ERROR'}, traceback.format_exc()) - else: - operator.report({'ERROR'}, str(exception)) + print(traceback.format_exc()) + if bpy.context.scene.fullTraceback: + operator.report({"ERROR"}, traceback.format_exc()) + else: + operator.report({"ERROR"}, str(exception)) + def highlightWeightErrors(obj, elements, elementType): - return # Doesn't work currently - if bpy.context.mode != 'OBJECT': - bpy.ops.object.mode_set(mode = 'OBJECT') - bpy.ops.object.select_all(action = "DESELECT") - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - bpy.ops.object.mode_set(mode = 'EDIT') - bpy.ops.mesh.select_all(action = "DESELECT") - bpy.ops.mesh.select_mode(type = elementType) - bpy.ops.object.mode_set(mode = 'OBJECT') - print(elements) - for element in elements: - element.select = True + return # Doesn't work currently + if bpy.context.mode != "OBJECT": + bpy.ops.object.mode_set(mode="OBJECT") + bpy.ops.object.select_all(action="DESELECT") + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + bpy.ops.object.mode_set(mode="EDIT") + bpy.ops.mesh.select_all(action="DESELECT") + bpy.ops.mesh.select_mode(type=elementType) + bpy.ops.object.mode_set(mode="OBJECT") + print(elements) + for element in elements: + element.select = True + def checkIdentityRotation(obj, rotation, allowYaw): - rotationDiff = rotation.to_euler() - if abs(rotationDiff.x) > 0.001 or (not allowYaw and abs(rotationDiff.y) > 0.001) or abs(rotationDiff.z) > 0.001: - raise PluginError("Box \"" + obj.name + "\" cannot have a non-zero world rotation " + \ - ("(except yaw)" if allowYaw else "") + ", currently at (" + \ - str(rotationDiff[0]) + ', ' + str(rotationDiff[1]) + ', ' + str(rotationDiff[2]) + ')') + rotationDiff = rotation.to_euler() + if abs(rotationDiff.x) > 0.001 or (not allowYaw and abs(rotationDiff.y) > 0.001) or abs(rotationDiff.z) > 0.001: + raise PluginError( + 'Box "' + + obj.name + + '" cannot have a non-zero world rotation ' + + ("(except yaw)" if allowYaw else "") + + ", currently at (" + + str(rotationDiff[0]) + + ", " + + str(rotationDiff[1]) + + ", " + + str(rotationDiff[2]) + + ")" + ) + def setOrigin(target, obj): - bpy.ops.object.select_all(action = "DESELECT") - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - bpy.ops.object.transform_apply() - bpy.context.scene.cursor.location = target.location - bpy.ops.object.origin_set(type = 'ORIGIN_CURSOR') - bpy.ops.object.select_all(action = "DESELECT") + bpy.ops.object.select_all(action="DESELECT") + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + bpy.ops.object.transform_apply() + bpy.context.scene.cursor.location = target.location + bpy.ops.object.origin_set(type="ORIGIN_CURSOR") + bpy.ops.object.select_all(action="DESELECT") + def checkIfPathExists(filePath): - if not os.path.exists(filePath): - raise PluginError(filePath + " does not exist.") + if not os.path.exists(filePath): + raise PluginError(filePath + " does not exist.") + def makeWriteInfoBox(layout): - writeBox = layout.box() - writeBox.label(text = 'Along with header edits, this will write to:') - return writeBox + writeBox = layout.box() + writeBox.label(text="Along with header edits, this will write to:") + return writeBox + def writeBoxExportType(writeBox, headerType, name, levelName, levelOption): - if headerType == 'Actor': - writeBox.label(text = 'actors/' + toAlnum(name)) - elif headerType == 'Level': - if levelOption != 'custom': - levelName = levelOption - writeBox.label(text = 'levels/' + toAlnum(levelName) + '/' + toAlnum(name)) + if headerType == "Actor": + writeBox.label(text="actors/" + toAlnum(name)) + elif headerType == "Level": + if levelOption != "custom": + levelName = levelOption + writeBox.label(text="levels/" + toAlnum(levelName) + "/" + toAlnum(name)) + def getExportDir(customExport, dirPath, headerType, levelName, texDir, dirName): - # Get correct directory from decomp base, and overwrite texDir - if not customExport: - if headerType == 'Actor': - dirPath = os.path.join(dirPath, 'actors') - texDir = 'actors/' + dirName - elif headerType == 'Level': - dirPath = os.path.join(dirPath, 'levels/' + levelName) - texDir = 'levels/' + levelName + # Get correct directory from decomp base, and overwrite texDir + if not customExport: + if headerType == "Actor": + dirPath = os.path.join(dirPath, "actors") + texDir = "actors/" + dirName + elif headerType == "Level": + dirPath = os.path.join(dirPath, "levels/" + levelName) + texDir = "levels/" + levelName + + return dirPath, texDir - return dirPath, texDir def overwriteData(headerRegex, name, value, filePath, writeNewBeforeString, isFunction): - if os.path.exists(filePath): - dataFile = open(filePath, 'r') - data = dataFile.read() - dataFile.close() + if os.path.exists(filePath): + dataFile = open(filePath, "r") + data = dataFile.read() + dataFile.close() + + matchResult = re.search( + headerRegex + + re.escape(name) + + ("\s*\((((?!\)).)*)\)\s*\{(((?!\}).)*)\}" if isFunction else "\[\]\s*=\s*\{(((?!;).)*);"), + data, + re.DOTALL, + ) + if matchResult: + data = data[: matchResult.start(0)] + value + data[matchResult.end(0) :] + else: + if writeNewBeforeString is not None: + cmdPos = data.find(writeNewBeforeString) + if cmdPos == -1: + raise PluginError("Could not find '" + writeNewBeforeString + "'.") + data = data[:cmdPos] + value + "\n" + data[cmdPos:] + else: + data += "\n" + value + dataFile = open(filePath, "w", newline="\n") + dataFile.write(data) + dataFile.close() + else: + raise PluginError(filePath + " does not exist.") - matchResult = re.search(headerRegex + re.escape(name) + \ - ('\s*\((((?!\)).)*)\)\s*\{(((?!\}).)*)\}' if isFunction else \ - '\[\]\s*=\s*\{(((?!;).)*);'), data, re.DOTALL) - if matchResult: - data = data[:matchResult.start(0)] + value + data[matchResult.end(0):] - else: - if writeNewBeforeString is not None: - cmdPos = data.find(writeNewBeforeString) - if cmdPos == -1: - raise PluginError("Could not find '" + writeNewBeforeString + "'.") - data = data[:cmdPos] + value + '\n' + data[cmdPos:] - else: - data += '\n' + value - dataFile = open(filePath, 'w', newline='\n') - dataFile.write(data) - dataFile.close() - else: - raise PluginError(filePath + " does not exist.") def writeIfNotFound(filePath, stringValue, footer): - if os.path.exists(filePath): - fileData = open(filePath, 'r') - fileData.seek(0) - stringData = fileData.read() - fileData.close() - if stringValue not in stringData: - if len(footer) > 0: - footerIndex = stringData.rfind(footer) - if footerIndex == -1: - raise PluginError("Footer " + footer + " does not exist.") - stringData = stringData[:footerIndex] + stringValue + '\n' + stringData[footerIndex:] - else: - stringData += stringValue - fileData = open(filePath, 'w', newline = '\n') - fileData.write(stringData) - fileData.close() - else: - raise PluginError(filePath + " does not exist.") + if os.path.exists(filePath): + fileData = open(filePath, "r") + fileData.seek(0) + stringData = fileData.read() + fileData.close() + if stringValue not in stringData: + if len(footer) > 0: + footerIndex = stringData.rfind(footer) + if footerIndex == -1: + raise PluginError("Footer " + footer + " does not exist.") + stringData = stringData[:footerIndex] + stringValue + "\n" + stringData[footerIndex:] + else: + stringData += stringValue + fileData = open(filePath, "w", newline="\n") + fileData.write(stringData) + fileData.close() + else: + raise PluginError(filePath + " does not exist.") + def deleteIfFound(filePath, stringValue): - if os.path.exists(filePath): - fileData = open(filePath, 'r') - fileData.seek(0) - stringData = fileData.read() - fileData.close() - if stringValue in stringData: - stringData = stringData.replace(stringValue, '') - fileData = open(filePath, 'w', newline = '\n') - fileData.write(stringData) - fileData.close() + if os.path.exists(filePath): + fileData = open(filePath, "r") + fileData.seek(0) + stringData = fileData.read() + fileData.close() + if stringValue in stringData: + stringData = stringData.replace(stringValue, "") + fileData = open(filePath, "w", newline="\n") + fileData.write(stringData) + fileData.close() + def yield_children(obj: bpy.types.Object): - yield obj - if obj.children: - for o in obj.children: - yield from yield_children(o) + yield obj + if obj.children: + for o in obj.children: + yield from yield_children(o) + def store_original_mtx(): - active_obj = bpy.context.view_layer.objects.active - for obj in yield_children(active_obj): - obj['original_mtx'] = obj.matrix_local + active_obj = bpy.context.view_layer.objects.active + for obj in yield_children(active_obj): + obj["original_mtx"] = obj.matrix_local + def rotate_bounds(bounds, mtx: mathutils.Matrix): - return [ - (mtx @ mathutils.Vector(b)).to_tuple() - for b in bounds - ] + return [(mtx @ mathutils.Vector(b)).to_tuple() for b in bounds] + def obj_scale_is_unified(obj): - '''Combine scale values into a set to ensure all values are the same''' - return len(set(obj.scale)) == 1 + """Combine scale values into a set to ensure all values are the same""" + return len(set(obj.scale)) == 1 + def translation_rotation_from_mtx(mtx: mathutils.Matrix): - '''Strip scale from matrix''' - t, r, _ = mtx.decompose() - return Matrix.Translation(t) @ r.to_matrix().to_4x4() + """Strip scale from matrix""" + t, r, _ = mtx.decompose() + return Matrix.Translation(t) @ r.to_matrix().to_4x4() + def scale_mtx_from_vector(scale: mathutils.Vector): - return mathutils.Matrix.Diagonal(scale[0:3]).to_4x4() + return mathutils.Matrix.Diagonal(scale[0:3]).to_4x4() -def copy_object_and_apply(obj: bpy.types.Object, apply_scale = False, apply_modifiers = False): - if apply_scale or apply_modifiers: - # it's a unique mesh, use object name - obj['instanced_mesh_name'] = obj.name - obj.original_name = obj.name - if apply_scale: - obj['original_mtx'] = translation_rotation_from_mtx(mathutils.Matrix(obj['original_mtx'])) +def copy_object_and_apply(obj: bpy.types.Object, apply_scale=False, apply_modifiers=False): + if apply_scale or apply_modifiers: + # it's a unique mesh, use object name + obj["instanced_mesh_name"] = obj.name - obj_copy = obj.copy() - obj_copy.parent = None - # reset transformations - obj_copy.location = mathutils.Vector([0.0, 0.0, 0.0]) - obj_copy.scale = mathutils.Vector([1.0, 1.0, 1.0]) - obj_copy.rotation_quaternion = mathutils.Quaternion([1, 0, 0, 0]) - obj_copy.data = obj_copy.data.copy() + obj.original_name = obj.name + if apply_scale: + obj["original_mtx"] = translation_rotation_from_mtx(mathutils.Matrix(obj["original_mtx"])) - if apply_modifiers: - # In order to correctly apply modifiers, we have to go through blender and add the object to the collection, then apply modifiers - prev_active = bpy.context.view_layer.objects.active - bpy.context.collection.objects.link(obj_copy) - obj_copy.select_set(True) - bpy.context.view_layer.objects.active = obj_copy - for modifier in obj_copy.modifiers: - attemptModifierApply(modifier) + obj_copy = obj.copy() + obj_copy.parent = None + # reset transformations + obj_copy.location = mathutils.Vector([0.0, 0.0, 0.0]) + obj_copy.scale = mathutils.Vector([1.0, 1.0, 1.0]) + obj_copy.rotation_quaternion = mathutils.Quaternion([1, 0, 0, 0]) + obj_copy.data = obj_copy.data.copy() - bpy.context.view_layer.objects.active = prev_active + if apply_modifiers: + # In order to correctly apply modifiers, we have to go through blender and add the object to the collection, then apply modifiers + prev_active = bpy.context.view_layer.objects.active + bpy.context.collection.objects.link(obj_copy) + obj_copy.select_set(True) + bpy.context.view_layer.objects.active = obj_copy + for modifier in obj_copy.modifiers: + attemptModifierApply(modifier) - mtx = transform_mtx_blender_to_n64() - if apply_scale: - mtx = mtx @ scale_mtx_from_vector(obj.scale) + bpy.context.view_layer.objects.active = prev_active - obj_copy.data.transform(mtx) - # Flag used for finding these temp objects - obj_copy['temp_export'] = True + mtx = transform_mtx_blender_to_n64() + if apply_scale: + mtx = mtx @ scale_mtx_from_vector(obj.scale) + + obj_copy.data.transform(mtx) + # Flag used for finding these temp objects + obj_copy["temp_export"] = True + + # Override for F3D culling bounds (used in addCullCommand) + bounds_mtx = transform_mtx_blender_to_n64() + if apply_scale: + bounds_mtx = bounds_mtx @ scale_mtx_from_vector(obj.scale) # apply scale if needed + obj_copy["culling_bounds"] = rotate_bounds(obj_copy.bound_box, bounds_mtx) - # Override for F3D culling bounds (used in addCullCommand) - bounds_mtx = transform_mtx_blender_to_n64() - if apply_scale: - bounds_mtx = bounds_mtx @ scale_mtx_from_vector(obj.scale) # apply scale if needed - obj_copy['culling_bounds'] = rotate_bounds(obj_copy.bound_box, bounds_mtx) def store_original_meshes(add_warning: Callable[[str], None]): - ''' - - Creates new objects at 0, 0, 0 with shared mesh - - Original mesh name is saved to each object - ''' - instanced_meshes = set() - active_obj = bpy.context.view_layer.objects.active - for obj in yield_children(active_obj): - if obj.data is not None: - has_modifiers = len(obj.modifiers) != 0 - has_uneven_scale = not obj_scale_is_unified(obj) - shares_mesh = obj.data.users > 1 - can_instance = not has_modifiers and not has_uneven_scale - should_instance = can_instance and (shares_mesh or obj.scaleFromGeolayout) + """ + - Creates new objects at 0, 0, 0 with shared mesh + - Original mesh name is saved to each object + """ + instanced_meshes = set() + active_obj = bpy.context.view_layer.objects.active + for obj in yield_children(active_obj): + if obj.data is not None: + has_modifiers = len(obj.modifiers) != 0 + has_uneven_scale = not obj_scale_is_unified(obj) + shares_mesh = obj.data.users > 1 + can_instance = not has_modifiers and not has_uneven_scale + should_instance = can_instance and (shares_mesh or obj.scaleFromGeolayout) - if should_instance: - # add `_shared_mesh` to instanced name because `obj.data.name` can be the same as object names - obj['instanced_mesh_name'] = f'{obj.data.name}_shared_mesh' - obj.original_name = obj.name + if should_instance: + # add `_shared_mesh` to instanced name because `obj.data.name` can be the same as object names + obj["instanced_mesh_name"] = f"{obj.data.name}_shared_mesh" + obj.original_name = obj.name - if obj.data.name not in instanced_meshes: - instanced_meshes.add(obj.data.name) - copy_object_and_apply(obj) - else: - if shares_mesh and has_modifiers: - add_warning( - f'Object "{obj.name}" cannot be instanced due to having modifiers so an extra displaylist will be created. Remove modifiers to allow instancing.') - if shares_mesh and has_uneven_scale: - add_warning( - f'Object "{obj.name}" cannot be instanced due to uneven object scaling and an extra displaylist will be created. Set all scale values to the same value to allow instancing.') + if obj.data.name not in instanced_meshes: + instanced_meshes.add(obj.data.name) + copy_object_and_apply(obj) + else: + if shares_mesh and has_modifiers: + add_warning( + f'Object "{obj.name}" cannot be instanced due to having modifiers so an extra displaylist will be created. Remove modifiers to allow instancing.' + ) + if shares_mesh and has_uneven_scale: + add_warning( + f'Object "{obj.name}" cannot be instanced due to uneven object scaling and an extra displaylist will be created. Set all scale values to the same value to allow instancing.' + ) + + copy_object_and_apply(obj, apply_scale=True, apply_modifiers=has_modifiers) + bpy.context.view_layer.objects.active = active_obj - copy_object_and_apply(obj, apply_scale=True, apply_modifiers=has_modifiers) - bpy.context.view_layer.objects.active = active_obj def get_obj_temp_mesh(obj): - for o in bpy.data.objects: - if ( - o.get('temp_export') - and o.get('instanced_mesh_name') == obj.get('instanced_mesh_name') - ): - return o + for o in bpy.data.objects: + if o.get("temp_export") and o.get("instanced_mesh_name") == obj.get("instanced_mesh_name"): + return o + def duplicateHierarchy(obj, ignoreAttr, includeEmpties, areaIndex): - # Duplicate objects to apply scale / modifiers / linked data - bpy.ops.object.select_all(action = 'DESELECT') - selectMeshChildrenOnly(obj, None, includeEmpties, areaIndex) - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - bpy.ops.object.duplicate() - try: - tempObj = bpy.context.view_layer.objects.active - allObjs = bpy.context.selected_objects + # Duplicate objects to apply scale / modifiers / linked data + bpy.ops.object.select_all(action="DESELECT") + selectMeshChildrenOnly(obj, None, includeEmpties, areaIndex) + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + bpy.ops.object.duplicate() + try: + tempObj = bpy.context.view_layer.objects.active + allObjs = bpy.context.selected_objects - bpy.ops.object.make_single_user(obdata = True) - bpy.ops.object.transform_apply(location = False, - rotation = True, scale = True, properties = False) + bpy.ops.object.make_single_user(obdata=True) + bpy.ops.object.transform_apply(location=False, rotation=True, scale=True, properties=False) - for selectedObj in allObjs: - bpy.ops.object.select_all(action = 'DESELECT') - selectedObj.select_set(True) - bpy.context.view_layer.objects.active = selectedObj + for selectedObj in allObjs: + bpy.ops.object.select_all(action="DESELECT") + selectedObj.select_set(True) + bpy.context.view_layer.objects.active = selectedObj + + for modifier in selectedObj.modifiers: + attemptModifierApply(modifier) + for selectedObj in allObjs: + if ignoreAttr is not None and getattr(selectedObj, ignoreAttr): + for child in selectedObj.children: + bpy.ops.object.select_all(action="DESELECT") + child.select_set(True) + bpy.context.view_layer.objects.active = child + bpy.ops.object.parent_clear(type="CLEAR_KEEP_TRANSFORM") + selectedObj.parent.select_set(True) + bpy.context.view_layer.objects.active = selectedObj.parent + bpy.ops.object.parent_set(keep_transform=True) + selectedObj.parent = None + return tempObj, allObjs + except Exception as e: + cleanupDuplicatedObjects(allObjs) + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + raise Exception(str(e)) + + +enumSM64PreInlineGeoLayoutObjects = {"Geo ASM", "Geo Branch", "Geo Displaylist", "Custom Geo Command"} - for modifier in selectedObj.modifiers: - attemptModifierApply(modifier) - for selectedObj in allObjs: - if ignoreAttr is not None and getattr(selectedObj, ignoreAttr): - for child in selectedObj.children: - bpy.ops.object.select_all(action = 'DESELECT') - child.select_set(True) - bpy.context.view_layer.objects.active = child - bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM') - selectedObj.parent.select_set(True) - bpy.context.view_layer.objects.active = selectedObj.parent - bpy.ops.object.parent_set(keep_transform = True) - selectedObj.parent = None - return tempObj, allObjs - except Exception as e: - cleanupDuplicatedObjects(allObjs) - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - raise Exception(str(e)) -enumSM64PreInlineGeoLayoutObjects = { - 'Geo ASM', - 'Geo Branch', - 'Geo Displaylist', - 'Custom Geo Command' -} def checkIsSM64PreInlineGeoLayout(sm64_obj_type): - return sm64_obj_type in enumSM64PreInlineGeoLayoutObjects + return sm64_obj_type in enumSM64PreInlineGeoLayoutObjects + enumSM64InlineGeoLayoutObjects = { - 'Geo ASM', - 'Geo Branch', - 'Geo Translate/Rotate', - 'Geo Translate Node', - 'Geo Rotation Node', - 'Geo Billboard', - 'Geo Scale', - 'Geo Displaylist', - 'Custom Geo Command' + "Geo ASM", + "Geo Branch", + "Geo Translate/Rotate", + "Geo Translate Node", + "Geo Rotation Node", + "Geo Billboard", + "Geo Scale", + "Geo Displaylist", + "Custom Geo Command", } -def checkIsSM64InlineGeoLayout(sm64_obj_type): - return sm64_obj_type in enumSM64InlineGeoLayoutObjects -enumSM64EmptyWithGeolayout = { - 'None', - 'Level Root', - 'Area Root', - 'Switch' -} + +def checkIsSM64InlineGeoLayout(sm64_obj_type): + return sm64_obj_type in enumSM64InlineGeoLayoutObjects + + +enumSM64EmptyWithGeolayout = {"None", "Level Root", "Area Root", "Switch"} + + def checkSM64EmptyUsesGeoLayout(sm64_obj_type): - return sm64_obj_type in enumSM64EmptyWithGeolayout or checkIsSM64InlineGeoLayout(sm64_obj_type) + return sm64_obj_type in enumSM64EmptyWithGeolayout or checkIsSM64InlineGeoLayout(sm64_obj_type) + def selectMeshChildrenOnly(obj, ignoreAttr, includeEmpties, areaIndex): - checkArea = areaIndex is not None and obj.data is None - if checkArea and obj.sm64_obj_type == 'Area Root' and obj.areaIndex != areaIndex: - return - ignoreObj = ignoreAttr is not None and getattr(obj, ignoreAttr) - isMesh = isinstance(obj.data, bpy.types.Mesh) - isEmpty = ( - obj.data is None - and includeEmpties - and checkSM64EmptyUsesGeoLayout(obj.sm64_obj_type) - ) - if (isMesh or isEmpty) and not ignoreObj: - obj.select_set(True) - obj.original_name = obj.name - for child in obj.children: - if checkArea and obj.sm64_obj_type == 'Level Root': - if not (child.data is None and child.sm64_obj_type == 'Area Root'): - continue - selectMeshChildrenOnly(child, ignoreAttr, includeEmpties, areaIndex) + checkArea = areaIndex is not None and obj.data is None + if checkArea and obj.sm64_obj_type == "Area Root" and obj.areaIndex != areaIndex: + return + ignoreObj = ignoreAttr is not None and getattr(obj, ignoreAttr) + isMesh = isinstance(obj.data, bpy.types.Mesh) + isEmpty = obj.data is None and includeEmpties and checkSM64EmptyUsesGeoLayout(obj.sm64_obj_type) + if (isMesh or isEmpty) and not ignoreObj: + obj.select_set(True) + obj.original_name = obj.name + for child in obj.children: + if checkArea and obj.sm64_obj_type == "Level Root": + if not (child.data is None and child.sm64_obj_type == "Area Root"): + continue + selectMeshChildrenOnly(child, ignoreAttr, includeEmpties, areaIndex) + def cleanupDuplicatedObjects(selected_objects): - meshData = [] - for selectedObj in selected_objects: - if selectedObj.data is not None and isinstance(selectedObj.data, bpy.types.Mesh): - meshData.append(selectedObj.data) - for selectedObj in selected_objects: - bpy.data.objects.remove(selectedObj) - for mesh in meshData: - bpy.data.meshes.remove(mesh) + meshData = [] + for selectedObj in selected_objects: + if selectedObj.data is not None and isinstance(selectedObj.data, bpy.types.Mesh): + meshData.append(selectedObj.data) + for selectedObj in selected_objects: + bpy.data.objects.remove(selectedObj) + for mesh in meshData: + bpy.data.meshes.remove(mesh) + def cleanupTempMeshes(): - '''Delete meshes that have been duplicated for instancing''' - remove_data = [] - for obj in bpy.data.objects: - if obj.get('temp_export'): - remove_data.append(obj.data) - bpy.data.objects.remove(obj) - else: - if obj.get('instanced_mesh_name'): - del obj['instanced_mesh_name'] - if obj.get('original_mtx'): - del obj['original_mtx'] + """Delete meshes that have been duplicated for instancing""" + remove_data = [] + for obj in bpy.data.objects: + if obj.get("temp_export"): + remove_data.append(obj.data) + bpy.data.objects.remove(obj) + else: + if obj.get("instanced_mesh_name"): + del obj["instanced_mesh_name"] + if obj.get("original_mtx"): + del obj["original_mtx"] + + for data in remove_data: + data_type = type(data) + if data_type == bpy.types.Mesh: + bpy.data.meshes.remove(data) + elif data_type == bpy.types.Curve: + bpy.data.curves.remove(data) - for data in remove_data: - data_type = type(data) - if data_type == bpy.types.Mesh: - bpy.data.meshes.remove(data) - elif data_type == bpy.types.Curve: - bpy.data.curves.remove(data) def combineObjects(obj, includeChildren, ignoreAttr, areaIndex): - obj.original_name = obj.name + obj.original_name = obj.name - # Duplicate objects to apply scale / modifiers / linked data - bpy.ops.object.select_all(action = 'DESELECT') - if includeChildren: - selectMeshChildrenOnly(obj, ignoreAttr, False, areaIndex) - else: - obj.select_set(True) - if len(bpy.context.selected_objects) == 0: - return None, [] - bpy.ops.object.duplicate() - joinedObj = None - try: - # duplicate obj and apply modifiers / make single user - allObjs = bpy.context.selected_objects - bpy.ops.object.make_single_user(obdata = True) - bpy.ops.object.transform_apply(location = False, - rotation = True, scale = True, properties = False) - for selectedObj in allObjs: - bpy.ops.object.select_all(action = 'DESELECT') - selectedObj.select_set(True) - for modifier in selectedObj.modifiers: - attemptModifierApply(modifier) + # Duplicate objects to apply scale / modifiers / linked data + bpy.ops.object.select_all(action="DESELECT") + if includeChildren: + selectMeshChildrenOnly(obj, ignoreAttr, False, areaIndex) + else: + obj.select_set(True) + if len(bpy.context.selected_objects) == 0: + return None, [] + bpy.ops.object.duplicate() + joinedObj = None + try: + # duplicate obj and apply modifiers / make single user + allObjs = bpy.context.selected_objects + bpy.ops.object.make_single_user(obdata=True) + bpy.ops.object.transform_apply(location=False, rotation=True, scale=True, properties=False) + for selectedObj in allObjs: + bpy.ops.object.select_all(action="DESELECT") + selectedObj.select_set(True) + for modifier in selectedObj.modifiers: + attemptModifierApply(modifier) - bpy.ops.object.select_all(action = 'DESELECT') + bpy.ops.object.select_all(action="DESELECT") - # Joining causes orphan data, so we remove it manually. - meshList = [] - for selectedObj in allObjs: - selectedObj.select_set(True) - meshList.append(selectedObj.data) + # Joining causes orphan data, so we remove it manually. + meshList = [] + for selectedObj in allObjs: + selectedObj.select_set(True) + meshList.append(selectedObj.data) - joinedObj = bpy.context.selected_objects[0] - bpy.context.view_layer.objects.active = joinedObj - joinedObj.select_set(True) - meshList.remove(joinedObj.data) - bpy.ops.object.join() - setOrigin(obj, joinedObj) + joinedObj = bpy.context.selected_objects[0] + bpy.context.view_layer.objects.active = joinedObj + joinedObj.select_set(True) + meshList.remove(joinedObj.data) + bpy.ops.object.join() + setOrigin(obj, joinedObj) - bpy.ops.object.select_all(action = 'DESELECT') - bpy.context.view_layer.objects.active = joinedObj - joinedObj.select_set(True) + bpy.ops.object.select_all(action="DESELECT") + bpy.context.view_layer.objects.active = joinedObj + joinedObj.select_set(True) - # Need to clear parent transform in order to correctly apply transform. - bpy.ops.object.parent_clear(type='CLEAR_KEEP_TRANSFORM') - bpy.ops.object.transform_apply(location = False, - rotation = True, scale = True, properties = False) - bpy.context.view_layer.objects.active = joinedObj - joinedObj.select_set(True) - bpy.ops.object.transform_apply(location = False, - rotation = True, scale = True, properties = False) + # Need to clear parent transform in order to correctly apply transform. + bpy.ops.object.parent_clear(type="CLEAR_KEEP_TRANSFORM") + bpy.ops.object.transform_apply(location=False, rotation=True, scale=True, properties=False) + bpy.context.view_layer.objects.active = joinedObj + joinedObj.select_set(True) + bpy.ops.object.transform_apply(location=False, rotation=True, scale=True, properties=False) - except Exception as e: - cleanupDuplicatedObjects(allObjs) - obj.select_set(True) - bpy.context.view_layer.objects.active = obj - raise Exception(str(e)) + except Exception as e: + cleanupDuplicatedObjects(allObjs) + obj.select_set(True) + bpy.context.view_layer.objects.active = obj + raise Exception(str(e)) + + return joinedObj, meshList - return joinedObj, meshList def cleanupCombineObj(tempObj, meshList): - for mesh in meshList: - bpy.data.meshes.remove(mesh) - cleanupDuplicatedObjects([tempObj]) - #obj.select_set(True) - #bpy.context.view_layer.objects.active = obj + for mesh in meshList: + bpy.data.meshes.remove(mesh) + cleanupDuplicatedObjects([tempObj]) + # obj.select_set(True) + # bpy.context.view_layer.objects.active = obj + def writeInsertableFile(filepath, dataType, address_ptrs, startPtr, data): - address = 0 - openfile = open(filepath, 'wb') + address = 0 + openfile = open(filepath, "wb") - # 0-4 - Data Type - openfile.write(dataType.to_bytes(4, 'big')) - address += 4 + # 0-4 - Data Type + openfile.write(dataType.to_bytes(4, "big")) + address += 4 - # 4-8 - Data Size - openfile.seek(address) - openfile.write(len(data).to_bytes(4, 'big')) - address += 4 + # 4-8 - Data Size + openfile.seek(address) + openfile.write(len(data).to_bytes(4, "big")) + address += 4 - # 8-12 Start Address - openfile.seek(address) - openfile.write(startPtr.to_bytes(4, 'big')) - address += 4 + # 8-12 Start Address + openfile.seek(address) + openfile.write(startPtr.to_bytes(4, "big")) + address += 4 - # 12-16 - Number of pointer addresses - openfile.seek(address) - openfile.write(len(address_ptrs).to_bytes(4, 'big')) - address += 4 + # 12-16 - Number of pointer addresses + openfile.seek(address) + openfile.write(len(address_ptrs).to_bytes(4, "big")) + address += 4 - # 16-? - Pointer address list - for i in range(len(address_ptrs)): - openfile.seek(address) - openfile.write(address_ptrs[i].to_bytes(4, 'big')) - address += 4 + # 16-? - Pointer address list + for i in range(len(address_ptrs)): + openfile.seek(address) + openfile.write(address_ptrs[i].to_bytes(4, "big")) + address += 4 + + openfile.seek(address) + openfile.write(data) + openfile.close() - openfile.seek(address) - openfile.write(data) - openfile.close() def colorTo16bitRGBA(color): - r = int(round(color[0] * 31)) - g = int(round(color[1] * 31)) - b = int(round(color[2] * 31)) - a = 1 if color[3] > 0.5 else 0 + r = int(round(color[0] * 31)) + g = int(round(color[1] * 31)) + b = int(round(color[2] * 31)) + a = 1 if color[3] > 0.5 else 0 + + return (r << 11) | (g << 6) | (b << 1) | a - return (r << 11) | (g << 6) | (b << 1) | a # On 2.83/2.91 the rotate operator rotates in the opposite direction (???) def getDirectionGivenAppVersion(): - if bpy.app.version[1] == 83 or bpy.app.version[1] == 91: - return -1 - else: - return 1 + if bpy.app.version[1] == 83 or bpy.app.version[1] == 91: + return -1 + else: + return 1 + def applyRotation(objList, angle, axis): - bpy.context.scene.tool_settings.use_transform_data_origin = False - bpy.context.scene.tool_settings.use_transform_pivot_point_align = False - bpy.context.scene.tool_settings.use_transform_skip_children = False + bpy.context.scene.tool_settings.use_transform_data_origin = False + bpy.context.scene.tool_settings.use_transform_pivot_point_align = False + bpy.context.scene.tool_settings.use_transform_skip_children = False - bpy.ops.object.select_all(action = "DESELECT") - for obj in objList: - obj.select_set(True) - bpy.context.view_layer.objects.active = objList[0] + bpy.ops.object.select_all(action="DESELECT") + for obj in objList: + obj.select_set(True) + bpy.context.view_layer.objects.active = objList[0] - direction = getDirectionGivenAppVersion() + direction = getDirectionGivenAppVersion() + + bpy.ops.transform.rotate(value=direction * angle, orient_axis=axis, orient_type="GLOBAL") + bpy.ops.object.transform_apply(location=False, rotation=True, scale=True, properties=False) - bpy.ops.transform.rotate(value = direction * angle, orient_axis = axis, orient_type='GLOBAL') - bpy.ops.object.transform_apply(location = False, - rotation = True, scale = True, properties = False) def doRotation(angle, axis): - direction = getDirectionGivenAppVersion() - bpy.ops.transform.rotate(value = direction * angle, orient_axis = axis, orient_type='GLOBAL') + direction = getDirectionGivenAppVersion() + bpy.ops.transform.rotate(value=direction * angle, orient_axis=axis, orient_type="GLOBAL") + def getAddressFromRAMAddress(RAMAddress): - addr = RAMAddress - 0x80000000 - if addr < 0: - raise PluginError("Invalid RAM address.") - return addr + addr = RAMAddress - 0x80000000 + if addr < 0: + raise PluginError("Invalid RAM address.") + return addr + def getObjectQuaternion(obj): - if obj.rotation_mode == 'QUATERNION': - rotation = mathutils.Quaternion(obj.rotation_quaternion) - elif obj.rotation_mode == 'AXIS_ANGLE': - rotation = mathutils.Quaternion(obj.rotation_axis_angle) - else: - rotation = mathutils.Euler( - obj.rotation_euler, obj.rotation_mode).to_quaternion() - return rotation + if obj.rotation_mode == "QUATERNION": + rotation = mathutils.Quaternion(obj.rotation_quaternion) + elif obj.rotation_mode == "AXIS_ANGLE": + rotation = mathutils.Quaternion(obj.rotation_axis_angle) + else: + rotation = mathutils.Euler(obj.rotation_euler, obj.rotation_mode).to_quaternion() + return rotation + def tempName(name): - letters = string.digits - return name + '_temp' + "".join(random.choice(letters) for i in range(10)) + letters = string.digits + return name + "_temp" + "".join(random.choice(letters) for i in range(10)) + def label_split(layout, name, text): - split = layout.split(factor = 0.5) - split.label(text = name) - split.label(text = text) + split = layout.split(factor=0.5) + split.label(text=name) + split.label(text=text) + def enum_label_split(layout, name, data, prop, enumItems): - split = layout.split(factor = 0.5) - split.label(text = name) - split.enum_item_name(data, prop, enumItems) + split = layout.split(factor=0.5) + split.label(text=name) + split.enum_item_name(data, prop, enumItems) + def prop_split(layout, data, field, name, **prop_kwargs): - split = layout.split(factor = 0.5) - split.label(text = name) - split.prop(data, field, text = '', **prop_kwargs) + split = layout.split(factor=0.5) + split.label(text=name) + split.prop(data, field, text="", **prop_kwargs) + def toAlnum(name): - if name is None or name == '': - return None - for i in range(len(name)): - if not name[i].isalnum(): - name = name[:i] + '_' + name[i+1:] - if name[0].isdigit(): - name = '_' + name - return name + if name is None or name == "": + return None + for i in range(len(name)): + if not name[i].isalnum(): + name = name[:i] + "_" + name[i + 1 :] + if name[0].isdigit(): + name = "_" + name + return name + def get64bitAlignedAddr(address): - endNibble = hex(address)[-1] - if endNibble != '0' and endNibble != '8': - address = ceil(address / 8) * 8 - return address + endNibble = hex(address)[-1] + if endNibble != "0" and endNibble != "8": + address = ceil(address / 8) * 8 + return address + + +def getNameFromPath(path, removeExtension=False): + if path[:2] == "//": + path = path[2:] + name = os.path.basename(path) + if removeExtension: + name = os.path.splitext(name)[0] + return toAlnum(name) -def getNameFromPath(path, removeExtension = False): - if path[:2] == '//': - path = path[2:] - name = os.path.basename(path) - if removeExtension: - name = os.path.splitext(name)[0] - return toAlnum(name) def gammaCorrect(color): - return [ - gammaCorrectValue(color[0]), - gammaCorrectValue(color[1]), - gammaCorrectValue(color[2])] + return [gammaCorrectValue(color[0]), gammaCorrectValue(color[1]), gammaCorrectValue(color[2])] + def gammaCorrectValue(u): - if u < 0.0031308: - y = u * 12.92 - else: - y = 1.055 * pow(u, (1/2.4)) - 0.055 + if u < 0.0031308: + y = u * 12.92 + else: + y = 1.055 * pow(u, (1 / 2.4)) - 0.055 + + return min(max(y, 0), 1) - return min(max(y, 0), 1) def gammaInverse(color): - return [ - gammaInverseValue(color[0]), - gammaInverseValue(color[1]), - gammaInverseValue(color[2])] + return [gammaInverseValue(color[0]), gammaInverseValue(color[1]), gammaInverseValue(color[2])] + def gammaInverseValue(u): - if u < 0.04045: - y = u / 12.92 - else: - y = ((u + 0.055) / 1.055) ** 2.4 + if u < 0.04045: + y = u / 12.92 + else: + y = ((u + 0.055) / 1.055) ** 2.4 + + return min(max(y, 0), 1) - return min(max(y, 0), 1) def printBlenderMessage(msgSet, message, blenderOp): - if blenderOp is not None: - blenderOp.report(msgSet, message) - else: - print(message) + if blenderOp is not None: + blenderOp.report(msgSet, message) + else: + print(message) + def bytesToInt(value): - return int.from_bytes(value, 'big') + return int.from_bytes(value, "big") -def bytesToHex(value, byteSize = 4): - return format(bytesToInt(value), '#0' + str(byteSize * 2 + 2) + 'x') -def bytesToHexClean(value, byteSize = 4): - return format(bytesToInt(value), '0' + str(byteSize * 2) + 'x') +def bytesToHex(value, byteSize=4): + return format(bytesToInt(value), "#0" + str(byteSize * 2 + 2) + "x") + + +def bytesToHexClean(value, byteSize=4): + return format(bytesToInt(value), "0" + str(byteSize * 2) + "x") + + +def intToHex(value, byteSize=4): + return format(value, "#0" + str(byteSize * 2 + 2) + "x") -def intToHex(value, byteSize = 4): - return format(value, '#0' + str(byteSize * 2 + 2) + 'x') def intToBytes(value, byteSize): - return bytes.fromhex(intToHex(value, byteSize)[2:]) + return bytes.fromhex(intToHex(value, byteSize)[2:]) + # byte input # returns an integer, usually used for file seeking positions def decodeSegmentedAddr(address, segmentData): - #print(bytesAsHex(address)) - if address[0] not in segmentData: - raise PluginError("Segment " + str(address[0]) + ' not found in segment list.') - segmentStart = segmentData[address[0]][0] - return segmentStart + bytesToInt(address[1:4]) + # print(bytesAsHex(address)) + if address[0] not in segmentData: + raise PluginError("Segment " + str(address[0]) + " not found in segment list.") + segmentStart = segmentData[address[0]][0] + return segmentStart + bytesToInt(address[1:4]) -#int input + +# int input # returns bytes, usually used for writing new segmented addresses def encodeSegmentedAddr(address, segmentData): - segment = getSegment(address, segmentData) - segmentStart = segmentData[segment][0] + segment = getSegment(address, segmentData) + segmentStart = segmentData[segment][0] + + segmentedAddr = address - segmentStart + return intToBytes(segment, 1) + intToBytes(segmentedAddr, 3) - segmentedAddr = address - segmentStart - return intToBytes(segment, 1) + intToBytes(segmentedAddr, 3) def getSegment(address, segmentData): - for segment, interval in segmentData.items(): - if address in range(*interval): - return segment + for segment, interval in segmentData.items(): + if address in range(*interval): + return segment + + raise PluginError("Address " + hex(address) + " is not found in any of the provided segments.") - raise PluginError("Address " + hex(address) + \ - " is not found in any of the provided segments.") # Position def readVectorFromShorts(command, offset): - return [readFloatFromShort(command, valueOffset) for valueOffset - in range(offset, offset + 6, 2)] + return [readFloatFromShort(command, valueOffset) for valueOffset in range(offset, offset + 6, 2)] + def readFloatFromShort(command, offset): - return int.from_bytes(command[offset: offset + 2], - 'big', signed = True) / bpy.context.scene.blenderToSM64Scale + return int.from_bytes(command[offset : offset + 2], "big", signed=True) / bpy.context.scene.blenderToSM64Scale + def writeVectorToShorts(command, offset, values): - for i in range(3): - valueOffset = offset + i * 2 - writeFloatToShort(command, valueOffset, values[i]) + for i in range(3): + valueOffset = offset + i * 2 + writeFloatToShort(command, valueOffset, values[i]) + def writeFloatToShort(command, offset, value): - command[offset : offset + 2] = \ - int(round(value * bpy.context.scene.blenderToSM64Scale)).to_bytes( - 2, 'big', signed = True) + command[offset : offset + 2] = int(round(value * bpy.context.scene.blenderToSM64Scale)).to_bytes( + 2, "big", signed=True + ) + def convertFloatToShort(value): - return int(round((value * bpy.context.scene.blenderToSM64Scale))) + return int(round((value * bpy.context.scene.blenderToSM64Scale))) + def convertEulerFloatToShort(value): - return int(round(degrees(value))) + return int(round(degrees(value))) + # Rotation @@ -1085,117 +1197,128 @@ def convertEulerFloatToShort(value): # Zero rotation starts at Z+ on an XZ plane and goes counterclockwise. # 2**16 - 1 is the last value before looping around again. def readEulerVectorFromShorts(command, offset): - return [readEulerFloatFromShort(command, valueOffset) for valueOffset - in range(offset, offset + 6, 2)] + return [readEulerFloatFromShort(command, valueOffset) for valueOffset in range(offset, offset + 6, 2)] + def readEulerFloatFromShort(command, offset): - return radians(int.from_bytes(command[offset: offset + 2], - 'big', signed = True)) + return radians(int.from_bytes(command[offset : offset + 2], "big", signed=True)) + def writeEulerVectorToShorts(command, offset, values): - for i in range(3): - valueOffset = offset + i * 2 - writeEulerFloatToShort(command, valueOffset, values[i]) + for i in range(3): + valueOffset = offset + i * 2 + writeEulerFloatToShort(command, valueOffset, values[i]) + def writeEulerFloatToShort(command, offset, value): - command[offset : offset + 2] = int(round(degrees(value))).to_bytes( - 2, 'big', signed = True) + command[offset : offset + 2] = int(round(degrees(value))).to_bytes(2, "big", signed=True) + # convert 32 bit (8888) to 16 bit (5551) color def convert32to16bitRGBA(oldPixel): - if oldPixel[3] > 127: - alpha = 1 - else: - alpha = 0 - newPixel = (oldPixel[0] >> 3) << 11 |\ - (oldPixel[1] >> 3) << 6 |\ - (oldPixel[2] >> 3) << 1 |\ - alpha - return newPixel.to_bytes(2, 'big') + if oldPixel[3] > 127: + alpha = 1 + else: + alpha = 0 + newPixel = (oldPixel[0] >> 3) << 11 | (oldPixel[1] >> 3) << 6 | (oldPixel[2] >> 3) << 1 | alpha + return newPixel.to_bytes(2, "big") + # convert normalized RGB values to bytes (0-255) def convertRGB(normalizedRGB): - return bytearray([ - int(normalizedRGB[0] * 255), - int(normalizedRGB[1] * 255), - int(normalizedRGB[2] * 255) - ]) + return bytearray([int(normalizedRGB[0] * 255), int(normalizedRGB[1] * 255), int(normalizedRGB[2] * 255)]) + + # convert normalized RGB values to bytes (0-255) def convertRGBA(normalizedRGBA): - return bytearray([ - int(normalizedRGBA[0] * 255), - int(normalizedRGBA[1] * 255), - int(normalizedRGBA[2] * 255), - int(normalizedRGBA[3] * 255) - ]) + return bytearray( + [ + int(normalizedRGBA[0] * 255), + int(normalizedRGBA[1] * 255), + int(normalizedRGBA[2] * 255), + int(normalizedRGBA[3] * 255), + ] + ) + def vector3ComponentMultiply(a, b): - return mathutils.Vector( - (a.x * b.x, a.y * b.y, a.z * b.z) - ) + return mathutils.Vector((a.x * b.x, a.y * b.y, a.z * b.z)) + # Position values are signed shorts. def convertPosition(position): - positionShorts = [int(floatValue) for floatValue in position] - F3DPosition = bytearray(0) - for shortData in [shortValue.to_bytes(2, 'big', signed=True) for shortValue in positionShorts]: - F3DPosition.extend(shortData) - return F3DPosition + positionShorts = [int(floatValue) for floatValue in position] + F3DPosition = bytearray(0) + for shortData in [shortValue.to_bytes(2, "big", signed=True) for shortValue in positionShorts]: + F3DPosition.extend(shortData) + return F3DPosition + # UVs in F3D are a fixed point short: s10.5 (hence the 2**5) # fixed point is NOT exponent+mantissa, it is integer+fraction def convertUV(normalizedUVs, textureWidth, textureHeight): - #print(str(normalizedUVs[0]) + " - " + str(normalizedUVs[1])) - F3DUVs = convertFloatToFixed16Bytes(normalizedUVs[0] * textureWidth) +\ - convertFloatToFixed16Bytes(normalizedUVs[1] * textureHeight) - return F3DUVs + # print(str(normalizedUVs[0]) + " - " + str(normalizedUVs[1])) + F3DUVs = convertFloatToFixed16Bytes(normalizedUVs[0] * textureWidth) + convertFloatToFixed16Bytes( + normalizedUVs[1] * textureHeight + ) + return F3DUVs + def convertFloatToFixed16Bytes(value): - value *= 2**5 - value = min(max(value, -2**15), 2**15 - 1) + value *= 2**5 + value = min(max(value, -(2**15)), 2**15 - 1) + + return int(round(value)).to_bytes(2, "big", signed=True) - return int(round(value)).to_bytes(2, 'big', signed = True) def convertFloatToFixed16(value): - return int(round(value * (2**5))) + return int(round(value * (2**5))) - # We want support for large textures with 32 bit UVs - #value *= 2**5 - #value = min(max(value, -2**15), 2**15 - 1) - #return int.from_bytes( - # int(round(value)).to_bytes(2, 'big', signed = True), 'big') + # We want support for large textures with 32 bit UVs + # value *= 2**5 + # value = min(max(value, -2**15), 2**15 - 1) + # return int.from_bytes( + # int(round(value)).to_bytes(2, 'big', signed = True), 'big') # Normal values are signed bytes (-128 to 127) # Normalized magnitude = 127 def convertNormal(normal): - F3DNormal = bytearray(0) - for axis in normal: - F3DNormal.extend(int(axis * 127).to_bytes(1, 'big', signed=True)) - return F3DNormal + F3DNormal = bytearray(0) + for axis in normal: + F3DNormal.extend(int(axis * 127).to_bytes(1, "big", signed=True)) + return F3DNormal + def byteMask(data, offset, amount): - return bitMask(data, offset * 8, amount * 8) + return bitMask(data, offset * 8, amount * 8) + + def bitMask(data, offset, amount): - return (~(-1 << amount) << offset & data) >> offset + return (~(-1 << amount) << offset & data) >> offset + def read16bitRGBA(data): - r = bitMask(data, 11, 5) / ((2**5) - 1) - g = bitMask(data, 6, 5) / ((2**5) - 1) - b = bitMask(data, 1, 5) / ((2**5) - 1) - a = bitMask(data, 0, 1) / ((2**1) - 1) + r = bitMask(data, 11, 5) / ((2**5) - 1) + g = bitMask(data, 6, 5) / ((2**5) - 1) + b = bitMask(data, 1, 5) / ((2**5) - 1) + a = bitMask(data, 0, 1) / ((2**1) - 1) - return [r,g,b,a] + return [r, g, b, a] + + +def join_c_args(args: "list[str]"): + return ", ".join(args) -def join_c_args(args: 'list[str]'): - return ', '.join(args) def translate_blender_to_n64(translate: mathutils.Vector): - return transform_mtx_blender_to_n64() @ translate + return transform_mtx_blender_to_n64() @ translate + def rotate_quat_blender_to_n64(rotation: mathutils.Quaternion): - new_rot = (transform_mtx_blender_to_n64() @ rotation.to_matrix().to_4x4() @ transform_mtx_blender_to_n64().inverted()) + new_rot = transform_mtx_blender_to_n64() @ rotation.to_matrix().to_4x4() @ transform_mtx_blender_to_n64().inverted() return new_rot.to_quaternion() + def all_values_equal_x(vals: Iterable, test): - return len(set(vals) - set([test])) == 0 + return len(set(vals) - set([test])) == 0 diff --git a/pyproject.toml b/pyproject.toml index 65c7367..3340c81 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,8 +6,7 @@ line-length = 120 target-version = [ - 'py37', # used by Blender 2.80 - 'py39', # used by Blender 3.0.1 + 'py310', # used by Blender 3.1 ] # What files to exclude when running Black on directories (for example `black .`)