Created
April 23, 2011 13:07
-
-
Save szastupov/938592 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include "material.h" | |
#include "opengl.h" | |
uint32_t VertexAttrib::convertType(type_t type) | |
{ | |
switch (type) { | |
case FLOAT: | |
return GL_FLOAT; | |
case SHORT: | |
return GL_SHORT; | |
case USHORT: | |
return GL_UNSIGNED_SHORT; | |
case BYTE: | |
return GL_BYTE; | |
case UBYTE: | |
return GL_UNSIGNED_BYTE; | |
} | |
ASSERT(!"should not be reached"); | |
return 0; | |
} | |
void VertexAttrib::bind() const | |
{ | |
m_vb->bind(); | |
glVertexAttribPointer(m_loc, | |
m_components, | |
m_type, | |
GL_FALSE, | |
m_stride, | |
(GLvoid*)m_offset); | |
glEnableVertexAttribArray(m_loc); | |
} | |
void VertexAttrib::unbind() const | |
{ | |
glDisableVertexAttribArray(m_loc); | |
} | |
Material::Material(ShaderProgramPtr prog) | |
: m_program(prog) | |
, m_MatrixModelView(prog->getUniformID("g_ModelView", Uniform::MATRIX4)) | |
, m_MatrixProjection(prog->getUniformID("g_Projection", Uniform::MATRIX4)) | |
, m_MatrixNormal(prog->getUniformID("g_Normal", Uniform::MATRIX3)) | |
, m_textureUnits(0) | |
, m_blending(REPLACE) | |
, m_depthWrite(true) | |
{} | |
UniformTexture* Material::addUniformTexture(const char *name) | |
{ | |
int loc = m_program->getUniformID(name, Uniform::TEXTURE); | |
if (loc == -1) | |
FAIL("uniform %s not found\n", name); | |
int textureUnit = m_textureUnits++; | |
UniformTexture *uv = new UniformTexture(loc, textureUnit); | |
m_uniforms.push_back(uv); | |
return uv; | |
} | |
Uniform* Material::findUniform(int id) | |
{ | |
for (size_t i = 0; i < m_uniforms.size(); i++) | |
if (m_uniforms[i].getID() == id) | |
return &m_uniforms[i]; | |
return NULL; | |
} | |
VBOPtr Material::addAttrib(const char *name, | |
uint32_t components, | |
VertexAttrib::type_t type, | |
VBOPtr va, | |
uint32_t stride, uint32_t offset) | |
{ | |
ASSERT(va->isArrayBuffer()); | |
int loc = m_program->getAttribID(name, components); | |
m_attributes.push_back(VertexAttrib(loc, components, type, stride, offset, va)); | |
return va; | |
} | |
void Material::loadBlending() const | |
{ | |
switch (m_blending) { | |
case REPLACE: | |
glBlendFunc(GL_ONE, GL_ZERO); | |
break; | |
case ADD: | |
glBlendFunc(GL_ONE, GL_ONE); | |
break; | |
case ALPHA: | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
break; | |
case ALPHA_ADD: | |
glBlendFunc(GL_SRC_ALPHA, GL_ONE); | |
break; | |
} | |
} | |
void Material::loadMatrices(const Matrix4f &model, const Matrix4f &projection) const | |
{ | |
if (m_MatrixModelView.getID() != -1) | |
m_MatrixModelView.loadValue(model); | |
if (m_MatrixProjection.getID() != -1) | |
m_MatrixProjection.loadValue(projection); | |
if (m_MatrixNormal.getID() != -1) { | |
Matrix3f model3x3(model); | |
m_MatrixNormal.loadValue(model3x3.inverseTransposed()); | |
} | |
} | |
void Material::loadUniforms() const | |
{ | |
for (size_t i = 0; i < m_uniforms.size(); i++) | |
m_uniforms[i].load(); | |
} | |
void Material::loadAttributes() const | |
{ | |
for (size_t i = 0; i < m_attributes.size(); i++) | |
m_attributes[i].bind(); | |
} | |
void Material::unloadAttributes() const | |
{ | |
for (size_t i = 0; i < m_attributes.size(); i++) | |
m_attributes[i].unbind(); | |
} | |
Material* Material::clone() const | |
{ | |
Material *mclone = new Material(m_program); | |
mclone->m_uniforms.reserve(m_uniforms.size()); | |
for (size_t i = 0; i < m_uniforms.size(); i++) | |
mclone->m_uniforms.push_back(m_uniforms[i].clone()); | |
mclone->m_attributes = m_attributes; | |
mclone->m_textureUnits = m_textureUnits; | |
mclone->m_blending = m_blending; | |
return mclone; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef MATERIAL_H | |
#define MATERIAL_H | |
#include <boost/ptr_container/ptr_vector.hpp> | |
#include "shader.h" | |
#include "buffers.h" | |
#include "sp.h" | |
struct VertexAttrib { | |
public: | |
typedef enum { | |
FLOAT, SHORT, USHORT, BYTE, UBYTE | |
} type_t; | |
VertexAttrib(uint32_t loc, | |
uint32_t components, | |
type_t type, | |
uint32_t stride, | |
uint32_t offset, | |
VBOPtr va) | |
: m_loc(loc) | |
, m_components(components) | |
, m_type(convertType(type)) | |
, m_stride(stride) | |
, m_offset(offset) | |
, m_vb(va) | |
{ | |
} | |
void bind() const; | |
void unbind() const; | |
private: | |
uint32_t m_loc; | |
uint32_t m_components; | |
uint32_t m_type; | |
uint32_t m_stride; | |
uint32_t m_offset; | |
VBOPtr m_vb; | |
static uint32_t convertType(type_t); | |
}; | |
class Material : public RefCounted<Material> { | |
public: | |
typedef enum { | |
REPLACE, ADD, ALPHA, ALPHA_ADD | |
} blending_t; | |
explicit Material(ShaderProgramPtr prog); | |
UniformTexture* addUniformTexture(const char *name); | |
template <class T> | |
UniformValue<T>* addUniformValue(const char *name) | |
{ | |
int type = UniformTypeTraits<T>::type; | |
int id = m_program->getUniformID(name, type); | |
if (id == -1) | |
FAIL("uniform %s not found\n", name); | |
UniformValue<T> *uv = new UniformValue<T>(id); | |
m_uniforms.push_back(uv); | |
return uv; | |
} | |
Uniform* findUniform(int id); | |
template <class T> | |
UniformValue<T>* getUniformValue(const char *name) | |
{ | |
int type = UniformTypeTraits<T>::type; | |
int id = m_program->getUniformID(name, type); | |
if (id == -1) | |
FAIL("uniform %s not found\n", name); | |
Uniform *uf = findUniform(id); | |
if (uf) | |
return static_cast<UniformValue<T>*>(uf); | |
else { | |
UniformValue<T> *uv = new UniformValue<T>(id); | |
m_uniforms.push_back(uv); | |
return uv; | |
} | |
} | |
VBOPtr addAttrib(const char *name, | |
uint32_t components, | |
VertexAttrib::type_t type, | |
VBOPtr va, | |
uint32_t stride, uint32_t offset); | |
VBOPtr addAttrib(const char *name, | |
uint32_t components, | |
VertexAttrib::type_t type, | |
VBOPtr va) | |
{ | |
return addAttrib(name, components, type, va, 0, 0); | |
} | |
const ShaderProgram* getProgram() const | |
{ | |
return m_program.get(); | |
} | |
void loadUniforms() const; | |
void loadAttributes() const; | |
void unloadAttributes() const; | |
void loadMatrices(const Matrix4f &model, const Matrix4f &projection) const; | |
void loadBlending() const; | |
void setBlending(blending_t b) | |
{ | |
m_blending = b; | |
} | |
blending_t getBlending() const | |
{ | |
return m_blending; | |
} | |
void setDepthWrite(bool enable) | |
{ | |
m_depthWrite = enable; | |
} | |
bool getDepthWrite() const | |
{ | |
return m_depthWrite; | |
} | |
Material* clone() const; | |
private: | |
ShaderProgramPtr m_program; | |
boost::ptr_vector<Uniform> m_uniforms; | |
std::vector<VertexAttrib> m_attributes; | |
Uniform m_MatrixModelView; | |
Uniform m_MatrixProjection; | |
Uniform m_MatrixNormal; | |
int m_textureUnits; | |
blending_t m_blending; | |
bool m_depthWrite; | |
}; | |
typedef boost::intrusive_ptr<Material> MaterialPtr; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <cstring> | |
#include <algorithm> | |
#include "opengl.h" | |
#include "shader.h" | |
Shader::Shader(GLenum type, const char *origin, const char *source) | |
: m_type(type) | |
, m_shader(0) | |
{ | |
m_shader = glCreateShader(m_type); | |
glShaderSource(m_shader, 1, &source, NULL); | |
glCompileShader(m_shader); | |
GLint shader_ok; | |
glGetShaderiv(m_shader, GL_COMPILE_STATUS, &shader_ok); | |
if (!shader_ok) { | |
GLint logLen = 0; | |
// Fuck you Qualcomm, your crappy drivers is PITA. | |
// Why the fuck GL_INFO_LOG_LENGTH is always zero? | |
#ifdef ANDROID | |
logLen = 1024; | |
#else | |
glGetShaderiv(m_shader, GL_INFO_LOG_LENGTH, &logLen); | |
#endif | |
char *lbuf = new char[logLen]; | |
glGetShaderInfoLog(m_shader, logLen, NULL, lbuf); | |
FAIL("Failed to compile shader %s: %s", origin, lbuf); | |
// We are dying anyway, so there is no point to free memory | |
} | |
} | |
Shader::~Shader() | |
{ | |
glDeleteShader(m_shader); | |
} | |
GLuint Shader::get() const | |
{ | |
return m_shader; | |
} | |
ShaderProgram::ShaderProgram() | |
: m_program(0) | |
{ | |
m_program = glCreateProgram(); | |
} | |
ShaderProgram::~ShaderProgram() | |
{ | |
glDeleteProgram(m_program); | |
} | |
void ShaderProgram::addShader(const Shader &shader) | |
{ | |
glAttachShader(m_program, shader.get()); | |
} | |
static int convertUniformType(GLenum type) | |
{ | |
#define CASE(g, v) case g: return Uniform::v | |
switch (type) { | |
CASE(GL_FLOAT_MAT4, MATRIX4); | |
CASE(GL_FLOAT_MAT3, MATRIX3); | |
CASE(GL_FLOAT_VEC4, VEC4); | |
CASE(GL_FLOAT_VEC3, VEC3); | |
CASE(GL_INT, INT); | |
CASE(GL_FLOAT, FLOAT); | |
CASE(GL_SAMPLER_2D, TEXTURE); | |
default: | |
ASSERT(0); | |
} | |
#undef CASE | |
return -1; | |
} | |
static uint32_t getComponentsCount(uint32_t type, const char *name) | |
{ | |
switch (type) { | |
case GL_FLOAT: | |
return 1; | |
break; | |
case GL_FLOAT_VEC2: | |
return 2; | |
break; | |
case GL_FLOAT_VEC3: | |
return 3; | |
break; | |
case GL_FLOAT_VEC4: | |
return 4; | |
break; | |
default: | |
FAIL("don't know how to handle attribute type %d for %s", type, name); | |
break; | |
} | |
} | |
template <class T> | |
static bool namecmp(const T &v1, const T &v2) | |
{ | |
return strcmp(v1.name, v2.name) < 0; | |
} | |
void ShaderProgram::link() | |
{ | |
glLinkProgram(m_program); | |
GLint program_ok; | |
glGetProgramiv(m_program, GL_LINK_STATUS, &program_ok); | |
if (!program_ok) { | |
GLint logLen = 0; | |
glGetProgramiv(m_program, GL_INFO_LOG_LENGTH, &logLen); | |
char *lbuf = new char[logLen]; | |
glGetProgramInfoLog(m_program, logLen, NULL, lbuf); | |
FAIL("Failed to compile program: %s", lbuf); | |
} | |
int nuf = 0; | |
glGetProgramiv(m_program, GL_ACTIVE_UNIFORMS, &nuf); | |
m_uniforms.resize(nuf); | |
for (int i = 0; i < nuf; i++) { | |
int len, size; | |
GLenum type; | |
UniformLocation &ul = m_uniforms[i]; | |
glGetActiveUniform(m_program, i, sizeof(ul.name), &len, &size, &type, ul.name); | |
ul.location = glGetUniformLocation(m_program, ul.name); | |
ul.type = convertUniformType(type); | |
} | |
std::sort(m_uniforms.begin(), m_uniforms.end(), namecmp<UniformLocation>); | |
int nattr = 0; | |
glGetProgramiv(m_program, GL_ACTIVE_ATTRIBUTES, &nattr); | |
m_attributes.resize(nattr); | |
for (int i = 0; i < nattr; i++) { | |
int len, size; | |
GLenum type; | |
AttributeLocation &al = m_attributes[i]; | |
glGetActiveAttrib(m_program, i, sizeof(al.name), &len, &size, &type, al.name); | |
al.location = glGetAttribLocation(m_program, al.name); | |
al.components = getComponentsCount(type, al.name); | |
} | |
std::sort(m_attributes.begin(), m_attributes.end(), namecmp<AttributeLocation>); | |
} | |
void ShaderProgram::use() const | |
{ | |
glUseProgram(m_program); | |
} | |
template <class T> | |
const T* binsearch(const std::vector<T> &vec, const char *key) | |
{ | |
int from = 0, to = vec.size(); | |
while (to-from > 0) { | |
size_t n = (to-from)/2; | |
size_t in = from+n; | |
const T *val = &vec[in]; | |
int cmp = strcmp(key, val->name); | |
if (cmp == 0) | |
return val; | |
if (cmp < 0) | |
to = in; | |
else | |
from = in+1; | |
} | |
return NULL; | |
} | |
GLint ShaderProgram::getAttribID(const char *name, uint32_t components) | |
{ | |
const AttributeLocation *al = binsearch(m_attributes, name); | |
if (!al) | |
FAIL("attribute %s not found\n", name); | |
if (al->components < components) | |
FAIL("shader attribute %s declares %d components but you are trying to bind %d components", | |
name, al->components, components); | |
return al->location; | |
} | |
int ShaderProgram::getUniformID(const char *name, int type) const | |
{ | |
const UniformLocation *ul = binsearch(m_uniforms, name); | |
if (!ul) | |
return -1; | |
if (ul->type != type) | |
FAIL("uniform type missmatch %s %d != %d\n", name, ul->type, type); | |
return ul->location; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef SHADER_H | |
#define SHADER_H | |
#include <vector> | |
#include <stdint.h> | |
#include "uniforms.h" | |
#include "sp.h" | |
class Shader : public RefCounted<Shader> { | |
unsigned m_type; | |
unsigned m_shader; | |
public: | |
Shader(unsigned type, const char *origin, const char *source); | |
~Shader(); | |
unsigned getType() const | |
{ | |
return m_type; | |
} | |
unsigned get() const; | |
}; | |
typedef boost::intrusive_ptr<Shader> ShaderPtr; | |
struct UniformLocation { | |
char name[64]; | |
int location; | |
int type; | |
}; | |
struct AttributeLocation { | |
char name[64]; | |
uint32_t location; | |
uint32_t components; | |
}; | |
class ShaderProgram : public RefCounted<ShaderProgram> { | |
public: | |
ShaderProgram(); | |
~ShaderProgram(); | |
void addShader(const Shader &shader); | |
void link(); | |
void use() const; | |
int getAttribID(const char *name, uint32_t components); | |
int getUniformID(const char *name, int type) const; | |
const std::vector<UniformLocation>& getUniforms() | |
{ | |
return m_uniforms; | |
} | |
private: | |
unsigned m_program; | |
std::vector<UniformLocation> m_uniforms; | |
std::vector<AttributeLocation> m_attributes; | |
}; | |
typedef boost::intrusive_ptr<ShaderProgram> ShaderProgramPtr; | |
#endif |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment