#pragma once
#include "object.hpp"
#include "common.hpp"


class Plane: public Object {
    private:
        vertex_t normal, dira_norm, dirb_norm;
        coord_t dira_len, dirb_len;
        bool intersect(const ray_t&, const vertex_t&, vertex_t&, coord_t&, coord_t&) const;

    public:
        const vertex_t pos, dira, dirb; // parallelogram, actually

        Plane(Texture* t, vertex_t p, vertex_t a, vertex_t b);
        bool intersect(const ray_t&) const;
        bool intersect(intersect_ctx_t&, const ray_t&, const vertex_t& raynrm, vertex_t& rv) const;
        void intersect(intersect_ctx_t&, const ray_t&, const vertex_t& rv, vertex_t& nrm, LightValue&, Img::rgb_t*) const;
        coord_t sqdist(const vertex_t&, coord_t, coord_t) const;
        void from_uv(coord_t u, coord_t v, vertex_t& rv, vertex_t& nrm) const;
        void max_uv(coord_t&, coord_t&) const;
};


class AxisPlane: public Object {
    private:
        int null_os; // which axis
        int a_os, b_os; // other axises
        vertex_t nrm;

    public:
        const vertex_t a, b;

        AxisPlane(Texture* t, vertex_t a, vertex_t b);
        bool intersect(const ray_t&) const;
        bool intersect(intersect_ctx_t&, const ray_t&, const vertex_t& raynrm, vertex_t& rv) const;
        void intersect(intersect_ctx_t&, const ray_t&, const vertex_t& rv, vertex_t& nrm, LightValue&, Img::rgb_t*) const;
        coord_t sqdist(const vertex_t&, coord_t, coord_t) const;
        void from_uv(coord_t u, coord_t v, vertex_t& rv, vertex_t& nrm) const;
        void max_uv(coord_t&, coord_t&) const;
};


class Sphere: public Object {
    private:
        bool intersect(const ray_t&, coord_t&) const;

    public:
        const vertex_t pos;
        const coord_t radius;

        Sphere(Texture* t, vertex_t p, coord_t r);
        bool intersect(const ray_t&) const;
        bool intersect(intersect_ctx_t&, const ray_t&, const vertex_t& raynrm, vertex_t& rv) const;
        void intersect(intersect_ctx_t&, const ray_t&, const vertex_t& rv, vertex_t& nrm, LightValue&, Img::rgb_t*) const;
        coord_t sqdist(const vertex_t&, coord_t, coord_t) const;
        void from_uv(coord_t u, coord_t v, vertex_t& rv, vertex_t& nrm) const;
        void max_uv(coord_t&, coord_t&) const;
};


class Cylinder: public Object {
    private:
        vertex_t normal, center;
        coord_t normal_len;
        vertex_t n1, n2;
        int mid_os;
        bool intersect(const ray_t&, coord_t&, coord_t&) const;

    public:
        const vertex_t origin, direction;
        const coord_t radius;

        Cylinder(Texture* t, vertex_t o, vertex_t d, coord_t r);
        bool intersect(const ray_t&) const;
        bool intersect(intersect_ctx_t&, const ray_t&, const vertex_t& raynrm, vertex_t& rv) const;
        void intersect(intersect_ctx_t&, const ray_t&, const vertex_t& rv, vertex_t& nrm, LightValue&, Img::rgb_t*) const;
        coord_t sqdist(const vertex_t&, coord_t, coord_t) const;
        void from_uv(coord_t u, coord_t v, vertex_t& rv, vertex_t& nrm) const;
        void max_uv(coord_t&, coord_t&) const;
};