Back to home

Bare bones openGL in openFrameworks

During our last openFrameworks freakDay meeting we discussed the usage of VBOs, vertex attributes and shaders in openFrameworks.  To explain the openGL concepts I created a demo application and shader which shows how to use openGL only without the need of ofShader, ofVBO.

// Error.h
/*
**  error.h
**
**  Copyright (c) 2008 Max Rupp (feelgood@cs.pdx.edu) All rights reserved.
*/
 
#ifndef __ERROR_H__
#define __ERROR_H__
#define DEBUG
#ifdef  DEBUG
 
#include <stdlib.h>
#include <assert.h>
/*
#define eglGetError( )\
        {\
            for ( GLenum Error = glGetError( ); ( GL_NO_ERROR != Error ); Error = glGetError( ) )\
            {\
                switch ( Error )\
                {\
                    case GL_INVALID_ENUM:      printf( "\n%s\n\n", "GL_INVALID_ENUM"      ); assert( 0 ); break;\
                    case GL_INVALID_VALUE:     printf( "\n%s\n\n", "GL_INVALID_VALUE"     ); assert( 0 ); break;\
                    case GL_INVALID_OPERATION: printf( "\n%s\n\n", "GL_INVALID_OPERATION" ); assert( 0 ); break;\
                    case GL_STACK_OVERFLOW:    printf( "\n%s\n\n", "GL_STACK_OVERFLOW"    ); assert( 0 ); break;\
                    case GL_STACK_UNDERFLOW:   printf( "\n%s\n\n", "GL_STACK_UNDERFLOW"   ); assert( 0 ); break;\
                    case GL_OUT_OF_MEMORY:     printf( "\n%s\n\n", "GL_OUT_OF_MEMORY"     ); assert( 0 ); break;\
                    default:                                                                              break;\
                }\
            }\
        }
*/
#define eglGetError()
#define eglCheckFramebufferStatus( )\
        {\
            switch ( glCheckFramebufferStatus( GL_FRAMEBUFFER ) )\
            {\
                case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:         printf( "\n%s\n\n", "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT"         ); assert( 0 ); break;\
                case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: printf( "\n%s\n\n", "GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT" ); assert( 0 ); break;\
                case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:        printf( "\n%s\n\n", "GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER"        ); assert( 0 ); break;\
                case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:        printf( "\n%s\n\n", "GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER"        ); assert( 0 ); break;\
                case GL_FRAMEBUFFER_UNSUPPORTED:                   printf( "\n%s\n\n", "GL_FRAMEBUFFER_UNSUPPORTED"                   ); assert( 0 ); break;\
                case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:        printf( "\n%s\n\n", "GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE"        ); assert( 0 ); break;\
                case GL_FRAMEBUFFER_UNDEFINED:                     printf( "\n%s\n\n", "GL_FRAMEBUFFER_UNDEFINED"                     ); assert( 0 ); break;\
                default:                                                                                                                              break;\
            }\
        }
 
#define eglGetShaderInfoLog( Shader )\
        {\
            GLint   Status, Count;\
            GLchar *Error;\
            \
            glGetShaderiv( Shader, GL_COMPILE_STATUS, &Status );\
            \
            if ( !Status )\
            {\
                glGetShaderiv( Shader, GL_INFO_LOG_LENGTH, &Count );\
                \
                if ( Count > 0 )\
                {\
					Error = (GLchar *)malloc(Count);\
					glGetShaderInfoLog( Shader, Count, NULL, Error );\
                    \
                    printf( "%s\n", Error );\
                    \
                    free( Error );\
                    \
                    assert( 0 );\
                }\
            }\
        }
 
#else
 
#define eglGetError( )
 
#define eglCheckFramebufferStatus( )
 
#define eglGetShaderInfoLog( Shader )
 
#endif /*   DEBUG     */
#endif /* __ERROR_H__ */
// testApp.h
#pragma once
 
#include "ofMain.h"
#include "Error.h"
 
class testApp : public ofBaseApp{
 
	public:
		void setup();
		void update();
		void draw();
 
		void keyPressed  (int key);
		void keyReleased(int key);
		void mouseMoved(int x, int y );
		void mouseDragged(int x, int y, int button);
		void mousePressed(int x, int y, int button);
		void mouseReleased(int x, int y, int button);
		void windowResized(int w, int h);
		void dragEvent(ofDragInfo dragInfo);
		void gotMessage(ofMessage msg);
 
		// shader 
		GLuint shader_vertex;
		GLuint shader_fragment;
		GLuint prog;
		GLint pos_attrib;
		GLint col_attrib;
		GLint custom_attrib;
 
		// vbo
		GLuint buffer;
		string readFile(string file);
 
};
// testApp.cpp
#include "testApp.h"
#include <stdlib.h>
#include <fstream>
 
