farmlands/src/graphics/GameRenderer.cpp

147 lines
4.0 KiB
C++

/*
* GameRenderer.cpp
*
* Created on: Nov 13, 2016
* Author: tibi
*/
#include <GameState.h>
#include <graphics/GameRenderer.h>
#include <math/GameMath.h>
#include <resources/Resources.h>
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 */