Browse Source

WIP, rewriting stuff to use SDL instead of SFML

opengl-renderer-broken
Martin Dørum 4 years ago
parent
commit
e71e20c6c5

+ 5
- 3
CMakeLists.txt View File

@@ -13,7 +13,7 @@ add_compile_options(-std=c++2a -Wall -Wextra -Wpedantic -Wno-unused-parameter)
if(CMAKE_BUILD_TYPE STREQUAL Sanitize OR CMAKE_BUILD_TYPE STREQUAL "")
message(STATUS "Build mode: Sanitize")
add_compile_options(-g -fsanitize=address)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=address")
add_link_options(-fsanitize=address)
elseif(CMAKE_BUILD_TYPE STREQUAL Debug)
message(STATUS "Build mode: Debug")
add_compile_options(-g)
@@ -27,7 +27,9 @@ endif()

add_subdirectory(third_party)

set(libraries sfml-graphics sfml-system sfml-window sfml-audio ImGui-SFML::ImGui-SFML imgui dl)
set(libraries
sfml-graphics sfml-system sfml-window sfml-audio ImGui-SFML::ImGui-SFML
imgui SDL2 SDL2_image dl z)

# We want to be able to use C++20 designated initializers,
# but Clang doesn't support them yet.
@@ -44,7 +46,7 @@ add_subdirectory(core.mod)

add_executable(swan
src/main.cc)
target_link_libraries(swan libswan ${libraries} imgui)
target_link_libraries(swan libswan ${libraries})

