git.haldean.org dotmatrix / master main.cpp
master

Tree @master (Download .tar.gz)

main.cpp @masterraw · history · blame

#include <cstdint>
#include <iostream>
#include <random>
#include <vector>

#include <Eigen/Dense>
#include <png++/png.hpp>

#include "perspective.hpp"

using namespace Eigen;

#define W 1000
#define H 400

static Matrix<uint16_t, Dynamic, Dynamic> img;
typedef png::basic_rgb_pixel<uint8_t> pixel;

uint8_t c[7][3] {
        { 255,   250,   243 },
        { 210,   204,   200 },
        { 180,   168,   160 },
        { 140,   140,   135 },
        { 110,   104,   100 },
        {  50,    40,    35 },
        {   0,     0,     0 },
};
/*
uint8_t c[7][3] {
        { 0,     0,     40  },
        { 140,   0,     0   },
        { 180,   30,    0   },
        { 200,   140,   0   },
        { 255,   200,   80  },
        { 255,   255,   140 },
        { 255,   255,   240 },
};
*/

Vector2f random_uv()
{
        static std::random_device rd;
        static std::default_random_engine rande(rd());
        static std::uniform_real_distribution<float> dist_u(0, 2 * M_PI);
        static std::normal_distribution<float> dist_v(M_PI / 2, M_PI / 6);

        float u = dist_u(rande);
        float v = dist_v(rande);
        return Vector2f(u, v);
}

void point(Vector2i p)
{
        int x = p[0];
        int y = p[1];
        if (x >= 0 && x < img.rows() && y >= 0 && y < img.cols())
                img(x, y)++;
}

void line(Vector2i start, Vector2i end)
{
        if (start[0] > end[0])
                std::swap(start, end);
        Vector2i delta = end - start;
        bool flip = false;
        if (fabs(delta[1]) > fabs(delta[0]))
        {
                int t;
                t = start[0]; start[0] = start[1]; start[1] = t;
                t = end[0]; end[0] = end[1]; end[1] = t;
                t = delta[0]; delta[0] = delta[1]; delta[1] = t;
                flip = true;
        }

        double derr = fabs((double) delta[1] / (double) delta[0]);
        double err = derr - 0.5;
        int y = start[1];
        if (delta[0] == 0)
        {
                for (int y = start[0]; y <= start[1]; delta[1] > 0 ? y++ : y--)
                        point(Vector2i(start[0], y));
                return;
        }
        for (int x = start[0]; x <= end[0]; x++)
        {
                if (flip)
                        point(Vector2i(y, x));
                else
                        point(Vector2i(x, y));
                err += derr;
                while (err >= 0.5)
                {
                        if (delta[1] > 0) y++;
                        else y--;
                        err -= 1.;
                }
        }
}

Vector2i uv2ss(Vector2f uv, float t)
{
        static Matrix4f view = lookAt<float>(
                Vector3f(0, 10, 0),
                //Vector3f(0.75, 0.65, 0),
                Vector3f(0, 0, 0),
                Vector3f(0, 0, 1));
        static Matrix4f proj =
                perspective<float>(M_PI / 7, 1., 0.1, 100);
        static Matrix4f mvp = proj * view;

        Vector4f h;
        h.block(0, 0, 3, 1) =
                AngleAxisf(4 * M_PI * t, Vector3f::UnitX()) *
                AngleAxisf(uv[0] + 2 * M_PI * t, Vector3f::UnitZ()) *
                AngleAxisf(uv[1], Vector3f::UnitY()) *
                Vector3f::UnitZ();
        h[3] = 1;
        Vector4f p = mvp * h;
        int x = int(roundf(p[0] * 100)) + W / 2;
        int y = int(roundf(p[1] * 100)) + H / 2;
        return Vector2i(x, y);
}

int main() {
        img.resize(W, H);

        Vector3f r3;
        Vector4f p;
        size_t i, j;
        float u, v;
        Vector2i s, e;

        std::vector<std::pair<Vector2f, Vector2f>> edges;
        for (int i = 0; i < 1000; i++)
        {
                Vector2f uv1 = random_uv();
                Vector2f uv2 = random_uv();
                edges.push_back(std::make_pair(uv1, uv2));
        }

        const int framecount = 0;
        for (int f = 0; f < framecount; f++)
        {
                float t = (float) f / framecount;
                img.setZero();
                if (true)
                {
                        for (const auto &pp : edges)
                        {
                                s = uv2ss(pp.first, t);
                                e = uv2ss(pp.second, t);
                                line(s, e);
                        }
                }
                if (false)
                {
                        const float step = 0.01;
                        for (float u = 0; u < 2 * M_PI; u += step)
                        {
                                for (float v = 0; v < M_PI; v += step)
                                {
                                        e = uv2ss(Vector2f(u, v), t);
                                        point(e);
                                }
                        }
                }

                png::image<pixel> out(W, H);
                for (i = 0; i < W; i++)
                {
                        for (j = 0; j < H; j++)
                        {
                                uint16_t step = img(i, j);
                                if (step > 6)
                                        step = 6;
                                auto px = pixel(
                                        c[step][0], c[step][1], c[step][2]);
                                out.set_pixel(i, j, px);
                        }
                }
                char buf[32];
                sprintf(buf, "output-%06d.png", f);
                out.write(buf);
        }
        return 0;
}