#include #include #include #include #include #include #include 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 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()); } } }