Browse Source

a kind of lighting effect

fix/style
Martin Dørum 3 years ago
parent
commit
262ca389fe

+ 1
- 0
core.mod/CMakeLists.txt View File

@@ -16,6 +16,7 @@ set(assets
assets/tile/dirt.png
assets/tile/leaves.png
assets/tile/tree-trunk.png
assets/tile/torch.png
assets/misc/background-cave.png)
foreach(a ${assets})
configure_file("${a}" "${a}" COPYONLY)

BIN
core.mod/assets-src/tiles/torch.xcf View File


BIN
core.mod/assets/tile/torch.png View File


+ 7
- 0
core.mod/src/entities/PlayerEntity.cc View File

@@ -31,6 +31,13 @@ void PlayerEntity::update(const Swan::Context &ctx, float dt) {
if (ctx.game.isMousePressed(SDL_BUTTON_LEFT))
ctx.plane.breakTile(mouse_tile_);

// Place block
if (ctx.game.isMousePressed(SDL_BUTTON_RIGHT)) {
if (ctx.plane.getTileID(mouse_tile_) == ctx.world.getTileID("@::air")) {
ctx.plane.setTile(mouse_tile_, "core::torch");
}
}

// Move left
if (ctx.game.isKeyPressed(SDL_SCANCODE_A) || ctx.game.isKeyPressed(SDL_SCANCODE_LEFT)) {
physics_.force += Swan::Vec2(-MOVE_FORCE, 0);

+ 7
- 0
core.mod/src/main.cc View File

@@ -15,6 +15,7 @@ public:
registerImage("tile/grass");
registerImage("tile/tree-trunk");
registerImage("tile/leaves");
registerImage("tile/torch");
registerImage("entity/player-running");
registerImage("entity/player-still");
registerImage("misc/background-cave");
@@ -43,6 +44,12 @@ public:
.name = "leaves",
.image = "core/tile/leaves",
});
registerTile({
.name = "torch",
.image = "core/tile/torch",
.is_solid = false,
.light_level = 20,
});

registerItem({
.name = "stone",

+ 4
- 2
libswan/include/swan/Chunk.h View File

@@ -30,7 +30,7 @@ public:

Chunk(ChunkPos pos): pos_(pos) {
data_.reset(new uint8_t[DATA_SIZE]);
memset(getLightData(), 255, CHUNK_WIDTH * CHUNK_HEIGHT);
memset(getLightData(), 0, CHUNK_WIDTH * CHUNK_HEIGHT);
}

Tile::ID *getTileData() {
@@ -65,10 +65,11 @@ public:

void setLightData(RelPos pos, uint8_t level) {
getLightData()[pos.y * CHUNK_WIDTH + pos.x] = level;
need_render_ = true;
need_light_render_ = true;
}

void render(const Context &ctx, SDL_Renderer *rnd);
void renderLight(const Context &ctx, SDL_Renderer *rnd);

void compress();
void decompress();
@@ -93,6 +94,7 @@ private:

ssize_t compressed_size_ = -1; // -1 if not compressed, a positive number if compressed
bool need_render_ = false;
bool need_light_render_ = false;
float deactivate_timer_ = DEACTIVATE_INTERVAL;
bool is_modified_ = false;


+ 4
- 1
libswan/include/swan/Tile.h View File

@@ -19,16 +19,19 @@ public:
std::string name;
std::string image;
bool is_solid = true;
uint8_t light_level = 0;
std::optional<std::string> dropped_item = std::nullopt;
};

Tile(const ResourceManager &resources, const Builder &builder):
name_(builder.name), image_(resources.getImage(builder.image)),
is_solid_(builder.is_solid), dropped_item_(builder.dropped_item) {}
is_solid_(builder.is_solid), light_level_(builder.light_level),
dropped_item_(builder.dropped_item) {}

const std::string name_;
const ImageResource &image_;
const bool is_solid_;
const uint8_t light_level_;
const std::optional<std::string> dropped_item_;

static std::unique_ptr<Tile> createInvalid(const ResourceManager &ctx);

+ 3
- 0
libswan/include/swan/WorldPlane.h View File

@@ -79,6 +79,9 @@ public:
std::unique_ptr<WorldGen> gen_;

private:
void addLight(TilePos pos, uint8_t level);
void removeLight(TilePos pos, uint8_t level);

std::map<std::pair<int, int>, Chunk> chunks_;
std::vector<Chunk *> active_chunks_;
std::vector<std::pair<ChunkPos, Chunk *>> tick_chunks_;

+ 40
- 21
libswan/src/Chunk.cc View File

@@ -72,6 +72,40 @@ void Chunk::decompress() {
compressed_size_ = -1;
}

void Chunk::renderLight(const Context &ctx, SDL_Renderer *rnd) {
std::optional<RenderTarget> target;

// The texture might not be created yet
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);

target.emplace(rnd, texture_.get());
} else {
target.emplace(rnd, texture_.get());
}

// 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) {
int level = getLightLevel({ x, y });
if (level >= 8)
color.change(0, 0, 0, 0);
else
color.change(0, 0, 0, 255 - level * 32);
SDL_Rect rect{ x, y, 1, 1 };
SDL_RenderFillRect(rnd, &rect);
}
}

