Browse Source

wow, that was many changes.

This should've been multiple commits, but hey, it's late.
opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
718281b35b

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

@@ -1,7 +1,8 @@
add_library(core.mod SHARED
src/main.cc
src/WGDefault.cc
src/entities/EntPlayer.cc)
src/entities/EntPlayer.cc
src/entities/EntItemStack.cc)
set_target_properties(core.mod PROPERTIES OUTPUT_NAME mod PREFIX "")
target_link_libraries(core.mod libswan)


+ 23
- 0
core.mod/src/entities/EntItemStack.cc View File

@@ -0,0 +1,23 @@
#include "EntItemStack.h"

EntItemStack::EntItemStack(const Swan::Context &ctx, const Swan::SRF &params):
body_(SIZE, MASS) {

readSRF(ctx, params);
}

void EntItemStack::readSRF(const Swan::Context &ctx, const Swan::SRF &srf) {
auto &arr = dynamic_cast<const Swan::SRFArray &>(srf);
auto *pos = dynamic_cast<Swan::SRFFloatArray *>(arr.val[0].get());
auto *name = dynamic_cast<Swan::SRFString *>(arr.val[1].get());

body_.pos_.set(pos->val[0], pos->val[1]);
item_ = &ctx.world.getItem(name->val);
}

Swan::SRF *EntItemStack::writeSRF(const Swan::Context &ctx) {
return new Swan::SRFArray{
new Swan::SRFFloatArray{ body_.pos_.x_, body_.pos_.y_ },
new Swan::SRFString{ item_->name },
};
}

+ 24
- 0
core.mod/src/entities/EntItemStack.h View File

@@ -0,0 +1,24 @@
#pragma once

#include <swan/swan.h>

class EntItemStack: public Swan::Entity {
public:
class Factory: public Swan::Entity::Factory {
Swan::Entity *create(const Swan::Context &ctx, const Swan::SRF &params) override {
return new EntItemStack(ctx, params);
}
};

EntItemStack(const Swan::Context &ctx, const Swan::SRF &params);

void readSRF(const Swan::Context &ctx, const Swan::SRF &srf) override;
Swan::SRF *writeSRF(const Swan::Context &ctx) override;

private:
static constexpr float MASS = 80;
static constexpr Swan::Vec2 SIZE = Swan::Vec2(0.5, 0.5);

Swan::Item *item_ = &Swan::Item::INVALID_ITEM;
Swan::Body body_;
};

+ 4
- 4
core.mod/src/entities/EntPlayer.cc View File

