Newer
Older
Import / applications / HighwayDash / ports / Game / HUD.cpp
//  BlockyFroggy
//  Copyright © 2017 John Ryland.
//  All rights reserved.
#include "HUD.h"
#include <vector>
#include <string>


extern const char* s_hudVertexShader;
extern const char* s_hudFragmentShader;


 /*


 struct {
     int a[100], b[100], c[100];
 } SOA;
 
 struct {
     int a, b, c;
 } AOS[100];



// declaration
struct S {
  int a, b, c;
};
// instantiate
S array[SIZE];
// access
S[n].a;


translates to:


// declaration
struct S {
  int a[SIZE], b[SIZE], c[SIZE];
};

// instantiate
S array;

// access
S.a[n];


idea 1, use macros:


// declaration
DECLARE_STRUCT_BEGIN(S)
  MEMBER(int, a)
  MEMBER(int, b)
  MEMBER(int, c)
DECLARE_STRUCT_END(S)

// instantiate
MAKE_SOA(array, S, SIZE);

// access
GET(array, a, n);


// Biased to SOA rather than AOS
template <typename T>
struct Struct {
  bool m_isSoa;
};

template <typename T, SIZE>
struct BaseSOA : public Struct {
  BaseSOA() : m_isSoa(true) {}
  // Need a constexpr to work out the member count of T - perhaps ryland's device can do it
  void* T[memberCount];
  // Then need to allocate the memory - ryland's device again with sizeof for each member
  // Then need accessors with re-interpret casts
};

template <typename T, SIZE>
struct BaseAOS : public Struct {
  BaseAOS() : m_isSoa(false) {}
  T m_array[SIZE];
};

struct S {
  int a; int *get_a(size_t idx) { return a[idx]; }
  int b; int *get_b(size_t idx) { return b[idx]; }
  int c; int *get_c(size_t idx) { return c[idx]; }
  S(bool soa, size_t siz = 1) { a = new int[siz]; ... using ryland's device }
};


BaseSOA<S> array(SIZE);
array.a[n];


DECLARE_STRUCT_BEGIN(S)
  MEMBER(int, a)
  MEMBER(int, b)
  MEMBER(int, c)
DECLARE_STRUCT_END(S)


template <size_t SIZE=1>
struct S
{
  int a[SIZE];
  int b[SIZE];
  int c[SIZE];
};


// Just as you might expect
#define MAKE_AOS(array, S, SIZE) \
     S array[SIZE]; \
     const bool array##_isSOA = false;


#define MAKE_SOA(array, S, SIZE) \
     S<SIZE> array; \
     const bool array##_isSOA = true;


#define GET(array, a, n) \
     ((array##_isSOA) ? array.a[n] : array[n].a[0])


 */



HUDRenderLayer::HUDRenderLayer()
{
}


HUDRenderLayer::~HUDRenderLayer()
{
}


/*
 
// concept, don't specify locations and uniform locations and vertex attribute layout
// instead define it more declaritively rather than programatically
// eg: list member variables that are uniforms, and the code is generated for this and inserted in to the shader code
// the attribute layout is also mapped from a struct and the members to map, and the code generated from sizeof struct and offsets

VariableMappings
{
    consts, uniforms and attributes
    attributes -> vertex shader
    consts & uniforms -> both
}
*/


