Created
April 17, 2012 19:39
-
-
Save StonedXander/2408501 to your computer and use it in GitHub Desktop.
Some VBO Stuff
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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 | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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