LightPointEmission.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. #include "LightPointEmission.h"
  2. #include "LightShape.h"
  3. #include "LightSystem.h"
  4. #include <iostream>
  5. #include <cassert>
  6. #include <cmath>
  7. using namespace ltbl;
  8. void LightPointEmission::render(const sf::View& view,
  9. sf::RenderTexture& lightTempTexture, sf::RenderTexture& emissionTempTexture, sf::RenderTexture& antumbraTempTexture,
  10. const std::vector<QuadtreeOccupant*>& shapes,
  11. sf::Shader& unshadowShader, sf::Shader& lightOverShapeShader,
  12. bool normalsEnabled, sf::Shader& normalsShader)
  13. {
  14. emissionTempTexture.clear();
  15. emissionTempTexture.setView(view);
  16. emissionTempTexture.draw(_emissionSprite);
  17. emissionTempTexture.display();
  18. // Note: We don't want origin from _emissionSprite.getTransform,
  19. // as the center point is the origin itself.
  20. sf::Transform t = _emissionSprite.getTransform();
  21. t.translate(_emissionSprite.getOrigin());
  22. sf::Vector2f castCenter = t.transformPoint(_localCastCenter);
  23. float shadowExtension = _shadowOverExtendMultiplier * (getAABB().width + getAABB().height);
  24. struct OuterEdges {
  25. std::vector<int> _outerBoundaryIndices;
  26. std::vector<sf::Vector2f> _outerBoundaryVectors;
  27. };
  28. std::vector<OuterEdges> outerEdges(shapes.size());
  29. std::vector<int> innerBoundaryIndices;
  30. std::vector<sf::Vector2f> innerBoundaryVectors;
  31. std::vector<LightSystem::Penumbra> penumbras;
  32. sf::RenderStates maskRenderStates;
  33. maskRenderStates.blendMode = sf::BlendNone;
  34. sf::RenderStates antumbraRenderStates;
  35. antumbraRenderStates.blendMode = sf::BlendMultiply;
  36. //----- Emission
  37. lightTempTexture.clear();
  38. lightTempTexture.setView(view);
  39. if (normalsEnabled) {
  40. auto oglLightPosition = lightTempTexture.mapCoordsToPixel(_emissionSprite.getPosition());
  41. normalsShader.setParameter("lightPosition", oglLightPosition.x, static_cast<int>(lightTempTexture.getSize().y - oglLightPosition.y), 0.15f);
  42. const auto& lightColor = _emissionSprite.getColor();
  43. sf::Vector3f oglLightColor{lightColor.r / 255.f, lightColor.g / 255.f, lightColor.b / 255.f};
  44. normalsShader.setParameter("lightColor", oglLightColor);
  45. // TODO Having a better interface for emission sprite settings would make us able to precompute and stores these values
  46. // But all that depends on the view
  47. auto oglOrigin = lightTempTexture.mapCoordsToPixel({0.f, 0.f});
  48. auto oglLightWidthPos = lightTempTexture.mapCoordsToPixel({getAABB().width, 0.f}) - oglOrigin;
  49. auto oglLightHeightPos = lightTempTexture.mapCoordsToPixel({0.f, getAABB().height}) - oglOrigin;
  50. float oglLightWidth = std::sqrt(oglLightWidthPos.x * oglLightWidthPos.x + oglLightWidthPos.y * oglLightWidthPos.y);
  51. float oglLightHeight = std::sqrt(oglLightHeightPos.x * oglLightHeightPos.x + oglLightHeightPos.y * oglLightHeightPos.y);
  52. normalsShader.setParameter("lightSize", oglLightWidth, oglLightHeight);
  53. lightTempTexture.draw(_emissionSprite, &normalsShader);
  54. }
  55. else {
  56. lightTempTexture.draw(_emissionSprite);
  57. }
  58. //----- Shapes
  59. // Mask off light shape (over-masking - mask too much, reveal penumbra/antumbra afterwards)
  60. unsigned shapesCount = shapes.size();
  61. for (unsigned i = 0; i < shapesCount; ++i) {
  62. LightShape* pLightShape = static_cast<LightShape*>(shapes[i]);
  63. // Get boundaries
  64. innerBoundaryIndices.clear();
  65. innerBoundaryVectors.clear();
  66. penumbras.clear();
  67. LightSystem::getPenumbrasPoint(penumbras, innerBoundaryIndices, innerBoundaryVectors, outerEdges[i]._outerBoundaryIndices, outerEdges[i]._outerBoundaryVectors, pLightShape->_shape, castCenter, _sourceRadius);
  68. if (innerBoundaryIndices.size() != 2 || outerEdges[i]._outerBoundaryIndices.size() != 2)
  69. continue;
  70. // Render shape
  71. if (!pLightShape->_renderLightOverShape) {
  72. pLightShape->_shape.setFillColor(sf::Color::Black);
  73. lightTempTexture.draw(pLightShape->_shape);
  74. }
  75. sf::Vector2f as = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(outerEdges[i]._outerBoundaryIndices[0]));
  76. sf::Vector2f bs = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(outerEdges[i]._outerBoundaryIndices[1]));
  77. sf::Vector2f ad = outerEdges[i]._outerBoundaryVectors[0];
  78. sf::Vector2f bd = outerEdges[i]._outerBoundaryVectors[1];
  79. sf::Vector2f intersectionOuter;
  80. // Handle antumbras as a seperate case
  81. if (rayIntersect(as, ad, bs, bd, intersectionOuter)) {
  82. sf::Vector2f asi = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[0]));
  83. sf::Vector2f bsi = pLightShape->_shape.getTransform().transformPoint(pLightShape->_shape.getPoint(innerBoundaryIndices[1]));
  84. sf::Vector2f adi = innerBoundaryVectors[0];
  85. sf::Vector2f bdi = innerBoundaryVectors[1];
  86. antumbraTempTexture.clear(sf::Color::White);
  87. antumbraTempTexture.setView(view);
  88. sf::Vector2f intersectionInner;
  89. if (rayIntersect(asi, adi, bsi, bdi, intersectionInner)) {
  90. sf::ConvexShape maskShape;
  91. maskShape.setPointCount(3);
  92. maskShape.setPoint(0, asi);
  93. maskShape.setPoint(1, bsi);
  94. maskShape.setPoint(2, intersectionInner);
  95. maskShape.setFillColor(sf::Color::Black);
  96. antumbraTempTexture.draw(maskShape);
  97. }
  98. else {
  99. sf::ConvexShape maskShape;
  100. maskShape.setPointCount(4);
  101. maskShape.setPoint(0, asi);
  102. maskShape.setPoint(1, bsi);
  103. maskShape.setPoint(2, bsi + vectorNormalize(bdi) * shadowExtension);
  104. maskShape.setPoint(3, asi + vectorNormalize(adi) * shadowExtension);
  105. maskShape.setFillColor(sf::Color::Black);
  106. antumbraTempTexture.draw(maskShape);
  107. }
  108. // Add light back for antumbra/penumbras
  109. sf::VertexArray vertexArray;
  110. vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles);
  111. vertexArray.resize(3);
  112. sf::RenderStates penumbraRenderStates;
  113. penumbraRenderStates.blendMode = sf::BlendAdd;
  114. penumbraRenderStates.shader = &unshadowShader;
  115. // Unmask with penumbras
  116. for (unsigned j = 0; j < penumbras.size(); j++) {
  117. unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness);
  118. unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness);
  119. vertexArray[0].position = penumbras[j]._source;
  120. vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * shadowExtension;
  121. vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * shadowExtension;
  122. vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f);
  123. vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f);
  124. vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f);
  125. antumbraTempTexture.draw(vertexArray, penumbraRenderStates);
  126. }
  127. antumbraTempTexture.display();
  128. // Multiply back to lightTempTexture
  129. sf::Sprite s;
  130. s.setTexture(antumbraTempTexture.getTexture());
  131. lightTempTexture.setView(lightTempTexture.getDefaultView());
  132. lightTempTexture.draw(s, antumbraRenderStates);
  133. lightTempTexture.setView(view);
  134. }
  135. else {
  136. sf::ConvexShape maskShape;
  137. maskShape.setPointCount(4);
  138. maskShape.setPoint(0, as);
  139. maskShape.setPoint(1, bs);
  140. maskShape.setPoint(2, bs + vectorNormalize(bd) * shadowExtension);
  141. maskShape.setPoint(3, as + vectorNormalize(ad) * shadowExtension);
  142. maskShape.setFillColor(sf::Color::Black);
  143. lightTempTexture.draw(maskShape);
  144. sf::VertexArray vertexArray;
  145. vertexArray.setPrimitiveType(sf::PrimitiveType::Triangles);
  146. vertexArray.resize(3);
  147. sf::RenderStates penumbraRenderStates;
  148. penumbraRenderStates.blendMode = sf::BlendMultiply;
  149. penumbraRenderStates.shader = &unshadowShader;
  150. // Unmask with penumbras
  151. for (unsigned j = 0; j < penumbras.size(); j++) {
  152. unshadowShader.setParameter("lightBrightness", penumbras[j]._lightBrightness);
  153. unshadowShader.setParameter("darkBrightness", penumbras[j]._darkBrightness);
  154. vertexArray[0].position = penumbras[j]._source;
  155. vertexArray[1].position = penumbras[j]._source + vectorNormalize(penumbras[j]._lightEdge) * shadowExtension;
  156. vertexArray[2].position = penumbras[j]._source + vectorNormalize(penumbras[j]._darkEdge) * shadowExtension;
  157. vertexArray[0].texCoords = sf::Vector2f(0.0f, 1.0f);
  158. vertexArray[1].texCoords = sf::Vector2f(1.0f, 0.0f);
  159. vertexArray[2].texCoords = sf::Vector2f(0.0f, 0.0f);
  160. lightTempTexture.draw(vertexArray, penumbraRenderStates);
  161. }
  162. }
  163. }
  164. for (unsigned i = 0; i < shapesCount; i++) {
  165. LightShape* pLightShape = static_cast<LightShape*>(shapes[i]);
  166. if (pLightShape->_renderLightOverShape) {
  167. pLightShape->_shape.setFillColor(sf::Color::White);
  168. lightTempTexture.draw(pLightShape->_shape, &lightOverShapeShader);
  169. }
  170. else {
  171. pLightShape->_shape.setFillColor(sf::Color::Black);
  172. lightTempTexture.draw(pLightShape->_shape);
  173. }
  174. }
  175. //----- Finish
  176. lightTempTexture.display();
  177. }