Recently I started using OpenGL in C++ for some 3D rendering, but oddly enough it seems to only work on a few machines. I'm using OpenGL 3.0 or higher (at the moment it is set to 3.0) using vertex array objects (not sure how its called, but the API revision that removed glBegin, glEnd and such).
Before testing it on another machine I always ask for their GPU drivers, most of them support OpenGL 4.2, if not, I make sure they at least support 3.0. Yet on some machines my application simply crashes, or doesn't render anything, OpenGL does not throw any errors (I check errors at least once each frame). It works perfectly fine on my own machine though, and in some cases my machine is even older than some machines on which it doesn't work.
I started using only OpenGL itself and GLEW, but switched to SFML and GLEW for ease of use and some other features I like, OpenGL itself didn't change its behavior though. I did rewrite the engine I was working on at some point to encapsulate all the GL calls and incorporate vertex array objects and some other features, in fact I can give you a list of all the API calls the application uses. Obviously it doesn't use of all of them in the test application, but these are all the calls I use in the engine (this is the bare minimum to be able to render, so yes, the engine is not even near finished):
- glAttachShader
- glBindAttribLocation
- glBindBuffer
- glBindVertexArray
- glBufferData
- glBufferSubData
- glClear
- glClearColor
- glClearDepth
- glCompileShader
- glCreateProgram
- glCreateShader
- glCullFace
- glDeleteBuffers
- glDeleteProgram
- glDeleteShader
- glDeleteVertexArrays
- glDepthFunc
- glDepthMask
- glDepthRange
- glDisableVertexAttribArray
- glDrawElements
- glEnable
- glEnableVertexAttribArray
- glFrontFace
- glGenBuffers
- glGenVertexArrays
- glGetAttribLocation
- glGetBufferParameteriv
- glGetBufferSubData
- glGetError
- glGetIntegerv
- glGetProgramInfoLog
- glGetProgramiv
- glGetShaderInfoLog
- glGetShaderiv
- glGetShaderSource
- glGetUniformLocation
- glIsProgram
- glIsShader
- glLinkProgram
- glMapBufferRange
- glPixelStorei
- glShaderSource
- glUniform(1i, 1ui, 1f, 2f, 3f, 4f, Matrix3fv, Matrix4fv)
- glUnmapBuffer
- glUseProgram
- glVertexAttrib(1i, 1ui, 1f, 2f, 3f, 4f)
- glVertexAttribPointer
In short, the Shader and ShaderProgram part is nothing special, I have some methods to create/compile them, set some attribute locations beforehand and finally set attributes/uniforms. The buffer objects aren't anything special either, you can write, read and map the buffers, at the moment I'm only using GL_ARRAY_BUFFER and GL_ELEMENT_ARRAY_BUFFER. Finally I'm using vertex array objects to actually render objects, obviously I set attribute pointers, and encapsulated draw calls and program usage, it always uses indexed drawing.
Also, I extensively searched on google and on stack overflow itself for an answer. But all the problems have to do with OpenGL not working anywhere, e.g. some API calls weren't called in order or not at all. Sadly none of these answers work for me, it has always worked on my own machine and other machines I can directly access, but it has never worked when I send the application to someone else to test it on their machine.
Hope this was specific enough XD
EDIT, copy from post down below
Every test is done on either windows vista or 7. I've thrown in an OpenGL error check for about each and every API call, and none seem to catch any error. I'm not able to reproduce it on my own machine, but after some more tracing on other machines I found that it does not crash untill rendering. The setup works fine, it creates all the buffers and objects perfectly fine, but as soon as I try to render a mesh (VAO) it crashes without any errors (well except .exe has stopped working). I suspect the commands glUseProgram or glDrawElements
About an example, unless you want to search through about 10 classes, I can't give you a short example
EDIT, tiny bit of code rendering an object
Mesh class adds these structs to the object so it knows what to draw:
// Define Geometry (draw command)
struct Geometry
{
// Primitives
PrimitiveType primitiveType;
// Indices
IndexType indexType;
unsigned int count; // elements
unsigned int offset; // bytes
};
Oh, btw, a 'geometry tag' is just a string under which multiple draw calls can be 'put', couple definitions:
// Define a list of primitives
typedef std::vector<Geometry> GeometryList;
// Define Geometry ordered by tag
typedef std::map<const std::string, GeometryList> GeometryMap;
For every 'draw' call it returns a string so the mesh class can bind the appropiate material.
//-----------------------------------------------------------------------
const std::string HardwareObject::nextGeometryTag()
{
// Loop back
GeometryMap::const_iterator end = _geometry.end();
if(_activeGeometry == end)
{
// Bind and go to begin
glBindVertexArray(_GL_VertexArray);
_activeGeometry = _geometry.begin();
}
// Check if new tag exists
else if(++_activeGeometry == end)
{
// Unbind and return empty tag
glBindVertexArray(0);
return "";
}
return _activeGeometry->first;
}
//-----------------------------------------------------------------------
bool HardwareObject::drawGeometryTag() const
{
// Validate current tag
if(_activeGeometry == _geometry.end()) return false;
// Draw each geometry call of tag
for(GeometryList::const_iterator it = _activeGeometry->second.begin(); it != _activeGeometry->second.end(); ++it)
glDrawElements(it->primitiveType, it->count, it->indexType, (void*)it->offset);
// GL Error
return !Console::GET().getError("HardwareObject Drawing");
}
//-----------------------------------------------------------------------
void HardwareObject::resetGeometryTag()
{
_activeGeometry = _geometry.end();
}
EDIT, the mesh calling all the above methods to actually render the object
the lockVertexAttributes() just makes sure all the attribute pointers are bound to the correct vertex buffer. The bind method of the HardwareProgram does nothing more than checking if the programs is compiled and calling glUseProgram
//-----------------------------------------------------------------------
bool Mesh::render()
{
// Lock vertex attributes
if(!lockVertexAttributes()) return false;
// To avoid errors
_object.resetGeometryTag();
// Loop while there's a tag
for(std::string tag = _object.nextGeometryTag(); tag != ""; tag = _object.nextGeometryTag())
{
// Find material
MaterialMap::const_iterator it = _materials.find(tag);
if(it == _materials.end()) continue;
// Bind material (get program directly)
const HardwareProgram *prog = it->second->getProgram();
if(!prog) continue;
if(!prog->bind()) continue;
// Draw tag
_object.drawGeometryTag();
}
// Ok!
return true;
}
GL_ELEMENT_ARRAY_BUFFER
binding in your VAO ? – SkerryglDrawElements
or equivalent. – Skerry