test_drawing.cpp

Back to 2d drawing

test/pastel/gfx/

// Description: Testing for drawing
// DocumentationOf: drawing.h

#include "test/test_init.h"

#include "pastel/sys/view/extendedconstviews.h"
#include "pastel/sys/view.h"

#include "pastel/gfx/image_file.h"
#include "pastel/gfx/color.h"
#include "pastel/gfx/drawing.h"
#include "pastel/gfx/image_gfxrenderer.h"
#include "pastel/gfx/gfxrenderer_tools.h"
#include "pastel/gfx/texture.h"
#include "pastel/gfx/mipmap.h"
#include "pastel/gfx/filter.h"

#include "pastel/math/sampling/uniform_sampling.h"

#include <boost/lambda/lambda.hpp>
using namespace boost::lambda;

namespace
{

    void testTextureCase(const Texture<Color>& texture)
    {
        integer width = 512;
        integer height = 512;
        Array<Color> image(Vector2i(width, height));

        drawBox(
            AlignedBox2(0, 0, width, height),
            texture,
            arrayView(image));

        savePcx(image, "texture_" + texture.fullName() + ".pcx");
    }

}

TEST_CASE("Texture (Texture)")
{
    Color colorSet[] = 
    {
        Color(1, 0, 0),
        Color(0, 1, 0),
        Color(0, 0, 1),
        Color(1, 1, 1)
    };

    LinearColor_Texture<Color> smooth =
        linearColorTexture<Color, 2>(
        range(colorSet));

    testTextureCase(
        mixTexture(
        subTexture(smooth, AlignedBox2(-1, -1, 2, 2)),
        colorTexture<Color, 2>(Color(0)), 
        subTexture(noiseTexture<2>(), 
        AlignedBox2(0, 0, 0.2, 0.2))));

    testTextureCase(
        mixTexture(
        colorTexture<Color, 2>(Color(0)),
        subTexture(smooth, AlignedBox2(-1, -1, 2, 2)),
        subTexture(turbulenceTexture<2>(),
        AlignedBox2(0, 0, 0.1, 0.1))));
}

TEST_CASE("View (View)")
{
    Array<Color, 2> image(Vector2i(500, 500), Color(0));

    clear(Color(1), subView(arrayView(image), AlignedBox2i(10, 20, 100, 110)));
    clear(Color(1), sparseView(subView(arrayView(image), AlignedBox2i(110, 120, 200, 210)), Vector2i(0), Vector2i(2, 2)));

    clear(Color(0, 0, 1), rowView(arrayView(image), 0, Vector2i(10, 10)));
    clear(Color(0, 0, 1), rowView(arrayView(image), 1, Vector2i(10, 10)));

    copy(constSubView(constArrayView(image), AlignedBox2i(0, 0, 200, 200)),
        subView(arrayView(image), AlignedBox2i(300, 300, 500, 500)));

    savePcx(image, "drawing_view.pcx");
}

TEST_CASE("Binary (Binary)")
{
    Array<bool, 2> image(Vector2i(500, 500), false);

    clear(false, arrayView(image));

    drawBox(AlignedBox2(100, 100, 200, 200), true,
        arrayView(image));

    drawSegment(Segment2(Vector2(250, 50), Vector2(300, 30)),
        true, arrayView(image));

    saveBinaryPcx(image, "drawing_binary.pcx");
}

TEST_CASE("FloodFill (FloodFill)")
{
    Array<Color, 2> image(Vector2i(500, 500), Color(0));

    Image_GfxRenderer<Color> renderer;

    renderer.setImage(&image);
    renderer.setViewWindow(AlignedBox2(-1, -1, 1, 1));
    renderer.setFilled(false);

    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(Vector2(0), 0.5), 20);

    renderer.setColor(randomRgbColor());
    drawTriangle(renderer, Triangle2(Vector2(0), Vector2(0, -1), Vector2(0.5)));

    floodFill(0, 0, randomRgbColor(), arrayView(image));

    savePcx(image, "drawing_floodfill.pcx");
}

namespace
{

    template <typename Real, integer N>
    Vector<Real, N> randomPoint(
        const AlignedBox<Real, N>& region)
    {
        return region.min() + randomVector<Real, N>() * region.extent();
    }

}

