@@ -12,11 +12,13 @@ static int getStoneLevel(const siv::PerlinNoise &perlin, int x) { | |||
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 texmax = 20; | |||
//int texmax = 20; | |||
if (pos.y > texmin) { | |||
/* | |||
SDL_Texture *tex = bgCave_.texture_.get(); | |||
Uint8 alpha = std::clamp( | |||
@@ -27,6 +29,7 @@ void DefaultWorldGen::drawBackground(const Swan::Context &ctx, Swan::Win &win, S | |||
Swan::Draw::parallaxBackground( | |||
win, tex, std::nullopt, std::nullopt, | |||
pos.x * Swan::TILE_SIZE, pos.y * Swan::TILE_SIZE, 0.7); | |||
TODO */ | |||
} | |||
} | |||
@@ -13,9 +13,10 @@ public: | |||
tAir_(world.getTileID("@::air")), | |||
tTreeTrunk_(world.getTileID("core::tree-trunk")), | |||
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; | |||
void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override; | |||
Swan::EntityRef spawnPlayer(const Swan::Context &ctx) override; | |||
@@ -23,6 +24,6 @@ public: | |||
private: | |||
Swan::Tile::ID genTile(Swan::TilePos pos); | |||
Swan::Tile::ID tGrass_, tDirt_, tStone_, tAir_, tTreeTrunk_, tLeaves_; | |||
Swan::ImageResource &bgCave_; | |||
Cygnet::RenderSprite bgCave_; | |||
siv::PerlinNoise perlin_ = siv::PerlinNoise(100); | |||
}; |
@@ -19,7 +19,8 @@ ItemStackEntity::ItemStackEntity(const Swan::Context &ctx, const PackObject &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_Texture *tex = item_->image_.texture_.get(); | |||
@@ -27,6 +28,7 @@ void ItemStackEntity::draw(const Swan::Context &ctx, Swan::Win &win) { | |||
win.showTexture(body_.pos, tex, &rect, | |||
{ .hscale = 0.5, .vscale = 0.5 }); | |||
TODO */ | |||
} | |||
void ItemStackEntity::update(const Swan::Context &ctx, float dt) { |
@@ -7,7 +7,7 @@ public: | |||
ItemStackEntity(const Swan::Context &ctx, Swan::Vec2 pos, const std::string &item); | |||
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 tick(const Swan::Context &ctx, float dt) override; | |||
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; |
@@ -14,9 +14,9 @@ PlayerEntity::PlayerEntity(const Swan::Context &ctx, const PackObject &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) { |
@@ -11,7 +11,7 @@ public: | |||
using PhysicsEntity::get; | |||
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 tick(const Swan::Context &ctx, float dt) override; | |||
void deserialize(const Swan::Context &ctx, const PackObject &obj) override; | |||
@@ -36,11 +36,11 @@ private: | |||
PlayerEntity(const Swan::Context &ctx): | |||
PhysicsEntity(SIZE), | |||
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( | |||
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; |
@@ -10,15 +10,9 @@ public: | |||
breakListener_ = world.evtTileBreak_.subscribe( | |||
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({ | |||
.name = "stone", |
@@ -30,7 +30,7 @@ struct RenderTile { | |||
struct RenderCamera { | |||
SwanCommon::Vec2 pos; | |||
SwanCommon::Vec2i size; | |||
float zoom; | |||
float zoom = 0; | |||
}; | |||
class Renderer { |
@@ -44,11 +44,8 @@ public: | |||
ResourceManager(ResourceBuilder &&builder); | |||
~ResourceManager(); | |||
RenderSprite getSprite(std::string name) { return sprites_.at(std::move(name)); } | |||
void tick(); | |||
private: | |||
Renderer &rnd_; | |||
std::unordered_map<std::string, RenderSprite> sprites_; | |||
std::unordered_map<std::string, RenderTile> tiles_; |
@@ -14,7 +14,6 @@ add_library(libswan SHARED | |||
src/LightServer.cc | |||
src/Mod.cc | |||
src/OS.cc | |||
src/Resource.cc | |||
src/World.cc | |||
src/WorldPlane.cc) | |||
target_include_directories(libswan |
@@ -1,28 +1,27 @@ | |||
#pragma once | |||
#include <SDL.h> | |||
#include <cygnet/Renderer.h> | |||
#include "common.h" | |||
#include "Resource.h" | |||
#include "Clock.h" | |||
#include "Resource.h" | |||
namespace Swan { | |||
class Animation { | |||
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 draw(const Vec2 &pos, Win &win); | |||
void draw(const Vec2 &pos, Cygnet::Renderer &rnd); | |||
void reset(); | |||
private: | |||
ImageResource &resource_; | |||
Cygnet::RenderSprite sprite_; | |||
float interval_; | |||
float timer_; | |||
SDL_RendererFlip flip_; | |||
Cygnet::Mat3gf mat_; | |||
int frame_ = 0; | |||
}; | |||
@@ -47,9 +47,9 @@ public: | |||
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; | |||
drawList_.push_back({ pos, tex }); | |||
drawList_.push_back({pos, id}); | |||
} | |||
void setTileData(RelPos pos, Tile::ID id) { | |||
@@ -66,12 +66,9 @@ public: | |||
needLightRender_ = true; | |||
} | |||
void render(const Context &ctx, SDL_Renderer *rnd); | |||
void renderLight(const Context &ctx, SDL_Renderer *rnd); | |||
void compress(); | |||
void decompress(); | |||
void draw(const Context &ctx, Win &win); | |||
void draw(const Context &ctx, Cygnet::Renderer &rnd); | |||
TickAction tick(float dt); | |||
bool isActive() { return deactivateTimer_ > 0; } | |||
@@ -83,21 +80,16 @@ public: | |||
private: | |||
static constexpr float DEACTIVATE_INTERVAL = 20; | |||
void renderList(SDL_Renderer *rnd); | |||
bool isCompressed() { return compressedSize_ != -1; } | |||
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 | |||
bool needRender_ = false; | |||
bool needLightRender_ = false; | |||
float deactivateTimer_ = DEACTIVATE_INTERVAL; | |||
bool isModified_ = false; | |||
CPtr<SDL_Texture, SDL_DestroyTexture> texture_; | |||
CPtr<SDL_Texture, SDL_DestroyTexture> lightTexture_; | |||
}; | |||
} |
@@ -61,7 +61,7 @@ public: | |||
virtual EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) = 0; | |||
virtual void update(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; | |||
private: | |||
@@ -84,7 +84,7 @@ public: | |||
EntityRef spawn(const Context &ctx, const Entity::PackObject &obj) override; | |||
void update(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; | |||
private: | |||
@@ -190,11 +190,11 @@ inline void EntityCollectionImpl<Ent>::tick(const Context &ctx, float dt) { | |||
} | |||
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()); | |||
for (auto &ent: entities_) { | |||
ZoneScopedN("draw"); | |||
ent->draw(ctx, win); | |||
ent->draw(ctx, rnd); | |||
} | |||
} | |||
@@ -33,7 +33,7 @@ public: | |||
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 tick(const Context &ctx, float dt) {} | |||
virtual void onDespawn(const Context &ctx) {} |
@@ -8,7 +8,6 @@ | |||
#include <cygnet/Renderer.h> | |||
#include "common.h" | |||
#include "Resource.h" | |||
#include "Mod.h" | |||
#include "World.h" | |||
@@ -16,10 +15,6 @@ namespace Swan { | |||
class Game { | |||
public: | |||
Game(Win &win): | |||
win_(win), | |||
mousePos_(0, 0) {} | |||
void createWorld(const std::string &worldgen, const std::vector<std::string> &modPaths); | |||
void onKeyDown(SDL_Keysym sym) { | |||
@@ -69,11 +64,8 @@ public: | |||
void tick(float dt); | |||
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::RenderCamera cam_; | |||
private: | |||
std::bitset<SDL_NUM_SCANCODES> pressedKeys_; |
@@ -2,7 +2,6 @@ | |||
#include <string> | |||
#include "Resource.h" | |||
#include "Tile.h" | |||
namespace Swan { |
@@ -12,7 +12,6 @@ | |||
#include "WorldGen.h" | |||
#include "Entity.h" | |||
#include "Collection.h" | |||
#include "Resource.h" | |||
#include "OS.h" | |||
#include "util.h" | |||
@@ -1,53 +0,0 @@ | |||
#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_; | |||
}; | |||
} |
@@ -3,9 +3,6 @@ | |||
#include <stdint.h> | |||
#include <string> | |||
#include <optional> | |||
#include <memory> | |||
#include "Resource.h" | |||
namespace Swan { | |||
@@ -1,109 +0,0 @@ | |||
#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_; | |||
}; | |||
} |
@@ -15,7 +15,6 @@ | |||
#include "WorldGen.h" | |||
#include "Entity.h" | |||
#include "Collection.h" | |||
#include "Resource.h" | |||
#include "Mod.h" | |||
#include "EventEmitter.h" | |||
@@ -43,9 +42,10 @@ public: | |||
Tile::ID getTileID(const std::string &name); | |||
Tile &getTile(const std::string &name); | |||
Item &getItem(const std::string &name); | |||
Cygnet::RenderSprite &getSprite(const std::string &name); | |||
SDL_Color backgroundColor(); | |||
void draw(Win &win); | |||
void draw(Cygnet::Renderer &rnd); | |||
void update(float dt); | |||
void tick(float dt); | |||
@@ -57,7 +57,6 @@ public: | |||
Game *game_; // TODO: reference, not pointer | |||
std::mt19937 random_; | |||
std::vector<ModWrapper> mods_; | |||
//ResourceManager resources_; | |||
Cygnet::ResourceManager resources_; | |||
// World owns tiles and items, the mod just has Builder objects |
@@ -13,7 +13,6 @@ namespace Swan { | |||
class World; | |||
class WorldPlane; | |||
class ImageResource; | |||
class WorldGen { | |||
public: | |||
@@ -24,7 +23,7 @@ public: | |||
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 void genChunk(WorldPlane &plane, Chunk &chunk) = 0; |
@@ -70,7 +70,7 @@ public: | |||
void breakTile(TilePos pos); | |||
SDL_Color backgroundColor(); | |||
void draw(Win &win); | |||
void draw(Cygnet::Renderer &rnd); | |||
void update(float dt); | |||
void tick(float dt); | |||
@@ -6,6 +6,13 @@ | |||
#include <swan-common/Vector2.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 { | |||
using namespace SwanCommon; | |||
@@ -16,14 +23,11 @@ using ChunkPos = Vec2i; | |||
class Game; | |||
class World; | |||
class WorldPlane; | |||
class Win; | |||
class ResourceManager; | |||
struct Context { | |||
Game &game; | |||
World &world; | |||
WorldPlane &plane; | |||
ResourceManager &resources; | |||
}; | |||
} |
@@ -5,18 +5,18 @@ | |||
#include <initializer_list> | |||
#include <utility> | |||
#include "Win.h" | |||
namespace Swan { | |||
namespace Draw { | |||
SDL_Color linearGradient( | |||
float val, std::initializer_list<std::pair<float, SDL_Color>> colors); | |||
/* | |||
void parallaxBackground( | |||
Win &win, SDL_Texture *tex, | |||
std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect, | |||
float x, float y, float factor); | |||
TODO */ | |||
} | |||
} |
@@ -12,10 +12,8 @@ | |||
#include <swan/ItemStack.h> | |||
#include <swan/Mod.h> | |||
#include <swan/OS.h> | |||
#include <swan/Resource.h> | |||
#include <swan/SlotVector.h> | |||
#include <swan/Tile.h> | |||
#include <swan/Win.h> | |||
#include <swan/World.h> | |||
#include <swan/WorldGen.h> | |||
#include <swan/WorldPlane.h> |
@@ -4,8 +4,6 @@ | |||
namespace Swan { | |||
class Win; | |||
struct BodyTrait { | |||
struct Body; | |||
struct Tag {}; | |||
@@ -32,7 +30,7 @@ struct BodyTrait { | |||
Vec2 midRight() { return { right(), midY() }; } | |||
Vec2 bottomRight() { return { right(), bottom() }; } | |||
void outline(Win &win); | |||
//void outline(Win &win); TODO | |||
}; | |||
}; | |||
@@ -52,21 +52,19 @@ public: | |||
Result(ResultOk, T &&val): isOk_(true), v_(ResultOk{}, std::move(val)) {} | |||
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); | |||
} else { | |||
new (&v_.err) T(other.v_.err); | |||
} | |||
} | |||
Result(Result &&other) { | |||
isOk_ = other.isOk_; | |||
Result(Result &&other): isOk_(other.isOk_) { | |||
if (other.isOk_) { | |||
new (&v_.val) T(std::move(other.v_.val)); | |||
} else { | |||
new (&v_.err) T(std::move(other.v_.err)); | |||
new (&v_.err) Err(std::move(other.v_.err)); | |||
} | |||
} | |||
@@ -77,7 +75,7 @@ public: | |||
Result<T, Err> &operator=(const Result<T, Err> &other) { | |||
destroy(); | |||
isOk_ = other.isOk_; | |||
if (other.isOk_) { | |||
if (isOk_) { | |||
new (&v_.val) T(other.v_.val); | |||
} else { | |||
new (&v_.err) Err(other.v_.err); |
@@ -1,7 +1,6 @@ | |||
#include "Animation.h" | |||
#include "Win.h" | |||
#include "gfxutil.h" | |||
#include <cygnet/Renderer.h> | |||
namespace Swan { | |||
@@ -11,14 +10,13 @@ void Animation::tick(float dt) { | |||
timer_ += interval_; | |||
frame_ += 1; | |||
if (frame_ >= resource_.numFrames_) | |||
if (frame_ >= sprite_.frameCount) | |||
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() { |
@@ -10,7 +10,6 @@ | |||
#include "gfxutil.h" | |||
#include "World.h" | |||
#include "Game.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
@@ -32,7 +31,6 @@ void Chunk::compress() { | |||
data_.reset(new uint8_t[destlen]); | |||
memcpy(data_.get(), dest, destlen); | |||
texture_.reset(); | |||
compressedSize_ = destlen; | |||
info | |||
@@ -46,6 +44,8 @@ void Chunk::compress() { | |||
} else { | |||
warn << "Chunk compression error: " << ret << " (Out of memory?)"; | |||
} | |||
// TODO: Delete renderChunk_ | |||
} | |||
void Chunk::decompress() { | |||
@@ -71,101 +71,11 @@ void Chunk::decompress() { | |||
<< compressedSize_ << " bytes to " | |||
<< DATA_SIZE << " bytes."; | |||
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()) | |||
return; | |||
@@ -173,21 +83,12 @@ void Chunk::draw(const Context &ctx, Win &win) { | |||
if (needRender_) | |||
return; | |||
// We're responsible for the light level rendering though | |||
if (needLightRender_) | |||
renderLight(ctx, win.renderer_); | |||
if (drawList_.size() > 0) { | |||
renderList(win.renderer_); | |||
//renderList(win.renderer_); TODO | |||
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) { |
@@ -7,7 +7,6 @@ | |||
#include "log.h" | |||
#include "Tile.h" | |||
#include "OS.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
@@ -22,8 +21,8 @@ void Game::createWorld(const std::string &worldgen, const std::vector<std::strin | |||
TilePos Game::getMouseTile() { | |||
auto mousePos = getMousePos(); | |||
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() { | |||
@@ -31,18 +30,18 @@ SDL_Color Game::backgroundColor() { | |||
} | |||
void Game::draw() { | |||
world_->draw(win_); | |||
world_->draw(renderer_); | |||
} | |||
void Game::update(float dt) { | |||
world_->update(dt); | |||
// 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; | |||
didPressKeys_.reset(); |
@@ -1,132 +0,0 @@ | |||
#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; | |||
} | |||
} |
@@ -5,7 +5,6 @@ | |||
#include "log.h" | |||
#include "Game.h" | |||
#include "Win.h" | |||
#include "Clock.h" | |||
#include "assets.h" | |||
@@ -260,16 +259,6 @@ WorldPlane &World::addPlane(const std::string &gen) { | |||
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) { | |||
auto iter = tilesMap_.find(name); | |||
if (iter == tilesMap_.end()) { | |||
@@ -285,14 +274,34 @@ Tile &World::getTile(const std::string &name) { | |||
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() { | |||
return planes_[currentPlane_]->backgroundColor(); | |||
} | |||
void World::draw(Win &win) { | |||
void World::draw(Cygnet::Renderer &rnd) { | |||
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) { |
@@ -8,7 +8,6 @@ | |||
#include "World.h" | |||
#include "Game.h" | |||
#include "Clock.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
@@ -38,7 +37,6 @@ Context WorldPlane::getContext() { | |||
.game = *world_->game_, | |||
.world = *world_, | |||
.plane = *this, | |||
.resources = world_->resources_ | |||
}; | |||
} | |||
@@ -124,7 +122,7 @@ void WorldPlane::setTileID(TilePos pos, Tile::ID id) { | |||
if (id != old) { | |||
Tile &newTile = world_->getTileByID(id); | |||
Tile &oldTile = world_->getTileByID(old); | |||
chunk.setTileID(rp, id, newTile.image.texture_.get()); | |||
chunk.setTileID(rp, id); | |||
chunk.markModified(); | |||
if (!oldTile.isSolid && newTile.isSolid) { | |||
@@ -203,13 +201,13 @@ SDL_Color WorldPlane::backgroundColor() { | |||
return gen_->backgroundColor(world_->player_->pos); | |||
} | |||
void WorldPlane::draw(Win &win) { | |||
void WorldPlane::draw(Cygnet::Renderer &rnd) { | |||
ZoneScopedN("WorldPlane draw"); | |||
std::lock_guard<std::mutex> lock(mut_); | |||
auto ctx = getContext(); | |||
auto &pbody = *(world_->player_); | |||
gen_->drawBackground(ctx, win, pbody.pos); | |||
gen_->drawBackground(ctx, rnd, pbody.pos); | |||
ChunkPos pcpos = ChunkPos( | |||
(int)floor(pbody.pos.x / CHUNK_WIDTH), | |||
@@ -217,27 +215,31 @@ void WorldPlane::draw(Win &win) { | |||
// Just init one chunk per frame | |||
if (chunkInitList_.size() > 0) { | |||
/* | |||
Chunk *chunk = chunkInitList_.front(); | |||
chunkInitList_.pop_front(); | |||
chunk->render(ctx, win.renderer_); | |||
TODO */ | |||
} | |||
for (int x = -1; x <= 1; ++x) { | |||
for (int y = -1; y <= 1; ++y) { | |||
auto iter = chunks_.find(pcpos + ChunkPos(x, y)); | |||
if (iter != chunks_.end()) | |||
iter->second.draw(ctx, win); | |||
iter->second.draw(ctx, rnd); | |||
} | |||
} | |||
for (auto &coll: entColls_) | |||
coll->draw(ctx, win); | |||
coll->draw(ctx, rnd); | |||
/* | |||
if (debugBoxes_.size() > 0) { | |||
for (auto &pos: debugBoxes_) { | |||
win.drawRect(pos, Vec2(1, 1)); | |||
rnd.drawRect(pos, Vec2(1, 1)); | |||
} | |||
} | |||
TODO */ | |||
} | |||
void WorldPlane::update(float dt) { |
@@ -44,6 +44,7 @@ SDL_Color linearGradient( | |||
return arr[size - 1].second; | |||
} | |||
/* | |||
void parallaxBackground( | |||
Win &win, SDL_Texture *tex, | |||
std::optional<SDL_Rect> srcrect, std::optional<SDL_Rect> destrect, | |||
@@ -92,6 +93,7 @@ void parallaxBackground( | |||
} | |||
} | |||
} | |||
TODO */ | |||
} | |||
} |
@@ -1,11 +1,10 @@ | |||
#include "traits/BodyTrait.h" | |||
#include "Win.h" | |||
namespace Swan { | |||
/* | |||
void BodyTrait::Body::outline(Win &win) { | |||
win.drawRect(pos, size); | |||
} | |||
} TODO */ | |||
} |
@@ -1,7 +1,6 @@ | |||
#include "traits/PhysicsTrait.h" | |||
#include "WorldPlane.h" | |||
#include "Win.h" | |||
namespace Swan { | |||