Clone of Bael'Zharon's Respite @ https://github.com/boardwalk/bzr

LandRenderer.cpp 8.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. /*
  2. * Bael'Zharon's Respite
  3. * Copyright (C) 2014 Daniel Skorupski
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License along
  15. * with this program; if not, write to the Free Software Foundation, Inc.,
  16. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  17. */
  18. #include "graphics/LandRenderer.h"
  19. #include "graphics/LandRenderData.h"
  20. #include "graphics/Renderer.h"
  21. #include "graphics/util.h"
  22. #include "resource/ImgColor.h"
  23. #include "resource/ImgTex.h"
  24. #include "resource/Region.h"
  25. #include "Camera.h"
  26. #include "Core.h"
  27. #include "Land.h"
  28. #include "LandcellManager.h"
  29. #include "ResourceCache.h"
  30. #include <glm/gtc/matrix_inverse.hpp>
  31. #include <glm/gtc/matrix_transform.hpp>
  32. #include <algorithm>
  33. #include "graphics/shaders/LandVertexShader.h"
  34. #include "graphics/shaders/LandFragmentShader.h"
  35. static const int kTerrainArraySize = 512;
  36. static const uint32_t kBlendTextures[] =
  37. {
  38. 0xFFFFFFFF, // 0 special case, all white
  39. 0x00000000, // 1 special case, all black
  40. 0x06006d61, // 2 vertical, black to white, left of center
  41. 0x06006d6c, // 3 top left corner, black, semi ragged
  42. 0x06006d6d, // 4 top left corner, black, ragged
  43. 0x06006d60, // 5 top left corner, black, rounded
  44. 0x06006d30, // 6 vertical, black to white, very left of center, wavy
  45. 0x06006d37, // 7 small corner
  46. 0x06006d6b, // 8 big corner
  47. 0x06006d60, // 9 big corner
  48. 0x06006d36 // A wavy diagonal
  49. };
  50. static const int kBlendArraySize = 512;
  51. static const int kBlendArrayDepth = sizeof(kBlendTextures) / sizeof(kBlendTextures[0]);
  52. LandRenderer::LandRenderer()
  53. {
  54. initProgram();
  55. initTerrainTexture();
  56. initBlendTexture();
  57. }
  58. LandRenderer::~LandRenderer()
  59. {
  60. program_.destroy();
  61. glDeleteTextures(1, &terrainTexture_);
  62. glDeleteTextures(1, &blendTexture_);
  63. }
  64. void LandRenderer::render(const glm::mat4& projectionMat, const glm::mat4& viewMat)
  65. {
  66. program_.use();
  67. glActiveTexture(GL_TEXTURE0);
  68. glBindTexture(GL_TEXTURE_2D_ARRAY, terrainTexture_);
  69. glActiveTexture(GL_TEXTURE1);
  70. glBindTexture(GL_TEXTURE_2D_ARRAY, blendTexture_);
  71. LandcellManager& landcellManager = Core::get().landcellManager();
  72. glm::vec3 cameraPosition = Core::get().camera().position();
  73. glUniform4f(program_.getUniform("cameraPosition"),
  74. static_cast<GLfloat>(cameraPosition.x),
  75. static_cast<GLfloat>(cameraPosition.y),
  76. static_cast<GLfloat>(cameraPosition.z), 1.0f);
  77. glm::vec4 viewLightPosition = viewMat * glm::vec4{lightPosition_.x, lightPosition_.y, lightPosition_.z, 1.0};
  78. glUniform3f(program_.getUniform("lightPosition"),
  79. static_cast<GLfloat>(viewLightPosition.x),
  80. static_cast<GLfloat>(viewLightPosition.y),
  81. static_cast<GLfloat>(viewLightPosition.z));
  82. for(auto& pair : landcellManager)
  83. {
  84. if(pair.first.isStructure())
  85. {
  86. continue;
  87. }
  88. int dx = pair.first.x() - landcellManager.center().x();
  89. int dy = pair.first.y() - landcellManager.center().y();
  90. glm::vec3 blockPosition{dx * 192.0, dy * 192.0, 0.0};
  91. const Land& land = static_cast<const Land&>(*pair.second);
  92. renderLand(land, projectionMat, viewMat, blockPosition);
  93. }
  94. }
  95. void LandRenderer::setLightPosition(const glm::vec3& lightPosition)
  96. {
  97. lightPosition_ = lightPosition;
  98. }
  99. void LandRenderer::renderLand(
  100. const Land& land,
  101. const glm::mat4& projectionMat,
  102. const glm::mat4& viewMat,
  103. const glm::vec3& position)
  104. {
  105. glm::mat4 worldMat = glm::translate(glm::mat4{}, position);
  106. loadMat3ToUniform(glm::inverseTranspose(glm::mat3(viewMat * worldMat)), program_.getUniform("normalMatrix"));
  107. loadMat4ToUniform(worldMat, program_.getUniform("worldMatrix"));
  108. loadMat4ToUniform(viewMat, program_.getUniform("viewMatrix"));
  109. loadMat4ToUniform(projectionMat, program_.getUniform("projectionMatrix"));
  110. if(!land.renderData())
  111. {
  112. land.renderData().reset(new LandRenderData(land));
  113. }
  114. LandRenderData& landRenderData = static_cast<LandRenderData&>(*land.renderData());
  115. landRenderData.render();
  116. }
  117. void LandRenderer::initProgram()
  118. {
  119. program_.create();
  120. program_.attach(GL_VERTEX_SHADER, LandVertexShader);
  121. program_.attach(GL_FRAGMENT_SHADER, LandFragmentShader);
  122. program_.link();
  123. program_.use();
  124. // samplers
  125. GLuint terrainTexLocation = program_.getUniform("terrainTex");
  126. glUniform1i(terrainTexLocation, 0); // corresponds to GL_TEXTURE0
  127. GLuint blendTexLocation = program_.getUniform("blendTex");
  128. glUniform1i(blendTexLocation, 1);
  129. GLuint normalTexLocation = program_.getUniform("normalTex");
  130. glUniform1i(normalTexLocation, 2);
  131. // lighting parameters
  132. glUniform3f(program_.getUniform("lightIntensity"), 1.0f, 1.0f, 1.0f);
  133. glUniform3f(program_.getUniform("Kd"), 0.7f, 0.7f, 0.7f);
  134. glUniform3f(program_.getUniform("Ka"), 0.5f, 0.5f, 0.5f);
  135. glUniform3f(program_.getUniform("Ks"), 0.0f, 0.0f, 0.0f);
  136. glUniform1f(program_.getUniform("shininess"), 1.0);
  137. }
  138. void LandRenderer::initTerrainTexture()
  139. {
  140. const Region& region = Core::get().region();
  141. GLsizei numTextures = static_cast<GLsizei>(region.terrainTextures.size());
  142. // allocate terrain texture
  143. glGenTextures(1, &terrainTexture_);
  144. glBindTexture(GL_TEXTURE_2D_ARRAY, terrainTexture_);
  145. glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, Core::get().renderer().textureMinFilter());
  146. glTexParameterf(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAX_ANISOTROPY_EXT, Core::get().renderer().textureMaxAnisotropy());
  147. glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB8, kTerrainArraySize, kTerrainArraySize, numTextures, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
  148. // populate terrain texture
  149. for(GLint i = 0; i < numTextures; i++)
  150. {
  151. ResourcePtr imgTex = Core::get().resourceCache().get(region.terrainTextures[i].resourceId);
  152. const Image& image = imgTex->cast<ImgTex>().imgColor->cast<ImgColor>().image;
  153. if(image.width() != kTerrainArraySize || image.height() != kTerrainArraySize)
  154. {
  155. throw runtime_error("Bad terrain image size");
  156. }
  157. if(image.format() != PixelFormat::kA8R8G8B8)
  158. {
  159. throw runtime_error("Bad terrain image format");
  160. }
  161. glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, kTerrainArraySize, kTerrainArraySize, 1, GL_BGRA, GL_UNSIGNED_BYTE, image.data());
  162. }
  163. glGenerateMipmap(GL_TEXTURE_2D_ARRAY);
  164. }
  165. void LandRenderer::initBlendTexture()
  166. {
  167. // allocate blend texture
  168. glGenTextures(1, &blendTexture_);
  169. glBindTexture(GL_TEXTURE_2D_ARRAY, blendTexture_);
  170. glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  171. glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
  172. glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
  173. glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
  174. glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_R8, kBlendArraySize, kBlendArraySize, kBlendArrayDepth, 0, GL_RED, GL_UNSIGNED_BYTE, nullptr);
  175. // populate blend texture
  176. for(int i = 0; i < kBlendArrayDepth; i++)
  177. {
  178. Image image;
  179. if(kBlendTextures[i] == 0x00000000)
  180. {
  181. image.init(PixelFormat::kCustomLscapeAlpha, kBlendArraySize, kBlendArraySize, nullptr);
  182. }
  183. else if(kBlendTextures[i] == 0xFFFFFFFF)
  184. {
  185. image.init(PixelFormat::kCustomLscapeAlpha, kBlendArraySize, kBlendArraySize, nullptr);
  186. image.fill(0xFF);
  187. }
  188. else
  189. {
  190. ResourcePtr imgColor = Core::get().resourceCache().get(kBlendTextures[i]);
  191. image = imgColor->cast<ImgColor>().image;
  192. }
  193. if(image.width() != kBlendArraySize || image.height() != kBlendArraySize)
  194. {
  195. throw runtime_error("Bad alpha image size");
  196. }
  197. if(image.format() != PixelFormat::kCustomLscapeAlpha)
  198. {
  199. throw runtime_error("Bad alpha image format");
  200. }
  201. glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, kBlendArraySize, kBlendArraySize, 1, GL_RED, GL_UNSIGNED_BYTE, image.data());
  202. }
  203. }