Code Assist, OpenGL VAO/VBO Classes not drawing - c++

Edit II:
Current Code works great! Thanks everyone. I went ahead and included my shader code for reference at the bottom though they do absolutely nothing at this point really.
I am trying to get up and going with OpenGL 4.1 and am still very early in development. Currently I'm not even really using 4.0 features yet in this project, so this is just as much an OpenGL 3 question as well.
The goal I was working on first was simply working out two classes to handle VAOs and VBOs. I had some misconceptions but finally got past the blank screen.
/* THIS CODE IS NOW FULLY FUNCTIONAL */
/* well, fully is questionable lol, should work out of the box with glew and glfw */
/* A simple function that will read a file into an allocated char pointer buffer */
/* Borrowed from OpenGL.org tutorial */
char* filePull(char *file)
{
FILE *fptr;
long length;
char *buf;
fptr = fopen(file, "r"); /* Open file for reading */
if (!fptr) /* Return NULL on failure */
return NULL;
fseek(fptr, 0, SEEK_END); /* Seek to the end of the file */
length = ftell(fptr); /* Find out how many bytes into the file we are */
buf = (char*)malloc(length+1); /* Allocate a buffer for the entire length of the file and a null terminator */
fseek(fptr, 0, SEEK_SET); /* Go back to the beginning of the file */
fread(buf, length, 1, fptr); /* Read the contents of the file in to the buffer */
fclose(fptr); /* Close the file */
buf[length] = 0; /* Null terminator */
return buf; /* Return the buffer */
}
class VBO
{
public:
GLuint buffer;
bool isBound;
vector<void*> belongTo;
vector<GLfloat> vertex;
GLenum usage;
void Load()
{ glBufferData(GL_ARRAY_BUFFER, vertex.size()*sizeof(GLfloat), &vertex[0], usage); }
void Create(void* parent)
{
glGenBuffers(1, &buffer);
glBindBuffer(GL_ARRAY_BUFFER, buffer);
glBufferData(GL_ARRAY_BUFFER, vertex.size()*sizeof(GLfloat), &vertex[0], usage);
isBound=true;
belongTo.push_back(parent);
}
void Activate()
{
if(!isBound) glBindBuffer(GL_ARRAY_BUFFER, buffer);
isBound=true;
}
void Deactivate(){ glBindBuffer(GL_ARRAY_BUFFER, 0); }
VBO() : isBound(false), usage(GL_STATIC_DRAW)
{ }
~VBO() { }
private:
};
class VAO
{
public:
GLuint buffer;
string key;
unsigned long long cursor;
vector<VBO> child;
void Create()
{
glGenVertexArrays(1, &buffer);
for(unsigned int i=0; i<child.size(); i++)
child[i].Create(this);
}
void Activate()
{
glBindVertexArray(buffer);
for(unsigned int i=0; i<child.size(); i++)
child[i].Activate();
}
void Release(){ glBindVertexArray(0); }
void Remove(){ glDeleteVertexArrays(1, &buffer); }
VAO() : buffer(1) { }
~VAO() { }
private:
};
int main()
{
int width=640, height=480, frame=1; bool running = true;
glfwInit();
if( !glfwOpenWindow( width, height, 0, 0, 0, 0, 0, 0, GLFW_WINDOW ) )
{ glfwTerminate(); return 13; }
glfwSetWindowTitle("Genesis");
glewInit();
cout<<(GLEW_VERSION_4_1?"yes":"no"); //yes
GLchar *vsource, *fsource;
GLuint _vs, _fs;
GLuint Shader;
vsource = filePull("base.vert");
fsource = filePull("base.frag");
/* Compile Shaders */
_vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(_vs, 1, (const GLchar**)&vsource, 0);
glCompileShader(_vs);
// glGetShaderiv(_vs, GL_COMPILE_STATUS, &IsCompiled_VS);
_fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(_fs, 1, (const GLchar**)&fsource, 0);
glCompileShader(_fs);
/***************** ^ Vertex | Fragment v *********************/
glAttachShader(Shader, _vs);
glAttachShader(Shader, _fs);
// glGetShaderiv(_fs, GL_COMPILE_STATUS, &IsCompiled_FS);
glBindAttribLocation(Shader, 0, "posIn");
glLinkProgram(Shader);
// glGetProgramiv(shaderprogram, GL_LINK_STATUS, (int *)&IsLinked);
VAO Object3D;
VBO myVBO[3];
glUseProgram(Shader);
for(int i=0; i<9; i++)
myVBO[0].vertex.push_back((i%9)*.11); //Arbitrary vertex values
Object3D.child.push_back(myVBO[0]);
Object3D.Create();
glClearColor( 0.7f, 0.74f, 0.77f, 0.0f ); //Black got lonely
int i=0; while(running)
{
frame++;
glfwGetWindowSize( &width, &height );
height = height > 0 ? height : 1;
glViewport( 0, 0, width, height );
glClear( GL_COLOR_BUFFER_BIT );
/* Bind, Draw, Unbind */
Object3D.Activate();
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, false, 0, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 9);
Object3D.Release();
glfwSwapBuffers();
// exit if ESC was pressed or window was closed
running = !glfwGetKey(GLFW_KEY_ESC) && glfwGetWindowParam( GLFW_OPENED);
i++;
}
glUseProgram(0); glDisableVertexAttribArray(0);
glDetachShader(Shader, _vs); glDetachShader(Shader, _fs);
glDeleteProgram(Shader); glDeleteShader(_vs); glDeleteShader(_fs);
glDeleteVertexArrays(1, &Object3D.buffer);
glfwTerminate();
return 0;
}
Basically I'm just hoping to get anything on the screen at this point. I am using glfw and glew. Am I completely leaving some things out or do I only need to correct something? Code is somewhat mangled at the moment, sorry.
base.vert
// Fragment Shader – file "base.vert"
#version 300
in vec3 posIn;
out vec4 colorOut;
void main(void)
{
gl_Position = vec4(posIn, 1.0);
colorOut = vec4(3.0,6.0,4.0,1.0);
}
base.frag
// Vertex Shader – file "base.frag"
#version 300
out vec3 colorOut;
void main(void)
{
colorOut = vec3(1.0,10,1.0);
}

