#ifndef N_MD2IPOL_H
#define N_MD2IPOL_H
//------------------------------------------------------------------------------
/**
    define static mesh in visual hierarchie
*/
#ifndef N_VISNODE_H
#include "node/nvisnode.h"
#endif

#ifndef N_REF_H
#include "kernel/nref.h"
#endif

#ifndef N_RSRCPATH_H
#include "misc/nrsrcpath.h"
#endif

#ifndef N_DYNVERTEXBUFFER_H
#include "gfx/ndynvertexbuffer.h"
#endif

#ifndef N_ANIMNODE_H
#include "node/nanimnode.h"
#endif

#ifndef N_DYNAUTOREF_H
#include "kernel/ndynautoref.h"
#endif

#undef N_DEFINES
#define N_DEFINES nMD2Ipol
#include "kernel/ndefdllclass.h"

//------------------------------------------------------------------------------
class nGfxServer;
class nVertexBuffer;
class nIndexBuffer;
class nShadowServer;
class nShadowCaster;
class nShadowServer;


struct nMD2Animation
{
public:
	char name[32]; // 16 * 2 for safety
	int frames;
	int firstframe;
};
class N_DLLCLASS nMD2Ipol : public nAnimNode 
{
public:
    /// constructor
    nMD2Ipol();
    /// destructor
    virtual ~nMD2Ipol();
    /// object persistency
    virtual bool SaveCmds(nFileServer *);
    /// attach to scene
    virtual bool Attach(nSceneGraph2*);
    /// update internal state and render
    virtual void Compute(nSceneGraph2*);

    /// get pointer to embedded vertex buffer object
    nVertexBuffer *GetVertexBuffer(void);

    /// set read only flag
    void SetReadOnly(bool b);
    /// get readonly flag
    bool GetReadOnly();
    /// set filename of mesh file
    void SetFilename(const char *);
    /// get filename of mesh file
    const char *GetFilename();
    /// set as shadow caster state
    void SetCastShadow(bool b);
    /// can cast shadows?
    bool GetCastShadow();
    /// set current animation
    void SetAnimation(const char  *);
    /// get current animation
    const char * GetAnimation();
	/// get animation at index i (starting from 1)
    const char * GetAnimation(int i);
	/// get number of animations
	int GetAnimationCount();
	/// set numer of frames per second to be played
	void SetFPS(int);
	/// get number of frames per second to be played
	int GetFPS();

    static nClass *local_cl;
    static nKernelServer *ks;

protected:
    nAutoRef<nShadowServer> refShadowServer;
    nRef<nShadowCaster>     refShadowCaster;
    nRef<nVertexBuffer>     ref_vb;
    nRef<nIndexBuffer>      ref_ibuf;
    nRsrcPath               rsrc_path;
    bool					readonly;
    bool					castShadows;
	nMD2Animation			*Anims;
	int						m_anims;
	int						m_vertices;
	int						m_totalframes;
	nMD2Animation			*m_pLastAnim;
	int						m_LastFrame;
	nMD2Animation			*m_pCurrAnim;
	int						m_CurrFrame;
	int						m_FPS;
	float					m_AnimStart;

private:
	enum {
        N_UPDATE_COORD  = (1<<0),
        N_UPDATE_NORM   = (1<<1),
        N_UPDATE_RGBA   = (1<<2),
        N_UPDATE_UV0    = (1<<3),
        N_UPDATE_UV1    = (1<<4),
        N_UPDATE_UV2    = (1<<5),
        N_UPDATE_UV3    = (1<<6),
    };

	nDynVertexBuffer dyn_vb;
	int update_flags;

    bool load_mesh(void);
	bool load_raw(const char *, const char *, const char *);
	bool load_anim(const char *);
    void createTriList(ushort *, int);
	void interpolate(nSceneGraph2* sceneGraph, float l, int frameA, int frameB);
};
//------------------------------------------------------------------------------
/**
*/
inline
nMD2Ipol::nMD2Ipol() :
    refShadowServer(ks, this),
    refShadowCaster(this),
    ref_vb(this),
    ref_ibuf(this),
    readonly(false),
    castShadows(false),
	Anims(NULL),
	dyn_vb(ks, this),
	update_flags(0)
{
    this->refShadowServer = "/sys/servers/shadow";

	Anims = NULL;
	m_pLastAnim = NULL;
	m_pCurrAnim = NULL;
}

//------------------------------------------------------------------------------
/**
    Get pointer to embedded vertex buffer object.

    @return     pointer to vertex buffer object, NULL if loading mesh
                has failed
*/
inline
nVertexBuffer*
nMD2Ipol::GetVertexBuffer()
{
    if (!this->ref_vb.isvalid()) {
        if (!this->load_mesh()) return NULL;
    }
    return this->ref_vb.get();
}

//------------------------------------------------------------------------------
/**
    Set readonly status. Meshes which are never rendered need to be set to
    "readonly". Readonly meshes are for instance input meshes for mesh 
    interpolation, mixing or skinning.

    @param      b       readonly flag
*/
inline
void
nMD2Ipol::SetReadOnly(bool b)
{
    this->readonly = b;
}

//------------------------------------------------------------------------------
/**
    Get the current readonly status.

    @return             readonly flag
*/
inline
bool
nMD2Ipol::GetReadOnly()
{
    return this->readonly;
}

//------------------------------------------------------------------------------
/**
    Defines if this object should cast shadows. Must be defined BEFORE
    the mesh is loaded, toggling the flag will have no effect unless the 
    mesh is reloaded.

    @param      b       true if shadow casting, default is false
*/
inline
void
nMD2Ipol::SetCastShadow(bool b)
{
    this->castShadows = b;
}

//------------------------------------------------------------------------------
/**
    Return shadow casting state.

    @return     shadow casting flag   
*/
inline
bool
nMD2Ipol::GetCastShadow()
{
    return this->castShadows;
}

//------------------------------------------------------------------------------
/**
    Get name of current animation

    @return     name of current animation
*/
inline
const char *
nMD2Ipol::GetAnimation()
{
    return this->m_pCurrAnim->name;
}

//------------------------------------------------------------------------------
/**
    Get count of total animation

    @return     number of animations
*/
inline
int
nMD2Ipol::GetAnimationCount()
{
    return this->m_anims;
}

//------------------------------------------------------------------------------
/**
    Get name of animation i

    @return     index of animation wanted
*/
inline
const char *
nMD2Ipol::GetAnimation(int i)
{
	n_assert(i>0 && i < (this->m_anims +1))
    return this->Anims[i - 1].name;
}

//------------------------------------------------------------------------------
/**
    Get number for fps at which the animations will be played

    @return     fps
*/
inline
int
nMD2Ipol::GetFPS()
{
    return this->m_FPS;
}

//------------------------------------------------------------------------------
/**
    Set number for fps at which the animations will be played

    @param     fps
*/
inline
void
nMD2Ipol::SetFPS(int i)
{
	n_assert(i > 0)
    this->m_FPS = i;
}
//------------------------------------------------------------------------------
#endif
