/*global define*/
define([
'../Core/clone',
'../Core/combine',
'../Core/defaultValue',
'../Core/defined',
'../Core/defineProperties',
'./BlendingState',
'./CullFace'
], function(
clone,
combine,
defaultValue,
defined,
defineProperties,
BlendingState,
CullFace) {
"use strict";
/**
* An appearance defines the full GLSL vertex and fragment shaders and the
* render state used to draw a {@link Primitive}. All appearances implement
* this base Appearance
interface.
*
* @alias Appearance
* @constructor
*
* @param {Object} [options] Object with the following properties:
* @param {Boolean} [options.translucent=true] When true
, the geometry is expected to appear translucent so {@link Appearance#renderState} has alpha blending enabled.
* @param {Boolean} [options.closed=false] When true
, the geometry is expected to be closed so {@link Appearance#renderState} has backface culling enabled.
* @param {Material} [options.material=Material.ColorType] The material used to determine the fragment color.
* @param {String} [options.vertexShaderSource] Optional GLSL vertex shader source to override the default vertex shader.
* @param {String} [options.fragmentShaderSource] Optional GLSL fragment shader source to override the default fragment shader.
* @param {RenderState} [options.renderState] Optional render state to override the default render state.
*
* @see MaterialAppearance
* @see EllipsoidSurfaceAppearance
* @see PerInstanceColorAppearance
* @see DebugAppearance
* @see PolylineColorAppearance
* @see PolylineMaterialAppearance
*
* @demo {@link http://cesiumjs.org/Cesium/Apps/Sandcastle/index.html?src=Geometry%20and%20Appearances.html|Geometry and Appearances Demo}
*/
var Appearance = function(options) {
options = defaultValue(options, defaultValue.EMPTY_OBJECT);
/**
* The material used to determine the fragment color. Unlike other {@link Appearance}
* properties, this is not read-only, so an appearance's material can change on the fly.
*
* @type Material
*
* @see {@link https://github.com/AnalyticalGraphicsInc/cesium/wiki/Fabric|Fabric}
*/
this.material = options.material;
/**
* When true
, the geometry is expected to appear translucent.
*
* @type {Boolean}
*
* @default true
*/
this.translucent = defaultValue(options.translucent, true);
this._vertexShaderSource = options.vertexShaderSource;
this._fragmentShaderSource = options.fragmentShaderSource;
this._renderState = options.renderState;
this._closed = defaultValue(options.closed, false);
};
defineProperties(Appearance.prototype, {
/**
* The GLSL source code for the vertex shader.
*
* @memberof Appearance.prototype
*
* @type {String}
* @readonly
*/
vertexShaderSource : {
get : function() {
return this._vertexShaderSource;
}
},
/**
* The GLSL source code for the fragment shader. The full fragment shader
* source is built procedurally taking into account the {@link Appearance#material}.
* Use {@link Appearance#getFragmentShaderSource} to get the full source.
*
* @memberof Appearance.prototype
*
* @type {String}
* @readonly
*/
fragmentShaderSource : {
get : function() {
return this._fragmentShaderSource;
}
},
/**
* The WebGL fixed-function state to use when rendering the geometry.
*
* @memberof Appearance.prototype
*
* @type {Object}
* @readonly
*/
renderState : {
get : function() {
return this._renderState;
}
},
/**
* When true
, the geometry is expected to be closed.
*
* @memberof Appearance.prototype
*
* @type {Boolean}
* @readonly
*
* @default false
*/
closed : {
get : function() {
return this._closed;
}
}
});
/**
* Procedurally creates the full GLSL fragment shader source for this appearance
* taking into account {@link Appearance#fragmentShaderSource} and {@link Appearance#material}.
*
* @returns {String} The full GLSL fragment shader source.
*/
Appearance.prototype.getFragmentShaderSource = function() {
var parts = [];
if (this.flat) {
parts.push('#define FLAT');
}
if (this.faceForward) {
parts.push('#define FACE_FORWARD');
}
if (defined(this.material)) {
parts.push(this.material.shaderSource);
}
parts.push(this.fragmentShaderSource);
return parts.join('\n');
};
/**
* Determines if the geometry is translucent based on {@link Appearance#translucent} and {@link Material#isTranslucent}.
*
* @returns {Boolean} true
if the appearance is translucent.
*/
Appearance.prototype.isTranslucent = function() {
return (defined(this.material) && this.material.isTranslucent()) || (!defined(this.material) && this.translucent);
};
/**
* Creates a render state. This is not the final render state instance; instead,
* it can contain a subset of render state properties identical to the render state
* created in the context.
*
* @returns {Object} The render state.
*/
Appearance.prototype.getRenderState = function() {
var translucent = this.isTranslucent();
var rs = clone(this.renderState, false);
if (translucent) {
rs.depthMask = false;
rs.blending = BlendingState.ALPHA_BLEND;
} else {
rs.depthMask = true;
}
return rs;
};
/**
* @private
*/
Appearance.getDefaultRenderState = function(translucent, closed, existing) {
var rs = {
depthTest : {
enabled : true
}
};
if (translucent) {
rs.depthMask = false;
rs.blending = BlendingState.ALPHA_BLEND;
}
if (closed) {
rs.cull = {
enabled : true,
face : CullFace.BACK
};
}
if (defined(existing)) {
rs = combine(existing, rs, true);
}
return rs;
};
return Appearance;
});