@@ -17,6 +17,10 @@ class Chunk { | |||
public: | |||
using RelPos = TilePos; | |||
static constexpr size_t DATA_SIZE = | |||
CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID) + // Tiles | |||
CHUNK_WIDTH * CHUNK_HEIGHT; // Light levels | |||
// What does this chunk want the world gen to do after a tick? | |||
enum class TickAction { | |||
DEACTIVATE, | |||
@@ -25,7 +29,8 @@ public: | |||
}; | |||
Chunk(ChunkPos pos): pos_(pos) { | |||
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]); | |||
data_.reset(new uint8_t[DATA_SIZE]); | |||
memset(getLightData(), 255, CHUNK_WIDTH * CHUNK_HEIGHT); | |||
} | |||
Tile::ID *getTileData() { | |||
@@ -33,6 +38,11 @@ public: | |||
return (Tile::ID *)data_.get(); | |||
} | |||
uint8_t *getLightData() { | |||
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]; | |||
} | |||
@@ -47,6 +57,17 @@ public: | |||
need_render_ = true; | |||
} | |||
uint8_t getLightLevel(RelPos pos) { | |||
return getLightData()[pos.y * CHUNK_WIDTH + pos.x]; | |||
} | |||
void setLightLevel(RelPos pos, uint8_t level, SDL_Renderer *rnd); | |||
void setLightData(RelPos pos, uint8_t level) { | |||
getLightData()[pos.y * CHUNK_WIDTH + pos.x] = level; | |||
need_render_ = true; | |||
} | |||
void render(const Context &ctx, SDL_Renderer *rnd); | |||
void compress(); | |||
@@ -76,6 +97,7 @@ private: | |||
bool is_modified_ = false; | |||
CPtr<SDL_Texture, SDL_DestroyTexture> texture_; | |||
CPtr<SDL_Texture, SDL_DestroyTexture> light_texture_; | |||
}; | |||
} |
@@ -68,6 +68,14 @@ public: | |||
warn << "RenderCopyEx failed: " << SDL_GetError(); | |||
} | |||
void showTexture(const Vec2 &pos, SDL_Texture *tex, SDL_Rect *srcrect, | |||
SDL_Rect *dest, ShowTextureArgs args) { | |||
SDL_Point *center = args.center ? &*args.center : nullptr; | |||
SDL_Rect destrect = createDestRect(pos, Vec2(dest->w * args.hscale, dest->h * args.hscale)); | |||
if (SDL_RenderCopyEx(renderer_, tex, srcrect, &destrect, args.angle, center, args.flip) < 0) | |||
warn << "RenderCopyEx failed: " << SDL_GetError(); | |||
} | |||
// We want an overload which uses RenderCopy instead of RenderCopyEx, | |||
// because RenderCopy might be faster | |||
void showTexture(const Vec2 &pos, SDL_Texture *tex, SDL_Rect *srcrect) { | |||
@@ -76,6 +84,14 @@ public: | |||
warn << "RenderCopy failed: " << SDL_GetError(); | |||
} | |||
// Another overload without RenderCopyEx | |||
void showTexture(const Vec2 &pos, SDL_Texture *tex, SDL_Rect *srcrect, | |||
SDL_Rect *dest) { | |||
SDL_Rect destrect = createDestRect(pos, Vec2(dest->w, dest->h)); | |||
if (SDL_RenderCopy(renderer_, tex, srcrect, &destrect) < 0) | |||
warn << "RenderCopy failed: " << SDL_GetError(); | |||
} | |||
void drawRect(const Vec2 &pos, const Vec2 &size) { | |||
SDL_Rect destrect = createDestRect(pos, size * TILE_SIZE); | |||
if (SDL_RenderDrawRect(renderer_, &destrect) < 0) |
@@ -37,6 +37,10 @@ public: | |||
SDL_SetRenderDrawColor(rnd_, r, g, b, a); | |||
} | |||
void change(Uint8 r, Uint8 g, Uint8 b, Uint8 a = 255) { | |||
SDL_SetRenderDrawColor(rnd_, r, g, b, a); | |||
} | |||
~RenderDrawColor() { | |||
SDL_SetRenderDrawColor(rnd_, r_, g_, b_, a_); | |||
} |
@@ -24,7 +24,7 @@ void Chunk::compress() { | |||
uLongf destlen = sizeof(dest); | |||
int ret = compress2( | |||
(Bytef *)dest, &destlen, | |||
(Bytef *)data_.get(), CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID), | |||
(Bytef *)data_.get(), DATA_SIZE, | |||
Z_BEST_COMPRESSION); | |||
if (ret == Z_OK) { | |||
@@ -36,7 +36,7 @@ void Chunk::compress() { | |||
info | |||
<< "Compressed chunk " << pos_ << " from " | |||
<< CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID) << " bytes " | |||
<< DATA_SIZE << " bytes " | |||
<< "to " << destlen << " bytes"; | |||
} else if (ret == Z_BUF_ERROR) { | |||
info | |||
@@ -51,8 +51,8 @@ void Chunk::decompress() { | |||
if (!isCompressed()) | |||
return; | |||
auto dest = std::make_unique<uint8_t[]>(CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)); | |||
uLongf destlen = CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID); | |||
auto dest = std::make_unique<uint8_t[]>(DATA_SIZE); | |||
uLongf destlen = DATA_SIZE; | |||
int ret = uncompress( | |||
dest.get(), &destlen, | |||
(Bytef *)data_.get(), compressed_size_); | |||
@@ -68,7 +68,7 @@ void Chunk::decompress() { | |||
info | |||
<< "Decompressed chunk " << pos_ << " from " | |||
<< compressed_size_ << " bytes to " | |||
<< CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID) << " bytes."; | |||
<< DATA_SIZE << " bytes."; | |||
compressed_size_ = -1; | |||
} | |||
@@ -91,10 +91,19 @@ void Chunk::render(const Context &ctx, SDL_Renderer *rnd) { | |||
target.emplace(rnd, texture_.get()); | |||
} | |||
// Same with light texture | |||
if (!light_texture_) { | |||
light_texture_.reset(SDL_CreateTexture( | |||
ctx.game.win_.renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET, | |||
CHUNK_WIDTH, CHUNK_HEIGHT)); | |||
SDL_SetTextureBlendMode(light_texture_.get(), SDL_BLENDMODE_BLEND); | |||
} | |||
// We're caching tiles so we don't have to world.getTileByID() every time | |||
Tile::ID prevID = Tile::INVALID_ID; | |||
Tile *tile = ctx.game.invalid_tile_.get(); | |||
// Fill tile texture | |||
for (int y = 0; y < CHUNK_HEIGHT; ++y) { | |||
for (int x = 0; x < CHUNK_WIDTH; ++x) { | |||
Tile::ID id = getTileID(RelPos(x, y)); | |||
@@ -108,6 +117,18 @@ void Chunk::render(const Context &ctx, SDL_Renderer *rnd) { | |||
} | |||
} | |||
// Fill light texture | |||
target.emplace(rnd, light_texture_.get()); | |||
RenderBlendMode mode(rnd, SDL_BLENDMODE_NONE); | |||
RenderDrawColor color(rnd, 0, 0, 0, 0); | |||
for (int y = 0; y < CHUNK_HEIGHT; ++y) { | |||
for (int x = 0; x < CHUNK_WIDTH; ++x) { | |||
color.change(0, 0, 0, 255 - getLightLevel({ x, y })); | |||
SDL_Rect rect{ x, y, 1, 1 }; | |||
SDL_RenderFillRect(rnd, &rect); | |||
} | |||
} | |||
need_render_ = false; | |||
} | |||
@@ -143,10 +164,13 @@ void Chunk::draw(const Context &ctx, Win &win) { | |||
draw_list_.clear(); | |||
} | |||
auto chunkpos = pos_ * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT); | |||
SDL_Rect rect{ 0, 0, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE }; | |||
win.showTexture( | |||
pos_ * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT), | |||
texture_.get(), &rect); | |||
win.showTexture(chunkpos, texture_.get(), &rect); | |||
SDL_Rect texrect{ 0, 0, CHUNK_WIDTH, CHUNK_HEIGHT }; | |||
win.showTexture(chunkpos, light_texture_.get(), &texrect, &rect); | |||
} | |||
Chunk::TickAction Chunk::tick(float dt) { |