From 41ea2d8f94043d49fc26aaaa8030a73dcfdc2da9 Mon Sep 17 00:00:00 2001
From: Julian T <julian@jtle.dk>
Date: Sun, 24 Jan 2021 18:13:44 +0100
Subject: Create rust project

---
 .gitignore          |   1 +
 CMakeLists.txt      |  32 --------
 Cargo.toml          |   9 +++
 app/config.hpp      |  22 ------
 app/draw.cpp        |  32 --------
 app/draw.hpp        |  30 -------
 app/main.cpp        |  48 ------------
 app/mainwindow.cpp  |  50 ------------
 app/mainwindow.hpp  |  34 --------
 app/rendercoord.cpp | 220 ----------------------------------------------------
 app/rendercoord.hpp |  93 ----------------------
 src/common.hpp      |   6 --
 src/main.rs         |   3 +
 src/object.cpp      | 103 ------------------------
 src/object.hpp      |  76 ------------------
 src/ray.cpp         |  17 ----
 src/ray.hpp         |  15 ----
 src/render.cpp      | 166 ---------------------------------------
 src/render.hpp      |  61 ---------------
 src/scene.cpp       |   5 --
 src/scene.hpp       |  15 ----
 src/vector.cpp      | 106 -------------------------
 src/vector.hpp      |  33 --------
 test/main.cpp       |   2 -
 test/object.cpp     |  36 ---------
 test/vector.cpp     |  31 --------
 26 files changed, 13 insertions(+), 1233 deletions(-)
 create mode 100644 .gitignore
 delete mode 100644 CMakeLists.txt
 create mode 100644 Cargo.toml
 delete mode 100644 app/config.hpp
 delete mode 100644 app/draw.cpp
 delete mode 100644 app/draw.hpp
 delete mode 100644 app/main.cpp
 delete mode 100644 app/mainwindow.cpp
 delete mode 100644 app/mainwindow.hpp
 delete mode 100644 app/rendercoord.cpp
 delete mode 100644 app/rendercoord.hpp
 delete mode 100644 src/common.hpp
 create mode 100644 src/main.rs
 delete mode 100644 src/object.cpp
 delete mode 100644 src/object.hpp
 delete mode 100644 src/ray.cpp
 delete mode 100644 src/ray.hpp
 delete mode 100644 src/render.cpp
 delete mode 100644 src/render.hpp
 delete mode 100644 src/scene.cpp
 delete mode 100644 src/scene.hpp
 delete mode 100644 src/vector.cpp
 delete mode 100644 src/vector.hpp
 delete mode 100644 test/main.cpp
 delete mode 100644 test/object.cpp
 delete mode 100644 test/vector.cpp

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..ea8c4bf
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+/target
diff --git a/CMakeLists.txt b/CMakeLists.txt
deleted file mode 100644
index df9bd70..0000000
--- a/CMakeLists.txt
+++ /dev/null
@@ -1,32 +0,0 @@
-cmake_minimum_required(VERSION 3.10)
-
-project(pathtracing)
-
-# cmake options
-set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
-set(CMAKE_AUTOMOC ON)
-
-set(CMAKE_CXX_STANDARD 11)
-set(CMAKE_CXX_STANDARD_REQUIRED True)
-
-# Compiler options
-set(CMAKE_CXX_FLAGS "-Wall -Wextra")
-set(CMAKE_CXX_FLAGS_DEBUG "-g")
-set(CMAKE_CXX_FLAGS_RELEASE "-O3")
-
-FILE(GLOB app_sources ${CMAKE_SOURCE_DIR}/app/*.cpp)
-FILE(GLOB sources ${CMAKE_SOURCE_DIR}/src/*.cpp)
-FILE(GLOB test_sources ${CMAKE_SOURCE_DIR}/test/*.cpp)
-
-add_executable(pathtracing ${sources} ${app_sources})
-target_include_directories(pathtracing PUBLIC src)
-
-# Catch2 unittests
-add_custom_target(test)
-add_executable(run_test EXCLUDE_FROM_ALL ${sources} ${test_sources})
-target_include_directories(run_test PUBLIC src)
-add_dependencies(test run_test)
-
-# Qt
-find_package(Qt5 COMPONENTS Widgets REQUIRED)
-target_link_libraries(pathtracing Qt5::Widgets)
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644
index 0000000..621e7e3
--- /dev/null
+++ b/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "pathtrace"
+version = "0.1.0"
+authors = ["Julian T <julian@jtle.dk>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/app/config.hpp b/app/config.hpp
deleted file mode 100644
index 6e9962c..0000000
--- a/app/config.hpp
+++ /dev/null
@@ -1,22 +0,0 @@
-#ifndef CONFIG_H
-#define CONFIG_H
-
-#include <render.hpp>
-
-class Config {
-    public:
-        unsigned m_width, m_height;
-        unsigned m_maxhops, m_samples;
-        
-        unsigned m_framerate, m_workers;
-};
-
-class RendererConf : public Renderer {
-    public:
-        RendererConf(const Scene &scn, Vec3d eye, Vec3d target, Config &conf) 
-            : Renderer(scn, eye, target, conf.m_width, conf.m_height, conf.m_maxhops) {
-            
-            }
-};
-
-#endif
diff --git a/app/draw.cpp b/app/draw.cpp
deleted file mode 100644
index 88733ef..0000000
--- a/app/draw.cpp
+++ /dev/null
@@ -1,32 +0,0 @@
-#include "draw.hpp"
-#include <qnamespace.h>
-#include <qpainter.h>
-#include <qglobal.h>
-#include <qimage.h>
-#include <qrgb.h>
-#include <qtimer.h>
-#include <qwindowdefs.h>
-#include <iostream>
-
-DrawWidget::DrawWidget(const Config &conf) : 
-    QWidget(), m_conf(conf) {
-    m_drawbuffer = new QRgb[conf.m_width * conf.m_height];
-
-    m_img = QImage((uchar*)m_drawbuffer, conf.m_width, conf.m_height, QImage::Format_ARGB32);
-
-}
-
-void DrawWidget::paintEvent(QPaintEvent*) {
-    QPainter painter(this);
-
-    auto scaled = m_img.scaled(width(), height(), Qt::KeepAspectRatio);
-    painter.drawImage(0, 0, scaled);
-}
-
-void DrawWidget::redraw() {
-    repaint();
-}
-
-DrawWidget::~DrawWidget() {
-    delete[] m_drawbuffer;
-}
diff --git a/app/draw.hpp b/app/draw.hpp
deleted file mode 100644
index 454558c..0000000
--- a/app/draw.hpp
+++ /dev/null
@@ -1,30 +0,0 @@
-#ifndef DRAW_H
-#define DRAW_H
-
-#include "config.hpp"
-#include <qimage.h>
-#include <qtimer.h>
-#include <qwidget.h>
-
-class DrawWidget : public QWidget {
-    Q_OBJECT
-
-    public:
-        DrawWidget(const Config &conf);
-        void paintEvent(QPaintEvent*);
-
-        QRgb *m_drawbuffer;
-        QImage m_img;
-        unsigned m_width, m_height;
-
-        ~DrawWidget();
-    private slots:
-        void redraw();
-
-    private:
-        unsigned char i;
-
-        const Config &m_conf;
-};
-
-#endif
diff --git a/app/main.cpp b/app/main.cpp
deleted file mode 100644
index e53b8ad..0000000
--- a/app/main.cpp
+++ /dev/null
@@ -1,48 +0,0 @@
-#include <iostream>
-#include <qapplication.h>
-#include <qpushbutton.h>
-
-#include "mainwindow.hpp"
-#include "vector.hpp"
-#include <scene.hpp>
-#include <render.hpp>
-#include <object.hpp>
-
-using namespace std;
-
-int main(int argc, char *argv[])
-{
-    QApplication a(argc, argv);
-    Scene scn;
-    Config conf;
-    conf.m_width = 500;
-    conf.m_height = 500;
-    conf.m_maxhops = 5;
-    conf.m_samples = 100;
-    conf.m_framerate = 3;
-    conf.m_workers = 4;
-
-
-    Material blue(Color(0.3, 0.3, 1), 1);
-    Material red(Color(1, 0.3, 0.3), 1);
-    Material white(Color(1, 1, 1), 1);
-    Material em(Color(1, 1, 1), 0, 2);
-
-    scn.addShape(new Sphere(red, Vec3d(2, 6, -1), 1));
-    scn.addShape(new Sphere(white, Vec3d(0, 4, -1), 1.3));
-    scn.addShape(new Sphere(white, Vec3d(-2, 5, -2), 1.3));
-    scn.addShape(new Sphere(blue, Vec3d(0, 7, 0), 0.5));
-
-    scn.addShape(new Plane(em, Vec3d(0, 0, 0), Vec3d(0, 1, 0)));
-    scn.addShape(new Plane(white, Vec3d(0, 10, 0), Vec3d(0, 1, 0)));
-    scn.addShape(new Plane(white, Vec3d(0, 0, -5), Vec3d(0, 0, 1)));
-    scn.addShape(new Plane(red, Vec3d(-5, 0, 0), Vec3d(1, 0, 0)));
-    scn.addShape(new Plane(blue, Vec3d(5, 0, 0), Vec3d(1, 0, 0)));
-
-    RendererConf render(scn, Vec3d(0, 5, 4), Vec3d(0, 5, 0), conf);
-
-    MainWindow main(render, conf);
-    main.show();
-
-    return a.exec();
-}
diff --git a/app/mainwindow.cpp b/app/mainwindow.cpp
deleted file mode 100644
index eed98f9..0000000
--- a/app/mainwindow.cpp
+++ /dev/null
@@ -1,50 +0,0 @@
-#include "mainwindow.hpp"
-#include <qaction.h>
-#include <qapplication.h>
-#include <qlabel.h>
-#include <qnamespace.h>
-#include <QFileDialog>
-#include <QMessageBox>
-
-MainWindow::MainWindow(Renderer r, const Config &conf)
-    : m_drawer(conf),
-    runstatus("Not running", this),
-    m_render(this, m_drawer, r, conf, &runstatus),
-    m_conf(conf)
-{
-
-    setCentralWidget(&m_drawer);
-
-    auto saveAct = new QAction(tr("&Save as"), this);
-    saveAct->setStatusTip(tr("Save the rendered image"));
-    connect(saveAct, &QAction::triggered, this, &MainWindow::saveimage);
-
-    auto stopAct = new QAction(tr("&Stop"), this);
-    stopAct->setStatusTip(tr("Stop and sync threads"));
-    QObject::connect(stopAct, &QAction::triggered, &m_render, &RenderCoordinator::stop);
-
-    fileMenu = menuBar()->addMenu(tr("&File"));
-    fileMenu->addAction(saveAct);
-
-    fileMenu = menuBar()->addMenu(tr("&Render"));
-    fileMenu->addAction(stopAct);
-
-    helpMenu = menuBar()->addMenu(tr("&Help"));
-    helpMenu->addAction(tr("About Qt"), qApp, &QApplication::aboutQt);
-
-    statusBar()->addWidget(&runstatus);
-}
-
-void MainWindow::saveimage() {
-
-    QGuiApplication::setOverrideCursor(Qt::WaitCursor);
-    QString fileName = QFileDialog::getSaveFileName(this,
-            tr("Save image"), "", tr("PNG image (*.png);;All Files (*)"));
-    if (fileName.isEmpty()) {
-        return;
-    }
-
-    if (!m_drawer.m_img.save(fileName)) {
-        QMessageBox::information(this, tr("Unable to save file"), "");
-    }
-}
diff --git a/app/mainwindow.hpp b/app/mainwindow.hpp
deleted file mode 100644
index ffb4f08..0000000
--- a/app/mainwindow.hpp
+++ /dev/null
@@ -1,34 +0,0 @@
-#ifndef MAIN_H
-#define MAIN_H
-
-#include <QMainWindow>
-#include <QLabel>
-#include <QMenuBar>
-#include <QStatusBar>
-
-#include "config.hpp"
-#include "draw.hpp"
-#include "rendercoord.hpp"
-#include <qmainwindow.h>
-#include <render.hpp>
-
-class MainWindow : public QMainWindow {
-    Q_OBJECT
-
-    public:
-        MainWindow(Renderer r, const Config &conf);
-
-    private slots:
-        void saveimage();
-    private:
-        DrawWidget m_drawer;
-        QLabel runstatus;
-        RenderCoordinator m_render;
-
-        QMenu *fileMenu;
-        QMenu *helpMenu;
-
-        const Config &m_conf;
-};
-
-#endif
diff --git a/app/rendercoord.cpp b/app/rendercoord.cpp
deleted file mode 100644
index 00a6437..0000000
--- a/app/rendercoord.cpp
+++ /dev/null
@@ -1,220 +0,0 @@
-#include "rendercoord.hpp"
-#include <algorithm>
-#include <qobject.h>
-#include <iostream>
-#include <qrgb.h>
-
-#include <qsemaphore.h>
-#include <render.hpp>
-#include <sstream>
-
-uint32_t colorToUint32(const Color &c) {
-    Color cnew = Color(c);
-    cnew.clamp();
-    return (0xFF << 24) + 
-        (cnew.r() << 16) +
-        (cnew.g() << 8) +
-        cnew.b();
-}
-
-// Run by main thread
-RenderThread::RenderThread(Renderer r, unsigned threads, const Config &conf, QObject *parent, unsigned id) 
-    : QThread(parent),
-    m_lock(1),
-    m_render(r),
-    m_conf(conf),
-    m_pause(1)
-{
-    m_id = id;
-    m_workers = threads;
-}
-
-// Run on new thread
-void RenderThread::run() {
-    while (1) {
-        // Wait for work
-        m_work.acquire();
-
-        // Very expensive, but necesary to get live rendering
-        Color *sum = new Color[m_render.m_width * m_render.m_height];
-
-        m_current_samples = 0;
-
-        for (int sample = 0; sample < m_samples; sample++) {
-            m_current_samples = sample;
-            // Probably not that smart
-            m_pause.acquire();
-            m_pause.release();
-
-            for (unsigned y = m_id; y < m_render.m_height; y += m_workers) {
-                for (unsigned x = 0; x < m_render.m_width; x++) {
-                    auto index = x + y * m_render.m_width;
-                    sum[index] += m_render.render(m_render.m_width - x, m_render.m_height - y, 1);
-
-                    m_writebuffer[index] = colorToUint32(sum[index] / (sample+1));
-                }
-            }
-
-        }
-
-        // Signal done
-        m_lock.release();
-        emit done(m_id);
-    }
-}
-
-void RenderThread::pause() {
-    m_pause.acquire();
-}
-
-void RenderThread::resume() {
-    m_pause.release();
-}
-
-int RenderThread::render(QRgb *buffer, unsigned samples) {
-    // Check if already running
-    if (!m_lock.tryAcquire()) {
-        return 1;
-    }
-    m_writebuffer = buffer;
-    m_samples = samples;
-    m_work.release();
-    std::cout << samples << std::endl;
-
-    return 0;
-}
-
-unsigned RenderThread::stop() {
-    stopAt(m_current_samples);
-    return m_current_samples;
-}
-
-void RenderThread::stopAt(int at) {
-    m_samples = at;
-}
-
-// Running on main thread
-unsigned RenderThread::current_samples() {
-    // No sync should not be a problem here.
-    return m_current_samples;
-}
-
-RenderCoordinator::RenderCoordinator(QObject *parent, DrawWidget &target, Renderer r, const Config &conf, QLabel *status) 
-    : QObject(parent),
-    m_target(target),
-    m_renderer(r),
-    m_timer(this),
-    m_conf(conf)
-{
-    m_status = status;
-
-    // Create and start workers
-    for (unsigned i = 0; i < conf.m_workers; i++) {
-        auto thread = new RenderThread(m_renderer, conf.m_workers, conf, this, i);
-
-        thread->start();
-        QObject::connect(thread, &RenderThread::done, this, &RenderCoordinator::workerDone);
-
-        m_workers.push_back(thread);
-    }
-
-    render();
-
-}
-
-void RenderCoordinator::render() {
-    m_started = 0;
-    for (auto thd : m_workers) {
-        thd->render(m_target.m_drawbuffer, m_conf.m_samples);
-        m_started++;
-    }
-
-    m_state = running;
-    updateUi();
-
-    QObject::connect(&m_timer, &QTimer::timeout, this, &RenderCoordinator::updateUi);
-
-    m_timer.start(1000.0 / m_conf.m_framerate);
-}
-
-void RenderCoordinator::stop() {
-    unsigned max = 0;
-    for (auto thd : m_workers) {
-        thd->pause();
-
-        auto val = thd->current_samples();
-        if (val>max) {
-            max = val;
-        }
-    }
-
-    std::cout << max << std::endl;
-
-    for (auto thd : m_workers) {
-        thd->stopAt(max+1);
-        thd->resume();
-    }
-
-    m_state = stopping;
-    updateUi();
-}
-
-void RenderCoordinator::workerDone(unsigned workerid) {
-    std::cout << "Worker " << workerid << " done!" << std::endl;
-    if (--m_started) {
-        return;
-    }
-    std::cout << "All done :-)" << std::endl;
-
-    // All workers are done
-    m_state = stopped;
-    m_timer.stop();
-    updateUi();
-}
-
-unsigned RenderCoordinator::calcStats(unsigned *max, unsigned *min, double *avg) {
-    unsigned count = 0;
-    unsigned sum = 0;
-    for (auto thd : m_workers) {
-        auto val = thd->current_samples();
-        if (min && (val < *min || !count)) {
-            *min = val;
-        }
-        if (max && (val > *max || !count)) {
-            *max = val;
-        }
-
-        sum += val;
-        count++;
-    }
-
-    if (avg) {
-        *avg = (double)sum / count;
-    }
-
-    return count;
-}
-
-
-void RenderCoordinator::updateUi() {
-    m_target.repaint();
-
-    if (!m_status) {
-        return;
-    }
-
-    // Gather statictics from workers
-    unsigned max;
-    unsigned min;
-    double avg;
-    unsigned count = calcStats(&max, &min, &avg);
-
-    std::ostringstream status;
-    status << states[m_state] << 
-        " Threads: " << count <<
-        " Max: " << max << " samples" <<
-        " Min: " << min << " samples" <<
-        " Avg: " << avg << " samples";
-
-    m_status->setText(QString::fromStdString(status.str()));
-}
diff --git a/app/rendercoord.hpp b/app/rendercoord.hpp
deleted file mode 100644
index eea1b40..0000000
--- a/app/rendercoord.hpp
+++ /dev/null
@@ -1,93 +0,0 @@
-#ifndef RENDER_THREAD_H
-#define RENDER_THREAD_H
-
-#include "draw.hpp"
-#include "config.hpp"
-#include <atomic>
-#include <qlabel.h>
-#include <render.hpp>
-
-#include <qobject.h>
-#include <qrgb.h>
-#include <qthread.h>
-#include <qsemaphore.h>
-#include <vector>
-// https://doc.qt.io/archives/qt-4.8/qt-threads-mandelbrot-example.html
-
-class RenderThread : public QThread {
-    Q_OBJECT
-
-    public:
-        RenderThread(Renderer r, unsigned threads, const Config &cfg, QObject *parent = nullptr, unsigned id = 0);
-
-        // Returns 0 if successful or 1 if busy
-        int render(QRgb *buffer, unsigned samples);
-
-        void pause();
-        void resume();
-
-        unsigned stop();
-        void stopAt(int at);
-
-        unsigned current_samples();
-
-    signals:
-        void done(unsigned workerid);
-
-    protected:
-        void run();
-
-        QSemaphore m_lock;
-
-        QRgb *m_writebuffer;
-        std::atomic_int m_samples;
-        std::atomic_int m_current_samples;
-
-        Renderer m_render;
-
-        unsigned m_workers;
-
-        Config const m_conf;
-
-        // Value in here means work is to be done
-        QSemaphore m_work;
-        QSemaphore m_pause;
-        unsigned m_id;
-};
-
-const std::string states[] = { "Stopped", "Running", "Stopping" };
-enum State { stopped, running, stopping };
-
-class RenderCoordinator : public QObject {
-    Q_OBJECT
-
-    public:
-        RenderCoordinator(QObject *parent, DrawWidget &target, Renderer r, const Config &conf, QLabel *status=nullptr);
-        void setSamples(unsigned samples);
-        void render();
-
-    public slots:
-        void workerDone(unsigned workerid);
-        void stop();
-
-    private slots:
-        void updateUi();
-
-    private:
-        unsigned calcStats(unsigned *max, unsigned *min, double *avg);
-
-        DrawWidget &m_target;
-
-        Renderer m_renderer;
-        std::vector<RenderThread*> m_workers;
-        unsigned m_started;
-
-        QLabel *m_status;
-        QTimer m_timer;
-
-        State m_state;
-
-        const Config &m_conf;
-};
-
-#endif
diff --git a/src/common.hpp b/src/common.hpp
deleted file mode 100644
index fd219bf..0000000
--- a/src/common.hpp
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef COMMON_H
-#define COMMON_H
-
-#define ZERO_APPROX 1e-6
-
-#endif
diff --git a/src/main.rs b/src/main.rs
new file mode 100644
index 0000000..e7a11a9
--- /dev/null
+++ b/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/object.cpp b/src/object.cpp
deleted file mode 100644
index 1449cbb..0000000
--- a/src/object.cpp
+++ /dev/null
@@ -1,103 +0,0 @@
-#include "object.hpp"
-
-#include <math.h>
-#include <iostream>
-#include "common.hpp"
-
-void Color::clamp() {
-    if (m_x > 1) { m_x = 1; }
-    if (m_y > 1) { m_y = 1; }
-    if (m_z > 1) { m_z = 1; }
-}
-
-Material::Material(Color color, double defuse, double emissive) {
-    m_color = color;
-    m_defuse = defuse;
-    m_emissive = emissive;
-}
-
-Color Material::reflect(const Vec3d &normal, const Vec3d &in, const Vec3d &out, const Color &incol) const {
-    return Vec3d(m_color) * m_emissive + 
-         (Vec3d(m_color) * Vec3d(incol)) * (out.dot(normal) * m_defuse);
-}
-
-Sphere::Sphere(const Material &mat, Vec3d center, double radius) : Shape(mat) {
-    m_center = center;
-    m_radius = radius;
-}
-
-Plane::Plane(const Material &mat, Vec3d start, Vec3d norm) : Shape(mat) {
-    m_start = start;
-    m_norm = norm;
-
-    m_norm.normalize();
-}
-
-Vec3d Sphere::norm_at(const Vec3d &point, const Vec3d&) const {
-    auto res = point - m_center;
-    res.normalize();
-    return res;
-}
-
-// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-sphere-intersection
-double Sphere::intersect(const Ray &ray, bool skip_dist) const {
-    // Calculate O - C used multiple places
-    auto oc = ray.m_start - m_center;
-    // Calculate components of quadratic formula
-    // a = 1 when ray.direction is a unit vector
-    auto a = 1;
-    auto b = 2 * ray.m_direction.dot(oc);
-    auto c = oc.dot(oc) - m_radius * m_radius;
-
-    // Solve quadratic function
-    auto discr = b * b - 4 * a * c;
-    if (discr < 0) {
-        // No solution
-        return -1;
-    }
-    if (skip_dist) {
-        // Do not calculate distance
-        return 1;
-    }
-
-    auto q = (b > 0) ?
-        -0.5 * (b + sqrt(discr)):
-        -0.5 * (b - sqrt(discr));
-    auto t1 = q; // Assuming a = 1
-    auto t0 = c / q;
-
-    // Find correct result
-    if (t0 <= ZERO_APPROX) {
-        t0 = t1;
-    }
-
-    if (t0 <= ZERO_APPROX) {
-        return -1;
-    }
-
-    return t0;
-}
-
-Vec3d Plane::norm_at(const Vec3d&, const Vec3d &indir) const {
-    auto scale = m_norm.dot(indir);
-    return scale > 0 ? -m_norm : m_norm;
-}
-
-// https://www.scratchapixel.com/lessons/3d-basic-rendering/minimal-ray-tracer-rendering-simple-shapes/ray-plane-and-ray-disk-intersection
-// Requires that vectors are normalized
-// Skip dist is ignored as distance must be calculated
-double Plane::intersect(const Ray &ray, bool) const {
-    // If ray is parallel
-    auto nr = m_norm.dot(ray.m_direction);
-    if (abs(nr) < ZERO_APPROX) {
-        return -1;
-    }
-
-    // Calculate distance
-    auto dist = m_norm.dot(m_start - ray.m_start) / nr;
-    if (dist < 0) {
-        return -1;
-    }
-
-    return dist;
-}
diff --git a/src/object.hpp b/src/object.hpp
deleted file mode 100644
index e697ba2..0000000
--- a/src/object.hpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#ifndef OBJECT_H
-#define OBJECT_H
-
-#include <memory>
-#include "vector.hpp"
-#include "ray.hpp"
-
-class Color : public Vec3d {
-    public:
-        Color() {}
-        Color(const Vec3d &v) : Vec3d(v) {}
-        Color(double r, double g, double b) : Vec3d(r, g, b) {}
-
-        uint8_t r() { return m_x * 255; }
-        uint8_t g() { return m_y * 255; }
-        uint8_t b() { return m_z * 255; }
-
-        Color& operator+=(const Color& op) {
-            Vec3d::operator+=(op);
-            return *this;
-        }
-        void clamp();
-};
-
-// Implements phong BRDF 
-class Material {
-    public:
-        Material(Color color, double defuse, double emissive=0);
-
-        Color reflect(const Vec3d &normal, const Vec3d &in, const Vec3d &out, const Color &incol) const;
-
-        Color emits() const {
-            return m_color * m_emissive;
-        }
-
-        // Whether the material is reflective
-        bool reflects() const { return m_defuse > 0; }
-    private:
-        Color m_color;
-        double m_defuse;
-        double m_emissive;
-};
-
-class Shape {
-    public:
-        Shape(const Material &mat) : m_mat(mat) { }
-
-        virtual Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const = 0;
-        virtual double intersect(const Ray &ray, bool skip_dist) const = 0;
-
-        const Material &m_mat;
-};
-
-class Sphere : public Shape {
-    public:
-        Sphere(const Material &mat, Vec3d center, double radius);
-        Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const;
-        double intersect(const Ray &ray, bool skip_dist) const;
-
-    private:
-        Vec3d m_center;
-        double m_radius;
-};
-
-class Plane : public Shape {
-    public:
-        Plane(const Material &mat, Vec3d start, Vec3d norm);
-        Vec3d norm_at(const Vec3d &point, const Vec3d &indir) const;
-        double intersect(const Ray &ray, bool skip_dist) const;
-
-    private:
-        Vec3d m_start;
-        Vec3d m_norm;
-};
-
-#endif
diff --git a/src/ray.cpp b/src/ray.cpp
deleted file mode 100644
index 7bc6201..0000000
--- a/src/ray.cpp
+++ /dev/null
@@ -1,17 +0,0 @@
-#include "ray.hpp"
-
-Ray::Ray(Vec3d start, Vec3d direction, bool normalize) {
-    m_start = start;
-    m_direction = direction;
-
-    if (normalize) {
-        m_direction.normalize();
-    }
-}
-
-Ray::Ray(Vec3d a, Vec3d b) {
-    m_start = a;
-    m_direction = b - a;
-
-    m_direction.normalize();
-}
diff --git a/src/ray.hpp b/src/ray.hpp
deleted file mode 100644
index 6341d44..0000000
--- a/src/ray.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef RAY_H
-#define RAY_H
-
-#include "vector.hpp"
-
-class Ray {
-    public:
-        Ray(Vec3d start, Vec3d direction, bool normalize);
-        Ray(Vec3d a, Vec3d b);
-
-        Vec3d m_start;
-        Vec3d m_direction;
-};
-
-#endif
diff --git a/src/render.cpp b/src/render.cpp
deleted file mode 100644
index c278797..0000000
--- a/src/render.cpp
+++ /dev/null
@@ -1,166 +0,0 @@
-#include "render.hpp"
-#include "vector.hpp"
-#include "common.hpp"
-
-#include <cstdlib>
-#include <math.h>
-#include <iostream>
-
-#define FOV 1.74533
-
-// Uniform sampling
-#define SAMPLING_POWER 0
-
-const Vec3d up = Vec3d(0, 1, 0);
-
-void Random::seed(unsigned seed) {
-    for (unsigned i = 0; i < seed; i++) {
-        rand_r(&m_seed);
-    }
-}
-
-double Random::operator()() {
-    return (double)rand_r(&m_seed) / (double)RAND_MAX;
-}
-
-Sampler::Sampler(Random &src) : m_src(src) { }
-
-Vec3d Sampler::sample(const Vec3d &norm) {
-    /*
-    auto theta = asin(pow(1 - random(), (double)1 / (1 + SAMPLING_POWER)));
-    auto phi = 2 * M_PI * random();
-    */
-
-    auto theta = 2.0 * M_PI * m_src();
-    auto phi = acos(2.0 * m_src() - 1.0);
-
-    auto sinphi = sin(phi);
-
-    auto newvec = Vec3d(cos(theta) * sinphi, sin(theta) * sinphi, cos(phi));
-
-    if (newvec.dot(norm) <= 0) {
-        newvec = -newvec;
-    }
-
-    return newvec;
-}
-
-Renderer::Renderer(const Scene &scn, Vec3d eye, Vec3d target, unsigned width, unsigned height, unsigned maxhops) : 
-    m_sampler(m_random),
-    m_scn(scn)
-{
-    m_eye = eye;
-    m_target = target;
-    m_width = width;
-    m_height = height;
-    m_maxhops = maxhops;
-
-    recalculate();
-}
-
-void Renderer::recalculate() {
-    auto tmp = m_target - m_eye;
-
-    // Orthogonal vector to E
-    auto b = up.cross(tmp);
-
-    b.normalize();
-    tmp.normalize();
-
-    auto v = tmp.cross(b);
-
-    // Calculate size of viewplane
-    double gx = tan( FOV / 2);
-    double gy = gx * ((double) m_height / m_width);
-
-    // Calculate scaling vectors
-    m_qx = b * ((2 * gx) / (m_width - 1));
-    m_qy = v * ((2 * gy) / (m_height - 1));
-
-    // Calculate starting point
-    m_blc = tmp - (b * gx) - (v * gy);
-}
-
-Ray Renderer::findray(double x, double y) const {
-    auto dir = m_blc + (m_qx * x) + (m_qy * y);
-    return Ray(m_eye, dir, true);
-}
-
-Color Renderer::render(unsigned x, unsigned y, unsigned samples) {
-
-    Color sum(0, 0, 0);
-
-    for (unsigned i = 0; i < samples; i++) {
-        auto r = findray(x + m_random(), y + m_random());
-        sum += pathtrace_sample(r, 0);
-    }
-
-    if (samples < 2) {
-        return sum;
-    } else {
-        return Vec3d(sum) / (double)samples;
-    }
-}
-
-Color Renderer::pathtrace_sample(const Ray &r, unsigned hop) {
-    if (hop >= m_maxhops) {
-        return Color(0, 0, 0);
-    }
-
-    double dist;
-    auto res = cast_ray(r, 0, &dist);
-
-    if (!res) {
-        return Color(0, 0, 0);
-    }
-
-    auto col = res->m_mat.emits();
-    if (res->m_mat.reflects()) {
-        // Calculate endpoint
-        auto end = r.m_start + r.m_direction * dist;
-        auto norm = res->norm_at(end, r.m_direction);
-
-        auto randdir = m_sampler.sample(norm);
-        auto newray = Ray(end, randdir, true);
-        auto incol = pathtrace_sample(newray, hop+1);
-
-        col += res->m_mat.reflect(norm, r.m_direction, newray.m_direction, incol);
-    }
-
-    return col;
-}
-
-const Shape* Renderer::cast_ray(const Ray &r, double chk_dist, double *dist_ret) {
-    const Shape *smallest = nullptr;
-    double dist = 0;
-
-    for (auto obj : m_scn.objs) {
-        if (!obj) {
-            continue;
-        }
-        auto d = obj->intersect(r, false);
-        if (d > ZERO_APPROX) {
-            if (chk_dist > 0 && d < chk_dist) {
-                dist = d; smallest = obj;
-                goto exit;
-            }
-            if (d < dist || smallest == nullptr) {
-                dist = d; smallest = obj;
-            }
-        }
-    }
-
-    if (chk_dist > 0) {
-        // If we reach this it means none of the
-        // object where within distance.
-        return nullptr;
-    }
-
-exit:
-
-    if (dist_ret) {
-        *dist_ret = dist;
-    }
-
-    return smallest;
-}
diff --git a/src/render.hpp b/src/render.hpp
deleted file mode 100644
index 7557fce..0000000
--- a/src/render.hpp
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef RENDER_H
-#define RENDER_H
-
-#include "vector.hpp"
-#include "ray.hpp"
-#include "scene.hpp"
-
-class Random {
-    public:
-        void seed(unsigned seed);
-        double operator()();
-
-    private:
-        unsigned m_seed;
-};
-
-// Samples a random direction in a hemisphere, cosine weighed
-// https://blog.thomaspoulet.fr/uniform-sampling-on-unit-hemisphere/
-class Sampler {
-    public:
-        Sampler(Random &src);
-
-        Vec3d sample(const Vec3d &norm);
-
-    private:
-        Random &m_src;
-};
-
-class Renderer {
-    public:
-    Renderer(const Scene &scn, Vec3d eye, Vec3d target, unsigned width, unsigned height, unsigned maxhops);
-
-    Color render(unsigned x, unsigned y, unsigned samples);
-
-    unsigned m_width, m_height;
-    Sampler m_sampler;
-
-    private:
-    void recalculate();
-    Ray findray(double x, double y) const ;
-
-    Color pathtrace_sample(const Ray &r, unsigned hop);
-    // Will return first result less than chk_dist. 
-    // This is ignored if chk_dist is 0.
-    // If dist is non-null the resulting distance is written here.
-    const Shape* cast_ray(const Ray &r, double chk_dist, double *dist);
-
-    const Scene &m_scn;
-
-    Random m_random;
-
-    // User options
-    Vec3d m_eye, m_target;
-    unsigned m_maxhops;
-
-    // Calculated values
-    Vec3d m_qx, m_qy, m_blc;
-
-};
-
-#endif
diff --git a/src/scene.cpp b/src/scene.cpp
deleted file mode 100644
index a8c0695..0000000
--- a/src/scene.cpp
+++ /dev/null
@@ -1,5 +0,0 @@
-#include "scene.hpp"
-
-void Scene::addShape(const Shape *obj) {
-    objs.push_back(obj);
-}
diff --git a/src/scene.hpp b/src/scene.hpp
deleted file mode 100644
index f270409..0000000
--- a/src/scene.hpp
+++ /dev/null
@@ -1,15 +0,0 @@
-#ifndef SCENE_H
-#define SCENE_H
-
-#include <vector>
-#include "object.hpp"
-
-class Scene {
-    public:
-        void addShape(const Shape *obj);
-
-        std::vector<const Shape*> objs;
-
-};
-
-#endif
diff --git a/src/vector.cpp b/src/vector.cpp
deleted file mode 100644
index 51d8e2e..0000000
--- a/src/vector.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-#include "vector.hpp"
-
-#include <math.h>
-#include <stdexcept>
-
-Vec3d::Vec3d() {
-    set(0, 0, 0);
-}
-
-Vec3d::Vec3d(double x, double y, double z) {
-    set(x, y, z);
-}
-
-void Vec3d::set(double x, double y, double z) {
-    m_x = x;
-    m_y = y;
-    m_z = z;
-}
-
-void Vec3d::normalize() {
-    auto len = length();
-    if (len == 0) {
-        throw std::runtime_error("Normalizing zero vector");
-    }
-
-    m_x /= len;
-    m_y /= len;
-    m_z /= len;
-}
-
-double Vec3d::length() const {
-    return sqrt(m_x * m_x + m_y * m_y + m_z * m_z);
-}
-
-double Vec3d::dot(const Vec3d &vec) const {
-    return m_x * vec.m_x + m_y * vec.m_y + m_z * vec.m_z;
-}
-
-Vec3d Vec3d::cross(const Vec3d &vec) const {
-    return Vec3d(
-        m_y * vec.m_z - m_z * vec.m_y,
-        m_z * vec.m_x - m_x * vec.m_z,
-        m_x * vec.m_y - m_y * vec.m_x
-        );
-}
-
-Vec3d Vec3d::operator+(const Vec3d &vec) const {
-    return Vec3d(
-            m_x + vec.m_x, 
-            m_y + vec.m_y,
-            m_z + vec.m_z
-            );
-}
-
-Vec3d& Vec3d::operator+=(const Vec3d &vec) {
-    m_x += vec.m_x;
-    m_y += vec.m_y;
-    m_z += vec.m_z;
-    return *this;
-}
-
-Vec3d Vec3d::operator-(const Vec3d &vec) const {
-    return Vec3d(
-            m_x - vec.m_x, 
-            m_y - vec.m_y,
-            m_z - vec.m_z
-            );
-}
-
-Vec3d Vec3d::operator-() const {
-    return Vec3d(
-            -m_x,
-            -m_y,
-            -m_z
-            );
-}
-
-
-Vec3d Vec3d::operator*(double op) const {
-    return Vec3d(
-            m_x * op,
-            m_y * op,
-            m_z * op
-            );
-}
-
-Vec3d Vec3d::operator*(const Vec3d &vec) const {
-    return Vec3d(
-            m_x * vec.m_x,
-            m_y * vec.m_y,
-            m_z * vec.m_z
-            );
-}
-
-Vec3d Vec3d::operator/(double op) const {
-    return Vec3d(
-            m_x / op,
-            m_y / op,
-            m_z / op
-            );
-}
-
-std::ostream& operator<<(std::ostream &out, const Vec3d &v){
-    out << "[ " << v.m_x << ", " << v.m_y << ", " << v.m_z << " ]";
-    return out;
-}
diff --git a/src/vector.hpp b/src/vector.hpp
deleted file mode 100644
index 20e8210..0000000
--- a/src/vector.hpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#ifndef VECTOR_H
-#define VECTOR_H
-
-#include <iostream>
-
-class Vec3d {
-    public:
-        Vec3d();
-        Vec3d(double x, double y, double z);
-
-        void set(double x, double y, double z);
-        void normalize();
-
-        double length() const;
-        double dot(const Vec3d &vec) const;
-
-        Vec3d cross(const Vec3d &vec) const;
-
-        // Operators
-        Vec3d operator+(const Vec3d &vec) const;
-        Vec3d& operator+=(const Vec3d &vec);
-        Vec3d operator-(const Vec3d &vec) const;
-        Vec3d operator-() const;
-        Vec3d operator*(double) const;
-        Vec3d operator*(const Vec3d &vec) const;
-        Vec3d operator/(double) const;
-
-        friend std::ostream& operator<<(std::ostream& os, const Vec3d &v);
-
-        double m_x, m_y, m_z;
-};
-
-#endif
diff --git a/test/main.cpp b/test/main.cpp
deleted file mode 100644
index 4ed06df..0000000
--- a/test/main.cpp
+++ /dev/null
@@ -1,2 +0,0 @@
-#define CATCH_CONFIG_MAIN
-#include <catch2/catch.hpp>
diff --git a/test/object.cpp b/test/object.cpp
deleted file mode 100644
index bbce055..0000000
--- a/test/object.cpp
+++ /dev/null
@@ -1,36 +0,0 @@
-#include <object.hpp>
-#include <ray.hpp>
-#include <common.hpp>
-#include <vector.hpp>
-
-#include <catch2/catch.hpp>
-#include <math.h>
-
-TEST_CASE("Sphere normal at", "[sphere]") {
-    auto sph = Sphere(Vec3d(2, 3, 4), 2);
-
-    auto norm = sph.norm_at(Vec3d(2, 3, 2), Vec3d());
-    REQUIRE(norm.m_x == 0);
-    REQUIRE(norm.m_y == 0);
-    REQUIRE(norm.m_z == -1);
-}
-
-TEST_CASE("Sphere intersect", "[sphere]") {
-    auto sph = Sphere(Vec3d(2, 3, 4), 2);
-    auto ray = Ray(Vec3d(1, 0, 0), Vec3d(0, 1, 1.5), true);
-
-    auto dist = sph.intersect(ray, false);
-    REQUIRE(abs(dist - 3.28) < 0.01);
-}
-
-TEST_CASE("Plane intersect", "[plane]") {
-    auto pln = Plane(Vec3d(3, 4, 2), Vec3d(-6, -3, -2));
-    auto ray = Ray(Vec3d(0, 0, 0), Vec3d(-2, -1, 5));
-
-    auto dist = pln.intersect(ray, false);
-    REQUIRE(dist == -1);
-
-    ray = Ray(Vec3d(-2, -2, 0), Vec3d(-2, -1, 5));
-    dist = pln.intersect(ray, false);
-    REQUIRE(abs(dist - 20.4) < 0.1);
-}
diff --git a/test/vector.cpp b/test/vector.cpp
deleted file mode 100644
index 61648c6..0000000
--- a/test/vector.cpp
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <vector.hpp>
-#include <common.hpp>
-#include <catch2/catch.hpp>
-
-TEST_CASE( "Vector length", "[vector]" ) {
-    auto vec = Vec3d(2, 4, 4);
-    REQUIRE(vec.length() == 6);
-    vec.set(0, 0, 0);
-    REQUIRE(vec.length() == 0);
-    vec.set(0, 3.5, 0);
-    REQUIRE(vec.length() == 3.5);
-}
-
-TEST_CASE("Vector_normal", "[vector]") {
-    auto vec = Vec3d(4, 5, 4545);
-    REQUIRE(vec.length() != 1.0);
-    vec.normalize();
-    REQUIRE(vec.length() - 1.0 < ZERO_APPROX);
-    vec.set(0, 0, 0);
-    REQUIRE_THROWS(vec.normalize());
-}
-
-TEST_CASE("Vector dot", "[vector]") {
-    auto a = Vec3d(4, 5, 6);
-    auto b = Vec3d(1, 2, 3);
-    REQUIRE(a.dot(b) == 32);
-    a.set(0, 0, 0);
-    REQUIRE(a.dot(b) == 0);
-    a.set(0, 5, 0);
-    REQUIRE(a.dot(b) == 10);
-}
-- 
cgit v1.2.3