// *********************************************************
// Scene Class
// Author : Tamy Boubekeur (boubek@gmail.com).
// Copyright (C) 2010 Tamy Boubekeur.
// All rights reserved.
// *********************************************************

#ifndef SCENE_H
#define SCENE_H

#include <iostream>
#include <vector>

#include "Ray.h"
#include "BoundingBox.h"
#include "Triangle.h"

class Object;
class Light;

struct IntersectedTriangle
{
    Vec3Df point;
    float u, v, t;
    Triangle tri;

    IntersectedTriangle() : u(0), v(0), t(0) {}

    Vec3Df getFlatNormal(const Object* obj) const;
    Vec3Df getNormal(const Object* obj) const;
};

struct IntersectionResult
{
    const Object* obj;
    IntersectedTriangle i;

    IntersectionResult() : obj(0) {}

    Vec3Df getFlatNormal() const { return i.getFlatNormal(obj); }
    Vec3Df getNormal() const { return i.getNormal(obj); }

private:
    friend class Scene;
    void reset()
    {
        *this = IntersectionResult();
    }
};

class Scene
{
public:
    static Scene * getInstance ();
    static void destroyInstance ();

    bool loadScene(const std::string& filename);

    unsigned int getObjectNb() { return objects.size(); }
    const Object& getObjectRef(unsigned int i) const { return *objects[i]; }
    Object* getObject(unsigned int i) { return objects[i]; }

    unsigned int getLightNb() const { return lights.size(); }
    const Light& getLightRef(unsigned int i) const { return *lights[i]; }
    Light* getLight(unsigned int i) { return lights[i]; }

    void setAmbientLight(float al) { ambientLight = al; }
    float getAmbientLight() const { return ambientLight; }

    float getLightIntensity(const Vec3Df& point, const Light& l) const;

    inline const BoundingBox & getBoundingBox () const { return bbox; }
    void updateBoundingBox ();
    float getRadius() const;

    void enableShadows(bool b) { shadows = b; }
    bool areShadowsEnabled() const { return shadows; }

    void clear();

    bool intersect(Ray ray, IntersectionResult& res) const;
    bool intersectLights(const Ray& ray, const Light*& light, Vec3Df& point, float& t) const;

protected:
    Scene ();
    virtual ~Scene ();

private:
    void buildDefaultScene ();
    std::vector<Object*> objects;
    std::vector<Light*> lights;
    BoundingBox bbox;
    float ambientLight;
    bool shadows;
};


#endif // SCENE_H

// Some Emacs-Hints -- please don't remove:
//
//  Local Variables:
//  mode:C++
//  tab-width:4
//  End:
