From 3fa9af58bc907048a8ccadc2bef7736ec554a09d Mon Sep 17 00:00:00 2001 From: Kelly Rauchenberger Date: Tue, 5 Jun 2018 21:02:51 -0400 Subject: refactored so that the renderer is its own class --- CMakeLists.txt | 1 + src/game.h | 104 +++++++++++ src/main.cpp | 522 ++----------------------------------------------------- src/renderer.cpp | 309 ++++++++++++++++++++++++++++++++ src/renderer.h | 132 ++++++++++++++ 5 files changed, 561 insertions(+), 507 deletions(-) create mode 100644 src/game.h create mode 100644 src/renderer.cpp create mode 100644 src/renderer.h diff --git a/CMakeLists.txt b/CMakeLists.txt index e3b88fd..b492d05 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,6 +23,7 @@ include_directories( add_executable(Ether src/main.cpp + src/renderer.cpp vendor/fov.c ) diff --git a/src/game.h b/src/game.h new file mode 100644 index 0000000..1142efb --- /dev/null +++ b/src/game.h @@ -0,0 +1,104 @@ +#ifndef GAME_H_7D2B65AE +#define GAME_H_7D2B65AE + +#include +#include +#include +#include +#include "map.h" + +const int GAME_WIDTH = 640*2; +const int GAME_HEIGHT = 480*2; +const int TILE_WIDTH = 8*2; +const int TILE_HEIGHT = TILE_WIDTH; +const int INIT_ZOOM = 10; +const int ZOOM_X_FACTOR = 8; +const int ZOOM_Y_FACTOR = 6; +const int RADIUS = 8; + +enum class Tile { + Floor, + Wall, + Dust, + Lamp +}; + +enum class Source { + None, + Dust, + Lamp, + Player +}; + +enum class LoseState { + None, + PoppingLamps, + PoppingPlayer, + Outro +}; + +struct Input { + bool left = false; + bool right = false; + bool up = false; + bool down = false; +}; + +using coord = std::tuple; + +struct Kickup { + int x; + int y; + size_t cur; + size_t radius; + size_t chain; + std::set done; + std::set front; +}; + +struct MapData { + Tile tile = Tile::Floor; + bool lit = false; + bool wasLit = false; + size_t dustLife = 0; + Source lightType = Source::None; + int lightRadius = 0; + std::set litTiles; +}; + +class Game { +public: + + Game(std::mt19937& rng) : + rng(rng), + map( + -INIT_ZOOM * ZOOM_X_FACTOR / 2, + -INIT_ZOOM * ZOOM_Y_FACTOR / 2, + INIT_ZOOM * ZOOM_X_FACTOR, + INIT_ZOOM * ZOOM_Y_FACTOR) + { + } + + std::mt19937& rng; + + Map map; + std::list kickups; + int litSpots = 0; + bool dirtyLighting = true; + size_t numLamps = 0; + size_t numDust = 0; + + int player_x = 0; + int player_y = 0; + bool renderPlayer = true; + + int curZoom = INIT_ZOOM; + int maxZoom = INIT_ZOOM; + + bool zooming = false; + //size_t oldZoom; + int zoomProgress = 0; + +}; + +#endif /* end of include guard: GAME_H_7D2B65AE */ diff --git a/src/main.cpp b/src/main.cpp index 03e7cda..8f20635 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,455 +1,9 @@ -#include -#include -#include -#include #include -#include -#include #include #include -#include -#include #include "util.h" -#include "map.h" - -class sdl_error : public std::logic_error { -public: - - sdl_error() : std::logic_error(SDL_GetError()) - { - } -}; - -class img_error : public std::logic_error { -public: - - img_error() : std::logic_error(IMG_GetError()) - { - } -}; - -class window_deleter { -public: - - void operator()(SDL_Window* ptr) - { - SDL_DestroyWindow(ptr); - } -}; - -using window_ptr = std::unique_ptr; - -class renderer_deleter { -public: - - void operator()(SDL_Renderer* ptr) - { - SDL_DestroyRenderer(ptr); - } -}; - -using renderer_ptr = std::unique_ptr; - -class surface_deleter { -public: - - void operator()(SDL_Surface* ptr) - { - SDL_FreeSurface(ptr); - } -}; - -using surface_ptr = std::unique_ptr; - -class texture_deleter { -public: - - void operator()(SDL_Texture* ptr) - { - SDL_DestroyTexture(ptr); - } -}; - -using texture_ptr = std::unique_ptr; - -enum class Tile { - Floor, - Wall, - Dust, - Lamp -}; - -enum class Source { - None, - Dust, - Lamp, - Player -}; - -enum class LoseState { - None, - PoppingLamps, - PoppingPlayer, - Outro -}; - -const int GAME_WIDTH = 640*2; -const int GAME_HEIGHT = 480*2; -const int TILE_WIDTH = 8*2; -const int TILE_HEIGHT = TILE_WIDTH; -const int INIT_ZOOM = 10; -const int ZOOM_X_FACTOR = 8; -const int ZOOM_Y_FACTOR = 6; -const int RADIUS = 8; - -struct Input { - bool left = false; - bool right = false; - bool up = false; - bool down = false; -}; - -using coord = std::tuple; - -struct Kickup { - int x; - int y; - size_t cur; - size_t radius; - size_t chain; - std::set done; - std::set front; -}; - -struct MapData { - Tile tile = Tile::Floor; - bool lit = false; - bool wasLit = false; - double visibility = 0.0; - size_t dustLife = 0; - Source lightType = Source::None; - int lightRadius = 0; - std::set litTiles; -}; - -class Game { -public: - - Game(std::mt19937& rng) : - rng(rng), - map( - -INIT_ZOOM * ZOOM_X_FACTOR / 2, - -INIT_ZOOM * ZOOM_Y_FACTOR / 2, - INIT_ZOOM * ZOOM_X_FACTOR, - INIT_ZOOM * ZOOM_Y_FACTOR) - { - } - - std::mt19937& rng; - - Map map; - std::list kickups; - int litSpots = 0; - bool dirtyLighting = true; - size_t numLamps = 0; - size_t numDust = 0; - - int player_x = 0; - int player_y = 0; - bool renderPlayer = true; - - int curZoom = INIT_ZOOM; - int maxZoom = INIT_ZOOM; - - bool zooming = false; - //size_t oldZoom; - int zoomProgress = 0; - -}; - -void render( - SDL_Renderer* ren, - const Game& game, - bool drawDark = true) -{ - texture_ptr origFade; - { - surface_ptr pfs(IMG_Load("../res/lighting.png")); - if (!pfs) - { - throw img_error(); - } - - origFade = texture_ptr(SDL_CreateTextureFromSurface(ren, pfs.get())); - } - - SDL_SetTextureBlendMode(origFade.get(), SDL_BLENDMODE_BLEND); - - texture_ptr playerFade( - SDL_CreateTexture( - ren, - SDL_PIXELFORMAT_RGBA4444, - SDL_TEXTUREACCESS_TARGET, - 144, - 144)); - - if (!playerFade) - { - throw sdl_error(); - } - - SDL_SetRenderTarget(ren, playerFade.get()); - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); - SDL_SetRenderDrawColor(ren, 0, 0, 0, 0); - SDL_RenderClear(ren); - SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr); - - texture_ptr lampFade( - SDL_CreateTexture( - ren, - SDL_PIXELFORMAT_RGBA4444, - SDL_TEXTUREACCESS_TARGET, - 144, - 144)); - - if (!lampFade) - { - throw sdl_error(); - } - - SDL_SetRenderTarget(ren, lampFade.get()); - - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); - SDL_SetRenderDrawColor(ren, 0, 0, 0, 0); - SDL_RenderClear(ren); - SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr); - - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD); - SDL_SetRenderDrawColor(ren, 255, 204, 58, 255); - SDL_RenderFillRect(ren, nullptr); - - texture_ptr dustFade( - SDL_CreateTexture( - ren, - SDL_PIXELFORMAT_RGBA4444, - SDL_TEXTUREACCESS_TARGET, - 144, - 144)); - - if (!dustFade) - { - throw sdl_error(); - } - - SDL_SetRenderTarget(ren, dustFade.get()); - - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); - SDL_SetRenderDrawColor(ren, 0, 0, 0, 0); - SDL_RenderClear(ren); - SDL_RenderCopy(ren, origFade.get(), nullptr, nullptr); - - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_MOD); - SDL_SetRenderDrawColor(ren, 255, 150, 255, 255); - SDL_RenderFillRect(ren, nullptr); - - texture_ptr canvas( - SDL_CreateTexture( - ren, - SDL_PIXELFORMAT_RGBA8888, - SDL_TEXTUREACCESS_TARGET, - TILE_WIDTH * game.map.getWidth(), - TILE_HEIGHT * game.map.getHeight())); - - if (!canvas) - { - throw sdl_error(); - } - - SDL_SetRenderTarget(ren, canvas.get()); - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); - SDL_SetRenderDrawColor(ren, rand() % 255, rand() % 255, rand() % 255, 255); - SDL_RenderClear(ren); - - 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; - - if ((game.player_x == x && game.player_y == y) && game.renderPlayer) - { - SDL_SetRenderDrawColor(ren, 255, 255, 0, 255); - } else if (!game.map.at(x,y).lit) - { - if (drawDark) - { - SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); - } else { - draw = false; - } - } else { - int alpha = 255; - - switch (game.map.at(x,y).tile) - { - case Tile::Floor: - { - SDL_SetRenderDrawColor(ren, 210, 210, 210, alpha); - break; - } - - case Tile::Wall: - { - SDL_SetRenderDrawColor(ren, 100, 100, 100, alpha); - break; - } - - case Tile::Dust: - { - SDL_SetRenderDrawColor(ren, 128, 40, 255, alpha); - break; - } - - case Tile::Lamp: - { - SDL_SetRenderDrawColor(ren, 0, 255, 255, alpha); - break; - } - } - } - - if (draw) - { - SDL_Rect rect { - game.map.getTrueX(x) * TILE_WIDTH, - game.map.getTrueY(y) * TILE_HEIGHT, - TILE_WIDTH, - TILE_HEIGHT}; - - //SDL_RenderFillRect(ren, &rect); - - //int alpha = (1.0 - game.map.at(x,y).visibility) * 255; - //SDL_SetRenderDrawColor(ren, 40, 40, 40, 255); - SDL_RenderFillRect(ren, &rect); - } - } - } - - texture_ptr mask( - SDL_CreateTexture( - ren, - SDL_PIXELFORMAT_RGBA8888, - SDL_TEXTUREACCESS_TARGET, - TILE_WIDTH * game.map.getWidth(), - TILE_HEIGHT * game.map.getHeight())); - - if (!mask) - { - throw sdl_error(); - } - - SDL_SetRenderTarget(ren, mask.get()); - SDL_SetRenderDrawColor(ren, 0, 0, 0, 0); - SDL_RenderClear(ren); - - 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, - SDL_PIXELFORMAT_RGBA8888, - SDL_TEXTUREACCESS_TARGET, - TILE_WIDTH * game.map.getWidth(), - TILE_HEIGHT * game.map.getHeight())); - - if (!sourceMask) - { - throw sdl_error(); - } - - SDL_SetRenderTarget(ren, sourceMask.get()); - SDL_SetRenderDrawBlendMode(ren, SDL_BLENDMODE_NONE); - SDL_SetRenderDrawColor(ren, 0, 0, 0, 0); - SDL_RenderClear(ren); - - int fadeX = game.map.getTrueX(x) - game.map.at(x,y).lightRadius; - int fadeY = game.map.getTrueY(y) - game.map.at(x,y).lightRadius; - int fadeRight = game.map.getTrueX(x) + game.map.at(x,y).lightRadius; - int fadeBottom = game.map.getTrueY(y) + 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, lampFade.get(), nullptr, &fadeRect); - } else if (game.map.at(x,y).lightType == Source::Player) { - SDL_SetTextureBlendMode(playerFade.get(), SDL_BLENDMODE_NONE); - SDL_RenderCopy(ren, playerFade.get(), nullptr, &fadeRect); - } else if (game.map.at(x,y).lightType == Source::Dust) { - SDL_SetTextureBlendMode(dustFade.get(), SDL_BLENDMODE_NONE); - SDL_RenderCopy(ren, dustFade.get(), nullptr, &fadeRect); - } - - SDL_SetRenderDrawColor(ren, 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, &rect); - } - } - } - - SDL_SetRenderTarget(ren, mask.get()); - SDL_SetTextureBlendMode(sourceMask.get(), SDL_BLENDMODE_ADD); - SDL_RenderCopy(ren, sourceMask.get(), nullptr, nullptr); - } - } - } - - SDL_SetRenderTarget(ren, canvas.get()); - SDL_SetTextureBlendMode(mask.get(), SDL_BLENDMODE_MOD); - SDL_RenderCopy(ren, mask.get(), nullptr, nullptr); - - SDL_SetRenderTarget(ren, nullptr); - - if (!game.zooming) - { - SDL_RenderCopy(ren, canvas.get(), nullptr, nullptr); - } else { - // TODO: zooming back in to the player - SDL_Rect zoomRect { - ((game.maxZoom - game.curZoom) * TILE_WIDTH + game.zoomProgress) - * ZOOM_X_FACTOR / 2, - ((game.maxZoom - game.curZoom) * TILE_HEIGHT + game.zoomProgress) - * ZOOM_Y_FACTOR / 2, - (game.curZoom * TILE_WIDTH - game.zoomProgress) * ZOOM_X_FACTOR, - (game.curZoom * TILE_HEIGHT - game.zoomProgress) * ZOOM_Y_FACTOR - }; - - SDL_RenderCopy(ren, canvas.get(), &zoomRect, nullptr); - } - - SDL_RenderPresent(ren); -} +#include "game.h" +#include "renderer.h" void incrementIfSet(Game& game, int& count, int x, int y, Tile val = Tile::Wall) { @@ -543,7 +97,7 @@ void movePlayer(Game& game, int x, int y) } } -void recalculateLighting(Game& game, fov_settings_type* fov) +void recalculateLighting(Game& game) { game.litSpots = 0; @@ -551,12 +105,14 @@ void recalculateLighting(Game& game, fov_settings_type* fov) { md.wasLit = md.lit; md.lit = false; - md.visibility = 0.0; md.litTiles.clear(); } + fov_settings_type fov; + fov_settings_init(&fov); + fov_settings_set_opacity_test_function( - fov, + &fov, [] (void* data, int x, int y) { Game& game = *static_cast(data); @@ -564,7 +120,7 @@ void recalculateLighting(Game& game, fov_settings_type* fov) }); fov_settings_set_apply_lighting_function( - fov, + &fov, [] (void* data, int x, int y, int dx, int dy, void* source) { Game& game = *static_cast(data); @@ -580,21 +136,7 @@ void recalculateLighting(Game& game, fov_settings_type* fov) game.map.at(x,y).lit = true; - /*game.map.at(x,y).visibility = std::max( - game.map.at(x,y).visibility, - std::pow( - std::max( - 0.0, - 1.0 - std::sqrt(dx * dx + dy * dy) / lightRadius), - 1.0/3.0));*/ - sourceData.litTiles.emplace(x,y); - - //Source ls = *static_cast(source); - //if (static_cast(ls) > static_cast(m.lightSource[x+VIEW_WIDTH*y])) - { - //m.lightSource[x+VIEW_WIDTH*y] = ls; - } } }); @@ -620,7 +162,6 @@ void recalculateLighting(Game& game, fov_settings_type* fov) } game.map.at(x,y).lightType = ls; - //game.map.at(x,y).litTiles.clear(); if (ls != Source::None) { @@ -628,7 +169,7 @@ void recalculateLighting(Game& game, fov_settings_type* fov) game.map.at(x,y).litTiles.emplace(x,y); fov_circle( - fov, + &fov, static_cast(&game), static_cast(&game.map.at(x,y)), x, @@ -636,7 +177,6 @@ void recalculateLighting(Game& game, fov_settings_type* fov) lightRadius); game.map.at(x,y).lit = true; - game.map.at(x,y).visibility = 1.0; } } } @@ -832,44 +372,12 @@ int main(int, char**) std::random_device randomEngine; std::mt19937 rng(randomEngine()); - if (SDL_Init(SDL_INIT_VIDEO) != 0) - { - throw sdl_error(); - } - - if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) - { - throw img_error(); - } - try { - window_ptr win( - SDL_CreateWindow("Ether", 100, 100, GAME_WIDTH, GAME_HEIGHT, SDL_WINDOW_SHOWN)); - - if (!win) - { - throw sdl_error(); - } - - renderer_ptr ren( - SDL_CreateRenderer( - win.get(), - -1, - SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC)); - - if (!ren) - { - throw sdl_error(); - } - - SDL_SetRenderDrawBlendMode(ren.get(), SDL_BLENDMODE_BLEND); + Renderer renderer; Game game(rng); - std::unique_ptr fov(new fov_settings_type()); - fov_settings_init(fov.get()); - for (MapData& md : game.map.data()) { if (std::bernoulli_distribution(0.5)(rng)) @@ -1091,7 +599,7 @@ int main(int, char**) if (game.dirtyLighting) { - recalculateLighting(game, fov.get()); + recalculateLighting(game); for (int y = game.map.getTop(); y < game.map.getBottom(); y++) { @@ -1140,15 +648,15 @@ int main(int, char**) zoomAcc -= zoomDt; } - render(ren.get(), game, true); + renderer.render(game, true); } } catch (const sdl_error& ex) { std::cout << "SDL error (" << ex.what() << ")" << std::endl; + } catch (const img_error& ex) + { + std::cout << "SDL_IMG error (" << ex.what() << ")" << std::endl; } - IMG_Quit(); - SDL_Quit(); - return 0; } diff --git a/src/renderer.cpp b/src/renderer.cpp new file mode 100644 index 0000000..eddd11d --- /dev/null +++ b/src/renderer.cpp @@ -0,0 +1,309 @@ +#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); +} + +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; + + if ((game.player_x == x && game.player_y == y) && game.renderPlayer) + { + SDL_SetRenderDrawColor(ren_.get(), 255, 255, 0, 255); + } else if (!game.map.at(x,y).lit) + { + if (drawDark) + { + SDL_SetRenderDrawColor(ren_.get(), 40, 40, 40, 255); + } else { + draw = false; + } + } else { + int alpha = 255; + + switch (game.map.at(x,y).tile) + { + case Tile::Floor: + { + SDL_SetRenderDrawColor(ren_.get(), 210, 210, 210, alpha); + break; + } + + case Tile::Wall: + { + SDL_SetRenderDrawColor(ren_.get(), 100, 100, 100, alpha); + break; + } + + case Tile::Dust: + { + SDL_SetRenderDrawColor(ren_.get(), 128, 40, 255, alpha); + break; + } + + case Tile::Lamp: + { + SDL_SetRenderDrawColor(ren_.get(), 0, 255, 255, alpha); + break; + } + } + } + + if (draw) + { + SDL_Rect rect { + game.map.getTrueX(x) * TILE_WIDTH, + game.map.getTrueY(y) * TILE_HEIGHT, + TILE_WIDTH, + TILE_HEIGHT}; + + SDL_RenderFillRect(ren_.get(), &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 fadeX = game.map.getTrueX(x) - game.map.at(x,y).lightRadius; + int fadeY = game.map.getTrueY(y) - game.map.at(x,y).lightRadius; + int fadeRight = game.map.getTrueX(x) + game.map.at(x,y).lightRadius; + int fadeBottom = game.map.getTrueY(y) + 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); + + if (!game.zooming) + { + SDL_RenderCopy(ren_.get(), canvas.get(), nullptr, nullptr); + } else { + // TODO: zooming back in to the player + SDL_Rect zoomRect { + ((game.maxZoom - game.curZoom) * TILE_WIDTH + game.zoomProgress) + * ZOOM_X_FACTOR / 2, + ((game.maxZoom - game.curZoom) * TILE_HEIGHT + game.zoomProgress) + * ZOOM_Y_FACTOR / 2, + (game.curZoom * TILE_WIDTH - game.zoomProgress) * ZOOM_X_FACTOR, + (game.curZoom * TILE_HEIGHT - game.zoomProgress) * ZOOM_Y_FACTOR + }; + + SDL_RenderCopy(ren_.get(), canvas.get(), &zoomRect, nullptr); + } + + SDL_RenderPresent(ren_.get()); +} diff --git a/src/renderer.h b/src/renderer.h new file mode 100644 index 0000000..4aa27bb --- /dev/null +++ b/src/renderer.h @@ -0,0 +1,132 @@ +#ifndef RENDERER_H_6A58EC30 +#define RENDERER_H_6A58EC30 + +#include +#include +#include +#include + +class Game; + +class sdl_error : public std::logic_error { +public: + + sdl_error() : std::logic_error(SDL_GetError()) + { + } +}; + +class img_error : public std::logic_error { +public: + + img_error() : std::logic_error(IMG_GetError()) + { + } +}; + +class sdl_wrapper { +public: + + sdl_wrapper() + { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + sdl_error ex; + SDL_Quit(); + + throw ex; + } + } + + ~sdl_wrapper() + { + SDL_Quit(); + } +}; + +class img_wrapper { +public: + + img_wrapper() + { + if (IMG_Init(IMG_INIT_PNG) != IMG_INIT_PNG) + { + img_error ex; + IMG_Quit(); + + throw ex; + } + } + + ~img_wrapper() + { + IMG_Quit(); + } +}; + +class window_deleter { +public: + + void operator()(SDL_Window* ptr) + { + SDL_DestroyWindow(ptr); + } +}; + +using window_ptr = std::unique_ptr; + +class renderer_deleter { +public: + + void operator()(SDL_Renderer* ptr) + { + SDL_DestroyRenderer(ptr); + } +}; + +using renderer_ptr = std::unique_ptr; + +class surface_deleter { +public: + + void operator()(SDL_Surface* ptr) + { + SDL_FreeSurface(ptr); + } +}; + +using surface_ptr = std::unique_ptr; + +class texture_deleter { +public: + + void operator()(SDL_Texture* ptr) + { + SDL_DestroyTexture(ptr); + } +}; + +using texture_ptr = std::unique_ptr; + +class Renderer { +public: + + Renderer(); + + void render( + const Game& game, + bool drawDark = true); + +private: + + sdl_wrapper sdl_; + img_wrapper img_; + window_ptr win_; + renderer_ptr ren_; + + texture_ptr playerFade_; + texture_ptr lampFade_; + texture_ptr dustFade_; +}; + +#endif /* end of include guard: RENDERER_H_6A58EC30 */ -- cgit 1.4.1