diff --git a/.gitmodules b/.gitmodules index 84e7c1b..7426239 100644 --- a/.gitmodules +++ b/.gitmodules @@ -20,3 +20,4 @@ [submodule "docs/doxygen-awesome-css"] path = docs/doxygen-awesome-css url = https://github.com/jothepro/doxygen-awesome-css.git + diff --git a/CMakeLists.txt b/CMakeLists.txt index 8934839..dbb927e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ add_subdirectory(extern/SDL_mixer EXCLUDE_FROM_ALL) add_subdirectory(extern/SDL_ttf EXCLUDE_FROM_ALL) add_subdirectory(extern/tmxlite/tmxlite EXCLUDE_FROM_ALL) + file(GLOB_RECURSE SOURCES ${ENGINE_SOURCE_DIR}/src/*.cpp) add_library(${PROJECT_NAME} ${SOURCES}) diff --git a/include/AssetManager.h b/include/AssetManager.h index 1d3c97a..154b7ea 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -24,28 +24,24 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner); - void createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath); + void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, Textures textureEnum, Entity* owner); + void createPowerup(Vector2D pos, std::function pickupFunc, Textures texture); Vector2D calculateSpawnPosition(); PowerupType calculateType(); - //texture management - void addTexture(std::string id, const char* path); // sound management void addSoundEffect(std::string id, const char* path); void addMusic(std::string id, const char* path); - SDL_Texture* getTexture(std::string id); Mix_Chunk* getSound(std::string id); Mix_Music* getMusic(std::string id); private: Manager* man; - std::map textures; std::map soundEffects; std::map music; }; diff --git a/include/Map.h b/include/Map.h index 244322e..5e96186 100644 --- a/include/Map.h +++ b/include/Map.h @@ -16,7 +16,7 @@ class Map public: /*! * \brief Loads a .tmx map - * \details Loads a `.tmx` file and extracts all relevant data. Any entities (including tiles) are only spawned once + * \details Loads a `.tmx` file and extracts all relevant data. Any entities (including tiles) are only spawned once * \param path Path to the `.tmx` map file * \sa Map::generateTiles() */ diff --git a/include/SpriteComponent.h b/include/SpriteComponent.h index 0676549..0c84359 100644 --- a/include/SpriteComponent.h +++ b/include/SpriteComponent.h @@ -5,6 +5,7 @@ #include #include +#include "Textures.h" #include "AnimationHandler.h" #include "Component.h" #include "Direction.h" @@ -24,7 +25,7 @@ private: SDL_Texture* texture; SDL_Rect srcRect, destRect; - const char* texturePath; + Textures textureEnum; bool animated = false; uint8_t frames = 0; @@ -34,18 +35,24 @@ private: int textureXOffset; int textureYOffset; + //there should be a better solution as this variable is only used for the loading of the tmx map + //TODO: improve this in the future and also remove it from the scope of the developer + const char* path; //empty string if texture has a texture enum value, otherwise the path of the texture + public: - SpriteComponent(const char* path, int zIndex); + SpriteComponent(Textures texture, int zIndex); + SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex); SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex); SpriteComponent( - const char* path, + Textures texture, bool isAnimated, std::map>* animationList, std::string defaultAnimation, int zIndex); ~SpriteComponent(); - void setTexture(const char* path); + void setTexture(Textures texture); + void setMapTileTexture(const char* path); void init() override; void update() override; diff --git a/include/TextureManager.h b/include/TextureManager.h index 3e4f1c4..d77ad18 100644 --- a/include/TextureManager.h +++ b/include/TextureManager.h @@ -6,6 +6,19 @@ #include #include #include +#include "Textures.h" + +/*! + * \class TextureManager + * \brief A manager for loading, caching, and drawing textures. + * + * The `TextureManager` class is responsible for handling texture loading, caching, + * and rendering in the engine. It provides functions to add, load, and draw textures + * from files, as well as manage sprite sheets. + * + * \sa Textures "Textures" are used to identify textures within the engine. + * It is expected that they are implemented within the games scope. + */ class TextureManager { @@ -15,13 +28,59 @@ class TextureManager for (auto& it : this->texture_cache) { SDL_DestroyTexture(it.second); } + for (auto& it : this->mapTile_texture_cache) { + SDL_DestroyTexture(it.second); + } } - std::map texture_cache; + /*! + * \brief Adds a single texture to the cache. + * \param texture The texture identifier. + * \param filePath The file path to the texture file. + * + * This function loads the texture from the specified file and stores it in + * a cache. If loading the texture fails, an exception is thrown. + */ + void addSingleTexture(Textures texture, const char* filePath); - SDL_Texture* loadTexture(const char* fileName); + /*! + * \brief Adds multiple textures to the cache. + * \param textures A map of texture identifiers and corresponding file paths. + * + * This function iterates over the provided map of textures and loads each + * texture using `addSingleTexture`. It allows for several + * textures to be added at once. + */ + void addTextures(const std::map& textures); + + /*! + * \brief Loads a texture from the cache. + * \param texture The texture identifier. + * \return A pointer to the `SDL_Texture` if found, or `nullptr` if not found. + * + * This function looks up a texture within the cache and returns the + * corresponding `SDL_Texture*`. If the texture is not found, it logs an error + * message and returns `nullptr`. + */ + SDL_Texture* loadTexture(Textures texture); static std::vector splitSpriteSheet(SDL_Texture* spriteSheet, int width, int height, int spritesOnSheet); static void draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped = false); + + /*! + * \brief Loads a map tile texture from the file system and caches it. + * \param path The file path to the texture. + * \return `SDL_Texture*` representing the map tile. + * + * This function checks if the map tile texture is already cached. If not, it + * loads the texture from the file system and stores it in the cache. + * + * If loading fails, an exception is thrown with a descriptive error message. + * \todo should not be usable for the developer and only be accessed by the map class + */ + SDL_Texture* loadMapTileTexture(const char* path); + private: Manager* manager; + std::map texture_cache; + std::map mapTile_texture_cache; }; \ No newline at end of file diff --git a/include/Textures.h b/include/Textures.h new file mode 100644 index 0000000..eb63dfd --- /dev/null +++ b/include/Textures.h @@ -0,0 +1,14 @@ +#pragma once + +/*! + * \class Textures + * \brief Forward declaration of the \c Textures enum class. + * + * The \c Textures enum class is intended to be implemented within the game scope. + * This allows for customized texture entries to be defined based on the specific needs of the project. + * The base declaration ensures that the enum class can be referenced and used consistently throughout + * the engine while leaving the details of the texture identifiers up to the implementation. + * \sa \ref TextureManager "TextureManager" for how the enum is used. + */ + +enum class Textures; \ No newline at end of file diff --git a/include/TileComponent.h b/include/TileComponent.h index 8844daa..58f92a5 100644 --- a/include/TileComponent.h +++ b/include/TileComponent.h @@ -5,6 +5,7 @@ #include #include "Component.h" +#include "Textures.h" class SpriteComponent; class TransformComponent; @@ -17,17 +18,19 @@ public: SDL_Rect tileRect; int tileID; - const char* path; + Textures texture; TileComponent() = default; - TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict); + TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict); ~TileComponent() = default; void init() override; - bool hasCollision(){return this->collision;} - std::string getName(){return this->tileName;} + bool hasCollision() { + return this->collision; + } + + private: bool collision; - std::string tileName; }; \ No newline at end of file diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 25ce8ad..273e345 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -15,14 +15,12 @@ #include "PowerupComponent.h" #include +#include "Textures.h" + AssetManager::AssetManager(Manager* manager) : man(manager) {} AssetManager::~AssetManager() {} -void AssetManager::addTexture(std::string id, const char* path) { - textures.emplace(id, this->man->getGame()->textureManager->loadTexture(path)); -} - void AssetManager::addSoundEffect(std::string id, const char* path) { soundEffects.emplace(id, this->man->getGame()->soundManager->loadSound(path)); @@ -33,9 +31,6 @@ void AssetManager::addMusic(std::string id, const char* path) music.emplace(id, this->man->getGame()->soundManager->loadMusic(path)); } -SDL_Texture* AssetManager::getTexture(std::string id) { - return textures.at(id); -} Mix_Chunk* AssetManager::getSound(std::string id) { return soundEffects.at(id); @@ -46,23 +41,23 @@ Mix_Music* AssetManager::getMusic(std::string id) return music.at(id); } -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, const char* texturePath, Entity* owner) { +void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, int speed, Textures textureEnum, Entity* owner) { auto& projectile(man->addEntity()); projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects - projectile.addComponent(texturePath, 4); + projectile.addComponent(textureEnum, 4); projectile.addComponent(range, speed, velocity, owner); projectile.addComponent("projectile", 0.6f); projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE); } -void AssetManager::createPowerup(Vector2D pos, std::function pickupFunc, std::string texturePath) { +void AssetManager::createPowerup(Vector2D pos, std::function pickupFunc, Textures texture) { auto& powerups(man->addEntity()); powerups.addComponent(pos.x, pos.y, 32, 32, 1); //32x32 is standard size for objects try { - powerups.addComponent(texturePath.c_str(), 3); + powerups.addComponent(texture, 3); } catch (std::runtime_error e) { std::cout << e.what() << std::endl; diff --git a/src/Map.cpp b/src/Map.cpp index dab109b..9eb9212 100644 --- a/src/Map.cpp +++ b/src/Map.cpp @@ -39,7 +39,7 @@ template<> std::optional Map::getLayerProperty(const std::vector std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) +template<> std::optional Map::getLayerProperty(const std::vector& properties, std::string propertyName) { auto zIndexIterator = std::ranges::find_if(properties, [propertyName](const tmx::Property& property) { return property.getName().compare(propertyName) == 0; @@ -104,7 +104,7 @@ void Map::loadTileLayer(const tmx::TileLayer& layer) tmx::Vector2i textureSize; SDL_QueryTexture( - VEGO_Game().textureManager->loadTexture(texturePath), + VEGO_Game().textureManager->loadMapTileTexture(texturePath), nullptr, nullptr, &(textureSize.x), @@ -170,6 +170,7 @@ void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int tile.addComponent(x, y, mapTileSize.x, mapTileSize.y, 1); tile.addComponent(texturePath.c_str(), v, u, zIndex); // why does uv need to be reversed? + //TODO: also implement updated map stuff for this if (hasCollision) { // tag currently does not have a clear purposes, TODO: figure out appropriate tag name @@ -178,7 +179,7 @@ void Map::addTile(float x, float y, const tmx::Vector2u& mapTileSize, int u, int } } -void Map::generateTiles() +void Map::generateTiles() { std::ranges::for_each(this->tileConstructors, [](auto& function) { function(); diff --git a/src/SpriteComponent.cpp b/src/SpriteComponent.cpp index ae27ea7..80ef7a0 100644 --- a/src/SpriteComponent.cpp +++ b/src/SpriteComponent.cpp @@ -15,18 +15,25 @@ #include "Manager.h" #include "VEGO.h" -SpriteComponent::SpriteComponent(const char* path, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0) +SpriteComponent::SpriteComponent(Textures texture, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(0), textureYOffset(0) { - this->texturePath = path; + this->textureEnum = texture; + this->path = ""; } -SpriteComponent::SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) +SpriteComponent::SpriteComponent(Textures texture, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) { - this->texturePath = path; + this->textureEnum = texture; + this->path = ""; +} + +SpriteComponent::SpriteComponent(const char* path, int xOffset, int yOffset, int zIndex) : RenderObject(zIndex, VEGO_Game().renderManager), textureXOffset(xOffset), textureYOffset(yOffset) { + + this->path = path; } SpriteComponent::SpriteComponent( - const char* path, + Textures texture, bool isAnimated, std::map>* animationMap, std::string defaultAnimation, @@ -38,19 +45,26 @@ SpriteComponent::SpriteComponent( playAnimation(defaultAnimation); - this->texturePath = path; + this->textureEnum = texture; + + this->path = ""; } SpriteComponent::~SpriteComponent() {} -void SpriteComponent::setTexture(const char* path) +void SpriteComponent::setTexture(Textures texture) { - this->texture = VEGO_Game().textureManager->loadTexture(path); + this->texture = VEGO_Game().textureManager->loadTexture(texture); } void SpriteComponent::init() { - setTexture(this->texturePath); + if (this->path == "") { + setTexture(this->textureEnum); + } + else { + setMapTileTexture(this->path); + } this->transform = &entity->getComponent(); @@ -92,4 +106,8 @@ void SpriteComponent::playAnimation(std::string type) void SpriteComponent::setDirection(Direction direction) { this->flipped = direction == Direction::RIGHT; -} \ No newline at end of file +} + +void SpriteComponent::setMapTileTexture(const char *path) { + this->texture = VEGO_Game().textureManager->loadMapTileTexture(path); +} diff --git a/src/TextureManager.cpp b/src/TextureManager.cpp index 3e46d46..3b81ee3 100644 --- a/src/TextureManager.cpp +++ b/src/TextureManager.cpp @@ -3,24 +3,56 @@ #include #include #include +#include #include "GameInternal.h" -SDL_Texture* TextureManager::loadTexture(const char* fileName) -{ - auto it = this->texture_cache.find(fileName); - if (it != this->texture_cache.end()) { - return it->second; + +void TextureManager::addSingleTexture(Textures texture, const char* filePath) { + auto sdlTexture = IMG_LoadTexture(VEGO_Game().renderer, filePath); + + if (sdlTexture == nullptr) + throw std::runtime_error(std::string("Couldn't load texture '") + filePath + "'"); + + this->texture_cache.emplace(texture, sdlTexture); + std::cout << "Loaded texture at " << filePath << std::endl; +} + +void TextureManager::addTextures(const std::map &textures) { + for (auto texture : textures) { + addSingleTexture(texture.first, texture.second); } - auto texture = IMG_LoadTexture(this->manager->getGame()->renderer, fileName); - if (texture == NULL) throw std::runtime_error(std::string("Couldn't load texture '") + fileName + "'"); - this->texture_cache.emplace(std::string(fileName), texture); - printf("Loaded texture at '%s'\n", fileName); - return texture; +} + + +SDL_Texture* TextureManager::loadTexture(Textures texture) { + auto it = this->texture_cache.find(texture); + + if (it != this->texture_cache.end()) + return it->second; + + std::cout << "ERROR: Couldn't load texture!" << std::endl; + return nullptr; } void TextureManager::draw(SDL_Renderer* renderer, SDL_Texture* texture, SDL_Rect src, SDL_Rect dest, bool flipped) { SDL_RendererFlip flip = flipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE; SDL_RenderCopyEx(renderer, texture, &src, &dest, 0, NULL, flip); -} \ No newline at end of file +} + +SDL_Texture* TextureManager::loadMapTileTexture(const char *path) { + + //returns tile if it exists already + if(mapTile_texture_cache.contains(std::string(path))) + return mapTile_texture_cache.find(std::string(path))->second; + + auto newTexture = IMG_LoadTexture(VEGO_Game().renderer, path); + + if (newTexture == nullptr) + throw std::runtime_error(std::string("Couldn't load texture '") + path + "'"); + + this->mapTile_texture_cache.emplace(std::string(path), newTexture); + + return newTexture; +} diff --git a/src/TileComponent.cpp b/src/TileComponent.cpp index 4c33bf7..324c621 100644 --- a/src/TileComponent.cpp +++ b/src/TileComponent.cpp @@ -5,9 +5,9 @@ #include "Entity.h" #include "TransformComponent.h" #include "SpriteComponent.h" -#include "TileComponent.h" -TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict) + +TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map>* textureDict) { this->tileRect.x = x; this->tileRect.y = y; @@ -22,8 +22,7 @@ TileComponent::TileComponent(int x, int y, int w, int h, int id, const std::map< } this->collision = it->second.second; - this->tileName = it->second.first; - this->path = it->second.first.data(); + this->texture = it->second.first; } void TileComponent::init() @@ -31,7 +30,7 @@ void TileComponent::init() this->entity->addComponent(this->tileRect.x, this->tileRect.y, this->tileRect.w, this->tileRect.h, 1); this->transform = &entity->getComponent(); - this->entity->addComponent(this->path, 0); + this->entity->addComponent(this->texture, 0); this->sprite = &entity->getComponent(); }