&vertex
vertex is a vector. Taking its address will not give you a pointer to the data.
Edit to add:
Right. It still does not work, because you have at least 2 more issues:
You don't call any gl*Pointer call. The GL won't know what it needs to pull from your vertex buffer objects
your vertex data that you put in your vertex array is 3 times the same vertex. A triangle with the 3 points at the same location:
for(int i=0; i<9; i++)
myVBO[0].vertex.push_back((i%3)*.2); //Arbitrary vertex values
It creates 3 (.0 .2 .4) vectors, all at the same location.

That iBound member of VBO looks suspicious. The OpenGL binding state may change, for example after switching the bound VAO, but the VBO class instance still thinks it's active. Just drop iBound altogether and re-bind every time you need the object. With modern drivers rebinding an already bound object is almost for free.

Related

openGL GLFW White Screen w/ Loading Cursor on run

ISSUE: When launched, GLWindow displays only a white screen and the cursor displays a loading circle, signifying that something is still being loaded. The window displays "Not Responding" shortly after that.
I have tried downgrading to openGL 3.3 and have used glad to help with that, but the problem persists.
Hello all,
I've been working to create a sphere with alternating colors using a vertex shader.
The code that I've shared below was slightly altered from code that was used to shade a quad, which worked fine. I expect that there will be issues with similar logic being used to shade a circle, or to build a sphere and shade that. I am NOT at that point yet however. Something is keeping my GL Window from displaying properly and I am hoping that someone can help me with my GLFW and glew logic to share why the window is failing to load.
NOTE:I've edited this code to include comments for every step, which makes it seem much longer than it is. I would appreciate any help or insight.
PRIMARY CLASS
#include <iostream>
#include <sstream>
#define GLEW_STATIC
//always GLEW before GLFW
#include "GL/glew.h"
#include "GLFW/glfw3.h"
#include "glm/glm.hpp"
#include "ShaderProgram.h"
#ifndef M_PI
# define M_PI 3.141592653
#endif
/////gLOBAL
GLFWwindow* w = NULL;
const int wWidth = 800;
const int wHeight = 600;
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode);
//update colors based on average framerate
void averageFPS(GLFWwindow* window);
//screen resizing
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height);
bool initOpenGL();
static void error(int error, const char *desc)
{
fputs(desc, stderr);
}
//setting up values for keys
int main() {
if (!initOpenGL()) ///5IMPR
{
// An error occured
std::cerr << "GLFW not initialized" << std::endl;
return -1;
}
glfwSetErrorCallback(error);
GLfloat vertices[] = {
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
-0.5f, 1.0f, 0.0f
};
GLuint indices[] = {
0, 1, 2,
0, 2, 3
};
// 2. Set up buffers on the GPU
GLuint vbo, ibo, vao;
glGenBuffers(1, &vbo); // Generate an empty vertex buffer on the GPU
glBindBuffer(GL_ARRAY_BUFFER, vbo); // "bind" or set as the current buffer we are working with
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); // copy the data from CPU to GPU
glGenVertexArrays(1, &vao); // Tell OpenGL to create new Vertex Array Object
glBindVertexArray(vao); // Make it the current one
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL); // Define a layout for the first vertex buffer "0"
glEnableVertexAttribArray(0); // Enable the first attribute or attribute "0"
// Set up index buffer
glGenBuffers(1, &ibo); // Create buffer space on the GPU for the index buffer
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW);
glBindVertexArray(0); // unbind to make sure other code doesn't change it
ShaderProgram shaderProgram;
shaderProgram.assignShaders("shaders/ColorShader.vert", "shaders/ColorShader.frag");
////////SETUP RENDERING
while (!glfwWindowShouldClose(w))
{
averageFPS(w);
//process events
glfwPollEvents();
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT);
shaderProgram.use();
GLfloat time = (GLfloat)glfwGetTime();
GLfloat blueSetting = (sin(time) / 2) + 0.5f;
glm::vec2 pos;
pos.x = sin(time) / 2;
pos.y = cos(time) / 2;
shaderProgram.setUniform("vertColor", glm::vec4(0.0f, 0.0f, blueSetting, 1.0f));
shaderProgram.setUniform("posOffset", pos);
/////COLOR OF CIRCLE OUTLINE
//glColor4f(0.0, 0.0, 1.0, 1.0); //RGBA
//PRIMARY BODY
// Draw our line
glBegin(GL_LINE_LOOP);
//glColor3f(0,0,1);
static double iteration = 0;
// The x, y offset onto the screen -- this should later be centered
static const int offset = 150;
static const float radius = 50;
// Calculate our x, y cooredinates
double x1 = offset + radius + 100 * cos(1);
double y1 = offset + radius + 100 * sin(1);
static double wobble = 0.0;
// A = (π * r²)
double a = M_PI * (100 * 2); //area
// C = (2 * π * r)
double c = 2 * M_PI * 100; //circumference
static double b = 128;
for (double i = 0; i < 2 * M_PI; i = i + ((2 * M_PI) / b))
{
double x = x1 + radius * cos(i);
double y = y1 + radius * sin(i);
glVertex2f(x, y);
glVertex2f(x, y);
}
iteration += 0.01;
////PRIMARY BODY End
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
//glDrawElements(GL_LINE_LOOP, 6, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
// Swap buffers and look for events
glfwSwapBuffers(w);
}
//clean up
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(1, &vbo);
glDeleteBuffers(1, &ibo);
//glfwDestroyWindow(w);
glfwTerminate();
return 0;
}
///////START Initializing glfw glew etc
bool initOpenGL(){
//this method will exit on these conditions
GLuint error = glfwInit();
if (!error)
return false;
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
w = glfwCreateWindow(wWidth, wHeight, "Exercise", NULL, NULL);
//Filling Window
if (w== NULL)
{
std::cerr << "glfw window not created" << std::endl;
glfwTerminate();
return false;
}
//update context
glfwMakeContextCurrent(w);
// Initialize GLEWunifor
glewExperimental = GL_TRUE;
GLuint err = glewInit();
if (err != GLEW_OK)
{
std::cerr << "initialize GLEW Failed" << std::endl;
return false;
}
//setup key callbacks
glfwSetKeyCallback(w, key_callback);
glfwSetFramebufferSizeCallback(w, glfw_onFramebufferSize);
while (!glfwWindowShouldClose(w))
{
//int width, height;
// glfwGetFramebufferSize(w, &width, &height); //move out of while??
// glViewport(0, 0, width, height); //remove??
}
glClearColor(0.23f, 0.38f, 0.47f, 1.0f); ///5ADD
// Define the viewport dimensions
glViewport(0, 0, wWidth, wHeight); //necessary?
return true;
}
void key_callback(GLFWwindow *w, int key, int scancode, int action, int mode)
{
// See http://www.glfw.org/docs/latest/group__keys.html
if ((key == GLFW_KEY_ESCAPE || key == GLFW_KEY_Q) && action == GLFW_PRESS)
glfwSetWindowShouldClose(w, GL_TRUE);
if (key == GLFW_KEY_W && action == GLFW_PRESS)
{
bool showWires = false;
if (showWires)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
else
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
}
}
//whever window resizes, do this
void glfw_onFramebufferSize(GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
}
void averageFPS(GLFWwindow* window) ///5ADDdown
{
static double previousSeconds = 0.0;
static int frameCount = 0;
double passedSeconds;
double currentSeconds = glfwGetTime(); //seconds since GLFW started
passedSeconds = currentSeconds - previousSeconds;
// Limit time updates to 4 times per second
if (passedSeconds > 0.25)
{
previousSeconds = currentSeconds;
double fps = (double)frameCount / passedSeconds;
// double frameInMilSecs = 1000.0 / fps;
frameCount = 0;}
frameCount++;
}
SHADER MANAGER/HANDLER CLASS
#include "ShaderProgram.h"
#include <fstream>
#include <iostream>
#include <sstream>
ShaderProgram::ShaderProgram()
: mProgram(0){
}
ShaderProgram::~ShaderProgram()
{
glDeleteProgram(mProgram);
}
bool ShaderProgram::assignShaders(const char* vertFileName, const char* fragFileName)
{
//Shaders output objects called programs that define their relationship and lead to .exe functionality
//assigning pointer to the shader
string vsString = readFile(vertFileName);
string fsString = readFile(fragFileName);
const GLchar* fsSourcePtr = fsString.c_str();
const GLchar* vsSourcePtr = vsString.c_str();
//creating vertex shader(vs) shader object
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
//assigning shader source using address. Replaces the source code in a shader object //#arg (shader, count Strings, pointer to const File ,size)
glShaderSource(vs, 1, &vsSourcePtr, NULL);
glShaderSource(fs, 1, &fsSourcePtr, NULL);
glCompileShader(vs);
glCompileShader(fs);
testProgramCompile();
testShaderCompile(vs);
testShaderCompile(fs);
//createProgram returns GLUint which is basically an unsigned int... we will use This Handler to create a program object
mProgram = glCreateProgram();
if (mProgram == 0)
{
std::cerr << "Shader cannot be created" << std::endl;
return false;
}
//assign the program object(mProgram) to the Shader
glAttachShader(mProgram, vs);
glAttachShader(mProgram, fs);
//this method accepts a GLuint "program" . If its an object of type GL_VERTEX_SHADER,
//itll create a .exe that runs on the programmable vertex processor. same goes for geometric and fragment shaders if they were included
//it will also bind all user defined uniform variables and attributes to the program
//The program can then be made part of a defined state by calling useProgram
glLinkProgram(mProgram);
testProgramCompile();
testShaderCompile(vs);
testShaderCompile(vs);
//cleaning up the elements we already used
glDeleteShader(vs);
glDeleteShader(fs);
//clear the identifier lookup map(in this case, there's only one)
mUniformIdentifiers.clear();
return true;
}//end main
//Read the shaderFile. strngstream for reading multiple lines
string ShaderProgram:: readFile(const string& filename) {
std::stringstream strgstream;
std::ifstream file;
try
{
file.open(filename, std::ios::in);
if (!file.fail())
{
strgstream << file.rdbuf();
}
file.close();
}
catch (std::exception e)
{
std::cerr << "Error: File or File Name Issues" << std::endl;
}
return strgstream.str();
}
//use the Program Object we created in this current state(color)
void ShaderProgram::use()
{
if (mProgram != 0)
glUseProgram(mProgram);
}
void ShaderProgram::testProgramCompile() {
int status = 0;
GLuint program = mProgram;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetProgramiv( mProgram, GL_LINK_STATUS, &status); //requesting the status
if (status == GL_FALSE)
{
std::cerr << "Linking Error with Program " << std::endl;
}
}
void ShaderProgram :: testShaderCompile(GLuint shader) {
int status = 0;
// ///CHECKING GL_LINK_STATUS to see if Program Link was successul. Link Status will return GL_TRUE if it was
glGetProgramiv(shader, GL_LINK_STATUS, &status); //requesting the status
if (status == GL_FALSE)
{
std::cerr << "Linking Error with Shader " << std::endl;
}
}
////GETTERS AND SETTERS
GLuint ShaderProgram::getProgram() const
{
return mProgram;
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec2& v)
{
GLint address = getUniformIdentifier(name);
glUniform2f(address, v.x, v.y);
}
void ShaderProgram::setUniform(const GLchar* name, const glm::vec3& v)
{
GLint address = getUniformIdentifier(name);
glUniform3f(address, v.x, v.y, v.z);
}
void ShaderProgram:: setUniform(const GLchar* name, const glm::vec4& v) {
GLint address = getUniformIdentifier(name);
glUniform4f(address, v.x, v.y, v.z, v.w);
}
//Maybe need to switch places with setUniform
GLint ShaderProgram :: getUniformIdentifier(const GLchar* name) {
std::map<std::string, GLint>::iterator it;
it = mUniformIdentifiers.find(name);
//std::map<std::string, GLint>
// Only need to query the shader program IF it doesn't already exist.
if (it == mUniformIdentifiers.end())
{
// Find it and add it to the map
mUniformIdentifiers[name] = glGetUniformLocation(mProgram, name);
}
// Return it
return mUniformIdentifiers[name];
}
You have this in your init function.
while (!glfwWindowShouldClose(w))
{
//int width, height;
// glfwGetFramebufferSize(w, &width, &height); //move out of while??
// glViewport(0, 0, width, height); //remove??
}
Your code is presumably hanging here.

