From 380cc13abbd149869ce239d4edfb5ea262bc7efa Mon Sep 17 00:00:00 2001 From: Jack Andersen Date: Thu, 9 Apr 2020 17:20:20 -1000 Subject: [PATCH] Fixes for MP3 --- DataSpec/Blender/RetroMasterShader.py | 1062 +++++++++++++++---------- DataSpec/DNACommon/MayaSpline.hpp | 2 + DataSpec/DNACommon/RigInverter.cpp | 1 - DataSpec/DNAMP2/CINF.cpp | 43 +- DataSpec/DNAMP2/CINF.hpp | 11 +- DataSpec/DNAMP2/DNAMP2.cpp | 4 +- DataSpec/DNAMP2/MREA.cpp | 3 +- DataSpec/DNAMP3/CINF.cpp | 48 -- DataSpec/DNAMP3/CINF.hpp | 10 +- DataSpec/DNAMP3/CMDLMaterials.cpp | 550 ++++++------- DataSpec/DNAMP3/CMDLMaterials.hpp | 126 +-- DataSpec/DNAMP3/CMakeLists.txt | 3 +- DataSpec/DNAMP3/DNAMP3.cpp | 37 +- DataSpec/DNAMP3/MREA.cpp | 30 +- DataSpec/DNAMP3/MREA.hpp | 3 + DataSpec/DNAMP3/PATH.hpp | 6 + hecl | 2 +- 17 files changed, 1095 insertions(+), 846 deletions(-) delete mode 100644 DataSpec/DNAMP3/CINF.cpp create mode 100644 DataSpec/DNAMP3/PATH.hpp diff --git a/DataSpec/Blender/RetroMasterShader.py b/DataSpec/Blender/RetroMasterShader.py index 3d13f9625..4749aa409 100644 --- a/DataSpec/Blender/RetroMasterShader.py +++ b/DataSpec/Blender/RetroMasterShader.py @@ -721,11 +721,661 @@ def make_retro_dynamic_character_shader(): new_grp.links.new(final_add_shader.outputs['Shader'], alpha_mix.inputs[2]) new_grp.links.new(alpha_mix.outputs['Shader'], mat_out.inputs['Surface']) +# MP3 / DKCR Material Passes: +# https://wiki.axiodl.com/w/Materials_(Metroid_Prime_3) + +def make_retro_shader_mp3_color(): + new_grp = bpy.data.node_groups.new("__RetroShaderMP3Color", "ShaderNodeTree") + new_grp.use_fake_user = True + input = new_grp.inputs.new("NodeSocketColor", "DIFFC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketColor", "DIFBC") + input.default_value = (1.0, 1.0, 1.0, 1.0) + input = new_grp.inputs.new("NodeSocketColor", "CLRC") + input.default_value = (0.5, 0.5, 0.5, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "CLRA") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "TRAN") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "RFLDC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "RFLDA") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "RFLV") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketColor", "LRLD") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketColor", "LURDC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "LURDA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "INCAC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketInt", "Add INCA") + input.default_value = 0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "OPAC") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + new_grp.outputs.new("NodeSocketShader", "Shader") + nodes = {} + node = new_grp.nodes.new("ShaderNodeBsdfDiffuse") + node.name = "Diffuse BSDF.004" + nodes["Diffuse BSDF.004"] = node + node.label = "" + node.location = (-196.910400390625, -503.60546875) + node.inputs[0].default_value = (0.800000011920929, 0.800000011920929, 0.800000011920929, 1.0) + node.inputs[1].default_value = 0.0 + node.inputs[2].default_value = (0.0, 0.0, 0.0) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.009" + nodes["Add Shader.009"] = node + node.label = "" + node.location = (14.618888854980469, -571.516357421875) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.008" + nodes["Add Shader.008"] = node + node.label = "" + node.location = (6.4276123046875, -926.3602905273438) + node = new_grp.nodes.new("ShaderNodeBsdfDiffuse") + node.name = "Diffuse BSDF.005" + nodes["Diffuse BSDF.005"] = node + node.label = "" + node.location = (-189.85516357421875, -865.79345703125) + node.inputs[0].default_value = (0.800000011920929, 0.800000011920929, 0.800000011920929, 1.0) + node.inputs[1].default_value = 0.0 + node.inputs[2].default_value = (0.0, 0.0, 0.0) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix.005" + nodes["Mix.005"] = node + node.label = "" + node.location = (-190.5804901123047, -1017.0886840820312) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix.004" + nodes["Mix.004"] = node + node.label = "" + node.location = (-381.6676940917969, -870.815673828125) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.006" + nodes["Add Shader.006"] = node + node.label = "" + node.location = (220.7507781982422, -724.6066284179688) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.005" + nodes["Add Shader.005"] = node + node.label = "" + node.location = (218.0698699951172, -528.0934448242188) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.007" + nodes["Add Shader.007"] = node + node.label = "" + node.location = (388.0714416503906, -600.8295288085938) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix.002" + nodes["Mix.002"] = node + node.label = "" + node.location = (-192.1793212890625, -281.65264892578125) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.010" + nodes["Add Shader.010"] = node + node.label = "" + node.location = (522.2215576171875, -284.7532653808594) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix.001" + nodes["Mix.001"] = node + node.label = "" + node.location = (-198.2812957763672, -13.079503059387207) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeBsdfDiffuse") + node.name = "Diffuse BSDF.001" + nodes["Diffuse BSDF.001"] = node + node.label = "" + node.location = (-200.4605255126953, 138.9542694091797) + node.inputs[0].default_value = (0.800000011920929, 0.800000011920929, 0.800000011920929, 1.0) + node.inputs[1].default_value = 0.0 + node.inputs[2].default_value = (0.0, 0.0, 0.0) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.001" + nodes["Add Shader.001"] = node + node.label = "" + node.location = (-14.161624908447266, 32.61324691772461) + node = new_grp.nodes.new("NodeGroupOutput") + node.name = "Group Output" + nodes["Group Output"] = node + node.label = "" + node.location = (948.8831176757812, -299.1160583496094) + node = new_grp.nodes.new("ShaderNodeBsdfTransparent") + node.name = "Transparent BSDF.001" + nodes["Transparent BSDF.001"] = node + node.label = "" + node.location = (604.5911254882812, -88.7776870727539) + node.inputs[0].default_value = (1.0, 1.0, 1.0, 1.0) + node = new_grp.nodes.new("ShaderNodeMixShader") + node.name = "Mix Shader" + nodes["Mix Shader"] = node + node.label = "" + node.location = (772.179443359375, -91.1546401977539) + node.inputs[0].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.012" + nodes["Add Shader.012"] = node + node.label = "" + node.location = (776.751953125, -432.8694152832031) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.011" + nodes["Add Shader.011"] = node + node.label = "" + node.location = (779.857177734375, -294.9550476074219) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix.006" + nodes["Mix.006"] = node + node.label = "" + node.location = (-192.534912109375, -643.984619140625) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix.003" + nodes["Mix.003"] = node + node.label = "" + node.location = (-374.2341003417969, -515.1140747070312) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeMixRGB") + node.name = "Mix" + nodes["Mix"] = node + node.label = "" + node.location = (-500.3056640625, -114.82369995117188) + node.blend_type = "MULTIPLY" + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math" + nodes["Math"] = node + node.label = "" + node.location = (454.39404296875, 96.02081298828125) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.001" + nodes["Math.001"] = node + node.label = "" + node.location = (619.3079223632812, 90.52423095703125) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.002" + nodes["Math.002"] = node + node.label = "" + node.location = (785.3211059570312, 81.7295913696289) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeBsdfTransparent") + node.name = "Transparent BSDF" + nodes["Transparent BSDF"] = node + node.label = "" + node.location = (597.9944458007812, -480.7802734375) + node.inputs[0].default_value = (1.0, 1.0, 1.0, 1.0) + node = new_grp.nodes.new("NodeGroupInput") + node.name = "Group Input" + nodes["Group Input"] = node + node.label = "" + node.location = (-669.6587524414062, -193.9534149169922) + new_grp.links.new(nodes["Group Input"].outputs[0], nodes["Mix"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[1], nodes["Mix"].inputs[2]) + new_grp.links.new(nodes["Mix"].outputs[0], nodes["Mix.001"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[2], nodes["Mix.001"].inputs[2]) + new_grp.links.new(nodes["Mix.001"].outputs[0], nodes["Add Shader.001"].inputs[1]) + new_grp.links.new(nodes["Diffuse BSDF.001"].outputs[0], nodes["Add Shader.001"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[2], nodes["Diffuse BSDF.001"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[5], nodes["Mix.002"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[7], nodes["Mix.002"].inputs[2]) + new_grp.links.new(nodes["Mix.002"].outputs[0], nodes["Add Shader.005"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[5], nodes["Mix.003"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[8], nodes["Mix.003"].inputs[2]) + new_grp.links.new(nodes["Mix.003"].outputs[0], nodes["Diffuse BSDF.004"].inputs[0]) + new_grp.links.new(nodes["Diffuse BSDF.004"].outputs[0], nodes["Add Shader.009"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[5], nodes["Mix.004"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[10], nodes["Mix.004"].inputs[2]) + new_grp.links.new(nodes["Mix.004"].outputs[0], nodes["Diffuse BSDF.005"].inputs[0]) + new_grp.links.new(nodes["Diffuse BSDF.005"].outputs[0], nodes["Add Shader.008"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[9], nodes["Add Shader.006"].inputs[0]) + new_grp.links.new(nodes["Add Shader.005"].outputs[0], nodes["Add Shader.007"].inputs[0]) + new_grp.links.new(nodes["Add Shader.006"].outputs[0], nodes["Add Shader.007"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[10], nodes["Mix.005"].inputs[2]) + new_grp.links.new(nodes["Mix"].outputs[0], nodes["Mix.005"].inputs[1]) + new_grp.links.new(nodes["Add Shader.008"].outputs[0], nodes["Add Shader.006"].inputs[1]) + new_grp.links.new(nodes["Mix.005"].outputs[0], nodes["Add Shader.008"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[8], nodes["Mix.006"].inputs[2]) + new_grp.links.new(nodes["Mix"].outputs[0], nodes["Mix.006"].inputs[1]) + new_grp.links.new(nodes["Add Shader.009"].outputs[0], nodes["Add Shader.005"].inputs[1]) + new_grp.links.new(nodes["Mix.006"].outputs[0], nodes["Add Shader.009"].inputs[1]) + new_grp.links.new(nodes["Add Shader.007"].outputs[0], nodes["Add Shader.010"].inputs[1]) + new_grp.links.new(nodes["Add Shader.001"].outputs[0], nodes["Add Shader.010"].inputs[0]) + new_grp.links.new(nodes["Transparent BSDF"].outputs[0], nodes["Add Shader.012"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[11], nodes["Add Shader.012"].inputs[0]) + new_grp.links.new(nodes["Add Shader.012"].outputs[0], nodes["Add Shader.011"].inputs[1]) + new_grp.links.new(nodes["Add Shader.011"].outputs[0], nodes["Group Output"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[3], nodes["Math"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[13], nodes["Math"].inputs[1]) + new_grp.links.new(nodes["Math"].outputs[0], nodes["Math.001"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[4], nodes["Math.001"].inputs[1]) + new_grp.links.new(nodes["Math.001"].outputs[0], nodes["Math.002"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[6], nodes["Math.002"].inputs[0]) + new_grp.links.new(nodes["Math.002"].outputs[0], nodes["Mix Shader"].inputs[0]) + new_grp.links.new(nodes["Transparent BSDF.001"].outputs[0], nodes["Mix Shader"].inputs[1]) + new_grp.links.new(nodes["Add Shader.010"].outputs[0], nodes["Mix Shader"].inputs[2]) + new_grp.links.new(nodes["Mix Shader"].outputs[0], nodes["Add Shader.011"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[12], nodes["Transparent BSDF"].inputs[0]) + +def make_retro_shader_mp3_bloom(): + new_grp = bpy.data.node_groups.new("__RetroShaderMP3Bloom", "ShaderNodeTree") + new_grp.use_fake_user = True + input = new_grp.inputs.new("NodeSocketFloatFactor", "DIFFA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "DIFBA") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOL") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOD") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLODB") + input.default_value = 0.5 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "TRAN") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "INCAA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BNIF") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOI") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOIB") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "OPAC") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketInt", "Add INCA") + input.default_value = 0 + input.min_value = 0.000000 + input.max_value = 1.000000 + new_grp.outputs.new("NodeSocketShader", "Shader") + nodes = {} + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.003" + nodes["Math.003"] = node + node.label = "" + node.location = (-131.26889038085938, -228.6888885498047) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math" + nodes["Math"] = node + node.label = "" + node.location = (-501.6487731933594, -144.7719268798828) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.002" + nodes["Math.002"] = node + node.label = "" + node.location = (-328.3370666503906, -209.53160095214844) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("NodeGroupOutput") + node.name = "Group Output" + nodes["Group Output"] = node + node.label = "" + node.location = (1109.7938232421875, -257.2006530761719) + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.001" + nodes["Math.001"] = node + node.label = "" + node.location = (129.59579467773438, -299.0679626464844) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeBsdfDiffuse") + node.name = "Diffuse BSDF.002" + nodes["Diffuse BSDF.002"] = node + node.label = "" + node.location = (122.80331420898438, -150.7427520751953) + node.inputs[0].default_value = (0.800000011920929, 0.800000011920929, 0.800000011920929, 1.0) + node.inputs[1].default_value = 0.0 + node.inputs[2].default_value = (0.0, 0.0, 0.0) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.002" + nodes["Add Shader.002"] = node + node.label = "" + node.location = (312.7171325683594, -220.0266571044922) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.005" + nodes["Add Shader.005"] = node + node.label = "" + node.location = (-165.06072998046875, -549.3956298828125) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.006" + nodes["Add Shader.006"] = node + node.label = "" + node.location = (20.3157958984375, -545.8302612304688) + node = new_grp.nodes.new("ShaderNodeBsdfTransparent") + node.name = "Transparent BSDF.001" + nodes["Transparent BSDF.001"] = node + node.label = "" + node.location = (205.5854034423828, -558.1273803710938) + node.inputs[0].default_value = (1.0, 1.0, 1.0, 1.0) + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader.001" + nodes["Add Shader.001"] = node + node.label = "" + node.location = (399.876708984375, -533.2184448242188) + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.004" + nodes["Math.004"] = node + node.label = "" + node.location = (-354.23876953125, -508.8504943847656) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeAddShader") + node.name = "Add Shader" + nodes["Add Shader"] = node + node.label = "" + node.location = (875.3080444335938, -248.47450256347656) + node = new_grp.nodes.new("ShaderNodeBsdfTransparent") + node.name = "Transparent BSDF" + nodes["Transparent BSDF"] = node + node.label = "" + node.location = (502.63671875, -341.6871032714844) + node.inputs[0].default_value = (1.0, 1.0, 1.0, 1.0) + node = new_grp.nodes.new("ShaderNodeMath") + node.name = "Math.006" + nodes["Math.006"] = node + node.label = "" + node.location = (505.8763122558594, -171.7743377685547) + node.operation = "MULTIPLY" + node.inputs[0].default_value = 0.5 + node.inputs[1].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeMixShader") + node.name = "Mix Shader" + nodes["Mix Shader"] = node + node.label = "" + node.location = (682.0885620117188, -169.31057739257812) + node.inputs[0].default_value = 0.5 + node = new_grp.nodes.new("NodeGroupInput") + node.name = "Group Input" + nodes["Group Input"] = node + node.label = "" + node.location = (-669.6587524414062, -193.9534149169922) + new_grp.links.new(nodes["Group Input"].outputs[0], nodes["Math"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[1], nodes["Math"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[3], nodes["Math.002"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[4], nodes["Math.003"].inputs[1]) + new_grp.links.new(nodes["Math.002"].outputs[0], nodes["Math.003"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[2], nodes["Math.002"].inputs[0]) + new_grp.links.new(nodes["Math"].outputs[0], nodes["Math.001"].inputs[0]) + new_grp.links.new(nodes["Diffuse BSDF.002"].outputs[0], nodes["Add Shader.002"].inputs[0]) + new_grp.links.new(nodes["Math.001"].outputs[0], nodes["Add Shader.002"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[10], nodes["Math.006"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[5], nodes["Math.006"].inputs[0]) + new_grp.links.new(nodes["Math.006"].outputs[0], nodes["Mix Shader"].inputs[0]) + new_grp.links.new(nodes["Transparent BSDF"].outputs[0], nodes["Mix Shader"].inputs[1]) + new_grp.links.new(nodes["Transparent BSDF.001"].outputs[0], nodes["Add Shader.001"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[6], nodes["Math.004"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[7], nodes["Math.004"].inputs[1]) + new_grp.links.new(nodes["Math.003"].outputs[0], nodes["Math.001"].inputs[1]) + new_grp.links.new(nodes["Math.003"].outputs[0], nodes["Diffuse BSDF.002"].inputs[0]) + new_grp.links.new(nodes["Math.004"].outputs[0], nodes["Add Shader.005"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[8], nodes["Add Shader.005"].inputs[1]) + new_grp.links.new(nodes["Add Shader.005"].outputs[0], nodes["Add Shader.006"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[9], nodes["Add Shader.006"].inputs[1]) + new_grp.links.new(nodes["Add Shader.006"].outputs[0], nodes["Add Shader.001"].inputs[1]) + new_grp.links.new(nodes["Add Shader"].outputs[0], nodes["Group Output"].inputs[0]) + new_grp.links.new(nodes["Mix Shader"].outputs[0], nodes["Add Shader"].inputs[0]) + new_grp.links.new(nodes["Add Shader.002"].outputs[0], nodes["Mix Shader"].inputs[2]) + new_grp.links.new(nodes["Add Shader.001"].outputs[0], nodes["Add Shader"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[11], nodes["Transparent BSDF.001"].inputs[0]) + +def make_retro_shader_mp3(): + new_grp = bpy.data.node_groups.new("RetroShaderMP3", "ShaderNodeTree") + new_grp.use_fake_user = True + input = new_grp.inputs.new("NodeSocketColor", "DIFFC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "DIFFA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "DIFBC") + input.default_value = (1.0, 1.0, 1.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "DIFBA") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOL") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOD") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLODB") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "CLR") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "CLRA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "TRAN") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "RFLD") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "RFLDA") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "RFLV") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketColor", "LRLD") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketColor", "LURDC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "LURDA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketColor", "INCAC") + input.default_value = (0.0, 0.0, 0.0, 1.0) + input = new_grp.inputs.new("NodeSocketFloatFactor", "INCAA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketInt", "Add INCA") + input.default_value = 0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BNIF") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOI") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "BLOIB") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "OPAC") + input.default_value = 1.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "XRAYC") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "XRAYA") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + input = new_grp.inputs.new("NodeSocketFloatFactor", "XRBR") + input.default_value = 0.0 + input.min_value = 0.000000 + input.max_value = 1.000000 + nodes = {} + node = new_grp.nodes.new("ShaderNodeMixShader") + node.name = "Mix Shader" + nodes["Mix Shader"] = node + node.label = "" + node.location = (-118.33348846435547, -291.9857482910156) + node.inputs[0].default_value = 0.0 + node = new_grp.nodes.new("ShaderNodeOutputMaterial") + node.name = "Material Output" + nodes["Material Output"] = node + node.label = "" + node.location = (81.25957489013672, -265.6065368652344) + node.inputs[2].default_value = (0.0, 0.0, 0.0) + node = new_grp.nodes.new("ShaderNodeGroup") + node.name = "Group.001" + nodes["Group.001"] = node + node.label = "" + node.location = (-358.6896057128906, -60.17391586303711) + node.node_tree = bpy.data.node_groups["__RetroShaderMP3Color"] + node.inputs[0].default_value = (1.0, 1.0, 1.0, 1.0) + node.inputs[1].default_value = (1.0, 1.0, 1.0, 1.0) + node.inputs[2].default_value = (0.5, 0.5, 0.5, 1.0) + node.inputs[3].default_value = 0.5 + node.inputs[4].default_value = 0.5 + node.inputs[5].default_value = (0.0, 0.0, 0.0, 1.0) + node.inputs[6].default_value = 0.5 + node.inputs[7].default_value = (0.0, 0.0, 0.0, 1.0) + node.inputs[8].default_value = (0.0, 0.0, 0.0, 1.0) + node.inputs[9].default_value = (0.0, 0.0, 0.0, 1.0) + node.inputs[10].default_value = 0.0 + node.inputs[11].default_value = (0.0, 0.0, 0.0, 1.0) + node.inputs[12].default_value = 0 + node.inputs[13].default_value = 0.5 + node = new_grp.nodes.new("ShaderNodeGroup") + node.name = "Group" + nodes["Group"] = node + node.label = "" + node.location = (-356.9021301269531, -446.9474182128906) + node.node_tree = bpy.data.node_groups["__RetroShaderMP3Bloom"] + node.inputs[0].default_value = 1.0 + node.inputs[1].default_value = 1.0 + node.inputs[2].default_value = 0.0 + node.inputs[3].default_value = 0.0 + node.inputs[4].default_value = 0.5 + node.inputs[5].default_value = 0.5 + node.inputs[6].default_value = 0.0 + node.inputs[7].default_value = 0.0 + node.inputs[8].default_value = 0.0 + node.inputs[9].default_value = 0.0 + node.inputs[10].default_value = 0.5 + node.inputs[11].default_value = 0 + node = new_grp.nodes.new("NodeGroupInput") + node.name = "Group Input" + nodes["Group Input"] = node + node.label = "" + node.location = (-669.6587524414062, -193.9534149169922) + new_grp.links.new(nodes["Group Input"].outputs[0], nodes["Group.001"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[1], nodes["Group"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[3], nodes["Group"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[4], nodes["Group"].inputs[2]) + new_grp.links.new(nodes["Group Input"].outputs[5], nodes["Group"].inputs[3]) + new_grp.links.new(nodes["Group Input"].outputs[6], nodes["Group"].inputs[4]) + new_grp.links.new(nodes["Group Input"].outputs[17], nodes["Group"].inputs[6]) + new_grp.links.new(nodes["Group Input"].outputs[19], nodes["Group"].inputs[7]) + new_grp.links.new(nodes["Group Input"].outputs[20], nodes["Group"].inputs[8]) + new_grp.links.new(nodes["Group Input"].outputs[2], nodes["Group.001"].inputs[1]) + new_grp.links.new(nodes["Group Input"].outputs[7], nodes["Group.001"].inputs[2]) + new_grp.links.new(nodes["Group Input"].outputs[10], nodes["Group.001"].inputs[5]) + new_grp.links.new(nodes["Group Input"].outputs[12], nodes["Group.001"].inputs[7]) + new_grp.links.new(nodes["Group Input"].outputs[13], nodes["Group.001"].inputs[8]) + new_grp.links.new(nodes["Group Input"].outputs[14], nodes["Group.001"].inputs[9]) + new_grp.links.new(nodes["Group Input"].outputs[15], nodes["Group.001"].inputs[10]) + new_grp.links.new(nodes["Group Input"].outputs[16], nodes["Group.001"].inputs[11]) + new_grp.links.new(nodes["Group.001"].outputs[0], nodes["Mix Shader"].inputs[1]) + new_grp.links.new(nodes["Group"].outputs[0], nodes["Mix Shader"].inputs[2]) + new_grp.links.new(nodes["Mix Shader"].outputs[0], nodes["Material Output"].inputs[0]) + new_grp.links.new(nodes["Group Input"].outputs[21], nodes["Group"].inputs[9]) + new_grp.links.new(nodes["Group Input"].outputs[8], nodes["Group.001"].inputs[3]) + new_grp.links.new(nodes["Group Input"].outputs[9], nodes["Group.001"].inputs[4]) + new_grp.links.new(nodes["Group Input"].outputs[11], nodes["Group.001"].inputs[6]) + new_grp.links.new(nodes["Group Input"].outputs[22], nodes["Group.001"].inputs[13]) + new_grp.links.new(nodes["Group Input"].outputs[9], nodes["Group"].inputs[5]) + new_grp.links.new(nodes["Group Input"].outputs[22], nodes["Group"].inputs[10]) + new_grp.links.new(nodes["Group Input"].outputs[18], nodes["Group.001"].inputs[12]) + new_grp.links.new(nodes["Group Input"].outputs[18], nodes["Group"].inputs[11]) + ROOT_SHADER_GROUPS = ( make_retro_shader, make_retro_dynamic_shader, make_retro_dynamic_alpha_shader, - make_retro_dynamic_character_shader + make_retro_dynamic_character_shader, + make_retro_shader_mp3_color, + make_retro_shader_mp3_bloom, + make_retro_shader_mp3 ) # UV animation nodes: @@ -1196,414 +1846,6 @@ UV_ANIMATION_GROUPS = ( make_uva8 ) -# MP3 / DKCR Material Passes: -# https://wiki.axiodl.com/w/Materials_(Metroid_Prime_3) - -# Lightmap -def make_pass_diff(): - new_grp = bpy.data.node_groups.new('RetroPassDIFF', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Multiply1 - mult1 = new_grp.nodes.new('ShaderNodeMixRGB') - mult1.blend_type = 'ADD' - mult1.inputs[0].default_value = 1.0 - mult1.location = (-600, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], mult1.inputs[1]) - new_grp.links.new(grp_in.outputs[2], mult1.inputs[2]) - new_grp.links.new(mult1.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - - -# Rim Lighting Map -def make_pass_riml(): - new_grp = bpy.data.node_groups.new('RetroPassRIML', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Bloom Lightmap -def make_pass_blol(): - new_grp = bpy.data.node_groups.new('RetroPassBLOL', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Bloom Diffuse Map -def make_pass_blod(): - new_grp = bpy.data.node_groups.new('RetroPassBLOD', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Diffuse Map -def make_pass_clr(): - new_grp = bpy.data.node_groups.new('RetroPassCLR', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Multiply - mult1 = new_grp.nodes.new('ShaderNodeMixRGB') - mult1.blend_type = 'MULTIPLY' - mult1.inputs[0].default_value = 1.0 - grp_in.location = (-400, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], mult1.inputs[1]) - new_grp.links.new(grp_in.outputs[2], mult1.inputs[2]) - new_grp.links.new(mult1.outputs[0], grp_out.inputs[0]) - grp_out.inputs[1].default_value = 1.0 - -# Opacity Map -def make_pass_tran(): - new_grp = bpy.data.node_groups.new('RetroPassTRAN', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Multiply - mul1 = new_grp.nodes.new('ShaderNodeMath') - mul1.operation = 'MULTIPLY' - mul1.inputs[0].default_value = 1.0 - mul1.location = (-400, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], mul1.inputs[0]) - new_grp.links.new(grp_in.outputs[2], mul1.inputs[1]) - new_grp.links.new(mul1.outputs[0], grp_out.inputs[1]) - -# Opacity Map Inverted -def make_pass_tran_inv(): - new_grp = bpy.data.node_groups.new('RetroPassTRANInv', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Multiply - mul1 = new_grp.nodes.new('ShaderNodeMath') - mul1.operation = 'MULTIPLY' - mul1.inputs[0].default_value = 1.0 - mul1.location = (-400, 0) - - # Invert - inv1 = new_grp.nodes.new('ShaderNodeInvert') - inv1.inputs[0].default_value = 1.0 - inv1.location = (-600, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], mul1.inputs[1]) - new_grp.links.new(grp_in.outputs[2], inv1.inputs[1]) - new_grp.links.new(inv1.outputs[0], mul1.inputs[0]) - new_grp.links.new(mul1.outputs[0], grp_out.inputs[1]) - -# Incandescence Map -def make_pass_inca(): - new_grp = bpy.data.node_groups.new('RetroPassINCA', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Multiply - add1 = new_grp.nodes.new('ShaderNodeMixRGB') - add1.blend_type = 'ADD' - add1.inputs[0].default_value = 1.0 - grp_in.location = (-400, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], add1.inputs[1]) - new_grp.links.new(grp_in.outputs[2], add1.inputs[2]) - new_grp.links.new(add1.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - grp_out.inputs[1].default_value = 1.0 - -# Reflection Map -def make_pass_rfld(): - new_grp = bpy.data.node_groups.new('RetroPassRFLD', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Mask Color') - new_grp.inputs.new('NodeSocketFloat', 'Mask Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Multiply - mult1 = new_grp.nodes.new('ShaderNodeMixRGB') - mult1.location = (-600, 0) - mult1.blend_type = 'MULTIPLY' - mult1.inputs[0].default_value = 1.0 - - # Add - add1 = new_grp.nodes.new('ShaderNodeMixRGB') - add1.location = (-400, 0) - add1.blend_type = 'ADD' - add1.inputs[0].default_value = 1.0 - - # Links - new_grp.links.new(grp_in.outputs[0], add1.inputs[1]) - new_grp.links.new(grp_in.outputs[2], mult1.inputs[1]) - new_grp.links.new(grp_in.outputs[4], mult1.inputs[2]) - new_grp.links.new(mult1.outputs[0], add1.inputs[2]) - new_grp.links.new(add1.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Unk1 -def make_pass_lrld(): - new_grp = bpy.data.node_groups.new('RetroPassLRLD', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Unk2 -def make_pass_lurd(): - new_grp = bpy.data.node_groups.new('RetroPassLURD', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Bloom Incandescence Map -def make_pass_bloi(): - new_grp = bpy.data.node_groups.new('RetroPassBLOI', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# X-ray Reflection Map -def make_pass_xray(): - new_grp = bpy.data.node_groups.new('RetroPassXRAY', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -# Unused -def make_pass_toon(): - new_grp = bpy.data.node_groups.new('RetroPassTOON', 'ShaderNodeTree') - new_grp.inputs.new('NodeSocketColor', 'Prev Color') - new_grp.inputs.new('NodeSocketFloat', 'Prev Alpha') - new_grp.inputs.new('NodeSocketColor', 'Tex Color') - new_grp.inputs.new('NodeSocketFloat', 'Tex Alpha') - new_grp.outputs.new('NodeSocketColor', 'Next Color') - new_grp.outputs.new('NodeSocketFloat', 'Next Alpha') - new_grp.use_fake_user = True - - # Group inputs - grp_in = new_grp.nodes.new('NodeGroupInput') - grp_in.location = (-800, 0) - - # Group outputs - grp_out = new_grp.nodes.new('NodeGroupOutput') - grp_out.location = (0, 0) - - # Links - new_grp.links.new(grp_in.outputs[0], grp_out.inputs[0]) - new_grp.links.new(grp_in.outputs[1], grp_out.inputs[1]) - -MP3_PASS_GROUPS = ( - make_pass_diff, - make_pass_riml, - make_pass_blol, - make_pass_blod, - make_pass_clr, - make_pass_tran, - make_pass_tran_inv, - make_pass_inca, - make_pass_rfld, - make_pass_lrld, - make_pass_lurd, - make_pass_bloi, - make_pass_xray, - make_pass_toon -) - def make_master_shader_library(): make_additive_output() make_blend_opaque_output() @@ -1611,6 +1853,4 @@ def make_master_shader_library(): shad() for uva in UV_ANIMATION_GROUPS: uva() - for aPass in MP3_PASS_GROUPS: - aPass() diff --git a/DataSpec/DNACommon/MayaSpline.hpp b/DataSpec/DNACommon/MayaSpline.hpp index 00b48fae3..700f78833 100644 --- a/DataSpec/DNACommon/MayaSpline.hpp +++ b/DataSpec/DNACommon/MayaSpline.hpp @@ -14,6 +14,8 @@ struct MayaSpline : public BigDNA { Value amplitude; Value unk1; Value unk2; + Vector unk1Floats; + Vector unk2Floats; }; Vector knots; diff --git a/DataSpec/DNACommon/RigInverter.cpp b/DataSpec/DNACommon/RigInverter.cpp index a22f997c4..e1c6078ef 100644 --- a/DataSpec/DNACommon/RigInverter.cpp +++ b/DataSpec/DNACommon/RigInverter.cpp @@ -141,6 +141,5 @@ zeus::CVector3f RigInverter::restorePosition(atUint32 boneId, const ze template class RigInverter; template class RigInverter; -template class RigInverter; } // namespace DataSpec::DNAANIM diff --git a/DataSpec/DNAMP2/CINF.cpp b/DataSpec/DNAMP2/CINF.cpp index f0b5f39b7..6762c4238 100644 --- a/DataSpec/DNAMP2/CINF.cpp +++ b/DataSpec/DNAMP2/CINF.cpp @@ -1,5 +1,6 @@ #include "CINF.hpp" #include "hecl/Blender/Connection.hpp" +#include "DataSpec/DNAMP3/DNAMP3.hpp" namespace DataSpec::DNAMP2 { @@ -41,7 +42,8 @@ void CINF::sendVertexGroupsToBlender(hecl::blender::PyOutStream& os) const { } } -void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& cinfId) const { +template +void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const typename PAKBridge::PAKType::IDType& cinfId) const { DNAANIM::RigInverter inverter(*this); os.format(fmt( @@ -66,9 +68,18 @@ void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& c tailF[2], bone.m_origBone.id); } - for (const Bone& bone : bones) - if (bone.parentId != 97) - os.format(fmt("arm_bone_table[{}].parent = arm_bone_table[{}]\n"), bone.id, bone.parentId); + if constexpr (std::is_same_v) { + if (bones.size()) { + atUint32 nullId = bones[0].parentId; + for (const Bone& bone : bones) + if (bone.parentId != nullId) + os.format(fmt("arm_bone_table[{}].parent = arm_bone_table[{}]\n"), bone.id, bone.parentId); + } + } else { + for (const Bone& bone : bones) + if (bone.parentId != 97) + os.format(fmt("arm_bone_table[{}].parent = arm_bone_table[{}]\n"), bone.id, bone.parentId); + } os << "bpy.ops.object.mode_set(mode='OBJECT')\n"; @@ -76,8 +87,14 @@ void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& c os.format(fmt("arm_obj.pose.bones['{}'].rotation_mode = 'QUATERNION'\n"), *getBoneNameFromId(bone.m_origBone.id)); } +template void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& cinfId) const; +template void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, + const UniqueID64& cinfId) const; -std::string CINF::GetCINFArmatureName(const UniqueID32& cinfId) { return fmt::format(fmt("CINF_{}"), cinfId); } +template +std::string CINF::GetCINFArmatureName(const UniqueID& cinfId) { return fmt::format(fmt("CINF_{}"), cinfId); } +template std::string CINF::GetCINFArmatureName(const UniqueID32& cinfId); +template std::string CINF::GetCINFArmatureName(const UniqueID64& cinfId); int CINF::RecursiveAddArmatureBone(const Armature& armature, const BlenderBone* bone, int parent, int& curId, std::unordered_map& idMap, @@ -156,9 +173,10 @@ CINF::CINF(const Armature& armature, std::unordered_map& i boneIds.push_back(it->id); } +template bool CINF::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, - PAKRouter& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok, - std::function fileChanged) { + PAKRouter& pakRouter, const typename PAKBridge::PAKType::Entry& entry, bool force, + hecl::blender::Token& btok, std::function fileChanged) { if (!force && outPath.isFile()) return true; @@ -179,12 +197,21 @@ bool CINF::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl: CINF cinf; cinf.read(rs); - cinf.sendCINFToBlender(os, entry.id); + cinf.sendCINFToBlender(os, entry.id); os.centerView(); os.close(); return conn.saveBlend(); } +template bool CINF::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, + PAKRouter& pakRouter, const typename PAKBridge::PAKType::Entry& entry, + bool force, hecl::blender::Token& btok, + std::function fileChanged); +template bool CINF::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, + PAKRouter& pakRouter, + const typename DNAMP3::PAKBridge::PAKType::Entry& entry, bool force, + hecl::blender::Token& btok, std::function fileChanged); + bool CINF::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const hecl::blender::Armature& armature) { std::unordered_map boneIdMap; diff --git a/DataSpec/DNAMP2/CINF.hpp b/DataSpec/DNAMP2/CINF.hpp index 5f3637477..85831eb66 100644 --- a/DataSpec/DNAMP2/CINF.hpp +++ b/DataSpec/DNAMP2/CINF.hpp @@ -36,8 +36,10 @@ struct CINF : BigDNA { atUint32 getBoneIdxFromId(atUint32 id) const; const std::string* getBoneNameFromId(atUint32 id) const; void sendVertexGroupsToBlender(hecl::blender::PyOutStream& os) const; - void sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID32& cinfId) const; - static std::string GetCINFArmatureName(const UniqueID32& cinfId); + template + void sendCINFToBlender(hecl::blender::PyOutStream& os, const typename PAKBridge::PAKType::IDType& cinfId) const; + template + static std::string GetCINFArmatureName(const UniqueID& cinfId); CINF() = default; using Armature = hecl::blender::Armature; @@ -48,9 +50,10 @@ struct CINF : BigDNA { CINF(const Armature& armature, std::unordered_map& idMap); + template static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, - PAKRouter& pakRouter, const PAK::Entry& entry, bool force, hecl::blender::Token& btok, - std::function fileChanged); + PAKRouter& pakRouter, const typename PAKBridge::PAKType::Entry& entry, bool force, + hecl::blender::Token& btok, std::function fileChanged); static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const hecl::blender::Armature& armature); diff --git a/DataSpec/DNAMP2/DNAMP2.cpp b/DataSpec/DNAMP2/DNAMP2.cpp index 63cc69754..7b1bcacf4 100644 --- a/DataSpec/DNAMP2/DNAMP2.cpp +++ b/DataSpec/DNAMP2/DNAMP2.cpp @@ -25,6 +25,8 @@ namespace DataSpec::DNAMP2 { logvisor::Module Log("urde::DNAMP2"); static bool GetNoShare(std::string_view name) { + if (name == "FrontEnd.pak"sv) + return false; std::string lowerName(name); std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower); if (!lowerName.compare(0, 7, "metroid")) @@ -259,7 +261,7 @@ ResExtractor PAKBridge::LookupExtractor(const nod::Node& pakNode, con case SBIG('CMDL'): return {CMDL::Extract, {_SYS_STR(".blend")}, 1}; case SBIG('CINF'): - return {CINF::Extract, {_SYS_STR(".blend")}, 1}; + return {CINF::Extract, {_SYS_STR(".blend")}, 1}; case SBIG('ANCS'): return {ANCS::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 2}; case SBIG('MLVL'): diff --git a/DataSpec/DNAMP2/MREA.cpp b/DataSpec/DNAMP2/MREA.cpp index ee165529f..a8add1605 100644 --- a/DataSpec/DNAMP2/MREA.cpp +++ b/DataSpec/DNAMP2/MREA.cpp @@ -68,8 +68,7 @@ MREA::StreamReader::StreamReader(athena::io::IStreamReader& source, atUint32 blk , m_blkCount(blkCount) { m_blockInfos.reserve(blkCount); for (atUint32 i = 0; i < blkCount; ++i) { - m_blockInfos.emplace_back(); - BlockInfo& info = m_blockInfos.back(); + BlockInfo& info = m_blockInfos.emplace_back(); info.read(source); m_totalDecompLen += info.decompSize; } diff --git a/DataSpec/DNAMP3/CINF.cpp b/DataSpec/DNAMP3/CINF.cpp deleted file mode 100644 index d8cf6ec82..000000000 --- a/DataSpec/DNAMP3/CINF.cpp +++ /dev/null @@ -1,48 +0,0 @@ -#include "CINF.hpp" -#include "hecl/Blender/Connection.hpp" - -namespace DataSpec::DNAMP3 { - -void CINF::sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID64& cinfId) const { - DNAANIM::RigInverter inverter(*this); - - os.format(fmt("arm = bpy.data.armatures.new('CINF_{}')\n" - "arm_obj = bpy.data.objects.new(arm.name, arm)\n" - "bpy.context.scene.collection.objects.link(arm_obj)\n" - "bpy.context.view_layer.objects.active = arm_obj\n" - "bpy.ops.object.mode_set(mode='EDIT')\n" - "arm_bone_table = {{}}\n"), - cinfId); - - for (const DNAANIM::RigInverter::Bone& bone : inverter.getBones()) { - zeus::simd_floats originF(bone.m_origBone.origin.simd); - zeus::simd_floats tailF(bone.m_tail.mSimd); - os.format(fmt( - "bone = arm.edit_bones.new('{}')\n" - "bone.head = ({},{},{})\n" - "bone.tail = ({},{},{})\n" - "bone.use_inherit_scale = False\n" - "arm_bone_table[{}] = bone\n"), - *getBoneNameFromId(bone.m_origBone.id), originF[0], originF[1], originF[2], tailF[0], tailF[1], - tailF[2], bone.m_origBone.id); - } - - if (bones.size()) { - atUint32 nullId = bones[0].parentId; - for (const Bone& bone : bones) - if (bone.parentId != nullId) - os.format(fmt("arm_bone_table[{}].parent = arm_bone_table[{}]\n"), bone.id, bone.parentId); - } - - os << "bpy.ops.object.mode_set(mode='OBJECT')\n"; - - for (const DNAANIM::RigInverter::Bone& bone : inverter.getBones()) - os.format(fmt("arm_obj.pose.bones['{}'].rotation_mode = 'QUATERNION'\n"), - *getBoneNameFromId(bone.m_origBone.id)); -} - -std::string CINF::GetCINFArmatureName(const UniqueID64& cinfId) { - return fmt::format(fmt("CINF_{}"), cinfId); -} - -} // namespace DataSpec::DNAMP3 diff --git a/DataSpec/DNAMP3/CINF.hpp b/DataSpec/DNAMP3/CINF.hpp index 353f21bb8..d40286143 100644 --- a/DataSpec/DNAMP3/CINF.hpp +++ b/DataSpec/DNAMP3/CINF.hpp @@ -1,14 +1,8 @@ #pragma once #include "DataSpec/DNACommon/DNACommon.hpp" -#include "../DNAMP2/CINF.hpp" +#include "DataSpec/DNAMP2/CINF.hpp" namespace DataSpec::DNAMP3 { - -struct CINF : DNAMP2::CINF { - Delete expl; - void sendCINFToBlender(hecl::blender::PyOutStream& os, const UniqueID64& cinfId) const; - static std::string GetCINFArmatureName(const UniqueID64& cinfId); -}; - +using CINF = DNAMP2::CINF; } // namespace DataSpec::DNAMP3 diff --git a/DataSpec/DNAMP3/CMDLMaterials.cpp b/DataSpec/DNAMP3/CMDLMaterials.cpp index 75f82dae7..e2ff1c8ae 100644 --- a/DataSpec/DNAMP3/CMDLMaterials.cpp +++ b/DataSpec/DNAMP3/CMDLMaterials.cpp @@ -6,341 +6,291 @@ using Stream = hecl::blender::PyOutStream; namespace DataSpec::DNAMP3 { using Material = MaterialSet::Material; -template <> -void MaterialSet::Material::SectionFactory::Enumerate(typename Read::StreamT& reader) { - DNAFourCC type; - type.read(reader); - switch (ISection::Type(type.toUint32())) { - case ISection::Type::PASS: - section = std::make_unique(); - section->read(reader); - break; - case ISection::Type::CLR: - section = std::make_unique(); - section->read(reader); - break; - case ISection::Type::INT: - section = std::make_unique(); - section->read(reader); - break; - default: - section.reset(); - break; - } -} -template <> -void MaterialSet::Material::SectionFactory::Enumerate(typename Write::StreamT& writer) { - if (!section) - return; - writer.writeUBytes((atUint8*)§ion->m_type, 4); - section->write(writer); -} -template <> -void MaterialSet::Material::SectionFactory::Enumerate(typename BinarySize::StreamT& s) { - s += 4; - section->binarySize(s); -} - template <> void MaterialSet::Material::Enumerate(typename Read::StreamT& reader) { header.read(reader); - sections.clear(); - do { - sections.emplace_back(); - sections.back().read(reader); - } while (sections.back().section); - sections.pop_back(); + chunks.clear(); + do { chunks.emplace_back().read(reader); } while (!chunks.back().holds_alternative()); + chunks.pop_back(); } template <> void MaterialSet::Material::Enumerate(typename Write::StreamT& writer) { header.write(writer); - for (const SectionFactory& section : sections) - section.write(writer); - writer.writeUBytes((atUint8*)"END ", 4); + for (const auto& chunk : chunks) + chunk.visit([&](auto& arg) { arg.write(writer); }); + DNAFourCC(FOURCC('END ')).write(writer); } template <> void MaterialSet::Material::Enumerate(typename BinarySize::StreamT& s) { header.binarySize(s); - for (const SectionFactory& section : sections) - section.binarySize(s); + for (const auto& chunk : chunks) + chunk.visit([&](auto& arg) { arg.binarySize(s); }); s += 4; } void MaterialSet::RegisterMaterialProps(Stream& out) { - out << "bpy.types.Material.retro_alpha_test = bpy.props.BoolProperty(name='Retro: Punchthrough Alpha')\n" + out << "bpy.types.Material.retro_enable_bloom = bpy.props.BoolProperty(name='Retro: Enable Bloom')\n" + "bpy.types.Material.retro_force_lighting_stage = bpy.props.BoolProperty(name='Retro: Force Lighting Stage')\n" + "bpy.types.Material.retro_pre_inca_transparency = bpy.props.BoolProperty(name='Retro: Pre-INCA Transparency')\n" + "bpy.types.Material.retro_alpha_test = bpy.props.BoolProperty(name='Retro: Alpha Test')\n" "bpy.types.Material.retro_shadow_occluder = bpy.props.BoolProperty(name='Retro: Shadow Occluder')\n" - "bpy.types.Material.retro_lightmapped = bpy.props.BoolProperty(name='Retro: Lightmapped')\n" - "bpy.types.Material.retro_opac = bpy.props.IntProperty(name='Retro: OPAC')\n" - "bpy.types.Material.retro_blod = bpy.props.IntProperty(name='Retro: BLOD')\n" - "bpy.types.Material.retro_bloi = bpy.props.IntProperty(name='Retro: BLOI')\n" - "bpy.types.Material.retro_bnif = bpy.props.IntProperty(name='Retro: BNIF')\n" - "bpy.types.Material.retro_xrbr = bpy.props.IntProperty(name='Retro: XRBR')\n" + "bpy.types.Material.retro_solid_white = bpy.props.BoolProperty(name='Retro: Solid White Only')\n" + "bpy.types.Material.retro_reflection_alpha_target = bpy.props.BoolProperty(name='Retro: Reflection Alpha Target')\n" + "bpy.types.Material.retro_solid_color = bpy.props.BoolProperty(name='Retro: Solid Color Only')\n" + "bpy.types.Material.retro_exclude_scan = bpy.props.BoolProperty(name='Retro: Exclude From Scan Visor')\n" + "bpy.types.Material.retro_xray_opaque = bpy.props.BoolProperty(name='Retro: XRay Opaque')\n" + "bpy.types.Material.retro_xray_alpha_target = bpy.props.BoolProperty(name='Retro: XRay Alpha Target')\n" + "bpy.types.Material.retro_inca_color_mod = bpy.props.BoolProperty(name='Retro: INCA Color Mod')\n" "\n"; } +static void LoadTexture(Stream& out, const UniqueID64& tex, + const PAKRouter& pakRouter, const PAK::Entry& entry) { + std::string texName = pakRouter.getBestEntryName(tex); + const nod::Node* node; + const typename PAKRouter::EntryType* texEntry = pakRouter.lookupEntry(tex, &node); + hecl::ProjectPath txtrPath = pakRouter.getWorking(texEntry); + if (!txtrPath.isNone()) { + txtrPath.makeDirChain(false); + PAKEntryReadStream rs = texEntry->beginReadStream(*node); + TXTR::Extract(rs, txtrPath); + } + hecl::SystemString resPath = pakRouter.getResourceRelativePath(entry, tex); + hecl::SystemUTF8Conv resPathView(resPath); + out.format(fmt("if '{}' in bpy.data.images:\n" + " image = bpy.data.images['{}']\n" + "else:\n" + " image = bpy.data.images.load('''//{}''')\n" + " image.name = '{}'\n" + "\n"), texName, texName, resPathView, texName); +} + void MaterialSet::ConstructMaterial(Stream& out, const PAKRouter& pakRouter, const PAK::Entry& entry, const Material& material, unsigned groupIdx, unsigned matIdx) { - unsigned i; - - out.format(fmt( - "new_material = bpy.data.materials.new('MAT_{}_{}')\n" - "new_material.use_shadows = True\n" - "new_material.use_transparent_shadows = True\n" - "new_material.diffuse_color = (1.0,1.0,1.0)\n" - "new_material.use_nodes = True\n" - "new_material.blend_method = 'BLEND'\n" - "new_nodetree = new_material.node_tree\n" - "material_node = new_nodetree.nodes['Material']\n" - "final_node = new_nodetree.nodes['Output']\n" - "\n" - "gridder = hecl.Nodegrid(new_nodetree)\n" - "gridder.place_node(final_node, 3)\n" - "gridder.place_node(material_node, 0)\n" - "material_node.material = new_material\n" - "\n" - "texture_nodes = []\n" - "kcolor_nodes = []\n" - "color_combiner_nodes = []\n" - "alpha_combiner_nodes = []\n" - "tex_links = []\n" - "tev_reg_sockets = [None]*4\n" - "\n"), - groupIdx, matIdx); + out.format(fmt("new_material = bpy.data.materials.new('MAT_{}_{}')\n"), groupIdx, matIdx); + out << "new_material.use_fake_user = True\n" + "new_material.use_nodes = True\n" + "new_material.use_backface_culling = True\n" + "new_material.show_transparent_back = False\n" + "new_material.blend_method = 'BLEND'\n" + "new_nodetree = new_material.node_tree\n" + "for n in new_nodetree.nodes:\n" + " new_nodetree.nodes.remove(n)\n" + "\n" + "gridder = hecl.Nodegrid(new_nodetree)\n" + "new_nodetree.nodes.remove(gridder.frames[2])\n" + "\n" + "texture_nodes = []\n" + "kcolors = {}\n" + "kalphas = {}\n" + "tex_links = []\n" + "\n"; /* Material Flags */ out.format(fmt( + "new_material.retro_enable_bloom = {}\n" + "new_material.retro_force_lighting_stage = {}\n" + "new_material.retro_pre_inca_transparency = {}\n" "new_material.retro_alpha_test = {}\n" "new_material.retro_shadow_occluder = {}\n" - "new_material.diffuse_color = (1, 1, 1, {})\n"), + "new_material.retro_solid_white = {}\n" + "new_material.retro_reflection_alpha_target = {}\n" + "new_material.retro_solid_color = {}\n" + "new_material.retro_exclude_scan = {}\n" + "new_material.retro_xray_opaque = {}\n" + "new_material.retro_xray_alpha_target = {}\n" + "new_material.retro_inca_color_mod = False\n"), + material.header.flags.enableBloom() ? "True" : "False", + material.header.flags.forceLightingStage() ? "True" : "False", + material.header.flags.preIncaTransparency() ? "True" : "False", material.header.flags.alphaTest() ? "True" : "False", material.header.flags.shadowOccluderMesh() ? "True" : "False", - material.header.flags.shadowOccluderMesh() ? "0" : "1"); + material.header.flags.justWhite() ? "True" : "False", + material.header.flags.reflectionAlphaTarget() ? "True" : "False", + material.header.flags.justSolidColor() ? "True" : "False", + material.header.flags.excludeFromScanVisor() ? "True" : "False", + material.header.flags.xrayOpaque() ? "True" : "False", + material.header.flags.xrayAlphaTarget() ? "True" : "False"); - /* Blend factors */ - out << "blend_node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - "blend_node.name = 'Blend'\n" - "gridder.place_node(blend_node, 2)\n"; - if (material.header.flags.alphaBlending()) - out << "blend_node.node_tree = bpy.data.node_groups['HECLBlendOutput']\n"; - else if (material.header.flags.additiveBlending()) - out << "blend_node.node_tree = bpy.data.node_groups['HECLAdditiveOutput']\n"; - else { - out << "blend_node.node_tree = bpy.data.node_groups['HECLOpaqueOutput']\n" - "new_material.blend_method = 'OPAQUE'\n"; - } + out << "pnode = new_nodetree.nodes.new('ShaderNodeGroup')\n" + "pnode.name = 'Output'\n" + "pnode.node_tree = bpy.data.node_groups['RetroShaderMP3']\n" + "gridder.place_node(pnode, 1)\n"; - /* Texmap list */ - out << "tex_maps = []\n" - "pnode = None\n" - "anode = None\n" - "rflv_tex_node = None\n"; + if (material.header.flags.additiveIncandecence()) + out << "pnode.inputs['Add INCA'].default_value = 1\n"; - /* Add PASSes */ - i = 0; - unsigned texMapIdx = 0; - unsigned texMtxIdx = 0; - unsigned kColorIdx = 0; - Material::ISection* prevSection = nullptr; - for (const Material::SectionFactory& factory : material.sections) { - factory.section->constructNode(out, pakRouter, entry, prevSection, i++, texMapIdx, texMtxIdx, kColorIdx); - Material::SectionPASS* pass = Material::SectionPASS::castTo(factory.section.get()); - if (!pass || - (pass && Material::SectionPASS::Subtype(pass->subtype.toUint32()) != Material::SectionPASS::Subtype::RFLV)) - prevSection = factory.section.get(); - } + int texMtxIdx = 0; + for (const auto& chunk : material.chunks) { + if (const Material::PASS* pass = chunk.get_if()) { + LoadTexture(out, pass->txtrId, pakRouter, entry); + out << "# Texture\n" + "tex_node = new_nodetree.nodes.new('ShaderNodeTexImage')\n" + "texture_nodes.append(tex_node)\n" + "tex_node.image = image\n"; - /* Connect final PASS */ - out << "if pnode:\n" - " new_nodetree.links.new(pnode.outputs['Next Color'], final_node.inputs['Color'])\n" - "else:\n" - " new_nodetree.links.new(kcolor_nodes[-1][0].outputs[0], final_node.inputs['Color'])\n" - "if anode:\n" - " new_nodetree.links.new(anode.outputs['Value'], final_node.inputs['Alpha'])\n" - "elif pnode:\n" - " new_nodetree.links.new(pnode.outputs['Next Alpha'], final_node.inputs['Alpha'])\n" - "else:\n" - " new_nodetree.links.new(kcolor_nodes[-1][1].outputs[0], final_node.inputs['Alpha'])\n"; -} + if (!pass->uvAnim.empty()) { + const auto& uva = pass->uvAnim[0]; + switch (uva.uvSource) { + case Material::UVAnimationUVSource::Position: + default: + out << "tex_uv_node = new_nodetree.nodes.new('ShaderNodeTexCoord')\n" + "tex_links.append(new_nodetree.links.new(tex_uv_node.outputs['Window'], tex_node.inputs['Vector']))\n"; + break; + case Material::UVAnimationUVSource::Normal: + out << "tex_uv_node = new_nodetree.nodes.new('ShaderNodeTexCoord')\n" + "tex_links.append(new_nodetree.links.new(tex_uv_node.outputs['Normal'], tex_node.inputs['Vector']))\n"; + break; + case Material::UVAnimationUVSource::UV: + out.format(fmt("tex_uv_node = new_nodetree.nodes.new('ShaderNodeUVMap')\n" + "tex_links.append(new_nodetree.links.new(tex_uv_node.outputs['UV'], tex_node.inputs['Vector']))\n" + "tex_uv_node.uv_map = 'UV_{}'\n"), pass->uvSrc); + break; + } + out.format(fmt("tex_uv_node.label = 'MTX_{}'\n"), texMtxIdx); + } else { + out.format(fmt("tex_uv_node = new_nodetree.nodes.new('ShaderNodeUVMap')\n" + "tex_links.append(new_nodetree.links.new(tex_uv_node.outputs['UV'], tex_node.inputs['Vector']))\n" + "tex_uv_node.uv_map = 'UV_{}'\n"), pass->uvSrc); + } -void Material::SectionPASS::constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const { - /* Add Texture nodes */ - if (txtrId.isValid()) { - std::string texName = pakRouter.getBestEntryName(txtrId); - const nod::Node* node; - const PAK::Entry* texEntry = pakRouter.lookupEntry(txtrId, &node); - hecl::ProjectPath txtrPath = pakRouter.getWorking(texEntry); - if (txtrPath.isNone()) { - txtrPath.makeDirChain(false); - PAKEntryReadStream rs = texEntry->beginReadStream(*node); - TXTR::Extract(rs, txtrPath); + out << "gridder.place_node(tex_uv_node, 0)\n" + "gridder.place_node(tex_node, 0)\n" + "tex_uv_node.location[0] -= 120\n" + "tex_node.location[0] += 120\n" + "tex_node.location[1] += 176\n" + "\n"; + + if (!pass->uvAnim.empty()) { + const auto& uva = pass->uvAnim[0]; + DNAMP1::MaterialSet::Material::AddTextureAnim(out, uva.anim.mode, texMtxIdx++, uva.anim.vals); + } + + auto DoSwap = [&]() { + if (pass->flags.swapColorComponent() == Material::SwapColorComponent::Alpha) { + out << "swap_output = tex_node.outputs['Alpha']\n"; + } else { + out << "separate_node = new_nodetree.nodes.new('ShaderNodeSeparateRGB')\n" + "gridder.place_node(separate_node, 0, False)\n" + "separate_node.location[0] += 350\n" + "separate_node.location[1] += 350\n" + "new_nodetree.links.new(tex_node.outputs['Color'], separate_node.inputs[0])\n"; + out.format(fmt("swap_output = separate_node.outputs[{}]\n"), int(pass->flags.swapColorComponent())); + } + }; + + using Subtype = Material::PASS::Subtype; + switch (Subtype(pass->subtype.toUint32())) { + case Subtype::DIFF: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['DIFFC'])\n" + "new_nodetree.links.new(tex_node.outputs['Alpha'], pnode.inputs['DIFFA'])\n"; + break; + case Subtype::BLOL: + DoSwap(); + out << "new_nodetree.links.new(swap_output, pnode.inputs['BLOL'])\n"; + break; + case Subtype::BLOD: + DoSwap(); + out << "new_nodetree.links.new(swap_output, pnode.inputs['BLOD'])\n"; + break; + case Subtype::CLR: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['CLR'])\n" + "new_nodetree.links.new(tex_node.outputs['Alpha'], pnode.inputs['CLRA'])\n"; + break; + case Subtype::TRAN: + DoSwap(); + if (pass->flags.TRANInvert()) + out << "invert_node = new_nodetree.nodes.new('ShaderNodeInvert')\n" + "gridder.place_node(invert_node, 0, False)\n" + "invert_node.location[0] += 400\n" + "invert_node.location[1] += 350\n" + "new_nodetree.links.new(swap_output, invert_node.inputs['Color'])\n" + "swap_output = invert_node.outputs['Color']\n"; + out << "new_nodetree.links.new(swap_output, pnode.inputs['TRAN'])\n"; + break; + case Subtype::INCA: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['INCAC'])\n"; + if (pass->flags.alphaContribution()) { + DoSwap(); + out << "new_nodetree.links.new(swap_output, pnode.inputs['INCAA'])\n"; + } + out.format(fmt("new_material.retro_inca_color_mod = {}\n"), pass->flags.INCAColorMod() ? "True" : "False"); + break; + case Subtype::RFLV: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['RFLV'])\n"; + break; + case Subtype::RFLD: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['RFLD'])\n" + "new_nodetree.links.new(tex_node.outputs['Alpha'], pnode.inputs['RFLDA'])\n"; + break; + case Subtype::LRLD: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['LRLD'])\n"; + break; + case Subtype::LURD: + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['LURDC'])\n" + "new_nodetree.links.new(tex_node.outputs['Alpha'], pnode.inputs['LURDA'])\n"; + break; + case Subtype::BLOI: + DoSwap(); + out << "new_nodetree.links.new(swap_output, pnode.inputs['BLOI'])\n"; + break; + case Subtype::XRAY: + DoSwap(); + out << "new_nodetree.links.new(tex_node.outputs['Color'], pnode.inputs['XRAYC'])\n" + "new_nodetree.links.new(swap_output, pnode.inputs['XRAYA'])\n"; + break; + default: + Log.report(logvisor::Fatal, fmt("Unknown PASS subtype")); + break; + } + } else if (const Material::CLR* clr = chunk.get_if()) { + using Subtype = Material::CLR::Subtype; + athena::simd_floats vec4; + clr->color.toVec4f().simd.copy_to(vec4); + switch (Subtype(clr->subtype.toUint32())) { + case Subtype::CLR: + out.format(fmt("pnode.inputs['CLR'].default_value = ({}, {}, {}, 1.0)\n" + "pnode.inputs['CLRA'].default_value = {}\n"), + vec4[0], vec4[1], vec4[2], vec4[3]); + break; + case Subtype::DIFB: + out.format(fmt("pnode.inputs['DIFBC'].default_value = ({}, {}, {}, 1.0)\n" + "pnode.inputs['DIFBA'].default_value = {}\n"), + vec4[0], vec4[1], vec4[2], vec4[3]); + break; + default: + Log.report(logvisor::Fatal, fmt("Unknown CLR subtype")); + break; + } + } else if (const Material::INT* val = chunk.get_if()) { + using Subtype = Material::INT::Subtype; + switch (Subtype(val->subtype.toUint32())) { + case Subtype::OPAC: + out.format(fmt("pnode.inputs['OPAC'].default_value = {}\n"), val->value / 255.f); + break; + case Subtype::BLOD: + out.format(fmt("pnode.inputs['BLOD'].default_value = {}\n"), val->value / 255.f); + break; + case Subtype::BLOI: + out.format(fmt("pnode.inputs['BLOI'].default_value = {}\n"), val->value / 255.f); + break; + case Subtype::BNIF: + out.format(fmt("pnode.inputs['BNIF'].default_value = {}\n"), val->value / 255.f); + break; + case Subtype::XRBR: + out.format(fmt("pnode.inputs['XRBR'].default_value = {}\n"), val->value / 255.f); + break; + default: + Log.report(logvisor::Fatal, fmt("Unknown INT subtype")); + break; + } } - hecl::SystemString resPath = pakRouter.getResourceRelativePath(entry, txtrId); - hecl::SystemUTF8Conv resPathView(resPath); - out.format(fmt( - "if '{}' in bpy.data.textures:\n" - " image = bpy.data.images['{}']\n" - " texture = bpy.data.textures[image.name]\n" - "else:\n" - " image = bpy.data.images.load('''//{}''')\n" - " image.name = '{}'\n" - " texture = bpy.data.textures.new(image.name, 'IMAGE')\n" - " texture.image = image\n" - "tex_maps.append(texture)\n" - "\n"), - texName, texName, resPathView, texName); - if (uvAnim.size()) { - const UVAnimation& uva = uvAnim[0]; - DNAMP1::MaterialSet::Material::AddTexture(out, GX::TexGenSrc(uva.unk1 + (uva.unk1 < 2 ? 0 : 2)), texMtxIdx, - texMapIdx++, false); - DNAMP1::MaterialSet::Material::AddTextureAnim(out, uva.anim.mode, texMtxIdx++, uva.anim.vals); - } else - DNAMP1::MaterialSet::Material::AddTexture(out, GX::TexGenSrc(uvSrc + 4), -1, texMapIdx++, false); - } - - /* Special case for RFLV (environment UV mask) */ - if (Subtype(subtype.toUint32()) == Subtype::RFLV) { - if (txtrId.isValid()) - out << "rflv_tex_node = texture_nodes[-1]\n"; - return; - } - - /* Add PASS node */ - bool linkRAS = false; - out << "prev_pnode = pnode\n" - "pnode = new_nodetree.nodes.new('ShaderNodeGroup')\n"; - switch (Subtype(subtype.toUint32())) { - case Subtype::DIFF: { - out << "pnode.node_tree = bpy.data.node_groups['RetroPassDIFF']\n"; - if (txtrId.isValid()) { - out << "new_material.hecl_lightmap = texture.name\n" - << "texture.image.use_fake_user = True\n"; - } - linkRAS = true; - break; - } - case Subtype::RIML: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassRIML']\n"; - if (idx == 0) - linkRAS = true; - break; - case Subtype::BLOL: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassBLOL']\n"; - if (idx == 0) - linkRAS = true; - break; - case Subtype::BLOD: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassBLOD']\n"; - if (idx == 0) - linkRAS = true; - break; - case Subtype::CLR: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassCLR']\n"; - if (idx == 0) - linkRAS = true; - break; - case Subtype::TRAN: - if (flags.TRANInvert()) - out << "pnode.node_tree = bpy.data.node_groups['RetroPassTRANInv']\n"; - else - out << "pnode.node_tree = bpy.data.node_groups['RetroPassTRAN']\n"; - break; - case Subtype::INCA: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassINCA']\n"; - break; - case Subtype::RFLV: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassRFLV']\n"; - break; - case Subtype::RFLD: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassRFLD']\n" - "if rflv_tex_node:\n" - " new_nodetree.links.new(rflv_tex_node.outputs['Color'], pnode.inputs['Mask Color'])\n" - " new_nodetree.links.new(rflv_tex_node.outputs['Value'], pnode.inputs['Mask Alpha'])\n"; - break; - case Subtype::LRLD: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassLRLD']\n"; - break; - case Subtype::LURD: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassLURD']\n"; - break; - case Subtype::BLOI: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassBLOI']\n"; - break; - case Subtype::XRAY: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassXRAY']\n"; - break; - case Subtype::TOON: - out << "pnode.node_tree = bpy.data.node_groups['RetroPassTOON']\n"; - break; - default: - break; - } - out << "gridder.place_node(pnode, 2)\n"; - - if (txtrId.isValid()) { - out << "new_nodetree.links.new(texture_nodes[-1].outputs['Color'], pnode.inputs['Tex Color'])\n" - "new_nodetree.links.new(texture_nodes[-1].outputs['Value'], pnode.inputs['Tex Alpha'])\n"; - } - - if (linkRAS) - out << "new_nodetree.links.new(material_node.outputs['Color'], pnode.inputs['Prev Color'])\n" - "new_nodetree.links.new(material_node.outputs['Alpha'], pnode.inputs['Prev Alpha'])\n"; - else if (prevSection) { - if (prevSection->m_type == ISection::Type::PASS && - Subtype(static_cast(prevSection)->subtype.toUint32()) != Subtype::RFLV) - out << "new_nodetree.links.new(prev_pnode.outputs['Next Color'], pnode.inputs['Prev Color'])\n" - "new_nodetree.links.new(prev_pnode.outputs['Next Alpha'], pnode.inputs['Prev Alpha'])\n"; - else if (prevSection->m_type == ISection::Type::CLR) - out << "new_nodetree.links.new(kcolor_nodes[-1][0].outputs[0], pnode.inputs['Prev Color'])\n" - "new_nodetree.links.new(kcolor_nodes[-1][1].outputs[0], pnode.inputs['Prev Alpha'])\n"; - } - - /* Row Break in gridder */ - out << "gridder.row_break(2)\n"; -} - -void Material::SectionCLR::constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const { - DNAMP1::MaterialSet::Material::AddKcolor(out, color, kColorIdx++); - switch (Subtype(subtype.toUint32())) { - case Subtype::DIFB: - out << "kc_node.label += ' DIFB'\n" - "ka_node.label += ' DIFB'\n"; - break; - default: - break; - } -} - -void Material::SectionINT::constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const { - switch (Subtype(subtype.toUint32())) { - case Subtype::OPAC: { - GX::Color clr(value); - out.format(fmt( - "anode = new_nodetree.nodes.new('ShaderNodeValue')\n" - "anode.outputs['Value'].default_value = {}\n"), - float(clr[3]) / float(0xff)); - out << "gridder.place_node(anode, 1)\n"; - } break; - case Subtype::BLOD: - out.format(fmt("new_material.retro_blod = {}\n"), value); - break; - case Subtype::BLOI: - out.format(fmt("new_material.retro_bloi = {}\n"), value); - break; - case Subtype::BNIF: - out.format(fmt("new_material.retro_bnif = {}\n"), value); - break; - case Subtype::XRBR: - out.format(fmt("new_material.retro_xrbr = {}\n"), value); - break; - default: - break; } } } // namespace DataSpec::DNAMP3 + +AT_SPECIALIZE_TYPED_VARIANT_BIGDNA(DataSpec::DNAMP3::MaterialSet::Material::PASS, + DataSpec::DNAMP3::MaterialSet::Material::CLR, + DataSpec::DNAMP3::MaterialSet::Material::INT, + DataSpec::DNAMP3::MaterialSet::Material::END) diff --git a/DataSpec/DNAMP3/CMDLMaterials.hpp b/DataSpec/DNAMP3/CMDLMaterials.hpp index df73b62e0..89d562a72 100644 --- a/DataSpec/DNAMP3/CMDLMaterials.hpp +++ b/DataSpec/DNAMP3/CMDLMaterials.hpp @@ -18,6 +18,10 @@ struct MaterialSet : BigDNA { void addMaterialEndOff(atUint32) { ++materialCount; } struct Material : BigDNA { + enum class SwapColorComponent { Red, Green, Blue, Alpha }; + enum class UVAnimationUVSource : atUint16 { Position, Normal, UV }; + enum class UVAnimationMatrixConfig : atUint16 { NoMtxNoPost, MtxNoPost, NoMtxPost, MtxPost }; + AT_DECL_EXPLICIT_DNA using VAFlags = DNAMP1::MaterialSet::Material::VAFlags; struct Header : BigDNA { @@ -26,8 +30,18 @@ struct MaterialSet : BigDNA { struct Flags : BigDNA { AT_DECL_DNA Value flags; - bool alphaBlending() const { return (flags & 0x8) != 0; } - void setAlphaBlending(bool enabled) { + bool enableBloom() const { return (flags & 0x1) != 0; } + void setEnableBloom(bool enabled) { + flags &= ~0x1; + flags |= atUint32(enabled) << 0; + } + bool forceLightingStage() const { return (flags & 0x4) != 0; } + void setForceLightingStage(bool enabled) { + flags &= ~0x4; + flags |= atUint32(enabled) << 2; + } + bool preIncaTransparency() const { return (flags & 0x8) != 0; } + void setPreIncaTransparency(bool enabled) { flags &= ~0x8; flags |= atUint32(enabled) << 3; } @@ -36,8 +50,8 @@ struct MaterialSet : BigDNA { flags &= ~0x10; flags |= atUint32(enabled) << 4; } - bool additiveBlending() const { return (flags & 0x20) != 0; } - void setAdditiveBlending(bool enabled) { + bool additiveIncandecence() const { return (flags & 0x20) != 0; } + void setAdditiveIncandecence(bool enabled) { flags &= ~0x20; flags |= atUint32(enabled) << 5; } @@ -46,6 +60,36 @@ struct MaterialSet : BigDNA { flags &= ~0x100; flags |= atUint32(enabled) << 8; } + bool justWhite() const { return (flags & 0x200) != 0; } + void setJustWhite(bool enabled) { + flags &= ~0x200; + flags |= atUint32(enabled) << 9; + } + bool reflectionAlphaTarget() const { return (flags & 0x400) != 0; } + void setReflectionAlphaTarget(bool enabled) { + flags &= ~0x400; + flags |= atUint32(enabled) << 10; + } + bool justSolidColor() const { return (flags & 0x800) != 0; } + void setJustSolidColor(bool enabled) { + flags &= ~0x800; + flags |= atUint32(enabled) << 11; + } + bool excludeFromScanVisor() const { return (flags & 0x4000) != 0; } + void setExcludeFromScanVisor(bool enabled) { + flags &= ~0x4000; + flags |= atUint32(enabled) << 14; + } + bool xrayOpaque() const { return (flags & 0x8000) != 0; } + void setXRayOpaque(bool enabled) { + flags &= ~0x8000; + flags |= atUint32(enabled) << 15; + } + bool xrayAlphaTarget() const { return (flags & 0x10000) != 0; } + void setXRayAlphaTarget(bool enabled) { + flags &= ~0x10000; + flags |= atUint32(enabled) << 16; + } bool lightmapUVArray() const { return false; } /* For polymorphic compatibility with MP1/2 */ } flags; Value uniqueIdx; @@ -58,20 +102,12 @@ struct MaterialSet : BigDNA { const Header::Flags& getFlags() const { return header.flags; } const VAFlags& getVAFlags() const { return header.vaFlags; } - struct ISection : BigDNAV { - Delete expl; - enum class Type : atUint32 { PASS = SBIG('PASS'), CLR = SBIG('CLR '), INT = SBIG('INT ') } m_type; - ISection(Type type) : m_type(type) {} - virtual void constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const = 0; + enum class ChunkType : atUint32 { + PASS = 'PASS', CLR = 'CLR ', INT = 'INT ', END = 'END ' }; - struct SectionPASS : ISection { - SectionPASS() : ISection(ISection::Type::PASS) {} - static SectionPASS* castTo(ISection* sec) { - return sec->m_type == Type::PASS ? static_cast(sec) : nullptr; - } - AT_DECL_DNAV + + struct PASS : hecl::TypedRecordBigDNA { + AT_DECL_DNA Value size; enum class Subtype : atUint32 { DIFF = SBIG('DIFF'), @@ -93,6 +129,21 @@ struct MaterialSet : BigDNA { struct Flags : BigDNA { AT_DECL_DNA Value flags; + SwapColorComponent swapColorComponent() const { return SwapColorComponent(flags & 0x3); } + void setSwapColorComponent(SwapColorComponent comp) { + flags &= ~0x3; + flags |= atUint32(comp) << 0; + } + bool alphaContribution() const { return (flags & 0x4) != 0; } + void setAlphaContribution(bool enabled) { + flags &= ~0x4; + flags |= atUint32(enabled) << 2; + } + bool INCAColorMod() const { return (flags & 0x8) != 0; } + void setINCAColorMod(bool enabled) { + flags &= ~0x8; + flags |= atUint32(enabled) << 3; + } bool TRANInvert() const { return (flags & 0x10) != 0; } void setTRANInvert(bool enabled) { flags &= ~0x10; @@ -104,36 +155,21 @@ struct MaterialSet : BigDNA { Value uvAnimSize; struct UVAnimation : BigDNA { AT_DECL_DNA - Value unk1; - Value unk2; + Value uvSource; + Value mtxConfig; DNAMP1::MaterialSet::Material::UVAnimation anim; }; Vector uvAnim; - - void constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const override; }; - struct SectionCLR : ISection { - SectionCLR() : ISection(ISection::Type::CLR) {} - static SectionCLR* castTo(ISection* sec) { - return sec->m_type == Type::CLR ? static_cast(sec) : nullptr; - } - AT_DECL_DNAV + struct CLR : hecl::TypedRecordBigDNA { + AT_DECL_DNA enum class Subtype : atUint32 { CLR = SBIG('CLR '), DIFB = SBIG('DIFB') }; DNAFourCC subtype; GX::Color color; - - void constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const override; + CLR() = default; }; - struct SectionINT : ISection { - SectionINT() : ISection(ISection::Type::INT) {} - static SectionINT* castTo(ISection* sec) { - return sec->m_type == Type::INT ? static_cast(sec) : nullptr; - } - AT_DECL_DNAV + struct INT : hecl::TypedRecordBigDNA { + AT_DECL_DNA enum class Subtype : atUint32 { OPAC = SBIG('OPAC'), BLOD = SBIG('BLOD'), @@ -143,16 +179,12 @@ struct MaterialSet : BigDNA { }; DNAFourCC subtype; Value value; - - void constructNode(hecl::blender::PyOutStream& out, const PAKRouter& pakRouter, - const PAK::Entry& entry, const Material::ISection* prevSection, unsigned idx, - unsigned& texMapIdx, unsigned& texMtxIdx, unsigned& kColorIdx) const override; }; - struct SectionFactory : BigDNA { - AT_DECL_EXPLICIT_DNA - std::unique_ptr section; + struct END : hecl::TypedRecordBigDNA { + AT_DECL_DNA }; - std::vector sections; + using Chunk = hecl::TypedVariantBigDNA; + std::vector chunks; }; Vector materials; diff --git a/DataSpec/DNAMP3/CMakeLists.txt b/DataSpec/DNAMP3/CMakeLists.txt index 0c0ea91a6..e4950978b 100644 --- a/DataSpec/DNAMP3/CMakeLists.txt +++ b/DataSpec/DNAMP3/CMakeLists.txt @@ -14,11 +14,12 @@ set(DNAMP3_SOURCES DNAMP3.hpp DNAMP3.cpp PAK.cpp ANIM.cpp - CINF.cpp + CINF.hpp CHAR.cpp CMDL.hpp CMDL.cpp CMDLMaterials.cpp CSKR.cpp + PATH.hpp STRG.hpp STRG.cpp MAPA.hpp MREA.cpp) diff --git a/DataSpec/DNAMP3/DNAMP3.cpp b/DataSpec/DNAMP3/DNAMP3.cpp index a2b8199b0..c252ad33e 100644 --- a/DataSpec/DNAMP3/DNAMP3.cpp +++ b/DataSpec/DNAMP3/DNAMP3.cpp @@ -9,6 +9,7 @@ #include "CHAR.hpp" #include "MREA.hpp" #include "MAPA.hpp" +#include "PATH.hpp" #include "SAVW.hpp" #include "HINT.hpp" #include "DataSpec/DNACommon/TXTR.hpp" @@ -21,6 +22,8 @@ namespace DataSpec::DNAMP3 { logvisor::Module Log("urde::DNAMP3"); static bool GetNoShare(std::string_view name) { + if (name == "UniverseArea.pak"sv) + return false; std::string lowerName(name); std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower); if (!lowerName.compare(0, 7, "metroid")) @@ -194,6 +197,16 @@ void PAKBridge::addMAPATransforms(PAKRouter& pakRouter, fmt::format(fmt(_SYS_STR("!name_{}.yaml")), mlvl.worldNameId)); for (const MLVL::Area& area : mlvl.areas) { + { + /* Get PATH transform */ + const nod::Node* areaNode; + const PAK::Entry* areaEntry = pakRouter.lookupEntry(area.areaMREAId, &areaNode); + PAKEntryReadStream rs = areaEntry->beginReadStream(*areaNode); + UniqueID64 pathId = MREA::GetPATHId(rs); + if (pathId.isValid()) + addTo[pathId] = zeus::CMatrix4f(area.transformMtx[0], area.transformMtx[1], area.transformMtx[2], BottomRow) + .transposed(); + } hecl::ProjectPath areaDirPath = pakRouter.getWorking(area.areaMREAId).getParentPath(); if (area.areaNameId.isValid()) pathOverrides[area.areaNameId] = hecl::ProjectPath(areaDirPath, @@ -236,16 +249,20 @@ ResExtractor PAKBridge::LookupExtractor(const nod::Node& pakNode, con return {SAVWCommon::ExtractSAVW, {_SYS_STR(".yaml")}}; case SBIG('HINT'): return {HINT::Extract, {_SYS_STR(".yaml")}}; -// case SBIG('CMDL'): -// return {CMDL::Extract, {_SYS_STR(".blend")}, 1}; -// case SBIG('CHAR'): -// return {CHAR::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 2}; -// case SBIG('MLVL'): -// return {MLVL::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 3}; -// case SBIG('MREA'): -// return {MREA::Extract, {_SYS_STR(".blend")}, 4}; -// case SBIG('MAPA'): -// return {MAPA::Extract, {_SYS_STR(".blend")}, 4}; + case SBIG('CMDL'): + return {CMDL::Extract, {_SYS_STR(".blend")}, 1}; + case SBIG('CINF'): + return {CINF::Extract, {_SYS_STR(".blend")}, 1}; + case SBIG('CHAR'): + return {CHAR::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 2}; + case SBIG('MLVL'): + return {MLVL::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 3}; + case SBIG('MREA'): + return {MREA::Extract, {_SYS_STR(".blend")}, 4}; + case SBIG('MAPA'): + return {MAPA::Extract, {_SYS_STR(".blend")}, 4}; + case SBIG('PATH'): + return {PATH::Extract, {_SYS_STR(".blend")}, 5}; case SBIG('FSM2'): return {DNAFSM2::ExtractFSM2, {_SYS_STR(".yaml")}}; case SBIG('FONT'): diff --git a/DataSpec/DNAMP3/MREA.cpp b/DataSpec/DNAMP3/MREA.cpp index a54712423..293441c11 100644 --- a/DataSpec/DNAMP3/MREA.cpp +++ b/DataSpec/DNAMP3/MREA.cpp @@ -14,16 +14,14 @@ MREA::StreamReader::StreamReader(athena::io::IStreamReader& source, atUint32 blk m_blkCount = blkCount; m_blockInfos.reserve(blkCount); for (atUint32 i = 0; i < blkCount; ++i) { - m_blockInfos.emplace_back(); - BlockInfo& info = m_blockInfos.back(); + BlockInfo& info = m_blockInfos.emplace_back(); info.read(source); m_totalDecompLen += info.decompSize; } source.seekAlign32(); m_secIdxs.reserve(secIdxCount); for (atUint32 i = 0; i < secIdxCount; ++i) { - m_secIdxs.emplace_back(); - std::pair& idx = m_secIdxs.back(); + std::pair& idx = m_secIdxs.emplace_back(); idx.first.read(source); idx.second = source.readUint32Big(); } @@ -39,6 +37,15 @@ void MREA::StreamReader::writeSecIdxs(athena::io::IStreamWriter& writer) const { } } +bool MREA::StreamReader::seekToSection(FourCC sec, const std::vector& secSizes) { + auto search = std::find_if(m_secIdxs.begin(), m_secIdxs.end(), [sec](const auto& s) { return s.first == sec; }); + if (search != m_secIdxs.end()) { + DNAMP2::MREA::StreamReader::seekToSection(search->second, secSizes); + return true; + } + return false; +} + void MREA::ReadBabeDeadToBlender_3(hecl::blender::PyOutStream& os, athena::io::IStreamReader& rs) { atUint32 bdMagic = rs.readUint32Big(); if (bdMagic != 0xBABEDEAD) @@ -254,5 +261,20 @@ bool MREA::ExtractLayerDeps(PAKEntryReadStream& rs, PAKBridge::Level::Area& area return false; } +UniqueID64 MREA::GetPATHId(PAKEntryReadStream& rs) { + /* Do extract */ + Header head; + head.read(rs); + rs.seekAlign32(); + + /* MREA decompression stream */ + StreamReader drs(rs, head.compressedBlockCount, head.secIndexCount); + + /* Skip to PATH */ + if (drs.seekToSection(FOURCC('PFL2'), head.secSizes)) + return {drs}; + return {}; +} + } // namespace DNAMP3 } // namespace DataSpec diff --git a/DataSpec/DNAMP3/MREA.hpp b/DataSpec/DNAMP3/MREA.hpp index 35d234d54..5747b4393 100644 --- a/DataSpec/DNAMP3/MREA.hpp +++ b/DataSpec/DNAMP3/MREA.hpp @@ -13,6 +13,7 @@ struct MREA { StreamReader(athena::io::IStreamReader& source, atUint32 blkCount, atUint32 secIdxCount); std::vector>::const_iterator beginSecIdxs() { return m_secIdxs.begin(); } void writeSecIdxs(athena::io::IStreamWriter& writer) const; + bool seekToSection(FourCC sec, const std::vector& secSizes); }; struct Header : BigDNA { @@ -84,6 +85,8 @@ struct MREA { static void ReadBabeDeadToBlender_3(hecl::blender::PyOutStream& os, athena::io::IStreamReader& rs); + static UniqueID64 GetPATHId(PAKEntryReadStream& rs); + static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, PAKRouter& pakRouter, const PAK::Entry& entry, bool, hecl::blender::Token& btok, std::function); diff --git a/DataSpec/DNAMP3/PATH.hpp b/DataSpec/DNAMP3/PATH.hpp new file mode 100644 index 000000000..f2b218055 --- /dev/null +++ b/DataSpec/DNAMP3/PATH.hpp @@ -0,0 +1,6 @@ +#pragma once +#include "DataSpec/DNACommon/PATH.hpp" + +namespace DataSpec::DNAMP3 { +using PATH = DNAPATH::PATH; +} // namespace DataSpec::DNAMP3 diff --git a/hecl b/hecl index b3d91f520..87ad5cbc8 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit b3d91f520ad3a9429b0116f9b531ec12b2e71809 +Subproject commit 87ad5cbc81dad92d54c60d388157ca6300475c19