// Aqsis
// Copyright (c) 1997 - 2001, Paul C. Gregory
//
// Contact: pgregory@aqsis.com
//
// This library 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.
//
// 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

/**
 * Copyright (C) 2006-2007  NTT DATA CORPORATION
 * 
 * Version: 1.0.0 2007/04/01
 *  
 */
package net.cellcomputing.himawari.library;

import static net.cellcomputing.himawari.library.EqDisplayMode.ModeA;
import static net.cellcomputing.himawari.library.EqDisplayMode.ModeRGB;
import static net.cellcomputing.himawari.library.EqDisplayMode.ModeZ;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_Ci;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_Oi;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_P;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_alpha;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_ncomps;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_s;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_t;
import static net.cellcomputing.himawari.library.EqEnvVars.EnvVars_time;
import static net.cellcomputing.himawari.library.RiGlobal.QGetRenderContext;
import static net.cellcomputing.himawari.library.RiGlobal.gColBlack;
import static net.cellcomputing.himawari.library.RiGlobal.gColWhite;
import net.cellcomputing.himawari.accessory.primitive.p_float;
import net.cellcomputing.himawari.library.types.CqColor;
import net.cellcomputing.himawari.library.types.CqMatrix;
import net.cellcomputing.himawari.library.types.CqVector3D;
import net.cellcomputing.himawari.shaderexecenv.CqShaderExecEnv;

/**
 * 
 * Imagersourceの基底クラス。
 * 
 * @author NTT DATA Corporation
 */
