123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292 |
- /*
- * Bael'Zharon's Respite
- * Copyright (C) 2014 Daniel Skorupski
- *
- * This program 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.
- * This program 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 this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
- */
- #include "graphics/LandRenderData.h"
- #include "graphics/Program.h"
- #include "Land.h"
- LandRenderData::LandRenderData(const Land& land)
- {
- initGeometry(land);
- initNormalTexture(land);
- }
- LandRenderData::~LandRenderData()
- {
- glDeleteVertexArrays(1, &vertexArray_);
- glDeleteBuffers(1, &vertexBuffer_);
- glDeleteTextures(1, &normalTexture_);
- }
- void LandRenderData::render()
- {
- glBindVertexArray(vertexArray_);
- glActiveTexture(GL_TEXTURE2);
- glBindTexture(GL_TEXTURE_2D, normalTexture_);
- glDrawArrays(GL_TRIANGLES, 0, vertexCount_);
- }
- static void pushRotatedCoord(vector<GLfloat>& vertexData, fp_t s, fp_t t, int rotations, int scale)
- {
- fp_t cosine = glm::cos(pi() / fp_t(180.0) * fp_t(90.0) * rotations);
- fp_t sine = glm::sin(pi() / fp_t(180.0) * fp_t(90.0) * rotations);
- fp_t ns = (s - fp_t(0.5)) * cosine - (t - fp_t(0.5)) * sine + fp_t(0.5);
- fp_t nt = (s - fp_t(0.5)) * sine + (t - fp_t(0.5)) * cosine + fp_t(0.5);
- vertexData.push_back(ns * scale);
- vertexData.push_back(nt * scale);
- }
- void LandRenderData::initGeometry(const Land& land)
- {
- vector<GLfloat> vertexData;
- for(uint8_t y = 0; y < Land::kGridSize - 1; y++)
- {
- for(uint8_t x = 0; x < Land::kGridSize - 1; x++)
- {
- #define T(dx, dy) land.getTerrain(x + (dx), y + (dy))
- uint8_t terrain[]
- {
- T(0, 0), T(1, 0), T(1, 1), T(0, 1)
- };
- #undef T
- #define R(dx, dy) land.getRoad(x + (dx), y + (dy))
- uint8_t road[]
- {
- R(0, 0), R(1, 0), R(1, 1), R(0, 1)
- };
- #undef R
- uint32_t terrainDone = 0;
- vector<uint8_t> textures;
- vector<uint8_t> blendTextures;
- vector<uint8_t> rotations;
- for(int i = 0; i < 4; i++)
- {
- if(terrainDone & (1 << terrain[i]))
- {
- continue;
- }
- terrainDone |= (1 << terrain[i]);
- uint8_t bitfield = 0;
- for(int j = 0; j < 4; j++)
- {
- if(terrain[j] == terrain[i])
- {
- bitfield |= (1 << j);
- }
- }
- // number of 90 degree ccw rotations
- uint8_t rotationCount = 0;
- uint8_t blendTex = 0xFF;
- for(;;)
- {
- switch(bitfield)
- {
- case 0x1: // 0001
- blendTex = 8;
- break;
- case 0x9: // 1001
- blendTex = 2;
- break;
- case 0x5: // 0101
- blendTex = 0; // TODO
- break;
- case 0xE: // 1110
- blendTex = 0x80 + 0x8;
- break;
- case 0xF: // 1111
- blendTex = 1;
- break;
- }
- if(blendTex != 0xFF)
- {
- break;
- }
- bitfield = ((bitfield << 1) | (bitfield >> 3)) & 0xF;
- rotationCount++;
- }
- textures.push_back(terrain[i]);
- blendTextures.push_back(blendTex);
- rotations.push_back(rotationCount);
- }
- while(textures.size() < 4)
- {
- textures.push_back(0);
- blendTextures.push_back(0);
- rotations.push_back(0);
- }
- uint8_t roadScale = 3;
- {
- uint8_t bitfield = 0;
- uint8_t roadType = 0;
- for(int j = 0; j < 4; j++)
- {
- if(road[j])
- {
- bitfield |= (1 << j);
- roadType = road[j];
- }
- }
- uint8_t rotationCount = 0;
- uint8_t blendTex = 0xFF;
- for(;;)
- {
- switch(bitfield)
- {
- case 0x0: // 0000
- blendTex = 0;
- break;
- case 0x1: // 0001
- blendTex = 5;
- break;
- case 0x9: // 1001
- blendTex = 2;
- break;
- case 0x5: // 0101
- blendTex = 0xA;
- roadScale = 1;
- break;
- case 0xE: // 1110
- blendTex = 0x80 + 5;
- break;
- case 0xF: // 1111
- blendTex = 1;
- break;
- }
- if(blendTex != 0xFF)
- {
- break;
- }
- bitfield = ((bitfield << 1) | (bitfield >> 3)) & 0xF;
- rotationCount++;
- }
- static const uint8_t kCommonRoad = 0x20;
- static const uint8_t kRareRoad = 0x1F;
- textures.push_back((roadType == 1) ? kCommonRoad : kRareRoad);
- blendTextures.push_back(blendTex);
- rotations.push_back(rotationCount);
- }
- // See LandVertexShader.glsl to see what these are
- // Terrain textures are tiled twice per quad (this is specified in region)
- // Hence the dx * 2 and dy *2
- #define V(dx, dy) \
- vertexData.push_back(static_cast<float>((x + (dx)) * 24)); \
- vertexData.push_back(static_cast<float>((y + (dy)) * 24)); \
- vertexData.push_back(land.getHeight(x + (dx), y + (dy))); \
- vertexData.push_back(static_cast<float>((dx) * 2)); \
- vertexData.push_back(static_cast<float>((dy) * 2)); \
- pushRotatedCoord(vertexData, dx, dy, rotations[0], 1); \
- vertexData.push_back(blendTextures[0]); \
- vertexData.push_back(textures[0]); \
- pushRotatedCoord(vertexData, dx, dy, rotations[1], 1); \
- vertexData.push_back(blendTextures[1]); \
- vertexData.push_back(textures[1]); \
- pushRotatedCoord(vertexData, dx, dy, rotations[2], 1); \
- vertexData.push_back(blendTextures[2]); \
- vertexData.push_back(textures[2]); \
- pushRotatedCoord(vertexData, dx, dy, rotations[3], 1); \
- vertexData.push_back(blendTextures[3]); \
- vertexData.push_back(textures[3]); \
- pushRotatedCoord(vertexData, dx, dy, rotations[4], roadScale); \
- vertexData.push_back(blendTextures[4]); \
- vertexData.push_back(textures[4]);
- if(land.isSplitNESW(x, y))
- {
- // lower right triangle
- V(0, 0) V(1, 0) V(1, 1)
- // top left triangle
- V(1, 1) V(0, 1) V(0, 0)
- }
- else
- {
- // lower left triangle
- V(0, 0) V(1, 0) V(0, 1)
- // top right triangle
- V(1, 0) V(1, 1) V(0, 1)
- }
- #undef V
- }
- }
- static const int kComponentsPerVertex = 25;
- vertexCount_ = static_cast<GLsizei>(vertexData.size()) / kComponentsPerVertex;
- glGenVertexArrays(1, &vertexArray_);
- glBindVertexArray(vertexArray_);
- glGenBuffers(1, &vertexBuffer_);
- glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);
- glBufferData(GL_ARRAY_BUFFER, vertexData.size() * sizeof(GLfloat), vertexData.data(), GL_STATIC_DRAW);
- glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), nullptr);
- glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 3));
- glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 5));
- glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 9));
- glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 13));
- glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 17));
- glVertexAttribPointer(6, 4, GL_FLOAT, GL_FALSE, kComponentsPerVertex * sizeof(GLfloat), reinterpret_cast<GLvoid*>(sizeof(GLfloat) * 21));
- glEnableVertexAttribArray(0);
- glEnableVertexAttribArray(1);
- glEnableVertexAttribArray(2);
- glEnableVertexAttribArray(3);
- glEnableVertexAttribArray(4);
- glEnableVertexAttribArray(5);
- glEnableVertexAttribArray(6);
- }
- void LandRenderData::initNormalTexture(const Land& land)
- {
- glGenTextures(1, &normalTexture_);
- glBindTexture(GL_TEXTURE_2D, normalTexture_);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, Land::kOffsetMapSize, Land::kOffsetMapSize, 0, GL_RGB, GL_UNSIGNED_BYTE, land.normalMap());
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); // default is GL_NEAREST_MIPMAP_LINEAR
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
- }
|