/* 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 <osg/Texture1D>
#include <osg/Texture2D>
#include <osg/Texture3D>
#include <osg/TextureRectangle>
#include <osgCompute/Interoperability>

namespace osgCuda
{
    class Texture1DBuffer;
    class Texture2DBuffer;
    class Texture3DBuffer;
    class TextureRectangleBuffer;

    /**
    */
    class TextureStream : public osgCompute::BufferStream
    {
    public:
        void*					 _hostPtr;
        bool                     _hostPtrAllocated;
        bool                     _syncHost;
        void*					 _devPtr;
        bool                     _syncDevice;
        GLuint                   _bo;
        bool                     _boRegistered;
        unsigned int             _modifyCount;
        bool					 _syncTex;

        TextureStream();
        virtual ~TextureStream();

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

    /**
    */
    class TextureBuffer : public osgCompute::InteropBuffer
    {
    public:
        TextureBuffer();

        virtual osg::Texture* asTexture() = 0;
        virtual const osg::Texture* asTexture() const = 0;

        virtual bool init();

        virtual bool getIsRenderTarget() const = 0;

        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 setMemory( int value, unsigned int mapping = osgCompute::MAP_DEVICE, unsigned int offset = 0, unsigned int count = UINT_MAX, unsigned int hint = 0 );
        virtual bool resetMemory( unsigned int hint = 0 );

        virtual void clear();
    protected:
        virtual ~TextureBuffer();
        void clearLocal();

        virtual void clear( const osgCompute::Context& context ) const;

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

        virtual void* mapStream( TextureStream& stream, unsigned int mapping, unsigned int offset );
        virtual void unmapStream( TextureStream& stream );
        virtual void checkMappingWithinApply( const osgCompute::Context& context );

        virtual osgCompute::BufferStream* newStream() const;

        bool setupStream( unsigned int mapping, TextureStream& stream );
        bool allocStream( unsigned int mapping, TextureStream& stream );
        bool syncStream( unsigned int mapping, TextureStream& stream );


        virtual void syncModifiedCounter( const osgCompute::Context& context ) const = 0;
        virtual bool allocPBO( TextureStream& stream ) = 0;
        virtual void syncPBO( TextureStream& stream ) = 0;
        virtual void syncTexture( TextureStream& stream ) = 0;


    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::InteropBuffer* getBuffer();
        virtual const osgCompute::InteropBuffer* getBuffer() const;
        virtual osgCompute::InteropBuffer* getOrCreateBuffer();

        virtual void addHandle( const std::string& handle );
        virtual void removeHandle( const std::string& handle );
        virtual bool isAddressedByHandle( const std::string& handle ) const;

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

        virtual void clear();
    protected:
        friend class Texture1DBuffer;
        virtual ~Texture1D();
        void clearLocal();

        mutable Texture1DBuffer* 	_proxy;
        osgCompute::HandleSet		_handles;

    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::InteropBuffer* getBuffer();
        virtual const osgCompute::InteropBuffer* getBuffer() const;
        virtual osgCompute::InteropBuffer* getOrCreateBuffer();

        virtual void addHandle( const std::string& handle );
        virtual void removeHandle( const std::string& handle );
        virtual bool isAddressedByHandle( const std::string& handle ) const;

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

        virtual void setIsRenderTarget( bool isRenderTarget );
        virtual bool getIsRenderTarget() const;

        virtual void clear();
    protected:
        friend class Texture2DBuffer;
        virtual ~Texture2D();
        void clearLocal();

        mutable Texture2DBuffer* 	_proxy;
        bool						_isRenderTarget;
        osgCompute::HandleSet		_handles;

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

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

        META_Object( osgCuda, TextureRectangle )

        virtual osgCompute::InteropBuffer* getBuffer();
        virtual const osgCompute::InteropBuffer* getBuffer() const;
        virtual osgCompute::InteropBuffer* getOrCreateBuffer();

        virtual void addHandle( const std::string& handle );
        virtual void removeHandle( const std::string& handle );
        virtual bool isAddressedByHandle( const std::string& handle ) const;

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

        virtual void setIsRenderTarget( bool isRenderTarget );
        virtual bool getIsRenderTarget() const;

        virtual void clear();
    protected:
        friend class TextureRectangleBuffer;
        virtual ~TextureRectangle();
        void clearLocal();

        mutable TextureRectangleBuffer* _proxy;
        bool							_clear;
        bool							_isRenderTarget;
        osgCompute::HandleSet			_handles;

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

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

        META_Object( osgCuda, Texture3D )

        virtual osgCompute::InteropBuffer* getBuffer();
        virtual const osgCompute::InteropBuffer* getBuffer() const;
        virtual osgCompute::InteropBuffer* getOrCreateBuffer();

        virtual void addHandle( const std::string& handle );
        virtual void removeHandle( const std::string& handle );
        virtual bool isAddressedByHandle( const std::string& handle ) const;

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

        virtual void setIsRenderTarget( bool isRenderTarget );
        virtual bool getIsRenderTarget() const;

        virtual void clear();
    protected:
        friend class Texture3DBuffer;
        virtual ~Texture3D();
        void clearLocal();

        mutable Texture3DBuffer* 	_proxy;
        bool						_clear;
        bool						_isRenderTarget;
        osgCompute::HandleSet		_handles;
    private:
        // copy constructor and operator should not be called
        Texture3D( const Texture3D& , const osg::CopyOp& ) {}
        Texture3D& operator=(const Texture3D&) { return (*this); }
    };
}

#endif //OSGCUDA_TEXTUREBUFFER_H
