PageRenderTime 40ms CodeModel.GetById 12ms app.highlight 23ms RepoModel.GetById 1ms app.codeStats 1ms

/src/away3d/materials/methods/BasicDiffuseMethod.as

http://github.com/away3d/away3d-core-fp11
ActionScript | 372 lines | 247 code | 59 blank | 66 comment | 45 complexity | bbe13c0ca201d0703153f2c6746e1df8 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	
  9	use namespace arcane;
 10	
 11	/**
 12	 * BasicDiffuseMethod provides the default shading method for Lambert (dot3) diffuse lighting.
 13	 */
 14	public class BasicDiffuseMethod extends LightingMethodBase
 15	{
 16		private var _useAmbientTexture:Boolean;
 17		
 18		protected var _useTexture:Boolean;
 19		internal var _totalLightColorReg:ShaderRegisterElement;
 20		
 21		// TODO: are these registers at all necessary to be members?
 22		protected var _diffuseInputRegister:ShaderRegisterElement;
 23		
 24		private var _texture:Texture2DBase;
 25		private var _diffuseColor:uint = 0xffffff;
 26		private var _diffuseR:Number = 1, _diffuseG:Number = 1, _diffuseB:Number = 1, _diffuseA:Number = 1;
 27		protected var _shadowRegister:ShaderRegisterElement;
 28		
 29		protected var _alphaThreshold:Number = 0;
 30		protected var _isFirstLight:Boolean;
 31		
 32		/**
 33		 * Creates a new BasicDiffuseMethod object.
 34		 */
 35		public function BasicDiffuseMethod()
 36		{
 37			super();
 38		}
 39
 40		/**
 41		 * Set internally if the ambient method uses a texture.
 42		 */
 43		arcane function get useAmbientTexture():Boolean
 44		{
 45			return _useAmbientTexture;
 46		}
 47
 48		arcane function set useAmbientTexture(value:Boolean):void
 49		{
 50			if (_useAmbientTexture == value)
 51				return;
 52
 53			_useAmbientTexture = value;
 54
 55			invalidateShaderProgram();
 56		}
 57		
 58		override arcane function initVO(vo:MethodVO):void
 59		{
 60			vo.needsUV = _useTexture;
 61			vo.needsNormals = vo.numLights > 0;
 62		}
 63
 64		/**
 65		 * Forces the creation of the texture.
 66		 * @param stage3DProxy The Stage3DProxy used by the renderer
 67		 */
 68		public function generateMip(stage3DProxy:Stage3DProxy):void
 69		{
 70			if (_useTexture)
 71				_texture.getTextureForStage3D(stage3DProxy);
 72		}
 73
 74		/**
 75		 * The alpha component of the diffuse reflection.
 76		 */
 77		public function get diffuseAlpha():Number
 78		{
 79			return _diffuseA;
 80		}
 81		
 82		public function set diffuseAlpha(value:Number):void
 83		{
 84			_diffuseA = value;
 85		}
 86		
 87		/**
 88		 * The color of the diffuse reflection when not using a texture.
 89		 */
 90		public function get diffuseColor():uint
 91		{
 92			return _diffuseColor;
 93		}
 94		
 95		public function set diffuseColor(diffuseColor:uint):void
 96		{
 97			_diffuseColor = diffuseColor;
 98			updateDiffuse();
 99		}
100		
101		/**
102		 * The bitmapData to use to define the diffuse reflection color per texel.
103		 */
104		public function get texture():Texture2DBase
105		{
106			return _texture;
107		}
108		
109		public function set texture(value:Texture2DBase):void
110		{
111			if (Boolean(value) != _useTexture ||
112				(value && _texture && (value.hasMipMaps != _texture.hasMipMaps || value.format != _texture.format))) {
113				invalidateShaderProgram();
114			}
115			
116			_useTexture = Boolean(value);
117			_texture = value;
118		}
119		
120		/**
121		 * The minimum alpha value for which pixels should be drawn. This is used for transparency that is either
122		 * invisible or entirely opaque, often used with textures for foliage, etc.
123		 * Recommended values are 0 to disable alpha, or 0.5 to create smooth edges. Default value is 0 (disabled).
124		 */
125		public function get alphaThreshold():Number
126		{
127			return _alphaThreshold;
128		}
129		
130		public function set alphaThreshold(value:Number):void
131		{
132			if (value < 0)
133				value = 0;
134			else if (value > 1)
135				value = 1;
136			if (value == _alphaThreshold)
137				return;
138			
139			if (value == 0 || _alphaThreshold == 0)
140				invalidateShaderProgram();
141			
142			_alphaThreshold = value;
143		}
144		
145		/**
146		 * @inheritDoc
147		 */
148		override public function dispose():void
149		{
150			_texture = null;
151		}
152		
153		/**
154		 * @inheritDoc
155		 */
156		override public function copyFrom(method:ShadingMethodBase):void
157		{
158			var diff:BasicDiffuseMethod = BasicDiffuseMethod(method);
159			alphaThreshold = diff.alphaThreshold;
160			texture = diff.texture;
161			useAmbientTexture = diff.useAmbientTexture;
162			diffuseAlpha = diff.diffuseAlpha;
163			diffuseColor = diff.diffuseColor;
164		}
165
166		/**
167		 * @inheritDoc
168		 */
169		arcane override function cleanCompilationData():void
170		{
171			super.cleanCompilationData();
172			_shadowRegister = null;
173			_totalLightColorReg = null;
174			_diffuseInputRegister = null;
175		}
176		
177		/**
178		 * @inheritDoc
179		 */
180		override arcane function getFragmentPreLightingCode(vo:MethodVO, regCache:ShaderRegisterCache):String
181		{
182			var code:String = "";
183			
184			_isFirstLight = true;
185			
186			if (vo.numLights > 0) {
187				_totalLightColorReg = regCache.getFreeFragmentVectorTemp();
188				regCache.addFragmentTempUsages(_totalLightColorReg, 1);
189			}
190			
191			return code;
192		}
193		
194		/**
195		 * @inheritDoc
196		 */
197		override arcane function getFragmentCodePerLight(vo:MethodVO, lightDirReg:ShaderRegisterElement, lightColReg:ShaderRegisterElement, regCache:ShaderRegisterCache):String
198		{
199			var code:String = "";
200			var t:ShaderRegisterElement;
201			
202			// write in temporary if not first light, so we can add to total diffuse colour
203			if (_isFirstLight)
204				t = _totalLightColorReg;
205			else {
206				t = regCache.getFreeFragmentVectorTemp();
207				regCache.addFragmentTempUsages(t, 1);
208			}
209			
210			code += "dp3 " + t + ".x, " + lightDirReg + ", " + _sharedRegisters.normalFragment + "\n" +
211				"max " + t + ".w, " + t + ".x, " + _sharedRegisters.commons + ".y\n";
212			
213			if (vo.useLightFallOff)
214				code += "mul " + t + ".w, " + t + ".w, " + lightDirReg + ".w\n";
215			
216			if (_modulateMethod != null)
217				code += _modulateMethod(vo, t, regCache, _sharedRegisters);
218			
219			code += "mul " + t + ", " + t + ".w, " + lightColReg + "\n";
220			
221			if (!_isFirstLight) {
222				code += "add " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + t + "\n";
223				regCache.removeFragmentTempUsage(t);
224			}
225			
226			_isFirstLight = false;
227			
228			return code;
229		}
230		
231		/**
232		 * @inheritDoc
233		 */
234		arcane override function getFragmentCodePerProbe(vo:MethodVO, cubeMapReg:ShaderRegisterElement, weightRegister:String, regCache:ShaderRegisterCache):String
235		{
236			var code:String = "";
237			var t:ShaderRegisterElement;
238			
239			// write in temporary if not first light, so we can add to total diffuse colour
240			if (_isFirstLight)
241				t = _totalLightColorReg;
242			else {
243				t = regCache.getFreeFragmentVectorTemp();
244				regCache.addFragmentTempUsages(t, 1);
245			}
246			
247			code += "tex " + t + ", " + _sharedRegisters.normalFragment + ", " + cubeMapReg + " <cube,linear,miplinear>\n" +
248				"mul " + t + ".xyz, " + t + ".xyz, " + weightRegister + "\n";
249			
250			if (_modulateMethod != null)
251				code += _modulateMethod(vo, t, regCache, _sharedRegisters);
252			
253			if (!_isFirstLight) {
254				code += "add " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + t + "\n";
255				regCache.removeFragmentTempUsage(t);
256			}
257			
258			_isFirstLight = false;
259			
260			return code;
261		}
262		
263		/**
264		 * @inheritDoc
265		 */
266		override arcane function getFragmentPostLightingCode(vo:MethodVO, regCache:ShaderRegisterCache, targetReg:ShaderRegisterElement):String
267		{
268			var code:String = "";
269			var albedo:ShaderRegisterElement;
270			var cutOffReg:ShaderRegisterElement;
271			
272			// incorporate input from ambient
273			if (vo.numLights > 0) {
274				if (_shadowRegister)
275					code += applyShadow(vo, regCache);
276				albedo = regCache.getFreeFragmentVectorTemp();
277				regCache.addFragmentTempUsages(albedo, 1);
278			} else
279				albedo = targetReg;
280			
281			if (_useTexture) {
282				_diffuseInputRegister = regCache.getFreeTextureReg();
283				vo.texturesIndex = _diffuseInputRegister.index;
284				code += getTex2DSampleCode(vo, albedo, _diffuseInputRegister, _texture);
285				if (_alphaThreshold > 0) {
286					cutOffReg = regCache.getFreeFragmentConstant();
287					vo.fragmentConstantsIndex = cutOffReg.index*4;
288					code += "sub " + albedo + ".w, " + albedo + ".w, " + cutOffReg + ".x\n" +
289						"kil " + albedo + ".w\n" +
290						"add " + albedo + ".w, " + albedo + ".w, " + cutOffReg + ".x\n";
291				}
292			} else {
293				_diffuseInputRegister = regCache.getFreeFragmentConstant();
294				vo.fragmentConstantsIndex = _diffuseInputRegister.index*4;
295				code += "mov " + albedo + ", " + _diffuseInputRegister + "\n";
296			}
297			
298			if (vo.numLights == 0)
299				return code;
300			
301			code += "sat " + _totalLightColorReg + ", " + _totalLightColorReg + "\n";
302			
303			if (_useAmbientTexture) {
304				code += "mul " + albedo + ".xyz, " + albedo + ", " + _totalLightColorReg + "\n" +
305					"mul " + _totalLightColorReg + ".xyz, " + targetReg + ", " + _totalLightColorReg + "\n" +
306					"sub " + targetReg + ".xyz, " + targetReg + ", " + _totalLightColorReg + "\n" +
307					"add " + targetReg + ".xyz, " + albedo + ", " + targetReg + "\n";
308			} else {
309				code += "add " + targetReg + ".xyz, " + _totalLightColorReg + ", " + targetReg + "\n";
310				if (_useTexture) {
311					code += "mul " + targetReg + ".xyz, " + albedo + ", " + targetReg + "\n" +
312						"mov " + targetReg + ".w, " + albedo + ".w\n";
313				} else {
314					code += "mul " + targetReg + ".xyz, " + _diffuseInputRegister + ", " + targetReg + "\n" +
315						"mov " + targetReg + ".w, " + _diffuseInputRegister + ".w\n";
316				}
317			}
318			
319			regCache.removeFragmentTempUsage(_totalLightColorReg);
320			regCache.removeFragmentTempUsage(albedo);
321			
322			return code;
323		}
324
325		/**
326		 * Generate the code that applies the calculated shadow to the diffuse light
327		 * @param vo The MethodVO object for which the compilation is currently happening.
328		 * @param regCache The register cache the compiler is currently using for the register management.
329		 */
330		protected function applyShadow(vo:MethodVO, regCache:ShaderRegisterCache):String
331		{
332			return "mul " + _totalLightColorReg + ".xyz, " + _totalLightColorReg + ", " + _shadowRegister + ".w\n";
333		}
334		
335		/**
336		 * @inheritDoc
337		 */
338		override arcane function activate(vo:MethodVO, stage3DProxy:Stage3DProxy):void
339		{
340			if (_useTexture) {
341				stage3DProxy._context3D.setTextureAt(vo.texturesIndex, _texture.getTextureForStage3D(stage3DProxy));
342				if (_alphaThreshold > 0)
343					vo.fragmentData[vo.fragmentConstantsIndex] = _alphaThreshold;
344			} else {
345				var index:int = vo.fragmentConstantsIndex;
346				var data:Vector.<Number> = vo.fragmentData;
347				data[index] = _diffuseR;
348				data[index + 1] = _diffuseG;
349				data[index + 2] = _diffuseB;
350				data[index + 3] = _diffuseA;
351			}
352		}
353		
354		/**
355		 * Updates the diffuse color data used by the render state.
356		 */
357		private function updateDiffuse():void
358		{
359			_diffuseR = ((_diffuseColor >> 16) & 0xff)/0xff;
360			_diffuseG = ((_diffuseColor >> 8) & 0xff)/0xff;
361			_diffuseB = (_diffuseColor & 0xff)/0xff;
362		}
363
364		/**
365		 * Set internally by the compiler, so the method knows the register containing the shadow calculation.
366		 */
367		arcane function set shadowRegister(value:ShaderRegisterElement):void
368		{
369			_shadowRegister = value;
370		}
371	}
372}