assets/tiles/grass.png | assets/tiles/grass.png | ||||
assets/tiles/air.png | assets/tiles/air.png | ||||
assets/tiles/stone.png | assets/tiles/stone.png | ||||
assets/tiles/dirt.png) | |||||
assets/tiles/dirt.png | |||||
assets/tiles/tree-trunk.png) | |||||
foreach(a ${assets}) | foreach(a ${assets}) | ||||
configure_file("${a}" "${a}" COPYONLY) | configure_file("${a}" "${a}" COPYONLY) | ||||
endforeach(a) | endforeach(a) |
}; | }; | ||||
WGDefault(Swan::World &world): | WGDefault(Swan::World &world): | ||||
tGrass_(world.getTileID("core::grass")), tDirt_(world.getTileID("core::dirt")), | |||||
tGrass_(world.getTileID("core::tree-trunk")), tDirt_(world.getTileID("core::dirt")), | |||||
tStone_(world.getTileID("core::stone")), tAir_(world.getTileID("core::air")) {} | tStone_(world.getTileID("core::stone")), tAir_(world.getTileID("core::air")) {} | ||||
void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override; | void genChunk(Swan::WorldPlane &plane, Swan::Chunk &chunk) override; |
mod.registerImage({ "stone", "tiles/stone.png" }); | mod.registerImage({ "stone", "tiles/stone.png" }); | ||||
mod.registerImage({ "dirt", "tiles/dirt.png" }); | mod.registerImage({ "dirt", "tiles/dirt.png" }); | ||||
mod.registerImage({ "grass", "tiles/grass.png" }); | mod.registerImage({ "grass", "tiles/grass.png" }); | ||||
mod.registerImage({ "tree-trunk", "tiles/tree-trunk.png" }); | |||||
mod.registerImage({ "player-running", "entities/player-running.png", 64 }); | mod.registerImage({ "player-running", "entities/player-running.png", 64 }); | ||||
mod.registerImage({ "player-still", "entities/player-still.png", 64 }); | mod.registerImage({ "player-still", "entities/player-still.png", 64 }); | ||||
.image = "core::grass", | .image = "core::grass", | ||||
.dropped_item = "core::dirt", | .dropped_item = "core::dirt", | ||||
}); | }); | ||||
mod.registerTile({ | |||||
.name = "tree-trunk", | |||||
.image = "core::tree-trunk", | |||||
.dropped_item = "core::tree-trunk", | |||||
}); | |||||
mod.registerItem({ | mod.registerItem({ | ||||
.name = "stone", | .name = "stone", | ||||
.name = "grass", | .name = "grass", | ||||
.image = "core::grass", | .image = "core::grass", | ||||
}); | }); | ||||
mod.registerItem({ | |||||
.name = "tree-trunk", | |||||
.image = "core::tree-trunk", | |||||
}); | |||||
mod.registerWorldGen("default", std::make_unique<WGDefault::Factory>()); | mod.registerWorldGen("default", std::make_unique<WGDefault::Factory>()); | ||||
src/ItemStack.cc | src/ItemStack.cc | ||||
src/Mod.cc | src/Mod.cc | ||||
src/OS.cc | src/OS.cc | ||||
src/PerfCounter.cc | |||||
src/Resource.cc | src/Resource.cc | ||||
src/SRF.cc | src/SRF.cc | ||||
src/Tile.cc | src/Tile.cc |
namespace Swan { | |||||
#include "util.h" | |||||
#include <array> | |||||
namespace Swan { | |||||
class PerfCounter { | class PerfCounter { | ||||
public: | public: | ||||
template<typename T = double, size_t size = 64> | |||||
class Counter { | class Counter { | ||||
public: | public: | ||||
void count(double val) { | |||||
latest_ = val; | |||||
if (count_ >= 60) { | |||||
sum_ -= avg(); | |||||
sum_ += val; | |||||
} else { | |||||
sum_ += val; | |||||
count_ += 1; | |||||
} | |||||
void count(T val) { | |||||
buf_[idx_] = val; | |||||
idx_ = (idx_ + 1) % size; | |||||
} | } | ||||
double avg() { return sum_ / count_; } | |||||
double latest() { return latest_; } | |||||
// Fill a buffer with data, in the order they were written | |||||
template<typename DestT = T> | |||||
void fill(std::array<DestT, size> &buf) { | |||||
size_t r = idx_; | |||||
size_t w = 0; | |||||
do { | |||||
buf[w++] = (DestT)buf_[r]; | |||||
r = (r + 1) % size; | |||||
} while (r != idx_); | |||||
} | |||||
private: | private: | ||||
double latest_ = 0; | |||||
double sum_ = 0; | |||||
int count_ = 0; | |||||
T buf_[size] = {}; | |||||
size_t idx_ = 0; | |||||
}; | }; | ||||
void render(); | |||||
void countFrameTime(double secs) { frame_time_.count(secs); } | void countFrameTime(double secs) { frame_time_.count(secs); } | ||||
void countGameUpdate(double secs) { game_update_.count(secs); } | void countGameUpdate(double secs) { game_update_.count(secs); } | ||||
void countGameTick(double secs) { game_tick_.count(secs); } | void countGameTick(double secs) { game_tick_.count(secs); } | ||||
void countMemoryUsage(double bytes) { memory_usage_.count(bytes); } | void countMemoryUsage(double bytes) { memory_usage_.count(bytes); } | ||||
private: | private: | ||||
Counter frame_time_; | |||||
Counter game_update_; | |||||
Counter game_tick_; | |||||
Counter game_draw_; | |||||
Counter game_updates_per_frame_; | |||||
Counter render_present_; | |||||
Counter memory_usage_; | |||||
Counter<> frame_time_; | |||||
Counter<> game_update_; | |||||
Counter<> game_tick_; | |||||
Counter<> game_draw_; | |||||
Counter<> game_updates_per_frame_; | |||||
Counter<> render_present_; | |||||
Counter<> memory_usage_; | |||||
}; | }; | ||||
} | } |
info << "Using renderer: " << rinfo_.name; | 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() { | Vec2 getSize() { | ||||
int w, h; | int w, h; | ||||
SDL_GetWindowSize(window_, &w, &h); | SDL_GetWindowSize(window_, &w, &h); |
#include <memory> | #include <memory> | ||||
#include <chrono> | #include <chrono> | ||||
#include <type_traits> | #include <type_traits> | ||||
#include <stddef.h> | |||||
namespace Swan { | namespace Swan { | ||||
#include "PerfCounter.h" | #include "PerfCounter.h" | ||||
#include <imgui.h> | |||||
#include "util.h" | |||||
namespace Swan { | |||||
void PerfCounter::render() { | |||||
Deferred win([]{ ImGui::End(); }); | |||||
if (!ImGui::Begin("Perf Stats")) | |||||
return; | |||||
ImGui::PushItemWidth(ImGui::GetFontSize() * -12); | |||||
ImGui::Text("Hello World"); | |||||
std::array<float, 64> buf; | |||||
frame_time_.fill(buf); | |||||
ImGui::PlotLines("Frame Time", buf.data(), 64); | |||||
} | |||||
} |
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||||
uint32_t winflags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; | uint32_t winflags = SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; | ||||
uint32_t renderflags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC; | uint32_t renderflags = SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC; | ||||
float gui_scale = 2; | |||||
for (int i = 1; i < argc; ++i) { | for (int i = 1; i < argc; ++i) { | ||||
if (strcmp(argv[i], "--lodpi") == 0) { | if (strcmp(argv[i], "--lodpi") == 0) { | ||||
SDL_CreateWindow( | SDL_CreateWindow( | ||||
"Project: SWAN", | "Project: SWAN", | ||||
SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, | SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, | ||||
640, 480, winflags), | |||||
(int)(640 * gui_scale), (int)(480 * gui_scale), winflags), | |||||
SDL_DestroyWindow); | SDL_DestroyWindow); | ||||
// Load and display application icon | // Load and display application icon | ||||
SDL_DestroyRenderer); | SDL_DestroyRenderer); | ||||
sdlassert(renderer, "Could not create renderer"); | sdlassert(renderer, "Could not create renderer"); | ||||
Win win(window.get(), renderer.get(), 2); | |||||
Win win(window.get(), renderer.get(), gui_scale); | |||||
// Init ImGUI and ImGUI_SDL | // Init ImGUI and ImGUI_SDL | ||||
IMGUI_CHECKVERSION(); | IMGUI_CHECKVERSION(); | ||||
ImGui::CreateContext(); | ImGui::CreateContext(); | ||||
auto imgui = makeDeferred([] { ImGui::DestroyContext(); }); | auto imgui = makeDeferred([] { ImGui::DestroyContext(); }); | ||||
ImGuiSDL::Initialize(renderer.get(), 640, 480); | |||||
ImGuiSDL::Initialize(renderer.get(), (int)win.getPixSize().x, (int)win.getPixSize().y); | |||||
auto imgui_sdl = makeDeferred([] { ImGuiSDL::Deinitialize(); }); | auto imgui_sdl = makeDeferred([] { ImGuiSDL::Deinitialize(); }); | ||||
info << "Initialized with window size " << win.getPixSize(); | |||||
// ImGuiIO is to glue SDL and ImGUI together | // ImGuiIO is to glue SDL and ImGUI together | ||||
ImGuiIO& imgui_io = ImGui::GetIO(); | ImGuiIO& imgui_io = ImGui::GetIO(); | ||||
// ImGUI | // ImGUI | ||||
imgui_io.DeltaTime = dt; | imgui_io.DeltaTime = dt; | ||||
ImGui::NewFrame(); | ImGui::NewFrame(); | ||||
ImGui::ShowDemoWindow(); | |||||
RTClock draw_clock; | RTClock draw_clock; | ||||
game.draw(); | game.draw(); | ||||
pcounter.countGameDraw(draw_clock.duration()); | pcounter.countGameDraw(draw_clock.duration()); | ||||
pcounter.countFrameTime(total_frame_clock.duration()); | pcounter.countFrameTime(total_frame_clock.duration()); | ||||
pcounter.render(); | |||||
// Render ImGUI | // Render ImGUI | ||||
ImGui::Render(); | ImGui::Render(); | ||||
ImGuiSDL::Render(ImGui::GetDrawData()); | ImGuiSDL::Render(ImGui::GetDrawData()); | ||||
// ImGuiSDL changes renderer draw color... | |||||
SDL_SetRenderDrawColor(renderer.get(), 0, 0, 0, 255); | |||||
RTClock present_clock; | RTClock present_clock; | ||||
SDL_RenderPresent(renderer.get()); | SDL_RenderPresent(renderer.get()); | ||||
pcounter.countRenderPresent(present_clock.duration()); | pcounter.countRenderPresent(present_clock.duration()); |