// 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

//SIGGRAPH 2002; Larry G. Bake functions

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


import java.util.HashMap;

import net.cellcomputing.himawari.accessory.primitive.p_String;
import net.cellcomputing.himawari.accessory.primitive.p_float;
import net.cellcomputing.himawari.library.EqShaderType;
import net.cellcomputing.himawari.library.IqShaderData;
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.shadervm.shader_types;

import static net.cellcomputing.himawari.library.EqEnvVars.*;
import static net.cellcomputing.himawari.library.EqShaderType.*;

/**
 * 
 * shaderexecenvパッケージのグローバル関数・変数。
 * 
 * @author NTT DATA Corporation
 */
public strictfp class GlobalShaderExecEnv {
	
	
	public static final long dhash = "Data".hashCode();
	public static final long ihash = "Init".hashCode();
	public static final long cohash = "Code".hashCode();
	public static final long sehash = "segment".hashCode();
	public static final long phash = "param".hashCode();
	public static final long vhash = "varying".hashCode();
	public static final long uhash = "uniform".hashCode();
	public static final long ushash = "USES".hashCode();
	public static final long ehash = "external".hashCode();
	public static final long ouhash = "output".hashCode();
	
	public static shader_types[] gShaderTypeNames =
    {
        new shader_types( "surface", new EqShaderType(Type_Surface), 0L) ,
        new shader_types( "lightsource", new EqShaderType( Type_Lightsource ), 0L),
        new shader_types( "volume", new EqShaderType( Type_Volume ), 0L ) ,
        new shader_types( "displacement", new EqShaderType( Type_Displacement ), 0L) ,
        new shader_types( "transformation", new EqShaderType( Type_Transformation ), 0L) ,
        new shader_types( "imager", new EqShaderType( Type_Imager ), 0L)
    };
	
	public static int gcShaderTypeNames = gShaderTypeNames.length;

	//public static SqOpCodeTrans[] m_TransTable = new SqOpCodeTrans[325]; 
	
	
	
    
		
	    
	public static final String[] gVariableTypeNames =
	{
		"invalid",
		"float",
		"integer",
		"point",
		"string",
		"color",
		"triple",
		"hpoint",
		"normal",
		"vector",
		"void",
		"matrix",
		"sixteentuple",
	};
	
	public static final int gcVariableTypeNames = gVariableTypeNames.length;
	
	public static final String[] gVariableClassNames =
	{
		"invalid",
		"constant",
		"uniform",
		"varying",
		"vertex",
		"facevarying",
	};
	
	public static final int gcVariableClassNames = gVariableClassNames.length;
	
	public static final String[]	gVariableNames =
	{
		"Cs",
		"Os",
		"Ng",
		"du",
		"dv",
		"L",
		"Cl",
		"Ol",
		"P",
		"dPdu",
		"dPdv",
		"N",
		"u",
		"v",
		"s",
		"t",
		"I",
		"Ci",
		"Oi",
		"Ps",
		"E",
		"ncomps",
		"time",
		"alpha",
		"Ns",
	};
	
	public static final long[]	gVariableTokens =
	{
		gVariableNames[ 0 ].hashCode(),
		gVariableNames[ 1 ].hashCode(),
		gVariableNames[ 2 ].hashCode(),
		gVariableNames[ 3 ].hashCode(),
		gVariableNames[ 4 ].hashCode(),
		gVariableNames[ 5 ].hashCode(),
		gVariableNames[ 6 ].hashCode(),
		gVariableNames[ 7 ].hashCode(),
		gVariableNames[ 8 ].hashCode(),
		gVariableNames[ 9 ].hashCode(),
		gVariableNames[ 10 ].hashCode(),
		gVariableNames[ 11 ].hashCode(),
		gVariableNames[ 12 ].hashCode(),
		gVariableNames[ 13 ].hashCode(),
		gVariableNames[ 14 ].hashCode(),
		gVariableNames[ 15 ].hashCode(),
		gVariableNames[ 16 ].hashCode(),
		gVariableNames[ 17 ].hashCode(),
		gVariableNames[ 18 ].hashCode(),
		gVariableNames[ 19 ].hashCode(),
		gVariableNames[ 20 ].hashCode(),
		gVariableNames[ 21 ].hashCode(),
		gVariableNames[ 22 ].hashCode(),
		gVariableNames[ 23 ].hashCode(),
		gVariableNames[ 24 ].hashCode(),
	};
	
	
//	TODO: See if we can reduce these default requires further!
	public static final int	gDefUses = ( 1 << EnvVars_P ) | ( 1 << EnvVars_I ) | ( 1 << EnvVars_N ) | ( 1 << EnvVars_Ng ) | ( 1 << EnvVars_L ) | ( 1 << EnvVars_Cl ) | ( 1 << EnvVars_Ci ) | ( 1 << EnvVars_Oi ) | ( 1 << EnvVars_u ) | ( 1 << EnvVars_v );
	public static final int	gDefLightUses = ( 1 << EnvVars_P ) | ( 1 << EnvVars_L ) | ( 1 << EnvVars_Ps ) | ( 1 << EnvVars_Ns );
	
	
	//	 SO_sprintf
	//	 Helper function to process a string inserting variable, used in printf and format.
	public static final String SO_sprintf( final String str, int cParams, IqShaderData[] apParams, int varyingindex )
	{
		String strRes = ( "" );
		String strTrans = str;
//		strTrans = strTrans.TranslateEscapes();	//消しておく。

		int i = 0;
		int ivar = 0;
		while ( i < strTrans.length() )
		{
			switch ( strTrans.charAt( i ) )
			{
					case '%':   	// Insert variable.
					{
						i++;
						switch ( strTrans.charAt( i ) )
						{
								case 'f':
								{
									p_float f = new p_float();
									apParams[ ivar++ ] .GetFloat( f, varyingindex );
									String strVal;
									strVal = String.format( "%f", f.value );
									strRes += strVal;
								}
								break;

								case 'p':
								{
									CqVector3D vec = new CqVector3D();
									apParams[ ivar++ ] .GetPoint( vec, varyingindex );
									String strVal;
									strVal = String.format( "%f,%f,%f", vec.x, vec.y, vec.z );
									strRes += strVal;
								}
								break;

								case 'c':
								{
									CqColor col = new CqColor();
									apParams[ ivar++ ] .GetColor( col, varyingindex );
									String strVal;
									strVal = String.format( "%f,%f,%f", col.fRed(), col.fGreen(), col.fBlue() );
									strRes += strVal;
								}
								break;

								case 'm':
								{
									CqMatrix mat = new CqMatrix() ;
									apParams[ ivar++ ] .GetMatrix( mat, varyingindex );
									String strVal;
									strVal = String.format( "%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f\n%f,%f,%f,%f",
									               mat.m_aaElement[0][0], mat.m_aaElement[0][1], mat.m_aaElement[0][2], mat.m_aaElement[0][3],
									               mat.m_aaElement[1][0], mat.m_aaElement[1][1], mat.m_aaElement[1][2], mat.m_aaElement[1][3],
									               mat.m_aaElement[2][0], mat.m_aaElement[2][1], mat.m_aaElement[2][2], mat.m_aaElement[2][3],
									               mat.m_aaElement[3][0], mat.m_aaElement[3][1], mat.m_aaElement[3][2], mat.m_aaElement[3][3] );
									strRes += strVal;
								}
								break;

								case 's':
								{
									p_String stra = new p_String();
									apParams[ ivar++ ] .GetString( stra, varyingindex );
									strRes += stra.value;
								}
								break;

								default:
								{
									strRes += strTrans.charAt( i );
								}
								break;
						}
						i++;
					}
					break;

					default:
					{
						strRes += strTrans.charAt( i );
						i++;
					}
					break;
			}
		}
		return ( strRes );
	}

	
	public static final HashMap<String, BakingChannel> bake_init()
	{
		HashMap<String, BakingChannel> bd = new HashMap<String, BakingChannel>();

		return bd;
	}
	
	public static final void bake_done( HashMap<String, BakingChannel> bd )
	{
//		delete bd; // Will destroy bd, and in turn all its BakingChannel's
		for( BakingChannel bc : bd.values() ){
			bc.destruct();
		}
	}
	
	// Workhorse routine -- look up the channel name, add a new BakingChannel
	// if it doesn't exist, add one point's data to the channel.
	public static final void bake ( HashMap<String, BakingChannel> bd, final String name,
		                       float s, float t, int elsize, float[] data )
	{
		BakingChannel found = bd.get( name );;

		if ( found == null )
		{
			// This named map doesn't yet exist
			( bd ).put( name, new BakingChannel() );
			found = bd.get( name );
			BakingChannel bc = found;
			bc.init ( name, elsize );
			bc.moredata ( s, t, data );
		}
		else
		{
			BakingChannel bc = ( found );
			bc.moredata ( s, t, data );
		}
		
//		HashMap<String, BakingChannel>::iterator found = bd->find ( name );
//
//		if ( found == bd->end() )
//		{
//			// This named map doesn't yet exist
//			( *bd ) [ name ] = BakingChannel();
//			found = bd->find ( name );
//			BakingChannel &bc = ( found->second );
//			bc.init ( name.c_str(), elsize );
//			bc.moredata ( s, t, data );
//		}
//		else
//		{
//			BakingChannel &bc = ( found->second );
//			bc.moredata ( s, t, data );
//		}
	}

	public static final int bake_f( HashMap<String, BakingChannel> bd, String name, float s, float t, float f )
	{
		float[] bakedata = new float[]{f};

		bake ( bd, name, s, t, 1, bakedata );
		return 0;
	}
	
	// for baking a triple -- just call bake with appropriate args
	public static final int bake_3( HashMap<String, BakingChannel> bd, String name, float s, float t, float[] bakedata )
	{
		bake ( bd, name, s, t, 3, bakedata );
		return 0;
	}

	
	
	
	
	
	
}
