// // Lol Engine // // Copyright: (c) 2010-2011 Sam Hocevar // This program is free software; you can redistribute it and/or // modify it under the terms of the Do What The Fuck You Want To // Public License, Version 2, as published by Sam Hocevar. See // http://sam.zoy.org/projects/COPYING.WTFPL for more details. // #if defined HAVE_CONFIG_H # include "config.h" #endif #include #include #include #ifdef WIN32 # define WIN32_LEAN_AND_MEAN # include #endif #if defined __APPLE__ && defined __MACH__ # include #else # define GL_GLEXT_PROTOTYPES # include #endif #include "core.h" struct Tile { uint32_t prio, code; int x, y, z, o; }; #if SHADER_CRAP # define ATTRIB_POSITION 42 /* arbitrary id */ extern GLuint prog; extern GLint uni_mvp, uni_color; #endif /* * Scene implementation class */ class SceneData { friend class Scene; private: static int Compare(void const *p1, void const *p2) { Tile const *t1 = (Tile const *)p1; Tile const *t2 = (Tile const *)p2; return t2->prio - t1->prio; } Tile *tiles; int ntiles; float angle; GLuint *bufs; int nbufs; static Scene *scene; }; Scene *SceneData::scene = NULL; /* * Public Scene class */ Scene::Scene(float angle) : data(new SceneData()) { data->tiles = 0; data->ntiles = 0; data->angle = angle; data->bufs = 0; data->nbufs = 0; } Scene::~Scene() { /* FIXME: this must be done while the GL context is still active. * Change the architecture to make sure of that. */ glDeleteBuffers(data->nbufs, data->bufs); delete data; } Scene *Scene::GetDefault() { if (!SceneData::scene) SceneData::scene = new Scene(0.0f); return SceneData::scene; } void Scene::Reset() { if (SceneData::scene) delete SceneData::scene; SceneData::scene = NULL; } void Scene::AddTile(uint32_t code, int x, int y, int z, int o) { if ((data->ntiles % 1024) == 0) data->tiles = (Tile *)realloc(data->tiles, (data->ntiles + 1024) * sizeof(Tile)); /* FIXME: this sorting only works for a 45-degree camera */ data->tiles[data->ntiles].prio = -y - 2 * 32 * z + (o ? 0 : 32); data->tiles[data->ntiles].code = code; data->tiles[data->ntiles].x = x; data->tiles[data->ntiles].y = y; data->tiles[data->ntiles].z = z; data->tiles[data->ntiles].o = o; data->ntiles++; } void Scene::Render() // XXX: rename to Blit() { #if 0 // Randomise, then sort. for (int i = 0; i < data->ntiles; i++) { Tile tmp = data->tiles[i]; int j = rand() % data->ntiles; data->tiles[i] = data->tiles[j]; data->tiles[j] = tmp; } #endif qsort(data->tiles, data->ntiles, sizeof(Tile), SceneData::Compare); #if SHADER_CRAP float *vertices = new float[18]; vertices[0] = -0.5f; vertices[1] = 0.5f; vertices[2] = 0.0f; vertices[3] = 0.5f; vertices[4] = 0.5f; vertices[5] = 0.0f; vertices[6] = -0.5f; vertices[7] = -0.5f; vertices[8] = 0.0f; vertices[9] = 0.5f; vertices[10] = -0.5f; vertices[11] = 0.0f; vertices[12] = -0.5f; vertices[13] = -0.5f; vertices[14] = 0.0f; vertices[15] = 0.5f; vertices[16] = 0.5f; vertices[17] = 0.0f; const GLfloat colors[6][3] = { { 0.0, 0.0, 1.0 }, { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 1.0, 1.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 1.0, 0.0, 0.0 } }; const GLfloat tex[6][2] = { { 0.0, 0.0 }, { 1.0, 0.0 }, { 0.0, 1.0 }, { 1.0, 1.0 }, { 0.0, 1.0 }, { 1.0, 0.0 } }; GLuint id[4]; glGenVertexArrays(1, &id[0]); glBindVertexArray(id[0]); glGenBuffers(3, &id[1]); glBindBuffer(GL_ARRAY_BUFFER, id[1]); glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); glVertexAttribPointer((GLuint)0, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, id[2]); glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), colors, GL_STATIC_DRAW); glVertexAttribPointer((GLuint)1, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(1); glBindBuffer(GL_ARRAY_BUFFER, id[3]); glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), tex, GL_STATIC_DRAW); glVertexAttribPointer((GLuint)2, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(2); delete[] vertices; glUseProgram(prog); glBindVertexArray(id[0]); Tiler::Bind(1 << 16); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); #else // XXX: debug stuff glPushMatrix(); static float f = 0.0f; f += 0.05f; glTranslatef(320.0f, 240.0f, 0.0f); glRotatef(-data->angle, 1.0f, 0.0f, 0.0f); #if 0 glRotatef(3.0f * sinf(f), 1.0f, 0.0f, 0.0f); glRotatef(8.0f * cosf(f), 0.0f, 0.0f, 1.0f); #endif glTranslatef(-320.0f, -240.0f, 0.0f); // XXX: end of debug stuff for (int buf = 0, i = 0, n; i < data->ntiles; i = n, buf += 2) { /* Generate new vertex / texture coord buffers if necessary */ if (buf + 2 > data->nbufs) { data->bufs = (GLuint *)realloc(data->bufs, (buf + 2) * sizeof(GLuint)); glGenBuffers(buf + 2 - data->nbufs, data->bufs + data->nbufs); data->nbufs = buf + 2; } /* Count how many quads will be needed */ for (n = i + 1; n < data->ntiles; n++) if (data->tiles[i].code >> 16 != data->tiles[n].code >> 16) break; /* Create a vertex array object */ float *vertex = (float *)malloc(6 * 3 * (n - i) * sizeof(float)); float *texture = (float *)malloc(6 * 2 * (n - i) * sizeof(float)); for (int j = i; j < n; j++) { Tiler::BlitTile(data->tiles[j].code, data->tiles[j].x, data->tiles[j].y, data->tiles[j].z, data->tiles[j].o, vertex + 18 * (j - i), texture + 12 * (j - i)); } glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); #if SHADER_CRAP glUseProgram(prog); //float4x4 mvp(1.0f); //mvp = mvp - mvp; //glUniformMatrix4fv(uni_mvp, 1, GL_FALSE, (GLfloat *)&mvp[0][0]); //glUniform4f(uni_color, 1.0f, 0.0f, 1.0f, 1.0f); #endif glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf]); glBufferData(GL_ARRAY_BUFFER, 6 * 3 * (n - i) * sizeof(float), vertex, GL_DYNAMIC_DRAW); glVertexPointer(3, GL_FLOAT, 0, NULL); #if SHADER_CRAP glVertexAttribPointer(ATTRIB_POSITION, (n - i) * 6, GL_FLOAT, false, 0, vertex); glEnableVertexAttribArray(ATTRIB_POSITION); #endif glBindBuffer(GL_ARRAY_BUFFER, data->bufs[buf + 1]); glBufferData(GL_ARRAY_BUFFER, 6 * 2 * (n - i) * sizeof(float), texture, GL_DYNAMIC_DRAW); glTexCoordPointer(2, GL_FLOAT, 0, NULL); Tiler::Bind(data->tiles[i].code); glDrawArrays(GL_TRIANGLES, 0, (n - i) * 6); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_TEXTURE_COORD_ARRAY); free(vertex); free(texture); } glPopMatrix(); #endif free(data->tiles); data->tiles = 0; data->ntiles = 0; }