/*****************************************************************************
 * $LastChangedDate: 2010-02-03 13:50:46 -0500 (Wed, 03 Feb 2010) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Texture class.
 *//*
 * LEGAL:   COPYRIGHT (C) 2008 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#define FX_TEXTURE_CC 1
#include "base/module.hh"
using namespace base;
#include "fx/module.hh"
#include "fx/texture.hh"
#include "fx/image_cache.hh"

#include <osgDB/WriteFile>

namespace fx {

////////////////////////////////////////////////////////////////////////////////
/////////////////////////////////  Texture  ////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * Construct Texture from raw memory buffer.
 * @param   buf
 *          RGBA array.  Whether OSG will own buf depends on allocationMode.
 * @param   width
 *          Texture width defines size of buf.
 * @param   allocationMode
 *          osg::Image::AllocationMode { NO_DELETE, USE_NEW_DELETE, USE_MALLOC_FREE }
 *****************************************************************************/
Texture::Texture( uint8* buf, const uint width, const osg::Image::AllocationMode allocationMode )
:   mTextureObject(new osg::Texture2D)
{
    SET_TYPESIG(this,TYPESIG_TEXTURE);

    Configure();

    // man glTexImage2D
    RefPtr<osg::Image> image = new osg::Image;
    image->setImage( width,              // s
                     width,              // t
                     1,                  // r
                     GL_COMPRESSED_RGBA, // internalTextureformat (use texture compression)
                     GL_RGBA,            // pixelFormat
                     GL_UNSIGNED_BYTE,   // type
                     buf,                // data
                     allocationMode );   // AllocationMode
    mTextureObject->setImage( image.get() );
}

/*****************************************************************************
 * Construct Texture from osg::Image.
 *****************************************************************************/
Texture::Texture( RefPtr<osg::Image> image )
:   mTextureObject(new osg::Texture2D)
{
    SET_TYPESIG(this,TYPESIG_TEXTURE);

    Configure();

    mTextureObject->setImage( image.get() );
}

/*****************************************************************************
 * Construct Texture from file.  Uses ImageCache.
 *****************************************************************************/
Texture::Texture( const string& filename )
:   mTextureObject(new osg::Texture2D)
{
ASSERT( not filename.empty() );
    SET_TYPESIG(this,TYPESIG_TEXTURE);

    Configure();

    // Load texture image into texture object.  Might throw C++ exception.
    mTextureObject->setImage( GET_IMAGE_CACHE().LoadImage(filename).get() );
}

/*****************************************************************************
 * dtor.
 *****************************************************************************/
Texture::~Texture()
{
    INVALIDATE_TYPESIG(this,TYPESIG_TEXTURE);
}

/*****************************************************************************
 * Attach texture to node.
 *****************************************************************************/
void
Texture::Bind( osg::StateSet& stateset )
{
CHECK_TYPESIG(this,TYPESIG_TEXTURE);

    stateset.setTextureAttributeAndModes( 0, mTextureObject.get(), osg::StateAttribute::ON );
}

/*****************************************************************************
 * Write texture image to file.
 * @return True else exception.
 *****************************************************************************/
bool
Texture::SaveToFile( const string& filename )
{
    // Set the filename of the Image so that OSG has a way
    // to reference the file if the scene-graph is dumped.
    RefPtr<osg::Image> image = mTextureObject->getImage();
    if ( image == NULL )
        throw Exception( string("ERROR: no osg::Image to be written to file ") + filename );
    image->setFileName( filename );
    if ( not osgDB::writeImageFile( *image, filename ) )
        throw Exception( string("ERROR: writing texture to file ") + filename );
    return true;
}

/*****************************************************************************
 * Create osg::StateSet with new Texture bound to it.
 *****************************************************************************/
RefPtr<osg::StateSet>  // CLASS_METHOD
Texture::NewTextureAsStateSet( const string& filename )
{
    shptr<Texture> texture = new Texture( filename );
    RefPtr<osg::StateSet> stateSet = new osg::StateSet;
    texture->Bind( *stateSet );
    return stateSet;
}

} // namespace fx
