Skip to content

Commit

Permalink
Merge pull request #223 from jesusyoshi54/mat_bleed_optimizations
Browse files Browse the repository at this point in the history
Mat bleed and SM64 Geo Export Optimizations
  • Loading branch information
Yanis002 authored Jan 5, 2024
2 parents ffbe289 + b3bf9f9 commit b02373c
Show file tree
Hide file tree
Showing 8 changed files with 384 additions and 168 deletions.
4 changes: 3 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from . import addon_updater_ops
from .fast64_internal.operators import AddWaterBox
from .fast64_internal.panels import SM64_Panel
from .fast64_internal.utility import PluginError, raisePluginError, attemptModifierApply, prop_split
from .fast64_internal.utility import PluginError, raisePluginError, attemptModifierApply, prop_split, multilineLabel

from .fast64_internal.sm64 import SM64_Properties, sm64_register, sm64_unregister
from .fast64_internal.sm64.sm64_geolayout_bone import SM64_BoneProperties
Expand Down Expand Up @@ -165,6 +165,8 @@ def draw(self, context):
col.prop(context.scene, "f3d_simple", text="Simple Material UI")
col.prop(context.scene, "generateF3DNodeGraph", text="Generate F3D Node Graph For Materials")
col.prop(context.scene, "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")
col.prop(context.scene, "decomp_compatible", invert_checkbox=True, text="Homebrew Compatibility")
col.prop(context.scene, "ignoreTextureRestrictions")
if context.scene.ignoreTextureRestrictions:
Expand Down
433 changes: 314 additions & 119 deletions fast64_internal/f3d/f3d_bleed.py

Large diffs are not rendered by default.

22 changes: 14 additions & 8 deletions fast64_internal/f3d/f3d_gbi.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,17 @@ class DLFormat(enum.Enum):
Dynamic = 2


class GfxListTag(enum.Enum):
class GfxListTag(enum.IntFlag):
Geometry = 1
Material = 2
MaterialRevert = 3
Draw = 3
MaterialRevert = 4
Draw = 4
NoExport = 16

@property
def Export(self):
return not self & GfxListTag.NoExport



class GfxTag(enum.Flag):
Expand Down Expand Up @@ -2672,7 +2678,7 @@ def to_c_gfx_scroll(self, gfxFormatter: GfxFormatter) -> CScrollData:
data = CScrollData()
for fMaterial, _ in self.materials.values():
fMaterial: FMaterial
if fMaterial.material:
if fMaterial.material.tag.Export:
data.append(gfxFormatter.gfxScrollToC(fMaterial.material, self.f3d))
for fMesh in self.meshes.values():
fMesh: FMesh
Expand Down Expand Up @@ -2941,7 +2947,7 @@ def to_c(self, f3d, gfxFormatter):
data.append(self.vertexList.to_c())
for celTriList in self.celTriLists:
data.append(celTriList.to_c(f3d))
if self.triList:
if self.triList.tag.Export:
data.append(self.triList.to_c(f3d))
return data

Expand Down Expand Up @@ -3041,7 +3047,7 @@ def sets_rendermode(self):

def get_ptr_addresses(self, f3d):
addresses = self.material.get_ptr_addresses(f3d)
if self.revert is not None:
if self.revert is not None and self.revert.tag.Export:
addresses.extend(self.revert.get_ptr_addresses(f3d))
return addresses

Expand All @@ -3059,9 +3065,9 @@ def save_binary(self, romfile, f3d, segments):

def to_c(self, f3d):
data = CData()
if self.material:
if self.material.tag.Export:
data.append(self.material.to_c(f3d))
if self.revert is not None:
if self.revert is not None and self.revert.tag.Export:
data.append(self.revert.to_c(f3d))
return data

