/**
 * @file Sprites.h
 * \brief
 * A class for drawing animated sprites from image and mask bitmaps.
 */

#ifndef Sprites_h
#define Sprites_h

#include "Arduboy2.h"
#include "SpritesCommon.h"

/** \brief
 * A class for drawing animated sprites from image and mask bitmaps.
 *
 * \details
 * The functions in this class will draw to the screen buffer an image
 * contained in an array located in program memory. A mask can also be
 * specified or implied, which dictates how existing pixels in the buffer,
 * within the image boundaries, will be affected.
 *
 * A sprite or mask array contains one or more "frames". Each frame is intended
 * to show whatever the sprite represents in a different position, such as the
 * various poses for a running or jumping character. By specifying a different
 * frame each time the sprite is drawn, it can be animated.
 *
 * Each image array begins with values for the width and height of the sprite,
 * in pixels. The width can be any value. The height must be a multiple of
 * 8 pixels, but with proper masking, a sprite of any height can be created.
 *
 * For a separate mask array, as is used with `drawExternalMask()`, the width
 * and height are not included but must contain data of the same dimensions
 * as the corresponding image array.
 *
 * Following the width and height values for an image array, or from the
 * beginning of a separate mask array, the array contains the image and/or
 * mask data for each frame. Each byte represents a vertical column of 8 pixels
 * with the least significant bit (bit 0) at the top. The bytes are drawn as
 * 8 pixel high rows from left to right, top to bottom. When the end of a row
 * is reached, as specified by the width value, the next byte in the array will
 * be the start of the next row.
 *
 * Data for each frame after the first one immediately follows the previous
 * frame. Frame numbers start at 0.
 *
 * \note
 * \parblock
 * A separate `SpritesB` class is available as an alternative to this class.
 * The only difference is that the `SpritesB` class is optimized for small
 * code size rather than for execution speed. One or the other can be used
 * depending on whether size or speed is more important.
 *
 * Even if the speed is acceptable when using `SpritesB`, you should still try
 * using `Sprites`. In some cases `Sprites` will produce less code than
 * `SpritesB`, notably when only one of the functions is used.
 *
 * You can easily switch between using the `Sprites` class or the `SpritesB`
 * class by using one or the other to create an object instance:
 *
 * \code{.cpp}
 * Sprites sprites;  // Use this to optimize for execution speed
 * SpritesB sprites; // Use this to (likely) optimize for code size
 * \endcode
 * \endparblock
 *
 * \note
 * \parblock
 * In the example patterns given in each Sprites function description,
 * a # character represents a bit set to 1 and
 * a - character represents a bit set to 0.
 * \endparblock
 *
 * \see SpritesB
 */
class Sprites
{
  public:
    /** \brief
     * Draw a sprite using a separate image and mask array.
     *
     * \param x,y The coordinates of the top left pixel location.
     * \param bitmap A pointer to the array containing the image frames.
     * \param mask A pointer to the array containing the mask frames.
     * \param frame The frame number of the image to draw.
     * \param mask_frame The frame number for the mask to use (can be different
     * from the image frame number).
     *
     * \details
     * An array containing the image frames, and another array containing
     * corresponding mask frames, are used to draw a sprite.
     *
     * For the mask array, the width and height are not included but must
     * contain data of the same dimensions as the corresponding image array.
     *
     * Bits set to 1 in the mask indicate that the pixel will be set to the
     * value of the corresponding image bit. Bits set to 0 in the mask will be
     * left unchanged.
     *
     *     image  mask   before  after  (# = 1, - = 0)
     *
     *     -----  -###-  -----   -----
     *     --#--  #####  -----   --#--
     *     ##-##  ##-##  -----   ##-##
     *     --#--  #####  -----   --#--
     *     -----  -###-  -----   -----
     *
     *     image  mask   before  after
     *
     *     -----  -###-  #####   #---#
     *     --#--  #####  #####   --#--
     *     ##-##  #####  #####   ##-##
     *     --#--  #####  #####   --#--
     *     -----  -###-  #####   #---#
     */
    static void drawExternalMask(int16_t x, int16_t y, const uint8_t *bitmap,
                                 const uint8_t *mask, uint8_t frame, uint8_t mask_frame);

