#pragma once
#include "linked_elements.hpp"
#include "primitive_support_types.hpp"

namespace JabyEngine {
    namespace GPU {
        namespace internal {
            struct PolyCode : public CodeBase<PolyCode> {
                static constexpr uint8_t CmdValue = 0b001;

                static constexpr auto GouraudShading  = Bit(28 - BitCorrection);
                static constexpr auto FlatShading     = !GouraudShading;
                static constexpr auto QuadVertics     = Bit(27 - BitCorrection);
                static constexpr auto TriVertics      = !QuadVertics;

                static constexpr PolyCode create() {
                    return CodeBase<PolyCode>::create(CmdValue);
                }
            };

            template<typename T>
            struct PolyCodeInterface {
                typedef ::JabyEngine::GPU::internal::PolyCode Code;

                constexpr T& set_semi_transparent(bool set = true) {
                    static_cast<T*>(this)->code.set_tenary(set, Code::SemiTransparent, Code::NonTransparent);
                    return *static_cast<T*>(this);
                }

                constexpr T& set_texture_blending(bool set = true) {
                    static_cast<T*>(this)->code.set_tenary(set, Code::BlendTexture, Code::NoBlendTexture);
                    return *static_cast<T*>(this);
                }
            };

            template<typename T>
            struct Poly3Interface {};

            template<typename T>
            struct Poly4Interface {
                static constexpr Vertex vertex0_from(const AreaI16& area) {
                    return area.get_top_left();
                }

                static constexpr Vertex vertex1_from(const AreaI16& area) {
                    return area.get_top_right();
                }

                static constexpr Vertex vertex2_from(const AreaI16& area) {
                    return area.get_bottom_left();
                }

                static constexpr Vertex vertex3_from(const AreaI16& area) {
                    return area.get_bottom_right();
                }

                constexpr T& set_rect_size(const SizeI16& size) {
                    static_cast<T*>(this)->vertex1 = static_cast<const T*>(this)->vertex0.add(size.width, 0);
                    static_cast<T*>(this)->vertex2 = static_cast<const T*>(this)->vertex0.add(0,          size.height);
                    static_cast<T*>(this)->vertex3 = static_cast<const T*>(this)->vertex0.add(size.width, size.height);

                    return *static_cast<T*>(this);
                }

                constexpr T& set_rect_size_fast(const SizeI16& size) {
                    static_cast<T*>(this)->vertex1.x = static_cast<const T*>(this)->vertex0.x + size.width;
                    static_cast<T*>(this)->vertex2.y = static_cast<const T*>(this)->vertex0.y + size.height;
                    static_cast<T*>(this)->vertex3   = static_cast<const T*>(this)->vertex0.add(size.width, size.height);
                    
                    return *static_cast<T*>(this);
                }

                constexpr PositionI16 get_rect_pos() const {
                    return PositionI16::create(
                        static_cast<const T*>(this)->vertex0.x,
                        static_cast<const T*>(this)->vertex0.y
                    );
                }

                constexpr SizeI16 get_rect_size() const {
                    return SizeI16::create(
                        static_cast<const T*>(this)->vertex1.x - static_cast<const T*>(this)->vertex0.x,
                        static_cast<const T*>(this)->vertex2.y - static_cast<const T*>(this)->vertex0.y
                    );
                }
            };
        }

        /*
            1
           / \
          3 - 2
        */
        struct POLY_F3 : public internal::RenderPrimitive<POLY_F3>, public internal::PolyCodeInterface<POLY_F3>, public internal::Poly3Interface<POLY_F3>, public internal::LinkedElementCreator<POLY_F3> {
            static constexpr auto IdentityCode = Code::create().set(Code::FlatShading).set(Code::TriVertics).set(Code::Untextured).set(Code::NonTransparent);

            Color24 color;   // a
            Code    code;    // a
            Vertex  vertex0; // b
            Vertex  vertex1; // c
            Vertex  vertex2; // d

            static constexpr POLY_F3 create(const Vertex (&verticies)[3], Color24 color) {
                return POLY_F3 {
                    .color = color, .code = IdentityCode,
                    .vertex0 = verticies[0], 
                    .vertex1 = verticies[1], 
                    .vertex2 = verticies[2]
                };
            }
        };

