/*==LICENSE==*

CyanWorlds.com Engine - MMOG client, server and tools
Copyright (C) 2011  Cyan Worlds, Inc.

This program 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 3 of the License, or
(at your option) any later version.

This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.

You can contact Cyan Worlds, Inc. by email legal@cyan.com
 or by snail mail at:
      Cyan Worlds, Inc.
      14617 N Newport Hwy
      Mead, WA   99021

*==LICENSE==*/
///////////////////////////////////////////////////////////////////////////////
//                                                                           //
//  plRenderTarget.cpp - RenderTarget functions                              //
//  Cyan, Inc.                                                               //
//                                                                           //
//// Version History //////////////////////////////////////////////////////////
//                                                                           //
//  7.19.2001 mcn - Created.                                                 //
//                                                                           //
///////////////////////////////////////////////////////////////////////////////

#include "hsTypes.h"
#include "plRenderTarget.h"
#include "plCubicRenderTarget.h"
#include "hsStream.h"
#include "hsGDeviceRef.h"

#include "plPipeline.h"
#include "plgDispatch.h"
#include "pnMessage/plPipeResMakeMsg.h"

///////////////////////////////////////////////////////////////////////////////
//// plRenderTarget Functions /////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

void plRenderTarget::SetKey(plKey k)
{
    hsKeyedObject::SetKey(k);
    if( k )
    {
        if( !fParent )
            plgDispatch::Dispatch()->RegisterForExactType( plPipeRTMakeMsg::Index(), GetKey() );
    }
}



hsBool plRenderTarget::MsgReceive(plMessage* msg)
{
    plPipeRTMakeMsg* make = plPipeRTMakeMsg::ConvertNoRef(msg);
    if( make )
    {
        if( !GetDeviceRef() || GetDeviceRef()->IsDirty() )
        {
            make->Pipeline()->MakeRenderTargetRef(this);
        }
        return true;
    }
    return plBitmap::MsgReceive(msg);
}

UInt32  plRenderTarget::Read( hsStream *s )
{
    UInt32  total = plBitmap::Read( s );

    fWidth = s->ReadSwap16();
    fHeight = s->ReadSwap16();

    fProportionalViewport = s->ReadBool();
    if( fProportionalViewport )
    {
        fViewport.fProportional.fLeft = s->ReadSwapScalar();
        fViewport.fProportional.fTop = s->ReadSwapScalar();
        fViewport.fProportional.fRight = s->ReadSwapScalar();
        fViewport.fProportional.fBottom = s->ReadSwapScalar();
    }
    else
    {
        fViewport.fAbsolute.fLeft = s->ReadSwap16();
        fViewport.fAbsolute.fTop = s->ReadSwap16();
        fViewport.fAbsolute.fRight = s->ReadSwap16();
        fViewport.fAbsolute.fBottom = s->ReadSwap16();
    }

    fZDepth = s->ReadByte();
    fStencilDepth = s->ReadByte();

    return total + 2 * 2 + 2 + 4 * ( fProportionalViewport ? sizeof( hsScalar ) : sizeof( UInt16 ) ) + sizeof( hsBool );
}

UInt32  plRenderTarget::Write( hsStream *s )
{
    UInt32  total = plBitmap::Write( s );

    s->WriteSwap16( fWidth );
    s->WriteSwap16( fHeight );

    s->WriteBool( fProportionalViewport );
    if( fProportionalViewport )
    {
        s->WriteSwapScalar( fViewport.fProportional.fLeft );
        s->WriteSwapScalar( fViewport.fProportional.fTop );
        s->WriteSwapScalar( fViewport.fProportional.fRight );
        s->WriteSwapScalar( fViewport.fProportional.fBottom );
    }
    else
    {
        s->WriteSwap16( fViewport.fAbsolute.fLeft );
        s->WriteSwap16( fViewport.fAbsolute.fTop );
        s->WriteSwap16( fViewport.fAbsolute.fRight );
        s->WriteSwap16( fViewport.fAbsolute.fBottom );
    }

    s->WriteByte( fZDepth );
    s->WriteByte( fStencilDepth );

    return total + 2 * 2 + 2 + 4 * ( fProportionalViewport ? sizeof( hsScalar ) : sizeof( UInt16 ) ) + sizeof( hsBool );
}

///////////////////////////////////////////////////////////////////////////////
//// plCubicRenderTarget Functions ////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////

UInt32  plCubicRenderTarget::Read( hsStream *s )
{
    int     i;
    UInt32  total = plRenderTarget::Read( s );


    for( i = 0; i < 6; i++ )
    {
        if( fFaces[ i ] == nil )
            fFaces[ i ] = TRACKED_NEW plRenderTarget();

        fFaces[ i ]->fParent = this;
        total += fFaces[ i ]->Read( s );
    }

    return total;
}

UInt32  plCubicRenderTarget::Write( hsStream *s )
{
    int     i;
    UInt32  total = plRenderTarget::Write( s );
    

    for( i = 0; i < 6; i++ )
    {
        total += fFaces[ i ]->Write( s );
    }

    return total;
}

UInt32  plCubicRenderTarget::GetTotalSize( void ) const
{
    UInt32      size = 0, i;
    
    for( i = 0; i < 6; i++ )
    {
        if( fFaces[ i ] != nil )
            size += fFaces[ i ]->GetTotalSize();
    }

    return size;
}

//// SetCameraMatrix //////////////////////////////////////////////////////////

void    plCubicRenderTarget::SetCameraMatrix(const hsPoint3& pos)
{
    hsMatrix44::MakeEnvMapMatrices(pos, fWorldToCameras, fCameraToWorlds);
}