diff --git a/DataSpec/Blender/RetroMasterShader.py b/DataSpec/Blender/RetroMasterShader.py index 6e49ee676..4749aa409 100644 --- a/DataSpec/Blender/RetroMasterShader.py +++ b/DataSpec/Blender/RetroMasterShader.py @@ -58,6 +58,8 @@ def make_retro_shader(): lightmap_input.default_value = (0.0, 0.0, 0.0, 0.0) diffuse_input = new_grp.inputs.new('NodeSocketColor', 'Diffuse') diffuse_input.default_value = (0.0, 0.0, 0.0, 0.0) + diffuse_mod_input = new_grp.inputs.new('NodeSocketColor', 'DiffuseMod') + diffuse_mod_input.default_value = (1.0, 1.0, 1.0, 1.0) emissive_input = new_grp.inputs.new('NodeSocketColor', 'Emissive') emissive_input.default_value = (0.0, 0.0, 0.0, 0.0) specular_input = new_grp.inputs.new('NodeSocketColor', 'Specular') @@ -72,6 +74,10 @@ def make_retro_shader(): alpha_input.default_value = 1.0 alpha_input.min_value = 0.0 alpha_input.max_value = 1.0 + alpha_mod_input = new_grp.inputs.new('NodeSocketFloatFactor', 'AlphaMod') + alpha_mod_input.default_value = 1.0 + alpha_mod_input.min_value = 0.0 + alpha_mod_input.max_value = 1.0 new_grp.use_fake_user = True # Group inputs @@ -108,6 +114,17 @@ def make_retro_shader(): new_shader_model_mix1 = new_grp.nodes.new('ShaderNodeMixShader') new_shader_model_mix1.location = (-760, 340) + # Multiply (Multiples diffuse with diffusemod) + diffuse_mult = new_grp.nodes.new('ShaderNodeMixRGB') + diffuse_mult.location = (-1094, 122) + diffuse_mult.blend_type = 'MULTIPLY' + diffuse_mult.inputs['Fac'].default_value = 1.0 + + # Multiply (Multiples alpha with alphamod) + alpha_mult = new_grp.nodes.new('ShaderNodeMath') + alpha_mult.location = (-1094, -178) + alpha_mult.operation = 'MULTIPLY' + # Multiply (Multiplies static lightmap with diffuse) lightmap_mult = new_grp.nodes.new('ShaderNodeMixRGB') lightmap_mult.location = (-944, 122) @@ -164,17 +181,21 @@ def make_retro_shader(): mat_out.location = (150, -88) # Links + new_grp.links.new(grp_in.outputs['Diffuse'], diffuse_mult.inputs['Color1']) + new_grp.links.new(grp_in.outputs['DiffuseMod'], diffuse_mult.inputs['Color2']) + new_grp.links.new(grp_in.outputs['Alpha'], alpha_mult.inputs[0]) + new_grp.links.new(grp_in.outputs['AlphaMod'], alpha_mult.inputs[1]) new_grp.links.new(grp_in.outputs['Lightmap'], lightmap_mult.inputs['Color1']) - new_grp.links.new(grp_in.outputs['Diffuse'], lightmap_mult.inputs['Color2']) - new_grp.links.new(grp_in.outputs['Diffuse'], diffuse_bdsf.inputs['Color']) - new_grp.links.new(grp_in.outputs['Diffuse'], principled_bsdf.inputs['Base Color']) + new_grp.links.new(diffuse_mult.outputs['Color'], lightmap_mult.inputs['Color2']) + new_grp.links.new(diffuse_mult.outputs['Color'], diffuse_bdsf.inputs['Color']) + new_grp.links.new(diffuse_mult.outputs['Color'], principled_bsdf.inputs['Base Color']) new_grp.links.new(grp_in.outputs['Emissive'], emissive_add_shader.inputs[0]) new_grp.links.new(grp_in.outputs['Specular'], specular_mult.inputs['Color1']) new_grp.links.new(grp_in.outputs['Specular'], principled_bsdf.inputs['Specular']) new_grp.links.new(grp_in.outputs['ExtendedSpecular'], extended_specular_mult.inputs['Color1']) new_grp.links.new(grp_in.outputs['Reflection'], specular_mult.inputs['Color2']) new_grp.links.new(grp_in.outputs['Reflection'], extended_specular_mult.inputs['Color2']) - new_grp.links.new(grp_in.outputs['Alpha'], alpha_mix.inputs['Fac']) + new_grp.links.new(alpha_mult.outputs[0], alpha_mix.inputs['Fac']) new_grp.links.new(new_shader_model.outputs['Value'], new_shader_model_mix1.inputs[0]) new_grp.links.new(diffuse_bdsf.outputs['BSDF'], new_shader_model_mix1.inputs[1]) new_grp.links.new(grp_in.outputs['Specular'], invert.inputs['Color']) @@ -700,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: @@ -1175,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() @@ -1590,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/AROTBuilder.cpp b/DataSpec/DNACommon/AROTBuilder.cpp index fbe48dd41..c31ae21f0 100644 --- a/DataSpec/DNACommon/AROTBuilder.cpp +++ b/DataSpec/DNACommon/AROTBuilder.cpp @@ -4,7 +4,7 @@ #include #include "hecl/Blender/Connection.hpp" -#include "../DNAMP1/PATH.hpp" +#include "PATH.hpp" namespace DataSpec { logvisor::Module Log("AROTBuilder"); @@ -278,10 +278,10 @@ void AROTBuilder::Node::pathCountNodesAndLookups(size_t& nodeCount, size_t& look } } -void AROTBuilder::Node::pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAABB) { +template +void AROTBuilder::Node::pathWrite(DNAPATH::PATH& path, const zeus::CAABox& curAABB) { if (childNodes.empty()) { - path.octree.emplace_back(); - DNAMP1::PATH::OctreeNode& n = path.octree.back(); + auto& n = path.octree.emplace_back(); n.isLeaf = 1; n.aabb[0] = curAABB.min; n.aabb[1] = curAABB.max; @@ -299,8 +299,7 @@ void AROTBuilder::Node::pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAAB children[i] = path.octree.size() - 1; } - path.octree.emplace_back(); - DNAMP1::PATH::OctreeNode& n = path.octree.back(); + auto& n = path.octree.emplace_back(); n.isLeaf = 0; n.aabb[0] = curAABB.min; n.aabb[1] = curAABB.max; @@ -311,6 +310,10 @@ void AROTBuilder::Node::pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAAB } } +template void AROTBuilder::Node::pathWrite(DNAPATH::PATH& path, const zeus::CAABox& curAABB); +template void AROTBuilder::Node::pathWrite(DNAPATH::PATH& path, const zeus::CAABox& curAABB); +template void AROTBuilder::Node::pathWrite(DNAPATH::PATH& path, const zeus::CAABox& curAABB); + void AROTBuilder::build(std::vector>& secs, const zeus::CAABox& fullAabb, const std::vector& meshAabbs, const std::vector& meshes) { /* Recursively split */ @@ -406,15 +409,14 @@ std::pair, uint32_t> AROTBuilder::buildCol(const ColM return {std::move(ret), totalSize}; } -void AROTBuilder::buildPath(DNAMP1::PATH& path) { +template +void AROTBuilder::buildPath(DNAPATH::PATH& path) { /* Accumulate total AABB and gather region boxes */ std::vector regionBoxes; regionBoxes.reserve(path.regions.size()); zeus::CAABox fullAABB; - for (const DNAMP1::PATH::Region& r : path.regions) { - regionBoxes.emplace_back(r.aabb[0], r.aabb[1]); - fullAABB.accumulateBounds(regionBoxes.back()); - } + for (const auto& r : path.regions) + fullAABB.accumulateBounds(regionBoxes.emplace_back(r.aabb[0], r.aabb[1])); /* Recursively split */ BspNodeType dontCare; @@ -431,4 +433,8 @@ void AROTBuilder::buildPath(DNAMP1::PATH& path) { rootNode.pathWrite(path, fullAABB); } +template void AROTBuilder::buildPath(DNAPATH::PATH& path); +template void AROTBuilder::buildPath(DNAPATH::PATH& path); +template void AROTBuilder::buildPath(DNAPATH::PATH& path); + } // namespace DataSpec diff --git a/DataSpec/DNACommon/AROTBuilder.hpp b/DataSpec/DNACommon/AROTBuilder.hpp index 1ecabbce7..a10a00128 100644 --- a/DataSpec/DNACommon/AROTBuilder.hpp +++ b/DataSpec/DNACommon/AROTBuilder.hpp @@ -7,10 +7,12 @@ #include namespace DataSpec { -namespace DNAMP1 { +namespace DNAPATH { +template struct PATH; } + struct AROTBuilder { using ColMesh = hecl::blender::ColMesh; @@ -42,13 +44,15 @@ struct AROTBuilder { void writeColNodes(uint8_t*& ptr, const zeus::CAABox& curAABB); void pathCountNodesAndLookups(size_t& nodeCount, size_t& lookupCount); - void pathWrite(DNAMP1::PATH& path, const zeus::CAABox& curAABB); + template + void pathWrite(DNAPATH::PATH& path, const zeus::CAABox& curAABB); } rootNode; void build(std::vector>& secs, const zeus::CAABox& fullAabb, const std::vector& meshAabbs, const std::vector& meshes); std::pair, uint32_t> buildCol(const ColMesh& mesh, BspNodeType& rootOut); - void buildPath(DNAMP1::PATH& path); + template + void buildPath(DNAPATH::PATH& path); }; } // namespace DataSpec diff --git a/DataSpec/DNACommon/CMDL.cpp b/DataSpec/DNACommon/CMDL.cpp index 394d437fe..b20cc4067 100644 --- a/DataSpec/DNACommon/CMDL.cpp +++ b/DataSpec/DNACommon/CMDL.cpp @@ -521,7 +521,10 @@ void FinishBlenderMesh(hecl::blender::PyOutStream& os, unsigned matSetCount, int " use_vert_dict = vert_dict[0]\n" " merge_verts = [use_vert_dict[fv[od_entry['bm'].verts.layers.int['CMDLOriginalPosIdxs']]] for fv in " "face.verts]\n" - " if bm.faces.get(merge_verts) is not None:\n" + " try:\n" + " if bm.faces.get(merge_verts) is not None:\n" + " continue\n" + " except:\n" " continue\n" " merge_face = bm.faces.new(merge_verts)\n" " for i in range(len(face.loops)):\n" diff --git a/DataSpec/DNACommon/CMakeLists.txt b/DataSpec/DNACommon/CMakeLists.txt index 39a616532..4d77c84cf 100644 --- a/DataSpec/DNACommon/CMakeLists.txt +++ b/DataSpec/DNACommon/CMakeLists.txt @@ -4,6 +4,7 @@ make_dnalist(CMDL FSM2 MAPA MAPU + PATH MayaSpline EGMC SAVWCommon @@ -19,6 +20,7 @@ set(DNACOMMON_SOURCES CMDL.cpp MAPA.cpp MAPU.cpp + PATH.hpp PATH.cpp STRG.hpp STRG.cpp TXTR.hpp TXTR.cpp ANCS.hpp ANCS.cpp 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/DNAMP1/PATH.cpp b/DataSpec/DNACommon/PATH.cpp similarity index 52% rename from DataSpec/DNAMP1/PATH.cpp rename to DataSpec/DNACommon/PATH.cpp index 506995484..b756b5e73 100644 --- a/DataSpec/DNAMP1/PATH.cpp +++ b/DataSpec/DNACommon/PATH.cpp @@ -3,7 +3,7 @@ #include "zeus/CAABox.hpp" #include "DataSpec/DNACommon/AROTBuilder.hpp" -namespace DataSpec::DNAMP1 { +namespace DataSpec::DNAPATH { #define DUMP_OCTREE 0 @@ -13,71 +13,70 @@ static void OutputOctreeNode(hecl::blender::PyOutStream& os, int idx, const zeus const zeus::CVector3f pos = aabb.center(); const zeus::CVector3f extent = aabb.extents(); os.format( - "obj = bpy.data.objects.new('Leaf_%d', None)\n" - "bpy.context.scene.collection.objects.link(obj)\n" - "obj.location = (%f,%f,%f)\n" - "obj.scale = (%f,%f,%f)\n" - "obj.empty_display_type = 'CUBE'\n" - "obj.layers[1] = True\n" - "obj.layers[0] = False\n", idx, - pos.x(), pos.y(), pos.z(), extent.x(), extent.y(), extent.z()); + "obj = bpy.data.objects.new('Leaf_%d', None)\n" + "bpy.context.scene.collection.objects.link(obj)\n" + "obj.location = (%f,%f,%f)\n" + "obj.scale = (%f,%f,%f)\n" + "obj.empty_display_type = 'CUBE'\n" + "obj.layers[1] = True\n" + "obj.layers[0] = False\n", + idx, pos.x(), pos.y(), pos.z(), extent.x(), extent.y(), extent.z()); } #endif -void PATH::sendToBlender(hecl::blender::Connection& conn, std::string_view entryName, const zeus::CMatrix4f* xf, - const std::string& areaPath) { +template +void PATH::sendToBlender(hecl::blender::Connection& conn, std::string_view entryName, + const zeus::CMatrix4f* xf, const std::string& areaPath) { /* Open Py Stream and read sections */ hecl::blender::PyOutStream os = conn.beginPythonOut(true); - os << - "import bpy\n" - "import bmesh\n" - "from mathutils import Vector, Matrix\n" - "\n" - "bpy.types.Material.retro_path_idx_mask = bpy.props.IntProperty(name='Retro: Path Index Mask')\n" - "bpy.types.Material.retro_path_type_mask = bpy.props.IntProperty(name='Retro: Path Type Mask')\n" - "\n" - "material_dict = {}\n" - "material_index = []\n" - "def make_ground_material(idxMask):\n" - " mat = bpy.data.materials.new('Ground %X' % idxMask)\n" - " mat.diffuse_color = (0.8, 0.460, 0.194, 1.0)\n" - " return mat\n" - "def make_flyer_material(idxMask):\n" - " mat = bpy.data.materials.new('Flyer %X' % idxMask)\n" - " mat.diffuse_color = (0.016, 0.8, 0.8, 1.0)\n" - " return mat\n" - "def make_swimmer_material(idxMask):\n" - " mat = bpy.data.materials.new('Swimmer %X' % idxMask)\n" - " mat.diffuse_color = (0.074, 0.293, 0.8, 1.0)\n" - " return mat\n" - "def select_material(meshIdxMask, meshTypeMask):\n" - " key = (meshIdxMask, meshTypeMask)\n" - " if key in material_index:\n" - " return material_index.index(key)\n" - " elif key in material_dict:\n" - " material_index.append(key)\n" - " return len(material_index)-1\n" - " else:\n" - " if meshTypeMask == 0x2:\n" - " mat = make_flyer_material(meshIdxMask)\n" - " elif meshTypeMask == 0x4:\n" - " mat = make_swimmer_material(meshIdxMask)\n" - " else:\n" - " mat = make_ground_material(meshIdxMask)\n" - " mat.retro_path_idx_mask = meshIdxMask\n" - " mat.retro_path_type_mask = meshTypeMask\n" - " material_dict[key] = mat\n" - " material_index.append(key)\n" - " return len(material_index)-1\n" - "\n"; + os << "import bpy\n" + "import bmesh\n" + "from mathutils import Vector, Matrix\n" + "\n" + "bpy.types.Material.retro_path_idx_mask = bpy.props.IntProperty(name='Retro: Path Index Mask')\n" + "bpy.types.Material.retro_path_type_mask = bpy.props.IntProperty(name='Retro: Path Type Mask')\n" + "\n" + "material_dict = {}\n" + "material_index = []\n" + "def make_ground_material(idxMask):\n" + " mat = bpy.data.materials.new('Ground %X' % idxMask)\n" + " mat.diffuse_color = (0.8, 0.460, 0.194, 1.0)\n" + " return mat\n" + "def make_flyer_material(idxMask):\n" + " mat = bpy.data.materials.new('Flyer %X' % idxMask)\n" + " mat.diffuse_color = (0.016, 0.8, 0.8, 1.0)\n" + " return mat\n" + "def make_swimmer_material(idxMask):\n" + " mat = bpy.data.materials.new('Swimmer %X' % idxMask)\n" + " mat.diffuse_color = (0.074, 0.293, 0.8, 1.0)\n" + " return mat\n" + "def select_material(meshIdxMask, meshTypeMask):\n" + " key = (meshIdxMask, meshTypeMask)\n" + " if key in material_index:\n" + " return material_index.index(key)\n" + " elif key in material_dict:\n" + " material_index.append(key)\n" + " return len(material_index)-1\n" + " else:\n" + " if meshTypeMask == 0x2:\n" + " mat = make_flyer_material(meshIdxMask)\n" + " elif meshTypeMask == 0x4:\n" + " mat = make_swimmer_material(meshIdxMask)\n" + " else:\n" + " mat = make_ground_material(meshIdxMask)\n" + " mat.retro_path_idx_mask = meshIdxMask\n" + " mat.retro_path_type_mask = meshTypeMask\n" + " material_dict[key] = mat\n" + " material_index.append(key)\n" + " return len(material_index)-1\n" + "\n"; os.format(fmt("bpy.context.scene.name = '{}'\n"), entryName); - os << - "# Clear Scene\n" - "if len(bpy.data.collections):\n" - " bpy.data.collections.remove(bpy.data.collections[0])\n" - "\n" - "bm = bmesh.new()\n" - "height_lay = bm.faces.layers.float.new('Height')\n"; + os << "# Clear Scene\n" + "if len(bpy.data.collections):\n" + " bpy.data.collections.remove(bpy.data.collections[0])\n" + "\n" + "bm = bmesh.new()\n" + "height_lay = bm.faces.layers.float.new('Height')\n"; for (const Node& n : nodes) { zeus::simd_floats f(n.position.simd); @@ -91,16 +90,15 @@ void PATH::sendToBlender(hecl::blender::Connection& conn, std::string_view entry for (atUint32 i = 0; i < r.nodeCount; ++i) os.format(fmt("tri_verts.append(bm.verts[{}])\n"), r.nodeStart + i); - os.format(fmt( - "face = bm.faces.get(tri_verts)\n" - "if face is None:\n" - " face = bm.faces.new(tri_verts)\n" - " face.normal_flip()\n" - "face.material_index = select_material(0x{:04X}, 0x{:04X})\n" - "face.smooth = False\n" - "face[height_lay] = {}\n" - "\n"), - r.meshIndexMask, r.meshTypeMask, r.height); + os.format(fmt("face = bm.faces.get(tri_verts)\n" + "if face is None:\n" + " face = bm.faces.new(tri_verts)\n" + " face.normal_flip()\n" + "face.material_index = select_material(0x{:04X}, 0x{:04X})\n" + "face.smooth = False\n" + "face[height_lay] = {}\n" + "\n"), + r.meshIndexMask, r.meshTypeMask, r.height); #if 0 const zeus::CVector3f center = xf->multiplyOneOverW(r.centroid); @@ -152,15 +150,14 @@ void PATH::sendToBlender(hecl::blender::Connection& conn, std::string_view entry zeus::simd_floats xfMtxF[4]; for (int i = 0; i < 4; ++i) w.m[i].mSimd.copy_to(xfMtxF[i]); - os.format(fmt( - "mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n" - "mtxd = mtx.decompose()\n" - "path_mesh_obj.rotation_mode = 'QUATERNION'\n" - "path_mesh_obj.location = mtxd[0]\n" - "path_mesh_obj.rotation_quaternion = mtxd[1]\n" - "path_mesh_obj.scale = mtxd[2]\n"), - xfMtxF[0][0], xfMtxF[1][0], xfMtxF[2][0], xfMtxF[3][0], xfMtxF[0][1], xfMtxF[1][1], xfMtxF[2][1], xfMtxF[3][1], - xfMtxF[0][2], xfMtxF[1][2], xfMtxF[2][2], xfMtxF[3][2]); + os.format(fmt("mtx = Matrix((({},{},{},{}),({},{},{},{}),({},{},{},{}),(0.0,0.0,0.0,1.0)))\n" + "mtxd = mtx.decompose()\n" + "path_mesh_obj.rotation_mode = 'QUATERNION'\n" + "path_mesh_obj.location = mtxd[0]\n" + "path_mesh_obj.rotation_quaternion = mtxd[1]\n" + "path_mesh_obj.scale = mtxd[2]\n"), + xfMtxF[0][0], xfMtxF[1][0], xfMtxF[2][0], xfMtxF[3][0], xfMtxF[0][1], xfMtxF[1][1], xfMtxF[2][1], + xfMtxF[3][1], xfMtxF[0][2], xfMtxF[1][2], xfMtxF[2][2], xfMtxF[3][2]); } #if DUMP_OCTREE @@ -179,9 +176,11 @@ void PATH::sendToBlender(hecl::blender::Connection& conn, std::string_view entry os.close(); } -bool PATH::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) { +template +bool PATH::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) { PATH path; path.read(rs); hecl::blender::Connection& conn = btok.getBlenderConnection(); @@ -201,8 +200,9 @@ bool PATH::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl: return conn.saveBlend(); } -bool PATH::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, - const PathMesh& mesh, hecl::blender::Token& btok) { +template +bool PATH::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const PathMesh& mesh, + hecl::blender::Token& btok) { athena::io::MemoryReader r(mesh.data.data(), mesh.data.size()); PATH path; path.read(r); @@ -241,4 +241,8 @@ bool PATH::Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPat return true; } -} // namespace DataSpec::DNAMP1 \ No newline at end of file +template struct PATH; +template struct PATH; +template struct PATH; + +} // namespace DataSpec::DNAPATH \ No newline at end of file diff --git a/DataSpec/DNACommon/PATH.hpp b/DataSpec/DNACommon/PATH.hpp new file mode 100644 index 000000000..2a3f8d793 --- /dev/null +++ b/DataSpec/DNACommon/PATH.hpp @@ -0,0 +1,112 @@ +#pragma once + +#include "DataSpec/DNACommon/DNACommon.hpp" +#include "DataSpec/DNACommon/PAK.hpp" +#include "DataSpec/DNAMP1/DNAMP1.hpp" +#include "DataSpec/DNAMP2/DNAMP2.hpp" +#include "DataSpec/DNAMP3/DNAMP3.hpp" + +namespace DataSpec::DNAPATH { +template +struct RegionPointers {}; +template <> +struct RegionPointers : BigDNA { + AT_DECL_DNA + Value regionIdxPtr; +}; +template <> +struct RegionPointers : BigDNA { + AT_DECL_DNA + Value unk0; + Value unk1; + Value unk2; + Value regionIdxPtr; +}; +template <> +struct RegionPointers : BigDNA { + AT_DECL_DNA + Value unk0; + Value unk1; + Value unk2; + Value regionIdxPtr; +}; + +template +struct AT_SPECIALIZE_PARMS(DataSpec::DNAMP1::PAKBridge, DataSpec::DNAMP2::PAKBridge, DataSpec::DNAMP3::PAKBridge) PATH +: BigDNA { + using PathMesh = hecl::blender::PathMesh; + + AT_DECL_DNA + Value version; + + struct Node : BigDNA { + AT_DECL_DNA + Value position; + Value normal; + }; + Value nodeCount; + Vector nodes; + + struct Link : BigDNA { + AT_DECL_DNA + Value nodeIdx; + Value regionIdx; + Value width2d; + Value oneOverWidth2d; + }; + Value linkCount; + Vector links; + + struct Region : BigDNA { + AT_DECL_DNA + Value nodeCount; + Value nodeStart; + Value linkCount; + Value linkStart; + Value meshIndexMask; + Value meshTypeMask; + Value height; + Value normal; + Value regionIdx; + Value centroid; + Value aabb[2]; + Value> pointers; + }; + Value regionCount; + Vector regions; + + Vector bitmap1; + Vector bitmap2; + + /* Unused in all games, removed in MP3 */ + Vector + ? 0 + : (((((regionCount * regionCount) + 31) / 32) - bitmap1.size()) * 2))> + bitmap3; + + Value octreeRegionLookupCount; + Vector octreeRegionLookup; + + struct OctreeNode : BigDNA { + AT_DECL_DNA + Value isLeaf; + Value aabb[2]; + Value centroid; + Value children[8]; + Value regionCount; + Value regionStart; + }; + Value octreeNodeCount; + Vector octree; + + void sendToBlender(hecl::blender::Connection& conn, std::string_view entryName, const zeus::CMatrix4f* xf, + const std::string& areaPath); + + static bool 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); + + static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, const PathMesh& mesh, + hecl::blender::Token& btok); +}; +} // namespace DataSpec::DNAPATH 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/DNAMP1/CMDLMaterials.cpp b/DataSpec/DNAMP1/CMDLMaterials.cpp index 1d7543c3f..3e51255b6 100644 --- a/DataSpec/DNAMP1/CMDLMaterials.cpp +++ b/DataSpec/DNAMP1/CMDLMaterials.cpp @@ -34,12 +34,11 @@ void Material::AddTexture(Stream& out, GX::TexGenSrc type, int mtxIdx, uint32_t else texLabel = "Texture"; - out.format(fmt( - "# Texture\n" - "tex_node = new_nodetree.nodes.new('ShaderNodeTexImage')\n" - "tex_node.label = '{} {}'\n" - "texture_nodes.append(tex_node)\n"), - texLabel, texIdx); + out.format(fmt("# Texture\n" + "tex_node = new_nodetree.nodes.new('ShaderNodeTexImage')\n" + "tex_node.label = '{} {}'\n" + "texture_nodes.append(tex_node)\n"), + texLabel, texIdx); if (texIdx != 0xff) out.format(fmt("tex_node.image = tex_maps[{}]\n"), texIdx); @@ -52,11 +51,10 @@ void Material::AddTexture(Stream& out, GX::TexGenSrc type, int mtxIdx, uint32_t "tex_links.append(new_nodetree.links.new(tex_uv_node.outputs['Normal'], tex_node.inputs['Vector']))\n"; else if (type >= GX::TG_TEX0 && type <= GX::TG_TEX7) { uint8_t texIdx = type - GX::TG_TEX0; - 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"), - texIdx); + 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"), + texIdx); } out.format(fmt("tex_uv_node.label = '{}'\n"), mtxLabel); @@ -72,171 +70,162 @@ void Material::AddTexture(Stream& out, GX::TexGenSrc type, int mtxIdx, uint32_t void Material::AddTextureAnim(Stream& out, UVAnimation::Mode type, unsigned idx, const float* vals) { switch (type) { case UVAnimation::Mode::MvInvNoTranslation: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode0NodeN']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode0NodeN']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx); break; case UVAnimation::Mode::MvInv: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode1NodeN']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode1NodeN']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx); break; case UVAnimation::Mode::Scroll: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode2Node']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " node.inputs[1].default_value = ({},{},0)\n" - " node.inputs[2].default_value = ({},{},0)\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx, vals[0], vals[1], vals[2], vals[3]); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode2Node']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " node.inputs[1].default_value = ({},{},0)\n" + " node.inputs[2].default_value = ({},{},0)\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx, vals[0], vals[1], vals[2], vals[3]); break; case UVAnimation::Mode::Rotation: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode3Node']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " node.inputs[1].default_value = {}\n" - " node.inputs[2].default_value = {}\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx, vals[0], vals[1]); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode3Node']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " node.inputs[1].default_value = {}\n" + " node.inputs[2].default_value = {}\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx, vals[0], vals[1]); break; case UVAnimation::Mode::HStrip: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode4Node']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " node.inputs[1].default_value = {}\n" - " node.inputs[2].default_value = {}\n" - " node.inputs[3].default_value = {}\n" - " node.inputs[4].default_value = {}\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx, vals[0], vals[1], vals[2], vals[3]); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode4Node']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " node.inputs[1].default_value = {}\n" + " node.inputs[2].default_value = {}\n" + " node.inputs[3].default_value = {}\n" + " node.inputs[4].default_value = {}\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx, vals[0], vals[1], vals[2], vals[3]); break; case UVAnimation::Mode::VStrip: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode5Node']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " node.inputs[1].default_value = {}\n" - " node.inputs[2].default_value = {}\n" - " node.inputs[3].default_value = {}\n" - " node.inputs[4].default_value = {}\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx, vals[0], vals[1], vals[2], vals[3]); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode5Node']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " node.inputs[1].default_value = {}\n" + " node.inputs[2].default_value = {}\n" + " node.inputs[3].default_value = {}\n" + " node.inputs[4].default_value = {}\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx, vals[0], vals[1], vals[2], vals[3]); break; case UVAnimation::Mode::Model: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode6NodeN']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode6NodeN']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx); break; case UVAnimation::Mode::CylinderEnvironment: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode7NodeN']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " node.inputs[1].default_value = {}\n" - " node.inputs[2].default_value = {}\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx, vals[0], vals[1]); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode7NodeN']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " node.inputs[1].default_value = {}\n" + " node.inputs[2].default_value = {}\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx, vals[0], vals[1]); break; case UVAnimation::Mode::Eight: - out.format(fmt( - "for link in list(tex_links):\n" - " if link.from_node.label == 'MTX_{}':\n" - " tex_links.remove(link)\n" - " soc_from = link.from_socket\n" - " soc_to = link.to_socket\n" - " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" - " node.node_tree = bpy.data.node_groups['RetroUVMode8Node']\n" - " node.location[0] = link.from_node.location[0] + 50\n" - " node.location[1] = link.from_node.location[1] - 50\n" - " node.inputs[1].default_value = {}\n" - " node.inputs[2].default_value = {}\n" - " node.inputs[3].default_value = {}\n" - " node.inputs[4].default_value = {}\n" - " node.inputs[5].default_value = {}\n" - " node.inputs[6].default_value = {}\n" - " node.inputs[7].default_value = {}\n" - " node.inputs[8].default_value = {}\n" - " node.inputs[9].default_value = {}\n" - " new_nodetree.links.remove(link)\n" - " new_nodetree.links.new(soc_from, node.inputs[0])\n" - " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), - idx, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7], vals[8]); + out.format(fmt("for link in list(tex_links):\n" + " if link.from_node.label == 'MTX_{}':\n" + " tex_links.remove(link)\n" + " soc_from = link.from_socket\n" + " soc_to = link.to_socket\n" + " node = new_nodetree.nodes.new('ShaderNodeGroup')\n" + " node.node_tree = bpy.data.node_groups['RetroUVMode8Node']\n" + " node.location[0] = link.from_node.location[0] + 50\n" + " node.location[1] = link.from_node.location[1] - 50\n" + " node.inputs[1].default_value = {}\n" + " node.inputs[2].default_value = {}\n" + " node.inputs[3].default_value = {}\n" + " node.inputs[4].default_value = {}\n" + " node.inputs[5].default_value = {}\n" + " node.inputs[6].default_value = {}\n" + " node.inputs[7].default_value = {}\n" + " node.inputs[8].default_value = {}\n" + " node.inputs[9].default_value = {}\n" + " new_nodetree.links.remove(link)\n" + " new_nodetree.links.new(soc_from, node.inputs[0])\n" + " new_nodetree.links.new(node.outputs[0], soc_to)\n\n"), + idx, vals[0], vals[1], vals[2], vals[3], vals[4], vals[5], vals[6], vals[7], vals[8]); break; default: break; @@ -244,12 +233,12 @@ void Material::AddTextureAnim(Stream& out, UVAnimation::Mode type, unsigned idx, } void Material::AddKcolor(Stream& out, const GX::Color& col, unsigned idx) { - out.format(fmt( - "kcolors[{}] = ({}, {}, {}, {})\n" - "kalphas[{}] = {}\n" - "\n"), - idx, (float)col.color[0] / (float)0xff, (float)col.color[1] / (float)0xff, (float)col.color[2] / (float)0xff, - (float)col.color[3] / (float)0xff, idx, (float)col.color[3] / (float)0xff); + out.format(fmt("kcolors[{}] = ({}, {}, {}, {})\n" + "kalphas[{}] = {}\n" + "\n"), + idx, (float)col.color[0] / (float)0xff, (float)col.color[1] / (float)0xff, + (float)col.color[2] / (float)0xff, (float)col.color[3] / (float)0xff, idx, + (float)col.color[3] / (float)0xff); } template @@ -354,11 +343,10 @@ template static void _DescribeTEV(const MAT& mat) { for (uint32_t i = 0; i < mat.tevStageCount; ++i) { const auto& stage = mat.tevStages[i]; - fmt::print(stderr, fmt("A:{} B:{} C:{} D:{} -> {} | A:{} B:{} C:{} D:{} -> {}\n"), - ToString(stage.colorInA()), ToString(stage.colorInB()), - ToString(stage.colorInC()), ToString(stage.colorInD()), ToString(stage.colorOpOutReg()), - ToString(stage.alphaInA()), ToString(stage.alphaInB()), - ToString(stage.alphaInC()), ToString(stage.alphaInD()), ToString(stage.alphaOpOutReg())); + fmt::print(stderr, fmt("A:{} B:{} C:{} D:{} -> {} | A:{} B:{} C:{} D:{} -> {}\n"), ToString(stage.colorInA()), + ToString(stage.colorInB()), ToString(stage.colorInC()), ToString(stage.colorInD()), + ToString(stage.colorOpOutReg()), ToString(stage.alphaInA()), ToString(stage.alphaInB()), + ToString(stage.alphaInC()), ToString(stage.alphaInD()), ToString(stage.alphaOpOutReg())); } bool hasInd = mat.flags.samusReflectionIndirectTexture(); bool hasLm = mat.flags.lightmap(); @@ -388,12 +376,10 @@ struct KColLink { struct WhiteColorLink { const char* shaderInput; - explicit WhiteColorLink(const char* shaderInput) - : shaderInput(shaderInput) {} + explicit WhiteColorLink(const char* shaderInput) : shaderInput(shaderInput) {} }; -static void _GenerateRootShader(Stream& out, int) { - /* End of shader links */ +static void _GenerateRootShader(Stream& out, int) { /* End of shader links */ } template @@ -401,8 +387,8 @@ static void _GenerateRootShader(Stream& out, int tidx, TexLink tex, Targs... arg int texIdx = tex.texidx == -1 ? tidx : tex.texidx; out << "texture_nodes[" << texIdx << "].name = '" << tex.shaderInput << "'\n"; out << "texture_nodes[" << texIdx << "].label = '" << tex.shaderInput << "'\n"; - out << "new_nodetree.links.new(texture_nodes[" << texIdx << "].outputs['" << - (tex.alpha ? "Alpha" : "Color") << "'], node.inputs['" << tex.shaderInput << "'])\n"; + out << "new_nodetree.links.new(texture_nodes[" << texIdx << "].outputs['" << (tex.alpha ? "Alpha" : "Color") + << "'], node.inputs['" << tex.shaderInput << "'])\n"; if (tex.texidx == -1) ++tidx; _GenerateRootShader(out, tidx, args...); @@ -422,8 +408,8 @@ static void _GenerateRootShader(Stream& out, int tidx, ExtendedSpecularLink tex, template static void _GenerateRootShader(Stream& out, int tidx, KColLink kcol, Targs... args) { - out << "node.inputs['" << kcol.shaderInput << "'].default_value = " << - (kcol.alpha ? "kalphas[" : "kcolors[") << kcol.kcidx << "]\n"; + out << "node.inputs['" << kcol.shaderInput << "'].default_value = " << (kcol.alpha ? "kalphas[" : "kcolors[") + << kcol.kcidx << "]\n"; _GenerateRootShader(out, tidx, args...); } @@ -437,16 +423,18 @@ template static void _GenerateRootShader(Stream& out, const char* type, Targs... args) { out << "node = new_nodetree.nodes.new('ShaderNodeGroup')\n" "node.name = 'Output'\n" - "node.node_tree = bpy.data.node_groups['" << type << "']\n" + "node.node_tree = bpy.data.node_groups['" + << type + << "']\n" "gridder.place_node(node, 1)\n" "new_nodetree.links.new(node.outputs['Surface'], blend_node.inputs['Surface'])\n"; _GenerateRootShader(out, 0, args...); } -static TexLink operator "" _tex(const char* str, size_t) { return TexLink(str); } -static TexLink operator "" _texa(const char* str, size_t) { return TexLink(str, -1, true); } -static KColLink operator "" _kcol(const char* str, size_t) { return KColLink(str); } -static KColLink operator "" _kcola(const char* str, size_t) { return KColLink(str, 0, true); } +static TexLink operator"" _tex(const char* str, size_t) { return TexLink(str); } +static TexLink operator"" _texa(const char* str, size_t) { return TexLink(str, -1, true); } +static KColLink operator"" _kcol(const char* str, size_t) { return KColLink(str); } +static KColLink operator"" _kcola(const char* str, size_t) { return KColLink(str, 0, true); } template static void _ConstructMaterial(Stream& out, const MAT& material, unsigned groupIdx, unsigned matIdx) { @@ -470,22 +458,21 @@ static void _ConstructMaterial(Stream& out, const MAT& material, unsigned groupI "\n"; /* Material Flags */ - out.format(fmt( - "new_material.retro_depth_sort = {}\n" - "new_material.retro_alpha_test = {}\n" - "new_material.retro_samus_reflection = {}\n" - "new_material.retro_depth_write = {}\n" - "new_material.retro_samus_reflection_persp = {}\n" - "new_material.retro_shadow_occluder = {}\n" - "new_material.retro_samus_reflection_indirect = {}\n" - "new_material.retro_lightmapped = {}\n" - "new_material.diffuse_color = (1, 1, 1, {})\n"), - material.flags.depthSorting() ? "True" : "False", material.flags.alphaTest() ? "True" : "False", - material.flags.samusReflection() ? "True" : "False", material.flags.depthWrite() ? "True" : "False", - material.flags.samusReflectionSurfaceEye() ? "True" : "False", - material.flags.shadowOccluderMesh() ? "True" : "False", - material.flags.samusReflectionIndirectTexture() ? "True" : "False", material.flags.lightmap() ? "True" : "False", - material.flags.shadowOccluderMesh() ? "0" : "1"); + out.format(fmt("new_material.retro_depth_sort = {}\n" + "new_material.retro_alpha_test = {}\n" + "new_material.retro_samus_reflection = {}\n" + "new_material.retro_depth_write = {}\n" + "new_material.retro_samus_reflection_persp = {}\n" + "new_material.retro_shadow_occluder = {}\n" + "new_material.retro_samus_reflection_indirect = {}\n" + "new_material.retro_lightmapped = {}\n" + "new_material.diffuse_color = (1, 1, 1, {})\n"), + material.flags.depthSorting() ? "True" : "False", material.flags.alphaTest() ? "True" : "False", + material.flags.samusReflection() ? "True" : "False", material.flags.depthWrite() ? "True" : "False", + material.flags.samusReflectionSurfaceEye() ? "True" : "False", + material.flags.shadowOccluderMesh() ? "True" : "False", + material.flags.samusReflectionIndirectTexture() ? "True" : "False", + material.flags.lightmap() ? "True" : "False", material.flags.shadowOccluderMesh() ? "0" : "1"); /* Texture Indices */ out << "tex_maps = []\n"; @@ -537,131 +524,268 @@ static void _ConstructMaterial(Stream& out, const MAT& material, unsigned groupI /* Select appropriate root shader and link textures */ uint32_t hash = _HashTextureConfig(material); switch (hash) { + case 0x03FEE002: /* RetroShader: Diffuse, Emissive, Reflection, Alpha=1.0 */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, "Reflection"_tex); + break; case 0x0473AE40: /* RetroShader: Lightmap, Diffuse, Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex); + break; case 0x072D2CB3: /* RetroShader: Diffuse, Emissive, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, WhiteColorLink("Specular"), "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, WhiteColorLink("Specular"), + "Reflection"_tex); + break; + case 0x07AA75D7: /* RetroShader: Diffuse, Emissive, Alpha=DiffuseAlpha */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, TexLink("Alpha", 0, true)); + break; case 0x0879D346: /* RetroShader: KColorDiffuse, Alpha=Texture */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Alpha"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Alpha"_tex); + break; case 0x0DA256BB: /* Lightmap, Diffuse, Specular, Reflection, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, + "Alpha"_kcola); + break; case 0x11C41DA4: /* RetroDynamicCharacterShader: Diffuse, DynamicMaskTex, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroDynamicCharacterShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroDynamicCharacterShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, + "Reflection"_tex); + break; case 0x1218F83E: /* RetroShader: ObjLightmap, Diffuse, ExtendedSpecular, Reflection, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, ExtendedSpecularLink(), "Reflection"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, ExtendedSpecularLink(), "Reflection"_tex, + TexLink("Alpha", 1, true)); + break; case 0x129B8578: /* RetroShader: KColorDiffuse, Emissive, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Emissive"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Emissive"_tex, "Alpha"_kcola); + break; + case 0x15A00948: /* RetroShader: Diffuse, Emissive, Specular, ExtendedSpecular, Reflection, Alpha=1.0 */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "ExtendedSpecular"_tex, + "Reflection"_tex); + break; case 0x15A3E6E5: /* RetroShader: Diffuse, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Alpha"_kcola); + break; case 0x1BEB3E15: /* RetroShader: Diffuse, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); + break; case 0x2261E0EB: /* RetroShader: Diffuse, Emissive, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); + break; case 0x239C7724: /* RetroDynamicShader: Diffuse*Dynamic, Emissive*Dynamic, Alpha=1.0 */ - _GenerateRootShader(out, "RetroDynamicShader", "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroDynamicShader", "Diffuse"_tex, "Emissive"_tex); + break; case 0x240C4C84: /* RetroShader: Lightmap, KColorDiffuse, Specular, Reflection, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_kcol, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_kcol, "Specular"_tex, "Reflection"_tex, + "Alpha"_kcola); + break; case 0x2523A379: /* RetroDynamicShader: Emissive*Dynamic, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroDynamicShader", "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroDynamicShader", "Emissive"_tex, "Specular"_tex, "Reflection"_tex); + break; case 0x25E85017: /* RetroShader: Lightmap, KColorDiffuse, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_kcol, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_kcol, "Alpha"_kcola); + break; case 0x27FD5C6C: /* RetroShader: ObjLightmap, Diffuse, Specular, Reflection, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, + TexLink("Alpha", 1, true)); + break; case 0x2AD9F535: /* RetroShader: Emissive, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Emissive"_tex, WhiteColorLink("Specular"), "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Emissive"_tex, WhiteColorLink("Specular"), "Reflection"_tex); + break; case 0x2C9F5104: /* RetroShader: Diffuse, Specular, Reflection, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); + break; case 0x2D059429: /* RetroShader: Diffuse, Emissive, ExtendedSpecular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, ExtendedSpecularLink(), "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, ExtendedSpecularLink(), "Reflection"_tex); + break; case 0x30AC64BB: /* RetroShader: Diffuse, Specular, Reflection, Alpha=KAlpha, IndirectTex */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex, "Alpha"_kcola); break; - case 0x39BC4809: /* RetroDynamicShader: ObjLightmap*Dynamic, Diffuse*Dynamic, Emissive*Dynamic, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroDynamicShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex, + "Alpha"_kcola); + break; + case 0x39BC4809: /* RetroDynamicShader: ObjLightmap*Dynamic, Diffuse*Dynamic, Emissive*Dynamic, Specular, Reflection, + Alpha=1.0 */ + _GenerateRootShader(out, "RetroDynamicShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, + "Reflection"_tex); + break; case 0x3BF97299: /* RetroShader: Lightmap, Diffuse, Specular, Reflection, Alpha=KAlpha, IndirectTex */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, + "IndirectTex"_tex, "Alpha"_kcola); + break; + case 0x4184FBCA: /* RetroShader: Lightmap, Diffuse, Emissive, DiffuseAlpha */ + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, TexLink("Alpha", 1, true)); + break; case 0x47ECF3ED: /* RetroShader: Diffuse, Specular, Reflection, Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Emissive"_tex); + break; case 0x4BBDFFA6: /* RetroShader: Diffuse, Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); + break; case 0x4D4127A3: /* RetroShader: Lightmap, Diffuse, Specular, Reflection, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, + TexLink("Alpha", 1, true)); + break; case 0x54A92F25: /* RetroShader: ObjLightmap, KColorDiffuse, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_kcol, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_kcol, "Alpha"_kcola); + break; + case 0x58BAA415: /* RetroShader: Lightmap, Diffuse, Emissive, Alpha=1.0 */ + // TODO: Last stage assigns into unused reg2, perhaps for runtime material mod? + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex); + break; case 0x54C6204C: - _GenerateRootShader(out, "RetroShader"); break; + _GenerateRootShader(out, "RetroShader"); + break; case 0x5A62D5F0: /* RetroShader: Lightmap, Diffuse, UnusedExtendedSpecular?, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); + break; case 0x5CB59821: /* RetroShader: Diffuse, UnusedSpecular?, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Alpha"_kcola); + break; case 0x5D0F0069: /* RetroShader: Diffuse, Emissive, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, TexLink("Alpha", 0, true)); + break; case 0x5D80E53C: /* RetroShader: Emissive, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Emissive"_tex, "Specular"_tex, "Reflection"_tex); + break; case 0x5F0AB0E9: /* RetroShader: Lightmap, Diffuse, UnusedSpecular?, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); + break; case 0x5F189425: /* RetroShader: Lightmap, Diffuse, UnusedSpecular?, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Alpha"_kcola); + break; case 0x6601D113: /* RetroShader: Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Emissive"_tex); + break; case 0x694287FA: /* RetroShader: Diffuse, Emissive, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, WhiteColorLink("Specular"), "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, WhiteColorLink("Specular"), + "Reflection"_tex); + break; case 0x6D98D689: /* RetroDynamicAlphaShader: Diffuse*Dynamic, Specular, Reflection, Alpha=KAlpha*Dynamic */ - _GenerateRootShader(out, "RetroDynamicAlphaShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroDynamicAlphaShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); + break; case 0x7252CB90: /* RetroShader: Lightmap, Diffuse, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Alpha"_kcola); + break; + case 0x72BEDDAC: /* RetroShader: DiffuseMod, Diffuse, Emissive, Specular, Reflection Alpha=1.0 */ + _GenerateRootShader(out, "RetroShader", "DiffuseMod"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, + "Reflection"_tex); + break; case 0x76BEA57E: /* RetroShader: Lightmap, Diffuse, Emissive, Specular, Reflection, Alpha=1.0, IndirectTex */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, + "Reflection"_tex, "IndirectTex"_tex); + break; case 0x7D6A4487: /* RetroShader: Diffuse, Specular, Reflection, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, TexLink("Alpha", 0, true)); + break; + case 0x81106196: /* RetroDynamicShader: Emissive, Alpha=1.0 */ + _GenerateRootShader(out, "RetroDynamicShader", "Emissive"_tex); + break; case 0x84319328: /* RetroShader: Reflection, UnusedSpecular?, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", WhiteColorLink("Specular"), "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", WhiteColorLink("Specular"), "Reflection"_tex); + break; case 0x846215DA: /* RetroShader: Diffuse, Specular, Reflection, Alpha=DiffuseAlpha, IndirectTex */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex, + TexLink("Alpha", 0, true)); + break; + case 0x8C562AB1: /* RetroShader: Diffuse, Emissive, Alpha=1.0 */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); + break; case 0x8E916C01: /* RetroShader: NULL, all inputs 0 */ - _GenerateRootShader(out, "RetroShader"); break; + _GenerateRootShader(out, "RetroShader"); + break; case 0x957709F8: /* RetroShader: Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Emissive"_tex); + break; case 0x96ABB2D3: /* RetroShader: Lightmap, Diffuse, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); + break; case 0x985A0B67: /* RetroShader: Diffuse, UnusedSpecular?, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); + break; case 0x9B4453A2: /* RetroShader: Diffuse, Emissive, ExtendedSpecular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, ExtendedSpecularLink(), "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, ExtendedSpecularLink(), "Reflection"_tex); + break; case 0xA187C630: /* RetroShader: Diffuse, Emissive, UnusedReflection?, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); + break; + case 0xB26E9E2E: /* RetroShader: Diffuse, Emissive, Alpha=1.0 */ + // TODO: Last two stages assign into unused reg2, perhaps for runtime material mod? + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); + break; + case 0xC0E3FF1F: /* RetroShader: KColorDiffuse, Specular, Reflection, Alpha=KAlpha */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Specular"_tex, "Reflection"_tex, "Alpha"_kcola); + break; case 0xC138DCFA: /* RetroShader: Diffuse, Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex); + break; case 0xC3C8B1C8: /* RetroShader: KColorDiffuse, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Alpha"_kcola); + break; case 0xC689C8C6: /* RetroShader: Diffuse, ExtendedSpecular, Reflection, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, ExtendedSpecularLink(), "Reflection"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, ExtendedSpecularLink(), "Reflection"_tex, + TexLink("Alpha", 0, true)); + break; case 0xC6B18B28: /* RetroShader: Diffuse, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); + break; case 0xCD92D4C5: /* RetroShader: Diffuse, Reflection, Alpha=KAlpha */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, WhiteColorLink("Specular"), "Reflection"_tex, "Alpha"_kcola); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, WhiteColorLink("Specular"), "Reflection"_tex, "Alpha"_kcola); + break; + case 0xCE06F3F2: /* RetroShader: Diffuse, Alpha */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 1, true)); + break; case 0xD73E7728: /* RetroShader: ObjLightmap, Diffuse, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); + break; case 0xDB8F01AD: /* RetroDynamicShader: Diffuse*Dynamic, Emissive*Dynamic, UnusedSpecular?, Alpha=1.0 */ - _GenerateRootShader(out, "RetroDynamicShader", "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroDynamicShader", "Diffuse"_tex, "Emissive"_tex); + break; + case 0xE64D1085: /* RetroShader: Lightmap, Diffuse, Emissive, Reflection, Alpha=DiffuseAlpha */ + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Reflection"_tex, + TexLink("Alpha", 1, true)); + break; case 0xE6784B10: /* RetroShader: Lightmap, Diffuse, Specular, Reflection, Alpha=DiffuseAlpha, IndirectTex */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, "IndirectTex"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "Reflection"_tex, + "IndirectTex"_tex, TexLink("Alpha", 1, true)); + break; case 0xE68FF182: /* RetroShader: Diffuse, Emissive, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); + break; + case 0xE92F1340: /* RetroShader: Diffuse, Alpha=DiffuseAlpha*AlphaMod */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_tex, TexLink("Alpha", 0, true), TexLink("AlphaMod", 1, true)); + break; case 0xEB4645CF: /* RetroDynamicAlphaShader: Diffuse*Dynamic, Alpha=DiffuseAlpha*Dynamic */ - _GenerateRootShader(out, "RetroDynamicAlphaShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); break; + _GenerateRootShader(out, "RetroDynamicAlphaShader", "Diffuse"_tex, TexLink("Alpha", 0, true)); + break; case 0xECEF8D1F: /* RetroDynamicShader: Diffuse*Dynamic, Emissive*Dynamic, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroDynamicShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroDynamicShader", "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); + break; case 0xF1C26570: /* RetroShader: Lightmap, Diffuse, Specular, ExtendedSpecular, Reflection, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "ExtendedSpecular"_tex, "Reflection"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Specular"_tex, "ExtendedSpecular"_tex, + "Reflection"_tex, TexLink("Alpha", 1, true)); + break; + case 0xF345C16E: /* RetroShader: Emissive, Reflection, Alpha=1.0 */ + _GenerateRootShader(out, "RetroShader", "Emissive"_tex, "Reflection"_tex); + break; + case 0xF4DA0A86: /* RetroShader: KColorDiffuse, Emissive, Alpha=KAlpha */ + _GenerateRootShader(out, "RetroShader", "Diffuse"_kcol, "Emissive"_tex, "Alpha"_kcola); break; + break; case 0xF559DB08: /* RetroShader: Lightmap, Diffuse, Emissive, Specular, Reflection, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, "Reflection"_tex); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, "Specular"_tex, + "Reflection"_tex); + break; case 0xF9324367: /* RetroShader: Lightmap, Diffuse, Emissive, Alpha=1.0 */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex); + break; + case 0xFC2761B8: /* RetroShader: Lightmap, Diffuse, Alpha=DiffuseAlpha*AlphaMod */ + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true), + TexLink("AlphaMod", 2, true)); + break; case 0xFD95D7FD: /* RetroShader: ObjLightmap, Diffuse, Alpha=DiffuseAlpha */ - _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); break; + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, TexLink("Alpha", 1, true)); + break; + case 0xFFF3CEBB: /* RetroShader: Lightmap, Diffuse, Emissive, Alpha */ + _GenerateRootShader(out, "RetroShader", "Lightmap"_tex, "Diffuse"_tex, "Emissive"_tex, TexLink("Alpha", 3, true)); + break; default: _DescribeTEV(material); - Log.report(logvisor::Fatal, fmt("Unable to resolve shader hash {:08X}\n"), hash); break; + Log.report(logvisor::Fatal, fmt("Unable to resolve shader hash {:08X}\n"), hash); + break; } /* Has Lightmap? */ @@ -682,8 +806,7 @@ void MaterialSet::ConstructMaterial(Stream& out, const MaterialSet::Material& ma _ConstructMaterial(out, material, groupIdx, matIdx); } -MaterialSet::Material::Material(const hecl::blender::Material& mat, - std::vector& texPathsOut, +MaterialSet::Material::Material(const hecl::blender::Material& mat, std::vector& texPathsOut, int colorCount, bool lightmapUVs, bool matrixSkinning) { /* TODO: Rewrite for new shader rep */ XXH32_state_t xxHash; @@ -1090,7 +1213,6 @@ void HMDLMaterialSet::Material::PASS::Enumerate(typename Op::StreamT& s) { AT_SPECIALIZE_DNA(HMDLMaterialSet::Material::PASS) - std::string_view HMDLMaterialSet::Material::PASS::DNAType() { return "DataSpec::DNAMP1::HMDLMaterialSet::Material::PASS"sv; } diff --git a/DataSpec/DNAMP1/CMakeLists.txt b/DataSpec/DNAMP1/CMakeLists.txt index 3520e76c4..51ebe4bfe 100644 --- a/DataSpec/DNAMP1/CMakeLists.txt +++ b/DataSpec/DNAMP1/CMakeLists.txt @@ -11,7 +11,6 @@ make_dnalist(PAK CINF CSKR EVNT - PATH CMDLMaterials MREA DeafBabe @@ -50,7 +49,7 @@ set(DNAMP1_SOURCES ANIM.cpp CINF.cpp EVNT.cpp - PATH.cpp + PATH.hpp CMDL.hpp CMDL.cpp CMDLMaterials.cpp DCLN.cpp diff --git a/DataSpec/DNAMP1/PATH.hpp b/DataSpec/DNAMP1/PATH.hpp index 284a27fa0..07f0179f8 100644 --- a/DataSpec/DNAMP1/PATH.hpp +++ b/DataSpec/DNAMP1/PATH.hpp @@ -1,79 +1,6 @@ #pragma once - -#include "DataSpec/DNACommon/DNACommon.hpp" -#include "DataSpec/DNACommon/PAK.hpp" -#include "DNAMP1.hpp" +#include "DataSpec/DNACommon/PATH.hpp" namespace DataSpec::DNAMP1 { -struct PATH : BigDNA { - using PathMesh = hecl::blender::PathMesh; - - AT_DECL_DNA - Value version; - - struct Node : BigDNA { - AT_DECL_DNA - Value position; - Value normal; - }; - Value nodeCount; - Vector nodes; - - struct Link : BigDNA { - AT_DECL_DNA - Value nodeIdx; - Value regionIdx; - Value width2d; - Value oneOverWidth2d; - }; - Value linkCount; - Vector links; - - struct Region : BigDNA { - AT_DECL_DNA - Value nodeCount; - Value nodeStart; - Value linkCount; - Value linkStart; - Value meshIndexMask; - Value meshTypeMask; - Value height; - Value normal; - Value regionIdx; - Value centroid; - Value aabb[2]; - Value regionIdxPtr; - }; - Value regionCount; - Vector regions; - - Vector bitmap1; - Vector bitmap2; - Vector bitmap3; - - Value octreeRegionLookupCount; - Vector octreeRegionLookup; - - struct OctreeNode : BigDNA { - AT_DECL_DNA - Value isLeaf; - Value aabb[2]; - Value centroid; - Value children[8]; - Value regionCount; - Value regionStart; - }; - Value octreeNodeCount; - Vector octree; - - void sendToBlender(hecl::blender::Connection& conn, std::string_view entryName, const zeus::CMatrix4f* xf, - const std::string& areaPath); - - 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); - - static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, - const PathMesh& mesh, hecl::blender::Token& btok); -}; +using PATH = DNAPATH::PATH; } // namespace DataSpec::DNAMP1 diff --git a/DataSpec/DNAMP2/CINF.cpp b/DataSpec/DNAMP2/CINF.cpp index ab7cb48ab..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,7 +87,140 @@ 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, + std::map& nameMap) { + int selId; + auto search = idMap.find(bone->name); + if (search == idMap.end()) { + selId = curId++; + idMap.emplace(std::make_pair(bone->name, selId)); + } else + selId = search->second; + + bones.emplace_back(); + Bone& boneOut = bones.back(); + nameMap[bone->name] = selId; + boneOut.id = selId; + boneOut.parentId = parent; + boneOut.origin = bone->origin; + boneOut.linkedCount = bone->children.size() + 1; + boneOut.linked.reserve(boneOut.linkedCount); + + const BlenderBone* child; + boneOut.linked.push_back(parent); + for (size_t i = 0; (child = armature.getChild(bone, i)); ++i) + boneOut.linked.push_back(RecursiveAddArmatureBone(armature, child, boneOut.id, curId, idMap, nameMap)); + + return boneOut.id; +} + +CINF::CINF(const Armature& armature, std::unordered_map& idMap) { + idMap.reserve(armature.bones.size()); + bones.reserve(armature.bones.size()); + + std::map nameMap; + + const BlenderBone* bone = armature.getRoot(); + if (bone) { + if (bone->children.size()) { + int curId = 4; + const BlenderBone* child; + for (size_t i = 0; (child = armature.getChild(bone, i)); ++i) + RecursiveAddArmatureBone(armature, child, 3, curId, idMap, nameMap); + } + + bones.emplace_back(); + Bone& boneOut = bones.back(); + nameMap[bone->name] = 3; + boneOut.id = 3; + boneOut.parentId = 2; + boneOut.origin = bone->origin; + idMap.emplace(std::make_pair(bone->name, 3)); + + if (bone->children.size()) { + boneOut.linkedCount = 2; + boneOut.linked = {2, 4}; + } else { + boneOut.linkedCount = 1; + boneOut.linked = {2}; + } + } + + boneCount = bones.size(); + + names.reserve(nameMap.size()); + nameCount = nameMap.size(); + for (const auto& name : nameMap) { + names.emplace_back(); + Name& nameOut = names.back(); + nameOut.name = name.first; + nameOut.boneId = name.second; + } + + boneIdCount = boneCount; + boneIds.reserve(boneIdCount); + for (auto it = bones.crbegin(); it != bones.crend(); ++it) + boneIds.push_back(it->id); +} + +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) { + if (!force && outPath.isFile()) + return true; + + auto& conn = btok.getBlenderConnection(); + if (!conn.createBlend(outPath, hecl::blender::BlendType::Armature)) + return false; + auto os = conn.beginPythonOut(true); + + os.format(fmt("import bpy\n" + "from mathutils import Vector\n" + "bpy.context.scene.name = 'CINF_{}'\n" + "bpy.context.scene.hecl_arm_obj = bpy.context.scene.name\n" + "\n" + "# Clear Scene\n" + "if len(bpy.data.collections):\n" + " bpy.data.collections.remove(bpy.data.collections[0])\n" + "\n"), entry.id); + + CINF cinf; + cinf.read(rs); + 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; + CINF cinf(armature, boneIdMap); + + /* Write out CINF resource */ + athena::io::TransactionalFileWriter w(outPath.getAbsolutePath()); + cinf.write(w); + return true; +} } // namespace DataSpec::DNAMP2 diff --git a/DataSpec/DNAMP2/CINF.hpp b/DataSpec/DNAMP2/CINF.hpp index 6cebbd0c1..85831eb66 100644 --- a/DataSpec/DNAMP2/CINF.hpp +++ b/DataSpec/DNAMP2/CINF.hpp @@ -2,6 +2,7 @@ #include "DataSpec/DNACommon/DNACommon.hpp" #include "DataSpec/DNACommon/RigInverter.hpp" +#include "DNAMP2.hpp" namespace DataSpec::DNAMP2 { @@ -35,8 +36,27 @@ 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; + using BlenderBone = hecl::blender::Bone; + + int RecursiveAddArmatureBone(const Armature& armature, const BlenderBone* bone, int parent, int& curId, + std::unordered_map& idMap, std::map& nameMap); + + CINF(const Armature& armature, std::unordered_map& idMap); + + template + static bool 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); + + static bool Cook(const hecl::ProjectPath& outPath, const hecl::ProjectPath& inPath, + const hecl::blender::Armature& armature); }; } // namespace DataSpec::DNAMP2 diff --git a/DataSpec/DNAMP2/CMakeLists.txt b/DataSpec/DNAMP2/CMakeLists.txt index 504d14541..e04014768 100644 --- a/DataSpec/DNAMP2/CMakeLists.txt +++ b/DataSpec/DNAMP2/CMakeLists.txt @@ -23,6 +23,7 @@ set(DNAMP2_SOURCES MREA.cpp MAPA.hpp MAPU.hpp + PATH.hpp AFSM.hpp STRG.hpp STRG.cpp) diff --git a/DataSpec/DNAMP2/DNAMP2.cpp b/DataSpec/DNAMP2/DNAMP2.cpp index f0e1d7bc9..208bc8d14 100644 --- a/DataSpec/DNAMP2/DNAMP2.cpp +++ b/DataSpec/DNAMP2/DNAMP2.cpp @@ -4,9 +4,11 @@ #include "MLVL.hpp" #include "CMDL.hpp" #include "ANCS.hpp" +#include "CINF.hpp" #include "MREA.hpp" #include "MAPA.hpp" #include "MAPU.hpp" +#include "PATH.hpp" #include "AFSM.hpp" #include "SAVW.hpp" #include "AGSC.hpp" @@ -25,7 +27,9 @@ logvisor::Module Log("urde::DNAMP2"); static bool GetNoShare(std::string_view name) { std::string lowerName(name); std::transform(lowerName.begin(), lowerName.end(), lowerName.begin(), tolower); - if (!lowerName.compare(0, 7, "metroid")) + if (lowerName.compare(0, 7, "metroid") == 0) + return false; + if (lowerName.compare(0, 8, "frontend") == 0) return false; return true; } @@ -170,6 +174,18 @@ void PAKBridge::addCMDLRigPairs(PAKRouter& pakRouter, CharacterAssoci } } +void PAKBridge::addPATHToMREA(PAKRouter& pakRouter, + std::unordered_map& pathToMrea) const { + for (const auto& [id, entry] : m_pak.m_entries) { + if (entry.type == FOURCC('MREA')) { + PAKEntryReadStream rs = entry.beginReadStream(m_node); + UniqueID32 pathID = MREA::GetPATHId(rs); + if (pathID.isValid()) + pathToMrea[pathID] = id; + } + } +} + static const atVec4f BottomRow = {{0.f, 0.f, 0.f, 1.f}}; void PAKBridge::addMAPATransforms(PAKRouter& pakRouter, @@ -189,6 +205,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); + UniqueID32 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, @@ -234,6 +260,8 @@ ResExtractor PAKBridge::LookupExtractor(const nod::Node& pakNode, con return {SAVWCommon::ExtractSAVW, {_SYS_STR(".yaml")}}; case SBIG('CMDL'): return {CMDL::Extract, {_SYS_STR(".blend")}, 1}; + case SBIG('CINF'): + return {CINF::Extract, {_SYS_STR(".blend")}, 1}; case SBIG('ANCS'): return {ANCS::Extract, {_SYS_STR(".yaml"), _SYS_STR(".blend")}, 2}; case SBIG('MLVL'): @@ -244,6 +272,8 @@ ResExtractor PAKBridge::LookupExtractor(const nod::Node& pakNode, con return {MAPA::Extract, {_SYS_STR(".blend")}, 4}; case SBIG('MAPU'): return {MAPU::Extract, {_SYS_STR(".blend")}, 5}; + 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/DNAMP2/DNAMP2.hpp b/DataSpec/DNAMP2/DNAMP2.hpp index 279bba2c3..ee62edc12 100644 --- a/DataSpec/DNAMP2/DNAMP2.hpp +++ b/DataSpec/DNAMP2/DNAMP2.hpp @@ -31,6 +31,9 @@ public: void addCMDLRigPairs(PAKRouter& pakRouter, CharacterAssociations& charAssoc) const; + void addPATHToMREA(PAKRouter& pakRouter, + std::unordered_map& pathToMrea) const; + void addMAPATransforms(PAKRouter& pakRouter, std::unordered_map& addTo, std::unordered_map& pathOverrides) const; }; diff --git a/DataSpec/DNAMP2/DeafBabe.cpp b/DataSpec/DNAMP2/DeafBabe.cpp index 36a5e9b3c..e1c699914 100644 --- a/DataSpec/DNAMP2/DeafBabe.cpp +++ b/DataSpec/DNAMP2/DeafBabe.cpp @@ -26,12 +26,15 @@ void DeafBabe::BlenderInit(hecl::blender::PyOutStream& os) { " 'Rubber':(0.09, 0.02, 0.01)}\n" "\n" "# Diffuse Color Maker\n" + "from mathutils import Color\n" "def make_color(index, mat_type, name):\n" " new_mat = bpy.data.materials.new(name)\n" " if mat_type in TYPE_COLORS:\n" - " new_mat.diffuse_color = TYPE_COLORS[mat_type]\n" + " new_mat.diffuse_color = TYPE_COLORS[mat_type] + (1.0,)\n" " else:\n" - " new_mat.diffuse_color.hsv = ((index / 6.0) % 1.0, 1.0-((index // 6) / 6.0), 1)\n" + " col = Color()\n" + " col.hsv = ((index / 6.0) % 1.0, 1.0-((index // 6) / 6.0), 1)\n" + " new_mat.diffuse_color = tuple(col) + (1.0,)\n" " return new_mat\n" "\n" "bpy.types.Material.retro_unknown = bpy.props.BoolProperty(description='Retro: Unknown (U)')\n" diff --git a/DataSpec/DNAMP2/MREA.cpp b/DataSpec/DNAMP2/MREA.cpp index ba2bd6adb..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; } @@ -98,11 +97,11 @@ void MREA::StreamReader::seek(atInt64 diff, athena::SeekOrigin whence) { if (newAccum > target) break; dAccum = newAccum; - ++bIdx; if (info.compSize) cAccum += ROUND_UP_32(info.compSize); else cAccum += info.decompSize; + ++bIdx; } /* Seek source if needed */ @@ -116,6 +115,41 @@ void MREA::StreamReader::seek(atInt64 diff, athena::SeekOrigin whence) { m_posInBlk = target - dAccum; } +void MREA::StreamReader::seekToSection(atUint32 sec, const std::vector& secSizes) { + /* Determine which block contains section */ + atUint32 sAccum = 0; + atUint32 dAccum = 0; + atUint32 cAccum = 0; + atUint32 bIdx = 0; + for (BlockInfo& info : m_blockInfos) { + atUint32 newSAccum = sAccum + info.secCount; + if (newSAccum > sec) + break; + sAccum = newSAccum; + dAccum += info.decompSize; + if (info.compSize) + cAccum += ROUND_UP_32(info.compSize); + else + cAccum += info.decompSize; + ++bIdx; + } + + /* Seek source if needed */ + if (bIdx != m_nextBlk - 1) { + m_source.seek(m_blkBase + cAccum, athena::SeekOrigin::Begin); + m_nextBlk = bIdx; + nextBlock(); + } + + /* Seek within block */ + atUint32 target = dAccum; + while (sAccum != sec) + target += secSizes[sAccum++]; + + m_pos = target; + m_posInBlk = target - dAccum; +} + atUint64 MREA::StreamReader::readUBytesToBuf(void* buf, atUint64 len) { atUint8* bufCur = reinterpret_cast(buf); atUint64 rem = len; @@ -296,5 +330,19 @@ bool MREA::Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl: return conn.saveBlend(); } +UniqueID32 MREA::GetPATHId(PAKEntryReadStream& rs) { + /* Do extract */ + Header head; + head.read(rs); + rs.seekAlign32(); + + /* MREA decompression stream */ + StreamReader drs(rs, head.compressedBlockCount); + + /* Skip to PATH */ + drs.seekToSection(head.pathSecIdx, head.secSizes); + return {drs}; +} + } // namespace DNAMP2 } // namespace DataSpec diff --git a/DataSpec/DNAMP2/MREA.hpp b/DataSpec/DNAMP2/MREA.hpp index 5e678d5b7..65950865b 100644 --- a/DataSpec/DNAMP2/MREA.hpp +++ b/DataSpec/DNAMP2/MREA.hpp @@ -43,6 +43,7 @@ struct MREA { public: StreamReader(athena::io::IStreamReader& source, atUint32 blkCount); void seek(atInt64 diff, athena::SeekOrigin whence) override; + void seekToSection(atUint32 sec, const std::vector& secSizes); atUint64 position() const override { return m_pos; } atUint64 length() const override { return m_totalDecompLen; } atUint64 readUBytesToBuf(void* buf, atUint64 len) override; @@ -118,6 +119,8 @@ struct MREA { Value aabb[2]; }; + static UniqueID32 GetPATHId(PAKEntryReadStream& rs); + static bool Extract(const SpecBase& dataSpec, PAKEntryReadStream& rs, const hecl::ProjectPath& outPath, PAKRouter& pakRouter, const DNAMP2::PAK::Entry& entry, bool, hecl::blender::Token& btok, std::function); diff --git a/DataSpec/DNAMP2/PATH.hpp b/DataSpec/DNAMP2/PATH.hpp new file mode 100644 index 000000000..676f4479d --- /dev/null +++ b/DataSpec/DNAMP2/PATH.hpp @@ -0,0 +1,6 @@ +#pragma once +#include "DataSpec/DNACommon/PATH.hpp" + +namespace DataSpec::DNAMP2 { +using PATH = DNAPATH::PATH; +} // namespace DataSpec::DNAMP2 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/DataSpec/SpecMP2.cpp b/DataSpec/SpecMP2.cpp index 8111b2400..d013ca9ab 100644 --- a/DataSpec/SpecMP2.cpp +++ b/DataSpec/SpecMP2.cpp @@ -6,9 +6,11 @@ #include "DNAMP2/MLVL.hpp" #include "DNAMP2/STRG.hpp" #include "DNAMP2/AGSC.hpp" +#include "DNAMP2/PATH.hpp" #include "DNAMP2/MAPA.hpp" #include "DNAMP1/CSNG.hpp" #include "DNACommon/MAPU.hpp" +#include "DNACommon/PATH.hpp" #include "hecl/ClientProcess.hpp" #include "hecl/Blender/Connection.hpp" @@ -286,7 +288,11 @@ struct SpecMP2 : SpecBase { hecl::blender::Token& btok, FCookProgress progress) override {} void cookPathMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast, - hecl::blender::Token& btok, FCookProgress progress) override {} + hecl::blender::Token& btok, FCookProgress progress) override { + PathMesh mesh = ds.compilePathMesh(); + ds.close(); + DNAMP2::PATH::Cook(out, in, mesh, btok); + } void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast, hecl::blender::Token& btok, FCookProgress progress) override {} diff --git a/Runtime/MP1/MP1.hpp b/Runtime/MP1/MP1.hpp index 397031000..cf25985ec 100644 --- a/Runtime/MP1/MP1.hpp +++ b/Runtime/MP1/MP1.hpp @@ -4,7 +4,7 @@ #define MP1_USE_BOO 0 #endif #ifndef MP1_VARIABLE_DELTA_TIME -#define MP1_VARIABLE_DELTA_TIME 0 +#define MP1_VARIABLE_DELTA_TIME 1 #endif #include "IMain.hpp" diff --git a/hecl b/hecl index 0b42de34d..87ad5cbc8 160000 --- a/hecl +++ b/hecl @@ -1 +1 @@ -Subproject commit 0b42de34d0439ed46e393e0bb6de1b02641399a1 +Subproject commit 87ad5cbc81dad92d54c60d388157ca6300475c19