// // Lol Engine // // Copyright: (c) 2010-2011 Sam Hocevar <sam@hocevar.net> // 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 <cstdlib> #include <cstdio> #include <cmath> #ifdef WIN32 # define WIN32_LEAN_AND_MEAN # include <windows.h> #endif #if defined __APPLE__ && defined __MACH__ # include <OpenGL/gl.h> #else # define GL_GLEXT_PROTOTYPES # include <GL/gl.h> #endif #include "core.h" struct Tile { uint32_t prio, code; int x, y, z, o; }; #if LOL_EXPERIMENTAL extern Shader *stdshader; #endif extern mat4 model_matrix; /* * 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); // XXX: debug stuff model_matrix = mat4::translate(320.0f, 240.0f, 0.0f); model_matrix *= mat4::rotate(-data->angle, 1.0f, 0.0f, 0.0f); #if 0 static float f = 0.0f; f += 0.01f; model_matrix *= mat4::rotate(0.1f * sinf(f), 1.0f, 0.0f, 0.0f); model_matrix *= mat4::rotate(0.3f * cosf(f), 0.0f, 0.0f, 1.0f); #endif model_matrix *= mat4::translate(-320.0f, -240.0f, 0.0f); // XXX: end of debug stuff #if LOL_EXPERIMENTAL GLuint uni; uni = stdshader->GetUniformLocation("model_matrix"); glUniformMatrix4fv(uni, 1, GL_FALSE, &model_matrix[0][0]); float *vertices = new float[18]; vertices[0] = 0.0f; vertices[1] = 480.0f; vertices[2] = 0.0f; vertices[3] = 640.0f; vertices[4] = 480.0f; vertices[5] = 0.0f; vertices[6] = 0.0f; vertices[7] = 0.0f; vertices[8] = 0.0f; vertices[9] = 640.0f; vertices[10] = 0.0f; vertices[11] = 0.0f; vertices[12] = 0.0f; vertices[13] = 0.0f; vertices[14] = 0.0f; vertices[15] = 640.0f; vertices[16] = 480.0f; 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 vao, vbo[3], attr; glGenVertexArrays(1, &vao); glBindVertexArray(vao); glGenBuffers(3, &vbo[0]); attr = stdshader->GetAttribLocation("in_Position"); glBindBuffer(GL_ARRAY_BUFFER, vbo[0]); glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), vertices, GL_STATIC_DRAW); glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(attr); attr = stdshader->GetAttribLocation("in_Color"); glBindBuffer(GL_ARRAY_BUFFER, vbo[1]); glBufferData(GL_ARRAY_BUFFER, 18 * sizeof(GLfloat), colors, GL_STATIC_DRAW); glVertexAttribPointer(attr, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(attr); attr = stdshader->GetAttribLocation("in_TexCoord"); glBindBuffer(GL_ARRAY_BUFFER, vbo[2]); glBufferData(GL_ARRAY_BUFFER, 12 * sizeof(GLfloat), tex, GL_STATIC_DRAW); glVertexAttribPointer(attr, 2, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(attr); delete[] vertices; stdshader->Bind(); glBindVertexArray(vao); Tiler::Bind(1 << 16); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); #else glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glEnable(GL_ALPHA_TEST); glAlphaFunc(GL_GEQUAL, 0.01f); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glLoadIdentity(); glMultMatrixf(&model_matrix[0][0]); 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); 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); 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); } #endif free(data->tiles); data->tiles = 0; data->ntiles = 0; }