Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[F3D] Edge case for decals, use hashed for cutout materials instead of blend + more #401

Merged
merged 18 commits into from
Aug 20, 2024
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 20 additions & 9 deletions fast64_internal/f3d/f3d_gbi.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,15 +72,26 @@ class GfxMatWriteMethod(enum.Enum):
"F3DEX3": (56, 56),
}

drawLayerRenderMode = {
0: ("G_RM_ZB_OPA_SURF", "G_RM_NOOP2"),
1: ("G_RM_AA_ZB_OPA_SURF", "G_RM_NOOP2"),
2: ("G_RM_AA_ZB_OPA_DECAL", "G_RM_NOOP2"),
3: ("G_RM_AA_ZB_OPA_INTER", "G_RM_NOOP2"),
4: ("G_RM_AA_ZB_TEX_EDGE", "G_RM_NOOP2"),
5: ("G_RM_AA_ZB_XLU_SURF", "G_RM_NOOP2"),
6: ("G_RM_AA_ZB_XLU_DECAL", "G_RM_NOOP2"),
7: ("G_RM_AA_ZB_XLU_INTER", "G_RM_NOOP2"),
sm64_default_draw_layers = {
"0": ("G_RM_ZB_OPA_SURF", "G_RM_NOOP2"),
"1": ("G_RM_AA_ZB_OPA_SURF", "G_RM_NOOP2"),
"2": ("G_RM_AA_ZB_OPA_DECAL", "G_RM_NOOP2"),
"3": ("G_RM_AA_ZB_OPA_INTER", "G_RM_NOOP2"),
"4": ("G_RM_AA_ZB_TEX_EDGE", "G_RM_NOOP2"),
"5": ("G_RM_AA_ZB_XLU_SURF", "G_RM_NOOP2"),
"6": ("G_RM_AA_ZB_XLU_DECAL", "G_RM_NOOP2"),
"7": ("G_RM_AA_ZB_XLU_INTER", "G_RM_NOOP2"),
}

oot_default_draw_layers = {
"Opaque": ("G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"),
"Transparent": ("G_RM_AA_ZB_XLU_SURF", "G_RM_AA_ZB_XLU_SURF2"),
"Overlay": ("G_RM_AA_ZB_OPA_SURF", "G_RM_AA_ZB_OPA_SURF2"),
}

default_draw_layers = {
"SM64": sm64_default_draw_layers,
"OOT": oot_default_draw_layers,
}

CCMUXDict = {
Expand Down
94 changes: 62 additions & 32 deletions fast64_internal/f3d/f3d_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from mathutils import Color

from .f3d_enums import *
from .f3d_gbi import get_F3D_GBI, GBL_c1, GBL_c2, enumTexScroll, isUcodeF3DEX1
from .f3d_gbi import get_F3D_GBI, enumTexScroll, isUcodeF3DEX1, default_draw_layers
from .f3d_material_presets import *
from ..utility import *
from ..render_settings import Fast64RenderSettings_Properties, update_scene_props_from_render_settings
Expand Down Expand Up @@ -115,17 +115,6 @@
"Overlay": "1",
}

drawLayerSM64Alpha = {
"0": "OPA",
"1": "OPA",
"2": "OPA",
"3": "OPA",
"4": "CLIP",
"5": "XLU",
"6": "XLU",
"7": "XLU",
}

enumF3DMenu = [
("Combiner", "Combiner", "Combiner"),
("Sources", "Sources", "Sources"),
Expand Down Expand Up @@ -180,17 +169,52 @@ def update_draw_layer(self, context):
set_output_node_groups(material)


world_layer_defaults_attrs = {
"SM64": lambda world, layer: (
getattr(world, f"draw_layer_{layer}_cycle_1", ""),
getattr(world, f"draw_layer_{layer}_cycle_2", ""),
),
"OOT": lambda world, layer: (
getattr(world.ootDefaultRenderModes, f"{layer.lower()}Cycle1", ""),
getattr(world.ootDefaultRenderModes, f"{layer.lower()}Cycle2", ""),
),
}


def rendermode_preset_to_advanced(material: bpy.types.Material):
"""
Set all individual controls for the rendermode from the preset rendermode.
"""
settings = material.f3d_mat.rdp_settings
scene = bpy.context.scene
f3d_mat = material.f3d_mat
settings = f3d_mat.rdp_settings
f3d = get_F3D_GBI()

if settings.rendermode_advanced_enabled:
if settings.rendermode_advanced_enabled and settings.set_rendermode:
# Already in advanced mode, don't overwrite this with the preset
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can you update the comment to explain what happens wrt set_rendermode

afaict you're basically implementing material bleed from world defaults in the props. Wouldn't this be simpler by just setting the preset to the world defaults preset if set_rendermode is unchecked?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you give me feedback on if the comments are good now?

return

if settings.set_rendermode:
cycle_1, cycle_2 = settings.rendermode_preset_cycle_1, settings.rendermode_preset_cycle_2
else:
game_mode = scene.gameEditorMode
layer = getattr(f3d_mat.draw_layer, game_mode.lower(), None)
if layer is None: # Game mode has no layer, don´t change anything
return

# If no world defaults for game mode, fallback on get_with_default default arg
cycle_1, cycle_2 = default_draw_layers.get(game_mode, {}).get(layer, ("", ""))
if scene.world is not None and game_mode in world_layer_defaults_attrs:
possible_cycle_1, possible_cycle_2 = world_layer_defaults_attrs[game_mode](scene.world, layer)
Lilaa3 marked this conversation as resolved.
Show resolved Hide resolved
if getattr(f3d, possible_cycle_1, None) is not None and getattr(f3d, possible_cycle_2, None) is not None:
cycle_1, cycle_2 = possible_cycle_1, possible_cycle_2
try:
settings.rendermode_preset_cycle_1, settings.rendermode_preset_cycle_2 = cycle_1, cycle_2
except TypeError as exc:
print(
f"Render mode presets {cycle_1} or {cycle_2} probably not included in render mode preset enum:\n{exc}",
)

def get_with_default(preset, default):
# Use the material's settings even if we are not setting rendermode.
# This allows the user to enable setting rendermode, set it up as they
Expand All @@ -199,11 +223,11 @@ def get_with_default(preset, default):

is_two_cycle = settings.g_mdsft_cycletype == "G_CYC_2CYCLE"
if is_two_cycle:
r1 = get_with_default(settings.rendermode_preset_cycle_1, f3d.G_RM_FOG_SHADE_A)
r2 = get_with_default(settings.rendermode_preset_cycle_2, f3d.G_RM_AA_ZB_OPA_SURF2)
r1 = get_with_default(cycle_1, f3d.G_RM_FOG_SHADE_A)
r2 = get_with_default(cycle_2, f3d.G_RM_AA_ZB_OPA_SURF2)
r = r1 | r2
else:
r = get_with_default(settings.rendermode_preset_cycle_1, f3d.G_RM_AA_ZB_OPA_SURF)
r = get_with_default(cycle_1, f3d.G_RM_AA_ZB_OPA_SURF)
r1 = r
# The cycle 1 bits are copied to the cycle 2 bits at export if in 1-cycle mode
# (the hardware requires them to be the same). So, here we also move the cycle 1
Expand Down Expand Up @@ -240,14 +264,10 @@ def does_blender_use_mix(settings: "RDPSettings", mix: str, default_for_no_rende
return settings.blend_b1 == mix or (is_two_cycle and settings.blend_b2 == mix)


def is_blender_equation_equal(
settings: "RDPSettings", cycle: int, p: str, a: str, m: str, b: str, default_for_no_rendermode: bool = False
) -> bool:
def is_blender_equation_equal(settings: "RDPSettings", cycle: int, p: str, a: str, m: str, b: str) -> bool:
assert cycle in {1, 2, -1} # -1 = last cycle
if cycle == -1:
cycle = 2 if settings.g_mdsft_cycletype == "G_CYC_2CYCLE" else 1
if not settings.set_rendermode:
return default_for_no_rendermode
return (
getattr(settings, f"blend_p{cycle}") == p
and getattr(settings, f"blend_a{cycle}") == a
Expand All @@ -256,7 +276,7 @@ def is_blender_equation_equal(
)


def is_blender_doing_fog(settings: "RDPSettings", default_for_no_rendermode: bool) -> bool:
def is_blender_doing_fog(settings: "RDPSettings") -> bool:
return is_blender_equation_equal(
settings,
# If 2 cycle, fog must be in first cycle.
Expand All @@ -268,14 +288,12 @@ def is_blender_doing_fog(settings: "RDPSettings", default_for_no_rendermode: boo
# is color in and 1-A.
"G_BL_CLR_IN",
"G_BL_1MA",
default_for_no_rendermode,
)


def get_output_method(material: bpy.types.Material) -> str:
rendermode_preset_to_advanced(material) # Make sure advanced settings are updated
settings = material.f3d_mat.rdp_settings
if not settings.set_rendermode:
return drawLayerSM64Alpha[material.f3d_mat.draw_layer.sm64]
if settings.cvg_x_alpha:
return "CLIP"
if settings.force_bl and is_blender_equation_equal(
Expand All @@ -286,10 +304,18 @@ def get_output_method(material: bpy.types.Material) -> str:


def update_blend_method(material: Material, context):
blend_mode = get_output_method(material)
if material.f3d_mat.rdp_settings.zmode == "ZMODE_DEC":
blend_mode = "DECAL"
if bpy.app.version >= (4, 2, 0):
material.surface_render_method = "BLENDED"
elif get_output_method(material) == "OPA":
if blend_mode == "CLIP":
material.surface_render_method = "HASHED"
else:
material.surface_render_method = "BLENDED"
elif blend_mode == "OPA":
material.blend_method = "OPAQUE"
elif blend_mode == "CLIP":
material.blend_method = "HASHED"
else:
material.blend_method = "BLEND"

Expand Down Expand Up @@ -1417,6 +1443,12 @@ def update_all_node_values(material, context):
update_rendermode_preset(material, context)


def update_all_material_nodes(self, context):
for material in bpy.data.materials:
with context.temp_override(material=material):
update_all_node_values(material, context)
Lilaa3 marked this conversation as resolved.
Show resolved Hide resolved


def update_node_values_with_preset(self, context):
update_node_values(self, context, update_preset=True)

Expand Down Expand Up @@ -1583,7 +1615,7 @@ def update_fog_nodes(material: Material, context: Context):
fogBlender.node_tree = bpy.data.node_groups[
(
"FogBlender_On"
if shade_alpha_is_fog and is_blender_doing_fog(material.f3d_mat.rdp_settings, True)
if shade_alpha_is_fog and is_blender_doing_fog(material.f3d_mat.rdp_settings)
else "FogBlender_Off"
)
]
Expand Down Expand Up @@ -4761,9 +4793,7 @@ def mat_register():
savePresets()

Scene.f3d_type = bpy.props.EnumProperty(
name="F3D Microcode",
items=enumF3D,
default="F3D",
name="F3D Microcode", items=enumF3D, default="F3D", update=update_all_material_nodes
)

# RDP Defaults
Expand Down
13 changes: 7 additions & 6 deletions fast64_internal/oot/f3d/properties.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from bpy.types import PropertyGroup, Object, World, Material, UILayout
from bpy.props import PointerProperty, StringProperty, BoolProperty, EnumProperty, IntProperty, FloatProperty
from bpy.utils import register_class, unregister_class
from ...f3d.f3d_material import update_all_material_nodes
from ...f3d.f3d_parser import ootEnumDrawLayers
from ...utility import prop_split

Expand Down Expand Up @@ -149,12 +150,12 @@ def draw_props(self, layout: UILayout, mat: Object, drawLayer: str):

class OOTDefaultRenderModesProperty(PropertyGroup):
expandTab: BoolProperty()
opaqueCycle1: StringProperty(default="G_RM_AA_ZB_OPA_SURF")
opaqueCycle2: StringProperty(default="G_RM_AA_ZB_OPA_SURF2")
transparentCycle1: StringProperty(default="G_RM_AA_ZB_XLU_SURF")
transparentCycle2: StringProperty(default="G_RM_AA_ZB_XLU_SURF2")
overlayCycle1: StringProperty(default="G_RM_AA_ZB_OPA_SURF")
overlayCycle2: StringProperty(default="G_RM_AA_ZB_OPA_SURF2")
opaqueCycle1: StringProperty(default="G_RM_AA_ZB_OPA_SURF", update=update_all_material_nodes)
Lilaa3 marked this conversation as resolved.
Show resolved Hide resolved
opaqueCycle2: StringProperty(default="G_RM_AA_ZB_OPA_SURF2", update=update_all_material_nodes)
transparentCycle1: StringProperty(default="G_RM_AA_ZB_XLU_SURF", update=update_all_material_nodes)
transparentCycle2: StringProperty(default="G_RM_AA_ZB_XLU_SURF2", update=update_all_material_nodes)
overlayCycle1: StringProperty(default="G_RM_AA_ZB_OPA_SURF", update=update_all_material_nodes)
overlayCycle2: StringProperty(default="G_RM_AA_ZB_OPA_SURF2", update=update_all_material_nodes)

def draw_props(self, layout: UILayout):
inputGroup = layout.column()
Expand Down
66 changes: 49 additions & 17 deletions fast64_internal/sm64/sm64_f3d_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from ..panels import SM64_Panel
from ..f3d.f3d_writer import exportF3DCommon
from ..f3d.f3d_texture_writer import TexInfo
from ..f3d.f3d_material import TextureProperty, tmemUsageUI, all_combiner_uses, ui_procAnim
from ..f3d.f3d_material import TextureProperty, tmemUsageUI, all_combiner_uses, ui_procAnim, update_all_material_nodes
from .sm64_texscroll import modifyTexScrollFiles, modifyTexScrollHeadersGroup
from .sm64_utility import export_rom_checks, starSelectWarning
from .sm64_level_parser import parseLevelAtPointer
Expand Down Expand Up @@ -938,22 +938,54 @@ def sm64_dl_writer_register():
for cls in sm64_dl_writer_classes:
register_class(cls)

bpy.types.World.draw_layer_0_cycle_1 = bpy.props.StringProperty(default="G_RM_ZB_OPA_SURF")
bpy.types.World.draw_layer_0_cycle_2 = bpy.props.StringProperty(default="G_RM_ZB_OPA_SURF2")
bpy.types.World.draw_layer_1_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_SURF")
bpy.types.World.draw_layer_1_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_SURF2")
bpy.types.World.draw_layer_2_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_DECAL")
bpy.types.World.draw_layer_2_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_DECAL2")
bpy.types.World.draw_layer_3_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_INTER")
bpy.types.World.draw_layer_3_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_OPA_INTER2")
bpy.types.World.draw_layer_4_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_TEX_EDGE")
bpy.types.World.draw_layer_4_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_TEX_EDGE2")
bpy.types.World.draw_layer_5_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_SURF")
bpy.types.World.draw_layer_5_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_SURF2")
bpy.types.World.draw_layer_6_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_DECAL")
bpy.types.World.draw_layer_6_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_DECAL2")
bpy.types.World.draw_layer_7_cycle_1 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_INTER")
bpy.types.World.draw_layer_7_cycle_2 = bpy.props.StringProperty(default="G_RM_AA_ZB_XLU_INTER2")
bpy.types.World.draw_layer_0_cycle_1 = bpy.props.StringProperty(
default="G_RM_ZB_OPA_SURF", update=update_all_material_nodes
)
bpy.types.World.draw_layer_0_cycle_2 = bpy.props.StringProperty(
default="G_RM_ZB_OPA_SURF2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_1_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_OPA_SURF", update=update_all_material_nodes
)
bpy.types.World.draw_layer_1_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_OPA_SURF2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_2_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_OPA_DECAL", update=update_all_material_nodes
)
bpy.types.World.draw_layer_2_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_OPA_DECAL2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_3_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_OPA_INTER", update=update_all_material_nodes
)
bpy.types.World.draw_layer_3_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_OPA_INTER2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_4_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_TEX_EDGE", update=update_all_material_nodes
)
bpy.types.World.draw_layer_4_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_TEX_EDGE2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_5_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_XLU_SURF", update=update_all_material_nodes
)
bpy.types.World.draw_layer_5_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_XLU_SURF2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_6_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_XLU_DECAL", update=update_all_material_nodes
)
bpy.types.World.draw_layer_6_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_XLU_DECAL2", update=update_all_material_nodes
)
bpy.types.World.draw_layer_7_cycle_1 = bpy.props.StringProperty(
default="G_RM_AA_ZB_XLU_INTER", update=update_all_material_nodes
)
bpy.types.World.draw_layer_7_cycle_2 = bpy.props.StringProperty(
default="G_RM_AA_ZB_XLU_INTER2", update=update_all_material_nodes
)

bpy.types.Scene.DLExportStart = bpy.props.StringProperty(name="Start", default="11D8930")
bpy.types.Scene.DLExportEnd = bpy.props.StringProperty(name="End", default="11FFF00")
Expand Down
Loading