#ifndef _DNAMP1_CMDL_MATERIALS_HPP_ #define _DNAMP1_CMDL_MATERIALS_HPP_ #include #include "../DNACommon/DNACommon.hpp" #include "../DNACommon/GX.hpp" #include "../DNACommon/CMDL.hpp" #include "DNAMP1.hpp" namespace Retro { namespace DNAMP1 { struct MaterialSet : BigDNA { static constexpr bool OneSection() {return false;} DECL_DNA struct MaterialSetHead : BigDNA { DECL_DNA Value textureCount = 0; Vector textureIDs; Value materialCount = 0; Vector materialEndOffs; void addTexture(const UniqueID32& id) {textureIDs.push_back(id); ++textureCount;} void addMaterialEndOff(atUint32 off) {materialEndOffs.push_back(off); ++materialCount;} } head; struct Material : BigDNA { DECL_DNA struct Flags : BigDNA { DECL_DNA Value flags = 0; bool konstValuesEnabled() const {return (flags & 0x8) != 0;} void setKonstValuesEnabled(bool enabled) {flags &= ~0x8; flags |= atUint32(enabled) << 3;} bool depthSorting() const {return (flags & 0x10) != 0;} void setDepthSorting(bool enabled) {flags &= ~0x10; flags |= atUint32(enabled) << 4;} bool punchthroughAlpha() const {return (flags & 0x20) != 0;} void setPunchthroughAlpha(bool enabled) {flags &= ~0x20; flags |= atUint32(enabled) << 5;} bool samusReflection() const {return (flags & 0x40) != 0;} void setSamusReflection(bool enabled) {flags &= ~0x40; flags |= atUint32(enabled) << 6;} bool depthWrite() const {return (flags & 0x80) != 0;} void setDepthWrite(bool enabled) {flags &= ~0x80; flags |= atUint32(enabled) << 7;} bool samusReflectionSurfaceEye() const {return (flags & 0x100) != 0;} void setSamusReflectionSurfaceEye(bool enabled) {flags &= ~0x100; flags |= atUint32(enabled) << 8;} bool shadowOccluderMesh() const {return (flags & 0x200) != 0;} void setShadowOccluderMesh(bool enabled) {flags &= ~0x200; flags |= atUint32(enabled) << 9;} bool samusReflectionIndirectTexture() const {return (flags & 0x400) != 0;} void setSamusReflectionIndirectTexture(bool enabled) {flags &= ~0x400; flags |= atUint32(enabled) << 10;} bool lightmap() const {return (flags & 0x800) != 0;} void setLightmap(bool enabled) {flags &= ~0x800; flags |= atUint32(enabled) << 11;} bool lightmapUVArray() const {return (flags & 0x2000) != 0;} void setLightmapUVArray(bool enabled) {flags &= ~0x2000; flags |= atUint32(enabled) << 13;} atUint16 textureSlots() const {return (flags >> 16) != 0;} void setTextureSlots(atUint16 texslots) {flags &= ~0xffff0000; flags |= atUint32(texslots) << 16;} } flags; const Flags& getFlags() const {return flags;} Value textureCount = 0; Vector textureIdxs; struct VAFlags : BigDNA { DECL_DNA Value vaFlags = 0; GX::AttrType position() const {return GX::AttrType(vaFlags & 0x3);} void setPosition(GX::AttrType val) {vaFlags &= ~0x3; vaFlags |= atUint32(val);} GX::AttrType normal() const {return GX::AttrType(vaFlags >> 2 & 0x3);} void setNormal(GX::AttrType val) {vaFlags &= ~0xC; vaFlags |= atUint32(val) << 2;} GX::AttrType color0() const {return GX::AttrType(vaFlags >> 4 & 0x3);} void setColor0(GX::AttrType val) {vaFlags &= ~0x30; vaFlags |= atUint32(val) << 4;} GX::AttrType color1() const {return GX::AttrType(vaFlags >> 6 & 0x3);} void setColor1(GX::AttrType val) {vaFlags &= ~0xC0; vaFlags |= atUint32(val) << 6;} GX::AttrType tex0() const {return GX::AttrType(vaFlags >> 8 & 0x3);} void setTex0(GX::AttrType val) {vaFlags &= ~0x300; vaFlags |= atUint32(val) << 8;} GX::AttrType tex1() const {return GX::AttrType(vaFlags >> 10 & 0x3);} void setTex1(GX::AttrType val) {vaFlags &= ~0xC00; vaFlags |= atUint32(val) << 10;} GX::AttrType tex2() const {return GX::AttrType(vaFlags >> 12 & 0x3);} void setTex2(GX::AttrType val) {vaFlags &= ~0x3000; vaFlags |= atUint32(val) << 12;} GX::AttrType tex3() const {return GX::AttrType(vaFlags >> 14 & 0x3);} void setTex3(GX::AttrType val) {vaFlags &= ~0xC000; vaFlags |= atUint32(val) << 14;} GX::AttrType tex4() const {return GX::AttrType(vaFlags >> 16 & 0x3);} void setTex4(GX::AttrType val) {vaFlags &= ~0x30000; vaFlags |= atUint32(val) << 16;} GX::AttrType tex5() const {return GX::AttrType(vaFlags >> 18 & 0x3);} void setTex5(GX::AttrType val) {vaFlags &= ~0xC0000; vaFlags |= atUint32(val) << 18;} GX::AttrType tex6() const {return GX::AttrType(vaFlags >> 20 & 0x3);} void setTex6(GX::AttrType val) {vaFlags &= ~0x300000; vaFlags |= atUint32(val) << 20;} GX::AttrType pnMatIdx() const {return GX::AttrType(vaFlags >> 24 & 0x1);} void setPnMatIdx(GX::AttrType val) {vaFlags &= ~0x1000000; vaFlags |= atUint32(val & 0x1) << 24;} GX::AttrType tex0MatIdx() const {return GX::AttrType(vaFlags >> 25 & 0x1);} void setTex0MatIdx(GX::AttrType val) {vaFlags &= ~0x2000000; vaFlags |= atUint32(val & 0x1) << 25;} GX::AttrType tex1MatIdx() const {return GX::AttrType(vaFlags >> 26 & 0x1);} void setTex1MatIdx(GX::AttrType val) {vaFlags &= ~0x4000000; vaFlags |= atUint32(val & 0x1) << 26;} GX::AttrType tex2MatIdx() const {return GX::AttrType(vaFlags >> 27 & 0x1);} void setTex2MatIdx(GX::AttrType val) {vaFlags &= ~0x8000000; vaFlags |= atUint32(val & 0x1) << 27;} GX::AttrType tex3MatIdx() const {return GX::AttrType(vaFlags >> 28 & 0x1);} void setTex3MatIdx(GX::AttrType val) {vaFlags &= ~0x10000000; vaFlags |= atUint32(val & 0x1) << 28;} GX::AttrType tex4MatIdx() const {return GX::AttrType(vaFlags >> 29 & 0x1);} void setTex4MatIdx(GX::AttrType val) {vaFlags &= ~0x20000000; vaFlags |= atUint32(val & 0x1) << 29;} GX::AttrType tex5MatIdx() const {return GX::AttrType(vaFlags >> 30 & 0x1);} void setTex5MatIdx(GX::AttrType val) {vaFlags &= ~0x40000000; vaFlags |= atUint32(val & 0x1) << 30;} GX::AttrType tex6MatIdx() const {return GX::AttrType(vaFlags >> 31 & 0x1);} void setTex6MatIdx(GX::AttrType val) {vaFlags &= ~0x80000000; vaFlags |= atUint32(val & 0x1) << 31;} size_t vertDLSize() const { static size_t ATTR_SZ[] = {0,1,1,2}; size_t ret = 0; ret += ATTR_SZ[position()]; ret += ATTR_SZ[normal()]; ret += ATTR_SZ[color0()]; ret += ATTR_SZ[color1()]; ret += ATTR_SZ[tex0()]; ret += ATTR_SZ[tex1()]; ret += ATTR_SZ[tex2()]; ret += ATTR_SZ[tex3()]; ret += ATTR_SZ[tex4()]; ret += ATTR_SZ[tex5()]; ret += ATTR_SZ[tex6()]; ret += ATTR_SZ[pnMatIdx()]; ret += ATTR_SZ[tex0MatIdx()]; ret += ATTR_SZ[tex1MatIdx()]; ret += ATTR_SZ[tex2MatIdx()]; ret += ATTR_SZ[tex3MatIdx()]; ret += ATTR_SZ[tex4MatIdx()]; ret += ATTR_SZ[tex5MatIdx()]; ret += ATTR_SZ[tex6MatIdx()]; return ret; } } vaFlags; const VAFlags& getVAFlags() const {return vaFlags;} Value groupIdx; Vector konstCount; Vector konstColors; /** Slightly modified blend enums in Retro's implementation */ enum BlendFactor : atUint16 { GX_BL_ZERO, GX_BL_ONE, GX_BL_SRCCLR, GX_BL_INVSRCCLR, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_BL_DSTALPHA, GX_BL_INVDSTALPHA }; Value blendDstFac; Value blendSrcFac; Vector indTexSlot; Value colorChannelCount = 0; struct ColorChannel : BigDNA { DECL_DNA Value flags = 0; bool lighting() const {return (flags & 0x1) != 0;} void setLighting(bool enabled) {flags &= ~0x1; flags |= atUint32(enabled);} bool useAmbient() const {return (flags & 0x2) != 0;} void setUseAmbient(bool enabled) {flags &= ~0x2; flags |= atUint32(enabled) << 1;} bool useMaterial() const {return (flags & 0x4) != 0;} void setUseMaterial(bool enabled) {flags &= ~0x4; flags |= atUint32(enabled) << 2;} atUint8 lightmask() const {return atUint8(flags >> 3 & 0xff);} void setLightmask(atUint8 mask) {flags &= ~0x7f8; flags |= atUint32(mask) << 3;} GX::DiffuseFn diffuseFn() const {return GX::DiffuseFn(flags >> 11 & 0x3);} void setDiffuseFn(GX::DiffuseFn fn) {flags &= ~0x1800; flags |= atUint32(fn) << 11;} GX::AttnFn attenuationFn() const {return GX::AttnFn(flags >> 13 & 0x3);} void setAttenuationFn(GX::AttnFn fn) {flags &= ~0x6000; flags |= atUint32(fn) << 13;} }; Vector colorChannels; Value tevStageCount = 0; struct TEVStage : BigDNA { DECL_DNA Value ciFlags = 0; Value aiFlags = 0; Value ccFlags = 0; Value acFlags = 0; Value pad = 0; Value kaInput = 0; Value kcInput = 0; Value rascInput = 0; GX::TevColorArg colorInA() const {return GX::TevColorArg(ciFlags & 0xf);} void setColorInA(GX::TevColorArg val) {ciFlags &= ~0x1f; ciFlags |= atUint32(val);} GX::TevColorArg colorInB() const {return GX::TevColorArg(ciFlags >> 5 & 0xf);} void setColorInB(GX::TevColorArg val) {ciFlags &= ~0x3e0; ciFlags |= atUint32(val) << 5;} GX::TevColorArg colorInC() const {return GX::TevColorArg(ciFlags >> 10 & 0xf);} void setColorInC(GX::TevColorArg val) {ciFlags &= ~0x7c00; ciFlags |= atUint32(val) << 10;} GX::TevColorArg colorInD() const {return GX::TevColorArg(ciFlags >> 15 & 0xf);} void setColorInD(GX::TevColorArg val) {ciFlags &= ~0xf8000; ciFlags |= atUint32(val) << 15;} GX::TevAlphaArg alphaInA() const {return GX::TevAlphaArg(aiFlags & 0x7);} void setAlphaInA(GX::TevAlphaArg val) {aiFlags &= ~0x1f; aiFlags |= atUint32(val);} GX::TevAlphaArg alphaInB() const {return GX::TevAlphaArg(aiFlags >> 5 & 0x7);} void setAlphaInB(GX::TevAlphaArg val) {aiFlags &= ~0x3e0; aiFlags |= atUint32(val) << 5;} GX::TevAlphaArg alphaInC() const {return GX::TevAlphaArg(aiFlags >> 10 & 0x7);} void setAlphaInC(GX::TevAlphaArg val) {aiFlags &= ~0x7c00; aiFlags |= atUint32(val) << 10;} GX::TevAlphaArg alphaInD() const {return GX::TevAlphaArg(aiFlags >> 15 & 0x7);} void setAlphaInD(GX::TevAlphaArg val) {aiFlags &= ~0xf8000; aiFlags |= atUint32(val) << 15;} GX::TevOp colorOp() const {return GX::TevOp(ccFlags & 0xf);} void setColorOp(GX::TevOp val) {ccFlags &= ~0x1; ccFlags |= atUint32(val);} GX::TevBias colorOpBias() const {return GX::TevBias(ccFlags >> 4 & 0x3);} void setColorOpBias(GX::TevBias val) {ccFlags &= ~0x30; ccFlags |= atUint32(val) << 4;} GX::TevScale colorOpScale() const {return GX::TevScale(ccFlags >> 6 & 0x3);} void setColorOpScale(GX::TevScale val) {ccFlags &= ~0xc0; ccFlags |= atUint32(val) << 6;} bool colorOpClamp() const {return ccFlags >> 8 & 0x1;} void setColorOpClamp(bool val) {ccFlags &= ~0x100; ccFlags |= atUint32(val) << 8;} GX::TevRegID colorOpOutReg() const {return GX::TevRegID(ccFlags >> 9 & 0x3);} void setColorOpOutReg(GX::TevRegID val) {ccFlags &= ~0x600; ccFlags |= atUint32(val) << 9;} GX::TevOp alphaOp() const {return GX::TevOp(acFlags & 0xf);} void setAlphaOp(GX::TevOp val) {acFlags &= ~0x1; acFlags |= atUint32(val);} GX::TevBias alphaOpBias() const {return GX::TevBias(acFlags >> 4 & 0x3);} void setAlphaOpBias(GX::TevBias val) {acFlags &= ~0x30; acFlags |= atUint32(val) << 4;} GX::TevScale alphaOpScale() const {return GX::TevScale(acFlags >> 6 & 0x3);} void setAlphaOpScale(GX::TevScale val) {acFlags &= ~0xc0; acFlags |= atUint32(val) << 6;} bool alphaOpClamp() const {return acFlags >> 8 & 0x1;} void setAlphaOpClamp(bool val) {acFlags &= ~0x100; acFlags |= atUint32(val) << 8;} GX::TevRegID alphaOpOutReg() const {return GX::TevRegID(acFlags >> 9 & 0x3);} void setAlphaOpOutReg(GX::TevRegID val) {acFlags &= ~0x600; acFlags |= atUint32(val) << 9;} GX::TevKColorSel kColorIn() const {return GX::TevKColorSel(kcInput);} void setKColorIn(GX::TevKColorSel val) {kcInput = val;} GX::TevKAlphaSel kAlphaIn() const {return GX::TevKAlphaSel(kaInput);} void setKAlphaIn(GX::TevKAlphaSel val) {kaInput = val;} }; Vector tevStages; struct TEVStageTexInfo : BigDNA { DECL_DNA Value pad = 0; Value texSlot = 0xff; Value tcgSlot = 0xff; }; Vector tevStageTexInfo; Value tcgCount = 0; struct TexCoordGen : BigDNA { DECL_DNA Value flags = 0; GX::TexGenType type() const {return GX::TexGenType(flags & 0xf);} void setType(GX::TexGenType val) {flags &= ~0xf; flags |= atUint32(val);} GX::TexGenSrc source() const {return GX::TexGenSrc(flags >> 4 & 0x1f);} void setSource(GX::TexGenSrc val) {flags &= ~0x1f0; flags |= atUint32(val) << 4;} GX::TexMtx mtx() const {return GX::TexMtx((flags >> 9 & 0x1f) + 30);} void setMtx(GX::TexMtx val) {flags &= ~0x3e00; flags |= (atUint32(val)-30) << 9;} bool normalize() const {return flags >> 14 & 0x1;} void setNormalize(bool val) {flags &= ~0x4000; flags |= atUint32(val) << 14;} GX::PTTexMtx postMtx() const {return GX::PTTexMtx((flags >> 15 & 0x3f) + 64);} void setPostMtx(GX::PTTexMtx val) {flags &= ~0x1f8000; flags |= (atUint32(val)-64) << 15;} }; Vector tcgs; Value uvAnimsSize = 4; Value uvAnimsCount = 0; struct UVAnimation : BigDNA { Delete expl; enum Mode : atUint32 { ANIM_MV_INV_NOTRANS, ANIM_MV_INV, ANIM_SCROLL, ANIM_ROTATION, ANIM_HSTRIP, ANIM_VSTRIP, ANIM_MODEL, ANIM_MODE_WHO_MUST_NOT_BE_NAMED, ANIM_MODE_8 } mode; float vals[9]; void read(Athena::io::IStreamReader& reader) { mode = Mode(reader.readUint32Big()); switch (mode) { case ANIM_MV_INV_NOTRANS: case ANIM_MV_INV: case ANIM_MODEL: break; case ANIM_SCROLL: case ANIM_HSTRIP: case ANIM_VSTRIP: vals[0] = reader.readFloatBig(); vals[1] = reader.readFloatBig(); vals[2] = reader.readFloatBig(); vals[3] = reader.readFloatBig(); break; case ANIM_ROTATION: case ANIM_MODE_WHO_MUST_NOT_BE_NAMED: vals[0] = reader.readFloatBig(); vals[1] = reader.readFloatBig(); break; case ANIM_MODE_8: vals[0] = reader.readFloatBig(); vals[1] = reader.readFloatBig(); vals[2] = reader.readFloatBig(); vals[3] = reader.readFloatBig(); vals[4] = reader.readFloatBig(); vals[5] = reader.readFloatBig(); vals[6] = reader.readFloatBig(); vals[7] = reader.readFloatBig(); vals[8] = reader.readFloatBig(); break; } } void write(Athena::io::IStreamWriter& writer) const { writer.writeUint32Big(mode); switch (mode) { case ANIM_MV_INV_NOTRANS: case ANIM_MV_INV: case ANIM_MODEL: break; case ANIM_SCROLL: case ANIM_HSTRIP: case ANIM_VSTRIP: writer.writeFloatBig(vals[0]); writer.writeFloatBig(vals[1]); writer.writeFloatBig(vals[2]); writer.writeFloatBig(vals[3]); break; case ANIM_ROTATION: case ANIM_MODE_WHO_MUST_NOT_BE_NAMED: writer.writeFloatBig(vals[0]); writer.writeFloatBig(vals[1]); break; case ANIM_MODE_8: writer.writeFloatBig(vals[0]); writer.writeFloatBig(vals[1]); writer.writeFloatBig(vals[2]); writer.writeFloatBig(vals[3]); writer.writeFloatBig(vals[4]); writer.writeFloatBig(vals[5]); writer.writeFloatBig(vals[6]); writer.writeFloatBig(vals[7]); writer.writeFloatBig(vals[8]); break; } } size_t binarySize(size_t __isz) const { switch (mode) { case ANIM_MV_INV_NOTRANS: case ANIM_MV_INV: case ANIM_MODEL: return __isz + 4; case ANIM_SCROLL: case ANIM_HSTRIP: case ANIM_VSTRIP: return __isz + 20; case ANIM_ROTATION: case ANIM_MODE_WHO_MUST_NOT_BE_NAMED: return __isz + 12; case ANIM_MODE_8: return __isz + 40; } return __isz + 4; } UVAnimation() = default; UVAnimation(const std::string& gameFunction, const std::vector& gameArgs); }; Vector uvAnims; static void AddTexture(HECL::BlenderConnection::PyOutStream& out, GX::TexGenSrc type, int mtxIdx, uint32_t texIdx); static void AddTextureAnim(HECL::BlenderConnection::PyOutStream& out, MaterialSet::Material::UVAnimation::Mode type, unsigned idx, const float* vals); static void AddKcolor(HECL::BlenderConnection::PyOutStream& out, const GX::Color& col, unsigned idx); static void AddDynamicColor(HECL::BlenderConnection::PyOutStream& out, unsigned idx); static void AddDynamicAlpha(HECL::BlenderConnection::PyOutStream& out, unsigned idx); Material() = default; Material(const HECL::Backend::GX& gx, const std::unordered_map& iprops, const std::vector& texPathsIn, std::vector& texPathsOut, int colorCount, int uvCount, bool lightmapUVs, bool matrixSkinning, atUint32 grpIdx); }; Vector materials; static void RegisterMaterialProps(HECL::BlenderConnection::PyOutStream& out); static void ConstructMaterial(HECL::BlenderConnection::PyOutStream& out, const MaterialSet::Material& material, unsigned groupIdx, unsigned matIdx); void readToBlender(HECL::BlenderConnection::PyOutStream& os, const PAKRouter& pakRouter, const PAKRouter::EntryType& entry, unsigned setIdx) { DNACMDL::ReadMaterialSetToBlender_1_2(os, *this, pakRouter, entry, setIdx); } template void nameTextures(PAKRouter& pakRouter, const char* prefix, int setIdx) const { int matIdx = 0; for (const Material& mat : materials) { int stageIdx = 0; for (const Material::TEVStage& stage : mat.tevStages) { const Material::TEVStageTexInfo& texInfo = mat.tevStageTexInfo[stageIdx]; if (texInfo.texSlot == 0xff) { ++stageIdx; continue; } const NOD::Node* node; typename PAKRouter::EntryType* texEntry = (typename PAKRouter::EntryType*) pakRouter.lookupEntry(head.textureIDs[mat.textureIdxs[texInfo.texSlot]], &node); if (texEntry->name.size()) { if (texEntry->name.size() < 5 || texEntry->name.compare(0, 5, "mult_")) texEntry->name = "mult_" + texEntry->name; ++stageIdx; continue; } if (setIdx < 0) texEntry->name = HECL::Format("%s_%d_%d", prefix, matIdx, stageIdx); else texEntry->name = HECL::Format("%s_%d_%d_%d", prefix, setIdx, matIdx, stageIdx); if (mat.flags.lightmap() && stageIdx == 0) { texEntry->name += "light"; ++stageIdx; continue; } ++stageIdx; } ++matIdx; } } }; struct HMDLMaterialSet : BigDNA { static constexpr bool OneSection() {return false;} DECL_DNA MaterialSet::MaterialSetHead head; struct Material : BigDNA { DECL_DNA MaterialSet::Material::Flags flags; Value textureCount = 0; Vector textureIdxs; Vector indTexSlot; Value uvAnimsSize = 4; Value uvAnimsCount = 0; Vector uvAnims; String<-1> heclSource; HECL::Frontend::IR heclIr; Material() = default; Material(HECL::Frontend::Frontend& FE, const std::string& diagName, const HECL::BlenderConnection::DataStream::Mesh::Material& mat, const std::unordered_map& iprops, const std::vector& texPaths); }; Vector materials; }; } } #endif // _DNAMP1_CMDL_MATERIALS_HPP_