瀏覽代碼

a kind of lighting effect

fix/style
Martin Dørum 3 年之前
父節點
當前提交
262ca389fe

+ 1
- 0
core.mod/CMakeLists.txt 查看文件

assets/tile/dirt.png assets/tile/dirt.png
assets/tile/leaves.png assets/tile/leaves.png
assets/tile/tree-trunk.png assets/tile/tree-trunk.png
assets/tile/torch.png
assets/misc/background-cave.png) assets/misc/background-cave.png)
foreach(a ${assets}) foreach(a ${assets})
configure_file("${a}" "${a}" COPYONLY) configure_file("${a}" "${a}" COPYONLY)

二進制
core.mod/assets-src/tiles/torch.xcf 查看文件


二進制
core.mod/assets/tile/torch.png 查看文件


+ 7
- 0
core.mod/src/entities/PlayerEntity.cc 查看文件

if (ctx.game.isMousePressed(SDL_BUTTON_LEFT)) if (ctx.game.isMousePressed(SDL_BUTTON_LEFT))
ctx.plane.breakTile(mouse_tile_); 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 // Move left
if (ctx.game.isKeyPressed(SDL_SCANCODE_A) || ctx.game.isKeyPressed(SDL_SCANCODE_LEFT)) { if (ctx.game.isKeyPressed(SDL_SCANCODE_A) || ctx.game.isKeyPressed(SDL_SCANCODE_LEFT)) {
physics_.force += Swan::Vec2(-MOVE_FORCE, 0); physics_.force += Swan::Vec2(-MOVE_FORCE, 0);

+ 7
- 0
core.mod/src/main.cc 查看文件

registerImage("tile/grass"); registerImage("tile/grass");
registerImage("tile/tree-trunk"); registerImage("tile/tree-trunk");
registerImage("tile/leaves"); registerImage("tile/leaves");
registerImage("tile/torch");
registerImage("entity/player-running"); registerImage("entity/player-running");
registerImage("entity/player-still"); registerImage("entity/player-still");
registerImage("misc/background-cave"); registerImage("misc/background-cave");
.name = "leaves", .name = "leaves",
.image = "core/tile/leaves", .image = "core/tile/leaves",
}); });
registerTile({
.name = "torch",
.image = "core/tile/torch",
.is_solid = false,
.light_level = 20,
});


registerItem({ registerItem({
.name = "stone", .name = "stone",

+ 4
- 2
libswan/include/swan/Chunk.h 查看文件



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


Tile::ID *getTileData() { Tile::ID *getTileData() {


void setLightData(RelPos pos, uint8_t level) { void setLightData(RelPos pos, uint8_t level) {
getLightData()[pos.y * CHUNK_WIDTH + pos.x] = 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 render(const Context &ctx, SDL_Renderer *rnd);
void renderLight(const Context &ctx, SDL_Renderer *rnd);


void compress(); void compress();
void decompress(); void decompress();


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



+ 4
- 1
libswan/include/swan/Tile.h 查看文件

std::string name; std::string name;
std::string image; std::string image;
bool is_solid = true; bool is_solid = true;
uint8_t light_level = 0;
std::optional<std::string> dropped_item = std::nullopt; std::optional<std::string> dropped_item = std::nullopt;
}; };


Tile(const ResourceManager &resources, const Builder &builder): Tile(const ResourceManager &resources, const Builder &builder):
name_(builder.name), image_(resources.getImage(builder.image)), 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 std::string name_;
const ImageResource &image_; const ImageResource &image_;
const bool is_solid_; const bool is_solid_;
const uint8_t light_level_;
const std::optional<std::string> dropped_item_; const std::optional<std::string> dropped_item_;


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

+ 3
- 0
libswan/include/swan/WorldPlane.h 查看文件

std::unique_ptr<WorldGen> gen_; std::unique_ptr<WorldGen> gen_;


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

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

+ 40
- 21
libswan/src/Chunk.cc 查看文件

compressed_size_ = -1; 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) { void Chunk::render(const Context &ctx, SDL_Renderer *rnd) {
std::optional<RenderTarget> target; std::optional<RenderTarget> target;


target.emplace(rnd, texture_.get()); 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 // We're caching tiles so we don't have to world.getTileByID() every time
Tile::ID prevID = Tile::INVALID_ID; Tile::ID prevID = Tile::INVALID_ID;
Tile *tile = ctx.game.invalid_tile_.get(); Tile *tile = ctx.game.invalid_tile_.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) {
color.change(0, 0, 0, 255 - getLightLevel({ x, y }));
SDL_Rect rect{ x, y, 1, 1 };
SDL_RenderFillRect(rnd, &rect);
}
}

need_render_ = false; need_render_ = false;

renderLight(ctx, rnd);
} }


void Chunk::renderList(SDL_Renderer *rnd) { void Chunk::renderList(SDL_Renderer *rnd) {
if (need_render_) if (need_render_)
return; return;


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

if (draw_list_.size() > 0) { if (draw_list_.size() > 0) {
renderList(win.renderer_); renderList(win.renderer_);
draw_list_.clear(); draw_list_.clear();
} }



auto chunkpos = pos_ * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT); auto chunkpos = pos_ * Vec2i(CHUNK_WIDTH, CHUNK_HEIGHT);
SDL_Rect rect{ 0, 0, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE }; SDL_Rect rect{ 0, 0, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE };
win.showTexture(chunkpos, texture_.get(), &rect); win.showTexture(chunkpos, texture_.get(), &rect);

+ 71
- 1
libswan/src/WorldPlane.cc 查看文件



Tile::ID old = chunk.getTileID(rp); Tile::ID old = chunk.getTileID(rp);
if (id != old) { 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(); chunk.markModified();

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

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


debug_boxes_.push_back(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…
取消
儲存