summary refs log blame commit diff stats
path: root/src/renderer.cpp
blob: 90ce03f31cd00c6266b60bb000e0c4c941282479 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
12
13
14












                         
                                                                     
 





























































































                                                                                

                                                         










                                                                                    










                                                                                










                                                                             
 
                          
























                                                                                    




                                           
 
                                


                                                              
                            

                       


               
                                                  






                                                                         
                






                                                                       
 


                                                                  
                                                
         


       













                                                                                                        







































                                                                   









                                                                                                    

















































                                                                            















                                                                            
   






                                                                 
   
                      
 
#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};
}