Compare commits
2 Commits
d5531ce370
...
609f7337da
| Author | SHA1 | Date | |
|---|---|---|---|
| 609f7337da | |||
| d700aae02e |
@ -4,7 +4,7 @@
|
||||
namespace ougge {
|
||||
|
||||
Engine::Engine()
|
||||
: gameObjectPool(GAMEOBJECTPOOL_SIZE)
|
||||
: gameObjectPool(GAMEOBJECTPOOL_SIZE), textures(&resourceManager)
|
||||
{
|
||||
}
|
||||
|
||||
@ -17,7 +17,7 @@ void Engine::init(){
|
||||
}
|
||||
|
||||
void Engine::openMainWindow(const std::string& window_title){
|
||||
mainWindow.open(window_title);
|
||||
mainWindow.open(window_title, resourceManager);
|
||||
}
|
||||
|
||||
void Engine::startLoop(){
|
||||
|
||||
101
src/Engine.hpp
101
src/Engine.hpp
@ -1,50 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/function_shared_ptr.hpp"
|
||||
#include "mono/mono.hpp"
|
||||
#include "game/GameObjectPool.hpp"
|
||||
#include "gui/MainWindow.hpp"
|
||||
#include "resources/textures.hpp"
|
||||
|
||||
namespace ougge {
|
||||
|
||||
#define GAMEOBJECTPOOL_SIZE 64*1024
|
||||
|
||||
using UpdateFunc_t = function_shared_ptr<void(f64)>;
|
||||
|
||||
class Engine {
|
||||
bool loop_running = false;
|
||||
|
||||
game::GameObjectPool gameObjectPool;
|
||||
u64 obj_id = 0;
|
||||
MonoClass* gameObjectClass;
|
||||
Mono::Method<void(u64, u32)> gameObjectCtor;
|
||||
Mono::Method<void(f64)> gameObjectInvokeUpdate;
|
||||
Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent;
|
||||
|
||||
public:
|
||||
gui::MainWindow mainWindow;
|
||||
UpdateFunc_t updateCallback;
|
||||
|
||||
Mono::RuntimeJIT mono;
|
||||
std::shared_ptr<Mono::Assembly> engineManagedAssembly;
|
||||
|
||||
resources::CacheStorage<resources::Texture> textures;
|
||||
|
||||
Engine();
|
||||
void init();
|
||||
void openMainWindow(const std::string& window_title);
|
||||
// start game loop on the current thread
|
||||
void startLoop();
|
||||
void stopLoop();
|
||||
|
||||
game::GameObject& createGameObject();
|
||||
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName);
|
||||
|
||||
|
||||
private:
|
||||
void tryDrawFrame(f64 deltaTime);
|
||||
void updateGameObjects(f64 deltaTime);
|
||||
};
|
||||
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include "common/function_shared_ptr.hpp"
|
||||
#include "mono/mono.hpp"
|
||||
#include "game/GameObjectPool.hpp"
|
||||
#include "gui/MainWindow.hpp"
|
||||
#include "resources/textures.hpp"
|
||||
|
||||
namespace ougge {
|
||||
|
||||
#define GAMEOBJECTPOOL_SIZE 64*1024
|
||||
|
||||
using UpdateFunc_t = function_shared_ptr<void(f64)>;
|
||||
|
||||
class Engine {
|
||||
bool loop_running = false;
|
||||
|
||||
game::GameObjectPool gameObjectPool;
|
||||
u64 obj_id = 0;
|
||||
MonoClass* gameObjectClass;
|
||||
Mono::Method<void(u64, u32)> gameObjectCtor;
|
||||
Mono::Method<void(f64)> gameObjectInvokeUpdate;
|
||||
Mono::Method<Mono::Bool(Mono::String)> gameObjectTryCreateComponent;
|
||||
|
||||
public:
|
||||
gui::MainWindow mainWindow;
|
||||
UpdateFunc_t updateCallback;
|
||||
|
||||
Mono::RuntimeJIT mono;
|
||||
std::shared_ptr<Mono::Assembly> engineManagedAssembly;
|
||||
|
||||
resources::ResourceManager resourceManager;
|
||||
resources::CacheStorage<resources::Texture> textures;
|
||||
|
||||
Engine();
|
||||
void init();
|
||||
void openMainWindow(const std::string& window_title);
|
||||
// start game loop on the current thread
|
||||
void startLoop();
|
||||
void stopLoop();
|
||||
|
||||
game::GameObject& createGameObject();
|
||||
bool tryCreateComponent(game::GameObject& obj, const std::string& componentClassName);
|
||||
|
||||
|
||||
private:
|
||||
void tryDrawFrame(f64 deltaTime);
|
||||
void updateGameObjects(f64 deltaTime);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@ -4,8 +4,6 @@
|
||||
#include "MainWindow.hpp"
|
||||
#include "gui_exceptions.hpp"
|
||||
#include "../common/ougge_format.hpp"
|
||||
#include "../resources/fonts.hpp"
|
||||
#include "../resources/textures.hpp"
|
||||
#include "../common/math.hpp"
|
||||
|
||||
namespace ougge::gui {
|
||||
@ -21,7 +19,7 @@ f32 MainWindow::getDPI(){
|
||||
return dpi;
|
||||
}
|
||||
|
||||
void MainWindow::open(const std::string& window_title){
|
||||
void MainWindow::open(const std::string& window_title, resources::ResourceManager& resourceManager){
|
||||
SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING));
|
||||
SDL_version v;
|
||||
SDL_GetVersion(&v);
|
||||
@ -72,8 +70,12 @@ void MainWindow::open(const std::string& window_title){
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
resources::ResourceFactory* font_res = resourceManager.tryGetResource(default_font_path);
|
||||
if(font_res == nullptr)
|
||||
throw UsefulException("can't find default font resource");
|
||||
f32 dpi = getDPI();
|
||||
io.FontDefault = resources::ImFont_LoadFromResource(default_font, default_font_size, dpi);
|
||||
io.FontDefault = resources::ImFont_LoadFromResource(font_res, default_font_size, dpi);
|
||||
}
|
||||
|
||||
void MainWindow::close(){
|
||||
|
||||
@ -1,45 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <imgui.h>
|
||||
#include "../common/std.hpp"
|
||||
#include "../common/time.hpp"
|
||||
|
||||
/// converts hex color to float vector
|
||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
||||
/// converts float vector to hex color
|
||||
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
|
||||
|
||||
namespace ougge::gui {
|
||||
|
||||
#define default_font "DroidSans"
|
||||
|
||||
class MainWindow {
|
||||
public:
|
||||
i32 fps_max = 60;
|
||||
f32 default_font_size = 14.0f;
|
||||
ImVec4 clear_color = RGBAHexToF(35,35,50,255);
|
||||
SDL_Window* sdl_window = nullptr;
|
||||
SDL_Renderer* sdl_renderer = nullptr;
|
||||
|
||||
private:
|
||||
bool show_debug_window = true;
|
||||
bool show_demo_window = false;
|
||||
bool show_metrics_window = false;
|
||||
|
||||
public:
|
||||
void open(const std::string& window_title);
|
||||
void close();
|
||||
|
||||
/// process io events happened since previous frame
|
||||
void pollEvents(bool* loopRunning);
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
|
||||
f32 getDPI();
|
||||
private:
|
||||
void draw_debug_window();
|
||||
void draw_bg_window();
|
||||
};
|
||||
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <imgui.h>
|
||||
#include "../common/std.hpp"
|
||||
#include "../common/time.hpp"
|
||||
#include "../resources/resources.hpp"
|
||||
#include "../resources/fonts.hpp"
|
||||
|
||||
/// converts hex color to float vector
|
||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
||||
/// converts float vector to hex color
|
||||
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
|
||||
|
||||
namespace ougge::gui {
|
||||
|
||||
#define default_font_path "fonts/DroidSans.ttf"
|
||||
|
||||
class MainWindow {
|
||||
public:
|
||||
i32 fps_max = 60;
|
||||
f32 default_font_size = 14.0f;
|
||||
ImVec4 clear_color = RGBAHexToF(35,35,50,255);
|
||||
SDL_Window* sdl_window = nullptr;
|
||||
SDL_Renderer* sdl_renderer = nullptr;
|
||||
|
||||
private:
|
||||
bool show_debug_window = true;
|
||||
bool show_demo_window = false;
|
||||
bool show_metrics_window = false;
|
||||
|
||||
public:
|
||||
void open(const std::string& window_title, resources::ResourceManager& resourceManager);
|
||||
void close();
|
||||
|
||||
/// process io events happened since previous frame
|
||||
void pollEvents(bool* loopRunning);
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
|
||||
f32 getDPI();
|
||||
private:
|
||||
void draw_debug_window();
|
||||
void draw_bg_window();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
40
src/Resources/MemorySteam.cpp
Normal file
40
src/Resources/MemorySteam.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "MemoryStream.hpp"
|
||||
|
||||
class MemoryStreamBuf : public std::streambuf {
|
||||
public:
|
||||
MemoryStreamBuf(void* p, const std::size_t n);
|
||||
|
||||
virtual std::istream::pos_type seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which);
|
||||
};
|
||||
|
||||
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
|
||||
char* p=(char*)_p;
|
||||
setg(p, p, p + n);
|
||||
setp(p, p + n);
|
||||
}
|
||||
|
||||
std::istream::pos_type MemoryStreamBuf::seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
if (dir == std::ios_base::cur)
|
||||
gbump(off);
|
||||
else if (dir == std::ios_base::end)
|
||||
setg(eback(), egptr() + off, egptr());
|
||||
else if (dir == std::ios_base::beg)
|
||||
setg(eback(), eback() + off, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
|
||||
|
||||
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
|
||||
: std::istream(new MemoryStreamBuf((void*)p, n))
|
||||
{}
|
||||
|
||||
MemoryStreamRead::~MemoryStreamRead(){
|
||||
delete rdbuf();
|
||||
}
|
||||
8
src/Resources/MemoryStream.hpp
Normal file
8
src/Resources/MemoryStream.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
class MemoryStreamRead : public std::istream {
|
||||
public:
|
||||
MemoryStreamRead(const void* p, const std::size_t n);
|
||||
|
||||
virtual ~MemoryStreamRead();
|
||||
};
|
||||
@ -1,94 +0,0 @@
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include "../common/UsefulException.hpp"
|
||||
#include "../common/ougge_format.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "embedded_resources.h"
|
||||
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
Resource::Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func)
|
||||
: path(path), size(size), openStream(open_read_steam_func)
|
||||
{}
|
||||
|
||||
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
|
||||
char* p=(char*)_p;
|
||||
setg(p, p, p + n);
|
||||
setp(p, p + n);
|
||||
}
|
||||
|
||||
std::istream::pos_type MemoryStreamBuf::seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
if (dir == std::ios_base::cur)
|
||||
gbump(off);
|
||||
else if (dir == std::ios_base::end)
|
||||
setg(eback(), egptr() + off, egptr());
|
||||
else if (dir == std::ios_base::beg)
|
||||
setg(eback(), eback() + off, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
|
||||
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
|
||||
: std::istream(new MemoryStreamBuf((void*)p, n))
|
||||
{}
|
||||
|
||||
MemoryStreamRead::~MemoryStreamRead(){
|
||||
delete rdbuf();
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, Resource>* _resourceMap = nullptr;
|
||||
|
||||
void loadEmbeddedresources(){
|
||||
for(int i = 0; i < EmbeddedResource_table_count; i++){
|
||||
const EmbeddedResource& e = EmbeddedResource_table[i];
|
||||
std::cout <<"loading resource '" << e.path << "' "
|
||||
<< formatSizeHumanReadable(e.size) << std::endl;
|
||||
|
||||
auto embedded_resource_factory = [e]() -> std::unique_ptr<std::istream> {
|
||||
return std::make_unique<MemoryStreamRead>(e.data, e.size);
|
||||
};
|
||||
|
||||
auto r = _resourceMap->emplace(e.path,
|
||||
Resource(e.path, e.size, embedded_resource_factory));
|
||||
if(!r.second)
|
||||
throw UsefulException(ougge_format("can't load duplicate resource '%s'", e.path));
|
||||
}
|
||||
}
|
||||
|
||||
void init(){
|
||||
if(_resourceMap != nullptr)
|
||||
throw UsefulException("resource has been initialized already");
|
||||
_resourceMap = new std::unordered_map<std::string, Resource>();
|
||||
loadEmbeddedresources();
|
||||
}
|
||||
|
||||
Resource& getResource(const std::string& path){
|
||||
auto it = _resourceMap->find(path);
|
||||
if(it == _resourceMap->end())
|
||||
throw UsefulException(ougge_format("can't find resource '%s'", path.c_str()));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::string formatSizeHumanReadable(std::size_t b){
|
||||
std::stringstream ss;
|
||||
ss.precision(3);
|
||||
std::size_t k = b / 1024;
|
||||
std::size_t m = k / 1024;
|
||||
std::size_t g = m / 1024;
|
||||
|
||||
if(g)
|
||||
ss<<m / 1024.0f<<'G';
|
||||
else if(m)
|
||||
ss<<k / 1024.0f<<'M';
|
||||
else if(k)
|
||||
ss<<b / 1024.0f<<'K';
|
||||
else ss<<b;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,63 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "../common/std.hpp"
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
// call this in main()
|
||||
void init();
|
||||
|
||||
std::string formatSizeHumanReadable(std::size_t byte_n);
|
||||
|
||||
class Resource {
|
||||
public:
|
||||
const std::string path;
|
||||
const std::size_t size;
|
||||
|
||||
using StreamFactoryMethod = std::function< std::unique_ptr<std::istream> () >;
|
||||
|
||||
Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func);
|
||||
|
||||
const StreamFactoryMethod openStream;
|
||||
};
|
||||
|
||||
class MemoryStreamBuf : public std::streambuf {
|
||||
public:
|
||||
MemoryStreamBuf(void* p, const std::size_t n);
|
||||
|
||||
virtual std::istream::pos_type seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which);
|
||||
};
|
||||
|
||||
class MemoryStreamRead : public std::istream {
|
||||
public:
|
||||
MemoryStreamRead(const void* p, const std::size_t n);
|
||||
|
||||
virtual ~MemoryStreamRead();
|
||||
};
|
||||
|
||||
Resource& getResource(const std::string& path);
|
||||
|
||||
/// @brief stores requested resources in memory
|
||||
/// @tparam T must implement constructor `T(const Resource&, ...)`
|
||||
template<class T>
|
||||
class CacheStorage {
|
||||
std::unordered_map<std::string, T> _map;
|
||||
|
||||
public:
|
||||
template<typename... TCtorArgs>
|
||||
T& getOrCreate(const std::string& name, TCtorArgs&&... ctor_args){
|
||||
auto it = _map.find(name);
|
||||
if(it != _map.end())
|
||||
return it->second;
|
||||
auto& res = getResource(name);
|
||||
auto e = _map.emplace(name, T(res, ctor_args...));
|
||||
return e.first->second;
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -1,7 +1,4 @@
|
||||
#include <imgui.h>
|
||||
#include "resources.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "fonts.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
@ -16,17 +13,16 @@ ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi
|
||||
return io.Fonts->AddFontFromFileTTF(file_path.c_str(), font_size, nullptr, glyph_ranges);
|
||||
}
|
||||
|
||||
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi){
|
||||
ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi){
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
font_size *= dpi;
|
||||
ImFontConfig font_cfg = ImFontConfig();
|
||||
std::sprintf(font_cfg.Name, "%s %ipx", font_name.c_str(), (i32)font_size);
|
||||
std::sprintf(font_cfg.Name, "%s %ipx", res->path.c_str(), (i32)font_size);
|
||||
|
||||
auto& res = getResource("fonts/" + font_name + ".ttf");
|
||||
char* font_data = new char[res.size];
|
||||
res.openStream()->read(font_data, res.size);
|
||||
char* font_data = new char[res->size];
|
||||
res->openStream()->read(font_data, res->size);
|
||||
|
||||
return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res.size,
|
||||
return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res->size,
|
||||
font_size, &font_cfg, glyph_ranges);
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
#include <imgui.h>
|
||||
#include "../common/std.hpp"
|
||||
#include "resources.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi);
|
||||
|
||||
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi);
|
||||
ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi);
|
||||
|
||||
}
|
||||
|
||||
@ -1,96 +0,0 @@
|
||||
#include "textures.hpp"
|
||||
#include <SDL_image.h>
|
||||
#include "../gui/gui_exceptions.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
Texture::Texture(const Resource& r, SDL_Renderer* renderer)
|
||||
: Texture(*r.openStream(), r.size, renderer)
|
||||
{}
|
||||
|
||||
Texture::Texture(std::istream& s, size_t size, SDL_Renderer* renderer)
|
||||
: renderer(renderer), texture(nullptr), w(0), h(0)
|
||||
{
|
||||
SDL_RWops* sdl_stream = SDL_RWFromIStream(s, size);
|
||||
if(!sdl_stream)
|
||||
throw gui::SDLException();
|
||||
texture = std::shared_ptr<SDL_Texture>(IMG_LoadTexture_RW(renderer, sdl_stream, 1), SDL_DestroyTexture);
|
||||
if(!texture)
|
||||
throw gui::IMGException();
|
||||
SDL_TRY(SDL_QueryTexture(texture.get(), nullptr, nullptr, &w, &h));
|
||||
}
|
||||
|
||||
SDL_RenderCopyExF_Params::SDL_RenderCopyExF_Params()
|
||||
: rotation_angle(0), flip(SDL_FLIP_NONE)
|
||||
{}
|
||||
|
||||
void Texture::render(const SDL_FRect& target_section){
|
||||
SDL_TRY(
|
||||
SDL_RenderCopyF(renderer, texture.get(), nullptr, &target_section)
|
||||
);
|
||||
}
|
||||
|
||||
void Texture::render(const SDL_FRect& target_section, const SDL_Rect& texture_section){
|
||||
SDL_TRY(
|
||||
SDL_RenderCopyF(renderer, texture.get(), &texture_section, &target_section)
|
||||
);
|
||||
}
|
||||
|
||||
void Texture::render(const SDL_RenderCopyExF_Params& p){
|
||||
SDL_TRY(
|
||||
SDL_RenderCopyExF(renderer, texture.get(),
|
||||
optional_value_ptr_or_null(p.texture_section),
|
||||
optional_value_ptr_or_null(p.target_section),
|
||||
-1.0f * angleToDegree(normalizeAngle(p.rotation_angle)),
|
||||
optional_value_ptr_or_null(p.rotation_center),
|
||||
p.flip
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
static Sint64 istream_size(SDL_RWops* context){
|
||||
return (Sint64)(size_t)context->hidden.unknown.data2;
|
||||
}
|
||||
|
||||
static Sint64 istream_seek(SDL_RWops* context, Sint64 offset, i32 whence){
|
||||
std::istream* stream = (std::istream*)context->hidden.unknown.data1;
|
||||
switch(whence){
|
||||
case SEEK_SET: stream->seekg(offset, std::ios::beg); break;
|
||||
case SEEK_CUR: stream->seekg(offset, std::ios::cur); break;
|
||||
case SEEK_END: stream->seekg(offset, std::ios::end); break;
|
||||
default: break;
|
||||
}
|
||||
return stream->fail() ? -1 : (Sint64)stream->tellg();
|
||||
}
|
||||
|
||||
static size_t istream_read(SDL_RWops* context, void *ptr, size_t size, size_t maxnum){
|
||||
if(size == 0)
|
||||
return -1;
|
||||
std::istream* stream = (std::istream*)context->hidden.unknown.data1;
|
||||
stream->read((char*)ptr, size * maxnum);
|
||||
|
||||
return stream->bad() ? -1 : stream->gcount() / size;
|
||||
}
|
||||
|
||||
static i32 istream_close(SDL_RWops* context){
|
||||
if (context)
|
||||
SDL_FreeRW(context);
|
||||
return 0;
|
||||
}
|
||||
|
||||
SDL_RWops* SDL_RWFromIStream(std::istream& stream, size_t size){
|
||||
SDL_RWops* rwops = SDL_AllocRW();
|
||||
if(rwops) {
|
||||
rwops->size = istream_size;
|
||||
rwops->seek = istream_seek;
|
||||
rwops->read = istream_read;
|
||||
rwops->write = nullptr;
|
||||
rwops->close = istream_close;
|
||||
rwops->hidden.unknown.data1 = &stream;
|
||||
rwops->hidden.unknown.data2 = (void*)size;
|
||||
rwops->type = SDL_RWOPS_UNKNOWN;
|
||||
}
|
||||
return rwops;
|
||||
}
|
||||
|
||||
}
|
||||
@ -1,44 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <optional>
|
||||
#include <SDL.h>
|
||||
#include "resources.hpp"
|
||||
#include "../common/math.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
#define SDL_RectConstruct(X, Y, W, H) (SDL_Rect){X, Y, W, H}
|
||||
#define SDL_FRectConstruct(X, Y, W, H) (SDL_FRect){X, Y, W, H}
|
||||
#define SDL_PointConstruct(X, Y) (SDL_Point){X, Y, W, H}
|
||||
#define SDL_FPointConstruct(X, Y) (SDL_FPoint){X, Y, W, H}
|
||||
|
||||
#define optional_value_ptr_or_null(OPT) (OPT ? &(*OPT) : nullptr)
|
||||
|
||||
SDL_RWops* SDL_RWFromIStream(std::istream& stream, size_t size);
|
||||
|
||||
struct SDL_RenderCopyExF_Params {
|
||||
std::optional<SDL_Rect> texture_section;
|
||||
std::optional<SDL_FRect> target_section;
|
||||
std::optional<SDL_FPoint> rotation_center;
|
||||
angle_t rotation_angle;
|
||||
SDL_RendererFlip flip;
|
||||
|
||||
SDL_RenderCopyExF_Params();
|
||||
};
|
||||
|
||||
struct Texture {
|
||||
SDL_Renderer* renderer;
|
||||
std::shared_ptr<SDL_Texture> texture;
|
||||
i32 w;
|
||||
i32 h;
|
||||
|
||||
Texture(const Resource& r, SDL_Renderer* renderer);
|
||||
Texture(std::istream& s, size_t size, SDL_Renderer* renderer);
|
||||
|
||||
void render(const SDL_FRect& target_section);
|
||||
void render(const SDL_FRect& target_section, const SDL_Rect& texture_section);
|
||||
void render(const SDL_RenderCopyExF_Params& params);
|
||||
};
|
||||
|
||||
}
|
||||
@ -1,65 +1,84 @@
|
||||
#include <sstream>
|
||||
#include <stdarg.h>
|
||||
#include "ougge_format.hpp"
|
||||
#include "UsefulException.hpp"
|
||||
|
||||
std::string _ougge_format(const std::string& format_str, const size_t args_count, ...){
|
||||
va_list vl;
|
||||
va_start(vl, args_count);
|
||||
std::stringstream ss;
|
||||
|
||||
for(size_t i = 0; i < format_str.length(); i++){
|
||||
char c = format_str[i];
|
||||
|
||||
// format specifier
|
||||
if(c == '%'){
|
||||
c = format_str[++i];
|
||||
bool l = false;
|
||||
while(c == 'l'){
|
||||
l = true;
|
||||
c = format_str[++i];
|
||||
}
|
||||
|
||||
switch(c){
|
||||
case 'u':
|
||||
if(l) ss<<(u64)va_arg(vl, u64);
|
||||
else ss<<(u32)va_arg(vl, u32);
|
||||
break;
|
||||
case 'i':
|
||||
case 'd':
|
||||
if(l) ss<<(i64)va_arg(vl, i64);
|
||||
else ss<<(i32)va_arg(vl, i32);
|
||||
break;
|
||||
case 'f':
|
||||
// f32 is promoted to f64 when passed through '...'
|
||||
ss<<(f64)va_arg(vl, f64);
|
||||
break;
|
||||
case 'p':
|
||||
ss<<(void*)va_arg(vl, void*);
|
||||
break;
|
||||
case 'x':
|
||||
if(l) ss<<std::hex<<(u64)va_arg(vl, u64);
|
||||
else ss<<std::hex<<(u32)va_arg(vl, u32);
|
||||
break;
|
||||
case 's': {
|
||||
const char* cptr = va_arg(vl,char*);
|
||||
if(cptr != nullptr)
|
||||
ss<<cptr;
|
||||
else ss<<"<nullptr>";
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
ss<<(char)va_arg(vl,int);
|
||||
break;
|
||||
default:
|
||||
throw UsefulException("invalid format cpecifier");
|
||||
}
|
||||
}
|
||||
|
||||
// regular character
|
||||
else ss<<c;
|
||||
}
|
||||
|
||||
va_end(vl);
|
||||
return ss.str();
|
||||
}
|
||||
#include <sstream>
|
||||
#include <stdarg.h>
|
||||
#include "ougge_format.hpp"
|
||||
#include "UsefulException.hpp"
|
||||
|
||||
std::string _ougge_format(const std::string& format_str, const size_t args_count, ...){
|
||||
va_list vl;
|
||||
va_start(vl, args_count);
|
||||
std::stringstream ss;
|
||||
|
||||
for(size_t i = 0; i < format_str.length(); i++){
|
||||
char c = format_str[i];
|
||||
|
||||
// format specifier
|
||||
if(c == '%'){
|
||||
c = format_str[++i];
|
||||
bool l = false;
|
||||
while(c == 'l'){
|
||||
l = true;
|
||||
c = format_str[++i];
|
||||
}
|
||||
|
||||
switch(c){
|
||||
case 'u':
|
||||
if(l) ss<<(u64)va_arg(vl, u64);
|
||||
else ss<<(u32)va_arg(vl, u32);
|
||||
break;
|
||||
case 'i':
|
||||
case 'd':
|
||||
if(l) ss<<(i64)va_arg(vl, i64);
|
||||
else ss<<(i32)va_arg(vl, i32);
|
||||
break;
|
||||
case 'f':
|
||||
// f32 is promoted to f64 when passed through '...'
|
||||
ss<<(f64)va_arg(vl, f64);
|
||||
break;
|
||||
case 'p':
|
||||
ss<<(void*)va_arg(vl, void*);
|
||||
break;
|
||||
case 'x':
|
||||
if(l) ss<<std::hex<<(u64)va_arg(vl, u64);
|
||||
else ss<<std::hex<<(u32)va_arg(vl, u32);
|
||||
break;
|
||||
case 's': {
|
||||
const char* cptr = va_arg(vl,char*);
|
||||
if(cptr != nullptr)
|
||||
ss<<cptr;
|
||||
else ss<<"<nullptr>";
|
||||
break;
|
||||
}
|
||||
case 'c':
|
||||
ss<<(char)va_arg(vl,int);
|
||||
break;
|
||||
default:
|
||||
throw UsefulException("invalid format cpecifier");
|
||||
}
|
||||
}
|
||||
|
||||
// regular character
|
||||
else ss<<c;
|
||||
}
|
||||
|
||||
va_end(vl);
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
|
||||
std::string formatSizeHumanReadable(std::size_t b){
|
||||
std::stringstream ss;
|
||||
ss.precision(3);
|
||||
std::size_t k = b / 1024;
|
||||
std::size_t m = k / 1024;
|
||||
std::size_t g = m / 1024;
|
||||
|
||||
if(g)
|
||||
ss<<m / 1024.0f<<'G';
|
||||
else if(m)
|
||||
ss<<k / 1024.0f<<'M';
|
||||
else if(k)
|
||||
ss<<b / 1024.0f<<'K';
|
||||
else ss<<b;
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include "std.hpp"
|
||||
|
||||
std::string _ougge_format(const std::string& format_str, const size_t args_count, ...);
|
||||
#define ougge_format(FORMAT_STR, ARGS...) _ougge_format(FORMAT_STR, count_args(ARGS) ,##ARGS)
|
||||
#pragma once
|
||||
|
||||
#include "std.hpp"
|
||||
|
||||
std::string _ougge_format(const std::string& format_str, const size_t args_count, ...);
|
||||
#define ougge_format(FORMAT_STR, ARGS...) _ougge_format(FORMAT_STR, count_args(ARGS) ,##ARGS)
|
||||
|
||||
std::string formatSizeHumanReadable(std::size_t byte_n);
|
||||
|
||||
@ -4,8 +4,6 @@
|
||||
#include "MainWindow.hpp"
|
||||
#include "gui_exceptions.hpp"
|
||||
#include "../common/ougge_format.hpp"
|
||||
#include "../resources/fonts.hpp"
|
||||
#include "../resources/textures.hpp"
|
||||
#include "../common/math.hpp"
|
||||
|
||||
namespace ougge::gui {
|
||||
@ -21,7 +19,7 @@ f32 MainWindow::getDPI(){
|
||||
return dpi;
|
||||
}
|
||||
|
||||
void MainWindow::open(const std::string& window_title){
|
||||
void MainWindow::open(const std::string& window_title, resources::ResourceManager& resourceManager){
|
||||
SDL_TRY(SDL_Init(SDL_INIT_EVERYTHING));
|
||||
SDL_version v;
|
||||
SDL_GetVersion(&v);
|
||||
@ -72,8 +70,12 @@ void MainWindow::open(const std::string& window_title){
|
||||
|
||||
// Setup Dear ImGui style
|
||||
ImGui::StyleColorsDark();
|
||||
|
||||
resources::ResourceFactory* font_res = resourceManager.tryGetResource(default_font_path);
|
||||
if(font_res == nullptr)
|
||||
throw UsefulException("can't find default font resource");
|
||||
f32 dpi = getDPI();
|
||||
io.FontDefault = resources::ImFont_LoadFromResource(default_font, default_font_size, dpi);
|
||||
io.FontDefault = resources::ImFont_LoadFromResource(font_res, default_font_size, dpi);
|
||||
}
|
||||
|
||||
void MainWindow::close(){
|
||||
|
||||
@ -1,45 +1,47 @@
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <imgui.h>
|
||||
#include "../common/std.hpp"
|
||||
#include "../common/time.hpp"
|
||||
|
||||
/// converts hex color to float vector
|
||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
||||
/// converts float vector to hex color
|
||||
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
|
||||
|
||||
namespace ougge::gui {
|
||||
|
||||
#define default_font "DroidSans"
|
||||
|
||||
class MainWindow {
|
||||
public:
|
||||
i32 fps_max = 60;
|
||||
f32 default_font_size = 14.0f;
|
||||
ImVec4 clear_color = RGBAHexToF(35,35,50,255);
|
||||
SDL_Window* sdl_window = nullptr;
|
||||
SDL_Renderer* sdl_renderer = nullptr;
|
||||
|
||||
private:
|
||||
bool show_debug_window = true;
|
||||
bool show_demo_window = false;
|
||||
bool show_metrics_window = false;
|
||||
|
||||
public:
|
||||
void open(const std::string& window_title);
|
||||
void close();
|
||||
|
||||
/// process io events happened since previous frame
|
||||
void pollEvents(bool* loopRunning);
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
|
||||
f32 getDPI();
|
||||
private:
|
||||
void draw_debug_window();
|
||||
void draw_bg_window();
|
||||
};
|
||||
|
||||
}
|
||||
#pragma once
|
||||
|
||||
#include <SDL.h>
|
||||
#include <imgui.h>
|
||||
#include "../common/std.hpp"
|
||||
#include "../common/time.hpp"
|
||||
#include "../resources/resources.hpp"
|
||||
#include "../resources/fonts.hpp"
|
||||
|
||||
/// converts hex color to float vector
|
||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
||||
/// converts float vector to hex color
|
||||
#define RGBAFToHex(VEC4) {(u8)(VEC4.x*255), (u8)(VEC4.y*255), (u8)(VEC4.z*255), (u8)(VEC4.w*255)}
|
||||
|
||||
namespace ougge::gui {
|
||||
|
||||
#define default_font_path "fonts/DroidSans.ttf"
|
||||
|
||||
class MainWindow {
|
||||
public:
|
||||
i32 fps_max = 60;
|
||||
f32 default_font_size = 14.0f;
|
||||
ImVec4 clear_color = RGBAHexToF(35,35,50,255);
|
||||
SDL_Window* sdl_window = nullptr;
|
||||
SDL_Renderer* sdl_renderer = nullptr;
|
||||
|
||||
private:
|
||||
bool show_debug_window = true;
|
||||
bool show_demo_window = false;
|
||||
bool show_metrics_window = false;
|
||||
|
||||
public:
|
||||
void open(const std::string& window_title, resources::ResourceManager& resourceManager);
|
||||
void close();
|
||||
|
||||
/// process io events happened since previous frame
|
||||
void pollEvents(bool* loopRunning);
|
||||
void beginFrame();
|
||||
void endFrame();
|
||||
|
||||
f32 getDPI();
|
||||
private:
|
||||
void draw_debug_window();
|
||||
void draw_bg_window();
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
128
src/main.cpp
128
src/main.cpp
@ -1,63 +1,65 @@
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "common/UsefulException.hpp"
|
||||
#include "common/ougge_format.hpp"
|
||||
#include "Engine.hpp"
|
||||
#include "gui/gui.hpp"
|
||||
|
||||
using namespace ougge;
|
||||
|
||||
void drawTutel(Engine& engine){
|
||||
resources::Texture& tutel = engine.textures.getOrCreate("tutel.png", engine.mainWindow.sdl_renderer);
|
||||
resources::SDL_RenderCopyExF_Params params;
|
||||
params.target_section = SDL_FRectConstruct(100, 100, 400, 400);
|
||||
static i32 si = 1;
|
||||
params.rotation_angle = M_PI_4 * (si++ / engine.mainWindow.fps_max);
|
||||
tutel.render(params);
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv){
|
||||
try {
|
||||
resources::init();
|
||||
std::cout<<"initialized resource loader"<<std::endl;
|
||||
|
||||
Engine engine;
|
||||
std::cout<<"initialized mono jit runtime"<<std::endl;
|
||||
engine.init();
|
||||
std::cout<<"initialized game engine"<<std::endl;
|
||||
|
||||
game::GameObject& exampleObj = engine.createGameObject();
|
||||
std::string componentClassName = "Ougge.ExampleComponent";
|
||||
if(!engine.tryCreateComponent(exampleObj, componentClassName))
|
||||
throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str()));
|
||||
|
||||
std::cout<<"created ExampleObject"<<std::endl;
|
||||
|
||||
engine.updateCallback = [&engine](f64 deltaTime) -> void {
|
||||
drawTutel(engine);
|
||||
};
|
||||
|
||||
engine.openMainWindow("ougge");
|
||||
std::cout<<"created sdl window"<<std::endl;
|
||||
engine.startLoop();
|
||||
std::cout<<"sdl window has been cosed"<<std::endl;
|
||||
}
|
||||
catch(const std::exception& e){
|
||||
std::cerr<<"Catched exception: "<<e.what()<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
catch(const char* cstr){
|
||||
std::cerr<<"Catched error message (const char*): "<<cstr<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
catch(const std::string& str){
|
||||
std::cerr<<"Catched error message (std::string): "<<str<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
catch(...){
|
||||
std::cerr<<"Catched unknown error"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#define SDL_MAIN_HANDLED
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include "common/UsefulException.hpp"
|
||||
#include "common/ougge_format.hpp"
|
||||
#include "Engine.hpp"
|
||||
#include "gui/gui.hpp"
|
||||
|
||||
using namespace ougge;
|
||||
|
||||
void drawTutel(Engine& engine){
|
||||
resources::Texture* tutel = engine.textures.tryGetOrCreate("tutel.png", engine.mainWindow.sdl_renderer);
|
||||
if(tutel == nullptr){
|
||||
throw new UsefulException("couldn't find resource 'tutel.png'");
|
||||
}
|
||||
resources::SDL_RenderCopyExF_Params params;
|
||||
params.target_section = SDL_FRectConstruct(100, 100, 400, 400);
|
||||
static i32 si = 1;
|
||||
params.rotation_angle = M_PI_4 * (si++ / engine.mainWindow.fps_max);
|
||||
tutel->render(params);
|
||||
}
|
||||
|
||||
int main(int argc, const char** argv){
|
||||
try {
|
||||
std::cout<<"initialized resource loader"<<std::endl;
|
||||
|
||||
Engine engine;
|
||||
std::cout<<"initialized mono jit runtime"<<std::endl;
|
||||
engine.init();
|
||||
std::cout<<"initialized game engine"<<std::endl;
|
||||
|
||||
game::GameObject& exampleObj = engine.createGameObject();
|
||||
std::string componentClassName = "Ougge.ExampleComponent";
|
||||
if(!engine.tryCreateComponent(exampleObj, componentClassName))
|
||||
throw UsefulException(ougge_format("couldn't create component '%s'", componentClassName.c_str()));
|
||||
|
||||
std::cout<<"created ExampleObject"<<std::endl;
|
||||
|
||||
engine.updateCallback = [&engine](f64 deltaTime) -> void {
|
||||
drawTutel(engine);
|
||||
};
|
||||
|
||||
engine.openMainWindow("ougge");
|
||||
std::cout<<"created sdl window"<<std::endl;
|
||||
engine.startLoop();
|
||||
std::cout<<"sdl window has been cosed"<<std::endl;
|
||||
}
|
||||
catch(const std::exception& e){
|
||||
std::cerr<<"Catched exception: "<<e.what()<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
catch(const char* cstr){
|
||||
std::cerr<<"Catched error message (const char*): "<<cstr<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
catch(const std::string& str){
|
||||
std::cerr<<"Catched error message (std::string): "<<str<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
catch(...){
|
||||
std::cerr<<"Catched unknown error"<<std::endl;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
40
src/resources/MemorySteam.cpp
Normal file
40
src/resources/MemorySteam.cpp
Normal file
@ -0,0 +1,40 @@
|
||||
#include "MemoryStream.hpp"
|
||||
|
||||
class MemoryStreamBuf : public std::streambuf {
|
||||
public:
|
||||
MemoryStreamBuf(void* p, const std::size_t n);
|
||||
|
||||
virtual std::istream::pos_type seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which);
|
||||
};
|
||||
|
||||
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
|
||||
char* p=(char*)_p;
|
||||
setg(p, p, p + n);
|
||||
setp(p, p + n);
|
||||
}
|
||||
|
||||
std::istream::pos_type MemoryStreamBuf::seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
if (dir == std::ios_base::cur)
|
||||
gbump(off);
|
||||
else if (dir == std::ios_base::end)
|
||||
setg(eback(), egptr() + off, egptr());
|
||||
else if (dir == std::ios_base::beg)
|
||||
setg(eback(), eback() + off, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
|
||||
|
||||
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
|
||||
: std::istream(new MemoryStreamBuf((void*)p, n))
|
||||
{}
|
||||
|
||||
MemoryStreamRead::~MemoryStreamRead(){
|
||||
delete rdbuf();
|
||||
}
|
||||
8
src/resources/MemoryStream.hpp
Normal file
8
src/resources/MemoryStream.hpp
Normal file
@ -0,0 +1,8 @@
|
||||
#include <iostream>
|
||||
|
||||
class MemoryStreamRead : public std::istream {
|
||||
public:
|
||||
MemoryStreamRead(const void* p, const std::size_t n);
|
||||
|
||||
virtual ~MemoryStreamRead();
|
||||
};
|
||||
@ -1,7 +1,4 @@
|
||||
#include <imgui.h>
|
||||
#include "resources.hpp"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "fonts.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
@ -16,17 +13,16 @@ ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi
|
||||
return io.Fonts->AddFontFromFileTTF(file_path.c_str(), font_size, nullptr, glyph_ranges);
|
||||
}
|
||||
|
||||
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi){
|
||||
ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi){
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
font_size *= dpi;
|
||||
ImFontConfig font_cfg = ImFontConfig();
|
||||
std::sprintf(font_cfg.Name, "%s %ipx", font_name.c_str(), (i32)font_size);
|
||||
std::sprintf(font_cfg.Name, "%s %ipx", res->path.c_str(), (i32)font_size);
|
||||
|
||||
auto& res = getResource("fonts/" + font_name + ".ttf");
|
||||
char* font_data = new char[res.size];
|
||||
res.openStream()->read(font_data, res.size);
|
||||
char* font_data = new char[res->size];
|
||||
res->openStream()->read(font_data, res->size);
|
||||
|
||||
return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res.size,
|
||||
return io.Fonts->AddFontFromMemoryTTF((void*)(font_data), res->size,
|
||||
font_size, &font_cfg, glyph_ranges);
|
||||
}
|
||||
|
||||
|
||||
@ -1,12 +1,13 @@
|
||||
#pragma once
|
||||
|
||||
#include "imgui.h"
|
||||
#include <imgui.h>
|
||||
#include "../common/std.hpp"
|
||||
#include "resources.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
ImFont* ImFont_LoadFromFile(const std::string& file_path, f32 font_size, f32 dpi);
|
||||
|
||||
ImFont* ImFont_LoadFromResource(const std::string& font_name, f32 font_size, f32 dpi);
|
||||
ImFont* ImFont_LoadFromResource(ResourceFactory* res, f32 font_size, f32 dpi);
|
||||
|
||||
}
|
||||
|
||||
@ -4,45 +4,22 @@
|
||||
#include "../common/ougge_format.hpp"
|
||||
#include "resources.hpp"
|
||||
#include "embedded_resources.h"
|
||||
|
||||
#include "MemoryStream.hpp"
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
Resource::Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func)
|
||||
ResourceFactory::ResourceFactory(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func)
|
||||
: path(path), size(size), openStream(open_read_steam_func)
|
||||
{}
|
||||
|
||||
MemoryStreamBuf::MemoryStreamBuf(void* _p, const std::size_t n){
|
||||
char* p=(char*)_p;
|
||||
setg(p, p, p + n);
|
||||
setp(p, p + n);
|
||||
}
|
||||
|
||||
std::istream::pos_type MemoryStreamBuf::seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which)
|
||||
{
|
||||
if (dir == std::ios_base::cur)
|
||||
gbump(off);
|
||||
else if (dir == std::ios_base::end)
|
||||
setg(eback(), egptr() + off, egptr());
|
||||
else if (dir == std::ios_base::beg)
|
||||
setg(eback(), eback() + off, egptr());
|
||||
return gptr() - eback();
|
||||
}
|
||||
std::shared_ptr<ResourceMap> ResourceManager::_embeddedResourcesMap;
|
||||
|
||||
MemoryStreamRead::MemoryStreamRead(const void* p, const std::size_t n)
|
||||
: std::istream(new MemoryStreamBuf((void*)p, n))
|
||||
{}
|
||||
void ResourceManager::loadEmbeddedResources(){
|
||||
if(_embeddedResourcesMap != nullptr)
|
||||
return;
|
||||
|
||||
MemoryStreamRead::~MemoryStreamRead(){
|
||||
delete rdbuf();
|
||||
}
|
||||
|
||||
static std::unordered_map<std::string, Resource>* _resourceMap = nullptr;
|
||||
|
||||
void loadEmbeddedresources(){
|
||||
_embeddedResourcesMap = std::make_shared<ResourceMap>();
|
||||
for(int i = 0; i < EmbeddedResource_table_count; i++){
|
||||
const EmbeddedResource& e = EmbeddedResource_table[i];
|
||||
std::cout <<"loading resource '" << e.path << "' "
|
||||
@ -52,43 +29,36 @@ void loadEmbeddedresources(){
|
||||
return std::make_unique<MemoryStreamRead>(e.data, e.size);
|
||||
};
|
||||
|
||||
auto r = _resourceMap->emplace(e.path,
|
||||
Resource(e.path, e.size, embedded_resource_factory));
|
||||
auto r = _embeddedResourcesMap->emplace(e.path,
|
||||
ResourceFactory(e.path, e.size, embedded_resource_factory));
|
||||
if(!r.second)
|
||||
throw UsefulException(ougge_format("can't load duplicate resource '%s'", e.path));
|
||||
}
|
||||
}
|
||||
|
||||
void init(){
|
||||
if(_resourceMap != nullptr)
|
||||
throw UsefulException("resource has been initialized already");
|
||||
_resourceMap = new std::unordered_map<std::string, Resource>();
|
||||
loadEmbeddedresources();
|
||||
}
|
||||
|
||||
Resource& getResource(const std::string& path){
|
||||
auto it = _resourceMap->find(path);
|
||||
if(it == _resourceMap->end())
|
||||
throw UsefulException(ougge_format("can't find resource '%s'", path.c_str()));
|
||||
return it->second;
|
||||
}
|
||||
|
||||
std::string formatSizeHumanReadable(std::size_t b){
|
||||
std::stringstream ss;
|
||||
ss.precision(3);
|
||||
std::size_t k = b / 1024;
|
||||
std::size_t m = k / 1024;
|
||||
std::size_t g = m / 1024;
|
||||
|
||||
if(g)
|
||||
ss<<m / 1024.0f<<'G';
|
||||
else if(m)
|
||||
ss<<k / 1024.0f<<'M';
|
||||
else if(k)
|
||||
ss<<b / 1024.0f<<'K';
|
||||
else ss<<b;
|
||||
_resourceMaps.push_back(_embeddedResourcesMap);
|
||||
}
|
||||
|
||||
return ss.str();
|
||||
ResourceManager::ResourceManager(){
|
||||
loadEmbeddedResources();
|
||||
}
|
||||
|
||||
ResourceFactory* ResourceManager::tryGetResource(const std::string& path){
|
||||
// reverse iteration of linked list
|
||||
auto map_list_iterator = _resourceMaps.end();
|
||||
while(map_list_iterator != _resourceMaps.begin()){
|
||||
--map_list_iterator;
|
||||
auto map = *map_list_iterator;
|
||||
|
||||
auto resource_iterator = map->find(path);
|
||||
|
||||
// resource not found
|
||||
if(resource_iterator == map->end())
|
||||
return nullptr;
|
||||
|
||||
return &resource_iterator->second;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -4,60 +4,71 @@
|
||||
#include <iostream>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <list>
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
// call this in main()
|
||||
void init();
|
||||
|
||||
std::string formatSizeHumanReadable(std::size_t byte_n);
|
||||
|
||||
class Resource {
|
||||
class ResourceFactory {
|
||||
public:
|
||||
const std::string path;
|
||||
const std::size_t size;
|
||||
|
||||
using StreamFactoryMethod = std::function< std::unique_ptr<std::istream> () >;
|
||||
|
||||
Resource(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func);
|
||||
ResourceFactory(const std::string& path, const std::size_t size, StreamFactoryMethod open_read_steam_func);
|
||||
|
||||
const StreamFactoryMethod openStream;
|
||||
};
|
||||
|
||||
class MemoryStreamBuf : public std::streambuf {
|
||||
using ResourceMap = std::unordered_map<std::string, ResourceFactory>;
|
||||
|
||||
class ResourceManager {
|
||||
std::list<std::shared_ptr<ResourceMap>> _resourceMaps;
|
||||
static std::shared_ptr<ResourceMap> _embeddedResourcesMap;
|
||||
void loadEmbeddedResources();
|
||||
|
||||
public:
|
||||
MemoryStreamBuf(void* p, const std::size_t n);
|
||||
ResourceManager();
|
||||
|
||||
virtual std::istream::pos_type seekoff(
|
||||
std::istream::off_type off,
|
||||
std::ios_base::seekdir dir,
|
||||
std::ios_base::openmode which);
|
||||
void addResourceMap(std::shared_ptr<ResourceMap> m);
|
||||
|
||||
std::shared_ptr<ResourceMap> loadResouceMap();
|
||||
void removeResourceMap();
|
||||
|
||||
ResourceFactory* tryGetResource(const std::string& path);
|
||||
};
|
||||
|
||||
class MemoryStreamRead : public std::istream {
|
||||
public:
|
||||
MemoryStreamRead(const void* p, const std::size_t n);
|
||||
|
||||
virtual ~MemoryStreamRead();
|
||||
};
|
||||
|
||||
Resource& getResource(const std::string& path);
|
||||
|
||||
/// @brief stores requested resources in memory
|
||||
/// @tparam T must implement constructor `T(const Resource&, ...)`
|
||||
/// @tparam T must implement constructor `T(ResourceFactory*, ...)`
|
||||
template<class T>
|
||||
class CacheStorage {
|
||||
std::unordered_map<std::string, T> _map;
|
||||
ResourceManager* _resourceManager;
|
||||
|
||||
public:
|
||||
CacheStorage(ResourceManager*);
|
||||
CacheStorage(CacheStorage&&) = delete;
|
||||
CacheStorage(const CacheStorage&) = delete;
|
||||
|
||||
template<typename... TCtorArgs>
|
||||
T& getOrCreate(const std::string& name, TCtorArgs&&... ctor_args){
|
||||
T* tryGetOrCreate(const std::string& name, TCtorArgs&&... ctor_args){
|
||||
auto it = _map.find(name);
|
||||
if(it != _map.end())
|
||||
return it->second;
|
||||
auto& res = getResource(name);
|
||||
return &it->second;
|
||||
|
||||
ResourceFactory* res = _resourceManager->tryGetResource(name);
|
||||
if(res == nullptr)
|
||||
return nullptr;
|
||||
|
||||
auto e = _map.emplace(name, T(res, ctor_args...));
|
||||
return e.first->second;
|
||||
return &e.first->second;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <class T> inline CacheStorage<T>::CacheStorage(ResourceManager* resourceManager)
|
||||
: _resourceManager(resourceManager)
|
||||
{}
|
||||
|
||||
}
|
||||
|
||||
@ -4,8 +4,8 @@
|
||||
|
||||
namespace ougge::resources {
|
||||
|
||||
Texture::Texture(const Resource& r, SDL_Renderer* renderer)
|
||||
: Texture(*r.openStream(), r.size, renderer)
|
||||
Texture::Texture(ResourceFactory* r, SDL_Renderer* renderer)
|
||||
: Texture(*r->openStream(), r->size, renderer)
|
||||
{}
|
||||
|
||||
Texture::Texture(std::istream& s, size_t size, SDL_Renderer* renderer)
|
||||
|
||||
@ -33,7 +33,7 @@ struct Texture {
|
||||
i32 w;
|
||||
i32 h;
|
||||
|
||||
Texture(const Resource& r, SDL_Renderer* renderer);
|
||||
Texture(ResourceFactory* r, SDL_Renderer* renderer);
|
||||
Texture(std::istream& s, size_t size, SDL_Renderer* renderer);
|
||||
|
||||
void render(const SDL_FRect& target_section);
|
||||
|
||||
Loading…
Reference in New Issue
Block a user