set(assets
assets/icon.png

+ 28
- 17
core.mod/src/main.cc View File

@@ -7,38 +7,49 @@
extern "C" void mod_init(Swan::Mod &mod) {
mod.init("core");

mod.registerTile("air", new Swan::Tile{
.image = mod.loadImage("assets/tiles/air.png"),
mod.registerImage("air", "tiles/air.png");
mod.registerImage("stone", "tiles/stone.png");
mod.registerImage("dirt", "tiles/dirt.png");
mod.registerImage("grass", "tiles/grass.png");
mod.registerImage("player-running", "entities/player-running.png");
mod.registerImage("player-still", "entities/player-still.png");

mod.registerTile({
.name = "air",
.image = "core::air",
.is_solid = false,
});
mod.registerTile("stone", new Swan::Tile{
.image = mod.loadImage("assets/tiles/stone.png"),
mod.registerTile({
.name = "stone",
.image = "core::stone",
.dropped_item = "core::stone",
});
mod.registerTile("dirt", new Swan::Tile{
.image = mod.loadImage("assets/tiles/dirt.png"),
mod.registerTile({
.name = "dirt",
.image = "core::dirt",
.dropped_item = "core::dirt",
});
mod.registerTile("grass", new Swan::Tile{
.image = mod.loadImage("assets/tiles/grass.png"),
mod.registerTile({
.name = "grass",
.image = "core::grass",
.dropped_item = "core::dirt",
});

mod.registerItem("stone", new Swan::Item{
.image = mod.loadImage("assets/tiles/stone.png"),
mod.registerItem({
.name = "stone",
.image = "core::stone",
});
mod.registerItem("dirt", new Swan::Item{
.image = mod.loadImage("assets/tiles/dirt.png"),
mod.registerItem({
.name = "dirt",
.image = "core::dirt",
});
mod.registerItem("grass", new Swan::Item{
.image = mod.loadImage("assets/tiles/grass.png"),
mod.registerItem({
.name = "grass",
.image = "core::grass",
});

mod.registerWorldGen("default", new WGDefault::Factory());

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

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

+ 1
- 1
libswan/CMakeLists.txt View File

@@ -1,10 +1,10 @@
add_library(libswan SHARED
src/Animation.cc
src/Asset.cc
src/Body.cc
src/Chunk.cc
src/Game.cc
src/Item.cc
src/Resource.cc
src/Mod.cc
src/SRF.cc
src/Tile.cc

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

@@ -1,10 +1,9 @@
#pragma once

#include <SFML/Graphics/Sprite.hpp>

#include "common.h"
#include "Asset.h"
#include "Resource.h"
#include "Timer.h"
#include "Resource.h"

namespace Swan {

@@ -14,27 +13,19 @@ public:
HFLIP = 1,
};

Animation() = default;
Animation(int w, int h, float interval, const Asset &asset, int flags = 0) {
init(w, h, interval, asset, flags);
}

void init(int w, int h, float interval, const Asset &asset, int flags = 0);
Animation(ImageResource &resource, float interval):
resource_(resource), interval_(interval), timer_(interval) {}

void tick(float dt);
void draw(Win &win);
void reset();

int width_, height_;
void reset();

private:
ImageResource &resource_;
float interval_;
const Asset *asset_;
int fcount_;
float timer_;
int frame_ = 0;
bool dirty_ = true;
Timer timer_;
sf::Sprite sprite_;
};

}

+ 0
- 23
libswan/include/swan/Asset.h View File

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

#include <SFML/Graphics/Image.hpp>
#include <SFML/Graphics/Texture.hpp>

namespace Swan {

class Asset {
public:
Asset(const std::string &path): path_(path) {}

bool load(const std::string &pfx);

std::string name_;
std::string path_;
sf::Image image_;
sf::Texture tex_;

static Asset INVALID_ASSET;
static void initGlobal();
};

}

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

@@ -42,7 +42,7 @@ public:
bool isActive() { return deactivate_timer_ > 0; }

private:
static constexpr float DEACTIVATE_TIME = 20;
static constexpr float DEACTIVATE_INTERVAL = 20;
static sf::Uint8 *renderbuf;

bool isCompressed() { return compressed_size_ != -1; }
@@ -51,7 +51,7 @@ private:

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

struct Visuals {
sf::Texture tex_;

+ 6
- 8
libswan/include/swan/Game.h View File

@@ -6,19 +6,17 @@

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

namespace Swan {

class Game {
public:
Game(Win &win):
win_(win),
mouse_pos_(0, 0),
keys_pressed_(sf::Keyboard::Key::KeyCount, false),
mouse_pressed_(sf::Mouse::Button::ButtonCount, false),
win_(win) {}
mouse_pressed_(sf::Mouse::Button::ButtonCount, false) {}

void loadMod(const std::string &path);
void createWorld(const std::string &worldgen);

void onKeyPressed(sf::Keyboard::Key key) { keys_pressed_[(int)key] = true; }
@@ -36,16 +34,16 @@ public:
void update(float dt);
void tick(float dt);

static void initGlobal();

std::unique_ptr<World> world_ = NULL;
std::unique_ptr<ImageResource> invalid_image_ = NULL;
std::unique_ptr<Tile> invalid_tile_ = NULL;
std::unique_ptr<Item> invalid_item_ = NULL;
Win &win_;

private:
Vec2i mouse_pos_;
std::vector<bool> keys_pressed_;
std::vector<bool> mouse_pressed_;
std::vector<Mod> registered_mods_;
Win &win_;
};

}

+ 14
- 8
libswan/include/swan/Item.h View File

@@ -1,19 +1,25 @@
#pragma once

#include <memory>
#include <string>
#include <SFML/Graphics/Image.hpp>

#include "Resource.h"

namespace Swan {

struct Item {
std::unique_ptr<sf::Image> image;
class Item {
public:
struct Builder {
std::string name;
std::string image;
};

Item(const ImageResource &image, const std::string &mod, const Builder &builder):
name_(mod+"::"+builder.name), image_(image) {}

std::string name = "";
const std::string name_;
const ImageResource &image_;

static Item INVALID_ITEM;
static Item *createInvalid();
static void initGlobal();
static std::unique_ptr<Item> createInvalid(Context &ctx);
};

}

+ 15
- 15
libswan/include/swan/Mod.h View File

@@ -4,36 +4,36 @@
#include <string>
#include <vector>
#include <memory>
#include <SFML/Graphics/Image.hpp>
#include <SDL2/SDL.h>

#include "Tile.h"
#include "Item.h"
#include "WorldGen.h"
#include "Entity.h"
#include "Asset.h"
#include "Resource.h"

namespace Swan {

class Mod {
public:
using ModID = uint32_t;

void init(const std::string &name);
void registerTile(const std::string &name, Tile *tile);
void registerItem(const std::string &name, Item *item);
void registerWorldGen(const std::string &name, WorldGen::Factory *gen);
void registerEntity(const std::string &name, Entity::Factory *ent);
void registerAsset(const std::string &name, Asset *asset);

std::unique_ptr<sf::Image> loadImage(const std::string &path);
void registerImage(const std::string &name, const std::string &path, int frame_height = -1);

void registerTile(const Tile::Builder &tile);
void registerItem(const Item::Builder &item);
void registerWorldGen(const std::string &name, std::unique_ptr<WorldGen::Factory> gen);
void registerEntity(const std::string &name, std::unique_ptr<Entity::Factory> ent);

std::string name_;
std::string path_;
std::vector<std::shared_ptr<Tile>> tiles_;
std::vector<std::shared_ptr<Item>> items_;
std::vector<std::shared_ptr<WorldGen::Factory>> worldgens_;
std::vector<std::shared_ptr<Entity::Factory>> entities_;
std::vector<std::shared_ptr<Asset>> assets_;

std::unordered_map<std::string, std::unique_ptr<ImageResource>> images_;
std::unordered_map<std::string, Tile::Builder> tiles_;
std::unordered_map<std::string, Item::Builder> items_;
std::unordered_map<std::string, std::unique_ptr<WorldGen::Factory>> worldgens_;
std::unordered_map<std::string, std::unique_ptr<Entity::Factory>> entities_;
SDL_Renderer *renderer_;
bool inited_ = false;
};


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

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

#include <SDL2/SDL.h>
#include <stdint.h>
#include <string>
#include <memory>

#include "common.h"

namespace Swan {

class ImageResource {
public:
ImageResource(
SDL_Renderer *renderer, const std::string &name,
const std::string &path, int frame_height = -1);
ImageResource(
SDL_Renderer *renderer, const std::string &name,
int w, int h, uint8_t r, uint8_t g, uint8_t b);


void tick(float dt);

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 frame_height_;
int num_frames_;
std::string name_;
int frame_ = 0;

static std::unique_ptr<ImageResource> createInvalid(Context &ctx);

private:
float switch_interval_ = 1;
float switch_timer_ = switch_interval_;
};

}

+ 20
- 9
libswan/include/swan/Tile.h View File

@@ -2,25 +2,36 @@

#include <stdint.h>
#include <string>
#include <optional>
#include <memory>
#include <SFML/Graphics/Image.hpp>

#include "Item.h"
#include "Resource.h"

namespace Swan {

struct Tile {
class Tile {
public:
using ID = uint16_t;

std::unique_ptr<sf::Image> image;
bool is_solid = true;
std::string dropped_item = "";
struct Builder {
std::string name;
std::string image;
bool is_solid = true;
std::optional<std::string> dropped_item = std::nullopt;
};

Tile(const ImageResource &image, const std::string &mod, const Builder &builder):
name_(mod+"::"+builder.name), image_(image),
is_solid_(builder.is_solid), dropped_item_(builder.dropped_item) {}

std::string name = "";
const std::string name_;
const ImageResource &image_;
const bool is_solid_;
const std::optional<std::string> dropped_item_;

static Tile INVALID_TILE;
static std::unique_ptr<Tile> createInvalid(Context &ctx);
static ID INVALID_ID;
static Tile *createInvalid();
static void initGlobal();
};

}

+ 11
- 11
libswan/include/swan/Win.h View File

@@ -2,33 +2,33 @@

#include "common.h"

#include <SDL2/SDL.h>

namespace Swan {

class Win {
public:
Win(sf::RenderWindow *win): window_(win) {}
Win(SDL_Renderer *renderer): renderer_(renderer) {}

void setPos(const Vec2 &pos) {
transform_ = sf::Transform()
.scale(scale_, scale_)
.translate((pos - cam_) * TILE_SIZE);
//transform_ = sf::Transform()
// .scale(scale_, scale_)
// .translate((pos - cam_) * TILE_SIZE);
}

void draw(const sf::Drawable &drawable) {
window_->draw(drawable, transform_);
//window_->draw(drawable, transform_);
}

Vec2 getSize() {
sf::Vector2u v = window_->getSize();
return Vec2(v.x, v.y) / (TILE_SIZE * scale_);
//sf::Vector2u v = window_->getSize();
//return Vec2(v.x, v.y) / (TILE_SIZE * scale_);
return Vec2(10, 10);
}

float scale_ = 2;
Vec2 cam_;

private:
sf::RenderWindow *window_;
sf::Transform transform_;
SDL_Renderer *renderer_;
};

}

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

@@ -6,12 +6,12 @@
#include <random>

#include "common.h"
#include "Asset.h"
#include "Item.h"
#include "Tile.h"
#include "WorldPlane.h"
#include "WorldGen.h"
#include "Entity.h"
#include "Resource.h"

namespace Swan {

@@ -30,13 +30,13 @@ public:
void registerItem(std::shared_ptr<Item> i);
void registerWorldGen(std::shared_ptr<WorldGen::Factory> gen);
void registerEntity(std::shared_ptr<Entity::Factory> ent);
void registerAsset(std::shared_ptr<Asset> asset);
void registerImage(std::shared_ptr<ImageResource> i);

Tile &getTileByID(Tile::ID id);
Tile::ID getTileID(const std::string &name);
Tile &getTile(const std::string &name);
Item &getItem(const std::string &name);
Asset &getAsset(const std::string &name);
ImageResource &getImage(const std::string &name);

void draw(Win &win);
void update(float dt);
@@ -47,7 +47,7 @@ public:
std::map<std::string, std::shared_ptr<Item>> items_;
std::map<std::string, std::shared_ptr<WorldGen::Factory>> worldgens_;
std::map<std::string, std::shared_ptr<Entity::Factory>> ents_;
std::map<std::string, std::shared_ptr<Asset>> assets_;
std::map<std::string, std::shared_ptr<ImageResource>> images_;
Entity *player_;
Game *game_;


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

@@ -11,6 +11,9 @@ static constexpr int TILE_SIZE = 32;
static constexpr int TICK_RATE = 20;
static constexpr int CHUNK_HEIGHT = 64;
static constexpr int CHUNK_WIDTH = 64;
static constexpr int PLACEHOLDER_RED = 245;
static constexpr int PLACEHOLDER_GREEN = 66;
static constexpr int PLACEHOLDER_BLUE = 242;

using TilePos = Vec2i;
using ChunkPos = Vec2i;

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

@@ -1,13 +1,13 @@
#pragma once

#include <swan/Animation.h>
#include <swan/Asset.h>
#include <swan/Body.h>
#include <swan/BoundingBox.h>
#include <swan/Chunk.h>
#include <swan/Entity.h>
#include <swan/Game.h>
#include <swan/Mod.h>
#include <swan/Resource.h>
#include <swan/SRF.h>
#include <swan/Tile.h>
#include <swan/Timer.h>

+ 9
- 24
libswan/src/Animation.cc View File

@@ -4,41 +4,26 @@

namespace Swan {

void Animation::init(int w, int h, float interval, const Asset &asset, int flags) {
width_ = w;
height_ = h;
interval_ = interval;
asset_ = &asset;
fcount_ = (int)asset_->image_.getSize().y / height_;
sprite_.setTexture(asset_->tex_);
sprite_.setTextureRect(sf::IntRect(0, 0, width_, height_));

if (flags & (int)Flags::HFLIP) {
sprite_.setOrigin(Vec2(width_, 0));
sprite_.setScale(Vec2(-1, 1));
}
}

void Animation::tick(float dt) {
timer_.tick(dt);
if (timer_.periodic(interval_)) {
dirty_ = true;
timer_ -= dt;
if (timer_ <= 0) {
timer_ += interval_;

frame_ += 1;
if (frame_ >= fcount_)
if (frame_ >= resource_.num_frames_)
frame_ = 0;

sprite_.setTextureRect(sf::IntRect(0, height_ * frame_, width_, height_));
dirty_ = true;
}
}

void Animation::draw(Win &win) {
win.draw(sprite_);
}

void Animation::reset() {
timer_.reset();
frame_ = 0;
dirty_ = true;
timer_ = interval_;
frame_ = 0;
dirty_ = true;
}

}

+ 0
- 26
libswan/src/Asset.cc View File

@@ -1,26 +0,0 @@
#include "Asset.h"

#include "common.h"

namespace Swan {

Asset Asset::INVALID_ASSET("");

bool Asset::load(const std::string &pfx) {
if (!image_.loadFromFile(pfx + "/" + path_))
return false;

auto size = image_.getSize();
tex_.create(size.x, size.y);
tex_.update(image_);
return true;
}

void Asset::initGlobal() {
INVALID_ASSET.name_ = "@internal::invalid";
INVALID_ASSET.image_.create(TILE_SIZE, TILE_SIZE, sf::Color(245, 66, 242));
INVALID_ASSET.tex_.create(TILE_SIZE, TILE_SIZE);
INVALID_ASSET.tex_.update(INVALID_ASSET.image_);
}

}

+ 4
- 4
libswan/src/Body.cc View File

@@ -26,7 +26,7 @@ void Body::collideX(WorldPlane &plane) {
for (int y = (int)floor(bounds.top() + epsilon); y <= (int)floor(bounds.bottom() - epsilon); ++y) {
int lx = (int)floor(bounds.left() + epsilon);
Tile &left = plane.getTile({ lx, y });
if (left.is_solid) {
if (left.is_solid_) {
bounds.pos.x = (float)lx + 1.0;
collided = true;
break;
@@ -34,7 +34,7 @@ void Body::collideX(WorldPlane &plane) {

int rx = (int)floor(bounds.right() - epsilon);
Tile &right = plane.getTile({ rx, y });
if (right.is_solid) {
if (right.is_solid_) {
bounds.pos.x = (float)rx - bounds.size.x;
collided = true;
break;
@@ -58,7 +58,7 @@ void Body::collideY(WorldPlane &plane) {
for (int x = (int)floor(bounds.left() + epsilon); x <= (int)floor(bounds.right() - epsilon); ++x) {
int ty = (int)floor(bounds.top() + epsilon);
Tile &top = plane.getTile({ x, ty });
if (top.is_solid) {
if (top.is_solid_) {
bounds.pos.y = (float)ty + 1.0;
collided = true;
break;
@@ -66,7 +66,7 @@ void Body::collideY(WorldPlane &plane) {

int by = (int)floor(bounds.bottom() - epsilon);
Tile &right = plane.getTile({ x, by });
if (right.is_solid) {
if (right.is_solid_) {
bounds.pos.y = (float)by - bounds.size.y;
collided = true;
on_ground_ = true;

+ 5
- 4
libswan/src/Chunk.cc View File

@@ -27,7 +27,7 @@ void Chunk::setTileID(RelPos pos, Tile::ID id) {
void Chunk::drawBlock(RelPos pos, const Tile &t) {
keepActive();

visuals_->tex_.update(*t.image, pos.x * TILE_SIZE, pos.y * TILE_SIZE);
//visuals_->tex_.update(*t.image_, pos.x * TILE_SIZE, pos.y * TILE_SIZE);
visuals_->dirty_ = true;
}

@@ -97,7 +97,7 @@ void Chunk::decompress() {

void Chunk::render(const Context &ctx) {
Tile::ID prevID = Tile::INVALID_ID;
Tile *tile = &Tile::INVALID_TILE;
Tile *tile = ctx.game.invalid_tile_.get();

for (int x = 0; x < CHUNK_WIDTH; ++x) {
for (int y = 0; y < CHUNK_HEIGHT; ++y) {
@@ -107,7 +107,8 @@ void Chunk::render(const Context &ctx) {
tile = &ctx.world.getTileByID(id);
}

const sf::Uint8 *imgptr = tile->image->getPixelsPtr();
const sf::Uint8 *imgptr = NULL;
//const sf::Uint8 *imgptr = tile->image->getPixelsPtr();
for (int imgy = 0; imgy < TILE_SIZE; ++imgy) {
int pixx = x * TILE_SIZE;
int pixy = y * TILE_SIZE + imgy;
@@ -153,7 +154,7 @@ void Chunk::tick(float dt) {

bool Chunk::keepActive() {
bool wasActive = isActive();
deactivate_timer_ = DEACTIVATE_TIME;
deactivate_timer_ = DEACTIVATE_INTERVAL;

if (wasActive)
return false;

+ 1
- 40
libswan/src/Game.cc View File

@@ -4,48 +4,15 @@
#include <math.h>
#include <SFML/Window/Mouse.hpp>
#include <time.h>
#include <memory>

#include "Tile.h"
#include "Asset.h"
#include "Win.h"

namespace Swan {

void Game::loadMod(const std::string &path) {
std::string dlpath = path + "/mod.so";
void *dl = dlopen(dlpath.c_str(), RTLD_LAZY);
if (dl == NULL) {
fprintf(stderr, "%s\n", dlerror());
return;
}

void (*mod_init)(Mod &) = (void (*)(Mod &))dlsym(dl, "mod_init");
if (mod_init == NULL) {
fprintf(stderr, "%s\n", dlerror());
}

registered_mods_.push_back(Mod());
Mod &mod = registered_mods_.back();
mod.path_ = path;
mod_init(mod);
}

void Game::createWorld(const std::string &worldgen) {
world_.reset(new World(this, time(NULL)));
for (auto &mod: registered_mods_) {
world_->registerTile(std::shared_ptr<Tile>(Tile::createInvalid()));

for (auto &tile: mod.tiles_)
world_->registerTile(tile);
for (auto &item: mod.items_)
world_->registerItem(item);
for (auto &worldgen: mod.worldgens_)
world_->registerWorldGen(worldgen);
for (auto &entity: mod.entities_)
world_->registerEntity(entity);
for (auto &asset: mod.assets_)
world_->registerAsset(asset);
}

world_->setWorldGen(worldgen);
world_->setCurrentPlane(world_->addPlane());
@@ -71,10 +38,4 @@ void Game::tick(float dt) {
world_->tick(dt);
}

void Game::initGlobal() {
Tile::initGlobal();
Item::initGlobal();
Asset::initGlobal();
}

}

+ 8
- 16
libswan/src/Item.cc View File

@@ -1,24 +1,16 @@
#include "Item.h"

#include "Resource.h"
#include "Game.h"
#include "common.h"

namespace Swan {

Item Item::INVALID_ITEM;

static void initInvalid(Item *i) {
i->name = "@internal::invalid";
i->image.reset(new sf::Image());
i->image->create(TILE_SIZE, TILE_SIZE, sf::Color(254, 66, 242));
}

Item *Item::createInvalid() {
Item *i = new Item();
initInvalid(i);
return i;
}

void Item::initGlobal() {
initInvalid(&INVALID_ITEM);
std::unique_ptr<Item> Item::createInvalid(Context &ctx) {
return std::make_unique<Item>(*ctx.game.invalid_image_, "@internal", Builder{
.name = "invalid",
.image = "invalid",
});
}

}

+ 16
- 31
libswan/src/Mod.cc View File

@@ -11,47 +11,32 @@ void Mod::init(const std::string &name) {
fprintf(stderr, "Mod initing: %s\n", name_.c_str());
}

void Mod::registerTile(const std::string &name, Tile *tile) {
tile->name = name_ + "::" + name;
fprintf(stderr, "Adding tile: %s\n", tile->name.c_str());
tiles_.push_back(std::shared_ptr<Tile>(tile));
void Mod::registerImage(const std::string &name, const std::string &path, int frame_height) {
images_[name] = std::make_unique<ImageResource>(
renderer_, name_ = "::" + name, path, frame_height);
fprintf(stderr, "Adding image: %s\n", images_[name]->name_.c_str());
}

void Mod::registerItem(const std::string &name, Item *item) {
item->name = name_ + "::" + name;
fprintf(stderr, "Adding item: %s\n", item->name.c_str());
items_.push_back(std::shared_ptr<Item>(item));
void Mod::registerTile(const Tile::Builder &tile) {
tiles_[tile.name] = tile;
fprintf(stderr, "Adding tile: %s::%s\n", name_.c_str(), tile.name.c_str());
}

void Mod::registerWorldGen(const std::string &name, WorldGen::Factory *gen) {
void Mod::registerItem(const Item::Builder &item) {
items_[item.name] = item;
fprintf(stderr, "Adding item: %s::%s\n", name_.c_str(), item.name.c_str());
}

void Mod::registerWorldGen(const std::string &name, std::unique_ptr<WorldGen::Factory> gen) {
gen->name_ = name_ + "::" + name;
fprintf(stderr, "Adding world gen: %s\n", gen->name_.c_str());
worldgens_.push_back(std::shared_ptr<WorldGen::Factory>(gen));
worldgens_[name] = std::move(gen);
}

void Mod::registerEntity(const std::string &name, Entity::Factory *ent) {
void Mod::registerEntity(const std::string &name, std::unique_ptr<Entity::Factory> ent) {
ent->name_ = name_ + "::" + name;
fprintf(stderr, "Adding entity: %s\n",ent->name_.c_str());
entities_.push_back(std::shared_ptr<Entity::Factory>(ent));
}

void Mod::registerAsset(const std::string &name, Asset *asset) {
asset->name_ = name_ + "::" + name;

if (!asset->load(path_)) {
fprintf(stderr, "Asset %s: Failed to load image '%s'", name.c_str(), (path_ + "/" + asset->path_).c_str());
abort();
}

assets_.push_back(std::shared_ptr<Asset>(asset));
}

std::unique_ptr<sf::Image> Mod::loadImage(const std::string &path) {
std::unique_ptr<sf::Image> img(new sf::Image());
if (!img->loadFromFile(path_ + "/" + path))
img->create(TILE_SIZE, TILE_SIZE, sf::Color(245, 66, 242));

return img;
entities_[name] = std::move(ent);
}

}

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

@@ -0,0 +1,70 @@
#include "Resource.h"

#include <stdio.h>
#include <SDL2/SDL_image.h>

#include "common.h"
#include "Game.h"
#include "Win.h"

namespace Swan {

ImageResource::ImageResource(
SDL_Renderer *renderer, const std::string &name,
const std::string &path, int frame_height) {

surface_.reset(IMG_Load(path.c_str()));
if (surface_ == nullptr) {
fprintf(stderr, "Loading %s failed: %s\n", path.c_str(), SDL_GetError());

surface_.reset(SDL_CreateRGBSurface(
0, TILE_SIZE, TILE_SIZE, 32, 0, 0, 0, 0));

SDL_FillRect(surface_.get(), NULL, SDL_MapRGB(surface_->format,
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE));
}

if (frame_height < 0)
frame_height = surface_->h;

texture_.reset(SDL_CreateTexture(
renderer, surface_->format->format, SDL_TEXTUREACCESS_STATIC,
surface_->w, frame_height));

frame_height_ = frame_height;
num_frames_ = surface_->h / frame_height_;
name_ = name;
}

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

surface_.reset(SDL_CreateRGBSurface(
0, TILE_SIZE, TILE_SIZE, 32, 0, 0, 0, 0));
SDL_FillRect(surface_.get(), NULL, SDL_MapRGB(surface_->format, r, g, b));
texture_.reset(SDL_CreateTexture(
renderer, surface_->format->format, SDL_TEXTUREACCESS_STATIC, w, h));

frame_height_ = h;
num_frames_ = 1;
name_ = name;
}

void ImageResource::tick(float dt) {
switch_timer_ -= dt;
if (switch_timer_ <= 0) {
switch_timer_ += switch_interval_;
frame_ += 1;
if (frame_ >= num_frames_)
frame_ = 0;
}
}

std::unique_ptr<ImageResource> ImageResource::createInvalid(Context &ctx) {
return std::make_unique<ImageResource>(
ctx.game.win_.renderer_, "@internal::invalid", TILE_SIZE, TILE_SIZE,
PLACEHOLDER_RED, PLACEHOLDER_GREEN, PLACEHOLDER_BLUE);
}

}

+ 7
- 16
libswan/src/Tile.cc View File

@@ -1,26 +1,17 @@
#include "Tile.h"

#include "common.h"
#include <Game.h>

namespace Swan {

Tile Tile::INVALID_TILE;
Tile::ID Tile::INVALID_ID = 0;

static void initInvalid(Tile *t) {
t->name = "@internal::invalid";
t->image.reset(new sf::Image());
t->image->create(TILE_SIZE, TILE_SIZE, sf::Color(245, 66, 242));
t->is_solid = false;
}

Tile *Tile::createInvalid() {
Tile *t = new Tile();
initInvalid(t);
return t;
}

void Tile::initGlobal() {
initInvalid(&INVALID_TILE);
std::unique_ptr<Tile> Tile::createInvalid(Context &ctx) {
return std::make_unique<Tile>(*ctx.game.invalid_image_, "@internal", Builder{
.name = "invalid",
.image = "invalid",
});
}

}

+ 9
- 9
libswan/src/World.cc View File

@@ -49,12 +49,12 @@ void World::spawnPlayer() {

void World::registerTile(std::shared_ptr<Tile> t) {
Tile::ID id = tiles_.size();
tiles_map_[t->name] = id;
tiles_map_[t->name_] = id;
tiles_.push_back(std::move(t));
}

void World::registerItem(std::shared_ptr<Item> i) {
items_[i->name] = std::move(i);
items_[i->name_] = std::move(i);
}

void World::registerWorldGen(std::shared_ptr<WorldGen::Factory> gen) {
@@ -65,15 +65,15 @@ void World::registerEntity(std::shared_ptr<Entity::Factory> ent) {
ents_[ent->name_] = std::move(ent);
}

void World::registerAsset(std::shared_ptr<Asset> asset) {
assets_[asset->name_] = std::move(asset);
void World::registerImage(std::shared_ptr<ImageResource> i) {
images_[i->name_] = std::move(i);
}

Asset &World::getAsset(const std::string &name) {
auto iter = assets_.find(name);
if (iter == assets_.end()) {
ImageResource &World::getImage(const std::string &name) {
auto iter = images_.find(name);
if (iter == images_.end()) {
fprintf(stderr, "Tried to get non-existant asset ''%s'!\n", name.c_str());
return Asset::INVALID_ASSET;
abort();
}

return *iter->second;
@@ -83,7 +83,7 @@ Item &World::getItem(const std::string &name) {
auto iter = items_.find(name);
if (iter == items_.end()) {
fprintf(stderr, "Tried to get non-existant item ''%s'!\n", name.c_str());
return Item::INVALID_ITEM;
return *game_->invalid_item_;
}

return *iter->second;

+ 2
- 2
libswan/src/WorldPlane.cc View File

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

if (t.dropped_item != "") {
if (t.dropped_item_ != std::nullopt) {
spawnEntity("core::item-stack", SRFArray{
new SRFFloatArray{ (float)pos.x, (float)pos.y },
new SRFString{ t.dropped_item },
new SRFString{ *t.dropped_item_ },
});
}
}

+ 49
- 88
src/main.cc View File

@@ -1,7 +1,13 @@
#include <vector>
#include <time.h>
#include <unistd.h>
#include <stdio.h>
#include <vector>
#include <memory>
#include <chrono>
#include <ratio>

#include <SDL2/SDL.h>
#include <SDL2/SDL_image.h>

#include <swan/common.h>
#include <swan/World.h>
@@ -9,94 +15,58 @@
#include <swan/Timer.h>
#include <swan/Win.h>

#include <SFML/System/Clock.hpp>
#include <SFML/Audio.hpp>
using namespace Swan;

#include <imgui/imgui.h>
#include <imgui-SFML.h>
#define errassert(expr, str, errfn) do { \
if (!(expr)) { \
fprintf(stderr, "%s: %s\n", str, errfn()); \
return EXIT_FAILURE; \
} \
} while (0)

using namespace Swan;
#define sdlassert(expr, str) errassert(expr, str, SDL_GetError);
#define imgassert(expr, str) errassert(expr, str, IMG_GetError);

template<typename T>
using DeleteFunc = void (*)(T *);

int main() {
sf::Image icon;
if (!icon.loadFromFile("assets/icon.png")) {
fprintf(stderr, "Failed to load image 'icon.png'\n");
abort();
}
sdlassert(SDL_Init(SDL_INIT_VIDEO) >= 0, "Could not initialize SDL");
std::unique_ptr<void, DeleteFunc<void>> sdl(nullptr, [](void *){ SDL_Quit(); });

// Cretate window
sf::RenderWindow window(sf::VideoMode(800, 600), "Project: SWAN");
window.setVerticalSyncEnabled(true);
window.setIcon(icon.getSize().x, icon.getSize().y, icon.getPixelsPtr());
Win win(&window);

// Initialize ImGui
ImGui::SFML::Init(window);

// Create music
sf::SoundBuffer musicbuf;
sf::Sound music;
if (musicbuf.loadFromFile("assets/music/happy-1.wav")) {
music.setBuffer(musicbuf);
music.setLoop(true);
music.play();
} else {
fprintf(stderr, "Failed to load music! Am very sad.\n");
}
int imgflags = IMG_INIT_PNG;
imgassert(IMG_Init(imgflags) == imgflags, "Could not initialize SDL_Image");
std::unique_ptr<void, DeleteFunc<void>> sdl_image(nullptr, [](void *){ IMG_Quit(); });

std::unique_ptr<SDL_Window, DeleteFunc<SDL_Window>> window(
SDL_CreateWindow(
"Project: SWAN",
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED,
640, 480,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE),
SDL_DestroyWindow);

std::unique_ptr<SDL_Renderer, DeleteFunc<SDL_Renderer>> renderer(
SDL_CreateRenderer(
window.get(), -1, SDL_RENDERER_ACCELERATED),
SDL_DestroyRenderer);
sdlassert(renderer, "Could not create renderer\n");

Game::initGlobal();
Win win(renderer.get());

Game game(win);
game.loadMod("core.mod");

game.createWorld("core::default");
auto prevTime = std::chrono::steady_clock::now();

sf::Clock clock;
float fpsAcc = 0;
float tickAcc = 0;
int fcount = 0;
int slowFrames = 0;

while (window.isOpen()) {
sf::Event event;
while (window.pollEvent(event)) {
ImGui::SFML::ProcessEvent(event);

switch (event.type) {
case sf::Event::Closed:
window.close();
break;

case sf::Event::Resized:
window.setView(sf::View(sf::FloatRect(
0, 0, event.size.width, event.size.height)));
break;

case sf::Event::KeyPressed:
game.onKeyPressed(event.key.code);
break;

case sf::Event::KeyReleased:
game.onKeyReleased(event.key.code);
break;

case sf::Event::MouseMoved:
game.onMouseMove(event.mouseMove.x, event.mouseMove.y);
break;

case sf::Event::MouseButtonPressed:
game.onMousePressed(event.mouseButton.button);
break;

case sf::Event::MouseButtonReleased:
game.onMouseReleased(event.mouseButton.button);
break;

default: break;
}
}

float dt = clock.restart().asSeconds();
while (1) {
auto now = std::chrono::steady_clock::now();
std::chrono::duration<float> dur(prevTime - now);
prevTime = now;
float dt = dur.count();

// Display FPS
fpsAcc += dt;
@@ -107,6 +77,8 @@ int main() {
fcount = 0;
}

game.update(dt);

if (dt > 0.1) {
if (slowFrames == 0)
fprintf(stderr, "Warning: delta time is too high! (%.3fs).\n", dt);
@@ -118,9 +90,6 @@ int main() {
slowFrames = 0;
}

game.update(dt);

// Call tick TICK_RATE times per second
tickAcc += dt;
while (tickAcc >= 1.0 / TICK_RATE) {
tickAcc -= 1.0 / TICK_RATE;
@@ -128,17 +97,9 @@ int main() {
}
}

ImGui::SFML::Update(window, sf::seconds(dt));
ImGui::Begin("Test Window");
ImGui::Button("No.");
ImGui::End();
ImGui::ShowTestWindow();

window.clear();
game.draw();
ImGui::SFML::Render(window);
window.display();
SDL_UpdateWindowSurface(window.get());
}

return 0;
return EXIT_SUCCESS;
}

Loading…
Cancel
Save