#include "texture.hpp"


Texture::Texture(bool b, unsigned r): need_coords(b), radiosity(MIN(MAX(r, 0), 100)/100.0) {
}


Texture::~Texture() {
}


ColorTexture::ColorTexture(unsigned r, const Img::rgb_t& c): Texture(false, r), col(c) {
}


bool ColorTexture::max_dim(unsigned&, unsigned&) const {
    return false;
}


INLINE const Img::rgb_t& ColorTexture::get() const {
    return col;
}


INLINE const Img::rgb_t& ColorTexture::get(coord_t, coord_t) const {
    return get();
}


INLINE Img::rgb_t ColorTexture::get_uv(coord_t, coord_t) const {
    return get();
}


DummyTexture::DummyTexture(unsigned r): Texture(true, r), width(4), b(255,0,0), w(0,255,0) {
}


DummyTexture::DummyTexture(unsigned r, const Img::rgb_t bb, Img::rgb_t ww, unsigned w): Texture(true, r), width(w), b(bb), w(ww) {
}


bool DummyTexture::max_dim(unsigned&, unsigned&) const {
    return false;
}


INLINE const Img::rgb_t& DummyTexture::get() const {
    return b;
}


INLINE const Img::rgb_t& DummyTexture::get(coord_t x, coord_t y) const {
    const int xr = lround(x) / width;
    const int yr = lround(y) / width;
    return (xr % 2 != yr % 2)? b: w;
}


INLINE Img::rgb_t DummyTexture::get_uv(coord_t u, coord_t v) const { // ignores width
    assert(u >= 0.0 && u <= 1.0);
    assert(v >= 0.0 && v <= 1.0);
    return ((u <= 0.5) != (v <= 0.5))? b: w;
}


ImageTexture::ImageTexture(unsigned r, Img* i): Texture(true, r), img(i), avgcol(i->avg(0, 0, i->w, i->h)) {
}


bool ImageTexture::max_dim(unsigned& w, unsigned& h) const {
    w = img->w;
    h = img->h;
    return true;
}


ImageTexture::~ImageTexture() {
    delete img;
}


Texture* ImageTexture::load(unsigned r, const char* fn, const char* mod) {
    if (mod) {
        if (mod[0] < '0' || mod[0] > '3') return (Texture*)(new DummyTexture(r));
        if (mod[1] != 'x' && mod[1] != 'y' && mod[1] != '\0') return (Texture*)(new DummyTexture(r));
    }

    Img* i = Img::from_ppm(fn);
    if (!i) {
        return (Texture*)new DummyTexture(r);
    }

    if (mod) {
        for (int r=0; r<mod[0]-'0'; ++r) {
            Img* tmp = i->rotate();
            delete i;
            i = tmp;
        }
        if (mod[1] == 'x') {
            i->mirror_x();
        } else if (mod[1] == 'y') {
            i->mirror_y();
        }
    }

    return (Texture*)new ImageTexture(r, i);
}


INLINE const Img::rgb_t& ImageTexture::get() const {
    return avgcol;
}


const Img::rgb_t& ImageTexture::get(coord_t x, coord_t y) const {
    return img->at(lround(x) % img->w, lround(y) % img->h);
}


INLINE Img::rgb_t ImageTexture::get_uv(coord_t u, coord_t v) const {
    assert(u >= 0.0 && u <= 1.0);
    assert(v >= 0.0 && v <= 1.0);
    return img->interpolate(u*(img->w-1), v*(img->h-1));
}