GtkGLArea clears background but does not draw

I have been writing a simple GTK+ application and am just getting started with graphical development. I understand that this may not be a good place to start, jumping straight into 3D rendering, but I've done a small amount of it before and with great success using Glade and reading a plethora of docs, I figured it would not be hard to integrate the two - I figured incorrectly. The problem at hand is that glDrawArrays appears to not be working. I looked at this question and unfortunately, it did not help me. I followed some of this tutorial on OpenGL and also this tutorial on GtkGLArea again to no avail.
Can anyone point me in the right direction on this one? I'm not sure where to go from here.
The relevant code is below:
#include "RenderingManager.hpp"
RenderingManager::RenderingManager() {
///GTK+ Setup///
std::cout << "starting render constructor" << std::endl;
glArea = GTK_GL_AREA(gtk_gl_area_new());
std::cout << "got new glarea" << std::endl;
g_signal_connect(GTK_WIDGET(glArea), "render", G_CALLBACK(signal_render), this);
g_signal_connect(GTK_WIDGET(glArea), "realize", G_CALLBACK(signal_realize), this);
g_signal_connect(GTK_WIDGET(glArea), "unrealize", G_CALLBACK(signal_unrealize), this);
gtk_widget_show(GTK_WIDGET(glArea));
///Get Shaders///
// vshader.open("vertex.shader");
// fshader.open("fragment.shader");
std::cout << "finished render constructor" << std::endl;
}
void RenderingManager::onRender() {
// Dark blue background
glClearColor(0.1f, 0.0f, 0.1f, 0.0f);
draw_triangle();
glFlush();
}
void RenderingManager::initBuffers () {
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(g_vertex_buffer_data), g_vertex_buffer_data, GL_STATIC_DRAW);
}
void RenderingManager::loadShaders() {
// Read the Vertex Shader code from the file
std::ifstream VertexShaderStream("vertex.shader", std::ios::in);
if(VertexShaderStream.is_open()){
std::string Line = "";
while(getline(VertexShaderStream, Line))
vshader += "\n" + Line;
VertexShaderStream.close();
}
// Read the Fragment Shader code from the file
std::ifstream FragmentShaderStream("fragment.shader", std::ios::in);
if(FragmentShaderStream.is_open()){
std::string Line = "";
while(getline(FragmentShaderStream, Line))
fshader += "\n" + Line;
FragmentShaderStream.close();
}
GLuint vsh, fsh;
vsh = glCreateShader(GL_VERTEX_SHADER);
fsh = glCreateShader(GL_FRAGMENT_SHADER);
vshp = vshader.data();
fshp = fshader.data();
// vshp = vshader.get().c_str();
// fshp = fshader.get().c_str();
// vshader.get(vshp);
// fshader.get(fshp);
printf("%s\n%s\n", vshp, fshp);
glShaderSource(vsh, 1, &vshp, NULL);
glShaderSource(fsh, 1, &fshp, NULL);
glCompileShader(vsh);
glCompileShader(fsh);
shaderProgramID = glCreateProgram();
glAttachShader(shaderProgramID, vsh);
glAttachShader(shaderProgramID, fsh);
glLinkProgram(shaderProgramID);
GLint Result = GL_FALSE;
int InfoLogLength;
// Check Vertex Shader
glGetShaderiv(vsh, GL_COMPILE_STATUS, &Result);
glGetShaderiv(vsh, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
char* VertexShaderErrorMessage = new char[InfoLogLength+1];
glGetShaderInfoLog(vsh, InfoLogLength, NULL, &VertexShaderErrorMessage[0]);
printf("%s\n", &VertexShaderErrorMessage[0]);
}
// Check Fragment Shader
glGetShaderiv(fsh, GL_COMPILE_STATUS, &Result);
glGetShaderiv(fsh, GL_INFO_LOG_LENGTH, &InfoLogLength);
if ( InfoLogLength > 0 ){
char* FragmentShaderErrorMessage = new char[InfoLogLength+1];
glGetShaderInfoLog(fsh, InfoLogLength, NULL, &FragmentShaderErrorMessage[0]);
printf("%s\n", &FragmentShaderErrorMessage[0]);
}
}
void RenderingManager::onActivate() {
// We need to make the context current if we want to
// call GL API
gtk_gl_area_make_current (glArea);
glewExperimental = GL_TRUE;
glewInit();
loadShaders();
initBuffers();
}
void RenderingManager::signal_render(GtkGLArea *a, gpointer *user_data) {
reinterpret_cast<RenderingManager*>(user_data)->onRender();
}
void RenderingManager::signal_realize(GtkGLArea *a, gpointer *user_data) {
reinterpret_cast<RenderingManager*>(user_data)->onActivate();
}
void RenderingManager::signal_unrealize(GtkGLArea *a, gpointer *user_data) {
//Don't do this
//reinterpret_cast<RenderingManager*>(user_data)->~RenderingManager();
}
void RenderingManager::draw_triangle() {
// Clear the screen
glClear( GL_COLOR_BUFFER_BIT );
// Use our shader
glUseProgram(shaderProgramID);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(0);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangle !
glDrawArrays(GL_TRIANGLES, 0, 3); // 3 indices starting at 0 -> 1 triangle
glDisableVertexAttribArray(0);
}
GtkGLArea *RenderingManager::expose() {
//yikes
return glArea;
}
RenderingManager::~RenderingManager() {
glDeleteBuffers(1, &vbo);
glDeleteVertexArrays(1, &vao);
glDeleteProgram(shaderProgramID);
std::cout << "GL Resources deleted." << std::endl;
}
Due to the asynchronous nature of X11 (Gtk+ uses it) the gl-context can't be created before the window is realized (a connection to X11 is made).
Create the gl-context in your signal_realize() and make it current before drawing, which should be done handling signal expose_event (gtk+ 2) or draw(gtk+ 3)

