#include "renderer.h" #include "game.h" Renderer::Renderer() { win_ = window_ptr( SDL_CreateWindow( "Ether", 100, 100, GAME_WIDTH, GAME_HEIGHT, SDL_WINDOW_SHOWN)); 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::render( 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 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(game.zoomProgress) / static_cast(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}; }