From d00a07c99ddb031219a01242d08af26d88f1a87c Mon Sep 17 00:00:00 2001 From: Dragorn421 Date: Sat, 6 Jan 2024 01:12:17 +0100 Subject: [PATCH 1/2] black --- __init__.py | 6 +- fast64_internal/f3d/f3d_bleed.py | 46 +- fast64_internal/f3d/f3d_enums.py | 30 +- fast64_internal/f3d/f3d_gbi.py | 22 +- fast64_internal/f3d/f3d_generate_presets.py | 36 +- fast64_internal/f3d/f3d_material.py | 340 +++++---- fast64_internal/f3d/f3d_render_engine.py | 719 +++++++++--------- fast64_internal/f3d/f3d_writer.py | 86 ++- fast64_internal/f3d/flipbook.py | 1 + fast64_internal/f3d_material_converter.py | 2 +- fast64_internal/panels.py | 41 +- fast64_internal/render_settings.py | 518 +++++++------ .../sm64/c_templates/tile_scroll.py | 8 +- fast64_internal/sm64/parse_function_map.py | 19 +- fast64_internal/sm64/sm64_anim.py | 15 +- fast64_internal/sm64/sm64_collision.py | 3 +- fast64_internal/sm64/sm64_constants.py | 420 +++++----- .../sm64/sm64_geolayout_classes.py | 19 +- fast64_internal/sm64/sm64_geolayout_writer.py | 6 +- fast64_internal/sm64/sm64_objects.py | 4 +- fast64_internal/sm64/sm64_rom_tweaks.py | 1 - fast64_internal/sm64/sm64_texscroll.py | 2 - fast64_internal/sm64/sm64_utility.py | 22 +- fast64_internal/utility.py | 4 +- fast64_internal/utility_anim.py | 6 +- 25 files changed, 1231 insertions(+), 1145 deletions(-) diff --git a/__init__.py b/__init__.py index 86f79cd20..1ead79bbc 100644 --- a/__init__.py +++ b/__init__.py @@ -166,7 +166,11 @@ def draw(self, context): col.prop(context.scene, "generateF3DNodeGraph", text="Generate F3D Node Graph For Materials") col.prop(context.scene, "exportInlineF3D", text="Bleed and Inline Material Exports") if context.scene.exportInlineF3D: - multilineLabel(col.box(), "While inlining, all meshes will be restored to world default values.\n You can configure these values in the world properties tab.", icon="INFO") + multilineLabel( + col.box(), + "While inlining, all meshes will be restored to world default values.\n You can configure these values in the world properties tab.", + icon="INFO", + ) col.prop(context.scene, "decomp_compatible", invert_checkbox=True, text="Homebrew Compatibility") col.prop(context.scene, "ignoreTextureRestrictions") if context.scene.ignoreTextureRestrictions: diff --git a/fast64_internal/f3d/f3d_bleed.py b/fast64_internal/f3d/f3d_bleed.py index 95375b7a5..b1dbf2057 100644 --- a/fast64_internal/f3d/f3d_bleed.py +++ b/fast64_internal/f3d/f3d_bleed.py @@ -50,7 +50,6 @@ class BleedGraphics: - # bleed_state "enums" bleed_start = 1 bleed_in_progress = 2 @@ -126,7 +125,7 @@ def bleed_fModel(self, fModel: FModel, fMeshes: dict[FMesh]): # clear the gfx lists so they don't export def clear_gfx_lists(self, fModel: FModel): - for (fMaterial, texDimensions) in fModel.materials.values(): + for fMaterial, texDimensions in fModel.materials.values(): fMaterial.material.tag |= GfxListTag.NoExport if fMaterial.revert: fMaterial.revert.tag |= GfxListTag.NoExport @@ -134,10 +133,17 @@ def clear_gfx_lists(self, fModel: FModel): for tri_list in fMesh.triangleGroups: tri_list.triList.tag |= GfxListTag.NoExport - def bleed_fmesh(self, fMesh: FMesh, last_mat: FMaterial, cmd_list: GfxList, fmodel_materials, default_render_mode: list[str] = None): + def bleed_fmesh( + self, + fMesh: FMesh, + last_mat: FMaterial, + cmd_list: GfxList, + fmodel_materials, + default_render_mode: list[str] = None, + ): if bled_mat := self.bled_gfx_lists.get(cmd_list, None): return bled_mat - + bleed_state = self.bleed_start cur_fmat = None reset_cmd_dict = dict() @@ -169,7 +175,7 @@ def bleed_fmesh(self, fMesh: FMesh, last_mat: FMaterial, cmd_list: GfxList, fmod bleed_gfx_lists = BleedGfxLists() # set bleed state for cmd reverts bleed_state = self.bleed_in_progress - + last_mat = cur_fmat self.on_bleed_end(last_mat, cmd_list, fmesh_static_cmds, reset_cmd_dict, default_render_mode) return last_mat @@ -177,7 +183,7 @@ def bleed_fmesh(self, fMesh: FMesh, last_mat: FMaterial, cmd_list: GfxList, fmod def build_tmem_dict(self, cmd_list: GfxList): im_buffer = None tmem_dict = dict() - tile_dict = {i:0 for i in range(8)} # an assumption that hopefully never needs correction + tile_dict = {i: 0 for i in range(8)} # an assumption that hopefully never needs correction for cmd in cmd_list.commands: if type(cmd) == DPSetTextureImage: im_buffer = cmd @@ -188,7 +194,7 @@ def build_tmem_dict(self, cmd_list: GfxList): tmem_dict[tile_dict[cmd.tile]] = im_buffer continue return tmem_dict - + def bleed_textures(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): if last_mat: # bleed cmds if matching tile has duplicate cmds @@ -220,7 +226,7 @@ def bleed_textures(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: # now eval as normal conditionals for j, cmd in enumerate(cur_fmat.texture_DL.commands): if not cmd: - continue # some cmds are None from previous step + continue # some cmds are None from previous step if self.bleed_individual_cmd(commands_bled, cmd, bleed_state): if cmd in last_mat.texture_DL.commands: commands_bled.commands[j] = None @@ -252,9 +258,7 @@ def bleed_mat(self, cur_fmat: FMaterial, last_mat: FMaterial, bleed_state: int): commands_bled.commands.remove(SPEndDisplayList()) return commands_bled.commands - def bleed_tri_group( - self, tri_list: GfxList, cur_fmat: fMaterial, bleed_state: int - ): + def bleed_tri_group(self, tri_list: GfxList, cur_fmat: fMaterial, bleed_state: int): # remove SPEndDisplayList from triGroup while SPEndDisplayList() in tri_list.commands: tri_list.commands.remove(SPEndDisplayList()) @@ -281,7 +285,9 @@ def bleed_cmd_list(self, target_cmd_list: GfxList, bleed_state: int): return commands_bled # Put triGroup bleed gfx in the FMesh.draw object - def inline_triGroup(self, tri_list: GfxList, bleed_gfx_lists: BleedGfxLists, cmd_list: GfxList, reset_cmd_dict: dict[GbiMacro]): + def inline_triGroup( + self, tri_list: GfxList, bleed_gfx_lists: BleedGfxLists, cmd_list: GfxList, reset_cmd_dict: dict[GbiMacro] + ): # add material cmd_list.commands.extend(bleed_gfx_lists.bled_mats) # add textures @@ -329,7 +335,12 @@ def on_tri_group_bleed_end(self, triGroup: FTriGroup, last_mat: FMaterial, bleed return def on_bleed_end( - self, last_mat: FMaterial, cmd_list: GfxList, fmesh_static_cmds: list[GbiMacro], reset_cmd_dict: dict[GbiMacro], default_render_mode: list[str] = None + self, + last_mat: FMaterial, + cmd_list: GfxList, + fmesh_static_cmds: list[GbiMacro], + reset_cmd_dict: dict[GbiMacro], + default_render_mode: list[str] = None, ): # revert certain cmds for extra safety reset_cmds = self.create_reset_cmds(reset_cmd_dict, default_render_mode) @@ -338,14 +349,13 @@ def on_bleed_end( reset_cmds.remove(DPPipeSync) reset_cmds.insert(0, DPPipeSync) cmd_list.commands.extend(reset_cmds) - cmd_list.commands.extend(fmesh_static_cmds) # this is troublesome + cmd_list.commands.extend(fmesh_static_cmds) # this is troublesome cmd_list.commands.append(SPEndDisplayList()) self.bled_gfx_lists[cmd_list] = last_mat def create_reset_cmds(self, reset_cmd_dict: dict[GbiMacro], default_render_mode: list[str]): reset_cmds = [] for cmd_type, cmd_use in reset_cmd_dict.items(): - if cmd_type == DPPipeSync: reset_cmds.append(DPPipeSync()) @@ -493,7 +503,7 @@ def bleed_between_tris(self, cmd_list: GfxList, cmd: GbiMacro, bleed_state: int, class BleedGfxLists: bled_mats: GfxList = field(default_factory=list) bled_tex: GfxList = field(default_factory=list) - + @property def reset_command_dict(self): return { @@ -514,7 +524,7 @@ def add_reset_cmd(self, cmd: GbiMacro, reset_cmd_dict: dict[GbiMacro]): # separate other mode H and othermode L if type(cmd) == SPSetOtherMode: reset_cmd_dict[cmd.cmd] = cmd - + if type(cmd) in reset_cmd_list: reset_cmd_dict[type(cmd)] = cmd @@ -533,4 +543,4 @@ def find_material_from_jump_cmd( return bpy_material, fmaterial elif fmaterial.material == dl_jump.displayList: return bpy_material, fmaterial - return None, None \ No newline at end of file + return None, None diff --git a/fast64_internal/f3d/f3d_enums.py b/fast64_internal/f3d/f3d_enums.py index e17f108c1..452408c52 100644 --- a/fast64_internal/f3d/f3d_enums.py +++ b/fast64_internal/f3d/f3d_enums.py @@ -392,18 +392,38 @@ ] enumCelThreshMode = [ - ("Lighter", "Lighter", "This cel level is drawn when the lighting level per-pixel is LIGHTER than (>=) the threshold"), + ( + "Lighter", + "Lighter", + "This cel level is drawn when the lighting level per-pixel is LIGHTER than (>=) the threshold", + ), ("Darker", "Darker", "This cel level is drawn when the lighting level per-pixel is DARKER than (<) the threshold"), ] enumCelTintPipeline = [ - ("CC", "CC (tint in Prim Color)", "Cel shading puts tint color in Prim Color and tint level in Prim Alpha. Set up CC color to LERP between source color and tint color based on tint level, or multiply source color by tint color. Source may be Tex 0 or Env Color"), - ("Blender", "Blender (tint in Fog Color)", "Cel shading puts tint color in Fog Color and tint level in Fog Alpha. Set up blender to LERP between CC output and tint color based on tint level. Then set CC to Tex 0 * shade color (vertex colors)"), + ( + "CC", + "CC (tint in Prim Color)", + "Cel shading puts tint color in Prim Color and tint level in Prim Alpha. Set up CC color to LERP between source color and tint color based on tint level, or multiply source color by tint color. Source may be Tex 0 or Env Color", + ), + ( + "Blender", + "Blender (tint in Fog Color)", + "Cel shading puts tint color in Fog Color and tint level in Fog Alpha. Set up blender to LERP between CC output and tint color based on tint level. Then set CC to Tex 0 * shade color (vertex colors)", + ), ] enumCelCutoutSource = [ - ("TEXEL0", "Texture 0", "Cel shading material has binary alpha cutout from Texture 0 alpha. Does not work with I4 or I8 formats"), - ("TEXEL1", "Texture 1", "Cel shading material has binary alpha cutout from Texture 1 alpha. Does not work with I4 or I8 formats"), + ( + "TEXEL0", + "Texture 0", + "Cel shading material has binary alpha cutout from Texture 0 alpha. Does not work with I4 or I8 formats", + ), + ( + "TEXEL1", + "Texture 1", + "Cel shading material has binary alpha cutout from Texture 1 alpha. Does not work with I4 or I8 formats", + ), ("ENVIRONMENT", "None / Env Alpha", "Make sure your material writes env color, and set env alpha to opaque (255)"), ] diff --git a/fast64_internal/f3d/f3d_gbi.py b/fast64_internal/f3d/f3d_gbi.py index 24b2de723..04a476bf0 100644 --- a/fast64_internal/f3d/f3d_gbi.py +++ b/fast64_internal/f3d/f3d_gbi.py @@ -29,11 +29,10 @@ class GfxListTag(enum.IntFlag): MaterialRevert = 4 Draw = 4 NoExport = 16 - + @property def Export(self): return not self & GfxListTag.NoExport - class GfxTag(enum.Flag): @@ -2938,7 +2937,7 @@ def set_addr(self, startAddress, f3d): def save_binary(self, romfile, f3d, segments): for celTriList in self.celTriLists: - celTriList.save_binary(romfile, f3d, segments); + celTriList.save_binary(romfile, f3d, segments) self.triList.save_binary(romfile, f3d, segments) self.vertexList.save_binary(romfile) @@ -3779,9 +3778,7 @@ class SPAmbOcclusionAmbDir(GbiMacro): def to_binary(self, f3d, segments): if not f3d.F3DEX_GBI_3: raise PluginError("SPAmbOcclusionAmbDir requires F3DEX3 microcode") - return gsMoveWd( - f3d.G_MW_FX, f3d.G_MWO_AO_AMBIENT, (_SHIFTL(self.amb, 16, 16) | _SHIFTL(self.dir, 0, 16)), f3d - ) + return gsMoveWd(f3d.G_MW_FX, f3d.G_MWO_AO_AMBIENT, (_SHIFTL(self.amb, 16, 16) | _SHIFTL(self.dir, 0, 16)), f3d) @dataclass(unsafe_hash=True) @@ -3808,8 +3805,9 @@ class SPAmbOcclusion(GbiMacro): def to_binary(self, f3d, segments): if not f3d.F3DEX_GBI_3: raise PluginError("SPAmbOcclusion requires F3DEX3 microcode") - return SPAmbOcclusionAmbDir(self.amb, self.dir).to_binary(f3d, segments) + \ - SPAmbOcclusionPoint(self.point).to_binary(f3d, segments) + return SPAmbOcclusionAmbDir(self.amb, self.dir).to_binary(f3d, segments) + SPAmbOcclusionPoint( + self.point + ).to_binary(f3d, segments) @dataclass(unsafe_hash=True) @@ -3820,9 +3818,7 @@ class SPFresnelScale(GbiMacro): def to_binary(self, f3d, segments): if not f3d.F3DEX_GBI_3: raise PluginError("SPFresnelScale requires F3DEX3 microcode") - return gsMoveHalfwd( - f3d.G_MW_FX, f3d.G_MWO_FRESNEL_SCALE, self.scale, f3d - ) + return gsMoveHalfwd(f3d.G_MW_FX, f3d.G_MWO_FRESNEL_SCALE, self.scale, f3d) @dataclass(unsafe_hash=True) @@ -3833,9 +3829,7 @@ class SPFresnelOffset(GbiMacro): def to_binary(self, f3d, segments): if not f3d.F3DEX_GBI_3: raise PluginError("SPFresnelOffset requires F3DEX3 microcode") - return gsMoveHalfwd( - f3d.G_MW_FX, f3d.G_MWO_FRESNEL_OFFSET, self.offset, f3d - ) + return gsMoveHalfwd(f3d.G_MW_FX, f3d.G_MWO_FRESNEL_OFFSET, self.offset, f3d) @dataclass(unsafe_hash=True) diff --git a/fast64_internal/f3d/f3d_generate_presets.py b/fast64_internal/f3d/f3d_generate_presets.py index f5d381e3e..98c16ef1e 100644 --- a/fast64_internal/f3d/f3d_generate_presets.py +++ b/fast64_internal/f3d/f3d_generate_presets.py @@ -1,29 +1,29 @@ import os -basePath = 'presets/f3d' -data = '' +basePath = "presets/f3d" +data = "" presetList = "material_presets = {\n" for subdir in os.listdir(basePath): - subPath = os.path.join(basePath, subdir) - if subdir != '__pycache__' and subdir != 'user' and os.path.isdir(subPath): - presetList += '\t"' + subdir + '" : {\n' - for filename in os.listdir(subPath): - presetPath = os.path.join(subPath, filename) - if os.path.isfile(presetPath): - print(presetPath) - presetFile = open(presetPath, 'r') - presetData = presetFile.read() - presetFile.close() + subPath = os.path.join(basePath, subdir) + if subdir != "__pycache__" and subdir != "user" and os.path.isdir(subPath): + presetList += '\t"' + subdir + '" : {\n' + for filename in os.listdir(subPath): + presetPath = os.path.join(subPath, filename) + if os.path.isfile(presetPath): + print(presetPath) + presetFile = open(presetPath, "r") + presetData = presetFile.read() + presetFile.close() - data += filename[:-3] + " = '''\n" + presetData + "'''\n\n" - presetList += '\t\t"' + filename[:-3] + '" : ' + filename[:-3] + ',\n' - presetList += '\t},\n' + data += filename[:-3] + " = '''\n" + presetData + "'''\n\n" + presetList += '\t\t"' + filename[:-3] + '" : ' + filename[:-3] + ",\n" + presetList += "\t},\n" -presetList += '}\n' +presetList += "}\n" data += presetList -outFile = open('f3d_material_presets.py', 'w') +outFile = open("f3d_material_presets.py", "w") outFile.write(data) -outFile.close() \ No newline at end of file +outFile.close() diff --git a/fast64_internal/f3d/f3d_material.py b/fast64_internal/f3d/f3d_material.py index f5c20ae7e..da1794e50 100644 --- a/fast64_internal/f3d/f3d_material.py +++ b/fast64_internal/f3d/f3d_material.py @@ -275,7 +275,7 @@ def getZMode(material: Material): f3d = get_F3D_GBI() zmode = ((r1 | r2) & f3d.ZMODE_DEC) // f3d.ZMODE_INTER return enumZMode[zmode][0] - + class DrawLayerProperty(PropertyGroup): sm64: bpy.props.EnumProperty(items=sm64EnumDrawLayers, default="1", update=update_draw_layer) @@ -333,11 +333,11 @@ def F3DOrganizeLights(self, context): def combiner_uses( f3dMat: "F3DMaterialProperty", checkList, - checkCycle1 = True, - checkCycle2 = True, - checkColor = True, - checkAlpha = True, - swapTexelsCycle2 = True, + checkCycle1=True, + checkCycle2=True, + checkColor=True, + checkAlpha=True, + swapTexelsCycle2=True, ): is2Cycle = f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" for i in range(1, 3): @@ -376,21 +376,12 @@ def all_combiner_uses(f3d_mat: "F3DMaterialProperty") -> dict[str, bool]: f3d_mat, ["PRIMITIVE", "PRIMITIVE_ALPHA", "PRIM_LOD_FRAC"], ), - "Environment": combiner_uses( - f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"] - ), - "Shade": combiner_uses( - f3d_mat, ["SHADE"], checkAlpha = False - ), - "Shade Alpha": combiner_uses( - f3d_mat, ["SHADE"], checkColor = False - ) or combiner_uses( - f3d_mat, ["SHADE_ALPHA"], checkAlpha = False - ), + "Environment": combiner_uses(f3d_mat, ["ENVIRONMENT", "ENV_ALPHA"]), + "Shade": combiner_uses(f3d_mat, ["SHADE"], checkAlpha=False), + "Shade Alpha": combiner_uses(f3d_mat, ["SHADE"], checkColor=False) + or combiner_uses(f3d_mat, ["SHADE_ALPHA"], checkAlpha=False), "Key": combiner_uses(f3d_mat, ["CENTER", "SCALE"]), - "LOD Fraction": combiner_uses( - f3d_mat, ["LOD_FRACTION"] - ), + "LOD Fraction": combiner_uses(f3d_mat, ["LOD_FRACTION"]), "Convert": combiner_uses(f3d_mat, ["K4", "K5"]), } return useDict @@ -462,7 +453,7 @@ def indentGroup(parent: UILayout, textOrProp: Union[str, "F3DMaterialProperty"], c = indentGroup(inputGroup, f"Shade color = {shadeColorLabel}:", True) c.prop(settings, "g_fresnel_color") else: - inputGroup.column().label(text = f"Shade color = {shadeColorLabel}") + inputGroup.column().label(text=f"Shade color = {shadeColorLabel}") shadowMapInShadeAlpha = False if settings.g_fog: @@ -825,19 +816,23 @@ def ui_lower_render_mode(self, material, layout, useDropdown): if material.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE": if ( - material.rdp_settings.blend_b1 == "G_BL_A_MEM" or - material.rdp_settings.blend_p1 == "G_BL_CLR_MEM" or - material.rdp_settings.blend_m1 == "G_BL_CLR_MEM" + material.rdp_settings.blend_b1 == "G_BL_A_MEM" + or material.rdp_settings.blend_p1 == "G_BL_CLR_MEM" + or material.rdp_settings.blend_m1 == "G_BL_CLR_MEM" ): - multilineLabel(renderGroup.box(), - "RDP silicon bug: Framebuffer color / alpha in blender\n" + - "cycle 1 is broken, actually value from PREVIOUS pixel.", - 'ORPHAN_DATA') + multilineLabel( + renderGroup.box(), + "RDP silicon bug: Framebuffer color / alpha in blender\n" + + "cycle 1 is broken, actually value from PREVIOUS pixel.", + "ORPHAN_DATA", + ) if material.rdp_settings.blend_a2 == "G_BL_A_SHADE": - multilineLabel(renderGroup.box(), - "RDP silicon bug: Shade alpha in blender cycle 2\n" + - "is broken, actually shade alpha from NEXT pixel.", - 'ORPHAN_DATA') + multilineLabel( + renderGroup.box(), + "RDP silicon bug: Shade alpha in blender cycle 2\n" + + "is broken, actually shade alpha from NEXT pixel.", + "ORPHAN_DATA", + ) # cycle dependent - (P * A + M - B) / (A + B) combinerBox = renderGroup.box() @@ -933,9 +928,9 @@ def ui_cel_shading(self, material: Material, layout: UILayout): material.f3d_mat, "expand_cel_shading_ui", text="", - icon='TRIA_DOWN' if material.f3d_mat.expand_cel_shading_ui else 'TRIA_RIGHT', + icon="TRIA_DOWN" if material.f3d_mat.expand_cel_shading_ui else "TRIA_RIGHT", icon_only=True, - emboss=False + emboss=False, ) r.prop(material.f3d_mat, "use_cel_shading") if not material.f3d_mat.expand_cel_shading_ui: @@ -946,37 +941,37 @@ def ui_cel_shading(self, material: Material, layout: UILayout): cel = material.f3d_mat.cel_shading prop_split(inputGroup.row(), cel, "tintPipeline", "Tint pipeline:") prop_split(inputGroup.row(), cel, "cutoutSource", "Cutout:") - + if getZMode(material) != "ZMODE_OPA": - inputGroup.label(text = "zmode in blender / rendermode must be opaque.", icon = "ERROR") + inputGroup.label(text="zmode in blender / rendermode must be opaque.", icon="ERROR") if cel.cutoutSource == "ENVIRONMENT": if not material.f3d_mat.set_env or material.f3d_mat.env_color[3] != 1.0: - inputGroup.label(text = "Enable env color, and set env alpha to 255.", icon = "ERROR") + inputGroup.label(text="Enable env color, and set env alpha to 255.", icon="ERROR") else: tex = material.f3d_mat.tex0 if cel.cutoutSource == "TEXEL0" else material.f3d_mat.tex1 if tex.tex is None or not tex.tex_set: - inputGroup.label(text = f"Texture {cel.cutoutSource[5]} is not set up correctly.", icon = "ERROR") - + inputGroup.label(text=f"Texture {cel.cutoutSource[5]} is not set up correctly.", icon="ERROR") + if ( - len(cel.levels) >= 3 and - cel.levels[0].threshMode == cel.levels[1].threshMode and - not all([cel.levels[0].threshMode == lvl.threshMode for lvl in cel.levels[1:]]) + len(cel.levels) >= 3 + and cel.levels[0].threshMode == cel.levels[1].threshMode + and not all([cel.levels[0].threshMode == lvl.threshMode for lvl in cel.levels[1:]]) ): - multilineLabel(inputGroup.box(), - "If using both lighter and darker cel\n" + - "levels, one of each must be at the beginning", - "ERROR" + multilineLabel( + inputGroup.box(), + "If using both lighter and darker cel\n" + "levels, one of each must be at the beginning", + "ERROR", ) - + r = inputGroup.row(align=True) r.label(text="Cel levels:") - op = r.operator(CelLevelAdd.bl_idname, text="", icon='ADD') + op = r.operator(CelLevelAdd.bl_idname, text="", icon="ADD") op.materialName = material.name if len(cel.levels) > 0: - op = r.operator(CelLevelRemove.bl_idname, text="", icon='REMOVE') + op = r.operator(CelLevelRemove.bl_idname, text="", icon="REMOVE") op.materialName = material.name - + showSegHelp = False for level in cel.levels: box = inputGroup.box().column() @@ -1008,13 +1003,13 @@ def ui_cel_shading(self, material: Material, layout: UILayout): raise PluginError("Invalid tintType") if showSegHelp: tintName, tintNameCap = ("prim", "Prim") if cel.tintPipeline == "CC" else ("fog", "Fog") - multilineLabel(inputGroup, - "Segments: In your code, set up DL in segment(s) used with\n" + - f"gsDPSet{tintNameCap}Color then gsSPEndDisplayList at appropriate offset\n" + - f"with {tintName} color = tint color and {tintName} alpha = tint level.", - 'INFO' + multilineLabel( + inputGroup, + "Segments: In your code, set up DL in segment(s) used with\n" + + f"gsDPSet{tintNameCap}Color then gsSPEndDisplayList at appropriate offset\n" + + f"with {tintName} color = tint color and {tintName} alpha = tint level.", + "INFO", ) - def checkDrawLayersWarnings(self, f3dMat: "F3DMaterialProperty", useDict: Dict[str, bool], layout: UILayout): settings = f3dMat.rdp_settings @@ -1117,8 +1112,8 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl ui.enabled = enabled for letter in ["A", "B", "C", "D"]: r = ui.row().split(factor=0.25 if isAlpha else 0.1) - r.label(text = f"{letter}{' Alpha' if isAlpha else ''}:") - r.prop(combiner, f"{letter}{'_alpha' if isAlpha else ''}", text="") + r.label(text=f"{letter}{' Alpha' if isAlpha else ''}:") + r.prop(combiner, f"{letter}{'_alpha' if isAlpha else ''}", text="") isTwoCycle = f3dMat.rdp_settings.g_mdsft_cycletype == "G_CYC_2CYCLE" @@ -1129,7 +1124,9 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl drawCCProps(combinerCol, f3dMat.combiner1, False) drawCCProps(combinerCol, f3dMat.combiner1, True, not f3dMat.use_cel_shading) if f3dMat.use_cel_shading: - r = combinerBox.column().label(text = f"CC alpha{' cycle 1' if isTwoCycle else ''} is occupied by cel shading.") + r = combinerBox.column().label( + text=f"CC alpha{' cycle 1' if isTwoCycle else ''} is occupied by cel shading." + ) if isTwoCycle: combinerBox2 = layout.box() @@ -1139,11 +1136,15 @@ def drawCCProps(ui: UILayout, combiner: "CombinerProperty", isAlpha: bool, enabl drawCCProps(combinerCol2, f3dMat.combiner2, False) drawCCProps(combinerCol2, f3dMat.combiner2, True) - if combiner_uses(f3dMat, ["TEXEL0", "TEXEL0_ALPHA"], checkCycle1 = False, swapTexelsCycle2 = False): - combinerBox2.label(text = "'Texture 0' in Cycle 2 is actually Texture 1.", icon = "INFO") - if combiner_uses(f3dMat, ["TEXEL1", "TEXEL1_ALPHA"], checkCycle1 = False, swapTexelsCycle2 = False): - multilineLabel(combinerBox2, "RDP silicon bug: 'Texture 1' in Cycle 2 is actually\n" - + "Texture 0 for the NEXT pixel, causes visual issues.", "ORPHAN_DATA") + if combiner_uses(f3dMat, ["TEXEL0", "TEXEL0_ALPHA"], checkCycle1=False, swapTexelsCycle2=False): + combinerBox2.label(text="'Texture 0' in Cycle 2 is actually Texture 1.", icon="INFO") + if combiner_uses(f3dMat, ["TEXEL1", "TEXEL1_ALPHA"], checkCycle1=False, swapTexelsCycle2=False): + multilineLabel( + combinerBox2, + "RDP silicon bug: 'Texture 1' in Cycle 2 is actually\n" + + "Texture 0 for the NEXT pixel, causes visual issues.", + "ORPHAN_DATA", + ) if menuTab == "Sources": self.ui_uvCheck(layout, context) @@ -1222,23 +1223,25 @@ def draw(self, context): row.operator(AddPresetF3D.bl_idname, text="", icon="REMOVE").remove_active = True if settings.g_mdsft_alpha_compare == "G_AC_THRESHOLD" and settings.g_mdsft_cycletype == "G_CYC_2CYCLE": - multilineLabel(layout.box(), - "RDP silicon bug: Alpha compare in 2-cycle mode is broken.\n" + - "Compares to FIRST cycle CC alpha output from NEXT pixel.", - 'ORPHAN_DATA') + multilineLabel( + layout.box(), + "RDP silicon bug: Alpha compare in 2-cycle mode is broken.\n" + + "Compares to FIRST cycle CC alpha output from NEXT pixel.", + "ORPHAN_DATA", + ) if context.scene.f3d_simple and f3dMat.presetName != "Custom": self.draw_simple(f3dMat, material, layout, context) else: presetCol.prop(context.scene, "f3dUserPresetsOnly") self.draw_full(f3dMat, material, layout, context) - + if context.scene.f3d_type == "F3DEX3": self.ui_cel_shading(material, layout) else: r = layout.row() r.enabled = False - r.label(text="Use Cel Shading (requires F3DEX3)", icon='TRIA_RIGHT') + r.label(text="Use Cel Shading (requires F3DEX3)", icon="TRIA_RIGHT") def ui_tileScroll(tex, name, layout): @@ -1359,14 +1362,12 @@ def update_cel_cutout_source(self, context): return if not material.f3d_mat.use_cel_shading: return - + f3dMat = material.f3d_mat cel = f3dMat.cel_shading firstDarker = len(cel.levels) >= 1 and cel.levels[0].threshMode == "Darker" - - f3dMat.combiner1.A_alpha, f3dMat.combiner1.B_alpha = ( - ("1", "SHADE") if firstDarker else ("SHADE", "0") - ) + + f3dMat.combiner1.A_alpha, f3dMat.combiner1.B_alpha = ("1", "SHADE") if firstDarker else ("SHADE", "0") f3dMat.combiner1.C_alpha = cel.cutoutSource f3dMat.combiner1.D_alpha = "0" @@ -2116,9 +2117,9 @@ def createOrUpdateSceneProperties(): if upgrade_group and group: # Need to upgrade; remove old outputs - if bpy.app.version >= (4,0,0): + if bpy.app.version >= (4, 0, 0): for item in group.interface.items_tree: - if item.item_type == 'SOCKET' and item.in_out == 'OUTPUT': + if item.item_type == "SOCKET" and item.in_out == "OUTPUT": group.interface.remove(item) else: for out in group.outputs: @@ -2152,8 +2153,12 @@ def createOrUpdateSceneProperties(): _nodeBlender_Game_Scale: NodeSocketFloat = tree_interface.new_socket( "Blender_Game_Scale", socket_type="NodeSocketFloat", in_out="OUTPUT" ) - _nodeFogNear: NodeSocketFloat = tree_interface.new_socket("FogNear", socket_type="NodeSocketFloat", in_out="OUTPUT") - _nodeFogFar: NodeSocketFloat = tree_interface.new_socket("FogFar", socket_type="NodeSocketFloat", in_out="OUTPUT") + _nodeFogNear: NodeSocketFloat = tree_interface.new_socket( + "FogNear", socket_type="NodeSocketFloat", in_out="OUTPUT" + ) + _nodeFogFar: NodeSocketFloat = tree_interface.new_socket( + "FogFar", socket_type="NodeSocketFloat", in_out="OUTPUT" + ) _nodeShadeColor: NodeSocketColor = tree_interface.new_socket( "ShadeColor", socket_type="NodeSocketColor", in_out="OUTPUT" ) @@ -2163,7 +2168,7 @@ def createOrUpdateSceneProperties(): _nodeLightDirection: NodeSocketVector = tree_interface.new_socket( "LightDirection", socket_type="NodeSocketVector", in_out="OUTPUT" ) - + else: _nodeFogEnable: NodeSocketInt = new_group.outputs.new("NodeSocketInt", "FogEnable") _nodeFogColor: NodeSocketColor = new_group.outputs.new("NodeSocketColor", "FogColor") @@ -3270,66 +3275,63 @@ def draw(self, context): class CelLevelProperty(PropertyGroup): - threshMode : bpy.props.EnumProperty( - items = enumCelThreshMode, - name = "Draw when", - default = "Lighter", - update = update_cel_cutout_source - ) - threshold : bpy.props.IntProperty( - name = "Threshold", - description = "Light level at which the boundary between cel levels occurs. One level is >= this value, the other is < it", - min = 2, - max = 255, - default = 128 - ) - tintType : bpy.props.EnumProperty(items = enumCelTintType, name = "Tint type", default = "Fixed") - tintFixedLevel : bpy.props.IntProperty( - name = "Level", - description = "0: original color <=> 255: fully tint color", - min = 0, - max = 255, - default = 50, - ) - tintFixedColor : bpy.props.FloatVectorProperty( - name = "Tint color", - size = 3, - min = 0.0, - max = 1.0, - subtype = "COLOR", - ) - tintSegmentNum : bpy.props.IntProperty( - name = "Segment", - description = "Segment number to store tint DL in", - min = 8, - max = 0xD, - default = 8, - ) - tintSegmentOffset : bpy.props.IntProperty( - name = "Offset (instr)", - description = "Number of instructions (8 bytes) within this DL to jump to", - min = 0, - max = 1000, - default = 0, - ) - tintLightSlot : bpy.props.IntProperty( - name = "Light (/end)", - description = "Which light to load RGB color from, counting from the end. 0 = ambient, 1 = last directional / point light, 2 = second-to-last, etc.", - min = 0, - max = 9, - default = 1, - ) - - + threshMode: bpy.props.EnumProperty( + items=enumCelThreshMode, name="Draw when", default="Lighter", update=update_cel_cutout_source + ) + threshold: bpy.props.IntProperty( + name="Threshold", + description="Light level at which the boundary between cel levels occurs. One level is >= this value, the other is < it", + min=2, + max=255, + default=128, + ) + tintType: bpy.props.EnumProperty(items=enumCelTintType, name="Tint type", default="Fixed") + tintFixedLevel: bpy.props.IntProperty( + name="Level", + description="0: original color <=> 255: fully tint color", + min=0, + max=255, + default=50, + ) + tintFixedColor: bpy.props.FloatVectorProperty( + name="Tint color", + size=3, + min=0.0, + max=1.0, + subtype="COLOR", + ) + tintSegmentNum: bpy.props.IntProperty( + name="Segment", + description="Segment number to store tint DL in", + min=8, + max=0xD, + default=8, + ) + tintSegmentOffset: bpy.props.IntProperty( + name="Offset (instr)", + description="Number of instructions (8 bytes) within this DL to jump to", + min=0, + max=1000, + default=0, + ) + tintLightSlot: bpy.props.IntProperty( + name="Light (/end)", + description="Which light to load RGB color from, counting from the end. 0 = ambient, 1 = last directional / point light, 2 = second-to-last, etc.", + min=0, + max=9, + default=1, + ) + + class CelShadingProperty(PropertyGroup): - tintPipeline : bpy.props.EnumProperty(items = enumCelTintPipeline, name = "Tint pipeline", default = "CC") - cutoutSource : bpy.props.EnumProperty( - items = enumCelCutoutSource, - name = "Cutout", - default = "ENVIRONMENT", - update = update_cel_cutout_source, + tintPipeline: bpy.props.EnumProperty(items=enumCelTintPipeline, name="Tint pipeline", default="CC") + cutoutSource: bpy.props.EnumProperty( + items=enumCelCutoutSource, + name="Cutout", + default="ENVIRONMENT", + update=update_cel_cutout_source, ) - levels : bpy.props.CollectionProperty(type = CelLevelProperty, name = "Cel levels") + levels: bpy.props.CollectionProperty(type=CelLevelProperty, name="Cel levels") def celGetMaterialLevels(materialName): @@ -3342,27 +3344,27 @@ def celGetMaterialLevels(materialName): class CelLevelAdd(bpy.types.Operator): bl_idname = "material.f3d_cel_level_add" bl_label = "Add Cel Level" - bl_options = {'REGISTER', 'UNDO'} - - materialName : bpy.props.StringProperty() - + bl_options = {"REGISTER", "UNDO"} + + materialName: bpy.props.StringProperty() + def execute(self, context): levels = celGetMaterialLevels(self.materialName) levels.add() - return {'FINISHED'} + return {"FINISHED"} class CelLevelRemove(bpy.types.Operator): bl_idname = "material.f3d_cel_level_remove" bl_label = "Remove Last Level" - bl_options = {'REGISTER', 'UNDO'} - - materialName : bpy.props.StringProperty() - + bl_options = {"REGISTER", "UNDO"} + + materialName: bpy.props.StringProperty() + def execute(self, context): levels = celGetMaterialLevels(self.materialName) levels.remove(len(levels) - 1) - return {'FINISHED'} + return {"FINISHED"} def getOptimalFormat(tex, curFormat, isMultitexture): @@ -4097,9 +4099,9 @@ class F3DMaterialProperty(PropertyGroup): use_large_textures: bpy.props.BoolProperty(name="Large Texture Mode") large_edges: bpy.props.EnumProperty(items=enumLargeEdges, default="Clamp") - expand_cel_shading_ui : bpy.props.BoolProperty(name = "Expand Cel Shading UI") - use_cel_shading : bpy.props.BoolProperty(name = "Use Cel Shading", update = update_cel_cutout_source) - cel_shading : bpy.props.PointerProperty(type = CelShadingProperty) + expand_cel_shading_ui: bpy.props.BoolProperty(name="Expand Cel Shading UI") + use_cel_shading: bpy.props.BoolProperty(name="Use Cel Shading", update=update_cel_cutout_source) + cel_shading: bpy.props.PointerProperty(type=CelShadingProperty) def key(self) -> F3DMaterialHash: useDefaultLighting = self.set_lights and self.use_default_lighting @@ -4116,16 +4118,23 @@ def key(self) -> F3DMaterialHash: self.use_large_textures, self.use_cel_shading, self.cel_shading.tintPipeline if self.use_cel_shading else None, - tuple([( - c.threshMode, - c.threshold, - c.tintType, - c.tintFixedLevel, - c.tintFixedColor, - c.tintSegmentNum, - c.tintSegmentOffset, - c.tintLightSlot - ) for c in self.cel_shading.levels]) if self.use_cel_shading else None, + tuple( + [ + ( + c.threshMode, + c.threshold, + c.tintType, + c.tintFixedLevel, + c.tintFixedColor, + c.tintSegmentNum, + c.tintSegmentOffset, + c.tintLightSlot, + ) + for c in self.cel_shading.levels + ] + ) + if self.use_cel_shading + else None, self.use_default_lighting, self.set_blend, self.set_prim, @@ -4151,7 +4160,9 @@ def key(self) -> F3DMaterialHash: round(self.k5, 4) if self.set_k0_5 else None, self.combiner1.key() if self.set_combiner else None, self.combiner2.key() if self.set_combiner else None, - tuple([round(value, 4) for value in (self.ao_ambient, self.ao_directional, self.ao_point)]) if self.set_ao else None, + tuple([round(value, 4) for value in (self.ao_ambient, self.ao_directional, self.ao_point)]) + if self.set_ao + else None, tuple([round(value, 4) for value in (self.fresnel_lo, self.fresnel_hi)]) if self.set_fresnel else None, tuple([round(value, 4) for value in self.attroffs_st]) if self.set_attroffs_st else None, self.attroffs_z if self.set_attroffs_z else None, @@ -4403,7 +4414,10 @@ def mat_register(): ) Object.ignore_render = bpy.props.BoolProperty(name="Ignore Render") Object.ignore_collision = bpy.props.BoolProperty(name="Ignore Collision") - Object.bleed_independently = bpy.props.BoolProperty(name="Bleed Independently", description="While bleeding, this object will not inherit properties from previously drawn meshes in the drawing graph") + Object.bleed_independently = bpy.props.BoolProperty( + name="Bleed Independently", + description="While bleeding, this object will not inherit properties from previously drawn meshes in the drawing graph", + ) Object.f3d_lod_z = bpy.props.IntProperty( name="F3D LOD Z", min=1, diff --git a/fast64_internal/f3d/f3d_render_engine.py b/fast64_internal/f3d/f3d_render_engine.py index 15376d7a7..51442a71f 100644 --- a/fast64_internal/f3d/f3d_render_engine.py +++ b/fast64_internal/f3d/f3d_render_engine.py @@ -1,9 +1,9 @@ import bpy, math, time -from mathutils import * -from bgl import * +from mathutils import * +from bgl import * from bpy.utils import register_class, unregister_class -vertexShader = ''' +vertexShader = """ #version 330 core layout (location = 0) in vec3 pos; layout (location = 1) in vec2 uv; @@ -18,9 +18,9 @@ gl_Position = transform * vec4(pos, 1.0); // see how we directly give a vec3 to vec4's constructor vertexColor = vec4(0.5, 0.0, 0.0, 1.0); // set the output variable to a dark-red color } -''' +""" -fragmentShader = ''' +fragmentShader = """ #version 330 core out vec4 color; @@ -30,342 +30,352 @@ { color = vertexColor; } -''' +""" + class F3DRenderEngine(bpy.types.RenderEngine): + bl_idname = "f3d_renderer" + bl_label = "Fast3D" + use_preview = True + + # Init is called whenever a new render engine instance is created. Multiple + # instances may exist at the same time, for example for a viewport and final + # render. + def __init__(self): + self.draw_data = F3DDrawData() + self.first_time = False + + # When the render engine instance is destroy, this is called. Clean up any + # render engine data here, for example stopping running render threads. + def __del__(self): + pass + + # This is the method called by Blender for both final renders (F12) and + # small preview for materials, world and lights. + def render(self, depsgraph): + scene = depsgraph.scene + scale = scene.render.resolution_percentage / 100.0 + self.size_x = int(scene.render.resolution_x * scale) + self.size_y = int(scene.render.resolution_y * scale) + + # Fill the render result with a flat color. The framebuffer is + # defined as a list of pixels, each pixel itself being a list of + # R,G,B,A values. + if self.is_preview: + color = [0.1, 0.2, 0.1, 1.0] + else: + color = [0.2, 0.1, 0.1, 1.0] + + pixel_count = self.size_x * self.size_y + rect = [color] * pixel_count + + # Here we write the pixel values to the RenderResult + result = self.begin_result(0, 0, self.size_x, self.size_y) + layer = result.layers[0].passes["Combined"] + layer.rect = rect + self.end_result(result) + + # For viewport renders, this method gets called once at the start and + # whenever the scene or 3D viewport changes. This method is where data + # should be read from Blender in the same thread. Typically a render + # thread will be started to do the work while keeping Blender responsive. + + # Not called when viewport camera transform changes. + def view_update(self, context, depsgraph): + region = context.region + view3d = context.space_data + scene = depsgraph.scene + + # Get viewport dimensions + dimensions = region.width, region.height + + print("Start View Update: " + str(glGetError())) + if not self.first_time: + # First time initialization + self.first_time = True + for datablock in depsgraph.ids: + print(datablock) + if isinstance(datablock, bpy.types.Image): + self.draw_data.textures[datablock.name] = F3DRendererTexture(datablock) + print("Create Texture: " + str(glGetError())) + elif isinstance(datablock, bpy.types.Material): + self.draw_data.materials[datablock.name] = F3DRendererMaterial(datablock) + print("Create Material: " + str(glGetError())) + elif isinstance(datablock, bpy.types.Mesh): + pass + elif isinstance(datablock, bpy.types.Object) and datablock.type == "MESH": + self.draw_data.objects[datablock.name] = F3DRendererObject(datablock, self.draw_data) + print("Create Object: " + str(glGetError())) + else: + # Test which datablocks changed + for update in depsgraph.updates: + print("Datablock updated: ", update.id.name) + # if isinstance(update.id, bpy.types.Scene): + # for self.draw_data + + # Test if any material was added, removed or changed. + if depsgraph.id_type_updated("MATERIAL"): + print("Materials updated") + + # Loop over all object instances in the scene. + if self.first_time or depsgraph.id_type_updated("OBJECT"): + print("Updated object.") + for instance in depsgraph.object_instances: + pass + + context.region_data.perspective_matrix + print("End View Update: " + str(glGetError())) + + # For viewport renders, this method is called whenever Blender redraws + # the 3D viewport. The renderer is expected to quickly draw the render + # with OpenGL, and not perform other expensive work. + # Blender will draw overlays for selection and editing on top of the + # rendered image automatically. + def view_draw(self, context, depsgraph): + region = context.region + scene = depsgraph.scene + + # Get viewport dimensions + dimensions = region.width, region.height + + print("Start View Draw: " + str(glGetError())) + glEnable(GL_BLEND) + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) + self.draw_data.draw() + glDisable(GL_BLEND) - bl_idname = "f3d_renderer" - bl_label = "Fast3D" - use_preview = True - - # Init is called whenever a new render engine instance is created. Multiple - # instances may exist at the same time, for example for a viewport and final - # render. - def __init__(self): - self.draw_data = F3DDrawData() - self.first_time = False - - # When the render engine instance is destroy, this is called. Clean up any - # render engine data here, for example stopping running render threads. - def __del__(self): - pass - - # This is the method called by Blender for both final renders (F12) and - # small preview for materials, world and lights. - def render(self, depsgraph): - scene = depsgraph.scene - scale = scene.render.resolution_percentage / 100.0 - self.size_x = int(scene.render.resolution_x * scale) - self.size_y = int(scene.render.resolution_y * scale) - - # Fill the render result with a flat color. The framebuffer is - # defined as a list of pixels, each pixel itself being a list of - # R,G,B,A values. - if self.is_preview: - color = [0.1, 0.2, 0.1, 1.0] - else: - color = [0.2, 0.1, 0.1, 1.0] - - pixel_count = self.size_x * self.size_y - rect = [color] * pixel_count - - # Here we write the pixel values to the RenderResult - result = self.begin_result(0, 0, self.size_x, self.size_y) - layer = result.layers[0].passes["Combined"] - layer.rect = rect - self.end_result(result) - - # For viewport renders, this method gets called once at the start and - # whenever the scene or 3D viewport changes. This method is where data - # should be read from Blender in the same thread. Typically a render - # thread will be started to do the work while keeping Blender responsive. - - # Not called when viewport camera transform changes. - def view_update(self, context, depsgraph): - region = context.region - view3d = context.space_data - scene = depsgraph.scene - - # Get viewport dimensions - dimensions = region.width, region.height - - print("Start View Update: " + str(glGetError())) - if not self.first_time: - # First time initialization - self.first_time = True - for datablock in depsgraph.ids: - print(datablock) - if isinstance(datablock, bpy.types.Image): - self.draw_data.textures[datablock.name] = F3DRendererTexture(datablock) - print("Create Texture: " + str(glGetError())) - elif isinstance(datablock, bpy.types.Material): - self.draw_data.materials[datablock.name] = F3DRendererMaterial(datablock) - print("Create Material: " + str(glGetError())) - elif isinstance(datablock, bpy.types.Mesh): - pass - elif isinstance(datablock, bpy.types.Object) and datablock.type == "MESH": - self.draw_data.objects[datablock.name] = F3DRendererObject(datablock, self.draw_data) - print("Create Object: " + str(glGetError())) - else: - # Test which datablocks changed - for update in depsgraph.updates: - print("Datablock updated: ", update.id.name) - #if isinstance(update.id, bpy.types.Scene): - # for self.draw_data - - # Test if any material was added, removed or changed. - if depsgraph.id_type_updated('MATERIAL'): - print("Materials updated") - - # Loop over all object instances in the scene. - if self.first_time or depsgraph.id_type_updated('OBJECT'): - print("Updated object.") - for instance in depsgraph.object_instances: - pass - - context.region_data.perspective_matrix - print("End View Update: " + str(glGetError())) - - # For viewport renders, this method is called whenever Blender redraws - # the 3D viewport. The renderer is expected to quickly draw the render - # with OpenGL, and not perform other expensive work. - # Blender will draw overlays for selection and editing on top of the - # rendered image automatically. - def view_draw(self, context, depsgraph): - region = context.region - scene = depsgraph.scene - - # Get viewport dimensions - dimensions = region.width, region.height - - print("Start View Draw: " + str(glGetError())) - glEnable(GL_BLEND) - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA) - self.draw_data.draw() - glDisable(GL_BLEND) class F3DRendererTexture: - def __init__(self, image): - self.image = image - width, height = image.size - - self.texture_buffer = Buffer(GL_INT, 1) - image.gl_load() - self.texture_buffer[0] = image.bindcode - - #glGenTextures(1, self.texture) - glActiveTexture(GL_TEXTURE0) - glBindTexture(GL_TEXTURE_2D, self.texture_buffer[0]) - #glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, pixels) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) - glBindTexture(GL_TEXTURE_2D, 0) - - def __del__(self): - glBindTexture(GL_TEXTURE_2D, 0) - glDeleteTextures(1, self.texture_buffer) - - def bind(self): - glBindTexture(GL_TEXTURE_2D, self.texture_buffer[0]) + def __init__(self, image): + self.image = image + width, height = image.size + + self.texture_buffer = Buffer(GL_INT, 1) + image.gl_load() + self.texture_buffer[0] = image.bindcode + + # glGenTextures(1, self.texture) + glActiveTexture(GL_TEXTURE0) + glBindTexture(GL_TEXTURE_2D, self.texture_buffer[0]) + # glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_FLOAT, pixels) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR) + glBindTexture(GL_TEXTURE_2D, 0) + + def __del__(self): + glBindTexture(GL_TEXTURE_2D, 0) + glDeleteTextures(1, self.texture_buffer) + + def bind(self): + glBindTexture(GL_TEXTURE_2D, self.texture_buffer[0]) + class F3DRendererMaterial: - def __init__(self, material): - self.material = material - - def __del__(self): - pass + def __init__(self, material): + self.material = material + + def __del__(self): + pass - def update(self, viewport, projection, time): - pass + def update(self, viewport, projection, time): + pass + + def apply(self): + pass - def apply(self): - pass class F3DRendererObject: - def __init__(self, obj, render_data): - mesh = obj.data - self.submeshes = [] - facesByMat = {} - mesh.calc_loop_triangles() - for face in mesh.loop_triangles: - if face.material_index not in facesByMat: - facesByMat[face.material_index] = [] - facesByMat[face.material_index].append(face) - - for material_index, faces in facesByMat.items(): - material = mesh.materials[material_index] - # Material should always be added in view_update - #f3d_material = render_data.materials[material] - f3d_material = None - - self.submeshes.append(F3DRendererSubmesh(f3d_material, obj, faces, render_data)) - - def draw(self): - print("Draw Object: " + str(glGetError())) - for submesh in self.submeshes: - submesh.draw() + def __init__(self, obj, render_data): + mesh = obj.data + self.submeshes = [] + facesByMat = {} + mesh.calc_loop_triangles() + for face in mesh.loop_triangles: + if face.material_index not in facesByMat: + facesByMat[face.material_index] = [] + facesByMat[face.material_index].append(face) + + for material_index, faces in facesByMat.items(): + material = mesh.materials[material_index] + # Material should always be added in view_update + # f3d_material = render_data.materials[material] + f3d_material = None + + self.submeshes.append(F3DRendererSubmesh(f3d_material, obj, faces, render_data)) + + def draw(self): + print("Draw Object: " + str(glGetError())) + for submesh in self.submeshes: + submesh.draw() + class F3DRendererSubmesh: - def __init__(self, f3d_material, obj, triangles, render_data): - print("Begin submesh: " + str(glGetError())) - mesh = obj.data - loopIndices = [] - for triangle in triangles: - for loopIndex in triangle.loops: - loopIndices.append(loopIndex) - - self.material = f3d_material - self.obj = obj - - self.vertex_array = Buffer(GL_INT, 1) - glGenVertexArrays(1, self.vertex_array) - glBindVertexArray(self.vertex_array[0]) - - print("Gen/Bind VAO: " + str(glGetError())) - - self.vertex_buffer = Buffer(GL_INT, 3) - self.size = len(loopIndices) - glGenBuffers(3, self.vertex_buffer) - - position = [] - for loopIndex in loopIndices: - position.extend(mesh.vertices[mesh.loops[loopIndex].vertex_index].co[0:3]) - self.position_buffer = Buffer(GL_FLOAT, len(position), position) - - uv = [] - if 'UVMap' in mesh.uv_layers: - uv = [0, 0] * len(loopIndices) - else: - for loopUV in mesh.uv_layers['UVMap'].data: - uv.extend(loopUV.uv[0:2]) - self.uv_buffer = Buffer(GL_FLOAT, len(uv), uv) - - colorOrNormal = [] - if True: # TODO: Choose normal or vertex color - for loopIndex in loopIndices: - colorOrNormal.extend(mesh.loops[loopIndex].normal[0:3]) - else: - if 'Col' in mesh.vertex_colors: - color_data = mesh.vertex_colors['Col'].data - else: - color_data = [0,0,0] * len(loopIndices) - - if 'Alpha' in mesh.vertex_colors: - alpha_data = mesh.vertex_colors['Alpha'].data - else: - alpha_data = [0,0,0] * len(loopIndices) - - for loopIndex in loopIndices: - # TODO: Fix Alpha - colorOrNormal.extend(color_data[loopIndex][0:3] + [alpha_data[loopIndex][0]]) - self.colorOrNormal_buffer = Buffer(GL_FLOAT, len(colorOrNormal), colorOrNormal) - - position_location = glGetAttribLocation(render_data.shaderProgram, "pos") - uv_location = glGetAttribLocation(render_data.shaderProgram, "uv") - colorOrNormal_location = glGetAttribLocation(render_data.shaderProgram, "colorOrNormal") - print("pos: " + str(position_location) + ', uv: ' + str(uv_location) +\ - ", colorOrNormal: " + str(colorOrNormal_location)) - print("Get Attribute Locations: " + str(glGetError())) - - # Floats and Ints are 4 bytes? - glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer[0]) - print("Bind vertex buffer position: " + str(glGetError())) - glBufferData(GL_ARRAY_BUFFER, len(position) * 4, self.position_buffer, GL_STATIC_DRAW) - print("Buffer position data: " + str(glGetError())) - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) - glEnableVertexAttribArray(0) - print("Set Attribute Pointer: " + str(glGetError())) - - glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer[1]) - glBufferData(GL_ARRAY_BUFFER, len(uv) * 4, self.uv_buffer, GL_STATIC_DRAW) - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, None) - glEnableVertexAttribArray(0) - - glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer[2]) - glBufferData(GL_ARRAY_BUFFER, len(colorOrNormal) * 4, self.colorOrNormal_buffer, GL_STATIC_DRAW) - glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, None) - glEnableVertexAttribArray(2) - - glBindBuffer(GL_ARRAY_BUFFER, 0) - glBindVertexArray(0) - - self.render_data = render_data - - print("End submesh: " + str(glGetError())) - - - def draw(self): - print("Draw Start Submesh: " + str(glGetError())) - #glActiveTexture(GL_TEXTURE0) - #glBindTexture(GL_TEXTURE_2D, self.texture[0]) - - # Ignore material for now - #self.material.apply() - - # Handle modifiers? armatures? - transformLocation = glGetUniformLocation(self.render_data.shaderProgram, "transform") - glUniformMatrix4fv(transformLocation, 1, GL_FALSE, self.obj.matrix_world) - glBindVertexArray(self.vertex_array[0]) - glDrawArrays(GL_TRIANGLES, 0, self.size) - glBindVertexArray(0) - glBindTexture(GL_TEXTURE_2D, 0) - print("Draw End Submesh: " + str(glGetError())) - - def __del__(self): - glDeleteBuffers(3, self.vertex_buffer) - - glDeleteBuffers(1, self.position_buffer) - glDeleteBuffers(1, self.uv_buffer) - glDeleteBuffers(1, self.colorOrNormal_buffer) - - glDeleteVertexArrays(1, self.vertex_array) - glBindTexture(GL_TEXTURE_2D, 0) - #glDeleteTextures(1, self.texture) + def __init__(self, f3d_material, obj, triangles, render_data): + print("Begin submesh: " + str(glGetError())) + mesh = obj.data + loopIndices = [] + for triangle in triangles: + for loopIndex in triangle.loops: + loopIndices.append(loopIndex) + + self.material = f3d_material + self.obj = obj + + self.vertex_array = Buffer(GL_INT, 1) + glGenVertexArrays(1, self.vertex_array) + glBindVertexArray(self.vertex_array[0]) + + print("Gen/Bind VAO: " + str(glGetError())) + + self.vertex_buffer = Buffer(GL_INT, 3) + self.size = len(loopIndices) + glGenBuffers(3, self.vertex_buffer) + + position = [] + for loopIndex in loopIndices: + position.extend(mesh.vertices[mesh.loops[loopIndex].vertex_index].co[0:3]) + self.position_buffer = Buffer(GL_FLOAT, len(position), position) + + uv = [] + if "UVMap" in mesh.uv_layers: + uv = [0, 0] * len(loopIndices) + else: + for loopUV in mesh.uv_layers["UVMap"].data: + uv.extend(loopUV.uv[0:2]) + self.uv_buffer = Buffer(GL_FLOAT, len(uv), uv) + + colorOrNormal = [] + if True: # TODO: Choose normal or vertex color + for loopIndex in loopIndices: + colorOrNormal.extend(mesh.loops[loopIndex].normal[0:3]) + else: + if "Col" in mesh.vertex_colors: + color_data = mesh.vertex_colors["Col"].data + else: + color_data = [0, 0, 0] * len(loopIndices) + + if "Alpha" in mesh.vertex_colors: + alpha_data = mesh.vertex_colors["Alpha"].data + else: + alpha_data = [0, 0, 0] * len(loopIndices) + + for loopIndex in loopIndices: + # TODO: Fix Alpha + colorOrNormal.extend(color_data[loopIndex][0:3] + [alpha_data[loopIndex][0]]) + self.colorOrNormal_buffer = Buffer(GL_FLOAT, len(colorOrNormal), colorOrNormal) + + position_location = glGetAttribLocation(render_data.shaderProgram, "pos") + uv_location = glGetAttribLocation(render_data.shaderProgram, "uv") + colorOrNormal_location = glGetAttribLocation(render_data.shaderProgram, "colorOrNormal") + print( + "pos: " + + str(position_location) + + ", uv: " + + str(uv_location) + + ", colorOrNormal: " + + str(colorOrNormal_location) + ) + print("Get Attribute Locations: " + str(glGetError())) + + # Floats and Ints are 4 bytes? + glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer[0]) + print("Bind vertex buffer position: " + str(glGetError())) + glBufferData(GL_ARRAY_BUFFER, len(position) * 4, self.position_buffer, GL_STATIC_DRAW) + print("Buffer position data: " + str(glGetError())) + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, None) + glEnableVertexAttribArray(0) + print("Set Attribute Pointer: " + str(glGetError())) + + glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer[1]) + glBufferData(GL_ARRAY_BUFFER, len(uv) * 4, self.uv_buffer, GL_STATIC_DRAW) + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, None) + glEnableVertexAttribArray(0) + + glBindBuffer(GL_ARRAY_BUFFER, self.vertex_buffer[2]) + glBufferData(GL_ARRAY_BUFFER, len(colorOrNormal) * 4, self.colorOrNormal_buffer, GL_STATIC_DRAW) + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, None) + glEnableVertexAttribArray(2) + + glBindBuffer(GL_ARRAY_BUFFER, 0) + glBindVertexArray(0) + + self.render_data = render_data + + print("End submesh: " + str(glGetError())) + + def draw(self): + print("Draw Start Submesh: " + str(glGetError())) + # glActiveTexture(GL_TEXTURE0) + # glBindTexture(GL_TEXTURE_2D, self.texture[0]) + + # Ignore material for now + # self.material.apply() + + # Handle modifiers? armatures? + transformLocation = glGetUniformLocation(self.render_data.shaderProgram, "transform") + glUniformMatrix4fv(transformLocation, 1, GL_FALSE, self.obj.matrix_world) + glBindVertexArray(self.vertex_array[0]) + glDrawArrays(GL_TRIANGLES, 0, self.size) + glBindVertexArray(0) + glBindTexture(GL_TEXTURE_2D, 0) + print("Draw End Submesh: " + str(glGetError())) + + def __del__(self): + glDeleteBuffers(3, self.vertex_buffer) + + glDeleteBuffers(1, self.position_buffer) + glDeleteBuffers(1, self.uv_buffer) + glDeleteBuffers(1, self.colorOrNormal_buffer) + + glDeleteVertexArrays(1, self.vertex_array) + glBindTexture(GL_TEXTURE_2D, 0) + # glDeleteTextures(1, self.texture) + class F3DDrawData: - def __init__(self): - self.textures = {} - self.materials = {} - self.objects = {} - print("Start: " + str(glGetError())) - - # Create shader program - vertexHandle = glCreateShader(GL_VERTEX_SHADER) - fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER) - glShaderSource(vertexHandle, vertexShader) - glShaderSource(vertexHandle, fragmentShader) - glCompileShader(vertexHandle) - glCompileShader(fragmentHandle) - - print("Shader Created: " + str(glGetError())) - - self.shaderProgram = glCreateProgram() - glAttachShader(self.shaderProgram, vertexHandle) - glAttachShader(self.shaderProgram, fragmentHandle) - glLinkProgram(self.shaderProgram) - glDeleteShader(vertexHandle) - glDeleteShader(fragmentHandle) - - print("Program Created: " + str(glGetError())) - - #messageSize = Buffer(GL_INT, 1) - #message = Buffer(GL_BYTE, 1000) - #glGetShaderInfoLog(self.shaderProgram, 1000, messageSize, message) - print("End: " + str(glGetError())) - - def __del__(self): - for idName, f3dObject in self.objects.items(): - del f3dObject - - def draw(self): - print("Start Draw Data: " + str(glGetError())) - glClearColor(0.2, 0.3, 0.3, 1.0) - glClear(GL_COLOR_BUFFER_BIT) - - print("Before use program: " + str(glGetError())) - glUseProgram(self.shaderProgram) - for idName, f3dObject in self.objects.items(): - f3dObject.draw() + def __init__(self): + self.textures = {} + self.materials = {} + self.objects = {} + print("Start: " + str(glGetError())) + + # Create shader program + vertexHandle = glCreateShader(GL_VERTEX_SHADER) + fragmentHandle = glCreateShader(GL_FRAGMENT_SHADER) + glShaderSource(vertexHandle, vertexShader) + glShaderSource(vertexHandle, fragmentShader) + glCompileShader(vertexHandle) + glCompileShader(fragmentHandle) + + print("Shader Created: " + str(glGetError())) + + self.shaderProgram = glCreateProgram() + glAttachShader(self.shaderProgram, vertexHandle) + glAttachShader(self.shaderProgram, fragmentHandle) + glLinkProgram(self.shaderProgram) + glDeleteShader(vertexHandle) + glDeleteShader(fragmentHandle) + + print("Program Created: " + str(glGetError())) + + # messageSize = Buffer(GL_INT, 1) + # message = Buffer(GL_BYTE, 1000) + # glGetShaderInfoLog(self.shaderProgram, 1000, messageSize, message) + print("End: " + str(glGetError())) + + def __del__(self): + for idName, f3dObject in self.objects.items(): + del f3dObject + + def draw(self): + print("Start Draw Data: " + str(glGetError())) + glClearColor(0.2, 0.3, 0.3, 1.0) + glClear(GL_COLOR_BUFFER_BIT) + + print("Before use program: " + str(glGetError())) + glUseProgram(self.shaderProgram) + for idName, f3dObject in self.objects.items(): + f3dObject.draw() # RenderEngines also need to tell UI Panels that they are compatible with. @@ -373,40 +383,43 @@ def draw(self): # exclude any panels that are replaced by custom panels registered by the # render engine, or that are not supported. def get_panels(): - exclude_panels = { - 'VIEWLAYER_PT_filter', - 'VIEWLAYER_PT_layer_passes', - } + exclude_panels = { + "VIEWLAYER_PT_filter", + "VIEWLAYER_PT_layer_passes", + } + + panels = [] + for panel in bpy.types.Panel.__subclasses__(): + if hasattr(panel, "COMPAT_ENGINES") and "BLENDER_RENDER" in panel.COMPAT_ENGINES: + if panel.__name__ not in exclude_panels: + panels.append(panel) - panels = [] - for panel in bpy.types.Panel.__subclasses__(): - if hasattr(panel, 'COMPAT_ENGINES') and 'BLENDER_RENDER' in panel.COMPAT_ENGINES: - if panel.__name__ not in exclude_panels: - panels.append(panel) + return panels - return panels render_engine_classes = [ - #F3DRenderEngine, + # F3DRenderEngine, ] -def render_engine_register() : - for cls in render_engine_classes: - register_class(cls) - - for panel in get_panels(): - panel.COMPAT_ENGINES.add('CUSTOM') - #from bl_ui import (properties_render) - #properties_render.RENDER_PT_render.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname) +def render_engine_register(): + for cls in render_engine_classes: + register_class(cls) + + for panel in get_panels(): + panel.COMPAT_ENGINES.add("CUSTOM") + + # from bl_ui import (properties_render) + # properties_render.RENDER_PT_render.COMPAT_ENGINES.add(CustomRenderEngine.bl_idname) + -def render_engine_unregister() : - for cls in render_engine_classes: - unregister_class(cls) +def render_engine_unregister(): + for cls in render_engine_classes: + unregister_class(cls) - for panel in get_panels(): - if 'CUSTOM' in panel.COMPAT_ENGINES: - panel.COMPAT_ENGINES.remove('CUSTOM') + for panel in get_panels(): + if "CUSTOM" in panel.COMPAT_ENGINES: + panel.COMPAT_ENGINES.remove("CUSTOM") - #from bl_ui import (properties_render) - #properties_render.RENDER_PT_render.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname) \ No newline at end of file + # from bl_ui import (properties_render) + # properties_render.RENDER_PT_render.COMPAT_ENGINES.remove(CustomRenderEngine.bl_idname) diff --git a/fast64_internal/f3d/f3d_writer.py b/fast64_internal/f3d/f3d_writer.py index dd981b1b6..4dc61ab30 100644 --- a/fast64_internal/f3d/f3d_writer.py +++ b/fast64_internal/f3d/f3d_writer.py @@ -905,24 +905,27 @@ def processGeometry(self): self.triList.commands.extend(triCmds) else: if len(triCmds) <= 2: - self.writeCelLevels(triCmds = triCmds) + self.writeCelLevels(triCmds=triCmds) else: celTriList = self.triGroup.add_cel_tri_list() celTriList.commands.extend(triCmds) celTriList.commands.append(SPEndDisplayList()) - self.writeCelLevels(celTriList = celTriList) - + self.writeCelLevels(celTriList=celTriList) + def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional[List[GbiMacro]] = None) -> None: assert (celTriList == None) != (triCmds == None) f3dMat = self.material.f3d_mat cel = f3dMat.cel_shading f3d = get_F3D_GBI() - + # Don't want to have to change back and forth arbitrarily between decal and # opaque mode. So if you're using both lighter and darker, need to do those # first before switching to decal. if getZMode(self.material) != "ZMODE_OPA": - raise PluginError(f"Material {self.material.name} with cel shading: zmode in blender / rendermode must be opaque.", icon = "ERROR") + raise PluginError( + f"Material {self.material.name} with cel shading: zmode in blender / rendermode must be opaque.", + icon="ERROR", + ) wroteLighter = wroteDarker = usesDecal = False if len(cel.levels) == 0: raise PluginError(f"Material {self.material.name} with cel shading has no cel levels") @@ -931,15 +934,19 @@ def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional if wroteDarker: usesDecal = True elif usesDecal: - raise PluginError(f"Material {self.material.name}: must use Lighter and Darker cel levels before duplicating either of them") + raise PluginError( + f"Material {self.material.name}: must use Lighter and Darker cel levels before duplicating either of them" + ) wroteDarker = True else: if wroteLighter: usesDecal = True elif usesDecal: - raise PluginError(f"Material {self.material.name}: must use Lighter and Darker cel levels before duplicating either of them") + raise PluginError( + f"Material {self.material.name}: must use Lighter and Darker cel levels before duplicating either of them" + ) wroteLighter = True - + # Because this might not be the first tri list in the object with this # material, we have to set things even if they were set up already in # the material. @@ -951,17 +958,15 @@ def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional if usesDecal: if not wroteOpaque: wroteOpaque = True - self.triList.commands.append(SPSetOtherMode("G_SETOTHERMODE_L", - 10, 2, ["ZMODE_OPA"])) + self.triList.commands.append(SPSetOtherMode("G_SETOTHERMODE_L", 10, 2, ["ZMODE_OPA"])) if not wroteDecal and (darker and wroteDarker or not darker and wroteLighter): wroteDecal = True - self.triList.commands.append(SPSetOtherMode("G_SETOTHERMODE_L", - 10, 2, ["ZMODE_DEC"])) + self.triList.commands.append(SPSetOtherMode("G_SETOTHERMODE_L", 10, 2, ["ZMODE_DEC"])) if darker: wroteDarker = True else: wroteLighter = True - + if lastDarker != darker: lastDarker = darker # Set up CC. @@ -976,51 +981,52 @@ def writeCelLevels(self, celTriList: Optional[GfxList] = None, triCmds: Optional else: ccSettings *= 2 self.triList.commands.append(DPSetCombineMode(*ccSettings)) - + # Set up tint color and level if level.tintType == "Fixed": color = exportColor(level.tintFixedColor) if cel.tintPipeline == "CC": - self.triList.commands.append(DPSetPrimColor(0, 0, color[0], - color[1], color[2], level.tintFixedLevel)) + self.triList.commands.append( + DPSetPrimColor(0, 0, color[0], color[1], color[2], level.tintFixedLevel) + ) else: - self.triList.commands.append(DPSetFogColor(color[0], - color[1], color[2], level.tintFixedLevel)) + self.triList.commands.append(DPSetFogColor(color[0], color[1], color[2], level.tintFixedLevel)) elif level.tintType == "Segment": - self.triList.commands.append(SPDisplayList(GfxList( - f"{level.tintSegmentNum:#04x}{level.tintSegmentOffset * 8:06x}", - GfxListTag.Material, - DLFormat.Static - ))) + self.triList.commands.append( + SPDisplayList( + GfxList( + f"{level.tintSegmentNum:#04x}{level.tintSegmentOffset * 8:06x}", + GfxListTag.Material, + DLFormat.Static, + ) + ) + ) elif level.tintType == "Light": if cel.tintPipeline == "CC": - self.triList.commands.append(SPLightToPrimColor( - level.tintLightSlot, level.tintFixedLevel, 0, 0 - )) + self.triList.commands.append(SPLightToPrimColor(level.tintLightSlot, level.tintFixedLevel, 0, 0)) else: - self.triList.commands.append(SPLightToFogColor( - level.tintLightSlot, level.tintFixedLevel - )) + self.triList.commands.append(SPLightToFogColor(level.tintLightSlot, level.tintFixedLevel)) else: raise PluginError("Unknown tint type") - + # Set up threshold - self.triList.commands.append(DPSetBlendColor(255, 255, 255, - 0x100 - level.threshold if darker else level.threshold)) - self.triList.commands.append(SPAlphaCompareCull( - "G_ALPHA_COMPARE_CULL_ABOVE" if darker else - "G_ALPHA_COMPARE_CULL_BELOW", - level.threshold)) - + self.triList.commands.append( + DPSetBlendColor(255, 255, 255, 0x100 - level.threshold if darker else level.threshold) + ) + self.triList.commands.append( + SPAlphaCompareCull( + "G_ALPHA_COMPARE_CULL_ABOVE" if darker else "G_ALPHA_COMPARE_CULL_BELOW", level.threshold + ) + ) + # Draw tris, inline or by call if triCmds is not None: self.triList.commands.extend(triCmds) else: self.triList.commands.append(SPDisplayList(celTriList)) - + # Disable alpha compare culling for future DLs - self.triList.commands.append(SPAlphaCompareCull( - "G_ALPHA_COMPARE_CULL_DISABLE", 0)) + self.triList.commands.append(SPAlphaCompareCull("G_ALPHA_COMPARE_CULL_DISABLE", 0)) def addFace(self, face, stOffset): triIndices = [] diff --git a/fast64_internal/f3d/flipbook.py b/fast64_internal/f3d/flipbook.py index 8efcc009f..86e9f3bdb 100644 --- a/fast64_internal/f3d/flipbook.py +++ b/fast64_internal/f3d/flipbook.py @@ -252,6 +252,7 @@ def ootFlipbookAnimUpdate(self, armatureObj: bpy.types.Object, segment: str, ind # END GAME SPECIFIC CALLBACKS + # we use a handler since update functions are not called when a property is animated. @persistent def flipbookAnimHandler(dummy): diff --git a/fast64_internal/f3d_material_converter.py b/fast64_internal/f3d_material_converter.py index e9d2b974e..c8dead3b8 100644 --- a/fast64_internal/f3d_material_converter.py +++ b/fast64_internal/f3d_material_converter.py @@ -118,7 +118,7 @@ def set_best_draw_layer_for_materials(): mat.f3d_mat.draw_layer.sm64 = obj.draw_layer_static if len(obj.vertex_groups) == 0: - continue # object doesn't have vertex groups + continue # object doesn't have vertex groups # get vertex group in the polygon group = get_group_from_polygon(obj, p) diff --git a/fast64_internal/panels.py b/fast64_internal/panels.py index 6c598a488..adc5f97db 100644 --- a/fast64_internal/panels.py +++ b/fast64_internal/panels.py @@ -1,20 +1,20 @@ - import bpy -sm64GoalImport = 'Import' # Not in enum, separate UI option +sm64GoalImport = "Import" # Not in enum, separate UI option sm64GoalTypeEnum = [ - ('All', 'All', 'All'), - ('Export Object/Actor/Anim', 'Export Object/Actor/Anim', 'Export Object/Actor/Anim'), - ('Export Level', 'Export Level', 'Export Level'), - ('Export Displaylist', 'Export Displaylist', 'Export Displaylist'), - ('Export UI Image', 'Export UI Image', 'Export UI Image'), + ("All", "All", "All"), + ("Export Object/Actor/Anim", "Export Object/Actor/Anim", "Export Object/Actor/Anim"), + ("Export Level", "Export Level", "Export Level"), + ("Export Displaylist", "Export Displaylist", "Export Displaylist"), + ("Export UI Image", "Export UI Image", "Export UI Image"), ] + class SM64_Panel(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'SM64' - bl_options = {'DEFAULT_CLOSED'} + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "SM64" + bl_options = {"DEFAULT_CLOSED"} # goal refers to the selected sm64GoalTypeEnum, a different selection than this goal will filter this panel out goal = None # if this is True, the panel is hidden whenever the scene's exportType is not 'C' @@ -23,25 +23,26 @@ class SM64_Panel(bpy.types.Panel): @classmethod def poll(cls, context): sm64Props = bpy.context.scene.fast64.sm64 - if context.scene.gameEditorMode != 'SM64': + if context.scene.gameEditorMode != "SM64": return False elif not cls.goal: - return True # Panel should always be shown + return True # Panel should always be shown elif cls.goal == sm64GoalImport: # Only show if importing is enabled return sm64Props.showImportingMenus - elif cls.decomp_only and sm64Props.exportType != 'C': + elif cls.decomp_only and sm64Props.exportType != "C": return False sceneGoal = sm64Props.goal - return sceneGoal == 'All' or sceneGoal == cls.goal + return sceneGoal == "All" or sceneGoal == cls.goal + class OOT_Panel(bpy.types.Panel): - bl_space_type = 'VIEW_3D' - bl_region_type = 'UI' - bl_category = 'OOT' - bl_options = {'DEFAULT_CLOSED'} + bl_space_type = "VIEW_3D" + bl_region_type = "UI" + bl_category = "OOT" + bl_options = {"DEFAULT_CLOSED"} @classmethod def poll(cls, context): - return context.scene.gameEditorMode == 'OOT' + return context.scene.gameEditorMode == "OOT" diff --git a/fast64_internal/render_settings.py b/fast64_internal/render_settings.py index 850970e4e..3fa61049d 100644 --- a/fast64_internal/render_settings.py +++ b/fast64_internal/render_settings.py @@ -1,253 +1,265 @@ -import bpy -import mathutils -import math -from .utility import * - - -def on_update_sm64_render_settings(self, context: bpy.types.Context): - renderSettings: "Fast64RenderSettings_Properties" = context.scene.fast64.renderSettings - if renderSettings.sm64Area and renderSettings.useObjectRenderPreview: - area: bpy.types.Object = renderSettings.sm64Area - renderSettings.fogPreviewColor = tuple(c for c in area.area_fog_color) - renderSettings.fogPreviewPosition = tuple(round(p) for p in area.area_fog_position) - - renderSettings.clippingPlanes = tuple(float(p) for p in area.clipPlanes) - - -def on_update_oot_render_settings(self, context: bpy.types.Context): - renderSettings: "Fast64RenderSettings_Properties" = context.scene.fast64.renderSettings - if renderSettings.ootSceneObject is None or not renderSettings.useObjectRenderPreview: - return - header = ootGetSceneOrRoomHeader( - renderSettings.ootSceneObject, - renderSettings.ootSceneHeader, - False, - ) - if header is None: - return - lMode = header.skyboxLighting - if lMode == "0x01" or (lMode == "Custom" and not renderSettings.ootForceTimeOfDay): - if renderSettings.ootLightIdx >= len(header.lightList): - return - l = header.lightList[renderSettings.ootLightIdx] - renderSettings.ambientColor = tuple(c for c in l.ambient) - col0, dir0 = ootGetBaseOrCustomLight(l, 0, False, False) - renderSettings.lightColor = tuple(c for c in col0) - renderSettings.lightDirection = tuple(d for d in dir0) - # TODO: Implement light1 into shader nodes - # col1, dir1 = ootGetBaseOrCustomLight(l, 1, False, False) - # renderSettings.light1Color = tuple(c for c in col1) - # renderSettings.light1Direction = tuple(d for d in dir1) - renderSettings.fogPreviewColor = tuple(c for c in l.fogColor) - renderSettings.fogPreviewPosition = (l.fogNear, l.fogFar) - else: - if header.skyboxLighting == "0x00": - tod = header.timeOfDayLights - lights = [tod.dawn, tod.day, tod.dusk, tod.night] - else: - if renderSettings.ootLightIdx + 4 > len(header.lightList): - return - lights = header.lightList[renderSettings.ootLightIdx:renderSettings.ootLightIdx+4] - assert len(lights) == 4 - todTimes = [0.0, 4.0, 6.0, 8.0, 16.0, 17.0, 19.0, 24.0] - todSets = [ 3, 3, 0, 1, 1, 2, 3, 3] - t = renderSettings.ootTime - for i in range(len(todTimes) - 1): - assert t >= todTimes[i] - if t < todTimes[i+1]: - la, lb = lights[todSets[i]], lights[todSets[i+1]] - fade = (t - todTimes[i]) / (todTimes[i+1] - todTimes[i]) - break - else: - raise PluginError("OoT time of day out of range") - def interpColors(cola, colb, fade): - cola = mathutils.Vector(tuple(c for c in cola)) - colb = mathutils.Vector(tuple(c for c in colb)) - return cola + (colb - cola) * fade - renderSettings.ambientColor = interpColors(la.ambient, lb.ambient, fade) - col0a, _ = ootGetBaseOrCustomLight(la, 0, False, False) - col0b, _ = ootGetBaseOrCustomLight(lb, 0, False, False) - renderSettings.lightColor = col0a + (col0b - col0a) * fade - # TODO: Implement light1 into shader nodes - # col1a, _ = ootGetBaseOrCustomLight(la, 1, False, False) - # col1b, _ = ootGetBaseOrCustomLight(lb, 1, False, False) - # renderSettings.light1Color = col1a * fa + col1b * fb - sint, cost = math.sin(math.tau * t / 24.0), math.cos(math.tau * t / 24.0) - renderSettings.lightDirection = mathutils.Vector(( - sint * 120.0 / 127.0, - -cost * 120.0 / 127.0, - -cost * 20.0 / 127.0, - )).normalized() - # TODO: Implement light1 into shader nodes - # renderSettings.light1Direction = -renderSettings.lightDirection - renderSettings.fogColor = interpColors(la.fogColor, lb.fogColor, fade) - renderSettings.fogPreviewPosition = ( - la.fogNear + int(float(lb.fogNear - la.fogNear) * fade), - la.fogFar + int(float(lb.fogFar - la.fogFar ) * fade), - ) - - -def update_lighting_space(renderSettings: "Fast64RenderSettings_Properties"): - if renderSettings.useWorldSpaceLighting: - bpy.data.node_groups["ShdCol_L"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[ - "GeometryNormal_WorldSpace" - ] - else: - bpy.data.node_groups["ShdCol_L"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[ - "GeometryNormal_ViewSpace" - ] - - -def update_scene_props_from_render_settings( - context: bpy.types.Context, - sceneOutputs: bpy.types.NodeGroupOutput, - renderSettings: "Fast64RenderSettings_Properties", -): - enableFog = int(renderSettings.enableFogPreview) - sceneOutputs.inputs["FogEnable"].default_value = enableFog - - sceneOutputs.inputs["FogColor"].default_value = tuple(c for c in renderSettings.fogPreviewColor) - sceneOutputs.inputs["FogNear"].default_value = renderSettings.fogPreviewPosition[0] - sceneOutputs.inputs["FogFar"].default_value = renderSettings.fogPreviewPosition[1] - - sceneOutputs.inputs["F3D_NearClip"].default_value = float(renderSettings.clippingPlanes[0]) - sceneOutputs.inputs["F3D_FarClip"].default_value = float(renderSettings.clippingPlanes[1]) - - sceneOutputs.inputs["ShadeColor"].default_value = tuple(c for c in renderSettings.lightColor) - sceneOutputs.inputs["AmbientColor"].default_value = tuple(c for c in renderSettings.ambientColor) - sceneOutputs.inputs["LightDirection"].default_value = tuple( - d for d in (mathutils.Vector(renderSettings.lightDirection) @ transform_mtx_blender_to_n64()) - ) - - update_lighting_space(renderSettings) - - sceneOutputs.inputs["Blender_Game_Scale"].default_value = float(get_blender_to_game_scale(context)) - - -def on_update_render_preview_nodes(self, context: bpy.types.Context): - sceneProps = bpy.data.node_groups.get("SceneProperties") - if sceneProps == None: - print("Could not locate SceneProperties!") - return - - sceneOutputs: bpy.types.NodeGroupOutput = sceneProps.nodes["Group Output"] - renderSettings: "Fast64RenderSettings_Properties" = context.scene.fast64.renderSettings - update_scene_props_from_render_settings(context, sceneOutputs, renderSettings) - - -def on_update_render_settings(self, context: bpy.types.Context): - sceneProps = bpy.data.node_groups.get("SceneProperties") - if sceneProps == None: - print("Could not locate sceneProps!") - return - - match context.scene.gameEditorMode: - case "SM64": - on_update_sm64_render_settings(self, context) - case "OOT": - on_update_oot_render_settings(self, context) - case _: - pass - - on_update_render_preview_nodes(self, context) - - -def poll_sm64_area(self, object): - return object.sm64_obj_type == "Area Root" - - -def poll_oot_scene(self, object): - return object.ootEmptyType == "Scene" - - -def resync_scene_props(): - if "ShdCol_L" in bpy.data.node_groups and "GeometryNormal_WorldSpace" in bpy.data.node_groups: - renderSettings: "Fast64RenderSettings_Properties" = bpy.context.scene.fast64.renderSettings - # Lighting space needs to be updated due to the nodes being shared and reloaded - update_lighting_space(renderSettings) - - -class Fast64RenderSettings_Properties(bpy.types.PropertyGroup): - enableFogPreview: bpy.props.BoolProperty(name="Enable Fog Preview", default=True, update=on_update_render_settings) - fogPreviewColor: bpy.props.FloatVectorProperty( - name="Fog Color", - subtype="COLOR", - size=4, - min=0, - max=1, - default=(1, 1, 1, 1), - update=on_update_render_preview_nodes, - ) - ambientColor: bpy.props.FloatVectorProperty( - name="Ambient Light", - subtype="COLOR", - size=4, - min=0, - max=1, - default=(0.5, 0.5, 0.5, 1), - update=on_update_render_preview_nodes, - ) - lightColor: bpy.props.FloatVectorProperty( - name="Light Color", - subtype="COLOR", - size=4, - min=0, - max=1, - default=(1, 1, 1, 1), - update=on_update_render_preview_nodes, - ) - lightDirection: bpy.props.FloatVectorProperty( - name="Light Direction", - subtype="DIRECTION", - size=3, - min=-1, - max=1, - default=mathutils.Vector((0.5, 0.5, 1)).normalized(), # pre normalized - update=on_update_render_preview_nodes, - ) - useWorldSpaceLighting: bpy.props.BoolProperty( - name="Use World Space Lighting", default=True, update=on_update_render_settings - ) - # Fog Preview is int because values reflect F3D values - fogPreviewPosition: bpy.props.IntVectorProperty( - name="Fog Position", size=2, min=0, max=0x7FFFFFFF, default=(985, 1000), update=on_update_render_preview_nodes - ) - # Clipping planes are float because values reflect F3D values - clippingPlanes: bpy.props.FloatVectorProperty( - name="Clipping Planes", size=2, min=0, default=(100, 30000), update=on_update_render_preview_nodes - ) - useObjectRenderPreview: bpy.props.BoolProperty( - name="Use Object Preview", default=True, update=on_update_render_settings - ) - # SM64 - sm64Area: bpy.props.PointerProperty( - name="Area Object", type=bpy.types.Object, update=on_update_sm64_render_settings, poll=poll_sm64_area - ) - # OOT - ootSceneObject: bpy.props.PointerProperty( - name="Scene Object", type=bpy.types.Object, update=on_update_oot_render_settings, poll=poll_oot_scene - ) - ootSceneHeader: bpy.props.IntProperty( - name="Header/Setup", - description="Scene header / setup to use lighting data from", - min=0, soft_max=10, default=0, - update=on_update_oot_render_settings, - ) - ootForceTimeOfDay: bpy.props.BoolProperty( - name="Force Time of Day", - description="Interpolate between four lights based on the time", - default=False, - update=on_update_oot_render_settings, - ) - ootLightIdx: bpy.props.IntProperty( - name="Light Index", - min=0, soft_max=10, default=0, - update=on_update_oot_render_settings, - ) - ootTime: bpy.props.FloatProperty( - name="Time of Day (Hours)", - description="Time of day to emulate lighting conditions at, in hours", - min=0.0, max=23.99, default = 10.0, precision=2, subtype="TIME", unit="TIME", - update=on_update_oot_render_settings, - ) - +import bpy +import mathutils +import math +from .utility import * + + +def on_update_sm64_render_settings(self, context: bpy.types.Context): + renderSettings: "Fast64RenderSettings_Properties" = context.scene.fast64.renderSettings + if renderSettings.sm64Area and renderSettings.useObjectRenderPreview: + area: bpy.types.Object = renderSettings.sm64Area + renderSettings.fogPreviewColor = tuple(c for c in area.area_fog_color) + renderSettings.fogPreviewPosition = tuple(round(p) for p in area.area_fog_position) + + renderSettings.clippingPlanes = tuple(float(p) for p in area.clipPlanes) + + +def on_update_oot_render_settings(self, context: bpy.types.Context): + renderSettings: "Fast64RenderSettings_Properties" = context.scene.fast64.renderSettings + if renderSettings.ootSceneObject is None or not renderSettings.useObjectRenderPreview: + return + header = ootGetSceneOrRoomHeader( + renderSettings.ootSceneObject, + renderSettings.ootSceneHeader, + False, + ) + if header is None: + return + lMode = header.skyboxLighting + if lMode == "0x01" or (lMode == "Custom" and not renderSettings.ootForceTimeOfDay): + if renderSettings.ootLightIdx >= len(header.lightList): + return + l = header.lightList[renderSettings.ootLightIdx] + renderSettings.ambientColor = tuple(c for c in l.ambient) + col0, dir0 = ootGetBaseOrCustomLight(l, 0, False, False) + renderSettings.lightColor = tuple(c for c in col0) + renderSettings.lightDirection = tuple(d for d in dir0) + # TODO: Implement light1 into shader nodes + # col1, dir1 = ootGetBaseOrCustomLight(l, 1, False, False) + # renderSettings.light1Color = tuple(c for c in col1) + # renderSettings.light1Direction = tuple(d for d in dir1) + renderSettings.fogPreviewColor = tuple(c for c in l.fogColor) + renderSettings.fogPreviewPosition = (l.fogNear, l.fogFar) + else: + if header.skyboxLighting == "0x00": + tod = header.timeOfDayLights + lights = [tod.dawn, tod.day, tod.dusk, tod.night] + else: + if renderSettings.ootLightIdx + 4 > len(header.lightList): + return + lights = header.lightList[renderSettings.ootLightIdx : renderSettings.ootLightIdx + 4] + assert len(lights) == 4 + todTimes = [0.0, 4.0, 6.0, 8.0, 16.0, 17.0, 19.0, 24.0] + todSets = [3, 3, 0, 1, 1, 2, 3, 3] + t = renderSettings.ootTime + for i in range(len(todTimes) - 1): + assert t >= todTimes[i] + if t < todTimes[i + 1]: + la, lb = lights[todSets[i]], lights[todSets[i + 1]] + fade = (t - todTimes[i]) / (todTimes[i + 1] - todTimes[i]) + break + else: + raise PluginError("OoT time of day out of range") + + def interpColors(cola, colb, fade): + cola = mathutils.Vector(tuple(c for c in cola)) + colb = mathutils.Vector(tuple(c for c in colb)) + return cola + (colb - cola) * fade + + renderSettings.ambientColor = interpColors(la.ambient, lb.ambient, fade) + col0a, _ = ootGetBaseOrCustomLight(la, 0, False, False) + col0b, _ = ootGetBaseOrCustomLight(lb, 0, False, False) + renderSettings.lightColor = col0a + (col0b - col0a) * fade + # TODO: Implement light1 into shader nodes + # col1a, _ = ootGetBaseOrCustomLight(la, 1, False, False) + # col1b, _ = ootGetBaseOrCustomLight(lb, 1, False, False) + # renderSettings.light1Color = col1a * fa + col1b * fb + sint, cost = math.sin(math.tau * t / 24.0), math.cos(math.tau * t / 24.0) + renderSettings.lightDirection = mathutils.Vector( + ( + sint * 120.0 / 127.0, + -cost * 120.0 / 127.0, + -cost * 20.0 / 127.0, + ) + ).normalized() + # TODO: Implement light1 into shader nodes + # renderSettings.light1Direction = -renderSettings.lightDirection + renderSettings.fogColor = interpColors(la.fogColor, lb.fogColor, fade) + renderSettings.fogPreviewPosition = ( + la.fogNear + int(float(lb.fogNear - la.fogNear) * fade), + la.fogFar + int(float(lb.fogFar - la.fogFar) * fade), + ) + + +def update_lighting_space(renderSettings: "Fast64RenderSettings_Properties"): + if renderSettings.useWorldSpaceLighting: + bpy.data.node_groups["ShdCol_L"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[ + "GeometryNormal_WorldSpace" + ] + else: + bpy.data.node_groups["ShdCol_L"].nodes["GeometryNormal"].node_tree = bpy.data.node_groups[ + "GeometryNormal_ViewSpace" + ] + + +def update_scene_props_from_render_settings( + context: bpy.types.Context, + sceneOutputs: bpy.types.NodeGroupOutput, + renderSettings: "Fast64RenderSettings_Properties", +): + enableFog = int(renderSettings.enableFogPreview) + sceneOutputs.inputs["FogEnable"].default_value = enableFog + + sceneOutputs.inputs["FogColor"].default_value = tuple(c for c in renderSettings.fogPreviewColor) + sceneOutputs.inputs["FogNear"].default_value = renderSettings.fogPreviewPosition[0] + sceneOutputs.inputs["FogFar"].default_value = renderSettings.fogPreviewPosition[1] + + sceneOutputs.inputs["F3D_NearClip"].default_value = float(renderSettings.clippingPlanes[0]) + sceneOutputs.inputs["F3D_FarClip"].default_value = float(renderSettings.clippingPlanes[1]) + + sceneOutputs.inputs["ShadeColor"].default_value = tuple(c for c in renderSettings.lightColor) + sceneOutputs.inputs["AmbientColor"].default_value = tuple(c for c in renderSettings.ambientColor) + sceneOutputs.inputs["LightDirection"].default_value = tuple( + d for d in (mathutils.Vector(renderSettings.lightDirection) @ transform_mtx_blender_to_n64()) + ) + + update_lighting_space(renderSettings) + + sceneOutputs.inputs["Blender_Game_Scale"].default_value = float(get_blender_to_game_scale(context)) + + +def on_update_render_preview_nodes(self, context: bpy.types.Context): + sceneProps = bpy.data.node_groups.get("SceneProperties") + if sceneProps == None: + print("Could not locate SceneProperties!") + return + + sceneOutputs: bpy.types.NodeGroupOutput = sceneProps.nodes["Group Output"] + renderSettings: "Fast64RenderSettings_Properties" = context.scene.fast64.renderSettings + update_scene_props_from_render_settings(context, sceneOutputs, renderSettings) + + +def on_update_render_settings(self, context: bpy.types.Context): + sceneProps = bpy.data.node_groups.get("SceneProperties") + if sceneProps == None: + print("Could not locate sceneProps!") + return + + match context.scene.gameEditorMode: + case "SM64": + on_update_sm64_render_settings(self, context) + case "OOT": + on_update_oot_render_settings(self, context) + case _: + pass + + on_update_render_preview_nodes(self, context) + + +def poll_sm64_area(self, object): + return object.sm64_obj_type == "Area Root" + + +def poll_oot_scene(self, object): + return object.ootEmptyType == "Scene" + + +def resync_scene_props(): + if "ShdCol_L" in bpy.data.node_groups and "GeometryNormal_WorldSpace" in bpy.data.node_groups: + renderSettings: "Fast64RenderSettings_Properties" = bpy.context.scene.fast64.renderSettings + # Lighting space needs to be updated due to the nodes being shared and reloaded + update_lighting_space(renderSettings) + + +class Fast64RenderSettings_Properties(bpy.types.PropertyGroup): + enableFogPreview: bpy.props.BoolProperty(name="Enable Fog Preview", default=True, update=on_update_render_settings) + fogPreviewColor: bpy.props.FloatVectorProperty( + name="Fog Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=on_update_render_preview_nodes, + ) + ambientColor: bpy.props.FloatVectorProperty( + name="Ambient Light", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(0.5, 0.5, 0.5, 1), + update=on_update_render_preview_nodes, + ) + lightColor: bpy.props.FloatVectorProperty( + name="Light Color", + subtype="COLOR", + size=4, + min=0, + max=1, + default=(1, 1, 1, 1), + update=on_update_render_preview_nodes, + ) + lightDirection: bpy.props.FloatVectorProperty( + name="Light Direction", + subtype="DIRECTION", + size=3, + min=-1, + max=1, + default=mathutils.Vector((0.5, 0.5, 1)).normalized(), # pre normalized + update=on_update_render_preview_nodes, + ) + useWorldSpaceLighting: bpy.props.BoolProperty( + name="Use World Space Lighting", default=True, update=on_update_render_settings + ) + # Fog Preview is int because values reflect F3D values + fogPreviewPosition: bpy.props.IntVectorProperty( + name="Fog Position", size=2, min=0, max=0x7FFFFFFF, default=(985, 1000), update=on_update_render_preview_nodes + ) + # Clipping planes are float because values reflect F3D values + clippingPlanes: bpy.props.FloatVectorProperty( + name="Clipping Planes", size=2, min=0, default=(100, 30000), update=on_update_render_preview_nodes + ) + useObjectRenderPreview: bpy.props.BoolProperty( + name="Use Object Preview", default=True, update=on_update_render_settings + ) + # SM64 + sm64Area: bpy.props.PointerProperty( + name="Area Object", type=bpy.types.Object, update=on_update_sm64_render_settings, poll=poll_sm64_area + ) + # OOT + ootSceneObject: bpy.props.PointerProperty( + name="Scene Object", type=bpy.types.Object, update=on_update_oot_render_settings, poll=poll_oot_scene + ) + ootSceneHeader: bpy.props.IntProperty( + name="Header/Setup", + description="Scene header / setup to use lighting data from", + min=0, + soft_max=10, + default=0, + update=on_update_oot_render_settings, + ) + ootForceTimeOfDay: bpy.props.BoolProperty( + name="Force Time of Day", + description="Interpolate between four lights based on the time", + default=False, + update=on_update_oot_render_settings, + ) + ootLightIdx: bpy.props.IntProperty( + name="Light Index", + min=0, + soft_max=10, + default=0, + update=on_update_oot_render_settings, + ) + ootTime: bpy.props.FloatProperty( + name="Time of Day (Hours)", + description="Time of day to emulate lighting conditions at, in hours", + min=0.0, + max=23.99, + default=10.0, + precision=2, + subtype="TIME", + unit="TIME", + update=on_update_oot_render_settings, + ) diff --git a/fast64_internal/sm64/c_templates/tile_scroll.py b/fast64_internal/sm64/c_templates/tile_scroll.py index 90eb5c27f..6fa1adb69 100644 --- a/fast64_internal/sm64/c_templates/tile_scroll.py +++ b/fast64_internal/sm64/c_templates/tile_scroll.py @@ -1,4 +1,4 @@ -tile_scroll_c = '''#include +tile_scroll_c = """#include #include "game/memory.h" #include "game/tile_scroll.h" @@ -40,9 +40,9 @@ tile->v += t; } -''' +""" -tile_scroll_h = '''#include "types.h" +tile_scroll_h = """#include "types.h" #define PACK_TILESIZE(w, d) ((w << 2) + d) @@ -61,4 +61,4 @@ void shift_s_down(Gfx *dl, u32 cmd, u16 s); void shift_t_down(Gfx *dl, u32 cmd, u16 t); -''' \ No newline at end of file +""" diff --git a/fast64_internal/sm64/parse_function_map.py b/fast64_internal/sm64/parse_function_map.py index 06b3589bf..ae8842d84 100644 --- a/fast64_internal/sm64/parse_function_map.py +++ b/fast64_internal/sm64/parse_function_map.py @@ -1,23 +1,24 @@ from re import search -refresh_name = 'Refresh 13' -function_map_path = './sm64.us.map' -output_map_path = './sm64_function_map_output.py' +refresh_name = "Refresh 13" +function_map_path = "./sm64.us.map" +output_map_path = "./sm64_function_map_output.py" + def parse_func_map(): - mapfile = open(function_map_path, 'r') - outfile = open(output_map_path, 'w') + mapfile = open(function_map_path, "r") + outfile = open(output_map_path, "w") outfile.write('\t"' + refresh_name + '" : {\n') nextLine = mapfile.readline() - while nextLine != '' and nextLine != 'Linker script and memory map\n': + while nextLine != "" and nextLine != "Linker script and memory map\n": nextLine = mapfile.readline() - while nextLine != '' and nextLine != ' build/us/src/menu/level_select_menu.o(.text)\n': - if nextLine[:17] == ' ' * 16 + '0': + while nextLine != "" and nextLine != " build/us/src/menu/level_select_menu.o(.text)\n": + if nextLine[:17] == " " * 16 + "0": outfile.write('\t\t"' + nextLine[26:34] + '" : ') searchName = nextLine[34:] - searchResult = search(r'\s*(\S*).*', searchName) + searchResult = search(r"\s*(\S*).*", searchName) outfile.write('"' + searchResult.group(1) + '",\n') nextLine = mapfile.readline() outfile.write("\t}\n") diff --git a/fast64_internal/sm64/sm64_anim.py b/fast64_internal/sm64/sm64_anim.py index 2e3f23d24..8f3219d78 100644 --- a/fast64_internal/sm64/sm64_anim.py +++ b/fast64_internal/sm64/sm64_anim.py @@ -255,7 +255,6 @@ def exportAnimationC(armatureObj, loopAnim, dirPath, dirName, groupName, customE # if animation header isn´t already in the table then add it. if sm64_anim.header.name not in stringData: - # search for the NULL value which represents the end of the table # (this value is not present in vanilla animation tables) footerIndex = stringData.rfind("\tNULL,\n") @@ -295,7 +294,6 @@ def exportAnimationC(armatureObj, loopAnim, dirPath, dirName, groupName, customE def exportAnimationBinary(romfile, exportRange, armatureObj, DMAAddresses, segmentData, isDMA, loopAnim): - startAddress = get64bitAlignedAddr(exportRange[0]) sm64_anim = exportAnimationCommon(armatureObj, loopAnim, armatureObj.name) @@ -552,6 +550,7 @@ def importAnimationToBlender(romfile, startAddress, armatureObj, segmentData, is stashActionInArmature(armatureObj, anim) armatureObj.animation_data.action = anim + def readAnimation(name, romfile, startAddress, segmentData, isDMA): animationHeader = readAnimHeader(name, romfile, startAddress, segmentData, isDMA) @@ -697,7 +696,7 @@ def readValueIndex(romfile, startAddress): # multiply 2 because value is the index in array of shorts (???) startOffset = int.from_bytes(romfile.read(2), "big") * 2 - #print(str(hex(startAddress)) + ": " + str(numFrames) + " " + str(startOffset)) + # print(str(hex(startAddress)) + ": " + str(numFrames) + " " + str(startOffset)) return SM64_AnimIndex(numFrames, startOffset) @@ -956,7 +955,9 @@ def execute(self, context): if armatureObj.type != "ARMATURE": raise PluginError("Armature not selected.") - importAnimationToBlender(romfileSrc, animStart, armatureObj, segmentData, context.scene.isDMAImport, "sm64_anim") + importAnimationToBlender( + romfileSrc, animStart, armatureObj, segmentData, context.scene.isDMAImport, "sm64_anim" + ) romfileSrc.close() self.report({"INFO"}, "Success!") except Exception as e: @@ -992,7 +993,7 @@ def execute(self, context): for adress, animName in marioAnimations: importAnimationToBlender(romfileSrc, adress, armatureObj, {}, context.scene.isDMAImport, animName) - + romfileSrc.close() self.report({"INFO"}, "Success!") except Exception as e: @@ -1012,8 +1013,8 @@ class SM64_ImportAnimPanel(SM64_Panel): # called every frame def draw(self, context): col = self.layout.column() - propsAnimImport = col.operator(SM64_ImportAnimMario.bl_idname) - propsMarioAnimsImport = col.operator(SM64_ImportAllMarioAnims.bl_idname) + propsAnimImport = col.operator(SM64_ImportAnimMario.bl_idname) + propsMarioAnimsImport = col.operator(SM64_ImportAllMarioAnims.bl_idname) col.prop(context.scene, "isDMAImport") if not context.scene.isDMAImport: diff --git a/fast64_internal/sm64/sm64_collision.py b/fast64_internal/sm64/sm64_collision.py index 060cd3a26..b79e1aedf 100644 --- a/fast64_internal/sm64/sm64_collision.py +++ b/fast64_internal/sm64/sm64_collision.py @@ -295,7 +295,6 @@ def exportCollisionC( groupName, levelName, ): - dirPath, texDir = getExportDir(customExport, dirPath, headerType, levelName, "", name) name = toAlnum(name) @@ -396,7 +395,7 @@ def exportCollisionCommon(obj, transformMatrix, includeSpecials, includeChildren collision = Collision(toAlnum(name) + "_collision") for collisionType, faces in collisionDict.items(): collision.triangles[collisionType] = [] - for (faceVerts, specialParam, room) in faces: + for faceVerts, specialParam, room in faces: indices = [] for roundedPosition in faceVerts: index = collisionVertIndex(roundedPosition, collision.vertices) diff --git a/fast64_internal/sm64/sm64_constants.py b/fast64_internal/sm64/sm64_constants.py index ed20b6dd0..a27ba8554 100644 --- a/fast64_internal/sm64/sm64_constants.py +++ b/fast64_internal/sm64/sm64_constants.py @@ -1801,214 +1801,214 @@ def __init__(self, geoAddr, level, switchDict): marioAnimations = [ -# ( Adress, "Animation name" ), - ( 5162640, "0 - Slow ledge climb up"), - ( 5165520, "1 - Fall over backwards"), - ( 5165544, "2 - Backward air kb"), - ( 5172396, "3 - Dying on back"), - ( 5177044, "4 - Backflip"), - ( 5179584, "5 - Climbing up pole"), - ( 5185656, "6 - Grab pole short"), - ( 5186824, "7 - Grab pole swing part 1"), - ( 5186848, "8 - Grab pole swing part 2"), - ( 5191920, "9 - Handstand idle"), - ( 5194740, "10 - Handstand jump"), - ( 5194764, "11 - Start handstand"), - ( 5188592, "12 - Return from handstand"), - ( 5196388, "13 - Idle on pole"), - ( 5197436, "14 - A pose"), - ( 5197792, "15 - Skid on ground"), - ( 5197816, "16 - Stop skid"), - ( 5199596, "17 - Crouch from fast longjump"), - ( 5201048, "18 - Crouch from a slow longjump"), - ( 5202644, "19 - Fast longjump"), - ( 5204600, "20 - Slow longjump"), - ( 5205980, "21 - Airborne on stomach"), - ( 5207188, "22 - Walk with light object"), - ( 5211916, "23 - Run with light object"), - ( 5215136, "24 - Slow walk with light object"), - ( 5219864, "25 - Shivering and warming hands"), - ( 5225496, "26 - Shivering return to idle "), - ( 5226920, "27 - Shivering"), - ( 5230056, "28 - Climb down on ledge"), - ( 5231112, "29 - Credits - Waving"), - ( 5232768, "30 - Credits - Look up"), - ( 5234576, "31 - Credits - Return from look up"), - ( 5235700, "32 - Credits - Raising hand"), - ( 5243100, "33 - Credits - Lowering hand"), - ( 5245988, "34 - Credits - Taking off cap"), - ( 5248016, "35 - Credits - Start walking and look up"), - ( 5256508, "36 - Credits - Look back then run"), - ( 5266160, "37 - Final Bowser - Raise hand and spin"), - ( 5274456, "38 - Final Bowser - Wing cap take off"), - ( 5282084, "39 - Credits - Peach sign"), - ( 5291340, "40 - Stand up from lava boost"), - ( 5292628, "41 - Fire/Lava burn"), - ( 5293488, "42 - Wing cap flying"), - ( 5295016, "43 - Hang on owl"), - ( 5296876, "44 - Land on stomach"), - ( 5296900, "45 - Air forward kb"), - ( 5302796, "46 - Dying on stomach"), - ( 5306100, "47 - Suffocating"), - ( 5313796, "48 - Coughing"), - ( 5319500, "49 - Throw catch key"), - ( 5330436, "50 - Dying fall over"), - ( 5338604, "51 - Idle on ledge"), - ( 5341720, "52 - Fast ledge grab"), - ( 5343296, "53 - Hang on ceiling"), - ( 5347276, "54 - Put cap on"), - ( 5351252, "55 - Take cap off then on"), - ( 5358356, "56 - Quickly put cap on"), - ( 5359476, "57 - Head stuck in ground"), - ( 5372172, "58 - Ground pound landing"), - ( 5372824, "59 - Triple jump ground-pound"), - ( 5374304, "60 - Start ground-pound"), - ( 5374328, "61 - Ground-pound"), - ( 5375380, "62 - Bottom stuck in ground"), - ( 5387148, "63 - Idle with light object"), - ( 5390520, "64 - Jump land with light object"), - ( 5391892, "65 - Jump with light object"), - ( 5392704, "66 - Fall land with light object"), - ( 5393936, "67 - Fall with light object"), - ( 5394296, "68 - Fall from sliding with light object"), - ( 5395224, "69 - Sliding on bottom with light object"), - ( 5395248, "70 - Stand up from sliding with light object"), - ( 5396716, "71 - Riding shell"), - ( 5397832, "72 - Walking"), - ( 5403208, "73 - Forward flip"), - ( 5404784, "74 - Jump riding shell"), - ( 5405676, "75 - Land from double jump"), - ( 5407340, "76 - Double jump fall"), - ( 5408288, "77 - Single jump"), - ( 5408312, "78 - Land from single jump"), - ( 5411044, "79 - Air kick"), - ( 5412900, "80 - Double jump rise"), - ( 5413596, "81 - Start forward spinning"), - ( 5414876, "82 - Throw light object"), - ( 5416032, "83 - Fall from slide kick"), - ( 5418280, "84 - Bend kness riding shell"), - ( 5419872, "85 - Legs stuck in ground"), - ( 5431416, "86 - General fall"), - ( 5431440, "87 - General land"), - ( 5433276, "88 - Being grabbed"), - ( 5434636, "89 - Grab heavy object"), - ( 5437964, "90 - Slow land from dive"), - ( 5441520, "91 - Fly from cannon"), - ( 5442516, "92 - Moving right while hanging"), - ( 5444052, "93 - Moving left while hanging"), - ( 5445472, "94 - Missing cap"), - ( 5457860, "95 - Pull door walk in"), - ( 5463196, "96 - Push door walk in"), - ( 5467492, "97 - Unlock door"), - ( 5480428, "98 - Start reach pocket"), - ( 5481448, "99 - Reach pocket"), - ( 5483352, "100 - Stop reach pocket"), - ( 5484876, "101 - Ground throw"), - ( 5486852, "102 - Ground kick"), - ( 5489076, "103 - First punch"), - ( 5489740, "104 - Second punch"), - ( 5490356, "105 - First punch fast"), - ( 5491396, "106 - Second punch fast"), - ( 5492732, "107 - Pick up light object"), - ( 5493948, "108 - Pushing"), - ( 5495508, "109 - Start riding shell"), - ( 5497072, "110 - Place light object"), - ( 5498484, "111 - Forward spinning"), - ( 5498508, "112 - Backward spinning"), - ( 5498884, "113 - Breakdance"), - ( 5501240, "114 - Running"), - ( 5501264, "115 - Running (unused)"), - ( 5505884, "116 - Soft back kb"), - ( 5508004, "117 - Soft front kb"), - ( 5510172, "118 - Dying in quicksand"), - ( 5515096, "119 - Idle in quicksand"), - ( 5517836, "120 - Move in quicksand"), - ( 5528568, "121 - Electrocution"), - ( 5532480, "122 - Shocked"), - ( 5533160, "123 - Backward kb"), - ( 5535796, "124 - Forward kb"), - ( 5538372, "125 - Idle heavy object"), - ( 5539764, "126 - Stand against wall"), - ( 5544580, "127 - Side step left"), - ( 5548480, "128 - Side step right"), - ( 5553004, "129 - Start sleep idle"), - ( 5557588, "130 - Start sleep scratch"), - ( 5563636, "131 - Start sleep yawn"), - ( 5568648, "132 - Start sleep sitting"), - ( 5573680, "133 - Sleep idle"), - ( 5574280, "134 - Sleep start laying"), - ( 5577460, "135 - Sleep laying"), - ( 5579300, "136 - Dive"), - ( 5579324, "137 - Slide dive"), - ( 5580860, "138 - Ground bonk"), - ( 5584116, "139 - Stop slide light object"), - ( 5587364, "140 - Slide kick"), - ( 5588288, "141 - Crouch from slide kick"), - ( 5589652, "142 - Slide motionless"), - ( 5589676, "143 - Stop slide"), - ( 5591572, "144 - Fall from slide"), - ( 5592860, "145 - Slide"), - ( 5593404, "146 - Tiptoe"), - ( 5599280, "147 - Twirl land"), - ( 5600160, "148 - Twirl"), - ( 5600516, "149 - Start twirl"), - ( 5601072, "150 - Stop crouching"), - ( 5602028, "151 - Start crouching"), - ( 5602720, "152 - Crouching"), - ( 5605756, "153 - Crawling"), - ( 5613048, "154 - Stop crawling"), - ( 5613968, "155 - Start crawling"), - ( 5614876, "156 - Summon star"), - ( 5620036, "157 - Return star approach door"), - ( 5622256, "158 - Backwards water kb"), - ( 5626540, "159 - Swim with object part 1"), - ( 5627592, "160 - Swim with object part 2"), - ( 5628260, "161 - Flutter kick with object"), - ( 5629456, "162 - Action end with object in water"), - ( 5631180, "163 - Stop holding object in water"), - ( 5634048, "164 - Holding object in water"), - ( 5635976, "165 - Drowning part 1"), - ( 5641400, "166 - Drowning part 2"), - ( 5646324, "167 - Dying in water"), - ( 5649660, "168 - Forward kb in water"), - ( 5653848, "169 - Falling from water"), - ( 5655852, "170 - Swimming part 1"), - ( 5657100, "171 - Swimming part 2"), - ( 5658128, "172 - Flutter kick"), - ( 5660112, "173 - Action end in water"), - ( 5662248, "174 - Pick up object in water"), - ( 5663480, "175 - Grab object in water part 2"), - ( 5665916, "176 - Grab object in water part 1"), - ( 5666632, "177 - Throw object in water"), - ( 5669328, "178 - Idle in water"), - ( 5671428, "179 - Star dance in water"), - ( 5678200, "180 - Return from in water star dance"), - ( 5680324, "181 - Grab bowser"), - ( 5680348, "182 - Swing bowser"), - ( 5682008, "183 - Release bowser"), - ( 5685264, "184 - Holding bowser"), - ( 5686316, "185 - Heavy throw"), - ( 5688660, "186 - Walk panting"), - ( 5689924, "187 - Walk with heavy object"), - ( 5694332, "188 - Turning part 1"), - ( 5694356, "189 - Turning part 2"), - ( 5696160, "190 - Side flip land"), - ( 5697196, "191 - Side flip"), - ( 5699408, "192 - Triple jump land"), - ( 5702136, "193 - Triple jump"), - ( 5704880, "194 - First person"), - ( 5710580, "195 - Idle head left"), - ( 5712800, "196 - Idle head right"), - ( 5715020, "197 - Idle head center"), - ( 5717240, "198 - Handstand left"), - ( 5719184, "199 - Handstand right"), - ( 5722304, "200 - Wake up from sleeping"), - ( 5724228, "201 - Wake up from laying"), - ( 5726444, "202 - Start tiptoeing"), - ( 5728720, "203 - Slide jump"), - ( 5728744, "204 - Start wallkick"), - ( 5730404, "205 - Star dance"), - ( 5735864, "206 - Return from star dance"), - ( 5737600, "207 - Forwards spinning flip"), - ( 5740584, "208 - Triple jump fly"), + # ( Adress, "Animation name" ), + (5162640, "0 - Slow ledge climb up"), + (5165520, "1 - Fall over backwards"), + (5165544, "2 - Backward air kb"), + (5172396, "3 - Dying on back"), + (5177044, "4 - Backflip"), + (5179584, "5 - Climbing up pole"), + (5185656, "6 - Grab pole short"), + (5186824, "7 - Grab pole swing part 1"), + (5186848, "8 - Grab pole swing part 2"), + (5191920, "9 - Handstand idle"), + (5194740, "10 - Handstand jump"), + (5194764, "11 - Start handstand"), + (5188592, "12 - Return from handstand"), + (5196388, "13 - Idle on pole"), + (5197436, "14 - A pose"), + (5197792, "15 - Skid on ground"), + (5197816, "16 - Stop skid"), + (5199596, "17 - Crouch from fast longjump"), + (5201048, "18 - Crouch from a slow longjump"), + (5202644, "19 - Fast longjump"), + (5204600, "20 - Slow longjump"), + (5205980, "21 - Airborne on stomach"), + (5207188, "22 - Walk with light object"), + (5211916, "23 - Run with light object"), + (5215136, "24 - Slow walk with light object"), + (5219864, "25 - Shivering and warming hands"), + (5225496, "26 - Shivering return to idle "), + (5226920, "27 - Shivering"), + (5230056, "28 - Climb down on ledge"), + (5231112, "29 - Credits - Waving"), + (5232768, "30 - Credits - Look up"), + (5234576, "31 - Credits - Return from look up"), + (5235700, "32 - Credits - Raising hand"), + (5243100, "33 - Credits - Lowering hand"), + (5245988, "34 - Credits - Taking off cap"), + (5248016, "35 - Credits - Start walking and look up"), + (5256508, "36 - Credits - Look back then run"), + (5266160, "37 - Final Bowser - Raise hand and spin"), + (5274456, "38 - Final Bowser - Wing cap take off"), + (5282084, "39 - Credits - Peach sign"), + (5291340, "40 - Stand up from lava boost"), + (5292628, "41 - Fire/Lava burn"), + (5293488, "42 - Wing cap flying"), + (5295016, "43 - Hang on owl"), + (5296876, "44 - Land on stomach"), + (5296900, "45 - Air forward kb"), + (5302796, "46 - Dying on stomach"), + (5306100, "47 - Suffocating"), + (5313796, "48 - Coughing"), + (5319500, "49 - Throw catch key"), + (5330436, "50 - Dying fall over"), + (5338604, "51 - Idle on ledge"), + (5341720, "52 - Fast ledge grab"), + (5343296, "53 - Hang on ceiling"), + (5347276, "54 - Put cap on"), + (5351252, "55 - Take cap off then on"), + (5358356, "56 - Quickly put cap on"), + (5359476, "57 - Head stuck in ground"), + (5372172, "58 - Ground pound landing"), + (5372824, "59 - Triple jump ground-pound"), + (5374304, "60 - Start ground-pound"), + (5374328, "61 - Ground-pound"), + (5375380, "62 - Bottom stuck in ground"), + (5387148, "63 - Idle with light object"), + (5390520, "64 - Jump land with light object"), + (5391892, "65 - Jump with light object"), + (5392704, "66 - Fall land with light object"), + (5393936, "67 - Fall with light object"), + (5394296, "68 - Fall from sliding with light object"), + (5395224, "69 - Sliding on bottom with light object"), + (5395248, "70 - Stand up from sliding with light object"), + (5396716, "71 - Riding shell"), + (5397832, "72 - Walking"), + (5403208, "73 - Forward flip"), + (5404784, "74 - Jump riding shell"), + (5405676, "75 - Land from double jump"), + (5407340, "76 - Double jump fall"), + (5408288, "77 - Single jump"), + (5408312, "78 - Land from single jump"), + (5411044, "79 - Air kick"), + (5412900, "80 - Double jump rise"), + (5413596, "81 - Start forward spinning"), + (5414876, "82 - Throw light object"), + (5416032, "83 - Fall from slide kick"), + (5418280, "84 - Bend kness riding shell"), + (5419872, "85 - Legs stuck in ground"), + (5431416, "86 - General fall"), + (5431440, "87 - General land"), + (5433276, "88 - Being grabbed"), + (5434636, "89 - Grab heavy object"), + (5437964, "90 - Slow land from dive"), + (5441520, "91 - Fly from cannon"), + (5442516, "92 - Moving right while hanging"), + (5444052, "93 - Moving left while hanging"), + (5445472, "94 - Missing cap"), + (5457860, "95 - Pull door walk in"), + (5463196, "96 - Push door walk in"), + (5467492, "97 - Unlock door"), + (5480428, "98 - Start reach pocket"), + (5481448, "99 - Reach pocket"), + (5483352, "100 - Stop reach pocket"), + (5484876, "101 - Ground throw"), + (5486852, "102 - Ground kick"), + (5489076, "103 - First punch"), + (5489740, "104 - Second punch"), + (5490356, "105 - First punch fast"), + (5491396, "106 - Second punch fast"), + (5492732, "107 - Pick up light object"), + (5493948, "108 - Pushing"), + (5495508, "109 - Start riding shell"), + (5497072, "110 - Place light object"), + (5498484, "111 - Forward spinning"), + (5498508, "112 - Backward spinning"), + (5498884, "113 - Breakdance"), + (5501240, "114 - Running"), + (5501264, "115 - Running (unused)"), + (5505884, "116 - Soft back kb"), + (5508004, "117 - Soft front kb"), + (5510172, "118 - Dying in quicksand"), + (5515096, "119 - Idle in quicksand"), + (5517836, "120 - Move in quicksand"), + (5528568, "121 - Electrocution"), + (5532480, "122 - Shocked"), + (5533160, "123 - Backward kb"), + (5535796, "124 - Forward kb"), + (5538372, "125 - Idle heavy object"), + (5539764, "126 - Stand against wall"), + (5544580, "127 - Side step left"), + (5548480, "128 - Side step right"), + (5553004, "129 - Start sleep idle"), + (5557588, "130 - Start sleep scratch"), + (5563636, "131 - Start sleep yawn"), + (5568648, "132 - Start sleep sitting"), + (5573680, "133 - Sleep idle"), + (5574280, "134 - Sleep start laying"), + (5577460, "135 - Sleep laying"), + (5579300, "136 - Dive"), + (5579324, "137 - Slide dive"), + (5580860, "138 - Ground bonk"), + (5584116, "139 - Stop slide light object"), + (5587364, "140 - Slide kick"), + (5588288, "141 - Crouch from slide kick"), + (5589652, "142 - Slide motionless"), + (5589676, "143 - Stop slide"), + (5591572, "144 - Fall from slide"), + (5592860, "145 - Slide"), + (5593404, "146 - Tiptoe"), + (5599280, "147 - Twirl land"), + (5600160, "148 - Twirl"), + (5600516, "149 - Start twirl"), + (5601072, "150 - Stop crouching"), + (5602028, "151 - Start crouching"), + (5602720, "152 - Crouching"), + (5605756, "153 - Crawling"), + (5613048, "154 - Stop crawling"), + (5613968, "155 - Start crawling"), + (5614876, "156 - Summon star"), + (5620036, "157 - Return star approach door"), + (5622256, "158 - Backwards water kb"), + (5626540, "159 - Swim with object part 1"), + (5627592, "160 - Swim with object part 2"), + (5628260, "161 - Flutter kick with object"), + (5629456, "162 - Action end with object in water"), + (5631180, "163 - Stop holding object in water"), + (5634048, "164 - Holding object in water"), + (5635976, "165 - Drowning part 1"), + (5641400, "166 - Drowning part 2"), + (5646324, "167 - Dying in water"), + (5649660, "168 - Forward kb in water"), + (5653848, "169 - Falling from water"), + (5655852, "170 - Swimming part 1"), + (5657100, "171 - Swimming part 2"), + (5658128, "172 - Flutter kick"), + (5660112, "173 - Action end in water"), + (5662248, "174 - Pick up object in water"), + (5663480, "175 - Grab object in water part 2"), + (5665916, "176 - Grab object in water part 1"), + (5666632, "177 - Throw object in water"), + (5669328, "178 - Idle in water"), + (5671428, "179 - Star dance in water"), + (5678200, "180 - Return from in water star dance"), + (5680324, "181 - Grab bowser"), + (5680348, "182 - Swing bowser"), + (5682008, "183 - Release bowser"), + (5685264, "184 - Holding bowser"), + (5686316, "185 - Heavy throw"), + (5688660, "186 - Walk panting"), + (5689924, "187 - Walk with heavy object"), + (5694332, "188 - Turning part 1"), + (5694356, "189 - Turning part 2"), + (5696160, "190 - Side flip land"), + (5697196, "191 - Side flip"), + (5699408, "192 - Triple jump land"), + (5702136, "193 - Triple jump"), + (5704880, "194 - First person"), + (5710580, "195 - Idle head left"), + (5712800, "196 - Idle head right"), + (5715020, "197 - Idle head center"), + (5717240, "198 - Handstand left"), + (5719184, "199 - Handstand right"), + (5722304, "200 - Wake up from sleeping"), + (5724228, "201 - Wake up from laying"), + (5726444, "202 - Start tiptoeing"), + (5728720, "203 - Slide jump"), + (5728744, "204 - Start wallkick"), + (5730404, "205 - Star dance"), + (5735864, "206 - Return from star dance"), + (5737600, "207 - Forwards spinning flip"), + (5740584, "208 - Triple jump fly"), ] diff --git a/fast64_internal/sm64/sm64_geolayout_classes.py b/fast64_internal/sm64/sm64_geolayout_classes.py index 23fa4c39d..3b93d8d53 100644 --- a/fast64_internal/sm64/sm64_geolayout_classes.py +++ b/fast64_internal/sm64/sm64_geolayout_classes.py @@ -263,7 +263,7 @@ class BaseDisplayListNode: """Base displaylist node with common helper functions dealing with displaylists""" dl_ext = "WITH_DL" # add dl_ext to geo command if command has a displaylist - bleed_independently = False # base behavior, can be changed with obj boolProp + bleed_independently = False # base behavior, can be changed with obj boolProp def get_dl_address(self): if self.hasDL and (self.dlRef or self.DLmicrocode is not None): @@ -455,13 +455,15 @@ def to_c(self): class GeoLayoutBleed(BleedGraphics): def bleed_geo_layout_graph(self, fModel: FModel, geo_layout_graph: GeolayoutGraph, use_rooms: bool = False): last_materials = dict() # last used material should be kept track of per layer - + def walk(node, last_materials): base_node = node.node if type(base_node) == JumpNode: if base_node.geolayout: for node in base_node.geolayout.nodes: - last_materials = walk(node, last_materials if not use_rooms else dict()) if not use_rooms else dict() + last_materials = ( + walk(node, last_materials if not use_rooms else dict()) if not use_rooms else dict() + ) else: last_materials = dict() fMesh = getattr(base_node, "fMesh", None) @@ -469,7 +471,13 @@ def walk(node, last_materials): cmd_list = fMesh.drawMatOverrides.get(base_node.override_hash, None) or fMesh.draw last_mat = last_materials.get(base_node.drawLayer, None) default_render_mode = fModel.getRenderMode(base_node.drawLayer) - last_mat = self.bleed_fmesh(fMesh, last_mat if not base_node.bleed_independently else None, cmd_list, fModel.getAllMaterials().items(), default_render_mode) + last_mat = self.bleed_fmesh( + fMesh, + last_mat if not base_node.bleed_independently else None, + cmd_list, + fModel.getAllMaterials().items(), + default_render_mode, + ) # if the mesh has culling, it can be culled, and create invalid combinations of f3d to represent the current full DL if fMesh.cullVertexList: last_materials[base_node.drawLayer] = None @@ -481,7 +489,7 @@ def walk(node, last_materials): last_materials = dict() last_materials = walk(child, last_materials) return last_materials - + for node in geo_layout_graph.startGeolayout.nodes: last_materials = walk(node, last_materials) self.clear_gfx_lists(fModel) @@ -607,7 +615,6 @@ def to_c(self): class TranslateRotateNode(BaseDisplayListNode): def __init__(self, drawLayer, fieldLayout, hasDL, translate, rotate, dlRef: str = None): - self.drawLayer = drawLayer self.fieldLayout = fieldLayout self.hasDL = hasDL diff --git a/fast64_internal/sm64/sm64_geolayout_writer.py b/fast64_internal/sm64/sm64_geolayout_writer.py index 678edbbdc..73c3abcb5 100644 --- a/fast64_internal/sm64/sm64_geolayout_writer.py +++ b/fast64_internal/sm64/sm64_geolayout_writer.py @@ -344,7 +344,7 @@ def appendRevertToGeolayout(geolayoutGraph, fModel): # walk the geo layout graph to find the last used DL for each layer last_gfx_list = dict() - + def walk(node, last_gfx_list): base_node = node.node if type(base_node) == JumpNode: @@ -360,7 +360,7 @@ def walk(node, last_gfx_list): for child in node.children: last_gfx_list = walk(child, last_gfx_list) return last_gfx_list - + for node in geolayoutGraph.startGeolayout.nodes: last_gfx_list = walk(node, last_gfx_list) @@ -369,7 +369,7 @@ def walk(node, last_gfx_list): # remove SPEndDisplayList from gfx_list, materialRevert has its own SPEndDisplayList cmd while SPEndDisplayList() in gfx_list.commands: gfx_list.commands.remove(SPEndDisplayList()) - + gfx_list.commands.extend(materialRevert.commands) diff --git a/fast64_internal/sm64/sm64_objects.py b/fast64_internal/sm64/sm64_objects.py index 5e92fe6b3..7d82b49e1 100644 --- a/fast64_internal/sm64/sm64_objects.py +++ b/fast64_internal/sm64/sm64_objects.py @@ -1088,7 +1088,9 @@ class SM64ObjectPanel(bpy.types.Panel): @classmethod def poll(cls, context): - return context.scene.gameEditorMode == "SM64" and (context.object is not None and context.object.type == "EMPTY") + return context.scene.gameEditorMode == "SM64" and ( + context.object is not None and context.object.type == "EMPTY" + ) def draw_inline_obj(self, box: bpy.types.UILayout, obj: bpy.types.Object): obj_details: InlineGeolayoutObjConfig = inlineGeoLayoutObjects.get(obj.sm64_obj_type) diff --git a/fast64_internal/sm64/sm64_rom_tweaks.py b/fast64_internal/sm64/sm64_rom_tweaks.py index 76783296e..bd50b9cb8 100644 --- a/fast64_internal/sm64/sm64_rom_tweaks.py +++ b/fast64_internal/sm64/sm64_rom_tweaks.py @@ -3,7 +3,6 @@ def ExtendBank0x04(romfile, segmentData, segment4): - # Extend bank 0x04 romfile.seek(loadSegmentAddresses[0x04] + 4) oldStart = int.from_bytes(romfile.read(4), "big") diff --git a/fast64_internal/sm64/sm64_texscroll.py b/fast64_internal/sm64/sm64_texscroll.py index 441c2eaed..c9e6ec736 100644 --- a/fast64_internal/sm64/sm64_texscroll.py +++ b/fast64_internal/sm64/sm64_texscroll.py @@ -348,7 +348,6 @@ def modifyTexScrollHeadersGroup( def writeTexScrollHeadersGroup( exportDir: str, includeC: str, includeH: str, groupName: str, topLevelScrollFunc: str, dataInclude: str ): - # Create group scroll files fileStatus = createTexScrollHeadersGroup(exportDir, groupName, dataInclude) @@ -399,7 +398,6 @@ def writeTexScrollHeadersGroup( def removeTexScrollHeadersGroup(exportDir: str, includeC: str, includeH: str, groupName: str, topLevelScrollFunc: str): - includeH += "\n" includeC += "\n" diff --git a/fast64_internal/sm64/sm64_utility.py b/fast64_internal/sm64/sm64_utility.py index 9c72320d1..f06348683 100644 --- a/fast64_internal/sm64/sm64_utility.py +++ b/fast64_internal/sm64/sm64_utility.py @@ -1,17 +1,21 @@ import os + def starSelectWarning(operator, fileStatus): - if fileStatus is not None and not fileStatus.starSelectC: - operator.report({'WARNING'}, "star_select.c not found, skipping star select scrolling.") + if fileStatus is not None and not fileStatus.starSelectC: + operator.report({"WARNING"}, "star_select.c not found, skipping star select scrolling.") + def cameraWarning(operator, fileStatus): - if fileStatus is not None and not fileStatus.cameraC: - operator.report({'WARNING'}, "camera.c not found, skipping camera volume and zoom mask exporting.") + if fileStatus is not None and not fileStatus.cameraC: + operator.report({"WARNING"}, "camera.c not found, skipping camera volume and zoom mask exporting.") + + +ULTRA_SM64_MEMORY_C = "src/boot/memory.c" +SM64_MEMORY_C = "src/game/memory.c" -ULTRA_SM64_MEMORY_C = 'src/boot/memory.c' -SM64_MEMORY_C = 'src/game/memory.c' def getMemoryCFilePath(decompDir): - isUltra = os.path.exists(os.path.join(decompDir, ULTRA_SM64_MEMORY_C)) - relPath = ULTRA_SM64_MEMORY_C if isUltra else SM64_MEMORY_C - return os.path.join(decompDir, relPath) \ No newline at end of file + isUltra = os.path.exists(os.path.join(decompDir, ULTRA_SM64_MEMORY_C)) + relPath = ULTRA_SM64_MEMORY_C if isUltra else SM64_MEMORY_C + return os.path.join(decompDir, relPath) diff --git a/fast64_internal/utility.py b/fast64_internal/utility.py index c0775c84c..4d301e7b8 100644 --- a/fast64_internal/utility.py +++ b/fast64_internal/utility.py @@ -610,7 +610,7 @@ def int_from_s16(value: int) -> int: def int_from_s16_str(value: str) -> int: return int_from_s16(int(value, 0)) - + def float_from_u16_str(value: str) -> float: return float(int(value, 0)) / (2**16) @@ -1204,7 +1204,7 @@ def multilineLabel(layout: UILayout, text: str, icon: str = "NONE"): layout = layout.column() for i, line in enumerate(text.split("\n")): r = layout.row() - r.label(text = line, icon = icon if i == 0 else "NONE") + r.label(text=line, icon=icon if i == 0 else "NONE") r.scale_y = 0.75 diff --git a/fast64_internal/utility_anim.py b/fast64_internal/utility_anim.py index 488a09771..982706a16 100644 --- a/fast64_internal/utility_anim.py +++ b/fast64_internal/utility_anim.py @@ -23,7 +23,6 @@ class ArmatureApplyWithMeshOperator(bpy.types.Operator): # Called on demand (i.e. button press, menu item) # Can also be called from operator search menu (Spacebar) def execute(self, context): - from .utility import PluginError, raisePluginError try: @@ -179,6 +178,7 @@ def getIntersectionInterval(): return range_get_by_choice[anim_range_choice]() + def stashActionInArmature(armatureObj: bpy.types.Object, action: bpy.types.Action): """ Stashes an animation (action) into an armature´s nla tracks. @@ -194,11 +194,12 @@ def stashActionInArmature(armatureObj: bpy.types.Object, action: bpy.types.Actio if strip.action.name == action.name: return - print(f"Stashing \"{action.name}\" in the object \"{armatureObj.name}\".") + print(f'Stashing "{action.name}" in the object "{armatureObj.name}".') track = armatureObj.animation_data.nla_tracks.new() track.strips.new(action.name, int(action.frame_range[0]), action) + classes = (ArmatureApplyWithMeshOperator,) @@ -209,6 +210,5 @@ def utility_anim_register(): # called on add-on disabling def utility_anim_unregister(): - for cls in classes: unregister_class(cls) From ee6adccf5bcf8c0400d7e1d1dd5c6bc2a61dbfac Mon Sep 17 00:00:00 2001 From: Dragorn421 Date: Sat, 6 Jan 2024 13:37:00 +0100 Subject: [PATCH 2/2] Update ignored files for formatting, add updater files (since they come from another repo) --- pyproject.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 3340c81dc..368e56003 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,11 @@ target-version = [ # What files to exclude when running Black on directories (for example `black .`) # Use forward slashes for directory delimiters, even on Windows # This is a regular expression, escape dots with a backslash like '\.' -# Note: All whitespace seems to be trimmed (thankfully), probably by Black? +# Note: All whitespace seems to be removed (thankfully), probably by Black? extend-exclude = ''' -^/fast64_internal/f3d/f3d_constants\.py +^ +/fast64_internal/f3d/f3d_constants\.py +|addon_updater\.py +|addon_updater_ops\.py +$ '''