105 lines
3.6 KiB
C++
105 lines
3.6 KiB
C++
#include <renderer/renderer.hpp>
|
|
#include <algorithm>
|
|
#include <utils.hpp>
|
|
#include <state/gamestate.hpp>
|
|
#include <object/entity.hpp>
|
|
#include <window/window.hpp>
|
|
#include <object/camera.hpp>
|
|
|
|
namespace Game::Renderer {
|
|
Renderer::Renderer() : mRenderer(nullptr) {}
|
|
|
|
Renderer::~Renderer() {
|
|
destroy();
|
|
}
|
|
|
|
void Renderer::destroy() {
|
|
if (mRenderer) {
|
|
SDL_DestroyRenderer(mRenderer);
|
|
mRenderer = nullptr;
|
|
LOG("Renderer uničen");
|
|
}
|
|
}
|
|
|
|
bool Renderer::init(SDL_Window* window) {
|
|
// Request VSync before/at renderer setup; some backends honor this hint.
|
|
SDL_SetHint(SDL_HINT_RENDER_VSYNC, "1");
|
|
// Create renderer using the portable API. Some SDL3 backends may not support the old flags,
|
|
// so fall back to a software renderer via hint if the first attempt fails.
|
|
mRenderer = SDL_CreateRenderer(window, nullptr);
|
|
if (!mRenderer) {
|
|
WARN("Renderer creation failed, attempting software renderer: " << SDL_GetError());
|
|
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "software");
|
|
mRenderer = SDL_CreateRenderer(window, nullptr);
|
|
if (!mRenderer) {
|
|
std::string errorMsg = std::string("Neuspešno ustvarjanje rendererja: ") + std::string(SDL_GetError());
|
|
ERROR(errorMsg.c_str());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
mVSyncEnabled = SDL_SetRenderVSync(mRenderer, 1);
|
|
if (!mVSyncEnabled) {
|
|
WARN("VSync ni mogoče omogočiti, uporabljam programsko omejitev okvirjev: " << SDL_GetError());
|
|
}
|
|
|
|
if (!SDL_SetRenderDrawColor(mRenderer, 0, 0, 255, 255)) {
|
|
ERROR("Neuspelo nastavitev barve rendererja: " << SDL_GetError());
|
|
return false;
|
|
}
|
|
|
|
LOG("Renderer uspešno ustvarjen");
|
|
|
|
return true;
|
|
}
|
|
|
|
void Renderer::renderFrame() {
|
|
mClear();
|
|
|
|
float camX, camY;
|
|
Object::Camera::getInstance().getPosition(camX, camY);
|
|
int screenW, screenH;
|
|
SDL_GetWindowSizeInPixels(Window::Window::getSDLWindowBackend(), &screenW, &screenH);
|
|
// Pass the config to avoid wasting time recalculating it for every entity, since it's not gonna change during the frame
|
|
RendererConfig config{ camX, camY, screenW, screenH };
|
|
|
|
try {
|
|
Game::State::GameState::getInstance().withEntitiesLocked([&](auto& entities) {
|
|
std::vector<Game::Object::Entity*> renderOrder;
|
|
renderOrder.reserve(entities.size());
|
|
for (auto& [name, entity] : entities) {
|
|
(void)name;
|
|
if (entity) {
|
|
renderOrder.push_back(entity.get());
|
|
}
|
|
}
|
|
|
|
std::sort(renderOrder.begin(), renderOrder.end(), [](Game::Object::Entity* a, Game::Object::Entity* b) {
|
|
return a->getZIndex() < b->getZIndex();
|
|
});
|
|
|
|
for (auto* entity : renderOrder) {
|
|
if (entity && entity->isActive()) {
|
|
entity->render(this, config);
|
|
}
|
|
}
|
|
});
|
|
} catch (const std::exception& e) {
|
|
ERROR("Exception while rendering frame: " << e.what());
|
|
}
|
|
|
|
mPresent();
|
|
}
|
|
|
|
void Renderer::mClear() {
|
|
if (!SDL_RenderClear(mRenderer)) {
|
|
ERROR("Failed to clear renderer: " << SDL_GetError());
|
|
}
|
|
}
|
|
|
|
void Renderer::mPresent() {
|
|
if (!SDL_RenderPresent(mRenderer)) {
|
|
ERROR("Failed to present renderer: " << SDL_GetError());
|
|
}
|
|
}
|
|
} |