147 lines
4.0 KiB
C++
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 */
|