0417 CRTP 배치렌더링 디자인

CRTP써서 배치렌더링 디자인

생각해보니까, 여기 쓰이는 프리미티브 info들은
그냥 렌더링으로도 쓰일 수 있을 것 같다...
    배치또는 일반으로...
    아닌가? 일반 렌더링에는 월드 행렬을 받아야 한느데??

*** 이거 당연하겠지만 다이나믹 배칭임 ****

나중에 이거 쓰면 이렇게 되겠지...
참고로 이거 vec3하던지 vec2하던지,
    (확장성을 위해서 vec3로 받자......제발)
    (로테이션도 vec3 또는 쿼터니언으로....)
    (물론 변환은 CPU에서!)

BatchRenderer<QuadBatch, Quad>                          m_quad_batch_renderer{};
BatchRenderer<TextureQuadBatch, TextureQuad>        m_tex_quad_batch_renderer{};
BatchRenderer<TriangleBatch, Triangle>                    m_tri_batch_renderer{};
BatchRenderer<TextureTriangleBatch, TextureTriangle> m_tex_tri_batch_renderer{};
BatchRenderer<LineBatch, Line>                             m_line_batch_renderer{};
BatchRenderer<PointBatch, Point>                           m_point_batch_renderer{};

    Quad -> vec3 aPos + vec4 aColor;
    TextureQuad -> vec3 aPos, vec2 aTexCoord, int aTexIndex
    Triangle -> vec3 aPos, vec4 aColor;
    TextureTriangle -> vec3 aPos, vec2 aTexCoord, int aTexIndex
    Line -> vec3 aPos + vec4 aColor;
    Point -> vec3 aPos + vec4 aColor;

이게 의미가..있나??
일단 프리미티브 별로 렌더러 특수화를 해야 하는건 맞음.
그리고 CRTP를 쓸 거면 상위 클래스가 "구현 클래스가 뭘 먹는지" 알아야 함.
그냥 런타임 오버헤드 줄인다는 마인드로,
템플릿 인자 2개를 용서하자.

// ========== 수정 ============== //

용서가 안된다.
inner-using으로 바꾼다.

template<typename T>
class BatchRenderer {
using BatchInfo  = T::BatchInfo;
public:
    void submit(const BatchInfo& info) {
            self().submit(info);
    }
}

// ======================= //

template<typename T, typename C>
class BatchRenderer {
private:
    auto VAO, VBO, EBO;
    BufferData vertices, indices;
public:
    T& self() { return static_cast<T&>(*this) }
    const T& self() const { return static_cast<const T&>(*this) }
    void submit(const C& info) {
            self().submit(info);
    }
    void begin() {
        self().begin();
    }
    void end() {
        self().end();
    }
    // DO ACTUAL DRAW CALL HERE
    void flush() {
        self().flush();
    }
};

struct Primitive {
    virtual const char* str() const = 0;
};

// vec2 aPos + vec2 aTexCoord + int aTexIndex
struct TextureQuad : public Primitive {
    const char* str() const {return "TextureQuad"}
public:
    // 모두 in vec2 aPos로 환원되는 정보들
    Vector2f Position;
    Vector2f Pivot;
    float Rotation;
    Vector2f Scale;
    Vector2f Skew;
    Vector2f Size;
    // 매 프레임마다 배칭할 때,
    // std::unordered_map<const glw::Texture*, size_t> 를 초기화하고,
    // 만약 새로운 텍스쳐가 들어오면 맵에 추가 + 아이디 발급
    // 이미 있던 놈이면 그 텍스쳐의 아이디를 
    // aTexIndex로 보내기.
    const glw::Texture* Texture;
}


// vec2 aPos + vec4 aColor
struct Quad final : public Primitive {
    const char* str() const { return "Quad"  }
public:
    // 모두 in vec2 aPos로 환원되는 정보들
    Vector2f Position;
    Vector2f Pivot;
    float Rotation;
    Vector2f Scale;
    Vector2f Skew;
    Vector2f Size;
    // in vec4 aColor로 환원되는 정보들 (두번째 속성)
    Color4f Color;
    Color4f Modulate;
}

class QuadBatch : public BatchRenderer<QuadBatch, Quad> {
public:
    void submit(const Quad& info) {
        // 
    }
    void begin() {
        // 배칭...
    }
    void end() {
        // 배칭...
    }
    void flush() {
        // 렌더콜 부르기..
    }
};

// ==================================== //

        -- 또는 --

struct Quad {
    static const constexpr size_t 
    static const constexpr size_t IndexCount = 6;
};

이제 이거를 템플릿으로 전달.

BatchRenderer<Quad> m_quad_batch_renderer{};

배치렌더러는 내부에서 T의 오프셋 / 크기 등을 참조하여
배칭을 구성.

렌더서버는 draw_quad가 불리면 명시적으로
m_quad_batch_renderer.submit(pos, size)를 해서 배칭.

렌더서버는 드로우콜 끝나면 모든 배치 렌더러에 대해
flush