mirror of
				https://github.com/AxioDL/metaforce.git
				synced 2025-10-27 15:30:23 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			1230 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1230 lines
		
	
	
		
			54 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| #include "CMDLMaterials.hpp"
 | |
| #include "../DNAMP2/CMDLMaterials.hpp"
 | |
| #include "hecl/Blender/Connection.hpp"
 | |
| 
 | |
| using Stream = hecl::blender::PyOutStream;
 | |
| 
 | |
| namespace DataSpec::DNAMP1 {
 | |
| using Material = MaterialSet::Material;
 | |
| 
 | |
| void MaterialSet::RegisterMaterialProps(Stream& out) {
 | |
|   out << "bpy.types.Material.retro_depth_sort = bpy.props.BoolProperty(name='Retro: Transparent Depth Sort')\n"
 | |
|          "bpy.types.Material.retro_alpha_test = bpy.props.BoolProperty(name='Retro: Punchthrough Alpha')\n"
 | |
|          "bpy.types.Material.retro_samus_reflection = bpy.props.BoolProperty(name='Retro: Samus Reflection')\n"
 | |
|          "bpy.types.Material.retro_depth_write = bpy.props.BoolProperty(name='Retro: Depth Write')\n"
 | |
|          "bpy.types.Material.retro_samus_reflection_persp = bpy.props.BoolProperty(name='Retro: Samus Reflection "
 | |
|          "Perspective')\n"
 | |
|          "bpy.types.Material.retro_shadow_occluder = bpy.props.BoolProperty(name='Retro: Shadow Occluder')\n"
 | |
|          "bpy.types.Material.retro_samus_reflection_indirect = bpy.props.BoolProperty(name='Retro: Samus Reflection "
 | |
|          "Indirect Texture')\n"
 | |
|          "bpy.types.Material.retro_lightmapped = bpy.props.BoolProperty(name='Retro: Lightmapped')\n"
 | |
|          "\n";
 | |
| }
 | |
| 
 | |
| void Material::AddTexture(Stream& out, GX::TexGenSrc type, int mtxIdx, uint32_t texIdx, bool diffuse) {
 | |
|   std::string mtxLabel;
 | |
|   if (mtxIdx == -1)
 | |
|     mtxLabel = "IDENTITY";
 | |
|   else
 | |
|     mtxLabel = fmt::format(FMT_STRING("MTX_{}"), mtxIdx);
 | |
| 
 | |
|   std::string texLabel;
 | |
|   if (diffuse)
 | |
|     texLabel = "Diffuse";
 | |
|   else
 | |
|     texLabel = "Texture";
 | |
| 
 | |
|   out.format(FMT_STRING("# 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_STRING("tex_node.image = tex_maps[{}]\n"), texIdx);
 | |
| 
 | |
|   if (type == GX::TG_POS)
 | |
|     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";
 | |
|   else if (type == GX::TG_NRM)
 | |
|     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";
 | |
|   else if (type >= GX::TG_TEX0 && type <= GX::TG_TEX7) {
 | |
|     uint8_t texIdx = type - GX::TG_TEX0;
 | |
|     out.format(FMT_STRING("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_STRING("tex_uv_node.label = '{}'\n"), mtxLabel);
 | |
| 
 | |
|   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";
 | |
| }
 | |
| 
 | |
| void Material::AddTextureAnim(Stream& out, UVAnimation::Mode type, unsigned idx, const float* vals) {
 | |
|   switch (type) {
 | |
|   case UVAnimation::Mode::MvInvNoTranslation:
 | |
|     out.format(FMT_STRING("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_STRING("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_STRING("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_STRING("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_STRING("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_STRING("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_STRING("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_STRING("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_STRING("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;
 | |
|   }
 | |
| }
 | |
| 
 | |
| void Material::AddKcolor(Stream& out, const GX::Color& col, unsigned idx) {
 | |
|   out.format(FMT_STRING("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 <class MAT>
 | |
| static uint32_t _HashTextureConfig(const MAT& mat) {
 | |
|   XXH32_state_t xxHash;
 | |
|   XXH32_reset(&xxHash, 0);
 | |
|   for (uint32_t i = 0; i < mat.tevStageCount; ++i) {
 | |
|     const auto& stage = mat.tevStages[i];
 | |
|     XXH32_update(&xxHash, &stage.ciFlags, sizeof(stage.ciFlags));
 | |
|     XXH32_update(&xxHash, &stage.aiFlags, sizeof(stage.aiFlags));
 | |
|     XXH32_update(&xxHash, &stage.ccFlags, sizeof(stage.ccFlags));
 | |
|     XXH32_update(&xxHash, &stage.acFlags, sizeof(stage.acFlags));
 | |
|     XXH32_update(&xxHash, &stage.kaInput, sizeof(stage.kaInput));
 | |
|     XXH32_update(&xxHash, &stage.kcInput, sizeof(stage.kcInput));
 | |
|     XXH32_update(&xxHash, &stage.rascInput, sizeof(stage.rascInput));
 | |
|   }
 | |
|   bool hasInd = mat.flags.samusReflectionIndirectTexture();
 | |
|   XXH32_update(&xxHash, &hasInd, sizeof(hasInd));
 | |
|   bool hasLm = mat.flags.lightmap();
 | |
|   XXH32_update(&xxHash, &hasLm, sizeof(hasLm));
 | |
|   return XXH32_digest(&xxHash);
 | |
| }
 | |
| 
 | |
| static const char* ToString(GX::TevColorArg arg) {
 | |
|   switch (arg) {
 | |
|   case GX::CC_CPREV:
 | |
|     return "CC_CPREV";
 | |
|   case GX::CC_APREV:
 | |
|     return "CC_APREV";
 | |
|   case GX::CC_C0:
 | |
|     return "CC_C0";
 | |
|   case GX::CC_A0:
 | |
|     return "CC_A0";
 | |
|   case GX::CC_C1:
 | |
|     return "CC_C1";
 | |
|   case GX::CC_A1:
 | |
|     return "CC_A1";
 | |
|   case GX::CC_C2:
 | |
|     return "CC_C2";
 | |
|   case GX::CC_A2:
 | |
|     return "CC_A2";
 | |
|   case GX::CC_TEXC:
 | |
|     return "CC_TEXC";
 | |
|   case GX::CC_TEXA:
 | |
|     return "CC_TEXA";
 | |
|   case GX::CC_RASC:
 | |
|     return "CC_RASC";
 | |
|   case GX::CC_RASA:
 | |
|     return "CC_RASA";
 | |
|   case GX::CC_ONE:
 | |
|     return "CC_ONE";
 | |
|   case GX::CC_HALF:
 | |
|     return "CC_HALF";
 | |
|   case GX::CC_KONST:
 | |
|     return "CC_KONST";
 | |
|   case GX::CC_ZERO:
 | |
|     return "CC_ZERO";
 | |
|   default:
 | |
|     return "UNKNOWN";
 | |
|   }
 | |
| }
 | |
| 
 | |
| static const char* ToString(GX::TevAlphaArg arg) {
 | |
|   switch (arg) {
 | |
|   case GX::CA_APREV:
 | |
|     return "CA_APREV";
 | |
|   case GX::CA_A0:
 | |
|     return "CA_A0";
 | |
|   case GX::CA_A1:
 | |
|     return "CA_A1";
 | |
|   case GX::CA_A2:
 | |
|     return "CA_A2";
 | |
|   case GX::CA_TEXA:
 | |
|     return "CA_TEXA";
 | |
|   case GX::CA_RASA:
 | |
|     return "CA_RASA";
 | |
|   case GX::CA_KONST:
 | |
|     return "CA_KONST";
 | |
|   case GX::CA_ZERO:
 | |
|     return "CA_ZERO";
 | |
|   default:
 | |
|     return "UNKNOWN";
 | |
|   }
 | |
| }
 | |
| 
 | |
| static const char* ToString(GX::TevRegID arg) {
 | |
|   switch (arg) {
 | |
|   case GX::TEVPREV:
 | |
|     return "TEVPREV";
 | |
|   case GX::TEVREG0:
 | |
|     return "TEVREG0";
 | |
|   case GX::TEVREG1:
 | |
|     return "TEVREG1";
 | |
|   case GX::TEVREG2:
 | |
|     return "TEVREG2";
 | |
|   default:
 | |
|     return "UNKNOWN";
 | |
|   }
 | |
| }
 | |
| 
 | |
| template <class MAT>
 | |
| 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_STRING("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();
 | |
|   fmt::print(stderr, FMT_STRING("HasIndirect: {} HasLightmap: {}\n"), hasInd, hasLm);
 | |
| }
 | |
| 
 | |
| struct TexLink {
 | |
|   const char* shaderInput;
 | |
|   int texidx;
 | |
|   bool alpha;
 | |
|   TexLink(const char* shaderInput, int texidx = -1, bool alpha = false)
 | |
|   : shaderInput(shaderInput), texidx(texidx), alpha(alpha) {}
 | |
| };
 | |
| 
 | |
| struct ExtendedSpecularLink {
 | |
|   int texidx;
 | |
|   ExtendedSpecularLink(int texidx = -1) : texidx(texidx) {}
 | |
| };
 | |
| 
 | |
| struct KColLink {
 | |
|   const char* shaderInput;
 | |
|   int kcidx;
 | |
|   bool alpha;
 | |
|   KColLink(const char* shaderInput, int kcidx = 0, bool alpha = false)
 | |
|   : shaderInput(shaderInput), kcidx(kcidx), alpha(alpha) {}
 | |
| };
 | |
| 
 | |
| struct WhiteColorLink {
 | |
|   const char* shaderInput;
 | |
|   explicit WhiteColorLink(const char* shaderInput) : shaderInput(shaderInput) {}
 | |
| };
 | |
| 
 | |
| static void _GenerateRootShader(Stream& out, int) { /* End of shader links */
 | |
| }
 | |
| 
 | |
| template <typename... Targs>
 | |
| static void _GenerateRootShader(Stream& out, int tidx, TexLink tex, Targs... args) {
 | |
|   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";
 | |
|   if (tex.texidx == -1)
 | |
|     ++tidx;
 | |
|   _GenerateRootShader(out, tidx, args...);
 | |
| }
 | |
| 
 | |
| template <typename... Targs>
 | |
| static void _GenerateRootShader(Stream& out, int tidx, ExtendedSpecularLink tex, Targs... args) {
 | |
|   int texIdx = tex.texidx == -1 ? tidx : tex.texidx;
 | |
|   out << "texture_nodes[" << texIdx << "].name = 'Specular'\n";
 | |
|   out << "texture_nodes[" << texIdx << "].label = 'Specular'\n";
 | |
|   out << "new_nodetree.links.new(texture_nodes[" << texIdx << "].outputs['Color'], node.inputs['Specular'])\n";
 | |
|   out << "new_nodetree.links.new(texture_nodes[" << texIdx << "].outputs['Alpha'], node.inputs['ExtendedSpecular'])\n";
 | |
|   if (tex.texidx == -1)
 | |
|     ++tidx;
 | |
|   _GenerateRootShader(out, tidx, args...);
 | |
| }
 | |
| 
 | |
| template <typename... Targs>
 | |
| 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";
 | |
|   _GenerateRootShader(out, tidx, args...);
 | |
| }
 | |
| 
 | |
| template <typename... Targs>
 | |
| static void _GenerateRootShader(Stream& out, int tidx, WhiteColorLink wcol, Targs... args) {
 | |
|   out << "node.inputs['" << wcol.shaderInput << "'].default_value = (1.0, 1.0, 1.0, 1.0)\n";
 | |
|   _GenerateRootShader(out, tidx, args...);
 | |
| }
 | |
| 
 | |
| template <typename... Targs>
 | |
| 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"
 | |
|          "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); }
 | |
| 
 | |
| template <class MAT>
 | |
| static void _ConstructMaterial(Stream& out, const MAT& material, unsigned groupIdx, unsigned matIdx) {
 | |
|   unsigned i;
 | |
| 
 | |
|   out.format(FMT_STRING("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.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"
 | |
|          "\n"
 | |
|          "texture_nodes = []\n"
 | |
|          "kcolors = {}\n"
 | |
|          "kalphas = {}\n"
 | |
|          "tex_links = []\n"
 | |
|          "\n";
 | |
| 
 | |
|   /* Material Flags */
 | |
|   out.format(FMT_STRING("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";
 | |
|   for (atUint32 idx : material.textureIdxs)
 | |
|     out.format(FMT_STRING("tex_maps.append(texmap_list[{}])\n"), idx);
 | |
| 
 | |
|   /* KColor entries */
 | |
|   if (material.flags.konstValuesEnabled()) {
 | |
|     unsigned i = 0;
 | |
|     for (const GX::Color& col : material.konstColors)
 | |
|       Material::AddKcolor(out, col, i++);
 | |
|   }
 | |
| 
 | |
|   /* Blend factors */
 | |
|   out << "blend_node = new_nodetree.nodes.new('ShaderNodeGroup')\n"
 | |
|          "blend_node.name = 'Blend'\n"
 | |
|          "gridder.place_node(blend_node, 2)\n";
 | |
|   using BlendFactor = Material::BlendFactor;
 | |
|   if (material.blendDstFac != BlendFactor::BL_ZERO) {
 | |
|     if (material.blendDstFac == BlendFactor::BL_ONE)
 | |
|       out << "blend_node.node_tree = bpy.data.node_groups['HECLAdditiveOutput']\n";
 | |
|     else
 | |
|       out << "blend_node.node_tree = bpy.data.node_groups['HECLBlendOutput']\n";
 | |
|   } else {
 | |
|     out << "blend_node.node_tree = bpy.data.node_groups['HECLOpaqueOutput']\n"
 | |
|            "new_material.blend_method = 'OPAQUE'\n";
 | |
|   }
 | |
| 
 | |
|   /* Add texture maps/tcgs */
 | |
|   unsigned addedTcgs = 0;
 | |
|   bool diffuseStage = false;
 | |
|   for (i = 0; i < material.tevStageCount; ++i) {
 | |
|     if (material.tevStageTexInfo[i].tcgSlot != 0xff && !(addedTcgs >> material.tevStageTexInfo[i].tcgSlot & 1)) {
 | |
|       const Material::TexCoordGen& tcg = material.tcgs[material.tevStageTexInfo[i].tcgSlot];
 | |
|       GX::TexMtx mtx = tcg.mtx();
 | |
|       int mtxIdx = -1;
 | |
|       if (mtx >= GX::TEXMTX0 && mtx <= GX::TEXMTX9)
 | |
|         mtxIdx = (mtx - GX::TEXMTX0) / 3;
 | |
|       Material::AddTexture(out, tcg.source(), mtxIdx, material.tevStageTexInfo[i].texSlot, diffuseStage);
 | |
|       addedTcgs |= 1 << material.tevStageTexInfo[i].tcgSlot;
 | |
|     }
 | |
|     diffuseStage = material.tevStages[i].colorOpOutReg() == GX::TEVREG0;
 | |
|   }
 | |
| 
 | |
|   /* Indirect texture node */
 | |
|   if (material.flags.samusReflectionIndirectTexture())
 | |
|     Material::AddTexture(out, GX::TexGenSrc::TG_POS, -1, material.indTexSlot[0], false);
 | |
| 
 | |
|   /* 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;
 | |
|   case 0x072D2CB3: /* RetroShader: Diffuse, Emissive, Reflection, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0x0DA256BB: /* Lightmap, Diffuse, Specular, Reflection, Alpha=KAlpha */
 | |
|     _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;
 | |
|   case 0x1218F83E: /* RetroShader: ObjLightmap, Diffuse, ExtendedSpecular, Reflection, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   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;
 | |
|   case 0x1BEB3E15: /* RetroShader: Diffuse, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   case 0x239C7724: /* RetroDynamicShader: Diffuse*Dynamic, Emissive*Dynamic, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0x2523A379: /* RetroDynamicShader: Emissive*Dynamic, Specular, Reflection, Alpha=1.0 */
 | |
|     _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;
 | |
|   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;
 | |
|   case 0x2AD9F535: /* RetroShader: Emissive, Reflection, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0x2D059429: /* RetroShader: Diffuse, Emissive, ExtendedSpecular, Reflection, Alpha=1.0 */
 | |
|     _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;
 | |
|   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;
 | |
|   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;
 | |
|   case 0x4BBDFFA6: /* RetroShader: Diffuse, Emissive, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0x54A92F25: /* RetroShader: ObjLightmap, KColorDiffuse, Alpha=KAlpha */
 | |
|     _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;
 | |
|   case 0x5A62D5F0: /* RetroShader: Lightmap, Diffuse, UnusedExtendedSpecular?, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   case 0x5D0F0069: /* RetroShader: Diffuse, Emissive, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   case 0x5F0AB0E9: /* RetroShader: Lightmap, Diffuse, UnusedSpecular?, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   case 0x6601D113: /* RetroShader: Emissive, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0x6D98D689: /* RetroDynamicAlphaShader: Diffuse*Dynamic, Specular, Reflection, Alpha=KAlpha*Dynamic */
 | |
|     _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;
 | |
|   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;
 | |
|   case 0x7D6A4487: /* RetroShader: Diffuse, Specular, Reflection, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   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;
 | |
|   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;
 | |
|   case 0x957709F8: /* RetroShader: Emissive, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0x985A0B67: /* RetroShader: Diffuse, UnusedSpecular?, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   case 0xA187C630: /* RetroShader: Diffuse, Emissive, UnusedReflection?, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0xC3C8B1C8: /* RetroShader: KColorDiffuse, Alpha=KAlpha */
 | |
|     _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;
 | |
|   case 0xC6B18B28: /* RetroShader: Diffuse, Alpha=DiffuseAlpha */
 | |
|     _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;
 | |
|   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;
 | |
|   case 0xDB8F01AD: /* RetroDynamicShader: Diffuse*Dynamic, Emissive*Dynamic, UnusedSpecular?, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0xE68FF182: /* RetroShader: Diffuse, Emissive, Specular, Reflection, Alpha=1.0 */
 | |
|     _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;
 | |
|   case 0xECEF8D1F: /* RetroDynamicShader: Diffuse*Dynamic, Emissive*Dynamic, Specular, Reflection, Alpha=1.0 */
 | |
|     _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;
 | |
|   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;
 | |
|   case 0xF9324367: /* RetroShader: Lightmap, Diffuse, Emissive, Alpha=1.0 */
 | |
|     _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;
 | |
|   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_STRING("Unable to resolve shader hash {:08X}\n"), hash);
 | |
|     break;
 | |
|   }
 | |
| 
 | |
|   /* Has Lightmap? */
 | |
|   if (material.flags.lightmap()) {
 | |
|     if (material.tevStageTexInfo[0].texSlot != 0xff)
 | |
|       out << "new_material.hecl_lightmap = tex_maps[0].name\n"
 | |
|              "tex_maps[0].use_fake_user = True\n";
 | |
|   }
 | |
| 
 | |
|   /* Texmtx Animation Section */
 | |
|   i = 0;
 | |
|   for (const Material::UVAnimation& anim : material.uvAnims)
 | |
|     Material::AddTextureAnim(out, anim.mode, i++, anim.vals);
 | |
| }
 | |
| 
 | |
| void MaterialSet::ConstructMaterial(Stream& out, const MaterialSet::Material& material, unsigned groupIdx,
 | |
|                                     unsigned matIdx) {
 | |
|   _ConstructMaterial(out, material, groupIdx, matIdx);
 | |
| }
 | |
| 
 | |
| MaterialSet::Material::Material(const hecl::blender::Material& mat, std::vector<hecl::ProjectPath>& texPathsOut,
 | |
|                                 int colorCount, bool lightmapUVs, bool matrixSkinning) {
 | |
|   /* TODO: Rewrite for new shader rep */
 | |
|   XXH32_state_t xxHash;
 | |
|   XXH32_reset(&xxHash, 0);
 | |
| 
 | |
| #if 0
 | |
|   if (gx.m_kcolorCount) {
 | |
|     flags.setKonstValuesEnabled(true);
 | |
|     konstCount.push_back(gx.m_kcolorCount);
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   auto search = mat.iprops.find("retro_depth_sort");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setDepthSorting(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_alpha_test");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setAlphaTest(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_samus_reflection");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setSamusReflection(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_depth_write");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setDepthWrite(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_samus_reflection_persp");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setSamusReflectionSurfaceEye(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_shadow_occluder");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setShadowOccluderMesh(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_samus_reflection_indirect");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setSamusReflectionIndirectTexture(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_lightmapped");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setLightmap(search->second != 0);
 | |
| 
 | |
|   flags.setLightmapUVArray(lightmapUVs);
 | |
| 
 | |
| #if 0
 | |
|   atUint16 texFlags = 0;
 | |
|   atUint16 tcgFlags = 0;
 | |
|   tevStageTexInfo.reserve(gx.m_tevCount);
 | |
|   textureIdxs.reserve(gx.m_tevCount);
 | |
|   for (unsigned i = 0; i < gx.m_tevCount; ++i) {
 | |
|     const hecl::Backend::GX::TEVStage& stage = gx.m_tevs[i];
 | |
|     tevStageTexInfo.emplace_back();
 | |
|     TEVStageTexInfo& texInfo = tevStageTexInfo.back();
 | |
|     if (stage.m_texGenIdx != -1) {
 | |
|       texInfo.tcgSlot = stage.m_texGenIdx;
 | |
|       const hecl::Backend::GX::TexCoordGen& tcg = gx.m_tcgs[stage.m_texGenIdx];
 | |
|       if (tcg.m_src >= hecl::Backend::GX::TG_TEX0 && tcg.m_src <= hecl::Backend::GX::TG_TEX6)
 | |
|         tcgFlags |= 1 << (tcg.m_src - hecl::Backend::GX::TG_TEX0);
 | |
|     }
 | |
|     if (stage.m_texMapIdx != -1) {
 | |
|       texInfo.texSlot = textureIdxs.size();
 | |
|       const hecl::ProjectPath& texPath = texPathsIn.at(stage.m_texMapIdx);
 | |
|       texFlags |= 1 << i;
 | |
|       ++textureCount;
 | |
|       bool found = false;
 | |
|       for (size_t t = 0; t < texPathsOut.size(); ++t) {
 | |
|         if (texPath == texPathsOut[t]) {
 | |
|           found = true;
 | |
|           textureIdxs.push_back(t);
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|       if (!found) {
 | |
|         textureIdxs.push_back(texPathsOut.size());
 | |
|         texPathsOut.push_back(texPath);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
|   flags.setTextureSlots(texFlags);
 | |
| 
 | |
|   XXH32_update(&xxHash, &flags.flags, sizeof(flags.flags));
 | |
| 
 | |
|   vaFlags.setPosition(GX::INDEX16);
 | |
|   vaFlags.setNormal(GX::INDEX16);
 | |
| 
 | |
|   if (0 < colorCount)
 | |
|     vaFlags.setColor0(GX::INDEX16);
 | |
|   if (1 < colorCount)
 | |
|     vaFlags.setColor1(GX::INDEX16);
 | |
| 
 | |
|   if (tcgFlags & (1 << 0))
 | |
|     vaFlags.setTex0(GX::INDEX16);
 | |
|   if (tcgFlags & (1 << 1))
 | |
|     vaFlags.setTex1(GX::INDEX16);
 | |
|   if (tcgFlags & (1 << 2))
 | |
|     vaFlags.setTex2(GX::INDEX16);
 | |
|   if (tcgFlags & (1 << 3))
 | |
|     vaFlags.setTex3(GX::INDEX16);
 | |
|   if (tcgFlags & (1 << 4))
 | |
|     vaFlags.setTex4(GX::INDEX16);
 | |
|   if (tcgFlags & (1 << 5))
 | |
|     vaFlags.setTex5(GX::INDEX16);
 | |
|   if (tcgFlags & (1 << 6))
 | |
|     vaFlags.setTex6(GX::INDEX16);
 | |
| 
 | |
|   if (matrixSkinning) {
 | |
|     vaFlags.setPnMatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 0))
 | |
|       vaFlags.setTex0MatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 1))
 | |
|       vaFlags.setTex1MatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 2))
 | |
|       vaFlags.setTex2MatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 3))
 | |
|       vaFlags.setTex3MatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 4))
 | |
|       vaFlags.setTex4MatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 5))
 | |
|       vaFlags.setTex5MatIdx(GX::DIRECT);
 | |
|     if (tcgFlags & (1 << 6))
 | |
|       vaFlags.setTex6MatIdx(GX::DIRECT);
 | |
|   }
 | |
| 
 | |
|   XXH32_update(&xxHash, &vaFlags.vaFlags, sizeof(vaFlags.vaFlags));
 | |
| 
 | |
|   XXH32_update(&xxHash, &gx.m_kcolorCount, sizeof(gx.m_kcolorCount));
 | |
|   for (unsigned i = 0; i < gx.m_kcolorCount; ++i) {
 | |
|     konstColors.emplace_back(gx.m_kcolors[i]);
 | |
|     XXH32_update(&xxHash, &gx.m_kcolors[i].num, sizeof(gx.m_kcolors[i].num));
 | |
|   }
 | |
| 
 | |
|   blendDstFac = BlendFactor(gx.m_blendDst);
 | |
|   XXH32_update(&xxHash, &gx.m_blendDst, sizeof(gx.m_blendDst));
 | |
|   blendSrcFac = BlendFactor(gx.m_blendSrc);
 | |
|   XXH32_update(&xxHash, &gx.m_blendSrc, sizeof(gx.m_blendSrc));
 | |
|   if (flags.samusReflectionIndirectTexture()) {
 | |
|     indTexSlot.push_back(textureIdxs.size());
 | |
|     XXH32_update(&xxHash, &indTexSlot.back(), sizeof(indTexSlot.back()));
 | |
|   }
 | |
| 
 | |
|   colorChannelCount = 1;
 | |
|   XXH32_update(&xxHash, &colorChannelCount, sizeof(colorChannelCount));
 | |
|   colorChannels.emplace_back();
 | |
|   ColorChannel& ch = colorChannels.back();
 | |
|   for (unsigned i = 0; i < gx.m_tevCount; ++i) {
 | |
|     const hecl::Backend::GX::TEVStage& stage = gx.m_tevs[i];
 | |
|     for (int c = 0; c < 4; ++c)
 | |
|       if (stage.m_color[c] == hecl::Backend::GX::CC_RASC || stage.m_color[c] == hecl::Backend::GX::CC_RASA ||
 | |
|           stage.m_alpha[c] == hecl::Backend::GX::CA_RASA) {
 | |
|         ch.setLighting(true);
 | |
|         uint8_t one = 1;
 | |
|         XXH32_update(&xxHash, &one, sizeof(one));
 | |
|         break;
 | |
|       }
 | |
|     if (ch.lighting())
 | |
|       break;
 | |
|   }
 | |
|   ch.setDiffuseFn(GX::DF_CLAMP);
 | |
|   ch.setAttenuationFn(GX::AF_SPOT);
 | |
| 
 | |
|   tevStageCount = gx.m_tevCount;
 | |
|   XXH32_update(&xxHash, &tevStageCount, sizeof(tevStageCount));
 | |
|   tevStages.reserve(gx.m_tevCount);
 | |
|   for (unsigned i = 0; i < gx.m_tevCount; ++i) {
 | |
|     const hecl::Backend::GX::TEVStage& stage = gx.m_tevs[i];
 | |
|     tevStages.emplace_back();
 | |
|     TEVStage& target = tevStages.back();
 | |
| 
 | |
|     target.setColorInA(stage.m_color[0]);
 | |
|     target.setColorInB(stage.m_color[1]);
 | |
|     target.setColorInC(stage.m_color[2]);
 | |
|     target.setColorInD(stage.m_color[3]);
 | |
|     target.setAlphaInA(stage.m_alpha[0]);
 | |
|     target.setAlphaInB(stage.m_alpha[1]);
 | |
|     target.setAlphaInC(stage.m_alpha[2]);
 | |
|     target.setAlphaInD(stage.m_alpha[3]);
 | |
|     target.setColorOp(stage.m_cop);
 | |
|     target.setColorOpBias(GX::TB_ZERO);
 | |
|     target.setColorOpScale(GX::CS_SCALE_1);
 | |
|     target.setColorOpClamp(true);
 | |
|     target.setColorOpOutReg(stage.m_cRegOut);
 | |
|     target.setAlphaOp(stage.m_aop);
 | |
|     target.setAlphaOpBias(GX::TB_ZERO);
 | |
|     target.setAlphaOpScale(GX::CS_SCALE_1);
 | |
|     target.setAlphaOpClamp(true);
 | |
|     target.setAlphaOpOutReg(stage.m_aRegOut);
 | |
|     target.setKColorIn(stage.m_kColor);
 | |
|     target.setKAlphaIn(stage.m_kAlpha);
 | |
| 
 | |
|     target.setRASIn(GX::GX_COLOR_NULL);
 | |
|     for (int c = 0; c < 4; ++c)
 | |
|       if (stage.m_color[c] == hecl::Backend::GX::CC_RASC || stage.m_color[c] == hecl::Backend::GX::CC_RASA ||
 | |
|           stage.m_alpha[c] == hecl::Backend::GX::CA_RASA) {
 | |
|         target.setRASIn(GX::GX_COLOR0A0);
 | |
|         break;
 | |
|       }
 | |
| 
 | |
|     XXH32_update(&xxHash, &target.ciFlags, sizeof(target.ciFlags));
 | |
|     XXH32_update(&xxHash, &target.aiFlags, sizeof(target.aiFlags));
 | |
|     XXH32_update(&xxHash, &target.ccFlags, sizeof(target.ccFlags));
 | |
|     XXH32_update(&xxHash, &target.acFlags, sizeof(target.acFlags));
 | |
|     XXH32_update(&xxHash, &target.kaInput, sizeof(target.kaInput));
 | |
|     XXH32_update(&xxHash, &target.kcInput, sizeof(target.kcInput));
 | |
|     XXH32_update(&xxHash, &target.rascInput, sizeof(target.rascInput));
 | |
|   }
 | |
| 
 | |
|   tcgCount = gx.m_tcgCount;
 | |
|   XXH32_update(&xxHash, &tcgCount, sizeof(tcgCount));
 | |
|   for (unsigned i = 0; i < gx.m_tcgCount; ++i) {
 | |
|     const hecl::Backend::GX::TexCoordGen& tcg = gx.m_tcgs[i];
 | |
|     tcgs.emplace_back();
 | |
|     TexCoordGen& target = tcgs.back();
 | |
|     target.setType(GX::TG_MTX3x4);
 | |
|     target.setSource(tcg.m_src);
 | |
|     target.setMtx(tcg.m_mtx);
 | |
|     target.setNormalize(tcg.m_norm);
 | |
|     target.setPostMtx(tcg.m_pmtx);
 | |
| 
 | |
|     XXH32_update(&xxHash, &target.flags, sizeof(target.flags));
 | |
|   }
 | |
| 
 | |
|   uvAnimsSize = 4;
 | |
|   uvAnimsCount = 0;
 | |
|   for (; uvAnimsCount < 8;) {
 | |
|     bool found = false;
 | |
|     for (unsigned t = 0; t < gx.m_tcgCount; ++t) {
 | |
|       const hecl::Backend::GX::TexCoordGen& tcg = gx.m_tcgs[t];
 | |
|       if (tcg.m_mtx == GX::IDENTITY)
 | |
|         continue;
 | |
|       if ((tcg.m_mtx - GX::TEXMTX0) / 3 == uvAnimsCount) {
 | |
|         found = true;
 | |
|         ++uvAnimsCount;
 | |
|         uvAnims.emplace_back(tcg.m_gameFunction, tcg.m_gameArgs);
 | |
|         XXH32_update(&xxHash, tcg.m_gameFunction.data(), sizeof(tcg.m_gameFunction.size()));
 | |
|         for (const atVec4f& arg : tcg.m_gameArgs)
 | |
|           XXH32_update(&xxHash, &arg, sizeof(arg));
 | |
|         size_t tmpUvAnimsSize = uvAnimsSize;
 | |
|         uvAnims.back().binarySize(tmpUvAnimsSize);
 | |
|         uvAnimsSize = tmpUvAnimsSize;
 | |
|         break;
 | |
|       }
 | |
|     }
 | |
|     if (!found)
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   XXH32_update(&xxHash, &uvAnimsSize, sizeof(uvAnimsSize));
 | |
|   XXH32_update(&xxHash, &uvAnimsCount, sizeof(uvAnimsCount));
 | |
| #endif
 | |
| 
 | |
|   uniqueIdx = XXH32_digest(&xxHash);
 | |
| }
 | |
| 
 | |
| HMDLMaterialSet::Material::Material(const hecl::blender::Material& mat) {
 | |
|   auto search = mat.iprops.find("retro_depth_sort");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setDepthSorting(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_alpha_test");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setAlphaTest(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_samus_reflection");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setSamusReflection(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_depth_write");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setDepthWrite(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_samus_reflection_persp");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setSamusReflectionSurfaceEye(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_shadow_occluder");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setShadowOccluderMesh(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_samus_reflection_indirect");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setSamusReflectionIndirectTexture(search->second != 0);
 | |
| 
 | |
|   search = mat.iprops.find("retro_lightmapped");
 | |
|   if (search != mat.iprops.end())
 | |
|     flags.setLightmap(search->second != 0);
 | |
| 
 | |
|   XXH64_state_t xxh;
 | |
|   XXH64_reset(&xxh, 0);
 | |
|   shaderType = mat.shaderType;
 | |
|   XXH64_update(&xxh, &shaderType, sizeof(shaderType));
 | |
|   chunkCount = 0;
 | |
|   chunks.reserve(mat.chunks.size());
 | |
|   for (const auto& chunk : mat.chunks) {
 | |
|     chunk.visit([this, &xxh](const auto& var) {
 | |
|       using T = std::decay_t<decltype(var)>;
 | |
|       chunks.push_back(Chunk::Build(T::variant_type(), var));
 | |
|       var.hash(&xxh);
 | |
|       ++chunkCount;
 | |
|     });
 | |
|   }
 | |
|   blendMode = mat.blendMode;
 | |
|   XXH64_update(&xxh, &blendMode, sizeof(blendMode));
 | |
|   int hashFlags = 0;
 | |
|   if (flags.samusReflection())
 | |
|     hashFlags |= 1;
 | |
|   if (flags.samusReflectionIndirectTexture())
 | |
|     hashFlags |= 2;
 | |
|   if (flags.depthWrite())
 | |
|     hashFlags |= 4;
 | |
|   if (flags.alphaTest())
 | |
|     hashFlags |= 8;
 | |
|   XXH64_update(&xxh, &hashFlags, sizeof(hashFlags));
 | |
|   hash = XXH64_digest(&xxh);
 | |
| }
 | |
| 
 | |
| MaterialSet::Material::UVAnimation::UVAnimation(const std::string& gameFunction, const std::vector<atVec4f>& gameArgs) {
 | |
|   if (gameFunction == "RetroUVMode0NodeN")
 | |
|     mode = Mode::MvInvNoTranslation;
 | |
|   else if (gameFunction == "RetroUVMode1NodeN")
 | |
|     mode = Mode::MvInv;
 | |
|   else if (gameFunction == "RetroUVMode2Node") {
 | |
|     mode = Mode::Scroll;
 | |
|     if (gameArgs.size() < 2)
 | |
|       Log.report(logvisor::Fatal, FMT_STRING("Mode2 UV anim requires 2 vector arguments"));
 | |
|     vals[0] = gameArgs[0].simd[0];
 | |
|     vals[1] = gameArgs[0].simd[1];
 | |
|     vals[2] = gameArgs[1].simd[0];
 | |
|     vals[3] = gameArgs[1].simd[1];
 | |
|   } else if (gameFunction == "RetroUVMode3Node") {
 | |
|     mode = Mode::Rotation;
 | |
|     if (gameArgs.size() < 2)
 | |
|       Log.report(logvisor::Fatal, FMT_STRING("Mode3 UV anim requires 2 arguments"));
 | |
|     vals[0] = gameArgs[0].simd[0];
 | |
|     vals[1] = gameArgs[1].simd[0];
 | |
|   } else if (gameFunction == "RetroUVMode4Node") {
 | |
|     mode = Mode::HStrip;
 | |
|     if (gameArgs.size() < 4)
 | |
|       Log.report(logvisor::Fatal, FMT_STRING("Mode4 UV anim requires 4 arguments"));
 | |
|     vals[0] = gameArgs[0].simd[0];
 | |
|     vals[1] = gameArgs[1].simd[0];
 | |
|     vals[2] = gameArgs[2].simd[0];
 | |
|     vals[3] = gameArgs[3].simd[0];
 | |
|   } else if (gameFunction == "RetroUVMode5Node") {
 | |
|     mode = Mode::VStrip;
 | |
|     if (gameArgs.size() < 4)
 | |
|       Log.report(logvisor::Fatal, FMT_STRING("Mode5 UV anim requires 4 arguments"));
 | |
|     vals[0] = gameArgs[0].simd[0];
 | |
|     vals[1] = gameArgs[1].simd[0];
 | |
|     vals[2] = gameArgs[2].simd[0];
 | |
|     vals[3] = gameArgs[3].simd[0];
 | |
|   } else if (gameFunction == "RetroUVMode6NodeN")
 | |
|     mode = Mode::Model;
 | |
|   else if (gameFunction == "RetroUVMode7NodeN") {
 | |
|     mode = Mode::CylinderEnvironment;
 | |
|     if (gameArgs.size() < 2)
 | |
|       Log.report(logvisor::Fatal, FMT_STRING("Mode7 UV anim requires 2 arguments"));
 | |
|     vals[0] = gameArgs[0].simd[0];
 | |
|     vals[1] = gameArgs[1].simd[0];
 | |
|   } else
 | |
|     Log.report(logvisor::Fatal, FMT_STRING("unsupported UV anim '{}'"), gameFunction);
 | |
| }
 | |
| 
 | |
| template <class Op>
 | |
| void MaterialSet::Material::UVAnimation::Enumerate(typename Op::StreamT& s) {
 | |
|   Do<Op>({}, mode, s);
 | |
|   switch (mode) {
 | |
|   case Mode::MvInvNoTranslation:
 | |
|   case Mode::MvInv:
 | |
|   case Mode::Model:
 | |
|     break;
 | |
|   case Mode::Scroll:
 | |
|   case Mode::HStrip:
 | |
|   case Mode::VStrip:
 | |
|     for (int i = 0; i < 4; ++i)
 | |
|       Do<Op>({}, vals[i], s);
 | |
|     break;
 | |
|   case Mode::Rotation:
 | |
|   case Mode::CylinderEnvironment:
 | |
|     for (int i = 0; i < 2; ++i)
 | |
|       Do<Op>({}, vals[i], s);
 | |
|     break;
 | |
|   case Mode::Eight:
 | |
|     for (int i = 0; i < 9; ++i)
 | |
|       Do<Op>({}, vals[i], s);
 | |
|     break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| AT_SPECIALIZE_DNA(MaterialSet::Material::UVAnimation)
 | |
| 
 | |
| template <class Op>
 | |
| void HMDLMaterialSet::Material::PASS::Enumerate(typename Op::StreamT& s) {
 | |
|   Do<Op>(athena::io::PropId{"type"}, type, s);
 | |
|   Do<Op>(athena::io::PropId{"texId"}, texId, s);
 | |
|   Do<Op>(athena::io::PropId{"source"}, source, s);
 | |
|   Do<Op>(athena::io::PropId{"uvAnimType"}, uvAnimType, s);
 | |
|   size_t uvParmCount = uvAnimParamsCount();
 | |
|   for (size_t i = 0; i < uvParmCount; ++i)
 | |
|     Do<Op>({}, uvAnimParms[i], s);
 | |
|   Do<Op>(athena::io::PropId{"alpha"}, alpha, s);
 | |
| }
 | |
| 
 | |
| AT_SPECIALIZE_DNA(HMDLMaterialSet::Material::PASS)
 | |
| 
 | |
| std::string_view HMDLMaterialSet::Material::PASS::DNAType() {
 | |
|   return "DataSpec::DNAMP1::HMDLMaterialSet::Material::PASS"sv;
 | |
| }
 | |
| 
 | |
| } // namespace DataSpec::DNAMP1
 | |
| 
 | |
| namespace DataSpec::DNAMP2 {
 | |
| 
 | |
| void MaterialSet::ConstructMaterial(Stream& out, const MaterialSet::Material& material, unsigned groupIdx,
 | |
|                                     unsigned matIdx) {
 | |
|   DataSpec::DNAMP1::_ConstructMaterial(out, material, groupIdx, matIdx);
 | |
| }
 | |
| 
 | |
| } // namespace DataSpec::DNAMP2
 |