//////////////////////////////////////////////////////////////////////////////
//    Copyright 2004-2019, SenseGraphics AB
//
//    This file is part of H3D API.
//
//    H3D API is free software; you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation; either version 2 of the License, or
//    (at your option) any later version.
//
//    H3D API 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 General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with H3D API; if not, write to the Free Software
//    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
//
//    A commercial license is also available. Please contact us at 
//    www.sensegraphics.com for more information.
//
//
/// \file ShaderStorageBuffer.h
/// \brief Header file for ShaderStorageBuffer.
///
//
//////////////////////////////////////////////////////////////////////////////
#ifndef __SHADERSTORAGEBUFFER_H__
#define __SHADERSTORAGEBUFFER_H__

#include <H3D/ShaderChildNode.h>
#include <H3D/SFInt32.h>
#include <H3D/SFString.h>

namespace H3D {

  /// \ingroup H3DNodes
  /// \class ShaderStorageBuffer
  /// \brief This node provide a buffer object for OpenGL shader program to write
  /// into and read from.
  ///
  /// <b>Examples:</b>
  ///   - <a href="../../../H3DAPI/examples/All/ShaderStorageBuffer.x3d">ShaderStorageBuffer.x3d</a>
  ///     ( <a href="examples/ShaderStorageBuffer.x3d.html">Source</a> )
  ///
  /// \par Internal routes:
  /// \dotfile ShaderStorageBuffer.dot
  class H3DAPI_API ShaderStorageBuffer : 
    public ShaderChildNode {
  public:
  
    /// Constructor.
    ShaderStorageBuffer( Inst< DisplayList  > _displayList = 0,
                         Inst< SFNode       >  _metadata = 0,
                         Inst< SFInt32      > _width = 0,
                         Inst< SFInt32      > _height = 0,
                         Inst< SFInt32      > _depth = 0,
                         Inst< SFInt32      > _dataSize = 0,
                         Inst< SFString     > _storageName = 0
                         );



    /// specify the program will be used for attaching this shader storage buffer
    virtual void preRender( unsigned int program );

    /// update storage specification if necessary and attach it the shader program
    /// to be used
    virtual void render ( );


    /// update storage buffer
    virtual void prepareStorageBuffer ( );


    virtual int getStorageBlockBinding ( ){
      return storage_block_binding;
    }

    virtual void initialize ( );

    ~ShaderStorageBuffer ( );

    // width, height and depth is used to set the size
    // of the buffer data. It is actually just one value, as shader storage
    // buffer is used in shader, to separate it into three dimension
    // will make it more intuitive

    /// horizontal dimension for the data
    /// <b>Access type:</b> inputOutput \n
    /// <b>Default value:</b> 512 \n
    auto_ptr<SFInt32> width;

    /// vertical dimension for the data
    /// <b>Access type:</b> inputOutput \n
    /// <b>Default value:</b> 512 \n
    auto_ptr<SFInt32> height;

    /// layers for the data
    /// <b>Access type:</b> inputOutput \n
    /// <b>Default value:</b> 16 \n
    auto_ptr<SFInt32> depth;

    /// data size of the structure used for shader storage buffer
    /// the metric is bytes
    auto_ptr<SFInt32> dataSize;

    /// storage buffer name used in shader
    /// by default, it will use the node name if not being set
    auto_ptr<SFString> storageName;

    /// The H3DNodeDatabase for this node
    static H3DNodeDatabase database;

  protected:

    /// shader program that this shader storage buffer will be attached
    unsigned int program_handle;

    /// buffer id, generated by openGL
    int buffer_id;

    /// the active block index assigned by the shader, will have
    /// valid value only after the shader program get linked.
    unsigned int storage_block_index;

    /// the block binding point for shader storage buffer in openGL context
    /// its value must be less than the MAX_SHADER_STORAGE_BUFFER_BINDINGS.
    /// together with storage_block_index, it will connect the shader storage
    /// buffer between OpenGL and shader program
    int storage_block_binding;
    
    // collection of all the current storage block binding points already used, 
    // it will be used to help generate non-identical block binding id
    static set<size_t> global_block_bindings;
    static H3DUtil::MutexLock global_block_bindings_lock;
    static size_t max_block_bindings;
    static int generateShaderStorageBinding ( );
    static void deleteShaderStorageBinding ( int binding );
    // maximum ssbo size supported
    H3DUTIL_INT64 max_ssbo_size;
    auto_ptr<Field> rebuildBuffer;
  };
}

#endif
