<commit_before>#include "math/vec.hpp"
#include "math/mat.hpp"
#include "math/MatrixTransform.hpp"
#include "math/Sphere.hpp"
#include "math/misc.hpp"
#include "math/Ray.hpp"
#include "noncopyable.hpp"
#include "output.hpp"
#include "Optional.hpp"
#include <vector>
#include <memory>
#include <algorithm>
#include <limits>

using namespace yks;

struct Material {
	vec3 diffuse;

	Material(vec3 diffuse)
		: diffuse(diffuse)
	{}
};

struct Plane {
	vec3 normal;
	float distance;

	Plane(vec3 normal, float distance)
		: normal(normalized(normal)), distance(distance)
	{}
};

struct SceneShape {
	virtual Optional<float> intersect(const Ray r) const = 0;
};

struct ShapeSphere : SceneShape {
	Sphere sphere;

	ShapeSphere(vec3 origin, float radius)
		: sphere(origin, radius)
	{}

	virtual Optional<float> intersect(const Ray r) const {
		const vec3 o = r.origin - sphere.origin;
		const vec3 v = r.direction;

		float t1, t2;
		const int solutions = solve_quadratic(dot(v, v), 2*dot(o, v), dot(o, o) - sphere.radius*sphere.radius, t1, t2);
		
		if (solutions == 0) {
			return Optional<float>();
		} else if (solutions == 1) {
			return make_optional<float>(t1);
		} else {
			return make_optional<float>(std::min(t1, t2));
		}
	}
};

struct ShapePlane : SceneShape {
	Plane plane;

	ShapePlane(vec3 normal, float distance)
		: plane(normal, distance)
	{}

	virtual Optional<float> intersect(const Ray r) const {
		const float t = (plane.distance - dot(r.origin, plane.normal)) / dot(r.direction, plane.normal);
		return make_optional<float>(t);
	}
};

struct SceneObject {
	Material material;
	std::unique_ptr<SceneShape> shape;

	SceneObject(Material material, std::unique_ptr<SceneShape>&& shape)
		: material(material), shape(std::move(shape))
	{}

	SceneObject(SceneObject&& o)
		: material(std::move(o.material)), shape(std::move(o.shape))
	{}

private:
	NONCOPYABLE(SceneObject);
};

struct SceneLight {
	vec3 origin;
	vec3 intensity;
};

struct Camera {
	vec3 origin;
	mat3 orientation;
	float focal_distance; // distance from image plane

	Camera(vec3 origin, mat3 orientation, float focal_distance)
		: origin(origin), orientation(orientation), focal_distance(focal_distance)
	{}

	Ray createRay(const vec2 film_pos) const {
		const vec3 cameraspace_ray = mvec3(film_pos[0], film_pos[1], focal_distance);
		return Ray{origin, orientation * cameraspace_ray};
	}
};

struct Scene {
	Camera camera;
	std::vector<SceneObject> objects;

	Scene(Camera camera)
		: camera(camera)
	{}

	Scene(Scene&& o)
		: camera(std::move(o.camera)), objects(std::move(o.objects))
	{}

private:
	NONCOPYABLE(Scene);
};

Scene setup_scene() {
	Scene s(Camera(vec3_0, orient(vec3_y, -vec3_z), 0.5f));
	s.objects.push_back(SceneObject(
		Material(vec3_1),
		std::make_unique<ShapeSphere>(mvec3(0.0f, 0.0f, -2.0f), 1.0f)
		));
	s.objects.push_back(SceneObject(
		Material(mvec3(0.5f, 0.0f, 0.0f)),
		std::make_unique<ShapePlane>(vec3_y, -1.0f)
		));

	return std::move(s);
}

static vec2 filmspace_from_screenspace(const vec2 screen_pos, const vec2 screen_size) {
	return (screen_pos - (screen_size * 0.5f)) * 2.0f * (1.0f / screen_size[1]);
}

struct Intersection {
	float t;
	const SceneObject* object;
	const SceneShape* shape;
};
<commit_msg>Use matrices to transform shapes.<commit_after>#include "math/vec.hpp"
#include "math/mat.hpp"
#include "math/MatrixTransform.hpp"
#include "math/Sphere.hpp"
#include "math/misc.hpp"
#include "math/Ray.hpp"
#include "math/TransformPair.hpp"
#include "noncopyable.hpp"
#include "output.hpp"
#include "Optional.hpp"
#include <vector>
#include <memory>
#include <algorithm>
#include <limits>

