Get ecs to a somewhat functional state

This commit is contained in:
Bailey Harrison 2022-12-15 15:54:11 +00:00
parent 1e06df5dc2
commit 2f880981ac
18 changed files with 198 additions and 194 deletions

View File

@ -15,7 +15,7 @@ set(SRC_FILES
"src/input_manager.cpp"
"src/scene_manager.cpp"
"src/texture.cpp"
"src/resources/texture.cpp"
"src/gfx_device_vulkan.cpp"
@ -38,13 +38,14 @@ set(INCLUDE_FILES
"include/scene_manager.hpp"
"include/resource_manager.hpp"
"include/texture.hpp"
"include/resources/texture.hpp"
"include/gfx.hpp"
"include/gfx_device.hpp"
"include/scene.hpp"
"include/ecs_system.hpp"
"include/ecs/ecs_system.hpp"
"include/ecs/mesh_renderer.hpp"
"include/util/files.hpp"
)

View File

@ -1,6 +1,8 @@
#pragma once
#include <memory>
#include <string>
#include <filesystem>
namespace engine {
@ -26,12 +28,16 @@ namespace engine {
InputManager* inputManager() { return m_inputManager.get(); }
SceneManager* sceneManager() { return m_sceneManager.get(); }
std::string getResourcePath(const std::string relativePath) { return (m_resourcesPath / relativePath).string(); }
private:
std::unique_ptr<Window> m_window;
std::unique_ptr<GFXDevice> m_gfx;
std::unique_ptr<InputManager> m_inputManager;
std::unique_ptr<SceneManager> m_sceneManager;
std::filesystem::path m_resourcesPath;
};
}

View File

@ -1,9 +0,0 @@
#pragma once
namespace engine::components {
struct MeshRenderer {
int placeholder;
};
}

View File

@ -3,10 +3,10 @@
#include <map>
#include <memory>
namespace engine::ecs {
namespace engine {
template <class T>
class System {
class EcsSystem {
public:
std::map<uint32_t, T> m_components{};

View File

@ -0,0 +1,29 @@
#pragma once
#include "ecs_system.hpp"
#include "resources/texture.hpp"
#include "log.hpp"
namespace engine::ecs {
struct MeshRendererComponent {
int number;
const resources::Texture* texture;
};
class RendererSystem : public EcsSystem<MeshRendererComponent> {
public:
void onUpdate(float ts) override
{
for (const auto& [id, data] : m_components) {
DEBUG("rendering entity {}\tts={}", id, ts);
DEBUG(" with texture: {}, number = {}", (void*)data.texture, data.number);
}
}
};
}

View File

@ -16,32 +16,27 @@ namespace engine {
ResourceManager(const ResourceManager&) = delete;
ResourceManager& operator=(const ResourceManager&) = delete;
std::shared_ptr<T> add(const std::string& name, std::unique_ptr<T>&& resource)
T* add(const std::string& name, std::unique_ptr<T>&& resource)
{
if (m_resources.contains(name) == false) {
std::shared_ptr<T> ptr = std::move(resource);
m_resources.emplace(name, ptr);
m_resources.emplace(name, std::move(resource));
}
else {
throw std::runtime_error("Cannot add a resource which already exists");
}
return m_resources.at(name).lock();
return m_resources.at(name).get();
}
std::shared_ptr<T> get(const std::string& name)
T* get(const std::string& name)
{
if (m_resources.contains(name)) {
std::weak_ptr<T> resource = m_resources.at(name);
if (resource.expired() == false) {
return resource.lock();
}
return m_resources.at(name).get();
}
return {};
}
private:
// weak ptrs are used to check a resource's use count. If the use count of a resource hits 0, the resource can safely be deleted.
std::unordered_map<std::string, std::weak_ptr<T>> m_resources{};
std::unordered_map<std::string, std::unique_ptr<T>> m_resources{};
};

View File

@ -0,0 +1,22 @@
#pragma once
#include "gfx_device.hpp"
namespace engine::resources {
class Texture {
public:
Texture(GFXDevice* gfxDevice, const std::string& path);
~Texture();
Texture(const Texture&) = delete;
Texture& operator=(const Texture&) = delete;
gfx::Texture* getHandle();
private:
GFXDevice* m_gfxDevice;
gfx::Texture* m_gpuTexture;
};
}

View File

@ -1,7 +1,6 @@
#pragma once
#include "ecs_system.hpp"
#include "components/mesh_renderer.hpp"
#include "ecs/mesh_renderer.hpp"
#include "log.hpp"
@ -9,17 +8,6 @@
namespace engine {
class RendererSystem : public ecs::System<components::MeshRenderer> {
public:
void onUpdate(float ts) override
{
for (const auto& [id, data] : m_components) {
DEBUG("rendering entity {}\tts={}", id, ts);
}
}
};
class Scene {
public:
@ -35,7 +23,7 @@ namespace engine {
return m_nextEntityID++;
}
std::unique_ptr<RendererSystem> m_renderSystem;
std::unique_ptr<ecs::RendererSystem> m_renderSystem;
private:
uint32_t m_nextEntityID = 1000;

View File

@ -8,6 +8,9 @@
namespace engine {
class Scene; // "scene.hpp"
namespace resources {
class Texture;
}
class SceneManager {
@ -21,11 +24,14 @@ namespace engine {
void updateActiveScene(float ts);
/* getters */
ResourceManager<resources::Texture>* getTextureManager() { return m_textureManager.get(); }
private:
std::vector<std::unique_ptr<Scene>> m_scenes;
int m_activeSceneIndex = -1;
// const std::unique_ptr<ResourceManager<Texture>> m_textureManager;
std::unique_ptr<ResourceManager<resources::Texture>> m_textureManager;
};

View File

@ -1,25 +0,0 @@
#if 0
#pragma once
#include "engine_api.h"
#include "resource.hpp"
#include "gfx_device.hpp"
namespace engine::resources {
class ENGINE_API Texture : public Resource {
public:
Texture(const std::filesystem::path& resPath);
~Texture() override;
gfx::Texture* getHandle();
private:
gfx::Texture* m_gpuTexture;
};
}
#endif

View File

@ -8,5 +8,6 @@ namespace engine::util {
std::unique_ptr<std::vector<char>> readTextFile(const std::string& path);
std::unique_ptr<std::vector<uint8_t>> readBinaryFile(const std::string& path);
std::unique_ptr<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height);
}

View File

@ -12,6 +12,43 @@
// To allow the FPS-limiter to put the thread to sleep
#include <thread>
#ifdef _MSC_VER
#include <windows.h>
#include <direct.h>
#define MAX_PATH 260
#endif
static std::filesystem::path getResourcesPath()
{
std::filesystem::path resourcesPath{};
#ifdef _MSC_VER
CHAR exeDirBuf[MAX_PATH + 1];
GetModuleFileNameA(NULL, exeDirBuf, MAX_PATH + 1);
std::filesystem::path cwd = std::filesystem::path(exeDirBuf).parent_path();
(void)_chdir((const char*)std::filesystem::absolute(cwd).c_str());
#else
std::filesystem::path cwd = std::filesystem::current_path();
#endif
if (std::filesystem::is_directory(cwd / "res")) {
resourcesPath = cwd / "res";
}
else {
resourcesPath = cwd.parent_path() / "share" / "sdltest";
}
if (std::filesystem::is_directory(resourcesPath) == false) {
resourcesPath = cwd.root_path() / "usr" / "local" / "share" / "sdltest";
}
if (std::filesystem::is_directory(resourcesPath) == false) {
throw std::runtime_error("Unable to determine resources location. CWD: " + cwd.string());
}
return resourcesPath;
}
namespace engine {
Application::Application(const char* appName, const char* appVersion)
@ -20,6 +57,9 @@ namespace engine {
m_gfx = std::make_unique<GFXDevice>(appName, appVersion, m_window->getHandle());
m_inputManager = std::make_unique<InputManager>(window());
m_sceneManager = std::make_unique<SceneManager>();
// get base path for resources
m_resourcesPath = getResourcesPath();
}
Application::~Application() {}

38
src/resources/texture.cpp Normal file
View File

@ -0,0 +1,38 @@
#include "resources/texture.hpp"
#include "util/files.hpp"
#include "log.hpp"
#include <vector>
namespace engine::resources {
Texture::Texture(GFXDevice* gfxDevice, const std::string& path)
: m_gfxDevice(gfxDevice)
{
int width, height;
auto texbuf = util::readImageFile(path, &width, &height);
gfx::TextureFilter filter = gfx::TextureFilter::LINEAR;
if (width <= 8 || height <= 8) {
filter = gfx::TextureFilter::NEAREST;
}
m_gpuTexture = m_gfxDevice->createTexture(texbuf->data(), (uint32_t)width, (uint32_t)height, gfx::TextureFilter::LINEAR, filter);
DEBUG("loaded texture {}, width: {} height: {} size: {}", path, width, height, texbuf->size());
}
Texture::~Texture()
{
m_gfxDevice->destroyTexture(m_gpuTexture);
}
gfx::Texture* Texture::getHandle()
{
return m_gpuTexture;
}
}

View File

@ -1,12 +1,10 @@
#include "scene.hpp"
#include "components/mesh_renderer.hpp"
namespace engine {
Scene::Scene()
{
m_renderSystem = std::make_unique<RendererSystem>();
m_renderSystem = std::make_unique<ecs::RendererSystem>();
}
Scene::~Scene() {}

View File

@ -1,7 +1,7 @@
#include "scene_manager.hpp"
#include "scene.hpp"
#include "log.hpp"
#include "resources/texture.hpp"
#include <assert.h>
@ -9,6 +9,7 @@ namespace engine {
SceneManager::SceneManager()
{
m_textureManager = std::make_unique<ResourceManager<resources::Texture>>();
}
SceneManager::~SceneManager() {}

View File

@ -1,122 +0,0 @@
#if 0
#include "resources/texture.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <log.hpp>
#include <vector>
namespace engine::resources {
// returns false if unable to open file
static bool readPNG(const std::string& path, std::vector<uint8_t>* texbuf, int *width, int *height, bool *isRGBA)
{
int x, y, n;
unsigned char *data = stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha);
if (data == nullptr) {
return false;
}
const size_t size = (size_t)x * (size_t)y * 4;
texbuf->resize(size);
memcpy(texbuf->data(), data, size);
*width = x;
*height = y;
*isRGBA = true;
stbi_image_free(data);
return true;
}
static bool readGLRaw(const std::string& path, std::vector<uint8_t>* texbuf, int *width, int *height, bool *isRGBA)
{
FILE *fp = fopen(path.c_str(), "rb");
if (!fp) {
return false;
}
fseek(fp, 0x02, SEEK_SET);
uint64_t tex_data_offset;
fread(&tex_data_offset, sizeof(uint64_t), 1, fp);
fseek(fp, 0L, SEEK_END);
uint64_t end = ftell(fp);
texbuf->resize(end);
fseek(fp, (long)tex_data_offset, SEEK_SET);
fread(texbuf->data(), 1, end, fp);
fclose(fp);
*width = 4096;
*height = 4096;
*isRGBA = false;
return true;
}
Texture::Texture(const std::filesystem::path& originalResPath) : Resource(originalResPath, "texture")
{
std::string resString = originalResPath.string();
bool flipV = false;
if (resString.back() == '_') {
flipV = true;
resString.pop_back();
}
std::filesystem::path resPath{ resString };
auto texbuf = std::make_unique<std::vector<uint8_t>>();
int width, height;
bool isRGBA, success;
if (resPath.extension() == ".png" || resPath.extension() == ".jpg") {
success = readPNG(resPath.string(), texbuf.get(), &width, &height, &isRGBA);
} else {
success = readGLRaw(resPath.string(), texbuf.get(), &width, &height, &isRGBA);
}
if (!success) {
throw std::runtime_error("Unable to open texture: " + resPath.string());
}
if (isRGBA == false) {
throw std::runtime_error("Currently, only RGBA textures are supported. Size: " + std::to_string(texbuf->size()));
}
gfx::TextureFilter filter = gfx::TextureFilter::LINEAR;
if (width <= 8 || height <= 8) {
filter = gfx::TextureFilter::NEAREST;
}
m_gpuTexture = gfxdev->createTexture(texbuf->data(), (uint32_t)width, (uint32_t)height, gfx::TextureFilter::LINEAR, filter);
DEBUG("loaded texture {} width: {} height: {} size: {}", resPath.filename().string(), width, height, texbuf->size());
}
Texture::~Texture()
{
gfxdev->destroyTexture(m_gpuTexture);
}
gfx::Texture* Texture::getHandle()
{
return m_gpuTexture;
}
}
#endif

View File

@ -1,5 +1,8 @@
#include "util/files.hpp"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include <fstream>
namespace engine::util {
@ -48,5 +51,28 @@ namespace engine::util {
return buffer;
}
// returns false if unable to open file
std::unique_ptr<std::vector<uint8_t>> readImageFile(const std::string& path, int *width, int *height)
{
int x, y, n;
unsigned char *data = stbi_load(path.c_str(), &x, &y, &n, STBI_rgb_alpha);
if (data == nullptr) {
throw std::runtime_error("Unable to open file " + path);
}
const size_t size = (size_t)x * (size_t)y * 4;
auto buffer = std::make_unique<std::vector<uint8_t>>(size);
memcpy(buffer->data(), data, buffer->size());
*width = x;
*height = y;
stbi_image_free(data);
return buffer;
}
}

View File

@ -4,7 +4,7 @@
#include "window.hpp"
#include "scene_manager.hpp"
#include "scene.hpp"
#include "components/mesh_renderer.hpp"
#include "ecs/mesh_renderer.hpp"
void playGame()
{
@ -17,7 +17,16 @@ void playGame()
auto entity1 = myScene->createEntity();
myScene->m_renderSystem->m_components.emplace(entity1, engine::components::MeshRenderer());
auto myTexture = std::make_unique<engine::resources::Texture>(app.gfx(), app.getResourcePath("textures/grass.jpg"));
app.sceneManager()->getTextureManager()->add("GRASS", std::move(myTexture));
myScene->m_renderSystem->m_components.emplace(
entity1,
engine::ecs::MeshRendererComponent{
.number = 69,
.texture = app.sceneManager()->getTextureManager()->get("GRASS"),
}
);
app.sceneManager()->createScene(std::move(myScene));