public strictfp class CqImagersource {

	private IqShader		m_pShader;				///< Pointer to the associated shader.
	private CqAttributes	m_pAttributes;			///< Pointer to the associated attributes.

//	private int m_vGridRes;						///< Size of the bucket X
	private int m_uGridRes;						///<                    Y in pixels
	private int m_uXOrigin;						///< its origin 0,0 top left corner
	private int m_uYOrigin;						///<                      in pixels
	private IqShaderExecEnv m_pShaderExecEnv;
	
	
	//************************************************************************//
	//*** コンストラクタの定義
	//************************************************************************//
	
	public CqImagersource( final IqShader pShader, boolean fActive ){
		
		m_pShader = pShader;
		m_pAttributes = null;
		m_pShaderExecEnv = new CqShaderExecEnv();
		
		m_pAttributes = (CqAttributes)( QGetRenderContext().pattrCurrent() );
		m_pAttributes.AddRef();
	}
	
	public CqImagersource(  final IqShader pShader ){
		this( pShader, true );
	}
	
	public void destruct(){
		if( m_pAttributes!=null )
			m_pAttributes.Release();
		m_pAttributes = null;
	}
	
	
	//************************************************************************//
	//*** メソッドの定義
	//************************************************************************//
	
    /** Get a pointer to the associated Imagersource shader.
     * @return a pointer to a CqShader derived class.
     */
    public IqShader pShader()
    {
        return ( m_pShader );
    }

    /** Initialise the environment for the specified grid size
     *   and execute the shader on the complete grid.
     */
    public void Initialise( IqBucket pBucket )
    {
    	/*
    	 * @param uGridRes Integer grid resolution == 1.
    	 * @param vGridRes Integer grid resolution == 1.
    	 * @param x Integer Raster position.
    	 * @param y Integer Raster position.
    	 * @param color Initial value Ci.
    	 * @param opacity Initial value Oi.
    	 * @param depth Initial value depth (not required).
    	 * @param coverage Initial value "alpha"
    	 */ 
        QGetRenderContext().Stats().ImagerTimer().Start();

        int uGridRes = pBucket.Width();
        int vGridRes = pBucket.Height();
        int x = pBucket.XOrigin();
        int y = pBucket.YOrigin();

        m_uYOrigin = y;
        m_uXOrigin = x;
        m_uGridRes = uGridRes;
//        m_vGridRes = vGridRes;

        int mode = QGetRenderContext().optCurrent().GetIntegerOptionIndex( "System", "DisplayMode" , 0 ).value;
        float components;
        int j, i;
        float shuttertime = QGetRenderContext().optCurrent().GetFloatOptionIndex( "System", "Shutter" , 0 ).value;

        components = (mode & ModeRGB)!=0 ? 3 : 0;
        components += (mode & ModeA)!=0 ? 1 : 0;
        components = (mode & ModeZ)!=0 ? 1 : components;

        int Uses = ( 1 << EnvVars_P ) | ( 1 << EnvVars_Ci ) | ( 1 << EnvVars_Oi | ( 1 << EnvVars_ncomps ) | ( 1 << EnvVars_time ) | ( 1 << EnvVars_alpha ) | ( 1 << EnvVars_s ) | ( 1 << EnvVars_t ) );

        //m_pShaderExecEnv->Initialise( uGridRes, vGridRes, 0, boost::shared_ptr<IqTransform>(), m_pShader.get(), Uses );
        m_pShaderExecEnv.Initialise( uGridRes, vGridRes, null, null, m_pShader, Uses );

        // Initialise the geometric parameters in the shader exec env.

        P().Initialise( uGridRes, vGridRes );
        Ci().Initialise( uGridRes, vGridRes );
        Oi().Initialise( uGridRes, vGridRes );
        alpha().Initialise( uGridRes, vGridRes );
        s().Initialise( uGridRes, vGridRes );
        t().Initialise( uGridRes, vGridRes );

        //TODO dtime is not initialised yet
        //dtime().Initialise(uGridRes, vGridRes, i);

        ncomps().SetFloat( components );
        time().SetFloat( shuttertime );


        m_pShader.Initialise( uGridRes, vGridRes, m_pShaderExecEnv );
        for ( j = 0; j < vGridRes; j++ )
        {
            for ( i = 0; i < uGridRes; i++ )
            {
                int off = j * ( uGridRes + 1 ) + i;
                P().SetPoint( new CqVector3D( (float)x + i, (float)y + j, 0.0f ), off );
                Ci().SetColor( pBucket.Color( x + i, y + j ), off );
                CqColor opa = pBucket.Opacity( x + i, y + j );
                Oi().SetColor( opa, off );
                float avopa = ( opa.fRed() + opa.fGreen() + opa.fBlue() ) /3.0f;
                alpha().SetFloat( pBucket.Coverage( x + i, y + j ) * avopa, off );
                s().SetFloat( x + i + 0.5f, off );
                t().SetFloat( y + j + 0.5f, off );
            }
        }
        // Execute the Shader VM
        if ( m_pShader!=null )
        {
            m_pShader.Evaluate( m_pShaderExecEnv );
            alpha().SetFloat( 1.0f ); /* by default 3delight/bmrt set it to 1.0 */
        }

        QGetRenderContext().Stats().ImagerTimer().Stop();
    }
	
    //Forwarding functions for IqShaderExecEnv
    public	int	uGridRes()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.uGridRes() );
    }
    public	int	vGridRes()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.vGridRes() );
    }
    public	int	GridSize()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.GridSize() );
    }
    public	CqMatrix matObjectToWorld()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.matObjectToWorld() );
    }
    public	IqShaderData Cs()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Cs() );
    }
    public	IqShaderData Os()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Os() );
    }
    public	IqShaderData Ng()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Ng() );
    }
    public	IqShaderData du()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.du() );
    }
    public	IqShaderData dv()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.dv() );
    }
    public	IqShaderData L()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.L() );
    }
    public	IqShaderData Cl()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Cl() );
    }
    public IqShaderData Ol()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Ol() );
    }
    public IqShaderData P()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.P() );
    }
    public IqShaderData dPdu()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.dPdu() );
    }
    public IqShaderData dPdv()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.dPdv() );
    }
    public IqShaderData N()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.N() );
    }
    public IqShaderData u()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.u() );
    }
    public IqShaderData v()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.v() );
    }
    public IqShaderData s()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.s() );
    }
    public IqShaderData t()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.t() );
    }
    public IqShaderData I()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.I() );
    }
    public IqShaderData Ci()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Ci() );
    }
    public IqShaderData Oi()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Oi() );
    }
    public IqShaderData Ps()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Ps() );
    }
    public IqShaderData E()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.E() );
    }
    public IqShaderData ncomps()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.ncomps() );
    }
    public IqShaderData time()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.time() );
    }
    public IqShaderData alpha()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.alpha() );
    }
    public IqShaderData Ns()
    {
        assert( m_pShaderExecEnv!=null ); return ( m_pShaderExecEnv.Ns() );
    }
	
	
    /** After the running shader on the complete grid return the compute Ci
     * @param x Integer Raster position.
     * @param y Integer Raster position.
     */
    public CqColor Color( float x, float y )
    {
        CqColor result = new CqColor( gColBlack );

        int index = (int)( ( y - m_uYOrigin ) * ( m_uGridRes + 1 ) + x - m_uXOrigin );

        if ( (int)Ci().Size() >= index )
            Ci().GetColor( result, index );

        return result;
    }
    
    /** After the running shader on the complete grid return the compute Oi
     * @param x Integer Raster position.
     * @param y Integer Raster position.
     */
    public CqColor Opacity( float x, float y )
    {
    	CqColor result = new CqColor( gColWhite );

        int index = (int)( ( y - m_uYOrigin ) * ( m_uGridRes + 1 ) + x - m_uXOrigin );

        if ((int) Oi().Size() >= index )
            Oi().GetColor( result, index );

        return result;
    }

    /** After the running shader on the complete grid return the compute alpha
     * @param x Integer Raster position.
     * @param y Integer Raster position.
     * PS this is always 1.0 after running imager shader!
     */
    public float Alpha( float x, float y )
    {
        p_float result = new p_float();

        alpha().GetFloat( result );

        return result.value;
    }
	
	
	
}
