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.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  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> light_sources;
  14. };
  15. struct LightChunk {
  16. LightChunk() = default;
  17. LightChunk(NewLightChunk &&ch):
  18. blocks(std::move(ch.blocks)), light_sources(std::move(ch.light_sources)) {}
  19. std::bitset<CHUNK_WIDTH * CHUNK_HEIGHT> blocks;
  20. uint8_t light_levels[CHUNK_WIDTH * CHUNK_HEIGHT] = { 0 };
  21. uint8_t blocks_line[CHUNK_WIDTH] = { 0 };
  22. std::map<std::pair<int, int>, float> light_sources;
  23. std::vector<std::pair<TilePos, float>> bounces;
  24. bool was_updated = false;
  25. };
  26. class LightCallback {
  27. public:
  28. virtual void onLightChunkUpdated(const LightChunk &chunk, ChunkPos pos) = 0;
  29. };
  30. class LightServer {
  31. public:
  32. LightServer(LightCallback &cb);
  33. ~LightServer();
  34. void onSolidBlockAdded(TilePos pos);
  35. void onSolidBlockRemoved(TilePos pos);
  36. void onLightAdded(TilePos pos, float level);
  37. void onLightRemoved(TilePos pos, float level);
  38. void onChunkAdded(ChunkPos pos, NewLightChunk &&chunk);
  39. void onChunkRemoved(ChunkPos pos);
  40. private:
  41. static constexpr int LIGHT_CUTOFF_DIST = 64;
  42. static constexpr float LIGHT_CUTOFF = 1;
  43. struct Event {
  44. enum class Tag {
  45. BLOCK_ADDED, BLOCK_REMOVED, LIGHT_ADDED, LIGHT_REMOVED,
  46. CHUNK_ADDED, CHUNK_REMOVED,
  47. } tag;
  48. TilePos pos;
  49. union {
  50. float f;
  51. int i;
  52. };
  53. };
  54. bool tileIsSolid(TilePos pos);
  55. LightChunk *getChunk(ChunkPos cpos);
  56. float recalcTile(
  57. LightChunk &chunk, ChunkPos cpos, Vec2i rpos, TilePos base,
  58. std::vector<std::pair<TilePos, float>> &lights);
  59. void processChunkLights(LightChunk &chunk, ChunkPos cpos);
  60. void processChunkBounces(LightChunk &chunk, ChunkPos cpos);
  61. void processChunkSmoothing(LightChunk &chunk, ChunkPos cpos);
  62. void processEvent(const Event &event, std::vector<NewLightChunk> &newChunks);
  63. void run();
  64. LightCallback &cb_;
  65. bool running_ = true;
  66. std::map<std::pair<int, int>, LightChunk> chunks_;
  67. std::set<std::pair<int, int>> updated_chunks_;
  68. LightChunk *cached_chunk_ = nullptr;
  69. Vec2i cached_chunk_pos_;
  70. int buffer_ = 0;
  71. std::vector<Event> buffers_[2] = { {}, {} };
  72. std::vector<NewLightChunk> new_chunk_buffers_[2] = { {}, {} };
  73. std::thread thread_;
  74. std::condition_variable cond_;
  75. std::mutex mut_;
  76. };
  77. inline void LightServer::onSolidBlockAdded(TilePos pos) {
  78. std::lock_guard<std::mutex> lock(mut_);
  79. buffers_[buffer_].push_back({ Event::Tag::BLOCK_ADDED, pos, { .i = 0 } });
  80. cond_.notify_one();
  81. }
  82. inline void LightServer::onSolidBlockRemoved(TilePos pos) {
  83. std::lock_guard<std::mutex> lock(mut_);
  84. buffers_[buffer_].push_back({ Event::Tag::BLOCK_REMOVED, pos, { .i = 0 } });
  85. cond_.notify_one();
  86. }
  87. inline void LightServer::onLightAdded(TilePos pos, float level) {
  88. std::lock_guard<std::mutex> lock(mut_);
  89. buffers_[buffer_].push_back({ Event::Tag::LIGHT_ADDED, pos, { .f = level } });
  90. cond_.notify_one();
  91. }
  92. inline void LightServer::onLightRemoved(TilePos pos, float level) {
  93. std::lock_guard<std::mutex> lock(mut_);
  94. buffers_[buffer_].push_back({ Event::Tag::LIGHT_REMOVED, pos, { .f = level } });
  95. cond_.notify_one();
  96. }
  97. inline void LightServer::onChunkAdded(Vec2i pos, NewLightChunk &&chunk) {
  98. std::lock_guard<std::mutex> lock(mut_);
  99. buffers_[buffer_].push_back({ Event::Tag::CHUNK_ADDED, pos,
  100. { .i = (int)new_chunk_buffers_[buffer_].size() } });
  101. new_chunk_buffers_[buffer_].push_back(std::move(chunk));
  102. cond_.notify_one();
  103. }
  104. inline void LightServer::onChunkRemoved(Vec2i pos) {
  105. std::lock_guard<std::mutex> lock(mut_);
  106. buffers_[buffer_].push_back({ Event::Tag::CHUNK_REMOVED, pos, { .i = 0 } });
  107. cond_.notify_one();
  108. }
  109. }