PageRenderTime 476ms CodeModel.GetById 212ms app.highlight 13ms RepoModel.GetById 248ms app.codeStats 0ms

/src/away3d/materials/methods/TerrainDiffuseMethod.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 164 lines | 114 code | 24 blank | 26 comment | 12 complexity | 526ea7aca7eb3da5883275e28e810ca3 MD5 | raw file
  1package away3d.materials.methods
  2{
  3	import away3d.arcane;
  4	import away3d.core.managers.Stage3DProxy;
  5	import away3d.materials.compilation.ShaderRegisterCache;
  6	import away3d.materials.compilation.ShaderRegisterElement;
  7	import away3d.textures.Texture2DBase;
  8	import away3d.textures.TextureProxyBase;
  9	
 10	import flash.display3D.Context3D;
 11	
 12	use namespace arcane;
 13
 14	/**
 15	 * TerrainDiffuseMethod provides a diffuse method that uses different tiled textures with alpha masks to create a
 16	 * large surface with high detail and less apparent tiling.
 17	 */
 18	public class TerrainDiffuseMethod extends BasicDiffuseMethod
 19	{
 20		private var _blendingTexture:Texture2DBase;
 21		private var _splats:Vector.<Texture2DBase>;
 22		private var _numSplattingLayers:uint;
 23		private var _tileData:Array;
 24		
 25		/**
 26		 * Creates a new TerrainDiffuseMethod.
 27		 * @param splatTextures An array of Texture2DProxyBase containing the detailed textures to be tiled.
 28		 * @param blendingTexture The texture containing the blending data. The red, green, and blue channels contain the blending values for each of the textures in splatTextures, respectively.
 29		 * @param tileData The amount of times each splat texture needs to be tiled. The first entry in the array applies to the base texture, the others to the splats. If omitted, the default value of 50 is assumed for each.
 30		 */
 31		public function TerrainDiffuseMethod(splatTextures:Array, blendingTexture:Texture2DBase, tileData:Array)
 32		{
 33			super();
 34			_splats = Vector.<Texture2DBase>(splatTextures);
 35			_tileData = tileData;
 36			_blendingTexture = blendingTexture;
 37			_numSplattingLayers = _splats.length;
 38			if (_numSplattingLayers > 4)
 39				throw new Error("More than 4 splatting layers is not supported!");
 40		}
 41
 42		/**
 43		 * @inheritDoc
 44		 */
 45		override arcane function initConstants(vo:MethodVO):void
 46		{
 47			var data:Vector.<Number> = vo.fragmentData;
 48			var index:int = vo.fragmentConstantsIndex;
 49			data[index] = _tileData? _tileData[0] : 1;
 50			for (var i:int = 0; i < _numSplattingLayers; ++i) {
 51				if (i < 3)
 52					data[uint(index + i + 1)] = _tileData? _tileData[i + 1] : 50;
 53				else
 54					data[uint(index + i - 4)] = _tileData? _tileData[i + 1] : 50;
 55			}
 56		}
 57
 58		/**
 59		 * @inheritDoc
 60		 */
 61		arcane override function getFragmentPostLightingCode(vo:MethodVO, regCache:ShaderRegisterCache, targetReg:ShaderRegisterElement):String
 62		{
 63			var code:String = "";
 64			var albedo:ShaderRegisterElement;
 65			var scaleRegister:ShaderRegisterElement;
 66			var scaleRegister2:ShaderRegisterElement;
 67			
 68			// incorporate input from ambient
 69			if (vo.numLights > 0) {
 70				if (_shadowRegister)
 71					code += "mul " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ".xyz, " + _shadowRegister + ".w\n";
 72				code += "add " + targetReg + ".xyz, " + _totalLightColorReg + ".xyz, " + targetReg + ".xyz\n" +
 73					"sat " + targetReg + ".xyz, " + targetReg + ".xyz\n";
 74				regCache.removeFragmentTempUsage(_totalLightColorReg);
 75				
 76				albedo = regCache.getFreeFragmentVectorTemp();
 77				regCache.addFragmentTempUsages(albedo, 1);
 78			} else
 79				albedo = targetReg;
 80			
 81			if (!_useTexture)
 82				throw new Error("TerrainDiffuseMethod requires a diffuse texture!");
 83			_diffuseInputRegister = regCache.getFreeTextureReg();
 84			vo.texturesIndex = _diffuseInputRegister.index;
 85			var blendTexReg:ShaderRegisterElement = regCache.getFreeTextureReg();
 86			
 87			scaleRegister = regCache.getFreeFragmentConstant();
 88			if (_numSplattingLayers == 4)
 89				scaleRegister2 = regCache.getFreeFragmentConstant();
 90			
 91			var uv:ShaderRegisterElement = regCache.getFreeFragmentVectorTemp();
 92			regCache.addFragmentTempUsages(uv, 1);
 93			
 94			var uvReg:ShaderRegisterElement = _sharedRegisters.uvVarying;
 95			
 96			code += "mul " + uv + ", " + uvReg + ", " + scaleRegister + ".x\n" +
 97				getSplatSampleCode(vo, albedo, _diffuseInputRegister, texture, uv);
 98			
 99			var blendValues:ShaderRegisterElement = regCache.getFreeFragmentVectorTemp();
100			regCache.addFragmentTempUsages(blendValues, 1);
101			code += getTex2DSampleCode(vo, blendValues, blendTexReg, _blendingTexture, uvReg, "clamp");
102			var splatTexReg:ShaderRegisterElement;
103			
104			vo.fragmentConstantsIndex = scaleRegister.index*4;
105			var comps:Vector.<String> = Vector.<String>([ ".x", ".y", ".z", ".w" ]);
106			
107			for (var i:int = 0; i < _numSplattingLayers; ++i) {
108				var scaleRegName:String = i < 3? scaleRegister + comps[i + 1] : scaleRegister2 + comps[i - 3];
109				splatTexReg = regCache.getFreeTextureReg();
110				code += "mul " + uv + ", " + uvReg + ", " + scaleRegName + "\n" +
111					getSplatSampleCode(vo, uv, splatTexReg, _splats[i], uv);
112				
113				code += "sub " + uv + ", " + uv + ", " + albedo + "\n" +
114					"mul " + uv + ", " + uv + ", " + blendValues + comps[i] + "\n" +
115					"add " + albedo + ", " + albedo + ", " + uv + "\n";
116			}
117			regCache.removeFragmentTempUsage(uv);
118			regCache.removeFragmentTempUsage(blendValues);
119			
120			if (vo.numLights > 0) {
121				code += "mul " + targetReg + ".xyz, " + albedo + ".xyz, " + targetReg + ".xyz\n" +
122					"mov " + targetReg + ".w, " + albedo + ".w\n";
123				
124				regCache.removeFragmentTempUsage(albedo);
125			}
126			
127			return code;
128		}
129
130		/**
131		 * @inheritDoc
132		 */
133		arcane override function activate(vo:MethodVO, stage3DProxy:Stage3DProxy):void
134		{
135			var context:Context3D = stage3DProxy._context3D;
136			var i:int;
137			var texIndex:int = vo.texturesIndex;
138			super.activate(vo, stage3DProxy);
139			context.setTextureAt(texIndex + 1, _blendingTexture.getTextureForStage3D(stage3DProxy));
140			
141			texIndex += 2;
142			for (i = 0; i < _numSplattingLayers; ++i)
143				context.setTextureAt(i + texIndex, _splats[i].getTextureForStage3D(stage3DProxy));
144		}
145
146		/**
147		 * @inheritDoc
148		 */
149		override public function set alphaThreshold(value:Number):void
150		{
151			if (value > 0)
152				throw new Error("Alpha threshold not supported for TerrainDiffuseMethod");
153		}
154
155		/**
156		 * Gets the sample code for a single splat.
157		 */
158		protected function getSplatSampleCode(vo:MethodVO, targetReg:ShaderRegisterElement, inputReg:ShaderRegisterElement, texture:TextureProxyBase, uvReg:ShaderRegisterElement = null):String
159		{
160			uvReg ||= _sharedRegisters.uvVarying;
161			return getTex2DSampleCode(vo, targetReg, inputReg, texture, uvReg, "wrap");
162		}
163	}
164}