/* osgCompute - Copyright (C) 2008-2009 SVT Group
*
* This library is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 3 of
* the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesse General Public License for more details.
*
* The full license is in LICENSE file included with this distribution.
*/
#ifndef OSGCUDA_TEXTUREBUFFER_H
#define OSGCUDA_TEXTUREBUFFER_H 1

#include <driver_types.h>
#include <osg/Texture>
#include <osg/Texture1D>
#include <osg/Texture2D>
#include <osg/Texture3D>
#include <osg/TextureRectangle>
#include <osgCompute/Interoperability>

namespace osgCuda
{
    //enum TextureSyncOp
    //{
    //    SYNC_ARRAY = 0x100
    //};

    //enum TextureMapping
    //{
    //    MAP_DEVICE_ARRAY = 0x01000000 | osgCompute::MAP_DEVICE_SOURCE,
    //};

    /**
    */
    class LIBRARY_EXPORT TextureObject : public osgCompute::MemoryObject
    {
    public:
        void*						_hostPtr;
        void*						_devPtr;
        cudaArray*                  _graphicsArray;
        cudaGraphicsResource*       _graphicsResource;
        unsigned int	            _lastModifiedCount;

        TextureObject();
        virtual ~TextureObject();


    private:
        // not allowed to call copy-constructor or copy-operator
        TextureObject( const TextureObject& ) {}
        TextureObject& operator=( const TextureObject& ) { return *this; }
    };

    /**
    */
    class LIBRARY_EXPORT TextureBuffer : public osgCompute::InteropMemory
    {
    public:
        TextureBuffer();

        META_Object(osgCuda,TextureBuffer)

		virtual osgCompute::InteropObject* getInteropObject(); 
		virtual const osgCompute::InteropObject* getInteropObject() const; 

        virtual bool init();
        virtual bool initDimension();
        virtual bool initElementSize();

        virtual void* map( unsigned int mapping = osgCompute::MAP_DEVICE, unsigned int offset = 0, unsigned int hint = 0 );
        virtual void unmap( unsigned int hint = 0 );
        virtual bool reset( unsigned int hint = 0 );
        virtual bool isMappingAllowed( unsigned int mapping, unsigned int hint = 0 ) const;

        virtual void clear();
    protected:
        friend class Texture1D;
        friend class Texture2D;
        friend class Texture3D;
        friend class TextureRectangle;
        virtual ~TextureBuffer();
        void clearLocal();


        bool setup( unsigned int mapping );
        bool alloc( unsigned int mapping );
        bool sync( unsigned int mapping );

        virtual osgCompute::MemoryObject* createObject() const;
        virtual unsigned int computePitch() const;

        osg::ref_ptr<osg::Texture>		_texref; 
        unsigned int                    _usage;
    private:
        // copy constructor and operator should not be called
        TextureBuffer( const TextureBuffer& , const osg::CopyOp& ) {}
        TextureBuffer& operator=(const TextureBuffer&) { return (*this); }
    };


    ///**
    //*/
    //class LIBRARY_EXPORT Texture1D : public osg::Texture1D, public osgCompute::InteropObject
    //{
    //public:
    //    Texture1D();

    //    META_Object( osgCuda, Texture1D )

    //    virtual osgCompute::InteropMemory* getMemory();
    //    virtual const osgCompute::InteropMemory* getMemory() const;
	//    virtual osgCompute::InteropMemory* getOrCreateMemory();
		//virtual osgCompute::IdentifierSet& getIdentifiers();
		//virtual const osgCompute::IdentifierSet& getIdentifiers() const;

    //    virtual bool init();

    //    virtual void addIdentifier( const std::string& identifier );
    //    virtual void removeIdentifier( const std::string& identifier );
    //    virtual bool isIdentifiedBy( const std::string& identifier ) const;

    //    virtual void apply(osg::State& state) const;
    //    virtual void releaseGLObjects(osg::State* state=0) const;

    //    virtual void freeProxy();
    //    virtual bool isClear();
    //    virtual void clear();
    //protected:
    //    friend class TextureBuffer;
    //    virtual ~Texture1D();
    //    void clearLocal();

    //    mutable TextureBuffer* 	_proxy;
    //    bool						_clear;
    //    osgCompute::IdentifierSet		_identifiers;

    //private:
    //    // copy constructor and operator should not be called
    //    Texture1D( const Texture1D& , const osg::CopyOp& ) {}
    //    Texture1D& operator=(const Texture1D&) { return (*this); }
    //};