struct VertexData {
	ofVec3f pos;
	ofVec3f col;
	float custom;
};
 
//--------------------------------------------------------------
void testApp::setup(){
	ofBackground(33);
 
	// Compile and link shaders into a program.
	shader_vertex = glCreateShader(GL_VERTEX_SHADER); eglGetError();
	shader_fragment = glCreateShader(GL_FRAGMENT_SHADER); eglGetError();
 
	string vert_source = readFile("program.vert");
	string frag_source = readFile("program.frag");
	const char* vert_ptr = vert_source.c_str();
	const char* frag_ptr = frag_source.c_str();
	glShaderSource(shader_vertex, 1, &vert_ptr, NULL); eglGetError();
	glShaderSource(shader_fragment, 1, &frag_ptr, NULL); eglGetError();
 
	glCompileShader(shader_vertex); eglGetError();
	glCompileShader(shader_fragment); eglGetError();
 
	prog = glCreateProgram(); eglGetError();
	glAttachShader(prog, shader_vertex); eglGetError();
	glAttachShader(prog, shader_fragment); eglGetError();
	glLinkProgram(prog); eglGetError();
	glUseProgram(prog); eglGetError();
 
	// create buffer
	float s = 4;
	VertexData points[4];
	points[0].pos.set(-s, s, 0);
	points[1].pos.set(s,s, 0);
	points[2].pos.set(s,-s,0);
	points[3].pos.set(-s, -s, 0);
	points[0].col.set(1,0,0);
	points[1].col.set(0,1,0);
	points[2].col.set(0,0,1);
	points[3].col.set(1,0,1);
	points[0].custom = 0.5;
	points[1].custom = 1.0;
	points[2].custom = 1.0;
	points[3].custom = 0.8;		
	glGenBuffers(1, &buffer); eglGetError();
	glBindBuffer(GL_ARRAY_BUFFER, buffer); eglGetError();
	glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData)* 4, &points[0].pos.x, GL_DYNAMIC_DRAW); eglGetError();
 
	// enable vertex attributes.
	pos_attrib = glGetAttribLocation(prog, "pos"); eglGetError();
	col_attrib = glGetAttribLocation(prog, "col"); eglGetError();
	custom_attrib = glGetAttribLocation(prog, "custom"); eglGetError(); 
 
	glEnableVertexAttribArray(pos_attrib); eglGetError();
	glEnableVertexAttribArray(col_attrib); eglGetError();
	glEnableVertexAttribArray(custom_attrib); eglGetError();
 
	// where can opengl find the values in the buffer?
	glVertexAttribPointer(pos_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*)offsetof(VertexData, pos)); eglGetError();
	glVertexAttribPointer(col_attrib, 3, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*) offsetof(VertexData, col)); eglGetError();
	glVertexAttribPointer(custom_attrib, 1, GL_FLOAT, GL_FALSE, sizeof(VertexData), (GLvoid*) offsetof(VertexData, custom)); eglGetError();
}
 
string testApp::readFile(string fileName) {
	stringstream ss;
	ifstream frag_file;
	frag_file.open(ofToDataPath(fileName.c_str(),true).c_str());
	if(!frag_file.is_open()) {
		printf("Cannot open vertex shader.\n");
		::exit(1);
	}
	string line;
	while(getline(frag_file, line)) {
		ss << line << "\n";
	}
	return ss.str();
}
 
//--------------------------------------------------------------
void testApp::update(){
 
}
 
//--------------------------------------------------------------
void testApp::draw(){
	// reset gl.
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluPerspective(45, ofGetWidth()/ofGetHeight(), 0.1, 1000);
 
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0,0,-10);
 
	// and draw our vbo
	glBindBuffer(GL_ARRAY_BUFFER, buffer); eglGetError();
	glDrawArrays(GL_QUADS, 0, 4); eglGetError();
}
 
//--------------------------------------------------------------
void testApp::keyPressed(int key){
	if(key == ' ') {	
		float s = 4;
		float t = (ofGetElapsedTimef());
		float v = (1.0+sin(t)*0.5);
		VertexData points[4];
		points[0].pos.set(-s, s, 0);
		points[1].pos.set(s,s, 0);
		points[2].pos.set(s,-s,0);
		points[3].pos.set(-s, -s, 0);
		points[0].col.set(v,0,0);
		points[1].col.set(0,v,0);
		points[2].col.set(0,0,v);
		points[3].col.set(v,0,v);
		points[0].custom = v;
		points[1].custom = 1.0 * v; 
		points[2].custom = 1.0 * v;
		points[3].custom = 0.8 * v;
		glBindBuffer(GL_ARRAY_BUFFER, buffer); eglGetError();
		glBufferData(GL_ARRAY_BUFFER, sizeof(VertexData)* 4, &points[0].pos.x, GL_DYNAMIC_DRAW); eglGetError();
	}
}