#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;
}