void HUDRenderLayer::initialize()
{
    struct GLAttribute {
        std::string m_type;
        std::string m_name;
        int m_count;
        int m_glType;
        int m_convert;
        int m_size;
        void* m_offset;
    };
    std::vector<GLAttribute> attributeList;
    struct GLUniform {
        std::string m_type;
        std::string m_name;
        int m_mappedLocation;
    };
    std::vector<GLUniform> uniformsList;


    // Need to provide
    struct thing {
        float     t;
        float     xyPos[2];//x,y;
        float     ch[2];//u,v;
        float     col[3];//r,g,b;
        uint32_t  col2;
    } _thing;
    

    // Need to provide
    attributeList.emplace_back(GLAttribute{"float", "t",     1, GL_FLOAT,        GL_FALSE, sizeof(_thing), (void*)((char*)&_thing.t     - (char*)&_thing)});
    attributeList.emplace_back(GLAttribute{"vec2",  "xyPos", 2, GL_FLOAT,        GL_FALSE, sizeof(_thing), (void*)((char*)&_thing.xyPos - (char*)&_thing)});
    attributeList.emplace_back(GLAttribute{"vec2",  "ch",    2, GL_FLOAT,        GL_FALSE, sizeof(_thing), (void*)((char*)&_thing.ch    - (char*)&_thing)});
    attributeList.emplace_back(GLAttribute{"vec3",  "col",   3, GL_FLOAT,        GL_FALSE, sizeof(_thing), (void*)((char*)&_thing.col   - (char*)&_thing)});
    attributeList.emplace_back(GLAttribute{"vec4",  "col2",  4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(_thing), (void*)((char*)&_thing.col2   - (char*)&_thing)});
    // uint32_t as color -> converts to a normalized vec4 in the shader
    //glVertexAttribPointer(ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, GL_TRUE, 16+12, BUFFER_OFFSET(16));


    // Example
    //AddAttribute(col2);
    // Perhaps look at the serialize/deserialize code I have
    uniformsList.emplace_back(GLUniform{"highp vec2", "invScreen", 0});
    uniformsList.emplace_back(GLUniform{"sampler2D",  "texture",   1});


    // Inject the attributes and uniforms in to the shaders
    // Perhaps could inject in constants too
    std::string vertexShaderDeclarations;
    std::string fragmentShaderDeclarations;
    for (auto attrib : attributeList)
        vertexShaderDeclarations += "attribute " + attrib.m_type + " " + attrib.m_name + ";";
    for (auto uniform : uniformsList)
    {
        vertexShaderDeclarations   += "uniform " + uniform.m_type + " " + uniform.m_name + ";";
        fragmentShaderDeclarations += "uniform " + uniform.m_type + " " + uniform.m_name + ";";
    }

    // Setup overlay vertexes
    OptionsType options;
    m_program.loadShaders((vertexShaderDeclarations + s_hudVertexShader).c_str(), (fragmentShaderDeclarations + s_hudFragmentShader).c_str(),
                             Medium, options,
                             [attributeList](GLuint a_program){
                                 int idx = 0;
                                 for (auto attrib : attributeList)
                                 {
                                     glBindAttribLocation(a_program, idx, attrib.m_name.c_str());
                                     idx++;
                                 }
                             }, [uniformsList](GLuint a_program){
                                 int idx = 0;
                                 for (auto uniform : uniformsList)
                                 {
                                     uniform.m_mappedLocation = glGetUniformLocation(a_program, uniform.m_name.c_str());
                                     idx++;
                                 }
                             });
    GLuint vertexArray;
    glGenVertexArraysOES(1, &vertexArray);
    glBindVertexArrayOES(vertexArray);
    glGenBuffers(1, &m_hudVertexBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, m_hudVertexBuffer);
    int idx = 0;
    for (auto attrib : attributeList)
    {
        glVertexAttribPointer(idx, attrib.m_count, attrib.m_glType, attrib.m_convert, attrib.m_size, attrib.m_offset);
        idx++;
    }
    glBindVertexArrayOES(0);

/*
    //glBufferData   (<#GLenum target#>,                   <#GLsizeiptr size#>, <#const GLvoid *data#>, <#GLenum usage#>);
    //glBufferSubData(<#GLenum target#>, <#GLintptr offset#>, <#GLsizeiptr size#>, <#const GLvoid *data#>);

    
    glGenTextures(1, &m_hudTexId);
    glBindTexture(GL_TEXTURE_2D, m_hudTexId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    std::vector<unsigned char> fontData;
    unsigned long fontW, fontH;
    int error = ::decodePNG(fontData, fontW, fontH, Font6_png, Font6_png_len);
    if (error != 0 || fontW != 256 || fontH != 256)
        LogTag(LL_Error, "HUD", "error: %d\n", error);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, GL_RGBA, GL_UNSIGNED_BYTE, (const GLvoid *)&fontData[0]);
 */
}