    /**
    */
    class LIBRARY_EXPORT Texture2D : public osg::Texture2D, public osgCompute::InteropObject
    {
    public:
        Texture2D();

        META_Object( osgCuda, Texture2D )

        virtual osgCompute::InteropMemory* getInteropMemory();
        virtual const osgCompute::InteropMemory* getInteropMemory() const;
        virtual osgCompute::InteropMemory* getOrCreateInteropMemory();

        virtual bool init();

        virtual void addIdentifier( const std::string& identifier );
        virtual void removeIdentifier( const std::string& identifier );
		virtual bool isIdentifiedBy( const std::string& identifier ) const;
		virtual osgCompute::IdentifierSet& getIdentifiers();
		virtual const osgCompute::IdentifierSet& getIdentifiers() const;

        virtual void apply(osg::State& state) const;
        virtual void releaseGLObjects(osg::State* state=0) const;

        virtual void freeProxy();
        virtual bool isClear();
        virtual void clear();
    protected:
        friend class TextureBuffer;
        virtual ~Texture2D();
        void clearLocal();

        mutable TextureBuffer* 	    _proxy;
        bool						_clear;
        osgCompute::IdentifierSet	_identifiers;

    private:
        // copy constructor and operator should not be called
        Texture2D( const Texture2D& , const osg::CopyOp& ) {}
        Texture2D& operator=(const Texture2D&) { return (*this); }
    };

    /**
    */
    class LIBRARY_EXPORT Texture3D : public osg::Texture3D, public osgCompute::InteropObject
    {
    public:
        Texture3D();

        META_Object( osgCuda, Texture3D )

        virtual osgCompute::InteropMemory* getInteropMemory();
        virtual const osgCompute::InteropMemory* getInteropMemory() const;
		virtual osgCompute::InteropMemory* getOrCreateInteropMemory();
		virtual osgCompute::IdentifierSet& getIdentifiers();
		virtual const osgCompute::IdentifierSet& getIdentifiers() const;

        virtual bool init();

        virtual void addIdentifier( const std::string& identifier );
        virtual void removeIdentifier( const std::string& identifier );
        virtual bool isIdentifiedBy( const std::string& identifier ) const;

        virtual void apply(osg::State& state) const;
        virtual void releaseGLObjects(osg::State* state=0) const;

        virtual void freeProxy();
        virtual bool isClear();
        virtual void clear();
    protected:
        friend class TextureBuffer;
        virtual ~Texture3D();
        void clearLocal();

        mutable TextureBuffer* 	    _proxy;
        bool						_clear;
        osgCompute::IdentifierSet	_identifiers;

    private:
        // copy constructor and operator should not be called
        Texture3D( const Texture3D& , const osg::CopyOp& ) {}
        Texture3D& operator=(const Texture3D&) { return (*this); }
    };

    /**
    */
    class LIBRARY_EXPORT TextureRectangle : public osg::TextureRectangle, public osgCompute::InteropObject
    {
    public:
        TextureRectangle();

        META_Object( osgCuda, TextureRectangle )

        virtual osgCompute::InteropMemory* getInteropMemory();
        virtual const osgCompute::InteropMemory* getInteropMemory() const;
		virtual osgCompute::InteropMemory* getOrCreateInteropMemory();
		virtual osgCompute::IdentifierSet& getIdentifiers();
		virtual const osgCompute::IdentifierSet& getIdentifiers() const;

        virtual bool init();

        virtual void addIdentifier( const std::string& identifier );
        virtual void removeIdentifier( const std::string& identifier );
        virtual bool isIdentifiedBy( const std::string& identifier ) const;

        virtual void apply(osg::State& state) const;
        virtual void releaseGLObjects(osg::State* state=0) const;

        virtual void freeProxy();
        virtual bool isClear();
        virtual void clear();
    protected:
        friend class TextureBuffer;
        virtual ~TextureRectangle();
        void clearLocal();

        mutable TextureBuffer* 	    _proxy;
        bool						_clear;
        osgCompute::IdentifierSet	_identifiers;

    private:
        // copy constructor and operator should not be called
        TextureRectangle( const TextureRectangle& , const osg::CopyOp& ) {}
        TextureRectangle& operator=(const TextureRectangle&) { return (*this); }
    };
}

#endif //OSGCUDA_TEXTUREBUFFER_H