need_light_render_ = false;
}

void Chunk::render(const Context &ctx, SDL_Renderer *rnd) {
std::optional<RenderTarget> target;

@@ -91,14 +125,6 @@ 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();
@@ -117,19 +143,9 @@ 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;

renderLight(ctx, rnd);
}

void Chunk::renderList(SDL_Renderer *rnd) {
@@ -159,12 +175,15 @@ void Chunk::draw(const Context &ctx, Win &win) {
if (need_render_)
return;

// We're responsible for the light level rendering though
if (need_light_render_)
renderLight(ctx, win.renderer_);

if (draw_list_.size() > 0) {
renderList(win.renderer_);
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(chunkpos, texture_.get(), &rect);

+ 71
- 1
libswan/src/WorldPlane.cc View File

@@ -103,8 +103,18 @@ void WorldPlane::setTileID(TilePos pos, Tile::ID id) {

Tile::ID old = chunk.getTileID(rp);
if (id != old) {
chunk.setTileID(rp, id, world_->getTileByID(id).image_.texture_.get());
Tile &newTile = world_->getTileByID(id);
Tile &oldTile = world_->getTileByID(old);
chunk.setTileID(rp, id, newTile.image_.texture_.get());
chunk.markModified();

if (oldTile.light_level_ > 0) {
removeLight(pos, oldTile.light_level_);
}

if (newTile.light_level_ > 0) {
addLight(pos, newTile.light_level_);
}
}
}

@@ -255,4 +265,64 @@ void WorldPlane::debugBox(TilePos pos) {
debug_boxes_.push_back(pos);
}

void WorldPlane::addLight(TilePos pos, uint8_t level) {
int sqrLevel = level * level;

for (int y = -level; y <= level; ++y) {
for (int x = -level; x <= level; ++x) {
int sqrDist = x * x + y * y;
if (sqrDist > sqrLevel) {
continue;
}

int lightDiff = level - (int)sqrt(sqrDist);
if (lightDiff <= 0) {
continue;
}

TilePos tp = pos + Vec2i(x, y);
ChunkPos cp = chunkPos(tp);
Chunk::RelPos rp = relPos(tp);

Chunk &ch = getChunk(cp);
int light = (int)ch.getLightLevel(rp) + lightDiff;
if (light > 255) {
light = 255;
}

ch.setLightData(rp, light);
}
}
}

void WorldPlane::removeLight(TilePos pos, uint8_t level) {
int sqrLevel = level * level;

for (int y = -level; y <= level; ++y) {
for (int x = -level; x <= level; ++x) {
int sqrDist = x * x + y * y;
if (sqrDist > sqrLevel) {
continue;
}

int lightDiff = level - (int)sqrt(sqrDist);
if (lightDiff <= 0) {
continue;
}

TilePos tp = pos + Vec2i(x, y);
ChunkPos cp = chunkPos(tp);
Chunk::RelPos rp = relPos(tp);

Chunk &ch = getChunk(cp);
int light = (int)ch.getLightLevel(rp) - lightDiff;
if (light < 0) {
light = 0;
}

ch.setLightData(rp, light);
}
}
}

}

Loading…
Cancel
Save