#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;
loadTextureFromFile("../res/lighting.png", origFade);
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);
loadTextureFromFile("../res/player.png", playerSheet_);
loadTextureFromFile("../res/runninbloods.png", tileset_);
loadTextureFromFile("../res/lamp.png", lamp_);
loadTextureFromFile("../res/title0.png", titles_[0]);
SDL_QueryTexture(titles_[0].get(), nullptr, nullptr, &titleWidths_[0], &titleHeights_[0]);
}
void Renderer::renderGame(
const Game& game,
bool drawDark)
{
int windowTileWidth = game.curZoom * ZOOM_X_FACTOR + 2;
int windowTileHeight = game.curZoom * ZOOM_Y_FACTOR + 2;
texture_ptr canvas(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
windowTileWidth * TILE_WIDTH,
windowTileHeight * TILE_HEIGHT));
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());
int leftmost = game.player_x - game.curZoom * ZOOM_X_FACTOR / 2 - 1;
int topmost = game.player_y - game.curZoom * ZOOM_Y_FACTOR / 2 - 1;
for (int y = topmost; y < topmost + windowTileHeight; y++)
{
for (int x = leftmost; x < leftmost + windowTileWidth; x++)
{
bool draw = true;
bool drawColour = false;
SDL_Rect rect {
(x - leftmost) * TILE_WIDTH,
(y - topmost) * 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.player_x - leftmost) * TILE_WIDTH,
(game.player_y - topmost) * TILE_HEIGHT,
TILE_WIDTH,
TILE_HEIGHT};
if (game.moving) {
rect.x = game.moveProgress.getProgress((game.player_oldx - leftmost) * TILE_WIDTH, rect.x);
rect.y = game.moveProgress.getProgress((game.player_oldy - topmost) * 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,
windowTileWidth * TILE_WIDTH,
windowTileHeight * TILE_HEIGHT));
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 = topmost; y < topmost + windowTileHeight; y++)
{
for (int x = leftmost; x < leftmost + windowTileWidth; x++)
{
if (game.map.at(x,y).lightType != Source::None)
{
texture_ptr sourceMask(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
windowTileWidth * TILE_WIDTH,
windowTileHeight * TILE_HEIGHT));
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 = x - leftmost;
int posToUseY = y - topmost;
int xInterp = 0;
int yInterp = 0;
if (game.map.at(x,y).lightType == Source::Player && game.moving) {
if (game.player_x > game.player_oldx) {
xInterp = game.moveProgress.getProgress(-TILE_WIDTH, 0);
} else if (game.player_x < game.player_oldx) {
xInterp = game.moveProgress.getProgress(TILE_WIDTH, 0);
}
if (game.player_y > game.player_oldy) {
yInterp = game.moveProgress.getProgress(-TILE_HEIGHT, 0);
} else if (game.player_y < game.player_oldy) {
yInterp = game.moveProgress.getProgress(TILE_HEIGHT, 0);
}
}
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 + xInterp,
fadeY * TILE_HEIGHT + yInterp,
(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 {
(sx - leftmost) * TILE_WIDTH + xInterp,
(sy - topmost) * TILE_HEIGHT + yInterp,
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);
// TODO: this is just moving interp. we also need zoom
SDL_Rect zoomRect {
TILE_WIDTH, TILE_HEIGHT, (windowTileWidth - 2) * TILE_WIDTH, (windowTileHeight - 2) * TILE_HEIGHT
};
if (game.moving) {
double interp =
static_cast<double>(game.zoomProgress) /
static_cast<double>(game.zoomLength);
if (game.player_x > game.player_oldx) {
zoomRect.x = game.moveProgress.getProgress(0, TILE_WIDTH);
} else if (game.player_x < game.player_oldx) {
zoomRect.x = game.moveProgress.getProgress(2*TILE_WIDTH, TILE_WIDTH);
}
if (game.player_y > game.player_oldy) {
zoomRect.y = game.moveProgress.getProgress(0, TILE_HEIGHT);
} else if (game.player_y < game.player_oldy) {
zoomRect.y = game.moveProgress.getProgress(TILE_HEIGHT*2, TILE_HEIGHT);
}
}
SDL_RenderCopy(ren_.get(), canvas.get(), &zoomRect, nullptr);
SDL_RenderPresent(ren_.get());
}
void Renderer::renderTitle(int num, double fade) {
texture_ptr canvas(
SDL_CreateTexture(
ren_.get(),
SDL_PIXELFORMAT_RGBA8888,
SDL_TEXTUREACCESS_TARGET,
GAME_WIDTH,
GAME_HEIGHT));
if (!canvas)
{
throw sdl_error();
}
SDL_SetRenderTarget(ren_.get(), canvas.get());
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_NONE);
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, 255);
SDL_RenderClear(ren_.get());
if (fade > 0) {
SDL_Rect rect {
(GAME_WIDTH - titleWidths_[num]) / 2,
(GAME_HEIGHT - titleHeights_[num]) / 2,
titleWidths_[num],
titleHeights_[num]
};
SDL_RenderCopy(ren_.get(), titles_[num].get(), nullptr, &rect);
if (fade < 1) {
SDL_SetRenderDrawBlendMode(ren_.get(), SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(ren_.get(), 0, 0, 0, (1.0 - fade) * 255);
SDL_RenderFillRect(ren_.get(), nullptr);
}
}
SDL_SetRenderTarget(ren_.get(), nullptr);
SDL_RenderCopy(ren_.get(), canvas.get(), nullptr, nullptr);
SDL_RenderPresent(ren_.get());
}
std::tuple<int, int, int, int> Renderer::calculateZoomRect(const Game& game)
{
int w = game.curZoom * TILE_WIDTH * ZOOM_X_FACTOR;
int h = game.curZoom * TILE_HEIGHT * ZOOM_Y_FACTOR;
int x = (game.map.getTrueX(game.player_x) * TILE_WIDTH) - (w / 2);
int y = (game.map.getTrueY(game.player_y) * TILE_HEIGHT) - (h / 2);
/*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};
}
void Renderer::loadTextureFromFile(std::string_view path, texture_ptr& texture) {
surface_ptr pfs(IMG_Load(path.data()));
if (!pfs)
{
throw img_error();
}
texture = texture_ptr(SDL_CreateTextureFromSurface(ren_.get(), pfs.get()));
SDL_SetTextureBlendMode(texture.get(), SDL_BLENDMODE_BLEND);
}