TEST_CASE("PerspectiveTriangle (PerspectiveTriangle)")
{
    Array<Color, 2> image(Vector2i(500, 500));

    Array<Color, 2> texture;
    loadPcx("lena.pcx", texture);

    //std::cout << "Computing mipmaps.." << std::endl;
    MipMap<Color, 2> mipMap(constArrayView(texture));
    transform(mipMap, fitColor);

    MipImage_Texture<Color> sampler(mipMap);

    //std::cout << "Rendering.." << std::endl;

    AlignedBox3 region(
        Vector3(-100, -100, 0),
        Vector3(600, 600, 10));

    for (integer i = 0;i < 5;++i)
    {
        drawTriangle(
            Triangle3(
                randomPoint(region),
                randomPoint(region),
                randomPoint(region)),
            Triangle2(
                Vector2(0), Vector2(1, 0), Vector2(0.5, 1)),
            sampler,
            arrayView(image));
    }

    savePcx(image, "drawing_perspectivetriangle.pcx");
}

TEST_CASE("EwaPerspectiveTriangle (EwaPerspectiveTriangle)")
{
    integer superSample = 4;

    const integer width = 512 * superSample;
    const integer height = 512 * superSample;

    Array<Color, 2> image(Vector2i(width, height));

    Array<Color, 2> textureImage;
    loadPcx("lena.pcx", textureImage);

    //std::cout << "Rendering.." << std::endl;

    AlignedBox3 region(
        Vector3(-width / 4, -height / 4, 0),

        Vector3(width * 1.25, height * 1.25, 10));

    MipMap<Color, 2> mipMap(constArrayView(textureImage));
    EwaImage_Texture<Color> texture(mipMap);
    transform(mipMap, fitColor);

    for (integer i = 0;i < 5;++i)
    {
        drawTriangle(
            Triangle3(
                randomPoint(region),
                randomPoint(region),
                randomPoint(region)),
            Triangle2(
                Vector2(0), Vector2(1, 0), Vector2(0.5, 1)),
            texture,
            arrayView(image));
    }

    Array<Color> smallImage(Vector2i(width / superSample, height / superSample));
    resample<Color>(
        constArrayView(image),
        ArrayExtender<2, Color>(clampExtender()),
        lanczosFilter(2),
        arrayView(smallImage));
    transform(arrayView(smallImage), fitColor);

    savePcx(smallImage, "drawing_ewaperspectivetriangle.pcx");
}

TEST_CASE("TextureTriangle (TextureTriangle)")
{
    Array<Color, 2> image(Vector2i(500, 500));

    Array<Color, 2> texture;
    loadPcx("lena.pcx", texture);

    //std::cout << "Computing mipmaps.." << std::endl;
    MipMap<Color, 2> mipMap(constArrayView(texture));
    transform(mipMap, fitColor);

    MipImage_Texture<Color> sampler(mipMap);

    //std::cout << "Rendering.." << std::endl;

    AlignedBox2 region(
        Vector2(-100, -100),
        Vector2(600, 600));

    for (integer i = 0;i < 5;++i)
    {
        drawTriangle(
            Triangle2(
                randomPoint(region),
                randomPoint(region),
                randomPoint(region)),
            Triangle2(
                Vector2(0), Vector2(1, 0), Vector2(0.5, 1)),
            sampler,
            arrayView(image));
    }

    savePcx(image, "drawing_texturetriangle.pcx");
}

TEST_CASE("EwaTriangle (EwaTriangle)")
{
    Array<Color, 2> image(Vector2i(500, 500));

    Array<Color, 2> textureImage;
    loadPcx("lena.pcx", textureImage);

    //std::cout << "Rendering.." << std::endl;

    AlignedBox2 region(
        Vector2(-100, -100),
        Vector2(600, 600));

    MipMap<Color, 2> mipMap(constArrayView(textureImage));
    EwaImage_Texture<Color> texture(mipMap);
    transform(mipMap, fitColor);

    Triangle_Filter ewaFilter;
    for (integer i = 0;i < 5;++i)
    {
        drawTriangle(
            Triangle2(
                randomPoint(region),
                randomPoint(region),
                randomPoint(region)),
            Triangle2(
                Vector2(0), Vector2(1, 0), Vector2(0.5, 1)),
            texture,
            arrayView(image));
    }

    savePcx(image, "drawing_ewaimagetexturetriangle.pcx");
}

TEST_CASE("SolidTriangle (SolidTriangle)")
{
    Array<Color, 2> image(Vector2i(500, 500));

    Array<Color, 2> texture;
    loadPcx("lena.pcx", texture);

    //std::cout << "Rendering.." << std::endl;

    AlignedBox2 region(
        Vector2(-100, -100),
        Vector2(600, 600));

    for (integer i = 0;i < 5;++i)
    {
        drawTriangle(
            Triangle2(
                randomPoint(region),
                randomPoint(region),
                randomPoint(region)),
            randomRgbColor(),
            arrayView(image),
            transparentColorMixer<Color>(0.75));
    }

    savePcx(image, "drawing_solidtriangle.pcx");
}