using namespace yks;

struct Material {
	vec3 diffuse;

	Material(vec3 diffuse)
		: diffuse(diffuse)
	{}
};

struct Plane {
	vec3 normal;
	float distance;

	Plane(vec3 normal, float distance)
		: normal(normalized(normal)), distance(distance)
	{}
};

struct SceneShape {
	TransformPair transform;

	SceneShape(TransformPair transform)
		: transform(std::move(transform))
	{}

	virtual Optional<float> intersect(const Ray r) const = 0;
};

struct ShapeSphere : SceneShape {
	float radius;

	ShapeSphere(TransformPair transform, float radius)
		: SceneShape(transform), radius(radius)
	{}

	virtual Optional<float> intersect(const Ray r) const {
		const Ray local_ray = transform.localFromParent * r;
		const vec3 o = local_ray.origin;
		const vec3 v = local_ray.direction;

		float t1, t2;
		const int solutions = solve_quadratic(dot(v, v), 2*dot(o, v), dot(o, o) - radius*radius, t1, t2);
		
		if (solutions == 0) {
			return Optional<float>();
		} else if (solutions == 1) {
			return make_optional<float>(t1);
		} else {
			return make_optional<float>(std::min(t1, t2));
		}
	}
};

struct ShapePlane : SceneShape {
	ShapePlane(TransformPair transform)
		: SceneShape(std::move(transform))
	{}

	virtual Optional<float> intersect(const Ray r) const {
		const Ray local_ray = transform.localFromParent * r;
		const float t = -local_ray.origin[1] / local_ray.direction[1];
		return make_optional<float>(t);
	}
};

struct SceneObject {
	Material material;
	std::unique_ptr<SceneShape> shape;

	SceneObject(Material material, std::unique_ptr<SceneShape>&& shape)
		: material(material), shape(std::move(shape))
	{}

	SceneObject(SceneObject&& o)
		: material(std::move(o.material)), shape(std::move(o.shape))
	{}

private:
	NONCOPYABLE(SceneObject);
};

struct SceneLight {
	vec3 origin;
	vec3 intensity;
};

struct Camera {
	vec3 origin;
	mat3 orientation;
	float focal_distance; // distance from image plane

	Camera(vec3 origin, mat3 orientation, float focal_distance)
		: origin(origin), orientation(orientation), focal_distance(focal_distance)
	{}

	Ray createRay(const vec2 film_pos) const {
		const vec3 cameraspace_ray = mvec3(film_pos[0], film_pos[1], focal_distance);
		return Ray{origin, orientation * cameraspace_ray};
	}
};

struct Scene {
	Camera camera;
	std::vector<SceneObject> objects;

	Scene(Camera camera)
		: camera(camera)
	{}

	Scene(Scene&& o)
		: camera(std::move(o.camera)), objects(std::move(o.objects))
	{}

private:
	NONCOPYABLE(Scene);
};

Scene setup_scene() {
	Scene s(Camera(vec3_0, orient(vec3_y, -vec3_z), 0.5f));
	s.objects.push_back(SceneObject(
		Material(vec3_1),
		std::make_unique<ShapeSphere>(TransformPair().translate(vec3_z * -2), 1.0f)
		));
	s.objects.push_back(SceneObject(
		Material(mvec3(0.5f, 0.0f, 0.0f)),
		std::make_unique<ShapePlane>(TransformPair().translate(vec3_y * -0.5))
		));

	return std::move(s);
}

static vec2 filmspace_from_screenspace(const vec2 screen_pos, const vec2 screen_size) {
	return (screen_pos - (screen_size * 0.5f)) * 2.0f * (1.0f / screen_size[1]);
}

struct Intersection {
	float t;
	const SceneObject* object;
	const SceneShape* shape;
};

{'fraction_non_alphanumeric': 0.14332344213649853, 'fraction_numerical': 0.01913946587537092, 'mean_word_length': 5.128181818181818, 'pattern_counts': {'":': 0, '<': 35, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3457728', 'n_tokens_mistral': 2570, 'n_tokens_neox': 2393, 'n_words': 533}