void HUDRenderLayer::update(float /*a_dt*/)
{
    /*
    m_hudItemCount = (int)m_chars.size();
    const uint16_t fW = 10;
    const uint16_t fH = 16;
    m_items.clear();
    for (TextChar c : m_chars)
    {
        uint8_t chX = 0, chY = 0;
        
        if (c.ch == ' ')
        {
            m_hudItemCount--;
            continue;
        } else if (c.ch >= 'A' && c.ch <= 'Z') {
            chX = (c.ch - 'A') * 10;
        } else if (c.ch >= 'a' && c.ch <= 'z') {
            chX = (c.ch - 'a') * 10;
            chY = 16;
        } else if (c.ch >= '0' && c.ch <= '9') {
            chX = 1 + (c.ch - '0') * 10;
            chY = 32;
        } else {
            if (c.ch == '.') {chX =   1; chY = 48;}
            if (c.ch == '-') {chX =  11; chY = 48;}
            if (c.ch == ',') {chX =  21; chY = 48;}
            if (c.ch == '[') {chX =  31; chY = 48;}
            if (c.ch == '_') {chX =  41; chY = 48;}
            if (c.ch == ']') {chX =  51; chY = 48;}
            
            if (c.ch == ':') {chX =  61; chY = 48;}
            if (c.ch == '=') {chX =  71; chY = 48;}
            if (c.ch == ';') {chX =  81; chY = 48;}
            if (c.ch == '{') {chX =  91; chY = 48;}
            if (c.ch == '+') {chX = 101; chY = 48;}
            if (c.ch == '}') {chX = 111; chY = 48;}
            
            if (c.ch == '@') {chX = 121; chY = 48;}
            if (c.ch == '^') {chX = 131; chY = 48;}
            if (c.ch == '#') {chX = 141; chY = 48;}
            if (c.ch == '!') {chX = 151; chY = 48;}
            if (c.ch == '*') {chX = 161; chY = 48;}
            if (c.ch == '%') {chX = 171; chY = 48;}
            
            //   .----,
            //   [____]
            //
            //   :====;
            //   {++++}
            //
            //   @^^^^#
            //   !****%
            //
            //   "╔═╗╚═╝"
            
            
            
            //LogTag(LL_Error, "HUD", "Invalid char (%c)\n", c.ch);
        }
        
        m_items.emplace_back(HudItem(c.x,c.y,chX,chY,0*fW,0*fH,c.col));
        m_items.emplace_back(HudItem(c.x,c.y,chX,chY,0*fW,1*fH,c.col));
        m_items.emplace_back(HudItem(c.x,c.y,chX,chY,1*fW,1*fH,c.col));
        m_items.emplace_back(HudItem(c.x,c.y,chX,chY,1*fW,1*fH,c.col));
        m_items.emplace_back(HudItem(c.x,c.y,chX,chY,1*fW,0*fH,c.col));
        m_items.emplace_back(HudItem(c.x,c.y,chX,chY,0*fW,0*fH,c.col));
    }
    
    glBindBuffer(GL_ARRAY_BUFFER, m_hudVertexBuffer);
    static_assert(sizeof(HudItem) == 16+12, "bad size");
    glBufferData(GL_ARRAY_BUFFER, sizeof(HudItem)*m_hudItemCount*6, (void*)&m_items[0], GL_DYNAMIC_DRAW);
    //m_chars.clear();
     */
}


void HUDRenderLayer::draw()
{
    /*
    glDisable(GL_CULL_FACE);
    glDisable(GL_DEPTH_TEST);
    glEnable(GL_BLEND);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBindVertexArrayOES(m_vertexArray[2]);
    m_program.useProgram();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, m_hudTexId);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glUniform1i(uniforms[UNIFORM_HUD_TEXTURE], 0);
    //float invScreen[2] = { 2.0f / vp[2], -2.0f / vp[3] };
    glUniform2f(uniforms[UNIFORM_HUD_INV_SCREEN], 2.0f / vp[2], -2.0f / vp[3]);
    glDrawArrays(GL_TRIANGLES, 0, m_hudItemCount * 6);
     */
}