inline bool CreateDeclFromFVF()

in Utilities/FlexibleVertexFormat.h [203:354]


    inline bool CreateDeclFromFVF(uint32_t fvfCode, std::vector<D3DVERTEXELEMENT9>& decl)
    {
        static constexpr size_t s_texCoordSizes[] =
        {
            2 * sizeof(float),
            3 * sizeof(float),
            4 * sizeof(float),
            sizeof(float)
        };

        decl.clear();

        if ((fvfCode & ((D3DFVF_RESERVED0 | D3DFVF_RESERVED2) & ~D3DFVF_POSITION_MASK)) != 0)
            return false;

        uint32_t nTexCoords = (fvfCode & D3DFVF_TEXCOUNT_MASK) >> D3DFVF_TEXCOUNT_SHIFT;
        if (nTexCoords > 8)
            return false;

        size_t offset = 0;

        switch (fvfCode & D3DFVF_POSITION_MASK)
        {
        case 0:
            break;

        case D3DFVF_XYZRHW:
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITIONT, 0 }
            );
            offset = sizeof(float) * 4;
            break;

        case D3DFVF_XYZW:
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, 0, D3DDECLTYPE_FLOAT4, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }
            );
            offset = sizeof(float) * 4;
            break;

        default:
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, 0, D3DDECLTYPE_FLOAT3, D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_POSITION, 0 }
            );
            offset = sizeof(float) * 3;
            break;
        }

        size_t weights = 0;
        switch (fvfCode & D3DFVF_POSITION_MASK)
        {
        case D3DFVF_XYZB1: weights = 1; break;
        case D3DFVF_XYZB2: weights = 2; break;
        case D3DFVF_XYZB3: weights = 3; break;
        case D3DFVF_XYZB4: weights = 4; break;
        case D3DFVF_XYZB5: weights = 5; break;
        }

        if (weights > 0)
        {
            if (fvfCode & (D3DFVF_LASTBETA_UBYTE4 | D3DFVF_LASTBETA_D3DCOLOR))
            {
                // subtract one to convert to D3DDECLTYPE_FLOAT* and another for where the indices were
                if (weights > 1)
                {
                    decl.emplace_back(
                        D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset), static_cast<BYTE>(weights - 2),
                            D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }
                    );
                    offset += sizeof(float) * (weights - 1);
                }

                decl.emplace_back(
                    D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset),
                        static_cast<BYTE>((fvfCode & D3DFVF_LASTBETA_UBYTE4) ? D3DDECLTYPE_UBYTE4 : D3DDECLTYPE_D3DCOLOR),
                        D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDINDICES, 0 }
                );
                offset += sizeof(uint32_t);
            }
            else if (weights == 5)
            {
                // D3DFVF_XYZB5 is only supported when the 5th beta is D3DFVF_LASTBETA_UBYTE4/D3DCOLOR
                decl.clear();
                return false;
            }
            else
            {
                // subtract one to convert to D3DDECLTYPE_FLOAT*
                decl.emplace_back(
                    D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset), static_cast<BYTE>(weights - 1),
                        D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_BLENDWEIGHT, 0 }
                );
                offset += sizeof(float) * (weights - 1);
            }
        }

        if (fvfCode & D3DFVF_NORMAL)
        {
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset), D3DDECLTYPE_FLOAT3,
                    D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_NORMAL, 0 }
            );
            offset += sizeof(float) * 3;
        }

        if (fvfCode & D3DFVF_PSIZE)
        {
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset), D3DDECLTYPE_FLOAT1,
                    D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_PSIZE, 0 }
            );
            offset += sizeof(float);
        }

        if (fvfCode & D3DFVF_DIFFUSE)
        {
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset), D3DDECLTYPE_D3DCOLOR,
                    D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 0 }
            );
            offset += sizeof(uint32_t);
        }

        if (fvfCode & D3DFVF_SPECULAR)
        {
            decl.emplace_back(
                D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset), D3DDECLTYPE_D3DCOLOR,
                    D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_COLOR, 1 }
            );
            offset += sizeof(uint32_t);
        }

        if (nTexCoords > 0)
        {
            for (uint32_t t = 0; t < nTexCoords; ++t)
            {
                size_t texCoordSize = s_texCoordSizes[(fvfCode >> (16 + t * 2)) & 0x3];

                // D3DDECLTYPE_FLOAT1 = 0, D3DDECLTYPE_FLOAT4 = 3
                decl.emplace_back(
                    D3DVERTEXELEMENT9{ 0, static_cast<WORD>(offset),
                        static_cast<BYTE>(texCoordSize / sizeof(float) - 1),
                        D3DDECLMETHOD_DEFAULT, D3DDECLUSAGE_TEXCOORD, static_cast<BYTE>(t) }
                );
                offset += texCoordSize;
            }
        }

        decl.emplace_back(D3DVERTEXELEMENT9{ 0xFF, 0, D3DDECLTYPE_UNUSED, 0, 0, 0 });

        return true;
    }