package classes.away3d.materials
{
	import classes.away3d.arcane;
	import classes.away3d.containers.*;
	import classes.away3d.core.base.*;
    import classes.away3d.core.render.*;
    import classes.away3d.core.utils.*;
	import classes.away3d.core.vos.*;
	import classes.away3d.lights.*;
    
	import flash.utils.*;
	
	use namespace arcane;
	
	/**
	 * Color material with flat shading.
	 */
    public class ShadingColorMaterial extends ColorMaterial
    {
		/** @private */
        arcane  override function updateMaterial(source:Object3D, view:View3D):void
        {
        	var _source_scene_directionalLights:Array = source.scene.directionalLights;
        	for each (var directional:DirectionalLight3D in _source_scene_directionalLights) {
        		if (!directional.diffuseTransform[source] || view._updatedObjects[source]) {
        			directional.setDiffuseTransform(source);
        			_materialDirty = true;
        		}
        		
        		if (!directional.specularTransform[source])
        			directional.specularTransform[source] = new Dictionary(true);
        		
        		if (!directional.specularTransform[source][view] || view._updatedObjects[source] || view.updated) {
        			directional.setSpecularTransform(source, view);
        			_materialDirty = true;
        		}
        	}
        	
        	var _source_scene_pointLights:Array = source.scene.pointLights;
        	for each (var point:PointLight3D in _source_scene_pointLights) {
        		if (!point.viewPositions[view] || view._updatedObjects[source] || view.updated) {
        			point.setViewPosition(view);
        			_materialDirty = true;
        		}
        	}
        	
        	if (_materialDirty)
        		notifyMaterialUpdate();
        }
		/** @private */
        arcane override function renderTriangle(priIndex:uint, viewSourceObject:ViewSourceObject, renderer:Renderer):void
        {	
			var shade:FaceNormalShaderVO = shader.getTriangleShade(priIndex, viewSourceObject, renderer, shininess);
            fr = int(((ambient & 0xFF0000) * shade.kar + (diffuse & 0xFF0000) * shade.kdr + (specular & 0xFF0000) * shade.ksr) >> 16);
            fg = int(((ambient & 0x00FF00) * shade.kag + (diffuse & 0x00FF00) * shade.kdg + (specular & 0x00FF00) * shade.ksg) >> 8);
            fb = int(((ambient & 0x0000FF) * shade.kab + (diffuse & 0x0000FF) * shade.kdb + (specular & 0x0000FF) * shade.ksb));
            
            if (fr > 0xFF)
                fr = 0xFF;
            if (fg > 0xFF)
                fg = 0xFF;
            if (fb > 0xFF)
                fb = 0xFF;
           	
			if (debug)
				renderer._session.renderTriangleLineFill(_thickness, fr << 16 | fg << 8 | fb, _alpha, _wireColor, _wireAlpha, viewSourceObject.screenVertices, renderer.primitiveCommands[priIndex], viewSourceObject.screenIndices, renderer.primitiveProperties[priIndex*9], renderer.primitiveProperties[priIndex*9+1]);
        	else
            	renderer._session.renderTriangleColor(fr << 16 | fg << 8 | fb, alpha, viewSourceObject.screenVertices, renderer.primitiveCommands[priIndex], viewSourceObject.screenIndices, renderer.primitiveProperties[priIndex*9], renderer.primitiveProperties[priIndex*9+1]);

            if (cache) {
            	var faceVO:FaceVO = renderer.primitiveElements[priIndex] as FaceVO;
                if (faceVO != null)
                {
                    sfr = int(((ambient & 0xFF0000) * shade.kar + (diffuse & 0xFF0000) * shade.kdr) >> 16);
                    sfg = int(((ambient & 0x00FF00) * shade.kag + (diffuse & 0x00FF00) * shade.kdg) >> 8);
                    sfb = int(((ambient & 0x0000FF) * shade.kab + (diffuse & 0x0000FF) * shade.kdb));

                    if (sfr > 0xFF)
                        sfr = 0xFF;
                    if (sfg > 0xFF)
                        sfg = 0xFF;
                    if (sfb > 0xFF)
                        sfb = 0xFF;

                    faceVO.material = new ColorMaterial(sfr << 16 | sfg << 8 | sfb, {alpha:_alpha});
                }
            }
        }
        
		private var fr:int;
		private var fg:int;
		private var fb:int;
		private var sfr:int;
		private var sfg:int;
		private var sfb:int;
		private var shader:FaceNormalShader = new FaceNormalShader();
		
		/**
		 * Defines a color value for ambient light.
		 */
        public var ambient:uint;
		
		/**
		 * Defines a color value for diffuse light.
		 */
        public var diffuse:uint;
		
		/**
		 * Defines a color value for specular light.
		 */
        public var specular:uint;
                
        /**
        * Coefficient for shininess level
        */
        public var shininess:Number;
        
        /**
        * Defines whether the resulting shaded color of the surface should be cached.
        */
        public var cache:Boolean;
    	
		/**
        * Defines the color, A string, hex value or colorname representing the color of the material.
        */
		public override function get color():uint
		{
            return _color;
		}
		
        public override function set color(val:uint):void
		{
        	if (_color == val)
        		return;
        	
        	_color = val;
			
			ambient = diffuse = specular = _color;
			
			_materialDirty = true;
		}
    	
		/**
		 * Creates a new <code>ShadingColorMaterial</code> object.
		 * 
		 * @param	colorvalue				A string, hex value or colorname representing the color of the material.
		 * @param	init						[optional]	An initialisation object for specifying default instance properties.
		 */
        public function ShadingColorMaterial(color:* = null, init:Object = null)
        {
            super(color, init);
			
            ambient = ini.getColor("ambient", color);
            diffuse = ini.getColor("diffuse", color);
            specular = ini.getColor("specular", color);
            shininess = ini.getNumber("shininess", 20);
            cache = ini.getBoolean("cache", false);
        }
    }
}
