#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(game.zoomProgress) / static_cast(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 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(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}; } 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); }