Browse Source

libswan and core.mod now compiles

feature/replace-renderer
Martin Dørum 3 years ago
parent
commit
447d4e8d39

+ 5
- 2
core.mod/src/DefaultWorldGen.cc View File

return (int)(perlin.noise(x / 50.0, 10) * 10) + 10; return (int)(perlin.noise(x / 50.0, 10) * 10) + 10;
} }


void DefaultWorldGen::drawBackground(const Swan::Context &ctx, Swan::Win &win, Swan::Vec2 pos) {
void DefaultWorldGen::drawBackground(
const Swan::Context &ctx, Cygnet::Renderer &rnd, Swan::Vec2 pos) {
int texmin = 10; int texmin = 10;
int texmax = 20;
//int texmax = 20;


if (pos.y > texmin) { if (pos.y > texmin) {
/*
SDL_Texture *tex = bgCave_.texture_.get(); SDL_Texture *tex = bgCave_.texture_.get();


Uint8 alpha = std::clamp( Uint8 alpha = std::clamp(
Swan::Draw::parallaxBackground( Swan::Draw::parallaxBackground(
win, tex, std::nullopt, std::nullopt, win, tex, std::nullopt, std::nullopt,
pos.x * Swan::TILE_SIZE, pos.y * Swan::TILE_SIZE, 0.7); pos.x * Swan::TILE_SIZE, pos.y * Swan::TILE_SIZE, 0.7);
TODO */
} }
} }



+ 4
- 3
core.mod/src/DefaultWorldGen.h View File

tAir_(world.getTileID("@::air")), tAir_(world.getTileID("@::air")),
tTreeTrunk_(world.getTileID("core::tree-trunk")), tTreeTrunk_(world.getTileID("core::tree-trunk")),
tLeaves_(world.getTileID("core::leaves")), tLeaves_(world.getTileID("core::leaves")),
bgCave_(world.resources_.getImage("core/misc/background-cave")) {}
bgCave_(world.getSprite("core::misc/background-cave")) {}


void drawBackground(const Swan::Context &ctx, Swan::Win &win, Swan::Vec2 pos) override;
void drawBackground(
const Swan::Context &ctx, Cygnet::Renderer &rnd, Swan::Vec2 pos) override;
SDL_Color backgroundColor(Swan::Vec2 pos) override; SDL_Color backgroundColor(Swan::Vec2 pos) override;
void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override; void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override;
Swan::EntityRef spawnPlayer(const Swan::Context &ctx) override; Swan::EntityRef spawnPlayer(const Swan::Context &ctx) override;
private: private:
Swan::Tile::ID genTile(Swan::TilePos pos); Swan::Tile::ID genTile(Swan::TilePos pos);
Swan::Tile::ID tGrass_, tDirt_, tStone_, tAir_, tTreeTrunk_, tLeaves_; Swan::Tile::ID tGrass_, tDirt_, tStone_, tAir_, tTreeTrunk_, tLeaves_;
Swan::ImageResource &bgCave_;
Cygnet::RenderSprite bgCave_;
siv::PerlinNoise perlin_ = siv::PerlinNoise(100); siv::PerlinNoise perlin_ = siv::PerlinNoise(100);
}; };

+ 3
- 1
core.mod/src/entities/ItemStackEntity.cc View File

deserialize(ctx, obj); deserialize(ctx, obj);
} }


void ItemStackEntity::draw(const Swan::Context &ctx, Swan::Win &win) {
void ItemStackEntity::draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) {
/*
SDL_Rect rect = item_->image_.frameRect(); SDL_Rect rect = item_->image_.frameRect();


SDL_Texture *tex = item_->image_.texture_.get(); SDL_Texture *tex = item_->image_.texture_.get();


win.showTexture(body_.pos, tex, &rect, win.showTexture(body_.pos, tex, &rect,
{ .hscale = 0.5, .vscale = 0.5 }); { .hscale = 0.5, .vscale = 0.5 });
TODO */
} }


void ItemStackEntity::update(const Swan::Context &ctx, float dt) { void ItemStackEntity::update(const Swan::Context &ctx, float dt) {

+ 1
- 1
core.mod/src/entities/ItemStackEntity.h View File

ItemStackEntity(const Swan::Context &ctx, Swan::Vec2 pos, const std::string &item); ItemStackEntity(const Swan::Context &ctx, Swan::Vec2 pos, const std::string &item);
ItemStackEntity(const Swan::Context &ctx, const PackObject &obj); ItemStackEntity(const Swan::Context &ctx, const PackObject &obj);


void draw(const Swan::Context &ctx, Swan::Win &win) override;
void draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) override;
void update(const Swan::Context &ctx, float dt) override; void update(const Swan::Context &ctx, float dt) override;
void tick(const Swan::Context &ctx, float dt) override; void tick(const Swan::Context &ctx, float dt) override;
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; void deserialize(const Swan::Context &ctx, const PackObject &obj) override;

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

deserialize(ctx, obj); deserialize(ctx, obj);
} }


void PlayerEntity::draw(const Swan::Context &ctx, Swan::Win &win) {
body_.outline(win);
anims_[(int)state_].draw(body_.pos - Swan::Vec2(0.2, 0.1), win);
void PlayerEntity::draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) {
// body_.outline(win); TODO
anims_[(int)state_].draw(body_.pos - Swan::Vec2(0.2, 0.1), rnd);
} }


