//
//  RendererProtocol.h
//  Meteor
//
//  Created by Cesar Parent on 13/07/2015.
//  Copyright (c) 2015 Cesar Parent. All rights reserved.
//

#ifndef Meteor_RendererProtocol_h
#define Meteor_RendererProtocol_h

#include "../CPFoundation.h"
#include "../Geometry.h"
#include "Color.h"
#include <string>

NS_BEGIN

class Polygon;
class TextureProtocol;

/*!
 * @interface       RendererProtocol
 * @ingroup         Graphics
 * @brief           A protocol defining the API used to communicate with the hardware renderer and
 *                  draw textures and polygons.
 */
class RendererProtocol : public virtual CPObjectProtocol {
    
public:
    
    /*!
     * @enum        FilteringMode
     * @ingroup     Graphics
     * @brief       Texture filtering modes to use when the texture is drawn in a size other
     *              than its native size.
     */
    enum class FilteringMode {
        /// Each screen pixel gets the color of its nearest logical neighbour.
        Nearest,
        /// Each screen pixel's color is interpolated from the color of its logical neighbours.
        Linear,
    };
    
    /*!
     * @name        Managing the Renderer's state
     * @{
     */
    
    /*!
     * @brief       Pushes a target texture on the stack. Subsequent rendering calls will draw on
     *              that texture until it is popped using <code>popTarget()</code> or another
     *              texture is pushed.
     * @param       target      Texture to render to.
     */
    virtual void
    pushTarget(ARC<TextureProtocol> target) = 0;
    
    /*!
     * @brief       Removes the target texture currently on top of the stack. Subsequent rendering
     *              calls will draw on the new topmost texture, or the screen if the stack is empty.
     */
    virtual void
    popTarget() = 0;
    
    /*!
     * @brief       Rotate the renderer by an angle.
     * @param       angle       The angle to rotate the canvas by.
     */
    //virtual void
    //rotate(float angle) = 0;
    
    /*!
     * @brief       Translate the canvas along a vector.
     * @param       offset      The translation vector.
     */
    //virtual void
    //translate(const vec2& offset) = 0;
    
    /*!
     * @brief       Translate the renderer along x and y.
     * @param       dx          The translation along the x axis.
     * @param       sx          The translation along the y axis.
     */
    //virtual void
    //translate(float dx, float dy) = 0;
    
    //virtual void
    //scale(const vec2& scale) = 0;
    
    //virtual void
    //scale(float sx, float sy) = 0;*/
    
    /*!
     * @brief       Sets the renderer's origin rendering origin.
     * @param       origin      The renderer's origin.
     */
    virtual void
    setOriginMatrix(const mat33& origin) = 0;
    
    /*!
     * @brief       Sets the renderer's filtering mode used when scaling textures.
     * @param       mode        The renderer's filtering mode.
     */
    virtual void
    setFilteringMode(FilteringMode mode) = 0;
    
    /*!
     * @brief       Returns the renderer's filtering mode used when scaling textures.
     * @return      The renderer's filtering mode.
     */
    virtual FilteringMode
    setFilteringMode() = 0;
    
    /*!
     * @}
     * @name        Getting data from the renderer
     * @{
     */
    
    /*!
     * @brief       Returns a copy of the screen's pixels as ARGB bytes. This is used to create
     *              screenshots.
     * @param       size        The size of the returned array of pixels.
     * @return      An array of pixels that can be used to create surfaces.
     */
    virtual bool
    pixels(Uint8 pixels[], int pitch) = 0;
    
    virtual size2
    outputSize() = 0;
    
    /*!
     * @}
     * @name        Rendering objects
     * @{
     */
    
    /*!
     * @brief       Renders a line between two points
     * @param       start       Coordinates of the line's starting point.
     * @param       end         Coordinates of the line's end point.
     * @param       color       The line's color.
     */
    virtual void
    renderLine(const vec2& start, const vec2& end, const Color& color) = 0;
    
    /*!
     * @brief       Renders a texture on the screen.
     * @param       texture     Texture to render.
     * @param       position    Texture's position.
     * @param       anchor      Point in the texture that corresponds to its position.
     * @param       scale       Texture's scale factors.
     * @param       angle       Texture's rotation in radians.
     */
    virtual void
    renderTexture(TextureProtocol* texture,
                  const vec2& position,
                  const vec2& anchor,
                  const vec2& scale,
                  float angle) = 0;
    
    /*!
     * @brief       Renders a polygon on the screen.
     * @param       shape       Polygon to render.
     * @param       color       Polygon's stroke color.
     * @param       opacity     Polygon's opacity.
     */
    virtual void
    renderPolygon(const Polygon& shape, const Color& color, float opacity) = 0;
    
    /*!
     * @brief       Displays a filled polygon, on the screen.
     * @param       shape       Polygon object to draw.
     * @param       color       Polygon's fill color.
     * @param       opacity     Polygon's opacity.
     */
    virtual void
    fillPolygon(const Polygon& shape, const Color& color, float opacity) = 0;
    
    /*!
     * @brief       Clears the renderer's view.
     * @param       color       Color to fill the screen with. Defaults to
     *                          <code>Color::blackColor</code>
     */
    virtual void
    clear(const Color& color = Color::blackColor) = 0;
    
    /*!
     * @brief       Displays everything that was rendered since the last call on the screen.
     */
    virtual void
    present() = 0;
    
    /*!
     * @}
     * @name        Requesting Textures from the Renderer
     * @{
     */
    
    /*!
     * @brief       Returns a texture loaded from an image file.
     * @details     The returned texture's hardware data will be taken from a cache if it exists.
     *              Otherwise, it is loaded in hardware and then cached for future use.
     * @param       image       File name of the image to load.
     * @return      A texture loaded from the image.
     */
    virtual ARC<TextureProtocol>
    textureFromImage(const std::string& image) = 0;
    
    /*!
     * @brief       Returns an plain colored texture.
     * @param       size        Texture's dimensions in pixels.
     * @param       color       Texture's color.
     * @return      A plain colored texture.
     */
    virtual ARC<TextureProtocol>
    textureWithSizeAndColor(const size2& size, const Color& color) = 0;
    
    /*!
     * @brief       Returns a texture that can be used as a rendering target.
     * @param       size        Texture's dimensions in pixels.
     * @return      A target texture.
     */
    virtual ARC<TextureProtocol>
    targetTextureWithSize(const size2& size) = 0;
    
    /*!
     * @brief       Returns a texture filled with the given text, rendered with the given font.
     * @param       text        The text to render.
     * @param       font        The text's font filename.
     * @param       size        The text's font size.
     * @param       color       The text's font color.
     * @param       antialiased Wether the text should be drawn with antialiasing or not.
     * @return      A texture filled with the rendered text on a transparent background.
     */
    virtual ARC<TextureProtocol>
    textureWithText(const std::string& text,
                    const std::string& font,
                    int size,
                    const Color& color,
                    bool antialiased) = 0;
    
    /*!
     * @}
     * @name        Managing Caches
     * @{
     */
    
    /*!
     * @brief       Flushes the renderer's texture cache.
     * @details     Cached textures will stay in memory until every other object referencing them
     *              has released them.
     */
    virtual void
    flushTextureCache() = 0;
};

NS_END

#endif