    /** \brief
     * Draw a sprite using an array containing both image and mask values.
     *
     * \param x,y The coordinates of the top left pixel location.
     * \param bitmap A pointer to the array containing the image/mask frames.
     * \param frame The frame number of the image to draw.
     *
     * \details
     * An array containing combined image and mask data is used to draw a
     * sprite. Bytes are given in pairs with the first byte representing the
     * image pixels and the second byte specifying the corresponding mask.
     * The width given in the array still specifies the image width, so each
     * row of image and mask bytes will be twice the width value.
     *
     * Bits set to 1 in the mask indicate that the pixel will be set to the
     * value of the corresponding image bit. Bits set to 0 in the mask will be
     * left unchanged.
     *
     *     image  mask   before  after  (# = 1, - = 0)
     *
     *     -----  -###-  -----   -----
     *     --#--  #####  -----   --#--
     *     ##-##  ##-##  -----   ##-##
     *     --#--  #####  -----   --#--
     *     -----  -###-  -----   -----
     *
     *     image  mask   before  after
     *
     *     -----  -###-  #####   #---#
     *     --#--  #####  #####   --#--
     *     ##-##  #####  #####   ##-##
     *     --#--  #####  #####   --#--
     *     -----  -###-  #####   #---#
     */
    static void drawPlusMask(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);

    /** \brief
     * Draw a sprite by replacing the existing content completely.
     *
     * \param x,y The coordinates of the top left pixel location.
     * \param bitmap A pointer to the array containing the image frames.
     * \param frame The frame number of the image to draw.
     *
     * \details
     * A sprite is drawn by overwriting the pixels in the buffer with the data
     * from the specified frame in the array. No masking is done. A bit set
     * to 1 in the frame will set the pixel to 1 in the buffer, and a 0 in the
     * array will set a 0 in the buffer.
     *
     *     image  before  after  (# = 1, - = 0)
     *
     *     -----  -----   -----
     *     --#--  -----   --#--
     *     ##-##  -----   ##-##
     *     --#--  -----   --#--
     *     -----  -----   -----
     *
     *     image  before  after
     *
     *     -----  #####   -----
     *     --#--  #####   --#--
     *     ##-##  #####   ##-##
     *     --#--  #####   --#--
     *     -----  #####   -----
     */
    static void drawOverwrite(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);

    /** \brief
     * "Erase" a sprite.
     *
     * \param x,y The coordinates of the top left pixel location.
     * \param bitmap A pointer to the array containing the image frames.
     * \param frame The frame number of the image to erase.
     *
     * \details
     * The data from the specified frame in the array is used to erase a
     * sprite. To "erase" a sprite, bits set to 1 in the frame will set the
     * corresponding pixel in the buffer to 0. Frame bits set to 0 will remain
     * unchanged in the buffer.
     *
     *     image  before  after  (# = 1, - = 0)
     *
     *     -----  -----   -----
     *     --#--  -----   -----
     *     ##-##  -----   -----
     *     --#--  -----   -----
     *     -----  -----   -----
     *
     *     image  before  after
     *
     *     -----  #####   #####
     *     --#--  #####   ##-##
     *     ##-##  #####   --#--
     *     --#--  #####   ##-##
     *     -----  #####   #####
     */
    static void drawErase(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);

    /** \brief
     * Draw a sprite using only the bits set to 1.
     *
     * \param x,y The coordinates of the top left pixel location.
     * \param bitmap A pointer to the array containing the image frames.
     * \param frame The frame number of the image to draw.
     *
     * \details
     * Bits set to 1 in the frame will be used to draw the sprite by setting
     * the corresponding pixel in the buffer to 1. Bits set to 0 in the frame
     * will remain unchanged in the buffer.
     *
     *     image  before  after  (# = 1, - = 0)
     *
     *     -----  -----   -----
     *     --#--  -----   --#--
     *     ##-##  -----   ##-##
     *     --#--  -----   --#--
     *     -----  -----   -----
     *
     *     image  before  after
     *
     *     -----  #####   #####  (no change because all pixels were
     *     --#--  #####   #####  already white)
     *     ##-##  #####   #####
     *     --#--  #####   #####
     *     -----  #####   #####
     */
    static void drawSelfMasked(int16_t x, int16_t y, const uint8_t *bitmap, uint8_t frame);

    // Master function. Needs to be abstracted into separate function for
    // every render type.
    // (Not officially part of the API)
    static void draw(int16_t x, int16_t y,
                     const uint8_t *bitmap, uint8_t frame,
                     const uint8_t *mask, uint8_t sprite_frame,
                     uint8_t drawMode);

    // (Not officially part of the API)
    static void drawBitmap(int16_t x, int16_t y,
                           const uint8_t *bitmap, const uint8_t *mask,
                           uint8_t w, uint8_t h, uint8_t draw_mode);
};

#endif