void PlayerEntity::update(const Swan::Context &ctx, float dt) { void PlayerEntity::update(const Swan::Context &ctx, float dt) {

+ 5
- 5
core.mod/src/entities/PlayerEntity.h View File

using PhysicsEntity::get; using PhysicsEntity::get;
Inventory &get(InventoryTrait::Tag) override { return inventory_; } Inventory &get(InventoryTrait::Tag) override { return inventory_; }


void draw(const Swan::Context &ctx, Swan::Win &win) override;
void draw(const Swan::Context &ctx, Cygnet::Renderer &rnd) override;
void update(const Swan::Context &ctx, float dt) override; void update(const Swan::Context &ctx, float dt) override;
void tick(const Swan::Context &ctx, float dt) override; void tick(const Swan::Context &ctx, float dt) override;
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; void deserialize(const Swan::Context &ctx, const PackObject &obj) override;
PlayerEntity(const Swan::Context &ctx): PlayerEntity(const Swan::Context &ctx):
PhysicsEntity(SIZE), PhysicsEntity(SIZE),
anims_{ anims_{
Swan::Animation(ctx.resources.getImage("core/entity/player-still"), 0.8),
Swan::Animation(ctx.world.getSprite("core::entity/player-still"), 0.8),
Swan::Animation( Swan::Animation(
ctx.resources.getImage("core/entity/player-running"),
1, SDL_FLIP_HORIZONTAL),
Swan::Animation(ctx.resources.getImage("core/entity/player-running"), 1)
ctx.world.getSprite("core::entity/player-running"),
1, Cygnet::Mat3gf{}.scale({-1, 1})),
Swan::Animation(ctx.world.getSprite("core::entity/player-running"), 1),
} {} } {}


State state_ = State::IDLE; State state_ = State::IDLE;

+ 3
- 9
core.mod/src/main.cc View File

breakListener_ = world.evtTileBreak_.subscribe( breakListener_ = world.evtTileBreak_.subscribe(
std::bind_front(&CoreMod::onTileBreak, this)); std::bind_front(&CoreMod::onTileBreak, this));


registerImage("tile/stone");
registerImage("tile/dirt");
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");
registerSprite("entity/player-running");
registerSprite("entity/player-still");
registerSprite("misc/background-cave");


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

+ 1
- 1
libcygnet/include/cygnet/Renderer.h View File

struct RenderCamera { struct RenderCamera {
SwanCommon::Vec2 pos; SwanCommon::Vec2 pos;
SwanCommon::Vec2i size; SwanCommon::Vec2i size;
float zoom;
float zoom = 0;
}; };


class Renderer { class Renderer {

+ 0
- 3
libcygnet/include/cygnet/ResourceManager.h View File

ResourceManager(ResourceBuilder &&builder); ResourceManager(ResourceBuilder &&builder);
~ResourceManager(); ~ResourceManager();


RenderSprite getSprite(std::string name) { return sprites_.at(std::move(name)); }

void tick(); void tick();


private:
Renderer &rnd_; Renderer &rnd_;
std::unordered_map<std::string, RenderSprite> sprites_; std::unordered_map<std::string, RenderSprite> sprites_;
std::unordered_map<std::string, RenderTile> tiles_; std::unordered_map<std::string, RenderTile> tiles_;

+ 0
- 1
libswan/CMakeLists.txt View File

src/LightServer.cc src/LightServer.cc
src/Mod.cc src/Mod.cc
src/OS.cc src/OS.cc
src/Resource.cc
src/World.cc src/World.cc
src/WorldPlane.cc) src/WorldPlane.cc)
target_include_directories(libswan target_include_directories(libswan

+ 6
- 7
libswan/include/swan/Animation.h View File

#pragma once #pragma once


#include <SDL.h> #include <SDL.h>
#include <cygnet/Renderer.h>


#include "common.h" #include "common.h"
#include "Resource.h"
#include "Clock.h" #include "Clock.h"
#include "Resource.h"


namespace Swan { namespace Swan {


class Animation { class Animation {
public: public:
Animation(ImageResource &resource, float interval, SDL_RendererFlip flip = SDL_FLIP_NONE):
resource_(resource), interval_(interval), timer_(interval), flip_(flip) {}
Animation(Cygnet::RenderSprite sprite, float interval, Cygnet::Mat3gf mat = {}):
sprite_(sprite), interval_(interval), timer_(interval), mat_(mat) {}


void tick(float dt); void tick(float dt);
void draw(const Vec2 &pos, Win &win);
void draw(const Vec2 &pos, Cygnet::Renderer &rnd);
void reset(); void reset();


private: private:
ImageResource &resource_;
Cygnet::RenderSprite sprite_;
float interval_; float interval_;
float timer_; float timer_;
SDL_RendererFlip flip_;
Cygnet::Mat3gf mat_;
int frame_ = 0; int frame_ = 0;
}; };



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

return getTileData()[pos.y * CHUNK_WIDTH + pos.x]; return getTileData()[pos.y * CHUNK_WIDTH + pos.x];
} }


void setTileID(RelPos pos, Tile::ID id, SDL_Texture *tex) {
void setTileID(RelPos pos, Tile::ID id) {
getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id; getTileData()[pos.y * CHUNK_WIDTH + pos.x] = id;
drawList_.push_back({ pos, tex });
drawList_.push_back({pos, id});
} }


void setTileData(RelPos pos, Tile::ID id) { void setTileData(RelPos pos, Tile::ID id) {
needLightRender_ = true; needLightRender_ = true;
} }


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

void compress(); void compress();
void decompress(); void decompress();
void draw(const Context &ctx, Win &win);
void draw(const Context &ctx, Cygnet::Renderer &rnd);
TickAction tick(float dt); TickAction tick(float dt);


bool isActive() { return deactivateTimer_ > 0; } bool isActive() { return deactivateTimer_ > 0; }
private: private:
static constexpr float DEACTIVATE_INTERVAL = 20; static constexpr float DEACTIVATE_INTERVAL = 20;


void renderList(SDL_Renderer *rnd);

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


std::unique_ptr<uint8_t[]> data_; std::unique_ptr<uint8_t[]> data_;
std::vector<std::pair<RelPos, SDL_Texture *>> drawList_;
std::vector<std::pair<RelPos, Tile::ID>> drawList_;


ssize_t compressedSize_ = -1; // -1 if not compressed, a positive number if compressed ssize_t compressedSize_ = -1; // -1 if not compressed, a positive number if compressed
bool needRender_ = false; bool needRender_ = false;
bool needLightRender_ = false; bool needLightRender_ = false;
float deactivateTimer_ = DEACTIVATE_INTERVAL; float deactivateTimer_ = DEACTIVATE_INTERVAL;
bool isModified_ = false; bool isModified_ = false;

CPtr<SDL_Texture, SDL_DestroyTexture> texture_;
CPtr<SDL_Texture, SDL_DestroyTexture> lightTexture_;
}; };


} }