Use different shader programs in OpenGL?

I have to use two different shader programs in OpenGL for different objects.
I found that I have to use glUseProgram() to switch between different shader programs, but not much information on that.
How does generating and binding VAOs and VBOs work for each shader program (how & when) given that I have two different shader programs I use for different objects?
When you render objects in OpenGL, your code will look like this:
Bind program with glUseProgram, set uniforms with glUniform4fv, glUniformMatrix4fv, etc.
Bind the vertex array with glBindVertexArray.
Bind any textures you need with glActiveTexture and glBindTexture.
Change any other state, e.g., glEnable, glDisable, glBlendFunc.
Draw with glDrawArrays or glDrawElements.
If you want, reset state back to defaults.
These are all the things that you tend to do in vanilla OpenGL 3 code. You should already have this part working.
If you need to write multiple objects with different shader programs, you just do the above steps multiple times. State changes can be omitted if you are going to use the same state for multiple programs (except uniforms, which are saved separately for each program). For example, you might use the same VAO, the same textures, the same blending function, et cetera.
There are many tutorials on how OpenGL 3 drawing commands work, if you are looking for more detailed examples.
It is possible to switch program objects without having to specify their arguments all over again. In order for it to work, though, you must pre-assign the values of your vertex attribute array indices before compiling and linking, using glBindAttribLocation, making sure each of your programs uses separate indices. If you don't, then the same VBO may go to both programs. The VBOs being used by both programs must all be in the same VAO, which must be bound while the programs are active and the Draw commands are executed.
Here's an example:
// HELPER FUNCTIONS
// ================
// Read a file to a string.
char *load(const char *fn)
{
int fd = open(fn, O_RDONLY);
assert(fd != -1);
off_t size = lseek(fd, 0, SEEK_END);
assert(size != -1);
off_t res = lseek(fd, 0, SEEK_SET);
assert(res != -1);
size++; // null terminator
char *buf = (char *)malloc(size);
char *p = buf;
for (;;) {
// File has gotten bigger since we started? Fuck that.
assert(p - buf < size);
ssize_t nread = read(fd, (char *)p, 0x10000);
assert(nread != -1);
if (nread == 0) {
*p = '\0';
break;
}
#ifndef NDEBUG
// Null character? Fuck that shit.
void *nullbyte = memchr((char *)p, '\0', nread);
assert(nullbyte == NULL);
#endif
p += nread;
}
int cres = close(fd);
assert(cres == 0);
return buf;
}
// Compile the "type" shader named "filename" and attach it to
// "shader_program".
static void compile_shader(GLenum type, const char *filename,
GLuint shader_program)
{
GLuint shader = glCreateShader(type);
char *source = load(filename);
glShaderSource(shader, 1, &source, 0);
glCompileShader(shader);
#ifndef NDEBUG
GLint success;
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
if (!success) {
GLint log_length;
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
char *log = (char *)malloc(log_length);
glGetShaderInfoLog(shader, log_length, NULL, log);
fprintf(stderr, "Failed to compile %s:\n%s", filename, log);
abort();
}
#endif
glAttachShader(shader_program, shader);
}
// Return a shader program with vertex shader "vertfile" and the fragment
// shader "fragfile". The program is not linked, in case stuff still needs to
// be added.
GLuint compile_shader_program(const char *vertfile, const char *fragfile)
{
GLuint p = glCreateProgram();
compile_shader(GL_VERTEX_SHADER, vertfile, p);
compile_shader(GL_FRAGMENT_SHADER, fragfile, p);
return p;
}
// . . .
// INIT
// ====
// Make and bind the VAO, shared between both programs.
GLuint vao;
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
// Init one_program.
float square[] = {0.f, 0.f, 1.f, 0.f, 0.f, 1.f, 1.f, 1.f};
GLuint vbo;
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(square), square, GL_STATIC_DRAW);
// Make sure these indices are unique among all VBOs you are using to render.
GLuint attr = 0;
glEnableVertexAttribArray(attr);
glVertexAttribPointer(attr, 2, GL_FLOAT, GL_FALSE, 0, NULL);
GLuint one_program = compile_shader_program("glsl/2d.vert", "glsl/white.frag");
glBindAttribLocation(one_program, attr, "vertex_pos");
glLinkProgram(one_program);
// Set uniforms.
// . . .
// Do the same thing for the_other_program.
float triangle[] = {0.f, 0.f, 1.f, 0.f, 0.f, 1.f};
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(square), square, GL_STATIC_DRAW);
attr++;
glEnableVertexAttribArray(attr);
glVertexAttribPointer(attr, 2, GL_FLOAT, GL_FALSE, 0, NULL);
GLuint the_other_program =
compile_shader_program("glsl/2d.vert", "glsl/chrome.frag");
glBindAttribLocation(the_other_program, attr, "vertex_pos");
glLinkProgram(the_other_program);
// Set uniforms.
// . . .
// RENDER ONE FRAME
// ================
glUseProgram(one_program);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glUseProgram(the_other_program);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 3);

