// Copyright (c) 2013 Jascha Wetzel. All rights reserved.

#ifndef LIB_TFD_H
#define LIB_TFD_H

#include <c4d.h>

#ifdef __APPLE__
#include <tr1/memory>
#else
#include <memory>
#endif // __APPLE__

#if API_VERSION < 15000
typedef LONG Int32;
typedef SVector Vector32;
typedef LVector Vector64;
typedef SVector4 Vector4d32;
typedef LMatrix Matrix64;
#endif

namespace tfd
{

using std::tr1::shared_ptr;

class Channel;
class Shader;

const Int32
    ID_TFD_FLUID_CONTAINER = 1023131,
    LIB_API_VERSION = 2;

enum Interpolation
{ fast, smooth, sharp };

//==================================================================================================
/*!
    \brief TFD fluid container object in C4D's scene graph.
    BaseObject::GetType() will return tfd::ID_TFD_FLUID_CONTAINER for these objects.
 */
class TFDFluidContainer : public BaseObject
{
    TFDFluidContainer();
    ~TFDFluidContainer();

public:
    /*!
        \brief Returns a transform from world space to voxel space and the fluid container's bounding box.

        \param m        matrix object to receive the world-to-voxel transform
        \param bbox_neg left/bottom/back corner of the bounding box in world-space
        \param bbox_pos right/top/front corner of the bounding box in world-space
     */
    void
    get_world_to_voxel(
        Matrix64& m,
        Vector64& bbox_neg,
        Vector64& bbox_pos
    );

    /*!
        \brief Get a handle to a fluid channel for use with sample_channel().

        \param channel  name of the channel to take the sample from. Currently valid names are
        - "density"
        - "temperature"
        - "fuel"
        - "burn"
        - "solid"
        - "velocity.u"
        - "velocity.v"
        - "velocity.w"

        \return handle to the fluid channel.
    */
    shared_ptr<Channel>
    get_channel(const String& channel);

    /*!
        \brief Take a sample from the fluid container.

        \param field    channel to sample.
        \param p        point in voxel-space to take the sample at.
        \param interp   type of interpolation to use.

        \return interpolated value from the voxel grid.
    */
    float
    sample_channel(
        shared_ptr<Channel>& field,
        const Vector64& p,
        Interpolation interp
    );

    /*!
        \brief Get a handle to a shader for use with sample_shader().

        \param shader   name of shader to take the sample from. Currently valid names are
        - "smoke"
        - "fire"

        \return handle to the shader.
    */
    shared_ptr<Shader>
    get_shader(const String& shader);

    /*!
        \brief Take a shaded sample from the fluid container.

        \param shader   shader handle retrieved via get_shader().
        \param p        point in voxel-space to take the sample at.
        \param shader   name of shader to take the sample from. Currently valid names are
        - "smoke"
        - "fire"

        \return RGBA value of the shaded sample.
     */
    Vector4d32
    sample_shader(
        shared_ptr<Shader>& shader,
        const Vector64& p
    );
};

//==================================================================================================
struct TurbulenceFDLibrary : public C4DLibrary
{
    void (*get_world_to_voxel)(TFDFluidContainer*, Matrix64&, Vector64&, Vector64&);
    Channel* (*get_channel)(TFDFluidContainer*, const String&);
    float (*sample_channel)(Channel*, const Vector64&, Interpolation);
    Shader* (*get_shader)(TFDFluidContainer*, const String&);
    Vector4d32 (*sample_shader)(Shader*, const Vector64&);
    void (*delete_Channel)(Channel* f);
    void (*delete_Shader)(Shader* f);
};

} // namespace tfd

#endif // LIB_TFD_H