+ 4
- 4
libswan/include/swan/Collection.h View File

virtual EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) = 0; virtual EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) = 0;
virtual void update(const Context &ctx, float dt) = 0; virtual void update(const Context &ctx, float dt) = 0;
virtual void tick(const Context &ctx, float dt) = 0; virtual void tick(const Context &ctx, float dt) = 0;
virtual void draw(const Context &ctx, Win &win) = 0;
virtual void draw(const Context &ctx, Cygnet::Renderer &rnd) = 0;
virtual void erase(size_t idx, size_t generation) = 0; virtual void erase(size_t idx, size_t generation) = 0;


private: private:
EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) override; EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) override;
void update(const Context &ctx, float dt) override; void update(const Context &ctx, float dt) override;
void tick(const Context &ctx, float dt) override; void tick(const Context &ctx, float dt) override;
void draw(const Context &ctx, Win &win) override;
void draw(const Context &ctx, Cygnet::Renderer &rnd) override;
void erase(size_t idx, size_t generation) override; void erase(size_t idx, size_t generation) override;


private: private:
} }


template<typename Ent> template<typename Ent>
inline void EntityCollectionImpl<Ent>::draw(const Context &ctx, Win &win) {
inline void EntityCollectionImpl<Ent>::draw(const Context &ctx, Cygnet::Renderer &rnd) {
ZoneScopedN(typeid(Ent).name()); ZoneScopedN(typeid(Ent).name());
for (auto &ent: entities_) { for (auto &ent: entities_) {
ZoneScopedN("draw"); ZoneScopedN("draw");
ent->draw(ctx, win);
ent->draw(ctx, rnd);
} }
} }



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



virtual ~Entity() = default; virtual ~Entity() = default;


virtual void draw(const Context &ctx, Win &win) {}
virtual void draw(const Context &ctx, Cygnet::Renderer &rnd) {}
virtual void update(const Context &ctx, float dt) {} virtual void update(const Context &ctx, float dt) {}
virtual void tick(const Context &ctx, float dt) {} virtual void tick(const Context &ctx, float dt) {}
virtual void onDespawn(const Context &ctx) {} virtual void onDespawn(const Context &ctx) {}

+ 1
- 9
libswan/include/swan/Game.h View File

#include <cygnet/Renderer.h> #include <cygnet/Renderer.h>


#include "common.h" #include "common.h"
#include "Resource.h"
#include "Mod.h" #include "Mod.h"
#include "World.h" #include "World.h"




