Here is working fork of the JUCE GL demo (the spinning teapot).
Just replace JUCE/examples/OpenGLAppExample/Source/MainComponent.cpp with: https://gist.github.com/p-i-/202c06f88f704b2ce96f
...and add a JUCE/examples/OpenGLAppExample/Source/AttribHelper.h containing: https://gist.github.com/p-i-/520f5e9cea09f345ca15
I've commented out the Attribute class in MainComponent.cpp, providing instead my own (Attr) class in AttribHelper.h.
Other changes to MainComponent.cpp are:
#include "AttribHelper.h"
void createShaders()
{
vertexShader =...
fragmentShader = ...
ScopedPointer<OpenGLShaderProgram> newShader (new OpenGLShaderProgram (openGLContext));
String statusText;
if (newShader->addVertexShader (OpenGLHelpers::translateVertexShaderToV3 (vertexShader))
&& newShader->addFragmentShader (OpenGLHelpers::translateFragmentShaderToV3 (fragmentShader))
&& newShader->link())
{
shape = nullptr;
attributes = nullptr;
uniforms = nullptr;
shader = newShader;
shader->use();
static const std::vector<AttrData> attr_data = {
ATTR_DATA( Vertex, position , "position" ),
ATTR_DATA( Vertex, colour , "sourceColour" ),
ATTR_DATA( Vertex, texCoord , "texureCoordIn" )
};
shape = new Shape (openGLContext);
attributes = new Attr (openGLContext, *shader, attr_data); //Attributes (openGLContext, *shader);
uniforms = new Uniforms (openGLContext, *shader);
statusText = "GLSL: v" + String (OpenGLShaderProgram::getLanguageVersion(), 2);
}
else
{
statusText = newShader->getLastError();
}
}
Then later...
//ScopedPointer<Attributes> attributes;
ScopedPointer<Attr> attributes;
That ATTR_DATA macro looks like this:
struct AttrData {
const char* name;
GLenum gltype;
uint32_t dim;
uint32_t byteoffset;
uint32_t stride_bytes;
OpenGLShaderProgram::Attribute* juce_attr;
//ScopedPointer<OpenGLShaderProgram::Attribute> juce_attr;
};
#define ATTR_DATA( Vert, Attr, NameString ) \
AttrData{ \
/* name */ NameString, \
/* gltype */ glconst4type< std::remove_extent< decltype(Vert::Attr) >::type >::value, \
/* dim */ std::extent< decltype(Vert::Attr) >::value, \
/* byteoffset */ offsetof(Vert, Attr), \
/* stride_bytes */ sizeof(Vert), \
/* juce_attr */ nullptr \
}
It looks as though JUCE currently only provides support for glVertexAttribPointer. However, there is also glVertexAttrib{I,L}Pointer.
That is to say that I don't think JUCE currently handles non-float vertex attributes.
My implementation provides handling for these, although I've commented it out for the time being.
π
PS Full listing for AttribHelper.h:
/*
AttribHelper.h
Created: 11 Mar 2015 10:56:40am
Author: π
==============================================================================
*/
#ifndef ATTRIBHELPER_H_INCLUDED
#define ATTRIBHELPER_H_INCLUDED
#include “…/JuceLibraryCode/JuceHeader.h”
template <typename T>
struct glconst4type
{
static_assert( std::is_same<T, void>::value, “Invalid type!” );
static constexpr GLenum value = 0;
};
template <> struct glconst4type<unsigned char> {static constexpr GLenum value = GL_UNSIGNED_BYTE;};
template <> struct glconst4type<signed char> {static constexpr GLenum value = GL_BYTE;};
//template <> struct glconst4type<char> {static constexpr GLenum value = Utils::is_char_signed ? GL_BYTE : GL_UNSIGNED_BYTE;};
template <> struct glconst4type<unsigned short> {static constexpr GLenum value = GL_UNSIGNED_SHORT;};
template <> struct glconst4type<signed short> {static constexpr GLenum value = GL_SHORT;};
template <> struct glconst4type<unsigned int> {static constexpr GLenum value = GL_UNSIGNED_INT;};
template <> struct glconst4type<signed int> {static constexpr GLenum value = GL_INT;};
template <> struct glconst4type<float> {static constexpr GLenum value = GL_FLOAT;};
template <> struct glconst4type<double> {static constexpr GLenum value = GL_DOUBLE;};
struct AttrData {
const char* name;
GLenum gltype;
uint32_t dim;
uint32_t byteoffset;
uint32_t stride_bytes;
OpenGLShaderProgram::Attribute* juce_attr;
//ScopedPointer<OpenGLShaderProgram::Attribute> juce_attr;
};
#define ATTR_DATA( Vert, Attr, NameString )
AttrData{
/* name / NameString,
/ gltype / glconst4type< std::remove_extent< decltype(Vert::Attr) >::type >::value,
/ dim / std::extent< decltype(Vert::Attr) >::value,
/ byteoffset / offsetof(Vert, Attr),
/ stride_bytes / sizeof(Vert),
/ juce_attr */ nullptr
}
#define CX(x) std::cout << “’” << #x << "’: " << x << std::endl
#define COUT(x) std::cout << x << std::endl
struct Attr
{
const OpenGLContext& m_openGLContext;
const OpenGLShaderProgram& m_shader;
std::vector<AttrData> m_data;
Attr( OpenGLContext& context, OpenGLShaderProgram& shader, const std::vector<AttrData>& data )
: m_openGLContext{context}, m_shader{shader}, m_data{data}
{
CX( m_data.size() );
for( int i=0; i < m_data.size(); i++ )
{
GLint location = m_openGLContext.extensions.glGetAttribLocation (m_shader.getProgramID(), m_data[i].name );
if( location > -1 )
m_data[i].juce_attr = new OpenGLShaderProgram::Attribute (m_shader, m_data[i].name);
else {
COUT( "Attribute " << m_data[i].name << "not found in vertex-shader!" );
jassert(false);
}
}
}
void enable()
{
for( int i=0; i < m_data.size(); i++ )
{
const AttrData& a = m_data[i];
// switch( a.gltype )
// {
// case glconst4type<float>::value :
m_openGLContext.extensions.glVertexAttribPointer(
(GLuint) a.juce_attr->attributeID,
(GLint) a.dim,
(GLenum) a.gltype,
(GLboolean) GL_FALSE, // normalized
(GLsizei) a.stride_bytes,
(const GLvoid*) (uintptr_t) a.byteoffset
);
// break;
// case glconst4type<double>::value :
//
// m_openGLContext.extensions.glVertexAttribLPointer(
// (GLuint) i,
// (GLint) a.dim,
// (GLenum) a.gltype,
// (GLsizei) a.stride_bytes,
// (const GLvoid*) a.byteoffset
// );
// break;
//
// case 0 :
// static_assert( false, “Invalid type!” );
// break;
//
// default:
//
// m_openGLContext.extensions.glVertexAttribIPointer(
// (GLuint) i,
// (GLint) a.dim,
// (GLenum) a.gltype,
// (GLsizei) a.stride_bytes,
// (const GLvoid*) a.byteoffset
// );
// } // switch
m_openGLContext.extensions.glEnableVertexAttribArray( a.juce_attr -> attributeID );
} // i
} // enable()
void disable()
{
for( int i=0; i < m_data.size(); i++ )
m_openGLContext.extensions.glDisableVertexAttribArray( m_data[i].juce_attr -> attributeID );
}
};
#endif // ATTRIBHELPER_H_INCLUDED