@@ -15,6 +15,7 @@ struct RendererState; | |||
struct RenderChunk { | |||
GLuint tex; | |||
GLuint opacityTex; | |||
}; | |||
struct RenderSprite { | |||
@@ -48,8 +49,9 @@ public: | |||
void modifyTile(TileID id, const void *data); | |||
RenderChunk createChunk( | |||
TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]); | |||
void modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id); | |||
TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT], | |||
uint8_t opacities[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]); | |||
void modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id, uint8_t opacity); | |||
void destroyChunk(RenderChunk chunk); | |||
RenderSprite createSprite(void *data, int width, int height, int fh); |
@@ -662,9 +662,13 @@ void Renderer::modifyTile(TileID id, const void *data) { | |||
} | |||
RenderChunk Renderer::createChunk( | |||
TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]) { | |||
TileID tiles[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT], | |||
uint8_t opacities[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT]) { | |||
RenderChunk chunk; | |||
glGenTextures(1, &chunk.tex); | |||
GLuint texes[2]; | |||
glGenTextures(2, texes); | |||
chunk.tex = texes[0]; | |||
chunk.opacityTex = texes[1]; | |||
glCheck(); | |||
glActiveTexture(GL_TEXTURE0); | |||
@@ -685,6 +689,7 @@ RenderChunk Renderer::createChunk( | |||
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, | |||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | |||
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, tiles); | |||
glCheck(); | |||
} else if constexpr (std::endian::native == std::endian::big) { | |||
uint8_t buf[SwanCommon::CHUNK_WIDTH * SwanCommon::CHUNK_HEIGHT * 2]; | |||
for (size_t y = 0; y < SwanCommon::CHUNK_HEIGHT; ++y) { | |||
@@ -700,13 +705,20 @@ RenderChunk Renderer::createChunk( | |||
GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, | |||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | |||
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf); | |||
glCheck(); | |||
} | |||
glBindTexture(GL_TEXTURE_2D, chunk.opacityTex); | |||
glTexImage2D( | |||
GL_TEXTURE_2D, 0, GL_LUMINANCE, | |||
SwanCommon::CHUNK_WIDTH, SwanCommon::CHUNK_HEIGHT, | |||
0, GL_LUMINANCE, GL_UNSIGNED_BYTE, opacities); | |||
glCheck(); | |||
return chunk; | |||
} | |||
void Renderer::modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id) { | |||
void Renderer::modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id, uint8_t opacity) { | |||
glActiveTexture(GL_TEXTURE0); | |||
glBindTexture(GL_TEXTURE_2D, chunk.tex); | |||
glCheck(); | |||
@@ -720,18 +732,24 @@ void Renderer::modifyChunk(RenderChunk chunk, SwanCommon::Vec2i pos, TileID id) | |||
glTexSubImage2D( | |||
GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | |||
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, &id); | |||
glCheck(); | |||
} else if constexpr (std::endian::native == std::endian::big) { | |||
uint8_t buf[] = { (uint8_t)(id & 0xff), (uint8_t)((id & 0xff00) >> 8) }; | |||
glTexSubImage2D( | |||
GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | |||
GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, buf); | |||
glCheck(); | |||
} | |||
glCheck(); | |||
glBindTexture(GL_TEXTURE_2D, chunk.opacityTex); | |||
glTexSubImage2D( | |||
GL_TEXTURE_2D, 0, pos.x, pos.y, 1, 1, | |||
GL_LUMINANCE, GL_UNSIGNED_BYTE, &opacity); | |||
} | |||
void Renderer::destroyChunk(RenderChunk chunk) { | |||
glDeleteTextures(1, &chunk.tex); | |||
GLuint texes[] = {chunk.tex, chunk.opacityTex}; | |||
glDeleteTextures(2, texes); | |||
glCheck(); | |||
} | |||
@@ -19,7 +19,8 @@ public: | |||
using RelPos = TilePos; | |||
static constexpr size_t DATA_SIZE = | |||
CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID); | |||
CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID) + | |||
CHUNK_WIDTH * CHUNK_HEIGHT; | |||
// What does this chunk want the world gen to do after a tick? | |||
enum class TickAction { | |||
@@ -35,13 +36,19 @@ public: | |||
return (Tile::ID *)data_.get(); | |||
} | |||
uint8_t *getOpacityData() { | |||
assert(isActive()); | |||
return data_.get() + CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID); | |||
} | |||
Tile::ID getTileID(RelPos pos) { | |||
return getTileData()[pos.y * CHUNK_WIDTH + pos.x]; | |||
} | |||
void setTileID(RelPos pos, Tile::ID id) { | |||
void setTileID(RelPos pos, Tile::ID id, uint8_t opacity) { | |||
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id; | |||
changeList_.emplace_back(pos, id); | |||
getOpacityData()[pos.y * CHUNK_WIDTH + pos.x] = opacity; | |||
changeList_.emplace_back(pos, id, opacity); | |||
isModified_ = true; | |||
} | |||
@@ -71,7 +78,7 @@ private: | |||
std::unique_ptr<uint8_t[]> data_; | |||
std::vector<std::pair<RelPos, float>> lights_; | |||
std::vector<std::pair<RelPos, Tile::ID>> changeList_; | |||
std::vector<std::tuple<RelPos, Tile::ID, uint8_t>> changeList_; | |||
ssize_t compressedSize_ = -1; // -1 if not compressed, a positive number if compressed | |||
Cygnet::RenderChunk renderChunk_; |
@@ -118,11 +118,11 @@ void Chunk::draw(const Context &ctx, Cygnet::Renderer &rnd) { | |||
return; | |||
if (needChunkRender_) { | |||
renderChunk_ = rnd.createChunk(getTileData()); | |||
renderChunk_ = rnd.createChunk(getTileData(), getOpacityData()); | |||
needChunkRender_ = false; | |||
} else { | |||
for (auto [pos, id]: changeList_) { | |||
rnd.modifyChunk(renderChunk_, pos, id); | |||
for (auto [pos, id, opacity]: changeList_) { | |||
rnd.modifyChunk(renderChunk_, pos, id, opacity); | |||
} | |||
} | |||
@@ -105,7 +105,7 @@ void WorldPlane::setTileID(TilePos pos, Tile::ID id) { | |||
if (id != old) { | |||
Tile &newTile = world_->getTileByID(id); | |||
Tile &oldTile = world_->getTileByID(old); | |||
chunk.setTileID(rp, id); | |||
chunk.setTileID(rp, id, newTile.isSolid ? 255 : 0); | |||
if (newTile.lightLevel != oldTile.lightLevel) { | |||
if (oldTile.lightLevel > 0) { |