NVidia driver 320.86 texture buffer bug leads to crash

The following code crashes really quickly ( way before the max buffer size of 2^27 texels )
I stripped every useless line of code, to make it easier to read.
const int MAX_LAYER_DEPTH = 5;
#include "vapp.h"
#include "vmath.h"
#include <stdio.h>
BEGIN_APP_DECLARATION(OITDemo)
// Override functions from base class
virtual void Initialize(const char * title);
virtual void Display(bool auto_redraw);
virtual void Finalize(void);
virtual void Reshape(int width, int height);
GLuint linked_list_buffer;
GLuint linked_list_texture;
GLint current_width;
GLint current_height;
END_APP_DECLARATION()
DEFINE_APP(OITDemo, "Order Independent Transparency")
void OITDemo::Initialize(const char * title)
{
base::Initialize(title);
glGenBuffers(1, &linked_list_buffer);
glGenTextures(1, &linked_list_texture);
Reshape(100,100);
return;
}
void OITDemo::Display(bool auto_redraw)
{
glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
glBindImageTexture(1, linked_list_texture, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT);
base::Display();
return;
}
void OITDemo::Reshape(int width, int height)
{
current_width = width;
current_height = height;
glBindImageTexture(1, 0, 0, GL_FALSE, 0, GL_WRITE_ONLY, GL_RGBA32UI);
static GLuint texBufferSize = 2047;
++texBufferSize;
printf("%d : texBufferSize\n",texBufferSize);
glBindBuffer(GL_TEXTURE_BUFFER, linked_list_buffer);
glBufferData(GL_TEXTURE_BUFFER, texBufferSize * texBufferSize * MAX_LAYER_DEPTH * sizeof(vmath::vec4), NULL, GL_DYNAMIC_DRAW);
glBindBuffer(GL_TEXTURE_BUFFER, 0);
// Bind it to a texture (for use as a TBO)
glBindTexture(GL_TEXTURE_BUFFER, linked_list_texture);
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32UI, linked_list_buffer);
glBindTexture(GL_TEXTURE_BUFFER, 0);
glViewport(0, 0, current_width, current_height);
return;
}
void OITDemo::Finalize(void)
{
glDeleteTextures(1, &linked_list_texture);
glDeleteBuffers(1, &linked_list_buffer);
}
The driver most probably can't handle fragmentation
It crashes between reallocation of 21694445 ( 2083 x 2083 x 5 ) and 23587920 elements. The maximum buffer size ( number of texels ) returned by the graphic card is 2^27 ( 134 millions texels )
It seems to work better if we allocate one big buffer at the start of the application and never change it.
But fails miserably if we try to reallocate it during the life of the application.
Originally the code binds the image texture then trace using a shader that uses that image texture with imageStore but I discovered that I don't need any shader to make the driver crash.
Any clue to predict/prevent the driver crash?

