diff --git a/src/alternativa/engine3d/core/Camera3D.as b/src/alternativa/engine3d/core/Camera3D.as
index 9f792e3..ab1cbc7 100644
--- a/src/alternativa/engine3d/core/Camera3D.as
+++ b/src/alternativa/engine3d/core/Camera3D.as
@@ -319,6 +319,10 @@ public class Camera3D extends Object3D {
}
lightsLength = j;
lights.length = j;
+
+ // Sort lights by types
+ if (lightsLength > 0) sortLights(0, lightsLength - 1);
+
// Check getting in frustum and occluding
if (root.culling >= 0 && (root.boundBox == null || occludersLength == 0 || !root.boundBox.checkOcclusion(occluders, occludersLength, root.localToCameraTransform))) {
// Check if the ray crossing the bounding box
@@ -397,6 +401,38 @@ public class Camera3D extends Object3D {
cpuTimer = -1;
}
+
+ /**
+ * @private
+ */
+ private function sortLights(l:int, r:int):void {
+ var i:int = l;
+ var j:int = r;
+ var left:Light3D;
+ var index:int = (r + l) >> 1;
+ var m:Light3D = lights[index];
+ var mid:int = m.type;
+ var right:Light3D;
+ do {
+ while ((left = lights[i]).type < mid) {
+ i++;
+ }
+ while (mid < (right = lights[j]).type) {
+ j--;
+ }
+ if (i <= j) {
+ lights[i++] = right;
+ lights[j--] = left;
+ }
+ } while (i <= j);
+ if (l < j) {
+ sortLights(l, j);
+ }
+ if (i < r) {
+ sortLights(i, r);
+ }
+ }
+
/**
* Transforms point from global space to screen space. The view property should be defined.
* @param point Point in global space.
diff --git a/src/alternativa/engine3d/core/Light3D.as b/src/alternativa/engine3d/core/Light3D.as
index 31fae99..2554144 100644
--- a/src/alternativa/engine3d/core/Light3D.as
+++ b/src/alternativa/engine3d/core/Light3D.as
@@ -24,6 +24,16 @@ package alternativa.engine3d.core {
*/
public class Light3D extends Object3D {
+ /**
+ * @private
+ */
+ alternativa3d var type:int = 0;
+ alternativa3d static const AMBIENT:int = 1;
+ alternativa3d static const DIRECTIONAL:int = 2;
+ alternativa3d static const OMNI:int = 3;
+ alternativa3d static const SPOT:int = 4;
+ alternativa3d static const SHADOW_BIT:int = 0x100;
+
/**
* @private
*/
@@ -124,6 +134,7 @@ package alternativa.engine3d.core {
if (_shadow != null) _shadow._light = null;
_shadow = value;
if (value != null) value._light = this;
+ type = (value != null) ? type & ~SHADOW_BIT : type | SHADOW_BIT;
}
}
}
diff --git a/src/alternativa/engine3d/lights/AmbientLight.as b/src/alternativa/engine3d/lights/AmbientLight.as
index 829462b..10fba53 100644
--- a/src/alternativa/engine3d/lights/AmbientLight.as
+++ b/src/alternativa/engine3d/lights/AmbientLight.as
@@ -30,6 +30,7 @@ package alternativa.engine3d.lights {
* @param color Light color.
*/
public function AmbientLight(color:uint) {
+ this.type = AMBIENT;
this.color = color;
}
diff --git a/src/alternativa/engine3d/lights/DirectionalLight.as b/src/alternativa/engine3d/lights/DirectionalLight.as
index a5bc48f..a1e2547 100644
--- a/src/alternativa/engine3d/lights/DirectionalLight.as
+++ b/src/alternativa/engine3d/lights/DirectionalLight.as
@@ -31,6 +31,7 @@ package alternativa.engine3d.lights {
* @param color Color of light source.
*/
public function DirectionalLight(color:uint) {
+ this.type = DIRECTIONAL;
this.color = color;
}
diff --git a/src/alternativa/engine3d/lights/OmniLight.as b/src/alternativa/engine3d/lights/OmniLight.as
index ee23aec..07c55ae 100644
--- a/src/alternativa/engine3d/lights/OmniLight.as
+++ b/src/alternativa/engine3d/lights/OmniLight.as
@@ -39,6 +39,7 @@ package alternativa.engine3d.lights {
* @param attenuationEnd Distance from at which falloff is complete.
*/
public function OmniLight(color:uint, attenuationBegin:Number, attenuationEnd:Number) {
+ this.type = OMNI;
this.color = color;
this.attenuationBegin = attenuationBegin;
this.attenuationEnd = attenuationEnd;
diff --git a/src/alternativa/engine3d/lights/SpotLight.as b/src/alternativa/engine3d/lights/SpotLight.as
index fdd8d9e..4f54935 100644
--- a/src/alternativa/engine3d/lights/SpotLight.as
+++ b/src/alternativa/engine3d/lights/SpotLight.as
@@ -54,6 +54,7 @@ package alternativa.engine3d.lights {
* @param falloff Adjusts the angle of a light's falloff. The Falloff value is measured in radians.
*/
public function SpotLight(color:uint, attenuationBegin:Number, attenuationEnd:Number, hotspot:Number, falloff:Number) {
+ this.type = SPOT;
this.color = color;
this.attenuationBegin = attenuationBegin;
this.attenuationEnd = attenuationEnd;
diff --git a/src/alternativa/engine3d/materials/ShaderProgram.as b/src/alternativa/engine3d/materials/ShaderProgram.as
index edef8f8..6c928ed 100644
--- a/src/alternativa/engine3d/materials/ShaderProgram.as
+++ b/src/alternativa/engine3d/materials/ShaderProgram.as
@@ -20,7 +20,6 @@ package alternativa.engine3d.materials {
*/
public class ShaderProgram {
- public var key:String;
public var program:Program3D;
public var vertexShader:Linker;
diff --git a/src/alternativa/engine3d/materials/StandardMaterial.as b/src/alternativa/engine3d/materials/StandardMaterial.as
index 59e5ba0..b22080a 100644
--- a/src/alternativa/engine3d/materials/StandardMaterial.as
+++ b/src/alternativa/engine3d/materials/StandardMaterial.as
@@ -51,17 +51,18 @@ package alternativa.engine3d.materials {
*/
public class StandardMaterial extends TextureMaterial {
- private static const LIGHT_MAP:int = 1;
- private static const GLOSSINESS_MAP:int = 2;
- private static const SPECULAR_MAP:int = 4;
- private static const OPACITY_MAP:int = 8;
- private static const NORMAL_MAP_SPACE_BIT:int = 4;
- private static const ALPHA_TEST_BIT:int = 6;
- private static const OMNI_LIGHT_BIT:int = 8;
- private static const DIRECTIONAL_LIGHT_BIT:int = 11;
- private static const SPOT_LIGHT_BIT:int = 14;
- private static const OBJECT_TYPE_BIT:int = 17;
-
+ private static const LIGHT_MAP_BIT:int = 1;
+ private static const GLOSSINESS_MAP_BIT:int = 2;
+ private static const SPECULAR_MAP_BIT:int = 4;
+ private static const OPACITY_MAP_BIT:int = 8;
+ private static const NORMAL_MAP_SPACE_OFFSET:int = 4; // shift value
+ private static const ALPHA_TEST_OFFSET:int = 6;
+ private static const OMNI_LIGHT_OFFSET:int = 8;
+ private static const DIRECTIONAL_LIGHT_OFFSET:int = 11;
+ private static const SPOT_LIGHT_OFFSET:int = 14;
+ private static const SHADOW_OFFSET:int = 17;
+ // TODO: remove double cash by transform procedure. It increase speed by 1%
+// private static const OBJECT_TYPE_BIT:int = 19;
private static var caches:Dictionary = new Dictionary(true);
private var cachedContext3D:Context3D;
@@ -529,16 +530,9 @@ package alternativa.engine3d.materials {
* @param lightsLength
*/
private function getProgram(object:Object3D, programs:Array, camera:Camera3D, materialKey:int, opacityMap:TextureResource, alphaTest:int, lightsGroup:Vector., lightsLength:int, isFirstGroup:Boolean, shadowedLight:Light3D):StandardMaterialProgram {
- var key:int = materialKey + (opacityMap != null ? OPACITY_MAP : 0) + alphaTest << ALPHA_TEST_BIT;
+ var key:int = materialKey | (opacityMap != null ? OPACITY_MAP_BIT : 0) | (alphaTest << ALPHA_TEST_OFFSET);
var program:StandardMaterialProgram = programs[key];
-// var programsCount:int = programs.length;
-// for (var i:int = 0; i 0) {
@@ -1085,20 +1079,20 @@ package alternativa.engine3d.materials {
// Group of lights without shadow
// Form key
- materialKey = (isFirstGroup)?((lightMap != null) ? LIGHT_MAP : 0) : 0;
- materialKey +=
- ((_normalMapSpace==NormalMapSpace.OBJECT) ? 1 : (_normalMapSpace==NormalMapSpace.TANGENT_LEFT_HANDED) ? 2 : 3) << NORMAL_MAP_SPACE_BIT +
- (glossinessMap != null) ? GLOSSINESS_MAP : 0 +
- (specularMap != null) ? SPECULAR_MAP : 0;
+ materialKey = (isFirstGroup)?((lightMap != null) ? LIGHT_MAP_BIT : 0) : 0;
+ materialKey |=
+ (_normalMapSpace << NORMAL_MAP_SPACE_OFFSET) |
+ ((glossinessMap != null) ? GLOSSINESS_MAP_BIT : 0) |
+ ((specularMap != null) ? SPECULAR_MAP_BIT : 0);
for (j = 0; j < lightGroupLength; j++) {
light = lightGroup[j];
if (light is OmniLight) OmniLightCount++;
else if (light is DirectionalLight) DirectionalLightCount++;
else if (light is SpotLight) SpotLightCount++;
}
- materialKey += OmniLightCount << OMNI_LIGHT_BIT;
- materialKey += DirectionalLightCount << DIRECTIONAL_LIGHT_BIT;
- materialKey += SpotLightCount << SPOT_LIGHT_BIT;
+ materialKey |= OmniLightCount << OMNI_LIGHT_OFFSET;
+ materialKey |= DirectionalLightCount << DIRECTIONAL_LIGHT_OFFSET;
+ materialKey |= SpotLightCount << SPOT_LIGHT_OFFSET;
// Create program and drawUnit for group
@@ -1139,15 +1133,14 @@ package alternativa.engine3d.materials {
light = shadowGroup[j];
// Form key
- materialKey = (isFirstGroup)?((lightMap != null) ? LIGHT_MAP : 0) : 0;
- materialKey +=
- ((_normalMapSpace==NormalMapSpace.OBJECT) ? 1 : (_normalMapSpace==NormalMapSpace.TANGENT_LEFT_HANDED) ? 2 : 3) << NORMAL_MAP_SPACE_BIT +
- (glossinessMap != null) ? GLOSSINESS_MAP : 0 +
- (specularMap != null) ? SPECULAR_MAP : 0;
-
- if (light is OmniLight) materialKey += light.shadow.type << OMNI_LIGHT_BIT;
- else if (light is DirectionalLight) materialKey += light.shadow.type << DIRECTIONAL_LIGHT_BIT;
- else if (light is SpotLight) materialKey += light.shadow.type << SPOT_LIGHT_BIT;
+ materialKey = (isFirstGroup)?((lightMap != null) ? LIGHT_MAP_BIT : 0) : 0;
+ materialKey |= (_normalMapSpace << NORMAL_MAP_SPACE_OFFSET) |
+ ((glossinessMap != null) ? GLOSSINESS_MAP_BIT : 0) |
+ ((specularMap != null) ? SPECULAR_MAP_BIT : 0);
+ materialKey |= light.shadow.type << SHADOW_OFFSET;
+ if (light is OmniLight) materialKey |= 1 << OMNI_LIGHT_OFFSET;
+ else if (light is DirectionalLight) materialKey |= 1 << DIRECTIONAL_LIGHT_OFFSET;
+ else if (light is SpotLight) materialKey |= 1 << SPOT_LIGHT_OFFSET;
// Для группы создаем программу и дроуюнит
// Opaque pass
diff --git a/src/alternativa/engine3d/materials/TextureMaterial.as b/src/alternativa/engine3d/materials/TextureMaterial.as
index 3504555..b98ac30 100644
--- a/src/alternativa/engine3d/materials/TextureMaterial.as
+++ b/src/alternativa/engine3d/materials/TextureMaterial.as
@@ -172,6 +172,7 @@ package alternativa.engine3d.materials {
private function getProgram(object:Object3D, programs:Vector., camera:Camera3D, opacityMap:TextureResource, alphaTest:int):TextureMaterialProgram {
var key:int = (opacityMap != null ? 3 : 0) + alphaTest;
var program:TextureMaterialProgram = programs[key];
+
if (program == null) {
// Make program
// Vertex shader
diff --git a/src/alternativa/engine3d/shadows/Shadow.as b/src/alternativa/engine3d/shadows/Shadow.as
index 03628d0..d73526a 100644
--- a/src/alternativa/engine3d/shadows/Shadow.as
+++ b/src/alternativa/engine3d/shadows/Shadow.as
@@ -23,8 +23,9 @@ package alternativa.engine3d.shadows {
*/
public class Shadow {
- alternativa3d static const SIMPLE_MODE:int = 6;
- alternativa3d static const PCF_MODE:int = 7;
+ alternativa3d static const NONE_MODE:int = 0;
+ alternativa3d static const SIMPLE_MODE:int = 1;
+ alternativa3d static const PCF_MODE:int = 2;
/**
* Debug mode.
@@ -35,7 +36,7 @@ package alternativa.engine3d.shadows {
* @private
* Key for processing in materials.
*/
- alternativa3d var type:int = 6;
+ alternativa3d var type:int = 0;
/**
* @private