#ifndef HECLBACKEND_GX_HPP #define HECLBACKEND_GX_HPP #include "Backend.hpp" #include #include #include #include namespace HECL { namespace Backend { struct GX : IBackend { enum AttrType { NONE, DIRECT, INDEX8, INDEX16 }; enum TevOp { TEV_ADD = 0, TEV_SUB = 1, TEV_COMP_R8_GT = 8, TEV_COMP_R8_EQ = 9, TEV_COMP_GR16_GT = 10, TEV_COMP_GR16_EQ = 11, TEV_COMP_BGR24_GT = 12, TEV_COMP_BGR24_EQ = 13, TEV_COMP_RGB8_GT = 14, TEV_COMP_RGB8_EQ = 15, TEV_COMP_A8_GT = TEV_COMP_RGB8_GT, // for alpha channel TEV_COMP_A8_EQ = TEV_COMP_RGB8_EQ // for alpha channel }; enum TevBias { TB_ZERO = 0, TB_ADDHALF = 1, TB_SUBHALF = 2, }; enum TevScale { CS_SCALE_1 = 0, CS_SCALE_2 = 1, CS_SCALE_4 = 2, CS_DIVIDE_2 = 3 }; enum TexGenType { TG_MTX3x4 = 0, TG_MTX2x4, TG_BUMP0, TG_BUMP1, TG_BUMP2, TG_BUMP3, TG_BUMP4, TG_BUMP5, TG_BUMP6, TG_BUMP7, TG_SRTG }; enum TevRegID { TEVPREV = 0, TEVREG0 = 1, TEVREG1 = 2, TEVREG2 = 3, TEVLAZY = 5 }; enum TevColorArg { CC_CPREV = 0, /*!< Use the color value from previous TEV stage */ CC_APREV = 1, /*!< Use the alpha value from previous TEV stage */ CC_C0 = 2, /*!< Use the color value from the color/output register 0 */ CC_A0 = 3, /*!< Use the alpha value from the color/output register 0 */ CC_C1 = 4, /*!< Use the color value from the color/output register 1 */ CC_A1 = 5, /*!< Use the alpha value from the color/output register 1 */ CC_C2 = 6, /*!< Use the color value from the color/output register 2 */ CC_A2 = 7, /*!< Use the alpha value from the color/output register 2 */ CC_TEXC = 8, /*!< Use the color value from texture */ CC_TEXA = 9, /*!< Use the alpha value from texture */ CC_RASC = 10, /*!< Use the color value from rasterizer */ CC_RASA = 11, /*!< Use the alpha value from rasterizer */ CC_ONE = 12, CC_HALF = 13, CC_KONST = 14, CC_ZERO = 15, /*!< Use to pass zero value */ /* Non-GX */ CC_LAZY /*!< Lazy register allocation */ }; enum TevAlphaArg { CA_APREV = 0, /*!< Use the alpha value from previous TEV stage */ CA_A0 = 1, /*!< Use the alpha value from the color/output register 0 */ CA_A1 = 2, /*!< Use the alpha value from the color/output register 1 */ CA_A2 = 3, /*!< Use the alpha value from the color/output register 2 */ CA_TEXA = 4, /*!< Use the alpha value from texture */ CA_RASA = 5, /*!< Use the alpha value from rasterizer */ CA_KONST = 6, CA_ZERO = 7, /*!< Use to pass zero value */ /* Non-GX */ CA_LAZY /*!< Lazy register allocation */ }; enum TevKColorSel { TEV_KCSEL_8_8 = 0x00, TEV_KCSEL_7_8 = 0x01, TEV_KCSEL_6_8 = 0x02, TEV_KCSEL_5_8 = 0x03, TEV_KCSEL_4_8 = 0x04, TEV_KCSEL_3_8 = 0x05, TEV_KCSEL_2_8 = 0x06, TEV_KCSEL_1_8 = 0x07, TEV_KCSEL_1 = TEV_KCSEL_8_8, TEV_KCSEL_3_4 = TEV_KCSEL_6_8, TEV_KCSEL_1_2 = TEV_KCSEL_4_8, TEV_KCSEL_1_4 = TEV_KCSEL_2_8, TEV_KCSEL_K0 = 0x0C, TEV_KCSEL_K1 = 0x0D, TEV_KCSEL_K2 = 0x0E, TEV_KCSEL_K3 = 0x0F, TEV_KCSEL_K0_R = 0x10, TEV_KCSEL_K1_R = 0x11, TEV_KCSEL_K2_R = 0x12, TEV_KCSEL_K3_R = 0x13, TEV_KCSEL_K0_G = 0x14, TEV_KCSEL_K1_G = 0x15, TEV_KCSEL_K2_G = 0x16, TEV_KCSEL_K3_G = 0x17, TEV_KCSEL_K0_B = 0x18, TEV_KCSEL_K1_B = 0x19, TEV_KCSEL_K2_B = 0x1A, TEV_KCSEL_K3_B = 0x1B, TEV_KCSEL_K0_A = 0x1C, TEV_KCSEL_K1_A = 0x1D, TEV_KCSEL_K2_A = 0x1E, TEV_KCSEL_K3_A = 0x1F }; enum TevKAlphaSel { TEV_KASEL_8_8 = 0x00, TEV_KASEL_7_8 = 0x01, TEV_KASEL_6_8 = 0x02, TEV_KASEL_5_8 = 0x03, TEV_KASEL_4_8 = 0x04, TEV_KASEL_3_8 = 0x05, TEV_KASEL_2_8 = 0x06, TEV_KASEL_1_8 = 0x07, TEV_KASEL_1 = TEV_KASEL_8_8, TEV_KASEL_3_4 = TEV_KASEL_6_8, TEV_KASEL_1_2 = TEV_KASEL_4_8, TEV_KASEL_1_4 = TEV_KASEL_2_8, TEV_KASEL_K0_R = 0x10, TEV_KASEL_K1_R = 0x11, TEV_KASEL_K2_R = 0x12, TEV_KASEL_K3_R = 0x13, TEV_KASEL_K0_G = 0x14, TEV_KASEL_K1_G = 0x15, TEV_KASEL_K2_G = 0x16, TEV_KASEL_K3_G = 0x17, TEV_KASEL_K0_B = 0x18, TEV_KASEL_K1_B = 0x19, TEV_KASEL_K2_B = 0x1A, TEV_KASEL_K3_B = 0x1B, TEV_KASEL_K0_A = 0x1C, TEV_KASEL_K1_A = 0x1D, TEV_KASEL_K2_A = 0x1E, TEV_KASEL_K3_A = 0x1F }; enum TexGenSrc { TG_POS = 0, TG_NRM, TG_BINRM, TG_TANGENT, TG_TEX0, TG_TEX1, TG_TEX2, TG_TEX3, TG_TEX4, TG_TEX5, TG_TEX6, TG_TEX7, TG_TEXCOORD0, TG_TEXCOORD1, TG_TEXCOORD2, TG_TEXCOORD3, TG_TEXCOORD4, TG_TEXCOORD5, TG_TEXCOORD6, TG_COLOR0, TG_COLOR1 }; enum TexMtx { TEXMTX0 = 30, TEXMTX1 = 33, TEXMTX2 = 36, TEXMTX3 = 39, TEXMTX4 = 42, TEXMTX5 = 45, TEXMTX6 = 48, TEXMTX7 = 51, TEXMTX8 = 54, TEXMTX9 = 57, IDENTITY = 60 }; enum PTTexMtx { PTTEXMTX0 = 64, PTTEXMTX1 = 67, PTTEXMTX2 = 70, PTTEXMTX3 = 73, PTTEXMTX4 = 76, PTTEXMTX5 = 79, PTTEXMTX6 = 82, PTTEXMTX7 = 85, PTTEXMTX8 = 88, PTTEXMTX9 = 91, PTTEXMTX10 = 94, PTTEXMTX11 = 97, PTTEXMTX12 = 100, PTTEXMTX13 = 103, PTTEXMTX14 = 106, PTTEXMTX15 = 109, PTTEXMTX16 = 112, PTTEXMTX17 = 115, PTTEXMTX18 = 118, PTTEXMTX19 = 121, PTIDENTITY = 125 }; enum DiffuseFn { DF_NONE = 0, DF_SIGN, DF_CLAMP }; enum AttnFn { AF_SPEC = 0, AF_SPOT = 1, AF_NONE }; enum Primitive { POINTS = 0xb8, LINES = 0xa8, LINESTRIP = 0xb0, TRIANGLES = 0x90, TRIANGLESTRIP = 0x98, TRIANGLEFAN = 0xa0, QUADS = 0x80 }; struct TexCoordGen { TexGenSrc m_src = TG_TEX0; TexMtx m_mtx = IDENTITY; /* Not actually part of GX, but a way to relate out-of-band * texmtx animation parameters */ std::string m_gameFunction; std::vector m_gameArgs; }; unsigned m_tcgCount = 0; TexCoordGen m_tcgs[8]; unsigned m_texMtxCount = 0; TexCoordGen* m_texMtxRefs[8]; struct TEVStage { TevOp m_cop = TEV_ADD; TevOp m_aop = TEV_ADD; TevColorArg m_color[4] = {CC_ZERO, CC_ZERO, CC_ZERO, CC_ZERO}; TevAlphaArg m_alpha[4] = {CA_ZERO, CA_ZERO, CA_ZERO, CA_ZERO}; TevKColorSel m_kColor = TEV_KCSEL_1; TevKAlphaSel m_kAlpha = TEV_KASEL_1; TevRegID m_cRegOut = TEVPREV; TevRegID m_aRegOut = TEVPREV; int m_lazyCInIdx = -1; int m_lazyAInIdx = -1; int m_lazyCOutIdx = -1; int m_lazyAOutIdx = -1; int m_texMapIdx = -1; int m_texGenIdx = -1; /* Convenience Links */ TEVStage* m_prev = nullptr; TEVStage* m_next = nullptr; /* Remember this for debugging */ SourceLocation m_loc; }; unsigned m_tevCount = 0; TEVStage m_tevs[16]; int getStageIdx(const TEVStage* stage) const { for (int i=0 ; i=0 ; --i) if (!(regMask & (1 << i))) return i; diag.reportBackendErr(loc, "TEV C Register overflow"); return -1; } int pickALazy(Diagnostics& diag, const SourceLocation& loc, int stageIdx) const { int regMask = m_aRegMask; for (int i=stageIdx+1 ; i=0 ; --i) if (!(regMask & (1 << i))) return i; diag.reportBackendErr(loc, "TEV A Register overflow"); return -1; } enum BlendFactor : uint16_t { BL_ZERO, BL_ONE, BL_SRCCLR, BL_INVSRCCLR, BL_SRCALPHA, BL_INVSRCALPHA, BL_DSTALPHA, BL_INVDSTALPHA }; BlendFactor m_blendSrc; BlendFactor m_blendDst; struct Color : Athena::io::DNA { union { uint8_t color[4]; uint32_t num = 0; }; Color() = default; Color& operator=(const atVec4f& vec) { color[0] = uint8_t(std::min(std::max(vec.vec[0] * 255.f, 0.f), 255.f)); color[1] = uint8_t(std::min(std::max(vec.vec[1] * 255.f, 0.f), 255.f)); color[2] = uint8_t(std::min(std::max(vec.vec[2] * 255.f, 0.f), 255.f)); color[3] = uint8_t(std::min(std::max(vec.vec[3] * 255.f, 0.f), 255.f)); return *this; } Color& operator=(const atVec3f& vec) { color[0] = uint8_t(std::min(std::max(vec.vec[0] * 255.f, 0.f), 255.f)); color[1] = uint8_t(std::min(std::max(vec.vec[1] * 255.f, 0.f), 255.f)); color[2] = uint8_t(std::min(std::max(vec.vec[2] * 255.f, 0.f), 255.f)); color[3] = 0xff; return *this; } Color& operator=(uint8_t val) { color[0] = val; color[1] = val; color[2] = val; color[3] = val; return *this; } Color(const atVec4f& vec) {*this = vec;} Color(const atVec3f& vec) {*this = vec;} Color(uint8_t val) {*this = val;} bool operator==(const Color& other) const {return num == other.num;} bool operator!=(const Color& other) const {return num != other.num;} uint8_t operator[](size_t idx) const {return color[idx];} uint8_t& operator[](size_t idx) {return color[idx];} void read(Athena::io::IStreamReader& reader) {reader.readUBytesToBuf(&num, 4);} void write(Athena::io::IStreamWriter& writer) const {writer.writeUBytes(reinterpret_cast(&num), 4);} size_t binarySize(size_t __isz) const {return __isz + 4;} }; unsigned m_kcolorCount = 0; Color m_kcolors[4]; int m_alphaTraceStage = -1; bool operator==(const GX& other) const { if (m_tcgCount != other.m_tcgCount) return false; if (m_tevCount != other.m_tevCount) return false; if (m_blendSrc != other.m_blendSrc) return false; if (m_blendDst != other.m_blendDst) return false; if (m_kcolorCount != other.m_kcolorCount) return false; for (unsigned i=0 ; i