Skip to content

Instantly share code, notes, and snippets.

@BlockoS
Forked from StonedXander/Makefile
Created April 17, 2012 20:52
Show Gist options
  • Save BlockoS/2408974 to your computer and use it in GitHub Desktop.
Save BlockoS/2408974 to your computer and use it in GitHub Desktop.
Some VBO Stuff
#ifndef XDR_ASSET_H
#define XDR_ASSET_H
// Asset Management.
// Parsing : Human readable data in buffer to object.
//
/*
* <object id="...">
* <array method="TRIANGLES/STRIP/QUAD" material="materialID">
* <point x="..." y="..." z="..." r="..." g="..." b="..." u="..." v="..."/>
* <!-- ... -->
* </array>
* </object>
*/
// Hypothesis : Always 3 coordinates for points.
// Always 3 coordinates for color.
class Array {
private:
// Vertex Buffer Object identifier.
GLuint id;
// Number of vertices.
unsigned int numVert;
// Offset of the color array inside the VBO.
unsigned int colorOffset;
// Offset of the normal array inside the VBO.
unsigned int normalOffset;
// Offset of the texture coordinate inside the VBO.
unsigned int textureOffset;
// Drawing Method (e.g. GL_TRIANGLES).
GLuint method;
};
// - Initialise/Allocate VBO.
/*
* glGenBuffers(1, &id);
* glBindBuffer(GL_ARRAY_BUFFER, id);
* glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW);
* glBindBuffer(GL_ARRAY_BUFFER, 0);
*/
// Displaying : using object to display with VBO.
// - GL Rendering routines.
/*
* glBindBuffer(GL_ARRAY_BUFFER, id);
* glVertexPointer(numVertexCoord, typeV, 0, NULL); // typeV is usually GL_FLOAT
* glColorPointer(numColorCoord, typeC, 0, offsetColor); // typeC is usually GL_FLOAT
* glEnableClientState(GL_VERTEX_ARRAY); // Move this at the begining of all the managed objects display.
* glEnableClientState(GL_COLOR_ARRAY);
* glDrawArrays(method, 0, numPoint);
* glDisableClientState(GL_VERTEX_ARRAY); // Move this at the end of all the managed objects display.
* glDisableClientState(GL_COLOR_ARRAY);
*/
#endif
#include "BufferObject.h"
BufferObject::BufferObject() :
_id(0),
_target(GL_NONE),
_size(0),
_usage(0)
{}
BufferObject::~BufferObject() {}
bool BufferObject::Create(GLint target, GLsizei size, GLenum usage, const GLvoid *data)
{
if(_id)
{
Destroy();
}
_target = target;
_size = size;
_usage = usage;
glGenBuffers(1, &_id);
glBindBuffer(_target, _id);
glBufferData(_target, _size, data, GL_STATIC_DRAW);
GLenum err = glGetError();
glBindBuffer(_target, 0);
if(err != GL_NO_ERROR)
{
std::cerr << "An error occured while creating buffer object" << _id << " : " << gluErrorString(err) << std::endl;
return false;
}
return true;
}
void BufferObject::Destroy()
{
if(!_id)
return;
Unbind();
glDeleteBuffers(1, &_id);
_id = 0;
}
void BufferObject::Unbind() const
{
GLuint boundId;
GLenum binding;
switch(_target)
{
case GL_ARRAY_BUFFER:
binding = GL_ARRAY_BUFFER_BINDING;
break;
case GL_ELEMENT_ARRAY_BUFFER:
binding = GL_ELEMENT_ARRAY_BUFFER_BINDING;
break;
case GL_TEXTURE_BUFFER:
binding = GL_TEXTURE_BINDING_BUFFER;
break;
case GL_PIXEL_PACK_BUFFER:
binding = GL_PIXEL_PACK_BUFFER_BINDING;
break;
case GL_PIXEL_UNPACK_BUFFER:
binding = GL_PIXEL_UNPACK_BUFFER_BINDING;
break;
default:
glBindBuffer(_target, 0);
return;
};
glGetIntegerv(binding, (GLint*)&boundId);
if(boundId != _id) return;
glBindBuffer(_target, 0);
}
bool BufferObject::SetData( GLintptr offset, GLsizeiptr size, const GLvoid* data )
{
if(offset >= _size)
{
std::cerr << "Offset (" << offset << ") out of bound (vbo size: " << _size << ")" << std::endl;
return false;
}
if((offset+size) > _size)
{
std::cerr << "Buffer overflow (offset: " << offset << ", size: " << size << ", vbo size: " << _size << ')' << std::endl;
return false;
}
glBindBuffer(_target, _id);
glBufferSubData(_target, offset, size, data);
glBindBuffer(_target, 0);
return true;
}
GLvoid* BufferObject::MapRange(MappingMode mode, GLintptr offset, GLsizei size)
{
GLvoid* ptr;
glBindBuffer(_target, _id);
ptr = glMapBufferRange(_target, offset, size, ((mode == BUFFER_READ) ? GL_MAP_READ_BIT : (GL_MAP_WRITE_BIT | GL_MAP_INVALIDATE_BUFFER_BIT)) | GL_MAP_UNSYNCHRONIZED_BIT);
if(ptr == NULL)
{
GLenum err = glGetError();
std::cerr << "An error occured while mapping buffer object " << _id << " : " << gluErrorString(err) << std::endl;
return false;
}
return ptr;
}
void BufferObject::Unmap()
{
/* todo : get the bound id and check if it's mapped
GLint mapped;
glGetBufferParameteriv(_target, GL_BUFFER_MAPPED, &mapped);
*/
glUnmapBuffer(GL_TEXTURE_BUFFER);
}
#ifndef BUFFER_OBJECT_H
#define BUFFER_OBJECT_H
// todo: gl includes
class BufferObject
{
public:
BufferObject();
~BufferObject();
bool Create(GLint target, GLsizei size, GLenum usage, const GLvoid *data = NULL);
void Destroy();
inline void Bind() const;
inline void BindBase(GLenum bindTarget, GLuint index) const;
inline void BindRange(GLenum bindTarget, GLuint index, GLintptr offset, GLsizeiptr size) const;
void Unbind() const;
bool SetData(GLintptr offset, GLsizeiptr size, const GLvoid* data);
enum MappingMode
{
BUFFER_READ,
BUFFER_WRITE
};
GLvoid* MapRange(MappingMode mode, GLintptr offset, GLsizei size);
void Unmap();
GLuint Id () const { return _id; }
GLint Target() const { return _target; }
GLint Size () const { return _size; }
protected:
GLuint _id;
GLint _target;
GLint _size;
GLenum _usage;
};
void BufferObject::Bind() const
{
glBindBuffer(_target, _id);
}
void BufferObject::BindBase(GLenum bindTarget, GLuint index) const
{
glBindBufferBase(bindTarget, index, _id);
}
void BufferObject::BindRange(GLenum bindTarget, GLuint index, GLintptr offset, GLsizeiptr size) const
{
glBindBufferRange(bindTarget, index, _id, offset, size);
}
#endif // BUFFER_OBJECT_H
#include "microengine.h"
#include <GL/glfw.h>
#include <iostream>
int main(void) {
std::cout << "Model ..." << std::endl;
Model model(5);
std::cout << "Interpreter ..." << std::endl;
Interpreter interpreter(&model);
std::cout << "Display ..." << std::endl;
Display display(&model, &interpreter);
std::cout << "Loop ..." << std::endl;
if(display.initialize())
display.loop();
return 0;
}
microengine.o: microengine.h microengine.c
g++ -c microengine.C -I. -I../common
main.o: microengine.h main.c
g++ -c main.c -I. -I../common
all: main.o microengine.o
g++ main.o microengine.o -lGL -lglfw -lm -lpthread -o speedcoding
#include "Mesh.h"
Mesh::Mesh() :
_vertexCount(0),
_elementCount(0),
_elementSize(0),
_vao(0),
_vbo(),
_pritimive()
{}
Mesh::~Mesh()
{}
bool Mesh::Create(const GLfloat* vertexBuffer, int nVertices, const GLuint* triList, int nElements)
{
_vertexCount = nVertices;
_elementCount = 0;
if(!_vbo.Create(GL_ARRAY_BUFFER, _vertexCount * sizeof(GLfloat[8]), GL_STATIC_DRAW, vertexBuffer))
{
std::cerr << "An error occured during vertex data creation!" << std::endl;
return false;
}
_elementSize = nElements * 3;
if(!_pritimive.Create(GL_ELEMENT_ARRAY_BUFFER, _elementSize * sizeof(GLuint), GL_STATIC_DRAW, triList))
{
std::cerr << "An error occured during primitive element creation!" << std::endl;
_vbo.Destroy();
return false;
}
glGenVertexArrays(1, &_vao);
glBindVertexArray(_vao);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glEnableVertexAttribArray(2);
_vbo.Bind();
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(_vertexCount * sizeof(GLfloat[3])));
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 0, (GLvoid*)(_vertexCount * sizeof(GLfloat[5])));
_vbo.Unbind();
_pritimive.Bind();
glBindVertexArray(0);
// todo: get glerror and check if anything nasty occured.
return true;
}
void Mesh::Destroy()
{
glDeleteVertexArrays(1, &_vao);
_vbo.Destroy();
_pritimive.Destroy();
}
void Mesh::Render()
{
glBindVertexArray(_vao);
glDrawElements(GL_TRIANGLES, _elementSize, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
}
#ifndef MESH_H
#define MESH_H
#include "BufferObject.h"
class Mesh
{
public:
Mesh();
~Mesh();
// Create object
bool Create(const GLfloat* vertexBuffer, int nVertices, const GLuint* triList, int nElements);
// Destroy object
virtual void Destroy();
// Render object
virtual void Render();
GLsizei VertexCount () const { return _vertexCount; }
GLsizei ElementCount() const { return _elementCount; }
GLuint VAO() const { return _vao; };
protected:
// Create a vao
virtual bool CreateVao();
protected:
GLuint _vao;
GLsizei _vertexCount;
GLsizei _elementCount;
GLint _elementSize;
// Point + tex + normal
BufferObject _vbo;
BufferObject _pritimive;
AttributeInfo _pointCoordInfo;
AttributeInfo _texCoordInfo;
AttributeInfo _normalInfo;
ElementInfo _primitiveInfo;
};
#endif // MESH_H
#include "microengine.h"
#include <GL/glfw.h>
#include <stdlib.h>
#include <math.h>
#include <stdio.h>
#include <unistd.h>
#include <iostream>
Interpreter *Interpreter::current = 0;
Model::Model(unsigned int c) {
flag = 0;
lastUpdate = 0;
std::cout << "Allocate volumes ..." << std::endl;
volume = new Volume*[c];
volumeCapacity = c;
std::cout << "Initialise volumes : " << std::flush;
for(int i = 0; i < c; ++i) {
std::cout << i << " " << std::flush;
volume[i] = 0;
}
volumeCount = 1;
std::cout << std::endl << "Initialise first volume." << std::endl;
volume[0] = new Volume(1, 0);
}
Model::~Model() {
for(int i = 0; i < volumeCount; ++i) {
// We assume that volumes aren't null between 0 and volumeCount.
delete volume[i];
}
delete [] volume;
}
void Model::tick() {
pthread_mutex_lock(&mutex);
double currentTime = glfwGetTime();
double elapsed = currentTime - lastUpdate;
// Ok, given the elapsed time and the logical event, let's do some stuff.
double x = volume[0]->getX();
double y = volume[0]->getY();
double z = volume[0]->getZ();
double angle = volume[0]->getAngle();
double forwardProg = ( (((flag & LEVENT_FORWARD) != 0)?1:0)+
(((flag & LEVENT_BACK) != 0)?-1:0) ) * elapsed * 2;
// Speed is 1 unit/s.
double angleProg = ( (((flag & LEVENT_LEFT) != 0)?-1:0)+
(((flag & LEVENT_RIGHT) != 0)?1:0) ) * elapsed * 200;
// Angular speed is 200 deg/s.
angle += angleProg;
angleProg = (angle * 3.141516) / 180.0;
x += cos(angleProg) * forwardProg;
z += sin(angleProg) * forwardProg;
volume[0]->setAngle(angle);
volume[0]->setPosition(x, y, z);
// TODO Update other volumes.
lastUpdate = currentTime;
pthread_mutex_unlock(&mutex);
}
Volume **Model::getVolume() {
Volume **rc;
pthread_mutex_lock(&mutex);
rc = volume;
// TODO Model Double Buffering.
pthread_mutex_unlock(&mutex);
return rc;
}
void Model::start() {
threadFlag = true;
pthread_attr_t attr;
pthread_mutex_init(&mutex, 0);
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
pthread_create(&thread, &attr, Model::run, this);
pthread_attr_destroy(&attr);
// TODO Error management.
}
void Model::stop() {
threadFlag = false;
if(thread != 0) {
void *status;
pthread_join(thread, &status);
pthread_mutex_destroy(&mutex);
}
}
void *Model::run(void *subject) {
Model *model = static_cast<Model*>(subject);
if(0 == model) {
return 0;
}
while(model->threadFlag) {
model->tick();
usleep(45000);
}
}
void Interpreter::addKeyEvent(int key, int action) {
unsigned char flag = 0;
switch(key) {
case GLFW_KEY_UP:
flag = LEVENT_FORWARD;
break;
case GLFW_KEY_DOWN:
flag = LEVENT_BACK;
break;
case GLFW_KEY_LEFT:
flag = LEVENT_LEFT;
break;
case GLFW_KEY_RIGHT:
flag = LEVENT_RIGHT;
break;
case GLFW_KEY_ESC:
exit(1); // SHBLAM !
break;
default:
break;
}
if(action == GLFW_PRESS) {
model->addFlag(flag);
} else {
model->removeFlag(flag);
}
}
void GLFWCALL manageSystemKeyboardEvent(int key, int action) {
Interpreter *interpreter = Interpreter::getCurrent();
interpreter->addKeyEvent(key, action);
}
bool Display::initialize() {
if(glfwInit() != GL_TRUE) {
return false;
}
int window_width = 800;
int window_height = 600;
if (glfwOpenWindow(window_width, window_height, 8, 8, 8,
0, 0, 0, GLFW_WINDOW) != GL_TRUE)
return false;
glfwSetWindowTitle("The GLFW Window");
glfwSetKeyCallback(manageSystemKeyboardEvent);
// set the projection matrix to a normal frustum with a max depth of 50
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
float aspect_ratio = ((float)window_height) / window_width;
glFrustum(.5, -.5, -.5 * aspect_ratio, .5 * aspect_ratio, 1, 50);
glMatrixMode(GL_MODELVIEW);
return true;
}
void Display::loop() {
model->start();
while(1) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
draw();
// model->tick(); // In real life, this tick is done in a different thread.
glfwSwapBuffers();
}
}
void Display::draw() {
glLoadIdentity();
glTranslatef(0, 0, -30);
Volume **v = model->getVolume();
unsigned int count = model->getCount();
for(int i = 0; i < count; ++i, ++v) {
glTranslatef((*v)->getX(), (*v)->getZ(), 0);
glRotatef((*v)->getAngle(), 0, 0, 1);
glBegin(GL_QUADS);
glColor3f(0, 0, 1);
glVertex2d(-0.5, -0.5);
glVertex2d(0.5, -0.5);
glVertex2d(0.5, 0.5);
glVertex2d(-0.5, 0.5);
glEnd();
glBegin(GL_LINES);
glVertex2d(0, 0);
glVertex2d(1, 0);
glEnd();
}
}
Display::~Display() {
// Nada
}
#ifndef _MICRO_ENGINE_H_
#define _MICRO_ENGINE_H_
#include <GL/glfw.h>
#include <pthread.h>
// The so-called volume class is a cube/stuff with orientation on Y axis.
class Volume {
public:
Volume(double s, double a) : size(s), angle(a), x(0), y(0), z(0) {}
inline double getSize() { return size; }
inline double getAngle() { return angle; }
inline double getX() { return x; }
inline double getY() { return y; }
inline double getZ() { return z; }
void setSize(double s) { size = s; }
void setAngle(double a) { angle = a; }
void setPosition(double pX, double pY, double pZ) {
x = pX; y = pY; z = pZ;
}
private:
double size;
double angle;
double x;
double y;
double z;
};
#define LEVENT_FORWARD 1
#define LEVENT_BACK 2
#define LEVENT_LEFT 4
#define LEVENT_RIGHT 8
#define LEVENT_JUMP 16
// The model/scene is quite simple. For this speedcoding session,
// it only consists in a single volume.
class Model {
public:
Model(unsigned int); // Number of volume to manage.
~Model();
void setLastUpdate(double d) { lastUpdate = d; }
// Update tick.
void tick();
// Models retrieval.
Volume **getVolume();
unsigned int getCount() { return volumeCount; }
void addFlag(unsigned char fl) { flag |= fl; }
void removeFlag(unsigned char fl) { flag &= ~fl; };
unsigned char getFlag() { return flag; }
void start();
void stop();
private:
// The flag indicate which are the logical event in hold.
unsigned char flag;
Volume **volume;
unsigned int volumeCount;
unsigned int volumeCapacity;
double lastUpdate;
pthread_t thread;
pthread_mutex_t mutex;
bool threadFlag;
private:
static void *run( void * );
};
/*
* It is this guy who react to events.
* It will modify the model accordingly.
*
* In fact, it's a bit more complicated.
* The thing is that the interpreter gets
* system event, the current state of the world
* and generate logic events accordingly.
*
* Then, logic events, in conjunction with
* the current state of the world, generate
* world updates.
*/
class Interpreter {
public:
Interpreter(Model *m) : model(m) { current = this; }
// Add a system event based on keyboard.
void addKeyEvent(int key, int action);
static Interpreter *getCurrent() { return current; }
private:
static Interpreter *current;
Model *model;
};
void GLFWCALL manageSystemKeyboardEvent(int key, int action);
/*
* And finally, the display !
* This kind guy takes what's in the model and simply display it.
* How nice is that ?
*/
class Display {
public:
Display(Model *m, Interpreter *i) : model(m), interpreter(i) {}
bool initialize();
void loop();
~Display();
private:
void draw();
private:
Interpreter *interpreter;
Model *model;
};
#endif
/* Parsing handler using expat engine. */
#ifndef _PARSER_HANDLER_H_
#define _PARSER_HANDLER_H_
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <expat.h>
#define PARSER_HANDLER_BUFFER_SIZE 65536
/**
* Parser are parametrized with class implementing the following concept.
*
* void startElement(const XML_Char *, const XML_Char **);
* void endElement(const XML_Char *);
*
*/
template <typename T> class Parser {
public:
static void parse(T *target, const char *filename) {
char buffer[PARSER_HANDLER_BUFFER_SIZE];
int handle = open(filename, O_RDONLY);
ssize_t rdLen;
if(handle < 0) {
// TODO ERROR
return;
}
XML_Parser parser = XML_ParserCreate(NULL);
XML_SetUserData(parser, target);
XML_SetElementHandler(parser, startElementHandler, endElementHandler);
while((rdLen = read(handle, buffer, PARSER_HANDLER_BUFFER_SIZE)) > 0) {
if(!XML_Parse(parser,
buffer,
rdLen,
rdLen < PARSER_HANDLER_BUFFER_SIZE)) {
// TODO ERROR
break;
}
}
XML_ParserFree(parser);
close(handle);
}
private:
static void startElementHandler(void *data,
const XML_Char *name,
const XML_Char **atts) {
T* t = (T *) data;
t->startElement(name, atts);
}
static void endElementHandler(void *data,
const XML_Char *name) {
T *t = (T *) data;
t->endElement(name);
}
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment