Skip to content
Snippets Groups Projects
Select Git revision
  • 43c20b41fbdb835318d7e53a5dea0ca8a03b4a7a
  • 5.4 default protected
  • 5.5
  • dev/5.5
  • dev/5.4
  • dev/5.3_downgrade
  • feature/experimenttime_hack
  • 5.3 protected
  • _IntenSelect5.3
  • IntenSelect5.3
  • 4.27 protected
  • 4.26 protected
  • 5.0 protected
  • 4.22 protected
  • 4.21 protected
  • UE5.4-2024.1
  • UE5.4-2024.1-rc1
  • UE5.3-2023.1-rc3
  • UE5.3-2023.1-rc2
  • UE5.3-2023.1-rc
20 results

VirtualRealityPawn.cpp

Blame
  • Spritesheet.cpp 16.31 KiB
    /**
     * Spritesheet.hpp
     *
     * @date 30.1.2025
     * @author David Maul
     * @author Frederik Keens
     */
    
    #include "Spritesheet.hpp"
    #include "Engine.hpp"
    
    #include <SDL_image.h>
    #include <SDL_render.h>
    #include <cstddef>
    #include <cstdint>
    #include <highfive/H5File.hpp>
    #include <stdexcept>
    #include <string>
    #include <vector>
    
    namespace advanced_wars
    {
    
    Spritesheet::Spritesheet(std::string path, Engine& engine)
        : m_tileWidth(16), m_tileHeight(16), m_buildingWidth(16), m_buildingHeight(32)
    {
    
        HighFive::File file(path, HighFive::File::ReadOnly);
    
        // Tiles
        std::vector<std::string> tiles(
            {"plain",
             "water",
             "forest",
             "mountain",
             "bridge_horizontal",
             "bridge_vertical",
             "street_horizontal",
             "street_vertical",
             "street_crossing",
             "street_junction_right",
             "street_junction_left",
             "street_junction_down",
             "street_junction_up",
             "street_corner_top_left",
             "street_corner_top_right",
             "street_corner_bottom_left",
             "street_corner_bottom_right",
             "riff",
             "cliff_top",
             "cliff_bottom",
             "cliff_left",
             "cliff_right",
             "cliff_corner_top_left",
             "cliff_corner_top_right",
             "cliff_corner_bottom_left",
             "cliff_corner_bottom_right",
             "cliff_inverse_corner_top_left",
             "cliff_inverse_corner_top_right",
             "cliff_inverse_corner_bottom_left",
             "cliff_inverse_corner_bottom_right"});
    
        // every sub data set of tiles
        for (const auto& tile : tiles)
        {
            HighFive::DataSet unitsDs = file.getDataSet("tiles/" + tile);
    
            std::vector<std::vector<std::vector<uint32_t>>> tileFrames;
            unitsDs.read(tileFrames);
    
            std::vector<uint32_t> tileBuffer(16 * 16 * tileFrames.size(), 0);
    
            // every animation frame
            for (size_t n = 0; n < tileFrames.size(); n++)
            {
                for (size_t y = 0; y < 16; y++)
                {
                    for (size_t x = 0; x < 16; x++)
                    {
                        size_t index = (y * tileFrames.size() * 16) + (n * 16 + x);
    
                        tileBuffer.at(index) = tileFrames.at(n).at(16 - y - 1).at(x);
                    }
                }
            }
    
            SDL_Texture* tmp = SDL_CreateTexture(
                engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC,
                tileFrames.size() * 16, 16);
    
            SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
    
            if (tmp == nullptr)
            {
                throw std::runtime_error(
                    "Fehler beim Erstellen der Textur für die Tiles: " + std::string(SDL_GetError()));
            }
    
            if (SDL_UpdateTexture(
                    tmp, nullptr, tileBuffer.data(), tileFrames.size() * 16 * sizeof(int32_t)) != 0)
            {
                throw std::runtime_error(
                    "Fehler beim updaten der Textur für die Tiles: " + std::string(SDL_GetError()));
            }
    
            m_tileTextures.emplace_back(tmp, tileFrames.size());
        }
    
        // Buildings
        std::vector<std::string> buildingFactions(
            {"red", "blue", "green", "yellow", "purple", "neutral"});
    
        // every sub data set of buildings
        for (const std::string& faction : buildingFactions)
        {
            HighFive::DataSet buildingsDs = file.getDataSet("buildings/" + faction);
    
            std::vector<std::vector<std::vector<uint32_t>>> buildingsFrames;
    
            buildingsDs.read(buildingsFrames);
    
            std::vector<uint32_t> buildingBuffer(32 * 16 * buildingsFrames.size(), 0);
    
            // every type of building
            for (size_t n = 0; n < buildingsFrames.size(); n++)
            {
                for (size_t y = 0; y < 32; y++)
                {
                    for (size_t x = 0; x < 16; x++)
                    {
                        size_t index = (y * buildingsFrames.size() * 16) + (n * 16 + x);
    
                        buildingBuffer.at(index) = buildingsFrames.at(n).at(32 - y - 1).at(x);
                    }
                }
            }
    
            SDL_Texture* tmp = SDL_CreateTexture(
                engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC,
                buildingsFrames.size() * 16, 32);
    
            SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
    
            if (tmp == nullptr)
            {
                throw std::runtime_error(
                    "Fehler beim Erstellen der Textur für die Buildings: " +
                    std::string(SDL_GetError()));
            }
    
            if (SDL_UpdateTexture(
                    tmp, nullptr, buildingBuffer.data(),
                    buildingsFrames.size() * 16 * sizeof(int32_t)) != 0)
            {
                throw std::runtime_error(
                    "Fehler beim updaten der Textur für die Buildings: " + std::string(SDL_GetError()));
            }
    
            this->m_buildingTextures.push_back(tmp);
        }
    
        // Units
        std::vector<std::string> unitFactions({"red", "blue", "green", "yellow", "purple"});
    
        std::vector<std::string> units(
            {"infantery", "mechanized_infantery", "recon", "medium_tank", "heavy_tank", "neo_tank",
             "apc", "anti_air_tank", "artillery", "rocket_artillery", "anti_air_missile_launcher",
             "fighter", "bomber", "battle_helicopter", "transport_helicopter", "battleship", "cruiser",
             "lander", "submarine"});
    
        std::vector<std::string> unitStates({"idle", "unavailable"});
        std::vector<std::string> unitMovementStates({"left", "right", "down", "up"});
    
        // every factions sub data set
        for (size_t factionIdx = 0; factionIdx < unitFactions.size(); factionIdx++)
        {
            const std::string& faction = unitFactions.at(factionIdx);
            // Create entry for units for in a faction
            m_unitTextures.emplace_back();
    
            // every unit sub data set
            for (size_t unitIdx = 0; unitIdx < units.size(); unitIdx++)
            {
                const std::string& unit = units.at(unitIdx);
    
                // Create entry for states for a unit
                m_unitTextures.at(factionIdx).emplace_back();
    
                // every state sub data set
                for (const auto& unitState : unitStates)
                {
                    HighFive::DataSet unitsDs =
                        file.getDataSet("units/" + faction + "/" + unit + "/" + unitState);
    
                    std::vector<std::vector<std::vector<uint32_t>>> unitFrames;
                    unitsDs.read(unitFrames);
    
                    std::vector<uint32_t> unitBuffer(16 * 16 * unitFrames.size(), 0);
    
                    for (size_t n = 0; n < unitFrames.size(); n++)
                    {
                        for (size_t y = 0; y < 16; y++)
                        {
                            for (size_t x = 0; x < 16; x++)
                            {
                                size_t index = (y * unitFrames.size() * 16) + (n * 16 + x);
    
                                unitBuffer.at(index) = unitFrames.at(n).at(16 - y - 1).at(x);
                            }
                        }
                    }
    
                    SDL_Texture* tmp = SDL_CreateTexture(
                        engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC,
                        unitFrames.size() * 16, 16);
    
                    SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
    
                    if (tmp == nullptr)
                    {
                        throw std::runtime_error(
                            "Fehler beim Erstellen der Textur für die Units: " +
                            std::string(SDL_GetError()));
                    }
    
                    if (SDL_UpdateTexture(
                            tmp, nullptr, unitBuffer.data(),
                            unitFrames.size() * 16 * sizeof(int32_t)) != 0)
                    {
                        throw std::runtime_error(
                            "Fehler beim updaten der Textur für die Units: " +
                            std::string(SDL_GetError()));
                    }
    
                    m_unitTextures.at(factionIdx).at(unitIdx).emplace_back(tmp, unitFrames.size());
                }
    
                // every movement state sub data set
                for (const auto& movementState : unitMovementStates)
                {
                    HighFive::DataSet unitsDs =
                        file.getDataSet("units/" + faction + "/" + unit + "/movement/" + movementState);
    
                    std::vector<std::vector<std::vector<uint32_t>>> unitFrames;
                    unitsDs.read(unitFrames);
    
                    std::vector<uint32_t> unitBuffer(24 * 24 * unitFrames.size(), 0);
    
                    for (size_t n = 0; n < unitFrames.size(); n++)
                    {
                        for (size_t y = 0; y < 24; y++)
                        {
                            for (size_t x = 0; x < 24; x++)
                            {
                                size_t index = (y * unitFrames.size() * 24) + (n * 24 + x);
    
                                unitBuffer.at(index) = unitFrames.at(n).at(24 - y - 1).at(x);
                            }
                        }
                    }
    
                    SDL_Texture* tmp = SDL_CreateTexture(
                        engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC,
                        unitFrames.size() * 24, 24);
    
                    SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
    
                    if (tmp == nullptr)
                    {
                        throw std::runtime_error(
                            "Fehler beim Erstellen der Textur für die Units: " +
                            std::string(SDL_GetError()));
                    }
    
                    if (SDL_UpdateTexture(
                            tmp, nullptr, unitBuffer.data(),
                            unitFrames.size() * 24 * sizeof(int32_t)) != 0)
                    {
                        throw std::runtime_error(
                            "Fehler beim updaten der Textur für die Units: " +
                            std::string(SDL_GetError()));
                    }
    
                    m_unitTextures.at(factionIdx).at(unitIdx).emplace_back(tmp, unitFrames.size());
                }
            }
        }
    
        this->m_unitWidth = 16;
        this->m_unitHeight = 16;
        this->m_unitMovingWidth = 24;
        this->m_unitMovingHeight = 24;
    
        // Effects
        std::vector<std::string> effects(
            {"land_explosion", "air_explosion", "naval_explosion", "submarine_hide",
             "submarine_appear"});
    
        // Every effect sub data set
        for (size_t effectIdx = 0; effectIdx < effects.size(); effectIdx++)
        {
            HighFive::DataSet effectDs = file.getDataSet("effects/" + effects[effectIdx]);
    
            std::vector<std::vector<std::vector<uint32_t>>> effectFrames;
            effectDs.read(effectFrames);
    
            std::vector<uint32_t> effectBuffer(32 * 32 * effectFrames.size(), 0);
    
            // every animation frame
            for (size_t n = 0; n < effectFrames.size(); n++)
            {
                for (size_t y = 0; y < 32; y++)
                {
                    for (size_t x = 0; x < 32; x++)
                    {
                        size_t index = (y * effectFrames.size() * 32) + (n * 32 + x);
    
                        effectBuffer.at(index) = effectFrames.at(n).at(32 - y - 1).at(x);
                    }
                }
            }
    
            SDL_Texture* tmp = SDL_CreateTexture(
                engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC,
                effectFrames.size() * 32, 32);
    
            SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
    
            if (tmp == nullptr)
            {
                throw std::runtime_error(
                    "Fehler beim Erstellen der Textur für die Effects: " + std::string(SDL_GetError()));
            }
    
            if (SDL_UpdateTexture(
                    tmp, nullptr, effectBuffer.data(), effectFrames.size() * 32 * sizeof(int32_t)) != 0)
            {
                throw std::runtime_error(
                    "Fehler beim updaten der Textur für die Tiles: " + std::string(SDL_GetError()));
            }
    
            m_effectTextures.emplace_back(tmp, effectFrames.size());
        }
    
        this->m_effectWidth = 32;
        this->m_effectHeight = 32;
    
        // Numbers
        HighFive::DataSet numberDs = file.getDataSet("/misc/numbers");
    
        std::vector<std::vector<uint32_t>> numberFrames;
        numberDs.read(numberFrames);
    
        std::vector<uint32_t> numberBuffer(8 * 80, 0);
    
        for (int y = 0; y < 8; y++)
        {
            for (int x = 0; x < 80; x++)
            {
                int index = (y * 80) + x;
                numberBuffer.at(index) = numberFrames.at(8 - y - 1).at(x);
            }
        }
    
        SDL_Texture* tmp = SDL_CreateTexture(
            engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 80, 8);
    
        SDL_SetTextureBlendMode(tmp, SDL_BLENDMODE_BLEND);
    
        if (tmp == nullptr)
        {
            throw std::runtime_error(
                "Fehler beim Erstellen der Textur für die Numbers: " + std::string(SDL_GetError()));
        }
    
        if (SDL_UpdateTexture(tmp, nullptr, numberBuffer.data(), 80 * sizeof(int32_t)) != 0)
        {
            throw std::runtime_error(
                "Fehler beim updaten der Textur für die Numbers: " + std::string(SDL_GetError()));
        }
    
        this->m_numberTextures = tmp;
        this->m_numberWidth = 8;
        this->m_numberHeight = 8;
    
        // Bullet
        HighFive::DataSet bulletDs = file.getDataSet("/misc/bullet");
    
        std::vector<std::vector<uint32_t>> bulletFrames;
        bulletDs.read(bulletFrames);
    
        std::vector<uint32_t> bulletBuffer(8 * 8, 0);
    
        // every animation frame
    
        for (size_t y = 0; y < 8; y++)
        {
            for (size_t x = 0; x < 8; x++)
            {
                size_t index = (y * 8) + x;
    
                numberBuffer.at(index) = bulletFrames.at(8 - y - 1).at(x);
            }
        }
    
        SDL_Texture* bulletTmp = SDL_CreateTexture(
            engine.renderer(), SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STATIC, 8, 8);
    
        SDL_SetTextureBlendMode(bulletTmp, SDL_BLENDMODE_BLEND);
    
        if (bulletTmp == nullptr)
        {
            throw std::runtime_error(
                "Fehler beim Erstellen der Textur für die Bullets: " + std::string(SDL_GetError()));
        }
    
        if (SDL_UpdateTexture(bulletTmp, nullptr, numberBuffer.data(), 8 * sizeof(int32_t)) != 0)
        {
            throw std::runtime_error(
                "Fehler beim updaten der Textur für die Bullets: " + std::string(SDL_GetError()));
        }
    
        this->m_bulletTexture = bulletTmp;
        this->m_bulletWidth = 8;
        this->m_bulletHeight = 8;
    }
    
    // Tiles
    
    int Spritesheet::getTileWidth()
    {
        return m_tileWidth;
    }
    
    int Spritesheet::getTileHeight()
    {
        return m_tileHeight;
    }
    
    std::vector<std::pair<SDL_Texture*, int>>& Spritesheet::getTileTextures()
    {
        return m_tileTextures;
    }
    
    // Buildings
    int Spritesheet::getBuildingWidth()
    {
        return this->m_buildingWidth;
    }
    
    int Spritesheet::getBuildingHeight()
    {
        return this->m_buildingHeight;
    }
    
    std::vector<SDL_Texture*>& Spritesheet::getBuildingTextures()
    {
        return m_buildingTextures;
    }
    
    // Units
    int Spritesheet::getUnitWidth()
    {
        return this->m_unitWidth;
    }
    
    int Spritesheet::getUnitHeight()
    {
        return this->m_unitHeight;
    }
    
    int Spritesheet::getUnitMovingWidth()
    {
        return this->m_unitMovingWidth;
    }
    
    int Spritesheet::getUnitMovingHeight()
    {
        return this->m_unitMovingHeight;
    }
    
    std::vector<std::vector<std::vector<std::pair<SDL_Texture*, int>>>>& Spritesheet::getUnitTextures()
    {
        return this->m_unitTextures;
    }
    
    // Effects
    int Spritesheet::getEffectWidth()
    {
        return this->m_effectWidth;
    }
    
    int Spritesheet::getEffectHeight()
    {
        return this->m_effectHeight;
    }
    
    std::vector<std::pair<SDL_Texture*, int>>& Spritesheet::getEffectTextures()
    {
        return this->m_effectTextures;
    }
    
    // Numbers
    int Spritesheet::getNumberWidth()
    {
        return this->m_numberWidth;
    }
    
    int Spritesheet::getNumberHeight()
    {
        return this->m_numberHeight;
    }
    
    SDL_Texture* Spritesheet::getNumberTexture()
    {
        return this->m_numberTextures;
    }
    
    // Bullet
    SDL_Texture* Spritesheet::getBulletTexture()
    {
        return this->m_bulletTexture;
    }
    
    int Spritesheet::getBulletWidth()
    {
        return this->m_bulletWidth;
    }
    
    int Spritesheet::getBulletHeight()
    {
        return this->m_bulletHeight;
    }
    
    Spritesheet::~Spritesheet()
    {
        for (std::pair<SDL_Texture*, int> tileTexture : m_tileTextures)
        {
            SDL_DestroyTexture(tileTexture.first);
        }
    
        for (SDL_Texture* buildingTexture : m_buildingTextures)
        {
            SDL_DestroyTexture(buildingTexture);
        }
    
        for (const std::vector<std::vector<std::pair<SDL_Texture*, int>>>& faction : m_unitTextures)
        {
            for (const std::vector<std::pair<SDL_Texture*, int>>& unit : faction)
            {
                for (std::pair<SDL_Texture*, int> state : unit)
                {
                    SDL_DestroyTexture(state.first);
                }
            }
        }
    
        for (auto& [texture, i] : m_effectTextures)
        {
            SDL_DestroyTexture(texture);
        }
    
        SDL_DestroyTexture(m_numberTextures);
    
        SDL_DestroyTexture(m_bulletTexture);
    }
    
    } // namespace advanced_wars