Expand Down
2 changes: 2 additions & 0 deletions fast64_internal/f3d/f3d_material.py
Original file line number Diff line number Diff line change
Expand Up @@ -4403,6 +4403,7 @@ 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.f3d_lod_z = bpy.props.IntProperty(
name="F3D LOD Z",
min=1,
Expand All @@ -4424,6 +4425,7 @@ def mat_unregister():
del Scene.f3d_simple
del Object.ignore_render
del Object.ignore_collision
del Object.bleed_independently
del Object.use_f3d_culling
del Scene.f3dUserPresetsOnly
del Object.f3d_lod_z
Expand Down
3 changes: 2 additions & 1 deletion fast64_internal/f3d/f3d_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -450,8 +450,9 @@ def exportF3DCommon(obj, fModel, transformMatrix, includeChildren, name, DLForma
try:
infoDict = getInfoDict(tempObj)
triConverterInfo = TriangleConverterInfo(tempObj, None, fModel.f3d, transformMatrix, infoDict)
revert_materials = fModel.matWriteMethod == GfxMatWriteMethod.WriteDifferingAndRevert
fMeshes = saveStaticModel(
triConverterInfo, fModel, tempObj, transformMatrix, name, convertTextureData, True, None
triConverterInfo, fModel, tempObj, transformMatrix, name, convertTextureData, revert_materials, None
)
cleanupCombineObj(tempObj, meshList)
obj.select_set(True)
Expand Down
2 changes: 2 additions & 0 deletions fast64_internal/sm64/sm64_geolayout_bone.py
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ def draw(self, context):
col.prop(obj, "ignore_render")
col.prop(obj, "ignore_collision")
col.prop(obj, "use_f3d_culling")
if context.scene.exportInlineF3D:
col.prop(obj, "bleed_independently")
if obj_scale_is_unified(obj) and len(obj.modifiers) == 0:
col.prop(obj, "scaleFromGeolayout")
# prop_split(col, obj, 'room_num', 'Room')
Expand Down
13 changes: 7 additions & 6 deletions fast64_internal/sm64/sm64_geolayout_classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +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

def get_dl_address(self):
if self.hasDL and (self.dlRef or self.DLmicrocode is not None):
Expand Down Expand Up @@ -466,18 +467,18 @@ def walk(node, last_materials):
fMesh = getattr(base_node, "fMesh", None)
if fMesh:
cmd_list = fMesh.drawMatOverrides.get(base_node.override_hash, None) or fMesh.draw
lastMat = last_materials.get(base_node.drawLayer, None)
last_mat = last_materials.get(base_node.drawLayer, None)
default_render_mode = fModel.getRenderMode(base_node.drawLayer)
lastMat = self.bleed_fmesh(fModel.f3d, fMesh, lastMat, cmd_list, 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
else:
last_materials[base_node.drawLayer] = lastMat
# don't carry over lastmat if it is a switch node or geo asm node
if type(base_node) in [SwitchNode, FunctionNode]:
last_materials = dict()
last_materials[base_node.drawLayer] = last_mat
# don't carry over last_mat if it is a switch node or geo asm node
for child in node.children:
if type(base_node) in [SwitchNode, FunctionNode]:
last_materials = dict()
last_materials = walk(child, last_materials)
return last_materials

Expand Down
73 changes: 40 additions & 33 deletions fast64_internal/sm64/sm64_geolayout_writer.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@
geoNodeRotateOrder,
)

from ..f3d.f3d_bleed import (
find_material_from_jump_cmd,
)

from ..f3d.f3d_material import (
isTexturePointSampled,
)
Expand Down Expand Up @@ -333,24 +337,40 @@ def getCameraObj(camera):


def appendRevertToGeolayout(geolayoutGraph, fModel):
fModel.materialRevert = GfxList(
materialRevert = GfxList(
fModel.name + "_" + "material_revert_render_settings", GfxListTag.MaterialRevert, fModel.DLFormat
)
revertMatAndEndDraw(fModel.materialRevert, [DPSetEnvColor(0xFF, 0xFF, 0xFF, 0xFF), DPSetAlphaCompare("G_AC_NONE")])

# Get all draw layers, turn layers into strings (some are ints), deduplicate using a set
drawLayers = set(str(layer) for layer in geolayoutGraph.getDrawLayers())
revertMatAndEndDraw(materialRevert, [DPSetEnvColor(0xFF, 0xFF, 0xFF, 0xFF), DPSetAlphaCompare("G_AC_NONE")])

# 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:
if base_node.geolayout:
for node in base_node.geolayout.nodes:
last_gfx_list = walk(node, last_gfx_list)
else:
last_materials = dict()
fMesh = getattr(base_node, "fMesh", None)
if fMesh:
cmd_list = fMesh.drawMatOverrides.get(base_node.override_hash, None) or fMesh.draw
last_gfx_list[base_node.drawLayer] = cmd_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)

# Revert settings in each draw layer
for layer in sorted(drawLayers): # Must be sorted, otherwise ordering is random due to `set` behavior
dlNode = DisplayListNode(layer)
dlNode.DLmicrocode = fModel.materialRevert

# Assume first node is start render area
# This is important, since a render area groups things separately.
# If we added these nodes outside the render area, they would not happen
# right after the nodes inside.
geolayoutGraph.startGeolayout.nodes[0].children.append(TransformNode(dlNode))
for gfx_list in last_gfx_list.values():
# 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)


# Convert to Geolayout
Expand Down Expand Up @@ -1545,6 +1565,7 @@ def processMesh(
if not firstNodeProcessed:
node.DLmicrocode = fMesh.draw
node.fMesh = fMesh
node.bleed_independently = obj.bleed_independently
node.drawLayer = drawLayer # previous drawLayer assigments useless?
firstNodeProcessed = True
else:
Expand All @@ -1555,6 +1576,7 @@ def processMesh(
)
additionalNode.DLmicrocode = fMesh.draw
additionalNode.fMesh = fMesh
additionalNode.bleed_independently = obj.bleed_independently
additionalTransformNode = TransformNode(additionalNode)
transformNode.children.append(additionalTransformNode)
additionalTransformNode.parent = transformNode
Expand Down Expand Up @@ -2474,21 +2496,6 @@ def saveOverrideDraw(
last_replaced = None
command_index = 0

def find_material_from_jump_cmd(
material_list: tuple[tuple[bpy.types.Material, str, FAreaData], tuple[FMaterial, tuple[int, int]]],
dl_jump: SPDisplayList,
):
if dl_jump.displayList.tag == GfxListTag.Geometry:
return None, None
for mat in material_list:
fmaterial = mat[1][0]
bpy_material = mat[0][0]
if dl_jump.displayList.tag == GfxListTag.MaterialRevert and fmaterial.revert == dl_jump.displayList:
return bpy_material, fmaterial
elif fmaterial.material == dl_jump.displayList:
return bpy_material, fmaterial
return None, None

while command_index < len(meshMatOverride.commands):
command = meshMatOverride.commands[command_index]
if not isinstance(command, SPDisplayList):
Expand All @@ -2503,7 +2510,7 @@ def find_material_from_jump_cmd(

# replace the material load if necessary
# if we replaced the previous load with the same override, then remove the cmd to optimize DL
if command.displayList.tag == GfxListTag.Material:
if command.displayList.tag & GfxListTag.Material:
curMaterial = fmaterial
if shouldModify:
last_replaced = fmaterial
Expand All @@ -2527,14 +2534,14 @@ def find_material_from_jump_cmd(
prev_material = curMaterial

# replace the revert if the override has a revert, otherwise remove the command
if command.displayList.tag == GfxListTag.MaterialRevert and shouldModify:
if command.displayList.tag & GfxListTag.MaterialRevert and shouldModify:
if fOverrideMat.revert is not None:
command.displayList = fOverrideMat.revert
else:
meshMatOverride.commands.pop(command_index)
command_index -= 1

if not command.displayList.tag == GfxListTag.Geometry:
if not command.displayList.tag & GfxListTag.Geometry:
command_index += 1
continue
# If the previous command was a revert we added, remove it. All reverts must be followed by a load
Expand All @@ -2559,7 +2566,7 @@ def find_material_from_jump_cmd(
next_command = meshMatOverride.commands[command_index + 1]
if (
isinstance(next_command, SPDisplayList)
and next_command.displayList.tag == GfxListTag.Material
and next_command.displayList.tag & GfxListTag.Material
and next_command.displayList != prev_material.material
) or (isinstance(next_command, SPEndDisplayList)):
meshMatOverride.commands.insert(command_index + 1, SPDisplayList(fOverrideMat.revert))
Expand Down

0 comments on commit b02373c

Please sign in to comment.