Skip to content

Instantly share code, notes, and snippets.

@StonedXander
Created April 17, 2012 19:39
Show Gist options
  • Save StonedXander/2408501 to your computer and use it in GitHub Desktop.
Save StonedXander/2408501 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>
*/
GLfloat *buffer = new GLfloat[VBO_BUFFER_SIZE];
int bufferSize;
void finalizeArray() {
int offset = 0;
int size = _vertexCount * sizeof(GLfloat) * 3;
memcpy(_buffer, _position, size);
offset += size;
memcpy(_buffer + offset, _normal, size);
offset += size;
memcpy(_buffer + offset, _color, size);
offset += size;
size = _vertexCount * sizeof(GLfloat) * 2;
memcpy(_buffer + offset, _tex, size);
offset += size;
size = offset; // size is now the size of the VBO.
// Do the VBO storage stuff ...
addArray();
}
void finalizeObject() {
// _currentObject doesn't need anything.
// What should I do ?
}
void addArray() {
_currentObject->addArray(_buffer, _vertexCount, _primitive);
_vertexCount = 0;
}
void decodeObject(const XML_Char *name, const XML_Char **attr) {
if(_state == XDR_ASSET_ERROR)
return;
if(strcmp(name, "object") == 0) {
_currentObject = createEmptyObject();
_vertexCount = 0;
} else {
_state = XDR_ASSET_ERROR;
}
}
void decodeArray(const XML_Char *name, const XML_Char **attr) {
if(_state == XDR_ASSET_ERROR)
return;
if(strcmp(name, "array") == 0) {
_vertexCount = 0;
_primitive = DEFAULT_PRIMITIVE;
for(int i = 0; attr[i] != 0; i += 2) {
if(strcmp(attr[i], "method") == 0) {
_primitive = decodePrimitive(attr[i+1]);
} else if (strcmp(attr[i], "material") == 0) {
// TODO
}
}
} else {
_state = XDR_ASSET_ERROR;
}
}
/*
* _vertexCount : Number of vertex currently decoded.
* _position : Position array of { x, y, z }
* _normal : Normal array of {x, y, z}
* _tex : Texture coordinate array of {u, v}
* _color : Color array of {r, g, b}
*/
void decodePoint(const XML_Char *name, const XML_Char **attr) {
if(_state == XDR_ASSET_ERROR)
return;
if(strcmp(name, "vertex") == 0) {
++_vertexCount;
for(int i = 0; attr[i] != 0; i += 2) {
GLfloat value = atof(attr[i+1]);
if(strcmp(attr[i], "x") == 0) {
_position[vertexCount].x = value;
} else if(strcmp(attr[i], "y") == 0) {
_position[vertexCount].y = value;
} else if(strcmp(attr[i], "z") == 0) {
_position[vertexCount].z = value;
} else if(strcmp(attr[i], "nx") == 0) {
_normal[vertexCount].x = value;
} else if(strcmp(attr[i], "ny") == 0) {
_normal[vertexCount].y = value;
} else if(strcmp(attr[i], "nz") == 0) {
_normal[vertexCount].z = value;
} else if(strcmp(attr[i], "u") == 0) {
_tex[vertexCount].u = value;
} else if(strcmp(attr[i], "v") == 0) {
_tex[vertexCount].v = value;
} else if(strcmp(attr[i], "r") == 0) {
_color[vertexCount].r = value;
} else if(strcmp(attr[i], "g") == 0) {
_color[vertexCount].g = value;
} else if(strcmp(attr[i], "b") == 0) {
_color[vertexCount].b = value;
}
}
} else {
_state = XDR_ASSET_ERROR;
}
}
void endElement(const XML_Char *name) {
if(_state == XDR_ASSET_ERROR)
return;
if(strcmp(name, "array") == 0) {
finalizeArray();
_state = XDR_ASSET_ARRAY;
} else if(strcmp(name, "object") == 0) {
finalizeObject();
_state = XDR_ASSET_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 "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 "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