image_gfxrenderer.hpp

Back to Renderer

pastel/gfx/

#ifndef PASTELGFX_IMAGE_GFXRENDERER_HPP
#define PASTELGFX_IMAGE_GFXRENDERER_HPP

#include "pastel/gfx/image_gfxrenderer.h"
#include "pastel/gfx/drawing.h"
#include "pastel/gfx/texture/textures.h"

#include "pastel/sys/extender/indexextenders.h"

#include "pastel/math/affine/affine_transformation.h"

namespace Pastel
{

    template <typename Type>
    Image_GfxRenderer<Type>::Image_GfxRenderer(Array<Type, 2>* image)
        : GfxRenderer<Type>()
        , screenTransformation_(2)
        , image_(image)
        , textureImage_()
        , mipMap_()
        , nearestTexture_()
        , linearTexture_()
        , ewaTexture_(MipMap<Type, 2>(), ArrayExtender<2, Type>(clampExtender()))
        , texture_(0)
    {
    }

    template <typename Type>
    Image_GfxRenderer<Type>::~Image_GfxRenderer()
    {
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::setImage(Array<Type, 2>* image)
    {
        image_ = image;
    }

    template <typename Type>
    Array<Type, 2>* Image_GfxRenderer<Type>::image() const
    {
        return image_;
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::onSetViewTransformation()
    {
        updateModelView();
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::onSetModelTransformation()
    {
        updateModelView();
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::onSetTexture()
    {
        nearestTexture_.setImage(*textureImage_[Base::texture()]);
        linearTexture_.setImage(*textureImage_[Base::texture()]);
        mipTexture_.setMipMap(*mipMap_[Base::texture()]);
        ewaTexture_.setMipMap(*mipMap_[Base::texture()]);
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::onSetResamplingMode()
    {
        switch(Base::resamplingMode())
        {
        case ResamplingMode::Nearest:
            texture_ = &nearestTexture_;
            break;
        case ResamplingMode::Bilinear:
            texture_ = &linearTexture_;
            break;
        case ResamplingMode::Trilinear:
            texture_ = &mipTexture_;
            break;
        case ResamplingMode::Anisotropic:
            texture_ = &ewaTexture_;
            break;
        };
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::uploadMipMap(
        integer textureId, const MipMap<Type, 2>& mipMap)
    {
        ENSURE2(textureId >= 0 && textureId < textureImage_.size(),
            textureId, textureImage_.size());

        mipMap_[textureId] = &mipMap;
    }

    // Drawing

    template <typename Type>
    integer Image_GfxRenderer<Type>::uploadTexture(const Array<Type, 2>& image)
    {
        textureImage_.push_back(&image);
        mipMap_.push_back(0);

        return textureImage_.size() - 1;
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::clear() const
    {
        const Type& currentColor = Base::color();
        integer width = image_->width();
        integer height = image_->height();

        for (integer y = 0;y < height;++y)
        {
            for (integer x = 0;x < width;++x)
            {

                (*image_)(x, y) = currentColor;
            }
        }
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::drawPoint(
        const Vector2& point) const
    {
        const Type& currentColor = Base::color();
        Vector2 screenPoint = transform(point);

        // Set the closest pixel.

        drawPixel(screenPoint,

            currentColor, arrayView(*image_));
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::drawSegment(
        const Segment2& segment) const
    {
        const Type& currentColor = Base::color();
        Segment2 screenSegment = Segment2(
            transform(segment.start()),
            transform(segment.end()));

        Pastel::drawSegment(screenSegment, currentColor, arrayView(*image_));
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::drawTriangle(
        const Triangle2& triangle) const
    {
        const Type& currentColor = Base::color();
        Triangle2 screenTriangle(
            transform(triangle[0]),
            transform(triangle[1]),
            transform(triangle[2]));

        Pastel::drawTriangle(
            screenTriangle,
            Triangle2(),
            colorTexture<Type, 2>(currentColor),

            arrayView(*image_));
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::drawTriangle(
        const Triangle2& triangle,
        const Tuple<Type, 3>& colorTriangle) const
    {
        Triangle2 screenTriangle(
            transform(triangle[0]),
            transform(triangle[1]),
            transform(triangle[2]));

        Pastel::drawTriangle(
            screenTriangle,
            Triangle2(Vector2(0, 0), Vector2(1, 0), Vector2(0, 1)),
            linearSimplexTexture<Type>(colorTriangle),

            arrayView(*image_));
    }

    template <typename Type>
    void Image_GfxRenderer<Type>::drawTriangle(
        const Triangle2& triangle,
        const Triangle2& textureTriangle) const
    {
        if (Base::texture() >= textureImage_.size() ||
            textureImage_[Base::texture()]->empty())
        {
            drawTriangle(triangle);
        }

        Triangle2 screenTriangle(
            transform(triangle[0]),
            transform(triangle[1]),
            transform(triangle[2]));

        Pastel::drawTriangle(
            screenTriangle,
            textureTriangle,

            *texture_,
            arrayView(*image_));
    }

    // Private

    template <typename Type>
    void Image_GfxRenderer<Type>::updateModelView()
    {
        screenTransformation_ = Base::modelTransformation() *
            inverse(Base::viewTransformation());
    }

    template <typename Type>
    Vector2 Image_GfxRenderer<Type>::transform(const Vector2& point) const
    {
        const Vector2& viewPoint = transformPoint(screenTransformation_, point);
        Vector2 uv = (viewPoint - Base::viewWindow().min()) /
            Base::viewWindow().extent();

        return Vector2(uv * Vector2(image_->width(), image_->height()));
    }

}

#endif