Compare commits
2 Commits
6534996a52
...
drug
| Author | SHA1 | Date | |
|---|---|---|---|
| ee3c263547 | |||
| 66c5e0e710 |
@@ -4,6 +4,19 @@ project(Letnik3Zadnja)
|
|||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
if(APPLE AND NOT CMAKE_OSX_SYSROOT)
|
||||||
|
execute_process(
|
||||||
|
COMMAND xcrun --sdk macosx --show-sdk-path
|
||||||
|
OUTPUT_VARIABLE _macos_sdk_path
|
||||||
|
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||||
|
ERROR_QUIET
|
||||||
|
)
|
||||||
|
|
||||||
|
if(_macos_sdk_path)
|
||||||
|
set(CMAKE_OSX_SYSROOT "${_macos_sdk_path}" CACHE PATH "macOS SDK path" FORCE)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
option(FETCH "Fetch SDL dependencies instead of using system-installed packages" OFF)
|
option(FETCH "Fetch SDL dependencies instead of using system-installed packages" OFF)
|
||||||
|
|
||||||
# Compile flags
|
# Compile flags
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ namespace Game::Object {
|
|||||||
std::string mLastRenderedText; // to avoid rebuilding font unnecessarily
|
std::string mLastRenderedText; // to avoid rebuilding font unnecessarily
|
||||||
std::string mPlaceholder = "";
|
std::string mPlaceholder = "";
|
||||||
float mReservedPlaceholderWidth = 0.f; // Reserved pixel width for placeholder to avoid layout shifts
|
float mReservedPlaceholderWidth = 0.f; // Reserved pixel width for placeholder to avoid layout shifts
|
||||||
|
bool mIsHovered = false;
|
||||||
std::mutex mRenderMutex; // Protects mLastRenderedText and mReservedPlaceholderWidth from main-thread updates
|
std::mutex mRenderMutex; // Protects mLastRenderedText and mReservedPlaceholderWidth from main-thread updates
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,12 +7,128 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
|
#include <cstdint>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
#include <sstream>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
#include <utils.hpp>
|
#include <utils.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
constexpr const char* kLeaderboardFile = "leaderboard.bin";
|
||||||
|
constexpr std::size_t kLeaderboardNameCapacity = 24;
|
||||||
|
|
||||||
|
struct LeaderboardEntry {
|
||||||
|
char name[kLeaderboardNameCapacity + 1]{};
|
||||||
|
std::int32_t score = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::string trimLeaderboardName(const std::string& name) {
|
||||||
|
return name.substr(0, kLeaderboardNameCapacity);
|
||||||
|
}
|
||||||
|
|
||||||
|
LeaderboardEntry makeLeaderboardEntry(const std::string& name, int score) {
|
||||||
|
LeaderboardEntry entry{};
|
||||||
|
const std::string truncatedName = trimLeaderboardName(name);
|
||||||
|
std::copy(truncatedName.begin(), truncatedName.end(), entry.name);
|
||||||
|
entry.score = static_cast<std::int32_t>(score);
|
||||||
|
return entry;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<LeaderboardEntry> loadLeaderboardEntries() {
|
||||||
|
std::vector<LeaderboardEntry> entries;
|
||||||
|
|
||||||
|
std::ifstream file(kLeaderboardFile, std::ios::binary);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
LeaderboardEntry entry{};
|
||||||
|
file.read(entry.name, sizeof(entry.name));
|
||||||
|
if (!file) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.read(reinterpret_cast<char*>(&entry.score), sizeof(entry.score));
|
||||||
|
if (!file) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
entries.push_back(entry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return entries;
|
||||||
|
}
|
||||||
|
|
||||||
|
void saveLeaderboardEntries(const std::vector<LeaderboardEntry>& entries) {
|
||||||
|
std::ofstream file(kLeaderboardFile, std::ios::binary | std::ios::trunc);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
WARN("Neuspešno odpiranje leaderboard.bin za pisanje");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto& entry : entries) {
|
||||||
|
file.write(entry.name, sizeof(entry.name));
|
||||||
|
file.write(reinterpret_cast<const char*>(&entry.score), sizeof(entry.score));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void upsertLeaderboardEntry(std::vector<LeaderboardEntry>& entries, const std::string& playerName, int score) {
|
||||||
|
const std::string truncatedName = trimLeaderboardName(playerName);
|
||||||
|
entries.erase(
|
||||||
|
std::remove_if(entries.begin(), entries.end(), [&](const LeaderboardEntry& entry) {
|
||||||
|
return truncatedName == entry.name;
|
||||||
|
}),
|
||||||
|
entries.end()
|
||||||
|
);
|
||||||
|
|
||||||
|
entries.push_back(makeLeaderboardEntry(truncatedName, score));
|
||||||
|
|
||||||
|
std::sort(entries.begin(), entries.end(), [](const LeaderboardEntry& left, const LeaderboardEntry& right) {
|
||||||
|
if (left.score != right.score) {
|
||||||
|
return left.score > right.score;
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::string_view(left.name) < std::string_view(right.name);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string formatLeaderboardEntries(const std::vector<LeaderboardEntry>& entries) {
|
||||||
|
std::ostringstream stream;
|
||||||
|
stream << "Lestvica:";
|
||||||
|
|
||||||
|
if (entries.empty()) {
|
||||||
|
stream << "\n(brez vpisov)";
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (std::size_t index = 0; index < entries.size(); ++index) {
|
||||||
|
stream << "\n" << (index + 1) << ". " << entries[index].name << " - " << entries[index].score;
|
||||||
|
}
|
||||||
|
|
||||||
|
return stream.str();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string loadLeaderboardText() {
|
||||||
|
return formatLeaderboardEntries(loadLeaderboardEntries());
|
||||||
|
}
|
||||||
|
|
||||||
|
void refreshLeaderboardHudText() {
|
||||||
|
Game::GameManager::setSharedData("leaderboardText", loadLeaderboardText());
|
||||||
|
}
|
||||||
|
|
||||||
void writeFinalScoreFile(int score) {
|
void writeFinalScoreFile(int score) {
|
||||||
|
std::vector<LeaderboardEntry> leaderboardEntries = loadLeaderboardEntries();
|
||||||
|
std::string leaderboardPlayerName = Game::GameManager::getSharedData<std::string>("playerName");
|
||||||
|
if (leaderboardPlayerName.empty()) {
|
||||||
|
leaderboardPlayerName = "Player";
|
||||||
|
}
|
||||||
|
|
||||||
|
upsertLeaderboardEntry(leaderboardEntries, leaderboardPlayerName, score);
|
||||||
|
saveLeaderboardEntries(leaderboardEntries);
|
||||||
|
|
||||||
std::ofstream file("score.txt", std::ios::trunc);
|
std::ofstream file("score.txt", std::ios::trunc);
|
||||||
if (!file.is_open()) {
|
if (!file.is_open()) {
|
||||||
WARN("Neuspešno odpiranje score.txt za pisanje");
|
WARN("Neuspešno odpiranje score.txt za pisanje");
|
||||||
@@ -73,6 +189,7 @@ namespace Game::AGame {
|
|||||||
GameManager::setSharedData("gameStage", 1);
|
GameManager::setSharedData("gameStage", 1);
|
||||||
GameManager::setSharedData("gameWon", false);
|
GameManager::setSharedData("gameWon", false);
|
||||||
GameManager::setSharedData("gameLost", false);
|
GameManager::setSharedData("gameLost", false);
|
||||||
|
GameManager::setSharedData("leaderboardText", loadLeaderboardText());
|
||||||
|
|
||||||
mZIndex = -1; // Ensure background renders behind other entities
|
mZIndex = -1; // Ensure background renders behind other entities
|
||||||
mTex->setTiled(true); // Set the background texture to be tiled
|
mTex->setTiled(true); // Set the background texture to be tiled
|
||||||
@@ -280,6 +397,16 @@ namespace Game::AGame {
|
|||||||
void Background::update(float deltaTime) {
|
void Background::update(float deltaTime) {
|
||||||
(void)deltaTime;
|
(void)deltaTime;
|
||||||
|
|
||||||
|
if (GameManager::getSharedData<bool>("gameLost")) {
|
||||||
|
refreshLeaderboardHudText();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GameManager::getSharedData<bool>("gameWon")) {
|
||||||
|
refreshLeaderboardHudText();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const int enemyCount = GameManager::getSharedData<int>("enemyActiveCount");
|
const int enemyCount = GameManager::getSharedData<int>("enemyActiveCount");
|
||||||
const int trashCount = GameManager::getSharedData<int>("trashActiveCount");
|
const int trashCount = GameManager::getSharedData<int>("trashActiveCount");
|
||||||
const int stage = GameManager::getSharedData<int>("gameStage");
|
const int stage = GameManager::getSharedData<int>("gameStage");
|
||||||
@@ -347,6 +474,7 @@ namespace Game::AGame {
|
|||||||
mPendingLevelStage = stage + 1;
|
mPendingLevelStage = stage + 1;
|
||||||
} else if (!GameManager::getSharedData<bool>("gameWon")) {
|
} else if (!GameManager::getSharedData<bool>("gameWon")) {
|
||||||
writeFinalScoreFile(GameManager::getSharedData<int>("gameScore"));
|
writeFinalScoreFile(GameManager::getSharedData<int>("gameScore"));
|
||||||
|
refreshLeaderboardHudText();
|
||||||
GameManager::setSharedData("gameWon", true);
|
GameManager::setSharedData("gameWon", true);
|
||||||
LOG("Vsi nivoji so zaključeni");
|
LOG("Vsi nivoji so zaključeni");
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,18 +33,28 @@ namespace Game::AGame {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (GameManager::getSharedData<bool>("gameLost")) {
|
if (GameManager::getSharedData<bool>("gameLost")) {
|
||||||
if (getText() != "Umrl si!") {
|
const std::string leaderboardText = GameManager::getSharedData<std::string>("leaderboardText");
|
||||||
const std::string s = "Umrl si!";
|
std::string endText = "Umrl si!";
|
||||||
Window::Window::postToMainThread([this, s]() { setText(s); });
|
if (!leaderboardText.empty()) {
|
||||||
|
endText += "\n\n" + leaderboardText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getText() != endText) {
|
||||||
|
Window::Window::postToMainThread([this, endText]() { setText(endText); });
|
||||||
}
|
}
|
||||||
anchorTopRight();
|
anchorTopRight();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (GameManager::getSharedData<bool>("gameWon")) {
|
if (GameManager::getSharedData<bool>("gameWon")) {
|
||||||
if (getText() != "Zmagal si!") {
|
const std::string leaderboardText = GameManager::getSharedData<std::string>("leaderboardText");
|
||||||
const std::string s = "Zmagal si!";
|
std::string endText = "Zmagal si!";
|
||||||
Window::Window::postToMainThread([this, s]() { setText(s); });
|
if (!leaderboardText.empty()) {
|
||||||
|
endText += "\n\n" + leaderboardText;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getText() != endText) {
|
||||||
|
Window::Window::postToMainThread([this, endText]() { setText(endText); });
|
||||||
}
|
}
|
||||||
anchorTopRight();
|
anchorTopRight();
|
||||||
return;
|
return;
|
||||||
|
|||||||
@@ -255,17 +255,17 @@ int main() {
|
|||||||
|
|
||||||
// Title text (centered)
|
// Title text (centered)
|
||||||
auto* title = dynamic_cast<Game::Object::UIText*>(State::GameState::getInstance().addEntity(std::make_unique<Game::Object::UIText>("Title", titleFont, Object::DEFAULT_TRANSFORM, cx, titleY)));
|
auto* title = dynamic_cast<Game::Object::UIText*>(State::GameState::getInstance().addEntity(std::make_unique<Game::Object::UIText>("Title", titleFont, Object::DEFAULT_TRANSFORM, cx, titleY)));
|
||||||
if (title) title->setText("Game Name");
|
if (title) title->setText("Dol s Plastiko!");
|
||||||
|
|
||||||
// Name input box (larger and more visible) with a light gray background
|
// Name input box (larger and more visible) with a light gray background
|
||||||
auto textboxBg = createSolidColorTexture(gSDLRenderer, 400, 70, 180, 180, 180, 220); // Larger, slightly darker gray
|
auto textboxBg = createSolidColorTexture(gSDLRenderer, 400, 70, 180, 180, 180, 220); // Larger, slightly darker gray
|
||||||
auto* nameBox = dynamic_cast<Game::Object::UITextBox*>(State::GameState::getInstance().addEntity(std::make_unique<Game::Object::UITextBox>("NameBox", textboxBg, nameBoxFont, Object::DEFAULT_TRANSFORM, cx, textboxY)));
|
auto* nameBox = dynamic_cast<Game::Object::UITextBox*>(State::GameState::getInstance().addEntity(std::make_unique<Game::Object::UITextBox>("NameBox", textboxBg, nameBoxFont, Object::DEFAULT_TRANSFORM, cx, textboxY)));
|
||||||
if (nameBox) nameBox->setPlaceholder("Enter name...");
|
if (nameBox) nameBox->setPlaceholder("Vnesi ime...");
|
||||||
|
|
||||||
// Start button (below center)
|
// Start button (below center)
|
||||||
auto btnTex = std::dynamic_pointer_cast<Game::Renderer::Texture>(startButtonFont);
|
auto btnTex = std::dynamic_pointer_cast<Game::Renderer::Texture>(startButtonFont);
|
||||||
auto* btnEntity = dynamic_cast<Game::Object::UIButton*>(State::GameState::getInstance().addEntity(std::make_unique<Game::Object::UIButton>("StartButton", btnTex, Object::DEFAULT_TRANSFORM, reinterpret_cast<void*>(&startGameCallback), cx, startButtonY)));
|
auto* btnEntity = dynamic_cast<Game::Object::UIButton*>(State::GameState::getInstance().addEntity(std::make_unique<Game::Object::UIButton>("StartButton", btnTex, Object::DEFAULT_TRANSFORM, reinterpret_cast<void*>(&startGameCallback), cx, startButtonY)));
|
||||||
if (btnEntity) btnEntity->setText("Start Game");
|
if (btnEntity) btnEntity->setText("Začni igro");
|
||||||
|
|
||||||
// Replay button (below start button)
|
// Replay button (below start button)
|
||||||
auto replayBtnTex = std::dynamic_pointer_cast<Game::Renderer::Texture>(replayButtonFont);
|
auto replayBtnTex = std::dynamic_pointer_cast<Game::Renderer::Texture>(replayButtonFont);
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ namespace Game::Object {
|
|||||||
float bottom = mTransform.y + (mBackground ? mBackground->getHeight() * mTransform.adjustedScaleY() : 0.f);
|
float bottom = mTransform.y + (mBackground ? mBackground->getHeight() * mTransform.adjustedScaleY() : 0.f);
|
||||||
|
|
||||||
bool inside = (mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom);
|
bool inside = (mouseX >= left && mouseX <= right && mouseY >= top && mouseY <= bottom);
|
||||||
|
mIsHovered = inside;
|
||||||
if (inside && Input::isMouseButtonJustPressed(SDL_BUTTON_LEFT)) {
|
if (inside && Input::isMouseButtonJustPressed(SDL_BUTTON_LEFT)) {
|
||||||
mIsFocused = true;
|
mIsFocused = true;
|
||||||
// Enable SDL text input on main thread (requires SDL_Window pointer)
|
// Enable SDL text input on main thread (requires SDL_Window pointer)
|
||||||
@@ -225,6 +226,24 @@ namespace Game::Object {
|
|||||||
¢er,
|
¢er,
|
||||||
mIsFlipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE
|
mIsFlipped ? SDL_FLIP_HORIZONTAL : SDL_FLIP_NONE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (mIsHovered) {
|
||||||
|
Uint8 prevR = 0;
|
||||||
|
Uint8 prevG = 0;
|
||||||
|
Uint8 prevB = 0;
|
||||||
|
Uint8 prevA = 0;
|
||||||
|
SDL_BlendMode prevBlendMode = SDL_BLENDMODE_NONE;
|
||||||
|
|
||||||
|
SDL_GetRenderDrawColor(renderer->getSDLRenderer(), &prevR, &prevG, &prevB, &prevA);
|
||||||
|
SDL_GetRenderDrawBlendMode(renderer->getSDLRenderer(), &prevBlendMode);
|
||||||
|
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer->getSDLRenderer(), SDL_BLENDMODE_BLEND);
|
||||||
|
SDL_SetRenderDrawColor(renderer->getSDLRenderer(), 0, 0, 0, 28);
|
||||||
|
SDL_RenderFillRect(renderer->getSDLRenderer(), &dst);
|
||||||
|
|
||||||
|
SDL_SetRenderDrawColor(renderer->getSDLRenderer(), prevR, prevG, prevB, prevA);
|
||||||
|
SDL_SetRenderDrawBlendMode(renderer->getSDLRenderer(), prevBlendMode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Render font texture (text) on top of background
|
// Render font texture (text) on top of background
|
||||||
|
|||||||
@@ -1,4 +1,7 @@
|
|||||||
#include <renderer/font.hpp>
|
#include <renderer/font.hpp>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <string_view>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
namespace Game::Renderer {
|
namespace Game::Renderer {
|
||||||
Font::Font(const std::string& path, SDL_Renderer* renderer, int ptSize, std::string id)
|
Font::Font(const std::string& path, SDL_Renderer* renderer, int ptSize, std::string id)
|
||||||
@@ -40,12 +43,106 @@ namespace Game::Renderer {
|
|||||||
mLastText = text;
|
mLastText = text;
|
||||||
mLastColor = color;
|
mLastColor = color;
|
||||||
|
|
||||||
SDL_Surface* surf = TTF_RenderText_Blended(mFont, text.c_str(), text.size(), color);
|
const int fontLineSkip = TTF_GetFontLineSkip(mFont);
|
||||||
if (!surf) {
|
std::vector<std::string_view> lines;
|
||||||
|
std::size_t lineStart = 0;
|
||||||
|
while (lineStart <= text.size()) {
|
||||||
|
const std::size_t lineEnd = text.find('\n', lineStart);
|
||||||
|
if (lineEnd == std::string::npos) {
|
||||||
|
lines.emplace_back(text.data() + lineStart, text.size() - lineStart);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
lines.emplace_back(text.data() + lineStart, lineEnd - lineStart);
|
||||||
|
lineStart = lineEnd + 1;
|
||||||
|
if (lineStart == text.size()) {
|
||||||
|
lines.emplace_back(std::string_view{});
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lines.empty()) {
|
||||||
|
lines.emplace_back(std::string_view{});
|
||||||
|
}
|
||||||
|
|
||||||
|
struct LineSurface {
|
||||||
|
SDL_Surface* surface = nullptr;
|
||||||
|
int width = 0;
|
||||||
|
int height = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
std::vector<LineSurface> lineSurfaces;
|
||||||
|
lineSurfaces.reserve(lines.size());
|
||||||
|
|
||||||
|
int maxWidth = 0;
|
||||||
|
int totalHeight = 0;
|
||||||
|
|
||||||
|
for (const auto line : lines) {
|
||||||
|
LineSurface lineSurface{};
|
||||||
|
if (!line.empty()) {
|
||||||
|
int measuredWidth = 0;
|
||||||
|
int measuredHeight = 0;
|
||||||
|
if (!TTF_GetStringSize(mFont, line.data(), line.size(), &measuredWidth, &measuredHeight)) {
|
||||||
|
for (auto& storedLine : lineSurfaces) {
|
||||||
|
if (storedLine.surface) {
|
||||||
|
SDL_DestroySurface(storedLine.surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR("TTF_GetStringSize Error: " << SDL_GetError() << " (This object may be unusuable)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lineSurface.surface = TTF_RenderText_Blended(mFont, line.data(), line.size(), color);
|
||||||
|
if (!lineSurface.surface) {
|
||||||
|
for (auto& storedLine : lineSurfaces) {
|
||||||
|
if (storedLine.surface) {
|
||||||
|
SDL_DestroySurface(storedLine.surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
ERROR("TTF_RenderText_Blended Error: " << SDL_GetError() << " (This object may be unusuable)");
|
ERROR("TTF_RenderText_Blended Error: " << SDL_GetError() << " (This object may be unusuable)");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lineSurface.width = measuredWidth;
|
||||||
|
lineSurface.height = measuredHeight;
|
||||||
|
} else {
|
||||||
|
lineSurface.width = 0;
|
||||||
|
lineSurface.height = fontLineSkip;
|
||||||
|
}
|
||||||
|
|
||||||
|
maxWidth = std::max(maxWidth, lineSurface.width);
|
||||||
|
totalHeight += lineSurface.height;
|
||||||
|
lineSurfaces.push_back(lineSurface);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (maxWidth <= 0) {
|
||||||
|
maxWidth = 1;
|
||||||
|
}
|
||||||
|
if (totalHeight <= 0) {
|
||||||
|
totalHeight = std::max(1, fontLineSkip);
|
||||||
|
}
|
||||||
|
|
||||||
|
SDL_Surface* surf = SDL_CreateSurface(maxWidth, totalHeight, SDL_PIXELFORMAT_RGBA8888);
|
||||||
|
if (!surf) {
|
||||||
|
for (auto& storedLine : lineSurfaces) {
|
||||||
|
if (storedLine.surface) {
|
||||||
|
SDL_DestroySurface(storedLine.surface);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ERROR("SDL_CreateSurface Error: " << SDL_GetError() << " (This object may be unusuable)");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int currentY = 0;
|
||||||
|
for (auto& lineSurface : lineSurfaces) {
|
||||||
|
if (lineSurface.surface) {
|
||||||
|
SDL_Rect dstRect{0, currentY, lineSurface.width, lineSurface.height};
|
||||||
|
SDL_BlitSurface(lineSurface.surface, nullptr, surf, &dstRect);
|
||||||
|
SDL_DestroySurface(lineSurface.surface);
|
||||||
|
}
|
||||||
|
currentY += lineSurface.height;
|
||||||
|
}
|
||||||
|
|
||||||
// Convert to texture
|
// Convert to texture
|
||||||
mTex = SDL_CreateTextureFromSurface(mRenderer, surf);
|
mTex = SDL_CreateTextureFromSurface(mRenderer, surf);
|
||||||
SDL_DestroySurface(surf);
|
SDL_DestroySurface(surf);
|
||||||
|
|||||||
Reference in New Issue
Block a user