/* ** tilemap-common.h ** ** This file is part of mkxp. ** ** Copyright (C) 2014 Jonas Kulla ** ** mkxp is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 2 of the License, or ** (at your option) any later version. ** ** mkxp is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with mkxp. If not, see . */ #ifndef TILEMAPCOMMON_H #define TILEMAPCOMMON_H #include "table.h" #include "gl-util.h" #include "gl-meta.h" #include "sharedstate.h" #include "global-ibo.h" #include "glstate.h" #include "shader.h" #include "vertex.h" #include "quad.h" #include "etc-internal.h" #include #include #include #include static inline int wrap(int value, int range) { int res = value % range; return res < 0 ? res + range : res; } static inline int16_t tableGetWrapped(const Table &t, int x, int y, int z = 0) { return t.get(wrap(x, t.xSize()), wrap(y, t.ySize()), z); } enum AtSubPos { TopLeft = 0, TopRight = 1, BottomLeft = 2, BottomRight = 3, BottomLeftTable = 4, BottomRightTable = 5 }; static inline void atSelectSubPos(FloatRect &pos, int i) { switch (i) { case TopLeft: return; case TopRight: pos.x += 16; return; case BottomLeft: pos.y += 16; return; case BottomRight: pos.x += 16; pos.y += 16; return; case BottomLeftTable: pos.y += 24; return; case BottomRightTable: pos.x += 16; pos.y += 24; return; default: assert(!"Unreachable"); } } struct FlashMap { FlashMap() : dirty(false), data(0), allocQuads(0) { vao.vbo = VBO::gen(); vao.ibo = shState->globalIBO().ibo; GLMeta::vaoFillInVertexData(vao); GLMeta::vaoInit(vao); } ~FlashMap() { GLMeta::vaoFini(vao); VBO::del(vao.vbo); dataCon.disconnect(); } Table *getData() const { return data; } void setData(Table *value) { if (data == value) return; data = value; dataCon.disconnect(); dirty = true; if (!data) return; dataCon = data->modified.connect (sigc::mem_fun(this, &FlashMap::setDirty)); } void setViewport(const IntRect &value) { viewp = value; dirty = true; } void prepare() { if (!dirty) return; rebuildBuffer(); dirty = false; } void draw(float alpha, const Vec2i &trans) { const size_t count = quadCount(); if (count == 0) return; GLMeta::vaoBind(vao); glState.blendMode.pushSet(BlendAddition); FlashMapShader &shader = shState->shaders().flashMap; shader.bind(); shader.applyViewportProj(); shader.setAlpha(alpha); shader.setTranslation(trans); gl.DrawElements(GL_TRIANGLES, count * 6, _GL_INDEX_TYPE, 0); glState.blendMode.pop(); GLMeta::vaoUnbind(vao); } private: void setDirty() { dirty = true; } size_t quadCount() const { return vertices.size() / 4; } bool sampleFlashColor(Vec4 &out, int x, int y) const { int16_t packed = tableGetWrapped(*data, x, y); if (packed == 0) return false; const float max = 0xF; float b = ((packed & 0x000F) >> 0) / max; float g = ((packed & 0x00F0) >> 4) / max; float r = ((packed & 0x0F00) >> 8) / max; out = Vec4(r, g, b, 1); return true; } void rebuildBuffer() { vertices.clear(); if (!data) return; for (int x = 0; x < viewp.w; ++x) for (int y = 0; y < viewp.h; ++y) { Vec4 color; if (!sampleFlashColor(color, x+viewp.x, y+viewp.y)) continue; FloatRect posRect(x*32, y*32, 32, 32); CVertex v[4]; Quad::setPosRect(v, posRect); Quad::setColor(v, color); for (size_t i = 0; i < 4; ++i) vertices.push_back(v[i]); } if (vertices.size() == 0) return; VBO::bind(vao.vbo); if (quadCount() > allocQuads) { allocQuads = quadCount(); VBO::allocEmpty(sizeof(CVertex) * vertices.size()); } VBO::uploadSubData(0, sizeof(CVertex) * vertices.size(), dataPtr(vertices)); VBO::unbind(); /* Ensure global IBO size */ shState->ensureQuadIBO(quadCount()); } bool dirty; Table *data; sigc::connection dataCon; IntRect viewp; GLMeta::VAO vao; size_t allocQuads; std::vector vertices; }; #endif // TILEMAPCOMMON_H