TEST_CASE("Boxes (Boxes)")
{
    Array<Color, 2> image(Vector2i(640, 480));

    Image_GfxRenderer<Color> renderer;

    renderer.setImage(&image);
    renderer.setViewWindow(AlignedBox2(0, 0, 640, 480));

    Vector2 a(0, 0);
    Vector2 b(33.3, 45.6);
    Vector2 c(634.4, 200.1);
    Vector2 d(33.3, 0);
    Vector2 e(634.4, 45.6);

    renderer.setColor(randomRgbColor());
    drawBox(renderer, AlignedBox2(a, b));
    renderer.setColor(randomRgbColor());
    drawBox(renderer, AlignedBox2(b, c));
    renderer.setColor(randomRgbColor());
    drawBox(renderer, AlignedBox2(d, e));

    savePcx(image, "drawing_boxes.pcx");
}

TEST_CASE("MoreCircles (MoreCircles)")
{
    Array<Color, 2> image(Vector2i(640, 480));

    Image_GfxRenderer<Color> renderer;
    renderer.setImage(&image);
    renderer.setViewWindow(AlignedBox2(0, 0, 640, 480));
    renderer.setColor(randomRgbColor());

    for (integer i = 0;i < 10;++i)
    {
        for (integer j = 0;j < 10;++j)
        {
            drawCircle(renderer, Sphere2(Vector2(i * 64.1 + 32, j * 48 + 24), 20 + j * 0.1));
        }
    }

    savePcx(image, "drawing_morecircles.pcx");
}

TEST_CASE("Circles (Circles)")
{
    Array<Color, 2> image(Vector2i(640, 480));

    Image_GfxRenderer<Color> renderer;
    renderer.setImage(&image);
    renderer.setViewWindow(AlignedBox2(0, 0, 640, 480));

    Vector2 a(320, 240);

    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 100));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 99));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 98));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 96));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 94));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 91));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 88));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 84));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 80));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 75));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 70));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 64));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 58));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 51));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 44));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 36));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 28));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 19));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(a, 10));

    Vector2 b(55.3, 45.7);

    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(b, 20.1));
    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(b, 19.5));

    Vector2 c(-50, 480);

    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(c, 200));

    renderer.setColor(randomRgbColor());
    drawCircle(renderer, Sphere2(c, 45));

    savePcx(image, "drawing_circles.pcx");
}

TEST_CASE("Lines (Lines)")
{
    Array<Color, 2> image(Vector2i(640, 480));

    integer steps = 128;

    Vector2 center(50.5, 240.5);
    real radius = 200;

    real alphaStep = 2 * constantPi<real>() / steps;

    for (integer i = 0;i < steps;++i)
    {
        Vector2 to(
            center.x() + std::cos(alphaStep * i) * radius,
            center.y() + std::sin(alphaStep * i) * radius);

        /*
       Vector2 to(
           std::floor(center.x() + std::cos(alphaStep * i) * radius) + 0.5,
           std::floor(center.y() + std::sin(alphaStep * i) * radius) + 0.5);
       */

        drawSegment(Segment2(center, to), Color(1), arrayView(image));
    }

    savePcx(image, "drawing_lines.pcx");
}

TEST_CASE("MoreLines (MoreLines)")
{
    Array<Color, 2> image(Vector2i(640, 480));

    integer lines = 500;

    for (integer i = 0;i < lines;++i)
    {

        const Vector2 from(random<real>() * 1000 - 180, random<real>() * 740 - 180);
        const Vector2 to(random<real>() * 1000 - 180, random<real>() * 740 - 180);
        drawSegment(Segment2(from, to), randomRgbColor(), arrayView(image));
    }

    savePcx(image, "drawing_morelines.pcx");
}

TEST_CASE("EvenMoreLines (EvenMoreLines)")
{
    integer XLines = 5;
    integer YLines = 5;
    integer BoxWidth = 100;
    integer BoxHeight = 25;
    integer Border = 10;
    real YStart = 0.1;
    real YEnd = 0.9;
    real XYStep = (real)(YEnd - YStart) / (XLines - 1);
    real YYStep = (real)(YEnd - YStart) / (YLines - 1);

    Array<Color, 2> image(Vector2i(XLines* BoxWidth, YLines * BoxHeight));

    for (integer y = 0;y < YLines;++y)
    {
        for (integer x = 0;x < XLines;++x)
        {
            Vector2 from(
                x * BoxWidth + Border + 0.5,
                y * BoxHeight + Border + (YStart + x * XYStep));
            Vector2 to(
                x * BoxWidth + (BoxWidth - Border) + 0.5 ,
                y * BoxHeight + (BoxHeight - Border) + (YStart + y * YYStep));

            drawSegment(Segment2(from, to), Color(1), arrayView(image));
        }
    }

    savePcx(image, "drawing_evenmorelines.pcx");
}