#include "renderer.h"
#include "game.h"
Renderer::Renderer()
{
win_ = window_ptr(
SDL_CreateWindow(
"Ether",
100,
100,
GAME_WIDTH,
GAME_HEIGHT,
SDL_WINDOW_SHOWN));
SDL_SetWindowFullscreen(win_.get(), SDL_WINDOW_FULLSCREEN_DESKTOP);
if (!win_)
{
throw sdl_error();
}
ren_ = renderer_ptr(
SDL_CreateRenderer(
win_.get(),
-1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC));
if (!ren_)
{
throw sdl_error();
}
texture_ptr origFade;
{
surface_ptr pfs(IMG_Load("../res/lighting.png"));
if (!pfs)
{
throw img_error();
}
origFade = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get()));
}
SDL_SetTextureBlendMode(origFade.get(), SDL_BLENDMODE_BLEND);
playerFade_ = texture_ptr(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA4444,
SDL_TEXTUREACCESS_TARGET,
144,
144));
if (!playerFade_)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), playerFade_.get());
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0);
SDL_RenderClear(ren_.get());
SDL_RenderCopy(ren_.get(), origFade.get(), nullptr, nullptr);
lampFade_ = texture_ptr(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA4444,
SDL_TEXTUREACCESS_TARGET,
144,
144));
if (!lampFade_)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), lampFade_.get());
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0);
SDL_RenderClear(ren_.get());
SDL_RenderCopy(ren_.get(), origFade.get(), nullptr, nullptr);
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_MOD);
SDL_SetRenderDrawColor(ren_.get(), 255, 204, 58, 255);
SDL_RenderFillRect(ren_.get(), nullptr);
dustFade_ = texture_ptr(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA4444,
SDL_TEXTUREACCESS_TARGET,
144,
144));
if (!dustFade_)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), dustFade_.get());
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0);
SDL_RenderClear(ren_.get());
SDL_RenderCopy(ren_.get(), origFade.get(), nullptr, nullptr);
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_MOD);
SDL_SetRenderDrawColor(ren_.get(), 255, 150, 255, 255);
SDL_RenderFillRect(ren_.get(), nullptr);
SDL_SetRenderDrawColor(ren_.get(), 100, 100, 100, 255);
SDL_RenderFillRect(ren_.get(), nullptr);
{
surface_ptr pfs(IMG_Load("../res/player.png"));
if (!pfs)
{
throw img_error();
}
playerSheet_ = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get()));
}
SDL_SetTextureBlendMode(playerSheet_.get(), SDL_BLENDMODE_BLEND);
{
surface_ptr pfs(IMG_Load("../res/runninbloods.png"));
if (!pfs)
{
throw img_error();
}
tileset_ = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get()));
}
SDL_SetTextureBlendMode(tileset_.get(), SDL_BLENDMODE_BLEND);
{
surface_ptr pfs(IMG_Load("../res/lamp.png"));
if (!pfs)
{
throw img_error();
}
lamp_ = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get()));
}
SDL_SetTextureBlendMode(lamp_.get(), SDL_BLENDMODE_BLEND);
}
void Renderer::renderGame(
const Game& game,
bool drawDark)
{
texture_ptr canvas(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
TILE_WIDTH * game.map.getWidth(),
TILE_HEIGHT * game.map.getHeight()));
if (!canvas)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), canvas.get());
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ren_.get(), rand() % 255, rand() % 255, rand() % 255, 255);
SDL_RenderClear(ren_.get());
for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
{
for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
{
bool draw = true;
bool drawColour = false;
SDL_Rect rect {
game.map.getTrueX(x) * TILE_WIDTH,
game.map.getTrueY(y) * TILE_HEIGHT,
TILE_WIDTH,
TILE_HEIGHT};
if (!game.map.at(x,y).lit)
{
if (drawDark)
{
SDL_SetRenderDrawColor(ren_.get(), 40, 40, 40, 255);
drawColour = true;
} else {
draw = false;
}
}
if (draw)
{
if (game.map.at(x,y).tile != Tile::Wall) {
SDL_Rect tileRect {17 * 16, 15 * 16, 16, 16};
SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect);
if (game.map.at(x,y).renderId != -1) {
tileRect.x = game.map.at(x,y).renderId % 24 * 16;
tileRect.y = game.map.at(x,y).renderId / 24 * 16;
SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect);
}
} else {
SDL_Rect tileRect {
game.map.at(x,y).renderId % 24 * 16,
game.map.at(x,y).renderId / 24 * 16,
16,
16};
SDL_RenderCopy(ren_.get(), tileset_.get(), &tileRect, &rect);
}
if (game.map.at(x,y).tile == Tile::Lamp) {
SDL_RenderCopy(ren_.get(), lamp_.get(), nullptr, &rect);
}
if (drawColour) {
SDL_RenderFillRect(ren_.get(), &rect);
}
}
}
}
if (game.renderPlayer) {
SDL_Rect rect {
game.map.getTrueX(game.player_x) * TILE_WIDTH,
game.map.getTrueY(game.player_y) * TILE_HEIGHT,
TILE_WIDTH,
TILE_HEIGHT};
if (game.moving) {
rect.x = game.moveProgress.getProgress(game.map.getTrueX(game.player_oldx) * TILE_WIDTH, rect.x);
rect.y = game.moveProgress.getProgress(game.map.getTrueY(game.player_oldy) * TILE_HEIGHT, rect.y);
}
SDL_RenderCopy(ren_.get(), playerSheet_.get(), &game.playerAnim.getRenderRect(), &rect);
}
texture_ptr mask(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
TILE_WIDTH * game.map.getWidth(),
TILE_HEIGHT * game.map.getHeight()));
if (!mask)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), mask.get());
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0);
SDL_RenderClear(ren_.get());
for (int y = game.map.getTop(); y < game.map.getBottom(); y++)
{
for (int x = game.map.getLeft(); x < game.map.getRight(); x++)
{
if (game.map.at(x,y).lightType != Source::None)
{
texture_ptr sourceMask(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
TILE_WIDTH * game.map.getWidth(),
TILE_HEIGHT * game.map.getHeight()));
if (!sourceMask)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), sourceMask.get());
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0);
SDL_RenderClear(ren_.get());
int posToUseX = game.map.getTrueX(x);
int posToUseY = game.map.getTrueY(y);
if (game.map.at(x,y).lightType == Source::Player && game.moving) {
posToUseX = game.moveProgress.getProgress(game.map.getTrueX(game.player_oldx), posToUseX);
posToUseY = game.moveProgress.getProgress(game.map.getTrueY(game.player_oldy), posToUseY);
}
int fadeX = posToUseX - game.map.at(x,y).lightRadius;
int fadeY = posToUseY - game.map.at(x,y).lightRadius;
int fadeRight = posToUseX + game.map.at(x,y).lightRadius;
int fadeBottom = posToUseY + game.map.at(x,y).lightRadius;
SDL_Rect fadeRect {
fadeX * TILE_WIDTH,
fadeY * TILE_HEIGHT,
(game.map.at(x,y).lightRadius * 2 + 1) * TILE_WIDTH,
(game.map.at(x,y).lightRadius * 2 + 1) * TILE_HEIGHT};
if (game.map.at(x,y).lightType == Source::Lamp)
{
SDL_SetTextureBlendMode(lampFade_.get(), SDL_BLENDMODE_NONE);
SDL_RenderCopy(ren_.get(), lampFade_.get(), nullptr, &fadeRect);
} else if (game.map.at(x,y).lightType == Source::Player) {
SDL_SetTextureBlendMode(playerFade_.get(), SDL_BLENDMODE_NONE);
SDL_RenderCopy(ren_.get(), playerFade_.get(), nullptr, &fadeRect);
} else if (game.map.at(x,y).lightType == Source::Dust) {
SDL_SetTextureBlendMode(dustFade_.get(), SDL_BLENDMODE_NONE);
SDL_RenderCopy(ren_.get(), dustFade_.get(), nullptr, &fadeRect);
}
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 0);
for (int sy = fadeY; sy < fadeBottom; sy++)
{
for (int sx = fadeX; sx < fadeRight; sx++)
{
if (!game.map.at(x,y).litTiles.count({sx, sy}))
{
SDL_Rect rect {
game.map.getTrueX(sx) * TILE_WIDTH,
game.map.getTrueY(sy) * TILE_HEIGHT,
TILE_WIDTH,
TILE_HEIGHT};
SDL_RenderFillRect(ren_.get(), &rect);
}
}
}
SDL_SetRenderTarget(ren_.get(), mask.get());
SDL_SetTextureBlendMode(sourceMask.get(), SDL_BLENDMODE_ADD);
SDL_RenderCopy(ren_.get(), sourceMask.get(), nullptr, nullptr);
}
}
}
SDL_SetRenderTarget(ren_.get(), canvas.get());
SDL_SetTextureBlendMode(mask.get(), SDL_BLENDMODE_MOD);
SDL_RenderCopy(ren_.get(), mask.get(), nullptr, nullptr);
SDL_SetRenderTarget(ren_.get(), nullptr);
SDL_Rect zoomRect;
std::tie(zoomRect.x, zoomRect.y, zoomRect.w, zoomRect.h) =
calculateZoomRect(game);
SDL_RenderCopy(ren_.get(), canvas.get(), &zoomRect, nullptr);
SDL_RenderPresent(ren_.get());
}
std::tuple<int, int, int, int> Renderer::calculateZoomRect(const Game& game)
{
int x = game.map.getTrueX(game.curBoundX) * TILE_WIDTH;
int y = game.map.getTrueY(game.curBoundY) * TILE_HEIGHT;
int w = game.curZoom * TILE_WIDTH * ZOOM_X_FACTOR;
int h = game.curZoom * TILE_HEIGHT * ZOOM_Y_FACTOR;
if (game.zooming)
{
double interp =
static_cast<double>(game.zoomProgress) /
static_cast<double>(game.zoomLength);
x = (x - game.lastZoomLeft) * interp + game.lastZoomLeft;
y = (y - game.lastZoomTop) * interp + game.lastZoomTop;
w = (w - game.lastZoomWidth) * interp + game.lastZoomWidth;
h = (h - game.lastZoomHeight) * interp + game.lastZoomHeight;
}
return {x, y, w, h};
}