schulkinator / nanoreflect

An extremely simple C++ reflection library

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

nanoreflect

An extremely simple C++ reflection library. Mostly useful for vertex struct layout descriptions in graphics programs and games.

Example usage:

// Declare your structure as usual
struct Vertex {
  glm::vec3 pos;
  glm::vec2 uv;
  glm::vec3 normal;
};

// Then you must define your structure's type descriptor
REFLECTED_OBJECT_BEGIN(Vertex)
REFLECTED_OBJECT_MEMBER(Vertex, pos)
REFLECTED_OBJECT_MEMBER(Vertex, uv)
REFLECTED_OBJECT_MEMBER(Vertex, normal)
REFLECTED_OBJECT_END(Vertex)

// you can even use it with inherited objects
struct VertexWithTangent : public Vertex {
  glm::vec3 tangent;
};

// Define VertexWithTangent's type descriptor
// NOTE: You MUST list out the inherited fields again
REFLECTED_OBJECT_BEGIN(VertexWithTangent)
REFLECTED_OBJECT_MEMBER(VertexWithTangent, pos)
REFLECTED_OBJECT_MEMBER(VertexWithTangent, uv)
REFLECTED_OBJECT_MEMBER(VertexWithTangent, normal)
REFLECTED_OBJECT_MEMBER(VertexWithTangent, tangent)
REFLECTED_OBJECT_END(VertexWithTangent)

// Then to use the reflection in code you can do something like this (the Member object has the reflected field information):
nanoreflect::TypeDescriptor<Vertex>* type_desc = nanoreflect::GetTypeDescriptor<Vertex>();
nanoreflect::Member* member_pos = type_desc->GetMember(&Vertex::pos);
nanoreflect::Member* member_uv = type_desc->GetMember(&Vertex::uv);
nanoreflect::Member* member_normal = type_desc->GetMember(&Vertex::normal);
  
// Here's a real example using it with OpenGL to set up a VBO:
 void SetupBuffers() {
  glGenBuffers(1, &vertex_buffer);
  glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer);
  glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);
  glGenVertexArrays(1, &vaoId_);
  glBindVertexArray(vaoId_);

  const nanoreflect::TypeDescriptor<Vertex>* type_desc = nanoreflect::GetTypeDescriptor<Vertex>();
  const nanoreflect::Member* member_pos = type_desc->GetMember(&Vertex::pos);
  const nanoreflect::Member* member_uv = type_desc->GetMember(&Vertex::uv);
  const nanoreflect::Member* member_normal = type_desc->GetMember(&Vertex::normal);
  
  GLuint positionAttribLocation = member_pos->ordinal;
  glVertexAttribPointer(positionAttribLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(member_pos->offset)); // stride is in units of bytes, offset is also in bytes
  glEnableVertexAttribArray(positionAttribLocation);
  
  GLuint texcoordAttribLocation = member_uv->ordinal;
  glVertexAttribPointer(texcoordAttribLocation, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(member_uv->offset)); // stride is in units of bytes, offset is also in bytes
  glEnableVertexAttribArray(texcoordAttribLocation);
  
  GLuint normalAttribLocation = member_normal->ordinal;
  glVertexAttribPointer(normalAttribLocation, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), BUFFER_OFFSET(member_normal->offset)); // stride is in units of bytes, offset is also in bytes
  glEnableVertexAttribArray(normalAttribLocation);
  
  // generate the index buffer
  glGenBuffers(1, &index_buffer_id_);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id_);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW);
}

// Here's a different more generic and compact version of the above by iterating over the members
void SetupBuffers(std::vector<Vertex>& vertices, std::vector<uint16_t> indices, GLuint& vbo_id, GLuint& vao_id, GLuint& index_buffer_id) {
  glGenBuffers(1, &vbo_id);
  glBindBuffer(GL_ARRAY_BUFFER, vbo_id);
  glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(Vertex), vertices.data(), GL_STATIC_DRAW);
  glGenVertexArrays(1, &vao_id);
  glBindVertexArray(vao_id);

  const nanoreflect::TypeDescriptor<Vertex>* type_desc = nanoreflect::GetTypeDescriptor<Vertex>();
  const nanoreflect::TypeDescriptorData& vertex_type_data = type_desc->type_data;
  
  for (int i = 0; i < vertex_type_data.members.size(); ++i) {
    const nanoreflect::Member& member = vertex_type_data.members[i];
    GLuint attribLocation = member.ordinal;
    size_t num_floats = member.type_data.size / sizeof(float);
    printf("field type: %s, field name: %s, type_id: %u\n", member.type_data.type_name, member.name, member.type_data.type_id);
    glVertexAttribPointer(attribLocation, num_floats, GL_FLOAT, GL_FALSE, vertex_type_data.size, BUFFER_OFFSET(member.offset)); // stride is in units of bytes, offset is also in bytes
    glEnableVertexAttribArray(attribLocation);
  }
    
  // generate the index buffer
  glGenBuffers(1, &index_buffer_id);
  glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id);
  glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint16_t), indices.data(), GL_STATIC_DRAW);
}

About

An extremely simple C++ reflection library

License:MIT License


Languages

Language:C++ 100.0%