        struct POLY_FT3 : public internal::RenderPrimitive<POLY_FT3>, public internal::PolyCodeInterface<POLY_FT3>, public internal::Poly3Interface<POLY_FT3>, public internal::LinkedElementCreator<POLY_FT3> {
            struct VertexEx {
                Vertex     position;
                PageOffset tex_offset;
            };
            static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::Textured);

            Color24    color;       // a
            Code       code;        // a
            Vertex     vertex0;     // b
            PageOffset tex_offset0; // c
            PageClut   page_clut;   // c
            Vertex     vertex1;     // d
            PageOffset tex_offset1; // e
            TPage      tpage;       // e
            Vertex     vertex2;     // f
            PageOffset tex_offset2; // g
            uint16_t   padded2;     // g

            static constexpr POLY_FT3 create(const Vertex (&verticies)[3], const PageOffset (&tex_offsets)[3], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
                return POLY_FT3::create({
                    {verticies[0], tex_offsets[0]},
                    {verticies[1], tex_offsets[1]},
                    {verticies[2], tex_offsets[2]}
                }, tpage, clut, color);
            }

            static constexpr POLY_FT3 create(const VertexEx (&vertices_ex)[3], TPage tpage, PageClut clut, Color24 color) {
                return POLY_FT3 {
                    .color = color, .code = IdentityCode, 
                    .vertex0 = vertices_ex[0].position, .tex_offset0 = vertices_ex[0].tex_offset, .page_clut  = clut,
                    .vertex1 = vertices_ex[1].position, .tex_offset1 = vertices_ex[1].tex_offset, .tpage      = tpage,
                    .vertex2 = vertices_ex[2].position, .tex_offset2 = vertices_ex[2].tex_offset};
            }
        };

        struct POLY_G3 : public internal::RenderPrimitive<POLY_G3>, public internal::PolyCodeInterface<POLY_G3>, public internal::Poly3Interface<POLY_G3>, public internal::LinkedElementCreator<POLY_G3> {
            static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::GouraudShading);

            Color24 color0;  // a
            Code    code;    // a
            Vertex  vertex0; // b
            Color24 color1;  // c
            uint8_t pad1;    // c
            Vertex  vertex1; // d
            Color24 color2;  // e
            uint8_t pad2;    // e
            Vertex  vertex2; // f

            static constexpr POLY_G3 create(const Vertex (&verticies)[3], const Color24 (&color)[3]) {
                return POLY_G3::create({
                    {verticies[0], color[0]},
                    {verticies[1], color[1]},
                    {verticies[2], color[2]}
                }); 
            }

