A 2D tile-based sandbox game.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

LightServer.h 3.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #pragma once
  2. #include <thread>
  3. #include <vector>
  4. #include <unordered_map>
  5. #include <mutex>
  6. #include <condition_variable>
  7. #include <utility>
  8. #include <bitset>
  9. #include "common.h"
  10. namespace Swan {
  11. struct NewLightChunk {
  12. std::bitset<CHUNK_WIDTH * CHUNK_HEIGHT> blocks;
  13. std::map<std::pair<int, int>, float> lightSources;
  14. };
  15. struct LightChunk {
  16. LightChunk() = default;
  17. LightChunk(NewLightChunk &&ch);
  18. std::bitset<CHUNK_WIDTH * CHUNK_HEIGHT> blocks;
  19. uint8_t lightLevels[CHUNK_WIDTH * CHUNK_HEIGHT] = { 0 };
  20. float lightBuffers[CHUNK_WIDTH * CHUNK_HEIGHT * 2] = { 0 };
  21. int buffer = 0;
  22. uint8_t blocksLine[CHUNK_WIDTH] = { 0 };
  23. std::map<std::pair<int, int>, float> lightSources;
  24. std::vector<std::pair<TilePos, float>> bounces;
  25. float *lightBuffer() { return lightBuffers + CHUNK_WIDTH * CHUNK_HEIGHT * buffer; }
  26. bool wasUpdated = false;
  27. };
  28. class LightCallback {
  29. public:
  30. virtual void onLightChunkUpdated(const LightChunk &chunk, ChunkPos pos) = 0;
  31. };
  32. class LightServer {
  33. public:
  34. LightServer(LightCallback &cb);
  35. ~LightServer();
  36. void onSolidBlockAdded(TilePos pos);
  37. void onSolidBlockRemoved(TilePos pos);
  38. void onLightAdded(TilePos pos, float level);
  39. void onLightRemoved(TilePos pos, float level);
  40. void onChunkAdded(ChunkPos pos, NewLightChunk &&chunk);
  41. void onChunkRemoved(ChunkPos pos);
  42. private:
  43. static constexpr int LIGHT_CUTOFF_DIST = 64;
  44. static constexpr float LIGHT_CUTOFF = 0.001;
  45. struct Event {
  46. enum class Tag {
  47. BLOCK_ADDED, BLOCK_REMOVED, LIGHT_ADDED, LIGHT_REMOVED,
  48. CHUNK_ADDED, CHUNK_REMOVED,
  49. } tag;
  50. TilePos pos;
  51. union {
  52. float f;
  53. int i;
  54. };
  55. };
  56. bool tileIsSolid(TilePos pos);
  57. LightChunk *getChunk(ChunkPos cpos);
  58. float recalcTile(
  59. LightChunk &chunk, ChunkPos cpos, Vec2i rpos, TilePos base,
  60. std::vector<std::pair<TilePos, float>> &lights);
  61. void processChunkSun(LightChunk &chunk, ChunkPos cpos);
  62. void processChunkLights(LightChunk &chunk, ChunkPos cpos);
  63. void processChunkBounces(LightChunk &chunk, ChunkPos cpos);
  64. void processChunkSmoothing(LightChunk &chunk, ChunkPos cpos);
  65. void finalizeChunk(LightChunk &chunk);
  66. void processEvent(const Event &event, std::vector<NewLightChunk> &newChunks);
  67. void run();
  68. LightCallback &cb_;
  69. bool running_ = true;
  70. std::map<std::pair<int, int>, LightChunk> chunks_;
  71. std::set<std::pair<int, int>> updatedChunks_;
  72. LightChunk *cachedChunk_ = nullptr;
  73. Vec2i cachedChunkPos_;
  74. int buffer_ = 0;
  75. std::vector<Event> buffers_[2] = { {}, {} };
  76. std::vector<NewLightChunk> newChunkBuffers_[2] = { {}, {} };
  77. std::thread thread_;
  78. std::condition_variable cond_;
  79. std::mutex mut_;
  80. };
  81. inline void LightServer::onSolidBlockAdded(TilePos pos) {
  82. std::lock_guard<std::mutex> lock(mut_);
  83. buffers_[buffer_].push_back({ Event::Tag::BLOCK_ADDED, pos, { .i = 0 } });
  84. cond_.notify_one();
  85. }
  86. inline void LightServer::onSolidBlockRemoved(TilePos pos) {
  87. std::lock_guard<std::mutex> lock(mut_);
  88. buffers_[buffer_].push_back({ Event::Tag::BLOCK_REMOVED, pos, { .i = 0 } });
  89. cond_.notify_one();
  90. }
  91. inline void LightServer::onLightAdded(TilePos pos, float level) {
  92. std::lock_guard<std::mutex> lock(mut_);
  93. buffers_[buffer_].push_back({ Event::Tag::LIGHT_ADDED, pos, { .f = level } });
  94. cond_.notify_one();
  95. }
  96. inline void LightServer::onLightRemoved(TilePos pos, float level) {
  97. std::lock_guard<std::mutex> lock(mut_);
  98. buffers_[buffer_].push_back({ Event::Tag::LIGHT_REMOVED, pos, { .f = level } });
  99. cond_.notify_one();
  100. }
  101. inline void LightServer::onChunkAdded(Vec2i pos, NewLightChunk &&chunk) {
  102. std::lock_guard<std::mutex> lock(mut_);
  103. buffers_[buffer_].push_back({ Event::Tag::CHUNK_ADDED, pos,
  104. { .i = (int)newChunkBuffers_[buffer_].size() } });
  105. newChunkBuffers_[buffer_].push_back(std::move(chunk));
  106. cond_.notify_one();
  107. }
  108. inline void LightServer::onChunkRemoved(Vec2i pos) {
  109. std::lock_guard<std::mutex> lock(mut_);
  110. buffers_[buffer_].push_back({ Event::Tag::CHUNK_REMOVED, pos, { .i = 0 } });
  111. cond_.notify_one();
  112. }
  113. }