/* * GameRenderer.cpp * * Created on: Nov 13, 2016 * Author: tibi */ #include #include #include #include namespace farmlands { namespace graphics { GameRenderer::GameRenderer() : m_gameState(nullptr) { } GameRenderer::~GameRenderer() { } void GameRenderer::initialize(GameState* gameState) { m_gameState = gameState; } void GameRenderer::render() { prepareRender(); renderTileLayers(); renderPlayer(); } void GameRenderer::prepareRender() { m_cellW = m_gameState->currentLevel->m_cellWidth * m_gameState->camera.scale; m_cellH = m_gameState->currentLevel->m_cellHeight * m_gameState->camera.scale; } void GameRenderer::renderTileLayers() { // Compute how many cells fit on the screen float cellsOnScreenX = m_gameState->viewport.width / m_cellW; float cellsOnScreenY = m_gameState->viewport.height / m_cellH; int minCellX = floorf(m_gameState->camera.posX - cellsOnScreenX / 2); int minCellY = floorf(m_gameState->camera.posY - cellsOnScreenY / 2); int maxCellX = ceilf(m_gameState->camera.posX + cellsOnScreenX / 2); int maxCellY = ceilf(m_gameState->camera.posY + cellsOnScreenY / 2); // Clamp cell positions minCellX = clamp(minCellX, 0, (int)m_gameState->currentLevel->columnCount() - 1); minCellY = clamp(minCellY, 0, (int)m_gameState->currentLevel->rowCount() - 1); maxCellX = clamp(maxCellX, 0, (int)m_gameState->currentLevel->columnCount() - 1); maxCellY = clamp(maxCellY, 0, (int)m_gameState->currentLevel->rowCount() - 1); // Draw each layer for (size_t i = 0; i < m_gameState->currentLevel->layerCount(); i++) { int textureId = m_gameState->currentLevel->texture(i); // Render only visible tiles for (int y = minCellY; y <= maxCellY; y++) for (int x = minCellX; x <= maxCellX; x++) { int cellId = m_gameState->currentLevel->cell(i, y, x); // Obtain texture int texWidth, texHeight; SDL_Texture* texture = m_gameState->resManager.texture(textureId); SDL_QueryTexture(texture, NULL, NULL, &texWidth, &texHeight); // Compute texture coordinates int cellCol = (cellId * m_gameState->currentLevel->m_cellWidth) % texWidth; int cellRow = ((cellId * m_gameState->currentLevel->m_cellWidth) / texWidth) * m_gameState->currentLevel->m_cellHeight; // Calculate source position SDL_Rect src = { cellCol, cellRow, (int) m_gameState->currentLevel->m_cellWidth, (int) m_gameState->currentLevel->m_cellHeight }; // Calculate destination position SDL_Rect dest = { (int) xToScreen(x), (int) yToScreen(y), (int) ceilf(m_cellW), (int) ceilf(m_cellH) }; // Blit SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), texture, &src, &dest); } } } void GameRenderer::renderPlayer() { float posX = xToScreen(m_gameState->player.posX); float posY = yToScreen(m_gameState->player.posY); // Obtain texture int texWidth, texHeight; SDL_Texture* playerTexture = m_gameState->resManager.texture(resources::R::Player::Default); SDL_QueryTexture(playerTexture, NULL, NULL, &texWidth, &texHeight); // Draw using bottom center of texture as anchor point SDL_Rect dest = { (int) (posX - texWidth * m_gameState->camera.scale / 2), (int) (posY - texHeight * m_gameState->camera.scale), (int) (texWidth * m_gameState->camera.scale), (int) (texHeight * m_gameState->camera.scale), }; SDL_RenderCopy(m_gameState->sdlRenderer.internalRenderer(), playerTexture, NULL, &dest); } float GameRenderer::xToWorld(float x) { return (x - m_gameState->viewport.width / 2) / m_cellW + m_gameState->camera.posX; } float GameRenderer::yToWorld(float y) { return (y - m_gameState->viewport.height / 2) / m_cellH + m_gameState->camera.posY; } float GameRenderer::xToScreen(float x) { return (x - m_gameState->camera.posX) * m_cellW + m_gameState->viewport.width / 2; } float GameRenderer::yToScreen(float y) { return (y - m_gameState->camera.posY) * m_cellH + m_gameState->viewport.height / 2; } } /* namespace graphics */ } /* namespace farmlands */