Object.assign(pc, function () {
var keyA, keyB, sortPos, sortDir;
function sortManual(drawCallA, drawCallB) {
return drawCallA.drawOrder - drawCallB.drawOrder;
}
function sortMaterialMesh(drawCallA, drawCallB) {
keyA = drawCallA._key[pc.SORTKEY_FORWARD];
keyB = drawCallB._key[pc.SORTKEY_FORWARD];
if (keyA === keyB && drawCallA.mesh && drawCallB.mesh) {
return drawCallB.mesh.id - drawCallA.mesh.id;
}
return keyB - keyA;
}
function sortBackToFront(drawCallA, drawCallB) {
return drawCallB.zdist - drawCallA.zdist;
}
function sortFrontToBack(drawCallA, drawCallB) {
return drawCallA.zdist - drawCallB.zdist;
}
var sortCallbacks = [null, sortManual, sortMaterialMesh, sortBackToFront, sortFrontToBack];
function sortCameras(camA, camB) {
return camA.priority - camB.priority;
}
function sortLights(lightA, lightB) {
return lightB.key - lightA.key;
}
// Layers
var layerCounter = 0;
var VisibleInstanceList = function () {
this.list = [];
this.length = 0;
this.done = false;
};
var InstanceList = function () {
this.opaqueMeshInstances = [];
this.transparentMeshInstances = [];
this.shadowCasters = [];
// arrays of VisibleInstanceList for each camera
this.visibleOpaque = [];
this.visibleTransparent = [];
};
InstanceList.prototype.clearVisibleLists = function (cameraPass) {
if (this.visibleOpaque[cameraPass]) {
this.visibleOpaque[cameraPass].length = 0;
this.visibleOpaque[cameraPass].list.length = 0;
}
if (this.visibleTransparent[cameraPass]) {
this.visibleTransparent[cameraPass].length = 0;
this.visibleTransparent[cameraPass].list.length = 0;
}
};
/**
* @constructor
* @name pc.Layer
* @classdesc Layer represents a renderable subset of the scene. It can contain a list of mesh instances, lights and cameras,
* their render settings and also defines custom callbacks before, after or during rendering.
* Layers are organized inside {@link pc.LayerComposition} in a desired order.
* @description Create a new layer.
* @param {Object} options Object for passing optional arguments. These arguments are the same as properties of the Layer.
* @property {Boolean} enabled Enable the layer. Disabled layers are skipped. Defaults to true.
* @property {String} name Name of the layer. Can be used in {@link pc.LayerComposition#getLayerByName}.
* @property {Number} opaqueSortMode Defines the method used for sorting opaque (that is, not semi-transparent) mesh instances before rendering.
* Possible values are:
* <ul>
* <li>{@link pc.SORTMODE_NONE}</li>
* <li>{@link pc.SORTMODE_MANUAL}</li>
* <li>{@link pc.SORTMODE_MATERIALMESH}</li>
* <li>{@link pc.SORTMODE_BACK2FRONT}</li>
* <li>{@link pc.SORTMODE_FRONT2BACK}</li>
* </ul>
* Defaults to pc.SORTMODE_MATERIALMESH.
* @property {Number} transparentSortMode Defines the method used for sorting semi-transparent mesh instances before rendering.
* Possible values are:
* <ul>
* <li>{@link pc.SORTMODE_NONE}</li>
* <li>{@link pc.SORTMODE_MANUAL}</li>
* <li>{@link pc.SORTMODE_MATERIALMESH}</li>
* <li>{@link pc.SORTMODE_BACK2FRONT}</li>
* <li>{@link pc.SORTMODE_FRONT2BACK}</li>
* </ul>
* Defaults to pc.SORTMODE_BACK2FRONT.
* @property {pc.RenderTarget} renderTarget Render target to which rendering is performed. If not set, will render simply to the screen.
* @property {Number} shaderPass A type of shader to use during rendering. Possible values are:
* <ul>
* <li>{@link pc.SHADER_FORWARD}</li>
* <li>{@link pc.SHADER_FORWARDHDR}</li>
* <li>{@link pc.SHADER_DEPTH}</li>
* <li>Your own custom value. Should be in 19 - 31 range. Use {@link pc.StandardMaterial#onUpdateShader} to apply shader modifications based on this value.</li>
* </ul>
* Defaults to pc.SHADER_FORWARD.
* @property {Boolean} passThrough Tells that this layer is simple and needs to just render a bunch of mesh instances without lighting, skinning and morphing (faster).
*
* @property {Boolean} overrideClear Defines if layer should use camera clear parameters (true) or ignore them and use {@link pc.Layer#clearColor}, {@link pc.Layer#clearColorBuffer},
* {@link pc.Layer#clearDepthBuffer} and {@link pc.Layer#clearStencilBuffer}.
* @property {pc.Color} clearColor The color used to clear the canvas to before each camera starts to render.
* @property {Boolean} clearColorBuffer If true cameras will clear the color buffer to the color set in clearColor.
* @property {Boolean} clearDepthBuffer If true cameras will clear the depth buffer.
* @property {Boolean} clearStencilBuffer If true cameras will clear the stencil buffer.
*
* @property {pc.Layer} layerReference Make this layer render the same mesh instances that another layer does instead of having its own mesh instance list.
* Both layers must share cameras. Frustum culling is only performed for one layer.
* @property {Function} cullingMask Visibility mask that interacts with {@link pc.MeshInstance#mask}.
* @property {Function} onEnable Custom function that is called after the layer has been enabled.
* This happens when:
* <ul>
* <li>The layer is created with {@link pc.Layer#enabled} set to true (which is the default value).</li>
* <li>{@link pc.Layer#enabled} was changed from false to true</li>
* <li>{@link pc.Layer#incrementCounter} was called and incremented the counter above zero.</li>
* </ul>
* Useful for allocating resources this layer will use (e.g. creating render targets).
* @property {Function} onDisable Custom function that is called after the layer has been disabled.
* This happens when:
* <ul>
* <li>{@link pc.Layer#enabled} was changed from true to false</li>
* <li>{@link pc.Layer#decrementCounter} was called and set the counter to zero.</li>
* </ul>
* @property {Function} onPreCull Custom function that is called before visibility culling is performed for this layer.
* Useful, for example, if you want to modify camera projection while still using the same camera and make frustum culling work correctly with it
* (see {@link pc.CameraComponent#calculateTransform} and {@link pc.CameraComponent#calculateProjection}).
* This function will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPostCull Custom function that is called after visibiliy culling is performed for this layer.
* Useful for reverting changes done in {@link pc.Layer#onPreCull} and determining final mesh instance visibility (see {@link pc.MeshInstance#visibleThisFrame}).
* This function will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPreRender Custom function that is called before this layer is rendered.
* Useful, for example, for reacting on screen size changes.
* This function is called before the first occurrence of this layer in {@link pc.LayerComposition}.
* It will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPreRenderOpaque Custom function that is called before opaque mesh instances (not semi-transparent) in this layer are rendered.
* This function will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPreRenderTransparent Custom function that is called before semi-transparent mesh instances in this layer are rendered.
* This function will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPostRender Custom function that is called after this layer is rendered.
* Useful to revert changes made in {@link pc.Layer#onPreRender} or performing some processing on {@link pc.Layer#renderTarget}.
* This function is called after the last occurrence of this layer in {@link pc.LayerComposition}.
* It will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPostRenderOpaque Custom function that is called after opaque mesh instances (not semi-transparent) in this layer are rendered.
* This function will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onPostRenderTransparent Custom function that is called after semi-transparent mesh instances in this layer are rendered.
* This function will receive camera index as the only argument. You can get the actual camera being used by looking up {@link pc.LayerComposition#cameras} with this index.
* @property {Function} onDrawCall Custom function that is called before every mesh instance in this layer is rendered.
* It is not recommended to set this function when rendering many objects every frame due to performance reasons.
* @property {Function} id A unique ID of the layer.
* Layer IDs are stored inside {@link pc.ModelComponent#layers}, {@link pc.CameraComponent#layers}, {@link pc.LightComponent#layers} and {@link pc.ElementComponent#layers} instead of names.
* Can be used in {@link pc.LayerComposition#getLayerById}.
*/
var Layer = function (options) {
options = options || {};
if (options.id !== undefined) {
this.id = options.id;
layerCounter = Math.max(this.id + 1, layerCounter);
} else {
this.id = layerCounter++;
}
this.name = options.name;
this._enabled = options.enabled === undefined ? true : options.enabled;
this._refCounter = this._enabled ? 1 : 0;
this.opaqueSortMode = options.opaqueSortMode === undefined ? pc.SORTMODE_MATERIALMESH : options.opaqueSortMode;
this.transparentSortMode = options.transparentSortMode === undefined ? pc.SORTMODE_BACK2FRONT : options.transparentSortMode;
this.renderTarget = options.renderTarget;
this.shaderPass = options.shaderPass === undefined ? pc.SHADER_FORWARD : options.shaderPass;
this.passThrough = options.passThrough === undefined ? false : options.passThrough;
this.overrideClear = options.overrideClear === undefined ? false : options.overrideClear;
this._clearColor = new pc.Color(0, 0, 0, 1);
if (options.clearColor) {
this._clearColor.copy(options.clearColor);
}
this._clearColorBuffer = options.clearColorBuffer === undefined ? false : options.clearColorBuffer;
this._clearDepthBuffer = options.clearDepthBuffer === undefined ? false : options.clearDepthBuffer;
this._clearStencilBuffer = options.clearStencilBuffer === undefined ? false : options.clearStencilBuffer;
this._clearOptions = {
color: [this._clearColor.r, this._clearColor.g, this._clearColor.b, this._clearColor.a],
depth: 1,
stencil: 0,
flags: (this._clearColorBuffer ? pc.CLEARFLAG_COLOR : 0) | (this._clearDepthBuffer ? pc.CLEARFLAG_DEPTH : 0) | (this._clearStencilBuffer ? pc.CLEARFLAG_STENCIL : 0)
};
this.onPreCull = options.onPreCull;
this.onPreRender = options.onPreRender;
this.onPreRenderOpaque = options.onPreRenderOpaque;
this.onPreRenderTransparent = options.onPreRenderTransparent;
this.onPostCull = options.onPostCull;
this.onPostRender = options.onPostRender;
this.onPostRenderOpaque = options.onPostRenderOpaque;
this.onPostRenderTransparent = options.onPostRenderTransparent;
this.onDrawCall = options.onDrawCall;
this.onEnable = options.onEnable;
this.onDisable = options.onDisable;
if (this._enabled && this.onEnable) {
this.onEnable();
}
this.layerReference = options.layerReference; // should use the same camera
this.instances = options.layerReference ? options.layerReference.instances : new InstanceList();
this.cullingMask = options.cullingMask ? options.cullingMask : 0xFFFFFFFF;
this.opaqueMeshInstances = this.instances.opaqueMeshInstances;
this.transparentMeshInstances = this.instances.transparentMeshInstances;
this.shadowCasters = this.instances.shadowCasters;
this.customSortCallback = null;
this.customCalculateSortValues = null;
this._lightComponents = [];
this._lights = [];
this._sortedLights = [[], [], []];
this.cameras = [];
this._dirty = false;
this._dirtyLights = false;
this._dirtyCameras = false;
this._cameraHash = 0;
this._lightHash = 0;
this._staticLightHash = 0;
this._needsStaticPrepare = true;
this._staticPrepareDone = false;
// #ifdef PROFILER
this.skipRenderAfter = Number.MAX_VALUE;
this._skipRenderCounter = 0;
this._renderTime = 0;
this._forwardDrawCalls = 0;
this._shadowDrawCalls = 0;
// #endif
this._shaderVersion = -1;
this._version = 0;
this._lightCube = null;
};
Object.defineProperty(Layer.prototype, "enabled", {
get: function () {
return this._enabled;
},
set: function (val) {
if (val !== this._enabled) {
this._enabled = val;
if (val) {
this.incrementCounter();
if (this.onEnable) this.onEnable();
} else {
this.decrementCounter();
if (this.onDisable) this.onDisable();
}
}
}
});
Object.defineProperty(Layer.prototype, "clearColor", {
get: function () {
return this._clearColor;
},
set: function (val) {
this._clearColor.copy(val);
}
});
Layer.prototype._updateClearFlags = function () {
var flags = 0;
if (this._clearColorBuffer)
flags |= pc.CLEARFLAG_COLOR;
if (this._clearDepthBuffer)
flags |= pc.CLEARFLAG_DEPTH;
if (this._clearStencilBuffer)
flags |= pc.CLEARFLAG_STENCIL;
this._clearOptions.flags = flags;
};
Object.defineProperty(Layer.prototype, "clearColorBuffer", {
get: function () {
return this._clearColorBuffer;
},
set: function (val) {
this._clearColorBuffer = val;
this._updateClearFlags();
}
});
Object.defineProperty(Layer.prototype, "clearDepthBuffer", {
get: function () {
return this._clearDepthBuffer;
},
set: function (val) {
this._clearDepthBuffer = val;
this._updateClearFlags();
}
});
Object.defineProperty(Layer.prototype, "clearStencilBuffer", {
get: function () {
return this._clearStencilBuffer;
},
set: function (val) {
this._clearStencilBuffer = val;
this._updateClearFlags();
}
});
/**
* @private
* @function
* @name pc.Layer#incrementCounter
* @description Increments the usage counter of this layer.
* By default, layers are created with counter set to 1 (if {@link pc.Layer.enabled} is true) or 0 (if it was false).
* Incrementing the counter from 0 to 1 will enable the layer and call {@link pc.Layer.onEnable}.
* Use this function to "subscribe" multiple effects to the same layer. For example, if the layer is used to render a reflection texture which is used by 2 mirrors,
* then each mirror can call this function when visible and {@link pc.Layer.decrementCounter} if invisible.
* In such case the reflection texture won't be updated, when there is nothing to use it, saving performance.
*/
Layer.prototype.incrementCounter = function () {
if (this._refCounter === 0) {
this._enabled = true;
if (this.onEnable) this.onEnable();
}
this._refCounter++;
};
/**
* @private
* @function
* @name pc.Layer#decrementCounter
* @description Decrements the usage counter of this layer.
* Decrementing the counter from 1 to 0 will disable the layer and call {@link pc.Layer.onDisable}.
* See {@link pc.Layer#incrementCounter} for more details.
*/
Layer.prototype.decrementCounter = function () {
if (this._refCounter === 1) {
this._enabled = false;
if (this.onDisable) this.onDisable();
} else if (this._refCounter === 0) {
// #ifdef DEBUG
console.warn("Trying to decrement layer counter below 0");
// #endif
return;
}
this._refCounter--;
};
// SUBLAYER GROUPS
// If there are multiple sublayer with identical _cameraHash without anything in between, these
// are called a SUBLAYER GROUP instead of:
// for each sublayer
// for each camera
// we go:
// for each sublayerGroup
/**
* @function
* @name pc.Layer#addMeshInstances
* @description Adds an array of mesh instances to this layer.
* @param {Array} meshInstances Array of {@link pc.MeshInstance}.
* @param {Boolean} [skipShadowCasters] Set it to true if you don't want these mesh instances to cast shadows in this layer.
*/
Layer.prototype.addMeshInstances = function (meshInstances, skipShadowCasters) {
var sceneShaderVer = this._shaderVersion;
var m, arr, mat;
var casters = this.shadowCasters;
for (var i = 0; i < meshInstances.length; i++) {
m = meshInstances[i];
mat = m.material;
if (mat.blendType === pc.BLEND_NONE) {
arr = this.opaqueMeshInstances;
} else {
arr = this.transparentMeshInstances;
}
if (arr.indexOf(m) < 0) arr.push(m);
if (!skipShadowCasters && m.castShadow && casters.indexOf(m) < 0) casters.push(m);
if (!this.passThrough && sceneShaderVer >= 0 && mat._shaderVersion !== sceneShaderVer) { // clear old shader if needed
if (mat.updateShader !== pc.Material.prototype.updateShader) {
mat.clearVariants();
mat.shader = null;
}
mat._shaderVersion = sceneShaderVer;
}
}
if (!this.passThrough) this._dirty = true;
};
/**
* @function
* @name pc.Layer#removeMeshInstances
* @description Removes multiple mesh instances from this layer.
* @param {Array} meshInstances Array of {@link pc.MeshInstance}. If they were added to this layer, they will be removed.
* @param {Boolean} [skipShadowCasters] Set it to true if you want to still cast shadows from removed mesh instances or if they never did cast shadows before.
*/
Layer.prototype.removeMeshInstances = function (meshInstances, skipShadowCasters) {
var i, j, m, spliceOffset, spliceCount, len, drawCall;
var opaque = this.opaqueMeshInstances;
var transparent = this.transparentMeshInstances;
var casters = this.shadowCasters;
for (i = 0; i < meshInstances.length; i++) {
m = meshInstances[i];
// remove from opaque
spliceOffset = -1;
spliceCount = 0;
len = opaque.length;
for (j = 0; j < len; j++) {
drawCall = opaque[j];
if (drawCall === m) {
spliceOffset = j;
spliceCount = 1;
break;
}
if (drawCall._staticSource === m) {
if (spliceOffset < 0) spliceOffset = j;
spliceCount++;
} else if (spliceOffset >= 0) {
break;
}
}
if (spliceOffset >= 0) opaque.splice(spliceOffset, spliceCount);
// remove from transparent
spliceOffset = -1;
spliceCount = 0;
len = transparent.length;
for (j = 0; j < len; j++) {
drawCall = transparent[j];
if (drawCall === m) {
spliceOffset = j;
spliceCount = 1;
break;
}
if (drawCall._staticSource === m) {
if (spliceOffset < 0) spliceOffset = j;
spliceCount++;
} else if (spliceOffset >= 0) {
break;
}
}
if (spliceOffset >= 0) transparent.splice(spliceOffset, spliceCount);
// remove from shadows
if (skipShadowCasters) continue;
j = casters.indexOf(m);
if (j >= 0) casters.splice(j, 1);
}
this._dirty = true;
};
/**
* @function
* @name pc.Layer#clearMeshInstances
* @description Removes all mesh instances from this layer.
* @param {Boolean} [skipShadowCasters] Set it to true if you want to still cast shadows from removed mesh instances or if they never did cast shadows before.
*/
Layer.prototype.clearMeshInstances = function (skipShadowCasters) {
if (this.opaqueMeshInstances.length === 0 && this.transparentMeshInstances.length === 0) {
if (skipShadowCasters || this.shadowCasters.length === 0) return;
}
this.opaqueMeshInstances.length = 0;
this.transparentMeshInstances.length = 0;
if (!skipShadowCasters) this.shadowCasters.length = 0;
if (!this.passThrough) this._dirty = true;
};
/**
* @function
* @name pc.Layer#addLight
* @description Adds a light to this layer.
* @param {pc.LightComponent} light A {@link pc.LightComponent}.
*/
Layer.prototype.addLight = function (light) {
if (this._lightComponents.indexOf(light) >= 0) return;
this._lightComponents.push(light);
this._lights.push(light.light);
this._dirtyLights = true;
this._generateLightHash();
};
/**
* @function
* @name pc.Layer#removeLight
* @description Removes a light from this layer.
* @param {pc.LightComponent} light A {@link pc.LightComponent}.
*/
Layer.prototype.removeLight = function (light) {
var id = this._lightComponents.indexOf(light);
if (id < 0) return;
this._lightComponents.splice(id, 1);
id = this._lights.indexOf(light.light);
this._lights.splice(id, 1);
this._dirtyLights = true;
this._generateLightHash();
};
/**
* @function
* @name pc.Layer#clearLights
* @description Removes all lights from this layer.
*/
Layer.prototype.clearLights = function () {
this._lightComponents.length = 0;
this._lights.length = 0;
this._dirtyLights = true;
};
/**
* @function
* @name pc.Layer#addShadowCasters
* @description Adds an array of mesh instances to this layer, but only as shadow casters (they will not be rendered anywhere, but only cast shadows on other objects).
* @param {Array} meshInstances Array of {@link pc.MeshInstance}.
*/
Layer.prototype.addShadowCasters = function (meshInstances) {
var m;
var arr = this.shadowCasters;
for (var i = 0; i < meshInstances.length; i++) {
m = meshInstances[i];
if (!m.castShadow) continue;
if (arr.indexOf(m) < 0) arr.push(m);
}
this._dirtyLights = true;
};
/**
* @function
* @name pc.Layer#removeShadowCasters
* @description Removes multiple mesh instances from the shadow casters list of this layer, meaning they will stop casting shadows.
* @param {Array} meshInstances Array of {@link pc.MeshInstance}. If they were added to this layer, they will be removed.
*/
Layer.prototype.removeShadowCasters = function (meshInstances) {
var id;
var arr = this.shadowCasters;
for (var i = 0; i < meshInstances.length; i++) {
id = arr.indexOf(meshInstances[i]);
if (id >= 0) arr.splice(id, 1);
}
this._dirtyLights = true;
};
Layer.prototype._generateLightHash = function () {
// generate hash to check if layers have the same set of static lights
// order of lights shouldn't matter
if (this._lights.length > 0) {
this._lights.sort(sortLights);
var str = "";
var strStatic = "";
for (var i = 0; i < this._lights.length; i++) {
if (this._lights[i].isStatic) {
strStatic += this._lights[i].key;
} else {
str += this._lights[i].key;
}
}
if (str.length === 0) {
this._lightHash = 0;
} else {
this._lightHash = pc.hashCode(str);
}
if (strStatic.length === 0) {
this._staticLightHash = 0;
} else {
this._staticLightHash = pc.hashCode(strStatic);
}
} else {
this._lightHash = 0;
this._staticLightHash = 0;
}
};
Layer.prototype._generateCameraHash = function () {
// generate hash to check if cameras in layers are identical
// order of cameras shouldn't matter
if (this.cameras.length > 1) {
this.cameras.sort(sortCameras);
var str = "";
for (var i = 0; i < this.cameras.length; i++) {
str += this.cameras[i].entity.getGuid();
}
this._cameraHash = pc.hashCode(str);
} else {
this._cameraHash = 0;
}
this._dirtyCameras = true;
};
/**
* @function
* @name pc.Layer#addCamera
* @description Adds a camera to this layer.
* @param {pc.CameraComponent} camera A {@link pc.CameraComponent}.
*/
Layer.prototype.addCamera = function (camera) {
if (this.cameras.indexOf(camera) >= 0) return;
this.cameras.push(camera);
this._generateCameraHash();
};
/**
* @function
* @name pc.Layer#removeCamera
* @description Removes a camera from this layer.
* @param {pc.CameraComponent} camera A {@link pc.CameraComponent}.
*/
Layer.prototype.removeCamera = function (camera) {
var id = this.cameras.indexOf(camera);
if (id < 0) return;
this.cameras.splice(id, 1);
this._generateCameraHash();
// visible lists in layer are not updated after camera is removed
// so clear out any remaining mesh instances
this.instances.clearVisibleLists(id);
};
/**
* @function
* @name pc.Layer#clearCameras
* @description Removes all cameras from this layer.
*/
Layer.prototype.clearCameras = function () {
this.cameras.length = 0;
this._cameraHash = 0;
this._dirtyCameras = true;
};
Layer.prototype._sortCameras = function () {
this._generateCameraHash();
};
Layer.prototype._calculateSortDistances = function (drawCalls, drawCallsCount, camPos, camFwd) {
var i, drawCall, meshPos;
var tempx, tempy, tempz;
for (i = 0; i < drawCallsCount; i++) {
drawCall = drawCalls[i];
if (drawCall.command) continue;
if (drawCall.layer <= pc.LAYER_FX) continue; // Only alpha sort mesh instances in the main world (backwards comp)
meshPos = drawCall.aabb.center;
tempx = meshPos.x - camPos.x;
tempy = meshPos.y - camPos.y;
tempz = meshPos.z - camPos.z;
drawCall.zdist = tempx * camFwd.x + tempy * camFwd.y + tempz * camFwd.z;
}
};
Layer.prototype._sortVisible = function (transparent, cameraNode, cameraPass) {
var objects = this.instances;
var sortMode = transparent ? this.transparentSortMode : this.opaqueSortMode;
if (sortMode === pc.SORTMODE_NONE) return;
var visible = transparent ? objects.visibleTransparent[cameraPass] : objects.visibleOpaque[cameraPass];
if (sortMode === pc.SORTMODE_CUSTOM) {
sortPos = cameraNode.getPosition();
sortDir = cameraNode.forward;
if (this.customCalculateSortValues) {
this.customCalculateSortValues(visible.list, visible.length, sortPos, sortDir);
}
if (visible.list.length !== visible.length) {
visible.list.length = visible.length;
}
if (this.customSortCallback) {
visible.list.sort(this.customSortCallback);
}
} else {
if (sortMode === pc.SORTMODE_BACK2FRONT || sortMode === pc.SORTMODE_FRONT2BACK) {
sortPos = cameraNode.getPosition();
sortDir = cameraNode.forward;
this._calculateSortDistances(visible.list, visible.length, sortPos, sortDir);
}
if (visible.list.length !== visible.length) {
visible.list.length = visible.length;
}
visible.list.sort(sortCallbacks[sortMode]);
}
};
return {
Layer: Layer,
InstanceList: InstanceList,
VisibleInstanceList: VisibleInstanceList
};
}());