class Game { class Game {
public: public:
Game(Win &win):
win_(win),
mousePos_(0, 0) {}

void createWorld(const std::string &worldgen, const std::vector<std::string> &modPaths); void createWorld(const std::string &worldgen, const std::vector<std::string> &modPaths);


void onKeyDown(SDL_Keysym sym) { void onKeyDown(SDL_Keysym sym) {
void tick(float dt); void tick(float dt);


std::unique_ptr<World> world_ = NULL; std::unique_ptr<World> world_ = NULL;
std::unique_ptr<ImageResource> invalidImage_ = NULL;
std::unique_ptr<Tile> invalidTile_ = NULL;
std::unique_ptr<Item> invalidItem_ = NULL;
Win &win_;
Cygnet::Renderer renderer_; Cygnet::Renderer renderer_;
Cygnet::RenderCamera cam_;


private: private:
std::bitset<SDL_NUM_SCANCODES> pressedKeys_; std::bitset<SDL_NUM_SCANCODES> pressedKeys_;

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



#include <string> #include <string>


#include "Resource.h"
#include "Tile.h" #include "Tile.h"


namespace Swan { namespace Swan {

+ 0
- 1
libswan/include/swan/Mod.h View File

#include "WorldGen.h" #include "WorldGen.h"
#include "Entity.h" #include "Entity.h"
#include "Collection.h" #include "Collection.h"
#include "Resource.h"
#include "OS.h" #include "OS.h"
#include "util.h" #include "util.h"



+ 0
- 53
libswan/include/swan/Resource.h View File

#pragma once

#include <SDL.h>
#include <stdint.h>
#include <string>
#include <memory>
#include <unordered_map>

#include "common.h"

namespace Swan {

class ImageResource {
public:
ImageResource(
SDL_Renderer *renderer, const std::string &modpath, const std::string &id);
ImageResource(
SDL_Renderer *renderer, const std::string &name,
int w, int h, uint8_t r, uint8_t g, uint8_t b, uint8_t a = 255);

void tick(float dt);

SDL_Rect frameRect(int frame = -1) const {
if (frame == -1) frame = frame_;
return SDL_Rect{ 0, frameHeight_ * frame, surface_->w, frameHeight_ };
}

std::unique_ptr<SDL_Surface, void (*)(SDL_Surface *)> surface_{nullptr, &SDL_FreeSurface};
std::unique_ptr<SDL_Texture, void (*)(SDL_Texture *)> texture_{nullptr, &SDL_DestroyTexture};
int frameHeight_;
int numFrames_;
std::string name_;
int frame_ = 0;

private:
float switchInterval_ = 1;
float switchTimer_ = switchInterval_;
};

class ResourceManager {
public:
ResourceManager(Win &win);

void tick(float dt);

ImageResource &getImage(const std::string &name) const;
void addImage(std::unique_ptr<ImageResource> img) { images_[img->name_] = std::move(img); }

private:
std::unordered_map<std::string, std::unique_ptr<ImageResource>> images_;
};

}

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

#include <stdint.h> #include <stdint.h>
#include <string> #include <string>
#include <optional> #include <optional>
#include <memory>

#include "Resource.h"


namespace Swan { namespace Swan {



+ 0
- 109
libswan/include/swan/Win.h View File

#pragma once

#include "log.h"
#include "common.h"

#include <SDL.h>
#include <optional>

namespace Swan {

class Win {
public:
Win(SDL_Window *window, SDL_Renderer *renderer, float scale):
window_(window), renderer_(renderer), scale_(scale) {

if (SDL_GetRendererInfo(renderer_, &rinfo_) < 0) {
panic << "GetRenedrerInfo failed: " << SDL_GetError();
abort();
}

// For HiDPI, we must set the renderer's logical size.
int w, h;
SDL_GetWindowSize(window_, &w, &h);
onResize(w, h);

info << "Using renderer: " << rinfo_.name;
}

Vec2 getPixSize() {
int w, h;
SDL_GetWindowSize(window_, &w, &h);
return Vec2((float)w / scale_, (float)h / scale_);
}

Vec2 getSize() {
int w, h;
SDL_GetWindowSize(window_, &w, &h);
return Vec2(((float)w / (scale_ * zoom_)) / TILE_SIZE, ((float)h / (scale_ * zoom_)) / TILE_SIZE);
}

void onResize(int w, int h) {
SDL_RenderSetLogicalSize(renderer_, (int)((float)w / scale_), (int)((float)h / scale_));
}

SDL_Rect createDestRect(Vec2 pos, Vec2 pixsize) {
return SDL_Rect{
(int)floor((pos.x - cam_.x) * TILE_SIZE * zoom_),
(int)floor((pos.y - cam_.y) * TILE_SIZE * zoom_),
(int)ceil(pixsize.x * zoom_), (int)ceil(pixsize.y * zoom_),
};
}

struct ShowTextureArgs {
SDL_RendererFlip flip = SDL_FLIP_NONE;
double hscale = 1;
double vscale = 1;
double angle = 0;
std::optional<SDL_Point> center = std::nullopt;
};

void showTexture(
const Vec2 &pos, SDL_Texture *tex, SDL_Rect *srcrect,
ShowTextureArgs args) {

SDL_Point *center = args.center ? &*args.center : nullptr;
SDL_Rect destrect = createDestRect(pos, Vec2(srcrect->w * args.hscale, srcrect->h * args.hscale));
if (SDL_RenderCopyEx(renderer_, tex, srcrect, &destrect, args.angle, center, args.flip) < 0)
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) {
SDL_Rect destrect = createDestRect(pos, Vec2(srcrect->w, srcrect->h));
if (SDL_RenderCopy(renderer_, tex, srcrect, &destrect) < 0)
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)
warn << "RenderDrawRect failed: " << SDL_GetError();
}

Vec2 cam_;
float zoom_ = 1;
SDL_Window *window_;
SDL_Renderer *renderer_;
float scale_;
SDL_RendererInfo rinfo_;
};

}

+ 2
- 3
libswan/include/swan/World.h View File

#include "WorldGen.h" #include "WorldGen.h"
#include "Entity.h" #include "Entity.h"
#include "Collection.h" #include "Collection.h"
#include "Resource.h"
#include "Mod.h" #include "Mod.h"
#include "EventEmitter.h" #include "EventEmitter.h"


Tile::ID getTileID(const std::string &name); Tile::ID getTileID(const std::string &name);
Tile &getTile(const std::string &name); Tile &getTile(const std::string &name);
Item &getItem(const std::string &name); Item &getItem(const std::string &name);
Cygnet::RenderSprite &getSprite(const std::string &name);


SDL_Color backgroundColor(); SDL_Color backgroundColor();
void draw(Win &win);
void draw(Cygnet::Renderer &rnd);
void update(float dt); void update(float dt);
void tick(float dt); void tick(float dt);


Game *game_; // TODO: reference, not pointer Game *game_; // TODO: reference, not pointer
std::mt19937 random_; std::mt19937 random_;
std::vector<ModWrapper> mods_; std::vector<ModWrapper> mods_;
//ResourceManager resources_;
Cygnet::ResourceManager resources_; Cygnet::ResourceManager resources_;


// World owns tiles and items, the mod just has Builder objects // World owns tiles and items, the mod just has Builder objects

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



class World; class World;
class WorldPlane; class WorldPlane;
class ImageResource;


class WorldGen { class WorldGen {
public: public:


virtual ~WorldGen() = default; virtual ~WorldGen() = default;


virtual void drawBackground(const Context &ctx, Win &win, Vec2 pos) = 0;
virtual void drawBackground(const Context &ctx, Cygnet::Renderer &rnd, Vec2 pos) = 0;
virtual SDL_Color backgroundColor(Vec2 pos) = 0; virtual SDL_Color backgroundColor(Vec2 pos) = 0;


virtual void genChunk(WorldPlane &plane, Chunk &chunk) = 0; virtual void genChunk(WorldPlane &plane, Chunk &chunk) = 0;

+ 1
- 1
libswan/include/swan/WorldPlane.h View File

void breakTile(TilePos pos); void breakTile(TilePos pos);


SDL_Color backgroundColor(); SDL_Color backgroundColor();
void draw(Win &win);
void draw(Cygnet::Renderer &rnd);
void update(float dt); void update(float dt);
void tick(float dt); void tick(float dt);



+ 7
- 3
libswan/include/swan/common.h View File

#include <swan-common/Vector2.h> #include <swan-common/Vector2.h>
#include <swan-common/constants.h> #include <swan-common/constants.h>


// Forward declare the Cygnet::Renderer, because lots of functions will need
// to take a reference to it. It's nicer to not have to include Cygnet::Renderer
// in every header.
namespace Cygnet {
class Renderer;
}

namespace Swan { namespace Swan {


using namespace SwanCommon; using namespace SwanCommon;
class Game; class Game;
class World; class World;
class WorldPlane; class WorldPlane;
class Win;
class ResourceManager;


struct Context { struct Context {
Game &game; Game &game;
World &world; World &world;
WorldPlane &plane; WorldPlane &plane;
ResourceManager &resources;
}; };


} }

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

#include <initializer_list> #include <initializer_list>
#include <utility> #include <utility>


#include "Win.h"

namespace Swan { namespace Swan {
namespace Draw { namespace Draw {


SDL_Color linearGradient( SDL_Color linearGradient(
float val, std::initializer_list<std::pair<float, SDL_Color>> colors); float val, std::initializer_list<std::pair<float, SDL_Color>> colors);


/*
void parallaxBackground( void parallaxBackground(
Win &win, SDL_Texture *tex, Win &win, SDL_Texture *tex,
std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect, std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect,
float x, float y, float factor); float x, float y, float factor);
TODO */


} }
} }

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

#include <swan/ItemStack.h> #include <swan/ItemStack.h>
#include <swan/Mod.h> #include <swan/Mod.h>
#include <swan/OS.h> #include <swan/OS.h>
#include <swan/Resource.h>
#include <swan/SlotVector.h> #include <swan/SlotVector.h>
#include <swan/Tile.h> #include <swan/Tile.h>
#include <swan/Win.h>
#include <swan/World.h> #include <swan/World.h>
#include <swan/WorldGen.h> #include <swan/WorldGen.h>
#include <swan/WorldPlane.h> #include <swan/WorldPlane.h>

+ 1
- 3
libswan/include/swan/traits/BodyTrait.h View File



namespace Swan { namespace Swan {


class Win;

struct BodyTrait { struct BodyTrait {
struct Body; struct Body;
struct Tag {}; struct Tag {};
Vec2 midRight() { return { right(), midY() }; } Vec2 midRight() { return { right(), midY() }; }
Vec2 bottomRight() { return { right(), bottom() }; } Vec2 bottomRight() { return { right(), bottom() }; }


void outline(Win &win);
//void outline(Win &win); TODO
}; };
}; };



+ 5
- 7
libswan/include/swan/util.h View File

Result(ResultOk, T &&val): isOk_(true), v_(ResultOk{}, std::move(val)) {} Result(ResultOk, T &&val): isOk_(true), v_(ResultOk{}, std::move(val)) {}
Result(ResultErr, Err &&err): isOk_(false), v_(ResultErr{}, std::move(err)) {} Result(ResultErr, Err &&err): isOk_(false), v_(ResultErr{}, std::move(err)) {}


Result(const Result &other) {
isOk_ = other.isOk_;
if (other.isOk_) {
Result(const Result &other): isOk_(other.isOk_) {
if (isOk_) {
new (&v_.val) T(other.v_.val); new (&v_.val) T(other.v_.val);
} else { } else {
new (&v_.err) T(other.v_.err); new (&v_.err) T(other.v_.err);
} }
} }


Result(Result &&other) {
isOk_ = other.isOk_;
Result(Result &&other): isOk_(other.isOk_) {
if (other.isOk_) { if (other.isOk_) {
new (&v_.val) T(std::move(other.v_.val)); new (&v_.val) T(std::move(other.v_.val));
} else { } else {
new (&v_.err) T(std::move(other.v_.err));
new (&v_.err) Err(std::move(other.v_.err));
} }
} }


Result<T, Err> &operator=(const Result<T, Err> &other) { Result<T, Err> &operator=(const Result<T, Err> &other) {
destroy(); destroy();
isOk_ = other.isOk_; isOk_ = other.isOk_;
if (other.isOk_) {
if (isOk_) {
new (&v_.val) T(other.v_.val); new (&v_.val) T(other.v_.val);
} else { } else {
new (&v_.err) Err(other.v_.err); new (&v_.err) Err(other.v_.err);

+ 4
- 6
libswan/src/Animation.cc View File

#include "Animation.h" #include "Animation.h"


#include "Win.h"
#include "gfxutil.h"
#include <cygnet/Renderer.h>


namespace Swan { namespace Swan {


timer_ += interval_; timer_ += interval_;


frame_ += 1; frame_ += 1;
if (frame_ >= resource_.numFrames_)
if (frame_ >= sprite_.frameCount)
frame_ = 0; frame_ = 0;
} }
} }


void Animation::draw(const Vec2 &pos, Win &win) {
SDL_Rect rect = resource_.frameRect(frame_);
win.showTexture(pos, resource_.texture_.get(), &rect, { .flip = flip_ });
void Animation::draw(const Vec2 &pos, Cygnet::Renderer &rnd) {
rnd.drawSprite(sprite_, mat_, frame_);
} }


void Animation::reset() { void Animation::reset() {

+ 6
- 105
libswan/src/Chunk.cc View File

#include "gfxutil.h" #include "gfxutil.h"
#include "World.h" #include "World.h"
#include "Game.h" #include "Game.h"
#include "Win.h"


namespace Swan { namespace Swan {


data_.reset(new uint8_t[destlen]); data_.reset(new uint8_t[destlen]);
memcpy(data_.get(), dest, destlen); memcpy(data_.get(), dest, destlen);


texture_.reset();
compressedSize_ = destlen; compressedSize_ = destlen;


info info
} else { } else {
warn << "Chunk compression error: " << ret << " (Out of memory?)"; warn << "Chunk compression error: " << ret << " (Out of memory?)";
} }

// TODO: Delete renderChunk_
} }


void Chunk::decompress() { void Chunk::decompress() {
<< compressedSize_ << " bytes to " << compressedSize_ << " bytes to "
<< DATA_SIZE << " bytes."; << DATA_SIZE << " bytes.";
compressedSize_ = -1; compressedSize_ = -1;
}

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

// The texture might not be created yet
if (!lightTexture_) {
lightTexture_.reset(SDL_CreateTexture(
ctx.game.win_.renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,
CHUNK_WIDTH, CHUNK_HEIGHT));
SDL_SetTextureBlendMode(lightTexture_.get(), SDL_BLENDMODE_BLEND);

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


// Fill light texture
target.emplace(rnd, lightTexture_.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 b = getLightLevel({ x, y });
color.change(0, 0, 0, 255 - b);
SDL_Rect rect{ x, y, 1, 1 };
SDL_RenderFillRect(rnd, &rect);
}
}

needLightRender_ = false;
// TODO: Create renderChunk_
} }


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

// The texture might not be created yet
if (!texture_) {
texture_.reset(SDL_CreateTexture(
ctx.game.win_.renderer_, SDL_PIXELFORMAT_ARGB8888, SDL_TEXTUREACCESS_TARGET,
CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE));
SDL_SetTextureBlendMode(texture_.get(), SDL_BLENDMODE_BLEND);
target.emplace(rnd, texture_.get());

RenderBlendMode mode(rnd, SDL_BLENDMODE_NONE);
RenderDrawColor color(rnd, 0, 0, 0, 0);
SDL_Rect rect{ 0, 0, CHUNK_WIDTH * TILE_SIZE, CHUNK_HEIGHT * TILE_SIZE };
SDL_RenderFillRect(rnd, &rect);
} else {
target.emplace(rnd, texture_.get());
}

// We're caching tiles so we don't have to world.getTileByID() every time
Tile::ID prevID = World::INVALID_TILE_ID;
Tile *tile = ctx.game.invalidTile_.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));
if (id != prevID) {
prevID = id;
tile = &ctx.world.getTileByID(id);
}

SDL_Rect dest{x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE};
SDL_RenderCopy(rnd, tile->image.texture_.get(), nullptr, &dest);
}
}

needRender_ = false;

renderLight(ctx, rnd);
}

void Chunk::renderList(SDL_Renderer *rnd) {
// Here, we know that the texture is created.
// We still wanna render directly to the target texture
RenderTarget target(rnd, texture_.get());

// We must make sure the blend mode is NONE, because we want transparent
// pixels to actually overwrite non-transparent pixels
RenderBlendMode mode(rnd, SDL_BLENDMODE_NONE);

// When we FillRect, we must fill transparency.
RenderDrawColor color(rnd, 0, 0, 0, 0);

for (auto &[pos, tex]: drawList_) {
SDL_Rect dest{pos.x * TILE_SIZE, pos.y * TILE_SIZE, TILE_SIZE, TILE_SIZE};
SDL_RenderFillRect(rnd, &dest);
SDL_RenderCopy(rnd, tex, nullptr, &dest);
}
}

void Chunk::draw(const Context &ctx, Win &win) {
void Chunk::draw(const Context &ctx, Cygnet::Renderer &rnd) {
if (isCompressed()) if (isCompressed())
return; return;


if (needRender_) if (needRender_)
return; return;


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

if (drawList_.size() > 0) { if (drawList_.size() > 0) {
renderList(win.renderer_);
//renderList(win.renderer_); TODO
drawList_.clear(); drawList_.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);

SDL_Rect texrect{ 0, 0, CHUNK_WIDTH, CHUNK_HEIGHT };
win.showTexture(chunkpos, lightTexture_.get(), &texrect, &rect);
// rnd.drawChunk(renderChunk_, (Vec2)pos_ * Vec2{CHUNK_WIDTH, CHUNK_HEIGHT}); TODO
} }


Chunk::TickAction Chunk::tick(float dt) { Chunk::TickAction Chunk::tick(float dt) {

+ 10
- 11
libswan/src/Game.cc View File

#include "log.h" #include "log.h"
#include "Tile.h" #include "Tile.h"
#include "OS.h" #include "OS.h"
#include "Win.h"


namespace Swan { namespace Swan {


TilePos Game::getMouseTile() { TilePos Game::getMouseTile() {
auto mousePos = getMousePos(); auto mousePos = getMousePos();
return TilePos( return TilePos(
(int)floor(win_.cam_.x + mousePos.x / (Swan::TILE_SIZE * win_.zoom_)),
(int)floor(win_.cam_.y + mousePos.y / (Swan::TILE_SIZE * win_.zoom_)));
(int)floor(cam_.pos.x + mousePos.x / (Swan::TILE_SIZE * cam_.zoom)),
(int)floor(cam_.pos.y + mousePos.y / (Swan::TILE_SIZE * cam_.zoom)));
} }


SDL_Color Game::backgroundColor() { SDL_Color Game::backgroundColor() {
} }


void Game::draw() { void Game::draw() {
world_->draw(win_);
world_->draw(renderer_);
} }


void Game::update(float dt) { void Game::update(float dt) {
world_->update(dt);

// Zoom the window using the scroll wheel // Zoom the window using the scroll wheel
win_.zoom_ += (float)wasWheelScrolled() * 0.1f * win_.zoom_;
if (win_.zoom_ > 3)
win_.zoom_ = 3;
else if (win_.zoom_ < 0.3)
win_.zoom_ = 0.3;
cam_.zoom += (float)wasWheelScrolled() * 0.1f * cam_.zoom;
if (cam_.zoom > 3)
cam_.zoom = 3;
else if (cam_.zoom < 0.3)
cam_.zoom = 0.3;

world_->update(dt);


didScroll_ = 0; didScroll_ = 0;
didPressKeys_.reset(); didPressKeys_.reset();

+ 0
- 132
libswan/src/Resource.cc View File

#include "Resource.h"

#include <stdio.h>
#include <SDL_image.h>
#include <regex>
#include <cpptoml.h>
#include <string.h>
#include <errno.h>

#include "log.h"
#include "common.h"
#include "Win.h"

namespace Swan {

ImageResource::ImageResource(
SDL_Renderer *renderer, const std::string &modpath, const std::string &id) {
static std::regex first_part_re("^.*?/");

SDL_RendererInfo rinfo;
if (SDL_GetRendererInfo(renderer, &rinfo) < 0) {
panic << "GetRendererInfo failed: " << SDL_GetError();
abort();
}

uint32_t format = rinfo.texture_formats[0];
int bpp = 32;
uint32_t rmask, gmask, bmask, amask;
if (SDL_PixelFormatEnumToMasks(format, &bpp, &rmask, &gmask, &bmask, &amask) < 0) {
panic << "PixelFormatEnumToMasks failed: " << SDL_GetError();
abort();
}

std::string assetpath = modpath + "/assets/" +
std::regex_replace(id, first_part_re, "");

surface_.reset(IMG_Load((assetpath + ".png").c_str()));

// If we don't have a surface yet (either loading or conversion failed),
// create a placeholder
if (!surface_) {
warn << "Loading image " << id << " failed: " << SDL_GetError();

surface_.reset(SDL_CreateRGBSurface(
0, TILE_SIZE, TILE_SIZE, bpp, rmask, gmask, bmask, amask));
SDL_FillRect(surface_.get(), NULL, SDL_MapRGB(surface_->format,
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE));
}

frameHeight_ = 32;

// Load TOML if it exists
errno = ENOENT; // I don't know if ifstream is guaranteed to set errno
std::ifstream tomlfile(assetpath + ".toml");
if (tomlfile) {
cpptoml::parser parser(tomlfile);
try {
auto toml = parser.parse();
frameHeight_ = toml->get_as<int>("height").value_or(frameHeight_);
} catch (cpptoml::parse_exception &exc) {
warn << "Failed to parse toml file " << assetpath << ".toml: "
<< exc.what();
}
} else if (errno != ENOENT) {
warn << "Couldn't open " << assetpath << ".toml: " << strerror(errno);
}

texture_.reset(SDL_CreateTextureFromSurface(renderer, surface_.get()));
if (!texture_) {
panic << "CreateTexture failed: " << SDL_GetError();
abort();
}

numFrames_ = surface_->h / frameHeight_;
name_ = id;
}

ImageResource::ImageResource(
SDL_Renderer *renderer, const std::string &name,
int w, int h, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {

surface_.reset(SDL_CreateRGBSurface(
0, TILE_SIZE, TILE_SIZE, 32,
0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff));
SDL_FillRect(surface_.get(), NULL, SDL_MapRGBA(surface_->format, r, g, b, a));

texture_.reset(SDL_CreateTextureFromSurface(renderer, surface_.get()));
if (!texture_) {
panic << "CreateTexture failed: " << SDL_GetError();
abort();
}

frameHeight_ = h;
numFrames_ = 1;
name_ = name;
}

void ImageResource::tick(float dt) {
switchTimer_ -= dt;
if (switchTimer_ <= 0) {
switchTimer_ += switchInterval_;
frame_ += 1;
if (frame_ >= numFrames_)
frame_ = 0;
}
}

ResourceManager::ResourceManager(Win &win) {
addImage(std::make_unique<ImageResource>(
win.renderer_, "@::invalid", TILE_SIZE, TILE_SIZE,
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE));
addImage(std::make_unique<ImageResource>(
win.renderer_, "@::air", TILE_SIZE, TILE_SIZE,
0, 0, 0, 0));
}

void ResourceManager::tick(float dt) {
for (auto &[k, v]: images_) {
v->tick(dt);
}
}

ImageResource &ResourceManager::getImage(const std::string &name) const {
auto it = images_.find(name);
if (it == end(images_)) {
warn << "Couldn't find image " << name << "!";
return getImage("@::invalid");
}
return *it->second;
}

}

+ 23
- 14
libswan/src/World.cc View File



#include "log.h" #include "log.h"
#include "Game.h" #include "Game.h"
#include "Win.h"
#include "Clock.h" #include "Clock.h"
#include "assets.h" #include "assets.h"


return *planes_[id]; return *planes_[id];
} }


Item &World::getItem(const std::string &name) {
auto iter = items_.find(name);
if (iter == items_.end()) {
warn << "Tried to get non-existant item " << name << "!";
return *game_->invalidItem_;
}

return iter->second;
}

Tile::ID World::getTileID(const std::string &name) { Tile::ID World::getTileID(const std::string &name) {
auto iter = tilesMap_.find(name); auto iter = tilesMap_.find(name);
if (iter == tilesMap_.end()) { if (iter == tilesMap_.end()) {
return getTileByID(id); return getTileByID(id);
} }


Item &World::getItem(const std::string &name) {
auto iter = items_.find(name);
if (iter == items_.end()) {
warn << "Tried to get non-existent item " << name << "!";
return items_.at(INVALID_TILE_NAME);
}

return iter->second;
}

Cygnet::RenderSprite &World::getSprite(const std::string &name) {
auto iter = resources_.sprites_.find(name);
if (iter == resources_.sprites_.end()) {
warn << "Tried to get non-existent sprite " << name << "!";
return resources_.sprites_.at(INVALID_TILE_NAME);
}

return iter->second;
}

SDL_Color World::backgroundColor() { SDL_Color World::backgroundColor() {
return planes_[currentPlane_]->backgroundColor(); return planes_[currentPlane_]->backgroundColor();
} }


void World::draw(Win &win) {
void World::draw(Cygnet::Renderer &rnd) {
ZoneScopedN("World draw"); ZoneScopedN("World draw");
win.cam_ = player_->pos - (win.getSize() / 2) + (player_->size / 2);
planes_[currentPlane_]->draw(win);
game_->cam_.pos = player_->pos; // - (win.getSize() / 2) + (player_->size / 2); TODO
planes_[currentPlane_]->draw(rnd);
} }


void World::update(float dt) { void World::update(float dt) {

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

#include "World.h" #include "World.h"
#include "Game.h" #include "Game.h"
#include "Clock.h" #include "Clock.h"
#include "Win.h"


namespace Swan { namespace Swan {


.game = *world_->game_, .game = *world_->game_,
.world = *world_, .world = *world_,
.plane = *this, .plane = *this,
.resources = world_->resources_
}; };
} }


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


if (!oldTile.isSolid && newTile.isSolid) { if (!oldTile.isSolid && newTile.isSolid) {
return gen_->backgroundColor(world_->player_->pos); return gen_->backgroundColor(world_->player_->pos);
} }


void WorldPlane::draw(Win &win) {
void WorldPlane::draw(Cygnet::Renderer &rnd) {
ZoneScopedN("WorldPlane draw"); ZoneScopedN("WorldPlane draw");
std::lock_guard<std::mutex> lock(mut_); std::lock_guard<std::mutex> lock(mut_);
auto ctx = getContext(); auto ctx = getContext();
auto &pbody = *(world_->player_); auto &pbody = *(world_->player_);


gen_->drawBackground(ctx, win, pbody.pos);
gen_->drawBackground(ctx, rnd, pbody.pos);


ChunkPos pcpos = ChunkPos( ChunkPos pcpos = ChunkPos(
(int)floor(pbody.pos.x / CHUNK_WIDTH), (int)floor(pbody.pos.x / CHUNK_WIDTH),


// Just init one chunk per frame // Just init one chunk per frame
if (chunkInitList_.size() > 0) { if (chunkInitList_.size() > 0) {
/*
Chunk *chunk = chunkInitList_.front(); Chunk *chunk = chunkInitList_.front();
chunkInitList_.pop_front(); chunkInitList_.pop_front();
chunk->render(ctx, win.renderer_); chunk->render(ctx, win.renderer_);
TODO */
} }


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


for (auto &coll: entColls_) for (auto &coll: entColls_)
coll->draw(ctx, win);
coll->draw(ctx, rnd);


/*
if (debugBoxes_.size() > 0) { if (debugBoxes_.size() > 0) {
for (auto &pos: debugBoxes_) { for (auto &pos: debugBoxes_) {
win.drawRect(pos, Vec2(1, 1));
rnd.drawRect(pos, Vec2(1, 1));
} }
} }
TODO */
} }


void WorldPlane::update(float dt) { void WorldPlane::update(float dt) {

+ 2
- 0
libswan/src/drawutil.cc View File

return arr[size - 1].second; return arr[size - 1].second;
} }


/*
void parallaxBackground( void parallaxBackground(
Win &win, SDL_Texture *tex, Win &win, SDL_Texture *tex,
std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect, std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect,
} }
} }
} }
TODO */


} }
} }

+ 2
- 3
libswan/src/traits/BodyTrait.cc View File

#include "traits/BodyTrait.h" #include "traits/BodyTrait.h"


#include "Win.h"

namespace Swan { namespace Swan {


/*
void BodyTrait::Body::outline(Win &win) { void BodyTrait::Body::outline(Win &win) {
win.drawRect(pos, size); win.drawRect(pos, size);
}
} TODO */


} }

+ 0
- 1
libswan/src/traits/PhysicsTrait.cc View File

#include "traits/PhysicsTrait.h" #include "traits/PhysicsTrait.h"


#include "WorldPlane.h" #include "WorldPlane.h"
#include "Win.h"


namespace Swan { namespace Swan {



Loading…
Cancel
Save