void onResize(int w, int h); | void onResize(int w, int h); | ||||
SwanCommon::Vec2i size() { return { w_, h_ }; } | SwanCommon::Vec2i size() { return { w_, h_ }; } | ||||
SDL_Window *getWindow(); | |||||
SDL_Window *sdlWindow(); | |||||
private: | private: | ||||
std::unique_ptr<WindowState> state_; | std::unique_ptr<WindowState> state_; |
const unsigned char *bytes = (const unsigned char *)data; | const unsigned char *bytes = (const unsigned char *)data; | ||||
size_t x = tileId % state_->tilesPerLine; | size_t x = tileId % state_->tilesPerLine; | ||||
size_t y = tileId / state_->tilesPerLine; | size_t y = tileId / state_->tilesPerLine; | ||||
std::cerr << "Tile " << tileId << " to " << x << ", " << y << '\n'; | |||||
if (state_->width <= x) { | if (state_->width <= x) { | ||||
state_->width = x + 1; | state_->width = x + 1; |
glCheck(); | glCheck(); | ||||
} | } | ||||
SDL_Window *Window::getWindow() { | |||||
SDL_Window *Window::sdlWindow() { | |||||
return state_->window; | return state_->window; | ||||
} | } | ||||
src/gfxutil.cc | src/gfxutil.cc | ||||
src/ItemStack.cc | src/ItemStack.cc | ||||
src/LightServer.cc | src/LightServer.cc | ||||
src/Mod.cc | |||||
src/OS.cc | src/OS.cc | ||||
src/World.cc | src/World.cc | ||||
src/WorldPlane.cc) | src/WorldPlane.cc) |
namespace Swan { | namespace Swan { | ||||
class ModWrapper; | |||||
class Mod { | class Mod { | ||||
public: | public: | ||||
Mod(std::string name): name_(std::move(name)) {} | Mod(std::string name): name_(std::move(name)) {} | ||||
virtual ~Mod() = default; | virtual ~Mod() = default; | ||||
void registerTile(Tile::Builder tile); | |||||
void registerItem(Item::Builder item); | |||||
void registerWorldGen(std::string name, std::unique_ptr<WorldGen::Factory> gen); | |||||
void registerSprite(std::string sprite); | |||||
void registerTile(Tile::Builder tile) { tiles_.push_back(tile); } | |||||
void registerItem(Item::Builder item) { items_.push_back(item); } | |||||
void registerSprite(std::string sprite) { sprites_.push_back(sprite); } | |||||
template<typename WG> | template<typename WG> | ||||
void registerWorldGen(std::string name) { | void registerWorldGen(std::string name) { | ||||
worldGens_.push_back(WorldGen::Factory{ | worldGens_.push_back(WorldGen::Factory{ | ||||
.name = name_ + "::" + name, | |||||
.name = name, | |||||
.create = [](World &world) -> std::unique_ptr<WorldGen> { | .create = [](World &world) -> std::unique_ptr<WorldGen> { | ||||
return std::make_unique<WG>(world); | return std::make_unique<WG>(world); | ||||
} | } | ||||
std::is_move_constructible_v<Ent>, | std::is_move_constructible_v<Ent>, | ||||
"Entities must be movable"); | "Entities must be movable"); | ||||
entities_.push_back(EntityCollection::Factory{ | entities_.push_back(EntityCollection::Factory{ | ||||
.name = name_ + "::" + name, | |||||
.name = name, | |||||
.create = [](std::string name) -> std::unique_ptr<EntityCollection> { | .create = [](std::string name) -> std::unique_ptr<EntityCollection> { | ||||
return std::make_unique<EntityCollectionImpl<Ent>>(std::move(name)); | return std::make_unique<EntityCollectionImpl<Ent>>(std::move(name)); | ||||
} | } | ||||
}); | }); | ||||
} | } | ||||
private: | |||||
const std::string name_; | const std::string name_; | ||||
std::vector<std::string> images_; | |||||
std::vector<Tile::Builder> tiles_; | std::vector<Tile::Builder> tiles_; | ||||
std::vector<Item::Builder> items_; | std::vector<Item::Builder> items_; | ||||
std::vector<std::string> sprites_; | std::vector<std::string> sprites_; | ||||
std::vector<WorldGen::Factory> worldGens_; | std::vector<WorldGen::Factory> worldGens_; | ||||
std::vector<EntityCollection::Factory> entities_; | std::vector<EntityCollection::Factory> entities_; | ||||
friend ModWrapper; | |||||
}; | }; | ||||
class ModWrapper { | class ModWrapper { | ||||
mod_.reset(); | mod_.reset(); | ||||
} | } | ||||
const std::string &name() { return mod_->name_; } | |||||
const std::vector<Tile::Builder> &tiles() { return mod_->tiles_; } | |||||
const std::vector<Item::Builder> &items() { return mod_->items_; } | |||||
const std::vector<std::string> &sprites() { return mod_->sprites_; } | |||||
const std::vector<WorldGen::Factory> &worldGens() { return mod_->worldGens_; } | |||||
const std::vector<EntityCollection::Factory> &entities() { return mod_->entities_; } | |||||
std::unique_ptr<Mod> mod_; | std::unique_ptr<Mod> mod_; | ||||
std::string path_; | std::string path_; | ||||
OS::Dynlib dynlib_; | OS::Dynlib dynlib_; |
return *this; | return *this; | ||||
} | } | ||||
operator bool() { return isOk_; } | |||||
explicit operator bool() { return isOk_; } | |||||
bool isOk() { return isOk_; } | bool isOk() { return isOk_; } | ||||
Err &err() { return v_.err; } | Err &err() { return v_.err; } |
void Game::draw() { | void Game::draw() { | ||||
world_->draw(renderer_); | world_->draw(renderer_); | ||||
renderer_.draw(cam_); | |||||
info << "Rendered cam pos " << cam_.pos << " size " << cam_.size << " zoom " << cam_.zoom; | |||||
} | } | ||||
void Game::update(float dt) { | void Game::update(float dt) { |
#include "Mod.h" | |||||
#include <stdio.h> | |||||
#include <algorithm> | |||||
#include "util.h" | |||||
#include "log.h" | |||||
namespace Swan { | |||||
void Mod::registerTile(Tile::Builder tile) { | |||||
tiles_.push_back(tile); | |||||
info << " Adding tile: " << name_ << "::" << tile.name; | |||||
} | |||||
void Mod::registerItem(Item::Builder item) { | |||||
items_.push_back(item); | |||||
info << " Adding item: " << name_ << "::" << item.name; | |||||
} | |||||
void Mod::registerSprite(std::string path) { | |||||
sprites_.push_back(path); | |||||
info << "Adding sprite: " << name_ << "::" << path; | |||||
} | |||||
} |
// "core::stone", we need to know which directory the "core" mod is in | // "core::stone", we need to know which directory the "core" mod is in | ||||
std::unordered_map<std::string, std::string> modPaths; | std::unordered_map<std::string, std::string> modPaths; | ||||
for (auto &mod: mods_) { | for (auto &mod: mods_) { | ||||
modPaths[mod.mod_->name_] = mod.path_; | |||||
modPaths[mod.name()] = mod.path_; | |||||
} | } | ||||
auto loadTileImage = [&](std::string path) -> Result<ImageAsset> { | auto loadTileImage = [&](std::string path) -> Result<ImageAsset> { | ||||
// In the rendering system, there's no real difference between a tile | // In the rendering system, there's no real difference between a tile | ||||
// and an item. | // and an item. | ||||
for (auto &mod: mods_) { | for (auto &mod: mods_) { | ||||
for (auto &tileBuilder: mod.mod_->tiles_) { | |||||
for (auto &tileBuilder: mod.tiles()) { | |||||
auto image = loadTileImage(tileBuilder.image); | auto image = loadTileImage(tileBuilder.image); | ||||
std::string tileName = mod.mod_->name_ + "::" + tileBuilder.name; | |||||
std::string tileName = mod.name() + "::" + tileBuilder.name; | |||||
Tile::ID tileId = tiles_.size(); | Tile::ID tileId = tiles_.size(); | ||||
if (image) { | if (image) { | ||||
// Load all items which aren't just tiles in disguise. | // Load all items which aren't just tiles in disguise. | ||||
for (auto &mod: mods_) { | for (auto &mod: mods_) { | ||||
for (auto &itemBuilder: mod.mod_->items_) { | |||||
for (auto &itemBuilder: mod.items()) { | |||||
auto image = loadTileImage(itemBuilder.image); | auto image = loadTileImage(itemBuilder.image); | ||||
std::string itemName = mod.mod_->name_ + "::" + itemBuilder.name; | |||||
std::string itemName = mod.name() + "::" + itemBuilder.name; | |||||
Tile::ID itemId = nextItemId++; | Tile::ID itemId = nextItemId++; | ||||
if (image) { | if (image) { | ||||
// Load sprites | // Load sprites | ||||
for (auto &mod: mods_) { | for (auto &mod: mods_) { | ||||
for (auto spritePath: mod.mod_->sprites_) { | |||||
std::string path = mod.mod_->name_ + "::" + spritePath; | |||||
for (auto spritePath: mod.sprites()) { | |||||
std::string path = mod.name() + "::" + spritePath; | |||||
auto image = loadImageAsset(modPaths, path); | auto image = loadImageAsset(modPaths, path); | ||||
if (image) { | if (image) { | ||||
// Load world gens and entities | // Load world gens and entities | ||||
for (auto &mod: mods_) { | for (auto &mod: mods_) { | ||||
for (auto &worldGenFactory: mod.mod_->worldGens_) { | |||||
std::string name = mod.mod_->name_ + "::" + worldGenFactory.name; | |||||
for (auto &worldGenFactory: mod.worldGens()) { | |||||
std::string name = mod.name() + "::" + worldGenFactory.name; | |||||
worldGenFactories_.emplace(name, worldGenFactory); | worldGenFactories_.emplace(name, worldGenFactory); | ||||
} | } | ||||
for (auto &entCollFactory: mod.mod_->entities_) { | |||||
std::string name = mod.mod_->name_ + "::" + entCollFactory.name; | |||||
for (auto &entCollFactory: mod.entities()) { | |||||
std::string name = mod.name() + "::" + entCollFactory.name; | |||||
entCollFactories_.emplace(name, entCollFactory); | entCollFactories_.emplace(name, entCollFactory); | ||||
} | } | ||||
} | } |
} | } | ||||
auto modPart = path.substr(0, sep); | auto modPart = path.substr(0, sep); | ||||
auto pathPart = path.substr(sep, path.size() - sep - 2); | |||||
auto pathPart = path.substr(sep + 2, path.size() - sep - 2); | |||||
auto modPath = modPaths.find(modPart); | auto modPath = modPaths.find(modPart); | ||||
if (modPath == modPaths.end()) { | if (modPath == modPaths.end()) { | ||||
}; | }; | ||||
// TODO: Pixel formats? | // TODO: Pixel formats? | ||||
asset.data.reset(); | |||||
for (size_t y = 0; y < (size_t)surface->h; ++y) { | for (size_t y = 0; y < (size_t)surface->h; ++y) { | ||||
unsigned char *src = (unsigned char *)surface->pixels + y * surface->pitch; | unsigned char *src = (unsigned char *)surface->pixels + y * surface->pitch; | ||||
unsigned char *dest = asset.data.get() + y * surface->w * 4; | unsigned char *dest = asset.data.get() + y * surface->w * 4; |
CPtr<SDL_Surface, SDL_FreeSurface> icon( | CPtr<SDL_Surface, SDL_FreeSurface> icon( | ||||
IMG_Load("assets/icon.png")); | IMG_Load("assets/icon.png")); | ||||
sdlassert(icon, "Could not load icon"); | sdlassert(icon, "Could not load icon"); | ||||
SDL_SetWindowIcon(window.getWindow(), icon.get()); | |||||
SDL_SetWindowIcon(window.sdlWindow(), icon.get()); | |||||
// Init ImGUI and ImGUI_SDL | // Init ImGUI and ImGUI_SDL | ||||
/* | |||||
IMGUI_CHECKVERSION(); | IMGUI_CHECKVERSION(); | ||||
CPtr<ImGuiContext, ImGui::DestroyContext> context( | CPtr<ImGuiContext, ImGui::DestroyContext> context( | ||||
ImGui::CreateContext()); | ImGui::CreateContext()); | ||||
/* | |||||
ImGuiSDL::Initialize(renderer.get(), (int)win.getPixSize().x, (int)win.getPixSize().y); | ImGuiSDL::Initialize(renderer.get(), (int)win.getPixSize().x, (int)win.getPixSize().y); | ||||
Deferred<ImGuiSDL::Deinitialize> imguiSDL; | Deferred<ImGuiSDL::Deinitialize> imguiSDL; | ||||
info << "Initialized with window size " << win.getPixSize(); | info << "Initialized with window size " << win.getPixSize(); | ||||
TODO */ | |||||
// ImGuiIO is to glue SDL and ImGUI together | // ImGuiIO is to glue SDL and ImGUI together | ||||
ImGuiIO& imguiIO = ImGui::GetIO(); | ImGuiIO& imguiIO = ImGui::GetIO(); | ||||
imguiIO.BackendPlatformName = "imgui_sdl + Project: SWAN"; | imguiIO.BackendPlatformName = "imgui_sdl + Project: SWAN"; | ||||
TODO */ | |||||
// Create a world | // Create a world | ||||
Game game; | Game game; | ||||
case SDL_WINDOWEVENT: | case SDL_WINDOWEVENT: | ||||
if (evt.window.event == SDL_WINDOWEVENT_RESIZED) { | if (evt.window.event == SDL_WINDOWEVENT_RESIZED) { | ||||
imguiIO.DisplaySize.x = (float)evt.window.data1; | |||||
imguiIO.DisplaySize.y = (float)evt.window.data2; | |||||
//imguiIO.DisplaySize.x = (float)evt.window.data1; | |||||
//imguiIO.DisplaySize.y = (float)evt.window.data2; | |||||
window.onResize(evt.window.data1, evt.window.data2); | window.onResize(evt.window.data1, evt.window.data2); | ||||
} | } | ||||
break; | break; | ||||
break; | break; | ||||
case SDL_MOUSEMOTION: | case SDL_MOUSEMOTION: | ||||
/* | |||||
imguiIO.MousePos.x = (float)evt.motion.x; | imguiIO.MousePos.x = (float)evt.motion.x; | ||||
imguiIO.MousePos.y = (float)evt.motion.y; | imguiIO.MousePos.y = (float)evt.motion.y; | ||||
if (!imguiIO.WantCaptureMouse) | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onMouseMove(evt.motion.x, evt.motion.y); | game.onMouseMove(evt.motion.x, evt.motion.y); | ||||
break; | break; | ||||
case SDL_MOUSEBUTTONDOWN: | case SDL_MOUSEBUTTONDOWN: | ||||
/* | |||||
imguiIO.MouseDown[sdlButtonToImGuiButton(evt.button.button)] = true; | imguiIO.MouseDown[sdlButtonToImGuiButton(evt.button.button)] = true; | ||||
if (!imguiIO.WantCaptureMouse) | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onMouseDown(evt.button.x, evt.button.y, evt.button.button); | game.onMouseDown(evt.button.x, evt.button.y, evt.button.button); | ||||
break; | break; | ||||
case SDL_MOUSEBUTTONUP: | case SDL_MOUSEBUTTONUP: | ||||
/* | |||||
imguiIO.MouseDown[sdlButtonToImGuiButton(evt.button.button)] = false; | imguiIO.MouseDown[sdlButtonToImGuiButton(evt.button.button)] = false; | ||||
if (!imguiIO.WantCaptureMouse) | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onMouseUp(evt.button.x, evt.button.y, evt.button.button); | game.onMouseUp(evt.button.x, evt.button.y, evt.button.button); | ||||
break; | break; | ||||
case SDL_MOUSEWHEEL: | case SDL_MOUSEWHEEL: | ||||
/* | |||||
imguiIO.MouseWheel += (float)evt.wheel.y; | imguiIO.MouseWheel += (float)evt.wheel.y; | ||||
if (!imguiIO.WantCaptureMouse) | |||||
if (!imguiIO.WantCaptureMouse) */ | |||||
game.onScrollWheel(evt.wheel.y); | game.onScrollWheel(evt.wheel.y); | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
// ImGUI | // ImGUI | ||||
imguiIO.DeltaTime = dt; | |||||
ImGui::NewFrame(); | |||||
//imguiIO.DeltaTime = dt; | |||||
//ImGui::NewFrame(); | |||||
{ | { | ||||
ZoneScopedN("game draw"); | ZoneScopedN("game draw"); | ||||
game.cam_.size = window.size(); | |||||
game.draw(); | game.draw(); | ||||
} | } | ||||
// Render ImGUI | // Render ImGUI | ||||
{ | { | ||||
ZoneScopedN("imgui render"); | ZoneScopedN("imgui render"); | ||||
ImGui::Render(); | |||||
ImGuiSDL::Render(ImGui::GetDrawData()); | |||||
//ImGui::Render(); | |||||
//ImGuiSDL::Render(ImGui::GetDrawData()); | |||||
} | } | ||||
{ | { |