@@ -3,7 +3,7 @@
EntPlayer::EntPlayer(const Swan::Context &ctx, const Swan::SRF &params):
body_(SIZE, MASS) {

readSRF(params);
readSRF(ctx, params);

anims_[(int)State::IDLE].init(32, 64, 0.8,
ctx.world.getAsset("core::player-still"));
@@ -30,7 +30,7 @@ void EntPlayer::update(const Swan::Context &ctx, float dt) {

// Break block
if (ctx.game.isMousePressed(sf::Mouse::Button::Left))
ctx.plane.setTile(mouse_tile_, "core::air");
ctx.plane.breakBlock(mouse_tile_);

// Move left
if (ctx.game.isKeyPressed(sf::Keyboard::A) || ctx.game.isKeyPressed(sf::Keyboard::Left)) {
@@ -62,11 +62,11 @@ void EntPlayer::update(const Swan::Context &ctx, float dt) {
body_.collide(ctx.plane);
}

void EntPlayer::readSRF(const Swan::SRF &srf) {
void EntPlayer::readSRF(const Swan::Context &ctx, const Swan::SRF &srf) {
auto pos = dynamic_cast<const Swan::SRFFloatArray &>(srf);
body_.pos_.set(pos.val[0], pos.val[1]);
}

Swan::SRF *EntPlayer::writeSRF() {
Swan::SRF *EntPlayer::writeSRF(const Swan::Context &ctx) {
return new Swan::SRFFloatArray{ body_.pos_.x_, body_.pos_.y_ };
}

+ 2
- 2
core.mod/src/entities/EntPlayer.h View File

@@ -17,8 +17,8 @@ public:

void draw(const Swan::Context &ctx, Swan::Win &win) override;
void update(const Swan::Context &ctx, float dt) override;
void readSRF(const Swan::SRF &srf) override;
Swan::SRF *writeSRF() override;
void readSRF(const Swan::Context &ctx, const Swan::SRF &srf) override;
Swan::SRF *writeSRF(const Swan::Context &ctx) override;

private:
static constexpr float FORCE = 3000;

+ 5
- 4
core.mod/src/main.cc View File

@@ -2,6 +2,7 @@

#include "WGDefault.h"
#include "entities/EntPlayer.h"
#include "entities/EntItemStack.h"

extern "C" void mod_init(Swan::Mod &mod) {
mod.init("core");
@@ -9,19 +10,18 @@ extern "C" void mod_init(Swan::Mod &mod) {
mod.registerTile("air", new Swan::Tile{
.image = mod.loadImage("assets/tiles/air.png"),
.is_solid = false,
.dropped_item = "dirt",
});
mod.registerTile("stone", new Swan::Tile{
.image = mod.loadImage("assets/tiles/stone.png"),
.dropped_item = "stone",
.dropped_item = "core::stone",
});
mod.registerTile("dirt", new Swan::Tile{
.image = mod.loadImage("assets/tiles/dirt.png"),
.dropped_item = "dirt",
.dropped_item = "core::dirt",
});
mod.registerTile("grass", new Swan::Tile{
.image = mod.loadImage("assets/tiles/grass.png"),
.dropped_item = "grass",
.dropped_item = "core::grass",
});

mod.registerItem("stone", new Swan::Item{
@@ -37,6 +37,7 @@ extern "C" void mod_init(Swan::Mod &mod) {
mod.registerWorldGen("default", new WGDefault::Factory());

mod.registerEntity("player", new EntPlayer::Factory());
mod.registerEntity("item-stack", new EntItemStack::Factory());

mod.registerAsset("player-running", new Swan::Asset("assets/entities/player-running.png"));
mod.registerAsset("player-still", new Swan::Asset("assets/entities/player-still.png"));

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

@@ -17,6 +17,8 @@ class Chunk {
public:
using RelPos = TilePos;

ChunkPos pos_;

Chunk(ChunkPos pos): pos_(pos) {
data_.reset(new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)]);
visuals_.reset(new Visuals());
@@ -34,16 +36,22 @@ public:
void decompress();
void render(const Context &ctx);
void draw(const Context &ctx, Win &win);
void tick();

ChunkPos pos_;
bool keepActive(); // Returns true if chunk was inactive
bool isActive() { return active_timer_ != 0; }

private:
static constexpr int ACTIVE_TIMEOUT = 200;
static sf::Uint8 *renderbuf;

bool isCompressed() { return compressed_size_ != -1; }

std::unique_ptr<uint8_t[]> data_;

int 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;
int active_timer_ = ACTIVE_TIMEOUT;

struct Visuals {
sf::Texture tex_;

+ 2
- 2
libswan/include/swan/Entity.h View File

@@ -27,8 +27,8 @@ public:
virtual void draw(const Context &ctx, Win &win) {}
virtual void update(const Context &ctx, float dt) {}
virtual void tick() {}
virtual void readSRF(const SRF &srf) {}
virtual SRF *writeSRF() { return new SRFNone(); }
virtual void readSRF(const Swan::Context &ctx, const SRF &srf) {}
virtual SRF *writeSRF(const Swan::Context &ctx) { return new SRFNone(); }
};

}

+ 1
- 2
libswan/include/swan/Item.h View File

@@ -6,8 +6,7 @@

namespace Swan {

class Item {
public:
struct Item {
std::unique_ptr<sf::Image> image;

std::string name = "";

+ 24
- 2
libswan/include/swan/SRF.h View File

@@ -24,7 +24,7 @@ struct SRF {

struct SRFObject: SRF {
SRFObject() {}
SRFObject(std::initializer_list<std::pair<std::string, SRF *>> &lst);
SRFObject(std::initializer_list<std::pair<std::string, SRF *>> lst);

void serialize(std::ostream &os) const override;
void parse(std::istream &os) override;
@@ -35,7 +35,7 @@ struct SRFObject: SRF {

struct SRFArray: SRF {
SRFArray() {}
SRFArray(std::initializer_list<SRF *> &lst);
SRFArray(std::initializer_list<SRF *> lst);

void serialize(std::ostream &os) const override;
void parse(std::istream &os) override;
@@ -55,6 +55,28 @@ struct SRFString: SRF {
std::string val;
};

struct SRFByte: SRF {
SRFByte(): val(0) {}
SRFByte(uint8_t v): val(v) {}

void serialize(std::ostream &os) const override;
void parse(std::istream &os) override;
std::ostream &pretty(std::ostream &os) const override;

uint8_t val;
};

struct SRFWord: SRF {
SRFWord(): val(0) {}
SRFWord(uint16_t v): val(v) {}

void serialize(std::ostream &os) const override;
void parse(std::istream &os) override;
std::ostream &pretty(std::ostream &os) const override;

uint16_t val;
};

struct SRFInt: SRF {
SRFInt(): val(0) {}
SRFInt(int32_t v): val(v) {}

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

@@ -3,6 +3,8 @@
#include <vector>
#include <utility>
#include <memory>
#include <map>
#include <set>

#include "common.h"
#include "Chunk.h"
@@ -30,9 +32,11 @@ public:
Chunk &getChunk(ChunkPos pos);
void setTileID(TilePos pos, Tile::ID id);
void setTile(TilePos pos, const std::string &name);
Tile::ID getTileID(TilePos pos);
Tile &getTile(TilePos pos);

Entity &spawnPlayer();
void breakBlock(TilePos pos);

void draw(Win &win);
void update(float dt);
@@ -46,6 +50,7 @@ public:

private:
std::map<std::pair<int, int>, Chunk> chunks_;
std::set<Chunk *> active_chunks_;
std::vector<std::unique_ptr<Entity>> entities_;
std::vector<TilePos> debug_boxes_;
};

+ 34
- 8
libswan/src/Chunk.cc View File

@@ -11,9 +11,7 @@ namespace Swan {
sf::Uint8 *Chunk::renderbuf = new sf::Uint8[CHUNK_WIDTH * TILE_SIZE * CHUNK_HEIGHT * TILE_SIZE * 4];

Tile::ID *Chunk::getTileData() {
if (compressed_size_ != -1)
decompress();

keepActive();
return (Tile::ID *)data_.get();
}

@@ -26,15 +24,14 @@ void Chunk::setTileID(RelPos pos, Tile::ID id) {
}

void Chunk::drawBlock(RelPos pos, const Tile &t) {
if (compressed_size_ != -1)
decompress();
keepActive();

visuals_->tex_.update(*t.image, pos.x_ * TILE_SIZE, pos.y_ * TILE_SIZE);
visuals_->dirty_ = true;
}

void Chunk::compress() {
if (compressed_size_ != -1)
if (isCompressed())
return;

sf::Clock clock;
@@ -68,6 +65,11 @@ void Chunk::compress() {
}

void Chunk::decompress() {
if (!isCompressed())
return;

sf::Clock clock;

uint8_t *dest = new uint8_t[CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID)];
uLongf destlen = CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID);
int ret = uncompress(
@@ -86,6 +88,9 @@ void Chunk::decompress() {
visuals_->sprite_ = sf::Sprite();
visuals_->dirty_ = true;
need_render_ = true;
fprintf(stderr, "Decompressed chunk %i,%i from %li bytes to %lu bytes in %.3fs.\n",
pos_.x_, pos_.y_, compressed_size_, CHUNK_WIDTH * CHUNK_HEIGHT * sizeof(Tile::ID),
clock.getElapsedTime().asSeconds());
compressed_size_ = -1;
}

@@ -118,8 +123,8 @@ void Chunk::render(const Context &ctx) {
}

void Chunk::draw(const Context &ctx, Win &win) {
if (compressed_size_ != -1)
decompress();
if (isCompressed())
return;

if (need_render_) {
render(ctx);
@@ -135,4 +140,25 @@ void Chunk::draw(const Context &ctx, Win &win) {
win.draw(visuals_->sprite_);
}

void Chunk::tick() {
if (active_timer_ == 0)
return;

active_timer_ -= 1;
if (active_timer_ == 0) {
compress();
}
}

bool Chunk::keepActive() {
bool wasActive = isActive();
active_timer_ = ACTIVE_TIMEOUT;

if (wasActive)
return false;

decompress();
return true;
}

}

+ 52
- 12
libswan/src/SRF.cc View File

@@ -6,15 +6,17 @@ enum class Type {
OBJECT = 0,
ARRAY = 1,
STRING = 2,
INT = 3,
FLOAT = 4,
DOUBLE = 5,
NONE = 6,
BYTE_ARRAY = 7,
WORD_ARRAY = 8,
INT_ARRAY = 9,
FLOAT_ARRAY = 10,
DOUBLE_ARRAY = 11,
BYTE = 3,
WORD = 4,
INT = 5,
FLOAT = 6,
DOUBLE = 7,
NONE = 8,
BYTE_ARRAY = 9,
WORD_ARRAY = 10,
INT_ARRAY = 11,
FLOAT_ARRAY = 12,
DOUBLE_ARRAY = 13,
};

static void writeByte(std::ostream &os, uint8_t val) {
@@ -123,6 +125,10 @@ SRF *SRF::read(std::istream &is) {
srf = new SRFArray(); break;
case Type::STRING:
srf = new SRFString(); break;
case Type::BYTE:
srf = new SRFByte(); break;
case Type::WORD:
srf = new SRFWord(); break;
case Type::INT:
srf = new SRFInt(); break;
case Type::FLOAT:
@@ -147,7 +153,7 @@ SRF *SRF::read(std::istream &is) {
return srf;
}

SRFObject::SRFObject(std::initializer_list<std::pair<std::string, SRF *>> &lst) {
SRFObject::SRFObject(std::initializer_list<std::pair<std::string, SRF *>> lst) {
for (auto &[k, v]: lst)
val[k] = std::unique_ptr<SRF>(v);
}
@@ -186,7 +192,7 @@ std::ostream &SRFObject::pretty(std::ostream &os) const {
return os << " }";
}

SRFArray::SRFArray(std::initializer_list<SRF *> &lst) {
SRFArray::SRFArray(std::initializer_list<SRF *> lst) {
for (auto &v: lst)
val.push_back(std::unique_ptr<SRF>(v));
}
@@ -236,6 +242,38 @@ std::ostream &SRFString::pretty(std::ostream &os) const {
return os << '"' << val << '"';
}

void SRFByte::serialize(std::ostream &os) const {
writeByte(os, (uint8_t)Type::BYTE);
writeByte(os, val);
}

void SRFByte::parse(std::istream &is) {
val = readByte(is);
}

std::ostream &SRFByte::pretty(std::ostream &os) const {
return os << "0x"
<< hexchr((val & 0xf0) >> 4)
<< hexchr((val & 0x0f) >> 0);
}

void SRFWord::serialize(std::ostream &os) const {
writeByte(os, (uint8_t)Type::WORD);
writeWord(os, val);
}

void SRFWord::parse(std::istream &is) {
val = readWord(is);
}

std::ostream &SRFWord::pretty(std::ostream &os) const {
return os << "0x"
<< hexchr((val & 0xf000) >> 12)
<< hexchr((val & 0x0f00) >> 8)
<< hexchr((val & 0x00f0) >> 4)
<< hexchr((val & 0x000f) >> 0);
}

void SRFInt::serialize(std::ostream &os) const {
writeByte(os, (uint8_t)Type::INT);
writeInt(os, val);
@@ -300,7 +338,9 @@ void SRFByteArray::parse(std::istream &is) {
std::ostream &SRFByteArray::pretty(std::ostream &os) const {
os << "byte[ " << std::hex;
for (auto v: val) {
os << hexchr((v & 0xf0) >> 4) << hexchr((v & 0x0f) >> 0) << ' ';
os
<< hexchr((v & 0xf0) >> 4)
<< hexchr((v & 0x0f) >> 0) << ' ';
}

return os << ']';

+ 6
- 8
libswan/src/World.cc View File

@@ -8,14 +8,12 @@ namespace Swan {

static bool chunkLine(int l, sf::Clock &clock, WorldPlane &plane, ChunkPos &abspos, const Vec2i &dir) {
for (int i = 0; i < l; ++i) {
if (!plane.hasChunk(abspos)) {
plane.getChunk(abspos);

// Don't blow our frame budget on generating chunks,
// but generate as many as possible within the budget
if (clock.getElapsedTime().asSeconds() > 1.0 / 100)
return true;
}
plane.getChunk(abspos);

// Don't blow our frame budget on generating chunks,
// but generate as many as possible within the budget
if (clock.getElapsedTime().asSeconds() > 1.0 / 100)
return true;
abspos += dir;
}


+ 42
- 8
libswan/src/WorldPlane.cc View File

@@ -53,7 +53,10 @@ Chunk &WorldPlane::getChunk(ChunkPos pos) {
if (iter == chunks_.end()) {
iter = chunks_.emplace(pos, Chunk(pos)).first;
gen_->genChunk(*this, iter->second);
active_chunks_.insert(&iter->second);
iter->second.render(getContext());
} else if (iter->second.keepActive()) {
active_chunks_.insert(&iter->second);
}

return iter->second;
@@ -64,22 +67,45 @@ void WorldPlane::setTileID(TilePos pos, Tile::ID id) {
Chunk::RelPos rp = relPos(pos);
chunk.setTileID(rp, id);
chunk.drawBlock(rp, world_->getTileByID(id));

if (active_chunks_.find(&chunk) == active_chunks_.end())
active_chunks_.insert(&chunk);
}

void WorldPlane::setTile(TilePos pos, const std::string &name) {
setTileID(pos, world_->getTileID(name));
}

Tile &WorldPlane::getTile(TilePos pos) {
Tile::ID WorldPlane::getTileID(TilePos pos) {
Chunk &chunk = getChunk(chunkPos(pos));
Tile::ID id = chunk.getTileID(relPos(pos));
return world_->getTileByID(id);

if (active_chunks_.find(&chunk) == active_chunks_.end())
active_chunks_.insert(&chunk);

return chunk.getTileID(relPos(pos));

}

Tile &WorldPlane::getTile(TilePos pos) {
return world_->getTileByID(getTileID(pos));
}

Entity &WorldPlane::spawnPlayer() {
return gen_->spawnPlayer(*this);
}

void WorldPlane::breakBlock(TilePos pos) {
Tile &t = getTile(pos);
setTile(pos, "core::air");

if (t.dropped_item != "") {
spawnEntity("core::item-stack", SRFArray{
new SRFFloatArray{ pos.x_ + 0.5f, pos.y_ + 0.5f },
new SRFString{ t.dropped_item },
});
}
}

void WorldPlane::draw(Win &win) {
const Vec2 &ppos = world_->player_->getPos();
ChunkPos pcpos = ChunkPos(
@@ -88,9 +114,9 @@ void WorldPlane::draw(Win &win) {

for (int x = -1; x <= 1; ++x) {
for (int y = -1; y <= 1; ++y) {
auto chunk = chunks_.find(pcpos + ChunkPos(x, y));
if (chunk != chunks_.end())
chunk->second.draw(getContext(), win);
auto iter = chunks_.find(pcpos + ChunkPos(x, y));
if (iter != chunks_.end())
iter->second.draw(getContext(), win);
}
}

@@ -111,13 +137,21 @@ void WorldPlane::draw(Win &win) {

void WorldPlane::update(float dt) {
debug_boxes_.clear();
for (auto &ent: entities_)
ent->update(getContext(), dt);

// Don't use iterators, because an entity's update method might push_back to entities
for (size_t len = entities_.size(), i = 0; i < len; ++i)
entities_[i]->update(getContext(), dt);
}

void WorldPlane::tick() {
for (auto &ent: entities_)
ent->tick();

for (auto &chunk: active_chunks_) {
chunk->tick();
if (!chunk->isActive())
active_chunks_.erase(chunk);
}
}

void WorldPlane::debugBox(TilePos pos) {

Loading…
Cancel
Save