            static constexpr POLY_G3 create(const VertexColor (&verticies_ex)[3]) {
                return POLY_G3 {
                    .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position,
                    .color1 = verticies_ex[1].color, .pad1 = 0,            .vertex1 = verticies_ex[1].position,
                    .color2 = verticies_ex[2].color, .pad2 = 0,            .vertex2 = verticies_ex[2].position
                }; 
            }
        };

        struct POLY_GT3 : public internal::RenderPrimitive<POLY_GT3>, public internal::PolyCodeInterface<POLY_GT3>, public internal::Poly3Interface<POLY_GT3>, public internal::LinkedElementCreator<POLY_GT3> {
            struct VertexEx {
                Vertex     position;
                PageOffset tex_offset;
                Color24    color;
            };
            static constexpr auto IdentityCode = Code(POLY_G3::IdentityCode).set(Code::Textured);

            Color24    color0;      // a
            Code       code;        // a
            Vertex     vertex0;     // b 
            PageOffset tex_offset0; // c
            PageClut   page_clut;   // c
            Color24    color1;      // d
            uint8_t    pad1;        // d
            Vertex     vertex1;     // e
            PageOffset tex_offset1; // f
            TPage      tpage;       // f
            Color24    color2;      // g
            uint8_t    pad2;        // g
            Vertex     vertex2;     // h
            PageOffset tex_offset2; // i
            uint16_t   pad3;        // i

            static constexpr POLY_GT3 create(const Vertex (&verticies)[3], const PageOffset (&tex_offsets)[3], const Color24 (&color)[3], TPage tpage, PageClut clut) {
                return POLY_GT3::create({
                    {verticies[0], tex_offsets[0], color[0]},
                    {verticies[1], tex_offsets[1], color[1]},
                    {verticies[2], tex_offsets[2], color[2]}
                }, tpage, clut); 
            }
            
            static constexpr POLY_GT3 create(const VertexEx (&verticies_ex)[3], TPage tpage, PageClut clut) {
                return POLY_GT3 { 
                    .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, .tex_offset0 = verticies_ex[0].tex_offset, .page_clut = clut,
                    .color1 = verticies_ex[1].color, .pad1 = 0,            .vertex1 = verticies_ex[1].position, .tex_offset1 = verticies_ex[1].tex_offset, .tpage     = tpage, 
                    .color2 = verticies_ex[2].color, .pad2 = 0,            .vertex2 = verticies_ex[2].position, .tex_offset2 = verticies_ex[2].tex_offset, .pad3      = 0
                };
            }
        };

        /*
        1 - 2
        |   |
        3 - 4
        */
        struct POLY_F4 : public internal::RenderPrimitive<POLY_F4>, public internal::PolyCodeInterface<POLY_F4>, public internal::Poly4Interface<POLY_F4>, public internal::LinkedElementCreator<POLY_F4> {
            static constexpr auto IdentityCode = Code(POLY_F3::IdentityCode).set(Code::QuadVertics);

            Color24 color;   // a
            Code    code;    // a
            Vertex  vertex0; // b
            Vertex  vertex1; // c
            Vertex  vertex2; // d
            Vertex  vertex3; // e

            static constexpr POLY_F4 create(const Vertex (&verticies)[4], Color24 color) {
                return POLY_F4 { 
                    .color = color, .code = IdentityCode, 
                    .vertex0 = verticies[0], 
                    .vertex1 = verticies[1], 
                    .vertex2 = verticies[2], 
                    .vertex3 = verticies[3]
                };
            }
                
            static constexpr POLY_F4 create(const AreaI16& area, Color24 color) {
                return POLY_F4::create({
                    POLY_F4::vertex0_from(area),
                    POLY_F4::vertex1_from(area),
                    POLY_F4::vertex2_from(area),
                    POLY_F4::vertex3_from(area)
                }, color);
            }
        };

        struct POLY_FT4 : public internal::RenderPrimitive<POLY_FT4>, public internal::PolyCodeInterface<POLY_FT4>, public internal::Poly4Interface<POLY_FT4>, public internal::LinkedElementCreator<POLY_FT4> {
            typedef POLY_FT3::VertexEx VertexEx;
            static constexpr auto IdentityCode = Code(POLY_FT3::IdentityCode).set(Code::QuadVertics);

            Color24    color;       // a
            Code       code;        // a
            Vertex     vertex0;     // b
            PageOffset tex_offset0; // c
            PageClut   page_clut;   // c
            Vertex     vertex1;     // d
            PageOffset tex_offset1; // e
            TPage      tpage;       // e
            Vertex     vertex2;     // f
            PageOffset tex_offset2; // g
            uint16_t   pad2;        // g
            Vertex     vertex3;     // h
            PageOffset tex_offset3; // i
            uint16_t   pad3;        // i

            static constexpr POLY_FT4 create(const Vertex (&verticies)[4], const PageOffset (&tex_offsets)[4], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
                return POLY_FT4::create({
                    {verticies[0], tex_offsets[0]},
                    {verticies[1], tex_offsets[1]},
                    {verticies[2], tex_offsets[2]},
                    {verticies[3], tex_offsets[3]}
                }, tpage, clut, color);
            }
            
            static constexpr POLY_FT4 create(const VertexEx (&vertices_ex)[4], TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
                return POLY_FT4 { 
                    .color   = color, .code = IdentityCode, 
                    .vertex0 = vertices_ex[0].position, .tex_offset0 = vertices_ex[0].tex_offset, .page_clut = clut,
                    .vertex1 = vertices_ex[1].position, .tex_offset1 = vertices_ex[1].tex_offset, .tpage     = tpage,
                    .vertex2 = vertices_ex[2].position, .tex_offset2 = vertices_ex[2].tex_offset, .pad2 = 0,
                    .vertex3 = vertices_ex[3].position, .tex_offset3 = vertices_ex[3].tex_offset, .pad3 = 0 
                };
            }
            
            static constexpr POLY_FT4 create(const AreaI16& area, const PageOffset& tex_offset, TPage tpage, PageClut clut, Color24 color = Color24::Grey()) {
                return POLY_FT4::create({
                    {POLY_FT4::vertex0_from(area), tex_offset},
                    {POLY_FT4::vertex1_from(area), tex_offset.move(area.size.width - 1, 0)},
                    {POLY_FT4::vertex2_from(area), tex_offset.move(0,                   area.size.height - 1)},
                    {POLY_FT4::vertex3_from(area), tex_offset.move(area.size.width - 1, area.size.height - 1)}
                }, tpage, clut, color);
            }
        };

        struct POLY_G4 : public internal::RenderPrimitive<POLY_G4>, public internal::PolyCodeInterface<POLY_G4>, public internal::Poly4Interface<POLY_G4>, public internal::LinkedElementCreator<POLY_G4> {
            static constexpr auto IdentityCode = Code(POLY_G3::IdentityCode).set(Code::QuadVertics);

            Color24 color0;  // a
            Code    code;    // a
            Vertex  vertex0; // b
            Color24 color1;  // c
            uint8_t pad1;    // c
            Vertex  vertex1; // d
            Color24 color2;  // e
            uint8_t pad2;    // e
            Vertex  vertex2; // f
            Color24 color3;  // g
            uint8_t pad3;    // g
            Vertex  vertex3; // h

            static constexpr POLY_G4 create(const Vertex (&verticies)[4], const Color24 (&color)[4]) {
                return POLY_G4::create({
                    {verticies[0], color[0]},
                    {verticies[1], color[1]},
                    {verticies[2], color[2]},
                    {verticies[3], color[3]}
                }); 
            }

            static constexpr POLY_G4 create(const VertexColor (&verticies_ex)[4]) {
                return POLY_G4 {
                    .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position,
                    .color1 = verticies_ex[1].color, .pad1 = 0,            .vertex1 = verticies_ex[1].position,
                    .color2 = verticies_ex[2].color, .pad2 = 0,            .vertex2 = verticies_ex[2].position,
                    .color3 = verticies_ex[3].color, .pad3 = 0,            .vertex3 = verticies_ex[3].position
                };
            }

            static constexpr POLY_G4 create(const AreaI16& area, const Color24 (&color)[4]) {
                return POLY_G4::create({
                    {POLY_FT4::vertex0_from(area), color[0]},
                    {POLY_FT4::vertex1_from(area), color[1]},
                    {POLY_FT4::vertex2_from(area), color[2]},
                    {POLY_FT4::vertex3_from(area), color[3]}
                }); 
            }
        }; 

        struct POLY_GT4 : public internal::RenderPrimitive<POLY_GT4>, public internal::PolyCodeInterface<POLY_GT4>, public internal::Poly4Interface<POLY_GT4>, public internal::LinkedElementCreator<POLY_GT4> {
            typedef POLY_GT3::VertexEx VertexEx;
            static constexpr auto IdentityCode = Code(POLY_GT3::IdentityCode).set(Code::QuadVertics);

            Color24    color0;      // a
            Code       code;        // a
            Vertex     vertex0;     // b 
            PageOffset tex_offset0; // c
            PageClut   page_clut;   // c
            Color24    color1;      // d
            uint8_t    pad1;        // d
            Vertex     vertex1;     // e
            PageOffset tex_offset1; // f
            TPage      tpage;       // f
            Color24    color2;      // g
            uint8_t    pad2;        // g
            Vertex     vertex2;     // h
            PageOffset tex_offset2; // i
            uint16_t   pad3;        // i
            Color24    color3;      // j
            uint8_t    pad4;        // j
            Vertex     vertex3;     // k
            PageOffset tex_offset3; // l
            uint16_t   pad5;        // l

            static constexpr POLY_GT4 create(const Vertex (&verticies)[4], const PageOffset (&tex_offsets)[4], const Color24 (&color)[4], TPage tpage, PageClut clut) {
                return POLY_GT4::create({
                    {verticies[0], tex_offsets[0], color[0]},
                    {verticies[1], tex_offsets[1], color[1]},
                    {verticies[2], tex_offsets[2], color[2]},
                    {verticies[3], tex_offsets[3], color[3]},
                }, tpage, clut);
            }

            static constexpr POLY_GT4 create(const VertexEx (&verticies_ex)[4], TPage tpage, PageClut clut) {
                return POLY_GT4 {
                    .color0 = verticies_ex[0].color, .code = IdentityCode, .vertex0 = verticies_ex[0].position, .tex_offset0 = verticies_ex[0].tex_offset, .page_clut = clut,
                    .color1 = verticies_ex[1].color, .pad1 = 0,            .vertex1 = verticies_ex[1].position, .tex_offset1 = verticies_ex[1].tex_offset, .tpage     = tpage, 
                    .color2 = verticies_ex[2].color, .pad2 = 0,            .vertex2 = verticies_ex[2].position, .tex_offset2 = verticies_ex[2].tex_offset, .pad3      = 0,
                    .color3 = verticies_ex[3].color, .pad4 = 0,            .vertex3 = verticies_ex[3].position, .tex_offset3 = verticies_ex[3].tex_offset, .pad5      = 0
                };
            }

            static constexpr POLY_GT4 create(const AreaI16& area, const PageOffset& tex_offset, TPage tpage, PageClut clut, const Color24 (&color)[4]) {
                return POLY_GT4::create({
                    {POLY_FT4::vertex0_from(area), tex_offset,                                         color[0]},
                    {POLY_FT4::vertex1_from(area), tex_offset.move(area.size.width, 0),                color[1]},
                    {POLY_FT4::vertex2_from(area), tex_offset.move(0, area.size.height),               color[2]},
                    {POLY_FT4::vertex3_from(area), tex_offset.move(area.size.width, area.size.height), color[3]}
                }, tpage, clut);
            }
        };

        #define __jabyengine_poly_top_left(x, y, w, h)      x,       y
        #define __jabyengine_poly_top_right(x, y, w, h)    (x + w),  y
        #define __jabyengine_poly_bottom_left(x, y, w, h)   x,      (y + h)
        #define __jabyengine_poly_bottom_right(x, y, w, h) (x + w), (y + h)

        #define __jabyengine_polyFT4_vertex_rect(area, tex_off) { \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)),     JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},     \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)),    JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))},    \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)),  JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},  \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
        }

        #define __jabyengine_polyFT4_vertex_rect90(area, tex_off) { \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)),  JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},  \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)),     JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))},     \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)),    JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))},    \
        }

        #define __jabyengine_polyFT4_vertex_rect180(area, tex_off) { \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)),     JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},     \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)),    JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))},    \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)),  JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},  \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
        }

        #define __jabyengine_polyFT4_vertex_rect270(area, tex_off) { \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_right(area.position.x, area.position.y, area.size.width, area.size.height)),     JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},     \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_right(area.position.x, area.position.y, area.size.width, area.size.height)),    JabyEngine::GPU::PageOffset::create(__jabyengine_poly_top_right(tex_off.x, tex_off.y, area.size.width, area.size.height))},    \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_top_left(area.position.x, area.position.y, area.size.width, area.size.height)),  JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_left(tex_off.x, tex_off.y, area.size.width, area.size.height))},  \
            JabyEngine::GPU::POLY_FT4::VertexEx{JabyEngine::GPU::Vertex::create(__jabyengine_poly_bottom_left(area.position.x, area.position.y, area.size.width, area.size.height)), JabyEngine::GPU::PageOffset::create(__jabyengine_poly_bottom_right(tex_off.x, tex_off.y, area.size.width, area.size.height))}, \
        }

        typedef POLY_F3  FlatTriangle;
        typedef POLY_FT3 FlatTexturedTriangle;
        typedef POLY_G3  GouraudTriangle;
        typedef POLY_GT3 GouraudTexturedTriangle;

        typedef POLY_F4  FlatRectangle;
        typedef POLY_FT4 FlatTexturedRectangle;
        typedef POLY_G4  GouraudRectangle;
        typedef POLY_GT4 GouraudTexturedRectangle;

        static_assert(sizeof(POLY_F3)  == 16);
        static_assert(sizeof(POLY_FT3) == 28);
        static_assert(sizeof(POLY_G3)  == 24);
        static_assert(sizeof(POLY_GT3) == 36);

        static_assert(sizeof(POLY_F4)  == 20);
        static_assert(sizeof(POLY_FT4) == 36);
        static_assert(sizeof(POLY_G4)  == 32);
        static_assert(sizeof(POLY_GT4) == 48);
    }
}