/* 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_GEOMETRYBUFFER_H
#define OSGCUDA_GEOMETRYBUFFER_H 1

#include <osg/Geometry>
#include <osgCompute/Interoperability>

namespace osgCuda
{
    class Geometry;

    /**
    */
    class LIBRARY_EXPORT GeometryStream : public osgCompute::BufferStream
    {
    public:
        void*						_hostPtr;
        bool						_hostPtrAllocated;
        bool						_syncHost;
        void*						_devPtr;
        bool						_syncDevice;
        GLuint						_bo;
        bool						_boRegistered;
        std::vector<unsigned int>	_lastModifiedCount;

        GeometryStream();
        virtual ~GeometryStream();


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

    /**
    */
    class LIBRARY_EXPORT GeometryBuffer : public osgCompute::InteropBuffer
    {
    public:
        GeometryBuffer();

        META_Object(osgCuda,GeometryBuffer)

        virtual osgCompute::InteropObject* getObject(); 

        virtual bool init();

        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:
        friend class Geometry;
        virtual ~GeometryBuffer();
        void clearLocal();

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

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

        virtual osgCompute::BufferStream* newStream() const;

        osg::ref_ptr<osgCuda::Geometry>		_geomref;
    private:
        // copy constructor and operator should not be called
        GeometryBuffer( const GeometryBuffer& , const osg::CopyOp& ) {}
        GeometryBuffer& operator=(const GeometryBuffer&) { return (*this); }
    };

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

        META_Object( osgCuda, Geometry )

        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 bool init();

        virtual void drawImplementation(osg::RenderInfo& renderInfo) const;
        virtual void releaseGLObjects(osg::State* state=0) const;

        virtual bool isClear();
        virtual void clear();

    protected:
        friend class GeometryBuffer;
        virtual ~Geometry();
        void clearLocal();

        mutable GeometryBuffer* 	_proxy;
        bool						_clear;
        osgCompute::HandleSet		_handles;

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

#endif //OSGCUDA_GEOMETRYBUFFER_H
