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 */ | |||||
} | } | ||||
} | } | ||||
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); | ||||
}; | }; |
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) { |
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; |
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) { |
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; |
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", |
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 { |
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_; |
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 |
#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; | ||||
}; | }; | ||||
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_; | |||||
}; | }; | ||||
} | } |
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); | |||||
} | } | ||||
} | } | ||||
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) {} |
#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_; |
#include <string> | #include <string> | ||||
#include "Resource.h" | |||||
#include "Tile.h" | #include "Tile.h" | ||||
namespace Swan { | namespace Swan { |
#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" | ||||
#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_; | |||||
}; | |||||
} |
#include <stdint.h> | #include <stdint.h> | ||||
#include <string> | #include <string> | ||||
#include <optional> | #include <optional> | ||||
#include <memory> | |||||
#include "Resource.h" | |||||
namespace Swan { | namespace Swan { | ||||
#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_; | |||||
}; | |||||
} |
#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 |
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; |
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); | ||||
#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; | |||||
}; | }; | ||||
} | } |
#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 */ | |||||
} | } | ||||
} | } |
#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> |
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 | |||||
}; | }; | ||||
}; | }; | ||||
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); |
#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() { |
#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) { |
#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(); |
#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; | |||||
} | |||||
} |
#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) { |
#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) { |
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 */ | |||||
} | } | ||||
} | } |
#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 */ | |||||
} | } |
#include "traits/PhysicsTrait.h" | #include "traits/PhysicsTrait.h" | ||||
#include "WorldPlane.h" | #include "WorldPlane.h" | ||||
#include "Win.h" | |||||
namespace Swan { | namespace Swan { | ||||