Why am I getting "r300 FP: Compiler Error:" while attempting this OpenGL tutorial?

I downloaded the tutorial from OpenGL-tutorial.org, the OpenGL 2.1 port. I followed the directions to compile it (using C-make). Everything was working fine until I tried to run the tutorial for lesson 8. The terminal outputed the following message when I tried to run the executable from command line:
$ ./tutorial08_basic_shading
Compiling shader : StandardShading.vertexshader
Compiling shader : StandardShading.fragmentshader
Linking program
Loading OBJ file suzanne.obj...
r300 FP: Compiler Error:
Too many hardware temporaries used.
Using a dummy shader instead.
The resulting program that ran displayed a object that was completely black:
It should have looked like this:
The program tutorial08_basic_shading was compiled using tutorial08.cpp:
// Include standard headers
#include <stdio.h>
#include <stdlib.h>
#include <vector>
// Include GLEW
#include <GL/glew.h>
// Include GLFW
#include <GL/glfw.h>
// Include GLM
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
using namespace glm;
#include <common/shader.hpp>
#include <common/texture.hpp>
#include <common/controls.hpp>
#include <common/objloader.hpp>
#include <common/vboindexer.hpp>
int main( void )
{
// Initialise GLFW
if( !glfwInit() )
{
fprintf( stderr, "Failed to initialize GLFW\n" );
return -1;
}
glfwOpenWindowHint(GLFW_FSAA_SAMPLES, 4);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MAJOR, 2);
glfwOpenWindowHint(GLFW_OPENGL_VERSION_MINOR, 1);
// Open a window and create its OpenGL context
if( !glfwOpenWindow( 1024, 768, 0,0,0,0, 32,0, GLFW_WINDOW ) )
{
fprintf( stderr, "Failed to open GLFW window.\n" );
glfwTerminate();
return -1;
}
// Initialize GLEW
if (glewInit() != GLEW_OK) {
fprintf(stderr, "Failed to initialize GLEW\n");
return -1;
}
glfwSetWindowTitle( "Tutorial 08" );
// Ensure we can capture the escape key being pressed below
glfwEnable( GLFW_STICKY_KEYS );
glfwSetMousePos(1024/2, 768/2);
// Dark blue background
glClearColor(0.0f, 0.0f, 0.4f, 0.0f);
// Enable depth test
glEnable(GL_DEPTH_TEST);
// Accept fragment if it closer to the camera than the former one
glDepthFunc(GL_LESS);
// Cull triangles which normal is not towards the camera
glEnable(GL_CULL_FACE);
// Create and compile our GLSL program from the shaders
GLuint programID = LoadShaders( "StandardShading.vertexshader", "StandardShading.fragmentshader" );
// Get a handle for our "MVP" uniform
GLuint MatrixID = glGetUniformLocation(programID, "MVP");
GLuint ViewMatrixID = glGetUniformLocation(programID, "V");
GLuint ModelMatrixID = glGetUniformLocation(programID, "M");
// Get a handle for our buffers
GLuint vertexPosition_modelspaceID = glGetAttribLocation(programID, "vertexPosition_modelspace");
GLuint vertexUVID = glGetAttribLocation(programID, "vertexUV");
GLuint vertexNormal_modelspaceID = glGetAttribLocation(programID, "vertexNormal_modelspace");
// Load the texture
GLuint Texture = loadDDS("uvmap.DDS");
// Get a handle for our "myTextureSampler" uniform
GLuint TextureID = glGetUniformLocation(programID, "myTextureSampler");
// Read our .obj file
std::vector<glm::vec3> vertices;
std::vector<glm::vec2> uvs;
std::vector<glm::vec3> normals;
bool res = loadOBJ("suzanne.obj", vertices, uvs, normals);
// Load it into a VBO
GLuint vertexbuffer;
glGenBuffers(1, &vertexbuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
GLuint uvbuffer;
glGenBuffers(1, &uvbuffer);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glBufferData(GL_ARRAY_BUFFER, uvs.size() * sizeof(glm::vec2), &uvs[0], GL_STATIC_DRAW);
GLuint normalbuffer;
glGenBuffers(1, &normalbuffer);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glBufferData(GL_ARRAY_BUFFER, normals.size() * sizeof(glm::vec3), &normals[0], GL_STATIC_DRAW);
// Get a handle for our "LightPosition" uniform
glUseProgram(programID);
GLuint LightID = glGetUniformLocation(programID, "LightPosition_worldspace");
do{
// Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Use our shader
glUseProgram(programID);
// Compute the MVP matrix from keyboard and mouse input
computeMatricesFromInputs();
glm::mat4 ProjectionMatrix = getProjectionMatrix();
glm::mat4 ViewMatrix = getViewMatrix();
glm::mat4 ModelMatrix = glm::mat4(1.0);
glm::mat4 MVP = ProjectionMatrix * ViewMatrix * ModelMatrix;
// Send our transformation to the currently bound shader,
// in the "MVP" uniform
glUniformMatrix4fv(MatrixID, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(ModelMatrixID, 1, GL_FALSE, &ModelMatrix[0][0]);
glUniformMatrix4fv(ViewMatrixID, 1, GL_FALSE, &ViewMatrix[0][0]);
glm::vec3 lightPos = glm::vec3(4,4,4);
glUniform3f(LightID, lightPos.x, lightPos.y, lightPos.z);
// Bind our texture in Texture Unit 0
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, Texture);
// Set our "myTextureSampler" sampler to user Texture Unit 0
glUniform1i(TextureID, 0);
// 1rst attribute buffer : vertices
glEnableVertexAttribArray(vertexPosition_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, vertexbuffer);
glVertexAttribPointer(
vertexPosition_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 2nd attribute buffer : UVs
glEnableVertexAttribArray(vertexUVID);
glBindBuffer(GL_ARRAY_BUFFER, uvbuffer);
glVertexAttribPointer(
vertexUVID, // The attribute we want to configure
2, // size : U+V => 2
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// 3rd attribute buffer : normals
glEnableVertexAttribArray(vertexNormal_modelspaceID);
glBindBuffer(GL_ARRAY_BUFFER, normalbuffer);
glVertexAttribPointer(
vertexNormal_modelspaceID, // The attribute we want to configure
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(void*)0 // array buffer offset
);
// Draw the triangles !
glDrawArrays(GL_TRIANGLES, 0, vertices.size() );
glDisableVertexAttribArray(vertexPosition_modelspaceID);
glDisableVertexAttribArray(vertexUVID);
glDisableVertexAttribArray(vertexNormal_modelspaceID);
// Swap buffers
glfwSwapBuffers();
} // Check if the ESC key was pressed or the window was closed
while( glfwGetKey( GLFW_KEY_ESC ) != GLFW_PRESS &&
glfwGetWindowParam( GLFW_OPENED ) );
// Cleanup VBO and shader
glDeleteBuffers(1, &vertexbuffer);
glDeleteBuffers(1, &uvbuffer);
glDeleteBuffers(1, &normalbuffer);
glDeleteProgram(programID);
glDeleteTextures(1, &Texture);
// Close OpenGL window and terminate GLFW
glfwTerminate();
return 0;
}
The system it was compiled on is running Ubuntu 13.04 Raring Ringtail. The compiler was g++ I believe, and I am using OpenGL drivers for the ATI Radian xpress 1100 notebook graphics card (the proprietary drivers aren't compatible).
I was able to edit previous examples and compile them with g++ without any problems this far. The only new functions for this tutorial are found in objloader.cpp:
#include <vector>
#include <stdio.h>
#include <string>
#include <cstring>
#include <glm/glm.hpp>
#include "objloader.hpp"
// Very, VERY simple OBJ loader.
// Here is a short list of features a real function would provide :
// - Binary files. Reading a model should be just a few memcpy's away, not parsing a file at runtime. In short : OBJ is not very great.
// - Animations & bones (includes bones weights)
// - Multiple UVs
// - All attributes should be optional, not "forced"
// - More stable. Change a line in the OBJ file and it crashes.
// - More secure. Change another line and you can inject code.
// - Loading from memory, stream, etc
bool loadOBJ(
const char * path,
std::vector<glm::vec3> & out_vertices,
std::vector<glm::vec2> & out_uvs,
std::vector<glm::vec3> & out_normals
){
printf("Loading OBJ file %s...\n", path);
std::vector<unsigned int> vertexIndices, uvIndices, normalIndices;
std::vector<glm::vec3> temp_vertices;
std::vector<glm::vec2> temp_uvs;
std::vector<glm::vec3> temp_normals;
FILE * file = fopen(path, "r");
if( file == NULL ){
printf("Impossible to open the file ! Are you in the right path ? See Tutorial 1 for details\n");
return false;
}
while( 1 ){
char lineHeader[128];
// read the first word of the line
int res = fscanf(file, "%s", lineHeader);
if (res == EOF)
break; // EOF = End Of File. Quit the loop.
// else : parse lineHeader
if ( strcmp( lineHeader, "v" ) == 0 ){
glm::vec3 vertex;
fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z );
temp_vertices.push_back(vertex);
}else if ( strcmp( lineHeader, "vt" ) == 0 ){
glm::vec2 uv;
fscanf(file, "%f %f\n", &uv.x, &uv.y );
uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders.
temp_uvs.push_back(uv);
}else if ( strcmp( lineHeader, "vn" ) == 0 ){
glm::vec3 normal;
fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z );
temp_normals.push_back(normal);
}else if ( strcmp( lineHeader, "f" ) == 0 ){
std::string vertex1, vertex2, vertex3;
unsigned int vertexIndex[3], uvIndex[3], normalIndex[3];
int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2] );
if (matches != 9){
printf("File can't be read by our simple parser :-( Try exporting with other options\n");
return false;
}
vertexIndices.push_back(vertexIndex[0]);
vertexIndices.push_back(vertexIndex[1]);
vertexIndices.push_back(vertexIndex[2]);
uvIndices .push_back(uvIndex[0]);
uvIndices .push_back(uvIndex[1]);
uvIndices .push_back(uvIndex[2]);
normalIndices.push_back(normalIndex[0]);
normalIndices.push_back(normalIndex[1]);
normalIndices.push_back(normalIndex[2]);
}else{
// Probably a comment, eat up the rest of the line
char stupidBuffer[1000];
fgets(stupidBuffer, 1000, file);
}
}
// For each vertex of each triangle
for( unsigned int i=0; i<vertexIndices.size(); i++ ){
// Get the indices of its attributes
unsigned int vertexIndex = vertexIndices[i];
unsigned int uvIndex = uvIndices[i];
unsigned int normalIndex = normalIndices[i];
// Get the attributes thanks to the index
glm::vec3 vertex = temp_vertices[ vertexIndex-1 ];
glm::vec2 uv = temp_uvs[ uvIndex-1 ];
glm::vec3 normal = temp_normals[ normalIndex-1 ];
// Put the attributes in buffers
out_vertices.push_back(vertex);
out_uvs .push_back(uv);
out_normals .push_back(normal);
}
return true;
}
#ifdef USE_ASSIMP // don't use this #define, it's only for me (it AssImp fails to compile on your machine, at least all the other tutorials still work)
// Include AssImp
#include <assimp/Importer.hpp> // C++ importer interface
#include <assimp/scene.h> // Output data structure
#include <assimp/postprocess.h> // Post processing flags
bool loadAssImp(
const char * path,
std::vector<unsigned short> & indices,
std::vector<glm::vec3> & vertices,
std::vector<glm::vec2> & uvs,
std::vector<glm::vec3> & normals
){
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(path, 0/*aiProcess_JoinIdenticalVertices | aiProcess_SortByPType*/);
if( !scene) {
fprintf( stderr, importer.GetErrorString());
return false;
}
const aiMesh* mesh = scene->mMeshes[0]; // In this simple example code we always use the 1rst mesh (in OBJ files there is often only one anyway)
// Fill vertices positions
vertices.reserve(mesh->mNumVertices);
for(unsigned int i=0; i<mesh->mNumVertices; i++){
aiVector3D pos = mesh->mVertices[i];
vertices.push_back(glm::vec3(pos.x, pos.y, pos.z));
}
// Fill vertices texture coordinates
uvs.reserve(mesh->mNumVertices);
for(unsigned int i=0; i<mesh->mNumVertices; i++){
aiVector3D UVW = mesh->mTextureCoords[0][i]; // Assume only 1 set of UV coords; AssImp supports 8 UV sets.
uvs.push_back(glm::vec2(UVW.x, UVW.y));
}
// Fill vertices normals
normals.reserve(mesh->mNumVertices);
for(unsigned int i=0; i<mesh->mNumVertices; i++){
aiVector3D n = mesh->mNormals[i];
normals.push_back(glm::vec3(n.x, n.y, n.z));
}
// Fill face indices
indices.reserve(3*mesh->mNumFaces);
for (unsigned int i=0; i<mesh->mNumFaces; i++){
// Assume the model has only triangles.
indices.push_back(mesh->mFaces[i].mIndices[0]);
indices.push_back(mesh->mFaces[i].mIndices[1]);
indices.push_back(mesh->mFaces[i].mIndices[2]);
}
// The "scene" pointer will be deleted automatically by "importer"
}
#endif
sazanne.obj was provided with the tutorial and is in the same directory as tutorial08.cpp
The R300 architecture is one of the earliest shader model 2 GPUs there is. They've been introduced into the market 10 years ago. SM2 is a rather limited programming model with only very little hardware resources, only 4 texture indirections (i.e. texturing operations depending on other texturing operations) are the minimum that must be supported. And there is a hard instruction count limit.
In summary this means, that it takes an excellent GLSL compiler to squeeze as much out of the GPU as possible. Unfortunately GLSL compilers were never very much optimized for SM2 hardware – in fact when it comes to the R300 the proprietary driver's GLSL compiler produces worse code than the open source one. Most people programmed SM2 hardware in a sort of assembler code. And GLSL compilers became useful only when the next generation of GPUs hit the market, so nobody bothered to work on SM2 hardware target optimization.
What this means for you. Well, your GPU is simply too old to be of any use for GLSL development. You can still use the assembler to great effect – I have fond memories of squeezing out the last cycle, indirection limit and temporaries to attain a desired outcome; for example I was able to implement improved perlin noise on a Radeon 9800 GPU, when (almost) everyone else claimed it was impossible on SM2 class hardware.